From b8ab630f0a7eccf177035ee25c25d0c8a07d6ac7 Mon Sep 17 00:00:00 2001 From: Jip Fr <jipfrijlink@gmail.com> Date: Thu, 15 Jul 2021 20:15:41 +0200 Subject: [PATCH 1/5] style(selector): fix search type selection on mobile --- src/components/TypeSelector.css | 5 +++-- src/components/TypeSelector.js | 4 ++-- src/views/Search.js | 1 + 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/TypeSelector.css b/src/components/TypeSelector.css index 80902e74..2a3d0743 100644 --- a/src/components/TypeSelector.css +++ b/src/components/TypeSelector.css @@ -5,6 +5,8 @@ position: relative; margin-bottom: 1.5rem; max-width: 100%; +} +.typeSelector:not(.nowrap) { flex-wrap: wrap; } @@ -52,8 +54,7 @@ } @media screen and (max-width: 700px) { - .typeSelector { - width: 80%; + .typeSelector:not(.nowrap) { display: block; } } diff --git a/src/components/TypeSelector.js b/src/components/TypeSelector.js index ee96b275..05f545e3 100644 --- a/src/components/TypeSelector.js +++ b/src/components/TypeSelector.js @@ -5,14 +5,14 @@ import './TypeSelector.css' // setType: (txt: string) => void // choices: { label: string, value: string }[] // selected: string -export function TypeSelector({ setType, choices, selected }) { +export function TypeSelector({ setType, choices, selected, noWrap = false }) { const selectedIndex = choices.findIndex(v=>v.value===selected); const transformStyles = { opacity: selectedIndex!==-1?1:0, transform: `translateX(${selectedIndex!==-1?selectedIndex*7:0}rem)` } return ( - <div className="typeSelector"> + <div className={`typeSelector ${noWrap ? 'nowrap' : ''}`}> {choices.map(v=>( <div key={v.value} className={`choice ${selected===v.value?'selected':''}`} onClick={() => setType(v.value)}> {v.label} diff --git a/src/views/Search.js b/src/views/Search.js index 67b0179c..14d60b50 100644 --- a/src/views/Search.js +++ b/src/views/Search.js @@ -115,6 +115,7 @@ export function SearchView() { { label: "Movie", value: "movie" }, { label: "TV Show", value: "show" } ]} + noWrap={true} selected={type} /> <InputBox placeholder={ type === "movie" ? "Hamilton" : "Atypical" } onSubmit={(str) => searchMovie(str, type)} /> From cb29acb38c687ee8eeacb49bd7635b39b006a180 Mon Sep 17 00:00:00 2001 From: Jip Fr <jipfrijlink@gmail.com> Date: Thu, 15 Jul 2021 20:34:25 +0200 Subject: [PATCH 2/5] feat(video): store progress --- src/components/VideoElement.css | 2 +- src/components/VideoElement.js | 4 ++-- src/views/Movie.js | 31 ++++++++++++++++++++++++++++++- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/components/VideoElement.css b/src/components/VideoElement.css index cff2fd1d..f252de55 100644 --- a/src/components/VideoElement.css +++ b/src/components/VideoElement.css @@ -1,6 +1,6 @@ .videoElement { width: 100%; - background-color: var(--content); + background-color: black; border-radius: 5px; } diff --git a/src/components/VideoElement.js b/src/components/VideoElement.js index f1aa506a..35ec011a 100644 --- a/src/components/VideoElement.js +++ b/src/components/VideoElement.js @@ -5,7 +5,7 @@ import { VideoPlaceholder } from './VideoPlaceholder' // streamUrl: string // loading: boolean -export function VideoElement({ streamUrl, loading }) { +export function VideoElement({ streamUrl, loading, setProgress }) { const videoRef = React.useRef(null); const [error, setError] = React.useState(false); @@ -37,6 +37,6 @@ export function VideoElement({ streamUrl, loading }) { return <VideoPlaceholder>No video selected</VideoPlaceholder> return ( - <video className="videoElement" ref={videoRef} controls autoPlay /> + <video className="videoElement" ref={videoRef} controls autoPlay onProgress={setProgress} /> ) } diff --git a/src/views/Movie.js b/src/views/Movie.js index 18a00056..2b576b4b 100644 --- a/src/views/Movie.js +++ b/src/views/Movie.js @@ -57,6 +57,35 @@ export function MovieView(props) { } }, [episode, streamData, setStreamUrl]) + const setProgress = (evt) => { + console.log(streamData.slug, evt) + console.log(streamData) + let ls = JSON.parse(localStorage.getItem("video-progress") || "{}") + + // We're just checking lookmovie for now since there is only one scraper + if(!ls.lookmovie) ls.lookmovie = {} + if(!ls.lookmovie[streamData.type]) ls.lookmovie[streamData.type] = {} + if(!ls.lookmovie[streamData.type][streamData.slug]) { + ls.lookmovie[streamData.type][streamData.slug] = {} + } + + // Store real data + let key = streamData.type === "show" ? `${season}-${episode.episode}` : "full" + ls.lookmovie[streamData.type][streamData.slug][key] = { + currentlyAt: Math.floor(evt.currentTarget.currentTime), + totalDuration: Math.floor(evt.currentTarget.duration) + } + + if(streamData.type === "show") { + ls.lookmovie[streamData.type][streamData.slug][key].show = { + season, + episode: episode.episode + } + } + + localStorage.setItem("video-progress", JSON.stringify(ls)) + } + return ( <div className={`cardView showType-${streamData.type}`}> <Card fullWidth> @@ -66,7 +95,7 @@ export function MovieView(props) { {streamData.type === "show" ? <Title size="small"> Season {episode.season}: Episode {episode.episode} </Title> : undefined} - <VideoElement streamUrl={streamUrl} loading={loading}/> + <VideoElement streamUrl={streamUrl} loading={loading} setProgress={setProgress} /> {streamData.type === "show" ? <EpisodeSelector setSeason={setSeason} From 2b8878ed9aacfb302b8e7012e634eb740b381617 Mon Sep 17 00:00:00 2001 From: Jip Fr <jipfrijlink@gmail.com> Date: Thu, 15 Jul 2021 21:04:47 +0200 Subject: [PATCH 3/5] feat(progress): episode selector progress indicator --- src/components/EpisodeSelector.js | 29 +++++++++++++++++++++++++++-- src/components/NumberSelector.css | 16 +++++++++++++++- src/components/NumberSelector.js | 12 +++++++++++- src/views/Movie.js | 9 +++++---- 4 files changed, 58 insertions(+), 8 deletions(-) diff --git a/src/components/EpisodeSelector.js b/src/components/EpisodeSelector.js index e2281106..447a83cd 100644 --- a/src/components/EpisodeSelector.js +++ b/src/components/EpisodeSelector.js @@ -3,11 +3,36 @@ import { TypeSelector } from './TypeSelector'; import { NumberSelector } from './NumberSelector'; import './EpisodeSelector.css' -export function EpisodeSelector({ setSeason, setEpisode, seasons, episodes, currentSeason, currentEpisode }) { +export function EpisodeSelector({ setSeason, setEpisode, seasons, season, episodes, currentSeason, currentEpisode, slug }) { + + const choices = episodes.map(v => { + console.log(slug, season, v) + + let progressData = JSON.parse(localStorage.getItem('video-progress') || "{}") + + let currentlyAt = 0; + let totalDuration = 0; + + const progress = progressData?.lookmovie?.show?.[slug][`${season}-${v}`] + if(progress) { + console.log(progress) + currentlyAt = progress.currentlyAt + totalDuration = progress.totalDuration + } + + const percentage = Math.round((currentlyAt / totalDuration) * 100) + + return { + value: v.toString(), + label: v, + percentage + } + }) + return ( <div className="episodeSelector"> <TypeSelector setType={setSeason} choices={seasons.map(v=>({ value: v.toString(), label: `Season ${v}`}))} selected={currentSeason}/><br></br> - <NumberSelector setType={(e) => setEpisode({episode: e, season: currentSeason})} choices={episodes.map(v=>({ value: v.toString(), label: v}))} selected={currentEpisode.season === currentSeason?currentEpisode.episode:null}/> + <NumberSelector setType={(e) => setEpisode({episode: e, season: currentSeason})} choices={choices} selected={currentEpisode.season === currentSeason?currentEpisode.episode:null}/> </div> ) } diff --git a/src/components/NumberSelector.css b/src/components/NumberSelector.css index 21de53d1..87faf308 100644 --- a/src/components/NumberSelector.css +++ b/src/components/NumberSelector.css @@ -8,6 +8,8 @@ .numberSelector .choiceWrapper { position: relative; + border-radius: 10%; + overflow: hidden; } .numberSelector .choiceWrapper::before { @@ -34,7 +36,6 @@ font-weight: bold; cursor: pointer; user-select: none; - border-radius: 10%; box-sizing: border-box; } @@ -46,3 +47,16 @@ color: var(--choice-active-text, var(--text)); background-color: var(--choice-active); } + +.numberSelector .progressBar { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0.2; +} +.numberSelector .progressBarInner { + background: var(--theme-color); + height: 100%; +} \ No newline at end of file diff --git a/src/components/NumberSelector.js b/src/components/NumberSelector.js index ecbf9658..99742c9f 100644 --- a/src/components/NumberSelector.js +++ b/src/components/NumberSelector.js @@ -6,12 +6,22 @@ import './NumberSelector.css' // choices: { label: string, value: string }[] // selected: string export function NumberSelector({ setType, choices, selected }) { + + choices.forEach(choice => { + if(choice.percentage > 3) choice.percentage = Math.max(20, choice.percentage < 90 ? choice.percentage : 100) + }) + return ( <div className="numberSelector"> {choices.map(v=>( <div key={v.value} className="choiceWrapper"> - <div className={`choice ${selected&&selected===v.value?'selected':''}`} onClick={() => setType(v.value)}> + <div className={`choice ${selected&&selected===v.value?'selected':''}`} onClick={() => setType(v.value)}> {v.label} + {v.percentage > 0 ? ( + <div class="progressBar"> + <div class="progressBarInner" style={{width: `${v.percentage}%`}}></div> + </div> + ) : ''} </div> </div> ))} diff --git a/src/views/Movie.js b/src/views/Movie.js index 2b576b4b..ac8db275 100644 --- a/src/views/Movie.js +++ b/src/views/Movie.js @@ -54,12 +54,10 @@ export function MovieView(props) { }) return () => { cancel = true; - } + } }, [episode, streamData, setStreamUrl]) const setProgress = (evt) => { - console.log(streamData.slug, evt) - console.log(streamData) let ls = JSON.parse(localStorage.getItem("video-progress") || "{}") // We're just checking lookmovie for now since there is only one scraper @@ -73,7 +71,8 @@ export function MovieView(props) { let key = streamData.type === "show" ? `${season}-${episode.episode}` : "full" ls.lookmovie[streamData.type][streamData.slug][key] = { currentlyAt: Math.floor(evt.currentTarget.currentTime), - totalDuration: Math.floor(evt.currentTarget.duration) + totalDuration: Math.floor(evt.currentTarget.duration), + updatedAt: Date.now() } if(streamData.type === "show") { @@ -100,8 +99,10 @@ export function MovieView(props) { <EpisodeSelector setSeason={setSeason} setEpisode={setEpisode} + season={season} seasons={seasonList} episodes={episodeLists} + slug={streamData.slug} currentSeason={season} currentEpisode={episode} /> From 95cb59fcf627b0319aa8ade933bb3dd91cb6aba5 Mon Sep 17 00:00:00 2001 From: Jip Fr <jipfrijlink@gmail.com> Date: Thu, 15 Jul 2021 21:24:11 +0200 Subject: [PATCH 4/5] feat(progress): add progress in search on MovieRow --- src/components/MovieRow.css | 2 ++ src/components/MovieRow.js | 16 ++++++++++++++++ src/components/NumberSelector.css | 12 ------------ src/components/NumberSelector.js | 12 ++---------- src/components/PercentageOverlay.css | 12 ++++++++++++ src/components/PercentageOverlay.js | 13 +++++++++++++ src/views/Search.js | 2 +- 7 files changed, 46 insertions(+), 23 deletions(-) create mode 100644 src/components/PercentageOverlay.css create mode 100644 src/components/PercentageOverlay.js diff --git a/src/components/MovieRow.css b/src/components/MovieRow.css index 99a6cad0..a32463b5 100644 --- a/src/components/MovieRow.css +++ b/src/components/MovieRow.css @@ -1,4 +1,5 @@ .movieRow { + position: relative; display: flex; border-radius: 5px; background-color: var(--content); @@ -8,6 +9,7 @@ cursor: pointer; transition: transform 50ms ease-in-out; user-select: none; + overflow: hidden; } .movieRow p { diff --git a/src/components/MovieRow.js b/src/components/MovieRow.js index a3ae80bd..00a7d883 100644 --- a/src/components/MovieRow.js +++ b/src/components/MovieRow.js @@ -1,10 +1,25 @@ import React from 'react' import { Arrow } from './Arrow' import './MovieRow.css' +import { PercentageOverlay } from './PercentageOverlay' // title: string // onClick: () => void export function MovieRow(props) { + console.log(props) + + const progressData = JSON.parse(localStorage.getItem("video-progress") || "{}") + let progress; + let percentage = null; + if(props.type === "movie") { + progress = progressData?.lookmovie?.movie?.[props.slug]?.full + if(progress) { + console.log(progress) + percentage = Math.floor((progress.currentlyAt / progress.totalDuration) * 100) + } + } + console.log(percentage) + return ( <div className="movieRow" onClick={() => props.onClick && props.onClick()}> <div className="left"> @@ -15,6 +30,7 @@ export function MovieRow(props) { <p>Watch {props.type}</p> <Arrow/> </div> + <PercentageOverlay percentage={percentage} /> </div> ) } diff --git a/src/components/NumberSelector.css b/src/components/NumberSelector.css index 87faf308..3c8d5f06 100644 --- a/src/components/NumberSelector.css +++ b/src/components/NumberSelector.css @@ -48,15 +48,3 @@ background-color: var(--choice-active); } -.numberSelector .progressBar { - position: absolute; - bottom: 0; - left: 0; - width: 100%; - height: 100%; - opacity: 0.2; -} -.numberSelector .progressBarInner { - background: var(--theme-color); - height: 100%; -} \ No newline at end of file diff --git a/src/components/NumberSelector.js b/src/components/NumberSelector.js index 99742c9f..1bcf3d20 100644 --- a/src/components/NumberSelector.js +++ b/src/components/NumberSelector.js @@ -1,27 +1,19 @@ import React from 'react'; // import { Arrow } from './Arrow'; import './NumberSelector.css' +import { PercentageOverlay } from './PercentageOverlay'; // setType: (txt: string) => void // choices: { label: string, value: string }[] // selected: string export function NumberSelector({ setType, choices, selected }) { - - choices.forEach(choice => { - if(choice.percentage > 3) choice.percentage = Math.max(20, choice.percentage < 90 ? choice.percentage : 100) - }) - return ( <div className="numberSelector"> {choices.map(v=>( <div key={v.value} className="choiceWrapper"> <div className={`choice ${selected&&selected===v.value?'selected':''}`} onClick={() => setType(v.value)}> {v.label} - {v.percentage > 0 ? ( - <div class="progressBar"> - <div class="progressBarInner" style={{width: `${v.percentage}%`}}></div> - </div> - ) : ''} + <PercentageOverlay percentage={v.percentage} /> </div> </div> ))} diff --git a/src/components/PercentageOverlay.css b/src/components/PercentageOverlay.css new file mode 100644 index 00000000..259f25dd --- /dev/null +++ b/src/components/PercentageOverlay.css @@ -0,0 +1,12 @@ +.progressBar { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0.2; +} +.progressBarInner { + background: var(--theme-color); + height: 100%; +} \ No newline at end of file diff --git a/src/components/PercentageOverlay.js b/src/components/PercentageOverlay.js new file mode 100644 index 00000000..50a23a0a --- /dev/null +++ b/src/components/PercentageOverlay.js @@ -0,0 +1,13 @@ +import React from 'react' +import './PercentageOverlay.css' + +export function PercentageOverlay({ percentage }) { + + if(percentage && percentage > 3) percentage = Math.max(20, percentage < 90 ? percentage : 100) + + return percentage > 0 ? ( + <div class="progressBar"> + <div class="progressBarInner" style={{width: `${percentage}%`}}></div> + </div> + ) : <React.Fragment></React.Fragment> +} \ No newline at end of file diff --git a/src/views/Search.js b/src/views/Search.js index 14d60b50..c4ef950e 100644 --- a/src/views/Search.js +++ b/src/views/Search.js @@ -127,7 +127,7 @@ export function SearchView() { Whoops, there are a few {type}s like that </Title> {options?.map((v, i) => ( - <MovieRow key={i} title={v.title} 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} season={v.season} episode={v.episode} onClick={() => { setShowingOptions(false) getStream(v.title, v.slug, v.type, v.season, v.episode) }}/> From b67ab4995f8f25d7f5c138b59e2b6f68749b4123 Mon Sep 17 00:00:00 2001 From: Jip Fr <jipfrijlink@gmail.com> Date: Thu, 15 Jul 2021 21:25:50 +0200 Subject: [PATCH 5/5] chore: remove console.logs --- src/components/EpisodeSelector.js | 2 -- src/components/MovieRow.js | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/components/EpisodeSelector.js b/src/components/EpisodeSelector.js index 447a83cd..74a95dda 100644 --- a/src/components/EpisodeSelector.js +++ b/src/components/EpisodeSelector.js @@ -6,7 +6,6 @@ import './EpisodeSelector.css' export function EpisodeSelector({ setSeason, setEpisode, seasons, season, episodes, currentSeason, currentEpisode, slug }) { const choices = episodes.map(v => { - console.log(slug, season, v) let progressData = JSON.parse(localStorage.getItem('video-progress') || "{}") @@ -15,7 +14,6 @@ export function EpisodeSelector({ setSeason, setEpisode, seasons, season, episod const progress = progressData?.lookmovie?.show?.[slug][`${season}-${v}`] if(progress) { - console.log(progress) currentlyAt = progress.currentlyAt totalDuration = progress.totalDuration } diff --git a/src/components/MovieRow.js b/src/components/MovieRow.js index 00a7d883..9473dfa0 100644 --- a/src/components/MovieRow.js +++ b/src/components/MovieRow.js @@ -6,7 +6,6 @@ import { PercentageOverlay } from './PercentageOverlay' // title: string // onClick: () => void export function MovieRow(props) { - console.log(props) const progressData = JSON.parse(localStorage.getItem("video-progress") || "{}") let progress; @@ -14,11 +13,9 @@ export function MovieRow(props) { if(props.type === "movie") { progress = progressData?.lookmovie?.movie?.[props.slug]?.full if(progress) { - console.log(progress) percentage = Math.floor((progress.currentlyAt / progress.totalDuration) * 100) } } - console.log(percentage) return ( <div className="movieRow" onClick={() => props.onClick && props.onClick()}>