Sync from /srv/compose/unified-media-manager

This commit is contained in:
Christopher Mayor
2026-04-24 10:45:19 -07:00
commit 7dbd00e537
132 changed files with 25394 additions and 0 deletions

View File

@@ -0,0 +1,253 @@
-- Custom types
CREATE TYPE MEDIA_TYPE AS ENUM (
'movie', 'series', 'episode', 'music', 'album',
'audiobook', 'podcast', 'photo', 'other'
);
CREATE TYPE MEDIA_STATUS AS ENUM (
'unavailable', 'searching', 'downloading', 'importing',
'available', 'upgrading', 'failed'
);
CREATE TYPE QUEUE_STATUS AS ENUM (
'pending', 'downloading', 'imported', 'failed',
'blacklisted', 'cancelled'
);
-- Quality profiles
CREATE TABLE quality_profiles (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
media_types MEDIA_TYPE[] NOT NULL,
cutoff_quality JSONB NOT NULL,
allowed_qualities JSONB NOT NULL DEFAULT '[]',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Root folders
CREATE TABLE root_folders (
id SERIAL PRIMARY KEY,
path TEXT NOT NULL UNIQUE,
media_type MEDIA_TYPE NOT NULL,
free_space BIGINT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Tags
CREATE TABLE tags (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
color TEXT DEFAULT '#6366f1'
);
-- Scheduled tasks
CREATE TABLE scheduled_tasks (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
cron_expr TEXT NOT NULL,
last_run_at TIMESTAMPTZ,
next_run_at TIMESTAMPTZ,
enabled BOOLEAN DEFAULT true,
retention_days INTEGER DEFAULT 7
);
-- Indexers
CREATE TABLE indexers (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL UNIQUE,
implementation TEXT NOT NULL,
url TEXT NOT NULL,
api_key TEXT,
categories JSONB DEFAULT '[]',
settings JSONB DEFAULT '{}',
enabled BOOLEAN DEFAULT true,
priority INTEGER DEFAULT 0,
last_success_at TIMESTAMPTZ,
failure_count INTEGER DEFAULT 0,
disabled_until TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Download clients
CREATE TABLE download_clients (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
implementation TEXT NOT NULL,
host TEXT NOT NULL,
port INTEGER NOT NULL,
username TEXT,
password TEXT,
settings JSONB DEFAULT '{}',
enabled BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- Unified media table (partitioned by type)
CREATE TABLE media (
id BIGSERIAL,
media_type MEDIA_TYPE NOT NULL,
title TEXT NOT NULL,
sort_title TEXT NOT NULL,
original_title TEXT,
overview TEXT,
year INTEGER,
status MEDIA_STATUS NOT NULL DEFAULT 'unavailable',
monitored BOOLEAN NOT NULL DEFAULT false,
external_ids JSONB NOT NULL DEFAULT '{}',
metadata JSONB NOT NULL DEFAULT '{}',
images JSONB NOT NULL DEFAULT '[]',
quality_profile_id INTEGER REFERENCES quality_profiles(id),
root_folder_id INTEGER REFERENCES root_folders(id),
current_quality JSONB,
desired_quality JSONB,
added_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
last_search_at TIMESTAMPTZ,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ,
PRIMARY KEY (id, media_type)
) PARTITION BY LIST (media_type);
CREATE TABLE media_movie PARTITION OF media FOR VALUES IN ('movie');
CREATE TABLE media_series PARTITION OF media FOR VALUES IN ('series');
CREATE TABLE media_episode PARTITION OF media FOR VALUES IN ('episode');
CREATE TABLE media_music PARTITION OF media FOR VALUES IN ('music');
CREATE TABLE media_album PARTITION OF media FOR VALUES IN ('album');
CREATE TABLE media_audiobook PARTITION OF media FOR VALUES IN ('audiobook');
CREATE TABLE media_podcast PARTITION OF media FOR VALUES IN ('podcast');
CREATE TABLE media_photo PARTITION OF media FOR VALUES IN ('photo');
CREATE TABLE media_other PARTITION OF media FOR VALUES IN ('other');
-- Media indexes
CREATE INDEX idx_media_title ON media USING gin (to_tsvector('english', coalesce(title, '')));
CREATE INDEX idx_media_monitored ON media (monitored) WHERE monitored = true;
CREATE INDEX idx_media_status ON media (status, media_type);
CREATE INDEX idx_media_external_ids ON media USING gin (external_ids);
-- Media relations (series->episodes, album->tracks)
CREATE TABLE media_relations (
id BIGSERIAL PRIMARY KEY,
parent_id BIGINT NOT NULL,
child_id BIGINT NOT NULL,
relation TEXT NOT NULL,
position INTEGER,
season INTEGER,
UNIQUE(parent_id, child_id, relation)
);
-- Media tags
CREATE TABLE media_tags (
media_id BIGINT NOT NULL,
media_type MEDIA_TYPE NOT NULL,
tag_id INTEGER NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
PRIMARY KEY (media_id, media_type, tag_id)
);
-- Unified file tracking
CREATE TABLE media_files (
id BIGSERIAL PRIMARY KEY,
media_id BIGINT NOT NULL,
media_type MEDIA_TYPE NOT NULL,
path TEXT NOT NULL,
original_path TEXT,
file_name TEXT NOT NULL,
file_size BIGINT NOT NULL DEFAULT 0,
quality JSONB NOT NULL DEFAULT '{}',
codec TEXT,
resolution TEXT,
source TEXT,
is_hardlinked BOOLEAN DEFAULT false,
checksum TEXT,
transcode_status TEXT DEFAULT 'none',
transcode_preset TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ,
UNIQUE(media_id, media_type, path)
);
CREATE INDEX idx_media_files_media ON media_files (media_id, media_type);
CREATE INDEX idx_media_files_transcode ON media_files (transcode_status) WHERE transcode_status != 'done';
-- Download queue
CREATE TABLE download_queue (
id BIGSERIAL PRIMARY KEY,
media_id BIGINT NOT NULL,
media_type MEDIA_TYPE NOT NULL,
release_title TEXT NOT NULL,
release_url TEXT,
indexer TEXT NOT NULL,
download_client TEXT NOT NULL,
quality JSONB NOT NULL DEFAULT '{}',
size BIGINT,
protocol TEXT NOT NULL DEFAULT 'torrent',
status QUEUE_STATUS NOT NULL DEFAULT 'pending',
progress REAL DEFAULT 0,
error_message TEXT,
batch_id UUID,
priority INTEGER DEFAULT 0,
retry_count INTEGER DEFAULT 0,
max_retries INTEGER DEFAULT 3,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
started_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_queue_status ON download_queue (status, priority DESC);
CREATE INDEX idx_queue_batch ON download_queue (batch_id) WHERE batch_id IS NOT NULL;
CREATE INDEX idx_queue_media ON download_queue (media_id, media_type);
-- Blocklist
CREATE TABLE blocklist (
id BIGSERIAL PRIMARY KEY,
release_title TEXT NOT NULL,
source_title TEXT,
quality JSONB DEFAULT '{}',
indexer TEXT,
protocol TEXT DEFAULT 'torrent',
torrent_hash TEXT,
size BIGINT,
message TEXT,
media_id BIGINT,
media_type MEDIA_TYPE,
block_reason TEXT DEFAULT 'manual',
auto_expires_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_blocklist_media ON blocklist (media_id, media_type);
CREATE INDEX idx_blocklist_expires ON blocklist (auto_expires_at) WHERE auto_expires_at IS NOT NULL;
-- Task execution log
CREATE TABLE task_executions (
id BIGSERIAL PRIMARY KEY,
task_id INTEGER NOT NULL REFERENCES scheduled_tasks(id) ON DELETE CASCADE,
status TEXT NOT NULL DEFAULT 'running',
started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
ended_at TIMESTAMPTZ,
duration_ms INTEGER,
result JSONB,
error TEXT
);
CREATE INDEX idx_task_exec_task ON task_executions (task_id, started_at DESC);
-- Download history (partitioned for auto-cleanup)
CREATE TABLE download_history (
id BIGSERIAL,
media_id BIGINT NOT NULL,
media_type MEDIA_TYPE NOT NULL,
action TEXT NOT NULL,
release_title TEXT,
quality JSONB DEFAULT '{}',
indexer TEXT,
client TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (id, created_at)
) PARTITION BY RANGE (created_at);
CREATE TABLE download_history_current PARTITION OF download_history
FOR VALUES FROM (CURRENT_DATE - INTERVAL '90 days') TO (MAXVALUE);