jjlj
This commit is contained in:
@@ -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]:
|
||||
|
||||
Reference in New Issue
Block a user