This commit is contained in:
+19
-4
@@ -60,8 +60,17 @@ class NFOGuardConfig:
|
|||||||
self.max_concurrent = self._get_int_env("MAX_CONCURRENT_SERIES", 3, 1, 10)
|
self.max_concurrent = self._get_int_env("MAX_CONCURRENT_SERIES", 3, 1, 10)
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
|
self.db_type = os.environ.get("DB_TYPE", "sqlite").lower()
|
||||||
self.db_path = Path(os.environ.get("DB_PATH", "/app/data/media_dates.db"))
|
self.db_path = Path(os.environ.get("DB_PATH", "/app/data/media_dates.db"))
|
||||||
|
|
||||||
|
# PostgreSQL database settings
|
||||||
|
if self.db_type == "postgresql":
|
||||||
|
self.db_host = os.environ.get("DB_HOST", "localhost")
|
||||||
|
self.db_port = self._get_int_env("DB_PORT", 5432, 1, 65535)
|
||||||
|
self.db_name = os.environ.get("DB_NAME", "nfoguard")
|
||||||
|
self.db_user = os.environ.get("DB_USER", "nfoguard")
|
||||||
|
self.db_password = os.environ.get("DB_PASSWORD", "")
|
||||||
|
|
||||||
# External connections
|
# External connections
|
||||||
self._load_external_connections()
|
self._load_external_connections()
|
||||||
|
|
||||||
@@ -222,15 +231,21 @@ class NFOGuardConfig:
|
|||||||
return {
|
return {
|
||||||
"tv_paths": [str(p) for p in self.tv_paths],
|
"tv_paths": [str(p) for p in self.tv_paths],
|
||||||
"movie_paths": [str(p) for p in self.movie_paths],
|
"movie_paths": [str(p) for p in self.movie_paths],
|
||||||
"database_path": str(self.db_path),
|
"database": {
|
||||||
|
"type": self.db_type,
|
||||||
|
"path": str(self.db_path) if self.db_type == "sqlite" else None,
|
||||||
|
"host": getattr(self, 'db_host', None) if self.db_type == "postgresql" else None,
|
||||||
|
"port": getattr(self, 'db_port', None) if self.db_type == "postgresql" else None,
|
||||||
|
"name": getattr(self, 'db_name', None) if self.db_type == "postgresql" else None
|
||||||
|
},
|
||||||
"external_apis": {
|
"external_apis": {
|
||||||
"radarr": bool(self.radarr_url),
|
"radarr": bool(self.radarr_url),
|
||||||
"sonarr": bool(self.sonarr_url),
|
"sonarr": bool(self.sonarr_url),
|
||||||
"jellyseerr": bool(self.jellyseerr_url)
|
"jellyseerr": bool(self.jellyseerr_url)
|
||||||
},
|
},
|
||||||
"database_connection": {
|
"radarr_database": {
|
||||||
"type": self.db_type,
|
"type": getattr(self, 'radarr_db_type', None),
|
||||||
"configured": bool(self.db_type and self.db_host)
|
"configured": bool(getattr(self, 'radarr_db_type', None) and getattr(self, 'radarr_db_host', None))
|
||||||
},
|
},
|
||||||
"performance": {
|
"performance": {
|
||||||
"batch_delay": self.batch_delay,
|
"batch_delay": self.batch_delay,
|
||||||
|
|||||||
+214
-27
@@ -1,28 +1,76 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Database management for NFOGuard
|
Database management for NFOGuard
|
||||||
Handles SQLite database operations for tracking media dates and processing history
|
Handles SQLite and PostgreSQL database operations for tracking media dates and processing history
|
||||||
"""
|
"""
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import json
|
import json
|
||||||
import threading
|
import threading
|
||||||
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Optional, Dict, List, Any
|
from typing import Optional, Dict, List, Any, Union
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
|
||||||
class NFOGuardDatabase:
|
try:
|
||||||
"""Manages NFOGuard SQLite database operations"""
|
import psycopg2
|
||||||
|
import psycopg2.extras
|
||||||
|
POSTGRESQL_AVAILABLE = True
|
||||||
|
except ImportError:
|
||||||
|
psycopg2 = None
|
||||||
|
POSTGRESQL_AVAILABLE = False
|
||||||
|
|
||||||
def __init__(self, db_path: Path):
|
class NFOGuardDatabase:
|
||||||
self.db_path = Path(db_path)
|
"""Manages NFOGuard database operations for both SQLite and PostgreSQL"""
|
||||||
|
|
||||||
|
def __init__(self, config=None, db_path: Optional[Path] = None):
|
||||||
|
"""
|
||||||
|
Initialize database connection
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config: Configuration object with database settings
|
||||||
|
db_path: Path for SQLite database (backward compatibility)
|
||||||
|
"""
|
||||||
|
if config:
|
||||||
|
self.db_type = config.db_type
|
||||||
|
if self.db_type == "postgresql":
|
||||||
|
if not POSTGRESQL_AVAILABLE:
|
||||||
|
raise ImportError("psycopg2 is required for PostgreSQL support")
|
||||||
|
self.db_host = config.db_host
|
||||||
|
self.db_port = config.db_port
|
||||||
|
self.db_name = config.db_name
|
||||||
|
self.db_user = config.db_user
|
||||||
|
self.db_password = config.db_password
|
||||||
|
else:
|
||||||
|
self.db_path = Path(config.db_path)
|
||||||
self.db_path.parent.mkdir(parents=True, exist_ok=True)
|
self.db_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
else:
|
||||||
|
# Backward compatibility
|
||||||
|
self.db_type = "sqlite"
|
||||||
|
self.db_path = Path(db_path) if db_path else Path("/app/data/media_dates.db")
|
||||||
|
self.db_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
self._local = threading.local()
|
self._local = threading.local()
|
||||||
self._init_database()
|
self._init_database()
|
||||||
|
|
||||||
def _get_connection(self) -> sqlite3.Connection:
|
def _get_placeholder(self) -> str:
|
||||||
|
"""Get the correct parameter placeholder for this database type"""
|
||||||
|
return "%s" if self.db_type == "postgresql" else "?"
|
||||||
|
|
||||||
|
def _get_connection(self) -> Union[sqlite3.Connection, 'psycopg2.extensions.connection']:
|
||||||
"""Get thread-local database connection"""
|
"""Get thread-local database connection"""
|
||||||
if not hasattr(self._local, 'connection'):
|
if not hasattr(self._local, 'connection'):
|
||||||
|
if self.db_type == "postgresql":
|
||||||
|
self._local.connection = psycopg2.connect(
|
||||||
|
host=self.db_host,
|
||||||
|
port=self.db_port,
|
||||||
|
database=self.db_name,
|
||||||
|
user=self.db_user,
|
||||||
|
password=self.db_password,
|
||||||
|
cursor_factory=psycopg2.extras.RealDictCursor
|
||||||
|
)
|
||||||
|
self._local.connection.autocommit = True
|
||||||
|
else:
|
||||||
self._local.connection = sqlite3.connect(
|
self._local.connection = sqlite3.connect(
|
||||||
self.db_path,
|
self.db_path,
|
||||||
check_same_thread=False,
|
check_same_thread=False,
|
||||||
@@ -37,9 +85,11 @@ class NFOGuardDatabase:
|
|||||||
conn = self._get_connection()
|
conn = self._get_connection()
|
||||||
try:
|
try:
|
||||||
yield conn
|
yield conn
|
||||||
conn.commit()
|
if self.db_type == "sqlite":
|
||||||
|
conn.commit() # PostgreSQL uses autocommit
|
||||||
except Exception:
|
except Exception:
|
||||||
conn.rollback()
|
if self.db_type == "sqlite":
|
||||||
|
conn.rollback() # PostgreSQL uses autocommit
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def _init_database(self):
|
def _init_database(self):
|
||||||
@@ -47,6 +97,73 @@ class NFOGuardDatabase:
|
|||||||
with self.get_connection() as conn:
|
with self.get_connection() as conn:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
if self.db_type == "postgresql":
|
||||||
|
self._init_postgresql_tables(cursor)
|
||||||
|
else:
|
||||||
|
self._init_sqlite_tables(cursor)
|
||||||
|
|
||||||
|
print(f"✅ Database initialized: {self.db_type.upper()}")
|
||||||
|
|
||||||
|
def _init_postgresql_tables(self, cursor):
|
||||||
|
"""Initialize PostgreSQL tables"""
|
||||||
|
# Series table
|
||||||
|
cursor.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS series (
|
||||||
|
imdb_id VARCHAR(20) PRIMARY KEY,
|
||||||
|
path TEXT NOT NULL,
|
||||||
|
last_updated TIMESTAMP NOT NULL,
|
||||||
|
metadata JSONB
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
# Episodes table
|
||||||
|
cursor.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS episodes (
|
||||||
|
imdb_id VARCHAR(20) NOT NULL,
|
||||||
|
season INTEGER NOT NULL,
|
||||||
|
episode INTEGER NOT NULL,
|
||||||
|
aired DATE,
|
||||||
|
dateadded TIMESTAMP,
|
||||||
|
source VARCHAR(100),
|
||||||
|
last_updated TIMESTAMP NOT NULL,
|
||||||
|
PRIMARY KEY (imdb_id, season, episode),
|
||||||
|
FOREIGN KEY (imdb_id) REFERENCES series(imdb_id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
# Movies table
|
||||||
|
cursor.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS movies (
|
||||||
|
imdb_id VARCHAR(20) PRIMARY KEY,
|
||||||
|
path TEXT NOT NULL,
|
||||||
|
released DATE,
|
||||||
|
dateadded TIMESTAMP,
|
||||||
|
source VARCHAR(100),
|
||||||
|
last_updated TIMESTAMP NOT NULL,
|
||||||
|
has_video_file INTEGER DEFAULT 0
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
# Processing history table
|
||||||
|
cursor.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS processing_history (
|
||||||
|
id SERIAL PRIMARY KEY,
|
||||||
|
imdb_id VARCHAR(20) NOT NULL,
|
||||||
|
media_type VARCHAR(20) NOT NULL,
|
||||||
|
event_type VARCHAR(50) NOT NULL,
|
||||||
|
processed_at TIMESTAMP NOT NULL,
|
||||||
|
details TEXT
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
|
# Create indexes for PostgreSQL
|
||||||
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_episodes_imdb ON episodes(imdb_id)")
|
||||||
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_episodes_video ON episodes(has_video_file)")
|
||||||
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_movies_video ON movies(has_video_file)")
|
||||||
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_history_imdb ON processing_history(imdb_id)")
|
||||||
|
|
||||||
|
def _init_sqlite_tables(self, cursor):
|
||||||
|
"""Initialize SQLite tables"""
|
||||||
# Series table
|
# Series table
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
CREATE TABLE IF NOT EXISTS series (
|
CREATE TABLE IF NOT EXISTS series (
|
||||||
@@ -67,6 +184,7 @@ class NFOGuardDatabase:
|
|||||||
dateadded TEXT,
|
dateadded TEXT,
|
||||||
source TEXT,
|
source TEXT,
|
||||||
last_updated TEXT NOT NULL,
|
last_updated TEXT NOT NULL,
|
||||||
|
has_video_file BOOLEAN DEFAULT FALSE,
|
||||||
PRIMARY KEY (imdb_id, season, episode),
|
PRIMARY KEY (imdb_id, season, episode),
|
||||||
FOREIGN KEY (imdb_id) REFERENCES series(imdb_id)
|
FOREIGN KEY (imdb_id) REFERENCES series(imdb_id)
|
||||||
)
|
)
|
||||||
@@ -80,7 +198,8 @@ class NFOGuardDatabase:
|
|||||||
released TEXT,
|
released TEXT,
|
||||||
dateadded TEXT,
|
dateadded TEXT,
|
||||||
source TEXT,
|
source TEXT,
|
||||||
last_updated TEXT NOT NULL
|
last_updated TEXT NOT NULL,
|
||||||
|
has_video_file BOOLEAN DEFAULT FALSE
|
||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
@@ -96,7 +215,17 @@ class NFOGuardDatabase:
|
|||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
# Add missing columns if they don't exist (migration)
|
# Handle SQLite migrations for existing databases
|
||||||
|
self._handle_sqlite_migrations(cursor)
|
||||||
|
|
||||||
|
# Create indexes for SQLite
|
||||||
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_episodes_imdb ON episodes(imdb_id)")
|
||||||
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_episodes_video ON episodes(has_video_file)")
|
||||||
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_movies_video ON movies(has_video_file)")
|
||||||
|
cursor.execute("CREATE INDEX IF NOT EXISTS idx_history_imdb ON processing_history(imdb_id)")
|
||||||
|
|
||||||
|
def _handle_sqlite_migrations(self, cursor):
|
||||||
|
"""Handle SQLite database migrations for existing databases"""
|
||||||
# Check current schema and add missing columns
|
# Check current schema and add missing columns
|
||||||
cursor.execute("PRAGMA table_info(movies)")
|
cursor.execute("PRAGMA table_info(movies)")
|
||||||
movie_columns = [row[1] for row in cursor.fetchall()]
|
movie_columns = [row[1] for row in cursor.fetchall()]
|
||||||
@@ -124,20 +253,26 @@ class NFOGuardDatabase:
|
|||||||
cursor.execute("ALTER TABLE episodes ADD COLUMN last_updated TEXT")
|
cursor.execute("ALTER TABLE episodes ADD COLUMN last_updated TEXT")
|
||||||
cursor.execute("UPDATE episodes SET last_updated = datetime('now') WHERE last_updated IS NULL")
|
cursor.execute("UPDATE episodes SET last_updated = datetime('now') WHERE last_updated IS NULL")
|
||||||
|
|
||||||
# Create indexes
|
|
||||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_episodes_imdb ON episodes(imdb_id)")
|
|
||||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_episodes_video ON episodes(has_video_file)")
|
|
||||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_movies_video ON movies(has_video_file)")
|
|
||||||
cursor.execute("CREATE INDEX IF NOT EXISTS idx_history_imdb ON processing_history(imdb_id)")
|
|
||||||
|
|
||||||
def upsert_series(self, imdb_id: str, path: str, metadata: Optional[Dict] = None):
|
def upsert_series(self, imdb_id: str, path: str, metadata: Optional[Dict] = None):
|
||||||
"""Insert or update series record"""
|
"""Insert or update series record"""
|
||||||
with self.get_connection() as conn:
|
with self.get_connection() as conn:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
timestamp = datetime.utcnow()
|
||||||
|
|
||||||
|
if self.db_type == "postgresql":
|
||||||
|
cursor.execute("""
|
||||||
|
INSERT INTO series (imdb_id, path, last_updated, metadata)
|
||||||
|
VALUES (%s, %s, %s, %s)
|
||||||
|
ON CONFLICT (imdb_id) DO UPDATE SET
|
||||||
|
path = EXCLUDED.path,
|
||||||
|
last_updated = EXCLUDED.last_updated,
|
||||||
|
metadata = EXCLUDED.metadata
|
||||||
|
""", (imdb_id, path, timestamp, json.dumps(metadata) if metadata else None))
|
||||||
|
else:
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
INSERT OR REPLACE INTO series (imdb_id, path, last_updated, metadata)
|
INSERT OR REPLACE INTO series (imdb_id, path, last_updated, metadata)
|
||||||
VALUES (?, ?, ?, ?)
|
VALUES (?, ?, ?, ?)
|
||||||
""", (imdb_id, path, datetime.utcnow().isoformat(), json.dumps(metadata) if metadata else None))
|
""", (imdb_id, path, timestamp.isoformat(), json.dumps(metadata) if metadata else None))
|
||||||
|
|
||||||
def upsert_episode_date(self, imdb_id: str, season: int, episode: int,
|
def upsert_episode_date(self, imdb_id: str, season: int, episode: int,
|
||||||
aired: Optional[str], dateadded: Optional[str],
|
aired: Optional[str], dateadded: Optional[str],
|
||||||
@@ -145,28 +280,54 @@ class NFOGuardDatabase:
|
|||||||
"""Insert or update episode date record"""
|
"""Insert or update episode date record"""
|
||||||
with self.get_connection() as conn:
|
with self.get_connection() as conn:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
timestamp = datetime.utcnow()
|
||||||
|
|
||||||
|
if self.db_type == "postgresql":
|
||||||
|
cursor.execute("""
|
||||||
|
INSERT INTO episodes
|
||||||
|
(imdb_id, season, episode, aired, dateadded, source, has_video_file, last_updated)
|
||||||
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
|
ON CONFLICT (imdb_id, season, episode) DO UPDATE SET
|
||||||
|
aired = EXCLUDED.aired,
|
||||||
|
dateadded = EXCLUDED.dateadded,
|
||||||
|
source = EXCLUDED.source,
|
||||||
|
has_video_file = EXCLUDED.has_video_file,
|
||||||
|
last_updated = EXCLUDED.last_updated
|
||||||
|
""", (imdb_id, season, episode, aired, dateadded, source, has_video_file, timestamp))
|
||||||
|
else:
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
INSERT OR REPLACE INTO episodes
|
INSERT OR REPLACE INTO episodes
|
||||||
(imdb_id, season, episode, aired, dateadded, source, has_video_file, last_updated)
|
(imdb_id, season, episode, aired, dateadded, source, has_video_file, last_updated)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
""", (imdb_id, season, episode, aired, dateadded, source, has_video_file, datetime.utcnow().isoformat()))
|
""", (imdb_id, season, episode, aired, dateadded, source, has_video_file, timestamp.isoformat()))
|
||||||
|
|
||||||
def upsert_movie(self, imdb_id: str, path: str):
|
def upsert_movie(self, imdb_id: str, path: str):
|
||||||
"""Insert or update movie record"""
|
"""Insert or update movie record"""
|
||||||
with self.get_connection() as conn:
|
with self.get_connection() as conn:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
timestamp = datetime.utcnow()
|
||||||
|
|
||||||
|
if self.db_type == "postgresql":
|
||||||
|
cursor.execute("""
|
||||||
|
INSERT INTO movies (imdb_id, path, last_updated)
|
||||||
|
VALUES (%s, %s, %s)
|
||||||
|
ON CONFLICT (imdb_id) DO UPDATE SET
|
||||||
|
path = EXCLUDED.path,
|
||||||
|
last_updated = EXCLUDED.last_updated
|
||||||
|
""", (imdb_id, path, timestamp))
|
||||||
|
else:
|
||||||
try:
|
try:
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
INSERT OR REPLACE INTO movies (imdb_id, path, last_updated)
|
INSERT OR REPLACE INTO movies (imdb_id, path, last_updated)
|
||||||
VALUES (?, ?, ?)
|
VALUES (?, ?, ?)
|
||||||
""", (imdb_id, path, datetime.utcnow().isoformat()))
|
""", (imdb_id, path, timestamp.isoformat()))
|
||||||
except sqlite3.OperationalError as e:
|
except sqlite3.OperationalError as e:
|
||||||
if "no column named path" in str(e):
|
if "no column named path" in str(e):
|
||||||
# Fallback for databases without path column - just insert imdb_id
|
# Fallback for databases without path column - just insert imdb_id
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
INSERT OR REPLACE INTO movies (imdb_id, last_updated)
|
INSERT OR REPLACE INTO movies (imdb_id, last_updated)
|
||||||
VALUES (?, ?)
|
VALUES (?, ?)
|
||||||
""", (imdb_id, datetime.utcnow().isoformat()))
|
""", (imdb_id, timestamp.isoformat()))
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@@ -176,7 +337,25 @@ class NFOGuardDatabase:
|
|||||||
print(f"🔍 DATABASE UPSERT: imdb_id={imdb_id}, dateadded={dateadded}, source={source}")
|
print(f"🔍 DATABASE UPSERT: imdb_id={imdb_id}, dateadded={dateadded}, source={source}")
|
||||||
with self.get_connection() as conn:
|
with self.get_connection() as conn:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
# Use INSERT OR REPLACE to ensure we always update the dates properly
|
timestamp = datetime.utcnow()
|
||||||
|
|
||||||
|
if self.db_type == "postgresql":
|
||||||
|
# PostgreSQL version with UPSERT
|
||||||
|
cursor.execute("""
|
||||||
|
INSERT INTO movies (imdb_id, path, released, dateadded, source, has_video_file, last_updated)
|
||||||
|
VALUES (%s, COALESCE((SELECT path FROM movies WHERE imdb_id = %s), 'unknown'), %s, %s, %s, %s, %s)
|
||||||
|
ON CONFLICT (imdb_id) DO UPDATE SET
|
||||||
|
released = EXCLUDED.released,
|
||||||
|
dateadded = EXCLUDED.dateadded,
|
||||||
|
source = EXCLUDED.source,
|
||||||
|
has_video_file = EXCLUDED.has_video_file,
|
||||||
|
last_updated = EXCLUDED.last_updated
|
||||||
|
""", (imdb_id, imdb_id, released, dateadded, source, has_video_file, timestamp))
|
||||||
|
|
||||||
|
# Debug: Check what was actually saved
|
||||||
|
cursor.execute("SELECT dateadded, source FROM movies WHERE imdb_id = %s", (imdb_id,))
|
||||||
|
else:
|
||||||
|
# SQLite version with INSERT OR REPLACE
|
||||||
cursor.execute("""
|
cursor.execute("""
|
||||||
INSERT OR REPLACE INTO movies (imdb_id, path, released, dateadded, source, has_video_file, last_updated)
|
INSERT OR REPLACE INTO movies (imdb_id, path, released, dateadded, source, has_video_file, last_updated)
|
||||||
VALUES (
|
VALUES (
|
||||||
@@ -184,10 +363,11 @@ class NFOGuardDatabase:
|
|||||||
COALESCE((SELECT path FROM movies WHERE imdb_id = ?), 'unknown'),
|
COALESCE((SELECT path FROM movies WHERE imdb_id = ?), 'unknown'),
|
||||||
?, ?, ?, ?, ?
|
?, ?, ?, ?, ?
|
||||||
)
|
)
|
||||||
""", (imdb_id, imdb_id, released, dateadded, source, has_video_file, datetime.utcnow().isoformat()))
|
""", (imdb_id, imdb_id, released, dateadded, source, has_video_file, timestamp.isoformat()))
|
||||||
|
|
||||||
# Debug: Check what was actually saved
|
# Debug: Check what was actually saved
|
||||||
cursor.execute("SELECT dateadded, source FROM movies WHERE imdb_id = ?", (imdb_id,))
|
cursor.execute("SELECT dateadded, source FROM movies WHERE imdb_id = ?", (imdb_id,))
|
||||||
|
|
||||||
result = cursor.fetchone()
|
result = cursor.fetchone()
|
||||||
print(f"🔍 DATABASE VERIFY: After upsert, found dateadded={result[0] if result else 'NOT_FOUND'}, source={result[1] if result else 'NOT_FOUND'}")
|
print(f"🔍 DATABASE VERIFY: After upsert, found dateadded={result[0] if result else 'NOT_FOUND'}, source={result[1] if result else 'NOT_FOUND'}")
|
||||||
|
|
||||||
@@ -196,9 +376,14 @@ class NFOGuardDatabase:
|
|||||||
with self.get_connection() as conn:
|
with self.get_connection() as conn:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
if self.db_type == "postgresql":
|
||||||
|
query = "SELECT * FROM episodes WHERE imdb_id = %s"
|
||||||
|
params = [imdb_id]
|
||||||
|
if has_video_file_only:
|
||||||
|
query += " AND has_video_file = TRUE"
|
||||||
|
else:
|
||||||
query = "SELECT * FROM episodes WHERE imdb_id = ?"
|
query = "SELECT * FROM episodes WHERE imdb_id = ?"
|
||||||
params = [imdb_id]
|
params = [imdb_id]
|
||||||
|
|
||||||
if has_video_file_only:
|
if has_video_file_only:
|
||||||
query += " AND has_video_file = TRUE"
|
query += " AND has_video_file = TRUE"
|
||||||
|
|
||||||
@@ -209,9 +394,10 @@ class NFOGuardDatabase:
|
|||||||
"""Get episode date record"""
|
"""Get episode date record"""
|
||||||
with self.get_connection() as conn:
|
with self.get_connection() as conn:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute("""
|
ph = self._get_placeholder()
|
||||||
|
cursor.execute(f"""
|
||||||
SELECT * FROM episodes
|
SELECT * FROM episodes
|
||||||
WHERE imdb_id = ? AND season = ? AND episode = ?
|
WHERE imdb_id = {ph} AND season = {ph} AND episode = {ph}
|
||||||
""", (imdb_id, season, episode))
|
""", (imdb_id, season, episode))
|
||||||
|
|
||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
@@ -221,7 +407,8 @@ class NFOGuardDatabase:
|
|||||||
"""Get movie date record"""
|
"""Get movie date record"""
|
||||||
with self.get_connection() as conn:
|
with self.get_connection() as conn:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
cursor.execute("SELECT * FROM movies WHERE imdb_id = ?", (imdb_id,))
|
ph = self._get_placeholder()
|
||||||
|
cursor.execute(f"SELECT * FROM movies WHERE imdb_id = {ph}", (imdb_id,))
|
||||||
|
|
||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
return dict(row) if row else None
|
return dict(row) if row else None
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ def initialize_components():
|
|||||||
start_time = datetime.now(timezone.utc)
|
start_time = datetime.now(timezone.utc)
|
||||||
|
|
||||||
# Initialize core components
|
# Initialize core components
|
||||||
db = NFOGuardDatabase(config.db_path)
|
db = NFOGuardDatabase(config=config)
|
||||||
nfo_manager = NFOManager(config.manager_brand, config.debug)
|
nfo_manager = NFOManager(config.manager_brand, config.debug)
|
||||||
path_mapper = PathMapper(config)
|
path_mapper = PathMapper(config)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user