From a77d1454d80d7e693b3b13bf84039e37ea2663f7 Mon Sep 17 00:00:00 2001 From: Swakshan Date: Sun, 16 Mar 2025 22:20:40 +0530 Subject: [PATCH 1/4] extension(animez): Added popular, latest & search --- javascript/anime/src/en/animez.js | 163 ++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 javascript/anime/src/en/animez.js diff --git a/javascript/anime/src/en/animez.js b/javascript/anime/src/en/animez.js new file mode 100644 index 00000000..349da037 --- /dev/null +++ b/javascript/anime/src/en/animez.js @@ -0,0 +1,163 @@ +const mangayomiSources = [{ + "name": "AnimeZ", + "lang": "en", + "baseUrl": "https://animez.org", + "apiUrl": "", + "iconUrl": "https://www.google.com/s2/favicons?sz=256&domain=https://animez.org/", + "typeSource": "multi", + "itemType": 1, + "version": "0.0.1", + "pkgPath": "anime/src/en/animez.js" +}]; + +class DefaultExtension extends MProvider { + constructor() { + super(); + this.client = new Client(); + } + + getHeaders(url) { + return { + "Referer": this.source.baseUrl, + } + } + + getPreference(key) { + return new SharedPreferences().get(key); + } + + async request(slug) { + var url = this.source.baseUrl + slug + var res = await this.client.get(url, this.getHeaders()); + return new Document(res.body); + } + async page(slug) { + var body = await this.request(slug) + var list = [] + var hasNextPage = false; + + var animes = body.select("li.TPostMv") + animes.forEach(anime => { + var link = anime.selectFirst("a").getHref + var name = anime.selectFirst('h2.Title').text; + var imageUrl = this.source.baseUrl + anime.selectFirst('img').getSrc; + + list.push({ name, link, imageUrl }); + }); + + var paginations = body.select(".pagination > li") + hasNextPage = paginations[paginations.length - 1].text == "Last" ? true : false + + return { list, hasNextPage } + } + + sortByPref(key){ + var sort = parseInt(this.getPreference(key)) + var sortBy = "hot" + switch(sort){ + case 1:{ + sortBy = "lastest-chap" + break; + }case 2:{ + sortBy = "hot" + break; + } + case 3:{ + sortBy = "lastest-manga" + break; + } + case 4:{ + sortBy = "top-manga" + break; + } + case 5:{ + sortBy = "top-month" + break; + } + case 6:{ + sortBy = "top-week" + break; + } + case 7:{ + sortBy = "top-day" + break; + } + case 8:{ + sortBy = "follow" + break; + } + case 9:{ + sortBy = "comment" + break; + } + case 10:{ + sortBy = "num-chap" + break; + } + } + return sortBy; + + } + + async getPopular(page) { + var sortBy = this.sortByPref("animez_pref_popular_section") + var slug = `/?act=search&f[status]=all&f[sortby]=${sortBy}&&pageNum=${page}` + return await this.page(slug) + + } + get supportsLatest() { + throw new Error("supportsLatest not implemented"); + } + async getLatestUpdates(page) { + var sortBy = this.sortByPref("animez_pref_latest_section") + var slug = `/?act=search&f[status]=all&f[sortby]=${sortBy}&&pageNum=${page}` + return await this.page(slug) + } + async search(query, page, filters) { + var slug = `/?act=search&f[status]=all&f[keyword]=${query}&&pageNum=${page}` + return await this.page(slug) + } + async getDetail(url) { + throw new Error("getDetail not implemented"); + } + // For novel html content + async getHtmlContent(url) { + throw new Error("getHtmlContent not implemented"); + } + // Clean html up for reader + async cleanHtmlContent(html) { + throw new Error("cleanHtmlContent not implemented"); + } + // For anime episode video list + async getVideoList(url) { + throw new Error("getVideoList not implemented"); + } + // For manga chapter pages + async getPageList(url) { + throw new Error("getPageList not implemented"); + } + getFilterList() { + throw new Error("getFilterList not implemented"); + } + getSourcePreferences() { + return [{ + key: 'animez_pref_popular_section', + listPreference: { + title: 'Preferred popular content', + summary: '', + valueIndex: 1, + entries: ["Latest update", "Hot", "New releases", "Top all","Top month","Top week","Top day","Top follow","Top comments","Number of episodes"], + entryValues: ["1", "2" ,"3", "4","5","6","7","8","9","10"] + } + },{ + key: 'animez_pref_latest_section', + listPreference: { + title: 'Preferred latest content', + summary: '', + valueIndex: 0, + entries: ["Latest update", "Hot", "New releases", "Top all","Top month","Top week","Top day","Top follow","Top comments","Number of episodes"], + entryValues: ["1", "2" ,"3", "4","5","6","7","8","9","10"] + } + },] + } +} From fb22d4b3e1484f520ee4b448eac7f1e487f474fe Mon Sep 17 00:00:00 2001 From: Swakshan Date: Mon, 17 Mar 2025 17:14:30 +0530 Subject: [PATCH 2/4] extension(animez): Added anime details --- javascript/anime/src/en/animez.js | 110 ++++++++++++++++++++++++------ 1 file changed, 90 insertions(+), 20 deletions(-) diff --git a/javascript/anime/src/en/animez.js b/javascript/anime/src/en/animez.js index 349da037..9ed85d5c 100644 --- a/javascript/anime/src/en/animez.js +++ b/javascript/anime/src/en/animez.js @@ -6,7 +6,7 @@ const mangayomiSources = [{ "iconUrl": "https://www.google.com/s2/favicons?sz=256&domain=https://animez.org/", "typeSource": "multi", "itemType": 1, - "version": "0.0.1", + "version": "0.0.2", "pkgPath": "anime/src/en/animez.js" }]; @@ -40,7 +40,7 @@ class DefaultExtension extends MProvider { animes.forEach(anime => { var link = anime.selectFirst("a").getHref var name = anime.selectFirst('h2.Title').text; - var imageUrl = this.source.baseUrl + anime.selectFirst('img').getSrc; + var imageUrl = this.source.baseUrl +"/"+ anime.selectFirst('img').getSrc; list.push({ name, link, imageUrl }); }); @@ -51,46 +51,46 @@ class DefaultExtension extends MProvider { return { list, hasNextPage } } - sortByPref(key){ + sortByPref(key) { var sort = parseInt(this.getPreference(key)) var sortBy = "hot" - switch(sort){ - case 1:{ + switch (sort) { + case 1: { sortBy = "lastest-chap" break; - }case 2:{ + } case 2: { sortBy = "hot" break; } - case 3:{ + case 3: { sortBy = "lastest-manga" break; } - case 4:{ + case 4: { sortBy = "top-manga" break; } - case 5:{ + case 5: { sortBy = "top-month" break; } - case 6:{ + case 6: { sortBy = "top-week" break; } - case 7:{ + case 7: { sortBy = "top-day" break; } - case 8:{ + case 8: { sortBy = "follow" break; } - case 9:{ + case 9: { sortBy = "comment" break; } - case 10:{ + case 10: { sortBy = "num-chap" break; } @@ -118,7 +118,77 @@ class DefaultExtension extends MProvider { return await this.page(slug) } async getDetail(url) { - throw new Error("getDetail not implemented"); + var link = this.source.baseUrl + url; + var body = await this.request(url); + var name = body.selectFirst("#title-detail-manga").text + var animeId = body.selectFirst("#title-detail-manga").attr("data-manga") + var genre = [] + body.select("li.AAIco-adjust")[3].select("a").forEach(g => genre.push(g.text)) + var description = body.selectFirst("#summary_shortened").text + + + var chapters = [] + var chapLen = 0 + var pageNum = 1 + var hasNextPage = true; + while(hasNextPage) { + var pageSlug = `?act=ajax&code=load_list_chapter&manga_id=${animeId}&page_num=${pageNum}&chap_id=0&keyword=` + var pageBody = await this.request(pageSlug); + var parsedBody = JSON.parse(pageBody.html); + var nav = parsedBody.nav + if(nav==null){ // if "nav" doesnt exists there is no next page + hasNextPage = false; + + }else{ + var navLi = new Document(nav).select(".page-link.next").length + if(navLi>0){ // if "nav" exists and has li.next then there is next page + pageNum++; + }else{// if "nav" exists and doesn't have li.next then there is no next page + hasNextPage = false; + } + } + + + var list_chap = new Document(parsedBody.list_chap).select('li.wp-manga-chapter') + + list_chap.forEach(chapter => { + var a = chapter.selectFirst("a") + var title = a.text + var epLink = a.getHref + var scanlator = "Sub" + if(title.indexOf("Dub")>0){ + title = title.replace("-Dub","") + scanlator = "Dub" + + } + var epData = { + name:title, + url:epLink, + scanlator + } + if(chapLen>0){ + var pos = chapLen -1 + var lastEntry = chapters[pos] + if(lastEntry.name == epData.name){ // if last entries name is same then append url and scanlator to last entry + chapters.pop() // remove the last entry + epData.url = `${epData.url} || ${lastEntry.url}` + epData.scanlator = `${lastEntry.scanlator}, ${epData.scanlator}` + chapLen = pos; // since the last entry is removed the chapLen will decrease + } + } + + chapters.push(epData) + chapLen++; + }) + + } + + return { + link, + description, + chapters, + genre, + }; } // For novel html content async getHtmlContent(url) { @@ -146,17 +216,17 @@ class DefaultExtension extends MProvider { title: 'Preferred popular content', summary: '', valueIndex: 1, - entries: ["Latest update", "Hot", "New releases", "Top all","Top month","Top week","Top day","Top follow","Top comments","Number of episodes"], - entryValues: ["1", "2" ,"3", "4","5","6","7","8","9","10"] + entries: ["Latest update", "Hot", "New releases", "Top all", "Top month", "Top week", "Top day", "Top follow", "Top comments", "Number of episodes"], + entryValues: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] } - },{ + }, { key: 'animez_pref_latest_section', listPreference: { title: 'Preferred latest content', summary: '', valueIndex: 0, - entries: ["Latest update", "Hot", "New releases", "Top all","Top month","Top week","Top day","Top follow","Top comments","Number of episodes"], - entryValues: ["1", "2" ,"3", "4","5","6","7","8","9","10"] + entries: ["Latest update", "Hot", "New releases", "Top all", "Top month", "Top week", "Top day", "Top follow", "Top comments", "Number of episodes"], + entryValues: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] } },] } From 060e7faba52a4221a747e540b61cb8e9b337e934 Mon Sep 17 00:00:00 2001 From: Swakshan Date: Mon, 17 Mar 2025 17:37:19 +0530 Subject: [PATCH 3/4] extension(animez): Added stream extraction --- javascript/anime/src/en/animez.js | 67 +++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/javascript/anime/src/en/animez.js b/javascript/anime/src/en/animez.js index 9ed85d5c..f076c377 100644 --- a/javascript/anime/src/en/animez.js +++ b/javascript/anime/src/en/animez.js @@ -6,7 +6,7 @@ const mangayomiSources = [{ "iconUrl": "https://www.google.com/s2/favicons?sz=256&domain=https://animez.org/", "typeSource": "multi", "itemType": 1, - "version": "0.0.2", + "version": "1.0.0", "pkgPath": "anime/src/en/animez.js" }]; @@ -171,7 +171,7 @@ class DefaultExtension extends MProvider { var lastEntry = chapters[pos] if(lastEntry.name == epData.name){ // if last entries name is same then append url and scanlator to last entry chapters.pop() // remove the last entry - epData.url = `${epData.url} || ${lastEntry.url}` + epData.url = `${epData.url}||${lastEntry.url}` epData.scanlator = `${lastEntry.scanlator}, ${epData.scanlator}` chapLen = pos; // since the last entry is removed the chapLen will decrease } @@ -190,25 +190,49 @@ class DefaultExtension extends MProvider { genre, }; } - // For novel html content - async getHtmlContent(url) { - throw new Error("getHtmlContent not implemented"); - } - // Clean html up for reader - async cleanHtmlContent(html) { - throw new Error("cleanHtmlContent not implemented"); + + // Sorts streams based on user preference. + sortStreams(streams) { + var sortedStreams = []; + + var copyStreams = streams.slice() + var pref = this.getPreference("animez_pref_stream_audio"); + for (var stream of streams) { + if (stream.quality.indexOf(pref) > -1) { + sortedStreams.push(stream); + var index = copyStreams.indexOf(stream); + if (index > -1) { + copyStreams.splice(index, 1); + } + break; + } + } + return [...sortedStreams, ...copyStreams] } + // For anime episode video list async getVideoList(url) { - throw new Error("getVideoList not implemented"); - } - // For manga chapter pages - async getPageList(url) { - throw new Error("getPageList not implemented"); - } - getFilterList() { - throw new Error("getFilterList not implemented"); + var linkSlugs = url.split("||") + var streams = []; + for(var slug of linkSlugs){ + var body = await this.request(slug) + var iframeSrc = body.selectFirst("iframe").getSrc + var streamLink = iframeSrc.replace("/embed/","/anime/") + var audio = slug.indexOf("dub-") > -1 ? "Dub" : "Sub" + + streams.push({ + url: streamLink, + originalUrl: streamLink, + quality: audio, + }) + } + + + return sortStreams(streams); + + } + getSourcePreferences() { return [{ key: 'animez_pref_popular_section', @@ -228,6 +252,15 @@ class DefaultExtension extends MProvider { entries: ["Latest update", "Hot", "New releases", "Top all", "Top month", "Top week", "Top day", "Top follow", "Top comments", "Number of episodes"], entryValues: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"] } + }, { + key: 'animez_pref_stream_audio', + listPreference: { + title: 'Preferred stream audio', + summary: '', + valueIndex: 0, + entries: ["Sub","Dub"], + entryValues: ["Sub","Dub"], + } },] } } From d0db616ff66ec2d4b4efa4939b1ede372d85f98c Mon Sep 17 00:00:00 2001 From: Swakshan Date: Mon, 17 Mar 2025 18:24:40 +0530 Subject: [PATCH 4/4] extension(animez): Better episode title --- javascript/anime/src/en/animez.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/javascript/anime/src/en/animez.js b/javascript/anime/src/en/animez.js index f076c377..430597ef 100644 --- a/javascript/anime/src/en/animez.js +++ b/javascript/anime/src/en/animez.js @@ -6,7 +6,7 @@ const mangayomiSources = [{ "iconUrl": "https://www.google.com/s2/favicons?sz=256&domain=https://animez.org/", "typeSource": "multi", "itemType": 1, - "version": "1.0.0", + "version": "1.0.1", "pkgPath": "anime/src/en/animez.js" }]; @@ -161,6 +161,7 @@ class DefaultExtension extends MProvider { scanlator = "Dub" } + title = title.indexOf("Movie") > -1? title : `Episode ${title}` var epData = { name:title, url:epLink,