This commit is contained in:
nose
2025-11-27 10:59:01 -08:00
parent e9b505e609
commit 9eff65d1af
30 changed files with 2099 additions and 1095 deletions

View File

@@ -230,6 +230,16 @@ class LocalLibraryDB:
FOREIGN KEY (file_id) REFERENCES files(id) ON DELETE CASCADE
)
""")
cursor.execute("""
CREATE TABLE IF NOT EXISTS playlists (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT UNIQUE NOT NULL,
items TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
# Worker tracking tables (drop legacy workers table if still present)
self._ensure_worker_tables(cursor)
@@ -1386,6 +1396,104 @@ class LocalLibrarySearchOptimizer:
"""Fast tag-based search using database."""
if not self.db:
return []
try:
cursor = self.db.connection.cursor()
cursor.execute("""
SELECT f.file_path
FROM files f
JOIN tags t ON f.id = t.file_id
WHERE t.tag LIKE ?
LIMIT ?
""", (f"%{tag}%", limit))
return [Path(row[0]) for row in cursor.fetchall()]
except Exception as e:
logger.error(f"Tag search failed: {e}")
return []
def save_playlist(self, name: str, items: List[Dict[str, Any]]) -> bool:
"""Save a playlist to the database."""
if not self.db:
return False
try:
cursor = self.db.connection.cursor()
items_json = json.dumps(items)
cursor.execute("""
INSERT INTO playlists (name, items, updated_at)
VALUES (?, ?, CURRENT_TIMESTAMP)
ON CONFLICT(name) DO UPDATE SET
items = excluded.items,
updated_at = CURRENT_TIMESTAMP
""", (name, items_json))
self.db.connection.commit()
return True
except Exception as e:
logger.error(f"Failed to save playlist {name}: {e}")
return False
def get_playlists(self) -> List[Dict[str, Any]]:
"""Get all saved playlists."""
if not self.db:
return []
try:
cursor = self.db.connection.cursor()
cursor.execute("SELECT id, name, items, updated_at FROM playlists ORDER BY updated_at DESC")
results = []
for row in cursor.fetchall():
try:
items = json.loads(row['items'])
except json.JSONDecodeError:
items = []
results.append({
'id': row['id'],
'name': row['name'],
'items': items,
'updated_at': row['updated_at']
})
return results
except Exception as e:
logger.error(f"Failed to get playlists: {e}")
return []
def get_playlist(self, name: str) -> Optional[List[Dict[str, Any]]]:
"""Get a specific playlist by name."""
if not self.db:
return None
try:
cursor = self.db.connection.cursor()
cursor.execute("SELECT items FROM playlists WHERE name = ?", (name,))
row = cursor.fetchone()
if row:
try:
return json.loads(row['items'])
except json.JSONDecodeError:
return []
return None
except Exception as e:
logger.error(f"Failed to get playlist {name}: {e}")
return None
def get_playlist_by_id(self, playlist_id: int) -> Optional[Tuple[str, List[Dict[str, Any]]]]:
"""Get a specific playlist by ID. Returns (name, items)."""
if not self.db:
return None
try:
cursor = self.db.connection.cursor()
cursor.execute("SELECT name, items FROM playlists WHERE id = ?", (playlist_id,))
row = cursor.fetchone()
if row:
try:
items = json.loads(row['items'])
return (row['name'], items)
except json.JSONDecodeError:
return (row['name'], [])
return None
except Exception as e:
logger.error(f"Failed to get playlist ID {playlist_id}: {e}")
return None
if not self.db:
return []
return self.db.search_by_tag(tag, limit)
def search_by_hash(self, file_hash: str) -> Optional[Path]: