From c5bd38719f41b0abd87d242f04bfe1c9e0e026ae Mon Sep 17 00:00:00 2001 From: yxxyun Date: Sat, 5 Oct 2024 21:13:16 +0800 Subject: [PATCH] add UC extractor --- lib/eval/dart/bridge/m_provider.dart | 52 +++++++++++ lib/eval/dart/model/m_bridge.dart | 24 ++++- lib/eval/javascript/extractors.dart | 21 +++++ ..._extractor.dart => quarkuc_extractor.dart} | 91 +++++++++++++------ 4 files changed, 156 insertions(+), 32 deletions(-) rename lib/services/anime_extractors/{quark_extractor.dart => quarkuc_extractor.dart} (86%) diff --git a/lib/eval/dart/bridge/m_provider.dart b/lib/eval/dart/bridge/m_provider.dart index 78481a9..814cda2 100644 --- a/lib/eval/dart/bridge/m_provider.dart +++ b/lib/eval/dart/bridge/m_provider.dart @@ -346,6 +346,22 @@ class $MProvider extends MProvider with $Bridge { false), ]), ), + 'ucVideosExtractor': BridgeMethodDef( + BridgeFunctionDef( + returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future, [ + BridgeTypeRef(CoreTypes.list, [$MVideo.$type]) + ])), + params: [ + BridgeParameter( + 'url', + BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), + false), + BridgeParameter( + 'cookie', + BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), + false), + ]), + ), 'quarkFilesExtractor': BridgeMethodDef( BridgeFunctionDef( returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future, [ @@ -368,6 +384,28 @@ class $MProvider extends MProvider with $Bridge { false), ]), ), + 'ucFilesExtractor': BridgeMethodDef( + BridgeFunctionDef( + returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future, [ + BridgeTypeRef(CoreTypes.list, [ + BridgeTypeRef(CoreTypes.map, [ + BridgeTypeRef(CoreTypes.string), + BridgeTypeRef(CoreTypes.string) + ]) + ]) + ])), + params: [ + BridgeParameter( + 'url', + BridgeTypeAnnotation(BridgeTypeRef( + CoreTypes.list, [BridgeTypeRef(CoreTypes.string)])), + false), + BridgeParameter( + 'cookie', + BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), + false), + ]), + ), 'substringAfter': BridgeMethodDef( BridgeFunctionDef( returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)), @@ -946,6 +984,10 @@ class $MProvider extends MProvider with $Bridge { .wrap(MBridge.quarkVideosExtractor(args[0]!.$value, args[1]!.$value) .then((value) => $List.wrap(value.map((e) => _toMVideo(e)).toList())))), + "ucVideosExtractor" => $Function((_, __, List<$Value?> args) => $Future + .wrap(MBridge.ucVideosExtractor(args[0]!.$value, args[1]!.$value) + .then((value) => + $List.wrap(value.map((e) => _toMVideo(e)).toList())))), "quarkFilesExtractor" => $Function((_, __, List<$Value?> args) => $Future.wrap( MBridge.quarkFilesExtractor(args[0]!.$value, args[1]!.$value) @@ -957,6 +999,16 @@ class $MProvider extends MProvider with $Bridge { })) .toList()); }))), + "ucFilesExtractor" => $Function((_, __, List<$Value?> args) => $Future + .wrap(MBridge.ucFilesExtractor(args[0]!.$value, args[1]!.$value) + .then((value) { + return $List.wrap(value + .map((e) => $Map.wrap({ + $String('name'): $String(e['name'] ?? ''), + $String('url'): $String(e['url'] ?? ''), + })) + .toList()); + }))), "toVideo" => $Function((_, __, List<$Value?> args) { final value = MBridge.toVideo( args[0]!.$value, diff --git a/lib/eval/dart/model/m_bridge.dart b/lib/eval/dart/model/m_bridge.dart index 1fa1390..123989c 100644 --- a/lib/eval/dart/model/m_bridge.dart +++ b/lib/eval/dart/model/m_bridge.dart @@ -33,7 +33,7 @@ import 'package:mangayomi/utils/extensions/string_extensions.dart'; import 'package:mangayomi/utils/reg_exp_matcher.dart'; import 'package:xpath_selector_html_parser/xpath_selector_html_parser.dart'; import 'package:encrypt/encrypt.dart' as encrypt; -import 'package:mangayomi/services/anime_extractors/quark_extractor.dart'; +import 'package:mangayomi/services/anime_extractors/quarkuc_extractor.dart'; class WordSet { final List words; @@ -347,18 +347,32 @@ class MBridge { static Future>> quarkFilesExtractor( List url, String cookie) async { - QuarkExtractor quark = QuarkExtractor(); - await quark.initQuark(cookie); + QuarkUcExtractor quark = QuarkUcExtractor(); + await quark.initCloudDrive(cookie, CloudDriveType.quark); return await quark.videoFilesFromUrl(url); } + static Future>> ucFilesExtractor( + List url, String cookie) async { + QuarkUcExtractor uc = QuarkUcExtractor(); + await uc.initCloudDrive(cookie, CloudDriveType.uc); + return await uc.videoFilesFromUrl(url); + } + static Future> quarkVideosExtractor( String url, String cookie) async { - QuarkExtractor quark = QuarkExtractor(); - await quark.initQuark(cookie); + QuarkUcExtractor quark = QuarkUcExtractor(); + await quark.initCloudDrive(cookie, CloudDriveType.quark); return await quark.videosFromUrl(url); } + static Future> ucVideosExtractor( + String url, String cookie) async { + QuarkUcExtractor uc = QuarkUcExtractor(); + await uc.initCloudDrive(cookie, CloudDriveType.uc); + return await uc.videosFromUrl(url); + } + static Future> streamTapeExtractor( String url, String? quality) async { return await StreamTapeExtractor() diff --git a/lib/eval/javascript/extractors.dart b/lib/eval/javascript/extractors.dart index 830f614..d63c75c 100644 --- a/lib/eval/javascript/extractors.dart +++ b/lib/eval/javascript/extractors.dart @@ -29,10 +29,17 @@ class JsVideosExtractors { return (await MBridge.quarkVideosExtractor(args[0], args[1])) .encodeToJson(); }); + runtime.onMessage('ucVideosExtractor', (dynamic args) async { + return (await MBridge.ucVideosExtractor(args[0], args[1])).encodeToJson(); + }); runtime.onMessage('quarkFilesExtractor', (dynamic args) async { List urls = (args[0] as List).cast(); return (await MBridge.quarkFilesExtractor(urls, args[1])); }); + runtime.onMessage('ucFilesExtractor', (dynamic args) async { + List urls = (args[0] as List).cast(); + return (await MBridge.ucFilesExtractor(urls, args[1])); + }); runtime.onMessage('streamlareExtractor', (dynamic args) async { return (await MBridge.streamlareExtractor( args[0], args[1] ?? "", args[2] ?? "")) @@ -193,6 +200,13 @@ async function quarkVideosExtractor(url, cookie) { ); return JSON.parse(result); } +async function ucVideosExtractor(url, cookie) { + const result = await sendMessage( + "ucVideosExtractor", + JSON.stringify([url, cookie]) + ); + return JSON.parse(result); +} async function quarkFilesExtractor(urls, cookie) { const result = await sendMessage( "quarkFilesExtractor", @@ -200,6 +214,13 @@ async function quarkFilesExtractor(urls, cookie) { ); return result; } +async function ucFilesExtractor(urls, cookie) { + const result = await sendMessage( + "ucFilesExtractor", + JSON.stringify([urls, cookie]) + ); + return result; +} '''); } } diff --git a/lib/services/anime_extractors/quark_extractor.dart b/lib/services/anime_extractors/quarkuc_extractor.dart similarity index 86% rename from lib/services/anime_extractors/quark_extractor.dart rename to lib/services/anime_extractors/quarkuc_extractor.dart index d3ce4cb..d952ad2 100644 --- a/lib/services/anime_extractors/quark_extractor.dart +++ b/lib/services/anime_extractors/quarkuc_extractor.dart @@ -5,29 +5,55 @@ import 'package:http_interceptor/http_interceptor.dart'; import 'package:mangayomi/models/video.dart'; import 'package:mangayomi/services/http/m_client.dart'; -class QuarkExtractor { - final String apiUrl = "https://drive-pc.quark.cn/1/clouddrive/"; +enum CloudDriveType { + quark, + uc, +} + +class QuarkUcExtractor { + late CloudDriveType cloudDriveType; + String apiUrl = ""; //"https://drive-pc.quark.cn/1/clouddrive/"; String cookie = ""; Map shareTokenCache = {}; - final String pr = "pr=ucpro&fr=pc"; + String pr = ""; //"pr=ucpro&fr=pc"; final List subtitleExts = ['.srt', '.ass', '.scc', '.stl', '.ttml']; Map saveFileIdCaches = {}; String? saveDirId; final String saveDirName = 'TV'; - Future initQuark(String cookie) async { + Future initCloudDrive( + String cookie, CloudDriveType cloudDriveType) async { this.cookie = cookie; + this.cloudDriveType = cloudDriveType; + if (cloudDriveType == CloudDriveType.quark) { + apiUrl = "https://drive-pc.quark.cn/1/clouddrive/"; + pr = "pr=ucpro&fr=pc"; + } else { + apiUrl = "https://pc-api.uc.cn/1/clouddrive/"; + pr = "UCBrowser&fr=pc"; + } } Map getHeaders() { - return { - 'User-Agent': - 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) quark-cloud-drive/2.5.20 Chrome/100.0.4896.160 Electron/18.3.5.4-b478491100 Safari/537.36 Channel/pckk_other_ch', - 'Referer': 'https://pan.quark.cn/', - "Content-Type": "application/json", - "Cookie": cookie, - "Host": "drive-pc.quark.cn" - }; + if (cloudDriveType == CloudDriveType.quark) { + return { + 'User-Agent': + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) quark-cloud-drive/2.5.20 Chrome/100.0.4896.160 Electron/18.3.5.4-b478491100 Safari/537.36 Channel/pckk_other_ch', + 'Referer': 'https://pan.quark.cn/', + "Content-Type": "application/json", + "Cookie": cookie, + "Host": "drive-pc.quark.cn" + }; + } else { + return { + 'User-Agent': + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) uc-cloud-drive/2.5.20 Chrome/100.0.4896.160 Electron/18.3.5.4-b478491100 Safari/537.36 Channel/pckk_other_ch', + 'Referer': 'https://drive.uc.cn/', + "Content-Type": "application/json", + "Cookie": cookie, + "Host": "pc-api.uc.cn" + }; + } } Future> api( @@ -60,7 +86,12 @@ class QuarkExtractor { } Map? getShareData(String url) { - final regex = RegExp(r'https://pan\.quark\.cn/s/([^\\|#/]+)'); + RegExp regex; + if (cloudDriveType == CloudDriveType.quark) { + regex = RegExp(r'https://pan\.quark\.cn/s/([^\\|#/]+)'); + } else { + regex = RegExp(r'https://drive\.uc\.cn/s/([^?]+)'); + } final matches = regex.firstMatch(url); if (matches != null) { return { @@ -71,7 +102,7 @@ class QuarkExtractor { return null; } - List getPlayFormtQuarkList() { + List getPlayFormtList() { return ["normal", "low", "high", "super", "2k", "4k"]; } @@ -114,10 +145,12 @@ class QuarkExtractor { } else if (item['file'] == true && item['obj_category'] == 'video') { if (item['size'] < 1024 * 1024 * 5) continue; item['stoken'] = shareTokenCache[shareData['shareId']]['stoken']; - videos.add(Item.objectFrom(item, shareData['shareId']!, shareIndex)); + videos.add(Item.objectFrom( + item, shareData['shareId']!, shareIndex, cloudDriveType)); } else if (item['type'] == 'file' && subtitleExts.any((x) => item['file_name'].endsWith(x))) { - subtitles.add(Item.objectFrom(item, shareData['shareId']!, shareIndex)); + subtitles.add(Item.objectFrom( + item, shareData['shareId']!, shareIndex, cloudDriveType)); } } if (page < (listData['metadata']['_total'] / prePage).ceil()) { @@ -359,21 +392,21 @@ class QuarkExtractor { Future> videosFromUrl(String url) async { List parts = url.split('++'); - String fileId = parts[0]; - String fileToken = parts[1]; - String shareId = parts[2]; - String stoken = parts[3]; + String fileId = parts[1]; + String fileToken = parts[2]; + String shareId = parts[3]; + String stoken = parts[4]; - List subtitleParts = parts.length > 4 ? parts[4].split('+') : []; + List subtitleParts = parts.length > 5 ? parts[5].split('+') : []; // 原画起播慢,所以先获取normal // var originalQuality = // await getDownload(shareId, stoken, fileId, fileToken, true); - String? originalUrl = + String? originalUrl = //originalQuality?['download_url']; await getLiveTranscoding(shareId, stoken, fileId, fileToken, 'normal'); // 获取可用的质量列表 - List qualities = getPlayFormtQuarkList(); + List qualities = getPlayFormtList(); List