import 'dart:isolate'; import 'package:spotube/services/youtube_engine/youtube_engine.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart'; import 'dart:async'; /// It contains methods that are computationally expensive class IsolatedYoutubeExplode { final Isolate _isolate; final SendPort _sendPort; final ReceivePort _receivePort; IsolatedYoutubeExplode._( Isolate isolate, ReceivePort receivePort, SendPort sendPort, ) : _isolate = isolate, _receivePort = receivePort, _sendPort = sendPort; static IsolatedYoutubeExplode? _instance; static IsolatedYoutubeExplode get instance => _instance!; static bool get isInitialized => _instance != null; static Future initialize() async { if (_instance != null) { return; } final completer = Completer(); final receivePort = ReceivePort(); /// Listen for the main isolate to set the main port final subscription = receivePort.listen((message) { if (message is SendPort) { completer.complete(message); } }); final isolate = await Isolate.spawn(_isolateEntry, receivePort.sendPort); _instance = IsolatedYoutubeExplode._( isolate, receivePort, await completer.future, ); if (completer.isCompleted) { subscription.cancel(); } } static void _isolateEntry(SendPort mainSendPort) { final receivePort = ReceivePort(); final youtubeExplode = YoutubeExplode(); /// Send the main port to the main isolate mainSendPort.send(receivePort.sendPort); receivePort.listen((message) async { final SendPort replyPort = message[0]; final String methodName = message[1]; final List arguments = message[2]; // Run the requested method on YoutubeExplode var result = switch (methodName) { "search" => youtubeExplode.search .search( arguments[0] as String, filter: arguments.elementAtOrNull(1) ?? TypeFilters.video, ) .then((s) => s.toList()), "video" => youtubeExplode.videos.get(arguments[0] as String), "manifest" => youtubeExplode.videos.streamsClient.getManifest( arguments[0] as String, requireWatchPage: arguments.elementAtOrNull(1) ?? true, ytClients: arguments.elementAtOrNull(2) as List?, ), _ => throw ArgumentError('Invalid method name: $methodName'), }; replyPort.send(await result); }); } Future _runMethod(String methodName, List args) { final completer = Completer(); final responsePort = ReceivePort(); responsePort.listen((message) { completer.complete(message as T); responsePort.close(); }); _sendPort.send([responsePort.sendPort, methodName, args]); return completer.future; } Future> search( String query, { SearchFilter? filter, }) async { return _runMethod>("search", [query]); } Future