下载内容管理

This commit is contained in:
mtvpls
2026-02-26 22:47:39 +08:00
parent e3f4b72fa8
commit b3a460e300
7 changed files with 894 additions and 54 deletions

View File

@@ -47,6 +47,7 @@ import { NotificationPanel } from './NotificationPanel';
import { OfflineDownloadPanel } from './OfflineDownloadPanel';
import { useVersionCheck } from './VersionCheckProvider';
import { VersionPanel } from './VersionPanel';
import { DownloadManagementPanel } from './DownloadManagementPanel';
interface AuthInfo {
username?: string;
@@ -68,6 +69,7 @@ export const UserMenu: React.FC = () => {
const [isDeviceManagementOpen, setIsDeviceManagementOpen] = useState(false);
const [isEcoAppsOpen, setIsEcoAppsOpen] = useState(false);
const [isReportOpen, setIsReportOpen] = useState(false);
const [isDownloadManagementOpen, setIsDownloadManagementOpen] = useState(false);
const [authInfo, setAuthInfo] = useState<AuthInfo | null>(null);
const [storageType, setStorageType] = useState<string>('localstorage');
const [mounted, setMounted] = useState(false);
@@ -85,7 +87,7 @@ export const UserMenu: React.FC = () => {
// Body 滚动锁定 - 使用 overflow 方式避免布局问题
useEffect(() => {
if (isSettingsOpen || isChangePasswordOpen || isSubscribeOpen || isOfflineDownloadPanelOpen || isEmailSettingsOpen || isDeviceManagementOpen || isEcoAppsOpen || isReportOpen) {
if (isSettingsOpen || isChangePasswordOpen || isSubscribeOpen || isOfflineDownloadPanelOpen || isEmailSettingsOpen || isDeviceManagementOpen || isEcoAppsOpen || isReportOpen || isDownloadManagementOpen) {
const body = document.body;
const html = document.documentElement;
@@ -975,27 +977,59 @@ export const UserMenu: React.FC = () => {
// 保存目录句柄到 IndexedDB
const dbName = 'MoonTVPlus';
const storeName = 'dirHandles';
const request = indexedDB.open(dbName, 1);
request.onupgradeneeded = (event) => {
const db = (event.target as IDBOpenDBRequest).result;
if (!db.objectStoreNames.contains(storeName)) {
db.createObjectStore(storeName);
}
};
// 使用 Promise 包装 IndexedDB 操作
await new Promise<void>((resolve, reject) => {
const request = indexedDB.open(dbName, 2); // 使用版本 2与 download-db.ts 保持一致
request.onsuccess = (event) => {
const db = (event.target as IDBOpenDBRequest).result;
const transaction = db.transaction([storeName], 'readwrite');
const store = transaction.objectStore(storeName);
store.put(dirHandle, 'downloadDir');
};
request.onupgradeneeded = (event) => {
const db = (event.target as IDBOpenDBRequest).result;
request.onerror = () => {
console.error('无法打开 IndexedDB');
};
// 创建 dirHandles 表(如果不存在)
if (!db.objectStoreNames.contains(storeName)) {
db.createObjectStore(storeName);
}
// 创建 activeTasks 表(如果不存在)
if (!db.objectStoreNames.contains('activeTasks')) {
const activeStore = db.createObjectStore('activeTasks', { keyPath: 'id' });
activeStore.createIndex('status', 'status', { unique: false });
activeStore.createIndex('createdAt', 'createdAt', { unique: false });
}
// 创建 completedTasks 表(如果不存在)
if (!db.objectStoreNames.contains('completedTasks')) {
const completedStore = db.createObjectStore('completedTasks', { keyPath: 'id' });
completedStore.createIndex('source', 'source', { unique: false });
completedStore.createIndex('videoId', 'videoId', { unique: false });
completedStore.createIndex('completedAt', 'completedAt', { unique: false });
completedStore.createIndex('sourceVideoId', ['source', 'videoId'], { unique: false });
}
};
request.onsuccess = (event) => {
const db = (event.target as IDBOpenDBRequest).result;
const transaction = db.transaction([storeName], 'readwrite');
const store = transaction.objectStore(storeName);
const putRequest = store.put(dirHandle, 'downloadDir');
putRequest.onsuccess = () => {
db.close();
resolve();
};
putRequest.onerror = () => {
db.close();
reject(new Error('保存目录句柄失败'));
};
};
request.onerror = () => {
reject(new Error('无法打开 IndexedDB'));
};
});
} catch (err) {
console.error('用户取消选择目录', err);
console.error('选择目录失败:', err);
}
};
@@ -2329,6 +2363,17 @@ export const UserMenu: React.FC = () => {
</div>
)}
</div>
{/* 下载文件管理 */}
<div className='space-y-2'>
<button
onClick={() => setIsDownloadManagementOpen(true)}
className='w-full px-4 py-2 text-sm bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors flex items-center justify-center gap-2'
>
<Package className='w-4 h-4' />
</button>
</div>
</div>
)}
</div>
@@ -3676,6 +3721,17 @@ export const UserMenu: React.FC = () => {
document.body
)}
{/* 使用 Portal 将下载文件管理面板渲染到 document.body */}
{isDownloadManagementOpen &&
mounted &&
createPortal(
<DownloadManagementPanel
isOpen={isDownloadManagementOpen}
onClose={() => setIsDownloadManagementOpen(false)}
/>,
document.body
)}
{/* 使用 Portal 将邮件设置面板渲染到 document.body */}
{isEmailSettingsOpen &&
mounted &&