feat: Separate tracks by user

This commit is contained in:
joao
2025-08-15 11:13:42 -03:00
parent 0b240ba5f0
commit 696342e7dc
8 changed files with 41 additions and 2 deletions

View File

@@ -74,6 +74,7 @@ async def handle_download(album_id: str, request: Request, current_user: User =
"url": url,
"name": name_from_spotify,
"artist": artist_from_spotify,
"username": current_user.username,
"orig_request": orig_params,
}
)

View File

@@ -96,6 +96,7 @@ async def handle_download(playlist_id: str, request: Request, current_user: User
"url": url,
"name": name_from_spotify, # Use fetched name
"artist": artist_from_spotify, # Use fetched owner name as artist
"username": current_user.username,
"orig_request": orig_params,
}
)

View File

@@ -74,6 +74,7 @@ async def handle_download(track_id: str, request: Request, current_user: User =
"url": url,
"name": name_from_spotify,
"artist": artist_from_spotify,
"username": current_user.username,
"orig_request": orig_params,
}
)

View File

@@ -47,6 +47,7 @@ DEFAULT_MAIN_CONFIG = {
"artistSeparator": "; ",
"recursiveQuality": False,
"spotifyMetadata": True,
"separateTracksByUser": False,
"watch": {},
}

View File

@@ -70,6 +70,7 @@ def get_config_params():
"recursiveQuality": config.get(
"recursiveQuality", config.get("recursive_quality", False)
),
"separateTracksByUser": config.get("separateTracksByUser", False),
"watch": config.get("watch", {}),
}
except Exception as e:
@@ -93,6 +94,7 @@ def get_config_params():
"bitrate": None, # Default for bitrate
"artistSeparator": "; ",
"recursiveQuality": False,
"separateTracksByUser": False,
"watch": {},
}
@@ -362,6 +364,9 @@ class CeleryDownloadQueueManager:
"orig_request", task.get("original_request", {})
)
# Get username for user-specific paths
username = task.get("username", "")
complete_task = {
"download_type": incoming_type,
"type": task.get("type", incoming_type),
@@ -383,8 +388,10 @@ class CeleryDownloadQueueManager:
"real_time": self._parse_bool_param(
original_request.get("real_time"), config_params["realTime"]
),
"custom_dir_format": original_request.get(
"custom_dir_format", config_params["customDirFormat"]
"custom_dir_format": self._get_user_specific_dir_format(
original_request.get("custom_dir_format", config_params["customDirFormat"]),
config_params.get("separateTracksByUser", False),
username
),
"custom_track_format": original_request.get(
"custom_track_format", config_params["customTrackFormat"]
@@ -487,6 +494,23 @@ class CeleryDownloadQueueManager:
return param_value.lower() in ["true", "1", "yes", "y", "on"]
return bool(param_value)
def _get_user_specific_dir_format(self, base_format, separate_by_user, username):
"""
Modify the directory format to include username if separateTracksByUser is enabled
Args:
base_format (str): The base directory format from config
separate_by_user (bool): Whether to separate tracks by user
username (str): The username to include in path
Returns:
str: The modified directory format
"""
if separate_by_user and username:
# Add username as a subdirectory at the beginning
return f"{username}/{base_format}"
return base_format
def cancel_task(self, task_id):
"""
Cancels a task by its ID.

View File

@@ -22,6 +22,7 @@ interface DownloadSettings {
deezerQuality: "MP3_128" | "MP3_320" | "FLAC";
spotifyQuality: "NORMAL" | "HIGH" | "VERY_HIGH";
recursiveQuality: boolean; // frontend field (sent as camelCase to backend)
separateTracksByUser: boolean;
}
interface WatchConfig {
@@ -195,6 +196,13 @@ export function DownloadsTab({ config, isLoading }: DownloadsTabProps) {
<label htmlFor="recursiveQualityToggle" className="text-content-primary dark:text-content-primary-dark">Recursive Quality</label>
<input id="recursiveQualityToggle" type="checkbox" {...register("recursiveQuality")} className="h-6 w-6 rounded" />
</div>
<div className="flex items-center justify-between">
<label htmlFor="separateTracksByUserToggle" className="text-content-primary dark:text-content-primary-dark">Separate tracks by user</label>
<input id="separateTracksByUserToggle" type="checkbox" {...register("separateTracksByUser")} className="h-6 w-6 rounded" />
</div>
<p className="text-sm text-content-muted dark:text-content-muted-dark">
When enabled, downloads will be organized in user-specific subdirectories (downloads/username/...)
</p>
{/* Watch validation info */}
{watchConfig?.enabled && (

View File

@@ -54,6 +54,7 @@ export type FlatAppSettings = {
hlsThreads: number;
// Frontend-only flag used in DownloadsTab
recursiveQuality: boolean;
separateTracksByUser: boolean;
// Add defaults for the new formatting properties
track: string;
album: string;
@@ -90,6 +91,7 @@ const defaultSettings: FlatAppSettings = {
hlsThreads: 8,
// Frontend-only default
recursiveQuality: false,
separateTracksByUser: false,
// Add defaults for the new formatting properties
track: "{artist_name}/{album_name}/{track_number} - {track_name}",
album: "{artist_name}/{album_name}",

View File

@@ -27,6 +27,7 @@ export interface AppSettings {
m3u: boolean;
hlsThreads: number;
recursiveQuality: boolean;
separateTracksByUser: boolean;
// Properties from the old 'formatting' object
track: string;
album: string;