dsh-folia 4.16.1 → 4.16.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/routes/downloads.js +6 -37
- package/package.json +1 -1
package/lib/routes/downloads.js
CHANGED
|
@@ -15,18 +15,11 @@
|
|
|
15
15
|
* 注入契约:`disposers` / `base` / `serveFile` / `log`(队列由本模块自建单例)。
|
|
16
16
|
*/
|
|
17
17
|
import { createHash } from 'node:crypto';
|
|
18
|
-
import { existsSync, statSync } from 'node:fs';
|
|
19
18
|
import { join } from 'node:path';
|
|
20
19
|
import { homedir } from 'node:os';
|
|
21
20
|
import { createDownloadQueue } from '../download-queue.js';
|
|
22
21
|
export const DEPS = ['disposers', 'base', 'serveFile', 'log'];
|
|
23
22
|
|
|
24
|
-
/**
|
|
25
|
-
* 与 `lib/routes/site-media.js#EXT_OK` **必须一致**:那个模块按"扩展名在白名单里就保留、
|
|
26
|
-
* 否则用 `.bin`"算缓存文件名。这里查缓存时必须用同一套规则,否则永远命不中(=重复下载)。
|
|
27
|
-
*/
|
|
28
|
-
const SITE_MEDIA_EXT_OK = new Set(['.mp4', '.webm', '.mov', '.m4v', '.jpg', '.jpeg', '.png', '.webp', '.avif', '.gif']);
|
|
29
|
-
|
|
30
23
|
/** 本地库与状态文件的位置(与其它路由同一口径:DSH_HOME 或桌面端的 harness 目录)。 */
|
|
31
24
|
function dshHome() {
|
|
32
25
|
return process.env.DSH_HOME || join(process.env.APPDATA || homedir(), 'dsh-desktop', 'harness');
|
|
@@ -46,44 +39,20 @@ function libraryDest(kind, slug, ext) {
|
|
|
46
39
|
}
|
|
47
40
|
|
|
48
41
|
/**
|
|
49
|
-
* inventory
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
* ① 下载队列落地(`<home>/library/<kind>/…`)⇒ `/folia/local-media/<id>`
|
|
53
|
-
* ② **site-media 缓存**(首次播放时边下边播留下的那份)⇒ 走已有的
|
|
54
|
-
* `/folia/site-media/<name>?u=…`,它命中缓存时直接 `serveFile`,**不触网**
|
|
55
|
-
*
|
|
56
|
-
* 为什么必须查②:站点壁纸第一次播放会经过 site-media 代理并落盘,如果这里只看①,
|
|
57
|
-
* 同一份字节会被**再下载一遍**(21 MB 的包在弱网上就是"点了很久才出来"的主因),
|
|
58
|
-
* 而且磁盘上存两份。
|
|
42
|
+
* inventory 用:这条站点资源**是否已经落到本地**,以及它的 job id。
|
|
43
|
+
* 命中 ⇒ inventory 把 `media` 指向 `/folia/local-media/<id>`(渲染只读本地)。
|
|
44
|
+
* 未命中 ⇒ 返回 null,调用方保持原来的远端/代理地址(用户点了会先入队下载)。
|
|
59
45
|
*/
|
|
60
46
|
export function localCopyFor(url, kind = 'wallpaper') {
|
|
61
47
|
try {
|
|
62
|
-
const
|
|
63
|
-
const u = new URL(raw);
|
|
48
|
+
const u = new URL(String(url));
|
|
64
49
|
const ext = (u.pathname.match(/\.([a-z0-9]{2,5})$/i) || [])[1] || 'bin';
|
|
65
50
|
const slug = u.pathname.split('/').filter(Boolean).pop() || 'item';
|
|
66
51
|
const dest = libraryDest(kind, slug, ext);
|
|
67
52
|
const q = getDownloadQueue();
|
|
68
53
|
const job = q.snapshot().find((j) => j.dest === dest);
|
|
69
|
-
if (job
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
// ② site-media 缓存:键算法必须与 lib/routes/site-media.js#keyFor **逐字一致**
|
|
73
|
-
// (`sha256(url)[:32] + 规范化扩展名`),否则永远命不中。
|
|
74
|
-
const key = createHash('sha256').update(raw).digest('hex').slice(0, 32)
|
|
75
|
-
+ (SITE_MEDIA_EXT_OK.has('.' + ext.toLowerCase()) ? '.' + ext.toLowerCase() : '.bin');
|
|
76
|
-
const cached = join(dshHome(), 'cache', 'site-media', key);
|
|
77
|
-
if (existsSync(cached)) {
|
|
78
|
-
const name = raw.split('/').pop() || 'media';
|
|
79
|
-
return {
|
|
80
|
-
id: key,
|
|
81
|
-
url: '/folia/site-media/' + encodeURIComponent(name) + '?u=' + encodeURIComponent(raw),
|
|
82
|
-
bytes: (() => { try { return statSync(cached).size; } catch { return 0; } })(),
|
|
83
|
-
source: 'site-media-cache',
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
return null;
|
|
54
|
+
if (!job || job.status !== 'done') return null;
|
|
55
|
+
return { id: job.id, url: `/folia/local-media/${job.id}`, bytes: job.total };
|
|
87
56
|
} catch { return null; }
|
|
88
57
|
}
|
|
89
58
|
|