feat: implement torrent streaming support

Added react-native-torrent-streamer and TorrentService. Enabled magnet link forwarding to external players.
This commit is contained in:
Darkrock04 2026-03-16 16:23:06 +05:30
parent 5f49a7f2ab
commit 2d85094508
4 changed files with 97 additions and 6 deletions

View file

@ -92,6 +92,7 @@
"react-native-safe-area-context": "~5.7.0",
"react-native-screens": "^4.24.0",
"react-native-svg": "^15.15.3",
"react-native-torrent-streamer": "^0.2.3",
"react-native-url-polyfill": "^3.0.0",
"react-native-vector-icons": "^10.3.0",
"react-native-video": "^6.19.0",

View file

@ -17,6 +17,7 @@ import { localScraperService } from '../../services/pluginService';
import { VideoPlayerService } from '../../services/videoPlayerService';
import { streamCacheService } from '../../services/streamCacheService';
import { tmdbService } from '../../services/tmdbService';
import { torrentService } from '../../services/torrentService';
import { logger } from '../../utils/logger';
import { TABLET_BREAKPOINT } from './constants';
import {
@ -463,10 +464,26 @@ export const useStreamsScreen = () => {
});
}
// Block magnet links
if (typeof stream.url === 'string' && stream.url.startsWith('magnet:')) {
openAlert('Not supported', 'Torrent streaming is not supported yet.');
return;
// Let external players handle magnet links
const isMagnet = typeof stream.url === 'string' && stream.url.startsWith('magnet:');
// Process magnet links via the torrent service if using internal player
if (isMagnet && settings.preferredPlayer === 'internal' && !settings.useExternalPlayer) {
if (Platform.OS === 'android') {
try {
if (showInfo) showInfo('Starting Torrent Stream... Please wait.');
const localUrl = await torrentService.startStreaming(stream.url as string);
const torrentStream = { ...stream, url: localUrl };
navigateToPlayer(torrentStream);
return;
} catch (err) {
openAlert('Torrent Error', 'Failed to start the torrent stream.');
return;
}
} else {
openAlert('Not supported internally', 'Internal torrent streaming is only supported on Android. Please use an external player.');
return;
}
}
// iOS external player

View file

@ -0,0 +1,71 @@
import { Platform } from 'react-native';
import { logger } from '../utils/logger';
// @ts-ignore - Module might not have types
import TorrentStreamer from 'react-native-torrent-streamer';
export const torrentService = {
startStreaming: (url: string): Promise<string> => {
return new Promise((resolve, reject) => {
if (Platform.OS !== 'android') {
reject(new Error('Torrent streaming natively is only supported on Android.'));
return;
}
try {
TorrentStreamer.start(url);
const onReady = (data: any) => {
logger.log('[TorrentService] Torrent is ready at:', data.url);
// Remove listener once resolved to prevent memory leaks
TorrentStreamer.removeEventListener('ready', onReady);
resolve(data.url);
};
const onError = (error: any) => {
logger.error('[TorrentService] Error streaming torrent:', error);
TorrentStreamer.removeEventListener('error', onError);
reject(error);
};
TorrentStreamer.addEventListener('ready', onReady);
TorrentStreamer.addEventListener('error', onError);
} catch (err) {
logger.error('[TorrentService] Initialization error:', err);
reject(err);
}
});
},
stopStreaming: () => {
if (Platform.OS === 'android') {
try {
TorrentStreamer.stop();
logger.log('[TorrentService] Stopped torrent stream.');
} catch (err) {
logger.error('[TorrentService] Failed to stop stream:', err);
}
}
},
addListener: (event: 'status' | 'ready' | 'error', callback: (data: any) => void) => {
if (Platform.OS === 'android') {
try {
TorrentStreamer.addEventListener(event, callback);
} catch (err) {
logger.warn('[TorrentService] Could not add listener:', err);
}
}
},
removeListener: (event: 'status' | 'ready' | 'error', callback: (data: any) => void) => {
if (Platform.OS === 'android') {
try {
TorrentStreamer.removeEventListener(event, callback);
} catch (err) {
logger.warn('[TorrentService] Could not remove listener:', err);
}
}
}
};

View file

@ -29,11 +29,13 @@ export const VideoPlayerService = {
options.releaseDate
].filter(Boolean).join(' - ');
// Launch the intent to play the video
// Launch the intent to play the video or handle the magnet link
const isMagnet = url.startsWith('magnet:');
await IntentLauncher.startActivityAsync('android.intent.action.VIEW', {
data: url,
flags: 1, // FLAG_ACTIVITY_NEW_TASK
type: 'video/*',
type: isMagnet ? 'application/x-bittorrent' : 'video/*',
extra: {
'android.intent.extra.TITLE': fullTitle,
'position': 0, // Start from beginning