From aa728f970ba59e225941d1043710c257edf75e40 Mon Sep 17 00:00:00 2001 From: Daniel <790119+DanTheMan827@users.noreply.github.com> Date: Wed, 11 Mar 2026 20:10:38 +0000 Subject: [PATCH] feat(downloads): add discNumber template for file name. Also update disc number handling in download logic and metadata extraction --- index.html | 4 ++-- js/downloads.js | 37 ++++--------------------------------- js/metadata.js | 13 ++++++++++--- js/utils.js | 41 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 38 deletions(-) diff --git a/index.html b/index.html index 5a253c3..e1c3223 100644 --- a/index.html +++ b/index.html @@ -5141,8 +5141,8 @@
Filename Template Customize download filenames. Available: {trackNumber}, {artist}, {title}, - {album}Customize download filenames. Available: {discNumber}, {trackNumber}, + {artist}, {title}, {album}
0 ? parsed : null; -} - -function getExplicitTrackDiscNumber(track) { - const candidates = [ - track?.volumeNumber, - track?.discNumber, - track?.mediaNumber, - track?.media_number, - track?.volume, - track?.disc, - track?.volume?.number, - track?.disc?.number, - track?.media?.number, - track?.disc, - track?.disc_no, - track?.discNo, - track?.disc_number, - track?.mediaMetadata?.discNumber, - ]; - - for (const candidate of candidates) { - const parsed = toPositiveInt(candidate); - if (parsed) return parsed; - } - return null; -} - async function createDiscLayoutContext(tracks, api) { if (!playlistSettings.shouldSeparateDiscsInZip()) { return { separateByDisc: false, resolveDiscNumber: () => 1 }; } - const explicitDiscNumbers = tracks.map((track) => getExplicitTrackDiscNumber(track)); + const explicitDiscNumbers = tracks.map((track) => getTrackDiscNumber(track)); const explicitDistinct = new Set(explicitDiscNumbers.filter(Boolean)); if (explicitDistinct.size > 1) { @@ -85,7 +56,7 @@ async function createDiscLayoutContext(tracks, api) { if (explicitDiscNumbers[index]) return explicitDiscNumbers[index]; try { const fullTrack = await api.getTrackMetadata(track.id); - return getExplicitTrackDiscNumber(fullTrack); + return getTrackDiscNumber(fullTrack); } catch { return null; } @@ -590,7 +561,7 @@ async function bulkDownloadToZipStream( ...track, trackPath: trackPaths[index], })), - (track) => String(getExplicitTrackDiscNumber(track) || 1) + (track) => String(getTrackDiscNumber(track) || 1) ); const multiDisc = Object.keys(tracksByVolume).length > 1; diff --git a/js/metadata.js b/js/metadata.js index 76e24b9..d8bfb61 100644 --- a/js/metadata.js +++ b/js/metadata.js @@ -1,4 +1,11 @@ -import { getCoverBlob, getTrackTitle, getFullArtistString, getMimeType, getTrackCoverId } from './utils.js'; +import { + getCoverBlob, + getTrackTitle, + getFullArtistString, + getMimeType, + getTrackCoverId, + getTrackDiscNumber, +} from './utils.js'; import { fetchTagLib, addMetadataWithTagLib, getMetadataWithTagLib } from './taglib.ts'; import { doTimed, doTimedAsync } from './doTimed.ts'; import { managers } from './app.js'; @@ -35,7 +42,7 @@ export async function addMetadataToAudio(audioBlob, track, api, _quality, prefet const { coverFetch, lyricsFetch } = prefetchPromises; /** - * @type {import("./taglib.worker.ts").TagLibMetadata} + * @type {import("./taglib.types.ts").TagLibMetadata} */ const data = {}; @@ -47,7 +54,7 @@ export async function addMetadataToAudio(audioBlob, track, api, _quality, prefet data.albumTitle = track.album.title; data.albumArtist = track.album?.artist?.name || track.artist?.name; data.trackNumber = track.trackNumber; - data.discNumber = track.volumeNumber ?? track.discNumber; + data.discNumber = getTrackDiscNumber(track) || undefined; data.totalTracks = track.album.numberOfTracks; data.copyright = track.copyright; data.isrc = track.isrc; diff --git a/js/utils.js b/js/utils.js index 3b5bf8f..b9790e0 100644 --- a/js/utils.js +++ b/js/utils.js @@ -202,6 +202,7 @@ export const buildTrackFilename = (track, quality, extension = null) => { const artistName = track.artist?.name || track.artists?.[0]?.name || 'Unknown Artist'; const data = { + discNumber: getTrackDiscNumber(track) || 1, trackNumber: track.trackNumber, artist: artistName, title: getTrackTitle(track), @@ -629,3 +630,43 @@ export function getTrackCoverId(track) { null ); } + +/** + * Converts a value to a positive integer. + * @param {*} value - The value to convert to a positive integer. + * @returns {number|null} The parsed positive integer, or null if the value is not a finite positive number. + */ +export function toPositiveInt(value) { + const parsed = parseInt(value, 10); + return Number.isFinite(parsed) && parsed > 0 ? parsed : null; +} + +/** + * Extracts the disc number from a track object by checking multiple possible property names. + * @param {Object} track - The track object to extract the disc number from. + * @returns {number|null} The disc number as a positive integer, or null if no valid disc number is found. + */ +export function getTrackDiscNumber(track) { + const candidates = [ + track?.volumeNumber, + track?.discNumber, + track?.mediaNumber, + track?.media_number, + track?.volume, + track?.disc, + track?.volume?.number, + track?.disc?.number, + track?.media?.number, + track?.disc, + track?.disc_no, + track?.discNo, + track?.disc_number, + track?.mediaMetadata?.discNumber, + ]; + + for (const candidate of candidates) { + const parsed = toPositiveInt(candidate); + if (parsed) return parsed; + } + return null; +}