mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-04-20 23:22:07 +00:00
new anime server extractor
This commit is contained in:
parent
0c4b2f7360
commit
df8be849ac
13 changed files with 390 additions and 251 deletions
|
|
@ -14,6 +14,7 @@ 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/filemoon.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';
|
||||
|
|
@ -606,6 +607,11 @@ class MBridge {
|
|||
return await StreamWishExtractor().videosFromUrl(url, prefix);
|
||||
}
|
||||
|
||||
static Future<List<Video>> filemoonExtractor(
|
||||
String url, String prefix) async {
|
||||
return await FilemoonExtractor().videosFromUrl(url, prefix);
|
||||
}
|
||||
|
||||
static Future<List<Video>> mp4UploadExtractor(
|
||||
String url, String? headers, String prefix, String suffix) async {
|
||||
Map<String, String> newHeaders = {};
|
||||
|
|
@ -1556,6 +1562,25 @@ class $MBridge extends MBridge with $Bridge {
|
|||
],
|
||||
namedParams: []),
|
||||
isStatic: true),
|
||||
'filemoonExtractor': 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),
|
||||
nullable: true),
|
||||
false),
|
||||
],
|
||||
namedParams: []),
|
||||
isStatic: true),
|
||||
'getHtmlViaWebview': BridgeMethodDef(
|
||||
BridgeFunctionDef(
|
||||
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
|
||||
|
|
@ -1870,6 +1895,12 @@ class $MBridge extends MBridge with $Bridge {
|
|||
.then((value) =>
|
||||
$List.wrap(value.map((e) => _toVideoModel(e)).toList())));
|
||||
|
||||
static $Future $filemoonExtractor(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.filemoonExtractor(args[0]!.$value, args[1]!.$value)
|
||||
.then((value) =>
|
||||
$List.wrap(value.map((e) => _toVideoModel(e)).toList())));
|
||||
|
||||
static $Future $sendVidExtractor(
|
||||
Runtime runtime, $Value? target, List<$Value?> args) =>
|
||||
$Future.wrap(MBridge.sendVidExtractor(
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ Runtime runtimeEval(Uint8List bytecode) {
|
|||
'MBridge.streamTapeExtractor', $MBridge.$streamTapeExtractor);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
'MBridge.streamWishExtractor', $MBridge.$streamWishExtractor);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
'MBridge.filemoonExtractor', $MBridge.$filemoonExtractor);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
'MBridge.mp4UploadExtractor', $MBridge.$mp4UploadExtractor);
|
||||
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
|
||||
|
|
|
|||
61
lib/services/anime_extractors/filemoon.dart
Normal file
61
lib/services/anime_extractors/filemoon.dart
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
import 'package:http/http.dart' as http;
|
||||
import 'package:js_packer/js_packer.dart';
|
||||
import 'package:mangayomi/models/video.dart';
|
||||
import 'package:mangayomi/utils/extensions.dart';
|
||||
import 'package:mangayomi/utils/xpath_selector.dart';
|
||||
|
||||
class FilemoonExtractor {
|
||||
final http.Client client = http.Client();
|
||||
|
||||
Future<List<Video>> videosFromUrl(String url, String prefix) async {
|
||||
prefix = prefix.isEmpty ? "Filemoon - " : prefix;
|
||||
try {
|
||||
final response = await client.get(Uri.parse(url));
|
||||
|
||||
final jsEval = xpathSelector(response.body)
|
||||
.queryXPath('//script[contains(text(), "eval")]/text()')
|
||||
.attr;
|
||||
|
||||
final unpacked = _evalJs(jsEval!) ?? '';
|
||||
|
||||
final masterUrl = unpacked.isNotEmpty
|
||||
? unpacked.substringAfter('{file:"').substringBefore('"}')
|
||||
: '';
|
||||
|
||||
if (masterUrl.isEmpty) {
|
||||
return [];
|
||||
}
|
||||
|
||||
final masterPlaylistResponse = await client.get(Uri.parse(masterUrl));
|
||||
final masterPlaylist = masterPlaylistResponse.body;
|
||||
|
||||
final videoHeaders = {
|
||||
'Referer': url,
|
||||
'Origin': 'https://${Uri.parse(url).host}',
|
||||
};
|
||||
|
||||
const separator = '#EXT-X-STREAM-INF:';
|
||||
final playlists = masterPlaylist.split(separator).sublist(1);
|
||||
|
||||
return playlists.map((playlist) {
|
||||
final resolution =
|
||||
'${playlist.substringAfter('RESOLUTION=').substringAfter('x').substringBefore(',').trim()}p';
|
||||
final videoUrl = playlist.split('\n')[1].trim();
|
||||
|
||||
return Video(
|
||||
videoUrl,
|
||||
prefix + resolution,
|
||||
videoUrl,
|
||||
headers: videoHeaders,
|
||||
);
|
||||
}).toList();
|
||||
} catch (_) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String? _evalJs(String script) {
|
||||
final jsPacker = JSPacker(script);
|
||||
return jsPacker.unpack();
|
||||
}
|
||||
|
|
@ -12,41 +12,44 @@ class Mp4uploadExtractor {
|
|||
{String prefix = '', String suffix = ''}) async {
|
||||
final newHeaders = Map<String, String>.from(headers)
|
||||
..addAll({'referer': referer});
|
||||
try {
|
||||
final response = await http.get(Uri.parse(url), headers: newHeaders);
|
||||
String script = "";
|
||||
|
||||
final response = await http.get(Uri.parse(url), headers: newHeaders);
|
||||
String script = "";
|
||||
|
||||
final scriptElementWithEval = xpathSelector(response.body)
|
||||
.queryXPath(
|
||||
'//script[contains(text(), "eval") and contains(text(), "p,a,c,k,e,d")]/text()')
|
||||
.attrs;
|
||||
|
||||
if (scriptElementWithEval.isNotEmpty) {
|
||||
script = _evalJs(script)!;
|
||||
} else {
|
||||
final scriptElementWithSrc = xpathSelector(response.body)
|
||||
.queryXPath('//script[contains(text(), "player.src")]/text()')
|
||||
final scriptElementWithEval = xpathSelector(response.body)
|
||||
.queryXPath(
|
||||
'//script[contains(text(), "eval") and contains(text(), "p,a,c,k,e,d")]/text()')
|
||||
.attrs;
|
||||
if (scriptElementWithSrc.isNotEmpty) {
|
||||
script = scriptElementWithSrc.first!;
|
||||
|
||||
if (scriptElementWithEval.isNotEmpty) {
|
||||
script = _evalJs(script)!;
|
||||
} else {
|
||||
return [];
|
||||
final scriptElementWithSrc = xpathSelector(response.body)
|
||||
.queryXPath('//script[contains(text(), "player.src")]/text()')
|
||||
.attrs;
|
||||
if (scriptElementWithSrc.isNotEmpty) {
|
||||
script = scriptElementWithSrc.first!;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
final videoUrl = script
|
||||
.substringAfter('.src(')
|
||||
.substringBefore(')')
|
||||
.substringAfter('src:')
|
||||
.substringAfter('"')
|
||||
.substringBefore('"');
|
||||
final resolutionMatch = qualityRegex.firstMatch(script);
|
||||
final resolution = resolutionMatch?.group(1) ?? 'Unknown resolution';
|
||||
final quality = '$prefix Mp4Upload - $resolution $suffix';
|
||||
|
||||
return [
|
||||
Video(videoUrl, quality, videoUrl, headers: newHeaders),
|
||||
];
|
||||
} catch (_) {
|
||||
return [];
|
||||
}
|
||||
|
||||
final videoUrl = script
|
||||
.substringAfter('.src(')
|
||||
.substringBefore(')')
|
||||
.substringAfter('src:')
|
||||
.substringAfter('"')
|
||||
.substringBefore('"');
|
||||
final resolutionMatch = qualityRegex.firstMatch(script);
|
||||
final resolution = resolutionMatch?.group(1) ?? 'Unknown resolution';
|
||||
final quality = '$prefix Mp4Upload - $resolution $suffix';
|
||||
|
||||
return [
|
||||
Video(videoUrl, quality, videoUrl, headers: newHeaders),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,30 +7,34 @@ class MytvExtractor {
|
|||
final http.Client client = http.Client();
|
||||
|
||||
Future<List<Video>> videosFromUrl(String url) async {
|
||||
final response = await client.get(Uri.parse(url));
|
||||
final document = parse(response.body);
|
||||
final videoList = <Video>[];
|
||||
try {
|
||||
final response = await client.get(Uri.parse(url));
|
||||
final document = parse(response.body);
|
||||
final videoList = <Video>[];
|
||||
|
||||
document.querySelectorAll("script").forEach((script) {
|
||||
if (script.text.contains("CreatePlayer(\"v")) {
|
||||
final videosString = script.text;
|
||||
final videoUrl = videosString
|
||||
.substringAfter("\"v=")
|
||||
.substringBefore("\\u0026tp=video")
|
||||
.replaceAll("%26", "&")
|
||||
.replaceAll("%3a", ":")
|
||||
.replaceAll("%2f", "/")
|
||||
.replaceAll("%3f", "?")
|
||||
.replaceAll("%3d", "=");
|
||||
document.querySelectorAll("script").forEach((script) {
|
||||
if (script.text.contains("CreatePlayer(\"v")) {
|
||||
final videosString = script.text;
|
||||
final videoUrl = videosString
|
||||
.substringAfter("\"v=")
|
||||
.substringBefore("\\u0026tp=video")
|
||||
.replaceAll("%26", "&")
|
||||
.replaceAll("%3a", ":")
|
||||
.replaceAll("%2f", "/")
|
||||
.replaceAll("%3f", "?")
|
||||
.replaceAll("%3d", "=");
|
||||
|
||||
if (!videoUrl.contains("https:")) {
|
||||
videoList.add(Video(videoUrl, "Stream", videoUrl));
|
||||
} else {
|
||||
videoList.add(Video(videoUrl, "Mytv", videoUrl));
|
||||
if (!videoUrl.contains("https:")) {
|
||||
videoList.add(Video(videoUrl, "Stream", videoUrl));
|
||||
} else {
|
||||
videoList.add(Video(videoUrl, "Mytv", videoUrl));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return videoList;
|
||||
return videoList;
|
||||
} catch (_) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,31 +22,35 @@ class OkruExtractor {
|
|||
|
||||
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(']') ??
|
||||
'';
|
||||
try {
|
||||
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));
|
||||
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;
|
||||
} catch (_) {
|
||||
return [];
|
||||
}
|
||||
return videoList;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,52 +10,56 @@ class SendvidExtractor {
|
|||
SendvidExtractor(this.headers);
|
||||
|
||||
Future<List<Video>> videosFromUrl(String url, {String prefix = ""}) async {
|
||||
final videoList = <Video>[];
|
||||
final response = await client.get(Uri.parse(url));
|
||||
final document = parser.parse(response.body);
|
||||
final masterUrl =
|
||||
document.querySelector("source#video_source")?.attributes["src"];
|
||||
try {
|
||||
final videoList = <Video>[];
|
||||
final response = await client.get(Uri.parse(url));
|
||||
final document = parser.parse(response.body);
|
||||
final masterUrl =
|
||||
document.querySelector("source#video_source")?.attributes["src"];
|
||||
|
||||
if (masterUrl == null) {
|
||||
return videoList;
|
||||
}
|
||||
if (masterUrl == null) {
|
||||
return videoList;
|
||||
}
|
||||
|
||||
final masterHeaders = Map<String, String>.from(headers)
|
||||
..addAll({
|
||||
"Accept": "*/*",
|
||||
"Host": Uri.parse(masterUrl).host,
|
||||
"Origin": "https://${Uri.parse(url).host}",
|
||||
"Referer": "https://${Uri.parse(url).host}/",
|
||||
});
|
||||
|
||||
final masterPlaylistResponse =
|
||||
await client.get(Uri.parse(masterUrl), headers: masterHeaders);
|
||||
final masterPlaylist = masterPlaylistResponse.body;
|
||||
|
||||
final masterBase =
|
||||
"https://${Uri.parse(masterUrl).host}${Uri.parse(masterUrl).pathSegments.join("/")}/";
|
||||
|
||||
masterPlaylist
|
||||
.substringAfter("#EXT-X-STREAM-INF:")
|
||||
.split("#EXT-X-STREAM-INF:")
|
||||
.forEach((it) {
|
||||
final quality =
|
||||
"Sendvid:${it.substringAfter("RESOLUTION=").substringAfter("x").substringBefore(",")}p ";
|
||||
final videoUrl =
|
||||
masterBase + it.substringAfter("\n").substringBefore("\n");
|
||||
|
||||
final videoHeaders = Map<String, String>.from(headers)
|
||||
final masterHeaders = Map<String, String>.from(headers)
|
||||
..addAll({
|
||||
"Accept": "*/*",
|
||||
"Host": Uri.parse(videoUrl).host,
|
||||
"Host": Uri.parse(masterUrl).host,
|
||||
"Origin": "https://${Uri.parse(url).host}",
|
||||
"Referer": "https://${Uri.parse(url).host}/",
|
||||
});
|
||||
|
||||
videoList.add(
|
||||
Video(videoUrl, prefix + quality, videoUrl, headers: videoHeaders));
|
||||
});
|
||||
final masterPlaylistResponse =
|
||||
await client.get(Uri.parse(masterUrl), headers: masterHeaders);
|
||||
final masterPlaylist = masterPlaylistResponse.body;
|
||||
|
||||
return videoList;
|
||||
final masterBase =
|
||||
"https://${Uri.parse(masterUrl).host}${Uri.parse(masterUrl).pathSegments.join("/")}/";
|
||||
|
||||
masterPlaylist
|
||||
.substringAfter("#EXT-X-STREAM-INF:")
|
||||
.split("#EXT-X-STREAM-INF:")
|
||||
.forEach((it) {
|
||||
final quality =
|
||||
"Sendvid:${it.substringAfter("RESOLUTION=").substringAfter("x").substringBefore(",")}p ";
|
||||
final videoUrl =
|
||||
masterBase + it.substringAfter("\n").substringBefore("\n");
|
||||
|
||||
final videoHeaders = Map<String, String>.from(headers)
|
||||
..addAll({
|
||||
"Accept": "*/*",
|
||||
"Host": Uri.parse(videoUrl).host,
|
||||
"Origin": "https://${Uri.parse(url).host}",
|
||||
"Referer": "https://${Uri.parse(url).host}/",
|
||||
});
|
||||
|
||||
videoList.add(
|
||||
Video(videoUrl, prefix + quality, videoUrl, headers: videoHeaders));
|
||||
});
|
||||
|
||||
return videoList;
|
||||
} catch (_) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,30 +7,33 @@ class SibnetExtractor {
|
|||
|
||||
Future<List<Video>> videosFromUrl(String url) async {
|
||||
List<Video> videoList = [];
|
||||
try {
|
||||
final response = await client.get(Uri.parse(url));
|
||||
if (response.statusCode != 200) {
|
||||
return [];
|
||||
}
|
||||
|
||||
final response = await client.get(Uri.parse(url));
|
||||
if (response.statusCode != 200) {
|
||||
String script = response.body;
|
||||
String slug = script
|
||||
.substringAfter("player.src")
|
||||
.substringAfter("src:")
|
||||
.substringAfter("\"")
|
||||
.substringBefore("\"");
|
||||
|
||||
String videoUrl =
|
||||
slug.contains("http") ? slug : "https://${Uri.parse(url).host}$slug";
|
||||
|
||||
Map<String, String> videoHeaders = {
|
||||
"Referer": url,
|
||||
};
|
||||
|
||||
videoList.add(
|
||||
Video(videoUrl, "Sibnet", videoUrl, headers: videoHeaders),
|
||||
);
|
||||
|
||||
return videoList;
|
||||
} catch (_) {
|
||||
return [];
|
||||
}
|
||||
|
||||
String script = response.body;
|
||||
String slug = script
|
||||
.substringAfter("player.src")
|
||||
.substringAfter("src:")
|
||||
.substringAfter("\"")
|
||||
.substringBefore("\"");
|
||||
|
||||
String videoUrl =
|
||||
slug.contains("http") ? slug : "https://${Uri.parse(url).host}$slug";
|
||||
|
||||
Map<String, String> videoHeaders = {
|
||||
"Referer": url,
|
||||
};
|
||||
|
||||
videoList.add(
|
||||
Video(videoUrl, "Sibnet", videoUrl, headers: videoHeaders),
|
||||
);
|
||||
|
||||
return videoList;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,59 +7,64 @@ class StreamlareExtractor {
|
|||
|
||||
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"}',
|
||||
);
|
||||
try {
|
||||
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('"');
|
||||
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
|
||||
if (type == 'hls') {
|
||||
final masterPlaylistUrl = playlist
|
||||
.substringAfter('"file":"')
|
||||
.substringBefore('",')
|
||||
.replaceAll('\\', '');
|
||||
final response = await client.post(Uri.parse(apiUrl));
|
||||
final videoUrl = response.request!.url.toString();
|
||||
.substringBefore('"')
|
||||
.replaceAll(r'\/', '/');
|
||||
final masterPlaylistResponse =
|
||||
await client.get(Uri.parse(masterPlaylistUrl));
|
||||
final masterPlaylist = masterPlaylistResponse.body;
|
||||
|
||||
videoList.add(
|
||||
Video(videoUrl, _buildQuality(quality, prefix, suffix), videoUrl));
|
||||
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;
|
||||
}
|
||||
return videoList;
|
||||
} catch (_) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,27 +6,31 @@ import 'package:mangayomi/utils/extensions.dart';
|
|||
class StreamTapeExtractor {
|
||||
Future<List<Video>> videosFromUrl(String url,
|
||||
{String quality = "StreamTape"}) async {
|
||||
const baseUrl = "https://streamtape.com/e/";
|
||||
final newUrl =
|
||||
!url.startsWith(baseUrl) ? "$baseUrl${url.split("/")[4]}" : url;
|
||||
try {
|
||||
const baseUrl = "https://streamtape.com/e/";
|
||||
final newUrl =
|
||||
!url.startsWith(baseUrl) ? "$baseUrl${url.split("/")[4]}" : url;
|
||||
|
||||
final response = await http.Client().get(Uri.parse(newUrl));
|
||||
final document = parse(response.body);
|
||||
final response = await http.Client().get(Uri.parse(newUrl));
|
||||
final document = parse(response.body);
|
||||
|
||||
const targetLine = "document.getElementById('robotlink')";
|
||||
String script = "";
|
||||
final scri = document
|
||||
.querySelectorAll("script")
|
||||
.where((element) => element.innerHtml.contains(targetLine))
|
||||
.map((e) => e.innerHtml)
|
||||
.toList();
|
||||
if (scri.isEmpty) {
|
||||
const targetLine = "document.getElementById('robotlink')";
|
||||
String script = "";
|
||||
final scri = document
|
||||
.querySelectorAll("script")
|
||||
.where((element) => element.innerHtml.contains(targetLine))
|
||||
.map((e) => e.innerHtml)
|
||||
.toList();
|
||||
if (scri.isEmpty) {
|
||||
return [];
|
||||
}
|
||||
script = scri.first.split("$targetLine.innerHTML = '").last;
|
||||
final videoUrl =
|
||||
"https:${script.substringBefore("'")}${script.substringAfter("+ ('xcd").substringBefore("'")}";
|
||||
|
||||
return [Video(videoUrl, quality, videoUrl)];
|
||||
} catch (_) {
|
||||
return [];
|
||||
}
|
||||
script = scri.first.split("$targetLine.innerHTML = '").last;
|
||||
final videoUrl =
|
||||
"https:${script.substringBefore("'")}${script.substringAfter("+ ('xcd").substringBefore("'")}";
|
||||
|
||||
return [Video(videoUrl, quality, videoUrl)];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,49 +10,52 @@ class StreamWishExtractor {
|
|||
|
||||
Future<List<Video>> videosFromUrl(String url, String prefix) async {
|
||||
final videoList = <Video>[];
|
||||
try {
|
||||
final response = await client.get(Uri.parse(url), headers: headers);
|
||||
|
||||
final response = await client.get(Uri.parse(url), headers: headers);
|
||||
final jsEval = xpathSelector(response.body)
|
||||
.queryXPath('//script[contains(text(), "m3u8")]/text()')
|
||||
.attrs;
|
||||
if (jsEval.isEmpty) {
|
||||
return [];
|
||||
}
|
||||
|
||||
final jsEval = xpathSelector(response.body)
|
||||
.queryXPath('//script[contains(text(), "m3u8")]/text()')
|
||||
.attrs;
|
||||
if (jsEval.isEmpty) {
|
||||
return [];
|
||||
}
|
||||
String? masterUrl = _evalJs(jsEval.first!)
|
||||
?.substringAfter('source')
|
||||
.substringAfter('file:"')
|
||||
.substringBefore('"');
|
||||
|
||||
String? masterUrl = _evalJs(jsEval.first!)
|
||||
?.substringAfter('source')
|
||||
.substringAfter('file:"')
|
||||
.substringBefore('"');
|
||||
if (masterUrl == null) return [];
|
||||
|
||||
if (masterUrl == null) return [];
|
||||
final playlistHeaders = Map<String, String>.from(headers)
|
||||
..addAll({
|
||||
'Accept': '*/*',
|
||||
'Host': Uri.parse(masterUrl).host,
|
||||
'Origin': 'https://${Uri.parse(url).host}',
|
||||
'Referer': 'https://${Uri.parse(url).host}/',
|
||||
});
|
||||
|
||||
final playlistHeaders = Map<String, String>.from(headers)
|
||||
..addAll({
|
||||
'Accept': '*/*',
|
||||
'Host': Uri.parse(masterUrl).host,
|
||||
'Origin': 'https://${Uri.parse(url).host}',
|
||||
'Referer': 'https://${Uri.parse(url).host}/',
|
||||
final masterBase =
|
||||
'${'https://${Uri.parse(masterUrl).host}${Uri.parse(masterUrl).path}'.substringBeforeLast('/')}/';
|
||||
|
||||
final masterPlaylistResponse =
|
||||
await client.get(Uri.parse(masterUrl), headers: playlistHeaders);
|
||||
final masterPlaylist = masterPlaylistResponse.body;
|
||||
|
||||
const separator = '#EXT-X-STREAM-INF:';
|
||||
masterPlaylist.substringAfter(separator).split(separator).forEach((it) {
|
||||
final quality =
|
||||
'$prefix${it.substringAfter('RESOLUTION=').substringAfter('x').substringBefore(',')}p ';
|
||||
final videoUrl =
|
||||
masterBase + it.substringAfter('\n').substringBefore('\n');
|
||||
videoList
|
||||
.add(Video(videoUrl, quality, videoUrl, headers: playlistHeaders));
|
||||
});
|
||||
|
||||
final masterBase =
|
||||
'${'https://${Uri.parse(masterUrl).host}${Uri.parse(masterUrl).path}'.substringBeforeLast('/')}/';
|
||||
|
||||
final masterPlaylistResponse =
|
||||
await client.get(Uri.parse(masterUrl), headers: playlistHeaders);
|
||||
final masterPlaylist = masterPlaylistResponse.body;
|
||||
|
||||
const separator = '#EXT-X-STREAM-INF:';
|
||||
masterPlaylist.substringAfter(separator).split(separator).forEach((it) {
|
||||
final quality =
|
||||
'$prefix${it.substringAfter('RESOLUTION=').substringAfter('x').substringBefore(',')}p ';
|
||||
final videoUrl =
|
||||
masterBase + it.substringAfter('\n').substringBefore('\n');
|
||||
videoList
|
||||
.add(Video(videoUrl, quality, videoUrl, headers: playlistHeaders));
|
||||
});
|
||||
|
||||
return videoList;
|
||||
return videoList;
|
||||
} catch (_) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,22 +7,26 @@ 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;
|
||||
try {
|
||||
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('],');
|
||||
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();
|
||||
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();
|
||||
} catch (_) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,17 @@ extension StringExtensions on String {
|
|||
|
||||
return substring(0, endIndex);
|
||||
}
|
||||
|
||||
String substringBetween(String left, String right) {
|
||||
int startIndex = 0;
|
||||
int index = indexOf(left, startIndex);
|
||||
if (index == -1) return "";
|
||||
int leftIndex = index + left.length;
|
||||
int rightIndex = indexOf(right, leftIndex);
|
||||
if (rightIndex == -1) return "";
|
||||
startIndex = rightIndex + right.length;
|
||||
return substring(leftIndex, rightIndex);
|
||||
}
|
||||
}
|
||||
|
||||
extension LetExtension<T> on T {
|
||||
|
|
|
|||
Loading…
Reference in a new issue