diff --git a/src/locales/en-US.ts b/src/locales/en-US.ts index 3a5e0290..fcc38f31 100644 --- a/src/locales/en-US.ts +++ b/src/locales/en-US.ts @@ -40,6 +40,10 @@ export default { media: 'Media', unknown: 'Unknown', notice: 'Notice', + itemsPerPage: 'Items per page', + pageText: '{0}-{1} of {2}', + noDataText: 'No data', + loadingText: 'Loading...', }, mediaType: { movie: 'Movie', @@ -1109,7 +1113,7 @@ export default { }, site: { siteSync: 'Site Synchronization', - siteSyncDesc: 'Quickly sync site data from CookieCloud.', + siteSyncDesc: 'Quickly sync site data from CookieCloud', enableLocalCookieCloud: 'Enable Local CookieCloud Server', enableLocalCookieCloudHint: 'Use built-in CookieCloud service to sync site data, service address: http://localhost:3000/cookiecloud', @@ -1155,7 +1159,7 @@ export default { }, notification: { channels: 'Notification Channels', - channelsDesc: 'Set message sending channel parameters.', + channelsDesc: 'Set message sending channel parameters', organizeSuccess: 'Media Import', downloadAdded: 'Download Added', subscribeAdded: 'Subscribe Added', @@ -1202,7 +1206,7 @@ export default { }, words: { customIdentifiers: 'Custom Identifiers', - identifiersDesc: 'Add rules to preprocess torrent names or file names to correct identification.', + identifiersDesc: 'Add rules to preprocess torrent names or file names to correct identification', identifiersPlaceholder: 'Support regular expressions, special characters need \\ escape, one line for each rule', identifiersHint: 'Support regular expressions, special characters need \\ escape, one line for each rule', formatTitle: 'Supported configuration formats (mind the spaces):', @@ -1242,7 +1246,7 @@ export default { }, search: { basicSettings: 'Basic Settings', - basicSettingsDesc: 'Set data sources, rule groups and other basic information.', + basicSettingsDesc: 'Set data sources, rule groups and other basic information', recognizeSource: 'Recognition Data Source', recognizeSourceDesc: 'Default is TMDB. Douban is usually more friendly for Chinese works, but some foreign works have incomplete information.', @@ -1343,8 +1347,7 @@ export default { }, scheduler: { title: 'Scheduled Jobs', - subtitle: - "Includes built-in system services and plugin services. Manual execution will not affect the job's normal schedule.", + subtitle: 'Includes built-in system services and plugin services', provider: 'Provider', taskName: 'Task Name', taskStatus: 'Task Status', @@ -1391,6 +1394,52 @@ export default { settingsSaveSuccess: 'Subscription basic settings saved successfully', settingsSaveFailed: 'Failed to save subscription basic settings!', }, + cache: { + title: 'Cache', + description: 'Site cache and media recognition data cache management', + subtitle: 'Manage cached site resources', + refresh: 'Refresh Cache', + deleteSelected: 'Delete Selected', + clearAll: 'Clear All Cache', + refreshSuccess: 'Cache refresh completed', + refreshFailed: 'Failed to refresh cache', + clearSuccess: 'Cache clear completed', + clearFailed: 'Failed to clear cache', + deleteSuccess: 'Cache item deleted successfully', + deleteFailed: 'Failed to delete cache item', + deleteSelectedSuccess: 'Successfully deleted {count} cache items', + deleteSelectedFailed: 'Failed to delete cache items', + loadFailed: 'Failed to load cache data', + selectDeleteWarning: 'Please select cache items to delete', + reidentify: 'Re-identify', + reidentifySuccess: 'Re-identification completed', + reidentifyFailed: 'Re-identification failed', + poster: 'Poster', + torrentTitle: 'Title', + site: 'Site', + size: 'Size', + publishTime: 'Publish Time', + recognitionResult: 'Recognition Result', + actions: 'Actions', + unrecognized: 'Unrecognized', + noData: 'No cache data', + noDataHint: 'Click "Refresh Cache" button to get the latest torrent cache', + reidentifyDialog: { + title: 'Re-identify', + torrentInfo: 'Torrent Info', + tmdbId: 'TMDB ID', + tmdbIdHint: 'Optional, manually specify TMDB ID for recognition', + doubanId: 'Douban ID', + doubanIdHint: 'Optional, manually specify Douban ID for recognition', + autoHint: 'If no ID is specified, the torrent will be automatically re-identified', + cancel: 'Cancel', + confirm: 'Re-identify', + }, + mediaType: { + movie: 'Movie', + tv: 'TV Show', + }, + }, }, dialog: { progress: { diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 023a1d85..a58832c6 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -40,6 +40,10 @@ export default { media: '媒体', unknown: '未知', notice: '注意', + itemsPerPage: '每页条数', + pageText: '{0}-{1} 共 {2} 条', + noDataText: '没有数据', + loadingText: '加载中...', }, mediaType: { movie: '电影', @@ -941,7 +945,7 @@ export default { system: { custom: '自定义', basicSettings: '基础设置', - basicSettingsDesc: '设置服务器的全局功能。', + basicSettingsDesc: '设置服务器的全局功能', appDomain: '访问域名', appDomainHint: '用于发送通知时,添加快捷跳转地址', wallpaper: '背景壁纸', @@ -1099,7 +1103,7 @@ export default { }, site: { siteSync: '站点同步', - siteSyncDesc: '从CookieCloud快速同步站点数据。', + siteSyncDesc: '从CookieCloud快速同步站点数据', enableLocalCookieCloud: '启用本地CookieCloud服务器', enableLocalCookieCloudHint: '使用内建CookieCloud服务同步站点数据,服务地址为:http://localhost:3000/cookiecloud', serviceAddress: '服务地址', @@ -1142,7 +1146,7 @@ export default { }, notification: { channels: '通知渠道', - channelsDesc: '设置消息发送渠道参数。', + channelsDesc: '设置消息发送渠道参数', organizeSuccess: '资源入库', downloadAdded: '资源下载', subscribeAdded: '添加订阅', @@ -1189,7 +1193,7 @@ export default { }, words: { customIdentifiers: '自定义识别词', - identifiersDesc: '添加规则对种子名或者文件名进行预处理以校正识别。', + identifiersDesc: '添加规则对种子名或者文件名进行预处理以校正识别', identifiersPlaceholder: '支持正则表达式,特殊字符需要\\转义,一行为一组', identifiersHint: '支持正则表达式,特殊字符需要\\转义,一行为一组', formatTitle: '支持的配置格式(注意空格):', @@ -1225,7 +1229,7 @@ export default { }, search: { basicSettings: '基础设置', - basicSettingsDesc: '设定数据源、规则组等基础信息。', + basicSettingsDesc: '设定数据源、规则组等基础信息', recognizeSource: '识别数据源', recognizeSourceDesc: '默认使用TMDB。豆瓣识别中文作品通常更友好,但有些国外作品信息不完整。', themoviedb: 'TheMovieDb', @@ -1261,7 +1265,7 @@ export default { }, directory: { storage: '存储', - storageDesc: '设置本地或网盘存储。', + storageDesc: '设置本地或网盘存储', directory: '目录', mediaType: '媒体类型', directoryDesc: '设置媒体文件整理目录结构,按先后顺序依次匹配。', @@ -1323,7 +1327,7 @@ export default { }, scheduler: { title: '定时作业', - subtitle: '包含系统内置服务以及插件提供的服务,手动执行不会影响作业正常的时间表。', + subtitle: '包含系统内置服务以及插件提供的服务', provider: '提供者', taskName: '任务名称', taskStatus: '任务状态', @@ -1373,6 +1377,48 @@ export default { cache: { title: '缓存', description: '种子缓存、图片文件缓存管理', + subtitle: '管理缓存的站点资源', + refresh: '刷新缓存', + deleteSelected: '删除选中', + clearAll: '清空缓存', + refreshSuccess: '缓存刷新完成', + refreshFailed: '刷新缓存失败', + clearSuccess: '缓存清理完成', + clearFailed: '清理缓存失败', + deleteSuccess: '缓存项删除成功', + deleteFailed: '删除缓存项失败', + deleteSelectedSuccess: '成功删除 {count} 个缓存项', + deleteSelectedFailed: '删除缓存项失败', + loadFailed: '加载缓存数据失败', + selectDeleteWarning: '请选择要删除的缓存项', + reidentify: '重新识别', + reidentifySuccess: '重新识别完成', + reidentifyFailed: '重新识别失败', + poster: '海报', + torrentTitle: '标题', + site: '站点', + size: '大小', + publishTime: '发布时间', + recognitionResult: '识别结果', + actions: '操作', + unrecognized: '未识别', + noData: '暂无缓存数据', + noDataHint: '点击"刷新缓存"按钮获取最新的种子缓存', + reidentifyDialog: { + title: '重新识别', + torrentInfo: '种子信息', + tmdbId: 'TMDB ID', + tmdbIdHint: '可选,手动指定TMDB ID进行识别', + doubanId: '豆瓣 ID', + doubanIdHint: '可选,手动指定豆瓣ID进行识别', + autoHint: '如果不指定ID,将自动重新识别该种子', + cancel: '取消', + confirm: '重新识别', + }, + mediaType: { + movie: '电影', + tv: '电视剧', + }, }, }, dialog: { diff --git a/src/locales/zh-TW.ts b/src/locales/zh-TW.ts index c5fbfe2b..d043cd45 100644 --- a/src/locales/zh-TW.ts +++ b/src/locales/zh-TW.ts @@ -40,6 +40,10 @@ export default { media: '媒體', unknown: '未知', notice: '注意', + itemsPerPage: '每頁條數', + pageText: '{0}-{1} 共 {2} 條', + noDataText: '沒有數據', + loadingText: '加載中...', }, mediaType: { movie: '電影', @@ -943,7 +947,7 @@ export default { system: { custom: '自定義', basicSettings: '基礎設置', - basicSettingsDesc: '設置服務器的全局功能。', + basicSettingsDesc: '設置服務器的全局功能', appDomain: '訪問域名', appDomainHint: '用於發送通知時,添加快捷跳轉地址', wallpaper: '背景壁紙', @@ -1101,7 +1105,7 @@ export default { }, site: { siteSync: '站點同步', - siteSyncDesc: '從CookieCloud快速同步站點數據。', + siteSyncDesc: '從CookieCloud快速同步站點數據', enableLocalCookieCloud: '啟用本地CookieCloud服務器', enableLocalCookieCloudHint: '使用內建CookieCloud服務同步站點數據,服務地址為:http://localhost:3000/cookiecloud', serviceAddress: '服務地址', @@ -1144,7 +1148,7 @@ export default { }, notification: { channels: '通知渠道', - channelsDesc: '設置消息發送渠道參數。', + channelsDesc: '設置消息發送渠道參數', organizeSuccess: '資源入庫', downloadAdded: '資源下載', subscribeAdded: '添加訂閱', @@ -1191,7 +1195,7 @@ export default { }, words: { customIdentifiers: '自定義識別詞', - identifiersDesc: '添加規則對種子名或者文件名進行預處理以校正識別。', + identifiersDesc: '添加規則對種子名或者文件名進行預處理以校正識別', identifiersPlaceholder: '支持正則表達式,特殊字符需要\\轉義,一行為一組', identifiersHint: '支持正則表達式,特殊字符需要\\轉義,一行為一組', formatTitle: '支持的配置格式(注意空格):', @@ -1227,7 +1231,7 @@ export default { }, search: { basicSettings: '基礎設置', - basicSettingsDesc: '設定數據源、規則組等基礎信息。', + basicSettingsDesc: '設定數據源、規則組等基礎信息', recognizeSource: '識別數據源', recognizeSourceDesc: '默認使用TMDB。豆瓣識別中文作品通常更友好,但有些國外作品信息不完整。', themoviedb: 'TheMovieDb', @@ -1263,7 +1267,7 @@ export default { }, directory: { storage: '存儲', - storageDesc: '設置本地或網盤存儲。', + storageDesc: '設置本地或網盤存儲', directory: '目錄', directoryDesc: '設置媒體文件整理目錄結構,按先後順序依次匹配。', organizeAndScrap: '整理 & 刮削', @@ -1324,7 +1328,7 @@ export default { }, scheduler: { scheduledTasks: '定時作業', - scheduledTasksDesc: '包含系統內置服務以及插件提供的服務,手動執行不會影響作業正常的時間表。', + scheduledTasksDesc: '包含系統內置服務以及插件提供的服務', provider: '提供者', taskName: '任務名稱', taskStatus: '任務狀態', @@ -1371,6 +1375,52 @@ export default { settingsSaveSuccess: '訂閱基礎設置保存成功', settingsSaveFailed: '訂閱基礎設置保存失敗!', }, + cache: { + title: '緩存', + description: '種子緩存、圖片文件緩存管理', + subtitle: '管理緩存的站點資源', + refresh: '刷新緩存', + deleteSelected: '刪除選中', + clearAll: '清空緩存', + refreshSuccess: '緩存刷新完成', + refreshFailed: '刷新緩存失敗', + clearSuccess: '緩存清理完成', + clearFailed: '清理緩存失敗', + deleteSuccess: '緩存項刪除成功', + deleteFailed: '刪除緩存項失敗', + deleteSelectedSuccess: '成功刪除 {count} 個緩存項', + deleteSelectedFailed: '刪除緩存項失敗', + loadFailed: '加載緩存數據失敗', + selectDeleteWarning: '請選擇要刪除的緩存項', + reidentify: '重新識別', + reidentifySuccess: '重新識別完成', + reidentifyFailed: '重新識別失敗', + poster: '海報', + torrentTitle: '標題', + site: '站點', + size: '大小', + publishTime: '發布時間', + recognitionResult: '識別結果', + actions: '操作', + unrecognized: '未識別', + noData: '暫無緩存數據', + noDataHint: '點擊"刷新緩存"按鈕獲取最新的種子緩存', + reidentifyDialog: { + title: '重新識別', + torrentInfo: '種子信息', + tmdbId: 'TMDB ID', + tmdbIdHint: '可選,手動指定TMDB ID進行識別', + doubanId: '豆瓣 ID', + doubanIdHint: '可選,手動指定豆瓣ID進行識別', + autoHint: '如果不指定ID,將自動重新識別該種子', + cancel: '取消', + confirm: '重新識別', + }, + mediaType: { + movie: '電影', + tv: '電視劇', + }, + }, }, dialog: { progress: { diff --git a/src/views/setting/API.py b/src/views/setting/API.py deleted file mode 100644 index 2fd400f6..00000000 --- a/src/views/setting/API.py +++ /dev/null @@ -1,199 +0,0 @@ -from typing import Optional - -from fastapi import APIRouter, Depends - -from app import schemas -from app.chain.media import MediaChain -from app.chain.torrents import TorrentsChain -from app.core.config import settings -from app.core.context import MediaInfo -from app.core.metainfo import MetaInfo -from app.db.models import User -from app.db.user_oper import get_current_active_superuser -from app.utils.crypto import HashUtils - -router = APIRouter() - - -@router.get("/cache", summary="获取种子缓存", response_model=schemas.Response) -def torrents_cache(_: User = Depends(get_current_active_superuser)): - """ - 获取当前种子缓存数据 - """ - torrents_chain = TorrentsChain() - - # 获取spider和rss两种缓存 - if settings.SUBSCRIBE_MODE == "rss": - cache_info = torrents_chain.get_torrents("rss") - else: - cache_info = torrents_chain.get_torrents("spider") - - # 统计信息 - torrent_count = sum(len(torrents) for torrents in cache_info.values()) - - # 转换为前端需要的格式 - torrent_data = [] - for domain, contexts in cache_info.items(): - for context in contexts: - torrent_hash = HashUtils.md5(f"{context.torrent_info.title}{context.torrent_info.description}") - torrent_data.append({ - "hash": torrent_hash, - "domain": domain, - "title": context.torrent_info.title, - "description": context.torrent_info.description, - "size": context.torrent_info.size, - "pubdate": context.torrent_info.pubdate, - "site_name": context.torrent_info.site_name, - "media_name": context.media_info.title if context.media_info else "", - "media_year": context.media_info.year if context.media_info else "", - "media_type": context.media_info.type if context.media_info else "", - "season_episode": context.meta_info.season_episode if context.meta_info else "", - "resource_term": context.meta_info.resource_term if context.meta_info else "", - "enclosure": context.torrent_info.enclosure, - "page_url": context.torrent_info.page_url, - "poster_path": context.media_info.get_poster_image() if context.media_info else "", - "backdrop_path": context.media_info.get_backdrop_image() if context.media_info else "" - }) - - return schemas.Response(success=True, data={ - "count": torrent_count, - "sites": len(cache_info), - "data": torrent_data - }) - - -@router.delete("/cache/{domain}/{torrent_hash}", summary="删除指定种子缓存", - response_model=schemas.Response) -def delete_cache(domain: str, torrent_hash: str, _: User = Depends(get_current_active_superuser)): - """ - 删除指定的种子缓存 - :param domain: 站点域名 - :param torrent_hash: 种子hash(使用title+description的md5) - :param _: 当前用户,必须是超级用户 - """ - - torrents_chain = TorrentsChain() - - try: - # 获取当前缓存 - cache_data = torrents_chain.get_torrents() - - if domain not in cache_data: - return schemas.Response(success=False, message=f"站点 {domain} 缓存不存在") - - # 查找并删除指定种子 - original_count = len(cache_data[domain]) - cache_data[domain] = [ - context for context in cache_data[domain] - if HashUtils.md5(f"{context.torrent_info.title}{context.torrent_info.description}") != torrent_hash - ] - - if len(cache_data[domain]) == original_count: - return schemas.Response(success=False, message="未找到指定的种子") - - # 保存更新后的缓存 - torrents_chain.save_cache(cache_data, torrents_chain.cache_file) - - return schemas.Response(success=True, message="种子删除成功") - except Exception as e: - return schemas.Response(success=False, message=f"删除失败:{str(e)}") - - -@router.delete("/cache", summary="清理种子缓存", response_model=schemas.Response) -def clear_cache(_: User = Depends(get_current_active_superuser)): - """ - 清理所有种子缓存 - """ - torrents_chain = TorrentsChain() - - try: - torrents_chain.clear_torrents() - return schemas.Response(success=True, message="种子缓存清理完成") - except Exception as e: - return schemas.Response(success=False, message=f"清理失败:{str(e)}") - - -@router.post("/cache/refresh", summary="刷新种子缓存", response_model=schemas.Response) -def refresh_cache(_: User = Depends(get_current_active_superuser)): - """ - 刷新种子缓存 - """ - from app.chain.torrents import TorrentsChain - - torrents_chain = TorrentsChain() - - try: - result = torrents_chain.refresh() - - # 统计刷新结果 - total_count = sum(len(torrents) for torrents in result.values()) - sites_count = len(result) - - return schemas.Response(success=True, message=f"缓存刷新完成,共刷新 {sites_count} 个站点,{total_count} 个种子") - except Exception as e: - return schemas.Response(success=False, message=f"刷新失败:{str(e)}") - - -@router.post("/cache/reidentify/{domain}/{torrent_hash}", summary="重新识别种子", response_model=schemas.Response) -def reidentify_cache(domain: str, torrent_hash: str, - tmdbid: Optional[int] = None, doubanid: Optional[str] = None, - _: User = Depends(get_current_active_superuser)): - """ - 重新识别指定的种子 - :param domain: 站点域名 - :param torrent_hash: 种子hash(使用title+description的md5) - :param tmdbid: 手动指定的TMDB ID - :param doubanid: 手动指定的豆瓣ID - :param _: 当前用户,必须是超级用户 - """ - - torrents_chain = TorrentsChain() - media_chain = MediaChain() - - try: - # 获取当前缓存 - cache_data = torrents_chain.get_torrents() - - if domain not in cache_data: - return schemas.Response(success=False, message=f"站点 {domain} 缓存不存在") - - # 查找指定种子 - target_context = None - for context in cache_data[domain]: - if HashUtils.md5(f"{context.torrent_info.title}{context.torrent_info.description}") == torrent_hash: - target_context = context - break - - if not target_context: - return schemas.Response(success=False, message="未找到指定的种子") - - # 重新识别 - meta = MetaInfo(title=target_context.torrent_info.title, - subtitle=target_context.torrent_info.description) - if tmdbid or doubanid: - # 手动指定媒体信息 - mediainfo = MediaChain().recognize_media(meta=meta, tmdbid=tmdbid, doubanid=doubanid) - else: - # 自动重新识别 - mediainfo = media_chain.recognize_by_meta(meta) - - if not mediainfo: - # 创建空的媒体信息 - mediainfo = MediaInfo() - else: - # 清理多余数据 - mediainfo.clear() - - # 更新上下文中的媒体信息 - target_context.media_info = mediainfo - - # 保存更新后的缓存 - torrents_chain.save_cache(cache_data, TorrentsChain().cache_file) - - return schemas.Response(success=True, message="重新识别完成", data={ - "media_name": mediainfo.title if mediainfo else "", - "media_year": mediainfo.year if mediainfo else "", - "media_type": mediainfo.type.value if mediainfo and mediainfo.type else "" - }) - except Exception as e: - return schemas.Response(success=False, message=f"重新识别失败:{str(e)}") diff --git a/src/views/setting/AccountSettingCache.vue b/src/views/setting/AccountSettingCache.vue index e69de29b..dc3050bb 100644 --- a/src/views/setting/AccountSettingCache.vue +++ b/src/views/setting/AccountSettingCache.vue @@ -0,0 +1,388 @@ + + +