diff --git a/src/components/InputBox.css b/src/components/InputBox.css index d96ddf08..f1480b9c 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,36 @@ padding: .5rem 2.1rem; font-weight: bold; - cursor: pointer; } +.inputDropdown { + border-width: 0; + outline: none; + background-color: #36363e; + color: white; + padding: .7rem 1rem; + height: auto; + width: 25%; + color: white; + font-weight: bold; + cursor: pointer; +} + +.inputOptionBox { + border-width: 0; + outline: none; + background-color: #36363e; + color: white; + height: auto; + width: 10%; + box-sizing: border-box; +} + +.inputDropdown:hover { + background-color: #3C3D44; +} + .inputSearchButton:hover { background-color: #9C3179; } @@ -47,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; @@ -85,9 +114,24 @@ .inputSearchButton { margin-top: .5rem; + align-self: center; } .inputTextBox { + margin-top: .5rem; width: 100%; } + + .inputDropdown { + width: 100%; + padding: .7rem 1.5rem; + } + + .inputOptionBox { + margin-top: .5rem; + width: 50%; + /* align-items:stretch; */ + align-self: center; + padding: .7rem 1.5rem; + } } diff --git a/src/components/InputBox.js b/src/components/InputBox.js index 35e6c1a2..a42900b9 100644 --- a/src/components/InputBox.js +++ b/src/components/InputBox.js @@ -4,23 +4,52 @@ 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 [season, setSeason] = React.useState(""); + const [episode, setEpisode] = React.useState(""); + + const showContentType = type === "show" ? false : true; return (
{ e.preventDefault(); - onSubmit(value) + onSubmit(searchTerm, type, season, episode) return false; }}> + setValue(e.target.value)} + value={searchTerm} + onChange={(e) => setSearchTerm(e.target.value)} + required /> - + setSeason(e.target.value)} + hidden={showContentType} + required={!showContentType} + /> + setEpisode(e.target.value)} + hidden={showContentType} + required={!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 8acb5b00..914fe122 100644 --- a/src/lib/lookMovie.js +++ b/src/lib/lookMovie.js @@ -9,7 +9,13 @@ async function getVideoUrl(config) { 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 +37,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 +53,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 +66,35 @@ 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; + } + } + + if (id === '') { + return { url: '' } + } + const videoUrl = await getVideoUrl({ slug: slug, - movieId: data.id_movie, + id: id, type: type, }); return { url: videoUrl } } -async function findMovie(searchTerm) { - 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 @@ -97,4 +125,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/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/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 6ccafe3d..d40866e1 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' @@ -26,17 +26,24 @@ 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); + + if (url === '') { + return fail(`Not found: ${title} (${season}x${episode})`) + } + setProgress(maxSteps); setStreamUrl(url); setStreamData({ title, type, + season, + episode }) setText(`Streaming...`) navigate("movie") @@ -45,39 +52,44 @@ export function SearchView() { } } - async function searchMovie(query) { + async function searchMovie(query, contentType, season, episode) { setFailed(false); - setText(`Searching for "${query}"`); + setText(`Searching for ${contentType} "${query}" ${contentType === 'show' ? ` (${season}x${episode})` : ''}`); 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) { + options.forEach((o) => { + o.season = season; + o.episode = episode; + }); + setProgress(2); - setText("Choose your movie"); + setText(`Choose your ${contentType}`); setOptions(options); setShowingOptions(true); return; } const { title, slug, type } = options[0]; - getStream(title, slug, type); + getStream(title, slug, type, season, episode); } 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, season, episode)} /> 0} failed={failed} progress={progress} steps={maxSteps} text={text} /> @@ -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) }}/> ))}