From d13a12d1cce644f7ee5d3e9cad6bc6817e5cba4b Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Tue, 13 Jul 2021 15:42:46 +0100 Subject: [PATCH 0001/1989] Initial commit --- README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..010a6ebd --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +movie-web From 492b4fda8f605e36c9dc83f090de645af1ded5bc Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Tue, 13 Jul 2021 16:45:44 +0100 Subject: [PATCH 0002/1989] commit --- assets/css/style.css | 0 assets/js/index.js | 169 +++++++++++++++++++++++++++++++++++++++++++ index.html | 23 ++++++ 3 files changed, 192 insertions(+) create mode 100644 assets/css/style.css create mode 100644 assets/js/index.js create mode 100644 index.html diff --git a/assets/css/style.css b/assets/css/style.css new file mode 100644 index 00000000..e69de29b diff --git a/assets/js/index.js b/assets/js/index.js new file mode 100644 index 00000000..8a1e751c --- /dev/null +++ b/assets/js/index.js @@ -0,0 +1,169 @@ +const cfg = { + base: "https://hidden-inlet-27205.herokuapp.com/https://lookmovie.io" +} + +async function getVideoUrl(config) { + const accessToken = await getAccessToken(config); + const now = Math.floor(Date.now() / 1e3); + + let url = null; + + if (config.type === "tv") { + url = `${cfg.base}/manifests/shows/json/${accessToken}/${now}/${config.episodeId}/master.m3u8`; + } else if (config.type === "movie") { + url = `${cfg.base}/manifests/movies/json/${config.movieId}/${now}/${accessToken}/master.m3u8`; + } + + if (url) { + const videoOpts = await fetch(url).then((d) => d.json()); + + // Find video URL and return it (with a check for a full url if needed) + const opts = ["1080p", "1080", "720p", "720", "480p", "480", "auto"] + + let videoUrl = ""; + for (let res of opts) { + if (videoOpts[res] && !videoOpts[res].includes('dummy') && !videoOpts[res].includes('earth-1984') && !videoUrl) { + videoUrl = videoOpts[res] + } + } + + return videoUrl.startsWith("/") ? `${cfg.base}${videoUrl}` : videoUrl; + } + + return "Invalid type."; +} + +async function getAccessToken(config) { + let url = ""; + + if (config.type === "tv") { + // 'mbQFYTR499c9vfDmAwOFrg' // Retrieved from: https://lookmovie.io/api/v1/security/show-access?slug=1839578-person-of-interest-2011&token=&step=2 + url = `${cfg.base}/api/v1/security/show-access?slug=${config.slug}&token=&step=2`; + } else if (config.type === "movie") { + // https://lookmovie.io/api/v1/security/movie-access?id_movie=14358&token=1&sk=&step=1 + url = `${cfg.base}/api/v1/security/movie-access?id_movie=${config.movieId}&token=1&sk=&step=1`; + } + + const data = await fetch(url).then((d) => d.json()); + + const token = data?.data?.accessToken; + if (token) return token; + + return "Invalid type provided in config"; +} + +async function findMovie() { + const searchTerm = document.getElementById('search').value; + + const movieSearchRes = await fetch( + `https://hidden-inlet-27205.herokuapp.com/https://lookmovie.io/api/v1/movies/search/?q=${encodeURIComponent( + searchTerm + )}` + ).then((d) => d.json()); + const showSearchRes = await fetch( + `https://hidden-inlet-27205.herokuapp.com/https://lookmovie.io/api/v1/shows/search/?q=${encodeURIComponent( + searchTerm + )}` + ).then((d) => d.json()); + + let results = [ + ...movieSearchRes.result.map((v) => ({ ...v, type: "movie" })), + ...showSearchRes.result.map((v) => ({ ...v, type: "show" })), + ]; + + const fuse = new Fuse(results, { + threshold: 0.3, + distance: 200, + keys: ["title"], + }); + const matchedResults = fuse + .search(searchTerm.toString()) + .map((result) => result.item); + + let toShow; + if (matchedResults.length > 1) { + const response = window.prompt(`Pick a movie from:\n${matchedResults.map((i, v) => `${v}) ${i.title}`).join('\n')}`, 'Enter number'); + toShow = matchedResults[response]; + } else { + toShow = matchedResults[0]; + } + + if (!toShow) { + document.getElementById('error').innerHTML = 'Unable to find that, sorry!' + return; + } + + console.log(`Scraping the ${toShow.type} "${toShow.title}"`); + + // ! Now we get the ID and stuff we need + const url = `https://hidden-inlet-27205.herokuapp.com/https://lookmovie.io/${toShow.type}s/view/${toShow.slug}`; + const pageReq = await fetch(url).then((d) => d.text()); + + // Extract and parse JSON + let scriptJson = + "{" + + pageReq + .slice(pageReq.indexOf(`${toShow.type}_storage`)) + .split("};")[0] + .split("= {")[1] + .trim() + + "}"; + + const data = JSON5.parse(scriptJson); + + // Find the relevant id + let id = null; + let relevantEpisode; + if (toShow.type === "movie") { + id = data.id_movie; + } else if (toShow.type === "show") { + const episodeObj = data.seasons.find((v) => { + return v.season == season && v.episode == episode; + }); + if (episodeObj) { + console.log( + `Finding streams for ${toShow.title} ${season}x${episode}: ${episodeObj.title}` + ); + id = episodeObj.id_episode; + relevantEpisode = episodeObj; + } + } + + // Check ID + if (id === null) { + console.error(`Not found: S${season} E${episode}`); + return; + } + + // Generate object to send over to scraper + let reqObj = null; + if (toShow.type === "show") { + reqObj = { + slug: toShow.slug, + episodeId: id, + type: "tv", + }; + } else if (toShow.type === "movie") { + reqObj = { + slug: toShow.slug, + movieId: id, + type: "movie", + }; + } + + if (!reqObj) { + document.getElementById('error').innerHTML = 'Invalid type!' + return; + } + + const videoUrl = await getVideoUrl(reqObj); + + var video = document.getElementById('video'); + var videoSrc = `https://hidden-inlet-27205.herokuapp.com/${videoUrl}`; + if (Hls.isSupported()) { + var video = document.getElementById('video'); + var hls = new Hls(); + hls.attachMedia(video); + hls.loadSource(videoSrc); + } +} \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..a1d43324 --- /dev/null +++ b/index.html @@ -0,0 +1,23 @@ + + + + + + + movie-web + + + + + + +
+

+
+ + + + + + \ No newline at end of file From bf908089de8378277c811e19f72aa7deff2df9fa Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Tue, 13 Jul 2021 16:47:59 +0100 Subject: [PATCH 0003/1989] Create CNAME --- CNAME | 1 + 1 file changed, 1 insertion(+) create mode 100644 CNAME diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..faedab99 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +movie.squeezebox.dev \ No newline at end of file From 1c03b118084a1fd91e2b57bb5248acec6a6c2e38 Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Tue, 13 Jul 2021 16:58:38 +0100 Subject: [PATCH 0004/1989] readme --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 010a6ebd..8d4c77cf 100644 --- a/README.md +++ b/README.md @@ -1 +1,5 @@ -movie-web +# movie-web + +Available at: [movie.squeezebox.dev](https://movie.squeezebox.dev) + +Credits to [@JipFr](https://github.com/JipFr) for initial work on [movie-cli](https://github.com/JipFr/movie-cli) \ No newline at end of file From 964b4120533a26e99b1831747a2d4881ebda2ef0 Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Tue, 13 Jul 2021 18:15:56 +0100 Subject: [PATCH 0005/1989] some css --- assets/css/style.css | 59 +++++++++++ assets/fonts/JetBrainsMono-Regular.woff2 | Bin 0 -> 58016 bytes assets/js/index.js | 125 ++++++----------------- index.html | 23 +++-- 4 files changed, 107 insertions(+), 100 deletions(-) create mode 100644 assets/fonts/JetBrainsMono-Regular.woff2 diff --git a/assets/css/style.css b/assets/css/style.css index e69de29b..7801a75c 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -0,0 +1,59 @@ +@font-face { + font-family: 'JetBrainsMono'; + src: url(../fonts/JetBrainsMono-Regular.woff2); + font-weight: 400; + font-style: normal; +} + +html, body { + height: 1vh; +} + +body { + margin: 0; + color: #95979F; + background-color: #0c0e14; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 40 40'%3E%3Cg fill-rule='evenodd'%3E%3Cg fill='%23586ca8' fill-opacity='0.12'%3E%3Cpath d='M0 38.59l2.83-2.83 1.41 1.41L1.41 40H0v-1.41zM0 1.4l2.83 2.83 1.41-1.41L1.41 0H0v1.41zM38.59 40l-2.83-2.83 1.41-1.41L40 38.59V40h-1.41zM40 1.41l-2.83 2.83-1.41-1.41L38.59 0H40v1.41zM20 18.6l2.83-2.83 1.41 1.41L21.41 20l2.83 2.83-1.41 1.41L20 21.41l-2.83 2.83-1.41-1.41L18.59 20l-2.83-2.83 1.41-1.41L20 18.59z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); + font-family: 'JetBrainsMono'; +} + +.messages { + background-color: #2D313D; + border-radius: 10px; + width: 80%; + padding-left: 10px; +} + +.error { + color: #f3565d; +} + +.info { + color: #2e5bbd; +} + +.content { + padding: 1rem; + border-radius: 10px; + background-color: #2D313D; + width: 80%; +} + +.video { + width: 100%; +} + +form { + background-color: #2D313D; + padding: 5px; + width: 300px; + text-align: center; +} + +input[type="submit"] { + width: 20%; +} + +input[type="text"] { + width: 70%; +} \ No newline at end of file diff --git a/assets/fonts/JetBrainsMono-Regular.woff2 b/assets/fonts/JetBrainsMono-Regular.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..80c62dd1cd4fdf60e349d8099e91fe9a31f68907 GIT binary patch literal 58016 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 JK*`Pl00464oF@PP literal 0 HcmV?d00001 diff --git a/assets/js/index.js b/assets/js/index.js index 8a1e751c..b6431901 100644 --- a/assets/js/index.js +++ b/assets/js/index.js @@ -1,18 +1,12 @@ -const cfg = { - base: "https://hidden-inlet-27205.herokuapp.com/https://lookmovie.io" +function getCorsUrl(url) { + return `https://hidden-inlet-27205.herokuapp.com/${url}`; } async function getVideoUrl(config) { const accessToken = await getAccessToken(config); const now = Math.floor(Date.now() / 1e3); - let url = null; - - if (config.type === "tv") { - url = `${cfg.base}/manifests/shows/json/${accessToken}/${now}/${config.episodeId}/master.m3u8`; - } else if (config.type === "movie") { - url = `${cfg.base}/manifests/movies/json/${config.movieId}/${now}/${accessToken}/master.m3u8`; - } + let url = getCorsUrl(`https://lookmovie.io/manifests/movies/json/${config.movieId}/${now}/${accessToken}/master.m3u8`); if (url) { const videoOpts = await fetch(url).then((d) => d.json()); @@ -27,22 +21,14 @@ async function getVideoUrl(config) { } } - return videoUrl.startsWith("/") ? `${cfg.base}${videoUrl}` : videoUrl; + return videoUrl.startsWith("/") ? getCorsUrl(`https://lookmovie.io/${videoUrl}`) : getCorsUrl(videoUrl); } return "Invalid type."; } async function getAccessToken(config) { - let url = ""; - - if (config.type === "tv") { - // 'mbQFYTR499c9vfDmAwOFrg' // Retrieved from: https://lookmovie.io/api/v1/security/show-access?slug=1839578-person-of-interest-2011&token=&step=2 - url = `${cfg.base}/api/v1/security/show-access?slug=${config.slug}&token=&step=2`; - } else if (config.type === "movie") { - // https://lookmovie.io/api/v1/security/movie-access?id_movie=14358&token=1&sk=&step=1 - url = `${cfg.base}/api/v1/security/movie-access?id_movie=${config.movieId}&token=1&sk=&step=1`; - } + let url = getCorsUrl(`https://lookmovie.io/api/v1/security/movie-access?id_movie=${config.movieId}&token=1&sk=&step=1`); const data = await fetch(url).then((d) => d.json()); @@ -55,27 +41,13 @@ async function getAccessToken(config) { async function findMovie() { const searchTerm = document.getElementById('search').value; - const movieSearchRes = await fetch( - `https://hidden-inlet-27205.herokuapp.com/https://lookmovie.io/api/v1/movies/search/?q=${encodeURIComponent( - searchTerm - )}` - ).then((d) => d.json()); - const showSearchRes = await fetch( - `https://hidden-inlet-27205.herokuapp.com/https://lookmovie.io/api/v1/shows/search/?q=${encodeURIComponent( - searchTerm - )}` - ).then((d) => d.json()); + sendMessage('info', `Searching for "${searchTerm}"`) - let results = [ - ...movieSearchRes.result.map((v) => ({ ...v, type: "movie" })), - ...showSearchRes.result.map((v) => ({ ...v, type: "show" })), - ]; + 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" })) ]; - const fuse = new Fuse(results, { - threshold: 0.3, - distance: 200, - keys: ["title"], - }); + const fuse = new Fuse(results, { threshold: 0.3, distance: 200, keys: ["title"] }); const matchedResults = fuse .search(searchTerm.toString()) .map((result) => result.item); @@ -89,81 +61,46 @@ async function findMovie() { } if (!toShow) { - document.getElementById('error').innerHTML = 'Unable to find that, sorry!' + sendMessage('error', 'Unable to find that, sorry!') return; } - console.log(`Scraping the ${toShow.type} "${toShow.title}"`); + sendMessage('info', `Scraping the ${toShow.type} "${toShow.title}"`) - // ! Now we get the ID and stuff we need - const url = `https://hidden-inlet-27205.herokuapp.com/https://lookmovie.io/${toShow.type}s/view/${toShow.slug}`; + const url = getCorsUrl(`https://lookmovie.io/${toShow.type}s/view/${toShow.slug}`); const pageReq = await fetch(url).then((d) => d.text()); - // Extract and parse JSON - let scriptJson = - "{" + + const data = JSON5.parse("{" + pageReq .slice(pageReq.indexOf(`${toShow.type}_storage`)) .split("};")[0] .split("= {")[1] .trim() + - "}"; + "}" + ); - const data = JSON5.parse(scriptJson); + const videoUrl = await getVideoUrl({ + slug: toShow.slug, + movieId: data.id_movie, + type: "movie", + }); - // Find the relevant id - let id = null; - let relevantEpisode; - if (toShow.type === "movie") { - id = data.id_movie; - } else if (toShow.type === "show") { - const episodeObj = data.seasons.find((v) => { - return v.season == season && v.episode == episode; - }); - if (episodeObj) { - console.log( - `Finding streams for ${toShow.title} ${season}x${episode}: ${episodeObj.title}` - ); - id = episodeObj.id_episode; - relevantEpisode = episodeObj; - } - } + sendMessage('info', `Streaming "${toShow.title}"`) + streamVideo(videoUrl) +} - // Check ID - if (id === null) { - console.error(`Not found: S${season} E${episode}`); - return; - } - - // Generate object to send over to scraper - let reqObj = null; - if (toShow.type === "show") { - reqObj = { - slug: toShow.slug, - episodeId: id, - type: "tv", - }; - } else if (toShow.type === "movie") { - reqObj = { - slug: toShow.slug, - movieId: id, - type: "movie", - }; - } - - if (!reqObj) { - document.getElementById('error').innerHTML = 'Invalid type!' - return; - } - - const videoUrl = await getVideoUrl(reqObj); +function sendMessage(type, message) { + if (!['info', 'error'].includes(type)) return; + document.getElementById(type).innerHTML += `${message}
`; +} +function streamVideo(url) { var video = document.getElementById('video'); - var videoSrc = `https://hidden-inlet-27205.herokuapp.com/${videoUrl}`; + if (Hls.isSupported()) { var video = document.getElementById('video'); var hls = new Hls(); hls.attachMedia(video); - hls.loadSource(videoSrc); + hls.loadSource(url); } } \ No newline at end of file diff --git a/index.html b/index.html index a1d43324..9ec86391 100644 --- a/index.html +++ b/index.html @@ -5,19 +5,30 @@ movie-web + + + + -
-

+
+ +
+ +
+
- - - +
+ +

+

+
+
\ No newline at end of file From 0b99f1c35e86a9a71bd7ec2dfaf389d66000b2fc Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Tue, 13 Jul 2021 23:31:37 +0100 Subject: [PATCH 0006/1989] Port to react --- .github/workflows/build-deploy.yml | 54 + .gitignore | 23 + README.md | 8 +- assets/css/style.css | 59 - assets/fonts/JetBrainsMono-Regular.woff2 | Bin 58016 -> 0 bytes index.html | 34 - package.json | 42 + public/index.html | 20 + public/manifest.json | 25 + public/robots.txt | 3 + src/App.js | 31 + src/components/Arrow.css | 7 + src/components/Arrow.js | 14 + src/components/Card.css | 28 + src/components/Card.js | 28 + src/components/InputBox.css | 72 + src/components/InputBox.js | 26 + src/components/MovieRow.css | 45 + src/components/MovieRow.js | 19 + src/components/Progress.css | 43 + src/components/Progress.js | 21 + src/components/Title.css | 36 + src/components/Title.js | 25 + src/components/VideoElement.css | 3 + src/components/VideoElement.js | 28 + src/hooks/useMovie.js | 29 + src/index.css | 14 + src/index.js | 11 + assets/js/index.js => src/lib/lookMovie.js | 85 +- src/views/Movie.css | 0 src/views/Movie.js | 20 + src/views/NotFound.js | 15 + src/views/Search.css | 17 + src/views/Search.js | 96 + yarn.lock | 11417 +++++++++++++++++++ 35 files changed, 12255 insertions(+), 143 deletions(-) create mode 100644 .github/workflows/build-deploy.yml create mode 100644 .gitignore delete mode 100644 assets/css/style.css delete mode 100644 assets/fonts/JetBrainsMono-Regular.woff2 delete mode 100644 index.html create mode 100644 package.json create mode 100644 public/index.html create mode 100644 public/manifest.json create mode 100644 public/robots.txt create mode 100644 src/App.js create mode 100644 src/components/Arrow.css create mode 100644 src/components/Arrow.js create mode 100644 src/components/Card.css create mode 100644 src/components/Card.js create mode 100644 src/components/InputBox.css create mode 100644 src/components/InputBox.js create mode 100644 src/components/MovieRow.css create mode 100644 src/components/MovieRow.js create mode 100644 src/components/Progress.css create mode 100644 src/components/Progress.js create mode 100644 src/components/Title.css create mode 100644 src/components/Title.js create mode 100644 src/components/VideoElement.css create mode 100644 src/components/VideoElement.js create mode 100644 src/hooks/useMovie.js create mode 100644 src/index.css create mode 100644 src/index.js rename assets/js/index.js => src/lib/lookMovie.js (61%) create mode 100644 src/views/Movie.css create mode 100644 src/views/Movie.js create mode 100644 src/views/NotFound.js create mode 100644 src/views/Search.css create mode 100644 src/views/Search.js create mode 100644 yarn.lock diff --git a/.github/workflows/build-deploy.yml b/.github/workflows/build-deploy.yml new file mode 100644 index 00000000..5ce797d5 --- /dev/null +++ b/.github/workflows/build-deploy.yml @@ -0,0 +1,54 @@ +name: Build & deploy + +on: + push: + branches: + - master + pull_request: + branches: + - master + +jobs: + build: + name: Build + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Install Node.js + uses: actions/setup-node@v1 + with: + node-version: 13.x + + - name: Install NPM packages + run: npm ci + + - name: Build project + run: npm run build + + - name: Upload production-ready build files + uses: actions/upload-artifact@v2 + with: + name: production-files + path: ./build + + deploy: + name: Deploy + needs: build + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/master' + + steps: + - name: Download artifact + uses: actions/download-artifact@v2 + with: + name: production-files + path: ./build + + - name: Deploy to gh-pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./build \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..04c5395e --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/README.md b/README.md index 8d4c77cf..679d0dca 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # movie-web - -Available at: [movie.squeezebox.dev](https://movie.squeezebox.dev) - -Credits to [@JipFr](https://github.com/JipFr) for initial work on [movie-cli](https://github.com/JipFr/movie-cli) \ No newline at end of file +Small web app for watching movies easily. Check it out at **[movie.squeezebox.dev](https://movie.squeezebox.dev)**. +## Credits + - Thanks to [@JipFr](https://github.com/JipFr) for initial work on [movie-cli](https://github.com/JipFr/movie-cli) + - Thanks to [@mrjvs](https://github.com/mrjvs) for help porting to React diff --git a/assets/css/style.css b/assets/css/style.css deleted file mode 100644 index 7801a75c..00000000 --- a/assets/css/style.css +++ /dev/null @@ -1,59 +0,0 @@ -@font-face { - font-family: 'JetBrainsMono'; - src: url(../fonts/JetBrainsMono-Regular.woff2); - font-weight: 400; - font-style: normal; -} - -html, body { - height: 1vh; -} - -body { - margin: 0; - color: #95979F; - background-color: #0c0e14; - background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 40 40'%3E%3Cg fill-rule='evenodd'%3E%3Cg fill='%23586ca8' fill-opacity='0.12'%3E%3Cpath d='M0 38.59l2.83-2.83 1.41 1.41L1.41 40H0v-1.41zM0 1.4l2.83 2.83 1.41-1.41L1.41 0H0v1.41zM38.59 40l-2.83-2.83 1.41-1.41L40 38.59V40h-1.41zM40 1.41l-2.83 2.83-1.41-1.41L38.59 0H40v1.41zM20 18.6l2.83-2.83 1.41 1.41L21.41 20l2.83 2.83-1.41 1.41L20 21.41l-2.83 2.83-1.41-1.41L18.59 20l-2.83-2.83 1.41-1.41L20 18.59z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"); - font-family: 'JetBrainsMono'; -} - -.messages { - background-color: #2D313D; - border-radius: 10px; - width: 80%; - padding-left: 10px; -} - -.error { - color: #f3565d; -} - -.info { - color: #2e5bbd; -} - -.content { - padding: 1rem; - border-radius: 10px; - background-color: #2D313D; - width: 80%; -} - -.video { - width: 100%; -} - -form { - background-color: #2D313D; - padding: 5px; - width: 300px; - text-align: center; -} - -input[type="submit"] { - width: 20%; -} - -input[type="text"] { - width: 70%; -} \ No newline at end of file diff --git a/assets/fonts/JetBrainsMono-Regular.woff2 b/assets/fonts/JetBrainsMono-Regular.woff2 deleted file mode 100644 index 80c62dd1cd4fdf60e349d8099e91fe9a31f68907..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58016 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 JK*`Pl00464oF@PP diff --git a/index.html b/index.html deleted file mode 100644 index 9ec86391..00000000 --- a/index.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - movie-web - - - - - - - - - - -
- -
- -
- -
- -
- -

-

-
-
- - \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 00000000..29118a46 --- /dev/null +++ b/package.json @@ -0,0 +1,42 @@ +{ + "name": "movie-web", + "version": "0.1.0", + "private": true, + "homepage": "https://movie.squeezebox.dev", + "dependencies": { + "@testing-library/jest-dom": "^5.11.4", + "@testing-library/react": "^11.1.0", + "@testing-library/user-event": "^12.1.10", + "fuse.js": "^6.4.6", + "hls.js": "^1.0.7", + "json5": "^2.2.0", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "react-scripts": "4.0.3", + "web-vitals": "^1.0.1" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "eslintConfig": { + "extends": [ + "react-app", + "react-app/jest" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/public/index.html b/public/index.html new file mode 100644 index 00000000..b01aea56 --- /dev/null +++ b/public/index.html @@ -0,0 +1,20 @@ + + + + + + + + + + + movie-web + + + +
+ + diff --git a/public/manifest.json b/public/manifest.json new file mode 100644 index 00000000..9080f78d --- /dev/null +++ b/public/manifest.json @@ -0,0 +1,25 @@ +{ + "short_name": "movie-web", + "name": "movie-web", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + }, + { + "src": "logo192.png", + "type": "image/png", + "sizes": "192x192" + }, + { + "src": "logo512.png", + "type": "image/png", + "sizes": "512x512" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#191c24", + "background_color": "#0c0e14" +} diff --git a/public/robots.txt b/public/robots.txt new file mode 100644 index 00000000..e9e57dc4 --- /dev/null +++ b/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/src/App.js b/src/App.js new file mode 100644 index 00000000..7461c0bd --- /dev/null +++ b/src/App.js @@ -0,0 +1,31 @@ +import './index.css'; +import { SearchView } from './views/Search'; +import { NotFound } from './views/NotFound'; +import { MovieView } from './views/Movie'; +import { useMovie, MovieProvider} from './hooks/useMovie'; + +function Router() { + const { page } = useMovie(); + + if (page === "search") { + return + } + + if (page === "movie") { + return + } + + return ( + + ) +} + +function App() { + return ( + + + + ); +} + +export default App; diff --git a/src/components/Arrow.css b/src/components/Arrow.css new file mode 100644 index 00000000..0578ea6d --- /dev/null +++ b/src/components/Arrow.css @@ -0,0 +1,7 @@ +.feather.left { + transform: rotate(180deg); +} + +.arrow { + display: inline-block; +} diff --git a/src/components/Arrow.js b/src/components/Arrow.js new file mode 100644 index 00000000..373f810a --- /dev/null +++ b/src/components/Arrow.js @@ -0,0 +1,14 @@ +import React from 'react' +import './Arrow.css' + +// left?: boolean +export function Arrow(props) { + return ( +
+ + + + +
+ ) +} diff --git a/src/components/Card.css b/src/components/Card.css new file mode 100644 index 00000000..c3f24f63 --- /dev/null +++ b/src/components/Card.css @@ -0,0 +1,28 @@ +.card { + background-color: #22232A; + padding: 3rem 4rem; + width: 39rem; + max-width: 100%; + margin: 0 3rem; + border-radius: 10px; + box-sizing: border-box; + transition: height 500ms ease-in-out, transform 800ms ease-in-out, opacity 800ms ease-in-out; +} + +.card.full { + width: 75rem; +} + +.card-wrapper { + transition: height 500ms ease-in-out; + overflow: hidden; +} + +.card.doTransition { + opacity: 0; + transform: translateY(-.7rem); +} +.card.doTransition.show { + opacity: 1; + transform: translateY(0rem); +} \ No newline at end of file diff --git a/src/components/Card.js b/src/components/Card.js new file mode 100644 index 00000000..c7b73e9b --- /dev/null +++ b/src/components/Card.js @@ -0,0 +1,28 @@ +import React from 'react' +import './Card.css' + +// fullWidth: boolean +// show: boolean +// doTransition: boolean +export function Card(props) { + + const [showing, setShowing] = React.useState(false); + const measureRef = React.useRef(null) + const [height, setHeight] = React.useState(0); + + React.useEffect(() => { + if (!measureRef?.current) return; + setShowing(props.show); + setHeight(measureRef.current.clientHeight) + }, [props.show, measureRef]) + + return ( +
+
+ {props.children} +
+
+ ) +} diff --git a/src/components/InputBox.css b/src/components/InputBox.css new file mode 100644 index 00000000..ef774ce0 --- /dev/null +++ b/src/components/InputBox.css @@ -0,0 +1,72 @@ +.inputBar { + width: 100%; + display: flex; + height: 3rem; +} + +.inputBar > *:first-child{ + border-radius: 0 !important; + border-top-left-radius: 10px !important; + border-bottom-left-radius: 10px !important; +} + +.inputBar > *:last-child { + border-radius: 0 !important; + border-top-right-radius: 10px !important; + border-bottom-right-radius: 10px !important; +} + +.inputTextBox { + border-width: 0; + outline: none; + + background-color: #36363e; + color: white; + padding: .7rem 1.5rem; + height: auto; + flex: 1; +} + +.inputSearchButton { + background-color: #A73B83; + border-width: 0; + color: white; + padding: .5rem 2.1rem; + + font-weight: bold; + + cursor: pointer; +} + +.inputSearchButton:hover { + background-color: #9C3179; +} + +.inputTextBox:hover { + background-color: #3C3D44; +} + +.inputSearchButton .text > .arrow { + opacity: 0; + transition: opacity 0.2s ease-in-out, transform 0.2s ease-in-out; + position: absolute; + right: -0.8rem; + bottom: -0.2rem; +} +.inputSearchButton .text { + display: flex; + position: relative; + transition: transform 0.2s ease-in-out; +} +.inputSearchButton:hover .text > .arrow { + transform: translateX(8px); + opacity: 1; +} + +.inputSearchButton:hover .text { + transform: translateX(-10px); +} + +.inputSearchButton:active { + background-color: #8b286a; +} diff --git a/src/components/InputBox.js b/src/components/InputBox.js new file mode 100644 index 00000000..35e6c1a2 --- /dev/null +++ b/src/components/InputBox.js @@ -0,0 +1,26 @@ +import React from 'react'; +import { Arrow } from './Arrow'; +import './InputBox.css' + +// props = { onSubmit: (str) => {}, placeholder: string} +export function InputBox({ onSubmit, placeholder }) { + const [value, setValue] = React.useState(""); + + return ( +
{ + e.preventDefault(); + onSubmit(value) + return false; + }}> + setValue(e.target.value)} + /> + +
+ ) +} diff --git a/src/components/MovieRow.css b/src/components/MovieRow.css new file mode 100644 index 00000000..824aca4c --- /dev/null +++ b/src/components/MovieRow.css @@ -0,0 +1,45 @@ +.movieRow { + display: flex; + border-radius: 5px; + background-color: #35363D; + color: white; + padding: .8rem 1.5rem; + margin-top: .5rem; + cursor: pointer; + transition: transform 50ms ease-in-out; + user-select: none; +} + +.movieRow p { + margin: 0; +} + +.movieRow .left { + flex: 1; + display: flex; + align-items: flex-start; +} + +.movieRow .watch { + color: #D678B7; + display: flex; + align-items: center; +} + +.movieRow .watch .arrow { + margin-left: .5rem; + transition: transform 50ms ease-in-out; + transform: translateY(.1rem); +} + +.movieRow:active { + transform: scale(1.02); +} + +.movieRow:hover { + background-color: #3A3B40; +} + +.movieRow:hover .watch .arrow { + transform: translateX(.3rem) translateY(.1rem); +} \ No newline at end of file diff --git a/src/components/MovieRow.js b/src/components/MovieRow.js new file mode 100644 index 00000000..47955dec --- /dev/null +++ b/src/components/MovieRow.js @@ -0,0 +1,19 @@ +import React from 'react' +import { Arrow } from './Arrow' +import './MovieRow.css' + +// title: string +// onClick: () => void +export function MovieRow(props) { + return ( +
props.onClick && props.onClick()}> +
+ {props.title} +
+
+

Watch movie

+ +
+
+ ) +} diff --git a/src/components/Progress.css b/src/components/Progress.css new file mode 100644 index 00000000..9c0b84f4 --- /dev/null +++ b/src/components/Progress.css @@ -0,0 +1,43 @@ +.progress { + text-align: center; + color: #BCBECB; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + height: 5rem; + margin-top: 1rem; + transition: height 800ms ease-in-out, opacity 800ms ease-in-out; + opacity: 1; +} + +.progress.hide { + opacity: 0; + height: 0rem; +} + +.progress p { + margin: 0; + margin-bottom: 1rem; +} + +.progress .bar { + width: 13rem; + max-width: 100%; + background-color: #35363D; + border-radius: 10px; + height: 7px; + display: inline-block; +} + +.progress .bar .bar-inner { + transition: width 400ms ease-in-out, background-color 100ms ease-in-out; + background-color: #D463AE; + border-radius: 10px; + height: 100%; + width: 0%; +} + +.progress.failed .bar .bar-inner { + background-color: #d85b66; +} diff --git a/src/components/Progress.js b/src/components/Progress.js new file mode 100644 index 00000000..05af5c4c --- /dev/null +++ b/src/components/Progress.js @@ -0,0 +1,21 @@ +import React from 'react' +import './Progress.css' + +// show: boolean +// progress: number +// steps: number +// text: string +// failed: boolean +export function Progress(props) { + return ( +
+ { props.text && props.text.length > 0 ? ( +

{props.text}

) : null} +
+
+
+
+ ) +} \ No newline at end of file diff --git a/src/components/Title.css b/src/components/Title.css new file mode 100644 index 00000000..bd1790ed --- /dev/null +++ b/src/components/Title.css @@ -0,0 +1,36 @@ +.title { + font-size: 2rem; + color: white; + max-width: 20rem; + margin: 0; + padding: 0; + margin-bottom: 3.5rem; +} + +.title-size-medium { + font-size: 1.5rem; +} + +.title-accent { + color: #E880C5; + font-weight: 600; + margin: 0; + padding: 0; + margin-bottom: 0.5rem; + margin-top: 1rem; + display: inline-block; +} + +.title-accent.title-accent-link { + cursor: pointer; +} + +.title-accent.title-accent-link .arrow { + transition: transform 100ms ease-in-out; + transform: translateY(.1rem); + margin-right: .2rem; +} + +.title-accent.title-accent-link:hover .arrow { + transform: translateY(.1rem) translateX(-.5rem); +} diff --git a/src/components/Title.js b/src/components/Title.js new file mode 100644 index 00000000..2740f84c --- /dev/null +++ b/src/components/Title.js @@ -0,0 +1,25 @@ +import React from 'react'; +import { useMovie } from '../hooks/useMovie' +import { Arrow } from '../components/Arrow' +import './Title.css' + +// size: "big" | "medium" | "small" | null +// accent: string | null +// accentLink: string | null +export function Title(props) { + const { navigate } = useMovie(); + const size = props.size || "big"; + + const accentLink = props.accentLink || ""; + const accent = props.accent || ""; + return ( +
+ {accent.length > 0 ? ( +

accentLink.length > 0 && navigate(accentLink)} className={`title-accent ${accentLink.length > 0 ? 'title-accent-link' : ''}`}> + {accentLink.length > 0 ? () : null}{accent} +

+ ) : null} +

