From 83e105a198377879fac7e89d280f44859f2d8053 Mon Sep 17 00:00:00 2001 From: cwilvx Date: Sat, 13 Jul 2024 12:37:08 +0300 Subject: [PATCH] paginate folder tracks endpoint --- app/api/folder.py | 9 ++- app/lib/folderslib.py | 138 +++++++++++++++++++++--------------------- 2 files changed, 75 insertions(+), 72 deletions(-) diff --git a/app/api/folder.py b/app/api/folder.py index 098742af..2972c3e8 100644 --- a/app/api/folder.py +++ b/app/api/folder.py @@ -14,7 +14,7 @@ from showinfm import show_in_file_manager from app import settings from app.config import UserConfig from app.db.libdata import TrackTable -from app.lib.folderslib import GetFilesAndDirs, get_folders +from app.lib.folderslib import get_files_and_dirs, get_folders from app.serializers.track import serialize_track from app.utils.wintools import is_windows, win_replace_slash @@ -26,6 +26,8 @@ class FolderTree(BaseModel): folder: str = Field( "$home", example="$home", description="The folder to things from" ) + start: int = Field(0, description="The start index") + end: int = Field(50, description="The end index") tracks_only: bool = Field(False, description="Whether to only get tracks") @@ -39,7 +41,6 @@ def get_folder_tree(body: FolderTree): req_dir = body.folder tracks_only = body.tracks_only - config = UserConfig() root_dirs = config.rootDirs @@ -67,7 +68,9 @@ def get_folder_tree(body: FolderTree): else: req_dir = "/" + req_dir if not req_dir.startswith("/") else req_dir - res = GetFilesAndDirs(req_dir, tracks_only=tracks_only)() + res = get_files_and_dirs( + req_dir, start=body.start, end=body.end, tracks_only=tracks_only + ) 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 ff8bb9c2..ef7b7510 100644 --- a/app/lib/folderslib.py +++ b/app/lib/folderslib.py @@ -52,79 +52,79 @@ def get_folders(paths: list[str]): ] -class GetFilesAndDirs: +def get_files_and_dirs( + path: str, start: int, end: int, tracks_only: bool = False, skip_empty_folders=True +): """ - Get files and folders from a directory. + Given a path, returns a list of tracks and folders in that immediate path. + + Can recursively call itself to skip through empty folders. """ - def __init__(self, path: str, tracks_only=False) -> None: - self.path = path - self.tracks_only = tracks_only - - def get_files_and_dirs(self, path: str, skip_empty_folders=True): - """ - Given a path, returns a list of tracks and folders in that immediate path. - - Can recursively call itself to skip through empty folders. - """ - try: - entries = os.scandir(path) - except FileNotFoundError: - return { - "path": path, - "tracks": [], - "folders": [], - } - - dirs, files = [], [] - - for entry in entries: - ext = os.path.splitext(entry.name)[1].lower() - - if entry.is_dir() and not entry.name.startswith("."): - dir = win_replace_slash(entry.path) - # add a trailing slash to the folder path - # to avoid matching a folder starting with the same name as the root path - # eg. .../Music and .../Music VideosI - dirs.append(os.path.join(dir, "")) - elif entry.is_file() and ext in SUPPORTED_FILES: - files.append(win_replace_slash(entry.path)) - - files_ = [] - - for file in files: - try: - files_.append( - { - "path": file, - "time": os.path.getmtime(file), - } - ) - except OSError as e: - log.error(e) - - files_.sort(key=lambda f: f["time"]) - files = [f["path"] for f in files_] - - tracks = [] - if files: - tracks = list(FolderStore.get_tracks_by_filepaths(files)) - - folders = [] - if not self.tracks_only: - folders = get_folders(dirs) - - if skip_empty_folders and len(folders) == 1 and len(tracks) == 0: - # INFO: When we only have one folder and no tracks, - # skip through empty folders. - # Call recursively with the first folder in the list. - return self.get_files_and_dirs(folders[0].path) - + try: + entries = os.scandir(path) + except FileNotFoundError: return { "path": path, - "tracks": serialize_tracks(tracks), - "folders": folders, + "tracks": [], + "folders": [], } - def __call__(self): - return self.get_files_and_dirs(self.path) + dirs, files = [], [] + + for entry in entries: + ext = os.path.splitext(entry.name)[1].lower() + + if entry.is_dir() and not entry.name.startswith("."): + dir = win_replace_slash(entry.path) + # add a trailing slash to the folder path + # to avoid matching a folder starting with the same name as the root path + # eg. .../Music and .../Music VideosI + dirs.append(os.path.join(dir, "")) + elif entry.is_file() and ext in SUPPORTED_FILES: + files.append(win_replace_slash(entry.path)) + + files_ = [] + + for file in files: + try: + files_.append( + { + "path": file, + "time": os.path.getmtime(file), + } + ) + except OSError as e: + log.error(e) + + files_.sort(key=lambda f: f["time"]) + files = [f["path"] for f in files_] + + tracks = [] + if files: + if end == -1: + end = len(files) + + tracks = list(FolderStore.get_tracks_by_filepaths(files[start:end])) + + folders = [] + if not tracks_only: + folders = get_folders(dirs) + + if skip_empty_folders and len(folders) == 1 and len(tracks) == 0: + # INFO: When we only have one folder and no tracks, + # skip through empty folders. + # Call recursively with the first folder in the list. + return get_files_and_dirs( + folders[0].path, + start=start, + end=end, + tracks_only=tracks_only, + skip_empty_folders=True, + ) + + return { + "path": path, + "tracks": serialize_tracks(tracks), + "folders": folders, + }