feat: added xemovie as a scraper

breaking changes for lookmovie, cannot fix however due to lookmovie captcha
This commit is contained in:
lem6ns 2022-01-30 17:39:28 -07:00
parent 116a679736
commit 4c4719628c
5 changed files with 104 additions and 6 deletions

View File

@ -28,7 +28,7 @@ export function MovieRow(props) {
return ( return (
<div className="movieRow" tabIndex={0} onKeyPress={handleKeyPress} onClick={() => props.onClick && props.onClick()}> <div className="movieRow" tabIndex={0} onKeyPress={handleKeyPress} onClick={() => props.onClick && props.onClick()}>
{ props.source === "lookmovie" && ( { (props.source === "lookmovie" || props.source === "xemovie") && (
<div className="subtitleIcon"> <div className="subtitleIcon">
<svg id="subtitleIcon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg id="subtitleIcon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20 4H4C2.897 4 2 4.897 2 6V18C2 19.103 2.897 20 4 20H20C21.103 20 22 19.103 22 18V6C22 4.897 21.103 4 20 4ZM11 10H8V14H11V16H8C6.897 16 6 15.103 6 14V10C6 8.897 6.897 8 8 8H11V10ZM18 10H15V14H18V16H15C13.897 16 13 15.103 13 14V10C13 8.897 13.897 8 15 8H18V10Z" fill="#EEEEEE"/> <path d="M20 4H4C2.897 4 2 4.897 2 6V18C2 19.103 2.897 20 4 20H20C21.103 20 22 19.103 22 18V6C22 4.897 21.103 4 20 4ZM11 10H8V14H11V16H8C6.897 16 6 15.103 6 14V10C6 8.897 6.897 8 8 8H11V10ZM18 10H15V14H18V16H15C13.897 16 13 15.103 13 14V10C13 8.897 13.897 8 15 8H18V10Z" fill="#EEEEEE"/>

View File

@ -48,14 +48,14 @@ export function VideoElement({ streamUrl, loading, setProgress, videoRef, startT
if (!streamUrl.includes('.mp4')) { if (!streamUrl.includes('.mp4')) {
return ( return (
<video crossOrigin="anonymous" className="videoElement" ref={videoRef} controls autoPlay onProgress={setProgress} onLoadedData={onLoad}> <video className="videoElement" ref={videoRef} controls autoPlay onProgress={setProgress} onLoadedData={onLoad}>
{ streamData.subtitles && streamData.subtitles.map((sub, index) => <track key={index} kind="captions" label={sub.language} src={`${process.env.REACT_APP_CORS_PROXY_URL}https://lookmovie.io${sub.file}` } />) } { streamData.subtitles && streamData.subtitles.map((sub, index) => <track key={index} kind="captions" label={sub.language} src={sub.file} />) }
</video> </video>
) )
} else { } else {
return ( return (
<video crossOrigin="anonymous" className="videoElement" ref={videoRef} controls autoPlay onProgress={setProgress} onLoadedData={onLoad}> <video className="videoElement" ref={videoRef} controls autoPlay onProgress={setProgress} onLoadedData={onLoad}>
{ streamData.subtitles && streamData.subtitles.map((sub, index) => <track key={index} kind="captions" label={sub.language} src={`${process.env.REACT_APP_CORS_PROXY_URL}https://lookmovie.io${sub.file}` } />) } { streamData.subtitles && streamData.subtitles.map((sub, index) => <track key={index} kind="captions" label={sub.language} src={sub.file} />) }
<source src={streamUrl} type="video/mp4" /> <source src={streamUrl} type="video/mp4" />
</video> </video>
) )

View File

@ -1,4 +1,5 @@
import lookmovie from './scraper/lookmovie'; import lookmovie from './scraper/lookmovie';
import xemovie from './scraper/xemovie';
import theflix from './scraper/theflix'; import theflix from './scraper/theflix';
import vidzstore from './scraper/vidzstore'; import vidzstore from './scraper/vidzstore';
@ -6,6 +7,7 @@ async function findContent(searchTerm, type) {
const results = { options: []}; const results = { options: []};
const content = await Promise.all([ const content = await Promise.all([
// lookmovie.findContent(searchTerm, type), // lookmovie.findContent(searchTerm, type),
xemovie.findContent(searchTerm, type),
theflix.findContent(searchTerm, type), theflix.findContent(searchTerm, type),
vidzstore.findContent(searchTerm, type) vidzstore.findContent(searchTerm, type)
]); ]);
@ -30,6 +32,8 @@ async function getStreamUrl(slug, type, source, season, episode) {
return await theflix.getStreamUrl(slug, type, season, episode); return await theflix.getStreamUrl(slug, type, season, episode);
case 'vidzstore': case 'vidzstore':
return await vidzstore.getStreamUrl(slug); return await vidzstore.getStreamUrl(slug);
case 'xemovie':
return await xemovie.getStreamUrl(slug, type, season, episode);
default: default:
return; return;
} }
@ -41,6 +45,8 @@ async function getEpisodes(slug, source) {
return await lookmovie.getEpisodes(slug); return await lookmovie.getEpisodes(slug);
case 'theflix': case 'theflix':
return await theflix.getEpisodes(slug); return await theflix.getEpisodes(slug);
case 'xemovie':
return await xemovie.getEpisodes(slug);
default: default:
return; return;
} }

View File

@ -34,7 +34,7 @@ async function getStreamUrl(slug) {
const res = await fetch(url).then(d => d.text()); const res = await fetch(url).then(d => d.text());
const DOM = new DOMParser().parseFromString(res, "text/html"); const DOM = new DOMParser().parseFromString(res, "text/html");
return { url: `${process.env.REACT_APP_CORS_PROXY_URL}${DOM.querySelector("source").src}` }; return { url: DOM.querySelector("source").src };
} }
const vidzstore = { findContent, getStreamUrl } const vidzstore = { findContent, getStreamUrl }

View File

@ -0,0 +1,92 @@
const BASE_URL = `${process.env.REACT_APP_CORS_PROXY_URL}https://xemovie.co`;
async function findContent(searchTerm, type) {
try {
let results;
const searchUrl = `${BASE_URL}/search?q=${encodeURIComponent(searchTerm)}`;
const searchRes = await fetch(searchUrl).then((d) => d.text());
const parser = new DOMParser();
const doc = parser.parseFromString(searchRes, "text/html");
switch (type) {
case 'show':
// const showContainer = doc.querySelectorAll(".py-10")[1].querySelector(".grid");
// const showNodes = [...showContainer.querySelectorAll("a")].filter(link => !link.className);
// results = showNodes.map(node => {
// node = node.parentElement
// return {
// type,
// title: [...new Set(node.innerText.split("\n"))][1].split("(")[0].trim(),
// year: [...new Set(node.innerText.split("\n"))][3],
// slug: node.querySelector("a").href.split('/').pop(),
// source: "xemovie"
// }
// })
// break;
return { options: [] };
case 'movie':
const movieContainer = doc.querySelectorAll(".py-10")[0].querySelector(".grid");
const movieNodes = [...movieContainer.querySelectorAll("a")].filter(link => !link.className);
results = movieNodes.map(node => {
node = node.parentElement
return {
type,
title: [...new Set(node.innerText.split("\n"))][1].split("(")[0].trim(),
year: [...new Set(node.innerText.split("\n"))][3],
slug: node.querySelector("a").href.split('/').pop(),
source: "xemovie"
}
})
break;
default:
results = [];
break;
}
return { options: results };
} catch {
return { options: [] };
}
}
async function getStreamUrl(slug, type, season, episode) {
let url;
if (type === "show") {
} else {
url = `${BASE_URL}/movies/${slug}/watch`;
}
let mediaUrl = "";
let subtitles = [];
const res = await fetch(url).then(d => d.text());
const DOM = new DOMParser().parseFromString(res, "text/html");
for (const script of DOM.scripts) {
if (script.textContent.match(/https:\/\/s[0-9]\.xemovie\.com/)) {
// eslint-disable-next-line
let data = JSON.parse(JSON.stringify(eval(`(${script.textContent.replace("const data = ", "").split("};")[0]}})`)));
// eslint-disable-next-line
mediaUrl = data.playlist[0].file;
// eslint-disable-next-line
for (const subtitleTrack of data.playlist[0].tracks) {
const subtitleBlob = URL.createObjectURL(await fetch(`${process.env.REACT_APP_CORS_PROXY_URL}${subtitleTrack.file}`).then(res => res.blob())); // do this so no need for CORS errors
subtitles.push({
file: subtitleBlob,
language: subtitleTrack.label
})
}
}
}
return { url: mediaUrl, subtitles: subtitles }
}
async function getEpisodes(slug) {
}
const xemovie = { findContent, getStreamUrl, getEpisodes }
export default xemovie;