support in_quotes search query

This commit is contained in:
mungai-njoroge 2023-08-06 22:09:39 +03:00
parent 943d6e3590
commit f28d3f00bd
6 changed files with 238 additions and 174 deletions

View File

@ -20,16 +20,6 @@ api = Blueprint("playlist", __name__, url_prefix="/")
PL = SQLitePlaylistMethods PL = SQLitePlaylistMethods
insert_one_playlist = PL.insert_one_playlist
get_playlist_by_name = PL.get_playlist_by_name
count_playlist_by_name = PL.count_playlist_by_name
get_all_playlists = PL.get_all_playlists
get_playlist_by_id = PL.get_playlist_by_id
tracks_to_playlist = PL.add_tracks_to_playlist
update_playlist = PL.update_playlist
delete_playlist = PL.delete_playlist
remove_image = PL.remove_banner
def duplicate_images(images: list): def duplicate_images(images: list):
if len(images) == 1: if len(images) == 1:
@ -80,7 +70,7 @@ def send_all_playlists():
# get the no_images query param # get the no_images query param
no_images = request.args.get("no_images", False) no_images = request.args.get("no_images", False)
playlists = get_all_playlists() playlists = PL.get_all_playlists()
playlists = list(playlists) playlists = list(playlists)
for playlist in playlists: for playlist in playlists:
@ -109,7 +99,7 @@ def insert_playlist(name: str):
), ),
} }
return insert_one_playlist(playlist) return PL.insert_one_playlist(playlist)
@api.route("/playlist/new", methods=["POST"]) @api.route("/playlist/new", methods=["POST"])
@ -122,7 +112,7 @@ def create_playlist():
if data is None: if data is None:
return {"error": "Playlist name not provided"}, 400 return {"error": "Playlist name not provided"}, 400
existing_playlist_count = count_playlist_by_name(data["name"]) existing_playlist_count = PL.count_playlist_by_name(data["name"])
if existing_playlist_count > 0: if existing_playlist_count > 0:
return {"error": "Playlist already exists"}, 409 return {"error": "Playlist already exists"}, 409
@ -161,7 +151,7 @@ def get_artist_trackhashes(artisthash: str):
@api.route("/playlist/<playlist_id>/add", methods=["POST"]) @api.route("/playlist/<playlist_id>/add", methods=["POST"])
def add_track_to_playlist(playlist_id: str): def add_item_to_playlist(playlist_id: str):
""" """
Takes a playlist ID and a track hash, and adds the track to the playlist Takes a playlist ID and a track hash, and adds the track to the playlist
""" """
@ -191,10 +181,10 @@ def add_track_to_playlist(playlist_id: str):
else: else:
trackhashes = [] trackhashes = []
insert_count = tracks_to_playlist(int(playlist_id), trackhashes) insert_count = PL.add_tracks_to_playlist(int(playlist_id), trackhashes)
if insert_count == 0: if insert_count == 0:
return {"error": "Track already exists in playlist"}, 409 return {"error": "Item already exists in playlist"}, 409
PL.update_last_updated(int(playlist_id)) PL.update_last_updated(int(playlist_id))
@ -209,7 +199,7 @@ def get_playlist(playlistid: str):
no_tracks = request.args.get("no_tracks", False) no_tracks = request.args.get("no_tracks", False)
no_tracks = no_tracks == "true" no_tracks = no_tracks == "true"
playlist = get_playlist_by_id(int(playlistid)) playlist = PL.get_playlist_by_id(int(playlistid))
if playlist is None: if playlist is None:
return {"msg": "Playlist not found"}, 404 return {"msg": "Playlist not found"}, 404
@ -243,7 +233,7 @@ def update_playlist_info(playlistid: str):
if playlistid is None: if playlistid is None:
return {"error": "Playlist ID not provided"}, 400 return {"error": "Playlist ID not provided"}, 400
db_playlist = get_playlist_by_id(int(playlistid)) db_playlist = PL.get_playlist_by_id(int(playlistid))
if db_playlist is None: if db_playlist is None:
return {"error": "Playlist not found"}, 404 return {"error": "Playlist not found"}, 404
@ -279,7 +269,7 @@ def update_playlist_info(playlistid: str):
p_tuple = (*playlist.values(),) p_tuple = (*playlist.values(),)
update_playlist(int(playlistid), playlist) PL.update_playlist(int(playlistid), playlist)
playlist = models.Playlist(*p_tuple) playlist = models.Playlist(*p_tuple)
playlist.last_updated = date_string_to_time_passed(playlist.last_updated) playlist.last_updated = date_string_to_time_passed(playlist.last_updated)
@ -295,12 +285,12 @@ def remove_playlist_image(playlistid: str):
Removes the playlist image. Removes the playlist image.
""" """
pid = int(playlistid) pid = int(playlistid)
playlist = get_playlist_by_id(pid) playlist = PL.get_playlist_by_id(pid)
if playlist is None: if playlist is None:
return {"error": "Playlist not found"}, 404 return {"error": "Playlist not found"}, 404
remove_image(pid) PL.remove_image(pid)
playlist.image = None playlist.image = None
playlist.thumb = None playlist.thumb = None
@ -330,7 +320,7 @@ def remove_playlist():
except KeyError: except KeyError:
return message, 400 return message, 400
delete_playlist(pid) PL.delete_playlist(pid)
return {"msg": "Done"}, 200 return {"msg": "Done"}, 200
@ -373,7 +363,7 @@ def remove_tracks_from_playlist(pid: int):
def playlist_exists(name: str) -> bool: def playlist_exists(name: str) -> bool:
return count_playlist_by_name(name) > 0 return PL.count_playlist_by_name(name) > 0
@api.route("/playlist/save-item", methods=["POST"]) @api.route("/playlist/save-item", methods=["POST"])
@ -402,7 +392,12 @@ def save_item_as_playlist():
except KeyError: except KeyError:
itemhash = None itemhash = None
if itemtype == "folder": if itemtype is None or playlist_name is None or itemhash is None:
return msg
if itemtype == "track":
trackhashes = [itemhash]
elif itemtype == "folder":
trackhashes = get_path_trackhashes(itemhash) trackhashes = get_path_trackhashes(itemhash)
elif itemtype == "album": elif itemtype == "album":
trackhashes = get_album_trackhashes(itemhash) trackhashes = get_album_trackhashes(itemhash)
@ -419,7 +414,7 @@ def save_item_as_playlist():
if playlist is None: if playlist is None:
return {"error": "Playlist could not be created"}, 500 return {"error": "Playlist could not be created"}, 500
tracks_to_playlist(playlist.id, trackhashes) PL.add_tracks_to_playlist(playlist.id, trackhashes)
PL.update_last_updated(playlist.id) PL.update_last_updated(playlist.id)
return {"playlist_id": playlist.id}, 201 return {"playlist": playlist}, 201

