mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Store and restore download lists
This commit is contained in:
parent
a483955763
commit
f1cc396bfc
@ -28,6 +28,7 @@
|
|||||||
"expo-build-properties": "~0.8.3",
|
"expo-build-properties": "~0.8.3",
|
||||||
"expo-constants": "~14.4.2",
|
"expo-constants": "~14.4.2",
|
||||||
"expo-dev-client": "~2.4.12",
|
"expo-dev-client": "~2.4.12",
|
||||||
|
"expo-file-system": "~15.4.5",
|
||||||
"expo-font": "~11.4.0",
|
"expo-font": "~11.4.0",
|
||||||
"expo-linear-gradient": "~12.3.0",
|
"expo-linear-gradient": "~12.3.0",
|
||||||
"expo-linking": "~5.0.2",
|
"expo-linking": "~5.0.2",
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
"@material-symbols/svg-400": "*",
|
"@material-symbols/svg-400": "*",
|
||||||
"@shopify/flash-list": "^1.3.1",
|
"@shopify/flash-list": "^1.3.1",
|
||||||
"@tanstack/react-query": "*",
|
"@tanstack/react-query": "*",
|
||||||
|
"expo-file-system": "*",
|
||||||
"expo-linear-gradient": "*",
|
"expo-linear-gradient": "*",
|
||||||
"i18next": "*",
|
"i18next": "*",
|
||||||
"moti": "*",
|
"moti": "*",
|
||||||
@ -29,7 +30,8 @@
|
|||||||
"yoshiki": "*"
|
"yoshiki": "*"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@kesha-antonov/react-native-background-downloader": "^2.10.0"
|
"@kesha-antonov/react-native-background-downloader": "^2.10.0",
|
||||||
|
"expo-file-system": "^15.6.0"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"@kesha-antonov/react-native-background-downloader": {
|
"@kesha-antonov/react-native-background-downloader": {
|
||||||
|
@ -26,6 +26,7 @@ import {
|
|||||||
checkForExistingDownloads,
|
checkForExistingDownloads,
|
||||||
ensureDownloadsAreRunning,
|
ensureDownloadsAreRunning,
|
||||||
} from "@kesha-antonov/react-native-background-downloader";
|
} from "@kesha-antonov/react-native-background-downloader";
|
||||||
|
import { deleteAsync } from "expo-file-system";
|
||||||
import {
|
import {
|
||||||
Account,
|
Account,
|
||||||
Episode,
|
Episode,
|
||||||
@ -46,9 +47,9 @@ type State = {
|
|||||||
size: number;
|
size: number;
|
||||||
availableSize: number;
|
availableSize: number;
|
||||||
error?: string;
|
error?: string;
|
||||||
pause: () => void;
|
pause: (() => void) | null;
|
||||||
resume: () => void;
|
resume: (() => void) | null;
|
||||||
stop: () => void;
|
remove: () => void;
|
||||||
play: () => void;
|
play: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -74,11 +75,42 @@ const query = <T,>(query: QueryIdentifier<T>, info: Account): Promise<T> =>
|
|||||||
info.token.access_token,
|
info.token.access_token,
|
||||||
);
|
);
|
||||||
|
|
||||||
const listenToTask = (task: DownloadTask, update: (f: (old: State) => State) => void) => {
|
const setupDownloadTask = (
|
||||||
|
state: { data: Episode | Movie; info: WatchInfo; path: string },
|
||||||
|
task: DownloadTask,
|
||||||
|
store: ReturnType<typeof useStore>,
|
||||||
|
) => {
|
||||||
|
const stateAtom = atom({
|
||||||
|
status: task.state,
|
||||||
|
progress: task.percent * 100,
|
||||||
|
size: task.totalBytes,
|
||||||
|
availableSize: task.bytesWritten,
|
||||||
|
pause: () => {
|
||||||
|
task.pause();
|
||||||
|
store.set(stateAtom, (x) => ({ ...x, state: "PAUSED" }));
|
||||||
|
},
|
||||||
|
resume: () => {
|
||||||
|
task.resume();
|
||||||
|
store.set(stateAtom, (x) => ({ ...x, state: "DOWNLOADING" }));
|
||||||
|
},
|
||||||
|
remove: () => {
|
||||||
|
task.stop();
|
||||||
|
store.set(downloadAtom, (x) => x.filter((y) => y.data.id !== task.id));
|
||||||
|
},
|
||||||
|
play: () => {
|
||||||
|
// TODO: set useQuery cache
|
||||||
|
// TODO: move to the play page.
|
||||||
|
},
|
||||||
|
} as State);
|
||||||
|
|
||||||
|
// we use the store instead of the onMount because we want to update the state to cache it even if it was not
|
||||||
|
// used during this launch of the app.
|
||||||
|
const update = updater(store, stateAtom);
|
||||||
|
|
||||||
task
|
task
|
||||||
.begin(({ expectedBytes }) => update((x) => ({ ...x, size: expectedBytes })))
|
.begin(({ expectedBytes }) => update((x) => ({ ...x, size: expectedBytes })))
|
||||||
.progress((percent, availableSize, size) =>
|
.progress((percent, availableSize, size) =>
|
||||||
update((x) => ({ ...x, percent, size, availableSize })),
|
update((x) => ({ ...x, percent, size, availableSize, status: "DOWNLOADING" })),
|
||||||
)
|
)
|
||||||
.done(() => {
|
.done(() => {
|
||||||
update((x) => ({ ...x, percent: 100, status: "DONE" }));
|
update((x) => ({ ...x, percent: 100, status: "DONE" }));
|
||||||
@ -87,11 +119,36 @@ const listenToTask = (task: DownloadTask, update: (f: (old: State) => State) =>
|
|||||||
completeHandler(task.id);
|
completeHandler(task.id);
|
||||||
})
|
})
|
||||||
.error((error) => update((x) => ({ ...x, status: "FAILED", error })));
|
.error((error) => update((x) => ({ ...x, status: "FAILED", error })));
|
||||||
|
|
||||||
|
return { data: state.data, info: state.info, path: state.path, state: stateAtom };
|
||||||
|
};
|
||||||
|
|
||||||
|
const updater = (
|
||||||
|
store: ReturnType<typeof useStore>,
|
||||||
|
atom: PrimitiveAtom<State>,
|
||||||
|
): ((f: (old: State) => State) => void) => {
|
||||||
|
return (f) => {
|
||||||
|
// if it lags, we could only store progress info on status change and not on every change.
|
||||||
|
store.set(atom, f);
|
||||||
|
|
||||||
|
const downloads = store.get(downloadAtom);
|
||||||
|
storage.set(
|
||||||
|
"downloads",
|
||||||
|
JSON.stringify(
|
||||||
|
downloads.map((d) => ({
|
||||||
|
data: d.data,
|
||||||
|
info: d.info,
|
||||||
|
path: d.path,
|
||||||
|
state: store.get(d.state),
|
||||||
|
})),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useDownloader = () => {
|
export const useDownloader = () => {
|
||||||
const setDownloads = useSetAtom(downloadAtom);
|
const setDownloads = useSetAtom(downloadAtom);
|
||||||
const atomStore = useStore();
|
const store = useStore();
|
||||||
|
|
||||||
return async (type: "episode" | "movie", slug: string) => {
|
return async (type: "episode" | "movie", slug: string) => {
|
||||||
const account = getCurrentAccount()!;
|
const account = getCurrentAccount()!;
|
||||||
@ -114,27 +171,7 @@ export const useDownloader = () => {
|
|||||||
// network: Network.ALL,
|
// network: Network.ALL,
|
||||||
});
|
});
|
||||||
|
|
||||||
const state = atom({
|
setDownloads((x) => [...x, setupDownloadTask({ data, info, path }, task, store)]);
|
||||||
status: task.state,
|
|
||||||
progress: task.percent * 100,
|
|
||||||
size: task.totalBytes,
|
|
||||||
availableSize: task.bytesWritten,
|
|
||||||
pause: () => task.pause(),
|
|
||||||
resume: () => task.resume(),
|
|
||||||
stop: () => {
|
|
||||||
task.stop();
|
|
||||||
setDownloads((x) => x.filter((y) => y.data.id !== task.id));
|
|
||||||
},
|
|
||||||
play: () => {
|
|
||||||
// TODO: set useQuery cache
|
|
||||||
// TODO: move to the play page.
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// we use the store instead of the onMount because we want to update the state to cache it even if it was not
|
|
||||||
// used during this launch of the app.
|
|
||||||
listenToTask(task, (f) => atomStore.set(state, f));
|
|
||||||
setDownloads((x) => [...x, { data, info, path, state }]);
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -143,15 +180,39 @@ export const DownloadProvider = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function run() {
|
async function run() {
|
||||||
|
if (store.get(downloadAtom).length) return;
|
||||||
|
|
||||||
const tasks = await checkForExistingDownloads();
|
const tasks = await checkForExistingDownloads();
|
||||||
const downloads = store.get(downloadAtom);
|
const dls: { data: Episode | Movie; info: WatchInfo; path: string; state: State }[] =
|
||||||
|
JSON.parse(storage.getString("downloads") ?? "[]");
|
||||||
|
const downloads = dls.map((dl) => {
|
||||||
|
const t = tasks.find((x) => x.id == dl.data.id);
|
||||||
|
if (t) return setupDownloadTask(dl, t, store);
|
||||||
|
return {
|
||||||
|
data: dl.data,
|
||||||
|
info: dl.info,
|
||||||
|
path: dl.path,
|
||||||
|
state: atom({
|
||||||
|
status: dl.state.status === "DONE" ? "DONE" : "FAILED",
|
||||||
|
progress: dl.state.progress,
|
||||||
|
size: dl.state.size,
|
||||||
|
availableSize: dl.state.availableSize,
|
||||||
|
pause: null,
|
||||||
|
resume: null,
|
||||||
|
play: () => {
|
||||||
|
// TODO: setup this
|
||||||
|
},
|
||||||
|
remove: () => {
|
||||||
|
deleteAsync(dl.path);
|
||||||
|
store.set(downloadAtom, (x) => x.filter((y) => y.data.id !== dl.data.id));
|
||||||
|
},
|
||||||
|
} as State),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
store.set(downloadAtom, downloads);
|
||||||
|
|
||||||
for (const t of tasks) {
|
for (const t of tasks) {
|
||||||
const d = downloads.find((x) => x.data.id === t.id);
|
if (!downloads.find((x) => x.data.id === t.id)) t.stop();
|
||||||
if (!d) {
|
|
||||||
t.stop();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
listenToTask(t, (f) => store.set(d.state, f));
|
|
||||||
}
|
}
|
||||||
ensureDownloadsAreRunning();
|
ensureDownloadsAreRunning();
|
||||||
}
|
}
|
||||||
|
0
front/packages/ui/src/downloads/download.web.tsx
Normal file
0
front/packages/ui/src/downloads/download.web.tsx
Normal file
@ -2878,9 +2878,6 @@ __metadata:
|
|||||||
"@tanstack/react-query": "*"
|
"@tanstack/react-query": "*"
|
||||||
react: "*"
|
react: "*"
|
||||||
react-native: "*"
|
react-native: "*"
|
||||||
dependenciesMeta:
|
|
||||||
"@kesha-antonov/react-native-background-downloader":
|
|
||||||
optional: true
|
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
react-native-web:
|
react-native-web:
|
||||||
optional: true
|
optional: true
|
||||||
@ -2952,6 +2949,7 @@ __metadata:
|
|||||||
"@kyoo/primitives": "workspace:^"
|
"@kyoo/primitives": "workspace:^"
|
||||||
"@shopify/flash-list": ^1.6.3
|
"@shopify/flash-list": ^1.6.3
|
||||||
"@types/react": 18.2.39
|
"@types/react": 18.2.39
|
||||||
|
expo-file-system: ^15.6.0
|
||||||
react-native-uuid: ^2.0.1
|
react-native-uuid: ^2.0.1
|
||||||
typescript: ^5.3.2
|
typescript: ^5.3.2
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@ -2959,6 +2957,7 @@ __metadata:
|
|||||||
"@material-symbols/svg-400": "*"
|
"@material-symbols/svg-400": "*"
|
||||||
"@shopify/flash-list": ^1.3.1
|
"@shopify/flash-list": ^1.3.1
|
||||||
"@tanstack/react-query": "*"
|
"@tanstack/react-query": "*"
|
||||||
|
expo-file-system: "*"
|
||||||
expo-linear-gradient: "*"
|
expo-linear-gradient: "*"
|
||||||
i18next: "*"
|
i18next: "*"
|
||||||
moti: "*"
|
moti: "*"
|
||||||
@ -2971,6 +2970,8 @@ __metadata:
|
|||||||
dependenciesMeta:
|
dependenciesMeta:
|
||||||
"@kesha-antonov/react-native-background-downloader":
|
"@kesha-antonov/react-native-background-downloader":
|
||||||
optional: true
|
optional: true
|
||||||
|
expo-file-system:
|
||||||
|
optional: true
|
||||||
peerDependenciesMeta:
|
peerDependenciesMeta:
|
||||||
"@kesha-antonov/react-native-background-downloader":
|
"@kesha-antonov/react-native-background-downloader":
|
||||||
optional: true
|
optional: true
|
||||||
@ -7890,6 +7891,17 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"expo-file-system@npm:^15.6.0":
|
||||||
|
version: 15.9.0
|
||||||
|
resolution: "expo-file-system@npm:15.9.0"
|
||||||
|
dependencies:
|
||||||
|
uuid: ^3.4.0
|
||||||
|
peerDependencies:
|
||||||
|
expo: "*"
|
||||||
|
checksum: 9e10089cd28e7384fdb942c5a0515a5d7e5cd43637ebe42ab5cbc1fb5a06cf466d4ea195eea3479a4080fc30215c2e2df7048e83a6bae3413fff95b9487a5144
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"expo-file-system@npm:~15.4.0, expo-file-system@npm:~15.4.2":
|
"expo-file-system@npm:~15.4.0, expo-file-system@npm:~15.4.2":
|
||||||
version: 15.4.2
|
version: 15.4.2
|
||||||
resolution: "expo-file-system@npm:15.4.2"
|
resolution: "expo-file-system@npm:15.4.2"
|
||||||
@ -11301,6 +11313,7 @@ __metadata:
|
|||||||
expo-build-properties: ~0.8.3
|
expo-build-properties: ~0.8.3
|
||||||
expo-constants: ~14.4.2
|
expo-constants: ~14.4.2
|
||||||
expo-dev-client: ~2.4.12
|
expo-dev-client: ~2.4.12
|
||||||
|
expo-file-system: ~15.4.5
|
||||||
expo-font: ~11.4.0
|
expo-font: ~11.4.0
|
||||||
expo-linear-gradient: ~12.3.0
|
expo-linear-gradient: ~12.3.0
|
||||||
expo-linking: ~5.0.2
|
expo-linking: ~5.0.2
|
||||||
|
Loading…
x
Reference in New Issue
Block a user