Files
sendewerk/migrations/0021_post_production.sql
T

128 lines
5.2 KiB
SQL

CREATE TABLE post_recording_parts (
id TEXT PRIMARY KEY,
show_id TEXT NOT NULL REFERENCES shows(id) ON DELETE CASCADE,
label TEXT NOT NULL,
position INTEGER NOT NULL CHECK (position >= 0),
media_file_path TEXT NOT NULL DEFAULT '',
frame_rate REAL CHECK (frame_rate IS NULL OR (frame_rate > 0 AND frame_rate <= 240)),
timebase INTEGER CHECK (timebase IS NULL OR (timebase > 0 AND timebase <= 240)),
created_at_utc TEXT NOT NULL,
UNIQUE (show_id, position)
);
CREATE INDEX idx_post_recording_parts_show
ON post_recording_parts(show_id, position);
CREATE TABLE post_source_files (
id TEXT PRIMARY KEY,
show_id TEXT NOT NULL REFERENCES shows(id) ON DELETE CASCADE,
recording_part_id TEXT REFERENCES post_recording_parts(id) ON DELETE SET NULL,
original_name TEXT NOT NULL,
storage_name TEXT NOT NULL UNIQUE,
sha256 TEXT NOT NULL,
byte_size INTEGER NOT NULL CHECK (byte_size > 0),
content TEXT NOT NULL,
transcript_text TEXT NOT NULL DEFAULT '',
timecodes_json TEXT NOT NULL DEFAULT '[]',
imported_at_utc TEXT NOT NULL,
UNIQUE (show_id, sha256)
);
CREATE INDEX idx_post_source_files_show
ON post_source_files(show_id, imported_at_utc);
CREATE TABLE post_items (
id TEXT PRIMARY KEY,
show_id TEXT NOT NULL REFERENCES shows(id) ON DELETE CASCADE,
kind TEXT NOT NULL CHECK (kind IN ('youtube', 'clip', 'highlight')),
title TEXT NOT NULL,
status TEXT NOT NULL CHECK (status IN ('draft', 'review', 'approved', 'editing', 'done', 'published')),
recording_part_id TEXT REFERENCES post_recording_parts(id) ON DELETE SET NULL,
source_file_id TEXT REFERENCES post_source_files(id) ON DELETE SET NULL,
piece_id TEXT REFERENCES pieces(id) ON DELETE SET NULL,
notes TEXT NOT NULL DEFAULT '',
revision INTEGER NOT NULL DEFAULT 1 CHECK (revision >= 1),
position INTEGER NOT NULL CHECK (position >= 0),
created_at_utc TEXT NOT NULL,
updated_at_utc TEXT NOT NULL,
UNIQUE (show_id, kind, position)
);
CREATE INDEX idx_post_items_show_kind
ON post_items(show_id, kind, position);
CREATE TABLE post_youtube_videos (
item_id TEXT PRIMARY KEY REFERENCES post_items(id) ON DELETE CASCADE,
description TEXT NOT NULL DEFAULT '',
title_variants_json TEXT NOT NULL DEFAULT '[]',
thumbnail_concept TEXT NOT NULL DEFAULT '',
thumbnail_text TEXT NOT NULL DEFAULT '',
publication_status TEXT NOT NULL DEFAULT 'unpublished'
CHECK (publication_status IN ('unpublished', 'scheduled', 'published')),
published_at_utc TEXT,
youtube_url TEXT NOT NULL DEFAULT '',
video_format TEXT NOT NULL DEFAULT '16:9'
);
CREATE TABLE post_social_clips (
item_id TEXT PRIMARY KEY REFERENCES post_items(id) ON DELETE CASCADE,
clip_type TEXT NOT NULL DEFAULT 'other'
CHECK (clip_type IN ('storytime', 'opinion', 'explanation', 'gaming', 'humor', 'other')),
original_transcript TEXT NOT NULL DEFAULT '',
start_seconds INTEGER CHECK (start_seconds IS NULL OR start_seconds >= 0),
end_seconds INTEGER CHECK (end_seconds IS NULL OR end_seconds >= 0),
dramaturgy_notes TEXT NOT NULL DEFAULT '',
edit_instructions TEXT NOT NULL DEFAULT '',
shorts_title TEXT NOT NULL DEFAULT '',
shorts_description TEXT NOT NULL DEFAULT '',
shorts_hashtags TEXT NOT NULL DEFAULT '',
tiktok_caption TEXT NOT NULL DEFAULT '',
instagram_caption TEXT NOT NULL DEFAULT '',
social_hashtags TEXT NOT NULL DEFAULT '',
primary_hook TEXT NOT NULL DEFAULT '',
alternative_hooks TEXT NOT NULL DEFAULT '',
endcard_text TEXT NOT NULL DEFAULT '',
alternative_endcards TEXT NOT NULL DEFAULT '',
framing_notes TEXT NOT NULL DEFAULT '',
subtitle_notes TEXT NOT NULL DEFAULT '',
subtitle_srt TEXT NOT NULL DEFAULT '',
video_format TEXT NOT NULL DEFAULT '9:16',
target_tiktok INTEGER NOT NULL DEFAULT 1 CHECK (target_tiktok IN (0, 1)),
target_instagram INTEGER NOT NULL DEFAULT 1 CHECK (target_instagram IN (0, 1)),
target_shorts INTEGER NOT NULL DEFAULT 1 CHECK (target_shorts IN (0, 1)),
CHECK (end_seconds IS NULL OR start_seconds IS NULL OR end_seconds > start_seconds)
);
CREATE TABLE post_twitch_highlights (
item_id TEXT PRIMARY KEY REFERENCES post_items(id) ON DELETE CASCADE,
description TEXT NOT NULL DEFAULT '',
original_transcript TEXT NOT NULL DEFAULT '',
start_seconds INTEGER CHECK (start_seconds IS NULL OR start_seconds >= 0),
end_seconds INTEGER CHECK (end_seconds IS NULL OR end_seconds >= 0),
edit_instructions TEXT NOT NULL DEFAULT '',
publication_notes TEXT NOT NULL DEFAULT '',
video_format TEXT NOT NULL DEFAULT '16:9',
twitch_url TEXT NOT NULL DEFAULT '',
CHECK (end_seconds IS NULL OR start_seconds IS NULL OR end_seconds > start_seconds)
);
CREATE TABLE post_thumbnails (
id TEXT PRIMARY KEY,
youtube_item_id TEXT NOT NULL REFERENCES post_youtube_videos(item_id) ON DELETE CASCADE,
storage_name TEXT NOT NULL UNIQUE,
original_name TEXT NOT NULL,
mime_type TEXT NOT NULL,
byte_size INTEGER NOT NULL CHECK (byte_size > 0),
alt_text TEXT NOT NULL DEFAULT '',
position INTEGER NOT NULL CHECK (position >= 0),
is_selected INTEGER NOT NULL DEFAULT 0 CHECK (is_selected IN (0, 1)),
created_at_utc TEXT NOT NULL,
UNIQUE (youtube_item_id, position)
);
CREATE INDEX idx_post_thumbnails_item
ON post_thumbnails(youtube_item_id, position);
CREATE UNIQUE INDEX idx_post_one_selected_thumbnail
ON post_thumbnails(youtube_item_id) WHERE is_selected = 1;