mirror of
https://github.com/tcsenpai/swingmusic.git
synced 2025-06-06 19:25:34 +00:00
rewrite populate.get_image() to extract a
track thumbnail from the first track in an album that has one. + rewrite Populate.remove_modified with sets + clean the SqliteManager utility class + Rewrite ProcessTrackThumbnails to use a process pool instead of a thread pool + rewrite track store's remove_tracks_by_filepaths to utilize sets
This commit is contained in:
parent
1eac009fde
commit
9d4f7af581
@ -84,12 +84,12 @@ class SQLiteTrackMethods:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def remove_tracks_by_filepaths(filepaths: str | list[str]):
|
||||
def remove_tracks_by_filepaths(filepaths: str | set[str]):
|
||||
"""
|
||||
Removes a track or tracks from the database using their filepaths.
|
||||
"""
|
||||
if isinstance(filepaths, str):
|
||||
filepaths = [filepaths]
|
||||
filepaths = {filepaths}
|
||||
|
||||
with SQLiteManager() as cur:
|
||||
for filepath in filepaths:
|
||||
|
@ -5,6 +5,7 @@ Helper functions for use with the SQLite database.
|
||||
import sqlite3
|
||||
from sqlite3 import Connection, Cursor
|
||||
import time
|
||||
from typing import Optional
|
||||
|
||||
from app.models import Album, Playlist, Track
|
||||
from app.settings import Db
|
||||
@ -61,12 +62,12 @@ class SQLiteManager:
|
||||
for you. It also commits and closes the connection when you're done.
|
||||
"""
|
||||
|
||||
def __init__(self, conn: Connection | None = None, userdata_db=False) -> None:
|
||||
def __init__(self, conn: Optional[Connection] = None, userdata_db=False) -> None:
|
||||
"""
|
||||
When a connection is passed in, don't close the connection, because it's
|
||||
a connection to the search database [in memory db].
|
||||
"""
|
||||
self.conn: Connection | None = conn
|
||||
self.conn = conn
|
||||
self.CLOSE_CONN = True
|
||||
self.userdata_db = userdata_db
|
||||
|
||||
@ -90,7 +91,6 @@ class SQLiteManager:
|
||||
return self.conn.cursor()
|
||||
|
||||
def __exit__(self, exc_type, exc_value, exc_traceback):
|
||||
if self.conn:
|
||||
trial_count = 0
|
||||
|
||||
while trial_count < 10:
|
||||
|
@ -1,6 +1,7 @@
|
||||
from collections import deque
|
||||
import os
|
||||
from typing import Generator
|
||||
from tqdm import tqdm
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from requests import ConnectionError as RequestConnectionError
|
||||
from requests import ReadTimeout
|
||||
|
||||
@ -47,7 +48,6 @@ class Populate:
|
||||
|
||||
validate_tracks()
|
||||
tracks = get_all_tracks()
|
||||
tracks = list(tracks)
|
||||
|
||||
dirs_to_scan = sdb.get_root_dirs()
|
||||
|
||||
@ -66,13 +66,13 @@ class Populate:
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
files = []
|
||||
files = set()
|
||||
|
||||
for _dir in dirs_to_scan:
|
||||
files.extend(run_fast_scandir(_dir, full=True)[1])
|
||||
files = files.union(run_fast_scandir(_dir, full=True)[1])
|
||||
|
||||
self.remove_modified(tracks)
|
||||
untagged = self.filter_untagged(tracks, files)
|
||||
unmodified = self.remove_modified(tracks)
|
||||
untagged = files - unmodified
|
||||
|
||||
if len(untagged) != 0:
|
||||
self.tag_untagged(untagged, key)
|
||||
@ -101,23 +101,31 @@ class Populate:
|
||||
ProcessArtistColors()
|
||||
|
||||
@staticmethod
|
||||
def remove_modified(tracks: list[Track]):
|
||||
modified = [
|
||||
t.filepath for t in tracks if t.last_mod != os.path.getmtime(t.filepath)
|
||||
]
|
||||
def remove_modified(tracks: Generator[Track, None, None]):
|
||||
"""
|
||||
Removes tracks from the database that have been modified
|
||||
since they were added to the database.
|
||||
"""
|
||||
|
||||
unmodified = set()
|
||||
modified = set()
|
||||
|
||||
for track in tracks:
|
||||
if track.last_mod == os.path.getmtime(track.filepath):
|
||||
unmodified.add(track.filepath)
|
||||
continue
|
||||
|
||||
modified.add(track.filepath)
|
||||
|
||||
TrackStore.remove_tracks_by_filepaths(modified)
|
||||
remove_tracks_by_filepaths(modified)
|
||||
|
||||
@staticmethod
|
||||
def filter_untagged(tracks: list[Track], files: list[str]):
|
||||
tagged_files = [t.filepath for t in tracks]
|
||||
return set(files) - set(tagged_files)
|
||||
return unmodified
|
||||
|
||||
@staticmethod
|
||||
def tag_untagged(untagged: set[str], key: str):
|
||||
log.info("Found %s new tracks", len(untagged))
|
||||
tagged_tracks: list[dict] = []
|
||||
tagged_tracks: deque[dict] = deque()
|
||||
tagged_count = 0
|
||||
|
||||
fav_tracks = favdb.get_fav_tracks()
|
||||
@ -159,18 +167,47 @@ class Populate:
|
||||
|
||||
|
||||
def get_image(album: Album):
|
||||
for track in TrackStore.tracks:
|
||||
if track.albumhash == album.albumhash:
|
||||
extract_thumb(track.filepath, track.image)
|
||||
"""
|
||||
The function retrieves an image from an album by iterating through its tracks and extracting the thumbnail from the first track that has one.
|
||||
|
||||
:param album: An instance of the `Album` class representing the album to retrieve the image from.
|
||||
:type album: Album
|
||||
:return: None
|
||||
"""
|
||||
|
||||
matching_tracks = filter(
|
||||
lambda t: t.albumhash == album.albumhash, TrackStore.tracks
|
||||
)
|
||||
|
||||
try:
|
||||
track = next(matching_tracks)
|
||||
extracted = extract_thumb(track.filepath, track.image)
|
||||
|
||||
while not extracted:
|
||||
try:
|
||||
track = next(matching_tracks)
|
||||
extracted = extract_thumb(track.filepath, track.image)
|
||||
except StopIteration:
|
||||
break
|
||||
|
||||
return
|
||||
except StopIteration:
|
||||
pass
|
||||
|
||||
|
||||
from multiprocessing import Pool, cpu_count
|
||||
|
||||
|
||||
class ProcessTrackThumbnails:
|
||||
"""
|
||||
Extracts the album art from all albums in album store.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
with ThreadPoolExecutor(max_workers=4) as pool:
|
||||
with Pool(processes=cpu_count()) as pool:
|
||||
results = list(
|
||||
tqdm(
|
||||
pool.map(get_image, AlbumStore.albums),
|
||||
pool.imap_unordered(get_image, AlbumStore.albums),
|
||||
total=len(AlbumStore.albums),
|
||||
desc="Extracting track images",
|
||||
)
|
||||
|
@ -67,8 +67,7 @@ def extract_thumb(filepath: str, webp_path: str) -> bool:
|
||||
def extract_date(date_str: str | None, timestamp: float) -> int:
|
||||
try:
|
||||
return int(date_str.split("-")[0])
|
||||
except: # pylint: disable=bare-except
|
||||
print(datetime.datetime.fromtimestamp(timestamp).year)
|
||||
except Exception as e:
|
||||
return datetime.datetime.fromtimestamp(timestamp).year
|
||||
|
||||
|
||||
|
@ -92,7 +92,7 @@ class Watcher:
|
||||
)
|
||||
return
|
||||
except OSError as e:
|
||||
log.error('Failed to start watchdog. %s', e)
|
||||
log.error("Failed to start watchdog. %s", e)
|
||||
return
|
||||
|
||||
try:
|
||||
|
@ -53,15 +53,14 @@ class TrackStore:
|
||||
break
|
||||
|
||||
@classmethod
|
||||
def remove_tracks_by_filepaths(cls, filepaths: list[str]):
|
||||
def remove_tracks_by_filepaths(cls, filepaths: set[str]):
|
||||
"""
|
||||
Removes multiple tracks from the store by their filepaths.
|
||||
"""
|
||||
|
||||
paths_str = "~".join(filepaths)
|
||||
|
||||
for track in cls.tracks:
|
||||
if track.filepath in paths_str:
|
||||
if track.filepath in filepaths:
|
||||
cls.tracks.remove(track)
|
||||
|
||||
@classmethod
|
||||
|
@ -245,21 +245,3 @@ def clean_title(title: str) -> str:
|
||||
#
|
||||
# if "-" in title:
|
||||
# return remove_hyphen_remasters(title)
|
||||
|
||||
|
||||
# Traceback (most recent call last):
|
||||
# File "/usr/lib/python3.10/threading.py", line 1016, in _bootstrap_inner
|
||||
# self.run()
|
||||
# File "/usr/lib/python3.10/threading.py", line 953, in run
|
||||
# self._target(*self._args, **self._kwargs)
|
||||
# File "/home/cwilvx/code/swingmusic/app/periodic_scan.py", line 29, in run_periodic_scans
|
||||
# Populate(key=get_random_str())
|
||||
# File "/home/cwilvx/code/swingmusic/app/lib/populate.py", line 74, in __init__
|
||||
# self.tag_untagged(untagged, key)
|
||||
# File "/home/cwilvx/code/swingmusic/app/lib/populate.py", line 123, in tag_untagged
|
||||
# insert_many_tracks(tagged_tracks)
|
||||
# File "/home/cwilvx/code/swingmusic/app/db/sqlite/tracks.py", line 54, in insert_many_tracks
|
||||
# cls.insert_one_track(track, cur)
|
||||
# File "/home/cwilvx/code/swingmusic/app/db/sqlite/tracks.py", line 45, in insert_one_track
|
||||
# cur.execute(sql, track)
|
||||
# sqlite3.IntegrityError: UNIQUE constraint failed: tracks.filepath
|
||||
|
Loading…
x
Reference in New Issue
Block a user