From 10cbef99a2a2141b599d171a02308594ed691aa8 Mon Sep 17 00:00:00 2001 From: Chris Bendel Date: Thu, 25 Apr 2024 09:54:04 -0400 Subject: [PATCH 1/3] Testing --- manifest.ts | 9 +-- package.json | 2 + public/stealie-128.png | Bin 35792 -> 36945 bytes public/stealie-16.png | Bin 987 -> 0 bytes public/stealie-48.png | Bin 5885 -> 0 bytes src/pages/content/components/app.tsx | 98 ++++++++++++++++++++++++++- yarn.lock | 84 ++++++++++++++++++++++- 7 files changed, 183 insertions(+), 10 deletions(-) delete mode 100644 public/stealie-16.png delete mode 100644 public/stealie-48.png diff --git a/manifest.ts b/manifest.ts index 3ac74bc..d477e06 100755 --- a/manifest.ts +++ b/manifest.ts @@ -31,14 +31,7 @@ const manifest: chrome.runtime.ManifestV3 = { ], web_accessible_resources: [ { - resources: [ - "assets/js/*.js", - "assets/css/*.css", - // TODO Needed? - // "stealie-16.png", - // "stealie-48.png", - "stealie-128.png", - ], + resources: ["assets/js/*.js", "assets/css/*.css", "stealie-128.png"], matches: ["*://*/*"], }, ], diff --git a/package.json b/package.json index 3e323de..115378f 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,8 @@ }, "type": "module", "dependencies": { + "jszip": "^3.10.1", + "jszip-utils": "^0.1.0", "lodash-es": "^4.17.21", "react": "18.2.0", "react-dom": "18.2.0", diff --git a/public/stealie-128.png b/public/stealie-128.png index 22c0c0a7f5cfbc787eb0fa4ccf023fa1c2fbf5c3..e7ef7756bea2aeb043548652064c561e56f80aba 100644 GIT binary patch literal 36945 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�^?AbL^&N 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 { + return new Promise(function (resolve, reject) { + JSZipUtils.getBinaryContent(url, function (err, data) { + if (err) { + reject(err); + } else { + resolve(data); + } + }); + }); +}; const getMP3Urls = (show: ArchiveShow) => { const mp3Files = pickBy(show.files, function (file: ArchiveFile) { @@ -111,7 +125,8 @@ const DownloadButton: FC<{ show: ArchiveShow }> = ({ show }) => { const downloadShow = async (archiveShow: ArchiveShow) => { setLoading(true); - await createZip(archiveShow); + await doTheThing(archiveShow); + // await createZip(archiveShow); setLoading(false); }; @@ -128,3 +143,84 @@ const DownloadButton: FC<{ show: ArchiveShow }> = ({ show }) => { ); }; + +// https://codesandbox.io/p/sandbox/jszip-with-streamsaver-4t056i?file=%2Fsrc%2Findex.js%3A105%2C8 +const doTheThing = async (show: ArchiveShow) => { + const zip = new JSZip(); + + const mp3s = getMP3Urls(show); + + await Promise.all( + mp3s.map(async (mp3) => { + const res = await fetch(mp3.url); + const z = await JSZip.loadAsync(res.json()); + const stream = () => res.body; + + ctrl.enqueue({ name: `${mp3.title}.mp3`, stream }); + }) + ); + + const writeStream = streamSaver + .createWriteStream(`${getShowTitle(show)}.zip`) + .getWriter(); + zip + .generateInternalStream({ + type: "uint8array", + streamFiles: true, + compression: "DEFLATE", + }) + .on("data", (data) => writeStream.write(data)) + .on("error", (err) => console.error(err)) + .on("end", () => writeStream.close()) + .resume(); + + const infoUrl = getInfoFileUrl(show); + // zip.file("info.txt", urlToPromise(infoUrl), { binary: true }); + fetch(infoUrl).then(async (res) => { + const fileStream = streamSaver.createWriteStream( + `${getShowTitle(show)}/info.txt` + ); + + const readableStream = res.body; + + // more optimized + if (window.WritableStream && readableStream.pipeTo) { + await readableStream.pipeTo(fileStream); + return console.log("done writing"); + } + }); +}; + +// function getRemoteFile(file: string, url: string) { +// const localFile = fs.createWriteStream(file); +// const request = http.get(url, function (response) { +// const len = parseInt(response.headers["content-length"], 10); +// let cur = 0; +// const total = len / 1048576; //1048576 - bytes in 1 Megabyte +// +// response.on("data", function (chunk) { +// cur += chunk.length; +// showProgress(file, cur, len, total); +// }); +// +// response.on("end", function () { +// console.log("Download complete"); +// }); +// +// response.pipe(localFile); +// }); +// } +// +// function showProgress(file, cur, len, total) { +// console.log( +// "Downloading " + +// file + +// " - " + +// ((100.0 * cur) / len).toFixed(2) + +// "% (" + +// (cur / 1048576).toFixed(2) + +// " MB) of total size: " + +// total.toFixed(2) + +// " MB" +// ); +// } diff --git a/yarn.lock b/yarn.lock index 79bf491..7580721 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1454,6 +1454,11 @@ convert-source-map@^2.0.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + create-jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" @@ -2413,6 +2418,11 @@ ignore@^5.2.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.0.tgz#67418ae40d34d6999c95ff56016759c718c82f78" integrity sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg== +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + immutable@^4.0.0: version "4.3.4" resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.4.tgz#2e07b33837b4bb7662f288c244d1ced1ef65a78f" @@ -2447,7 +2457,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2: +inherits@2, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -2618,6 +2628,11 @@ isarray@^2.0.5: resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -3154,6 +3169,21 @@ jsonfile@^6.0.1: object.assign "^4.1.4" object.values "^1.1.6" +jszip-utils@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/jszip-utils/-/jszip-utils-0.1.0.tgz#8c04cdedcdb291e83f055f5b261b3a3188ceca0b" + integrity sha512-tBNe0o3HAf8vo0BrOYnLPnXNo5A3KsRMnkBFYjh20Y3GPYGfgyoclEMgvVchx0nnL+mherPi74yLPIusHUQpZg== + +jszip@^3.10.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2" + integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== + dependencies: + lie "~3.3.0" + pako "~1.0.2" + readable-stream "~2.3.6" + setimmediate "^1.0.5" + keyv@^4.5.3: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" @@ -3179,6 +3209,13 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +lie@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a" + integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== + dependencies: + immediate "~3.0.5" + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" @@ -3513,6 +3550,11 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +pako@~1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -3649,6 +3691,11 @@ pretty-format@^29.0.0, pretty-format@^29.7.0: ansi-styles "^5.0.0" react-is "^18.0.0" +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + prompts@^2.0.1: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" @@ -3730,6 +3777,19 @@ read-pkg@^3.0.0: normalize-package-data "^2.3.2" path-type "^3.0.0" +readable-stream@~2.3.6: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" @@ -3839,6 +3899,11 @@ safe-array-concat@^1.0.1: has-symbols "^1.0.3" isarray "^2.0.5" +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + safe-regex-test@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" @@ -3912,6 +3977,11 @@ set-function-name@^2.0.0: functions-have-names "^1.2.3" has-property-descriptors "^1.0.0" +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -4099,6 +4169,13 @@ string.prototype.trimstart@^1.0.7: define-properties "^1.2.0" es-abstract "^1.22.1" +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -4360,6 +4437,11 @@ url-parse@^1.5.3: querystringify "^2.1.1" requires-port "^1.0.0" +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + v8-to-istanbul@^9.0.1: version "9.2.0" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz#2ed7644a245cddd83d4e087b9b33b3e62dfd10ad" From 7bf9b1868c14d30cf6ac67557b0dedcfe367a541 Mon Sep 17 00:00:00 2001 From: Chris Bendel Date: Thu, 25 Apr 2024 19:45:06 -0400 Subject: [PATCH 2/3] Some polish --- package.json | 4 +- src/pages/content/components/app.tsx | 358 ++++++++++++++++--------- src/pages/content/models/interfaces.ts | 3 +- src/pages/content/style.scss | 14 + src/pages/content/utils/zip-stream.js | 234 ---------------- yarn.lock | 5 - 6 files changed, 241 insertions(+), 377 deletions(-) delete mode 100644 src/pages/content/utils/zip-stream.js diff --git a/package.json b/package.json index 115378f..845d7b4 100644 --- a/package.json +++ b/package.json @@ -18,11 +18,9 @@ "type": "module", "dependencies": { "jszip": "^3.10.1", - "jszip-utils": "^0.1.0", "lodash-es": "^4.17.21", "react": "18.2.0", - "react-dom": "18.2.0", - "streamsaver": "^2.0.6" + "react-dom": "18.2.0" }, "devDependencies": { "@rollup/plugin-typescript": "^8.5.0", diff --git a/src/pages/content/components/app.tsx b/src/pages/content/components/app.tsx index 9b13435..fa58736 100644 --- a/src/pages/content/components/app.tsx +++ b/src/pages/content/components/app.tsx @@ -1,29 +1,21 @@ -import { FC, useEffect, useState } from "react"; +import { + ChangeEvent, + ChangeEventHandler, + FC, + useEffect, + useState, +} from "react"; import { ArchiveFile, - MP3Url, ArchiveShow, + Track, } from "@pages/content/models/interfaces"; -import streamSaver from "streamsaver"; import pickBy from "lodash-es/pickBy"; import findKey from "lodash-es/findKey"; -import ZIP from "@pages/content/utils/zip-stream.js"; -import JSZip from "jszip"; -import JSZipUtils from "jszip-utils"; - -const urlToPromise = (url: string) => { - return new Promise(function (resolve, reject) { - JSZipUtils.getBinaryContent(url, function (err, data) { - if (err) { - reject(err); - } else { - resolve(data); - } - }); - }); -}; +import JSZip, { file } from "jszip"; +import SelectionChangedEvent = chrome.devtools.panels.SelectionChangedEvent; -const getMP3Urls = (show: ArchiveShow) => { +const getTracks = (show: ArchiveShow): Track[] => { const mp3Files = pickBy(show.files, function (file: ArchiveFile) { return file.format === "VBR MP3"; }); @@ -33,7 +25,7 @@ const getMP3Urls = (show: ArchiveShow) => { const url = baseURL + key; let title = data.title || data.original; title = title.replace(/-|[^-_,A-Za-z0-9 ]+/g, "").trim(); - return { title: index + 1 + ". " + title, track: title, url: url }; + return { title: index + 1 + ". " + title, url: url } as Track; }); }; @@ -49,37 +41,52 @@ const getInfoFileUrl = (show: ArchiveShow) => { // TODO Allow option for selecting show format OR // Prompt user for download title? window.prompt? const getShowTitle = (show: ArchiveShow) => { - return show.metadata.date[0]; + return ( + prompt(`Custom folder title? Default ${show.metadata.date[0]}`) || + show.metadata.date[0] + ); }; -const createZip = async (show: ArchiveShow) => { - const fileStream = streamSaver.createWriteStream(`${getShowTitle(show)}.zip`); - const mp3s = getMP3Urls(show); - - const readableZipStream = new ZIP({ - async pull(ctrl) { - // Gets executed everytime zip.js asks for more data - const infoFile = await fetch(getInfoFileUrl(show)); - ctrl.enqueue({ - name: "info.txt", - stream: () => infoFile.body, - }); +async function fetchWithRedirect(url: string) { + const response = await fetch(url, { redirect: "follow" }); + if (response.status === 302) { + const redirectUrl = response.headers.get("Location"); + console.log(redirectUrl); + if (!redirectUrl) { + throw new Error("Redirect URL not found"); + } + return fetch(redirectUrl); // Fetch the redirect URL + } else if (response.ok) { + return response; + } else { + throw new Error("Network response was not ok"); + } +} - // TODO Implement range fetching: https://www.zeng.dev/post/2023-http-range-and-play-mp4-in-browser/ - await Promise.all( - mp3s.map(async (mp3) => { - const res = await fetch(mp3.url); - const stream = () => res.body; - ctrl.enqueue({ name: `${mp3.title}.mp3`, stream }); - }) +async function fetchWithRetry(url: string, maxRetries = 3): Promise { + let retries = 0; + while (true) { + try { + const response = await fetchWithRedirect(url); + if (response.ok) { + return response; + } else { + throw new Error(`Failed to fetch: ${response.statusText}`); + } + } catch (error) { + retries++; + if (retries >= maxRetries) { + throw error; // If max retries exceeded, propagate the error + } + console.log( + `Error occurred, retrying (${retries}/${maxRetries}):`, + error ); - - ctrl.close(); - }, - }); - - return readableZipStream.pipeTo(fileStream); -}; + // Wait for a short duration before retrying (you can adjust the duration as needed) + await new Promise((resolve) => setTimeout(resolve, 1000 * retries)); + } + } +} export default function App() { const [archiveShow, setArchiveShow] = useState(); @@ -112,7 +119,16 @@ export default function App() { }} >

Grateful Grabber

- +
+ + +
@@ -120,107 +136,183 @@ export default function App() { ); } +const DownloadIndividualSong: FC<{ show: ArchiveShow }> = ({ show }) => { + const [loadingTracks, setLoadingTracks] = useState([]); + const tracks = getTracks(show); + + console.log(loadingTracks); + + const onDownload = async (track: Track) => { + setLoadingTracks((prevState) => [...prevState, track.title]); + await downloadFile(track.url, track.title, ".mp3"); + setLoadingTracks(loadingTracks.filter((t) => t == track.title)); + }; + + return ( + <> + + {loadingTracks.length > 0 ? ( + Downloading {loadingTracks} + ) : null} + + ); +}; + const DownloadButton: FC<{ show: ArchiveShow }> = ({ show }) => { const [loading, setLoading] = useState(false); + const [progress, setProgress] = useState(0); + const [error, setError] = useState(null); const downloadShow = async (archiveShow: ArchiveShow) => { + setError(null); setLoading(true); - await doTheThing(archiveShow); - // await createZip(archiveShow); + + await createZip(archiveShow, setProgress) + .then((blob) => downloadZip(archiveShow, blob, setProgress)) + .catch((error) => { + setError(error.toString()); + setLoading(false); + console.error("Error:", error); + }); + setLoading(false); }; return ( - + <> + + {progress ? : null} + {error && ( + + Something went wrong, restart the download, it should pick up where + you left off :) + + )} + ); }; -// https://codesandbox.io/p/sandbox/jszip-with-streamsaver-4t056i?file=%2Fsrc%2Findex.js%3A105%2C8 -const doTheThing = async (show: ArchiveShow) => { - const zip = new JSZip(); +async function downloadFile(url: string, fileName: string, extension = ".mp3") { + const response = await fetchWithRetry(url); + if (!response.ok) { + throw new Error(`Failed to download ${url}`); + } - const mp3s = getMP3Urls(show); + const blob = await response.blob(); - await Promise.all( - mp3s.map(async (mp3) => { - const res = await fetch(mp3.url); - const z = await JSZip.loadAsync(res.json()); - const stream = () => res.body; + // Create a temporary anchor element + const a = document.createElement("a"); + a.href = URL.createObjectURL(blob); + a.download = `${fileName}${extension}`; - ctrl.enqueue({ name: `${mp3.title}.mp3`, stream }); - }) + // Programmatically trigger the download + a.click(); + + // Clean up the URL.createObjectURL() resource + URL.revokeObjectURL(a.href); +} + +async function getFileBlob( + url: string, + onProgress?: (progress: number) => void +): Promise { + const response = await fetchWithRetry(url); + if (!response.ok) { + throw new Error(`Failed to download ${url}`); + } + + const contentLength = parseInt( + response.headers.get("Content-Length") || "0", + 10 ); + let receivedLength = 0; + const reader = response.body.getReader(); + const chunks: Uint8Array[] = []; + + while (true) { + const { done, value } = await reader.read(); - const writeStream = streamSaver - .createWriteStream(`${getShowTitle(show)}.zip`) - .getWriter(); - zip - .generateInternalStream({ - type: "uint8array", - streamFiles: true, - compression: "DEFLATE", - }) - .on("data", (data) => writeStream.write(data)) - .on("error", (err) => console.error(err)) - .on("end", () => writeStream.close()) - .resume(); - - const infoUrl = getInfoFileUrl(show); - // zip.file("info.txt", urlToPromise(infoUrl), { binary: true }); - fetch(infoUrl).then(async (res) => { - const fileStream = streamSaver.createWriteStream( - `${getShowTitle(show)}/info.txt` - ); - - const readableStream = res.body; - - // more optimized - if (window.WritableStream && readableStream.pipeTo) { - await readableStream.pipeTo(fileStream); - return console.log("done writing"); + if (done) { + break; } - }); -}; -// function getRemoteFile(file: string, url: string) { -// const localFile = fs.createWriteStream(file); -// const request = http.get(url, function (response) { -// const len = parseInt(response.headers["content-length"], 10); -// let cur = 0; -// const total = len / 1048576; //1048576 - bytes in 1 Megabyte -// -// response.on("data", function (chunk) { -// cur += chunk.length; -// showProgress(file, cur, len, total); -// }); -// -// response.on("end", function () { -// console.log("Download complete"); -// }); -// -// response.pipe(localFile); -// }); -// } -// -// function showProgress(file, cur, len, total) { -// console.log( -// "Downloading " + -// file + -// " - " + -// ((100.0 * cur) / len).toFixed(2) + -// "% (" + -// (cur / 1048576).toFixed(2) + -// " MB) of total size: " + -// total.toFixed(2) + -// " MB" -// ); -// } + chunks.push(value); + receivedLength += value.length; + const progress = receivedLength / contentLength; + onProgress?.(progress); + } + + return new Blob(chunks); +} + +// Define function to create a zip file from mp3 blobs with progress ingtrack +async function createZip( + show: ArchiveShow, + onProgress: (progress: number) => void +): Promise { + const zip = new JSZip(); + let completedCount = 0; + const mp3Urls = getTracks(show); + console.log(mp3Urls); + const infoFile = getInfoFileUrl(show); + + const infoBlob = await getFileBlob(infoFile); + zip.file("info.txt", infoBlob); + + for (const url of mp3Urls) { + const mp3Blob = await getFileBlob(url.url, (progress) => { + const overallProgress = (completedCount + progress) / mp3Urls.length; + onProgress(overallProgress); + }); + + zip.file(`${url.title}.mp3`, mp3Blob); + completedCount++; + onProgress(completedCount / mp3Urls.length); + } + + return await zip.generateAsync({ type: "blob" }); +} + +// Define function to download the zip file with progress tracking +function downloadZip( + archiveShow: ArchiveShow, + blob: Blob, + onProgress: (progress: number) => void +) { + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = `${getShowTitle(archiveShow)}.zip`; + a.click(); + onProgress(1); // Mark progress as completed +} diff --git a/src/pages/content/models/interfaces.ts b/src/pages/content/models/interfaces.ts index fe9b081..ce2c7df 100644 --- a/src/pages/content/models/interfaces.ts +++ b/src/pages/content/models/interfaces.ts @@ -21,8 +21,7 @@ export interface Metadata { date: string[]; } -export interface MP3Url { +export interface Track { title: string; - track: string; url: string; } diff --git a/src/pages/content/style.scss b/src/pages/content/style.scss index 0654416..be152c6 100644 --- a/src/pages/content/style.scss +++ b/src/pages/content/style.scss @@ -3,3 +3,17 @@ .content-view { font-size: 30px; } + +.loader { + border: 16px solid #f3f3f3; /* Light grey */ + border-top: 16px solid #3498db; /* Blue */ + border-radius: 50%; + width: 120px; + height: 120px; + animation: spin 2s linear infinite; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} diff --git a/src/pages/content/utils/zip-stream.js b/src/pages/content/utils/zip-stream.js deleted file mode 100644 index dbbe727..0000000 --- a/src/pages/content/utils/zip-stream.js +++ /dev/null @@ -1,234 +0,0 @@ -class Crc32 { - constructor() { - this.crc = -1; - } - - append(data) { - var crc = this.crc | 0; - var table = this.table; - for (var offset = 0, len = data.length | 0; offset < len; offset++) { - crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xff]; - } - this.crc = crc; - } - - get() { - return ~this.crc; - } -} -Crc32.prototype.table = (() => { - var i; - var j; - var t; - var table = []; - for (i = 0; i < 256; i++) { - t = i; - for (j = 0; j < 8; j++) { - t = t & 1 ? (t >>> 1) ^ 0xedb88320 : t >>> 1; - } - table[i] = t; - } - return table; -})(); - -const getDataHelper = (byteLength) => { - var uint8 = new Uint8Array(byteLength); - return { - array: uint8, - view: new DataView(uint8.buffer), - }; -}; - -const pump = (zipObj) => - zipObj.reader.read().then((chunk) => { - if (chunk.done) return zipObj.writeFooter(); - const outputData = chunk.value; - zipObj.crc.append(outputData); - zipObj.uncompressedLength += outputData.length; - zipObj.compressedLength += outputData.length; - zipObj.ctrl.enqueue(outputData); - }); - -/** - * [createWriter description] - * @param {Object} underlyingSource [description] - * @return {Boolean} [description] - */ -function createWriter(underlyingSource) { - const files = Object.create(null); - const filenames = []; - const encoder = new TextEncoder(); - let offset = 0; - let activeZipIndex = 0; - let ctrl; - let activeZipObject, closed; - - function next() { - activeZipIndex++; - activeZipObject = files[filenames[activeZipIndex]]; - if (activeZipObject) processNextChunk(); - else if (closed) closeZip(); - } - - var zipWriter = { - enqueue(fileLike) { - if (closed) - throw new TypeError( - "Cannot enqueue a chunk into a readable stream that is closed or has been requested to be closed" - ); - - let name = fileLike.name.trim(); - const date = new Date( - typeof fileLike.lastModified === "undefined" - ? Date.now() - : fileLike.lastModified - ); - - if (fileLike.directory && !name.endsWith("/")) name += "/"; - if (files[name]) throw new Error("File already exists."); - - const nameBuf = encoder.encode(name); - filenames.push(name); - - const zipObject = (files[name] = { - level: 0, - ctrl, - directory: !!fileLike.directory, - nameBuf, - comment: encoder.encode(fileLike.comment || ""), - compressedLength: 0, - uncompressedLength: 0, - writeHeader() { - var header = getDataHelper(26); - var data = getDataHelper(30 + nameBuf.length); - - zipObject.offset = offset; - zipObject.header = header; - if (zipObject.level !== 0 && !zipObject.directory) { - header.view.setUint16(4, 0x0800); - } - header.view.setUint32(0, 0x14000808); - header.view.setUint16( - 6, - (((date.getHours() << 6) | date.getMinutes()) << 5) | - (date.getSeconds() / 2), - true - ); - header.view.setUint16( - 8, - ((((date.getFullYear() - 1980) << 4) | (date.getMonth() + 1)) << - 5) | - date.getDate(), - true - ); - header.view.setUint16(22, nameBuf.length, true); - data.view.setUint32(0, 0x504b0304); - data.array.set(header.array, 4); - data.array.set(nameBuf, 30); - offset += data.array.length; - ctrl.enqueue(data.array); - }, - writeFooter() { - var footer = getDataHelper(16); - footer.view.setUint32(0, 0x504b0708); - - if (zipObject.crc) { - zipObject.header.view.setUint32(10, zipObject.crc.get(), true); - zipObject.header.view.setUint32( - 14, - zipObject.compressedLength, - true - ); - zipObject.header.view.setUint32( - 18, - zipObject.uncompressedLength, - true - ); - footer.view.setUint32(4, zipObject.crc.get(), true); - footer.view.setUint32(8, zipObject.compressedLength, true); - footer.view.setUint32(12, zipObject.uncompressedLength, true); - } - - ctrl.enqueue(footer.array); - offset += zipObject.compressedLength + 16; - next(); - }, - fileLike, - }); - - if (!activeZipObject) { - activeZipObject = zipObject; - processNextChunk(); - } - }, - close() { - if (closed) - throw new TypeError( - "Cannot close a readable stream that has already been requested to be closed" - ); - if (!activeZipObject) closeZip(); - closed = true; - }, - }; - - function closeZip() { - var length = 0; - var index = 0; - var indexFilename, file; - for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) { - file = files[filenames[indexFilename]]; - length += 46 + file.nameBuf.length + file.comment.length; - } - const data = getDataHelper(length + 22); - for (indexFilename = 0; indexFilename < filenames.length; indexFilename++) { - file = files[filenames[indexFilename]]; - data.view.setUint32(index, 0x504b0102); - data.view.setUint16(index + 4, 0x1400); - data.array.set(file.header.array, index + 6); - data.view.setUint16(index + 32, file.comment.length, true); - if (file.directory) { - data.view.setUint8(index + 38, 0x10); - } - data.view.setUint32(index + 42, file.offset, true); - data.array.set(file.nameBuf, index + 46); - data.array.set(file.comment, index + 46 + file.nameBuf.length); - index += 46 + file.nameBuf.length + file.comment.length; - } - data.view.setUint32(index, 0x504b0506); - data.view.setUint16(index + 8, filenames.length, true); - data.view.setUint16(index + 10, filenames.length, true); - data.view.setUint32(index + 12, length, true); - data.view.setUint32(index + 16, offset, true); - ctrl.enqueue(data.array); - ctrl.close(); - } - - function processNextChunk() { - if (!activeZipObject) return; - if (activeZipObject.directory) - return activeZipObject.writeFooter(activeZipObject.writeHeader()); - if (activeZipObject.reader) return pump(activeZipObject); - if (activeZipObject.fileLike.stream) { - activeZipObject.crc = new Crc32(); - activeZipObject.reader = activeZipObject.fileLike.stream().getReader(); - activeZipObject.writeHeader(); - } else next(); - } - return new ReadableStream({ - start: (c) => { - ctrl = c; - underlyingSource.start && - Promise.resolve(underlyingSource.start(zipWriter)); - }, - pull() { - return ( - processNextChunk() || - (underlyingSource.pull && - Promise.resolve(underlyingSource.pull(zipWriter))) - ); - }, - }); -} - -export default createWriter; -// window.ZIP = createWriter; diff --git a/yarn.lock b/yarn.lock index 7580721..9b9a0a9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4096,11 +4096,6 @@ stack-utils@^2.0.3: dependencies: escape-string-regexp "^2.0.0" -streamsaver@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/streamsaver/-/streamsaver-2.0.6.tgz#869d2347dd70191e0ac888d52296956a8cba2ed9" - integrity sha512-LK4e7TfCV8HzuM0PKXuVUfKyCB1FtT9L0EGxsFk5Up8njj0bXK8pJM9+Wq2Nya7/jslmCQwRK39LFm55h7NBTw== - string-length@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" From 469db1e1050b7e8e8d75f135c62f52ed65e8b86f Mon Sep 17 00:00:00 2001 From: Chris Bendel Date: Fri, 26 Apr 2024 09:11:51 -0400 Subject: [PATCH 3/3] individual downloads --- src/pages/content/components/app.tsx | 92 ++++++++++++++-------------- 1 file changed, 45 insertions(+), 47 deletions(-) diff --git a/src/pages/content/components/app.tsx b/src/pages/content/components/app.tsx index fa58736..84f5613 100644 --- a/src/pages/content/components/app.tsx +++ b/src/pages/content/components/app.tsx @@ -1,10 +1,4 @@ -import { - ChangeEvent, - ChangeEventHandler, - FC, - useEffect, - useState, -} from "react"; +import { FC, useEffect, useState } from "react"; import { ArchiveFile, ArchiveShow, @@ -12,8 +6,7 @@ import { } from "@pages/content/models/interfaces"; import pickBy from "lodash-es/pickBy"; import findKey from "lodash-es/findKey"; -import JSZip, { file } from "jszip"; -import SelectionChangedEvent = chrome.devtools.panels.SelectionChangedEvent; +import JSZip from "jszip"; const getTracks = (show: ArchiveShow): Track[] => { const mp3Files = pickBy(show.files, function (file: ArchiveFile) { @@ -38,11 +31,9 @@ const getInfoFileUrl = (show: ArchiveShow) => { return `${baseURL}/${infoFile}`; }; -// TODO Allow option for selecting show format OR -// Prompt user for download title? window.prompt? const getShowTitle = (show: ArchiveShow) => { - return ( - prompt(`Custom folder title? Default ${show.metadata.date[0]}`) || + return prompt( + `Custom folder title? Default ${show.metadata.date[0]}`, show.metadata.date[0] ); }; @@ -51,7 +42,6 @@ async function fetchWithRedirect(url: string) { const response = await fetch(url, { redirect: "follow" }); if (response.status === 302) { const redirectUrl = response.headers.get("Location"); - console.log(redirectUrl); if (!redirectUrl) { throw new Error("Redirect URL not found"); } @@ -119,16 +109,8 @@ export default function App() { }} >

Grateful Grabber

-
- - -
+ + @@ -140,17 +122,25 @@ const DownloadIndividualSong: FC<{ show: ArchiveShow }> = ({ show }) => { const [loadingTracks, setLoadingTracks] = useState([]); const tracks = getTracks(show); - console.log(loadingTracks); - - const onDownload = async (track: Track) => { - setLoadingTracks((prevState) => [...prevState, track.title]); - await downloadFile(track.url, track.title, ".mp3"); - setLoadingTracks(loadingTracks.filter((t) => t == track.title)); + const onDownload = async (event) => { + const selectedOption = event.target.selectedOptions[0]; + const title = selectedOption.text; + const url = selectedOption.value; + setLoadingTracks((prevState) => [...prevState, title]); + await downloadFile(url, title, ".mp3"); + setLoadingTracks(loadingTracks.filter((t) => t == title)); }; return ( - <> - {tracks.map((track) => { return ( @@ -158,20 +148,29 @@ const DownloadIndividualSong: FC<{ show: ArchiveShow }> = ({ show }) => { key={track.title} onSelect={() => onDownload(track)} value={track.url} - // disabled={loadingTracks.includes(track.title)} > {track.title} - {loadingTracks.includes(track.title) ? ( -
- ) : null} ); })} + {loadingTracks.length > 0 ? ( - Downloading {loadingTracks} +
+

Download queue

+ {loadingTracks.map((title) => ( + {title} + ))} +
) : null} - + ); }; @@ -182,10 +181,14 @@ const DownloadButton: FC<{ show: ArchiveShow }> = ({ show }) => { const downloadShow = async (archiveShow: ArchiveShow) => { setError(null); + + const showTitle = getShowTitle(archiveShow); + if (!showTitle) return; + setLoading(true); await createZip(archiveShow, setProgress) - .then((blob) => downloadZip(archiveShow, blob, setProgress)) + .then((blob) => downloadZip(showTitle, blob, setProgress)) .catch((error) => { setError(error.toString()); setLoading(false); @@ -193,6 +196,7 @@ const DownloadButton: FC<{ show: ArchiveShow }> = ({ show }) => { }); setLoading(false); + setProgress(0); }; return ( @@ -230,15 +234,12 @@ async function downloadFile(url: string, fileName: string, extension = ".mp3") { const blob = await response.blob(); - // Create a temporary anchor element const a = document.createElement("a"); a.href = URL.createObjectURL(blob); a.download = `${fileName}${extension}`; - // Programmatically trigger the download a.click(); - // Clean up the URL.createObjectURL() resource URL.revokeObjectURL(a.href); } @@ -275,7 +276,6 @@ async function getFileBlob( return new Blob(chunks); } -// Define function to create a zip file from mp3 blobs with progress ingtrack async function createZip( show: ArchiveShow, onProgress: (progress: number) => void @@ -283,7 +283,6 @@ async function createZip( const zip = new JSZip(); let completedCount = 0; const mp3Urls = getTracks(show); - console.log(mp3Urls); const infoFile = getInfoFileUrl(show); const infoBlob = await getFileBlob(infoFile); @@ -303,16 +302,15 @@ async function createZip( return await zip.generateAsync({ type: "blob" }); } -// Define function to download the zip file with progress tracking function downloadZip( - archiveShow: ArchiveShow, + folderName: string, blob: Blob, onProgress: (progress: number) => void ) { const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; - a.download = `${getShowTitle(archiveShow)}.zip`; + a.download = `${folderName}.zip`; a.click(); onProgress(1); // Mark progress as completed }