fix(downloads): cue generation now properly outputs correct tracks numbers and splits by disc
This commit is contained in:
parent
3ef50cb6ce
commit
8cf7979d47
2 changed files with 39 additions and 31 deletions
|
|
@ -584,13 +584,25 @@ async function bulkDownloadToZipStream(
|
|||
|
||||
// For albums, generate CUE file
|
||||
if (type === 'album' && playlistSettings.shouldGenerateCUE()) {
|
||||
const audioFilename = `${sanitizeForFilename(folderName)}.flac`; // Assume FLAC for CUE
|
||||
const cueContent = generateCUE(metadata, tracks, audioFilename);
|
||||
yield {
|
||||
name: `${folderName}/${sanitizeForFilename(folderName)}.cue`,
|
||||
lastModified: new Date(),
|
||||
input: cueContent,
|
||||
};
|
||||
// Split tracks by volumeNumber and iterate those groups.
|
||||
const tracksByVolume = Object.groupBy(
|
||||
tracks.map((track, index) => ({
|
||||
...track,
|
||||
trackPath: trackPaths[index],
|
||||
})),
|
||||
(track) => String(getExplicitTrackDiscNumber(track) || 1)
|
||||
);
|
||||
const multiDisc = Object.keys(tracksByVolume).length > 1;
|
||||
|
||||
for (const [volumeNumber, tracks] of Object.entries(tracksByVolume)) {
|
||||
const trackPaths = tracks.map((track) => track.trackPath);
|
||||
const cueContent = generateCUE(metadata, tracks, sanitizeForFilename(folderName), trackPaths);
|
||||
yield {
|
||||
name: `${folderName}/${sanitizeForFilename(folderName)}${multiDisc ? ` - Disc ${volumeNumber}` : ''}.cue`,
|
||||
lastModified: new Date(),
|
||||
input: cueContent,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Generate m3u/m3u8 last, using actual track paths collected during download
|
||||
|
|
@ -741,8 +753,7 @@ async function bulkDownloadToZipBlob(
|
|||
|
||||
// For albums, generate CUE file
|
||||
if (type === 'album' && playlistSettings.shouldGenerateCUE()) {
|
||||
const audioFilename = `${sanitizeForFilename(folderName)}.flac`; // Assume FLAC for CUE
|
||||
const cueContent = generateCUE(metadata, tracks, audioFilename);
|
||||
const cueContent = generateCUE(metadata, tracks, sanitizeForFilename(folderName), trackPaths);
|
||||
yield {
|
||||
name: `${folderName}/${sanitizeForFilename(folderName)}.cue`,
|
||||
lastModified: new Date(),
|
||||
|
|
@ -899,8 +910,7 @@ async function bulkDownloadToZipNeutralino(
|
|||
|
||||
// For albums, generate CUE file
|
||||
if (type === 'album' && playlistSettings.shouldGenerateCUE()) {
|
||||
const audioFilename = `${sanitizeForFilename(folderName)}.flac`; // Assume FLAC for CUE
|
||||
const cueContent = generateCUE(metadata, tracks, audioFilename);
|
||||
const cueContent = generateCUE(metadata, tracks, sanitizeForFilename(folderName), trackPaths);
|
||||
yield {
|
||||
name: `${folderName}/${sanitizeForFilename(folderName)}.cue`,
|
||||
lastModified: new Date(),
|
||||
|
|
@ -1246,8 +1256,7 @@ export async function downloadDiscography(artist, selectedReleases, api, quality
|
|||
}
|
||||
|
||||
if (playlistSettings.shouldGenerateCUE()) {
|
||||
const audioFilename = `${sanitizeForFilename(fullAlbum.title)}.flac`;
|
||||
const cueContent = generateCUE(fullAlbum, tracks, audioFilename);
|
||||
const cueContent = generateCUE(fullAlbum, tracks, sanitizeForFilename(fullAlbum.title), trackPaths);
|
||||
yield {
|
||||
name: `${fullFolderPath}/${sanitizeForFilename(fullAlbum.title)}.cue`,
|
||||
lastModified: new Date(),
|
||||
|
|
|
|||
|
|
@ -120,40 +120,39 @@ export function generateM3U8(
|
|||
* Generates CUE sheet content for albums
|
||||
* @param {Object} album - Album metadata
|
||||
* @param {Array} tracks - Array of track objects
|
||||
* @param {string} audioFilename - The main audio file name
|
||||
* @param {string} _audioFilenameBase - Unused; kept for API compatibility
|
||||
* @param {Array|null} trackPaths - Actual per-track resolved paths; when provided, each track gets its own FILE entry
|
||||
* @param {string} audioExtension - Audio file extension for generated paths (used when trackPaths is null)
|
||||
* @returns {string} CUE content
|
||||
*/
|
||||
export function generateCUE(album, tracks, audioFilename) {
|
||||
export function generateCUE(album, tracks, _audioFilenameBase, trackPaths = null, audioExtension = 'flac') {
|
||||
const performer = album.artist?.name || album.artist || 'Unknown Artist';
|
||||
const title = album.title || 'Unknown Album';
|
||||
|
||||
let content = `PERFORMER "${performer}"\n`;
|
||||
content += `TITLE "${title}"\n`;
|
||||
|
||||
// Add file reference
|
||||
const fileExtension = audioFilename.split('.').pop().toUpperCase();
|
||||
content += `FILE "${audioFilename}" ${fileExtension}\n`;
|
||||
|
||||
let currentTime = 0;
|
||||
|
||||
tracks.forEach((track, index) => {
|
||||
const resolvedPath = trackPaths ? trackPaths[index] : null;
|
||||
if (trackPaths && !resolvedPath) return;
|
||||
|
||||
const trackNumber = String(track.trackNumber || index + 1).padStart(2, '0');
|
||||
const trackTitle = track.title || 'Unknown Track';
|
||||
const trackPerformer = track.artist?.name || getTrackArtists(track) || performer;
|
||||
const duration = track.duration || 0;
|
||||
|
||||
const path =
|
||||
resolvedPath ??
|
||||
(() => {
|
||||
const filename = getTrackFilename(track, index + 1, audioExtension);
|
||||
return filename;
|
||||
})();
|
||||
|
||||
const fileExtension = path.split('.').pop().toUpperCase();
|
||||
content += `FILE "${path}" ${fileExtension}\n`;
|
||||
content += ` TRACK ${trackNumber} AUDIO\n`;
|
||||
content += ` TITLE "${trackTitle}"\n`;
|
||||
content += ` PERFORMER "${trackPerformer}"\n`;
|
||||
|
||||
// Calculate time in MM:SS:FF format (Frames = 75 per second)
|
||||
const minutes = Math.floor(currentTime / 60);
|
||||
const seconds = Math.floor(currentTime % 60);
|
||||
const frames = Math.floor((currentTime % 1) * 75);
|
||||
|
||||
content += ` INDEX 01 ${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}:${String(frames).padStart(2, '0')}\n`;
|
||||
|
||||
currentTime += duration;
|
||||
content += ` INDEX 01 00:00:00\n`;
|
||||
});
|
||||
|
||||
return content;
|
||||
|
|
|
|||
Loading…
Reference in a new issue