114 lines
3.4 KiB
TypeScript
114 lines
3.4 KiB
TypeScript
/*
|
|
* Shared types for the media archive. See docs/media.md and docs/media-scraper.md.
|
|
*/
|
|
|
|
export type MediaKind = "image" | "gif" | "video" | "audio";
|
|
|
|
export const MEDIA_KINDS: MediaKind[] = ["image", "gif", "video", "audio"];
|
|
|
|
export type ScrapeState =
|
|
| "queued"
|
|
| "running"
|
|
| "paused"
|
|
| "done"
|
|
| "failed"
|
|
| "pending-delete"
|
|
| "deleting"
|
|
| "deleted";
|
|
|
|
export type ScrapeMode = "links" | "download";
|
|
|
|
export type BackendName = "puppet" | "slopbot";
|
|
|
|
export interface CoreAttachment {
|
|
id: string | null;
|
|
filename: string;
|
|
url: string | null;
|
|
contentType: string | null;
|
|
size: number | null;
|
|
width: number | null;
|
|
height: number | null;
|
|
durationSecs: number | null;
|
|
}
|
|
|
|
export interface CoreEmbed {
|
|
type: string | null;
|
|
url: string | null;
|
|
title: string | null;
|
|
provider: string | null;
|
|
videoUrl: string | null;
|
|
imageUrl: string | null;
|
|
thumbnailUrl: string | null;
|
|
/** Dimensions of the video, image, or thumbnail, first one Discord provides. */
|
|
width?: number | null;
|
|
height?: number | null;
|
|
}
|
|
|
|
export interface CoreSticker {
|
|
id: string | null;
|
|
name: string | null;
|
|
formatType: number | null;
|
|
}
|
|
|
|
/** The part of a core message the extractor reads. Forwarded snapshots use the same shape. */
|
|
export interface MediaMessage {
|
|
attachments: CoreAttachment[];
|
|
embeds: CoreEmbed[];
|
|
stickerItems: CoreSticker[];
|
|
voiceMessage: boolean;
|
|
}
|
|
|
|
/** A message as shaped by the core bridge (`message.fetch`, `message.read`). */
|
|
export interface CoreMessage extends MediaMessage {
|
|
id: string;
|
|
author: { id: string; username: string; avatar: string | null };
|
|
content: string;
|
|
timestamp: string;
|
|
editedAt: string | null;
|
|
replyTo: { id: string; authorId: string | null; authorName: string | null } | null;
|
|
forwarded: Array<MediaMessage & { content: string; timestamp: string | null }>;
|
|
}
|
|
|
|
/** `scrape.json`: the state of one scrape. The directory is the scrape's identity. */
|
|
export interface ScrapeMeta {
|
|
id: string;
|
|
channelId: string;
|
|
guildId: string | null;
|
|
backend: BackendName;
|
|
mode: ScrapeMode;
|
|
state: ScrapeState;
|
|
/** The oldest message ID seen. The next page is fetched before it. */
|
|
cursor: string | null;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
pages: number;
|
|
messages: number;
|
|
media: Record<MediaKind, number>;
|
|
errors: number;
|
|
lastError: string | null;
|
|
/** Files fetched in download mode. */
|
|
downloaded?: number;
|
|
/** Files that failed after retries; skipped URLs are not counted here. */
|
|
downloadErrors?: number;
|
|
/** Cached image previews. */
|
|
previewed?: number;
|
|
/** When the scrape reached done or failed. */
|
|
finishedAt?: string | null;
|
|
/** Absolute destination for downloaded files. Null means the local `media/` folder. */
|
|
downloadDir?: string | null;
|
|
/** Lower message-ID boundary (exclusive), derived from the from-date. */
|
|
afterId?: string | null;
|
|
/** Upper message-ID boundary; the walk starts just below it. */
|
|
beforeId?: string | null;
|
|
/** From-date as ISO, for display in history. */
|
|
fromDate?: string | null;
|
|
/** To-date as ISO, for display in history. */
|
|
toDate?: string | null;
|
|
/** Discord search total for the range, when known (slopbot only). */
|
|
estimatedMessages?: number | null;
|
|
}
|
|
|
|
export function emptyMediaCounts(): Record<MediaKind, number> {
|
|
return { image: 0, gif: 0, video: 0, audio: 0 };
|
|
}
|