- "src/db/schema/content.ts" - "src/types/index.ts" - "src/db/repositories/content-repository.ts" - "src/services/queue.ts" - "drizzle/0012_adhoc_nullable_channel.sql" - "drizzle/meta/_journal.json" GSD-Task: S01/T01
52 lines
2.7 KiB
TypeScript
52 lines
2.7 KiB
TypeScript
import { sqliteTable, text, integer, real } from 'drizzle-orm/sqlite-core';
|
|
import { sql } from 'drizzle-orm';
|
|
import { channels } from './channels';
|
|
|
|
/** Individual content items (videos, audio tracks, livestreams). */
|
|
export const contentItems = sqliteTable('content_items', {
|
|
id: integer('id').primaryKey({ autoIncrement: true }),
|
|
channelId: integer('channel_id')
|
|
.references(() => channels.id, { onDelete: 'cascade' }),
|
|
title: text('title').notNull(),
|
|
platformContentId: text('platform_content_id').notNull(),
|
|
url: text('url').notNull(),
|
|
contentType: text('content_type').notNull(), // 'video' | 'audio' | 'livestream'
|
|
duration: integer('duration'), // seconds
|
|
filePath: text('file_path'),
|
|
fileSize: integer('file_size'), // bytes
|
|
format: text('format'), // container format e.g. 'mp4', 'webm', 'mp3'
|
|
qualityMetadata: text('quality_metadata', { mode: 'json' }), // actual quality info post-download
|
|
status: text('status').notNull().default('monitored'), // monitored|queued|downloading|downloaded|failed|ignored
|
|
thumbnailUrl: text('thumbnail_url'),
|
|
publishedAt: text('published_at'), // ISO datetime from platform (nullable)
|
|
downloadedAt: text('downloaded_at'), // ISO datetime when download completed (nullable)
|
|
monitored: integer('monitored', { mode: 'boolean' }).notNull().default(true), // per-item monitoring toggle
|
|
createdAt: text('created_at')
|
|
.notNull()
|
|
.default(sql`(datetime('now'))`),
|
|
updatedAt: text('updated_at')
|
|
.notNull()
|
|
.default(sql`(datetime('now'))`),
|
|
});
|
|
|
|
/** Format profiles defining preferred download quality/format settings. */
|
|
export const formatProfiles = sqliteTable('format_profiles', {
|
|
id: integer('id').primaryKey({ autoIncrement: true }),
|
|
name: text('name').notNull(),
|
|
videoResolution: text('video_resolution'), // e.g. '1080p', '720p', 'best'
|
|
audioCodec: text('audio_codec'), // e.g. 'opus', 'aac', 'mp3'
|
|
audioBitrate: text('audio_bitrate'), // e.g. '320k', '192k'
|
|
containerFormat: text('container_format'), // e.g. 'mp4', 'mkv', 'mp3'
|
|
isDefault: integer('is_default', { mode: 'boolean' }).notNull().default(false),
|
|
subtitleLanguages: text('subtitle_languages'),
|
|
embedSubtitles: integer('embed_subtitles', { mode: 'boolean' }).notNull().default(false),
|
|
embedChapters: integer('embed_chapters', { mode: 'boolean' }).notNull().default(false),
|
|
embedThumbnail: integer('embed_thumbnail', { mode: 'boolean' }).notNull().default(false),
|
|
sponsorBlockRemove: text('sponsor_block_remove'), // comma-separated categories: 'sponsor,selfpromo,interaction,intro,outro,preview,music_offtopic,filler'
|
|
createdAt: text('created_at')
|
|
.notNull()
|
|
.default(sql`(datetime('now'))`),
|
|
updatedAt: text('updated_at')
|
|
.notNull()
|
|
.default(sql`(datetime('now'))`),
|
|
});
|