View File

@ -2,13 +2,11 @@
Contains all the search routes. Contains all the search routes.
""" """
from unidecode import unidecode
from flask import Blueprint, request from flask import Blueprint, request
from unidecode import unidecode
from app import models from app import models
from app.lib import searchlib from app.lib import searchlib
from app.store.tracks import TrackStore from app.store.tracks import TrackStore
api = Blueprint("search", __name__, url_prefix="/") api = Blueprint("search", __name__, url_prefix="/")
@ -17,68 +15,45 @@ SEARCH_COUNT = 12
"""The max amount of items to return per request""" """The max amount of items to return per request"""
class SearchResults: def query_in_quotes(query: str) -> bool:
""" """
Holds all the search results. Returns True if the query is in quotes
""" """
return query.startswith('"') and query.endswith('"')
query: str = ""
tracks: list[models.Track] = []
albums: list[models.Album] = []
playlists: list[models.Playlist] = []
artists: list[models.Artist] = []
class Search: class Search:
def __init__(self, query: str) -> None: def __init__(self, query: str) -> None:
self.tracks: list[models.Track] = [] self.tracks: list[models.Track] = []
self.query = unidecode(query) self.query = unidecode(query)
SearchResults.query = self.query
def search_tracks(self): def search_tracks(self, in_quotes=False):
""" """
Calls :class:`SearchTracks` which returns the tracks that fuzzily match Calls :class:`SearchTracks` which returns the tracks that fuzzily match
the search terms. Then adds them to the `SearchResults` store. the search terms. Then adds them to the `SearchResults` store.
""" """
self.tracks = TrackStore.tracks self.tracks = TrackStore.tracks
tracks = searchlib.SearchTracks(self.query)() return searchlib.TopResults().search(
self.query, tracks_only=True, in_quotes=in_quotes
SearchResults.tracks = tracks )
return tracks
def search_artists(self): def search_artists(self):
"""Calls :class:`SearchArtists` which returns the artists that fuzzily match """Calls :class:`SearchArtists` which returns the artists that fuzzily match
the search term. Then adds them to the `SearchResults` store. the search term. Then adds them to the `SearchResults` store.
""" """
artists = searchlib.SearchArtists(self.query)() return searchlib.SearchArtists(self.query)()
SearchResults.artists = artists
return artists
def search_albums(self): def search_albums(self, in_quotes=False):
"""Calls :class:`SearchAlbums` which returns the albums that fuzzily match """Calls :class:`SearchAlbums` which returns the albums that fuzzily match
the search term. Then adds them to the `SearchResults` store. the search term. Then adds them to the `SearchResults` store.
""" """
albums = searchlib.SearchAlbums(self.query)() return searchlib.TopResults().search(
SearchResults.albums = albums self.query, albums_only=True, in_quotes=in_quotes
)
return albums
# def search_playlists(self):
# """Calls :class:`SearchPlaylists` which returns the playlists that fuzzily match
# the search term. Then adds them to the `SearchResults` store.
# """
# playlists = utils.Get.get_all_playlists()
# playlists = [serializer.Playlist(playlist) for playlist in playlists]
# playlists = searchlib.SearchPlaylists(playlists, self.query)()
# SearchResults.playlists = playlists
# return playlists
def get_top_results(self):
finder = searchlib.SearchAll()
return finder.search(self.query)
def get_top_results(self, in_quotes=False):
finder = searchlib.TopResults()
return finder.search(self.query, in_quotes=in_quotes)
@api.route("/search/tracks", methods=["GET"]) @api.route("/search/tracks", methods=["GET"])
@ -88,10 +63,12 @@ def search_tracks():
""" """
query = request.args.get("q") query = request.args.get("q")
in_quotes = query_in_quotes(query)
if not query: if not query:
return {"error": "No query provided"}, 400 return {"error": "No query provided"}, 400
tracks = Search(query).search_tracks() tracks = Search(query).search_tracks(in_quotes)
return { return {
"tracks": tracks[:SEARCH_COUNT], "tracks": tracks[:SEARCH_COUNT],
@ -106,14 +83,16 @@ def search_albums():
""" """
query = request.args.get("q") query = request.args.get("q")
in_quotes = query_in_quotes(query)
if not query: if not query:
return {"error": "No query provided"}, 400 return {"error": "No query provided"}, 400
tracks = Search(query).search_albums() albums = Search(query).search_albums(in_quotes)
return { return {
"albums": tracks[:SEARCH_COUNT], "albums": albums[:SEARCH_COUNT],
"more": len(tracks) > SEARCH_COUNT, "more": len(albums) > SEARCH_COUNT,
} }
@ -124,6 +103,7 @@ def search_artists():
""" """
query = request.args.get("q") query = request.args.get("q")
if not query: if not query:
return {"error": "No query provided"}, 400 return {"error": "No query provided"}, 400
@ -135,24 +115,6 @@ def search_artists():
} }
# @searchbp.route("/search/playlists", methods=["GET"])
# def search_playlists():
# """
# Searches for playlists.
# """
# query = request.args.get("q")
# if not query:
# return {"error": "No query provided"}, 400
# playlists = DoSearch(query).search_playlists()
# return {
# "playlists": playlists[:SEARCH_COUNT],
# "more": len(playlists) > SEARCH_COUNT,
# }
@api.route("/search/top", methods=["GET"]) @api.route("/search/top", methods=["GET"])
def get_top_results(): def get_top_results():
""" """
@ -160,21 +122,12 @@ def get_top_results():
""" """
query = request.args.get("q") query = request.args.get("q")
in_quotes = query_in_quotes(query)
if not query: if not query:
return {"error": "No query provided"}, 400 return {"error": "No query provided"}, 400
results = Search(query).get_top_results() return Search(query).get_top_results(in_quotes=in_quotes)
# max_results = 2
# return {
# "tracks": SearchResults.tracks[:max_results],
# "albums": SearchResults.albums[:max_results],
# "artists": SearchResults.artists[:max_results],
# "playlists": SearchResults.playlists[:max_results],
# }
return {
"results": results
}
@api.route("/search/loadmore") @api.route("/search/loadmore")
@ -182,28 +135,32 @@ def search_load_more():
""" """
Returns more songs, albums or artists from a search query. Returns more songs, albums or artists from a search query.
""" """
query = request.args.get("q")
in_quotes = query_in_quotes(query)
s_type = request.args.get("type") s_type = request.args.get("type")
index = int(request.args.get("index") or 0) index = int(request.args.get("index") or 0)
if s_type == "tracks": if s_type == "tracks":
t = SearchResults.tracks t = Search(query).search_tracks(in_quotes)
return { return {
"tracks": t[index: index + SEARCH_COUNT], "tracks": t[index : index + SEARCH_COUNT],
"more": len(t) > index + SEARCH_COUNT, "more": len(t) > index + SEARCH_COUNT,
} }
elif s_type == "albums": elif s_type == "albums":
a = SearchResults.albums a = Search(query).search_albums(in_quotes)
return { return {
"albums": a[index: index + SEARCH_COUNT], "albums": a[index : index + SEARCH_COUNT],
"more": len(a) > index + SEARCH_COUNT, "more": len(a) > index + SEARCH_COUNT,
} }
elif s_type == "artists": elif s_type == "artists":
a = SearchResults.artists a = Search(query).search_artists()
return { return {
"artists": a[index: index + SEARCH_COUNT], "artists": a[index : index + SEARCH_COUNT],
"more": len(a) > index + SEARCH_COUNT, "more": len(a) > index + SEARCH_COUNT,
} }
# TODO: Rewrite this file using generators where possible
# TODO: Rewrite this file using generators where possible

