fix cloud library scale and playback compatibility

Root cause: display-only cloud library filtering was reused by scan jobs, merged cloud mounts could be skipped, and OpenList listing relied on WebDAV/first-page behavior that could cap huge directories around 100 items. Cloud scans also let new items consume probe budget before existing rows with missing track/artwork metadata.\n\nChanges:\n- split display filtering from scannable cloud filtering so merged cloud mounts still scan\n- add OpenList API pagination with WebDAV fallback\n- prioritize existing cloud media missing metadata before new imports\n- restrict automatic cloud sync to one successful 19:00-21:00 daily window and keep manual scan immediate\n- disable startup cloud full-scan by default, with an explicit opt-in setting\n- improve Emby/cloud playback compatibility and cache/search/test coverage from the continued work
This commit is contained in:
ShukeBta
2026-06-11 18:31:01 +08:00
parent c22d8271ae
commit 23d1fbfddb
35 changed files with 2797 additions and 139 deletions
+11 -4
View File
@@ -302,18 +302,25 @@ const GROUPS: SettingGroup[] = [
items: [
{
key: 'cloud.auto_sync_enabled',
label: '自动同步网盘媒体库',
label: '夜间自动同步网盘媒体库',
type: 'toggle',
hint: '默认关闭,避免 NAS 反复递归读取大型网盘目录。需要定时刷新时再开启;手动扫描仍可在外部存储页面执行。',
hint: '默认关闭。开启后仅在每天 19:00-21:00 自动补齐缺失媒体并扫描新增;手动扫描仍可随时执行。',
defaultValue: 'false',
},
{
key: 'cloud.sync_interval_seconds',
label: '网盘媒体库同步间隔秒数',
label: '夜间窗口检查间隔秒数',
type: 'number',
hint: '最小 300 秒,建议 1800 秒或更高;手动可在任务调度中运行 cloud_sync。',
hint: '最小 300 秒,建议 1800 秒;同一天成功同步后不会重复全量扫,避免大型网盘反复递归。',
defaultValue: '1800',
},
{
key: 'cloud.boot_scan_enabled',
label: '启动后立即扫描网盘',
type: 'toggle',
hint: '默认关闭。仅排障或小型网盘建议开启;大型库请使用手动扫描或夜间自动同步。',
defaultValue: 'false',
},
{
key: 'cloud.upload_auto_enabled',
label: '启用自动转存',
+5 -5
View File
@@ -568,7 +568,7 @@ function CloudBrowser({ type }: { type: StorageType }) {
setMounting(true)
try {
const label = TYPE_LABEL[type] ?? type
const name = cur.id ? `${label} · ${cur.name}` : label
const name = cur.id ? cur.name : label
const res = await cloudAPI.mount(type, cur.id, name, mountMediaType, currentMountPath())
handleMountResult(res, cur.name)
await loadMounts()
@@ -589,10 +589,9 @@ function CloudBrowser({ type }: { type: StorageType }) {
let ok = 0
let skipped = 0
let failed = 0
const label = TYPE_LABEL[type] ?? type
for (const dir of dirs) {
try {
const result = await cloudAPI.mount(type, dir.id, `${label} · ${dir.name}`, 'auto', childMountPath(dir))
const result = await cloudAPI.mount(type, dir.id, dir.name, 'auto', childMountPath(dir))
const state = handleMountResult(result, dir.name)
if (state === 'skipped') skipped += 1
else ok += 1
@@ -733,6 +732,7 @@ function CloudBrowser({ type }: { type: StorageType }) {
</div>
<p className="basis-full text-xs text-ink-50">
挂载后不会复制网盘文件;后台会递归读取该目录里的子文件夹和媒体文件,扫描到的影片会自动加入对应媒体库。小目录通常几十秒,大目录取决于网盘接口速度。
如果已有同名同类型媒体库,会在首页和 Emby/SenPlayer 中自动归并显示。
</p>
<div className="flex flex-wrap items-center gap-2">
<select
@@ -753,7 +753,7 @@ function CloudBrowser({ type }: { type: StorageType }) {
disabled={mounting || batchMounting || loading}
onClick={mountCurrent}
>
{mounting ? '挂载中…' : '挂载当前目录为媒体库并递归扫描'}
{mounting ? '挂载中…' : '挂载当前目录并归并到媒体库'}
</button>
<button
type="button"
@@ -761,7 +761,7 @@ function CloudBrowser({ type }: { type: StorageType }) {
disabled={mounting || batchMounting || loading || items.every((item) => !item.is_dir)}
onClick={mountVisibleDirectories}
>
{batchMounting ? '批量挂载中…' : '一键把当前目录下所有文件夹挂载为媒体库'}
{batchMounting ? '批量挂载中…' : '一键挂载当前目录下所有文件夹'}
</button>
</div>
</div>