diff --git a/anime/source_generator.dart b/anime/source_generator.dart index 196f9f64..8accd63f 100644 --- a/anime/source_generator.dart +++ b/anime/source_generator.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'dart:developer'; import 'dart:io'; import '../model/source.dart'; +import 'src/ar/source.dart'; import 'src/en/aniwatch/sources.dart'; import 'src/en/gogoanime/source.dart'; // import 'src/en/wcostream/source.dart'; @@ -20,7 +21,8 @@ void main() { // wcostreamSource, animesultraSource, ...aniwatchSourcesList, - kisskhSource + kisskhSource, + okanimeSource ]; final List> jsonList = _sourcesList.map((source) => source.toJson()).toList(); diff --git a/anime/src/ar/okanime-v0.0.1.dart b/anime/src/ar/okanime-v0.0.1.dart new file mode 100644 index 00000000..b2a53ba8 --- /dev/null +++ b/anime/src/ar/okanime-v0.0.1.dart @@ -0,0 +1,163 @@ +import 'dart:convert'; +import 'package:bridge_lib/bridge_lib.dart'; + +getPopularAnime(MangaModel anime) async { + final data = {"url": anime.baseUrl}; + final res = await MBridge.http('GET', json.encode(data)); + if (res.isEmpty) { + return anime; + } + anime.urls = MBridge.xpath(res, + '//div[@class="section" and contains(text(),"افضل انميات")]/div[@class="section-content"]/div/div/div[contains(@class,"anime-card")]/div[@class="anime-title")]/h4/a/@href'); + + anime.names = MBridge.xpath(res, + '//div[@class="section" and contains(text(),"افضل انميات")]/div[@class="section-content"]/div/div/div[contains(@class,"anime-card")]/div[@class="anime-title")]/h4/a/text()'); + + anime.images = MBridge.xpath(res, + '//div[@class="section" and contains(text(),"افضل انميات")]/div[@class="section-content"]/div/div/div[contains(@class,"anime-card")]/div[@class="anime-image")]/img/@src'); + anime.hasNextPage = false; + return anime; +} + +getAnimeDetail(MangaModel anime) async { + final statusList = [ + {"يعرض الان": 0, "مكتمل": 1} + ]; + final data = {"url": anime.link}; + final res = await MBridge.http('GET', json.encode(data)); + if (res.isEmpty) { + return anime; + } + + final status = MBridge.xpath(res, + '//*[@class="full-list-info" and contains(text(),"حالة الأنمي")]/small/a/text()'); + if (status.isNotEmpty) { + anime.status = MBridge.parseStatus(status.first, statusList); + } + anime.description = + MBridge.xpath(res, '//*[@class="review-content"]/text()').first; + final genre = MBridge.xpath(res, '//*[@class="review-author-info"]/a/text()'); + anime.genre = genre; + + anime.urls = MBridge.xpath(res, + '//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h5/a/@href') + .reversed + .toList(); + + anime.names = MBridge.xpath(res, + '//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h5/a/text()') + .reversed + .toList(); + anime.chaptersDateUploads = []; + return anime; +} + +getLatestUpdatesAnime(MangaModel anime) async { + final data = {"url": "${anime.baseUrl}/espisode-list?page=${anime.page}"}; + final res = await MBridge.http('GET', json.encode(data)); + if (res.isEmpty) { + return anime; + } + anime.urls = MBridge.xpath(res, + '//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h4/a/@href'); + + anime.names = MBridge.xpath(res, + '//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h4/a/text()'); + + anime.images = MBridge.xpath(res, + '//*[contains(@class,"anime-card")]/div[@class="episode-image")]/img/@src'); + final nextPage = + MBridge.xpath(res, '//li[@class="page-item"]/a[@rel="next"]/@href'); + if (nextPage.isEmpty) { + anime.hasNextPage = false; + } else { + anime.hasNextPage = true; + } + return anime; +} + +searchAnime(MangaModel anime) async { + String url = "${anime.baseUrl}/search/?s=${anime.query}"; + if (anime.page > 1) { + url += "&page=${anime.page}"; + } + final data = {"url": url}; + final res = await MBridge.http('GET', json.encode(data)); + if (res.isEmpty) { + return anime; + } + anime.urls = MBridge.xpath(res, + '//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h4/a/@href'); + + anime.names = MBridge.xpath(res, + '//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h4/a/text()'); + + anime.images = MBridge.xpath(res, + '//*[contains(@class,"anime-card")]/div[@class="anime-image")]/img/@src'); + final nextPage = + MBridge.xpath(res, '//li[@class="page-item"]/a[@rel="next"]/@href'); + if (nextPage.isEmpty) { + anime.hasNextPage = false; + } else { + anime.hasNextPage = true; + } + return anime; +} + +getVideoList(MangaModel anime) async { + final datas = {"url": anime.link}; + print(anime.link); + final res = await MBridge.http('GET', json.encode(datas)); + + if (res.isEmpty) { + return []; + } + final urls = MBridge.xpath(res, '//*[@id="streamlinks"]/a/@data-src'); + final qualities = MBridge.xpath(res, '//*[@id="streamlinks"]/a/span/text()'); + + List videos = []; + for (var i = 0; i < urls.length; i++) { + final url = urls[i]; + final quality = getQuality(qualities[i]); + List a = []; + + if (url.contains("https://doo")) { + a = await MBridge.doodExtractor(url, "DoodStream - $quality"); + } else if (url.contains("mp4upload")) { + a = await MBridge.mp4UploadExtractor(url, null, "", ""); + } else if (url.contains("ok.ru")) { + a = await MBridge.okruExtractor(url); + } else if (url.contains("voe.sx")) { + a = await MBridge.voeExtractor(url, "VoeSX ($quality)"); + } else if (containsVidBom(url)) { + a = await MBridge.vidBomExtractor(url); + } + if (a.isNotEmpty) { + videos.addAll(a); + } + } + return videos; +} + +String getQuality(String quality) { + quality = quality.replaceAll(" ", ""); + if (quality == "HD") { + return "720p"; + } else if (quality == "FHD") { + return "1080p"; + } else if (quality == "SD") { + return "480p"; + } + return "240p"; +} + +bool containsVidBom(String url) { + url = url; + final list = ["vidbam", "vadbam", "vidbom", "vidbm"]; + for (var n in list) { + if (url.contains(n)) { + return true; + } + return false; + } +} diff --git a/anime/src/ar/source.dart b/anime/src/ar/source.dart new file mode 100644 index 00000000..51070287 --- /dev/null +++ b/anime/src/ar/source.dart @@ -0,0 +1,17 @@ +import '../../../model/source.dart'; +import '../../../utils/utils.dart'; + +Source get okanimeSource => _okanimeSource; +const okanimeVersion = "0.0.1"; +const okanimeSourceCodeUrl = + "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/ar/okanime/okanime-v$okanimeVersion.dart"; +Source _okanimeSource = Source( + name: "Okanime", + baseUrl: "https://www.okanime.xyz", + lang: "ar", + typeSource: "single", + iconUrl: getIconUrl("okanime", "ar"), + sourceCodeUrl: okanimeSourceCodeUrl, + version: okanimeVersion, + appMinVerReq: "0.0.48", + isManga: false); diff --git a/anime/src/fr/franime/franime-v0.0.21.dart b/anime/src/fr/franime/franime-v0.0.21.dart deleted file mode 100644 index 6006c5cb..00000000 --- a/anime/src/fr/franime/franime-v0.0.21.dart +++ /dev/null @@ -1,419 +0,0 @@ -import 'dart:convert'; -import 'package:bridge_lib/bridge_lib.dart'; - -Future dataBase(int sourceId) async { - final data = { - "url": "https://api.franime.fr/api/animes/", - "headers": {"Referer": "https://franime.fr/"}, - "sourceId": sourceId - }; - final res = await MBridge.http('GET', json.encode(data)); - return res; -} - -getPopularAnime(MangaModel anime) async { - final data = { - "url": "https://api.franime.fr/api/animes/", - "headers": {"Referer": "https://franime.fr/"}, - "sourceId": anime.sourceId - }; - final res = await MBridge.http('GET', json.encode(data)); - if (res.isEmpty) { - return []; - } - List animeList = animeResList(res); - - return animeList; -} - -List animeResList(String res) { - final statusList = [ - {"EN COURS": 0, "TERMINÉ": 1} - ]; - List animeList = []; - final langs = - MBridge.jsonPathToList(res, r'$..saisons[*].episodes[*].lang', 1); - int index = 0; - List jsonResList = MBridge.jsonDecodeToList(res, 1); - for (var animeJson in jsonResList) { - MangaModel anime = MangaModel(); - List seasons = MBridge.jsonDecodeToList( - MBridge.getMapValue(animeJson, "saisons", encode: true), 1); - final titleO = MBridge.getMapValue(animeJson, "titleO", 0); - final vo = MBridge.getMapValue(MBridge.listParse(langs, 0)[index], "vo", - encode: true); - final vf = MBridge.getMapValue(MBridge.listParse(langs, 0)[index], "vf", - encode: true); - final hasVostfr = MBridge.isEmptyOrIsNotEmpty( - MBridge.jsonDecodeToList( - MBridge.getMapValue(vo, "lecteurs", encode: true), 0), - 1); - final hasVf = MBridge.isEmptyOrIsNotEmpty( - MBridge.jsonDecodeToList( - MBridge.getMapValue(vf, "lecteurs", encode: true), 0), - 1); - String title = MBridge.getMapValue(animeJson, "title", 0); - final genre = MBridge.jsonDecodeToList( - MBridge.getMapValue(animeJson, "themes", encode: true), 0); - final description = MBridge.getMapValue(animeJson, "description", 0); - final status = MBridge.parseStatus( - MBridge.getMapValue(animeJson, "status", 0), statusList); - final imageUrl = MBridge.getMapValue(animeJson, "affiche", 0); - if (hasVostfr) { - for (int i = 0; i < seasons.length; i++) { - int ind = i + 1; - - anime.genre = genre; - - anime.description = description; - String seasonTitle = title; - if (seasons.length > 1) { - seasonTitle += " S$ind"; - } - if (hasVostfr) { - seasonTitle += " VOSTFR"; - } - anime.status = status; - anime.name = seasonTitle; - anime.imageUrl = imageUrl; - anime.link = - "/anime/${MBridge.regExp(titleO, "[^A-Za-z0-9 ]", "", 0, 0).replaceAll(" ", "-").toLowerCase()}?lang=vo&s=$ind"; - ind++; - } - } else if (hasVf) { - for (int i = 0; i < seasons.length; i++) { - int ind = i + 1; - anime.genre = genre; - anime.description = description; - String seasonTitle = title; - if (seasons.length > 1) { - seasonTitle += " S$ind"; - } - if (hasVf) { - seasonTitle += " VF"; - } - anime.status = status; - anime.name = seasonTitle; - anime.imageUrl = imageUrl; - anime.link = - "/anime/${MBridge.regExp(titleO, "[^A-Za-z0-9 ]", "", 0, 0).replaceAll(" ", "-").toLowerCase()}?lang=vo&s=$ind"; - ind++; - } - } - animeList.add(anime); - index++; - } - return animeList; -} - -String databaseAnimeByTitleO(String res, String titleO) { - print(titleO); - List datas = MBridge.jsonDecodeToList(res, 1); - for (var data in datas) { - if (MBridge.regExp(MBridge.getMapValue(data, "titleO", 0), "[^A-Za-z0-9 ]", - "", 0, 0) - .replaceAll(" ", "-") - .toLowerCase() == - "${titleO}") { - return data; - } - } - return ""; -} - -getAnimeDetail(MangaModel anime) async { - String language = "vo".toString(); - if (anime.link.contains("lang=")) { - language = MBridge.listParse( - MBridge.listParse(anime.link.split("lang="), 2)[0].split("&"), 1)[0]; - print(language); - } - String stem = MBridge.listParse( - MBridge.listParse(anime.link.split("/"), 2)[0].split("?"), 1)[0]; - final res = await dataBase(anime.sourceId); - if (res.isEmpty) { - return anime; - } - final animeByTitleOJson = databaseAnimeByTitleO(res, stem); - if (animeByTitleOJson.isEmpty) { - return anime; - } - String seasonsJson = - MBridge.jsonPathToList(animeByTitleOJson, r'$..saisons', 1)[0]; - List seasons = MBridge.jsonDecodeToList(seasonsJson, 1); - - if (anime.link.contains("s=")) { - int seasonNumber = - MBridge.intParse(MBridge.listParse(anime.link.split("s="), 2)[0]); - seasonsJson = MBridge.listParse(seasons, 0)[seasonNumber - 1]; - } else { - seasonsJson = MBridge.listParse(seasons, 0)[0]; - } - final episodesJson = - MBridge.jsonPathToList(seasonsJson, r'$..episodes', 1)[0]; - List episodes = MBridge.jsonDecodeToList(episodesJson, 1); - List episodesNames = []; - List episodesUrls = []; - for (int i = 0; i < episodes.length; i++) { - String episode = MBridge.listParse(episodes, 0)[i]; - final lang = MBridge.getMapValue(episode, "lang", encode: true); - final vo = MBridge.getMapValue(lang, "vo", encode: true); - final vf = MBridge.getMapValue(lang, "vf", encode: true); - final hasVostfr = MBridge.isEmptyOrIsNotEmpty( - MBridge.jsonDecodeToList( - MBridge.getMapValue(vo, "lecteurs", encode: true), 0), - 1); - final hasVf = MBridge.isEmptyOrIsNotEmpty( - MBridge.jsonDecodeToList( - MBridge.getMapValue(vf, "lecteurs", encode: true), 0), - 1); - bool playerIsNotEmpty = false; - if (language == "vo" && hasVostfr) { - playerIsNotEmpty = true; - } else if (language == "vf" && hasVf) { - playerIsNotEmpty = true; - } - if (playerIsNotEmpty) { - episodesUrls.add("${anime.link}&ep=${i + 1}"); - final title = MBridge.getMapValue(episode, "title", encode: true); - episodesNames.add(title.replaceAll('"', "")); - } - } - - anime.urls = MBridge.listParse(episodesUrls, 5); - anime.names = MBridge.listParse(episodesNames, 5); - anime.chaptersDateUploads = []; - return anime; -} - -getLatestUpdatesAnime(MangaModel anime) async { - final res = await dataBase(anime.sourceId); - - if (res.isEmpty) { - return anime; - } - List reversed = - MBridge.listParse(MBridge.jsonDecodeToList(res, 1), 5); - String reversedJson = "".toString(); - for (int i = 0; i < reversed.length; i++) { - final va = MBridge.listParse(reversed, 0)[i]; - String vg = "".toString(); - if (reversedJson.isNotEmpty) { - vg = ",".toString(); - } - reversedJson += "$vg$va"; - } - List animeList = animeResList("[${reversedJson}]"); - - return animeList; -} - -searchAnime(MangaModel anime) async { - final res = await dataBase(anime.sourceId); - - if (res.isEmpty) { - return anime; - } - List animeList = animeSeachFetch(res, anime.query); - return animeList; -} - -List animeSeachFetch(String res, query) { - final statusList = [ - {"EN COURS": 0, "TERMINÉ": 1} - ]; - List animeList = []; - final langs = - MBridge.jsonPathToList(res, r'$..saisons[*].episodes[*].lang', 1); - int index = 0; - List jsonResList = MBridge.jsonDecodeToList(res, 1); - for (var animeJson in jsonResList) { - MangaModel anime = MangaModel(); - - final titleO = MBridge.getMapValue(animeJson, "titleO", 0); - - final titleAlt = MBridge.getMapValue(animeJson, "titles", encode: true); - final enContains = MBridge.getMapValue(titleAlt, "en", 0) - .toString() - .toLowerCase() - .contains(query); - final enJpContains = MBridge.getMapValue(titleAlt, "en_jp", 0) - .toString() - .toLowerCase() - .contains(query); - final jaJpContains = MBridge.getMapValue(titleAlt, "ja_jp", 0) - .toString() - .toLowerCase() - .contains(query); - final titleOContains = titleO.toLowerCase().contains(query); - bool contains = false; - if (enContains) { - contains = true; - } - if (enJpContains) { - contains = true; - } - if (jaJpContains) { - contains = true; - } - if (titleOContains) { - contains = true; - } - if (contains) { - List seasons = MBridge.jsonDecodeToList( - MBridge.getMapValue(animeJson, "saisons", encode: true), 1); - final vo = - MBridge.getMapValue(MBridge.listParse(langs, 0)[index], "vo", 1); - final vf = - MBridge.getMapValue(MBridge.listParse(langs, 0)[index], "vf", 1); - final hasVostfr = MBridge.isEmptyOrIsNotEmpty( - MBridge.jsonDecodeToList( - MBridge.getMapValue(vo, "lecteurs", encode: true), 0), - 1); - final hasVf = MBridge.isEmptyOrIsNotEmpty( - MBridge.jsonDecodeToList( - MBridge.getMapValue(vf, "lecteurs", encode: true), 0), - 1); - String title = MBridge.getMapValue(animeJson, "title", 0); - final genre = MBridge.jsonDecodeToList( - MBridge.getMapValue(animeJson, "themes", 1), 0); - final description = MBridge.getMapValue(animeJson, "description", 0); - final status = MBridge.parseStatus( - MBridge.getMapValue(animeJson, "status", 0), statusList); - final imageUrl = MBridge.getMapValue(animeJson, "affiche", 0); - if (hasVostfr) { - for (int i = 0; i < seasons.length; i++) { - int ind = i + 1; - - anime.genre = genre; - anime.description = description; - String seasonTitle = title; - if (seasons.length > 1) { - seasonTitle += " S$ind"; - } - if (hasVostfr) { - seasonTitle += " VOSTFR"; - } - anime.status = status; - anime.name = seasonTitle; - anime.imageUrl = imageUrl; - anime.link = - "/anime/${MBridge.regExp(titleO, "[^A-Za-z0-9 ]", "", 0, 0).replaceAll(" ", "-").toLowerCase()}?lang=vo&s=$ind"; - ind++; - } - } else if (hasVf) { - for (int i = 0; i < seasons.length; i++) { - int ind = i + 1; - anime.genre = genre; - anime.description = description; - String seasonTitle = title; - if (seasons.length > 1) { - seasonTitle += " S$ind"; - } - if (hasVf) { - seasonTitle += " VF"; - } - anime.status = status; - anime.name = seasonTitle; - anime.imageUrl = imageUrl; - anime.link = - "/anime/${MBridge.regExp(titleO, "[^A-Za-z0-9 ]", "", 0, 0).replaceAll(" ", "-").toLowerCase()}?lang=vf&s=$ind"; - ind++; - } - } - animeList.add(anime); - } - - index++; - } - return animeList; -} - -getVideoList(MangaModel anime) async { - String language = "vo".toString(); - String videoBaseUrl = "https://api.franime.fr/api/anime".toString(); - if (anime.link.contains("lang=")) { - language = MBridge.listParse( - MBridge.listParse(anime.link.split("lang="), 2)[0].split("&"), 1)[0]; - print(language); - } - String stem = MBridge.listParse( - MBridge.listParse(anime.link.split("/"), 2)[0].split("?"), 1)[0]; - final res = await dataBase(anime.sourceId); - final animeByTitleOJson = databaseAnimeByTitleO(res, stem); - final animeId = MBridge.getMapValue(animeByTitleOJson, "id", 0); - videoBaseUrl += "/$animeId/"; - - String seasonsJson = - MBridge.jsonPathToList(animeByTitleOJson, r'$..saisons', 1)[0]; - List seasons = MBridge.jsonDecodeToList(seasonsJson, 1); - if (anime.link.contains("s=")) { - int seasonNumber = MBridge.intParse(MBridge.listParse( - MBridge.listParse(anime.link.split("s="), 2)[0].split("&"), 1)[0]); - print(seasonNumber); - videoBaseUrl += "${seasonNumber - 1}/"; - seasonsJson = MBridge.listParse(seasons, 0)[seasonNumber - 1]; - } else { - seasonsJson = MBridge.listParse(seasons, 0)[0]; - videoBaseUrl += "0/"; - } - final episodesJson = - MBridge.jsonPathToList(seasonsJson, r'$..episodes', 1)[0]; - List episodes = MBridge.jsonDecodeToList(episodesJson, 1); - String episode = "".toString(); - if (anime.link.contains("ep=")) { - int episodeNumber = - MBridge.intParse(MBridge.listParse(anime.link.split("ep="), 2)[0]); - print(episodeNumber); - episode = MBridge.listParse(episodes, 0)[episodeNumber - 1]; - videoBaseUrl += "${episodeNumber - 1}"; - } else { - episode = MBridge.listParse(episodes, 0)[0]; - videoBaseUrl += "0"; - } - final lang = MBridge.getMapValue(episode, "lang", encode: true); - final vo = MBridge.getMapValue(lang, "vo", encode: true); - final vf = MBridge.getMapValue(lang, "vf", encode: true); - final vostfrPlayers = MBridge.jsonDecodeToList( - MBridge.getMapValue(vo, "lecteurs", encode: true), 0); - final vfPlayers = MBridge.jsonDecodeToList( - MBridge.getMapValue(vf, "lecteurs", encode: true), 0); - final hasVostfr = MBridge.isEmptyOrIsNotEmpty(vostfrPlayers, 1); - final hasVf = MBridge.isEmptyOrIsNotEmpty(vfPlayers, 1); - List players = []; - if (language == "vo" && hasVostfr) { - players = vostfrPlayers; - print(players); - } else if (language == "vf" && hasVf) { - players = vfPlayers; - print(players); - } - List videos = []; - for (int i = 0; i < players.length; i++) { - String apiUrl = "$videoBaseUrl/$language/$i"; - String playerName = MBridge.listParse(players, 0)[i]; - final data = { - "url": apiUrl, - "headers": {"Referer": "https://franime.fr/"}, - "sourceId": anime.sourceId - }; - final playerUrl = await MBridge.http('GET', json.encode(data)); - List a = []; - if (playerName.contains("franime_myvi")) { - videos.add( - MBridge.toVideo(playerUrl, "FRAnime", playerUrl, null, null, null)); - } else if (playerName.contains("myvi")) { - a = await MBridge.myTvExtractor(playerUrl); - } else if (playerName.contains("sendvid")) { - a = await MBridge.sendVidExtractor( - playerUrl, json.encode({"Referer": "https://franime.fr/"}), ""); - } else if (playerName.contains("sibnet")) { - a = await MBridge.sibnetExtractor(playerUrl); - } else if (playerName.contains("sbfull")) {} - for (var vi in a) { - videos.add(vi); - } - } - - return videos; -} diff --git a/anime/src/fr/franime/franime-v0.0.22.dart b/anime/src/fr/franime/franime-v0.0.22.dart new file mode 100644 index 00000000..082fd929 --- /dev/null +++ b/anime/src/fr/franime/franime-v0.0.22.dart @@ -0,0 +1,382 @@ +import 'dart:convert'; +import 'package:bridge_lib/bridge_lib.dart'; + +Future dataBase(int sourceId) async { + final data = { + "url": "https://api.franime.fr/api/animes/", + "headers": {"Referer": "https://franime.fr/"} + }; + final res = await MBridge.http('GET', json.encode(data)); + return res; +} + +getPopularAnime(MangaModel anime) async { + final data = { + "url": "https://api.franime.fr/api/animes/", + "headers": {"Referer": "https://franime.fr/"} + }; + final res = await MBridge.http('GET', json.encode(data)); + if (res.isEmpty) { + return anime; + } + List animeList = animeResList(res); + + return animeList; +} + +List animeResList(String res) { + final statusList = [ + {"EN COURS": 0, "TERMINÉ": 1} + ]; + List animeList = []; + + var jsonResList = json.decode(res); + + for (var animeJson in jsonResList) { + final seasons = animeJson["saisons"]; + List vostfrListName = []; + List vfListName = []; + for (var season in seasons) { + for (var episode in season["episodes"]) { + final lang = episode["lang"]; + final vo = lang["vo"]; + final vf = lang["vf"]; + vostfrListName.add(vo["lecteurs"].isNotEmpty); + vfListName.add(vf["lecteurs"].isNotEmpty); + } + } + + final titleO = animeJson["titleO"]; + final title = animeJson["title"]; + final genre = animeJson["themes"]; + final description = animeJson["description"]; + final status = MBridge.parseStatus(animeJson["status"], statusList); + final imageUrl = animeJson["affiche"]; + bool hasVostfr = vostfrListName.contains(true); + bool hasVf = vfListName.contains(true); + if (hasVostfr || hasVf) { + for (int i = 0; i < seasons.length; i++) { + MangaModel anime = MangaModel(); + int ind = i + 1; + anime.genre = genre; + anime.description = description; + String seasonTitle = "".toString(); + String lang = ""; + if (title.isEmpty) { + seasonTitle = titleO; + } else { + seasonTitle = title; + } + if (seasons.length > 1) { + seasonTitle += " S$ind"; + } + if (hasVf) { + seasonTitle += " VF"; + lang = "vf".toString(); + } + if (hasVostfr) { + seasonTitle += " VOSTFR"; + lang = "vo".toString(); + } + + anime.status = status; + anime.name = seasonTitle; + anime.imageUrl = imageUrl; + anime.link = + "/anime/${MBridge.regExp(titleO, "[^A-Za-z0-9 ]", "", 0, 0).replaceAll(" ", "-").toLowerCase()}?lang=$lang&s=$ind"; + + animeList.add(anime); + } + } + } + return animeList; +} + +String databaseAnimeByTitleO(String res, String titleO) { + final datas = MBridge.jsonDecodeToList(res, 1); + for (var data in datas) { + if (MBridge.regExp( + MBridge.getMapValue(data, "titleO"), "[^A-Za-z0-9 ]", "", 0, 0) + .replaceAll(" ", "-") + .toLowerCase() == + "${titleO}") { + return data; + } + } + return ""; +} + +getAnimeDetail(MangaModel anime) async { + String language = "vo".toString(); + if (anime.link.contains("lang=")) { + language = MBridge.substringBefore( + MBridge.substringAfter(anime.link, "lang="), "&"); + } + String stem = + MBridge.substringBefore(MBridge.substringAfterLast(anime.link, "/"), "?"); + final res = await dataBase(anime.sourceId); + if (res.isEmpty) { + return anime; + } + final animeByTitleOJson = databaseAnimeByTitleO(res, stem); + if (animeByTitleOJson.isEmpty) { + return anime; + } + final seasons = json.decode(animeByTitleOJson)["saisons"]; + + var seasonsJson = seasons.first; + + if (anime.link.contains("s=")) { + int seasonNumber = MBridge.intParse( + MBridge.substringBefore(MBridge.substringAfter(anime.link, "s="), "&")); + seasonsJson = seasons[seasonNumber - 1]; + } + + final episodes = seasonsJson["episodes"]; + + List episodesNames = []; + List episodesUrls = []; + for (int i = 0; i < episodes.length; i++) { + final episode = episodes[i]; + + final lang = episode["lang"]; + + final vo = lang["vo"]; + final vf = lang["vf"]; + bool hasVostfr = vo["lecteurs"].isNotEmpty; + bool hasVf = vf["lecteurs"].isNotEmpty; + bool playerIsNotEmpty = false; + + if (language == "vo" && hasVostfr) { + playerIsNotEmpty = true; + } else if (language == "vf" && hasVf) { + playerIsNotEmpty = true; + } + if (playerIsNotEmpty) { + episodesUrls.add("${anime.link}&ep=${i + 1}"); + String title = episode["title"]; + episodesNames.add(title.replaceAll('"', "")); + } + } + + anime.urls = episodesUrls.reversed.toList(); + anime.names = episodesNames.reversed.toList(); + anime.chaptersDateUploads = []; + return anime; +} + +getLatestUpdatesAnime(MangaModel anime) async { + final res = await dataBase(anime.sourceId); + + if (res.isEmpty) { + return anime; + } + List list = json.decode(res); + List reversedList = list.reversed.toList(); + List animeList = animeResList(json.encode(reversedList)); + + return animeList; +} + +searchAnime(MangaModel anime) async { + final res = await dataBase(anime.sourceId); + + if (res.isEmpty) { + return anime; + } + List animeList = animeSeachFetch(res, anime.query); + return animeList; +} + +List animeSeachFetch(String res, query) { + final statusList = [ + {"EN COURS": 0, "TERMINÉ": 1} + ]; + List animeList = []; + final jsonResList = json.decode(res); + for (var animeJson in jsonResList) { + MangaModel anime = MangaModel(); + + final titleO = MBridge.getMapValue(json.encode(animeJson), "titleO"); + final titleAlt = + MBridge.getMapValue(json.encode(animeJson), "titles", encode: true); + final enContains = MBridge.getMapValue(titleAlt, "en") + .toString() + .toLowerCase() + .contains(query); + final enJpContains = MBridge.getMapValue(titleAlt, "en_jp") + .toString() + .toLowerCase() + .contains(query); + final jaJpContains = MBridge.getMapValue(titleAlt, "ja_jp") + .toString() + .toLowerCase() + .contains(query); + final titleOContains = titleO.toLowerCase().contains(query); + bool contains = false; + if (enContains) { + contains = true; + } + if (enJpContains) { + contains = true; + } + if (jaJpContains) { + contains = true; + } + if (titleOContains) { + contains = true; + } + if (contains) { + final seasons = animeJson["saisons"]; + List vostfrListName = []; + List vfListName = []; + for (var season in seasons) { + for (var episode in season["episodes"]) { + final lang = episode["lang"]; + final vo = lang["vo"]; + final vf = lang["vf"]; + vostfrListName.add(vo["lecteurs"].isNotEmpty); + vfListName.add(vf["lecteurs"].isNotEmpty); + } + } + final titleO = animeJson["titleO"]; + final title = animeJson["title"]; + final genre = animeJson["themes"]; + final description = animeJson["description"]; + final status = MBridge.parseStatus(animeJson["status"], statusList); + final imageUrl = animeJson["affiche"]; + + bool hasVostfr = vostfrListName.contains(true); + bool hasVf = vfListName.contains(true); + if (hasVostfr || hasVf) { + for (int i = 0; i < seasons.length; i++) { + MangaModel anime = MangaModel(); + int ind = i + 1; + anime.genre = genre; + anime.description = description; + String seasonTitle = "".toString(); + String lang = ""; + if (title.isEmpty) { + seasonTitle = titleO; + } else { + seasonTitle = title; + } + if (seasons.length > 1) { + seasonTitle += " S$ind"; + } + if (hasVf) { + seasonTitle += " VF"; + lang = "vf".toString(); + } + if (hasVostfr) { + seasonTitle += " VOSTFR"; + lang = "vo".toString(); + } + + anime.status = status; + anime.name = seasonTitle; + anime.imageUrl = imageUrl; + anime.link = + "/anime/${MBridge.regExp(titleO, "[^A-Za-z0-9 ]", "", 0, 0).replaceAll(" ", "-").toLowerCase()}?lang=$lang&s=$ind"; + + animeList.add(anime); + } + } + } + } + return animeList; +} + +getVideoList(MangaModel anime) async { + String language = "vo".toString(); + String videoBaseUrl = "https://api.franime.fr/api/anime".toString(); + if (anime.link.contains("lang=")) { + language = MBridge.substringBefore( + MBridge.substringAfter(anime.link, "lang="), "&"); + print(language); + } + String stem = + MBridge.substringBefore(MBridge.substringAfterLast(anime.link, "/"), "?"); + final res = await dataBase(anime.sourceId); + if (res.isEmpty) { + return anime; + } + final animeByTitleOJson = databaseAnimeByTitleO(res, stem); + if (animeByTitleOJson.isEmpty) { + return anime; + } + final animeId = json.decode(animeByTitleOJson)["id"]; + final seasons = json.decode(animeByTitleOJson)["saisons"]; + + var seasonsJson = seasons.first; + + videoBaseUrl += "/$animeId/"; + + if (anime.link.contains("s=")) { + int seasonNumber = MBridge.intParse( + MBridge.substringBefore(MBridge.substringAfter(anime.link, "s="), "&")); + print(seasonNumber); + videoBaseUrl += "${seasonNumber - 1}/"; + seasonsJson = seasons[seasonNumber - 1]; + } else { + videoBaseUrl += "0/"; + } + final episodesJson = seasonsJson["episodes"]; + var episode = episodesJson.first; + if (anime.link.contains("ep=")) { + int episodeNumber = + MBridge.intParse(MBridge.substringAfter(anime.link, "ep=")); + print(episodeNumber); + episode = episodesJson[episodeNumber - 1]; + videoBaseUrl += "${episodeNumber - 1}"; + } else { + videoBaseUrl += "0"; + } + final lang = episode["lang"]; + + final vo = lang["vo"]; + final vf = lang["vf"]; + bool hasVostfr = vo["lecteurs"].isNotEmpty; + bool hasVf = vf["lecteurs"].isNotEmpty; + List vostfrPlayers = vo["lecteurs"]; + List vfPlayers = vf["lecteurs"]; + List players = []; + if (language == "vo" && hasVostfr) { + players = vostfrPlayers; + } else if (language == "vf" && hasVf) { + players = vfPlayers; + } + List videos = []; + for (var i = 0; i < players.length; i++) { + String apiUrl = "$videoBaseUrl/$language/$i"; + String playerName = players[i]; + + VideoModel video = VideoModel(); + + final data = { + "url": apiUrl, + "headers": {"Referer": "https://franime.fr/"}, + "sourceId": anime.sourceId + }; + final playerUrl = await MBridge.http('GET', json.encode(data)); + List a = []; + if (playerName.contains("franime_myvi")) { + videos.add(video + ..url = playerUrl + ..originalUrl = playerUrl + ..quality = "FRAnime"); + } else if (playerName.contains("myvi")) { + a = await MBridge.myTvExtractor(playerUrl); + } else if (playerName.contains("sendvid")) { + a = await MBridge.sendVidExtractor( + playerUrl, json.encode({"Referer": "https://franime.fr/"}), ""); + } else if (playerName.contains("sibnet")) { + a = await MBridge.sibnetExtractor(playerUrl); + } else if (playerName.contains("sbfull")) {} + for (var vi in a) { + videos.add(vi); + } + } + + return videos; +} diff --git a/anime/src/fr/franime/source.dart b/anime/src/fr/franime/source.dart index 30a8ed06..89b04178 100644 --- a/anime/src/fr/franime/source.dart +++ b/anime/src/fr/franime/source.dart @@ -2,7 +2,7 @@ import '../../../../model/source.dart'; import '../../../../utils/utils.dart'; Source get franimeSource => _franimeSource; -const franimeVersion = "0.0.21"; +const franimeVersion = "0.0.22"; const franimeSourceCodeUrl = "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/fr/franime/franime-v$franimeVersion.dart"; Source _franimeSource = Source( @@ -15,5 +15,4 @@ Source _franimeSource = Source( sourceCodeUrl: franimeSourceCodeUrl, version: franimeVersion, isManga: false, - appMinVerReq: "0.0.4", isFullData: true); diff --git a/icons/mangayomi-ar-okanime.png b/icons/mangayomi-ar-okanime.png new file mode 100644 index 00000000..6057076d Binary files /dev/null and b/icons/mangayomi-ar-okanime.png differ