From f28ae2e662d8a81d36c5cd4ca017d4e901d8b317 Mon Sep 17 00:00:00 2001 From: Swakshan Date: Fri, 28 Mar 2025 19:05:46 +0530 Subject: [PATCH 1/4] anime(Animeonsen): Added latest and latest --- javascript/anime/src/en/animeonsen.js | 144 ++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 javascript/anime/src/en/animeonsen.js diff --git a/javascript/anime/src/en/animeonsen.js b/javascript/anime/src/en/animeonsen.js new file mode 100644 index 00000000..24ee29d8 --- /dev/null +++ b/javascript/anime/src/en/animeonsen.js @@ -0,0 +1,144 @@ +const mangayomiSources = [{ + "name": "Animeonsen", + "lang": ["en", "ja"], + "baseUrl": "https://www.animeonsen.xyz", + "apiUrl": "https://api.animeonsen.xyz", + "iconUrl": "https://www.google.com/s2/favicons?sz=256&domain=https://www.animeonsen.xyz", + "typeSource": "single", + "itemType": 1, + "version": "0.0.1", + "pkgPath": "anime/src/all/animeonsen.js" +}]; + +class DefaultExtension extends MProvider { + constructor() { + super(); + this.client = new Client(); + } + + getPreference(key) { + return new SharedPreferences().get(key); + } + + async getToken() { + const preferences = new SharedPreferences(); + var token_ts = parseInt(preferences.getString("animeosen_token_expiry_at", "0")) + var now_ts = parseInt(new Date().getTime() / 1000); + + // token lasts for 7days but still checking after 6days + if (now_ts - token_ts > 60 * 60 * 24 * 6) { + var tokenBody = { + client_id: "f296be26-28b5-4358-b5a1-6259575e23b7", + client_secret: "349038c4157d0480784753841217270c3c5b35f4281eaee029de21cb04084235", + grant_type: "client_credentials" + } + var res = await this.client.post("https://auth.animeonsen.xyz/oauth/token", {}, tokenBody) + res = JSON.parse(res.body) + var token = res.access_token + preferences.setString("animeosen_token", token); + preferences.setString("animeosen_token_expiry_at", "" + now_ts); + return token + } else { + return preferences.getString("animeosen_token", ""); + + } + } + + async getHeaders(slug) { + var brToken = "" + if (slug.endsWith("/search")) { + brToken = "0e36d0275d16b40d7cf153634df78bc229320d073f565db2aaf6d027e0c30b13" + } + else { + brToken = await this.getToken() + } + + return { Authorization: `Bearer ${brToken}` } + } + + async request(slug, body = {}) { + var api = `${this.source.apiUrl}${slug}` + var headers = await this.getHeaders(api) + var res = await this.client.get(api, headers, body) + return JSON.parse(res.body) + } + + async getHome(page) { + var limit = 20 + var start = (page - 1) * limit; + + var slug = `/v4/content/index?start=${start}&limit=${limit}` + var res = await this.request(slug) + + var pref_name = this.getPreference("animeonsen__pref_title_lang") + var imgRes = this.getPreference("animeonsen__pref_img_res") + + var hasNextPage = res.cursor.next[0] + var list = [] + for (var anime of res.content) { + var name_eng = anime.content_title_en + var name_jp = anime.content_title + var name = pref_name == "jpn" ? name_jp : name_eng; + var link = anime.content_id + var imageUrl = `${this.source.apiUrl}/v4/image/${imgRes}/${link}` + list.push({ name, imageUrl, link }); + } + return { list, hasNextPage } + } + + async getPopular(page) { + return await this.getHome(page) + } + get supportsLatest() { + throw new Error("supportsLatest not implemented"); + } + async getLatestUpdates(page) { + return await this.getHome(page) + } + async search(query, page, filters) { + throw new Error("search not implemented"); + } + 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: 'animeonsen__pref_title_lang', + listPreference: { + title: 'Preferred title language', + summary: '', + valueIndex: 0, + entries: ["Japenese", "English"], + entryValues: ["jpn", "en"] + } + }, { + key: 'animeonsen__pref_img_res', + listPreference: { + title: 'Preferred image resolution', + summary: '', + valueIndex: 1, + entries: ["Low", "Medium", "High"], + entryValues: ["240x300", "480x600", "960x1200"] + } + }]; + } +} From f22116f1d9fb59f34644d74e0c0dc91091c4649e Mon Sep 17 00:00:00 2001 From: Swakshan Date: Fri, 28 Mar 2025 22:09:54 +0530 Subject: [PATCH 2/4] anime(Animeonsen): Added search --- javascript/anime/src/en/animeonsen.js | 66 +++++++++++++++++++++------ 1 file changed, 53 insertions(+), 13 deletions(-) diff --git a/javascript/anime/src/en/animeonsen.js b/javascript/anime/src/en/animeonsen.js index 24ee29d8..2239173d 100644 --- a/javascript/anime/src/en/animeonsen.js +++ b/javascript/anime/src/en/animeonsen.js @@ -6,7 +6,7 @@ const mangayomiSources = [{ "iconUrl": "https://www.google.com/s2/favicons?sz=256&domain=https://www.animeonsen.xyz", "typeSource": "single", "itemType": 1, - "version": "0.0.1", + "version": "0.0.2", "pkgPath": "anime/src/all/animeonsen.js" }]; @@ -19,7 +19,7 @@ class DefaultExtension extends MProvider { getPreference(key) { return new SharedPreferences().get(key); } - + async getToken() { const preferences = new SharedPreferences(); var token_ts = parseInt(preferences.getString("animeosen_token_expiry_at", "0")) @@ -53,16 +53,36 @@ class DefaultExtension extends MProvider { brToken = await this.getToken() } - return { Authorization: `Bearer ${brToken}` } + return { + 'Authorization': `Bearer ${brToken}`, + 'content-type': "application/json" + } } async request(slug, body = {}) { + + var headers = await this.getHeaders(slug) + + if (slug.endsWith("/search")) { + + var api = `https://search.animeonsen.xyz${slug}` + var res = await this.client.post(api, headers, body) + return JSON.parse(res.body) + } var api = `${this.source.apiUrl}${slug}` - var headers = await this.getHeaders(api) - var res = await this.client.get(api, headers, body) + var res = await this.client.get(api, headers) return JSON.parse(res.body) } + animeContent(anime, pref_name, imgRes) { + var name_eng = anime.content_title_en + var name_jp = anime.content_title + var name = pref_name == "jpn" ? name_jp : name_eng; + var link = anime.content_id + var imageUrl = `${this.source.apiUrl}/v4/image/${imgRes}/${link}` + return { name, imageUrl, link }; + } + async getHome(page) { var limit = 20 var start = (page - 1) * limit; @@ -72,16 +92,11 @@ class DefaultExtension extends MProvider { var pref_name = this.getPreference("animeonsen__pref_title_lang") var imgRes = this.getPreference("animeonsen__pref_img_res") - + var hasNextPage = res.cursor.next[0] var list = [] for (var anime of res.content) { - var name_eng = anime.content_title_en - var name_jp = anime.content_title - var name = pref_name == "jpn" ? name_jp : name_eng; - var link = anime.content_id - var imageUrl = `${this.source.apiUrl}/v4/image/${imgRes}/${link}` - list.push({ name, imageUrl, link }); + list.push(this.animeContent(anime, pref_name, imgRes)); } return { list, hasNextPage } } @@ -96,7 +111,32 @@ class DefaultExtension extends MProvider { return await this.getHome(page) } async search(query, page, filters) { - throw new Error("search not implemented"); + var slug = "/indexes/content/search" + + var limit = 30; + var offset = (page - 1) * limit; + var nextOffset = offset + limit; + + var params = { limit, offset, q: query }; + + var res = await this.request(slug, params); + + var estimatedTotalHits = res.estimatedTotalHits + var hasNextPage = estimatedTotalHits > nextOffset; + + var list = [] + var hits = res.hits + var pref_name = this.getPreference("animeonsen__pref_title_lang") + var imgRes = this.getPreference("animeonsen__pref_img_res") + if (hits.length > 0) { + for (var anime of hits) { + list.push(this.animeContent(anime, pref_name, imgRes)); + } + } + return { list, hasNextPage } + + + } async getDetail(url) { throw new Error("getDetail not implemented"); From 0c04b59d23d1b9349c293fdd14cbee68e1b369c7 Mon Sep 17 00:00:00 2001 From: Swakshan Date: Sat, 29 Mar 2025 13:13:38 +0530 Subject: [PATCH 3/4] anime(Animeonsen): Added details --- javascript/anime/src/en/animeonsen.js | 74 +++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 11 deletions(-) diff --git a/javascript/anime/src/en/animeonsen.js b/javascript/anime/src/en/animeonsen.js index 2239173d..d199b0a1 100644 --- a/javascript/anime/src/en/animeonsen.js +++ b/javascript/anime/src/en/animeonsen.js @@ -6,7 +6,7 @@ const mangayomiSources = [{ "iconUrl": "https://www.google.com/s2/favicons?sz=256&domain=https://www.animeonsen.xyz", "typeSource": "single", "itemType": 1, - "version": "0.0.2", + "version": "0.0.3", "pkgPath": "anime/src/all/animeonsen.js" }]; @@ -69,7 +69,7 @@ class DefaultExtension extends MProvider { var res = await this.client.post(api, headers, body) return JSON.parse(res.body) } - var api = `${this.source.apiUrl}${slug}` + var api = `${this.source.apiUrl}/v4/content${slug}` var res = await this.client.get(api, headers) return JSON.parse(res.body) } @@ -87,11 +87,11 @@ class DefaultExtension extends MProvider { var limit = 20 var start = (page - 1) * limit; - var slug = `/v4/content/index?start=${start}&limit=${limit}` + var slug = `/index?start=${start}&limit=${limit}` var res = await this.request(slug) var pref_name = this.getPreference("animeonsen__pref_title_lang") - var imgRes = this.getPreference("animeonsen__pref_img_res") + var imgRes = this.getPreference("animeonsen__pref_img_res_1") var hasNextPage = res.cursor.next[0] var list = [] @@ -127,19 +127,62 @@ class DefaultExtension extends MProvider { var list = [] var hits = res.hits var pref_name = this.getPreference("animeonsen__pref_title_lang") - var imgRes = this.getPreference("animeonsen__pref_img_res") + var imgRes = this.getPreference("animeonsen__pref_img_res_1") if (hits.length > 0) { for (var anime of hits) { list.push(this.animeContent(anime, pref_name, imgRes)); } } return { list, hasNextPage } - - - } + + statusCode(status) { + return { + "currently_airing": 0, + "finished_airing": 1, + }[status] ?? 5; + } + async getDetail(url) { - throw new Error("getDetail not implemented"); + var link = `${this.source.baseUrl}/details/${url}` + var detailsApiSlug = `/${url}/extensive` + var animeDetails = await this.request(detailsApiSlug); + + var pref_name = this.getPreference("animeonsen_pref_ep_title_lang") + var imgRes = this.getPreference("animeonsen__pref_img_res_1") + + var name_eng = animeDetails.content_title_en + var name_jp = animeDetails.content_title + var name = pref_name == "jpn" ? name_jp : name_eng; + var link = animeDetails.content_id + var imageUrl = `${this.source.apiUrl}/v4/image/${imgRes}/${link}` + var is_movie = animeDetails.is_movie + + var mal_data = animeDetails.mal_data + var description = mal_data.synopsis + var genre = [] + mal_data.genres.forEach(g => genre.push(g.name)) + var status = this.statusCode(mal_data.status); + + var chapters = []; + var episodeAPISlug = `/${url}/episodes` + var episodeDetails = await this.request(episodeAPISlug); + + Object.keys(episodeDetails).forEach(ep => { + var ep_data = episodeDetails[ep] + + var ep_name_eng = ep_data.contentTitle_episode_en + var ep_name_jp = ep_data.contentTitle_episode_jp + var ep_name = pref_name == "jpn" ? ep_name_jp : ep_name_eng; + + chapters.push({ + name:`E${ep}: ${ep_name}`, + url: `/${url}/video/${ep}`, + }) + }) + + chapters.reverse() + return { name, imageUrl, status, description, genre,link, chapters } } // For novel html content async getHtmlContent(url) { @@ -171,13 +214,22 @@ class DefaultExtension extends MProvider { entryValues: ["jpn", "en"] } }, { - key: 'animeonsen__pref_img_res', + key: 'animeonsen_pref_ep_title_lang', + listPreference: { + title: 'Preferred episode title language', + summary: '', + valueIndex: 1, + entries: ["Japenese", "English"], + entryValues: ["jpn", "en"] + } + },{ + key: 'animeonsen__pref_img_res_1', listPreference: { title: 'Preferred image resolution', summary: '', valueIndex: 1, entries: ["Low", "Medium", "High"], - entryValues: ["240x300", "480x600", "960x1200"] + entryValues: ["210x300", "420x600", "840x1200"] } }]; } From aa011f8ec36f22630011fbc18ef3898d6b3a0a3e Mon Sep 17 00:00:00 2001 From: Swakshan Date: Sat, 29 Mar 2025 13:24:41 +0530 Subject: [PATCH 4/4] anime(Animeonsen): streams --- javascript/anime/src/en/animeonsen.js | 48 ++++++++++++++++----------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/javascript/anime/src/en/animeonsen.js b/javascript/anime/src/en/animeonsen.js index d199b0a1..c9f9a5bf 100644 --- a/javascript/anime/src/en/animeonsen.js +++ b/javascript/anime/src/en/animeonsen.js @@ -6,7 +6,7 @@ const mangayomiSources = [{ "iconUrl": "https://www.google.com/s2/favicons?sz=256&domain=https://www.animeonsen.xyz", "typeSource": "single", "itemType": 1, - "version": "0.0.3", + "version": "1.0.0", "pkgPath": "anime/src/all/animeonsen.js" }]; @@ -107,9 +107,8 @@ class DefaultExtension extends MProvider { get supportsLatest() { throw new Error("supportsLatest not implemented"); } - async getLatestUpdates(page) { - return await this.getHome(page) - } + + async search(query, page, filters) { var slug = "/indexes/content/search" @@ -184,25 +183,34 @@ class DefaultExtension extends MProvider { chapters.reverse() return { name, imageUrl, status, description, genre,link, chapters } } - // 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"); + var streamDetails = await this.request(url); + var streamData = streamDetails.uri + + var streams = [ + { + quality:`Default (720p)`, + url: streamData.stream, + originalUrl: streamData.stream + } + ]; + + var subtitles = []; + var subData = streamDetails.subtitles; + Object.keys(subData).forEach(sub => { + subtitles.push({ + label:sub, + file: subData[url] + }) + }); + + streams[0].subtitles = subtitles + + return streams } + getSourcePreferences() { return [{ key: 'animeonsen__pref_title_lang',