add UC extractor
This commit is contained in:
parent
0805c7417b
commit
c5bd38719f
4 changed files with 156 additions and 32 deletions
|
|
@ -346,6 +346,22 @@ class $MProvider extends MProvider with $Bridge<MProvider> {
|
|||
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<MProvider> {
|
|||
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<MProvider> {
|
|||
.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<MProvider> {
|
|||
}))
|
||||
.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,
|
||||
|
|
|
|||
|
|
@ -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<String> words;
|
||||
|
|
@ -347,18 +347,32 @@ class MBridge {
|
|||
|
||||
static Future<List<Map<String, String>>> quarkFilesExtractor(
|
||||
List<String> 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<List<Map<String, String>>> ucFilesExtractor(
|
||||
List<String> url, String cookie) async {
|
||||
QuarkUcExtractor uc = QuarkUcExtractor();
|
||||
await uc.initCloudDrive(cookie, CloudDriveType.uc);
|
||||
return await uc.videoFilesFromUrl(url);
|
||||
}
|
||||
|
||||
static Future<List<Video>> 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<List<Video>> ucVideosExtractor(
|
||||
String url, String cookie) async {
|
||||
QuarkUcExtractor uc = QuarkUcExtractor();
|
||||
await uc.initCloudDrive(cookie, CloudDriveType.uc);
|
||||
return await uc.videosFromUrl(url);
|
||||
}
|
||||
|
||||
static Future<List<Video>> streamTapeExtractor(
|
||||
String url, String? quality) async {
|
||||
return await StreamTapeExtractor()
|
||||
|
|
|
|||
|
|
@ -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<String> urls = (args[0] as List).cast<String>();
|
||||
return (await MBridge.quarkFilesExtractor(urls, args[1]));
|
||||
});
|
||||
runtime.onMessage('ucFilesExtractor', (dynamic args) async {
|
||||
List<String> urls = (args[0] as List).cast<String>();
|
||||
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;
|
||||
}
|
||||
''');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<String, dynamic> shareTokenCache = {};
|
||||
final String pr = "pr=ucpro&fr=pc";
|
||||
String pr = ""; //"pr=ucpro&fr=pc";
|
||||
final List<String> subtitleExts = ['.srt', '.ass', '.scc', '.stl', '.ttml'];
|
||||
Map<String, String> saveFileIdCaches = {};
|
||||
String? saveDirId;
|
||||
final String saveDirName = 'TV';
|
||||
|
||||
Future<void> initQuark(String cookie) async {
|
||||
Future<void> 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<String, String> 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<Map<String, dynamic>> api(
|
||||
|
|
@ -60,7 +86,12 @@ class QuarkExtractor {
|
|||
}
|
||||
|
||||
Map<String, String>? 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<String> getPlayFormtQuarkList() {
|
||||
List<String> 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<List<Video>> videosFromUrl(String url) async {
|
||||
List<String> 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<String> subtitleParts = parts.length > 4 ? parts[4].split('+') : [];
|
||||
List<String> 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<String> qualities = getPlayFormtQuarkList();
|
||||
List<String> qualities = getPlayFormtList();
|
||||
List<Video> videos = [];
|
||||
|
||||
for (String quality in qualities) {
|
||||
|
|
@ -504,9 +537,10 @@ class Item {
|
|||
int shareIndex = 0;
|
||||
int lastUpdateAt = 0;
|
||||
dynamic subtitle;
|
||||
late CloudDriveType cloudDriveType;
|
||||
|
||||
static Item objectFrom(
|
||||
Map<String, dynamic> itemJson, String shareId, int shareIndex) {
|
||||
static Item objectFrom(Map<String, dynamic> itemJson, String shareId,
|
||||
int shareIndex, CloudDriveType cloudDriveType) {
|
||||
Item item = Item();
|
||||
item.fileId = itemJson['fid'] ?? "";
|
||||
item.shareId = shareId;
|
||||
|
|
@ -520,6 +554,7 @@ class Item {
|
|||
item.parent = itemJson['pdir_fid'] ?? "";
|
||||
item.lastUpdateAt = itemJson['last_update_at'] ?? 0;
|
||||
item.shareIndex = shareIndex;
|
||||
item.cloudDriveType = cloudDriveType;
|
||||
return item;
|
||||
}
|
||||
|
||||
|
|
@ -548,6 +583,8 @@ class Item {
|
|||
}
|
||||
|
||||
String getDisplayName(String typeName) {
|
||||
String drivePrefix =
|
||||
cloudDriveType == CloudDriveType.quark ? '[quark]' : '[uc]';
|
||||
String displayName = getName();
|
||||
if (typeName == "电视剧") {
|
||||
List<String> replaceNameList = ["4k", "4K"];
|
||||
|
|
@ -567,11 +604,11 @@ class Item {
|
|||
displayName = numbers[0]!;
|
||||
}
|
||||
}
|
||||
return "$displayName ${getSize()}";
|
||||
return "$drivePrefix $displayName ${getSize()}";
|
||||
}
|
||||
|
||||
String getEpisodeUrl(String typeName) {
|
||||
return "${getDisplayName(typeName)}\$${getFileId()}++$shareFileToken++$shareId++$shareToken";
|
||||
return "${getDisplayName(typeName)}\$${cloudDriveType == CloudDriveType.quark ? "quark" : "uc"}++${getFileId()}++$shareFileToken++$shareId++$shareToken";
|
||||
}
|
||||
|
||||
String getHumanReadableSize(int bytes) {
|
||||
Loading…
Reference in a new issue