From 9bc65f751d31592936ba9adbbe26a7f1ff60be0e Mon Sep 17 00:00:00 2001 From: Factiven Date: Thu, 17 Aug 2023 04:25:24 +0700 Subject: [PATCH] feat(Moopa): add presence (#7576) * feat(Moopa): add presence * feat(Moopa): update metadata.json * feat(Moopa): update logo size * feat(Moopa): update timestamps * feat(Moopa): removed unnecessary curly * Update websites/M/Moopa/presence.ts Co-authored-by: Daniel Lau <32113157+theusaf@users.noreply.github.com> Signed-off-by: Factiven * feat(Moopa): added gettitle function * Update websites/M/Moopa/metadata.json Co-authored-by: Dark_Ville <42322979+DarkVillager@users.noreply.github.com> Signed-off-by: Factiven --------- Signed-off-by: Factiven Co-authored-by: Daniel Lau <32113157+theusaf@users.noreply.github.com> Co-authored-by: Dark_Ville <42322979+DarkVillager@users.noreply.github.com> --- websites/M/Moopa/metadata.json | 38 +++++++ websites/M/Moopa/presence.ts | 188 +++++++++++++++++++++++++++++++++ 2 files changed, 226 insertions(+) create mode 100644 websites/M/Moopa/metadata.json create mode 100644 websites/M/Moopa/presence.ts diff --git a/websites/M/Moopa/metadata.json b/websites/M/Moopa/metadata.json new file mode 100644 index 000000000000..277d7e944185 --- /dev/null +++ b/websites/M/Moopa/metadata.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://schemas.premid.app/metadata/1.9", + "author": { + "id": "338295424479789057", + "name": "factiven" + }, + "service": "Moopa", + "description": { + "en": "Moopa is a free Anime and Manga streaming website with AniList integration where you can easily track your progress with a single click of a button." + }, + "url": "moopa.live", + "version": "1.0.0", + "logo": "https://i.imgur.com/lelaLhp.png", + "thumbnail": "https://i.imgur.com/pNmZsH3.png", + "color": "#FF7F57", + "category": "anime", + "tags": [ + "anime", + "manga", + "streaming", + "video", + "anilist", + "free" + ], + "settings": [ + { + "id": "title", + "title": "Title Language", + "icon": "fa-solid fa-language", + "value": 0, + "values": [ + "Romaji", + "English", + "Native" + ] + } + ] +} \ No newline at end of file diff --git a/websites/M/Moopa/presence.ts b/websites/M/Moopa/presence.ts new file mode 100644 index 000000000000..975a38afdf57 --- /dev/null +++ b/websites/M/Moopa/presence.ts @@ -0,0 +1,188 @@ +const presence = new Presence({ + clientId: "1139510267311562842", + }), + browsingTimestamp = Math.floor(Date.now() / 1000); + +const enum Assets { + Logo = "https://i.imgur.com/lelaLhp.png", +} + +function getTitle(titleLang: number) { + const metaTitle = document.querySelector('meta[name="title"]'), + romajiTitle = metaTitle?.getAttribute("data-title-romaji"); + + switch (titleLang) { + case 0: { + return romajiTitle; + } + case 1: { + return metaTitle?.getAttribute("data-title-english") || romajiTitle; + } + case 2: { + return metaTitle?.getAttribute("data-title-native") || romajiTitle; + } + default: { + return null; + } + } +} + +presence.on("UpdateData", async () => { + const presenceData: PresenceData = { + largeImageKey: Assets.Logo, + startTimestamp: browsingTimestamp, + }, + titleLang = (await presence.getSetting("title")) as number, + { pathname, href } = document.location; + + if (pathname === "/" || pathname === "/en/") + presenceData.details = "Browsing Homepage"; + else if (pathname.includes("/id/")) + presenceData.details = "Browsing Anime/Manga"; + else if (pathname.includes("/profile/")) { + presenceData.details = + document.querySelector("h1.font-karla.font-bold.text-2xl.pt-7") + ?.textContent || "Getting data..."; + presenceData.state = "Viewing profile"; + } else if (pathname === "/en/anime/trending/") + presenceData.details = "Browsing trending Anime"; + else if (pathname === "/en/anime/popular/") + presenceData.details = "Browsing popular Anime"; + else if ( + pathname.includes("/anime/") && + !pathname.includes("/watch/") && + !pathname.includes("/search/") + ) { + if (document.querySelector('img[alt="404"]')) { + presenceData.state = "404 | Not Found"; + presenceData.details = "Browsing Anime/Manga"; + } else { + delete presenceData.startTimestamp; + const title = getTitle(titleLang); + + presenceData.largeImageKey = + document + .querySelector('img[alt="poster anime"]') + ?.getAttribute("src") || Assets.Logo; + presenceData.details = title || "Getting data..."; + presenceData.state = "Viewing info"; + + if (title) { + presenceData.buttons = [ + { + label: "View Anime", + url: href, + }, + ]; + } + } + } else if ( + pathname.includes("/manga/") && + !pathname.includes("/read/") && + !pathname.includes("/search/") + ) { + if (document.querySelector('img[alt="404"]')) { + presenceData.state = "404 | Not Found"; + presenceData.details = "Browsing Anime/Manga"; + } else { + delete presenceData.startTimestamp; + const title = document.querySelector("h1.title")?.textContent; + presenceData.largeImageKey = + document.querySelector('img[alt="cover image"]')?.getAttribute("src") || + Assets.Logo; + presenceData.details = title || "Getting data..."; + presenceData.state = "Viewing info"; + + if (title) { + presenceData.buttons = [ + { + label: "View Manga", + url: href, + }, + ]; + } + } + } else if (pathname.includes("/watch/")) { + if (document.querySelector('img[alt="404"]')) { + presenceData.state = "404 | Not Found"; + presenceData.details = "Browsing Anime/Manga"; + } else { + const playingEpisode = document + .querySelector("h3") + ?.textContent?.replace("Episode ", ""), + video: HTMLVideoElement = document.querySelector("video"); + if (video && !Number.isNaN(Number(video.duration))) { + presenceData.endTimestamp = presence + .getTimestampsfromMedia(video) + .pop(); + if (video.paused) { + presenceData.smallImageText = "Paused"; + presenceData.smallImageKey = Assets.Pause; + delete presenceData.startTimestamp; + delete presenceData.endTimestamp; + } else { + presenceData.smallImageText = "Playing"; + presenceData.smallImageKey = Assets.Play; + } + } + + const total = document + .querySelector("div.grid.w-full.pl-5") + ?.getAttribute("data-episode"), + title = getTitle(titleLang); + + if (title) { + presenceData.buttons = [ + { + label: "Stream Anime", + url: href, + }, + ]; + } + presenceData.largeImageKey = + document.querySelector('img[alt="Anime Cover"]')?.getAttribute("src") || + Assets.Logo; + presenceData.details = title || "Getting data..."; + if (playingEpisode) { + presenceData.state = `Episode ${playingEpisode} of ${ + total === "0" ? "???" : total + }`; + } + } + } else if (pathname.includes("/read/")) { + const title = document + .querySelector("title") + ?.textContent.replace("Manga - ", ""); + + presenceData.largeImageKey = + document + .querySelector('meta[id="CoverImage"]') + .getAttribute("data-manga-cover") || Assets.Logo; + presenceData.details = title || "Getting data..."; + presenceData.state = `Reading Chapter ${document + .querySelector('input[id="chapter-progress"]') + .getAttribute("value")}`; + presenceData.smallImageKey = Assets.Reading; + presenceData.smallImageText = "Reading"; + + if (title) { + presenceData.buttons = [ + { + label: "Read Manga", + url: href, + }, + ]; + } + } else if (pathname.includes("/search/") && pathname.includes("/anime/")) { + presenceData.details = "Browsing Anime"; + presenceData.state = "Searching..."; + presenceData.smallImageKey = Assets.Search; + } else if (pathname.includes("/search/") && pathname.includes("/manga/")) { + presenceData.details = "Browsing Manga"; + presenceData.state = "Searching..."; + presenceData.smallImageKey = Assets.Search; + } else presenceData.details = "Browsing Anime/Manga"; + + if (presenceData.details) presence.setActivity(presenceData); + else presence.setActivity(); +});