mirror of
https://github.com/imputnet/cobalt.git
synced 2026-10-24 02:52:18 +00:00
Use remote avatar URLs instead of downloading avatars
This commit is contained in:
parent
52c702a4be
commit
dba0ec9c84
4 changed files with 3 additions and 36 deletions
|
|
@ -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。它不可用时任务会明确失败并允许重试,避免生成缺字段的半成品记录。博主头像只使用元数据中的远程地址,不下载到项目内。
|
||||
|
||||
## 目录
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<void> {
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ export interface DownloadJob {
|
|||
status: JobStatus;
|
||||
progress: number;
|
||||
metadata?: PostMetadata;
|
||||
avatarPath?: string;
|
||||
media: MediaItem[];
|
||||
error?: string;
|
||||
attempts: number;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue