diff --git a/src/components/PlaylistInfo.tsx b/src/components/PlaylistInfo.tsx index 6df698a..0d9e0cf 100644 --- a/src/components/PlaylistInfo.tsx +++ b/src/components/PlaylistInfo.tsx @@ -4,7 +4,7 @@ import { IconMaterialSymbolsCheckCircle } from "./Icons"; type IPlaylistInfo = { currentVid: IVidWithCustom; playlist: validPlaylistSlugs; - isSavingSingle: boolean; + isSavingSingle: string[]; }; export function PlaylistInfo({ currentVid, @@ -26,7 +26,7 @@ export function PlaylistInfo({ )} - {isSavingSingle && ( + {currentVid.id && isSavingSingle.includes(currentVid.id) && (
diff --git a/src/components/Settings/BulkListing.tsx b/src/components/Settings/BulkListing.tsx index 20cb13d..6d9709c 100644 --- a/src/components/Settings/BulkListing.tsx +++ b/src/components/Settings/BulkListing.tsx @@ -38,6 +38,7 @@ type IDownloadListing = { setCurrentVid: Dispatch>; downloadProgress: downloadProgressInfo | undefined; setShapedPlaylist: Dispatch>; + setIsSavingSingle: Dispatch>; }; export function BulkListing({ playlistData, @@ -49,6 +50,7 @@ export function BulkListing({ currentVid, downloadProgress, setShapedPlaylist, + setIsSavingSingle, }: IDownloadListing) { const { t } = useTranslation(); const [booksSelected, setBooksSelected] = useState>(); @@ -138,6 +140,10 @@ export function BulkListing({ for await (const vidChapter of flattenedBooks) { if (skipVidDownload(vidChapter)) continue; + setIsSavingSingle((prev) => { + // biome-ignore lint/style/noNonNullAssertion: + return [...prev, ...flattenedBooks.map((vid) => vid.id!)]; + }); if (!vidChapter.savedSources?.poster || !vidChapter.savedSources?.video) { setDownloadProgress({ amount: 0, @@ -214,7 +220,7 @@ export function BulkListing({ size="small" fill="outline" color="primary" - disabled={!booksSelected?.length} + disabled={!booksSelected?.length && !downloadProgress?.started} className="text-surface" onClick={() => { if (downloadProgress?.started) { @@ -246,6 +252,7 @@ export function BulkListing({ booksToCancel={booksToCancel} setBooksToCancel={setBooksToCancel} clearBookFromFs={clearBookFromFs} + setIsSavingSingle={setIsSavingSingle} /> ))} diff --git a/src/components/Settings/DownloadBookItem.tsx b/src/components/Settings/DownloadBookItem.tsx index 790861b..ccad69c 100644 --- a/src/components/Settings/DownloadBookItem.tsx +++ b/src/components/Settings/DownloadBookItem.tsx @@ -25,6 +25,7 @@ type BookToDownloadProps = { booksToCancel: (string | undefined)[]; setBooksToCancel: Dispatch>; clearBookFromFs(videos: IVidWithCustom[]): void; + setIsSavingSingle: Dispatch>; }; function bookIsFullyDownloaded(book: IVidWithCustom[]) { return book.every((vid) => !!vid.savedSources?.video); @@ -153,6 +154,9 @@ export function BookToDownload(props: BookToDownloadProps) { const vidsWithIds = book.value .filter((v) => !!v.id) .map((v) => v.id) as string[]; + props.setIsSavingSingle((prev) => + prev.filter((id) => !vidsWithIds.includes(id)), + ); if ( window.dotAppBooksToCancel && Array.isArray(window.dotAppBooksToCancel) && diff --git a/src/lib/Ui.tsx b/src/lib/Ui.tsx index de82894..33db79b 100644 --- a/src/lib/Ui.tsx +++ b/src/lib/Ui.tsx @@ -463,6 +463,7 @@ export async function fetchBcData(playlist: validPlaylistSlugs) { // Always refresh savedData with freshest from api right now, but do merge in anythign previously saved. We can look at doing the caching stuff again later, but for now, prioritize freshness if (savedData) { + // NOTE: THERE WAS SOME BANDWIDTH SAVING HERE BY ONLY REFRESHING AFTER SO LONG, BUT WE'RE JUST GONNA EAT THE BANDWIDTH FOR A PLAYLIST FETCH HERE AND NOT HAVE ANYTHING STALE // if (savedData.refreshBy > Date.now()) { // return savedData; // } @@ -471,14 +472,16 @@ export async function fetchBcData(playlist: validPlaylistSlugs) { // savedData.expiresBy > Date.now() // ) { // This is a background update. If it fails while offline or whatever, it - const mergedWithSavedSource = await mergeInPreviouslySavedVids({ + mergeInPreviouslySavedVids({ existingPlaylistData: savedData.formattedVideos, playlist, }); - return mergedWithSavedSource; + return savedData; + // } // } // } } + // if we are fetching fresh, we have nothing cached and don't need to worry about mergeing in previously saved vids const data = await fetchBcApiEndpoint(playlist); if (!data) throw new Error("fetch failed"); mutateTimeStampBcResponse(data); diff --git a/src/lib/storage.ts b/src/lib/storage.ts index 82db8ef..7324403 100644 --- a/src/lib/storage.ts +++ b/src/lib/storage.ts @@ -22,8 +22,8 @@ export function makeVidSaver( vid: IVidWithCustom, ) { // NOTE: We could change this, but 10 seems like a reasonsable amount for avoiding timeouts. - const increment = 1024 * 1000 * 10; //1 kilobyte * 1000 (= 1mb) * 10 = (10mb) - // const increment = 10 * 10 * 1024; //10mb + // const increment = 1024 * 1000 * 10; //1 kilobyte * 1000 (= 1mb) * 10 = (10mb) + const increment = 1024 * 300; //1kb * 250 = 300kb const mp4FileName = `${vid.id}_mp4`; function getAggregatedBlobPath() { diff --git a/src/pages/Playlist.tsx b/src/pages/Playlist.tsx index 1274194..7e96467 100644 --- a/src/pages/Playlist.tsx +++ b/src/pages/Playlist.tsx @@ -67,7 +67,7 @@ function Playlist() { const [jumpingForwardAmount, setJumpingForwardAmount] = useState(null); const [jumpingBackAmount, setJumpingBackAmount] = useState(null); - const [isSavingSingle, setIsSavingSingle] = useState(false); + const [isSavingSingle, setIsSavingSingle] = useState([]); const alertRef: any = useRef(null); /*// #=============== PAGE FUNCTIONS ============= */ @@ -230,20 +230,21 @@ function Playlist() { vidJsPlayer.off("ended", autoPlayToNextBook); vidJsPlayer.one("ended", autoPlayToNextBook); // MAYBE: I HAD ERROR HANDLING FOR EXPIRED SRC errors on media not supported, but now fetchAndSetup no already fetches the latest sources, but leaving here in case need to troubleshoot more later - // vidJsPlayer.on("error", handleVidJsError); + vidJsPlayer.on("error", handleVidJsError); } }, [currentVid, vidJsPlayer]); - // async function handleVidJsError() { - // if (!vidJsPlayer) return; - // const err = vidJsPlayer.error(); - // if (!err) return; - // if (err.code === 4) { - // 4 is mdia src not supported. - // await fetchAndSetup(); - // } - // console.error(event); - // } + async function handleVidJsError() { + if (!vidJsPlayer) return; + const err = vidJsPlayer.error(); + if (!err) return; + console.error({ err }); + if (err.code === 4) { + // 4 is mdia src not supported. + // await fetchAndSetup(); + } + // console.error(event); + } // biome-ignore lint/correctness/useExhaustiveDependencies: useEffect(() => { @@ -350,7 +351,7 @@ function Playlist() { const commonAction = (action: "DOWNLOAD" | "DELETE") => { const settingsEl = document.querySelector("#settingsRef"); if (settingsEl) { - const adjustPlayerSpeedEvent = new CustomEvent( + const manageSingleVideoStorage = new CustomEvent( "manageSingleVideoStorage", { detail: { @@ -359,9 +360,10 @@ function Playlist() { }, }, ); - settingsEl.dispatchEvent(adjustPlayerSpeedEvent); - if (action === "DOWNLOAD") { - setIsSavingSingle(true); + settingsEl.dispatchEvent(manageSingleVideoStorage); + const curId = currentVid.id; + if (action === "DOWNLOAD" && curId) { + setIsSavingSingle((prev) => [...prev, curId]); } } }; @@ -395,9 +397,9 @@ function Playlist() { useEffect(() => { if (currentVid.savedSources?.video) { - setIsSavingSingle(false); + setIsSavingSingle((prev) => prev.filter((id) => id !== currentVid.id)); } - }, [currentVid.savedSources?.video]); + }, [currentVid.savedSources?.video, currentVid.id]); /*//# =============== MARKUP ============= */ return ( @@ -423,6 +425,7 @@ function Playlist() { playlistSlug={playlistInfo.playlist} setShapedPlaylist={setShapedPlaylist} setCurrentBook={setCurrentBook} + setIsSavingSingle={setIsSavingSingle} /> )}