From 4b04b8b155f3d17c82b60b50be1187c8d11019de Mon Sep 17 00:00:00 2001 From: mungai-njoroge Date: Sun, 7 Apr 2024 19:19:48 +0300 Subject: [PATCH] fix folder count + fix: file count when you have similar folder names + enforce trailing / on track folder paths --- app/api/__init__.py | 3 +++ app/api/folder.py | 8 +++++--- app/lib/folderslib.py | 37 +++++++++++++++++++++++++--------- app/lib/home/recentlyplayed.py | 3 +++ app/models/track.py | 6 ++++++ 5 files changed, 45 insertions(+), 12 deletions(-) diff --git a/app/api/__init__.py b/app/api/__init__.py index 206bc91e..a74624bc 100644 --- a/app/api/__init__.py +++ b/app/api/__init__.py @@ -39,6 +39,9 @@ The REST API exposed by your Swing Music server In endpoints that request multiple lists of items, this represents the number of items to return for each list. +#### Other infos + +- In the folders endpoint, you can request `'$home'` to get the root directories. --- [MIT License](https://github.com/swing-opensource/swingmusic?tab=MIT-1-ov-file#MIT-1-ov-file) | Copyright (c) {datetime.datetime.now().year} [Mungai Njoroge](https://mungai.vercel.app) diff --git a/app/api/folder.py b/app/api/folder.py index 12fb1fa2..bec377d0 100644 --- a/app/api/folder.py +++ b/app/api/folder.py @@ -23,7 +23,9 @@ api = APIBlueprint("folder", __name__, url_prefix="/folder", abp_tags=[tag]) class FolderTree(BaseModel): - folder: str = Field("$home", description="The folder to things from") + folder: str = Field( + "$home", example="$home", description="The folder to things from" + ) tracks_only: bool = Field(False, description="Whether to only get tracks") @@ -62,10 +64,10 @@ def get_folder_tree(body: FolderTree): # Remember, the trailing slash is removed in the client. req_dir += "/" else: - req_dir = "/" + req_dir + "/" if not req_dir.startswith("/") else req_dir + "/" + req_dir = "/" + req_dir if not req_dir.startswith("/") else req_dir res = GetFilesAndDirs(req_dir, tracks_only=tracks_only)() - res['folders'] = sorted(res['folders'], key=lambda i: i.name) + 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 160b53af..baf00733 100644 --- a/app/lib/folderslib.py +++ b/app/lib/folderslib.py @@ -25,6 +25,18 @@ def create_folder(path: str, trackcount=0, foldercount=0) -> Folder: ) +def get_first_child_from_path(root: str, maybe_child: str): + """ + Given a root path and a path, returns the first child from the root path. + """ + if not maybe_child.startswith(root) or maybe_child == root: + return None + + children = maybe_child.replace(root, "") + first = Path(children).parts[0] + + return os.path.join(root, first) + def get_folders(paths: list[str]): """ Filters out folders that don't have any tracks and @@ -33,24 +45,27 @@ def get_folders(paths: list[str]): count_dict = { "tracks": {path: 0 for path in paths}, # folders are immediate children of the root folder - "folders": {path: 0 for path in paths}, + "folders": {path: set() for path in paths}, } for track in TrackStore.tracks: for path in paths: - if track.folder.startswith(path): - count_dict["tracks"][path] += 1 - # increment folder count by counting the number of slashes - print("slash count", track.folder.count("/"), path.count("/")) - if track.folder.count("/") == path.count("/"): - count_dict["folders"][path] += 1 + # a child path should be longer than the root path + if len(track.folder) >= len(path) and track.folder.startswith(path): + count_dict["tracks"][path] += 1 + + # counting subfolders + p = get_first_child_from_path(path, track.folder) + + if p: + count_dict["folders"][path].add(p) folders = [ { "path": path, "trackcount": count_dict["tracks"][path], - "foldercount": count_dict["folders"][path], + "foldercount": len(count_dict["folders"][path]), } for path in paths ] @@ -92,7 +107,11 @@ class GetFilesAndDirs: ext = os.path.splitext(entry.name)[1].lower() if entry.is_dir() and not entry.name.startswith("."): - dirs.append(win_replace_slash(entry.path)) + 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)) diff --git a/app/lib/home/recentlyplayed.py b/app/lib/home/recentlyplayed.py index 927b974c..6d41c649 100644 --- a/app/lib/home/recentlyplayed.py +++ b/app/lib/home/recentlyplayed.py @@ -90,6 +90,9 @@ def get_recently_played(limit=7): if is_home_dir: folder = os.path.expanduser("~") + # print(folder) + # folder = os.path.join("/", folder, "") + # print(folder) count = len([t for t in TrackStore.tracks if t.folder == folder]) items.append( { diff --git a/app/models/track.py b/app/models/track.py index ee84f187..e15fc37f 100644 --- a/app/models/track.py +++ b/app/models/track.py @@ -1,4 +1,5 @@ from dataclasses import dataclass +import os from pathlib import Path from app.settings import SessionVarKeys, get_flag @@ -61,6 +62,11 @@ class Track: self.last_mod = int(self.last_mod) self.date = int(self.date) + # 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 Videos + self.folder = os.path.join(self.folder, "") + if self.artists is not None: artists = split_artists(self.artists) new_title = self.title