feat(downloads): add discNumber template for file name.
Also update disc number handling in download logic and metadata extraction
This commit is contained in:
parent
8cf7979d47
commit
aa728f970b
4 changed files with 57 additions and 38 deletions
|
|
@ -5141,8 +5141,8 @@
|
|||
<div class="info">
|
||||
<span class="label">Filename Template</span>
|
||||
<span class="description"
|
||||
>Customize download filenames. Available: {trackNumber}, {artist}, {title},
|
||||
{album}</span
|
||||
>Customize download filenames. Available: {discNumber}, {trackNumber},
|
||||
{artist}, {title}, {album}</span
|
||||
>
|
||||
</div>
|
||||
<input
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
getCoverBlob,
|
||||
getExtensionFromBlob,
|
||||
escapeHtml,
|
||||
getTrackDiscNumber,
|
||||
} from './utils.js';
|
||||
import { lyricsSettings, bulkDownloadSettings, losslessContainerSettings, playlistSettings } from './storage.js';
|
||||
import { addMetadataToAudio, prefetchMetadataObjects } from './metadata.js';
|
||||
|
|
@ -34,42 +35,12 @@ async function loadClientZip() {
|
|||
}
|
||||
}
|
||||
|
||||
function toPositiveInt(value) {
|
||||
const parsed = parseInt(value, 10);
|
||||
return Number.isFinite(parsed) && parsed > 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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
41
js/utils.js
41
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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue