import 'package:mangayomi/bridge_lib.dart'; import 'dart:convert'; class YoMovies extends MProvider { YoMovies(); final Client client = Client(); @override bool get supportsLatest => false; @override Future getPopular(MSource source, int page) async { String pageNu = page == 1 ? "" : "page/$page/"; final res = (await client.get(Uri.parse( "${preferenceBaseUrl(source.id)}/most-favorites/$pageNu"))) .body; final document = parseHtml(res); return animeFromElement( document.select("div.movies-list > div.ml-item"), document.selectFirst("ul.pagination > li.active + li")?.getHref != null); } @override Future getLatestUpdates(MSource source, int page) async { return MPages([], false); } @override Future search( MSource source, String query, int page, FilterList filterList) async { final filters = filterList.filters; String url = ""; String pageNu = page == 1 ? "" : "/page/$page"; if (query.isNotEmpty) { url = "${preferenceBaseUrl(source.id)}$pageNu/?s=$query"; } else { for (var filter in filters) { if (filter.type.isNotEmpty) { final first = filter.values[filter.state].value; if (first.isNotEmpty) { url = first; } } } url = "${preferenceBaseUrl(source.id)}$url$pageNu"; } final res = (await client.get(Uri.parse(url))).body; final document = parseHtml(res); return animeFromElement( document.select("div.movies-list > div.ml-item"), document.selectFirst("ul.pagination > li.active + li")?.getHref != null); } @override Future getDetail(MSource source, String url) async { url = Uri.parse(url).path; final res = (await client.get(Uri.parse("${preferenceBaseUrl(source.id)}$url"))) .body; final document = parseHtml(res); MManga anime = MManga(); var infoElement = document.selectFirst("div.mvi-content"); anime.description = infoElement.selectFirst("p.f-desc")?.text ?? ""; anime.genre = xpath(res, '//div[@class="mvici-left" and contains(text(),"Genre:")]/p/a/text()'); List episodeList = []; final seasonListElements = document.select("div#seasons > div.tvseason"); if (seasonListElements.isEmpty) { MChapter ep = MChapter(); ep.name = "Movie"; ep.url = url; episodeList.add(ep); } else { for (var season in seasonListElements) { var seasonText = season.selectFirst("div.les-title").text.trim(); for (var episode in season.select("div.les-content > a")) { var epNumber = substringAfter(episode.text.trim(), "pisode "); MChapter ep = MChapter(); ep.name = "$seasonText Ep. $epNumber"; ep.url = episode.getHref; episodeList.add(ep); } } } anime.chapters = episodeList.reversed.toList(); return anime; } @override Future> getVideoList(MSource source, String url) async { url = Uri.parse(url).path; final res = (await client.get(Uri.parse("${preferenceBaseUrl(source.id)}$url"))) .body; final document = parseHtml(res); final serverElements = document.select("div.movieplay > iframe"); List videos = []; for (var serverElement in serverElements) { var url = serverElement.getSrc; List a = []; if (url.contains("minoplres")) { a = await minoplresExtractor(url); } videos.addAll(a); } return sortVideos(videos, source.id); } @override List getSourcePreferences(MSource source) { return [ EditTextPreference( key: "overrideBaseUrl", title: "Override BaseUrl", summary: "", value: "https://yomovies.boo", dialogTitle: "Override BaseUrl", dialogMessage: "", text: "https://yomovies.boo"), ListPreference( key: "preferred_quality", title: "Preferred quality", summary: "", valueIndex: 0, entries: ["1080p", "720p", "480p", "360p"], entryValues: ["1080", "720", "480", "360"]) ]; } Future> minoplresExtractor(String url) async { List videos = []; final res = (await client.get(Uri.parse(url), headers: {"Referer": url})).body; final script = xpath(res, '//script[contains(text(),"sources:")]/text()'); if (script.isEmpty) return []; final masterUrl = substringBefore(substringAfter(script.first, "file:\""), '"'); final masterPlaylistRes = (await client.get(Uri.parse(masterUrl))).body; for (var it in substringAfter(masterPlaylistRes, "#EXT-X-STREAM-INF:") .split("#EXT-X-STREAM-INF:")) { final quality = "${substringBefore(substringBefore(substringAfter(substringAfter(it, "RESOLUTION="), "x"), ","), "\n")}p"; String videoUrl = substringBefore(substringAfter(it, "\n"), "\n"); MVideo video = MVideo(); video ..url = videoUrl ..originalUrl = videoUrl ..quality = "Minoplres - $quality"; videos.add(video); } return videos; } String preferenceBaseUrl(int sourceId) { return getPreferenceValue(sourceId, "overrideBaseUrl"); } MPages animeFromElement(List elements, bool hasNextPage) { List animeList = []; for (var element in elements) { MManga anime = MManga(); anime.name = element.selectFirst("div.qtip-title").text; anime.imageUrl = element.selectFirst("img[data-original]")?.attr("data-original") ?? ""; anime.link = element.selectFirst("a[href]").getHref; animeList.add(anime); } return MPages(animeList, hasNextPage); } 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; } @override List getFilterList(MSource source) { return [ HeaderFilter( "Note: Only one selection at a time works, and it ignores text search"), SeparatorFilter(), SelectFilter("BollywoodFilter", "Bollywood", 0, [ SelectFilterOption("", ""), SelectFilterOption("Dual Audio", "/genre/dual-audio"), SelectFilterOption("Hollywood Dubbed", "/account/?ptype=post&tax_category%5B%5D=dual-audio&wpas=1"), SelectFilterOption("South Dubbed", "/account/?ptype=post&tax_category%5B%5D=dual-audio&tax_category%5B%5D=south-special&wpas=1"), ]), SelectFilter("HollywoodFilter", "Hollywood", 0, [ SelectFilterOption("", ""), SelectFilterOption("English Series", "/series"), ]), SelectFilter("HindiSeriesFilter", "English Series", 0, [ SelectFilterOption("", ""), SelectFilterOption("Action", "/genre/action"), SelectFilterOption("Adventure", "/genre/adventure"), SelectFilterOption("Animation", "/genre/animation"), SelectFilterOption("Biography", "/genre/biography"), SelectFilterOption("Comedy", "/genre/comedy"), SelectFilterOption("Crime", "/genre/crime"), SelectFilterOption("Drama", "/genre/drama"), SelectFilterOption("Music", "/genre/music"), SelectFilterOption("Mystery", "/genre/mystery"), SelectFilterOption("Family", "/genre/family"), SelectFilterOption("Fantasy", "/genre/fantasy"), SelectFilterOption("Horror", "/genre/horror"), SelectFilterOption("History", "/genre/history"), SelectFilterOption("Romance", "/genre/romantic"), SelectFilterOption("Science Fiction", "/genre/science-fiction"), SelectFilterOption("Thriller", "/genre/thriller"), SelectFilterOption("War", "/genre/war"), ]), SelectFilter("ExtraMoviesFilter", "ExtraMovies", 0, [ SelectFilterOption("", ""), SelectFilterOption("Erotic", "/genre/erotic-movies"), ]), SelectFilter("HotSeriesFilter", "Hot Series", 0, [ SelectFilterOption("