From dba0ec9c84422c02e86a2e9a344da1e690ef91ae Mon Sep 17 00:00:00 2001 From: wolfmanster <68727977+wolfmanster@users.noreply.github.com> Date: Wed, 19 Aug 2026 16:50:25 +0800 Subject: [PATCH] Use remote avatar URLs instead of downloading avatars --- PRODUCT_README_CN.md | 2 +- apps/server/src/index.ts | 16 ++-------------- apps/server/src/queue.ts | 20 -------------------- apps/server/src/types.ts | 1 - 4 files changed, 3 insertions(+), 36 deletions(-) diff --git a/PRODUCT_README_CN.md b/PRODUCT_README_CN.md index d4001a49..6a8d3bdd 100644 --- a/PRODUCT_README_CN.md +++ b/PRODUCT_README_CN.md @@ -18,7 +18,7 @@ 1. 向本地 Cobalt `POST /` 请求媒体列表,并强制通过 Cobalt 代理媒体。 2. 请求 X 的公开嵌入数据端点 `cdn.syndication.twimg.com/tweet-result`,补齐 7 个元数据字段。 -公开嵌入端点无需 Cookie、账号和官方 API key,但不是 X 承诺稳定的正式 API。它不可用时任务会明确失败并允许重试,避免生成缺字段的半成品记录。头像会下载到项目内,不由浏览器直接请求远端。 +公开嵌入端点无需 Cookie、账号和官方 API key,但不是 X 承诺稳定的正式 API。它不可用时任务会明确失败并允许重试,避免生成缺字段的半成品记录。博主头像只使用元数据中的远程地址,不下载到项目内。 ## 目录 diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts index f4c0b1dd..e676bf93 100644 --- a/apps/server/src/index.ts +++ b/apps/server/src/index.ts @@ -23,13 +23,10 @@ app.use(cors()); app.use(express.json({ limit: '1mb' })); function publicJob(job: DownloadJob) { - const { avatarPath, ...visibleJob } = job; + const { avatarPath: _legacyAvatarPath, ...visibleJob } = job as DownloadJob & { avatarPath?: string }; return { ...visibleJob, - metadata: job.metadata ? { - ...job.metadata, - avatarUrl: avatarPath ? `/api/jobs/${job.id}/avatar` : '', - } : undefined, + metadata: job.metadata, media: job.media.map(({ sourceUrl: _sourceUrl, localPath: _localPath, ...media }) => ({ ...media, previewUrl: `/api/jobs/${job.id}/media/${media.id}`, @@ -110,15 +107,6 @@ app.post('/api/jobs/:id/retry', (req, res) => { app.delete('/api/history', async (_req, res) => res.json({ removed: await store.clearCompleted() })); -app.get('/api/jobs/:jobId/avatar', (req, res) => { - const job = store.get(req.params.jobId); - if (!job?.avatarPath) return res.status(404).end(); - const filePath = path.resolve(store.dataDir, job.avatarPath); - if (!filePath.startsWith(`${path.resolve(store.mediaDir)}${path.sep}`) || !fs.existsSync(filePath)) return res.status(404).end(); - res.setHeader('Cache-Control', 'private, max-age=3600'); - return fs.createReadStream(filePath).pipe(res); -}); - app.get('/api/jobs/:jobId/media/:mediaId', async (req, res) => { const job = store.get(req.params.jobId); const media = job?.media.find((item) => item.id === req.params.mediaId); diff --git a/apps/server/src/queue.ts b/apps/server/src/queue.ts index 9d90c092..8a63c8a8 100644 --- a/apps/server/src/queue.ts +++ b/apps/server/src/queue.ts @@ -101,8 +101,6 @@ export class DownloadQueue extends EventEmitter { this.store.update(jobId, { metadata, media, status: 'downloading', progress: 12 }); this.emitChange(); - await this.downloadAvatar(job, metadata.avatarUrl, controller.signal); - for (let index = 0; index < media.length; index += 1) { await this.downloadMedia(job, media[index]!, index, media.length, controller.signal); } @@ -126,24 +124,6 @@ export class DownloadQueue extends EventEmitter { } } - private async downloadAvatar(job: DownloadJob, avatarUrl: string, signal: AbortSignal): Promise { - if (!avatarUrl) return; - try { - const response = await fetch(avatarUrl, { signal }); - if (!response.ok) return; - const contentType = response.headers.get('content-type')?.split(';')[0]; - const extension = contentType ? (EXTENSIONS[contentType] ?? 'jpg') : 'jpg'; - const jobDir = path.join(this.store.mediaDir, job.id); - await fsp.mkdir(jobDir, { recursive: true }); - const avatarPath = path.join(jobDir, `avatar.${extension}`); - await fsp.writeFile(avatarPath, Buffer.from(await response.arrayBuffer())); - this.store.update(job.id, { avatarPath: path.relative(this.store.dataDir, avatarPath) }); - } catch (error) { - if (signal.aborted) throw error; - // Avatar failure does not discard otherwise valid post media. - } - } - private async downloadMedia( job: DownloadJob, media: MediaItem, diff --git a/apps/server/src/types.ts b/apps/server/src/types.ts index c4fd37e1..639bddbd 100644 --- a/apps/server/src/types.ts +++ b/apps/server/src/types.ts @@ -36,7 +36,6 @@ export interface DownloadJob { status: JobStatus; progress: number; metadata?: PostMetadata; - avatarPath?: string; media: MediaItem[]; error?: string; attempts: number;