View File

@ -77,7 +77,9 @@ class CheckArtistImages:
with Pool(cpu_count()) as pool: with Pool(cpu_count()) as pool:
res = list( res = list(
tqdm( tqdm(
pool.imap_unordered(self.download_image, artist_store.ArtistStore.artists), pool.imap_unordered(
self.download_image, artist_store.ArtistStore.artists
),
total=len(artist_store.ArtistStore.artists), total=len(artist_store.ArtistStore.artists),
desc="Downloading missing artist images", desc="Downloading missing artist images",
) )
@ -164,10 +166,17 @@ def get_all_artists(tracks: list[Track], albums: list[Album]) -> list[Artist]:
artist_from_albums = get_albumartists(albums=albums) artist_from_albums = get_albumartists(albums=albums)
artists = list(artists_from_tracks.union(artist_from_albums)) artists = list(artists_from_tracks.union(artist_from_albums))
artists = sorted(artists) artists.sort()
lower_artists = set(a.lower().strip() for a in artists) # Remove duplicates
indices = [[ar.lower().strip() for ar in artists].index(a) for a in lower_artists] artists_dup_free = set()
artists = [artists[i] for i in indices] artist_hashes = set()
return [Artist(a) for a in artists] for artist in artists:
artist_hash = create_hash(artist, decode=True)
if artist_hash not in artist_hashes:
artists_dup_free.add(artist)
artist_hashes.add(artist_hash)
return [Artist(a) for a in artists_dup_free]

View File

@ -1,21 +1,23 @@
""" """
This library contains all the functions related to the search functionality. This library contains all the functions related to the search functionality.
""" """
from typing import List, Generator, TypeVar, Any from typing import Any, Generator, List, TypeVar
import itertools
from rapidfuzz import fuzz, process from rapidfuzz import process, utils
from unidecode import unidecode from unidecode import unidecode
from app import models from app import models
from app.utils.remove_duplicates import remove_duplicates from app.models.enums import FavType
from app.models.track import Track
from app.store.albums import AlbumStore from app.store.albums import AlbumStore
from app.store.artists import ArtistStore from app.store.artists import ArtistStore
from app.store.tracks import TrackStore from app.store.tracks import TrackStore
ratio = fuzz.ratio from app.utils.remove_duplicates import remove_duplicates
wratio = fuzz.WRatio from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
# ratio = fuzz.ratio
# wratio = fuzz.WRatio
class Cutoff: class Cutoff:
@ -56,6 +58,7 @@ class SearchTracks:
track_titles, track_titles,
score_cutoff=Cutoff.tracks, score_cutoff=Cutoff.tracks,
limit=Limit.tracks, limit=Limit.tracks,
processor=utils.default_process,
) )
tracks = [self.tracks[i[2]] for i in results] tracks = [self.tracks[i[2]] for i in results]
@ -67,7 +70,7 @@ class SearchArtists:
self.query = query self.query = query
self.artists = ArtistStore.artists self.artists = ArtistStore.artists
def __call__(self) -> list: def __call__(self):
""" """
Gets all artists with a given name. Gets all artists with a given name.
""" """
@ -78,6 +81,7 @@ class SearchArtists:
artists, artists,
score_cutoff=Cutoff.artists, score_cutoff=Cutoff.artists,
limit=Limit.artists, limit=Limit.artists,
processor=utils.default_process,
) )
return [self.artists[i[2]] for i in results] return [self.artists[i[2]] for i in results]
@ -100,17 +104,11 @@ class SearchAlbums:
albums, albums,
score_cutoff=Cutoff.albums, score_cutoff=Cutoff.albums,
limit=Limit.albums, limit=Limit.albums,
processor=utils.default_process,
) )
return [self.albums[i[2]] for i in results] return [self.albums[i[2]] for i in results]
# get all artists that matched the query
# for get all albums from the artists
# get all albums that matched the query
# return [**artist_albums **albums]
# recheck next and previous artist on play next or add to playlist
class SearchPlaylists: class SearchPlaylists:
def __init__(self, playlists: List[models.Playlist], query: str) -> None: def __init__(self, playlists: List[models.Playlist], query: str) -> None:
@ -124,12 +122,13 @@ class SearchPlaylists:
playlists, playlists,
score_cutoff=Cutoff.playlists, score_cutoff=Cutoff.playlists,
limit=Limit.playlists, limit=Limit.playlists,
processor=utils.default_process,
) )
return [self.playlists[i[2]] for i in results] return [self.playlists[i[2]] for i in results]
_type = List[models.Track | models.Album | models.Artist] _type = models.Track | models.Album | models.Artist
_S2 = TypeVar("_S2") _S2 = TypeVar("_S2")
_ResultType = int | float _ResultType = int | float
@ -148,7 +147,7 @@ def get_titles(items: _type):
yield text yield text
class SearchAll: class TopResults:
""" """
Joins all tracks, albums and artists Joins all tracks, albums and artists
then fuzzy searches them as a single unit. then fuzzy searches them as a single unit.
@ -156,11 +155,11 @@ class SearchAll:
@staticmethod @staticmethod
def collect_all(): def collect_all():
all_items: _type = [] all_items: list[_type] = []
all_items.extend(ArtistStore.artists)
all_items.extend(TrackStore.tracks) all_items.extend(TrackStore.tracks)
all_items.extend(AlbumStore.albums) all_items.extend(AlbumStore.albums)
all_items.extend(ArtistStore.artists)
return all_items, get_titles(all_items) return all_items, get_titles(all_items)
@ -169,44 +168,157 @@ class SearchAll:
items = list(items) items = list(items)
results = process.extract( results = process.extract(
query=query, query=query, choices=items, score_cutoff=Cutoff.tracks, limit=1
choices=items,
score_cutoff=Cutoff.tracks,
limit=20
) )
return results return results
@staticmethod @staticmethod
def sort_results(items: _type): def map_with_type(item: _type):
""" """
Separates results into differrent lists using itertools.groupby. Map the results to their respective types.
""" """
mapped_items = [ if isinstance(item, models.Track):
{"type": "track", "item": item} if isinstance(item, models.Track) else return {"type": "track", "item": item}
{"type": "album", "item": item} if isinstance(item, models.Album) else
{"type": "artist", "item": item} if isinstance(item, models.Artist) else
{"type": "Unknown", "item": item} for item in items
]
mapped_items.sort(key=lambda x: x["type"]) if isinstance(item, models.Album):
tracks = TrackStore.get_tracks_by_albumhash(item.albumhash)
tracks = remove_duplicates(tracks)
groups = [ item.get_date_from_tracks(tracks)
list(group) for key, group in try:
itertools.groupby(mapped_items, lambda x: x["type"]) item.duration = sum((t.duration for t in tracks))
] except AttributeError:
item.duration = 0
# merge items of a group into a dict that looks like: {"albums": [album1, ...]} item.check_is_single(tracks)
groups = [
{f"{group[0]['type']}s": [i['item'] for i in group]} for group in groups
]
return groups if not item.is_single:
item.check_type()
item.is_favorite = favdb.check_is_favorite(
item.albumhash, fav_type=FavType.album
)
return {"type": "album", "item": item}
if isinstance(item, models.Artist):
track_count = 0
duration = 0
for track in TrackStore.get_tracks_by_artisthash(item.artisthash):
track_count += 1
duration += track.duration
album_count = AlbumStore.count_albums_by_artisthash(item.artisthash)
item.set_trackcount(track_count)
item.set_albumcount(album_count)
item.set_duration(duration)
return {"type": "artist", "item": item}
@staticmethod @staticmethod
def search(query: str): def get_track_items(item: dict[str, _type], query: str, limit=5):
items, titles = SearchAll.collect_all() tracks: list[Track] = []
results = SearchAll.get_results(titles, query)
results = [items[i[2]] for i in results]
return SearchAll.sort_results(results) if item["type"] == "track":
tracks.extend(SearchTracks(query)())
if item["type"] == "album":
t = TrackStore.get_tracks_by_albumhash(item["item"].albumhash)
t.sort(key=lambda x: x.last_mod)
# if there are less than the limit, get more tracks
if len(t) < limit:
remainder = limit - len(t)
more_tracks = SearchTracks(query)()
t.extend(more_tracks[:remainder])
tracks.extend(t)
if item["type"] == "artist":
t = TrackStore.get_tracks_by_artisthash(item["item"].artisthash)
t.sort(key=lambda x: x.last_mod)
# if there are less than the limit, get more tracks
if len(t) < limit:
remainder = limit - len(t)
more_tracks = SearchTracks(query)()
t.extend(more_tracks[:remainder])
tracks.extend(t)
return tracks[:limit]
@staticmethod
def get_album_items(item: dict[str, _type], query: str, limit=6):
if item["type"] == "track":
return SearchAlbums(query)()[:limit]
if item["type"] == "album":
return SearchAlbums(query)()[:limit]
if item["type"] == "artist":
albums = AlbumStore.get_albums_by_artisthash(item["item"].artisthash)
# if there are less than the limit, get more albums
if len(albums) < limit:
remainder = limit - len(albums)
more_albums = SearchAlbums(query)()
albums.extend(more_albums[:remainder])
return albums[:limit]
@staticmethod
def search(query: str, albums_only=False, tracks_only=False, in_quotes=False):
items, titles = TopResults.collect_all()
results = TopResults.get_results(titles, query)
tracks_limit = Limit.tracks if tracks_only else 5
albums_limit = Limit.albums if albums_only else 6
artists_limit = 3
# map results to their respective items
try:
result = [items[i[2]] for i in results][0]
except IndexError:
if tracks_only:
return []
if albums_only:
return []
return {
"top_result": None,
"tracks": [],
"artists": [],
"albums": [],
}
result = TopResults.map_with_type(result)
if in_quotes:
top_tracks = SearchTracks(query)()[:tracks_limit]
else:
top_tracks = TopResults.get_track_items(result, query, limit=tracks_limit)
if tracks_only:
return top_tracks
if in_quotes:
albums = SearchAlbums(query)()[:albums_limit]
else:
albums = TopResults.get_album_items(result, query, limit=albums_limit)
if albums_only:
return albums
artists = SearchArtists(query)()[:artists_limit]
return {
"top_result": result,
"tracks": top_tracks,
"artists": artists,
"albums": albums,
}