{props.children}

+
+ ) +} diff --git a/src/components/VideoElement.css b/src/components/VideoElement.css new file mode 100644 index 00000000..9a1f47f7 --- /dev/null +++ b/src/components/VideoElement.css @@ -0,0 +1,3 @@ +.videoElement { + width: 100%; +} diff --git a/src/components/VideoElement.js b/src/components/VideoElement.js new file mode 100644 index 00000000..4aa2cd7d --- /dev/null +++ b/src/components/VideoElement.js @@ -0,0 +1,28 @@ +import React from 'react' +import Hls from 'hls.js' +import './VideoElement.css' + +// streamUrl: string +export function VideoElement({ streamUrl }) { + const videoRef = React.useRef(null); + + React.useEffect(() => { + if (!videoRef || !videoRef.current) return; + + const hls = new Hls(); + + if (!Hls.isSupported() && videoRef.current.canPlayType('application/vnd.apple.mpegurl')) { + videoRef.current.src = streamUrl; + return; + } else if (!Hls.isSupported()) { + return; // TODO show error + } + + hls.attachMedia(videoRef.current); + hls.loadSource(streamUrl); + }, [videoRef, streamUrl]) + + return ( +
-

Watch movie

+ year: {props.year} +

Watch {props.type}

diff --git a/src/lib/lookMovie.js b/src/lib/lookMovie.js index d627ec28..8acb5b00 100644 --- a/src/lib/lookMovie.js +++ b/src/lib/lookMovie.js @@ -57,7 +57,7 @@ async function getStreamUrl(slug, type) { const videoUrl = await getVideoUrl({ slug: slug, movieId: data.id_movie, - type: "movie", + type: type, }); return { url: videoUrl } @@ -83,15 +83,16 @@ async function findMovie(searchTerm) { matchedResults.forEach((r) => res.options.push({ title: r.title, slug: r.slug, - type: r.type + type: r.type, + year: r.year })); return res; } else { - const { title, slug, type } = matchedResults[0]; + const { title, slug, type, year } = matchedResults[0]; return { - options: [{ title, slug, type }] + options: [{ title, slug, type, year }] } } } diff --git a/src/views/Search.js b/src/views/Search.js index 4e884ed1..6ccafe3d 100644 --- a/src/views/Search.js +++ b/src/views/Search.js @@ -58,9 +58,9 @@ export function SearchView() { return fail("Could not find that movie") } else if (options.length > 1) { setProgress(2); - setText("Choose your movie") - setOptions(options.map(v=>({ title: v.title, slug: v.slug, type: v.type }))); - setShowingOptions(true) + setText("Choose your movie"); + setOptions(options); + setShowingOptions(true); return; } @@ -86,7 +86,7 @@ export function SearchView() { Whoops, there are a few movies like that {options?.map((v, i) => ( - { + { setShowingOptions(false) getStream(v.title, v.slug, v.type) }}/> From c92fbbe8b83c1a4fe2a856aeb41ba3c85811aa7f Mon Sep 17 00:00:00 2001 From: montylion Date: Wed, 14 Jul 2021 11:18:07 +0200 Subject: [PATCH 0014/1989] Update movie release date indicator --- src/components/MovieRow.css | 6 ++++++ src/components/MovieRow.js | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/MovieRow.css b/src/components/MovieRow.css index 2be6c016..45986130 100644 --- a/src/components/MovieRow.css +++ b/src/components/MovieRow.css @@ -17,7 +17,13 @@ .movieRow .left { flex: 1; display: flex; + flex-flow: row wrap; align-items: flex-start; + margin-right: 0.5rem; +} + +.movieRow .left .year { + color: #BCBECB; } .movieRow .watch { diff --git a/src/components/MovieRow.js b/src/components/MovieRow.js index b1958fe0..a3ae80bd 100644 --- a/src/components/MovieRow.js +++ b/src/components/MovieRow.js @@ -8,10 +8,10 @@ export function MovieRow(props) { return (
props.onClick && props.onClick()}>
- {props.title} + {props.title}  + ({props.year})
- year: {props.year}

Watch {props.type}

From 8edadfb75e0f71a96ba44e7c8de6235b9178bcb6 Mon Sep 17 00:00:00 2001 From: montylion Date: Wed, 14 Jul 2021 11:21:12 +0200 Subject: [PATCH 0015/1989] Fix GitHub link position Was broken on mobile --- src/views/Search.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/views/Search.css b/src/views/Search.css index 94437a9a..6653acbf 100644 --- a/src/views/Search.css +++ b/src/views/Search.css @@ -13,11 +13,11 @@ } .cardView > div:first-child { - margin-top: 0; + margin-top: 38px; } .topRightCredits { - position: fixed; + position: absolute; right: 1rem; top: 1rem; margin-top: 0 !important; From b94f2792b7bd9872532e8179fad26487e3c0123a Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Wed, 14 Jul 2021 10:43:24 +0100 Subject: [PATCH 0016/1989] Attempt PWA support --- public/manifest.json | 25 ------- public/service-worker.js | 2 + public/site.webmanifest | 7 +- src/index.js | 3 + src/service-worker.js | 72 ++++++++++++++++++ src/serviceWorkerRegistration.js | 125 +++++++++++++++++++++++++++++++ 6 files changed, 206 insertions(+), 28 deletions(-) delete mode 100644 public/manifest.json create mode 100644 public/service-worker.js create mode 100644 src/service-worker.js create mode 100644 src/serviceWorkerRegistration.js diff --git a/public/manifest.json b/public/manifest.json deleted file mode 100644 index ad5d4b43..00000000 --- a/public/manifest.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "short_name": "movie-web", - "name": "movie-web", - "icons": [ - { - "src": "favicon.ico", - "sizes": "64x64 32x32 24x24 16x16", - "type": "image/x-icon" - }, - { - "src": "logo192.png", - "type": "image/png", - "sizes": "192x192" - }, - { - "src": "logo512.png", - "type": "image/png", - "sizes": "512x512" - } - ], - "start_url": ".", - "display": "standalone", - "theme_color": "#E880C5", - "background_color": "#16171D" -} diff --git a/public/service-worker.js b/public/service-worker.js new file mode 100644 index 00000000..c76c1d65 --- /dev/null +++ b/public/service-worker.js @@ -0,0 +1,2 @@ +!function(e){var t={};function n(r){if(t[r])return t[r].exports;var a=t[r]={i:r,l:!1,exports:{}};return e[r].call(a.exports,a,a.exports,n),a.l=!0,a.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var a in e)n.d(r,a,function(t){return e[t]}.bind(null,a));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/",n(n.s=7)}([function(e,t,n){e.exports=n(6)},function(e,t,n){"use strict";try{self["workbox:core:5.1.4"]&&_()}catch(r){}},function(e,t,n){"use strict";try{self["workbox:precaching:5.1.4"]&&_()}catch(r){}},function(e,t,n){"use strict";try{self["workbox:routing:5.1.4"]&&_()}catch(r){}},function(e,t,n){"use strict";try{self["workbox:strategies:5.1.4"]&&_()}catch(r){}},function(e,t,n){"use strict";try{self["workbox:expiration:5.1.4"]&&_()}catch(r){}},function(e,t,n){var r=function(e){"use strict";var t,n=Object.prototype,r=n.hasOwnProperty,a="function"===typeof Symbol?Symbol:{},i=a.iterator||"@@iterator",c=a.asyncIterator||"@@asyncIterator",u=a.toStringTag||"@@toStringTag";function o(e,t,n){return Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}),e[t]}try{o({},"")}catch(U){o=function(e,t,n){return e[t]=n}}function s(e,t,n,r){var a=t&&t.prototype instanceof y?t:y,i=Object.create(a.prototype),c=new O(r||[]);return i._invoke=function(e,t,n){var r=h;return function(a,i){if(r===p)throw new Error("Generator is already running");if(r===v){if("throw"===a)throw i;return S()}for(n.method=a,n.arg=i;;){var c=n.delegate;if(c){var u=E(c,n);if(u){if(u===d)continue;return u}}if("next"===n.method)n.sent=n._sent=n.arg;else if("throw"===n.method){if(r===h)throw r=v,n.arg;n.dispatchException(n.arg)}else"return"===n.method&&n.abrupt("return",n.arg);r=p;var o=f(e,t,n);if("normal"===o.type){if(r=n.done?v:l,o.arg===d)continue;return{value:o.arg,done:n.done}}"throw"===o.type&&(r=v,n.method="throw",n.arg=o.arg)}}}(e,n,c),i}function f(e,t,n){try{return{type:"normal",arg:e.call(t,n)}}catch(U){return{type:"throw",arg:U}}}e.wrap=s;var h="suspendedStart",l="suspendedYield",p="executing",v="completed",d={};function y(){}function m(){}function g(){}var x={};x[i]=function(){return this};var w=Object.getPrototypeOf,b=w&&w(w(T([])));b&&b!==n&&r.call(b,i)&&(x=b);var k=g.prototype=y.prototype=Object.create(x);function _(e){["next","throw","return"].forEach((function(t){o(e,t,(function(e){return this._invoke(t,e)}))}))}function R(e,t){function n(a,i,c,u){var o=f(e[a],e,i);if("throw"!==o.type){var s=o.arg,h=s.value;return h&&"object"===typeof h&&r.call(h,"__await")?t.resolve(h.__await).then((function(e){n("next",e,c,u)}),(function(e){n("throw",e,c,u)})):t.resolve(h).then((function(e){s.value=e,c(s)}),(function(e){return n("throw",e,c,u)}))}u(o.arg)}var a;this._invoke=function(e,r){function i(){return new t((function(t,a){n(e,r,t,a)}))}return a=a?a.then(i,i):i()}}function E(e,n){var r=e.iterator[n.method];if(r===t){if(n.delegate=null,"throw"===n.method){if(e.iterator.return&&(n.method="return",n.arg=t,E(e,n),"throw"===n.method))return d;n.method="throw",n.arg=new TypeError("The iterator does not provide a 'throw' method")}return d}var a=f(r,e.iterator,n.arg);if("throw"===a.type)return n.method="throw",n.arg=a.arg,n.delegate=null,d;var i=a.arg;return i?i.done?(n[e.resultName]=i.value,n.next=e.nextLoc,"return"!==n.method&&(n.method="next",n.arg=t),n.delegate=null,d):i:(n.method="throw",n.arg=new TypeError("iterator result is not an object"),n.delegate=null,d)}function L(e){var t={tryLoc:e[0]};1 in e&&(t.catchLoc=e[1]),2 in e&&(t.finallyLoc=e[2],t.afterLoc=e[3]),this.tryEntries.push(t)}function q(e){var t=e.completion||{};t.type="normal",delete t.arg,e.completion=t}function O(e){this.tryEntries=[{tryLoc:"root"}],e.forEach(L,this),this.reset(!0)}function T(e){if(e){var n=e[i];if(n)return n.call(e);if("function"===typeof e.next)return e;if(!isNaN(e.length)){var a=-1,c=function n(){for(;++a=0;--i){var c=this.tryEntries[i],u=c.completion;if("root"===c.tryLoc)return a("end");if(c.tryLoc<=this.prev){var o=r.call(c,"catchLoc"),s=r.call(c,"finallyLoc");if(o&&s){if(this.prev=0;--n){var a=this.tryEntries[n];if(a.tryLoc<=this.prev&&r.call(a,"finallyLoc")&&this.prev=0;--t){var n=this.tryEntries[t];if(n.finallyLoc===e)return this.complete(n.completion,n.afterLoc),q(n),d}},catch:function(e){for(var t=this.tryEntries.length-1;t>=0;--t){var n=this.tryEntries[t];if(n.tryLoc===e){var r=n.completion;if("throw"===r.type){var a=r.arg;q(n)}return a}}throw new Error("illegal catch attempt")},delegateYield:function(e,n,r){return this.delegate={iterator:T(e),resultName:n,nextLoc:r},"next"===this.method&&(this.arg=t),d}},e}(e.exports);try{regeneratorRuntime=r}catch(a){Function("r","regeneratorRuntime = r")(r)}},function(e,t,n){"use strict";function r(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var c,u=!0,o=!1;return{s:function(){n=e[Symbol.iterator]()},n:function(){var e=n.next();return u=e.done,e},e:function(e){o=!0,c=e},f:function(){try{u||null==n.return||n.return()}finally{if(o)throw c}}}}function u(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){return(o=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}function s(e,t){if("function"!==typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&o(e,t)}function f(e){return(f=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function h(){if("undefined"===typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"===typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],(function(){}))),!0}catch(e){return!1}}function l(e){return(l="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function p(e,t){return!t||"object"!==l(t)&&"function"!==typeof t?function(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}(e):t}function v(e){var t=h();return function(){var n,r=f(e);if(t){var a=f(this).constructor;n=Reflect.construct(r,arguments,a)}else n=r.apply(this,arguments);return p(this,n)}}function d(e,t,n){return(d=h()?Reflect.construct:function(e,t,n){var r=[null];r.push.apply(r,t);var a=new(Function.bind.apply(e,r));return n&&o(a,n.prototype),a}).apply(null,arguments)}function y(e){var t="function"===typeof Map?new Map:void 0;return(y=function(e){if(null===e||(n=e,-1===Function.toString.call(n).indexOf("[native code]")))return e;var n;if("function"!==typeof e)throw new TypeError("Super expression must either be null or a function");if("undefined"!==typeof t){if(t.has(e))return t.get(e);t.set(e,r)}function r(){return d(e,arguments,f(this).constructor)}return r.prototype=Object.create(e.prototype,{constructor:{value:r,enumerable:!1,writable:!0,configurable:!0}}),o(r,e)})(e)}var m=function(e){for(var t=e,n=arguments.length,r=new Array(n>1?n-1:0),a=1;a0&&(t+=" :: ".concat(JSON.stringify(r))),t},g=function(e){s(n,e);var t=v(n);function n(e,r){var a;u(this,n);var i=m(e,r);return(a=t.call(this,i)).name=e,a.details=r,a}return n}(y(Error)),x=new Set;function w(e){x.add(e)}var b={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!==typeof registration?registration.scope:""},k=function(e){return[b.prefix,e,b.suffix].filter((function(e){return e&&e.length>0})).join("-")},_=function(e){return e||k(b.precache)},R=function(e){return e||k(b.runtime)},E=n(0),L=n.n(E);function q(e,t,n,r,a,i,c){try{var u=e[i](c),o=u.value}catch(s){return void n(s)}u.done?t(o):Promise.resolve(o).then(r,a)}function O(e){return function(){var t=this,n=arguments;return new Promise((function(r,a){var i=e.apply(t,n);function c(e){q(i,r,a,c,u,"next",e)}function u(e){q(i,r,a,c,u,"throw",e)}c(void 0)}))}}function T(){return S.apply(this,arguments)}function S(){return(S=O(L.a.mark((function e(){var t,n,r;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:0,t=c(x),e.prev=2,t.s();case 4:if((n=t.n()).done){e.next=11;break}return r=n.value,e.next=8,r();case 8:0;case 9:e.next=4;break;case 11:e.next=16;break;case 13:e.prev=13,e.t0=e.catch(2),t.e(e.t0);case 16:return e.prev=16,t.f(),e.finish(16);case 19:0;case 20:case"end":return e.stop()}}),e,null,[[2,13,16,19]])})))).apply(this,arguments)}var U,N=function(e){return new URL(String(e),location.href).href.replace(new RegExp("^".concat(location.origin)),"")},j=function(e,t){return e.filter((function(e){return t in e}))},A=function(){var e=O(L.a.mark((function e(t){var n,r,a,i,u,o,s,f;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:n=t.request,r=t.mode,a=t.plugins,i=j(void 0===a?[]:a,"cacheKeyWillBeUsed"),u=n,o=c(i),e.prev=4,o.s();case 6:if((s=o.n()).done){e.next=15;break}return f=s.value,e.next=10,f.cacheKeyWillBeUsed.call(f,{mode:r,request:u});case 10:"string"===typeof(u=e.sent)&&(u=new Request(u));case 13:e.next=6;break;case 15:e.next=20;break;case 17:e.prev=17,e.t0=e.catch(4),o.e(e.t0);case 20:return e.prev=20,o.f(),e.finish(20);case 23:return e.abrupt("return",u);case 24:case"end":return e.stop()}}),e,null,[[4,17,20,23]])})));return function(t){return e.apply(this,arguments)}}(),M=function(){var e=O(L.a.mark((function e(t){var n,r,a,i,u,o,s,f,h,l;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:n=t.request,r=t.response,a=t.event,i=t.plugins,u=r,o=!1,s=c(void 0===i?[]:i),e.prev=4,s.s();case 6:if((f=s.n()).done){e.next=19;break}if(!("cacheWillUpdate"in(h=f.value))){e.next=17;break}return o=!0,l=h.cacheWillUpdate,e.next=13,l.call(h,{request:n,response:u,event:a});case 13:if(u=e.sent){e.next=17;break}return e.abrupt("break",19);case 17:e.next=6;break;case 19:e.next=24;break;case 21:e.prev=21,e.t0=e.catch(4),s.e(e.t0);case 24:return e.prev=24,s.f(),e.finish(24);case 27:return o||(u=u&&200===u.status?u:void 0),e.abrupt("return",u||null);case 29:case"end":return e.stop()}}),e,null,[[4,21,24,27]])})));return function(t){return e.apply(this,arguments)}}(),C=function(){var e=O(L.a.mark((function e(t){var n,r,a,i,u,o,s,f,h,l,p,v,d;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return n=t.cacheName,r=t.request,a=t.event,i=t.matchOptions,u=t.plugins,o=void 0===u?[]:u,e.next=3,self.caches.open(n);case 3:return s=e.sent,e.next=6,A({plugins:o,request:r,mode:"read"});case 6:return f=e.sent,e.next=9,s.match(f,i);case 9:h=e.sent,l=c(o),e.prev=12,l.s();case 14:if((p=l.n()).done){e.next=24;break}if(!("cachedResponseWillBeUsed"in(v=p.value))){e.next=22;break}return d=v.cachedResponseWillBeUsed,e.next=20,d.call(v,{cacheName:n,event:a,matchOptions:i,cachedResponse:h,request:f});case 20:h=e.sent;case 22:e.next=14;break;case 24:e.next=29;break;case 26:e.prev=26,e.t0=e.catch(12),l.e(e.t0);case 29:return e.prev=29,l.f(),e.finish(29);case 32:return e.abrupt("return",h);case 33:case"end":return e.stop()}}),e,null,[[12,26,29,32]])})));return function(t){return e.apply(this,arguments)}}(),K={put:function(){var e=O(L.a.mark((function e(t){var n,r,a,i,u,o,s,f,h,l,p,v,d,y,m;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:n=t.cacheName,r=t.request,a=t.response,i=t.event,u=t.plugins,o=void 0===u?[]:u,s=t.matchOptions,e.next=4;break;case 4:return e.next=6,A({plugins:o,request:r,mode:"write"});case 6:if(f=e.sent,a){e.next=10;break}throw new g("cache-put-with-no-response",{url:N(f.url)});case 10:return e.next=12,M({event:i,plugins:o,response:a,request:f});case 12:if(h=e.sent){e.next=16;break}return e.abrupt("return");case 16:return e.next=18,self.caches.open(n);case 18:if(l=e.sent,!((p=j(o,"cacheDidUpdate")).length>0)){e.next=26;break}return e.next=23,C({cacheName:n,matchOptions:s,request:f});case 23:e.t0=e.sent,e.next=27;break;case 26:e.t0=null;case 27:return v=e.t0,e.prev=29,e.next=32,l.put(f,h);case 32:e.next=40;break;case 34:if(e.prev=34,e.t1=e.catch(29),"QuotaExceededError"!==e.t1.name){e.next=39;break}return e.next=39,T();case 39:throw e.t1;case 40:d=c(p),e.prev=41,d.s();case 43:if((y=d.n()).done){e.next=49;break}return m=y.value,e.next=47,m.cacheDidUpdate.call(m,{cacheName:n,event:i,oldResponse:v,newResponse:h,request:f});case 47:e.next=43;break;case 49:e.next=54;break;case 51:e.prev=51,e.t2=e.catch(41),d.e(e.t2);case 54:return e.prev=54,d.f(),e.finish(54);case 57:case"end":return e.stop()}}),e,null,[[29,34],[41,51,54,57]])})));return function(t){return e.apply(this,arguments)}}(),match:C};function P(){if(void 0===U){var e=new Response("");if("body"in e)try{new Response(e.body),U=!0}catch(t){U=!1}U=!1}return U}function I(e){e.then((function(){}))}function D(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){if("undefined"!==typeof Symbol&&Symbol.iterator in Object(e)){var n=[],r=!0,a=!1,i=void 0;try{for(var c,u=e[Symbol.iterator]();!(r=(c=u.next()).done)&&(n.push(c.value),!t||n.length!==t);r=!0);}catch(o){a=!0,i=o}finally{try{r||null==u.return||u.return()}finally{if(a)throw i}}return n}}(e,t)||a(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function W(e,t){for(var n=0;n2&&void 0!==arguments[2]?arguments[2]:{},i=a.onupgradeneeded,c=a.onversionchange;u(this,e),this._db=null,this._name=t,this._version=n,this._onupgradeneeded=i,this._onversionchange=c||function(){return r.close()}}return F(e,[{key:"db",get:function(){return this._db}},{key:"open",value:function(){var e=O(L.a.mark((function e(){var t=this;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(!this._db){e.next=2;break}return e.abrupt("return");case 2:return e.next=4,new Promise((function(e,n){var r=!1;setTimeout((function(){r=!0,n(new Error("The open request was blocked and timed out"))}),t.OPEN_TIMEOUT);var a=indexedDB.open(t._name,t._version);a.onerror=function(){return n(a.error)},a.onupgradeneeded=function(e){r?(a.transaction.abort(),a.result.close()):"function"===typeof t._onupgradeneeded&&t._onupgradeneeded(e)},a.onsuccess=function(){var n=a.result;r?n.close():(n.onversionchange=t._onversionchange.bind(t),e(n))}}));case 4:return this._db=e.sent,e.abrupt("return",this);case 6:case"end":return e.stop()}}),e,this)})));return function(){return e.apply(this,arguments)}}()},{key:"getKey",value:function(){var e=O(L.a.mark((function e(t,n){return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,this.getAllKeys(t,n,1);case 2:return e.abrupt("return",e.sent[0]);case 3:case"end":return e.stop()}}),e,this)})));return function(t,n){return e.apply(this,arguments)}}()},{key:"getAll",value:function(){var e=O(L.a.mark((function e(t,n,r){return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,this.getAllMatching(t,{query:n,count:r});case 2:return e.abrupt("return",e.sent);case 3:case"end":return e.stop()}}),e,this)})));return function(t,n,r){return e.apply(this,arguments)}}()},{key:"getAllKeys",value:function(){var e=O(L.a.mark((function e(t,n,r){var a;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,this.getAllMatching(t,{query:n,count:r,includeKeys:!0});case 2:return a=e.sent,e.abrupt("return",a.map((function(e){return e.key})));case 4:case"end":return e.stop()}}),e,this)})));return function(t,n,r){return e.apply(this,arguments)}}()},{key:"getAllMatching",value:function(){var e=O(L.a.mark((function e(t){var n,r,a,i,c,u,o,s,f,h=arguments;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return n=h.length>1&&void 0!==h[1]?h[1]:{},r=n.index,a=n.query,i=void 0===a?null:a,c=n.direction,u=void 0===c?"next":c,o=n.count,s=n.includeKeys,f=void 0!==s&&s,e.next=3,this.transaction([t],"readonly",(function(e,n){var a=e.objectStore(t),c=r?a.index(r):a,s=[],h=c.openCursor(i,u);h.onsuccess=function(){var e=h.result;e?(s.push(f?e:e.value),o&&s.length>=o?n(s):e.continue()):n(s)}}));case 3:return e.abrupt("return",e.sent);case 4:case"end":return e.stop()}}),e,this)})));return function(t){return e.apply(this,arguments)}}()},{key:"transaction",value:function(){var e=O(L.a.mark((function e(t,n,r){var a=this;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,this.open();case 2:return e.next=4,new Promise((function(e,i){var c=a._db.transaction(t,n);c.onabort=function(){return i(c.error)},c.oncomplete=function(){return e()},r(c,(function(t){return e(t)}))}));case 4:return e.abrupt("return",e.sent);case 5:case"end":return e.stop()}}),e,this)})));return function(t,n,r){return e.apply(this,arguments)}}()},{key:"_call",value:function(){var e=O(L.a.mark((function e(t,n,r){var a,i,c,u,o=arguments;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:for(a=o.length,i=new Array(a>3?a-3:0),c=3;c1?a-1:0),c=1;c0?n.clone():null,e.prev=12,h=c(u),e.prev=14,h.s();case 16:if((l=h.n()).done){e.next=27;break}if(!("requestWillFetch"in(p=l.value))){e.next=25;break}return v=p.requestWillFetch,d=n.clone(),e.next=23,v.call(p,{request:d,event:a});case 23:n=e.sent;case 25:e.next=16;break;case 27:e.next=32;break;case 29:e.prev=29,e.t0=e.catch(14),h.e(e.t0);case 32:return e.prev=32,h.f(),e.finish(32);case 35:e.next=40;break;case 37:throw e.prev=37,e.t1=e.catch(12),new g("plugin-error-request-will-fetch",{thrownError:e.t1});case 40:if(y=n.clone(),e.prev=41,"navigate"!==n.mode){e.next=48;break}return e.next=45,fetch(n);case 45:m=e.sent,e.next=51;break;case 48:return e.next=50,fetch(n,r);case 50:m=e.sent;case 51:0,x=c(u),e.prev=53,x.s();case 55:if((w=x.n()).done){e.next=64;break}if(!("fetchDidSucceed"in(b=w.value))){e.next=62;break}return e.next=60,b.fetchDidSucceed.call(b,{event:a,request:y,response:m});case 60:m=e.sent;case 62:e.next=55;break;case 64:e.next=69;break;case 66:e.prev=66,e.t2=e.catch(53),x.e(e.t2);case 69:return e.prev=69,x.f(),e.finish(69);case 72:return e.abrupt("return",m);case 75:e.prev=75,e.t3=e.catch(41),k=c(s),e.prev=79,k.s();case 81:if((_=k.n()).done){e.next=87;break}return R=_.value,e.next=85,R.fetchDidFail.call(R,{error:e.t3,event:a,originalRequest:f.clone(),request:y.clone()});case 85:e.next=81;break;case 87:e.next=92;break;case 89:e.prev=89,e.t4=e.catch(79),k.e(e.t4);case 92:return e.prev=92,k.f(),e.finish(92);case 95:throw e.t3;case 96:case"end":return e.stop()}}),e,null,[[12,37],[14,29,32,35],[41,75],[53,66,69,72],[79,89,92,95]])})));return function(t){return e.apply(this,arguments)}}()};function J(e,t){return V.apply(this,arguments)}function V(){return(V=O(L.a.mark((function e(t,n){var r,a,i,c;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(r=t.clone(),a={headers:new Headers(r.headers),status:r.status,statusText:r.statusText},i=n?n(a):a,!P()){e.next=7;break}e.t0=r.body,e.next=10;break;case 7:return e.next=9,r.blob();case 9:e.t0=e.sent;case 10:return c=e.t0,e.abrupt("return",new Response(c,i));case 12:case"end":return e.stop()}}),e)})))).apply(this,arguments)}n(5);var z="cache-entries",X=function(e){var t=new URL(e,location.href);return t.hash="",t.href},Z=function(){function e(t){var n=this;u(this,e),this._cacheName=t,this._db=new H("workbox-expiration",1,{onupgradeneeded:function(e){return n._handleUpgrade(e)}})}return F(e,[{key:"_handleUpgrade",value:function(e){var t=e.target.result.createObjectStore(z,{keyPath:"id"});t.createIndex("cacheName","cacheName",{unique:!1}),t.createIndex("timestamp","timestamp",{unique:!1}),Y(this._cacheName)}},{key:"setTimestamp",value:function(){var e=O(L.a.mark((function e(t,n){var r;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return t=X(t),r={url:t,timestamp:n,cacheName:this._cacheName,id:this._getId(t)},e.next=4,this._db.put(z,r);case 4:case"end":return e.stop()}}),e,this)})));return function(t,n){return e.apply(this,arguments)}}()},{key:"getTimestamp",value:function(){var e=O(L.a.mark((function e(t){var n;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,this._db.get(z,this._getId(t));case 2:return n=e.sent,e.abrupt("return",n.timestamp);case 4:case"end":return e.stop()}}),e,this)})));return function(t){return e.apply(this,arguments)}}()},{key:"expireEntries",value:function(){var e=O(L.a.mark((function e(t,n){var r,a,i,u,o,s=this;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,this._db.transaction(z,"readwrite",(function(e,r){var a=e.objectStore(z).index("timestamp").openCursor(null,"prev"),i=[],c=0;a.onsuccess=function(){var e=a.result;if(e){var u=e.value;u.cacheName===s._cacheName&&(t&&u.timestamp=n?i.push(e.value):c++),e.continue()}else r(i)}}));case 2:r=e.sent,a=[],i=c(r),e.prev=5,i.s();case 7:if((u=i.n()).done){e.next=14;break}return o=u.value,e.next=11,this._db.delete(z,o.id);case 11:a.push(o.url);case 12:e.next=7;break;case 14:e.next=19;break;case 16:e.prev=16,e.t0=e.catch(5),i.e(e.t0);case 19:return e.prev=19,i.f(),e.finish(19);case 22:return e.abrupt("return",a);case 23:case"end":return e.stop()}}),e,this,[[5,16,19,22]])})));return function(t,n){return e.apply(this,arguments)}}()},{key:"_getId",value:function(e){return this._cacheName+"|"+X(e)}}]),e}(),ee=function(){function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};u(this,e),this._isRunning=!1,this._rerunRequested=!1,this._maxEntries=n.maxEntries,this._maxAgeSeconds=n.maxAgeSeconds,this._cacheName=t,this._timestampModel=new Z(t)}return F(e,[{key:"expireEntries",value:function(){var e=O(L.a.mark((function e(){var t,n,r,a,i,u;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(!this._isRunning){e.next=3;break}return this._rerunRequested=!0,e.abrupt("return");case 3:return this._isRunning=!0,t=this._maxAgeSeconds?Date.now()-1e3*this._maxAgeSeconds:0,e.next=7,this._timestampModel.expireEntries(t,this._maxEntries);case 7:return n=e.sent,e.next=10,self.caches.open(this._cacheName);case 10:r=e.sent,a=c(n),e.prev=12,a.s();case 14:if((i=a.n()).done){e.next=20;break}return u=i.value,e.next=18,r.delete(u);case 18:e.next=14;break;case 20:e.next=25;break;case 22:e.prev=22,e.t0=e.catch(12),a.e(e.t0);case 25:return e.prev=25,a.f(),e.finish(25);case 28:0,this._isRunning=!1,this._rerunRequested&&(this._rerunRequested=!1,I(this.expireEntries()));case 31:case"end":return e.stop()}}),e,this,[[12,22,25,28]])})));return function(){return e.apply(this,arguments)}}()},{key:"updateTimestamp",value:function(){var e=O(L.a.mark((function e(t){return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=3,this._timestampModel.setTimestamp(t,Date.now());case 3:case"end":return e.stop()}}),e,this)})));return function(t){return e.apply(this,arguments)}}()},{key:"isURLExpired",value:function(){var e=O(L.a.mark((function e(t){var n,r;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(this._maxAgeSeconds){e.next=6;break}e.next=3;break;case 3:return e.abrupt("return",!1);case 6:return e.next=8,this._timestampModel.getTimestamp(t);case 8:return n=e.sent,r=Date.now()-1e3*this._maxAgeSeconds,e.abrupt("return",n0&&void 0!==arguments[0]?arguments[0]:{};u(this,e),this.cachedResponseWillBeUsed=function(){var e=O(L.a.mark((function e(n){var r,a,i,c,u,o,s;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(r=n.event,a=n.request,i=n.cacheName,c=n.cachedResponse){e.next=3;break}return e.abrupt("return",null);case 3:if(u=t._isResponseDateFresh(c),I((o=t._getCacheExpiration(i)).expireEntries()),s=o.updateTimestamp(a.url),r)try{r.waitUntil(s)}catch(f){0}return e.abrupt("return",u?c:null);case 9:case"end":return e.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}(),this.cacheDidUpdate=function(){var e=O(L.a.mark((function e(n){var r,a,i;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return r=n.cacheName,a=n.request,i=t._getCacheExpiration(r),e.next=5,i.updateTimestamp(a.url);case 5:return e.next=7,i.expireEntries();case 7:case"end":return e.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}(),this._config=n,this._maxAgeSeconds=n.maxAgeSeconds,this._cacheExpirations=new Map,n.purgeOnQuotaError&&w((function(){return t.deleteCacheAndMetadata()}))}return F(e,[{key:"_getCacheExpiration",value:function(e){if(e===R())throw new g("expire-custom-caches-only");var t=this._cacheExpirations.get(e);return t||(t=new ee(e,this._config),this._cacheExpirations.set(e,t)),t}},{key:"_isResponseDateFresh",value:function(e){if(!this._maxAgeSeconds)return!0;var t=this._getDateHeaderTimestamp(e);return null===t||t>=Date.now()-1e3*this._maxAgeSeconds}},{key:"_getDateHeaderTimestamp",value:function(e){if(!e.headers.has("date"))return null;var t=e.headers.get("date"),n=new Date(t).getTime();return isNaN(n)?null:n}},{key:"deleteCacheAndMetadata",value:function(){var e=O(L.a.mark((function e(){var t,n,r,a,i;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:t=c(this._cacheExpirations),e.prev=1,t.s();case 3:if((n=t.n()).done){e.next=11;break}return r=D(n.value,2),a=r[0],i=r[1],e.next=7,self.caches.delete(a);case 7:return e.next=9,i.delete();case 9:e.next=3;break;case 11:e.next=16;break;case 13:e.prev=13,e.t0=e.catch(1),t.e(e.t0);case 16:return e.prev=16,t.f(),e.finish(16);case 19:this._cacheExpirations=new Map;case 20:case"end":return e.stop()}}),e,this,[[1,13,16,19]])})));return function(){return e.apply(this,arguments)}}()}]),e}(),ne=(n(2),[]),re=function(){return ne};function ae(e){if(!e)throw new g("add-to-cache-list-unexpected-type",{entry:e});if("string"===typeof e){var t=new URL(e,location.href);return{cacheKey:t.href,url:t.href}}var n=e.revision,r=e.url;if(!r)throw new g("add-to-cache-list-unexpected-type",{entry:e});if(!n){var a=new URL(r,location.href);return{cacheKey:a.href,url:a.href}}var i=new URL(r,location.href),c=new URL(r,location.href);return i.searchParams.set("__WB_REVISION__",n),{cacheKey:i.href,url:c.href}}var ie,ce=function(){function e(t){u(this,e),this._cacheName=_(t),this._urlsToCacheKeys=new Map,this._urlsToCacheModes=new Map,this._cacheKeysToIntegrities=new Map}return F(e,[{key:"addToCacheList",value:function(e){var t,n=[],r=c(e);try{for(r.s();!(t=r.n()).done;){var a=t.value;"string"===typeof a?n.push(a):a&&void 0===a.revision&&n.push(a.url);var i=ae(a),u=i.cacheKey,o=i.url,s="string"!==typeof a&&a.revision?"reload":"default";if(this._urlsToCacheKeys.has(o)&&this._urlsToCacheKeys.get(o)!==u)throw new g("add-to-cache-list-conflicting-entries",{firstEntry:this._urlsToCacheKeys.get(o),secondEntry:u});if("string"!==typeof a&&a.integrity){if(this._cacheKeysToIntegrities.has(u)&&this._cacheKeysToIntegrities.get(u)!==a.integrity)throw new g("add-to-cache-list-conflicting-integrities",{url:o});this._cacheKeysToIntegrities.set(u,a.integrity)}if(this._urlsToCacheKeys.set(o,u),this._urlsToCacheModes.set(o,s),n.length>0){var f="Workbox is precaching URLs without revision "+"info: ".concat(n.join(", "),"\nThis is generally NOT safe. ")+"Learn more at https://bit.ly/wb-precache";console.warn(f)}}}catch(h){r.e(h)}finally{r.f()}}},{key:"install",value:function(){var e=O(L.a.mark((function e(){var t,n,r,a,i,u,o,s,f,h,l,p,v,d,y,m=this,g=arguments;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return t=g.length>0&&void 0!==g[0]?g[0]:{},n=t.event,r=t.plugins,a=[],i=[],e.next=6,self.caches.open(this._cacheName);case 6:return u=e.sent,e.next=9,u.keys();case 9:o=e.sent,s=new Set(o.map((function(e){return e.url}))),f=c(this._urlsToCacheKeys);try{for(f.s();!(h=f.n()).done;)l=D(h.value,2),p=l[0],v=l[1],s.has(v)?i.push(p):a.push({cacheKey:v,url:p})}catch(x){f.e(x)}finally{f.f()}return d=a.map((function(e){var t=e.cacheKey,a=e.url,i=m._cacheKeysToIntegrities.get(t),c=m._urlsToCacheModes.get(a);return m._addURLToCache({cacheKey:t,cacheMode:c,event:n,integrity:i,plugins:r,url:a})})),e.next=16,Promise.all(d);case 16:return y=a.map((function(e){return e.url})),e.abrupt("return",{updatedURLs:y,notUpdatedURLs:i});case 19:case"end":return e.stop()}}),e,this)})));return function(){return e.apply(this,arguments)}}()},{key:"activate",value:function(){var e=O(L.a.mark((function e(){var t,n,r,a,i,u,o;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,self.caches.open(this._cacheName);case 2:return t=e.sent,e.next=5,t.keys();case 5:n=e.sent,r=new Set(this._urlsToCacheKeys.values()),a=[],i=c(n),e.prev=9,i.s();case 11:if((u=i.n()).done){e.next=19;break}if(o=u.value,r.has(o.url)){e.next=17;break}return e.next=16,t.delete(o);case 16:a.push(o.url);case 17:e.next=11;break;case 19:e.next=24;break;case 21:e.prev=21,e.t0=e.catch(9),i.e(e.t0);case 24:return e.prev=24,i.f(),e.finish(24);case 27:return e.abrupt("return",{deletedURLs:a});case 29:case"end":return e.stop()}}),e,this,[[9,21,24,27]])})));return function(){return e.apply(this,arguments)}}()},{key:"_addURLToCache",value:function(){var e=O(L.a.mark((function e(t){var n,r,a,i,u,o,s,f,h,l,p,v;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return n=t.cacheKey,r=t.url,a=t.cacheMode,i=t.event,u=t.plugins,o=t.integrity,s=new Request(r,{integrity:o,cache:a,credentials:"same-origin"}),e.next=4,$.fetch({event:i,plugins:u,request:s});case 4:f=e.sent,l=c(u||[]);try{for(l.s();!(p=l.n()).done;)"cacheWillUpdate"in(v=p.value)&&(h=v)}catch(d){l.e(d)}finally{l.f()}if(!h){e.next=13;break}return e.next=10,h.cacheWillUpdate({event:i,request:s,response:f});case 10:e.t0=e.sent,e.next=14;break;case 13:e.t0=f.status<400;case 14:if(e.t0){e.next=17;break}throw new g("bad-precaching-response",{url:r,status:f.status});case 17:if(!f.redirected){e.next=21;break}return e.next=20,J(f);case 20:f=e.sent;case 21:return e.next=23,K.put({event:i,plugins:u,response:f,request:n===r?s:new Request(n),cacheName:this._cacheName,matchOptions:{ignoreSearch:!0}});case 23:case"end":return e.stop()}}),e,this)})));return function(t){return e.apply(this,arguments)}}()},{key:"getURLsToCacheKeys",value:function(){return this._urlsToCacheKeys}},{key:"getCachedURLs",value:function(){return i(this._urlsToCacheKeys.keys())}},{key:"getCacheKeyForURL",value:function(e){var t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}},{key:"matchPrecache",value:function(){var e=O(L.a.mark((function e(t){var n,r,a;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(n=t instanceof Request?t.url:t,!(r=this.getCacheKeyForURL(n))){e.next=7;break}return e.next=5,self.caches.open(this._cacheName);case 5:return a=e.sent,e.abrupt("return",a.match(r));case 7:return e.abrupt("return",void 0);case 8:case"end":return e.stop()}}),e,this)})));return function(t){return e.apply(this,arguments)}}()},{key:"createHandler",value:function(){var e=this,t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];return function(){var n=O(L.a.mark((function n(r){var a,i;return L.a.wrap((function(n){for(;;)switch(n.prev=n.next){case 0:return a=r.request,n.prev=1,n.next=4,e.matchPrecache(a);case 4:if(!(i=n.sent)){n.next=7;break}return n.abrupt("return",i);case 7:throw new g("missing-precache-entry",{cacheName:e._cacheName,url:a instanceof Request?a.url:a});case 10:if(n.prev=10,n.t0=n.catch(1),!t){n.next=15;break}return n.abrupt("return",fetch(a));case 15:throw n.t0;case 16:case"end":return n.stop()}}),n,null,[[1,10]])})));return function(e){return n.apply(this,arguments)}}()}},{key:"createHandlerBoundToURL",value:function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],n=this.getCacheKeyForURL(e);if(!n)throw new g("non-precached-url",{url:e});var r=this.createHandler(t),a=new Request(e);return function(){return r({request:a})}}}]),e}(),ue=function(){return ie||(ie=new ce),ie};function oe(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=function(){var n=a[r];t.some((function(e){return e.test(n)}))&&e.searchParams.delete(n)},r=0,a=i(e.searchParams.keys());r1&&void 0!==d[1]?d[1]:{},n=t.ignoreURLParametersMatching,r=t.directoryIndex,a=t.cleanURLs,i=t.urlManipulation,(u=new URL(e,location.href)).hash="",y.next=5,u.href;case 5:return o=oe(u,n),y.next=8,o.href;case 8:if(!r||!o.pathname.endsWith("/")){y.next=13;break}return(s=new URL(o.href)).pathname+=r,y.next=13,s.href;case 13:if(!a){y.next=18;break}return(f=new URL(o.href)).pathname+=".html",y.next=18,f.href;case 18:if(!i){y.next=37;break}h=i({url:u}),l=c(h),y.prev=21,l.s();case 23:if((p=l.n()).done){y.next=29;break}return v=p.value,y.next=27,v.href;case 27:y.next=23;break;case 29:y.next=34;break;case 31:y.prev=31,y.t0=y.catch(21),l.e(y.t0);case 34:return y.prev=34,l.f(),y.finish(34);case 37:case"end":return y.stop()}}),se,null,[[21,31,34,37]])}var he=function(e,t){var n,r=ue().getURLsToCacheKeys(),a=c(fe(e,t));try{for(a.s();!(n=a.n()).done;){var i=n.value,u=r.get(i);if(u)return u}}catch(o){a.e(o)}finally{a.f()}},le=!1;function pe(e){le||(!function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.ignoreURLParametersMatching,n=void 0===t?[/^utm_/]:t,r=e.directoryIndex,a=void 0===r?"index.html":r,i=e.cleanURLs,c=void 0===i||i,u=e.urlManipulation,o=_();self.addEventListener("fetch",(function(e){var t=he(e.request.url,{cleanURLs:c,directoryIndex:a,ignoreURLParametersMatching:n,urlManipulation:u});if(t){var r=self.caches.open(o).then((function(e){return e.match(t)})).then((function(e){return e||fetch(t)}));e.respondWith(r)}}))}(e),le=!0)}var ve=function(e){var t=ue(),n=re();e.waitUntil(t.install({event:e,plugins:n}).catch((function(e){throw e})))},de=function(e){var t=ue();e.waitUntil(t.activate())};n(3);var ye,me=function(e){return e&&"object"===typeof e?e:{handle:e}},ge=function e(t,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"GET";u(this,e),this.handler=me(n),this.match=t,this.method=r},xe=function(e){s(n,e);var t=v(n);function n(e,r,a){u(this,n);return t.call(this,(function(t){var n=t.url,r=e.exec(n.href);if(r&&(n.origin===location.origin||0===r.index))return r.slice(1)}),r,a)}return n}(ge),we=function(){function e(){u(this,e),this._routes=new Map}return F(e,[{key:"routes",get:function(){return this._routes}},{key:"addFetchListener",value:function(){var e=this;self.addEventListener("fetch",(function(t){var n=t.request,r=e.handleRequest({request:n,event:t});r&&t.respondWith(r)}))}},{key:"addCacheListener",value:function(){var e=this;self.addEventListener("message",(function(t){if(t.data&&"CACHE_URLS"===t.data.type){var n=t.data.payload;0;var r=Promise.all(n.urlsToCache.map((function(t){"string"===typeof t&&(t=[t]);var n=d(Request,i(t));return e.handleRequest({request:n})})));t.waitUntil(r),t.ports&&t.ports[0]&&r.then((function(){return t.ports[0].postMessage(!0)}))}}))}},{key:"handleRequest",value:function(e){var t=this,n=e.request,r=e.event;var a=new URL(n.url,location.href);if(a.protocol.startsWith("http")){var i=this.findMatchingRoute({url:a,request:n,event:r}),c=i.params,u=i.route,o=u&&u.handler;if(!o&&this._defaultHandler&&(o=this._defaultHandler),o){var s;0;try{s=o.handle({url:a,request:n,event:r,params:c})}catch(f){s=Promise.reject(f)}return s instanceof Promise&&this._catchHandler&&(s=s.catch((function(e){return t._catchHandler.handle({url:a,request:n,event:r})}))),s}}}},{key:"findMatchingRoute",value:function(e){var t=e.url,n=e.request,r=e.event;var a,i=c(this._routes.get(n.method)||[]);try{for(i.s();!(a=i.n()).done;){var u=a.value,o=void 0,s=u.match({url:t,request:n,event:r});if(s)return o=s,(Array.isArray(s)&&0===s.length||s.constructor===Object&&0===Object.keys(s).length||"boolean"===typeof s)&&(o=void 0),{route:u,params:o}}}catch(f){i.e(f)}finally{i.f()}return{}}},{key:"setDefaultHandler",value:function(e){this._defaultHandler=me(e)}},{key:"setCatchHandler",value:function(e){this._catchHandler=me(e)}},{key:"registerRoute",value:function(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}},{key:"unregisterRoute",value:function(e){if(!this._routes.has(e.method))throw new g("unregister-route-but-not-found-with-method",{method:e.method});var t=this._routes.get(e.method).indexOf(e);if(!(t>-1))throw new g("unregister-route-route-not-registered");this._routes.get(e.method).splice(t,1)}}]),e}(),be=function(){return ye||((ye=new we).addFetchListener(),ye.addCacheListener()),ye};function ke(e,t,n){var r;if("string"===typeof e){var a=new URL(e,location.href);r=new ge((function(e){return e.url.href===a.href}),t,n)}else if(e instanceof RegExp)r=new xe(e,t,n);else if("function"===typeof e)r=new ge(e,t,n);else{if(!(e instanceof ge))throw new g("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});r=e}return be().registerRoute(r),r}n(4);var _e,Re={cacheWillUpdate:function(){var e=O(L.a.mark((function e(t){var n;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(200!==(n=t.response).status&&0!==n.status){e.next=3;break}return e.abrupt("return",n);case 3:return e.abrupt("return",null);case 4:case"end":return e.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}()},Ee=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(u(this,e),this._cacheName=R(t.cacheName),this._plugins=t.plugins||[],t.plugins){var n=t.plugins.some((function(e){return!!e.cacheWillUpdate}));this._plugins=n?t.plugins:[Re].concat(i(t.plugins))}else this._plugins=[Re];this._fetchOptions=t.fetchOptions,this._matchOptions=t.matchOptions}return F(e,[{key:"handle",value:function(){var e=O(L.a.mark((function e(t){var n,r,a,i,c;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return n=t.event,r=t.request,[],"string"===typeof r&&(r=new Request(r)),a=this._getFromNetwork({request:r,event:n}),e.next=7,K.match({cacheName:this._cacheName,request:r,event:n,matchOptions:this._matchOptions,plugins:this._plugins});case 7:if(!(i=e.sent)){e.next=13;break}if(n)try{n.waitUntil(a)}catch(c){0}e.next=23;break;case 13:return e.prev=14,e.next=17,a;case 17:i=e.sent,e.next=23;break;case 20:e.prev=20,e.t0=e.catch(14),c=e.t0;case 23:if(i){e.next=26;break}throw new g("no-response",{url:r.url,error:c});case 26:return e.abrupt("return",i);case 27:case"end":return e.stop()}}),e,this,[[14,20]])})));return function(t){return e.apply(this,arguments)}}()},{key:"_getFromNetwork",value:function(){var e=O(L.a.mark((function e(t){var n,r,a,i;return L.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return n=t.request,r=t.event,e.next=3,$.fetch({request:n,event:r,fetchOptions:this._fetchOptions,plugins:this._plugins});case 3:if(a=e.sent,i=K.put({cacheName:this._cacheName,request:n,response:a.clone(),event:r,plugins:this._plugins}),r)try{r.waitUntil(i)}catch(c){0}return e.abrupt("return",a);case 7:case"end":return e.stop()}}),e,this)})));return function(t){return e.apply(this,arguments)}}()}]),e}();self.addEventListener("activate",(function(){return self.clients.claim()})),function(e){ue().addToCacheList(e),e.length>0&&(self.addEventListener("install",ve),self.addEventListener("activate",de))}([{'revision':'1f7feee4366a0b6ef0a4eb382c3fe542','url':'/index.html'},{'revision':null,'url':'/static/css/main.642eee9a.chunk.css'},{'revision':null,'url':'/static/js/2.00db38da.chunk.js'},{'revision':null,'url':'/static/js/main.24f2182f.chunk.js'},{'revision':null,'url':'/static/js/runtime-main.4e2c014c.js'}]),pe(_e);var Le,qe=new RegExp("/[^/?]+\\.[^/]+$");ke((function(e){var t=e.request,n=e.url;return"navigate"===t.mode&&(!n.pathname.startsWith("/_")&&!n.pathname.match(qe))}),(Le="/index.html",ue().createHandlerBoundToURL(Le))),ke((function(e){var t=e.url;return t.origin===self.location.origin&&t.pathname.endsWith(".png")}),new Ee({cacheName:"images",plugins:[new te({maxEntries:50})]})),self.addEventListener("message",(function(e){e.data&&"SKIP_WAITING"===e.data.type&&self.skipWaiting()}))}]); +//# sourceMappingURL=service-worker.js.map \ No newline at end of file diff --git a/public/site.webmanifest b/public/site.webmanifest index d9870d77..a0a302a6 100644 --- a/public/site.webmanifest +++ b/public/site.webmanifest @@ -1,6 +1,6 @@ { - "name": "", - "short_name": "", + "name": "movie-web", + "short_name": "movie-web", "icons": [ { "src": "/android-chrome-192x192.png", @@ -15,5 +15,6 @@ ], "theme_color": "#E880C5", "background_color": "#16171D", - "display": "standalone" + "display": "standalone", + "start_url": "/" } diff --git a/src/index.js b/src/index.js index 6832e783..2ac37109 100644 --- a/src/index.js +++ b/src/index.js @@ -2,6 +2,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; +import * as serviceWorkerRegistration from './serviceWorkerRegistration'; ReactDOM.render( @@ -9,3 +10,5 @@ ReactDOM.render( , document.getElementById('root') ); + +serviceWorkerRegistration.register(); \ No newline at end of file diff --git a/src/service-worker.js b/src/service-worker.js new file mode 100644 index 00000000..0f1e0ce0 --- /dev/null +++ b/src/service-worker.js @@ -0,0 +1,72 @@ +/* eslint-disable no-restricted-globals */ + +// This service worker can be customized! +// See https://developers.google.com/web/tools/workbox/modules +// for the list of available Workbox modules, or add any other +// code you'd like. +// You can also remove this file if you'd prefer not to use a +// service worker, and the Workbox build step will be skipped. + +import { clientsClaim } from 'workbox-core'; +import { ExpirationPlugin } from 'workbox-expiration'; +import { precacheAndRoute, createHandlerBoundToURL } from 'workbox-precaching'; +import { registerRoute } from 'workbox-routing'; +import { StaleWhileRevalidate } from 'workbox-strategies'; + +clientsClaim(); + +// Precache all of the assets generated by your build process. +// Their URLs are injected into the manifest variable below. +// This variable must be present somewhere in your service worker file, +// even if you decide not to use precaching. See https://cra.link/PWA +precacheAndRoute(self.__WB_MANIFEST); + +// Set up App Shell-style routing, so that all navigation requests +// are fulfilled with your index.html shell. Learn more at +// https://developers.google.com/web/fundamentals/architecture/app-shell +const fileExtensionRegexp = new RegExp('/[^/?]+\\.[^/]+$'); +registerRoute( + // Return false to exempt requests from being fulfilled by index.html. + ({ request, url }) => { + // If this isn't a navigation, skip. + if (request.mode !== 'navigate') { + return false; + } // If this is a URL that starts with /_, skip. + + if (url.pathname.startsWith('/_')) { + return false; + } // If this looks like a URL for a resource, because it contains // a file extension, skip. + + if (url.pathname.match(fileExtensionRegexp)) { + return false; + } // Return true to signal that we want to use the handler. + + return true; + }, + createHandlerBoundToURL(process.env.PUBLIC_URL + '/index.html') +); + +// An example runtime caching route for requests that aren't handled by the +// precache, in this case same-origin .png requests like those from in public/ +registerRoute( + // Add in any other file extensions or routing criteria as needed. + ({ url }) => url.origin === self.location.origin && url.pathname.endsWith('.png'), // Customize this strategy as needed, e.g., by changing to CacheFirst. + new StaleWhileRevalidate({ + cacheName: 'images', + plugins: [ + // Ensure that once this runtime cache reaches a maximum size the + // least-recently used images are removed. + new ExpirationPlugin({ maxEntries: 50 }), + ], + }) +); + +// This allows the web app to trigger skipWaiting via +// registration.waiting.postMessage({type: 'SKIP_WAITING'}) +self.addEventListener('message', (event) => { + if (event.data && event.data.type === 'SKIP_WAITING') { + self.skipWaiting(); + } +}); + +// Any other custom service worker logic can go here. diff --git a/src/serviceWorkerRegistration.js b/src/serviceWorkerRegistration.js new file mode 100644 index 00000000..26468c7c --- /dev/null +++ b/src/serviceWorkerRegistration.js @@ -0,0 +1,125 @@ +// This optional code is used to register a service worker. +// register() is not called by default. + +// This lets the app load faster on subsequent visits in production, and gives +// it offline capabilities. However, it also means that developers (and users) +// will only see deployed updates on subsequent visits to a page, after all the +// existing tabs open on the page have been closed, since previously cached +// resources are updated in the background. + +// To learn more about the benefits of this model and instructions on how to +// opt-in, read https://cra.link/PWA + +const isLocalhost = Boolean( + window.location.hostname === 'localhost' || + // [::1] is the IPv6 localhost address. + window.location.hostname === '[::1]' || + // 127.0.0.0/8 are considered localhost for IPv4. + window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/) +); + +export function register(config) { + if ('serviceWorker' in navigator) { + // The URL constructor is available in all browsers that support SW. + const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); + + if (publicUrl.origin !== window.location.origin) { + return; + } + + window.addEventListener('load', () => { + const swUrl = `${publicUrl}service-worker.js`; + + if (isLocalhost) { + checkValidServiceWorker(swUrl, config); + } else { + // Is not localhost. Just register service worker + registerValidSW(swUrl, config); + } + }); + } +} + +function registerValidSW(swUrl, config) { + navigator.serviceWorker + .register(swUrl) + .then((registration) => { + registration.onupdatefound = () => { + const installingWorker = registration.installing; + if (installingWorker == null) { + return; + } + installingWorker.onstatechange = () => { + if (installingWorker.state === 'installed') { + if (navigator.serviceWorker.controller) { + // 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) { + config.onUpdate(registration); + } + } else { + // 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) { + config.onSuccess(registration); + } + } + } + }; + }; + }) + .catch((error) => { + console.error('Error during service worker registration:', error); + }); +} + +function checkValidServiceWorker(swUrl, config) { + // Check if the service worker can be found. If it can't reload the page. + fetch(swUrl, { + headers: { 'Service-Worker': 'script' }, + }) + .then((response) => { + // Ensure service worker exists, and that we really are getting a JS file. + const contentType = response.headers.get('content-type'); + if ( + response.status === 404 || + (contentType != null && contentType.indexOf('javascript') === -1) + ) { + // No service worker found. Probably a different app. Reload the page. + navigator.serviceWorker.ready.then((registration) => { + registration.unregister().then(() => { + window.location.reload(); + }); + }); + } else { + // Service worker found. Proceed as normal. + registerValidSW(swUrl, config); + } + }) + .catch(() => { + console.log('No internet connection found. App is running in offline mode.'); + }); +} + +export function unregister() { + if ('serviceWorker' in navigator) { + navigator.serviceWorker.ready + .then((registration) => { + registration.unregister(); + }) + .catch((error) => { + console.error(error.message); + }); + } +} From 19891569b753387be4a40e0e8bd4b31008a3f7e0 Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Wed, 14 Jul 2021 16:15:25 +0100 Subject: [PATCH 0017/1989] 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 0018/1989] 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 0019/1989] 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 0020/1989] 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); From 57e9bc2dc17313e8de8932d1de5f63f9dcc30fae Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Wed, 14 Jul 2021 23:09:42 +0100 Subject: [PATCH 0021/1989] Better show support --- public/index.html | 2 +- src/components/Card.css | 2 +- src/components/EpisodeSelector.css | 0 src/components/EpisodeSelector.js | 13 ++++ src/components/InputBox.css | 60 +++------------- src/components/InputBox.js | 34 ++------- src/components/MovieRow.css | 14 ++-- src/components/MovieRow.js | 1 - src/components/NumberSelector.css | 48 +++++++++++++ src/components/NumberSelector.js | 20 ++++++ src/components/Progress.css | 6 +- src/components/Title.css | 9 ++- src/components/TypeSelector.css | 59 ++++++++++++++++ src/components/TypeSelector.js | 24 +++++++ src/components/VideoElement.css | 2 +- src/components/VideoElement.js | 15 +++- src/hooks/useMovie.js | 2 +- src/index.css | 29 +++++++- src/lib/lookMovie.js | 39 +++++++++-- src/service-worker.js | 72 ------------------- src/views/Movie.css | 3 + src/views/Movie.js | 71 +++++++++++++++++-- src/views/Search.css | 2 +- src/views/Search.js | 64 ++++++++++++----- yarn.lock | 109 ++++++++++++++++++++++++++++- 25 files changed, 495 insertions(+), 205 deletions(-) create mode 100644 src/components/EpisodeSelector.css create mode 100644 src/components/EpisodeSelector.js create mode 100644 src/components/NumberSelector.css create mode 100644 src/components/NumberSelector.js create mode 100644 src/components/TypeSelector.css create mode 100644 src/components/TypeSelector.js delete mode 100644 src/service-worker.js diff --git a/public/index.html b/public/index.html index 4c313487..885b2d5b 100644 --- a/public/index.html +++ b/public/index.html @@ -20,7 +20,7 @@ movie-web - +
diff --git a/src/components/Card.css b/src/components/Card.css index 710f0e49..6dabda2b 100644 --- a/src/components/Card.css +++ b/src/components/Card.css @@ -1,5 +1,5 @@ .card { - background-color: #22232A; + background-color: var(--card); padding: 3rem 4rem; margin: 0 3rem; border-radius: 10px; diff --git a/src/components/EpisodeSelector.css b/src/components/EpisodeSelector.css new file mode 100644 index 00000000..e69de29b diff --git a/src/components/EpisodeSelector.js b/src/components/EpisodeSelector.js new file mode 100644 index 00000000..3881c64c --- /dev/null +++ b/src/components/EpisodeSelector.js @@ -0,0 +1,13 @@ +import React from 'react'; +import { TypeSelector } from './TypeSelector'; +import { NumberSelector } from './NumberSelector'; +import './EpisodeSelector.css' + +export function EpisodeSelector({ setSeason, setEpisode, seasons, episodes, currentSeason, currentEpisode }) { + return ( +
+ ({ value: v.toString(), label: `Season ${v}`}))} selected={currentSeason}/>

+ setEpisode({episode: e, season: currentSeason})} choices={episodes.map(v=>({ value: v.toString(), label: v}))} selected={currentEpisode.season === currentSeason?currentEpisode.episode:null}/> +
+ ) +} diff --git a/src/components/InputBox.css b/src/components/InputBox.css index f1480b9c..4339c9e7 100644 --- a/src/components/InputBox.css +++ b/src/components/InputBox.css @@ -19,8 +19,8 @@ .inputTextBox { border-width: 0; outline: none; - background-color: #36363e; - color: white; + background-color: var(--content); + color: var(--text); padding: .7rem 1.5rem; height: auto; flex: 1; @@ -28,52 +28,21 @@ } .inputSearchButton { - background-color: #A73B83; + background-color: var(--button); border-width: 0; - color: white; + color: var(--text); 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; + background-color: var(--button-hover); } .inputTextBox:hover { - background-color: #3C3D44; -} - -.inputOptionBox:hover { - background-color: #3C3D44; + background-color: var(--content-hover); } .inputSearchButton .text > .arrow { @@ -83,11 +52,13 @@ right: -0.8rem; bottom: -0.2rem; } + .inputSearchButton .text { display: flex; position: relative; transition: transform 0.2s ease-in-out; } + .inputSearchButton:hover .text > .arrow { transform: translateX(8px); opacity: 1; @@ -98,7 +69,7 @@ } .inputSearchButton:active { - background-color: #8b286a; + background-color: var(--button-active); } @media screen and (max-width: 700px) { @@ -121,17 +92,4 @@ 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 a42900b9..f1f5d2ea 100644 --- a/src/components/InputBox.js +++ b/src/components/InputBox.js @@ -5,22 +5,13 @@ import './InputBox.css' // props = { onSubmit: (str) => {}, placeholder: string} 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, season, episode) + onSubmit(searchTerm) return false; }}> - 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.css b/src/components/MovieRow.css index 45986130..99a6cad0 100644 --- a/src/components/MovieRow.css +++ b/src/components/MovieRow.css @@ -1,8 +1,8 @@ .movieRow { display: flex; border-radius: 5px; - background-color: #35363D; - color: white; + background-color: var(--content); + color: var(--text); padding: .8rem 1.5rem; margin-top: .5rem; cursor: pointer; @@ -23,11 +23,11 @@ } .movieRow .left .year { - color: #BCBECB; + color: var(--text-secondary); } .movieRow .watch { - color: #D678B7; + color: var(--theme-color-text); display: flex; align-items: center; } @@ -43,7 +43,7 @@ } .movieRow:hover { - background-color: #3A3B40; + background-color: var(--content-hover); } .movieRow:hover .watch .arrow { @@ -51,8 +51,8 @@ } .attribute { - color: white; - background-color: #D678B7; + color: var(--text); + background-color: var(--theme-color); font-size: .75rem; padding: .25rem; border-radius: 10px; diff --git a/src/components/MovieRow.js b/src/components/MovieRow.js index c304aa4d..a3ae80bd 100644 --- a/src/components/MovieRow.js +++ b/src/components/MovieRow.js @@ -12,7 +12,6 @@ export function MovieRow(props) { ({props.year})
-

Watch {props.type}

diff --git a/src/components/NumberSelector.css b/src/components/NumberSelector.css new file mode 100644 index 00000000..4f8e62f9 --- /dev/null +++ b/src/components/NumberSelector.css @@ -0,0 +1,48 @@ +.numberSelector { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(2.5rem, 1fr)); + gap: 5px; + position: relative; + margin-bottom: 1.5rem; +} + +.numberSelector .choiceWrapper { + position: relative; +} + +.numberSelector .choiceWrapper::before { + content: ''; + display: block; + width: 100%; + padding-bottom: 100%; +} + +.numberSelector .choice { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: var(--choice); + margin-right: 5px; + padding: .2rem; + display: flex; + justify-content: center; + align-items: center; + text-align: center; + color: var(--text); + font-weight: bold; + cursor: pointer; + user-select: none; + border-radius: 10%; + box-sizing: border-box; +} + +.numberSelector .choice:hover { + background-color: var(--choice-hover); +} + +.numberSelector .choice.selected { + color: var(--text); + background-color: var(--choice-hover); +} diff --git a/src/components/NumberSelector.js b/src/components/NumberSelector.js new file mode 100644 index 00000000..ecbf9658 --- /dev/null +++ b/src/components/NumberSelector.js @@ -0,0 +1,20 @@ +import React from 'react'; +// import { Arrow } from './Arrow'; +import './NumberSelector.css' + +// setType: (txt: string) => void +// choices: { label: string, value: string }[] +// selected: string +export function NumberSelector({ setType, choices, selected }) { + return ( +
+ {choices.map(v=>( +
+
setType(v.value)}> + {v.label} +
+
+ ))} +
+ ) +} diff --git a/src/components/Progress.css b/src/components/Progress.css index 9c0b84f4..a0116519 100644 --- a/src/components/Progress.css +++ b/src/components/Progress.css @@ -1,6 +1,6 @@ .progress { text-align: center; - color: #BCBECB; + color: var(--text-secondary); display: flex; align-items: center; justify-content: center; @@ -32,12 +32,12 @@ .progress .bar .bar-inner { transition: width 400ms ease-in-out, background-color 100ms ease-in-out; - background-color: #D463AE; + background-color: var(--theme-color); border-radius: 10px; height: 100%; width: 0%; } .progress.failed .bar .bar-inner { - background-color: #d85b66; + background-color: var(--failed); } diff --git a/src/components/Title.css b/src/components/Title.css index 6796dce9..c5691634 100644 --- a/src/components/Title.css +++ b/src/components/Title.css @@ -1,6 +1,6 @@ .title { font-size: 2rem; - color: white; + color: var(--text); /* max-width: 20rem; */ margin: 0; padding: 0; @@ -10,9 +10,13 @@ .title-size-medium { font-size: 1.5rem; } +.title-size-small { + font-size: 1.1rem; + color: #afb1b8; +} .title-accent { - color: #E880C5; + color: var(--theme-color); font-weight: 600; margin: 0; padding: 0; @@ -34,3 +38,4 @@ .title-accent.title-accent-link:hover .arrow { transform: translateY(.1rem) translateX(-.5rem); } + diff --git a/src/components/TypeSelector.css b/src/components/TypeSelector.css new file mode 100644 index 00000000..39273f17 --- /dev/null +++ b/src/components/TypeSelector.css @@ -0,0 +1,59 @@ + +/* TODO better responsiveness, use dropdown if more than 5 options */ +.typeSelector { + display: inline-flex; + position: relative; + margin-bottom: 1.5rem; + max-width: 100%; + flex-wrap: wrap; +} + +.typeSelector::before { + content: ""; + position: absolute; + width: 100%; + bottom: 0; + background-color: #3a3c46; + height: 4px; + border-radius: 2px; +} + +.typeSelector .choice { + width: 7rem; + height: 3rem; + padding: .3rem .2rem; + display: flex; + justify-content: center; + align-items: center; + text-align: center; + box-sizing: border-box; + color: #585A67; + font-weight: bold; + cursor: pointer; + user-select: none; +} + +.typeSelector .choice:hover { + color: #afb1b8; +} + +.typeSelector .choice.selected { + color: var(--text); +} + +.typeSelector .selectedBar { + position: absolute; + height: 4px; + width: 7rem; + background-color: var(--theme-color); + border-radius: 2px; + bottom: 0; + transition: transform 150ms ease-in-out; +} + +@media screen and (max-width: 700px) { + .typeSelector { + width: 80%; + display: block; + } +} diff --git a/src/components/TypeSelector.js b/src/components/TypeSelector.js new file mode 100644 index 00000000..ee96b275 --- /dev/null +++ b/src/components/TypeSelector.js @@ -0,0 +1,24 @@ +import React from 'react'; +// import { Arrow } from './Arrow'; +import './TypeSelector.css' + +// setType: (txt: string) => void +// choices: { label: string, value: string }[] +// selected: string +export function TypeSelector({ setType, choices, selected }) { + const selectedIndex = choices.findIndex(v=>v.value===selected); + const transformStyles = { + opacity: selectedIndex!==-1?1:0, + transform: `translateX(${selectedIndex!==-1?selectedIndex*7:0}rem)` + } + return ( +
+ {choices.map(v=>( +
setType(v.value)}> + {v.label} +
+ ))} +
+
+ ) +} diff --git a/src/components/VideoElement.css b/src/components/VideoElement.css index f3a684a6..bb829039 100644 --- a/src/components/VideoElement.css +++ b/src/components/VideoElement.css @@ -5,6 +5,6 @@ } .videoElementText { - color: white; + color: var(--text); margin: 0; } diff --git a/src/components/VideoElement.js b/src/components/VideoElement.js index 2bdba8da..c568302e 100644 --- a/src/components/VideoElement.js +++ b/src/components/VideoElement.js @@ -3,13 +3,14 @@ import Hls from 'hls.js' import './VideoElement.css' // streamUrl: string -export function VideoElement({ streamUrl }) { +// loading: boolean +export function VideoElement({ streamUrl, loading }) { const videoRef = React.useRef(null); const [error, setError] = React.useState(false); React.useEffect(() => { setError(false) - if (!videoRef || !videoRef.current) return; + if (!videoRef || !videoRef.current || !streamUrl || streamUrl.length === 0 || loading) return; const hls = new Hls(); @@ -23,11 +24,19 @@ export function VideoElement({ streamUrl }) { hls.attachMedia(videoRef.current); hls.loadSource(streamUrl); - }, [videoRef, streamUrl]) + }, [videoRef, streamUrl, loading]) + + // TODO make better loading/error/empty state if (error) return (

Your browser is not supported

) + if (loading) + return

Loading episode

+ + if (!streamUrl || streamUrl.length === 0) + return

No video selected

+ return (