import 'package:mangayomi/bridge_lib.dart'; import 'dart:convert'; class Vumeto extends MProvider { Vumeto({required this.source}); MSource source; final Client client = Client(source); @override bool get supportsLatest => true; @override Map get headers => { "Cookie": "_ga=GA1.1.2064759276.1741681027; _ga_5HMNDC3ZE4=GS1.1.1741824276.8.1.1741824749.0.0.0", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36", "Referer": "https://vumeto.com/", }; @override Future getPopular(int page) async { final url = 'https://vumeto.com/most-popular'; final resp = await client.get(Uri.parse(url)); final document = parseHtml(resp.body); return MPages(scrapeAnimeList(document), false); } @override Future getLatestUpdates(int page) async { final url = 'https://vumeto.com/recently-updated'; final resp = await client.get(Uri.parse(url)); final document = parseHtml(resp.body); return MPages(scrapeAnimeList(document), false); } @override Future search(String query, int page, FilterList filterList) async { final url = 'https://vumeto.com/search?q=$query'; final resp = await client.get(Uri.parse(url)); final document = parseHtml(resp.body); return MPages(scrapeAnimeList(document), false); } String fixUrl(String encodedUrl) { return encodedUrl .split('url=') .last .split('&w') .first .replaceAll('%3A', ':') .replaceAll('%2F', '/') .replaceAll('%3F', '?') .replaceAll('%3D', '=') .replaceAll('%26', '&'); } List scrapeAnimeList(MDocument document) { List? animeElements = document.getElementsByClassName( 'relative group border-0', ); List results = []; if (animeElements != null) { for (var anime in animeElements) { String? title = anime.selectFirst('h3')?.text ?? ''; String? animeUrl = anime.selectFirst('a')?.attr('href') ?? ''; String? imageUrl = anime.selectFirst('img')?.attr('src') ?? ''; MManga manga = MManga(); manga.name = title; manga.link = "https://vumeto.com/watch/" + animeUrl.replaceAll('/info/', '').split('/').first + '?ep=1'; manga.imageUrl = fixUrl(imageUrl.split('url=').last); results.add(manga); } } return results; } @override Future getDetail(String url) async { final statusList = [ {"Releasing": 0, "Finished": 1}, ]; final uri = Uri.parse(url); final resp = await client.get(uri, headers); final document = parseHtml(resp.body); final description = document.selectFirst("meta[name='description']").attr("content") ?? ''; MStatus status = MStatus.unknown; final statusStart = resp.body.indexOf(":", resp.body.indexOf("\\\"status\\\"")); final statusEnd = resp.body.indexOf("\\\",", statusStart); if (statusStart != -1 && statusEnd != -1) { final rawStatus = resp.body.substring(statusStart + 1, statusEnd); status = parseStatus(rawStatus.replaceAll("\\\"", ""), statusList); } final genresStart = resp.body.indexOf("[", resp.body.indexOf("\\\"genres\\\":")); final genresEnd = resp.body.indexOf("]", genresStart); var genres = []; if (genresStart != -1 && genresEnd != -1) { final genreLinks = resp.body.substring(genresStart + 1, genresEnd).split(","); genres = genreLinks.map((String e) => e.replaceAll("\\\"", "")).toList(); } List chapters = []; final scripts = document.getElementsByTagName("script"); String jsonData = ""; for (var script in scripts!) { if (script.text!.contains("episodesData")) { final regex = RegExp( r'self\.__next_f\.push\(\[1,".*?",null,(.*?)\]\)', dotAll: true, ); final match = regex.firstMatch(script.text!); if (match != null && match.groupCount >= 1) { String cleaned = match.group(1)!.replaceAll(r'\', ''); jsonData = cleaned.substring(0, cleaned.length - 3); break; } else { print("Regex did not match."); } } } Map parsedData = json.decode(jsonData); List episodesData = parsedData['episodesData']; for (var ep in episodesData) { MChapter ch = MChapter(); final number = (ep?['episodeNo'] ?? episodesData.indexOf(ep) + 1).toString(); ch.name = "Episode $number"; ch.url = url.split('?').first + '?ep=$number'; if (!chapters.any((c) => c.name == ch.name)) { chapters.add(ch); } } MManga result = MManga(); result.description = description; result.status = status; result.genre = genres; result.chapters = chapters.reversed.toList(); return result; } String stripTags(String htmlString) { final RegExp exp = RegExp( r'<[^>]*>', multiLine: true, caseSensitive: false, ); return htmlString.replaceAll(exp, '').trim(); } @override Future> getVideoList(String url) async { try { final resp = await client.get(Uri.parse(url), headers); final document = parseHtml(resp.body); final scripts = document.getElementsByTagName("script"); if (scripts.isEmpty) { print("No