feat: Separate tracks by user
This commit is contained in:
@@ -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,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -47,6 +47,7 @@ DEFAULT_MAIN_CONFIG = {
|
||||
"artistSeparator": "; ",
|
||||
"recursiveQuality": False,
|
||||
"spotifyMetadata": True,
|
||||
"separateTracksByUser": False,
|
||||
"watch": {},
|
||||
}
|
||||
|
||||
|
||||
@@ -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": {},
|
||||
}
|
||||
|
||||
@@ -361,6 +363,9 @@ class CeleryDownloadQueueManager:
|
||||
original_request = task.get(
|
||||
"orig_request", task.get("original_request", {})
|
||||
)
|
||||
|
||||
# Get username for user-specific paths
|
||||
username = task.get("username", "")
|
||||
|
||||
complete_task = {
|
||||
"download_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.
|
||||
|
||||
@@ -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 && (
|
||||
|
||||
@@ -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}",
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user