swingmusic/app/store/store.py
geoffrey45 d43dcbff46 break down store.py into multiple files in a module
+ fix last updated date bug
2023-03-25 03:05:38 +03:00

151 lines
4.0 KiB
Python

"""
In memory store.
"""
from pathlib import Path
from tqdm import tqdm
from app.models import Folder
from app.utils.bisection import UseBisection
from app.utils.hashing import create_folder_hash
from app.utils.wintools import win_replace_slash
from .tracks import TrackStore
class FolderStore:
"""
This class holds all tracks in memory and provides methods for
interacting with them.
"""
folders: list[Folder] = []
@classmethod
def check_has_tracks(cls, path: str): # type: ignore
"""
Checks if a folder has tracks.
"""
path_hashes = "".join(f.path_hash for f in cls.folders)
path_hash = create_folder_hash(*Path(path).parts[1:])
return path_hash in path_hashes
@classmethod
def is_empty_folder(cls, path: str):
"""
Checks if a folder has tracks using tracks in the store.
"""
all_folders = set(track.folder for track in TrackStore.tracks)
folder_hashes = "".join(
create_folder_hash(*Path(f).parts[1:]) for f in all_folders
)
path_hash = create_folder_hash(*Path(path).parts[1:])
return path_hash in folder_hashes
@staticmethod
def create_folder(path: str) -> Folder:
"""
Creates a folder object from a path.
"""
folder = Path(path)
return Folder(
name=folder.name,
path=win_replace_slash(str(folder)),
is_sym=folder.is_symlink(),
has_tracks=True,
path_hash=create_folder_hash(*folder.parts[1:]),
)
@classmethod
def add_folder(cls, path: str):
"""
Adds a folder to the store.
"""
if cls.check_has_tracks(path):
return
folder = cls.create_folder(path)
cls.folders.append(folder)
@classmethod
def remove_folder(cls, path: str):
"""
Removes a folder from the store.
"""
for folder in cls.folders:
if folder.path == path:
cls.folders.remove(folder)
break
@classmethod
def process_folders(cls):
"""
Creates a list of folders from the tracks in the store.
"""
cls.folders.clear()
all_folders = [track.folder for track in TrackStore.tracks]
all_folders = set(all_folders)
all_folders = [
folder for folder in all_folders if not cls.check_has_tracks(folder)
]
all_folders = [Path(f) for f in all_folders]
# all_folders = [f for f in all_folders if f.exists()]
valid_folders = []
for folder in all_folders:
try:
if folder.exists():
valid_folders.append(folder)
except PermissionError:
pass
for path in tqdm(valid_folders, desc="Processing folders"):
folder = cls.create_folder(str(path))
cls.folders.append(folder)
@classmethod
def get_folder(cls, path: str): # type: ignore
"""
Returns a folder object by its path.
"""
# TODO: Modify this method to accept a list of paths, sorting is computationally expensive.
folders = sorted(cls.folders, key=lambda x: x.path)
folder = UseBisection(folders, "path", [path])()[0]
if folder is not None:
return folder
has_tracks = cls.check_has_tracks(path)
if not has_tracks:
return None
folder = cls.create_folder(path)
cls.folders.append(folder)
return folder
@classmethod
def get_folders_count(cls, paths: list[str]) -> list[dict[str, int]]:
count_dict = {path: 0 for path in paths}
for track in TrackStore.tracks:
for path in paths:
if track.filepath.startswith(path):
count_dict[path] += 1
result = [{"path": path, "count": count_dict[path]} for path in paths]
# TODO: Modify this method to return Folder objects with
# track count mapped. Keep an eye on function complexity.
return result