From 73ef273e69e30bce1c71c9f21aa5295047819c7d Mon Sep 17 00:00:00 2001 From: kodjomoustapha <107993382+kodjodevf@users.noreply.github.com> Date: Wed, 3 Jan 2024 10:55:41 +0100 Subject: [PATCH] New source: AniFlix (DE) --- anime/source_generator.dart | 4 +- anime/src/de/aniflix/aniflix.dart | 240 ++++++++++++++++++++++++++++++ anime/src/de/aniflix/icon.png | Bin 0 -> 3487 bytes anime/src/de/aniflix/source.dart | 16 ++ 4 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 anime/src/de/aniflix/aniflix.dart create mode 100644 anime/src/de/aniflix/icon.png create mode 100644 anime/src/de/aniflix/source.dart diff --git a/anime/source_generator.dart b/anime/source_generator.dart index 1227d430..7ba2e412 100644 --- a/anime/source_generator.dart +++ b/anime/source_generator.dart @@ -6,6 +6,7 @@ import 'multisrc/datalifeengine/sources.dart'; import 'multisrc/dopeflix/sources.dart'; import 'multisrc/zorotheme/sources.dart'; import 'src/ar/okanime/source.dart'; +import 'src/de/aniflix/source.dart'; import 'src/en/aniwave/source.dart'; import 'src/en/dramacool/source.dart'; import 'src/en/gogoanime/source.dart'; @@ -44,7 +45,8 @@ void main() { dramacoolSource, yomoviesSource, animesamaSource, - nineanimetv + nineanimetv, + aniflix ]; final List> jsonList = _sourcesList.map((source) => source.toJson()).toList(); diff --git a/anime/src/de/aniflix/aniflix.dart b/anime/src/de/aniflix/aniflix.dart new file mode 100644 index 00000000..f8820e57 --- /dev/null +++ b/anime/src/de/aniflix/aniflix.dart @@ -0,0 +1,240 @@ +import 'package:mangayomi/bridge_lib.dart'; +import 'dart:convert'; + +class AniFlix extends MProvider { + AniFlix(); + + @override + Future getPopular(MSource source, int page) async { + final headers = getHeader(source.baseUrl); + final data = { + "url": "${source.baseUrl}/api/show/new/${page - 1}", + "headers": headers + }; + final res = await http('GET', json.encode(data)); + + return parseAnimeList(res, source.baseUrl, true); + } + + @override + Future getLatestUpdates(MSource source, int page) async { + final headers = getHeader(source.baseUrl); + final data = { + "url": "${source.baseUrl}/api/show/airing/${page - 1}", + "headers": headers + }; + final res = await http('GET', json.encode(data)); + final datas = json.decode(res); + List animeList = []; + List ids = []; + for (var data in datas) { + final anim = data["season"]["show"]; + if (!ids.contains(anim["id"])) { + ids.add(anim["id"]); + MManga anime = MManga(); + anime.name = anim["name"]; + anime.imageUrl = + "${source.baseUrl}/storage/" + (anim["cover_portrait"] ?? ""); + anime.link = + getUrlWithoutDomain("${source.baseUrl}/api/show/${anim['url']}"); + anime.description = anim["description"]; + if (anim["airing"] == 0) { + anime.status = MStatus.completed; + } else if (anim["airing"] == 1) { + anime.status = MStatus.ongoing; + } + animeList.add(anime); + } + } + return MPages(animeList, true); + } + + @override + Future search( + MSource source, String query, int page, FilterList filterList) async { + final data = { + "url": "${source.baseUrl}/api/show/search", + "body": {"search": query}, + "headers": { + 'Referer': source.baseUrl, + 'Accept': 'application/json', + 'Content-Type': 'application/json' + } + }; + final res = await http('POST', json.encode(data)); + return parseAnimeList(res, source.baseUrl, false); + } + + @override + Future getDetail(MSource source, String url) async { + final data = {"url": "${source.baseUrl}$url"}; + + final res = await http('GET', json.encode(data)); + MManga anime = MManga(); + final jsonRes = json.decode(res); + anime.name = jsonRes["name"]; + if (jsonRes["cover_portrait"] != null) { + anime.imageUrl = "${source.baseUrl}/storage/" + jsonRes["cover_portrait"]; + } + anime.description = jsonRes["description"]; + anime.genre = (jsonRes["genres"] as List>) + .map((e) => e["name"]) + .toList(); + var seasons = jsonRes["seasons"]; + final animeUrl = jsonRes["url"]; + List? episodesList = []; + for (var season in seasons) { + List> episodes = season["episodes"]; + for (var episode in episodes) { + String name = episode["name"] ?? ""; + if (name.toLowerCase().contains("folge") || + name.toLowerCase().contains("episode")) { + name = ""; + } else { + name = ": $name"; + } + MChapter ep = MChapter(); + ep.name = "Staffel ${season["number"]} Folge ${episode["number"]}$name"; + ep.url = + "/api/episode/show/$animeUrl/season/${season["number"]}/episode/${episode["number"]}"; + episodesList.add(ep); + } + } + + anime.chapters = episodesList.reversed.toList(); + return anime; + } + + @override + Future> getVideoList(MSource source, String url) async { + final headers = getHeader(source.baseUrl); + final data = {"url": "${source.baseUrl}$url", "headers": headers}; + final res = await http('GET', json.encode(data)); + final jsonRes = json.decode(res)["streams"]; + List videos = []; + final hosterSelection = preferenceHosterSelection(source.id); + for (var stream in jsonRes) { + List a = []; + String quality = '${stream["hoster"]["name"]} - ${stream["lang"]}'; + String link = stream["link"]; + print(link); + if (link.contains("https://dood") && + hosterSelection.contains("doodstream")) { + a = await doodExtractor(link, quality); + } else if (link.contains("https://streamtape") && + hosterSelection.contains("streamtape")) { + a = await streamTapeExtractor(link, quality); + } else if (link.contains("https://voe.sx") && + hosterSelection.contains("voe")) { + a = await voeExtractor(link, quality); + } else if (link.contains("https://streamlare") && + hosterSelection.contains("streamlare")) { + a = await streamlareExtractor(link, quality, '', ''); + } + videos.addAll(a); + } + + return sortVideos(videos, source.id); + } + + String getUrlWithoutDomain(String orig) { + final uri = Uri.parse(orig.replaceAll(' ', '%20')); + String out = uri.path; + if (uri.query.isNotEmpty) { + out += '?${uri.query}'; + } + if (uri.fragment.isNotEmpty) { + out += '#${uri.fragment}'; + } + return out; + } + + MPages parseAnimeList(String res, String baseUrl, bool hasNextPage) { + final datas = json.decode(res); + List animeList = []; + + for (var data in datas) { + MManga anime = MManga(); + anime.name = data["name"]; + anime.imageUrl = "$baseUrl/storage/" + (data["cover_portrait"] ?? ""); + anime.link = getUrlWithoutDomain("$baseUrl/api/show/${data['url']}"); + anime.description = data["description"]; + if (data["airing"] == 0) { + anime.status = MStatus.completed; + } else if (data["airing"] == 1) { + anime.status = MStatus.ongoing; + } + animeList.add(anime); + } + return MPages(animeList, hasNextPage); + } + + List sortVideos(List videos, int sourceId) { + print(videos.length); + String hoster = getPreferenceValue(sourceId, "preferred_hoster"); + String sub = getPreferenceValue(sourceId, "preferred_sub"); + videos.sort((MVideo a, MVideo b) { + int hosterMatchA = 0; + if (a.url.toLowerCase().contains(hoster.toLowerCase()) && + a.quality.toLowerCase().contains(sub.toLowerCase())) { + hosterMatchA = 1; + } + int hosterMatchB = 0; + if (b.url.toLowerCase().contains(hoster.toLowerCase()) && + b.quality.toLowerCase().contains(sub.toLowerCase())) { + hosterMatchB = 1; + } + return hosterMatchB - hosterMatchA; + }); + return videos; + } + + List preferenceHosterSelection(int sourceId) { + return getPreferenceValue(sourceId, "hoster_selectionn"); + } + + @override + List getSourcePreferences(MSource source) { + return [ + ListPreference( + key: "preferred_hoster", + title: "Standard-Hoster", + summary: "", + valueIndex: 0, + entries: [ + "Streamtape", + "Doodstream", + "Voe", + "Streamlare" + ], + entryValues: [ + "https://streamtape.com", + "https://dood", + "https://voe.sx", + "https://streamlare.com" + ]), + ListPreference( + key: "preferred_sub", + title: "Standardmäßig Sub oder Dub?", + summary: "", + valueIndex: 0, + entries: ["Sub", "Dub"], + entryValues: ["Sub", "Dub"]), + MultiSelectListPreference( + key: "hoster_selectionn", + title: "Hoster auswählen", + summary: "", + entries: ["Streamtape", "Doodstream", "Voe", "Streamlare"], + entryValues: ["streamtape", "doodstream", "voe", "streamlare"], + values: ["streamtape", "doodstream", "voe", "streamlare"]), + ]; + } +} + +Map getHeader(String url) { + return {'Referer': url}; +} + +AniFlix main() { + return AniFlix(); +} diff --git a/anime/src/de/aniflix/icon.png b/anime/src/de/aniflix/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..cd1812728b70621d623e0e8bbd27959bf389c3b9 GIT binary patch literal 3487 zcmV;Q4Pf$#P)@9%I{RlYgn#W^a;bz63|e!q~ymx-pLCu zywEUzaBz@q+qUt}JMZ8)wf~J*UU`K#-uNdVTKw{ZAN&q4zx;AdnGcQ~o)1o(U|T`amNwB_C{-o6Scsxb zf{95GvB2XrC8|geae53zlrBU>ThmzS}IfG(G> zx@S~6B+uyhs#=%!##f4xxxMwtcZ2}XbJ?+D#|_III&_H6&d!E;)22N+hM z8XTnQ=*Lm3_7o@ya@4CBz{rY1pksko8fp~@b%GXEWvYIcNhsGR1%ZY)`lpx=xc~lz zY}~kU%>47`&*S?(OO`CTfd+t-f=3?NP?vx7@L?VpGT;h^l;D?sAvOu7#td{yNskFD zcKY`-iZ&_88~DqCu;L@udV<4&t|-XHCipE+@XG-W5>f_s&J;*ulVnV+1@NCkl8YrV zbqG*OvSY_{b(;HS%Rk5ndf0 zsw=ZxDn3<;w@Xnp)hYx(&A1R44wf{pUN2S3{&|bTs{=_iHAhK~6%4QTM+E(_rEDq$ z=-3~`TJT!m#Fk7=x(RA-ZsM6|o~cX!@WT%)0>6>{kLqYfO392FEv#9yrY_&#*Nf)@ zDaC$WYFNhx$Dun&^42>F72E%=Lb994MX=hd6+;^M>w!r49`MqPcp-Sj$4Bq+X%V{f zQ>-JldGn*pojbQK{p87$kq^_FqeqYO&_fT6Sw}XT1z_E}b-1oulXvO-dFGzE5QUv7 z#s1PrC2zIkva6+)UDI3G=sH}ja*W?{or(bW`^mEXZ@L08YW>un>xN6QLhP6(nD18k z29fxK*ZakUw+2lr0jZS7jvdd9DSUuar%o|z)+}buoOwe6T-Ra!`g$$t>B-Sql8|xv z0yq~Y!u*bxVr?qTTG!)LSi5I#ljDF9d>$A+(^bTz6hou7*X@n_fUXeiY>OATX=> z;(C0pLxzN)tCSG4SV$Hs1x9e7G>Vv%B0ow4$|2>mO@jLznM6Y6@YBG*4hRNAGj#}1 zO7i^kJCLKo!F)c?o;`b5wrtr=!_Q<0Bh9_{-dh(X=`e%??;|o2Jcq7gp(g*ufqpuF z)5nQYz;T@ru*r2RLfki!q|Xq7)l%}+7=rv!iyGBG5S9DCzc$4NeBc>3w5>(ck^ z*@KjdIdkSPJUq1#M?fPp^_#9;}{;CjED48`%YcT}G-}wo{INWb6Y1*z0S~2a|g$!-O;DNew#RI*hvuRMUZzx~mWFJmPa|Ho#Xk@tV*+tUf ze{>T4c)(|2Ks?%jC*XHeF2!mBMErs}>HYrQz~mo@G9eA{Jdf?$x8Jm!F^1mWUUu%> zS(n${-OcduFvb|poH@gS1q(>0)3sW1`7*Q4eF@WAK`ORQYh`n`1x!c=$SPUsK>fw+ z1z>a>xr7zx>W2Z}PNl&Zn$V=ttct_aX~Hl^D!%O*?sGDL!6{G9h{*Pz3k~lTrx*dt zm$x?@(=o=dckf=b)^v1q(BI!rCX->_ym@uy4jg!oQmI53hGRxaJv}{iIvH@HXy&0z zb3DW>K!@c(os5(`*3_H~P3tfs10W2d-#P@XBXTNQ5rvrxrNcs{lj+AWp1L%Gf5?Y- z zAuA^#O{%JAt4J`l^TMy??@a5zZ6A zvZj2gRHCP+r_##befM2DIy&m=JaFJW9uy9jv;iGJ7)F9Ccead)>^m}cx}(FycrZts z#2=LBbWQ9lj7ajRa=t=yI?#L&+_~f6ZZ@B$09spHSGjKHAkhgR+HsUjrM!j@Xl*DK zM=-{a$wX6-#+Zg3wPJCEFw{sX@jMqPMV(L4+E6GI`9A^;NMrPn?-w=?4h|lnsw+2X z8W02_K~T79xk6!lLxx&wip3G`M%cBXmHp{ZLA^RtPau2;ow7e9>KI z?}afYFvj$SVQ^$*#D8sMWaz(v0pKc=^d-G=IS;r8XabrX$C>83>A6bb-o-vagdwF; zsdzaEf _aniflix; +const _aniflixVersion = "0.0.1"; +const _aniflixCodeUrl = + "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/anime/src/de/aniflix/aniflix.dart"; +Source _aniflix = Source( + name: "Aniflix", + baseUrl: "https://aniflix.cc", + lang: "de", + typeSource: "single", + iconUrl: + "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/anime/src/de/aniflix/icon.png", + sourceCodeUrl: _aniflixCodeUrl, + version: _aniflixVersion, + isManga: false);