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: false, 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; 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 streamUrl = ""; 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) { if (!script.textContent) continue; if (script.textContent.match(/https:\/\/[a-z][0-9]\.xemovie\.com/)) { const data = JSON.parse(JSON.stringify(eval(`(${script.textContent.replace("const data = ", "").split("};")[0]}})`))); streamUrl = data.playlist[0].file; for (const [index, subtitleTrack] of data.playlist[0].tracks.entries()) { const subtitleBlob = URL.createObjectURL( 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 }) } } } const streamType = streamUrl.split('.').at(-1); if (streamType !== "mp4" && streamType !== "m3u8") throw new Error("Unsupported stream type"); return { url: streamUrl, type: streamType, captions: subtitles } as MWMediaStream; } };