Add $year variable support to file path templates
Introduces the $year variable for album, single, and playlist path templates, allowing users to include the release year in file organization. Updates the backend to extract and provide the year, adjusts the web UI to document the new variable, and updates validation logic to recognize $year as valid in templates.
This commit is contained in:
parent
3bd8c4f94c
commit
a8935ae8f5
4 changed files with 24 additions and 10 deletions
|
|
@ -48,6 +48,7 @@
|
||||||
},
|
},
|
||||||
"file_organization": {
|
"file_organization": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
"_template_variables": "Available: $artist, $albumartist, $album, $title, $track, $year, $playlist",
|
||||||
"templates": {
|
"templates": {
|
||||||
"album_path": "$albumartist/$albumartist - $album/$track - $title",
|
"album_path": "$albumartist/$albumartist - $album/$track - $title",
|
||||||
"single_path": "$artist/$artist - $title/$title",
|
"single_path": "$artist/$artist - $title/$title",
|
||||||
|
|
|
||||||
|
|
@ -6948,6 +6948,14 @@ def _build_final_path_for_track(context, spotify_artist, album_info, file_ext):
|
||||||
original_search = context.get("original_search_result", {})
|
original_search = context.get("original_search_result", {})
|
||||||
playlist_folder_mode = track_info.get("_playlist_folder_mode", False)
|
playlist_folder_mode = track_info.get("_playlist_folder_mode", False)
|
||||||
|
|
||||||
|
# Extract year from spotify_album for template use (safe for all modes)
|
||||||
|
year = 'Unknown'
|
||||||
|
spotify_album = context.get("spotify_album", {})
|
||||||
|
if spotify_album and spotify_album.get('release_date'):
|
||||||
|
release_date = spotify_album['release_date']
|
||||||
|
if release_date and len(release_date) >= 4:
|
||||||
|
year = release_date[:4]
|
||||||
|
|
||||||
# Determine which template type to use
|
# Determine which template type to use
|
||||||
if playlist_folder_mode:
|
if playlist_folder_mode:
|
||||||
# PLAYLIST MODE
|
# PLAYLIST MODE
|
||||||
|
|
@ -6960,7 +6968,8 @@ def _build_final_path_for_track(context, spotify_artist, album_info, file_ext):
|
||||||
'album': track_name,
|
'album': track_name,
|
||||||
'title': track_name,
|
'title': track_name,
|
||||||
'playlist_name': playlist_name,
|
'playlist_name': playlist_name,
|
||||||
'track_number': 1
|
'track_number': 1,
|
||||||
|
'year': year
|
||||||
}
|
}
|
||||||
|
|
||||||
folder_path, filename_base = _get_file_path_from_template(template_context, 'playlist_path')
|
folder_path, filename_base = _get_file_path_from_template(template_context, 'playlist_path')
|
||||||
|
|
@ -6997,7 +7006,8 @@ def _build_final_path_for_track(context, spotify_artist, album_info, file_ext):
|
||||||
'albumartist': spotify_artist["name"] if isinstance(spotify_artist, dict) else spotify_artist.name,
|
'albumartist': spotify_artist["name"] if isinstance(spotify_artist, dict) else spotify_artist.name,
|
||||||
'album': album_info['album_name'],
|
'album': album_info['album_name'],
|
||||||
'title': clean_track_name,
|
'title': clean_track_name,
|
||||||
'track_number': track_number
|
'track_number': track_number,
|
||||||
|
'year': year
|
||||||
}
|
}
|
||||||
|
|
||||||
folder_path, filename_base = _get_file_path_from_template(template_context, 'album_path')
|
folder_path, filename_base = _get_file_path_from_template(template_context, 'album_path')
|
||||||
|
|
@ -7032,7 +7042,8 @@ def _build_final_path_for_track(context, spotify_artist, album_info, file_ext):
|
||||||
'albumartist': spotify_artist["name"] if isinstance(spotify_artist, dict) else spotify_artist.name,
|
'albumartist': spotify_artist["name"] if isinstance(spotify_artist, dict) else spotify_artist.name,
|
||||||
'album': album_info.get('album_name', clean_track_name) if album_info else clean_track_name,
|
'album': album_info.get('album_name', clean_track_name) if album_info else clean_track_name,
|
||||||
'title': clean_track_name,
|
'title': clean_track_name,
|
||||||
'track_number': 1
|
'track_number': 1,
|
||||||
|
'year': year
|
||||||
}
|
}
|
||||||
|
|
||||||
folder_path, filename_base = _get_file_path_from_template(template_context, 'single_path')
|
folder_path, filename_base = _get_file_path_from_template(template_context, 'single_path')
|
||||||
|
|
@ -7076,6 +7087,7 @@ def _apply_path_template(template: str, context: dict) -> str:
|
||||||
result = result.replace('$album', context.get('album', 'Unknown Album'))
|
result = result.replace('$album', context.get('album', 'Unknown Album'))
|
||||||
result = result.replace('$title', context.get('title', 'Unknown Track'))
|
result = result.replace('$title', context.get('title', 'Unknown Track'))
|
||||||
result = result.replace('$track', f"{context.get('track_number', 1):02d}")
|
result = result.replace('$track', f"{context.get('track_number', 1):02d}")
|
||||||
|
result = result.replace('$year', str(context.get('year', 'Unknown')))
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2772,19 +2772,19 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Album Path Template:</label>
|
<label>Album Path Template:</label>
|
||||||
<input type="text" id="template-album-path" placeholder="$albumartist/$albumartist - $album/$track - $title">
|
<input type="text" id="template-album-path" placeholder="$albumartist/$albumartist - $album/$track - $title">
|
||||||
<small style="color: #888;">Variables: $albumartist, $artist, $album, $title, $track</small>
|
<small style="color: #888;">Variables: $albumartist, $artist, $album, $title, $track, $year</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Single Path Template:</label>
|
<label>Single Path Template:</label>
|
||||||
<input type="text" id="template-single-path" placeholder="$artist/$artist - $title/$title">
|
<input type="text" id="template-single-path" placeholder="$artist/$artist - $title/$title">
|
||||||
<small style="color: #888;">Variables: $artist, $title, $album</small>
|
<small style="color: #888;">Variables: $artist, $title, $album, $year</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Playlist Path Template:</label>
|
<label>Playlist Path Template:</label>
|
||||||
<input type="text" id="template-playlist-path" placeholder="$playlist/$artist - $title">
|
<input type="text" id="template-playlist-path" placeholder="$playlist/$artist - $title">
|
||||||
<small style="color: #888;">Variables: $playlist, $artist, $title</small>
|
<small style="color: #888;">Variables: $playlist, $artist, $title, $year</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|
|
||||||
|
|
@ -1484,9 +1484,9 @@ function validateFileOrganizationTemplates() {
|
||||||
|
|
||||||
// Valid variables for each template type
|
// Valid variables for each template type
|
||||||
const validVars = {
|
const validVars = {
|
||||||
album: ['$artist', '$albumartist', '$album', '$title', '$track'],
|
album: ['$artist', '$albumartist', '$album', '$title', '$track', '$year'],
|
||||||
single: ['$artist', '$albumartist', '$album', '$title'],
|
single: ['$artist', '$albumartist', '$album', '$title', '$year'],
|
||||||
playlist: ['$artist', '$playlist', '$title']
|
playlist: ['$artist', '$playlist', '$title', '$year']
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get template values
|
// Get template values
|
||||||
|
|
@ -7219,7 +7219,8 @@ async function startMissingTracksProcess(playlistId) {
|
||||||
};
|
};
|
||||||
|
|
||||||
// If this is an artist album download, use album name and include full context
|
// If this is an artist album download, use album name and include full context
|
||||||
if (playlistId.startsWith('artist_album_')) {
|
// Match both 'artist_album_' and 'enhanced_search_album_' prefixes
|
||||||
|
if (playlistId.startsWith('artist_album_') || playlistId.startsWith('enhanced_search_album_')) {
|
||||||
requestBody.playlist_name = process.album?.name || process.playlist.name;
|
requestBody.playlist_name = process.album?.name || process.playlist.name;
|
||||||
requestBody.is_album_download = true;
|
requestBody.is_album_download = true;
|
||||||
requestBody.album_context = process.album; // Full Spotify album object
|
requestBody.album_context = process.album; // Full Spotify album object
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue