diff --git a/app/api/folder.py b/app/api/folder.py index 2972c3e8..ff612b75 100644 --- a/app/api/folder.py +++ b/app/api/folder.py @@ -23,11 +23,46 @@ api = APIBlueprint("folder", __name__, url_prefix="/folder", abp_tags=[tag]) class FolderTree(BaseModel): - folder: str = Field( - "$home", example="$home", description="The folder to things from" + folder: str = Field("$home", description="The folder to things from") + tracksortby: str = Field( + "default", + description="""The field to sort tracks by. Options: [ + "default", + "album", + "albumartists", + "artists", + "bitrate", + "date", + "disc", + "duration", + "lastmod", + "lastplayed", + "playduration", + "playcount", + "title", + ]""", + ) + tracksort_reverse: bool = Field( + False, + description="Whether to reverse the sort order of the tracks", + ) + foldersortby: str = Field( + "lastmod", + description="""The field to sort folders by. + Options: [ + "default", + "name", + "lastmod", + "trackcount", + ] + """, + ) + foldersort_reverse: bool = Field( + True, + description="Whether to reverse the sort order of the folders", ) start: int = Field(0, description="The start index") - end: int = Field(50, description="The end index") + limit: int = Field(50, description="The max number of items to return") tracks_only: bool = Field(False, description="Whether to only get tracks") @@ -69,9 +104,15 @@ def get_folder_tree(body: FolderTree): req_dir = "/" + req_dir if not req_dir.startswith("/") else req_dir res = get_files_and_dirs( - req_dir, start=body.start, end=body.end, tracks_only=tracks_only + req_dir, + start=body.start, + limit=body.limit, + tracks_only=tracks_only, + tracksortby=body.tracksortby, + foldersortby=body.foldersortby, + tracksort_reverse=body.tracksort_reverse, + foldersort_reverse=body.foldersort_reverse, ) - res["folders"] = sorted(res["folders"], key=lambda i: i.name) return res diff --git a/app/lib/folderslib.py b/app/lib/folderslib.py index ef7b7510..b04a2933 100644 --- a/app/lib/folderslib.py +++ b/app/lib/folderslib.py @@ -1,6 +1,7 @@ import os from pathlib import Path +from app.lib.sortlib import sort_folders, sort_tracks from app.logger import log from app.models import Folder from app.serializers.track import serialize_tracks @@ -11,7 +12,7 @@ from app.utils.wintools import win_replace_slash # from app.db.libdata import TrackTable as TrackDB -def create_folder(path: str, trackcount=0, foldercount=0) -> Folder: +def create_folder(path: str, trackcount=0) -> Folder: """ Creates a folder object from a path. """ @@ -22,7 +23,6 @@ def create_folder(path: str, trackcount=0, foldercount=0) -> Folder: path=win_replace_slash(str(folder)) + "/", is_sym=folder.is_symlink(), trackcount=trackcount, - foldercount=foldercount, ) @@ -46,14 +46,22 @@ def get_folders(paths: list[str]): """ folders = FolderStore.count_tracks_containing_paths(paths) return [ - create_folder(f["path"], f["trackcount"], foldercount=0) + create_folder(f["path"], f["trackcount"]) for f in folders if f["trackcount"] > 0 ] def get_files_and_dirs( - path: str, start: int, end: int, tracks_only: bool = False, skip_empty_folders=True + path: str, + start: int, + limit: int, + tracksortby: str, + foldersortby: str, + tracksort_reverse: bool, + foldersort_reverse: bool, + tracks_only: bool = False, + skip_empty_folders=True, ): """ Given a path, returns a list of tracks and folders in that immediate path. @@ -102,14 +110,17 @@ def get_files_and_dirs( tracks = [] if files: - if end == -1: - end = len(files) + if limit == -1: + limit = len(files) - tracks = list(FolderStore.get_tracks_by_filepaths(files[start:end])) + tracks = list(FolderStore.get_tracks_by_filepaths(files)) + tracks = sort_tracks(tracks, tracksortby, tracksort_reverse) + tracks = tracks[start : start + limit] folders = [] if not tracks_only: folders = get_folders(dirs) + folders = sort_folders(folders, foldersortby, foldersort_reverse) if skip_empty_folders and len(folders) == 1 and len(tracks) == 0: # INFO: When we only have one folder and no tracks, @@ -118,7 +129,11 @@ def get_files_and_dirs( return get_files_and_dirs( folders[0].path, start=start, - end=end, + limit=limit, + tracksortby=tracksortby, + foldersortby=foldersortby, + tracksort_reverse=tracksort_reverse, + foldersort_reverse=foldersort_reverse, tracks_only=tracks_only, skip_empty_folders=True, ) @@ -127,4 +142,5 @@ def get_files_and_dirs( "path": path, "tracks": serialize_tracks(tracks), "folders": folders, + "total": len(files), } diff --git a/app/lib/index.py b/app/lib/index.py index 4118663e..dff48dc1 100644 --- a/app/lib/index.py +++ b/app/lib/index.py @@ -14,17 +14,6 @@ from app.store.folder import FolderStore from app.store.tracks import TrackStore from app.utils.threading import background -def load_and_map(): - key = str(time()) - FolderStore.load_filepaths() - AlbumStore.load_albums(key) - ArtistStore.load_artists(key) - - map_scrobble_data() - map_favorites() - map_artist_colors() - map_album_colors() - class IndexEverything: def __init__(self) -> None: @@ -36,6 +25,10 @@ class IndexEverything: ArtistStore.load_artists(key) FolderStore.load_filepaths() + # map colors + map_album_colors() + map_artist_colors() + map_scrobble_data() map_favorites() diff --git a/app/lib/sortlib.py b/app/lib/sortlib.py new file mode 100644 index 00000000..3198f855 --- /dev/null +++ b/app/lib/sortlib.py @@ -0,0 +1,44 @@ +from itertools import groupby +import os +from pprint import pprint +from app.lib.albumslib import sort_by_track_no +from app.models.folder import Folder +from app.models.track import Track +from app.utils import flatten + + +def sort_tracks(tracks: list[Track], key: str, reverse: bool = False): + """ + Sorts a list of tracks by a key. + """ + if key == "default": + return tracks + + sortfunc = lambda x: getattr(x, key) + + if key == "artists" or key == "albumartists": + sortfunc = lambda x: getattr(x, key)[0]["name"] + + if key == "disc": + # INFO: Group tracks into albums, then sort them by disc number. + tracks = sorted(tracks, key=lambda x: x.album) + groups = groupby(tracks, lambda x: x.albumhash) + + return flatten([sort_by_track_no(list(g)) for k, g in groups]) + + return sorted(tracks, key=sortfunc, reverse=reverse) + + +def sort_folders(folders: list[Folder], key: str, reverse: bool = False): + """ + Sorts a list of folders by a key. + """ + if key == "default": + return folders + + sortfunc = lambda x: getattr(x, key) + + if key == "lastmod": + sortfunc = lambda x: os.path.getmtime(x.path) + + return sorted(folders, key=sortfunc, reverse=reverse) diff --git a/app/models/folder.py b/app/models/folder.py index cd92b0bc..f86dd324 100644 --- a/app/models/folder.py +++ b/app/models/folder.py @@ -7,4 +7,3 @@ class Folder: path: str is_sym: bool = False trackcount: int = 0 - foldercount: int = 0