mirror of
https://github.com/sussy-code/smov.git
synced 2025-01-01 16:37:39 +01:00
Merge pull request #17 from JamesHawkinss/feature/gomostream
Support gomostream, and proper support for multiple sources
This commit is contained in:
commit
3b6f0c8277
12 changed files with 292 additions and 79 deletions
|
@ -7,6 +7,7 @@
|
||||||
"@testing-library/jest-dom": "^5.11.4",
|
"@testing-library/jest-dom": "^5.11.4",
|
||||||
"@testing-library/react": "^11.1.0",
|
"@testing-library/react": "^11.1.0",
|
||||||
"@testing-library/user-event": "^12.1.10",
|
"@testing-library/user-event": "^12.1.10",
|
||||||
|
"crypto-js": "^4.0.0",
|
||||||
"fuse.js": "^6.4.6",
|
"fuse.js": "^6.4.6",
|
||||||
"hls.js": "^1.0.7",
|
"hls.js": "^1.0.7",
|
||||||
"json5": "^2.2.0",
|
"json5": "^2.2.0",
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { TypeSelector } from './TypeSelector';
|
||||||
import { NumberSelector } from './NumberSelector';
|
import { NumberSelector } from './NumberSelector';
|
||||||
import './EpisodeSelector.css'
|
import './EpisodeSelector.css'
|
||||||
|
|
||||||
export function EpisodeSelector({ setSeason, setEpisode, seasons, season, episodes, currentSeason, currentEpisode, slug }) {
|
export function EpisodeSelector({ setSeason, setEpisode, seasons, season, episodes, currentSeason, currentEpisode, slug, source }) {
|
||||||
|
|
||||||
const choices = episodes.map(v => {
|
const choices = episodes.map(v => {
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ export function EpisodeSelector({ setSeason, setEpisode, seasons, season, episod
|
||||||
let currentlyAt = 0;
|
let currentlyAt = 0;
|
||||||
let totalDuration = 0;
|
let totalDuration = 0;
|
||||||
|
|
||||||
const progress = progressData?.lookmovie?.show?.slug?.[`${season}-${v}`]
|
const progress = progressData?.[source]?.show?.slug?.[`${season}-${v}`]
|
||||||
if(progress) {
|
if(progress) {
|
||||||
currentlyAt = progress.currentlyAt
|
currentlyAt = progress.currentlyAt
|
||||||
totalDuration = progress.totalDuration
|
totalDuration = progress.totalDuration
|
||||||
|
|
|
@ -11,7 +11,7 @@ export function MovieRow(props) {
|
||||||
let progress;
|
let progress;
|
||||||
let percentage = null;
|
let percentage = null;
|
||||||
if(props.type === "movie") {
|
if(props.type === "movie") {
|
||||||
progress = progressData?.lookmovie?.movie?.[props.slug]?.full
|
progress = progressData?.[props.source]?.movie?.[props.slug]?.full
|
||||||
if(progress) {
|
if(progress) {
|
||||||
percentage = Math.floor((progress.currentlyAt / progress.totalDuration) * 100)
|
percentage = Math.floor((progress.currentlyAt / progress.totalDuration) * 100)
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ export function MovieRow(props) {
|
||||||
<span className="year">({props.year})</span>
|
<span className="year">({props.year})</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="watch">
|
<div className="watch">
|
||||||
|
<span className="attribute">{props.source}</span>
|
||||||
<p>Watch {props.type}</p>
|
<p>Watch {props.type}</p>
|
||||||
<Arrow/>
|
<Arrow/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
// import { Arrow } from './Arrow';
|
|
||||||
import './TypeSelector.css'
|
import './TypeSelector.css'
|
||||||
|
|
||||||
// setType: (txt: string) => void
|
// setType: (txt: string) => void
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import Hls from 'hls.js'
|
import Hls from 'hls.js'
|
||||||
import './VideoElement.css'
|
|
||||||
import { VideoPlaceholder } from './VideoPlaceholder'
|
import { VideoPlaceholder } from './VideoPlaceholder'
|
||||||
|
|
||||||
|
import './VideoElement.css'
|
||||||
|
|
||||||
// streamUrl: string
|
// streamUrl: string
|
||||||
// loading: boolean
|
// loading: boolean
|
||||||
export function VideoElement({ streamUrl, loading, setProgress }) {
|
export function VideoElement({ streamUrl, loading, setProgress }) {
|
||||||
|
@ -10,21 +11,23 @@ export function VideoElement({ streamUrl, loading, setProgress }) {
|
||||||
const [error, setError] = React.useState(false);
|
const [error, setError] = React.useState(false);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
setError(false)
|
if (!streamUrl.endsWith('.mp4')) {
|
||||||
if (!videoRef || !videoRef.current || !streamUrl || streamUrl.length === 0 || loading) return;
|
setError(false)
|
||||||
|
if (!videoRef || !videoRef.current || !streamUrl || streamUrl.length === 0 || loading) return;
|
||||||
const hls = new Hls();
|
|
||||||
|
const hls = new Hls();
|
||||||
if (!Hls.isSupported() && videoRef.current.canPlayType('application/vnd.apple.mpegurl')) {
|
|
||||||
videoRef.current.src = streamUrl;
|
if (!Hls.isSupported() && videoRef.current.canPlayType('application/vnd.apple.mpegurl')) {
|
||||||
return;
|
videoRef.current.src = streamUrl;
|
||||||
} else if (!Hls.isSupported()) {
|
return;
|
||||||
setError(true)
|
} else if (!Hls.isSupported()) {
|
||||||
return;
|
setError(true)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hls.attachMedia(videoRef.current);
|
||||||
|
hls.loadSource(streamUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
hls.attachMedia(videoRef.current);
|
|
||||||
hls.loadSource(streamUrl);
|
|
||||||
}, [videoRef, streamUrl, loading])
|
}, [videoRef, streamUrl, loading])
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
|
@ -36,7 +39,15 @@ export function VideoElement({ streamUrl, loading, setProgress }) {
|
||||||
if (!streamUrl || streamUrl.length === 0)
|
if (!streamUrl || streamUrl.length === 0)
|
||||||
return <VideoPlaceholder>No video selected</VideoPlaceholder>
|
return <VideoPlaceholder>No video selected</VideoPlaceholder>
|
||||||
|
|
||||||
return (
|
if (!streamUrl.endsWith('.mp4')) {
|
||||||
<video className="videoElement" ref={videoRef} controls autoPlay onProgress={setProgress} />
|
return (
|
||||||
)
|
<video className="videoElement" ref={videoRef} controls autoPlay onProgress={setProgress} />
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<video className="videoElement" ref={videoRef} controls autoPlay onProgress={setProgress}>
|
||||||
|
<source src={streamUrl} type="video/mp4" />
|
||||||
|
</video>
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
92
src/lib/gomostream.js
Normal file
92
src/lib/gomostream.js
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
import { unpack } from './util/unpacker';
|
||||||
|
|
||||||
|
const CORS_URL = 'https://hidden-inlet-27205.herokuapp.com/';
|
||||||
|
const BASE_URL = `${CORS_URL}https://gomo.to`;
|
||||||
|
const MOVIE_URL = `${BASE_URL}/movie`
|
||||||
|
const DECODING_URL = `${BASE_URL}/decoding_v3.php`
|
||||||
|
|
||||||
|
async function findContent(searchTerm, type) {
|
||||||
|
try {
|
||||||
|
if (type !== 'movie') return;
|
||||||
|
|
||||||
|
const term = searchTerm.toLowerCase()
|
||||||
|
const imdbRes = await fetch(`${CORS_URL}https://v2.sg.media-imdb.com/suggestion/${term.slice(0, 1)}/${term}.json`).then(d => d.json())
|
||||||
|
|
||||||
|
const results = [];
|
||||||
|
imdbRes.d.forEach((e) => {
|
||||||
|
if (!e.id.startsWith('tt')) return;
|
||||||
|
|
||||||
|
// Block tv shows
|
||||||
|
if (e.q === "TV series") return;
|
||||||
|
if (e.q === "TV mini-series") return;
|
||||||
|
if (e.q === "video game") return;
|
||||||
|
if (e.q === "TV movie") return;
|
||||||
|
if (e.q === "TV special") return;
|
||||||
|
|
||||||
|
results.push({
|
||||||
|
title: e.l,
|
||||||
|
slug: e.id,
|
||||||
|
type: 'movie',
|
||||||
|
year: e.y,
|
||||||
|
source: 'gomostream'
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
if (results.length > 1) {
|
||||||
|
return { options: results };
|
||||||
|
} else {
|
||||||
|
return { options: [ { ...results[0], source: 'gomostream' } ] }
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
throw new Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getStreamUrl(slug, type, season, episode) {
|
||||||
|
if (type !== 'movie') return;
|
||||||
|
|
||||||
|
// Get stream to go with IMDB ID
|
||||||
|
const site1 = await fetch(`${MOVIE_URL}/${slug}`).then((d) => d.text());
|
||||||
|
|
||||||
|
if (site1 === "Movie not available.")
|
||||||
|
return { url: '' };
|
||||||
|
|
||||||
|
const tc = site1.match(/var tc = '(.+)';/)?.[1]
|
||||||
|
const _token = site1.match(/"_token": "(.+)",/)?.[1]
|
||||||
|
|
||||||
|
const fd = new FormData()
|
||||||
|
fd.append('tokenCode', tc)
|
||||||
|
fd.append('_token', _token)
|
||||||
|
|
||||||
|
const src = await fetch(DECODING_URL, {
|
||||||
|
method: "POST",
|
||||||
|
body: fd,
|
||||||
|
headers: {
|
||||||
|
'x-token': tc.slice(5, 13).split("").reverse().join("") + "13574199"
|
||||||
|
}
|
||||||
|
}).then((d) => d.json());
|
||||||
|
|
||||||
|
const embedUrl = src.find(url => url.includes('gomo.to'));
|
||||||
|
const site2 = await fetch(`${CORS_URL}${embedUrl}`).then((d) => d.text());
|
||||||
|
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const site2Dom = parser.parseFromString(site2, "text/html");
|
||||||
|
|
||||||
|
console.log(site2Dom.body)
|
||||||
|
|
||||||
|
if (site2Dom.body.innerText === "File was deleted")
|
||||||
|
return { url: '' }
|
||||||
|
|
||||||
|
const script = site2Dom.querySelectorAll("script")[8].innerHTML;
|
||||||
|
|
||||||
|
let unpacked = unpack(script).split('');
|
||||||
|
unpacked.splice(0, 43);
|
||||||
|
let index = unpacked.findIndex((e) => e === '"');
|
||||||
|
const url = unpacked.slice(0, index).join('');
|
||||||
|
|
||||||
|
return { url }
|
||||||
|
}
|
||||||
|
|
||||||
|
const gomostream = { findContent, getStreamUrl }
|
||||||
|
export default gomostream;
|
44
src/lib/index.js
Normal file
44
src/lib/index.js
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import lookMovie from './lookMovie';
|
||||||
|
import gomostream from './gomostream';
|
||||||
|
|
||||||
|
async function findContent(searchTerm, type) {
|
||||||
|
const results = { options: []};
|
||||||
|
const content = await Promise.all([
|
||||||
|
lookMovie.findContent(searchTerm, type),
|
||||||
|
gomostream.findContent(searchTerm, type)
|
||||||
|
]);
|
||||||
|
|
||||||
|
content.forEach((o) => {
|
||||||
|
if (!o || !o.options) return;
|
||||||
|
|
||||||
|
o.options.forEach((i) => {
|
||||||
|
if (!i) return;
|
||||||
|
results.options.push(i)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getStreamUrl(slug, type, source, season, episode) {
|
||||||
|
switch (source) {
|
||||||
|
case 'lookmovie':
|
||||||
|
return await lookMovie.getStreamUrl(slug, type, season, episode);
|
||||||
|
case 'gomostream':
|
||||||
|
return await gomostream.getStreamUrl(slug, type, season, episode);
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getEpisodes(slug, source) {
|
||||||
|
switch (source) {
|
||||||
|
case 'lookmovie':
|
||||||
|
return await lookMovie.getEpisodes(slug);
|
||||||
|
case 'gomostream':
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { findContent, getStreamUrl, getEpisodes }
|
|
@ -17,23 +17,19 @@ async function getVideoUrl(config) {
|
||||||
url = getCorsUrl(`https://lookmovie.io/manifests/shows/json/${accessToken}/${now}/${config.id}/master.m3u8`);
|
url = getCorsUrl(`https://lookmovie.io/manifests/shows/json/${accessToken}/${now}/${config.id}/master.m3u8`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (url) {
|
const videoOpts = await fetch(url).then((d) => d.json());
|
||||||
const videoOpts = await fetch(url).then((d) => d.json());
|
|
||||||
|
|
||||||
// Find video URL and return it (with a check for a full url if needed)
|
// Find video URL and return it (with a check for a full url if needed)
|
||||||
const opts = ["1080p", "1080", "720p", "720", "480p", "480", "auto"]
|
const opts = ["1080p", "1080", "720p", "720", "480p", "480", "auto"]
|
||||||
|
|
||||||
let videoUrl = "";
|
let videoUrl = "";
|
||||||
for (let res of opts) {
|
for (let res of opts) {
|
||||||
if (videoOpts[res] && !videoOpts[res].includes('dummy') && !videoOpts[res].includes('earth-1984') && !videoUrl) {
|
if (videoOpts[res] && !videoOpts[res].includes('dummy') && !videoOpts[res].includes('earth-1984') && !videoUrl) {
|
||||||
videoUrl = videoOpts[res]
|
videoUrl = videoOpts[res]
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return videoUrl.startsWith("/") ? getCorsUrl(`https://lookmovie.io/${videoUrl}`) : getCorsUrl(videoUrl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return "Invalid type.";
|
return videoUrl.startsWith("/") ? `https://lookmovie.io${videoUrl}` : videoUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAccessToken(config) {
|
async function getAccessToken(config) {
|
||||||
|
@ -66,7 +62,18 @@ async function getEpisodes(slug) {
|
||||||
"}"
|
"}"
|
||||||
);
|
);
|
||||||
|
|
||||||
return data.seasons
|
let seasons = [];
|
||||||
|
let episodes = [];
|
||||||
|
data.seasons.forEach((e) => {
|
||||||
|
if (!seasons.includes(e.season))
|
||||||
|
seasons.push(e.season);
|
||||||
|
|
||||||
|
if (!episodes[e.season])
|
||||||
|
episodes[e.season] = []
|
||||||
|
episodes[e.season].push(e.episode)
|
||||||
|
})
|
||||||
|
|
||||||
|
return { seasons, episodes }
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getStreamUrl(slug, type, season, episode) {
|
async function getStreamUrl(slug, type, season, episode) {
|
||||||
|
@ -85,14 +92,14 @@ async function getStreamUrl(slug, type, season, episode) {
|
||||||
let id = '';
|
let id = '';
|
||||||
|
|
||||||
if (type === "movie") {
|
if (type === "movie") {
|
||||||
id = data.id_movie;
|
id = data.id_movie;
|
||||||
} else if (type === "show") {
|
} else if (type === "show") {
|
||||||
const episodeObj = data.seasons.find((v) => { return v.season === season && v.episode === episode; });
|
const episodeObj = data.seasons.find((v) => { return v.season === season && v.episode === episode; });
|
||||||
|
|
||||||
if (episodeObj) {
|
if (episodeObj) {
|
||||||
id = episodeObj.id_episode;
|
id = episodeObj.id_episode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id === '') {
|
if (id === '') {
|
||||||
return { url: '' }
|
return { url: '' }
|
||||||
|
@ -107,11 +114,10 @@ async function getStreamUrl(slug, type, season, episode) {
|
||||||
return { url: videoUrl }
|
return { url: videoUrl }
|
||||||
}
|
}
|
||||||
|
|
||||||
async function findContent(searchTerm, type) {
|
async function findContent(searchTerm, type) {
|
||||||
// const searchUrl = getCorsUrl(`https://lookmovie.io/api/v1/${type}s/search/?q=${encodeURIComponent(searchTerm)}`);
|
|
||||||
const searchUrl = getCorsUrl(`https://lookmovie.io/${type}s/search/?q=${encodeURIComponent(searchTerm)}`);
|
const searchUrl = getCorsUrl(`https://lookmovie.io/${type}s/search/?q=${encodeURIComponent(searchTerm)}`);
|
||||||
const searchRes = await fetch(searchUrl).then((d) => d.text());
|
const searchRes = await fetch(searchUrl).then((d) => d.text());
|
||||||
|
|
||||||
// Parse DOM to find search results on full search page
|
// Parse DOM to find search results on full search page
|
||||||
const parser = new DOMParser();
|
const parser = new DOMParser();
|
||||||
const doc = parser.parseFromString(searchRes, "text/html");
|
const doc = parser.parseFromString(searchRes, "text/html");
|
||||||
|
@ -136,22 +142,24 @@ async function findContent(searchTerm, type) {
|
||||||
|
|
||||||
if (matchedResults.length > 1) {
|
if (matchedResults.length > 1) {
|
||||||
const res = { options: [] };
|
const res = { options: [] };
|
||||||
|
|
||||||
matchedResults.forEach((r) => res.options.push({
|
matchedResults.forEach((r) => res.options.push({
|
||||||
title: r.title,
|
title: r.title,
|
||||||
slug: r.slug,
|
slug: r.slug,
|
||||||
type: r.type,
|
type: r.type,
|
||||||
year: r.year
|
year: r.year,
|
||||||
|
source: 'lookmovie'
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
} else {
|
} else {
|
||||||
const { title, slug, type, year } = matchedResults[0];
|
const { title, slug, type, year } = matchedResults[0];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
options: [{ title, slug, type, year }]
|
options: [{ title, slug, type, year, source: 'lookmovie' }]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { findContent, getStreamUrl, getEpisodes };
|
const lookMovie = { findContent, getStreamUrl, getEpisodes };
|
||||||
|
export default lookMovie;
|
53
src/lib/util/unpacker.js
Normal file
53
src/lib/util/unpacker.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
const alphabet = {
|
||||||
|
62: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||||
|
95: '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'
|
||||||
|
};
|
||||||
|
|
||||||
|
function _filterargs(str) {
|
||||||
|
var juicers = [
|
||||||
|
/}\('([\s\S]*)', *(\d+), *(\d+), *'([\s\S]*)'\.split\('\|'\), *(\d+), *([\s\S]*)\)\)/,
|
||||||
|
/}\('([\s\S]*)', *(\d+), *(\d+), *'([\s\S]*)'\.split\('\|'\)/
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var c = 0; c < juicers.length; ++c) {
|
||||||
|
var m, juicer = juicers[c];
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-cond-assign
|
||||||
|
if (m = juicer.exec(str)) {
|
||||||
|
return [m[1], m[4].split('|'), parseInt(m[2]), parseInt(m[3])];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error("Could not make sense of p.a.c.k.e.r data (unexpected code structure)");
|
||||||
|
}
|
||||||
|
|
||||||
|
function _unbaser(base) {
|
||||||
|
if (2 <= base <= 36) return (str) => parseInt(str, base);
|
||||||
|
|
||||||
|
const dictionary = {};
|
||||||
|
var alpha = alphabet[base];
|
||||||
|
if (!alpha) throw new Error("Unsupported encoding");
|
||||||
|
|
||||||
|
for (let c = 0; c < alpha.length; ++alpha) {
|
||||||
|
dictionary[alpha[c]] = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (str) => str.split("").reverse().reduce((cipher, ind) => Math.pow(base, ind) * dictionary[cipher]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function unpack(str) {
|
||||||
|
var params = _filterargs(str);
|
||||||
|
var payload = params[0], symtab = params[1], radix = params[2], count = params[3];
|
||||||
|
|
||||||
|
if (count !== symtab.length) {
|
||||||
|
throw new Error("Malformed p.a.c.k.e.r. symtab. (" + count + " != " + symtab.length + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
var unbase = _unbaser(radix);
|
||||||
|
var lookup = (word) => symtab[unbase(word)] || word;
|
||||||
|
var source = payload.replace(/\b\w+\b/g, lookup);
|
||||||
|
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { unpack };
|
|
@ -4,8 +4,9 @@ import { Card } from '../components/Card'
|
||||||
import { useMovie } from '../hooks/useMovie'
|
import { useMovie } from '../hooks/useMovie'
|
||||||
import { VideoElement } from '../components/VideoElement'
|
import { VideoElement } from '../components/VideoElement'
|
||||||
import { EpisodeSelector } from '../components/EpisodeSelector'
|
import { EpisodeSelector } from '../components/EpisodeSelector'
|
||||||
|
import { getStreamUrl } from '../lib/index'
|
||||||
|
|
||||||
import './Movie.css'
|
import './Movie.css'
|
||||||
import { getStreamUrl } from '../lib/lookMovie'
|
|
||||||
|
|
||||||
export function MovieView(props) {
|
export function MovieView(props) {
|
||||||
const { streamUrl, streamData, setStreamUrl } = useMovie();
|
const { streamUrl, streamData, setStreamUrl } = useMovie();
|
||||||
|
@ -42,7 +43,7 @@ export function MovieView(props) {
|
||||||
}
|
}
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
getStreamUrl(streamData.slug, streamData.type, episode.season, episode.episode)
|
getStreamUrl(streamData.slug, streamData.type, streamData.source, episode.season, episode.episode)
|
||||||
.then(({url}) => {
|
.then(({url}) => {
|
||||||
if (cancel) return;
|
if (cancel) return;
|
||||||
setStreamUrl(url)
|
setStreamUrl(url)
|
||||||
|
@ -105,6 +106,7 @@ export function MovieView(props) {
|
||||||
slug={streamData.slug}
|
slug={streamData.slug}
|
||||||
currentSeason={season}
|
currentSeason={season}
|
||||||
currentEpisode={episode}
|
currentEpisode={episode}
|
||||||
|
source={streamData.source}
|
||||||
/>
|
/>
|
||||||
: ''}
|
: ''}
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { InputBox } from '../components/InputBox'
|
import { InputBox } from '../components/InputBox';
|
||||||
import { Title } from '../components/Title'
|
import { Title } from '../components/Title';
|
||||||
import { Card } from '../components/Card'
|
import { Card } from '../components/Card';
|
||||||
import { ErrorBanner } from '../components/ErrorBanner'
|
import { ErrorBanner } from '../components/ErrorBanner';
|
||||||
import { MovieRow } from '../components/MovieRow'
|
import { MovieRow } from '../components/MovieRow';
|
||||||
import { Arrow } from '../components/Arrow'
|
import { Arrow } from '../components/Arrow';
|
||||||
import { Progress } from '../components/Progress'
|
import { Progress } from '../components/Progress';
|
||||||
import { findContent, getStreamUrl, getEpisodes } from '../lib/lookMovie'
|
import { findContent, getStreamUrl, getEpisodes } from '../lib/index';
|
||||||
import { useMovie } from '../hooks/useMovie';
|
import { useMovie } from '../hooks/useMovie';
|
||||||
import { TypeSelector } from '../components/TypeSelector'
|
import { TypeSelector } from '../components/TypeSelector';
|
||||||
|
|
||||||
import './Search.css'
|
import './Search.css';
|
||||||
|
|
||||||
export function SearchView() {
|
export function SearchView() {
|
||||||
const { navigate, setStreamUrl, setStreamData } = useMovie();
|
const { navigate, setStreamUrl, setStreamData } = useMovie();
|
||||||
|
@ -30,7 +30,7 @@ export function SearchView() {
|
||||||
setFailed(true)
|
setFailed(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getStream(title, slug, type) {
|
async function getStream(title, slug, type, source) {
|
||||||
setStreamUrl("");
|
setStreamUrl("");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -40,21 +40,15 @@ export function SearchView() {
|
||||||
let seasons = [];
|
let seasons = [];
|
||||||
let episodes = [];
|
let episodes = [];
|
||||||
if (type === "show") {
|
if (type === "show") {
|
||||||
const episodeData = await getEpisodes(slug);
|
const data = await getEpisodes(slug, source);
|
||||||
episodeData.forEach((e) => {
|
seasons = data.seasons;
|
||||||
if (!seasons.includes(e.season))
|
episodes = data.episodes;
|
||||||
seasons.push(e.season);
|
|
||||||
|
|
||||||
if (!episodes[e.season])
|
|
||||||
episodes[e.season] = []
|
|
||||||
episodes[e.season].push(e.episode)
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let realUrl = '';
|
let realUrl = '';
|
||||||
if (type === "movie") {
|
if (type === "movie") {
|
||||||
const { url } = await getStreamUrl(slug, type);
|
// getStreamUrl(slug, type, source, season, episode)
|
||||||
|
const { url } = await getStreamUrl(slug, type, source);
|
||||||
|
|
||||||
if (url === '') {
|
if (url === '') {
|
||||||
return fail(`Not found: ${title}`)
|
return fail(`Not found: ${title}`)
|
||||||
|
@ -69,11 +63,13 @@ export function SearchView() {
|
||||||
type,
|
type,
|
||||||
seasons,
|
seasons,
|
||||||
episodes,
|
episodes,
|
||||||
slug
|
slug,
|
||||||
|
source
|
||||||
})
|
})
|
||||||
setText(`Streaming...`)
|
setText(`Streaming...`)
|
||||||
navigate("movie")
|
navigate("movie")
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
fail("Failed to get stream")
|
fail("Failed to get stream")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,7 +81,7 @@ export function SearchView() {
|
||||||
setShowingOptions(false)
|
setShowingOptions(false)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { options } = await findContent(query, contentType)
|
const { options } = await findContent(query, contentType);
|
||||||
|
|
||||||
if (options.length === 0) {
|
if (options.length === 0) {
|
||||||
return fail(`Could not find that ${contentType}`)
|
return fail(`Could not find that ${contentType}`)
|
||||||
|
@ -97,9 +93,10 @@ export function SearchView() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { title, slug, type } = options[0];
|
const { title, slug, type, source } = options[0];
|
||||||
getStream(title, slug, type);
|
getStream(title, slug, type, source);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
fail(`Failed to watch ${contentType}`)
|
fail(`Failed to watch ${contentType}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,9 +137,9 @@ export function SearchView() {
|
||||||
Whoops, there are a few {type}s like that
|
Whoops, there are a few {type}s like that
|
||||||
</Title>
|
</Title>
|
||||||
{options?.map((v, i) => (
|
{options?.map((v, i) => (
|
||||||
<MovieRow key={i} title={v.title} slug={v.slug} type={v.type} year={v.year} season={v.season} episode={v.episode} onClick={() => {
|
<MovieRow key={i} title={v.title} slug={v.slug} type={v.type} year={v.year} source={v.source} onClick={() => {
|
||||||
setShowingOptions(false)
|
setShowingOptions(false)
|
||||||
getStream(v.title, v.slug, v.type, v.season, v.episode)
|
getStream(v.title, v.slug, v.type, v.source)
|
||||||
}}/>
|
}}/>
|
||||||
))}
|
))}
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
@ -3654,6 +3654,11 @@ crypto-browserify@^3.11.0:
|
||||||
randombytes "^2.0.0"
|
randombytes "^2.0.0"
|
||||||
randomfill "^1.0.3"
|
randomfill "^1.0.3"
|
||||||
|
|
||||||
|
crypto-js@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.0.0.tgz#2904ab2677a9d042856a2ea2ef80de92e4a36dcc"
|
||||||
|
integrity sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg==
|
||||||
|
|
||||||
crypto-random-string@^1.0.0:
|
crypto-random-string@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
|
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
|
||||||
|
|
Loading…
Reference in a new issue