Files
JKVideo/store/downloadStore.ts
Developer 3f82646496 init
2026-03-26 12:15:40 +08:00

97 lines
2.8 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { create } from 'zustand';
import AsyncStorage from '@react-native-async-storage/async-storage';
export interface DownloadTask {
bvid: string;
title: string;
cover: string;
qn: number;
qdesc: string;
status: 'downloading' | 'done' | 'error';
progress: number; // 0-1
fileSize?: number; // bytes
localUri?: string;
error?: string;
createdAt: number;
}
interface DownloadStore {
tasks: Record<string, DownloadTask>; // key: `${bvid}_${qn}`
hasLoaded: boolean;
addTask: (key: string, task: DownloadTask) => void;
updateTask: (key: string, patch: Partial<DownloadTask>) => void;
removeTask: (key: string) => void;
loadFromStorage: () => Promise<void>;
}
const STORAGE_KEY = 'download_tasks';
export const useDownloadStore = create<DownloadStore>((set, get) => ({
tasks: {},
hasLoaded: false,
addTask: (key, task) => {
const next = { ...get().tasks, [key]: task };
set({ tasks: next });
persistTasks(next);
},
updateTask: (key, patch) => {
set((s) => {
const prev = s.tasks[key];
if (!prev) return s;
const updated = { ...prev, ...patch };
const next = { ...s.tasks, [key]: updated };
// 只在状态/localUri变化时持久化progress 不持久化(避免高频写 AsyncStorage
if (patch.status !== undefined || patch.localUri !== undefined || patch.error !== undefined || patch.fileSize !== undefined) {
persistTasks(next);
}
return { tasks: next };
});
},
removeTask: (key) => {
set((s) => {
const next = { ...s.tasks };
delete next[key];
persistTasks(next);
return { tasks: next };
});
},
loadFromStorage: async () => {
// 已加载过则跳过,防止重复调用覆盖正在进行的下载状态
if (get().hasLoaded) return;
try {
const raw = await AsyncStorage.getItem(STORAGE_KEY);
if (raw) {
const saved: Record<string, DownloadTask> = JSON.parse(raw);
// 重启后 downloading 任务无法续传,标记为 error
Object.keys(saved).forEach((k) => {
if (saved[k].status === 'downloading') {
saved[k].status = 'error';
saved[k].error = '下载被中断,请重试';
saved[k].progress = 0;
}
});
set({ tasks: saved, hasLoaded: true });
} else {
set({ hasLoaded: true });
}
} catch {
set({ hasLoaded: true });
}
},
}));
function persistTasks(tasks: Record<string, DownloadTask>) {
// 只持久化 done/errordownloading 重启后无法续传无需保存
const toSave: Record<string, DownloadTask> = {};
Object.keys(tasks).forEach((k) => {
if (tasks[k].status !== 'downloading') {
toSave[k] = tasks[k];
}
});
AsyncStorage.setItem(STORAGE_KEY, JSON.stringify(toSave)).catch(() => {});
}