mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-03 20:13:02 +00:00
rewrite album and artist stores using in-mem hashmap stores
This commit is contained in:
+36
-27
@@ -4,26 +4,24 @@ Contains all the album routes.
|
|||||||
|
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from pydantic import Field
|
from pydantic import BaseModel, Field
|
||||||
from flask_openapi3 import Tag
|
from flask_openapi3 import Tag
|
||||||
from flask_openapi3 import APIBlueprint
|
from flask_openapi3 import APIBlueprint
|
||||||
from app.api.apischemas import AlbumHashSchema, AlbumLimitSchema, ArtistHashSchema
|
from app.api.apischemas import AlbumHashSchema, AlbumLimitSchema, ArtistHashSchema
|
||||||
|
|
||||||
from app.config import UserConfig
|
from app.config import UserConfig
|
||||||
from app.db.libdata import ArtistTable
|
|
||||||
from app.db.libdata import AlbumTable as AlbumDb, TrackTable as TrackDb
|
|
||||||
from app.db.userdata import SimilarArtistTable
|
from app.db.userdata import SimilarArtistTable
|
||||||
|
from app.models.album import Album
|
||||||
from app.settings import Defaults
|
from app.settings import Defaults
|
||||||
from app.utils import flatten
|
from app.store.albums import AlbumStore
|
||||||
|
from app.store.artists import ArtistStore
|
||||||
|
from app.store.tracks import TrackStore
|
||||||
from app.utils.hashing import create_hash
|
from app.utils.hashing import create_hash
|
||||||
from app.lib.albumslib import sort_by_track_no
|
from app.lib.albumslib import sort_by_track_no
|
||||||
from app.serializers.album import serialize_for_card_many
|
from app.serializers.album import serialize_for_card_many
|
||||||
from app.serializers.track import serialize_tracks
|
from app.serializers.track import serialize_tracks
|
||||||
from app.db.sqlite.albumcolors import SQLiteAlbumMethods as adb
|
|
||||||
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
||||||
from app.db.sqlite.lastfm.similar_artists import SQLiteLastFMSimilarArtists as lastfmdb
|
|
||||||
|
|
||||||
get_albums_by_albumartist = adb.get_albums_by_albumartist
|
|
||||||
check_is_fav = favdb.check_is_favorite
|
check_is_fav = favdb.check_is_favorite
|
||||||
|
|
||||||
bp_tag = Tag(name="Album", description="Single album")
|
bp_tag = Tag(name="Album", description="Single album")
|
||||||
@@ -39,12 +37,14 @@ def get_album_tracks_and_info(body: AlbumHashSchema):
|
|||||||
Returns album info and tracks for the given albumhash.
|
Returns album info and tracks for the given albumhash.
|
||||||
"""
|
"""
|
||||||
albumhash = body.albumhash
|
albumhash = body.albumhash
|
||||||
album = AlbumDb.get_album_by_albumhash(albumhash)
|
# album = AlbumDb.get_album_by_albumhash(albumhash)
|
||||||
|
albumentry = AlbumStore.albummap.get(albumhash)
|
||||||
|
|
||||||
if album is None:
|
if albumentry is None:
|
||||||
return {"error": "Album not found"}, 404
|
return {"error": "Album not found"}, 404
|
||||||
|
|
||||||
tracks = TrackDb.get_tracks_by_albumhash(albumhash)
|
album = albumentry.album
|
||||||
|
tracks = TrackStore.get_tracks_by_trackhashes(albumentry.trackhashes)
|
||||||
album.trackcount = len(tracks)
|
album.trackcount = len(tracks)
|
||||||
album.duration = sum(t.duration for t in tracks)
|
album.duration = sum(t.duration for t in tracks)
|
||||||
album.check_type(
|
album.check_type(
|
||||||
@@ -52,6 +52,7 @@ def get_album_tracks_and_info(body: AlbumHashSchema):
|
|||||||
)
|
)
|
||||||
|
|
||||||
track_total = sum({int(t.extra.get("track_total", 1) or 1) for t in tracks})
|
track_total = sum({int(t.extra.get("track_total", 1) or 1) for t in tracks})
|
||||||
|
avg_bitrate = sum(t.bitrate for t in tracks) // (len(tracks) or 1)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"info": album,
|
"info": album,
|
||||||
@@ -61,7 +62,7 @@ def get_album_tracks_and_info(body: AlbumHashSchema):
|
|||||||
# 1. All the tracks have the correct track totals
|
# 1. All the tracks have the correct track totals
|
||||||
# 2. Tracks with the same track total are from the same disc
|
# 2. Tracks with the same track total are from the same disc
|
||||||
"track_total": track_total,
|
"track_total": track_total,
|
||||||
"avg_bitrate": sum(t.bitrate for t in tracks) // len(tracks),
|
"avg_bitrate": avg_bitrate,
|
||||||
},
|
},
|
||||||
"copyright": tracks[0].copyright,
|
"copyright": tracks[0].copyright,
|
||||||
"tracks": serialize_tracks(tracks, remove_disc=False),
|
"tracks": serialize_tracks(tracks, remove_disc=False),
|
||||||
@@ -76,7 +77,7 @@ def get_album_tracks(path: AlbumHashSchema):
|
|||||||
Returns all the tracks in the given album, sorted by disc and track number.
|
Returns all the tracks in the given album, sorted by disc and track number.
|
||||||
NOTE: No album info is returned.
|
NOTE: No album info is returned.
|
||||||
"""
|
"""
|
||||||
tracks = TrackDb.get_tracks_by_albumhash(path.albumhash)
|
tracks = AlbumStore.get_album_tracks(path.albumhash)
|
||||||
tracks = sort_by_track_no(tracks)
|
tracks = sort_by_track_no(tracks)
|
||||||
|
|
||||||
return serialize_tracks(tracks)
|
return serialize_tracks(tracks)
|
||||||
@@ -105,7 +106,11 @@ def get_more_from_artist(body: GetMoreFromArtistsBody):
|
|||||||
limit = body.limit
|
limit = body.limit
|
||||||
base_title = body.base_title
|
base_title = body.base_title
|
||||||
|
|
||||||
all_albums = AlbumDb.get_albums_by_artisthashes(albumartists)
|
all_albums: dict[str, list[Album]] = {}
|
||||||
|
|
||||||
|
for artisthash in albumartists:
|
||||||
|
all_albums[artisthash] = AlbumStore.get_albums_by_artisthash(artisthash)
|
||||||
|
|
||||||
seen_hashes = set()
|
seen_hashes = set()
|
||||||
|
|
||||||
for artisthash, albums in all_albums.items():
|
for artisthash, albums in all_albums.items():
|
||||||
@@ -128,14 +133,15 @@ def get_more_from_artist(body: GetMoreFromArtistsBody):
|
|||||||
return all_albums
|
return all_albums
|
||||||
|
|
||||||
|
|
||||||
class GetAlbumVersionsBody(ArtistHashSchema):
|
class GetAlbumVersionsBody(BaseModel):
|
||||||
og_album_title: str = Field(
|
og_album_title: str = Field(
|
||||||
description="The original album title (album.og_title)",
|
description="The original album title (album.og_title)",
|
||||||
example=Defaults.API_ALBUMNAME,
|
example=Defaults.API_ALBUMNAME,
|
||||||
)
|
)
|
||||||
base_title: str = Field(
|
|
||||||
description="The base title of the album to exclude from the results.",
|
albumhash: str = Field(
|
||||||
example=Defaults.API_ALBUMNAME,
|
description="The album hash of the album to exclude from the results.",
|
||||||
|
example=Defaults.API_ALBUMHASH,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -146,18 +152,23 @@ def get_album_versions(body: GetAlbumVersionsBody):
|
|||||||
|
|
||||||
Returns other versions of the given album.
|
Returns other versions of the given album.
|
||||||
"""
|
"""
|
||||||
og_album_title = body.og_album_title
|
albumhash = body.albumhash
|
||||||
base_title = body.base_title
|
|
||||||
artisthash = body.artisthash
|
|
||||||
|
|
||||||
albums = AlbumDb.get_albums_by_base_title(base_title)
|
album = AlbumStore.albummap.get(albumhash)
|
||||||
|
if not album:
|
||||||
|
return []
|
||||||
|
artisthash = album.album.artisthashes[0]
|
||||||
|
albums = AlbumStore.get_albums_by_artisthash(artisthash)
|
||||||
|
|
||||||
|
basetitle = album.basetitle
|
||||||
albums = [
|
albums = [
|
||||||
a
|
a
|
||||||
for a in albums
|
for a in albums
|
||||||
if a.og_title != og_album_title
|
if a.og_title != album.album.og_title
|
||||||
|
if a.base_title == basetitle
|
||||||
and artisthash in {a["artisthash"] for a in a.albumartists}
|
and artisthash in {a["artisthash"] for a in a.albumartists}
|
||||||
]
|
]
|
||||||
print(albums)
|
|
||||||
return serialize_for_card_many(albums)
|
return serialize_for_card_many(albums)
|
||||||
|
|
||||||
|
|
||||||
@@ -181,10 +192,8 @@ def get_similar_albums(query: GetSimilarAlbumsQuery):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
artisthashes = similar_artists.get_artist_hash_set()
|
artisthashes = similar_artists.get_artist_hash_set()
|
||||||
artists = ArtistTable.get_artists_by_artisthashes(artisthashes)
|
artists = ArtistStore.get_artists_by_hashes(artisthashes)
|
||||||
|
albums = AlbumStore.get_albums_by_artisthashes([a.artisthash for a in artists])
|
||||||
albums = AlbumDb.get_albums_by_artisthashes([a.artisthash for a in artists])
|
|
||||||
albums = flatten(albums.values())
|
|
||||||
sample = random.sample(albums, min(len(albums), limit))
|
sample = random.sample(albums, min(len(albums), limit))
|
||||||
|
|
||||||
return serialize_for_card_many(sample[:limit])
|
return serialize_for_card_many(sample[:limit])
|
||||||
|
|||||||
+17
-14
@@ -17,14 +17,16 @@ from app.api.apischemas import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
from app.config import UserConfig
|
from app.config import UserConfig
|
||||||
from app.db.libdata import ArtistTable
|
|
||||||
from app.db.libdata import AlbumTable, TrackTable
|
|
||||||
from app.db.userdata import SimilarArtistTable
|
from app.db.userdata import SimilarArtistTable
|
||||||
|
|
||||||
from app.serializers.album import serialize_for_card_many
|
from app.serializers.album import serialize_for_card_many
|
||||||
from app.serializers.artist import serialize_for_cards
|
from app.serializers.artist import serialize_for_cards
|
||||||
from app.serializers.track import serialize_tracks
|
from app.serializers.track import serialize_tracks
|
||||||
|
|
||||||
|
from app.store.albums import AlbumStore
|
||||||
|
from app.store.artists import ArtistStore
|
||||||
|
from app.store.tracks import TrackStore
|
||||||
|
|
||||||
bp_tag = Tag(name="Artist", description="Single artist")
|
bp_tag = Tag(name="Artist", description="Single artist")
|
||||||
api = APIBlueprint("artist", __name__, url_prefix="/artist", abp_tags=[bp_tag])
|
api = APIBlueprint("artist", __name__, url_prefix="/artist", abp_tags=[bp_tag])
|
||||||
|
|
||||||
@@ -39,13 +41,15 @@ def get_artist(path: ArtistHashSchema, query: TrackLimitSchema):
|
|||||||
artisthash = path.artisthash
|
artisthash = path.artisthash
|
||||||
limit = query.limit
|
limit = query.limit
|
||||||
|
|
||||||
artist = ArtistTable.get_artist_by_hash(artisthash)
|
entry = ArtistStore.artistmap.get(artisthash)
|
||||||
if artist is None:
|
|
||||||
|
if entry is None:
|
||||||
return {"error": "Artist not found"}, 404
|
return {"error": "Artist not found"}, 404
|
||||||
|
|
||||||
tracks = TrackTable.get_tracks_by_artisthash(artisthash)
|
tracks = TrackStore.get_tracks_by_trackhashes(entry.trackhashes)
|
||||||
tcount = len(tracks)
|
tcount = len(tracks)
|
||||||
|
|
||||||
|
artist = entry.artist
|
||||||
if artist.albumcount == 0 and tcount < 10:
|
if artist.albumcount == 0 and tcount < 10:
|
||||||
limit = tcount
|
limit = tcount
|
||||||
|
|
||||||
@@ -85,19 +89,19 @@ def get_artist_albums(path: ArtistHashSchema, query: GetArtistAlbumsQuery):
|
|||||||
|
|
||||||
limit = query.limit
|
limit = query.limit
|
||||||
|
|
||||||
artist = ArtistTable.get_artist_by_hash(artisthash)
|
entry = ArtistStore.artistmap.get(artisthash)
|
||||||
|
|
||||||
if artist is None:
|
if entry is None:
|
||||||
return {"error": "Artist not found"}, 404
|
return {"error": "Artist not found"}, 404
|
||||||
|
|
||||||
albums = AlbumTable.get_albums_by_artisthash(artisthash)
|
albums = AlbumStore.get_albums_by_hashes(entry.albumhashes)
|
||||||
tracks = TrackTable.get_tracks_by_artisthash(artisthash)
|
tracks = TrackStore.get_tracks_by_trackhashes(entry.trackhashes)
|
||||||
|
|
||||||
missing_albumhashes = {
|
missing_albumhashes = {
|
||||||
t.albumhash for t in tracks if t.albumhash not in {a.albumhash for a in albums}
|
t.albumhash for t in tracks if t.albumhash not in {a.albumhash for a in albums}
|
||||||
}
|
}
|
||||||
|
|
||||||
albums.extend(AlbumTable.get_albums_by_albumhashes(missing_albumhashes))
|
albums.extend(AlbumStore.get_albums_by_hashes(missing_albumhashes))
|
||||||
albumdict = {a.albumhash: a for a in albums}
|
albumdict = {a.albumhash: a for a in albums}
|
||||||
|
|
||||||
config = UserConfig()
|
config = UserConfig()
|
||||||
@@ -135,7 +139,7 @@ def get_artist_albums(path: ArtistHashSchema, query: GetArtistAlbumsQuery):
|
|||||||
for key, value in res.items():
|
for key, value in res.items():
|
||||||
res[key] = serialize_for_card_many(value[:limit])
|
res[key] = serialize_for_card_many(value[:limit])
|
||||||
|
|
||||||
res["artistname"] = artist.name
|
res["artistname"] = entry.artist.name
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
@@ -146,8 +150,7 @@ def get_all_artist_tracks(path: ArtistHashSchema):
|
|||||||
|
|
||||||
Returns all artists by a given artist.
|
Returns all artists by a given artist.
|
||||||
"""
|
"""
|
||||||
# tracks = TrackStore.get_tracks_by_artisthash(path.artisthash)
|
tracks = ArtistStore.get_artist_tracks(path.artisthash)
|
||||||
tracks = TrackTable.get_tracks_by_artisthash(path.artisthash)
|
|
||||||
return serialize_tracks(tracks)
|
return serialize_tracks(tracks)
|
||||||
|
|
||||||
|
|
||||||
@@ -162,7 +165,7 @@ def get_similar_artists(path: ArtistHashSchema, query: ArtistLimitSchema):
|
|||||||
if result is None:
|
if result is None:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
similar = ArtistTable.get_artists_by_artisthashes(result.get_artist_hash_set())
|
similar = ArtistStore.get_artists_by_hashes(result.get_artist_hash_set())
|
||||||
|
|
||||||
if len(similar) > limit:
|
if len(similar) > limit:
|
||||||
similar = random.sample(similar, min(limit, len(similar)))
|
similar = random.sample(similar, min(limit, len(similar)))
|
||||||
|
|||||||
@@ -317,7 +317,6 @@ class AlbumTable(Base):
|
|||||||
|
|
||||||
for artist in artisthashes:
|
for artist in artisthashes:
|
||||||
result = conn.execute(
|
result = conn.execute(
|
||||||
# NOTE: The artist dict keys need to in the same order they appear in the db for this to work!
|
|
||||||
select(AlbumTable).where(AlbumTable.artisthashes.contains(artist))
|
select(AlbumTable).where(AlbumTable.artisthashes.contains(artist))
|
||||||
)
|
)
|
||||||
albums[artist] = albums_to_dataclasses(result.fetchall())
|
albums[artist] = albums_to_dataclasses(result.fetchall())
|
||||||
|
|||||||
+2
-3
@@ -12,8 +12,7 @@ from app.db.sqlite.albumcolors import SQLiteAlbumMethods as aldb
|
|||||||
from app.db.sqlite.artistcolors import SQLiteArtistMethods as adb
|
from app.db.sqlite.artistcolors import SQLiteArtistMethods as adb
|
||||||
from app.db.sqlite.utils import SQLiteManager
|
from app.db.sqlite.utils import SQLiteManager
|
||||||
|
|
||||||
from app.store.artists import ArtistStore
|
# from app.store.artists import ArtistStore
|
||||||
from app.store.albums import AlbumStore
|
|
||||||
from app.logger import log
|
from app.logger import log
|
||||||
from app.lib.errors import PopulateCancelledError
|
from app.lib.errors import PopulateCancelledError
|
||||||
from app.utils.progressbar import tqdm
|
from app.utils.progressbar import tqdm
|
||||||
@@ -101,7 +100,7 @@ class ProcessArtistColors:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, instance_key: str) -> None:
|
def __init__(self, instance_key: str) -> None:
|
||||||
all_artists = [a for a in ArtistStore.artists if len(a.colors) == 0]
|
# all_artists = [a for a in ArtistStore.artists if len(a.colors) == 0]
|
||||||
|
|
||||||
global PROCESS_ARTIST_COLORS_KEY
|
global PROCESS_ARTIST_COLORS_KEY
|
||||||
PROCESS_ARTIST_COLORS_KEY = instance_key
|
PROCESS_ARTIST_COLORS_KEY = instance_key
|
||||||
|
|||||||
+121
-122
@@ -2,13 +2,14 @@ import gc
|
|||||||
import os
|
import os
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
from time import time
|
from time import time
|
||||||
from typing import Generator
|
|
||||||
from app import settings
|
from app import settings
|
||||||
from app.config import UserConfig
|
from app.config import UserConfig
|
||||||
from app.db.libdata import ArtistTable
|
from app.db.libdata import ArtistTable
|
||||||
from app.db.libdata import AlbumTable, TrackTable
|
from app.db.libdata import TrackTable
|
||||||
from app.lib.populate import CordinateMedia
|
from app.lib.populate import CordinateMedia
|
||||||
from app.lib.taglib import extract_thumb, get_tags
|
from app.lib.taglib import extract_thumb, get_tags
|
||||||
|
from app.models.album import Album
|
||||||
|
from app.models.artist import Artist
|
||||||
from app.models.track import Track
|
from app.models.track import Track
|
||||||
from app.store.folder import FolderStore
|
from app.store.folder import FolderStore
|
||||||
from app.utils.filesystem import run_fast_scandir
|
from app.utils.filesystem import run_fast_scandir
|
||||||
@@ -141,154 +142,152 @@ class IndexTracks:
|
|||||||
print("Done")
|
print("Done")
|
||||||
|
|
||||||
|
|
||||||
class IndexAlbums:
|
# class IndexAlbums:
|
||||||
def __init__(self) -> None:
|
def create_albums():
|
||||||
albums = dict()
|
albums = dict()
|
||||||
all_tracks: list[Track] = TrackTable.get_all()
|
all_tracks: list[Track] = TrackTable.get_all()
|
||||||
|
|
||||||
if len(all_tracks) == 0:
|
for track in all_tracks:
|
||||||
return
|
if track.albumhash not in albums:
|
||||||
|
albums[track.albumhash] = {
|
||||||
|
"albumartists": track.albumartists,
|
||||||
|
"artisthashes": [a["artisthash"] for a in track.albumartists],
|
||||||
|
"albumhash": track.albumhash,
|
||||||
|
"base_title": None,
|
||||||
|
"color": None,
|
||||||
|
"created_date": track.last_mod,
|
||||||
|
"date": track.date,
|
||||||
|
"duration": track.duration,
|
||||||
|
"genres": [*track.genres] if track.genres else [],
|
||||||
|
"og_title": track.og_album,
|
||||||
|
"lastplayed": track.lastplayed,
|
||||||
|
"playcount": track.playcount,
|
||||||
|
"playduration": track.playduration,
|
||||||
|
"title": track.album,
|
||||||
|
"trackcount": 1,
|
||||||
|
"extra": {}
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
album = albums[track.albumhash]
|
||||||
|
album["trackcount"] += 1
|
||||||
|
album["playcount"] += track.playcount
|
||||||
|
album["playduration"] += track.playduration
|
||||||
|
album["lastplayed"] = max(album["lastplayed"], track.lastplayed)
|
||||||
|
album["duration"] += track.duration
|
||||||
|
album["date"] = min(album["date"], track.date)
|
||||||
|
album["created_date"] = min(album["created_date"], track.last_mod)
|
||||||
|
|
||||||
for track in all_tracks:
|
if track.genres:
|
||||||
if track.albumhash not in albums:
|
album["genres"].extend(track.genres)
|
||||||
albums[track.albumhash] = {
|
|
||||||
"albumartists": track.albumartists,
|
for album in albums.values():
|
||||||
"artisthashes": [a["artisthash"] for a in track.albumartists],
|
genres = []
|
||||||
"albumhash": track.albumhash,
|
for genre in album["genres"]:
|
||||||
"base_title": None,
|
if genre not in genres:
|
||||||
"color": None,
|
genres.append(genre)
|
||||||
|
|
||||||
|
album["genres"] = genres
|
||||||
|
album["genrehashes"] = " ".join([g['genrehash'] for g in genres])
|
||||||
|
album["base_title"], _ = get_base_album_title(album["og_title"])
|
||||||
|
|
||||||
|
del genres
|
||||||
|
|
||||||
|
# AlbumTable.remove_all()
|
||||||
|
# AlbumTable.insert_many(list(albums.values()))
|
||||||
|
return [Album(**album) for album in albums.values()]
|
||||||
|
|
||||||
|
|
||||||
|
# class IndexArtists:
|
||||||
|
def create_artists():
|
||||||
|
all_tracks: list[Track] = TrackTable.get_all()
|
||||||
|
artists = dict()
|
||||||
|
|
||||||
|
for track in all_tracks:
|
||||||
|
this_artists = track.artists
|
||||||
|
|
||||||
|
for a in track.albumartists:
|
||||||
|
if a not in this_artists:
|
||||||
|
a["in_track"] = False
|
||||||
|
this_artists.append(a)
|
||||||
|
|
||||||
|
for thisartist in this_artists:
|
||||||
|
if thisartist["artisthash"] not in artists:
|
||||||
|
artists[thisartist["artisthash"]] = {
|
||||||
|
"albumcount": None,
|
||||||
|
"albums": {track.albumhash},
|
||||||
|
"artisthash": thisartist["artisthash"],
|
||||||
"created_date": track.last_mod,
|
"created_date": track.last_mod,
|
||||||
"date": track.date,
|
"date": track.date,
|
||||||
"duration": track.duration,
|
"duration": track.duration,
|
||||||
"genres": [*track.genres] if track.genres else [],
|
"genres": track.genres if track.genres else [],
|
||||||
"og_title": track.og_album,
|
"name": None,
|
||||||
|
"names": {thisartist["name"]},
|
||||||
"lastplayed": track.lastplayed,
|
"lastplayed": track.lastplayed,
|
||||||
"playcount": track.playcount,
|
"playcount": track.playcount,
|
||||||
"playduration": track.playduration,
|
"playduration": track.playduration,
|
||||||
"title": track.album,
|
"trackcount": None,
|
||||||
"trackcount": 1,
|
"tracks": (
|
||||||
|
{track.trackhash}
|
||||||
|
if thisartist.get("in_track", True)
|
||||||
|
else set()
|
||||||
|
),
|
||||||
|
"extra": {},
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
album = albums[track.albumhash]
|
artist = artists[thisartist["artisthash"]]
|
||||||
album["trackcount"] += 1
|
artist["duration"] += track.duration
|
||||||
album["playcount"] += track.playcount
|
artist["playcount"] += track.playcount
|
||||||
album["playduration"] += track.playduration
|
artist["playduration"] += track.playduration
|
||||||
album["lastplayed"] = max(album["lastplayed"], track.lastplayed)
|
artist["albums"].add(track.albumhash)
|
||||||
album["duration"] += track.duration
|
artist["date"] = min(artist["date"], track.date)
|
||||||
album["date"] = min(album["date"], track.date)
|
artist["lastplayed"] = max(artist["lastplayed"], track.lastplayed)
|
||||||
album["created_date"] = min(album["created_date"], track.last_mod)
|
artist["created_date"] = min(artist["created_date"], track.last_mod)
|
||||||
|
artist["names"].add(thisartist["name"])
|
||||||
|
|
||||||
|
if thisartist.get("in_track", True):
|
||||||
|
artist["tracks"].add(track.trackhash)
|
||||||
|
|
||||||
if track.genres:
|
if track.genres:
|
||||||
album["genres"].extend(track.genres)
|
artist["genres"].extend(track.genres)
|
||||||
|
|
||||||
for album in albums.values():
|
for artist in artists.values():
|
||||||
genres = []
|
artist["albumcount"] = len(artist["albums"])
|
||||||
for genre in album["genres"]:
|
artist["trackcount"] = len(artist["tracks"])
|
||||||
if genre not in genres:
|
|
||||||
genres.append(genre)
|
|
||||||
|
|
||||||
album["genres"] = genres
|
genres = []
|
||||||
album["base_title"], _ = get_base_album_title(album["og_title"])
|
|
||||||
|
|
||||||
del genres
|
for genre in artist["genres"]:
|
||||||
|
if genre not in genres:
|
||||||
|
genres.append(genre)
|
||||||
|
|
||||||
AlbumTable.remove_all()
|
artist["genres"] = genres
|
||||||
AlbumTable.insert_many(list(albums.values()))
|
artist["genrehashes"] = " ".join([g['genrehash'] for g in genres])
|
||||||
del albums
|
artist["name"] = sorted(artist["names"])[0]
|
||||||
|
|
||||||
|
# INFO: Delete temporary keys
|
||||||
|
del artist["names"]
|
||||||
|
del artist["tracks"]
|
||||||
|
del artist["albums"]
|
||||||
|
|
||||||
class IndexArtists:
|
# INFO: Delete local variables
|
||||||
def __init__(self) -> None:
|
del genres
|
||||||
all_tracks: list[Track] = TrackTable.get_all()
|
|
||||||
artists = dict()
|
|
||||||
|
|
||||||
if len(all_tracks) == 0:
|
# ArtistTable.remove_all()
|
||||||
return
|
# ArtistTable.insert_many(list(artists.values()))
|
||||||
|
# del artists
|
||||||
for track in all_tracks:
|
return [Artist(**artist) for artist in artists.values()]
|
||||||
this_artists = track.artists
|
|
||||||
|
|
||||||
for a in track.albumartists:
|
|
||||||
if a not in this_artists:
|
|
||||||
a["in_track"] = False
|
|
||||||
this_artists.append(a)
|
|
||||||
|
|
||||||
for thisartist in this_artists:
|
|
||||||
if thisartist["artisthash"] not in artists:
|
|
||||||
artists[thisartist["artisthash"]] = {
|
|
||||||
"albumcount": None,
|
|
||||||
"albums": {track.albumhash},
|
|
||||||
"artisthash": thisartist["artisthash"],
|
|
||||||
"created_date": track.last_mod,
|
|
||||||
"date": track.date,
|
|
||||||
"duration": track.duration,
|
|
||||||
"genres": track.genres if track.genres else [],
|
|
||||||
"name": None,
|
|
||||||
"names": {thisartist["name"]},
|
|
||||||
"lastplayed": track.lastplayed,
|
|
||||||
"playcount": track.playcount,
|
|
||||||
"playduration": track.playduration,
|
|
||||||
"trackcount": None,
|
|
||||||
"tracks": (
|
|
||||||
{track.trackhash}
|
|
||||||
if thisartist.get("in_track", True)
|
|
||||||
else set()
|
|
||||||
),
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
artist = artists[thisartist["artisthash"]]
|
|
||||||
artist["duration"] += track.duration
|
|
||||||
artist["playcount"] += track.playcount
|
|
||||||
artist["playduration"] += track.playduration
|
|
||||||
artist["albums"].add(track.albumhash)
|
|
||||||
artist["date"] = min(artist["date"], track.date)
|
|
||||||
artist["lastplayed"] = max(artist["lastplayed"], track.lastplayed)
|
|
||||||
artist["created_date"] = min(artist["created_date"], track.last_mod)
|
|
||||||
artist["names"].add(thisartist["name"])
|
|
||||||
|
|
||||||
|
|
||||||
if thisartist.get("in_track", True):
|
|
||||||
artist["tracks"].add(track.trackhash)
|
|
||||||
|
|
||||||
if track.genres:
|
|
||||||
artist["genres"].extend(track.genres)
|
|
||||||
|
|
||||||
for artist in artists.values():
|
|
||||||
artist["albumcount"] = len(artist["albums"])
|
|
||||||
artist["trackcount"] = len(artist["tracks"])
|
|
||||||
|
|
||||||
genres = []
|
|
||||||
|
|
||||||
for genre in artist["genres"]:
|
|
||||||
if genre not in genres:
|
|
||||||
genres.append(genre)
|
|
||||||
|
|
||||||
artist["genres"] = genres
|
|
||||||
artist["name"] = sorted(artist["names"])[0]
|
|
||||||
|
|
||||||
# INFO: Delete temporary keys
|
|
||||||
del artist["names"]
|
|
||||||
del artist["tracks"]
|
|
||||||
del artist["albums"]
|
|
||||||
|
|
||||||
# INFO: Delete local variables
|
|
||||||
del genres
|
|
||||||
|
|
||||||
ArtistTable.remove_all()
|
|
||||||
ArtistTable.insert_many(list(artists.values()))
|
|
||||||
del artists
|
|
||||||
|
|
||||||
|
|
||||||
class IndexEverything:
|
class IndexEverything:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
IndexTracks(instance_key=time())
|
IndexTracks(instance_key=time())
|
||||||
IndexAlbums()
|
# IndexAlbums()
|
||||||
IndexArtists()
|
# IndexArtists()
|
||||||
FolderStore.load_filepaths()
|
FolderStore.load_filepaths()
|
||||||
|
|
||||||
# pass
|
# pass
|
||||||
|
|
||||||
CordinateMedia(instance_key=str(time()))
|
# CordinateMedia(instance_key=str(time()))
|
||||||
gc.collect()
|
gc.collect()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,6 @@ class Album:
|
|||||||
Creates an album object
|
Creates an album object
|
||||||
"""
|
"""
|
||||||
|
|
||||||
id: int
|
|
||||||
albumartists: list[dict[str, str]]
|
albumartists: list[dict[str, str]]
|
||||||
albumhash: str
|
albumhash: str
|
||||||
artisthashes: list[str]
|
artisthashes: list[str]
|
||||||
@@ -34,6 +33,7 @@ class Album:
|
|||||||
playduration: int
|
playduration: int
|
||||||
extra: dict
|
extra: dict
|
||||||
|
|
||||||
|
id: int = -1
|
||||||
type: str = "album"
|
type: str = "album"
|
||||||
image: str = ""
|
image: str = ""
|
||||||
versions: list[str] = dataclasses.field(default_factory=list)
|
versions: list[str] = dataclasses.field(default_factory=list)
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ class Artist:
|
|||||||
Artist class
|
Artist class
|
||||||
"""
|
"""
|
||||||
|
|
||||||
id: str
|
|
||||||
name: str
|
name: str
|
||||||
albumcount: int
|
albumcount: int
|
||||||
artisthash: str
|
artisthash: str
|
||||||
@@ -53,6 +52,7 @@ class Artist:
|
|||||||
playduration: int
|
playduration: int
|
||||||
extra: dict
|
extra: dict
|
||||||
|
|
||||||
|
id: int = -1
|
||||||
image: str = ""
|
image: str = ""
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
|
|||||||
@@ -47,4 +47,6 @@ def load_into_mem():
|
|||||||
# AlbumStore.load_albums(instance_key)
|
# AlbumStore.load_albums(instance_key)
|
||||||
# ArtistStore.load_artists(instance_key)
|
# ArtistStore.load_artists(instance_key)
|
||||||
TrackStore.load_all_tracks(get_random_str())
|
TrackStore.load_all_tracks(get_random_str())
|
||||||
|
AlbumStore.load_albums('a')
|
||||||
|
ArtistStore.load_artists('a')
|
||||||
FolderStore.load_filepaths()
|
FolderStore.load_filepaths()
|
||||||
+66
-48
@@ -1,9 +1,13 @@
|
|||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
import json
|
import json
|
||||||
|
from pprint import pprint
|
||||||
import random
|
import random
|
||||||
|
from typing import Iterable
|
||||||
|
|
||||||
from app.db.sqlite.albumcolors import SQLiteAlbumMethods as aldb
|
from app.db.sqlite.albumcolors import SQLiteAlbumMethods as aldb
|
||||||
|
from app.lib.tagger import create_albums
|
||||||
from app.models import Album, Track
|
from app.models import Album, Track
|
||||||
|
from app.store.artists import ArtistStore
|
||||||
from app.utils.customlist import CustomList
|
from app.utils.customlist import CustomList
|
||||||
from app.utils.remove_duplicates import remove_duplicates
|
from app.utils.remove_duplicates import remove_duplicates
|
||||||
|
|
||||||
@@ -14,8 +18,19 @@ from app.utils.progressbar import tqdm
|
|||||||
ALBUM_LOAD_KEY = ""
|
ALBUM_LOAD_KEY = ""
|
||||||
|
|
||||||
|
|
||||||
|
class AlbumMapEntry:
|
||||||
|
def __init__(self, album: Album) -> None:
|
||||||
|
self.album = album
|
||||||
|
self.trackhashes: set[str] = set()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def basetitle(self):
|
||||||
|
return self.album.base_title
|
||||||
|
|
||||||
|
|
||||||
class AlbumStore:
|
class AlbumStore:
|
||||||
albums: list[Album] = CustomList()
|
albums: list[Album] = CustomList()
|
||||||
|
albummap: dict[str, AlbumMapEntry] = {}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_album(track: Track):
|
def create_album(track: Track):
|
||||||
@@ -36,43 +51,28 @@ class AlbumStore:
|
|||||||
global ALBUM_LOAD_KEY
|
global ALBUM_LOAD_KEY
|
||||||
ALBUM_LOAD_KEY = instance_key
|
ALBUM_LOAD_KEY = instance_key
|
||||||
|
|
||||||
cls.albums = CustomList()
|
|
||||||
|
|
||||||
print("Loading albums... ", end="")
|
print("Loading albums... ", end="")
|
||||||
tracks = remove_duplicates(TrackStore.tracks)
|
|
||||||
|
cls.albummap = {
|
||||||
|
album.albumhash: AlbumMapEntry(album=album) for album in create_albums()
|
||||||
|
}
|
||||||
|
tracks = remove_duplicates(TrackStore.get_flat_list())
|
||||||
tracks = sorted(tracks, key=lambda t: t.albumhash)
|
tracks = sorted(tracks, key=lambda t: t.albumhash)
|
||||||
grouped = groupby(tracks, lambda t: t.albumhash)
|
grouped = groupby(tracks, lambda t: t.albumhash)
|
||||||
|
|
||||||
for albumhash, tracks in grouped:
|
for albumhash, tracks in grouped:
|
||||||
tracks = list(tracks)
|
cls.albummap[albumhash].trackhashes = {t.trackhash for t in tracks}
|
||||||
sample = tracks[0]
|
|
||||||
|
|
||||||
if sample is None:
|
# db_albums: list[tuple] = aldb.get_all_albums()
|
||||||
continue
|
|
||||||
|
|
||||||
count = len(list(tracks))
|
# for album in db_albums:
|
||||||
duration = sum(t.duration for t in tracks)
|
# albumhash = album[1]
|
||||||
created_date = min(t.created_date for t in tracks)
|
# colors = json.loads(album[2])
|
||||||
|
|
||||||
album = AlbumStore.create_album(sample)
|
# for _al in cls.albums:
|
||||||
|
# if _al.albumhash == albumhash:
|
||||||
album.get_date_from_tracks(tracks)
|
# _al.set_colors(colors)
|
||||||
album.set_count(count)
|
# break
|
||||||
album.set_duration(duration)
|
|
||||||
album.set_created_date(created_date)
|
|
||||||
|
|
||||||
cls.albums.append(album)
|
|
||||||
|
|
||||||
db_albums: list[tuple] = aldb.get_all_albums()
|
|
||||||
|
|
||||||
for album in db_albums:
|
|
||||||
albumhash = album[1]
|
|
||||||
colors = json.loads(album[2])
|
|
||||||
|
|
||||||
for _al in cls.albums:
|
|
||||||
if _al.albumhash == albumhash:
|
|
||||||
_al.set_colors(colors)
|
|
||||||
break
|
|
||||||
|
|
||||||
print("Done!")
|
print("Done!")
|
||||||
|
|
||||||
@@ -98,9 +98,7 @@ class AlbumStore:
|
|||||||
Returns N albums by the given albumartist, excluding the specified album.
|
Returns N albums by the given albumartist, excluding the specified album.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
albums = [
|
albums = [album for album in cls.albums if artisthash in album.artisthashes]
|
||||||
album for album in cls.albums if artisthash in album.albumartists_hashes
|
|
||||||
]
|
|
||||||
|
|
||||||
albums = [
|
albums = [
|
||||||
album
|
album
|
||||||
@@ -126,25 +124,11 @@ class AlbumStore:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_albums_by_hashes(cls, albumhashes: list[str]) -> list[Album]:
|
def get_albums_by_hashes(cls, albumhashes: Iterable[str]) -> list[Album]:
|
||||||
"""
|
"""
|
||||||
Returns albums by their hashes.
|
Returns albums by their hashes.
|
||||||
"""
|
"""
|
||||||
albums_str = "-".join(albumhashes)
|
return [cls.albummap[albumhash].album for albumhash in albumhashes]
|
||||||
albums = [a for a in cls.albums if a.albumhash in albums_str]
|
|
||||||
|
|
||||||
# sort albums by the order of the hashes
|
|
||||||
albums.sort(key=lambda x: albumhashes.index(x.albumhash))
|
|
||||||
return albums
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_albums_by_artisthash(cls, artisthash: str) -> list[Album]:
|
|
||||||
"""
|
|
||||||
Returns all albums by the given artist.
|
|
||||||
"""
|
|
||||||
return [
|
|
||||||
album for album in cls.albums if artisthash in album.albumartists_hashes
|
|
||||||
]
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def count_albums_by_artisthash(cls, artisthash: str):
|
def count_albums_by_artisthash(cls, artisthash: str):
|
||||||
@@ -174,3 +158,37 @@ class AlbumStore:
|
|||||||
Removes an album from the store.
|
Removes an album from the store.
|
||||||
"""
|
"""
|
||||||
cls.albums = CustomList(a for a in cls.albums if a.albumhash != albumhash)
|
cls.albums = CustomList(a for a in cls.albums if a.albumhash != albumhash)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_albums_by_artisthash(cls, hash: str):
|
||||||
|
"""
|
||||||
|
Returns all albums by the given artist hash.
|
||||||
|
"""
|
||||||
|
artist = ArtistStore.artistmap.get(hash)
|
||||||
|
|
||||||
|
if not artist:
|
||||||
|
return []
|
||||||
|
|
||||||
|
return [cls.albummap[albumhash].album for albumhash in artist.albumhashes]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_albums_by_artisthashes(cls, hashes: Iterable[str]):
|
||||||
|
"""
|
||||||
|
Returns all albums by the given artist hashes.
|
||||||
|
"""
|
||||||
|
albums = []
|
||||||
|
for hash in hashes:
|
||||||
|
albums.extend(cls.get_albums_by_artisthash(hash))
|
||||||
|
|
||||||
|
return albums
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_album_tracks(cls, albumhash: str) -> list[Track]:
|
||||||
|
"""
|
||||||
|
Returns all tracks for the given album hash.
|
||||||
|
"""
|
||||||
|
album = cls.albummap.get(albumhash)
|
||||||
|
if not album:
|
||||||
|
return []
|
||||||
|
|
||||||
|
return TrackStore.get_tracks_by_trackhashes(album.trackhashes)
|
||||||
|
|||||||
+46
-16
@@ -1,19 +1,30 @@
|
|||||||
import json
|
import json
|
||||||
|
from typing import Iterable
|
||||||
|
|
||||||
from app.db.sqlite.artistcolors import SQLiteArtistMethods as ardb
|
from app.db.sqlite.artistcolors import SQLiteArtistMethods as ardb
|
||||||
|
from app.lib.tagger import create_artists
|
||||||
from app.models import Artist
|
from app.models import Artist
|
||||||
from app.utils.bisection import use_bisection
|
from app.utils.bisection import use_bisection
|
||||||
from app.utils.customlist import CustomList
|
from app.utils.customlist import CustomList
|
||||||
from app.utils.progressbar import tqdm
|
from app.utils.progressbar import tqdm
|
||||||
|
from .tracks import TrackStore
|
||||||
|
|
||||||
from .albums import AlbumStore
|
# from .albums import AlbumStore
|
||||||
from .tracks import TrackStore
|
from .tracks import TrackStore
|
||||||
|
|
||||||
ARTIST_LOAD_KEY = ""
|
ARTIST_LOAD_KEY = ""
|
||||||
|
|
||||||
|
|
||||||
|
class ArtistMapEntry:
|
||||||
|
def __init__(self, artist: Artist) -> None:
|
||||||
|
self.artist = artist
|
||||||
|
self.albumhashes: set[str] = set()
|
||||||
|
self.trackhashes: set[str] = set()
|
||||||
|
|
||||||
|
|
||||||
class ArtistStore:
|
class ArtistStore:
|
||||||
artists: list[Artist] = CustomList()
|
artists: list[Artist] = CustomList()
|
||||||
|
artistmap: dict[str, ArtistMapEntry] = {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load_artists(cls, instance_key: str):
|
def load_artists(cls, instance_key: str):
|
||||||
@@ -24,15 +35,27 @@ class ArtistStore:
|
|||||||
ARTIST_LOAD_KEY = instance_key
|
ARTIST_LOAD_KEY = instance_key
|
||||||
|
|
||||||
print("Loading artists... ", end="")
|
print("Loading artists... ", end="")
|
||||||
cls.artists.clear()
|
cls.artistmap.clear()
|
||||||
|
|
||||||
cls.artists.extend(get_all_artists(TrackStore.tracks, AlbumStore.albums))
|
cls.artistmap = {
|
||||||
print("Done!")
|
artist.artisthash: ArtistMapEntry(artist=artist)
|
||||||
for artist in ardb.get_all_artists():
|
for artist in create_artists()
|
||||||
|
}
|
||||||
|
|
||||||
|
for track in TrackStore.get_flat_list():
|
||||||
if instance_key != ARTIST_LOAD_KEY:
|
if instance_key != ARTIST_LOAD_KEY:
|
||||||
return
|
return
|
||||||
|
|
||||||
cls.map_artist_color(artist)
|
for hash in track.artisthashes:
|
||||||
|
cls.artistmap[hash].trackhashes.add(track.trackhash)
|
||||||
|
cls.artistmap[hash].albumhashes.add(track.albumhash)
|
||||||
|
|
||||||
|
print("Done!")
|
||||||
|
# for artist in ardb.get_all_artists():
|
||||||
|
# if instance_key != ARTIST_LOAD_KEY:
|
||||||
|
# return
|
||||||
|
|
||||||
|
# cls.map_artist_color(artist)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def map_artist_color(cls, artist_tuple: tuple):
|
def map_artist_color(cls, artist_tuple: tuple):
|
||||||
@@ -65,24 +88,20 @@ class ArtistStore:
|
|||||||
cls.artists.append(artist)
|
cls.artists.append(artist)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_artist_by_hash(cls, artisthash: str) -> Artist:
|
def get_artist_by_hash(cls, artisthash: str):
|
||||||
"""
|
"""
|
||||||
Returns an artist by its hash.P
|
Returns an artist by its hash.P
|
||||||
"""
|
"""
|
||||||
artists = sorted(cls.artists, key=lambda x: x.artisthash)
|
entry = cls.artistmap.get(artisthash, None)
|
||||||
try:
|
if entry is not None:
|
||||||
artist = use_bisection(artists, "artisthash", [artisthash])[0]
|
return entry.artist
|
||||||
return artist
|
|
||||||
except IndexError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_artists_by_hashes(cls, artisthashes: list[str]) -> list[Artist]:
|
def get_artists_by_hashes(cls, artisthashes: Iterable[str]):
|
||||||
"""
|
"""
|
||||||
Returns artists by their hashes.
|
Returns artists by their hashes.
|
||||||
"""
|
"""
|
||||||
artists = sorted(cls.artists, key=lambda x: x.artisthash)
|
artists = [cls.get_artist_by_hash(hash) for hash in artisthashes]
|
||||||
artists = use_bisection(artists, "artisthash", artisthashes)
|
|
||||||
return [a for a in artists if a is not None]
|
return [a for a in artists if a is not None]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@@ -113,3 +132,14 @@ class ArtistStore:
|
|||||||
Removes an artist from the store.
|
Removes an artist from the store.
|
||||||
"""
|
"""
|
||||||
cls.artists = CustomList(a for a in cls.artists if a.artisthash != artisthash)
|
cls.artists = CustomList(a for a in cls.artists if a.artisthash != artisthash)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_artist_tracks(cls, artisthash: str):
|
||||||
|
"""
|
||||||
|
Returns all tracks by the given artist hash.
|
||||||
|
"""
|
||||||
|
entry = cls.artistmap.get(artisthash)
|
||||||
|
if entry is not None:
|
||||||
|
return TrackStore.get_tracks_by_trackhashes(entry.trackhashes)
|
||||||
|
|
||||||
|
return []
|
||||||
|
|||||||
+5
-4
@@ -1,8 +1,7 @@
|
|||||||
# from tqdm import tqdm
|
# from tqdm import tqdm
|
||||||
|
|
||||||
import itertools
|
import itertools
|
||||||
import sys
|
from typing import Callable, Iterable
|
||||||
from typing import Callable
|
|
||||||
from flask_jwt_extended import current_user
|
from flask_jwt_extended import current_user
|
||||||
from app.db.libdata import TrackTable
|
from app.db.libdata import TrackTable
|
||||||
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
||||||
@@ -243,7 +242,7 @@ class TrackStore:
|
|||||||
# ================================================
|
# ================================================
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_tracks_by_trackhashes(cls, trackhashes: list[str]) -> list[Track]:
|
def get_tracks_by_trackhashes(cls, trackhashes: Iterable[str]) -> list[Track]:
|
||||||
"""
|
"""
|
||||||
Returns a list of tracks by their hashes.
|
Returns a list of tracks by their hashes.
|
||||||
"""
|
"""
|
||||||
@@ -259,7 +258,9 @@ class TrackStore:
|
|||||||
tracks.append(track)
|
tracks.append(track)
|
||||||
|
|
||||||
# sort the tracks in the order of the given trackhashes
|
# sort the tracks in the order of the given trackhashes
|
||||||
tracks.sort(key=lambda t: trackhashes.index(t.trackhash))
|
if type(trackhashes) == list:
|
||||||
|
tracks.sort(key=lambda t: trackhashes.index(t.trackhash))
|
||||||
|
|
||||||
return tracks
|
return tracks
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
Reference in New Issue
Block a user