From a433018660dd715814c917694c4a4e7c0fadbb1d Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Mon, 2 May 2022 17:30:48 +0100 Subject: [PATCH] Add xemovie for movies This provider also supports series but it has not yet been implemented --- src/providers/list/xemovie/index.ts | 105 ++++++++++++++++++++++++++++ src/providers/methods/providers.ts | 2 + 2 files changed, 107 insertions(+) create mode 100644 src/providers/list/xemovie/index.ts diff --git a/src/providers/list/xemovie/index.ts b/src/providers/list/xemovie/index.ts new file mode 100644 index 00000000..6690b0e0 --- /dev/null +++ b/src/providers/list/xemovie/index.ts @@ -0,0 +1,105 @@ +import { + MWMediaProvider, + MWMediaType, + MWPortableMedia, + MWMediaStream, + MWQuery, + MWProviderMediaResult, + MWMediaCaption +} from "providers/types"; + +import { CORS_PROXY_URL } from "mw_constants"; + +export const xemovieScraper: MWMediaProvider = { + id: "xemovie", + enabled: true, + type: [MWMediaType.MOVIE], + displayName: "xemovie", + + async getMediaFromPortable(media: MWPortableMedia): Promise { + const res = await fetch( + `${CORS_PROXY_URL}https://xemovie.co/movies/${media.mediaId}/watch`, + ).then(d => d.text()); + + const DOM = new DOMParser().parseFromString(res, "text/html"); + + const title = DOM.querySelector(".text-primary.text-lg.font-extrabold")?.textContent || ""; + const year = DOM.querySelector("div.justify-between:nth-child(3) > div:nth-child(2)")?.textContent || ""; + + return { + ...media, + title, + year, + } as MWProviderMediaResult; + }, + + async searchForMedia(query: MWQuery): Promise { + const term = query.searchQuery.toLowerCase(); + + const searchUrl = `${CORS_PROXY_URL}https://xemovie.co/search?q=${encodeURIComponent(term)}`; + const searchRes = await fetch(searchUrl).then((d) => d.text()); + + const parser = new DOMParser(); + const doc = parser.parseFromString(searchRes, "text/html"); + + const movieContainer = doc.querySelectorAll(".py-10")[0].querySelector(".grid"); + if (!movieContainer) return []; + const movieNodes = Array.from(movieContainer.querySelectorAll("a")).filter(link => !link.className); + + const results: MWProviderMediaResult[] = movieNodes.map((node) => { + const parent = node.parentElement; + if (!parent) return; + + const aElement = parent.querySelector("a"); + if (!aElement) return; + + // eslint-disable-next-line consistent-return + return { + title: parent.querySelector("div > div > a > h6")?.textContent, + year: parent.querySelector("div.float-right")?.textContent, + mediaId: aElement.href.split('/').pop() || "", + } + }).filter((d): d is MWProviderMediaResult => !!d); + + return results; + }, + + async getStream(media: MWPortableMedia): Promise { + if (media.mediaType !== MWMediaType.MOVIE) throw new Error("Incorrect type") + + const url = `${CORS_PROXY_URL}https://xemovie.co/movies/${media.mediaId}/watch`; + + let mediaUrl = ""; + const subtitles: MWMediaCaption[] = []; + + const res = await fetch(url).then(d => d.text()); + const scripts = Array.from(new DOMParser().parseFromString(res, "text/html").querySelectorAll("script")); + + for (const script of scripts) { + // eslint-disable-next-line no-continue + if (!script.textContent) continue; + + if (script.textContent.match(/https:\/\/[a-z][0-9]\.xemovie\.com/)) { + // eslint-disable-next-line + let data = JSON.parse(JSON.stringify(eval(`(${script.textContent.replace("const data = ", "").split("};")[0]}})`))); + mediaUrl = data.playlist[0].file; + + // eslint-disable-next-line + for (const [index, subtitleTrack] of data.playlist[0].tracks.entries()) { + const subtitleBlob = URL.createObjectURL( + // eslint-disable-next-line no-await-in-loop + await fetch(`${CORS_PROXY_URL}${subtitleTrack.file}`).then((captionRes) => captionRes.blob()) + ); // do this so no need for CORS errors + + subtitles.push({ + id: index, + url: subtitleBlob, + label: subtitleTrack.label + }) + } + } + } + + return { url: mediaUrl, type: "mp4", captions: subtitles } as MWMediaStream; + } +}; diff --git a/src/providers/methods/providers.ts b/src/providers/methods/providers.ts index 720b42c2..142f068b 100644 --- a/src/providers/methods/providers.ts +++ b/src/providers/methods/providers.ts @@ -2,11 +2,13 @@ import { theFlixScraper } from "providers/list/theflix"; import { gDrivePlayerScraper } from "providers/list/gdriveplayer"; import { MWWrappedMediaProvider, WrapProvider } from "providers/wrapper"; import { gomostreamScraper } from "providers/list/gomostream"; +import { xemovieScraper } from "providers/list/xemovie"; export const mediaProvidersUnchecked: MWWrappedMediaProvider[] = [ WrapProvider(theFlixScraper), WrapProvider(gDrivePlayerScraper), WrapProvider(gomostreamScraper), + WrapProvider(xemovieScraper), ]; export const mediaProviders: MWWrappedMediaProvider[] =