Capture YouTube titles from Discord's embed cache
This commit is contained in:
@@ -100,6 +100,14 @@ export interface ScrapeEngineOptions {
|
||||
) => Promise<string | null>;
|
||||
/** Delay before the single suspect retry. Default 50 s. */
|
||||
suspectRetryMs?: number;
|
||||
/**
|
||||
* Title and author from the source message's Discord embed. Preferred over the provider
|
||||
* oEmbed: Discord keeps the embed data even after a video is deleted.
|
||||
*/
|
||||
embedMeta?: (
|
||||
scrapeId: string,
|
||||
media: { id: number; url: string; playUrl: string | null }
|
||||
) => Promise<{ title: string; author: string | null } | null>;
|
||||
/** Read dimensions and duration from a downloaded file. Defaults to ffprobe. */
|
||||
probe?: (
|
||||
path: string
|
||||
@@ -605,7 +613,15 @@ export class ScrapeEngine {
|
||||
break;
|
||||
}
|
||||
|
||||
const resolved = await resolveEmbedTitle(row.url, options);
|
||||
// Discord's cached embed data survives a deleted video; ask it first.
|
||||
const fromDiscord = await this.options.embedMeta?.(meta.id, {
|
||||
id: row.id,
|
||||
url: row.url,
|
||||
playUrl: row.play_url
|
||||
});
|
||||
const resolved =
|
||||
fromDiscord ??
|
||||
(await resolveEmbedTitle(row.url, options));
|
||||
if (resolved) {
|
||||
store.markTitle(row.id, resolved.title, resolved.author);
|
||||
result.titled++;
|
||||
|
||||
@@ -34,6 +34,8 @@ export interface ExtractedMedia {
|
||||
previewUrl: string | null;
|
||||
/** Embed title, when Discord provides one (YouTube and friends). Null elsewhere. */
|
||||
title: string | null;
|
||||
/** Embed author (the YouTube channel Discord shows). Null elsewhere. */
|
||||
titleAuthor: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,7 +97,8 @@ function extractEmbed(embed: CoreEmbed): ExtractedMedia | null {
|
||||
width: embed.width ?? null,
|
||||
height: embed.height ?? null,
|
||||
durationSecs: null,
|
||||
title: embed.title ?? null
|
||||
title: embed.title ?? null,
|
||||
titleAuthor: embed.authorName ?? null
|
||||
};
|
||||
|
||||
if (embed.videoUrl) {
|
||||
@@ -150,7 +153,8 @@ function extractSticker(sticker: CoreSticker): ExtractedMedia | null {
|
||||
durationSecs: null,
|
||||
downloaded: false,
|
||||
previewUrl: null,
|
||||
title: null
|
||||
title: null,
|
||||
titleAuthor: null
|
||||
};
|
||||
}
|
||||
|
||||
@@ -178,7 +182,8 @@ function extractFrom(message: MediaMessage): ExtractedMedia[] {
|
||||
: null,
|
||||
downloaded: false,
|
||||
previewUrl: null,
|
||||
title: null
|
||||
title: null,
|
||||
titleAuthor: null
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -404,7 +404,7 @@ export class ScrapeStore {
|
||||
"INSERT OR REPLACE INTO messages (id, author_id, author_name, timestamp, content) VALUES (?, ?, ?, ?, ?)"
|
||||
);
|
||||
const insertMedia = this.db.prepare(
|
||||
"INSERT OR IGNORE INTO media (kind, source, author_id, author_name, posted_at, url, play_url, provider, content_type, size, width, height, aspect_ratio, duration_secs, downloaded, preview_url, title, title_key, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
||||
"INSERT OR IGNORE INTO media (kind, source, author_id, author_name, posted_at, url, play_url, provider, content_type, size, width, height, aspect_ratio, duration_secs, downloaded, preview_url, title, title_key, title_author, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
|
||||
);
|
||||
const findMedia = this.db.prepare("SELECT id FROM media WHERE url = ?");
|
||||
const linkSource = this.db.prepare(
|
||||
@@ -443,6 +443,7 @@ export class ScrapeStore {
|
||||
item.previewUrl,
|
||||
item.title,
|
||||
item.title ? normalizeTitleKey(item.title) : null,
|
||||
item.titleAuthor,
|
||||
createdAt
|
||||
);
|
||||
if (result.changes > 0) added[item.kind]++;
|
||||
|
||||
@@ -35,6 +35,8 @@ export interface CoreEmbed {
|
||||
type: string | null;
|
||||
url: string | null;
|
||||
title: string | null;
|
||||
/** Discord's embed author line (the YouTube channel name). */
|
||||
authorName?: string | null;
|
||||
provider: string | null;
|
||||
videoUrl: string | null;
|
||||
imageUrl: string | null;
|
||||
|
||||
Reference in New Issue
Block a user