From 19891569b753387be4a40e0e8bd4b31008a3f7e0 Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Wed, 14 Jul 2021 16:15:25 +0100 Subject: [PATCH 1/4] begin show implementation --- src/components/InputBox.css | 37 +++++++++++++++++++++++++++++++++++-- src/components/InputBox.js | 20 +++++++++++++++----- src/lib/lookMovie.js | 4 ++-- src/views/Search.js | 20 ++++++++++---------- 4 files changed, 62 insertions(+), 19 deletions(-) diff --git a/src/components/InputBox.css b/src/components/InputBox.css index d96ddf08..bed5eb06 100644 --- a/src/components/InputBox.css +++ b/src/components/InputBox.css @@ -19,7 +19,6 @@ .inputTextBox { border-width: 0; outline: none; - background-color: #36363e; color: white; padding: .7rem 1.5rem; @@ -35,10 +34,38 @@ padding: .5rem 2.1rem; font-weight: bold; - cursor: pointer; } +.inputDropdown { + border-width: 0; + outline: none; + background-color: #36363e; + color: white; + padding: .7rem; + height: auto; + width: 20%; + color: white; + + font-weight: bold; + cursor: pointer; +} + +.inputOptionBox { + border-width: 0; + outline: none; + background-color: #36363e; + color: white; + /* padding: .7rem 1.5rem; */ + height: auto; + width: 5%; + box-sizing: border-box; +} + +.inputDropdown:hover { + background-color: #3C3D44; +} + .inputSearchButton:hover { background-color: #9C3179; } @@ -85,9 +112,15 @@ .inputSearchButton { margin-top: .5rem; + align-self: center; } .inputTextBox { width: 100%; } + + .inputDropdown { + width: 100%; + margin-bottom: .5rem; + } } diff --git a/src/components/InputBox.js b/src/components/InputBox.js index 35e6c1a2..eaaa387b 100644 --- a/src/components/InputBox.js +++ b/src/components/InputBox.js @@ -4,23 +4,33 @@ import './InputBox.css' // props = { onSubmit: (str) => {}, placeholder: string} export function InputBox({ onSubmit, placeholder }) { - const [value, setValue] = React.useState(""); + const [searchTerm, setSearchTerm] = React.useState(""); + const [type, setType] = React.useState("movie"); + + const showContentType = type === "show" ? false : true; return (
{ e.preventDefault(); - onSubmit(value) + onSubmit(searchTerm, type) return false; }}> + setValue(e.target.value)} + value={searchTerm} + onChange={(e) => setSearchTerm(e.target.value)} + required /> - + + +
) } diff --git a/src/lib/lookMovie.js b/src/lib/lookMovie.js index 8acb5b00..fc379f4c 100644 --- a/src/lib/lookMovie.js +++ b/src/lib/lookMovie.js @@ -63,7 +63,7 @@ async function getStreamUrl(slug, type) { return { url: videoUrl } } -async function findMovie(searchTerm) { +async function findContent(searchTerm, type) { const searchUrl = getCorsUrl(`https://lookmovie.io/api/v1/movies/search/?q=${encodeURIComponent(searchTerm)}`); const searchRes = await fetch(searchUrl).then((d) => d.json()); let results = [...searchRes.result.map((v) => ({ ...v, type: "movie" }))]; @@ -97,4 +97,4 @@ async function findMovie(searchTerm) { } } -export { findMovie, getStreamUrl }; \ No newline at end of file +export { findContent, getStreamUrl }; \ No newline at end of file diff --git a/src/views/Search.js b/src/views/Search.js index 6ccafe3d..7ce3fc48 100644 --- a/src/views/Search.js +++ b/src/views/Search.js @@ -5,7 +5,7 @@ import { Card } from '../components/Card' import { MovieRow } from '../components/MovieRow' import { Arrow } from '../components/Arrow' import { Progress } from '../components/Progress' -import { findMovie, getStreamUrl } from '../lib/lookMovie' +import { findContent, getStreamUrl } from '../lib/lookMovie' import { useMovie } from '../hooks/useMovie'; import './Search.css' @@ -45,20 +45,20 @@ export function SearchView() { } } - async function searchMovie(query) { + async function searchMovie(query, contentType) { setFailed(false); - setText(`Searching for "${query}"`); + setText(`Searching for ${contentType} "${query}"`); setProgress(1) setShowingOptions(false) try { - const { options } = await findMovie(query) + const { options } = await findContent(query, contentType) if (options.length === 0) { - return fail("Could not find that movie") + return fail(`Could not find that ${contentType}`) } else if (options.length > 1) { setProgress(2); - setText("Choose your movie"); + setText(`Choose your ${contentType}`); setOptions(options); setShowingOptions(true); return; @@ -67,17 +67,17 @@ export function SearchView() { const { title, slug, type } = options[0]; getStream(title, slug, type); } catch (err) { - fail("Failed to watch movie") + fail(`Failed to watch ${contentType}`) } } return (
- - What movie do you wanna watch? + <Title accent="Because watching content legally is boring"> + What do you wanna watch? - searchMovie(str)} /> + searchMovie(str, type)} /> 0} failed={failed} progress={progress} steps={maxSteps} text={text} /> From 32a8518193a8034550a97b17a3ddfd212b1129f2 Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Wed, 14 Jul 2021 17:31:35 +0100 Subject: [PATCH 2/4] shows work! --- src/components/InputBox.css | 20 ++++++++++++---- src/components/InputBox.js | 25 +++++++++++++++++--- src/lib/lookMovie.js | 39 ++++++++++++++++++++++++++------ src/serviceWorkerRegistration.js | 6 ----- src/views/Search.js | 12 +++++----- 5 files changed, 75 insertions(+), 27 deletions(-) diff --git a/src/components/InputBox.css b/src/components/InputBox.css index bed5eb06..f7d2b16d 100644 --- a/src/components/InputBox.css +++ b/src/components/InputBox.css @@ -42,11 +42,10 @@ outline: none; background-color: #36363e; color: white; - padding: .7rem; + padding: .7rem 1rem; height: auto; - width: 20%; + width: 25%; color: white; - font-weight: bold; cursor: pointer; } @@ -56,7 +55,6 @@ outline: none; background-color: #36363e; color: white; - /* padding: .7rem 1.5rem; */ height: auto; width: 5%; box-sizing: border-box; @@ -74,6 +72,10 @@ background-color: #3C3D44; } +.inputOptionBox:hover { + background-color: #3C3D44; +} + .inputSearchButton .text > .arrow { opacity: 0; transition: opacity 0.2s ease-in-out, transform 0.2s ease-in-out; @@ -116,11 +118,19 @@ } .inputTextBox { + margin-top: .5rem; width: 100%; } .inputDropdown { width: 100%; - margin-bottom: .5rem; + padding: .7rem 1.5rem; + } + + .inputOptionBox { + margin-top: .5rem; + width: 50%; + align-items:stretch; + padding: .7rem 1.5rem; } } diff --git a/src/components/InputBox.js b/src/components/InputBox.js index eaaa387b..a392733c 100644 --- a/src/components/InputBox.js +++ b/src/components/InputBox.js @@ -6,13 +6,15 @@ import './InputBox.css' export function InputBox({ onSubmit, placeholder }) { const [searchTerm, setSearchTerm] = React.useState(""); const [type, setType] = React.useState("movie"); + const [season, setSeason] = React.useState(""); + const [episode, setEpisode] = React.useState(""); const showContentType = type === "show" ? false : true; return (
{ e.preventDefault(); - onSubmit(searchTerm, type) + onSubmit(searchTerm, type, season, episode) return false; }}> - + setSeason(e.target.value)} + hidden={showContentType} + required={!showContentType} + /> + setEpisode(e.target.value)} + hidden={showContentType} + required={!showContentType} />
) diff --git a/src/lib/lookMovie.js b/src/lib/lookMovie.js index fc379f4c..9c3014f1 100644 --- a/src/lib/lookMovie.js +++ b/src/lib/lookMovie.js @@ -6,10 +6,17 @@ function getCorsUrl(url) { } async function getVideoUrl(config) { + // return getCorsUrl('https://vdoc1.sallenes.space/_eTeNnlOAFdWb-gPYTiQfg/1626297249/storage3/shows/0413573-greys-anatomy-2005/6-S1E1-1553949090/720p/v2-index.m3u8'); const accessToken = await getAccessToken(config); const now = Math.floor(Date.now() / 1e3); - let url = getCorsUrl(`https://lookmovie.io/manifests/movies/json/${config.movieId}/${now}/${accessToken}/master.m3u8`); + let url = ''; + + if (config.type === 'movie') { + url = getCorsUrl(`https://lookmovie.io/manifests/movies/json/${config.id}/${now}/${accessToken}/master.m3u8`); + } else if (config.type === 'show') { + 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()); @@ -31,7 +38,13 @@ async function getVideoUrl(config) { } async function getAccessToken(config) { - let url = getCorsUrl(`https://lookmovie.io/api/v1/security/movie-access?id_movie=${config.movieId}&token=1&sk=&step=1`); + let url = ''; + + if (config.type === 'movie') { + url = getCorsUrl(`https://lookmovie.io/api/v1/security/movie-access?id_movie=${config.id}&token=1&sk=&step=1`); + } else if (config.type === 'show') { + url = getCorsUrl(`https://lookmovie.io/api/v1/security/show-access?slug=${config.slug}&token=&step=2`); + } const data = await fetch(url).then((d) => d.json()); @@ -41,7 +54,7 @@ async function getAccessToken(config) { return "Invalid type provided in config"; } -async function getStreamUrl(slug, type) { +async function getStreamUrl(slug, type, season, episode) { const url = getCorsUrl(`https://lookmovie.io/${type}s/view/${slug}`); const pageReq = await fetch(url).then((d) => d.text()); @@ -54,19 +67,31 @@ async function getStreamUrl(slug, type) { "}" ); + let id = ''; + + if (type === "movie") { + id = data.id_movie; + } else if (type === "show") { + const episodeObj = data.seasons.find((v) => { return v.season === season && v.episode === episode; }); + + if (episodeObj) { + id = episodeObj.id_episode; + } + } + const videoUrl = await getVideoUrl({ slug: slug, - movieId: data.id_movie, + id: id, type: type, }); return { url: videoUrl } } -async function findContent(searchTerm, type) { - const searchUrl = getCorsUrl(`https://lookmovie.io/api/v1/movies/search/?q=${encodeURIComponent(searchTerm)}`); +async function findContent(searchTerm, type) { + const searchUrl = getCorsUrl(`https://lookmovie.io/api/v1/${type}s/search/?q=${encodeURIComponent(searchTerm)}`); const searchRes = await fetch(searchUrl).then((d) => d.json()); - let results = [...searchRes.result.map((v) => ({ ...v, type: "movie" }))]; + const results = [...searchRes.result.map((v) => ({ ...v, type: type}))]; const fuse = new Fuse(results, { threshold: 0.3, distance: 200, keys: ["title"] }); const matchedResults = fuse diff --git a/src/serviceWorkerRegistration.js b/src/serviceWorkerRegistration.js index 26468c7c..a96b00d5 100644 --- a/src/serviceWorkerRegistration.js +++ b/src/serviceWorkerRegistration.js @@ -55,10 +55,6 @@ function registerValidSW(swUrl, config) { // At this point, the updated precached content has been fetched, // but the previous service worker will still serve the older // content until all client tabs are closed. - console.log( - 'New content is available and will be used when all ' + - 'tabs for this page are closed. See https://cra.link/PWA.' - ); // Execute callback if (config && config.onUpdate) { @@ -68,7 +64,6 @@ function registerValidSW(swUrl, config) { // At this point, everything has been precached. // It's the perfect time to display a // "Content is cached for offline use." message. - console.log('Content is cached for offline use.'); // Execute callback if (config && config.onSuccess) { @@ -108,7 +103,6 @@ function checkValidServiceWorker(swUrl, config) { } }) .catch(() => { - console.log('No internet connection found. App is running in offline mode.'); }); } diff --git a/src/views/Search.js b/src/views/Search.js index 7ce3fc48..f6ef4912 100644 --- a/src/views/Search.js +++ b/src/views/Search.js @@ -26,12 +26,12 @@ export function SearchView() { setFailed(true) } - async function getStream(title, slug, type) { + async function getStream(title, slug, type, season, episode) { setStreamUrl(""); try { setProgress(2); setText(`Getting stream for "${title}"`) - const { url } = await getStreamUrl(slug, type); + const { url } = await getStreamUrl(slug, type, season, episode); setProgress(maxSteps); setStreamUrl(url); setStreamData({ @@ -45,9 +45,9 @@ export function SearchView() { } } - async function searchMovie(query, contentType) { + async function searchMovie(query, contentType, season, episode) { setFailed(false); - setText(`Searching for ${contentType} "${query}"`); + setText(`Searching for ${contentType} "${query}" ${contentType === 'show' ? ` (${season}x${episode})` : ''}`); setProgress(1) setShowingOptions(false) @@ -65,7 +65,7 @@ export function SearchView() { } const { title, slug, type } = options[0]; - getStream(title, slug, type); + getStream(title, slug, type, season, episode); } catch (err) { fail(`Failed to watch ${contentType}`) } @@ -77,7 +77,7 @@ export function SearchView() { What do you wanna watch? - searchMovie(str, type)} /> + searchMovie(str, type, season, episode)} /> 0} failed={failed} progress={progress} steps={maxSteps} text={text} /> From 3bd0e7a69e239e766fd0c62bf4f17eeec10baaff Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Wed, 14 Jul 2021 18:03:10 +0100 Subject: [PATCH 3/4] Finished show support --- src/components/InputBox.css | 5 +++-- src/components/InputBox.js | 4 ++-- src/components/MovieRow.js | 1 + src/components/Title.css | 2 +- src/lib/lookMovie.js | 4 ++++ src/views/Movie.js | 2 +- src/views/Search.js | 16 ++++++++++++++-- 7 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/components/InputBox.css b/src/components/InputBox.css index f7d2b16d..f1480b9c 100644 --- a/src/components/InputBox.css +++ b/src/components/InputBox.css @@ -56,7 +56,7 @@ background-color: #36363e; color: white; height: auto; - width: 5%; + width: 10%; box-sizing: border-box; } @@ -130,7 +130,8 @@ .inputOptionBox { margin-top: .5rem; width: 50%; - align-items:stretch; + /* align-items:stretch; */ + align-self: center; padding: .7rem 1.5rem; } } diff --git a/src/components/InputBox.js b/src/components/InputBox.js index a392733c..a42900b9 100644 --- a/src/components/InputBox.js +++ b/src/components/InputBox.js @@ -34,7 +34,7 @@ export function InputBox({ onSubmit, placeholder }) { type='text' className='inputOptionBox' id='inputOptionBoxSeason' - placeholder='season' + placeholder='Season' value={season} onChange={(e) => setSeason(e.target.value)} hidden={showContentType} @@ -44,7 +44,7 @@ export function InputBox({ onSubmit, placeholder }) { type='text' className='inputOptionBox' id='inputOptionBoxEpisode' - placeholder='episode' + placeholder='Episode' value={episode} onChange={(e) => setEpisode(e.target.value)} hidden={showContentType} diff --git a/src/components/MovieRow.js b/src/components/MovieRow.js index a3ae80bd..c304aa4d 100644 --- a/src/components/MovieRow.js +++ b/src/components/MovieRow.js @@ -12,6 +12,7 @@ export function MovieRow(props) { ({props.year})
+

Watch {props.type}

diff --git a/src/components/Title.css b/src/components/Title.css index bd1790ed..6796dce9 100644 --- a/src/components/Title.css +++ b/src/components/Title.css @@ -1,7 +1,7 @@ .title { font-size: 2rem; color: white; - max-width: 20rem; + /* max-width: 20rem; */ margin: 0; padding: 0; margin-bottom: 3.5rem; diff --git a/src/lib/lookMovie.js b/src/lib/lookMovie.js index 9c3014f1..b6d19178 100644 --- a/src/lib/lookMovie.js +++ b/src/lib/lookMovie.js @@ -79,6 +79,10 @@ async function getStreamUrl(slug, type, season, episode) { } } + if (id === '') { + return { url: '' } + } + const videoUrl = await getVideoUrl({ slug: slug, id: id, diff --git a/src/views/Movie.js b/src/views/Movie.js index d0f9a83e..a1b3438d 100644 --- a/src/views/Movie.js +++ b/src/views/Movie.js @@ -11,7 +11,7 @@ export function MovieView(props) {
- { streamData.title } + {streamData.title} {streamData.type === "show" ? `(${streamData.season}x${streamData.episode})` : '' } diff --git a/src/views/Search.js b/src/views/Search.js index f6ef4912..d40866e1 100644 --- a/src/views/Search.js +++ b/src/views/Search.js @@ -32,11 +32,18 @@ export function SearchView() { setProgress(2); setText(`Getting stream for "${title}"`) const { url } = await getStreamUrl(slug, type, season, episode); + + if (url === '') { + return fail(`Not found: ${title} (${season}x${episode})`) + } + setProgress(maxSteps); setStreamUrl(url); setStreamData({ title, type, + season, + episode }) setText(`Streaming...`) navigate("movie") @@ -57,6 +64,11 @@ export function SearchView() { if (options.length === 0) { return fail(`Could not find that ${contentType}`) } else if (options.length > 1) { + options.forEach((o) => { + o.season = season; + o.episode = episode; + }); + setProgress(2); setText(`Choose your ${contentType}`); setOptions(options); @@ -86,9 +98,9 @@ export function SearchView() { Whoops, there are a few movies like that {options?.map((v, i) => ( - { + { setShowingOptions(false) - getStream(v.title, v.slug, v.type) + getStream(v.title, v.slug, v.type, v.season, v.episode) }}/> ))} From fd708f2e5c65c41c993a063d26b4f99c8ed8eae7 Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Wed, 14 Jul 2021 18:04:45 +0100 Subject: [PATCH 4/4] Remove comment --- src/lib/lookMovie.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib/lookMovie.js b/src/lib/lookMovie.js index b6d19178..914fe122 100644 --- a/src/lib/lookMovie.js +++ b/src/lib/lookMovie.js @@ -6,7 +6,6 @@ function getCorsUrl(url) { } async function getVideoUrl(config) { - // return getCorsUrl('https://vdoc1.sallenes.space/_eTeNnlOAFdWb-gPYTiQfg/1626297249/storage3/shows/0413573-greys-anatomy-2005/6-S1E1-1553949090/720p/v2-index.m3u8'); const accessToken = await getAccessToken(config); const now = Math.floor(Date.now() / 1e3);