commit
980f1e4c28
4 changed files with 156 additions and 32 deletions
|
|
@ -346,6 +346,22 @@ class $MProvider extends MProvider with $Bridge<MProvider> {
|
||||||
false),
|
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(
|
'quarkFilesExtractor': BridgeMethodDef(
|
||||||
BridgeFunctionDef(
|
BridgeFunctionDef(
|
||||||
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future, [
|
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future, [
|
||||||
|
|
@ -368,6 +384,28 @@ class $MProvider extends MProvider with $Bridge<MProvider> {
|
||||||
false),
|
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(
|
'substringAfter': BridgeMethodDef(
|
||||||
BridgeFunctionDef(
|
BridgeFunctionDef(
|
||||||
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.string)),
|
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)
|
.wrap(MBridge.quarkVideosExtractor(args[0]!.$value, args[1]!.$value)
|
||||||
.then((value) =>
|
.then((value) =>
|
||||||
$List.wrap(value.map((e) => _toMVideo(e)).toList())))),
|
$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) =>
|
"quarkFilesExtractor" => $Function((_, __, List<$Value?> args) =>
|
||||||
$Future.wrap(
|
$Future.wrap(
|
||||||
MBridge.quarkFilesExtractor(args[0]!.$value, args[1]!.$value)
|
MBridge.quarkFilesExtractor(args[0]!.$value, args[1]!.$value)
|
||||||
|
|
@ -957,6 +999,16 @@ class $MProvider extends MProvider with $Bridge<MProvider> {
|
||||||
}))
|
}))
|
||||||
.toList());
|
.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) {
|
"toVideo" => $Function((_, __, List<$Value?> args) {
|
||||||
final value = MBridge.toVideo(
|
final value = MBridge.toVideo(
|
||||||
args[0]!.$value,
|
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:mangayomi/utils/reg_exp_matcher.dart';
|
||||||
import 'package:xpath_selector_html_parser/xpath_selector_html_parser.dart';
|
import 'package:xpath_selector_html_parser/xpath_selector_html_parser.dart';
|
||||||
import 'package:encrypt/encrypt.dart' as encrypt;
|
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 {
|
class WordSet {
|
||||||
final List<String> words;
|
final List<String> words;
|
||||||
|
|
@ -347,18 +347,32 @@ class MBridge {
|
||||||
|
|
||||||
static Future<List<Map<String, String>>> quarkFilesExtractor(
|
static Future<List<Map<String, String>>> quarkFilesExtractor(
|
||||||
List<String> url, String cookie) async {
|
List<String> url, String cookie) async {
|
||||||
QuarkExtractor quark = QuarkExtractor();
|
QuarkUcExtractor quark = QuarkUcExtractor();
|
||||||
await quark.initQuark(cookie);
|
await quark.initCloudDrive(cookie, CloudDriveType.quark);
|
||||||
return await quark.videoFilesFromUrl(url);
|
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(
|
static Future<List<Video>> quarkVideosExtractor(
|
||||||
String url, String cookie) async {
|
String url, String cookie) async {
|
||||||
QuarkExtractor quark = QuarkExtractor();
|
QuarkUcExtractor quark = QuarkUcExtractor();
|
||||||
await quark.initQuark(cookie);
|
await quark.initCloudDrive(cookie, CloudDriveType.quark);
|
||||||
return await quark.videosFromUrl(url);
|
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(
|
static Future<List<Video>> streamTapeExtractor(
|
||||||
String url, String? quality) async {
|
String url, String? quality) async {
|
||||||
return await StreamTapeExtractor()
|
return await StreamTapeExtractor()
|
||||||
|
|
|
||||||
|
|
@ -29,10 +29,17 @@ class JsVideosExtractors {
|
||||||
return (await MBridge.quarkVideosExtractor(args[0], args[1]))
|
return (await MBridge.quarkVideosExtractor(args[0], args[1]))
|
||||||
.encodeToJson();
|
.encodeToJson();
|
||||||
});
|
});
|
||||||
|
runtime.onMessage('ucVideosExtractor', (dynamic args) async {
|
||||||
|
return (await MBridge.ucVideosExtractor(args[0], args[1])).encodeToJson();
|
||||||
|
});
|
||||||
runtime.onMessage('quarkFilesExtractor', (dynamic args) async {
|
runtime.onMessage('quarkFilesExtractor', (dynamic args) async {
|
||||||
List<String> urls = (args[0] as List).cast<String>();
|
List<String> urls = (args[0] as List).cast<String>();
|
||||||
return (await MBridge.quarkFilesExtractor(urls, args[1]));
|
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 {
|
runtime.onMessage('streamlareExtractor', (dynamic args) async {
|
||||||
return (await MBridge.streamlareExtractor(
|
return (await MBridge.streamlareExtractor(
|
||||||
args[0], args[1] ?? "", args[2] ?? ""))
|
args[0], args[1] ?? "", args[2] ?? ""))
|
||||||
|
|
@ -193,6 +200,13 @@ async function quarkVideosExtractor(url, cookie) {
|
||||||
);
|
);
|
||||||
return JSON.parse(result);
|
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) {
|
async function quarkFilesExtractor(urls, cookie) {
|
||||||
const result = await sendMessage(
|
const result = await sendMessage(
|
||||||
"quarkFilesExtractor",
|
"quarkFilesExtractor",
|
||||||
|
|
@ -200,6 +214,13 @@ async function quarkFilesExtractor(urls, cookie) {
|
||||||
);
|
);
|
||||||
return result;
|
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/models/video.dart';
|
||||||
import 'package:mangayomi/services/http/m_client.dart';
|
import 'package:mangayomi/services/http/m_client.dart';
|
||||||
|
|
||||||
class QuarkExtractor {
|
enum CloudDriveType {
|
||||||
final String apiUrl = "https://drive-pc.quark.cn/1/clouddrive/";
|
quark,
|
||||||
|
uc,
|
||||||
|
}
|
||||||
|
|
||||||
|
class QuarkUcExtractor {
|
||||||
|
late CloudDriveType cloudDriveType;
|
||||||
|
String apiUrl = ""; //"https://drive-pc.quark.cn/1/clouddrive/";
|
||||||
String cookie = "";
|
String cookie = "";
|
||||||
Map<String, dynamic> shareTokenCache = {};
|
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'];
|
final List<String> subtitleExts = ['.srt', '.ass', '.scc', '.stl', '.ttml'];
|
||||||
Map<String, String> saveFileIdCaches = {};
|
Map<String, String> saveFileIdCaches = {};
|
||||||
String? saveDirId;
|
String? saveDirId;
|
||||||
final String saveDirName = 'TV';
|
final String saveDirName = 'TV';
|
||||||
|
|
||||||
Future<void> initQuark(String cookie) async {
|
Future<void> initCloudDrive(
|
||||||
|
String cookie, CloudDriveType cloudDriveType) async {
|
||||||
this.cookie = cookie;
|
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 = "pr=UCBrowser&fr=pc";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String> getHeaders() {
|
Map<String, String> getHeaders() {
|
||||||
return {
|
if (cloudDriveType == CloudDriveType.quark) {
|
||||||
'User-Agent':
|
return {
|
||||||
'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',
|
'User-Agent':
|
||||||
'Referer': 'https://pan.quark.cn/',
|
'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',
|
||||||
"Content-Type": "application/json",
|
'Referer': 'https://pan.quark.cn/',
|
||||||
"Cookie": cookie,
|
"Content-Type": "application/json",
|
||||||
"Host": "drive-pc.quark.cn"
|
"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(
|
Future<Map<String, dynamic>> api(
|
||||||
|
|
@ -60,7 +86,12 @@ class QuarkExtractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String>? getShareData(String url) {
|
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);
|
final matches = regex.firstMatch(url);
|
||||||
if (matches != null) {
|
if (matches != null) {
|
||||||
return {
|
return {
|
||||||
|
|
@ -71,7 +102,7 @@ class QuarkExtractor {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> getPlayFormtQuarkList() {
|
List<String> getPlayFormtList() {
|
||||||
return ["normal", "low", "high", "super", "2k", "4k"];
|
return ["normal", "low", "high", "super", "2k", "4k"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -114,10 +145,12 @@ class QuarkExtractor {
|
||||||
} else if (item['file'] == true && item['obj_category'] == 'video') {
|
} else if (item['file'] == true && item['obj_category'] == 'video') {
|
||||||
if (item['size'] < 1024 * 1024 * 5) continue;
|
if (item['size'] < 1024 * 1024 * 5) continue;
|
||||||
item['stoken'] = shareTokenCache[shareData['shareId']]['stoken'];
|
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' &&
|
} else if (item['type'] == 'file' &&
|
||||||
subtitleExts.any((x) => item['file_name'].endsWith(x))) {
|
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()) {
|
if (page < (listData['metadata']['_total'] / prePage).ceil()) {
|
||||||
|
|
@ -359,21 +392,21 @@ class QuarkExtractor {
|
||||||
|
|
||||||
Future<List<Video>> videosFromUrl(String url) async {
|
Future<List<Video>> videosFromUrl(String url) async {
|
||||||
List<String> parts = url.split('++');
|
List<String> parts = url.split('++');
|
||||||
String fileId = parts[0];
|
String fileId = parts[1];
|
||||||
String fileToken = parts[1];
|
String fileToken = parts[2];
|
||||||
String shareId = parts[2];
|
String shareId = parts[3];
|
||||||
String stoken = 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
|
// 原画起播慢,所以先获取normal
|
||||||
// var originalQuality =
|
// var originalQuality =
|
||||||
// await getDownload(shareId, stoken, fileId, fileToken, true);
|
// await getDownload(shareId, stoken, fileId, fileToken, true);
|
||||||
String? originalUrl =
|
String? originalUrl = //originalQuality?['download_url'];
|
||||||
await getLiveTranscoding(shareId, stoken, fileId, fileToken, 'normal');
|
await getLiveTranscoding(shareId, stoken, fileId, fileToken, 'normal');
|
||||||
|
|
||||||
// 获取可用的质量列表
|
// 获取可用的质量列表
|
||||||
List<String> qualities = getPlayFormtQuarkList();
|
List<String> qualities = getPlayFormtList();
|
||||||
List<Video> videos = [];
|
List<Video> videos = [];
|
||||||
|
|
||||||
for (String quality in qualities) {
|
for (String quality in qualities) {
|
||||||
|
|
@ -504,9 +537,10 @@ class Item {
|
||||||
int shareIndex = 0;
|
int shareIndex = 0;
|
||||||
int lastUpdateAt = 0;
|
int lastUpdateAt = 0;
|
||||||
dynamic subtitle;
|
dynamic subtitle;
|
||||||
|
late CloudDriveType cloudDriveType;
|
||||||
|
|
||||||
static Item objectFrom(
|
static Item objectFrom(Map<String, dynamic> itemJson, String shareId,
|
||||||
Map<String, dynamic> itemJson, String shareId, int shareIndex) {
|
int shareIndex, CloudDriveType cloudDriveType) {
|
||||||
Item item = Item();
|
Item item = Item();
|
||||||
item.fileId = itemJson['fid'] ?? "";
|
item.fileId = itemJson['fid'] ?? "";
|
||||||
item.shareId = shareId;
|
item.shareId = shareId;
|
||||||
|
|
@ -520,6 +554,7 @@ class Item {
|
||||||
item.parent = itemJson['pdir_fid'] ?? "";
|
item.parent = itemJson['pdir_fid'] ?? "";
|
||||||
item.lastUpdateAt = itemJson['last_update_at'] ?? 0;
|
item.lastUpdateAt = itemJson['last_update_at'] ?? 0;
|
||||||
item.shareIndex = shareIndex;
|
item.shareIndex = shareIndex;
|
||||||
|
item.cloudDriveType = cloudDriveType;
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -548,6 +583,8 @@ class Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
String getDisplayName(String typeName) {
|
String getDisplayName(String typeName) {
|
||||||
|
String drivePrefix =
|
||||||
|
cloudDriveType == CloudDriveType.quark ? '[quark]' : '[uc]';
|
||||||
String displayName = getName();
|
String displayName = getName();
|
||||||
if (typeName == "电视剧") {
|
if (typeName == "电视剧") {
|
||||||
List<String> replaceNameList = ["4k", "4K"];
|
List<String> replaceNameList = ["4k", "4K"];
|
||||||
|
|
@ -567,11 +604,11 @@ class Item {
|
||||||
displayName = numbers[0]!;
|
displayName = numbers[0]!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "$displayName ${getSize()}";
|
return "$drivePrefix $displayName ${getSize()}";
|
||||||
}
|
}
|
||||||
|
|
||||||
String getEpisodeUrl(String typeName) {
|
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) {
|
String getHumanReadableSize(int bytes) {
|
||||||
Loading…
Reference in a new issue