mirror of
https://github.com/tcsenpai/swingmusic.git
synced 2025-06-02 17:30:18 +00:00
add function to validate albums
+ extract colors in watchdogg + rename color db files
This commit is contained in:
parent
4a7416853a
commit
861a854f91
@ -7,7 +7,7 @@ from dataclasses import asdict
|
||||
|
||||
from flask import Blueprint, request
|
||||
|
||||
from app.db.sqlite.albums import SQLiteAlbumMethods as adb
|
||||
from app.db.sqlite.albumcolors import SQLiteAlbumMethods as adb
|
||||
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
||||
from app.db.sqlite.lastfm.similar_artists import SQLiteLastFMSimilarArtists as lastfmdb
|
||||
from app.models import FavType, Track
|
||||
|
@ -8,11 +8,9 @@ api = Blueprint("colors", __name__, url_prefix="/colors")
|
||||
def get_album_color(albumhash: str):
|
||||
album = Store.get_album_by_hash(albumhash)
|
||||
|
||||
if len(album.colors) > 0:
|
||||
return {
|
||||
"color": album.colors[0]
|
||||
}
|
||||
msg = {"color": ""}
|
||||
|
||||
return {
|
||||
"color": ""
|
||||
}
|
||||
if album is None or len(album.colors) == 0:
|
||||
return msg, 404
|
||||
|
||||
return {"color": album.colors[0]}
|
||||
|
@ -49,7 +49,7 @@ def send_track_file(trackhash: str):
|
||||
|
||||
try:
|
||||
return send_file(track.filepath, mimetype=audio_type)
|
||||
except FileNotFoundError:
|
||||
except (FileNotFoundError, OSError) as e:
|
||||
return msg, 404
|
||||
|
||||
return msg, 404
|
||||
|
@ -44,3 +44,23 @@ class SQLiteAlbumMethods:
|
||||
return tuples_to_albums(albums)
|
||||
|
||||
return []
|
||||
|
||||
@staticmethod
|
||||
def exists(albumhash: str, cur: Cursor = None):
|
||||
"""
|
||||
Checks if an album exists in the database.
|
||||
"""
|
||||
|
||||
sql = "SELECT COUNT(1) FROM albums WHERE albumhash = ?"
|
||||
|
||||
def _exists(cur: Cursor):
|
||||
cur.execute(sql, (albumhash,))
|
||||
count = cur.fetchone()[0]
|
||||
|
||||
return count != 0
|
||||
|
||||
if cur:
|
||||
return _exists(cur)
|
||||
|
||||
with SQLiteManager() as cur:
|
||||
return _exists(cur)
|
@ -43,3 +43,22 @@ class SQLiteArtistMethods:
|
||||
|
||||
for artist in cur_.fetchall():
|
||||
yield artist
|
||||
|
||||
@staticmethod
|
||||
def exists(artisthash: str, cur: Cursor = None):
|
||||
"""
|
||||
Checks if an artist exists in the database.
|
||||
"""
|
||||
sql = "SELECT COUNT(1) FROM artists WHERE artisthash = ?"
|
||||
|
||||
def _exists(cur: Cursor):
|
||||
cur.execute(sql, (artisthash,))
|
||||
count = cur.fetchone()[0]
|
||||
|
||||
return count != 0
|
||||
|
||||
if cur:
|
||||
return _exists(cur)
|
||||
|
||||
with SQLiteManager() as cur:
|
||||
return _exists(cur)
|
@ -1,3 +1,22 @@
|
||||
"""
|
||||
Contains methods relating to albums.
|
||||
"""
|
||||
"""
|
||||
|
||||
from tqdm import tqdm
|
||||
from app.store.albums import AlbumStore
|
||||
from app.store.tracks import TrackStore
|
||||
|
||||
|
||||
def validate_albums():
|
||||
"""
|
||||
Removes albums that have no tracks.
|
||||
|
||||
Probably albums that were added from incompletely written files.
|
||||
"""
|
||||
|
||||
album_hashes = {t.albumhash for t in TrackStore.tracks}
|
||||
albums = AlbumStore.albums
|
||||
|
||||
for album in tqdm(albums, desc="Validating albums"):
|
||||
if album.albumhash not in album_hashes:
|
||||
AlbumStore.remove_album(album)
|
||||
|
@ -9,8 +9,8 @@ import colorgram
|
||||
from tqdm import tqdm
|
||||
|
||||
from app import settings
|
||||
from app.db.sqlite.albums import SQLiteAlbumMethods as db
|
||||
from app.db.sqlite.artists import SQLiteArtistMethods as adb
|
||||
from app.db.sqlite.albumcolors import SQLiteAlbumMethods as aldb
|
||||
from app.db.sqlite.artistcolors import SQLiteArtistMethods as adb
|
||||
from app.db.sqlite.utils import SQLiteManager
|
||||
|
||||
from app.store.artists import ArtistStore
|
||||
@ -58,11 +58,8 @@ class ProcessAlbumColors:
|
||||
with SQLiteManager() as cur:
|
||||
try:
|
||||
for album in tqdm(albums, desc="Processing missing album colors"):
|
||||
sql = "SELECT COUNT(1) FROM albums WHERE albumhash = ?"
|
||||
cur.execute(sql, (album.albumhash,))
|
||||
count = cur.fetchone()[0]
|
||||
|
||||
if count != 0:
|
||||
exists = aldb.exists(album.albumhash, cur=cur)
|
||||
if exists:
|
||||
continue
|
||||
|
||||
colors = process_color(album.albumhash)
|
||||
@ -72,7 +69,7 @@ class ProcessAlbumColors:
|
||||
|
||||
album.set_colors(colors)
|
||||
color_str = json.dumps(colors)
|
||||
db.insert_one_album(cur, album.albumhash, color_str)
|
||||
aldb.insert_one_album(cur, album.albumhash, color_str)
|
||||
finally:
|
||||
cur.close()
|
||||
|
||||
@ -90,12 +87,9 @@ class ProcessArtistColors:
|
||||
for artist in tqdm(
|
||||
all_artists, desc="Processing missing artist colors"
|
||||
):
|
||||
sql = "SELECT COUNT(1) FROM artists WHERE artisthash = ?"
|
||||
exists = adb.exists(artist.artisthash, cur=cur)
|
||||
|
||||
cur.execute(sql, (artist.artisthash,))
|
||||
count = cur.fetchone()[0]
|
||||
|
||||
if count != 0:
|
||||
if exists:
|
||||
continue
|
||||
|
||||
colors = process_color(artist.artisthash, is_album=False)
|
||||
|
@ -9,10 +9,10 @@ from tqdm import tqdm
|
||||
|
||||
from app import settings
|
||||
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
||||
from app.db.sqlite.lastfm.similar_artists import \
|
||||
SQLiteLastFMSimilarArtists as lastfmdb
|
||||
from app.db.sqlite.lastfm.similar_artists import SQLiteLastFMSimilarArtists as lastfmdb
|
||||
from app.db.sqlite.settings import SettingsSQLMethods as sdb
|
||||
from app.db.sqlite.tracks import SQLiteTrackMethods
|
||||
from app.lib.albumslib import validate_albums
|
||||
from app.lib.artistlib import CheckArtistImages
|
||||
from app.lib.colorlib import ProcessAlbumColors, ProcessArtistColors
|
||||
from app.lib.taglib import extract_thumb, get_tags
|
||||
@ -51,6 +51,8 @@ class Populate:
|
||||
POPULATE_KEY = key
|
||||
|
||||
validate_tracks()
|
||||
validate_albums()
|
||||
|
||||
tracks = get_all_tracks()
|
||||
|
||||
dirs_to_scan = sdb.get_root_dirs()
|
||||
@ -122,8 +124,7 @@ class Populate:
|
||||
if track.last_mod == os.path.getmtime(track.filepath):
|
||||
unmodified.add(track.filepath)
|
||||
continue
|
||||
except FileNotFoundError:
|
||||
print(f"File not found: {track.filepath}")
|
||||
except (FileNotFoundError, OSError) as e:
|
||||
TrackStore.remove_track_obj(track)
|
||||
remove_tracks_by_filepaths(track.filepath)
|
||||
|
||||
|
@ -78,7 +78,11 @@ def extract_date(date_str: str | None) -> int | None:
|
||||
def get_tags(filepath: str):
|
||||
filetype = filepath.split(".")[-1]
|
||||
filename = (filepath.split("/")[-1]).replace(f".{filetype}", "")
|
||||
last_mod = os.path.getmtime(filepath)
|
||||
|
||||
try:
|
||||
last_mod = os.path.getmtime(filepath)
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
|
||||
try:
|
||||
tags = TinyTag.get(filepath)
|
||||
|
@ -11,9 +11,9 @@ from app.store.tracks import TrackStore
|
||||
|
||||
def validate_tracks() -> None:
|
||||
"""
|
||||
Gets all songs under the ~/ directory.
|
||||
Removes track records whose files no longer exist.
|
||||
"""
|
||||
for track in tqdm(TrackStore.tracks, desc="Checking for deleted tracks"):
|
||||
for track in tqdm(TrackStore.tracks, desc="Validating tracks"):
|
||||
if not os.path.exists(track.filepath):
|
||||
TrackStore.remove_track_obj(track)
|
||||
tdb.remove_tracks_by_filepaths(track.filepath)
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""
|
||||
This library contains the classes and functions related to the watchdog file watcher.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import sqlite3
|
||||
import time
|
||||
@ -9,10 +10,14 @@ from watchdog.events import PatternMatchingEventHandler
|
||||
from watchdog.observers import Observer
|
||||
|
||||
from app import settings
|
||||
|
||||
from app.db.sqlite.settings import SettingsSQLMethods as sdb
|
||||
from app.db.sqlite.tracks import SQLiteManager
|
||||
from app.db.sqlite.tracks import SQLiteTrackMethods as db
|
||||
from app.lib.taglib import get_tags
|
||||
from app.db.sqlite.albumcolors import SQLiteAlbumMethods as aldb
|
||||
|
||||
from app.lib.colorlib import process_color
|
||||
from app.lib.taglib import extract_thumb, get_tags
|
||||
from app.logger import log
|
||||
from app.models import Artist, Track
|
||||
from app.store.albums import AlbumStore
|
||||
@ -123,6 +128,22 @@ class Watcher:
|
||||
self.run()
|
||||
|
||||
|
||||
def handle_colors(cur: sqlite3.Cursor, albumhash: str):
|
||||
exists = aldb.exists(albumhash, cur)
|
||||
|
||||
if exists:
|
||||
return
|
||||
|
||||
colors = process_color(albumhash, is_album=True)
|
||||
|
||||
if colors is None:
|
||||
return
|
||||
|
||||
aldb.insert_one_album(cur=cur, albumhash=albumhash, colors=json.dumps(colors))
|
||||
|
||||
return colors
|
||||
|
||||
|
||||
def add_track(filepath: str) -> None:
|
||||
"""
|
||||
Processes the audio tags for a given file ands add them to the database and store.
|
||||
@ -138,14 +159,23 @@ def add_track(filepath: str) -> None:
|
||||
if tags is None or tags["bitrate"] == 0 or tags["duration"] == 0:
|
||||
return
|
||||
|
||||
colors = None
|
||||
|
||||
with SQLiteManager() as cur:
|
||||
db.insert_one_track(tags, cur)
|
||||
extracted = extract_thumb(filepath, tags["albumhash"] + ".webp")
|
||||
|
||||
if not extracted:
|
||||
return
|
||||
|
||||
colors = handle_colors(cur, tags["albumhash"])
|
||||
|
||||
track = Track(**tags)
|
||||
TrackStore.add_track(track)
|
||||
|
||||
if not AlbumStore.album_exists(track.albumhash):
|
||||
album = AlbumStore.create_album(track)
|
||||
album.set_colors(colors)
|
||||
AlbumStore.add_album(album)
|
||||
|
||||
artists: list[Artist] = track.artist + track.albumartist # type: ignore
|
||||
@ -154,6 +184,7 @@ def add_track(filepath: str) -> None:
|
||||
if not ArtistStore.artist_exists(artist.artisthash):
|
||||
ArtistStore.add_artist(Artist(artist.name))
|
||||
|
||||
extract_thumb(filepath, track.image)
|
||||
|
||||
def remove_track(filepath: str) -> None:
|
||||
"""
|
||||
@ -277,7 +308,7 @@ class Handler(PatternMatchingEventHandler):
|
||||
|
||||
if current_size == previous_size:
|
||||
# Wait for a short duration to ensure the file write operation is complete
|
||||
time.sleep(0.5)
|
||||
time.sleep(5)
|
||||
|
||||
# Check the file size again
|
||||
current_size = os.path.getsize(event.src_path)
|
||||
|
@ -157,7 +157,6 @@ class Album:
|
||||
return self.title.strip().endswith(" EP")
|
||||
|
||||
def check_is_single(self, tracks: list[Track]):
|
||||
|
||||
"""
|
||||
Checks if the album is a single.
|
||||
"""
|
||||
|
@ -1,5 +1,5 @@
|
||||
from dataclasses import asdict
|
||||
from app.models.album import Album
|
||||
from app.models import Album
|
||||
|
||||
|
||||
def album_serializer(album: Album, to_remove: set[str]) -> dict:
|
||||
|
@ -4,7 +4,7 @@ import random
|
||||
from tqdm import tqdm
|
||||
|
||||
from app.models import Album, Track
|
||||
from app.db.sqlite.albums import SQLiteAlbumMethods as aldb
|
||||
from app.db.sqlite.albumcolors import SQLiteAlbumMethods as aldb
|
||||
from .tracks import TrackStore
|
||||
from ..utils.hashing import create_hash
|
||||
|
||||
@ -133,6 +133,13 @@ class AlbumStore:
|
||||
"""
|
||||
return albumhash in "-".join([a.albumhash for a in cls.albums])
|
||||
|
||||
@classmethod
|
||||
def remove_album(cls, album: Album):
|
||||
"""
|
||||
Removes an album from the store.
|
||||
"""
|
||||
cls.albums.remove(album)
|
||||
|
||||
@classmethod
|
||||
def remove_album_by_hash(cls, albumhash: str):
|
||||
"""
|
||||
|
@ -2,7 +2,7 @@ import json
|
||||
|
||||
from tqdm import tqdm
|
||||
|
||||
from app.db.sqlite.artists import SQLiteArtistMethods as ardb
|
||||
from app.db.sqlite.artistcolors import SQLiteArtistMethods as ardb
|
||||
from app.lib.artistlib import get_all_artists
|
||||
from app.models import Artist
|
||||
from app.utils.bisection import UseBisection
|
||||
|
41
poetry.lock
generated
41
poetry.lock
generated
@ -1,5 +1,31 @@
|
||||
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "about-time"
|
||||
version = "4.2.1"
|
||||
description = "Easily measure timing and throughput of code blocks, with beautiful human friendly representations."
|
||||
optional = false
|
||||
python-versions = ">=3.7, <4"
|
||||
files = [
|
||||
{file = "about-time-4.2.1.tar.gz", hash = "sha256:6a538862d33ce67d997429d14998310e1dbfda6cb7d9bbfbf799c4709847fece"},
|
||||
{file = "about_time-4.2.1-py3-none-any.whl", hash = "sha256:8bbf4c75fe13cbd3d72f49a03b02c5c7dca32169b6d49117c257e7eb3eaee341"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alive-progress"
|
||||
version = "3.1.4"
|
||||
description = "A new kind of Progress Bar, with real-time throughput, ETA, and very cool animations!"
|
||||
optional = false
|
||||
python-versions = ">=3.7, <4"
|
||||
files = [
|
||||
{file = "alive-progress-3.1.4.tar.gz", hash = "sha256:74a95d8d0d42bc99d3a3725dbd06ebb852245f1b64e301a7c375b92b22663f7b"},
|
||||
{file = "alive_progress-3.1.4-py3-none-any.whl", hash = "sha256:c80ad87ce9c1054b01135a87fae69ecebbfc2107497ae87cbe6aec7e534903db"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
about-time = "4.2.1"
|
||||
grapheme = "0.6.0"
|
||||
|
||||
[[package]]
|
||||
name = "altgraph"
|
||||
version = "0.17.3"
|
||||
@ -280,6 +306,19 @@ files = [
|
||||
Flask = ">=0.9"
|
||||
Six = "*"
|
||||
|
||||
[[package]]
|
||||
name = "grapheme"
|
||||
version = "0.6.0"
|
||||
description = "Unicode grapheme helpers"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "grapheme-0.6.0.tar.gz", hash = "sha256:44c2b9f21bbe77cfb05835fec230bd435954275267fea1858013b102f8603cca"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
test = ["pytest", "sphinx", "sphinx-autobuild", "twine", "wheel"]
|
||||
|
||||
[[package]]
|
||||
name = "gunicorn"
|
||||
version = "20.1.0"
|
||||
@ -1329,4 +1368,4 @@ files = [
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.10,<3.12"
|
||||
content-hash = "81941c92f1b4a468b554fc7eeae857897f352142cc3c03393349297ac11dcaae"
|
||||
content-hash = "da0e11b5066258d0a56917ea1143fa7196c6de88bd7d6b9f2fc060d84e6bf36f"
|
||||
|
@ -20,6 +20,7 @@ Unidecode = "^1.3.6"
|
||||
psutil = "^5.9.4"
|
||||
show-in-file-manager = "^1.1.4"
|
||||
pendulum = "^2.1.2"
|
||||
alive-progress = "^3.1.4"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pylint = "^2.15.5"
|
||||
|
@ -1,7 +1,7 @@
|
||||
import json
|
||||
import sqlite3
|
||||
import os
|
||||
from app.db.sqlite.artists import SQLiteArtistMethods
|
||||
from app.db.sqlite.artistcolors import SQLiteArtistMethods
|
||||
from app.db.sqlite.queries import CREATE_APPDB_TABLES
|
||||
|
||||
from app.db.sqlite.utils import SQLiteManager
|
||||
|
Loading…
x
Reference in New Issue
Block a user