added new anime servers extractors
This commit is contained in:
parent
6a80f194ae
commit
b21a9409af
19 changed files with 479 additions and 84 deletions
|
|
@ -14,18 +14,24 @@ import 'package:json_path/json_path.dart';
|
|||
import 'package:mangayomi/eval/bridge_class/model.dart';
|
||||
import 'package:mangayomi/eval/bridge_class/video_model.dart';
|
||||
import 'package:mangayomi/services/anime_extractors/dood_extractor.dart';
|
||||
import 'package:mangayomi/services/anime_extractors/gogo_cdn_extractor.dart';
|
||||
import 'package:mangayomi/services/anime_extractors/mp4_upload_extractor.dart';
|
||||
import 'package:mangayomi/services/anime_extractors/my_tv_extractor.dart';
|
||||
import 'package:mangayomi/services/anime_extractors/send_vid_extractor.dart';
|
||||
import 'package:mangayomi/services/anime_extractors/gogocdn_extractor.dart';
|
||||
import 'package:mangayomi/services/anime_extractors/mp4upload_extractor.dart';
|
||||
import 'package:mangayomi/services/anime_extractors/mytv_extractor.dart';
|
||||
import 'package:mangayomi/services/anime_extractors/okru_extractor.dart';
|
||||
import 'package:mangayomi/services/anime_extractors/sendvid_extractor.dart';
|
||||
import 'package:mangayomi/services/anime_extractors/sibnet_extractor.dart';
|
||||
import 'package:mangayomi/services/anime_extractors/stream_tape_extractor.dart';
|
||||
import 'package:mangayomi/services/anime_extractors/streamlare_extractor.dart';
|
||||
import 'package:mangayomi/services/anime_extractors/streamtape_extractor.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/models/video.dart';
|
||||
import 'package:mangayomi/modules/webview/webview.dart';
|
||||
import 'package:mangayomi/services/anime_extractors/vidbom_extractor.dart';
|
||||
import 'package:mangayomi/services/anime_extractors/voe_extractor.dart';
|
||||
import 'package:mangayomi/services/anime_extractors/your_upload_extractor.dart';
|
||||
import 'package:mangayomi/services/http_service/cloudflare/cloudflare_bypass.dart';
|
||||
import 'package:mangayomi/utils/constant.dart';
|
||||
import 'package:mangayomi/utils/extensions.dart';
|
||||
import 'package:mangayomi/utils/reg_exp_matcher.dart';
|
||||
import 'package:mangayomi/utils/xpath_selector.dart';
|
||||
import 'package:xpath_selector_html_parser/xpath_selector_html_parser.dart';
|
||||
|
|
@ -220,7 +226,7 @@ class MBridge {
|
|||
static Future<String> getHtmlViaWebview(String url, String rule) async {
|
||||
bool isOk = false;
|
||||
String? html;
|
||||
if (Platform.isWindows || Platform.isLinux) {
|
||||
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
|
||||
final webview = await WebviewWindow.create(
|
||||
configuration: CreateConfiguration(
|
||||
windowHeight: 500,
|
||||
|
|
@ -551,15 +557,12 @@ class MBridge {
|
|||
|
||||
static String subString(String text, String pattern, int type) {
|
||||
String result = "";
|
||||
//substring before
|
||||
if (type == 0) {
|
||||
result = text.split(pattern).first;
|
||||
} else
|
||||
// substring after last
|
||||
if (type == 1) {
|
||||
result = text.substringBefore(pattern);
|
||||
} else if (type == 1) {
|
||||
result = text.split(pattern).last;
|
||||
} else if (type == 2) {
|
||||
result = text.substring(text.lastIndexOf(pattern) + 1);
|
||||
result = text.substringAfter(pattern);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -725,6 +728,39 @@ class MBridge {
|
|||
);
|
||||
}
|
||||
|
||||
static Future<List<Video>> okruExtractor(String url) async {
|
||||
return await OkruExtractor().videosFromUrl(
|
||||
url,
|
||||
);
|
||||
}
|
||||
|
||||
static Future<List<Video>> yourUploadExtractor(
|
||||
String url, String? headers, String? name, String prefix) async {
|
||||
Map<String, String> newHeaders = {};
|
||||
if (headers != null) {
|
||||
newHeaders = (jsonDecode(headers) as Map)
|
||||
.map((key, value) => MapEntry(key.toString(), value.toString()));
|
||||
}
|
||||
return await YourUploadExtractor().videosFromUrl(url, newHeaders,
|
||||
prefix: prefix, name: name ?? "YourUpload");
|
||||
}
|
||||
|
||||
static Future<List<Video>> voeExtractor(String url, String? quality) async {
|
||||
return await VoeExtractor().videosFromUrl(url, quality);
|
||||
}
|
||||
|
||||
static Future<List<Video>> vidBomExtractor(String url) async {
|
||||
return await VidBomExtractor().videosFromUrl(
|
||||
url,
|
||||
);
|
||||
}
|
||||
|
||||
static Future<List<Video>> streamlareExtractor(
|
||||
String url, String prefix, String suffix) async {
|
||||
return await StreamlareExtractor()
|
||||
.videosFromUrl(url, prefix: prefix, suffix: suffix);
|
||||
}
|
||||
|
||||
static List<Video> toVideos(
|
||||
String url, String quality, String originalUrl, String? headers) {
|
||||
Map<String, String> newHeaders = {};
|
||||
|
|
@ -840,6 +876,74 @@ class $MBridge extends MBridge with $Bridge {
|
|||
],
|
||||
namedParams: []),
|
||||
isStatic: true),
|
||||
'okruExtractor': BridgeMethodDef(
|
||||
BridgeFunctionDef(
|
||||
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
|
||||
[BridgeTypeRef.type(RuntimeTypes.dynamicType)])),
|
||||
params: [
|
||||
BridgeParameter(
|
||||
'url',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType)),
|
||||
false),
|
||||
],
|
||||
namedParams: []),
|
||||
isStatic: true),
|
||||
'voeExtractor': BridgeMethodDef(
|
||||
BridgeFunctionDef(
|
||||
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
|
||||
[BridgeTypeRef.type(RuntimeTypes.dynamicType)])),
|
||||
params: [
|
||||
BridgeParameter(
|
||||
'url',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType)),
|
||||
false),
|
||||
BridgeParameter(
|
||||
'quality',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType),
|
||||
nullable: true),
|
||||
false),
|
||||
],
|
||||
namedParams: []),
|
||||
isStatic: true),
|
||||
'vidBomExtractor': BridgeMethodDef(
|
||||
BridgeFunctionDef(
|
||||
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
|
||||
[BridgeTypeRef.type(RuntimeTypes.dynamicType)])),
|
||||
params: [
|
||||
BridgeParameter(
|
||||
'url',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType)),
|
||||
false),
|
||||
],
|
||||
namedParams: []),
|
||||
isStatic: true),
|
||||
'streamlareExtractor': BridgeMethodDef(
|
||||
BridgeFunctionDef(
|
||||
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
|
||||
[BridgeTypeRef.type(RuntimeTypes.dynamicType)])),
|
||||
params: [
|
||||
BridgeParameter(
|
||||
'url',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType)),
|
||||
false),
|
||||
BridgeParameter(
|
||||
'prefix',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType)),
|
||||
false),
|
||||
BridgeParameter(
|
||||
'suffix',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType)),
|
||||
false),
|
||||
],
|
||||
namedParams: []),
|
||||
isStatic: true),
|
||||
'sendVidExtractor': BridgeMethodDef(
|
||||
BridgeFunctionDef(
|
||||
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
|
||||
|
|
@ -864,6 +968,36 @@ class $MBridge extends MBridge with $Bridge {
|
|||
],
|
||||
namedParams: []),
|
||||
isStatic: true),
|
||||
'yourUploadExtractor': BridgeMethodDef(
|
||||
BridgeFunctionDef(
|
||||
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
|
||||
[BridgeTypeRef.type(RuntimeTypes.dynamicType)])),
|
||||
params: [
|
||||
BridgeParameter(
|
||||
'url',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType)),
|
||||
false),
|
||||
BridgeParameter(
|
||||
'headers',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType),
|
||||
nullable: true),
|
||||
false),
|
||||
BridgeParameter(
|
||||
'name',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType),
|
||||
nullable: true),
|
||||
false),
|
||||
BridgeParameter(
|
||||
'prefix',
|
||||
BridgeTypeAnnotation(
|
||||
BridgeTypeRef.type(RuntimeTypes.stringType)),
|
||||
false),
|
||||
],
|
||||
namedParams: []),
|
||||
isStatic: true),
|
||||
'subString': BridgeMethodDef(
|
||||
BridgeFunctionDef(
|
||||
returns: BridgeTypeAnnotation(
|
||||
|
|
@ -1560,77 +1694,62 @@ class $MBridge extends MBridge with $Bridge {
|
|||
|
||||
static $Future $gogoCdnExtractor(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.gogoCdnExtractor(args[0]!.$value)
|
||||
.then((value) => $List.wrap(value
|
||||
.map((e) => $VideoModel.wrap(VideoModel()
|
||||
..headers = e.headers
|
||||
..originalUrl = e.originalUrl
|
||||
..quality = e.quality
|
||||
..url = e.url))
|
||||
.toList())));
|
||||
$Future.wrap(MBridge.gogoCdnExtractor(args[0]!.$value).then(
|
||||
(value) => $List.wrap(value.map((e) => _toVideoModel(e)).toList())));
|
||||
|
||||
static $Future $doodExtractor(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.doodExtractor(args[0]!.$value)
|
||||
.then((value) => $List.wrap(value
|
||||
.map((e) => $VideoModel.wrap(VideoModel()
|
||||
..headers = e.headers
|
||||
..originalUrl = e.originalUrl
|
||||
..quality = e.quality
|
||||
..url = e.url))
|
||||
.toList())));
|
||||
$Future.wrap(MBridge.doodExtractor(args[0]!.$value).then(
|
||||
(value) => $List.wrap(value.map((e) => _toVideoModel(e)).toList())));
|
||||
static $Future $streamTapeExtractor(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.streamTapeExtractor(args[0]!.$value)
|
||||
.then((value) => $List.wrap(value
|
||||
.map((e) => $VideoModel.wrap(VideoModel()
|
||||
..headers = e.headers
|
||||
..originalUrl = e.originalUrl
|
||||
..quality = e.quality
|
||||
..url = e.url))
|
||||
.toList())));
|
||||
$Future.wrap(MBridge.streamTapeExtractor(args[0]!.$value).then(
|
||||
(value) => $List.wrap(value.map((e) => _toVideoModel(e)).toList())));
|
||||
static $Future $mp4UploadExtractor(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.mp4UploadExtractor(args[0]!.$value, args[1]!.$value,
|
||||
args[2]!.$value, args[3]!.$value)
|
||||
.then((value) => $List.wrap(value
|
||||
.map((e) => $VideoModel.wrap(VideoModel()
|
||||
..headers = e.headers
|
||||
..originalUrl = e.originalUrl
|
||||
..quality = e.quality
|
||||
..url = e.url))
|
||||
.toList())));
|
||||
.then((value) =>
|
||||
$List.wrap(value.map((e) => _toVideoModel(e)).toList())));
|
||||
static $Future $sendVidExtractor(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.sendVidExtractor(
|
||||
args[0]!.$value, args[1]!.$value, args[2]!.$value)
|
||||
.then((value) => $List.wrap(value
|
||||
.map((e) => $VideoModel.wrap(VideoModel()
|
||||
..headers = e.headers
|
||||
..originalUrl = e.originalUrl
|
||||
..quality = e.quality
|
||||
..url = e.url))
|
||||
.toList())));
|
||||
.then((value) =>
|
||||
$List.wrap(value.map((e) => _toVideoModel(e)).toList())));
|
||||
static $Future $yourUploadExtractor(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.yourUploadExtractor(args[0]!.$value, args[1]!.$value,
|
||||
args[2]!.$value, args[3]!.$value)
|
||||
.then((value) =>
|
||||
$List.wrap(value.map((e) => _toVideoModel(e)).toList())));
|
||||
static $Future $sibnetExtractor(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.sibnetExtractor(args[0]!.$value)
|
||||
.then((value) => $List.wrap(value
|
||||
.map((e) => $VideoModel.wrap(VideoModel()
|
||||
..headers = e.headers
|
||||
..originalUrl = e.originalUrl
|
||||
..quality = e.quality
|
||||
..url = e.url))
|
||||
.toList())));
|
||||
$Future.wrap(MBridge.sibnetExtractor(args[0]!.$value).then(
|
||||
(value) => $List.wrap(value.map((e) => _toVideoModel(e)).toList())));
|
||||
static $Future $myTvExtractor(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.myTvExtractor(args[0]!.$value)
|
||||
.then((value) => $List.wrap(value
|
||||
.map((e) => $VideoModel.wrap(VideoModel()
|
||||
..headers = e.headers
|
||||
..originalUrl = e.originalUrl
|
||||
..quality = e.quality
|
||||
..url = e.url))
|
||||
.toList())));
|
||||
$Future.wrap(MBridge.myTvExtractor(args[0]!.$value).then(
|
||||
(value) => $List.wrap(value.map((e) => _toVideoModel(e)).toList())));
|
||||
static $Future $okruExtractor(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.okruExtractor(args[0]!.$value).then(
|
||||
(value) => $List.wrap(value.map((e) => _toVideoModel(e)).toList())));
|
||||
|
||||
static $Future $voeExtractor(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.voeExtractor(args[0]!.$value, args[1]!.$value).then(
|
||||
(value) => $List.wrap(value.map((e) => _toVideoModel(e)).toList())));
|
||||
static $Future $vidBomExtractor(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.vidBomExtractor(args[0]!.$value).then(
|
||||
(value) => $List.wrap(value.map((e) => _toVideoModel(e)).toList())));
|
||||
static $Future $streamlareExtractor(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.streamlareExtractor(
|
||||
args[0]!.$value, args[1]!.$value, args[2]!.$value)
|
||||
.then((value) =>
|
||||
$List.wrap(value.map((e) => _toVideoModel(e)).toList())));
|
||||
static $bool $isEmptyOrIsNotEmpty(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) {
|
||||
return $bool(MBridge.isEmptyOrIsNotEmpty(
|
||||
|
|
@ -1656,3 +1775,9 @@ void _botToast(String title) {
|
|||
duration: const Duration(seconds: 5),
|
||||
title: title);
|
||||
}
|
||||
|
||||
$VideoModel _toVideoModel(Video e) => $VideoModel.wrap(VideoModel()
|
||||
..headers = e.headers
|
||||
..originalUrl = e.originalUrl
|
||||
..quality = e.quality
|
||||
..url = e.url);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,16 @@ Runtime runtimeEval(Uint8List bytecode) {
|
|||
'MBridge.sendVidExtractor', $MBridge.$sendVidExtractor);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
'MBridge.sibnetExtractor', $MBridge.$sibnetExtractor);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
'MBridge.okruExtractor', $MBridge.$okruExtractor);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
'MBridge.yourUploadExtractor', $MBridge.$yourUploadExtractor);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
'MBridge.voeExtractor', $MBridge.$voeExtractor);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
'MBridge.vidBomExtractor', $MBridge.$vidBomExtractor);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
'MBridge.streamlareExtractor', $MBridge.$streamlareExtractor);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
'MBridge.jsonPathToString', $MBridge.$jsonPathToString);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
|
|
|
|||
|
|
@ -87,5 +87,6 @@ class Source {
|
|||
apiUrl = json['apiUrl'];
|
||||
version = json['version'];
|
||||
isManga = json['isManga'] ?? true;
|
||||
isFullData = json['isFullData'] ?? false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -384,7 +384,7 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
|
|||
Flexible(
|
||||
child: GridViewWidget(
|
||||
controller: _scrollController,
|
||||
itemCount: _length,
|
||||
itemCount: data.length < _length ? data.length : _length,
|
||||
itemBuilder: (context, index) {
|
||||
if (index == _length - 1 && _isLoading) {
|
||||
return buildProgressIndicator();
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:mangayomi/modules/more/widgets/incognito_mode_widget.dart';
|
||||
|
|
@ -59,16 +61,53 @@ class MoreScreen extends StatelessWidget {
|
|||
icon: Icons.history_outlined,
|
||||
title: l10n.history,
|
||||
),
|
||||
// ListTile(
|
||||
// onTap: () {},
|
||||
// leading: const SizedBox(
|
||||
// height: 40,
|
||||
// child: Icon(Icons.settings_backup_restore_sharp)),
|
||||
// title: const Text('Backup and restore'),
|
||||
// ),
|
||||
// const Divider(
|
||||
// color: Colors.grey,
|
||||
// ),
|
||||
ListTile(
|
||||
onTap: () {
|
||||
final data = {
|
||||
'variables': {
|
||||
'type': 'anime',
|
||||
'size': 26,
|
||||
'dateRange': 7,
|
||||
'page': 1,
|
||||
},
|
||||
'query': """
|
||||
query(
|
||||
%type: VaildPopularTypeEnumType!
|
||||
%size: Int!
|
||||
%page: Int
|
||||
%dateRange: Int
|
||||
) {
|
||||
queryPopular(
|
||||
type: %type
|
||||
size: %size
|
||||
dateRange: %dateRange
|
||||
page: %page
|
||||
) {
|
||||
total
|
||||
recommendations {
|
||||
anyCard {
|
||||
_id
|
||||
name
|
||||
thumbnail
|
||||
englishName
|
||||
nativeName
|
||||
slugTime
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""",
|
||||
};
|
||||
print(jsonEncode(data));
|
||||
print(Uri.parse("https://api.allanime.day").host);
|
||||
},
|
||||
leading: const SizedBox(
|
||||
height: 40, child: Icon(Icons.settings_backup_restore_sharp)),
|
||||
title: const Text('Backup and restore'),
|
||||
),
|
||||
const Divider(
|
||||
color: Colors.grey,
|
||||
),
|
||||
ListTileWidget(
|
||||
onTap: () {
|
||||
context.push('/settings');
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class _MangaWebViewState extends ConsumerState<MangaWebView> {
|
|||
double progress = 0;
|
||||
@override
|
||||
void initState() {
|
||||
if (Platform.isWindows || Platform.isLinux) {
|
||||
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
|
||||
_runWebViewDesktop();
|
||||
} else {
|
||||
setState(() {
|
||||
|
|
|
|||
50
lib/services/anime_extractors/okru_extractor.dart
Normal file
50
lib/services/anime_extractors/okru_extractor.dart
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import 'package:http/http.dart' as http;
|
||||
import 'package:html/parser.dart' show parse;
|
||||
import 'package:mangayomi/models/video.dart';
|
||||
import 'package:mangayomi/utils/extensions.dart';
|
||||
|
||||
class OkruExtractor {
|
||||
final http.Client client = http.Client();
|
||||
|
||||
String fixQuality(String quality) {
|
||||
final qualities = {
|
||||
'ultra': '2160p',
|
||||
'quad': '1440p',
|
||||
'full': '1080p',
|
||||
'hd': '720p',
|
||||
'sd': '480p',
|
||||
'low': '360p',
|
||||
'lowest': '240p',
|
||||
'mobile': '144p',
|
||||
};
|
||||
return qualities[quality] ?? quality;
|
||||
}
|
||||
|
||||
Future<List<Video>> videosFromUrl(String url,
|
||||
{String prefix = '', bool fixQualities = true}) async {
|
||||
final response = await client.get(Uri.parse(url));
|
||||
final document = parse(response.body);
|
||||
final videosString = document
|
||||
.querySelector('div[data-options]')
|
||||
?.attributes['data-options']!
|
||||
.substringAfter(
|
||||
'''\\"videos\\":[{\\\\"name\\\\":\\\\"''').substringBefore(']') ??
|
||||
'';
|
||||
List<Video> videoList = [];
|
||||
List<String> values =
|
||||
videosString.split('''{\\\\"name\\\\":\\\\"''').reversed.toList();
|
||||
for (var value in values) {
|
||||
final videoUrl = value
|
||||
.substringAfter('''url\\\\":\\\\"''').substringBefore(
|
||||
'''\\"''').replaceAll(r'\\u0026', '&');
|
||||
final quality = value.substringBefore('''\\"''');
|
||||
final fixedQuality = fixQualities ? fixQuality(quality) : quality;
|
||||
final videoQuality =
|
||||
'${prefix.isNotEmpty ? '$prefix ' : ''}Okru:$fixedQuality';
|
||||
if (videoUrl.startsWith('https://')) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl));
|
||||
}
|
||||
}
|
||||
return videoList;
|
||||
}
|
||||
}
|
||||
75
lib/services/anime_extractors/streamlare_extractor.dart
Normal file
75
lib/services/anime_extractors/streamlare_extractor.dart
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
import 'package:http/http.dart' as http;
|
||||
import 'package:mangayomi/models/video.dart';
|
||||
import 'package:mangayomi/utils/extensions.dart';
|
||||
|
||||
class StreamlareExtractor {
|
||||
final http.Client client = http.Client();
|
||||
|
||||
Future<List<Video>> videosFromUrl(String url,
|
||||
{String prefix = "", String suffix = ""}) async {
|
||||
final id = url.split('/').last;
|
||||
final playlistResponse = await client.post(
|
||||
Uri.parse('https://slwatch.co/api/video/stream/get'),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: '{"id":"$id"}',
|
||||
);
|
||||
|
||||
final playlist = playlistResponse.body;
|
||||
final type = playlist.substringAfter('"type":"').substringBefore('"');
|
||||
|
||||
if (type == 'hls') {
|
||||
final masterPlaylistUrl = playlist
|
||||
.substringAfter('"file":"')
|
||||
.substringBefore('"')
|
||||
.replaceAll(r'\/', '/');
|
||||
final masterPlaylistResponse =
|
||||
await client.get(Uri.parse(masterPlaylistUrl));
|
||||
final masterPlaylist = masterPlaylistResponse.body;
|
||||
|
||||
const separator = '#EXT-X-STREAM-INF';
|
||||
return masterPlaylist
|
||||
.substringAfter(separator)
|
||||
.split(separator)
|
||||
.map((value) {
|
||||
final quality =
|
||||
'${value.substringAfter('RESOLUTION=').substringAfter('x').substringBefore(',')}p';
|
||||
final videoUrl =
|
||||
value.substringAfter('\n').substringBefore('\n').let((urlPart) {
|
||||
return !urlPart.startsWith('http')
|
||||
? masterPlaylistUrl.substringBefore('master.m3u8') + urlPart
|
||||
: urlPart;
|
||||
});
|
||||
|
||||
return Video(
|
||||
videoUrl, _buildQuality(quality, prefix, suffix), videoUrl);
|
||||
}).toList();
|
||||
} else {
|
||||
const separator = '"label":"';
|
||||
List<Video> videoList = [];
|
||||
List<String> values = playlist.substringAfter(separator).split(separator);
|
||||
for (var value in values) {
|
||||
final quality = value.substringAfter(separator).substringBefore('",');
|
||||
final apiUrl = value
|
||||
.substringAfter('"file":"')
|
||||
.substringBefore('",')
|
||||
.replaceAll('\\', '');
|
||||
final response = await client.post(Uri.parse(apiUrl));
|
||||
final videoUrl = response.request!.url.toString();
|
||||
|
||||
videoList.add(
|
||||
Video(videoUrl, _buildQuality(quality, prefix, suffix), videoUrl));
|
||||
}
|
||||
return videoList;
|
||||
}
|
||||
}
|
||||
|
||||
String _buildQuality(String resolution,
|
||||
[String prefix = '', String suffix = '']) {
|
||||
final buffer = StringBuffer();
|
||||
if (prefix.isNotEmpty) buffer.write('$prefix ');
|
||||
buffer.write('Streamlare:$resolution');
|
||||
if (suffix.isNotEmpty) buffer.write(' $suffix');
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
28
lib/services/anime_extractors/vidbom_extractor.dart
Normal file
28
lib/services/anime_extractors/vidbom_extractor.dart
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import 'package:http/http.dart' as http;
|
||||
import 'package:mangayomi/models/video.dart';
|
||||
import 'package:mangayomi/utils/extensions.dart';
|
||||
import 'package:mangayomi/utils/xpath_selector.dart';
|
||||
|
||||
class VidBomExtractor {
|
||||
final http.Client client = http.Client();
|
||||
|
||||
Future<List<Video>> videosFromUrl(String url) async {
|
||||
final response = await client.get(Uri.parse(url));
|
||||
final script = xpathSelector(response.body)
|
||||
.queryXPath('//script[contains(text(), "sources")]/text()')
|
||||
.attrs;
|
||||
|
||||
final data =
|
||||
script.first!.substringAfter('sources: [').substringBefore('],');
|
||||
|
||||
return data.split('file:"').skip(1).map((source) {
|
||||
final src = source.substringBefore('"');
|
||||
var quality =
|
||||
'Vidbom: ${source.substringAfter('label:"').substringBefore('"')}';
|
||||
if (quality.length > 15) {
|
||||
quality = 'Vidshare: 480p';
|
||||
}
|
||||
return Video(src, quality, src);
|
||||
}).toList();
|
||||
}
|
||||
}
|
||||
30
lib/services/anime_extractors/voe_extractor.dart
Normal file
30
lib/services/anime_extractors/voe_extractor.dart
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import 'package:http/http.dart' as http;
|
||||
import 'package:mangayomi/models/video.dart';
|
||||
import 'package:mangayomi/utils/extensions.dart';
|
||||
import 'package:mangayomi/utils/xpath_selector.dart';
|
||||
|
||||
class VoeExtractor {
|
||||
http.Client client = http.Client();
|
||||
|
||||
Future<List<Video>> videosFromUrl(String url, String? quality) async {
|
||||
try {
|
||||
final response = await client.get(Uri.parse(url));
|
||||
final script = xpathSelector(response.body)
|
||||
.queryXPath(
|
||||
'//script[contains(text(), "const sources") or contains(text(), "var sources")]/text()')
|
||||
.attrs;
|
||||
if (script.isEmpty) {
|
||||
return [];
|
||||
}
|
||||
final videoUrl =
|
||||
script.first!.substringAfter("hls': '").substringBefore("'");
|
||||
final resolution =
|
||||
script.first!.substringAfter("video_height': ").substringBefore(",");
|
||||
final qualityStr = quality ?? "VoeCDN(${resolution}p)";
|
||||
|
||||
return [Video(url, qualityStr, videoUrl)];
|
||||
} catch (_) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
31
lib/services/anime_extractors/your_upload_extractor.dart
Normal file
31
lib/services/anime_extractors/your_upload_extractor.dart
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import 'package:http/http.dart' as http;
|
||||
import 'package:mangayomi/models/video.dart';
|
||||
import 'package:mangayomi/utils/extensions.dart';
|
||||
import 'package:mangayomi/utils/xpath_selector.dart';
|
||||
|
||||
class YourUploadExtractor {
|
||||
http.Client client = http.Client();
|
||||
|
||||
Future<List<Video>> videosFromUrl(String url, Map<String, String> headers,
|
||||
{String name = "YourUpload", String prefix = ""}) async {
|
||||
final newHeaders = Map<String, String>.from(headers);
|
||||
newHeaders["referer"] = "https://www.yourupload.com/";
|
||||
|
||||
try {
|
||||
final response = await client.get(Uri.parse(url), headers: newHeaders);
|
||||
final baseData = xpathSelector(response.body)
|
||||
.queryXPath('//script[contains(text(), "jwplayerOptions")]/text()')
|
||||
.attrs;
|
||||
if (baseData.isNotEmpty) {
|
||||
final basicUrl =
|
||||
baseData.first!.substringAfter("file: '").substringBefore("',");
|
||||
final quality = prefix + name;
|
||||
return [Video(basicUrl, quality, basicUrl, headers: newHeaders)];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
} catch (_) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@ Future<String> cloudflareBypass(
|
|||
final ua = isar.settings.getSync(227)!.userAgent!;
|
||||
bool isOk = false;
|
||||
String? html;
|
||||
if (Platform.isWindows || Platform.isLinux) {
|
||||
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
|
||||
final webview = await WebviewWindow.create(
|
||||
configuration: CreateConfiguration(
|
||||
windowHeight: 500,
|
||||
|
|
|
|||
|
|
@ -13,4 +13,10 @@ extension StringExtensions on String {
|
|||
|
||||
return substring(0, endIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension LetExtension<T> on T {
|
||||
R let<R>(R Function(T) block) {
|
||||
return block(this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -527,10 +527,10 @@ packages:
|
|||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_meedu_videoplayer
|
||||
sha256: f84e647f1f52aa96b6e3367c8db15b44174dd1144b3ebd91d41693605dea13f7
|
||||
sha256: "6849b2b05c8413f2efbb70cf5be759b2e6a978e373e58c8d8bb87414ba141e6c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.20"
|
||||
version: "4.2.21"
|
||||
flutter_plugin_android_lifecycle:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
@ -873,10 +873,10 @@ packages:
|
|||
dependency: transitive
|
||||
description:
|
||||
name: media_kit_libs_windows_video
|
||||
sha256: "4aa12f61c9989c4d7159ed0c15640d645dbe59026ac9057a3651d026a409dcb9"
|
||||
sha256: b343e644927982a2ef3db63877b36d84bdda8173d8318ca0d1c68c1ea8a35982
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
version: "1.0.5"
|
||||
media_kit_native_event_loop:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
|||
Loading…
Reference in a new issue