mirror of
https://github.com/Dvorinka/SpotifyRecAlg.git
synced 2026-06-03 20:13:03 +00:00
first commit
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
"""
|
||||
Migrations module.
|
||||
|
||||
Discovers migration classes from explicitly registered modules and applies
|
||||
pending migrations in deterministic order.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
import inspect
|
||||
import logging
|
||||
import os
|
||||
from types import ModuleType
|
||||
|
||||
from swingmusic.db.metadata import MigrationTable
|
||||
from swingmusic.migrations.base import Migration
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
DEFAULT_MIGRATION_MODULES = [
|
||||
"swingmusic.migrations.production_setup_migration",
|
||||
]
|
||||
|
||||
OPTIONAL_MIGRATION_MODULES = [
|
||||
(
|
||||
"SWINGMUSIC_ENABLE_UPDATE_TRACKING_MIGRATIONS",
|
||||
"swingmusic.migrations.update_tracking_migration",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def get_all_migrations(module: ModuleType) -> list[type[Migration]]:
|
||||
"""
|
||||
Extract all enabled migration classes from a module.
|
||||
"""
|
||||
|
||||
def predicate(obj):
|
||||
return (
|
||||
inspect.isclass(obj)
|
||||
and issubclass(obj, Migration)
|
||||
and obj.enabled
|
||||
and obj is not Migration
|
||||
and obj.__module__ == module.__name__
|
||||
)
|
||||
|
||||
return [obj for _, obj in inspect.getmembers(module, predicate)]
|
||||
|
||||
|
||||
def _load_migration_modules() -> list[ModuleType]:
|
||||
modules: list[ModuleType] = []
|
||||
|
||||
for module_path in DEFAULT_MIGRATION_MODULES:
|
||||
modules.append(importlib.import_module(module_path))
|
||||
|
||||
for flag, module_path in OPTIONAL_MIGRATION_MODULES:
|
||||
enabled = os.getenv(flag, "").strip().lower() in {"1", "true", "yes", "on"}
|
||||
if not enabled:
|
||||
continue
|
||||
|
||||
try:
|
||||
modules.append(importlib.import_module(module_path))
|
||||
except Exception as error:
|
||||
log.exception(
|
||||
"Failed to import optional migration module %s: %s", module_path, error
|
||||
)
|
||||
|
||||
return modules
|
||||
|
||||
|
||||
def apply_migrations():
|
||||
"""
|
||||
Applies pending migrations and records the migration index.
|
||||
"""
|
||||
modules = _load_migration_modules()
|
||||
migrations = [
|
||||
migration for module in modules for migration in get_all_migrations(module)
|
||||
]
|
||||
migrations.sort(key=lambda migration: migration.__name__)
|
||||
|
||||
current_index = MigrationTable.get_version()
|
||||
if current_index < 0:
|
||||
current_index = 0
|
||||
|
||||
if current_index > len(migrations):
|
||||
log.warning(
|
||||
"Migration index %s exceeds known migrations %s. Clamping index.",
|
||||
current_index,
|
||||
len(migrations),
|
||||
)
|
||||
current_index = len(migrations)
|
||||
|
||||
to_apply = migrations[current_index:]
|
||||
for migration in to_apply:
|
||||
migration.migrate()
|
||||
log.info("Applied migration: %s", migration.__name__)
|
||||
|
||||
MigrationTable.set_version(len(migrations))
|
||||
@@ -0,0 +1,13 @@
|
||||
class Migration:
|
||||
"""
|
||||
Base migration class.
|
||||
"""
|
||||
|
||||
enabled: bool = True
|
||||
|
||||
@staticmethod
|
||||
def migrate():
|
||||
"""
|
||||
Code to run when migrating, override this method.
|
||||
"""
|
||||
pass
|
||||
@@ -0,0 +1,130 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
from swingmusic.config import UserConfig
|
||||
from swingmusic.db.libdata import TrackTable
|
||||
from swingmusic.db.production import (
|
||||
LyricsStatusTable,
|
||||
SetupStateTable,
|
||||
TrackedPlaylistTable,
|
||||
UserRootDirOwnershipTable,
|
||||
)
|
||||
from swingmusic.db.userdata import UserTable
|
||||
from swingmusic.migrations.base import Migration
|
||||
from swingmusic.services.library_projection import get_owner_user, sync_owner_projection
|
||||
|
||||
|
||||
class Migration001EnsureSetupState(Migration):
|
||||
@staticmethod
|
||||
def migrate():
|
||||
SetupStateTable.ensure_singleton()
|
||||
|
||||
|
||||
class Migration002SyncOwnerProjection(Migration):
|
||||
@staticmethod
|
||||
def migrate():
|
||||
owner = get_owner_user()
|
||||
if not owner:
|
||||
return
|
||||
sync_owner_projection(owner.id)
|
||||
|
||||
|
||||
class Migration003BackfillLyricsStatus(Migration):
|
||||
@staticmethod
|
||||
def migrate():
|
||||
for track in TrackTable.get_all():
|
||||
filepath = track.filepath
|
||||
if not filepath:
|
||||
continue
|
||||
|
||||
track_path = Path(filepath)
|
||||
has_lrc = (
|
||||
track_path.with_suffix(".lrc").exists()
|
||||
or track_path.with_suffix(".elrc").exists()
|
||||
)
|
||||
has_embedded = bool((track.extra or {}).get("lyrics"))
|
||||
|
||||
if has_embedded:
|
||||
status = "embedded"
|
||||
source = "tags"
|
||||
elif has_lrc:
|
||||
status = "lrc"
|
||||
source = "lrc"
|
||||
else:
|
||||
status = "missing"
|
||||
source = None
|
||||
|
||||
LyricsStatusTable.upsert(
|
||||
trackhash=track.trackhash,
|
||||
filepath=filepath,
|
||||
status=status,
|
||||
source=source,
|
||||
has_embedded=has_embedded,
|
||||
has_lrc=has_lrc,
|
||||
last_error=None,
|
||||
extra={"migration": "backfill"},
|
||||
increment_attempt=False,
|
||||
)
|
||||
|
||||
|
||||
class Migration004BackfillUserRootOwnership(Migration):
|
||||
@staticmethod
|
||||
def migrate():
|
||||
config_roots = UserConfig().rootDirs or []
|
||||
if config_roots:
|
||||
primary_root = config_roots[0]
|
||||
if primary_root == "$home":
|
||||
base_root = os.path.join(os.path.expanduser("~"), "Music")
|
||||
else:
|
||||
base_root = os.path.expanduser(primary_root)
|
||||
else:
|
||||
base_root = os.path.join(os.path.expanduser("~"), "Music")
|
||||
|
||||
for user in UserTable.get_all():
|
||||
if UserRootDirOwnershipTable.get_paths(user.id):
|
||||
continue
|
||||
|
||||
if "owner" in user.roles or "admin" in user.roles:
|
||||
UserRootDirOwnershipTable.assign_paths(user.id, config_roots)
|
||||
continue
|
||||
|
||||
safe_username = (
|
||||
re.sub(r"[^\w\-. ]", "", user.username or "").strip()
|
||||
or f"user-{user.id}"
|
||||
)
|
||||
user_root = os.path.join(base_root, "SwingMusic Users", safe_username)
|
||||
os.makedirs(user_root, exist_ok=True)
|
||||
UserRootDirOwnershipTable.assign_paths(user.id, [user_root])
|
||||
|
||||
|
||||
class Migration005NormalizeTrackedPlaylists(Migration):
|
||||
@staticmethod
|
||||
def migrate():
|
||||
now = int(time.time())
|
||||
for row in TrackedPlaylistTable.all().scalars():
|
||||
interval = max(120, int(row.sync_interval_seconds or 900))
|
||||
update_payload = {}
|
||||
|
||||
if int(row.sync_interval_seconds or 0) != interval:
|
||||
update_payload["sync_interval_seconds"] = interval
|
||||
|
||||
if not row.next_sync_at:
|
||||
update_payload["next_sync_at"] = int(
|
||||
row.updated_at or row.created_at or now
|
||||
)
|
||||
|
||||
if row.status not in {"active", "syncing", "failed", "paused", "deleted"}:
|
||||
update_payload["status"] = "active"
|
||||
|
||||
if row.snapshot_track_ids is None:
|
||||
update_payload["snapshot_track_ids"] = []
|
||||
|
||||
if row.last_result is None:
|
||||
update_payload["last_result"] = {}
|
||||
|
||||
if update_payload:
|
||||
TrackedPlaylistTable.update_row(row.id, update_payload)
|
||||
@@ -0,0 +1,344 @@
|
||||
"""
|
||||
Migration for Update Tracking System Tables
|
||||
|
||||
This migration creates all the necessary tables for the artist update
|
||||
tracking system, including follows, releases, notifications, and preferences.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from swingmusic.db import db
|
||||
from swingmusic.migrations.base import Migration
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Migration001UpdateTracking(Migration):
|
||||
"""
|
||||
Create tables for the update tracking system
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def migrate():
|
||||
"""
|
||||
Create all update tracking tables
|
||||
"""
|
||||
logger.info("Starting update tracking migration")
|
||||
|
||||
try:
|
||||
# Create artist_follows table
|
||||
logger.info("Creating artist_follows table")
|
||||
db.session.execute("""
|
||||
CREATE TABLE IF NOT EXISTS artist_follows (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL,
|
||||
artist_id TEXT NOT NULL UNIQUE,
|
||||
artist_name TEXT NOT NULL,
|
||||
follow_level TEXT NOT NULL DEFAULT 'followed',
|
||||
auto_download_new_releases BOOLEAN DEFAULT FALSE,
|
||||
preferred_quality TEXT DEFAULT 'flac',
|
||||
notification_preferences TEXT DEFAULT '{}',
|
||||
follow_date DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
last_check_date DATETIME NULL,
|
||||
FOREIGN KEY (user_id) REFERENCES users (id)
|
||||
)
|
||||
""")
|
||||
|
||||
# Create release_updates table
|
||||
logger.info("Creating release_updates table")
|
||||
db.session.execute("""
|
||||
CREATE TABLE IF NOT EXISTS release_updates (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
release_id TEXT NOT NULL UNIQUE,
|
||||
artist_id TEXT NOT NULL,
|
||||
artist_name TEXT NOT NULL,
|
||||
release_title TEXT NOT NULL,
|
||||
release_type TEXT NOT NULL,
|
||||
release_date DATE NOT NULL,
|
||||
spotify_url TEXT NOT NULL,
|
||||
cover_image_url TEXT NULL,
|
||||
total_tracks INTEGER NOT NULL,
|
||||
popularity INTEGER DEFAULT 0,
|
||||
explicit BOOLEAN DEFAULT FALSE,
|
||||
discovered_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
processed_at DATETIME NULL,
|
||||
download_status TEXT DEFAULT 'pending',
|
||||
auto_downloaded BOOLEAN DEFAULT FALSE,
|
||||
notification_sent BOOLEAN DEFAULT FALSE
|
||||
)
|
||||
""")
|
||||
|
||||
# Create update_notifications table
|
||||
logger.info("Creating update_notifications table")
|
||||
db.session.execute("""
|
||||
CREATE TABLE IF NOT EXISTS update_notifications (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL,
|
||||
release_id TEXT NOT NULL,
|
||||
notification_type TEXT NOT NULL,
|
||||
sent_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
opened_at DATETIME NULL,
|
||||
action_taken TEXT NULL,
|
||||
FOREIGN KEY (user_id) REFERENCES users (id),
|
||||
FOREIGN KEY (release_id) REFERENCES release_updates (release_id)
|
||||
)
|
||||
""")
|
||||
|
||||
# Create update_monitoring_preferences table
|
||||
logger.info("Creating update_monitoring_preferences table")
|
||||
db.session.execute("""
|
||||
CREATE TABLE IF NOT EXISTS update_monitoring_preferences (
|
||||
user_id INTEGER PRIMARY KEY,
|
||||
enable_artist_monitoring BOOLEAN DEFAULT TRUE,
|
||||
check_frequency TEXT DEFAULT 'daily',
|
||||
auto_download_favorites BOOLEAN DEFAULT FALSE,
|
||||
auto_download_followed BOOLEAN DEFAULT FALSE,
|
||||
max_auto_downloads_per_week INTEGER DEFAULT 5,
|
||||
quality_preference TEXT DEFAULT 'flac',
|
||||
storage_limit_mb INTEGER DEFAULT 10240,
|
||||
notification_channels TEXT DEFAULT '{}',
|
||||
exclude_explicit BOOLEAN DEFAULT FALSE,
|
||||
preferred_release_types TEXT DEFAULT '["album", "ep", "single"]',
|
||||
FOREIGN KEY (user_id) REFERENCES users (id)
|
||||
)
|
||||
""")
|
||||
|
||||
# Create download_tasks table
|
||||
logger.info("Creating download_tasks table")
|
||||
db.session.execute("""
|
||||
CREATE TABLE IF NOT EXISTS download_tasks (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
release_id TEXT NOT NULL,
|
||||
track_id TEXT NOT NULL,
|
||||
track_title TEXT NOT NULL,
|
||||
artist_name TEXT NOT NULL,
|
||||
album_name TEXT NOT NULL,
|
||||
spotify_url TEXT NOT NULL,
|
||||
quality_preference TEXT DEFAULT 'flac',
|
||||
status TEXT DEFAULT 'pending',
|
||||
priority TEXT DEFAULT 'normal',
|
||||
progress INTEGER DEFAULT 0,
|
||||
file_path TEXT NULL,
|
||||
error_message TEXT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
started_at DATETIME NULL,
|
||||
completed_at DATETIME NULL,
|
||||
auto_downloaded BOOLEAN DEFAULT FALSE,
|
||||
added_to_library BOOLEAN DEFAULT FALSE,
|
||||
FOREIGN KEY (release_id) REFERENCES release_updates (release_id)
|
||||
)
|
||||
""")
|
||||
|
||||
# Create artist_follow_history table
|
||||
logger.info("Creating artist_follow_history table")
|
||||
db.session.execute("""
|
||||
CREATE TABLE IF NOT EXISTS artist_follow_history (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL,
|
||||
artist_id TEXT NOT NULL,
|
||||
artist_name TEXT NOT NULL,
|
||||
action TEXT NOT NULL,
|
||||
old_level TEXT NULL,
|
||||
new_level TEXT NULL,
|
||||
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (user_id) REFERENCES users (id)
|
||||
)
|
||||
""")
|
||||
|
||||
# Create release_update_history table
|
||||
logger.info("Creating release_update_history table")
|
||||
db.session.execute("""
|
||||
CREATE TABLE IF NOT EXISTS release_update_history (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
release_id TEXT NOT NULL,
|
||||
artist_id TEXT NOT NULL,
|
||||
artist_name TEXT NOT NULL,
|
||||
release_title TEXT NOT NULL,
|
||||
release_type TEXT NOT NULL,
|
||||
action TEXT NOT NULL,
|
||||
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
metadata TEXT NULL
|
||||
)
|
||||
""")
|
||||
|
||||
# Create update_tracking_stats table
|
||||
logger.info("Creating update_tracking_stats table")
|
||||
db.session.execute("""
|
||||
CREATE TABLE IF NOT EXISTS update_tracking_stats (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL,
|
||||
stat_date DATE NOT NULL,
|
||||
total_followed_artists INTEGER DEFAULT 0,
|
||||
new_releases_discovered INTEGER DEFAULT 0,
|
||||
auto_downloads_completed INTEGER DEFAULT 0,
|
||||
manual_downloads_completed INTEGER DEFAULT 0,
|
||||
notifications_sent INTEGER DEFAULT 0,
|
||||
notifications_opened INTEGER DEFAULT 0,
|
||||
storage_used_mb INTEGER DEFAULT 0,
|
||||
FOREIGN KEY (user_id) REFERENCES users (id),
|
||||
UNIQUE(user_id, stat_date)
|
||||
)
|
||||
""")
|
||||
|
||||
# Create indexes for better performance
|
||||
logger.info("Creating indexes")
|
||||
|
||||
# Indexes for artist_follows
|
||||
db.session.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_artist_follows_user_id ON artist_follows(user_id)
|
||||
""")
|
||||
db.session.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_artist_follows_artist_id ON artist_follows(artist_id)
|
||||
""")
|
||||
|
||||
# Indexes for release_updates
|
||||
db.session.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_release_updates_artist_id ON release_updates(artist_id)
|
||||
""")
|
||||
db.session.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_release_updates_release_date ON release_updates(release_date)
|
||||
""")
|
||||
db.session.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_release_updates_discovered_at ON release_updates(discovered_at)
|
||||
""")
|
||||
|
||||
# Indexes for update_notifications
|
||||
db.session.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_update_notifications_user_id ON update_notifications(user_id)
|
||||
""")
|
||||
db.session.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_update_notifications_release_id ON update_notifications(release_id)
|
||||
""")
|
||||
db.session.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_update_notifications_sent_at ON update_notifications(sent_at)
|
||||
""")
|
||||
|
||||
# Indexes for download_tasks
|
||||
db.session.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_download_tasks_release_id ON download_tasks(release_id)
|
||||
""")
|
||||
db.session.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_download_tasks_status ON download_tasks(status)
|
||||
""")
|
||||
db.session.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_download_tasks_priority ON download_tasks(priority)
|
||||
""")
|
||||
db.session.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_download_tasks_created_at ON download_tasks(created_at)
|
||||
""")
|
||||
|
||||
# Indexes for history tables
|
||||
db.session.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_artist_follow_history_user_id ON artist_follow_history(user_id)
|
||||
""")
|
||||
db.session.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_artist_follow_history_timestamp ON artist_follow_history(timestamp)
|
||||
""")
|
||||
db.session.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_release_update_history_release_id ON release_update_history(release_id)
|
||||
""")
|
||||
db.session.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_release_update_history_timestamp ON release_update_history(timestamp)
|
||||
""")
|
||||
|
||||
# Indexes for stats
|
||||
db.session.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_update_tracking_stats_user_id ON update_tracking_stats(user_id)
|
||||
""")
|
||||
db.session.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_update_tracking_stats_stat_date ON update_tracking_stats(stat_date)
|
||||
""")
|
||||
|
||||
# Commit the transaction
|
||||
db.session.commit()
|
||||
logger.info("Update tracking migration completed successfully")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error during update tracking migration: {e}")
|
||||
db.session.rollback()
|
||||
raise
|
||||
|
||||
|
||||
class Migration002UpdateTrackingTriggers(Migration):
|
||||
"""
|
||||
Create triggers for update tracking system
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def migrate():
|
||||
"""
|
||||
Create triggers for automatic history tracking
|
||||
"""
|
||||
logger.info("Creating update tracking triggers")
|
||||
|
||||
try:
|
||||
# Trigger for artist follow history
|
||||
db.session.execute("""
|
||||
CREATE TRIGGER IF NOT EXISTS artist_follow_history_insert
|
||||
AFTER INSERT ON artist_follows
|
||||
BEGIN
|
||||
INSERT INTO artist_follow_history
|
||||
(user_id, artist_id, artist_name, action, new_level, timestamp)
|
||||
VALUES
|
||||
(NEW.user_id, NEW.artist_id, NEW.artist_name, 'follow', NEW.follow_level, CURRENT_TIMESTAMP);
|
||||
END
|
||||
""")
|
||||
|
||||
# Trigger for artist unfollow history
|
||||
db.session.execute("""
|
||||
CREATE TRIGGER IF NOT EXISTS artist_follow_history_delete
|
||||
AFTER DELETE ON artist_follows
|
||||
BEGIN
|
||||
INSERT INTO artist_follow_history
|
||||
(user_id, artist_id, artist_name, action, old_level, timestamp)
|
||||
VALUES
|
||||
(OLD.user_id, OLD.artist_id, OLD.artist_name, 'unfollow', OLD.follow_level, CURRENT_TIMESTAMP);
|
||||
END
|
||||
""")
|
||||
|
||||
# Trigger for artist follow level change
|
||||
db.session.execute("""
|
||||
CREATE TRIGGER IF NOT EXISTS artist_follow_history_update
|
||||
AFTER UPDATE ON artist_follows
|
||||
WHEN OLD.follow_level != NEW.follow_level
|
||||
BEGIN
|
||||
INSERT INTO artist_follow_history
|
||||
(user_id, artist_id, artist_name, action, old_level, new_level, timestamp)
|
||||
VALUES
|
||||
(NEW.user_id, NEW.artist_id, NEW.artist_name, 'level_change', OLD.follow_level, NEW.follow_level, CURRENT_TIMESTAMP);
|
||||
END
|
||||
""")
|
||||
|
||||
# Trigger for release update discovery
|
||||
db.session.execute("""
|
||||
CREATE TRIGGER IF NOT EXISTS release_update_discovered
|
||||
AFTER INSERT ON release_updates
|
||||
BEGIN
|
||||
INSERT INTO release_update_history
|
||||
(release_id, artist_id, artist_name, release_title, release_type, action, timestamp)
|
||||
VALUES
|
||||
(NEW.release_id, NEW.artist_id, NEW.artist_name, NEW.release_title, NEW.release_type, 'discovered', CURRENT_TIMESTAMP);
|
||||
END
|
||||
""")
|
||||
|
||||
# Trigger for release update download completion
|
||||
db.session.execute("""
|
||||
CREATE TRIGGER IF NOT EXISTS release_update_downloaded
|
||||
AFTER UPDATE ON release_updates
|
||||
WHEN OLD.download_status != 'completed' AND NEW.download_status = 'completed'
|
||||
BEGIN
|
||||
INSERT INTO release_update_history
|
||||
(release_id, artist_id, artist_name, release_title, release_type, action, timestamp, metadata)
|
||||
VALUES
|
||||
(NEW.release_id, NEW.artist_id, NEW.artist_name, NEW.release_title, NEW.release_type, 'downloaded', CURRENT_TIMESTAMP,
|
||||
json_object('auto_downloaded', NEW.auto_downloaded));
|
||||
END
|
||||
""")
|
||||
|
||||
db.session.commit()
|
||||
logger.info("Update tracking triggers created successfully")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating update tracking triggers: {e}")
|
||||
db.session.rollback()
|
||||
raise
|
||||
Reference in New Issue
Block a user