mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-04 20:43:04 +00:00
86fabcd5e3
+ merge main.py and manage.py + move start logic to swingmusic/__main__.py + add a run.py on the project root
299 lines
7.9 KiB
Python
299 lines
7.9 KiB
Python
"""
|
|
Contains all the folder routes.
|
|
"""
|
|
|
|
from datetime import datetime
|
|
import os
|
|
from pathlib import Path
|
|
|
|
import psutil
|
|
from pydantic import BaseModel, Field
|
|
from flask_openapi3 import Tag
|
|
from flask_openapi3 import APIBlueprint
|
|
from showinfm import show_in_file_manager
|
|
|
|
from swingmusic import settings
|
|
from swingmusic.config import UserConfig
|
|
from swingmusic.db.libdata import TrackTable
|
|
from swingmusic.db.userdata import FavoritesTable, PlaylistTable
|
|
from swingmusic.lib.folderslib import get_files_and_dirs, get_folders
|
|
from swingmusic.serializers.track import serialize_track, serialize_tracks
|
|
from swingmusic.store.tracks import TrackStore
|
|
from swingmusic.utils.wintools import is_windows, win_replace_slash
|
|
|
|
tag = Tag(name="Folders", description="Get folders and tracks in a directory")
|
|
api = APIBlueprint("folder", __name__, url_prefix="/folder", abp_tags=[tag])
|
|
|
|
|
|
class FolderTree(BaseModel):
|
|
folder: str = Field("$home", description="The folder to things from")
|
|
sorttracksby: str = Field(
|
|
"default",
|
|
description="""The field to sort tracks by. Options: [
|
|
"default",
|
|
"album",
|
|
"albumartists",
|
|
"artists",
|
|
"bitrate",
|
|
"date",
|
|
"disc",
|
|
"duration",
|
|
"last_mod",
|
|
"lastplayed",
|
|
"playduration",
|
|
"playcount",
|
|
"title",
|
|
]""",
|
|
)
|
|
tracksort_reverse: bool = Field(
|
|
False,
|
|
description="Whether to reverse the sort order of the tracks",
|
|
)
|
|
sortfoldersby: str = Field(
|
|
"lastmod",
|
|
description="""The field to sort folders by.
|
|
Options: [
|
|
"default",
|
|
"name",
|
|
"lastmod",
|
|
"trackcount",
|
|
]
|
|
""",
|
|
)
|
|
foldersort_reverse: bool = Field(
|
|
False,
|
|
description="Whether to reverse the sort order of the folders",
|
|
)
|
|
start: int = Field(0, description="The start index")
|
|
limit: int = Field(50, description="The max number of items to return")
|
|
tracks_only: bool = Field(False, description="Whether to only get tracks")
|
|
|
|
|
|
@api.post("")
|
|
def get_folder_tree(body: FolderTree):
|
|
"""
|
|
Get folder
|
|
|
|
Returns a list of all the folders and tracks in the given folder.
|
|
"""
|
|
og_req_dir = body.folder
|
|
req_dir = body.folder
|
|
tracks_only = body.tracks_only
|
|
|
|
config = UserConfig()
|
|
root_dirs = config.rootDirs
|
|
|
|
try:
|
|
if req_dir == "$home" and root_dirs[0] == "$home":
|
|
req_dir = settings.Paths.USER_HOME_DIR
|
|
except IndexError:
|
|
pass
|
|
|
|
if req_dir == "$home":
|
|
if len(root_dirs) == 1:
|
|
req_dir = root_dirs[0]
|
|
else:
|
|
folders = get_folders(root_dirs)
|
|
|
|
return {
|
|
"folders": folders,
|
|
"tracks": [],
|
|
}
|
|
|
|
if req_dir.startswith("$playlist"):
|
|
splits = req_dir.split("/")
|
|
|
|
if len(splits) == 2:
|
|
pid = splits[1]
|
|
playlist = PlaylistTable.get_by_id(int(pid))
|
|
tracks = TrackStore.get_tracks_by_trackhashes(
|
|
playlist.trackhashes[
|
|
body.start : body.start + body.limit if body.limit != -1 else None
|
|
]
|
|
)
|
|
|
|
return {
|
|
"path": req_dir,
|
|
"folders": [],
|
|
"tracks": serialize_tracks(tracks),
|
|
}
|
|
|
|
playlists = PlaylistTable.get_all()
|
|
playlists = sorted(
|
|
playlists,
|
|
key=lambda p: datetime.strptime(p.last_updated, "%Y-%m-%d %H:%M:%S"),
|
|
reverse=True,
|
|
)
|
|
|
|
return {
|
|
"path": req_dir,
|
|
"folders": [
|
|
{
|
|
"name": p.name,
|
|
"path": f"$playlist/{p.id}",
|
|
"trackcount": p.count,
|
|
}
|
|
for p in playlists
|
|
],
|
|
"tracks": [],
|
|
}
|
|
|
|
if req_dir == "$favorites":
|
|
tracks, total = FavoritesTable.get_fav_tracks(body.start, body.limit)
|
|
tracks = TrackStore.get_tracks_by_trackhashes([t.hash for t in tracks])
|
|
|
|
return {
|
|
"tracks": serialize_tracks(tracks),
|
|
"folders": [],
|
|
"path": req_dir,
|
|
}
|
|
|
|
if is_windows():
|
|
# Trailing slash needed when drive letters are passed,
|
|
# Remember, the trailing slash is removed in the client.
|
|
# req_dir += "/"
|
|
pass
|
|
else:
|
|
req_dir = "/" + req_dir if not req_dir.startswith("/") else req_dir
|
|
|
|
results = get_files_and_dirs(
|
|
req_dir,
|
|
start=body.start,
|
|
limit=body.limit,
|
|
tracks_only=tracks_only,
|
|
tracksortby=body.sorttracksby,
|
|
foldersortby=body.sortfoldersby,
|
|
tracksort_reverse=body.tracksort_reverse,
|
|
foldersort_reverse=body.foldersort_reverse,
|
|
)
|
|
|
|
if og_req_dir == "$home" and config.showPlaylistsInFolderView:
|
|
# Get all playlists and return them as a list of folders
|
|
playlists_item = {
|
|
"name": "Playlists",
|
|
"path": "$playlists",
|
|
"trackcount": sum(p.count for p in PlaylistTable.get_all()),
|
|
}
|
|
|
|
favorites_item = {
|
|
"name": "Favorites",
|
|
"path": "$favorites",
|
|
"trackcount": FavoritesTable.get_fav_tracks(0, -1)[1],
|
|
}
|
|
|
|
results["folders"].insert(0, playlists_item)
|
|
results["folders"].insert(0, favorites_item)
|
|
|
|
return results
|
|
|
|
|
|
def get_all_drives(is_win: bool = False):
|
|
"""
|
|
Returns a list of all the drives on a Windows machine.
|
|
"""
|
|
drives_ = psutil.disk_partitions(all=True)
|
|
drives = [Path(d.mountpoint).as_posix() for d in drives_]
|
|
|
|
if is_win:
|
|
return drives
|
|
else:
|
|
remove = (
|
|
"/boot",
|
|
"/tmp",
|
|
"/snap",
|
|
"/var",
|
|
"/sys",
|
|
"/proc",
|
|
"/etc",
|
|
"/run",
|
|
"/dev",
|
|
)
|
|
drives = [d for d in drives if not d.startswith(remove)]
|
|
|
|
return drives
|
|
|
|
|
|
class DirBrowserBody(BaseModel):
|
|
folder: str = Field(
|
|
"$root",
|
|
description="The folder to list directories from",
|
|
)
|
|
|
|
|
|
@api.post("/dir-browser")
|
|
def list_folders(body: DirBrowserBody):
|
|
"""
|
|
List folders
|
|
|
|
Returns a list of all the folders in the given folder.
|
|
Used when selecting root dirs.
|
|
"""
|
|
req_dir = body.folder
|
|
is_win = is_windows()
|
|
|
|
if req_dir == "$root":
|
|
return {
|
|
"folders": [{"name": d, "path": d} for d in get_all_drives(is_win=is_win)]
|
|
}
|
|
|
|
if is_win:
|
|
req_dir += "/"
|
|
else:
|
|
req_dir = "/" + req_dir + "/"
|
|
req_dir = str(Path(req_dir).resolve())
|
|
|
|
try:
|
|
entries = os.scandir(req_dir)
|
|
except PermissionError:
|
|
return {"folders": []}
|
|
|
|
dirs = [e.name for e in entries if e.is_dir() and not e.name.startswith(".")]
|
|
dirs = [
|
|
{"name": d, "path": win_replace_slash(os.path.join(req_dir, d))} for d in dirs
|
|
]
|
|
|
|
return {
|
|
"folders": sorted(dirs, key=lambda i: i["name"]),
|
|
}
|
|
|
|
|
|
class FolderOpenInFileManagerQuery(BaseModel):
|
|
path: str = Field(
|
|
description="The path to open in the file manager",
|
|
)
|
|
|
|
|
|
@api.get("/show-in-files")
|
|
def open_in_file_manager(query: FolderOpenInFileManagerQuery):
|
|
"""
|
|
Open in file manager
|
|
|
|
Opens the given path in the file manager on the host machine.
|
|
"""
|
|
show_in_file_manager(query.path)
|
|
|
|
return {"success": True}
|
|
|
|
|
|
class GetTracksInPathQuery(BaseModel):
|
|
path: str = Field(
|
|
description="The path to get tracks from",
|
|
)
|
|
|
|
|
|
@api.get("/tracks/all")
|
|
def get_tracks_in_path(query: GetTracksInPathQuery):
|
|
"""
|
|
Get tracks in path
|
|
|
|
Gets all (or a max of 300) tracks from the given path and its subdirectories.
|
|
|
|
Used when adding tracks to the queue.
|
|
"""
|
|
tracks = TrackTable.get_tracks_in_path(query.path)
|
|
tracks = (serialize_track(t) for t in tracks if Path(t.filepath).exists())
|
|
|
|
return {
|
|
"tracks": list(tracks)[:300],
|
|
}
|