f24543f401
- Add sqlx with PostgreSQL support for database operations - Create DbService with artist/album upsert and listing methods - Add database schema (14 tables) in containers/init.sql - Add library controller (GET /api/library/artists, /albums, /stats) - Merge sync_artist + ingest into single POST /api/sync endpoint - Support configurable sync: download (bool), store (bool), album filter - Connect to database at startup with graceful fallback
226 lines
9.4 KiB
SQL
226 lines
9.4 KiB
SQL
-- Music Aggregator Database Schema
|
|
-- Based on docs/erd.puml
|
|
|
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
|
|
|
-- ══════════════════════════════════════════════════════════════
|
|
-- CONFIGURATION
|
|
-- ══════════════════════════════════════════════════════════════
|
|
|
|
CREATE TABLE quality_profiles (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
name TEXT NOT NULL UNIQUE,
|
|
cutoff INT NOT NULL DEFAULT 0,
|
|
items JSONB NOT NULL DEFAULT '[]',
|
|
upgrade_allowed BOOLEAN NOT NULL DEFAULT true
|
|
);
|
|
|
|
CREATE TABLE metadata_profiles (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
name TEXT NOT NULL UNIQUE,
|
|
primary_album_types JSONB NOT NULL DEFAULT '["Album", "EP"]',
|
|
secondary_album_types JSONB NOT NULL DEFAULT '[]',
|
|
release_statuses JSONB NOT NULL DEFAULT '["Official"]'
|
|
);
|
|
|
|
CREATE TABLE root_folders (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
name TEXT NOT NULL,
|
|
path TEXT NOT NULL UNIQUE,
|
|
default_quality_profile_id UUID REFERENCES quality_profiles(id),
|
|
default_metadata_profile_id UUID REFERENCES metadata_profiles(id)
|
|
);
|
|
|
|
CREATE TABLE indexers (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
name TEXT NOT NULL,
|
|
implementation TEXT NOT NULL,
|
|
settings JSONB NOT NULL DEFAULT '{}',
|
|
enable_rss BOOLEAN NOT NULL DEFAULT true,
|
|
enable_search BOOLEAN NOT NULL DEFAULT true,
|
|
priority INT NOT NULL DEFAULT 25
|
|
);
|
|
|
|
CREATE TABLE download_clients (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
name TEXT NOT NULL,
|
|
implementation TEXT NOT NULL,
|
|
settings JSONB NOT NULL DEFAULT '{}',
|
|
protocol TEXT NOT NULL DEFAULT 'torrent',
|
|
priority INT NOT NULL DEFAULT 1,
|
|
enabled BOOLEAN NOT NULL DEFAULT true
|
|
);
|
|
|
|
-- ══════════════════════════════════════════════════════════════
|
|
-- CORE MUSIC ENTITIES
|
|
-- ══════════════════════════════════════════════════════════════
|
|
|
|
CREATE TABLE artist_metadata (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
foreign_artist_id TEXT UNIQUE,
|
|
name TEXT NOT NULL,
|
|
sort_name TEXT,
|
|
disambiguation TEXT,
|
|
artist_type TEXT,
|
|
status TEXT,
|
|
overview TEXT,
|
|
images JSONB NOT NULL DEFAULT '[]',
|
|
links JSONB NOT NULL DEFAULT '[]',
|
|
genres JSONB NOT NULL DEFAULT '[]',
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE TABLE artists (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
metadata_id UUID NOT NULL REFERENCES artist_metadata(id) ON DELETE CASCADE,
|
|
quality_profile_id UUID REFERENCES quality_profiles(id),
|
|
metadata_profile_id UUID REFERENCES metadata_profiles(id),
|
|
root_folder_id UUID REFERENCES root_folders(id),
|
|
path TEXT,
|
|
monitored BOOLEAN NOT NULL DEFAULT true,
|
|
monitor_new_items TEXT NOT NULL DEFAULT 'all',
|
|
last_info_sync TIMESTAMPTZ,
|
|
added_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE TABLE albums (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
artist_metadata_id UUID NOT NULL REFERENCES artist_metadata(id) ON DELETE CASCADE,
|
|
foreign_album_id TEXT UNIQUE,
|
|
title TEXT NOT NULL,
|
|
clean_title TEXT,
|
|
disambiguation TEXT,
|
|
overview TEXT,
|
|
album_type TEXT,
|
|
release_date DATE,
|
|
images JSONB NOT NULL DEFAULT '[]',
|
|
genres JSONB NOT NULL DEFAULT '[]',
|
|
monitored BOOLEAN NOT NULL DEFAULT true,
|
|
added_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE TABLE album_releases (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
album_id UUID NOT NULL REFERENCES albums(id) ON DELETE CASCADE,
|
|
foreign_release_id TEXT UNIQUE,
|
|
title TEXT NOT NULL,
|
|
status TEXT,
|
|
duration_ms INT,
|
|
release_date DATE,
|
|
country TEXT[],
|
|
label TEXT[],
|
|
format TEXT,
|
|
track_count INT,
|
|
monitored BOOLEAN NOT NULL DEFAULT true
|
|
);
|
|
|
|
CREATE TABLE track_files (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
album_id UUID NOT NULL REFERENCES albums(id) ON DELETE CASCADE,
|
|
path TEXT NOT NULL,
|
|
relative_path TEXT NOT NULL,
|
|
size BIGINT NOT NULL DEFAULT 0,
|
|
file_hash TEXT,
|
|
audio_hash TEXT,
|
|
quality JSONB NOT NULL DEFAULT '{}',
|
|
media_info JSONB NOT NULL DEFAULT '{}',
|
|
scene_name TEXT,
|
|
release_group TEXT,
|
|
date_added TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE TABLE tracks (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
album_release_id UUID NOT NULL REFERENCES album_releases(id) ON DELETE CASCADE,
|
|
artist_metadata_id UUID NOT NULL REFERENCES artist_metadata(id) ON DELETE CASCADE,
|
|
track_file_id UUID REFERENCES track_files(id) ON DELETE SET NULL,
|
|
foreign_track_id TEXT UNIQUE,
|
|
title TEXT NOT NULL,
|
|
track_number INT NOT NULL DEFAULT 1,
|
|
disc_number INT NOT NULL DEFAULT 1,
|
|
duration_ms INT,
|
|
explicit BOOLEAN NOT NULL DEFAULT false
|
|
);
|
|
|
|
-- ══════════════════════════════════════════════════════════════
|
|
-- DOWNLOAD TRACKING
|
|
-- ══════════════════════════════════════════════════════════════
|
|
|
|
CREATE TABLE wanted_albums (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
album_id UUID NOT NULL UNIQUE REFERENCES albums(id) ON DELETE CASCADE,
|
|
priority INT NOT NULL DEFAULT 0,
|
|
search_count INT NOT NULL DEFAULT 0,
|
|
last_searched_at TIMESTAMPTZ,
|
|
added_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
CREATE TABLE download_queue (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
artist_id UUID REFERENCES artists(id) ON DELETE SET NULL,
|
|
album_id UUID REFERENCES albums(id) ON DELETE SET NULL,
|
|
download_id TEXT,
|
|
title TEXT NOT NULL,
|
|
size BIGINT NOT NULL DEFAULT 0,
|
|
size_left BIGINT NOT NULL DEFAULT 0,
|
|
status TEXT NOT NULL DEFAULT 'queued',
|
|
progress REAL NOT NULL DEFAULT 0.0,
|
|
error_message TEXT,
|
|
protocol TEXT NOT NULL DEFAULT 'torrent',
|
|
indexer TEXT,
|
|
download_client TEXT,
|
|
torrent_hash TEXT,
|
|
output_path TEXT,
|
|
added_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
completed_at TIMESTAMPTZ
|
|
);
|
|
|
|
CREATE TABLE blocklist (
|
|
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
|
artist_id UUID NOT NULL REFERENCES artists(id) ON DELETE CASCADE,
|
|
album_id UUID REFERENCES albums(id) ON DELETE CASCADE,
|
|
source_title TEXT NOT NULL,
|
|
quality JSONB NOT NULL DEFAULT '{}',
|
|
size BIGINT NOT NULL DEFAULT 0,
|
|
protocol TEXT,
|
|
indexer TEXT,
|
|
message TEXT,
|
|
torrent_hash TEXT,
|
|
date TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
-- ══════════════════════════════════════════════════════════════
|
|
-- INDEXES
|
|
-- ══════════════════════════════════════════════════════════════
|
|
|
|
CREATE INDEX idx_artist_metadata_name ON artist_metadata(name);
|
|
CREATE INDEX idx_artist_metadata_foreign_id ON artist_metadata(foreign_artist_id);
|
|
CREATE INDEX idx_albums_artist ON albums(artist_metadata_id);
|
|
CREATE INDEX idx_albums_foreign_id ON albums(foreign_album_id);
|
|
CREATE INDEX idx_albums_release_date ON albums(release_date);
|
|
CREATE INDEX idx_album_releases_album ON album_releases(album_id);
|
|
CREATE INDEX idx_tracks_release ON tracks(album_release_id);
|
|
CREATE INDEX idx_tracks_artist ON tracks(artist_metadata_id);
|
|
CREATE INDEX idx_track_files_album ON track_files(album_id);
|
|
CREATE INDEX idx_track_files_hash ON track_files(file_hash);
|
|
CREATE INDEX idx_track_files_audio_hash ON track_files(audio_hash);
|
|
CREATE INDEX idx_wanted_albums_priority ON wanted_albums(priority DESC);
|
|
CREATE INDEX idx_download_queue_status ON download_queue(status);
|
|
CREATE INDEX idx_download_queue_album ON download_queue(album_id);
|
|
CREATE INDEX idx_blocklist_artist ON blocklist(artist_id);
|
|
CREATE INDEX idx_blocklist_torrent ON blocklist(torrent_hash);
|
|
|
|
-- ══════════════════════════════════════════════════════════════
|
|
-- DEFAULT DATA
|
|
-- ══════════════════════════════════════════════════════════════
|
|
|
|
INSERT INTO quality_profiles (name, cutoff, items, upgrade_allowed) VALUES
|
|
('Any', 0, '[]', true),
|
|
('Lossless', 1, '[{"quality": "FLAC", "allowed": true}, {"quality": "ALAC", "allowed": true}]', true),
|
|
('Standard', 2, '[{"quality": "MP3-320", "allowed": true}, {"quality": "MP3-VBR-V0", "allowed": true}]', true);
|
|
|
|
INSERT INTO metadata_profiles (name, primary_album_types, secondary_album_types, release_statuses) VALUES
|
|
('Standard', '["Album", "EP"]', '[]', '["Official"]'),
|
|
('All', '["Album", "EP", "Single", "Broadcast", "Other"]', '["Compilation", "Soundtrack", "Spokenword", "Interview", "Audiobook", "Live", "Remix", "DJ-mix", "Mixtape/Street", "Demo"]', '["Official", "Promotional", "Bootleg"]');
|