View File

@ -10,12 +10,10 @@ from watchdog.events import PatternMatchingEventHandler
from watchdog.observers import Observer from watchdog.observers import Observer
from app import settings from app import settings
from app.db.sqlite.albumcolors import SQLiteAlbumMethods as aldb
from app.db.sqlite.settings import SettingsSQLMethods as sdb from app.db.sqlite.settings import SettingsSQLMethods as sdb
from app.db.sqlite.tracks import SQLiteManager from app.db.sqlite.tracks import SQLiteManager
from app.db.sqlite.tracks import SQLiteTrackMethods as db from app.db.sqlite.tracks import SQLiteTrackMethods as db
from app.db.sqlite.albumcolors import SQLiteAlbumMethods as aldb
from app.lib.colorlib import process_color from app.lib.colorlib import process_color
from app.lib.taglib import extract_thumb, get_tags from app.lib.taglib import extract_thumb, get_tags
from app.logger import log from app.logger import log
@ -199,7 +197,7 @@ def remove_track(filepath: str) -> None:
db.remove_tracks_by_filepaths(filepath) db.remove_tracks_by_filepaths(filepath)
TrackStore.remove_track_by_filepath(filepath) TrackStore.remove_track_by_filepath(filepath)
empty_album = TrackStore.count_tracks_by_hash(track.albumhash) > 0 empty_album = TrackStore.count_tracks_by_trackhash(track.albumhash) > 0
if empty_album: if empty_album:
AlbumStore.remove_album_by_hash(track.albumhash) AlbumStore.remove_album_by_hash(track.albumhash)

View File

@ -84,18 +84,11 @@ class TrackStore:
tdb.remove_tracks_by_folders(to_remove) tdb.remove_tracks_by_folders(to_remove)
@classmethod @classmethod
def count_tracks_by_hash(cls, trackhash: str) -> int: def count_tracks_by_trackhash(cls, trackhash: str) -> int:
""" """
Counts the number of tracks with a specific hash. Counts the number of tracks with a specific trackhash.
""" """
return sum(1 for track in cls.tracks if track.trackhash == trackhash)
count = 0
for track in cls.tracks:
if track.trackhash == trackhash:
count += 1
return count
@classmethod @classmethod
def make_track_fav(cls, trackhash: str): def make_track_fav(cls, trackhash: str):