diff --git a/anime/multisrc/dopeflix/dopeflix-v0.0.15.dart b/anime/multisrc/dopeflix/dopeflix-v0.0.2.dart similarity index 75% rename from anime/multisrc/dopeflix/dopeflix-v0.0.15.dart rename to anime/multisrc/dopeflix/dopeflix-v0.0.2.dart index f4866fd2..38c62203 100644 --- a/anime/multisrc/dopeflix/dopeflix-v0.0.15.dart +++ b/anime/multisrc/dopeflix/dopeflix-v0.0.2.dart @@ -6,18 +6,21 @@ class DopeFlix extends MProvider { @override Future getPopular(MSource source, int page) async { - final data = {"url": "${source.baseUrl}/movie?page=$page"}; + final data = { + "url": + "${preferenceBaseUrl(source.id)}/${getPreferenceValue(source.id, "preferred_popular_page")}?page=$page" + }; final res = await http('GET', json.encode(data)); return parseAnimeList(res); } @override Future getLatestUpdates(MSource source, int page) async { - final data = {"url": "${source.baseUrl}/home"}; + final data = {"url": "${preferenceBaseUrl(source.id)}/home"}; final res = await http('GET', json.encode(data)); List animeList = []; final path = - '//section[contains(text(),"Latest Movies")]/div/div[@class="film_list-wrap"]/div[@class="flw-item"]/div[@class="film-poster"]'; + '//section[contains(text(),"${getPreferenceValue(source.id, "preferred_latest_page")}")]/div/div[@class="film_list-wrap"]/div[@class="flw-item"]/div[@class="film-poster"]'; final urls = xpath(res, '$path/a/@href'); final names = xpath(res, '$path/a/@title'); final images = xpath(res, '$path/img/@data-src'); @@ -36,7 +39,7 @@ class DopeFlix extends MProvider { Future search( MSource source, String query, int page, FilterList filterList) async { final filters = filterList.filters; - String url = "${source.baseUrl}"; + String url = "${preferenceBaseUrl(source.id)}"; if (query.isNotEmpty) { url += "/search/${query.replaceAll(" ", "-")}?page=$page"; @@ -79,7 +82,7 @@ class DopeFlix extends MProvider { @override Future getDetail(MSource source, String url) async { url = Uri.parse(url).path; - final data = {"url": "${source.baseUrl}$url"}; + final data = {"url": "${preferenceBaseUrl(source.id)}$url"}; final res = await http('GET', json.encode(data)); MManga anime = MManga(); final description = xpath(res, '//div[@class="description"]/text()'); @@ -98,10 +101,12 @@ class DopeFlix extends MProvider { if (dataType == "1") { MChapter episode = MChapter(); episode.name = "Movie"; - episode.url = "${source.baseUrl}/ajax/movie/episodes/$id"; + episode.url = "${preferenceBaseUrl(source.id)}/ajax/movie/episodes/$id"; episodesList.add(episode); } else { - final dataS = {"url": "${source.baseUrl}/ajax/v2/tv/seasons/$id"}; + final dataS = { + "url": "${preferenceBaseUrl(source.id)}/ajax/v2/tv/seasons/$id" + }; final resS = await http('GET', json.encode(dataS)); final seasonIds = @@ -112,7 +117,8 @@ class DopeFlix extends MProvider { final seasonId = seasonIds[i]; final seasonName = seasonNames[i]; final dataE = { - "url": "${source.baseUrl}/ajax/v2/season/episodes/$seasonId" + "url": + "${preferenceBaseUrl(source.id)}/ajax/v2/season/episodes/$seasonId" }; final html = await http('GET', json.encode(dataE)); final epsHtml = querySelectorAll(html, @@ -120,7 +126,8 @@ class DopeFlix extends MProvider { typeElement: 2, attributes: "", typeRegExp: 0); - print("${source.baseUrl}/ajax/v2/season/episodes/$seasonId"); + print( + "${preferenceBaseUrl(source.id)}/ajax/v2/season/episodes/$seasonId"); for (var epHtml in epsHtml) { final episodeId = xpath(epHtml, '//div[contains(@class,"eps-item")]/@data-id') @@ -130,7 +137,8 @@ class DopeFlix extends MProvider { final epName = xpath(epHtml, '//h3[@class="film-name"]/text()').first; MChapter episode = MChapter(); episode.name = "$seasonName $epNum $epName"; - episode.url = "${source.baseUrl}/ajax/v2/episode/servers/$episodeId"; + episode.url = + "${preferenceBaseUrl(source.id)}/ajax/v2/episode/servers/$episodeId"; episodesList.add(episode); } } @@ -142,8 +150,8 @@ class DopeFlix extends MProvider { @override Future> getVideoList(MSource source, String url) async { url = Uri.parse(url).path; - final res = - await http('GET', json.encode({"url": "${source.baseUrl}/$url"})); + final res = await http( + 'GET', json.encode({"url": "${preferenceBaseUrl(source.id)}/$url"})); final vidsHtml = querySelectorAll(res, selector: "ul.fss-list a.btn-play", typeElement: 2, @@ -154,7 +162,9 @@ class DopeFlix extends MProvider { final id = xpath(vidHtml, '//a/@data-id').first; final name = xpath(vidHtml, '//span/text()').first; final resSource = await http( - 'GET', json.encode({"url": "${source.baseUrl}/ajax/sources/$id"})); + 'GET', + json.encode( + {"url": "${preferenceBaseUrl(source.id)}/ajax/sources/$id"})); final vidUrl = substringBefore(substringAfter(resSource, "\"link\":\""), "\""); List a = []; @@ -212,6 +222,7 @@ class DopeFlix extends MProvider { subtitles.add(subtitle); } catch (_) {} } + subtitles = sortSubs(subtitles, source.id); if (type == "hls") { final masterPlaylistRes = await http('GET', json.encode({"url": masterUrl})); @@ -248,7 +259,7 @@ class DopeFlix extends MProvider { videos.addAll(a); } - return videos; + return sortVideos(videos, source.id); } Future>> generateIndexPairs() async { @@ -261,8 +272,8 @@ class DopeFlix extends MProvider { script = script.substring(0, script.lastIndexOf(',')); final list = script .split(",") - .map((e) { - String value = substringAfter((e as String), "="); + .map((String e) { + String value = substringAfter(e, "="); if (value.contains("0x")) { return int.parse(substringAfter(value, "0x"), radix: 16); } else { @@ -273,7 +284,7 @@ class DopeFlix extends MProvider { .skip(1) .toList(); return chunked(list, 2) - .map((list) => (list as List).reversed.toList()) + .map((List list) => list.reversed.toList()) .toList(); } @@ -405,6 +416,119 @@ class DopeFlix extends MProvider { ]; } + @override + List getSourcePreferences(MSource source) { + return [ + ListPreference( + key: "preferred_domain", + title: "Preferred domain", + summary: "", + valueIndex: 0, + entries: ["dopebox.to", "dopebox.se"], + entryValues: ["https://dopebox.to", "https://dopebox.se"]), + ListPreference( + key: "preferred_quality", + title: "Preferred Quality", + summary: "", + valueIndex: 0, + entries: ["1080p", "720p", "480p", "360p"], + entryValues: ["1080p", "720p", "480p", "360p"]), + ListPreference( + key: "preferred_subLang", + title: "Preferred sub language", + summary: "", + valueIndex: 1, + entries: [ + "Arabic", + "English", + "French", + "German", + "Hungarian", + "Italian", + "Japanese", + "Portuguese", + "Romanian", + "Russian", + "Spanish" + ], + entryValues: [ + "Arabic", + "English", + "French", + "German", + "Hungarian", + "Italian", + "Japanese", + "Portuguese", + "Romanian", + "Russian", + "Spanish" + ]), + ListPreference( + key: "preferred_latest_page", + title: "Preferred latest page", + summary: "", + valueIndex: 0, + entries: ["Movies", "TV Shows"], + entryValues: ["Latest Movies", "Latest TV Shows"]), + ListPreference( + key: "preferred_popular_page", + title: "Preferred popular page", + summary: "", + valueIndex: 0, + entries: ["Movies", "TV Shows"], + entryValues: ["movie", "tv-show"]), + ]; + } + + List sortVideos(List videos, int sourceId) { + String quality = getPreferenceValue(sourceId, "preferred_quality"); + + videos.sort((MVideo a, MVideo b) { + int qualityMatchA = 0; + if (a.quality.contains(quality)) { + qualityMatchA = 1; + } + int qualityMatchB = 0; + if (b.quality.contains(quality)) { + qualityMatchB = 1; + } + if (qualityMatchA != qualityMatchB) { + return qualityMatchB - qualityMatchA; + } + + final regex = RegExp(r'(\d+)p'); + final matchA = regex.firstMatch(a.quality); + final matchB = regex.firstMatch(b.quality); + final int qualityNumA = int.tryParse(matchA?.group(1) ?? '0') ?? 0; + final int qualityNumB = int.tryParse(matchB?.group(1) ?? '0') ?? 0; + return qualityNumB - qualityNumA; + }); + + return videos; + } + + List sortSubs(List subs, int sourceId) { + String lang = getPreferenceValue(sourceId, "preferred_subLang"); + + subs.sort((MTrack a, MTrack b) { + int langMatchA = 0; + if (a.label.toLowerCase().contains(lang.toLowerCase())) { + langMatchA = 1; + } + int langMatchB = 0; + if (b.label.toLowerCase().contains(lang.toLowerCase())) { + langMatchB = 1; + } + return langMatchB - langMatchA; + }); + return subs; + } + + String preferenceBaseUrl(int sourceId) { + return getPreferenceValue(sourceId, "preferred_domain"); + } + String ll(String url) { if (url.contains("?")) { return "&"; diff --git a/anime/multisrc/dopeflix/sources.dart b/anime/multisrc/dopeflix/sources.dart index b86b0fef..4bb6f18f 100644 --- a/anime/multisrc/dopeflix/sources.dart +++ b/anime/multisrc/dopeflix/sources.dart @@ -1,7 +1,7 @@ import '../../../model/source.dart'; import '../../../utils/utils.dart'; -const dopeflixVersion = "0.0.15"; +const dopeflixVersion = "0.0.2"; const dopeflixSourceCodeUrl = "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/multisrc/dopeflix/dopeflix-v$dopeflixVersion.dart"; diff --git a/anime/multisrc/zorotheme/sources.dart b/anime/multisrc/zorotheme/sources.dart index 80a15686..66715cea 100644 --- a/anime/multisrc/zorotheme/sources.dart +++ b/anime/multisrc/zorotheme/sources.dart @@ -1,7 +1,7 @@ import '../../../model/source.dart'; import '../../../utils/utils.dart'; -const zorothemeVersion = "0.0.5"; +const zorothemeVersion = "0.0.55"; const zorothemeSourceCodeUrl = "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/multisrc/zorotheme/zorotheme-v$zorothemeVersion.dart"; diff --git a/anime/multisrc/zorotheme/zorotheme-v0.0.5.dart b/anime/multisrc/zorotheme/zorotheme-v0.0.55.dart similarity index 79% rename from anime/multisrc/zorotheme/zorotheme-v0.0.5.dart rename to anime/multisrc/zorotheme/zorotheme-v0.0.55.dart index affc3b4a..ad0cb3b1 100644 --- a/anime/multisrc/zorotheme/zorotheme-v0.0.5.dart +++ b/anime/multisrc/zorotheme/zorotheme-v0.0.55.dart @@ -223,7 +223,8 @@ class ZoroTheme extends MProvider { typeRegExp: 0); List videos = []; - + final hosterSelection = preferenceHosterSelection(source.id); + final typeSelection = preferenceTypeSelection(source.id); for (var i = 0; i < names.length; i++) { final name = names[i]; final id = ids[i]; @@ -236,19 +237,22 @@ class ZoroTheme extends MProvider { final resE = await http('GET', json.encode(datasE)); String epUrl = substringBefore(substringAfter(resE, "\"link\":\""), "\""); - print(epUrl); + List a = []; - if (name.contains("Vidstreaming")) { - a = await rapidCloudExtractor(epUrl, "Vidstreaming - $subDub"); - } else if (name.contains("Vidcloud")) { - a = await rapidCloudExtractor(epUrl, "Vidcloud - $subDub"); - } else if (name.contains("StreamTape")) { - a = await streamTapeExtractor(epUrl, "StreamTape - $subDub"); + + if (hosterSelection.contains(name) && typeSelection.contains(subDub)) { + if (name.contains("Vidstreaming")) { + a = await rapidCloudExtractor(epUrl, "Vidstreaming - $subDub"); + } else if (name.contains("Vidcloud")) { + a = await rapidCloudExtractor(epUrl, "Vidcloud - $subDub"); + } else if (name.contains("StreamTape")) { + a = await streamTapeExtractor(epUrl, "StreamTape - $subDub"); + } + videos.addAll(a); } - videos.addAll(a); } - return videos; + return sortVideos(videos, source.id); } MPages animeElementM(String res) { @@ -421,6 +425,98 @@ class ZoroTheme extends MProvider { ]; } + @override + List getSourcePreferences(MSource source) { + return [ + ListPreference( + key: "preferred_quality", + title: "Preferred Quality", + summary: "", + valueIndex: 1, + entries: ["1080p", "720p", "480p", "360p"], + entryValues: ["1080", "720", "480", "360"]), + ListPreference( + key: "preferred_server", + title: "Preferred server", + summary: "", + valueIndex: 0, + entries: ["Vidstreaming", "VidCloud", "StreamTape"], + entryValues: ["Vidstreaming", "VidCloud", "StreamTape"]), + ListPreference( + key: "preferred_type", + title: "Preferred Type", + summary: "", + valueIndex: 0, + entries: ["Sub", "Dub"], + entryValues: ["sub", "dub"]), + MultiSelectListPreference( + key: "hoster_selection", + title: "Enable/Disable Hosts", + summary: "", + entries: ["Vidstreaming", "VidCloud", "StreamTape"], + entryValues: ["Vidstreaming", "Vidcloud", "StreamTape"], + values: ["Vidstreaming", "Vidcloud", "StreamTape"]), + MultiSelectListPreference( + key: "type_selection", + title: "Enable/Disable Types", + summary: "", + entries: ["Sub", "Dub"], + entryValues: ["sub", "dub"], + values: ["sub", "dub"]), + ]; + } + + List sortVideos(List videos, int sourceId) { + String quality = getPreferenceValue(sourceId, "preferred_quality"); + String server = getPreferenceValue(sourceId, "preferred_server"); + String type = getPreferenceValue(sourceId, "preferred_type"); + videos = videos + .where( + (MVideo e) => e.quality.toLowerCase().contains(type.toLowerCase())) + .toList(); + videos.sort((MVideo a, MVideo b) { + int qualityMatchA = 0; + if (a.quality.contains(quality)) { + qualityMatchA = 1; + } + int qualityMatchB = 0; + if (b.quality.contains(quality)) { + qualityMatchB = 1; + } + if (qualityMatchA != qualityMatchB) { + return qualityMatchB - qualityMatchA; + } + + final regex = RegExp(r'(\d+)p'); + final matchA = regex.firstMatch(a.quality); + final matchB = regex.firstMatch(b.quality); + final int qualityNumA = int.tryParse(matchA?.group(1) ?? '0') ?? 0; + final int qualityNumB = int.tryParse(matchB?.group(1) ?? '0') ?? 0; + return qualityNumB - qualityNumA; + }); + + videos.sort((MVideo a, MVideo b) { + int serverMatchA = 0; + if (a.quality.toLowerCase().contains(server.toLowerCase())) { + serverMatchA = 1; + } + int serverMatchB = 0; + if (b.quality.toLowerCase().contains(server.toLowerCase())) { + serverMatchB = 1; + } + return serverMatchB - serverMatchA; + }); + return videos; + } + + List preferenceHosterSelection(int sourceId) { + return getPreferenceValue(sourceId, "hoster_selection"); + } + + List preferenceTypeSelection(int sourceId) { + return getPreferenceValue(sourceId, "type_selection"); + } + String ll(String url) { if (url.contains("?")) { return "&"; diff --git a/anime/src/en/aniwave/aniwave-v0.0.15.dart b/anime/src/en/aniwave/aniwave-v0.0.2.dart similarity index 72% rename from anime/src/en/aniwave/aniwave-v0.0.15.dart rename to anime/src/en/aniwave/aniwave-v0.0.2.dart index eacd89e7..beb8d443 100644 --- a/anime/src/en/aniwave/aniwave-v0.0.15.dart +++ b/anime/src/en/aniwave/aniwave-v0.0.2.dart @@ -6,7 +6,9 @@ class Aniwave extends MProvider { @override Future getPopular(MSource source, int page) async { - final data = {"url": "${source.baseUrl}/filter?sort=trending&page=$page"}; + final data = { + "url": "${preferenceBaseUrl(source.id)}/filter?sort=trending&page=$page" + }; final res = await http('GET', json.encode(data)); return parseAnimeList(res); } @@ -14,7 +16,8 @@ class Aniwave extends MProvider { @override Future getLatestUpdates(MSource source, int page) async { final data = { - "url": "${source.baseUrl}/filter?sort=recently_updated&page=$page" + "url": + "${preferenceBaseUrl(source.id)}/filter?sort=recently_updated&page=$page" }; final res = await http('GET', json.encode(data)); return parseAnimeList(res); @@ -24,7 +27,7 @@ class Aniwave extends MProvider { Future search( MSource source, String query, int page, FilterList filterList) async { final filters = filterList.filters; - String url = "${source.baseUrl}/filter?keyword=$query"; + String url = "${preferenceBaseUrl(source.id)}/filter?keyword=$query"; for (var filter in filters) { if (filter.type == "OrderFilter") { @@ -98,7 +101,7 @@ class Aniwave extends MProvider { final statusList = [ {"Releasing": 0, "Completed": 1} ]; - final data = {"url": "${source.baseUrl}${url}"}; + final data = {"url": "${preferenceBaseUrl(source.id)}${url}"}; final res = await http('GET', json.encode(data)); MManga anime = MManga(); final status = xpath(res, '//div[contains(text(),"Status")]/span/text()'); @@ -124,7 +127,9 @@ class Aniwave extends MProvider { .first; final encrypt = vrfEncrypt(id); final vrf = "vrf=${Uri.encodeComponent(encrypt)}"; - final dataEp = {"url": "${source.baseUrl}/ajax/episode/list/$id?$vrf"}; + final dataEp = { + "url": "${preferenceBaseUrl(source.id)}/ajax/episode/list/$id?$vrf" + }; final resEp = await http('GET', json.encode(dataEp)); final html = json.decode(resEp)["result"]; List? episodesList = []; @@ -172,8 +177,11 @@ class Aniwave extends MProvider { final ids = substringBefore(url, "&"); final encrypt = vrfEncrypt(ids); final vrf = "vrf=${Uri.encodeComponent(encrypt)}"; - final res = await http('GET', - json.encode({"url": "${source.baseUrl}/ajax/server/list/$ids?$vrf"})); + final res = await http( + 'GET', + json.encode({ + "url": "${preferenceBaseUrl(source.id)}/ajax/server/list/$ids?$vrf" + })); final html = json.decode(res)["result"]; final vidsHtml = querySelectorAll(html, selector: "div.servers > div", @@ -191,25 +199,34 @@ class Aniwave extends MProvider { final vrf = "vrf=${Uri.encodeComponent(encrypt)}"; final res = await http( 'GET', - json.encode( - {"url": "${source.baseUrl}/ajax/server/$serverId?$vrf"})); + json.encode({ + "url": + "${preferenceBaseUrl(source.id)}/ajax/server/$serverId?$vrf" + })); final status = json.decode(res)["status"]; if (status == 200) { List a = []; final url = vrfDecrypt(json.decode(res)["result"]["url"]); - if (url.contains("mp4upload")) { - a = await mp4UploadExtractor(url, null, "", type); - } else if (url.contains("streamtape")) { - a = await streamTapeExtractor(url, "StreamTape - $type"); - } else if (url.contains("filemoon")) { - a = await filemoonExtractor(url, "", type); + final hosterSelection = preferenceHosterSelection(source.id); + final typeSelection = preferenceTypeSelection(source.id); + if (typeSelection.contains(type.toLowerCase())) { + if (url.contains("mp4upload") && + hosterSelection.contains("mp4upload")) { + a = await mp4UploadExtractor(url, null, "", type); + } else if (url.contains("streamtape") && + hosterSelection.contains("streamtape")) { + a = await streamTapeExtractor(url, "StreamTape - $type"); + } else if (url.contains("filemoon") && + hosterSelection.contains("filemoon")) { + a = await filemoonExtractor(url, "", type); + } + videos.addAll(a); } - videos.addAll(a); } } } - return videos; + return sortVideos(videos, source.id); } MPages parseAnimeList(String res) { @@ -427,6 +444,147 @@ class Aniwave extends MProvider { ]; } + @override + List getSourcePreferences(MSource source) { + return [ + ListPreference( + key: "preferred_domain", + title: "Preferred domain", + summary: "", + valueIndex: 0, + entries: [ + "aniwave.to", + "aniwave.bz", + "aniwave.ws" + ], + entryValues: [ + "https://aniwave.to", + "https://aniwave.bz", + "https://aniwave.ws" + ]), + ListPreference( + key: "preferred_quality", + title: "Preferred Quality", + summary: "", + valueIndex: 0, + entries: ["1080p", "720p", "480p", "360p"], + entryValues: ["1080", "720", "480", "360"]), + ListPreference( + key: "preferred_language", + title: "Preferred Type", + summary: "", + valueIndex: 0, + entries: ["Sub", "Softsub", "Dub"], + entryValues: ["Sub", "Softsub", "Dub"]), + ListPreference( + key: "preferred_server", + title: "Preferred server", + summary: "", + valueIndex: 0, + entries: [ + "VidPlay", + "MyCloud", + "Filemoon", + "StreamTape", + "Mp4Upload" + ], + entryValues: [ + "vidplay", + "mycloud", + "filemoon", + "streamtape", + "mp4upload" + ]), + MultiSelectListPreference( + key: "hoster_selection", + title: "Enable/Disable Hosts", + summary: "", + entries: [ + "VidPlay", + "MyCloud", + "Filemoon", + "StreamTape", + "Mp4Upload" + ], + entryValues: [ + "vidplay", + "mycloud", + "filemoon", + "streamtape", + "mp4upload" + ], + values: [ + "vidplay", + "mycloud", + "filemoon", + "streamtape", + "mp4upload" + ]), + MultiSelectListPreference( + key: "type_selection", + title: "Enable/Disable Type", + summary: "", + entries: ["Sub", "Softsub", "Dub"], + entryValues: ["sub", "softsub", "dub"], + values: ["sub", "softsub", "dub"]), + ]; + } + + String preferenceBaseUrl(int sourceId) { + return getPreferenceValue(sourceId, "preferred_domain"); + } + + List preferenceHosterSelection(int sourceId) { + return getPreferenceValue(sourceId, "hoster_selection"); + } + + List preferenceTypeSelection(int sourceId) { + return getPreferenceValue(sourceId, "type_selection"); + } + + List sortVideos(List videos, int sourceId) { + String quality = getPreferenceValue(sourceId, "preferred_quality"); + String server = getPreferenceValue(sourceId, "preferred_server"); + String lang = getPreferenceValue(sourceId, "preferred_language"); + videos = videos + .where( + (MVideo e) => e.quality.toLowerCase().contains(lang.toLowerCase())) + .toList(); + videos.sort((MVideo a, MVideo b) { + int qualityMatchA = 0; + if (a.quality.contains(quality)) { + qualityMatchA = 1; + } + int qualityMatchB = 0; + if (b.quality.contains(quality)) { + qualityMatchB = 1; + } + if (qualityMatchA != qualityMatchB) { + return qualityMatchB - qualityMatchA; + } + + final regex = RegExp(r'(\d+)p'); + final matchA = regex.firstMatch(a.quality); + final matchB = regex.firstMatch(b.quality); + final int qualityNumA = int.tryParse(matchA?.group(1) ?? '0') ?? 0; + final int qualityNumB = int.tryParse(matchB?.group(1) ?? '0') ?? 0; + return qualityNumB - qualityNumA; + }); + + videos.sort((MVideo a, MVideo b) { + int serverMatchA = 0; + if (a.quality.toLowerCase().contains(server.toLowerCase())) { + serverMatchA = 1; + } + int serverMatchB = 0; + if (b.quality.toLowerCase().contains(server.toLowerCase())) { + serverMatchB = 1; + } + return serverMatchB - serverMatchA; + }); + return videos; + } + String ll(String url) { if (url.contains("?")) { return "&"; @@ -435,14 +593,6 @@ class Aniwave extends MProvider { } } -Map getMirrorPref() { - return { - "aniwave.to": "https://aniwave.to", - "aniwave.bz": "https://aniwave.bz", - "aniwave.ws": "https://aniwave.ws", - }; -} - Aniwave main() { return Aniwave(); } diff --git a/anime/src/en/aniwave/source.dart b/anime/src/en/aniwave/source.dart index f0e53a31..abcbad96 100644 --- a/anime/src/en/aniwave/source.dart +++ b/anime/src/en/aniwave/source.dart @@ -2,7 +2,7 @@ import '../../../../model/source.dart'; import '../../../../utils/utils.dart'; Source get aniwave => _aniwave; -const aniwaveVersion = "0.0.15"; +const aniwaveVersion = "0.0.2"; const aniwaveCodeUrl = "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/en/aniwave/aniwave-v$aniwaveVersion.dart"; Source _aniwave = Source( diff --git a/anime/src/en/gogoanime/gogoanime-v0.0.4.dart b/anime/src/en/gogoanime/gogoanime-v0.0.5.dart similarity index 87% rename from anime/src/en/gogoanime/gogoanime-v0.0.4.dart rename to anime/src/en/gogoanime/gogoanime-v0.0.5.dart index b6eab5d9..2d63ecf0 100644 --- a/anime/src/en/gogoanime/gogoanime-v0.0.4.dart +++ b/anime/src/en/gogoanime/gogoanime-v0.0.5.dart @@ -6,7 +6,9 @@ class GogoAnime extends MProvider { @override Future getPopular(MSource source, int page) async { - final data = {"url": "${source.baseUrl}/popular.html?page=$page"}; + final data = { + "url": "${preferenceBaseUrl(source.id)}/popular.html?page=$page" + }; final res = await http('GET', json.encode(data)); List animeList = []; @@ -130,14 +132,15 @@ class GogoAnime extends MProvider { } } if (genre.isNotEmpty) { - url = "${source.baseUrl}/genre/$genre?page=$page"; + url = "${preferenceBaseUrl(source.id)}/genre/$genre?page=$page"; } else if (recent.isNotEmpty) { url = "https://ajax.gogo-load.com/ajax/page-recent-release.html?page=$page&type=$recent"; } else if (season.isNotEmpty) { - url = "${source.baseUrl}/$season?page=$page"; + url = "${preferenceBaseUrl(source.id)}/$season?page=$page"; } else { - url = "${source.baseUrl}/filter.html?keyword=$query$filterStr&page=$page"; + url = + "${preferenceBaseUrl(source.id)}/filter.html?keyword=$query$filterStr&page=$page"; } final data = {"url": url}; @@ -167,7 +170,7 @@ class GogoAnime extends MProvider { "Completed": 1, } ]; - final data = {"url": "${source.baseUrl}$url"}; + final data = {"url": "${preferenceBaseUrl(source.id)}$url"}; final res = await http('GET', json.encode(data)); MManga anime = MManga(); final status = xpath( @@ -213,7 +216,7 @@ class GogoAnime extends MProvider { @override Future> getVideoList(MSource source, String url) async { - final datas = {"url": "${source.baseUrl}$url"}; + final datas = {"url": "${preferenceBaseUrl(source.id)}$url"}; final res = await http('GET', json.encode(datas)); final serverUrls = @@ -221,27 +224,30 @@ class GogoAnime extends MProvider { final serverNames = xpath(res, '//*[@class="anime_muti_link"]/ul/li/@class'); List videos = []; + final hosterSelection = preferenceHosterSelection(source.id); for (var i = 0; i < serverNames.length; i++) { final name = serverNames[i]; final url = serverUrls[i]; List a = []; - if (name.contains("anime")) { - a = await gogoCdnExtractor(url); - } else if (name.contains("vidcdn")) { - a = await gogoCdnExtractor(url); - } else if (name.contains("doodstream")) { - a = await doodExtractor(url); - } else if (name.contains("mp4upload")) { - a = await mp4UploadExtractor(url, null, "", ""); - } else if (name.contains("filelions")) { - a = await streamWishExtractor(url, "FileLions"); - } else if (name.contains("streamwish")) { - a = await streamWishExtractor(url, "StreamWish"); + if (hosterSelection.contains(name)) { + if (name.contains("anime")) { + a = await gogoCdnExtractor(url); + } else if (name.contains("vidcdn")) { + a = await gogoCdnExtractor(url); + } else if (name.contains("doodstream")) { + a = await doodExtractor(url); + } else if (name.contains("mp4upload")) { + a = await mp4UploadExtractor(url, null, "", ""); + } else if (name.contains("filelions")) { + a = await streamWishExtractor(url, "FileLions"); + } else if (name.contains("streamwish")) { + a = await streamWishExtractor(url, "StreamWish"); + } + videos.addAll(a); } - videos.addAll(a); } - return videos; + return sortVideos(videos, source.id); } @override @@ -1025,6 +1031,124 @@ class GogoAnime extends MProvider { ]), ]; } + + @override + List getSourcePreferences(MSource source) { + return [ + EditTextPreference( + key: "override_baseurl_v${source.id}", + title: "Override BaseUrl", + summary: + "For temporary uses. Updating the extension will erase this setting.", + value: "https://gogoanime3.net", + dialogTitle: "Override BaseUrl", + dialogMessage: "Default: https://gogoanime3.net", + text: "https://gogoanime3.net"), + ListPreference( + key: "preferred_quality", + title: "Preferred quality", + summary: "", + valueIndex: 0, + entries: ["1080p", "720p", "480p", "360p"], + entryValues: ["1080", "720", "480", "360"]), + ListPreference( + key: "preferred_server", + title: "Preferred server", + summary: "", + valueIndex: 0, + entries: [ + "Gogostream", + "Vidstreaming", + "Doodstream", + "StreamWish", + "Mp4upload", + "FileLions" + ], + entryValues: [ + "Gogostream", + "Vidstreaming", + "Doodstream", + "StreamWish", + "Mp4upload", + "FileLions" + ]), + MultiSelectListPreference( + key: "hoster_selection", + title: "Enable/Disable Hosts", + summary: "", + entries: [ + "Gogostream", + "Vidstreaming", + "Doodstream", + "StreamWish", + "Mp4upload", + "FileLions" + ], + entryValues: [ + "vidcdn", + "anime", + "doodstream", + "streamwish", + "mp4upload", + "filelions" + ], + values: [ + "vidcdn", + "anime", + "doodstream", + "streamwish", + "mp4upload", + "filelions" + ]), + ]; + } + + String preferenceBaseUrl(int sourceId) { + return getPreferenceValue(sourceId, "override_baseurl_v$sourceId"); + } + + List preferenceHosterSelection(int sourceId) { + return getPreferenceValue(sourceId, "hoster_selection"); + } + + List sortVideos(List videos, int sourceId) { + String quality = getPreferenceValue(sourceId, "preferred_quality"); + String server = getPreferenceValue(sourceId, "preferred_server"); + + videos.sort((MVideo a, MVideo b) { + int qualityMatchA = 0; + if (a.quality.contains(quality)) { + qualityMatchA = 1; + } + int qualityMatchB = 0; + if (b.quality.contains(quality)) { + qualityMatchB = 1; + } + if (qualityMatchA != qualityMatchB) { + return qualityMatchB - qualityMatchA; + } + + final regex = RegExp(r'(\d+)p'); + final matchA = regex.firstMatch(a.quality); + final matchB = regex.firstMatch(b.quality); + final int qualityNumA = int.tryParse(matchA?.group(1) ?? '0') ?? 0; + final int qualityNumB = int.tryParse(matchB?.group(1) ?? '0') ?? 0; + return qualityNumB - qualityNumA; + }); + + videos.sort((MVideo a, MVideo b) { + int serverMatchA = 0; + if (a.quality.contains(server)) { + serverMatchA = 1; + } + int serverMatchB = 0; + if (b.quality.contains(server)) { + serverMatchB = 1; + } + return serverMatchB - serverMatchA; + }); + return videos; + } } GogoAnime main() { diff --git a/anime/src/en/gogoanime/source.dart b/anime/src/en/gogoanime/source.dart index 88ef15c7..31bb14f5 100644 --- a/anime/src/en/gogoanime/source.dart +++ b/anime/src/en/gogoanime/source.dart @@ -2,7 +2,7 @@ import '../../../../model/source.dart'; import '../../../../utils/utils.dart'; Source get gogoanimeSource => _gogoanimeSource; -const gogoanimeVersion = "0.0.4"; +const gogoanimeVersion = "0.0.5"; const gogoanimeSourceCodeUrl = "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/en/gogoanime/gogoanime-v$gogoanimeVersion.dart"; Source _gogoanimeSource = Source( diff --git a/model/source.dart b/model/source.dart index ce9b7335..23f29ba8 100644 --- a/model/source.dart +++ b/model/source.dart @@ -47,7 +47,7 @@ class Source { this.version = "", this.isManga = true, this.isFullData = false, - this.appMinVerReq = "0.1.1"}); + this.appMinVerReq = "0.1.2"}); Map toJson() { return {