Skip auto M3U export for album downloads — playlists only (#241)
- autoSavePlaylistM3U() returns early for album downloads (detected by playlistId prefix) — albums are already grouped by media servers, M3U just creates empty duplicate playlists (Navidrome auto-imports them) - Fix broken isAlbum detection — data-context was always "playlist", now uses reliable playlistId prefix matching - Update toggle label: "playlists and albums" → "playlists" - Update hint text to explain albums are skipped and why - Manual Export M3U button still works for both (explicit user action)
This commit is contained in:
parent
22552032e2
commit
7c85c31e8b
2 changed files with 13 additions and 12 deletions
|
|
@ -5295,11 +5295,11 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="checkbox-label">
|
<label class="checkbox-label">
|
||||||
<input type="checkbox" id="m3u-export-enabled">
|
<input type="checkbox" id="m3u-export-enabled">
|
||||||
Auto-save M3U file when downloading playlists and albums
|
Auto-save M3U file when downloading playlists
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="help-text">
|
<div class="help-text">
|
||||||
Saves an M3U playlist file to the same folder as the downloaded tracks.
|
Saves an M3U playlist file alongside your music. Albums are skipped — they're already grouped by your media server.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11464,7 +11464,8 @@ async function openDownloadMissingModal(playlistId) {
|
||||||
|
|
||||||
async function autoSavePlaylistM3U(playlistId) {
|
async function autoSavePlaylistM3U(playlistId) {
|
||||||
/**
|
/**
|
||||||
* Automatically save M3U file server-side for playlist and album modals.
|
* Automatically save M3U file server-side for playlist modals only.
|
||||||
|
* Albums are skipped — they're already grouped by media servers.
|
||||||
* The server checks the m3u_export.enabled setting before writing.
|
* The server checks the m3u_export.enabled setting before writing.
|
||||||
*/
|
*/
|
||||||
const process = activeDownloadProcesses[playlistId];
|
const process = activeDownloadProcesses[playlistId];
|
||||||
|
|
@ -11478,9 +11479,10 @@ async function autoSavePlaylistM3U(playlistId) {
|
||||||
const m3uContent = generateM3UContent(playlistId);
|
const m3uContent = generateM3UContent(playlistId);
|
||||||
if (!m3uContent) return;
|
if (!m3uContent) return;
|
||||||
|
|
||||||
// Determine context type and gather metadata
|
// Skip M3U for albums — albums are already naturally grouped in media servers
|
||||||
const dataContext = modal.querySelector('.download-missing-modal-content')?.getAttribute('data-context');
|
const albumPrefixes = ['artist_album_', 'discover_album_', 'enhanced_search_album_', 'seasonal_album_', 'spotify_library_', 'beatport_release_', 'discover_cache_'];
|
||||||
const isAlbum = dataContext === 'artist_album';
|
if (albumPrefixes.some(p => playlistId.startsWith(p))) return;
|
||||||
|
|
||||||
const playlistName = process.playlist?.name || process.playlistName || 'Playlist';
|
const playlistName = process.playlist?.name || process.playlistName || 'Playlist';
|
||||||
const artistName = process.artist?.name || '';
|
const artistName = process.artist?.name || '';
|
||||||
const albumName = process.album?.name || '';
|
const albumName = process.album?.name || '';
|
||||||
|
|
@ -11494,7 +11496,7 @@ async function autoSavePlaylistM3U(playlistId) {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
playlist_name: playlistName,
|
playlist_name: playlistName,
|
||||||
m3u_content: m3uContent,
|
m3u_content: m3uContent,
|
||||||
context_type: isAlbum ? 'album' : 'playlist',
|
context_type: 'playlist',
|
||||||
artist_name: artistName,
|
artist_name: artistName,
|
||||||
album_name: albumName,
|
album_name: albumName,
|
||||||
year: year
|
year: year
|
||||||
|
|
@ -11502,7 +11504,7 @@ async function autoSavePlaylistM3U(playlistId) {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
console.log(`✅ Auto-saved M3U for ${isAlbum ? 'album' : 'playlist'}: ${playlistName}`);
|
console.log(`✅ Auto-saved M3U for playlist: ${playlistName}`);
|
||||||
} else {
|
} else {
|
||||||
console.warn(`⚠️ Failed to auto-save M3U for ${playlistName}`);
|
console.warn(`⚠️ Failed to auto-save M3U for ${playlistName}`);
|
||||||
}
|
}
|
||||||
|
|
@ -11623,9 +11625,8 @@ async function exportPlaylistAsM3U(playlistId) {
|
||||||
URL.revokeObjectURL(url);
|
URL.revokeObjectURL(url);
|
||||||
|
|
||||||
// Also save server-side to the relevant folder (force=true bypasses setting check)
|
// Also save server-side to the relevant folder (force=true bypasses setting check)
|
||||||
const modal = document.getElementById(`download-missing-modal-${playlistId}`);
|
const albumPrefixes = ['artist_album_', 'discover_album_', 'enhanced_search_album_', 'seasonal_album_', 'spotify_library_', 'beatport_release_', 'discover_cache_'];
|
||||||
const dataContext = modal?.querySelector('.download-missing-modal-content')?.getAttribute('data-context');
|
const isAlbumExport = albumPrefixes.some(p => playlistId.startsWith(p));
|
||||||
const isAlbum = dataContext === 'artist_album';
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const releaseDate = process.album?.release_date || '';
|
const releaseDate = process.album?.release_date || '';
|
||||||
|
|
@ -11636,7 +11637,7 @@ async function exportPlaylistAsM3U(playlistId) {
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
playlist_name: playlistName,
|
playlist_name: playlistName,
|
||||||
m3u_content: m3uContent,
|
m3u_content: m3uContent,
|
||||||
context_type: isAlbum ? 'album' : 'playlist',
|
context_type: isAlbumExport ? 'album' : 'playlist',
|
||||||
artist_name: process.artist?.name || '',
|
artist_name: process.artist?.name || '',
|
||||||
album_name: process.album?.name || '',
|
album_name: process.album?.name || '',
|
||||||
year: year,
|
year: year,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue