diff --git a/src/components/VideoElement.js b/src/components/VideoElement.js
index 35ec011a..9d26ff50 100644
--- a/src/components/VideoElement.js
+++ b/src/components/VideoElement.js
@@ -10,21 +10,23 @@ export function VideoElement({ streamUrl, loading, setProgress }) {
const [error, setError] = React.useState(false);
React.useEffect(() => {
- setError(false)
- if (!videoRef || !videoRef.current || !streamUrl || streamUrl.length === 0 || loading) return;
-
- const hls = new Hls();
-
- if (!Hls.isSupported() && videoRef.current.canPlayType('application/vnd.apple.mpegurl')) {
- videoRef.current.src = streamUrl;
- return;
- } else if (!Hls.isSupported()) {
- setError(true)
- return;
+ if (!streamUrl.endsWith('.mp4')) {
+ setError(false)
+ if (!videoRef || !videoRef.current || !streamUrl || streamUrl.length === 0 || loading) return;
+
+ const hls = new Hls();
+
+ if (!Hls.isSupported() && videoRef.current.canPlayType('application/vnd.apple.mpegurl')) {
+ videoRef.current.src = streamUrl;
+ return;
+ } else if (!Hls.isSupported()) {
+ setError(true)
+ return;
+ }
+
+ hls.attachMedia(videoRef.current);
+ hls.loadSource(streamUrl);
}
-
- hls.attachMedia(videoRef.current);
- hls.loadSource(streamUrl);
}, [videoRef, streamUrl, loading])
if (error)
@@ -36,7 +38,13 @@ export function VideoElement({ streamUrl, loading, setProgress }) {
if (!streamUrl || streamUrl.length === 0)
return No video selected
- return (
-
- )
+ if (!streamUrl.endsWith('.mp4')) {
+ return (
+
+ )
+ } else {
+ return (
+
+ )
+ }
}
diff --git a/src/lib/gomostream.js b/src/lib/gomostream.js
index 954a9333..affebfbf 100644
--- a/src/lib/gomostream.js
+++ b/src/lib/gomostream.js
@@ -1,3 +1,5 @@
+import { unpacker } from './unpacker';
+
const CORS_URL = 'https://hidden-inlet-27205.herokuapp.com/';
const BASE_URL = `${CORS_URL}https://gomo.to`;
const MOVIE_URL = `${BASE_URL}/movie`
@@ -9,37 +11,68 @@ async function findContent(searchTerm, type) {
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 movieId = imdbRes.d[0]?.id
- if(!movieId) {
- return;
+
+ const results = [];
+ imdbRes.d.forEach((e) => {
+ if (!e.id.startsWith('tt')) return;
+
+ results.push({
+ title: e.l,
+ slug: e.id,
+ type: 'movie',
+ year: e.y
+ })
+ });
+
+ if (results.length > 1) {
+ return { options: results };
+ } else {
+ return { options: [results[0]] }
}
- console.log(imdbRes, movieId)
+
+ // const movieId = imdbRes.d[0]?.id
+ // if (!movieId) return;
- // Get stream to go with IMDB ID
- const site1 = await fetch(`${MOVIE_URL}/${movieId}`).then((d) => d.text());
-
- 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());
-
- console.log(src);
- const embedUrl = src.find(url => url.includes('gomo.to'));
- const site2 = await fetch(`${CORS_URL}${embedUrl}`).then((d) => d.text());
} catch (err) {
console.log(err);
throw new Error(err)
}
}
-export { findContent }
\ No newline at end of file
+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());
+
+ 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");
+ const script = site2Dom.querySelectorAll("script")[8].innerHTML;
+
+ let unpacked = unpacker.unpack(script).split('');
+ unpacked.splice(0, 43);
+ let index = unpacked.findIndex((e) => e === '"');
+ const url = unpacked.slice(0, index).join('');
+
+ return { url }
+}
+
+export { findContent, getStreamUrl }
\ No newline at end of file
diff --git a/src/lib/unpacker.js b/src/lib/unpacker.js
new file mode 100644
index 00000000..7031bb4b
--- /dev/null
+++ b/src/lib/unpacker.js
@@ -0,0 +1,46 @@
+/* port of https://github.com/beautify-web/js-beautify/blob/master/python/jsbeautifier/unpackers/packer.py (MIT) */
+const unpacker = {
+ unpack: function (str) {
+ var params = unpacker.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 = unpacker.unbaser(radix);
+ var lookup = (word) => symtab[unbase(word)] || word;
+ var source = payload.replace(/\b\w+\b/g, lookup);
+ return source;
+ },
+ filterargs: function(str) {
+ /* [\s\S] insteadof . because javascript has no dotall modifier */
+ 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)");
+ },
+ alphabet: {
+ 62: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ 95: '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'
+ },
+ unbaser: function(base)
+ {
+ if (2 <= base <= 36) return (str) => parseInt(str, base);
+ var dictionary = {};
+ var alphabet = unpacker.alphabet[base];
+ if (!alphabet) throw new Error("Unsupported encoding");
+ for (var c = 0; c < alphabet.length; ++alphabet) {
+ dictionary[alphabet[c]] = c;
+ }
+ return (str) => str.split("").reverse().reduce((cipher, ind) => Math.pow(base, ind) * dictionary[cipher]);
+ }
+};
+
+export { unpacker };
\ No newline at end of file
diff --git a/src/views/Search.js b/src/views/Search.js
index c50d9a58..6be9256f 100644
--- a/src/views/Search.js
+++ b/src/views/Search.js
@@ -6,7 +6,8 @@ import { ErrorBanner } from '../components/ErrorBanner'
import { MovieRow } from '../components/MovieRow'
import { Arrow } from '../components/Arrow'
import { Progress } from '../components/Progress'
-import { findContent, getStreamUrl, getEpisodes } from '../lib/lookMovie'
+import { /* findContent, getStreamUrl,*/ getEpisodes } from '../lib/lookMovie'
+import { findContent, getStreamUrl } from '../lib/gomostream';
import { useMovie } from '../hooks/useMovie';
import { TypeSelector } from '../components/TypeSelector'