fix context menu downloading to add metadata
This commit is contained in:
parent
acef04366d
commit
4b483c76d2
3 changed files with 17 additions and 36 deletions
|
|
@ -10,7 +10,7 @@ import { createRouter, updateTabTitle } from './router.js';
|
||||||
import { initializeSettings } from './settings.js';
|
import { initializeSettings } from './settings.js';
|
||||||
import { initializePlayerEvents, initializeTrackInteractions } from './events.js';
|
import { initializePlayerEvents, initializeTrackInteractions } from './events.js';
|
||||||
import { initializeUIInteractions } from './ui-interactions.js';
|
import { initializeUIInteractions } from './ui-interactions.js';
|
||||||
import { downloadAlbumAsZip, downloadDiscography, downloadCurrentTrack, downloadPlaylistAsZip } from './downloads.js';
|
import { downloadAlbumAsZip, downloadDiscography, downloadPlaylistAsZip } from './downloads.js';
|
||||||
import { debounce, SVG_PLAY } from './utils.js';
|
import { debounce, SVG_PLAY } from './utils.js';
|
||||||
|
|
||||||
function initializeCasting(audioPlayer, castBtn) {
|
function initializeCasting(audioPlayer, castBtn) {
|
||||||
|
|
@ -205,7 +205,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
|
|
||||||
initializeSettings(scrobbler, player, api, ui);
|
initializeSettings(scrobbler, player, api, ui);
|
||||||
initializePlayerEvents(player, audioPlayer, scrobbler);
|
initializePlayerEvents(player, audioPlayer, scrobbler);
|
||||||
initializeTrackInteractions(player, api, document.querySelector('.main-content'), document.getElementById('context-menu'));
|
initializeTrackInteractions(player, api, document.querySelector('.main-content'), document.getElementById('context-menu'), lyricsManager);
|
||||||
initializeUIInteractions(player, api);
|
initializeUIInteractions(player, api);
|
||||||
initializeKeyboardShortcuts(player, audioPlayer, lyricsPanel);
|
initializeKeyboardShortcuts(player, audioPlayer, lyricsPanel);
|
||||||
initializeMediaSessionHandlers(player);
|
initializeMediaSessionHandlers(player);
|
||||||
|
|
@ -268,7 +268,9 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
document.getElementById('download-current-btn')?.addEventListener('click', () => {
|
document.getElementById('download-current-btn')?.addEventListener('click', () => {
|
||||||
downloadCurrentTrack(player.currentTrack, player.quality, api, lyricsManager);
|
if (player.currentTrack) {
|
||||||
|
downloadTrackWithMetadata(player.currentTrack, player.quality, api, lyricsManager);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Auto-update lyrics when track changes
|
// Auto-update lyrics when track changes
|
||||||
|
|
|
||||||
|
|
@ -515,7 +515,8 @@ function completeBulkDownload(notifEl, success = true, message = null) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function downloadCurrentTrack(track, quality, api, lyricsManager = null) {
|
export async function downloadTrackWithMetadata(track, quality, api, lyricsManager = null, abortController = null) {
|
||||||
|
|
||||||
if (!track) {
|
if (!track) {
|
||||||
alert('No track is currently playing');
|
alert('No track is currently playing');
|
||||||
return;
|
return;
|
||||||
|
|
@ -523,8 +524,10 @@ export async function downloadCurrentTrack(track, quality, api, lyricsManager =
|
||||||
|
|
||||||
const filename = buildTrackFilename(track, quality);
|
const filename = buildTrackFilename(track, quality);
|
||||||
|
|
||||||
|
const controller = abortController || new AbortController();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { taskEl, abortController } = addDownloadTask(
|
const { taskEl, taskAbortController } = addDownloadTask(
|
||||||
track.id,
|
track.id,
|
||||||
track,
|
track,
|
||||||
filename,
|
filename,
|
||||||
|
|
@ -544,7 +547,7 @@ export async function downloadCurrentTrack(track, quality, api, lyricsManager =
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const resp = await fetch(streamUrl, { signal: abortController.signal, cache: 'no-store' });
|
const resp = await fetch(streamUrl, { signal: controller.signal, cache: 'no-store' });
|
||||||
if (!resp.ok) throw new Error(`Fetch failed: ${resp.status}`);
|
if (!resp.ok) throw new Error(`Fetch failed: ${resp.status}`);
|
||||||
|
|
||||||
const contentLength = resp.headers.get('Content-Length');
|
const contentLength = resp.headers.get('Content-Length');
|
||||||
|
|
@ -586,7 +589,8 @@ export async function downloadCurrentTrack(track, quality, api, lyricsManager =
|
||||||
try {
|
try {
|
||||||
const meta = buildTrackMetadata(track, api);
|
const meta = buildTrackMetadata(track, api);
|
||||||
const metaFilename = filename.replace(/\.[^.]+$/, '.json');
|
const metaFilename = filename.replace(/\.[^.]+$/, '.json');
|
||||||
zip.file(metaFilename, JSON.stringify(meta, null, 2));
|
const jsonContent = JSON.stringify(meta, null, 2);
|
||||||
|
zip.file(metaFilename, jsonContent);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('Could not create metadata for current track', e);
|
console.warn('Could not create metadata for current track', e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
33
js/events.js
33
js/events.js
|
|
@ -1,7 +1,8 @@
|
||||||
//js/events.js
|
//js/events.js
|
||||||
import { SVG_PLAY, SVG_PAUSE, SVG_VOLUME, SVG_MUTE, REPEAT_MODE, trackDataStore, RATE_LIMIT_ERROR_MESSAGE, buildTrackFilename } from './utils.js';
|
import { SVG_PLAY, SVG_PAUSE, SVG_VOLUME, SVG_MUTE, REPEAT_MODE, trackDataStore, RATE_LIMIT_ERROR_MESSAGE, buildTrackFilename } from './utils.js';
|
||||||
import { lastFMStorage } from './storage.js';
|
import { lastFMStorage } from './storage.js';
|
||||||
import { addDownloadTask, updateDownloadProgress, completeDownloadTask } from './downloads.js';
|
import { addDownloadTask, updateDownloadProgress, completeDownloadTask, downloadTrackWithMetadata } from './downloads.js';
|
||||||
|
import { lyricsSettings } from './storage.js';
|
||||||
import { updateTabTitle } from './router.js';
|
import { updateTabTitle } from './router.js';
|
||||||
|
|
||||||
export function initializePlayerEvents(player, audioPlayer, scrobbler) {
|
export function initializePlayerEvents(player, audioPlayer, scrobbler) {
|
||||||
|
|
@ -278,7 +279,7 @@ function initializeSmoothSliders(audioPlayer, player) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initializeTrackInteractions(player, api, mainContent, contextMenu) {
|
export function initializeTrackInteractions(player, api, mainContent, contextMenu, lyricsManager) {
|
||||||
let contextTrack = null;
|
let contextTrack = null;
|
||||||
|
|
||||||
mainContent.addEventListener('click', e => {
|
mainContent.addEventListener('click', e => {
|
||||||
|
|
@ -337,33 +338,7 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen
|
||||||
player.addToQueue(contextTrack);
|
player.addToQueue(contextTrack);
|
||||||
renderQueue(player);
|
renderQueue(player);
|
||||||
} else if (action === 'download' && contextTrack) {
|
} else if (action === 'download' && contextTrack) {
|
||||||
const quality = player.quality;
|
await downloadTrackWithMetadata(contextTrack, player.quality, api, lyricsManager);
|
||||||
const filename = buildTrackFilename(contextTrack, quality);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const { taskEl, abortController } = addDownloadTask(
|
|
||||||
contextTrack.id,
|
|
||||||
contextTrack,
|
|
||||||
filename,
|
|
||||||
api
|
|
||||||
);
|
|
||||||
|
|
||||||
await api.downloadTrack(contextTrack.id, quality, filename, {
|
|
||||||
signal: abortController.signal,
|
|
||||||
onProgress: (progress) => {
|
|
||||||
updateDownloadProgress(contextTrack.id, progress);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
completeDownloadTask(contextTrack.id, true);
|
|
||||||
} catch (error) {
|
|
||||||
if (error.name !== 'AbortError') {
|
|
||||||
const errorMsg = error.message === RATE_LIMIT_ERROR_MESSAGE
|
|
||||||
? error.message
|
|
||||||
: 'Download failed. Please try again.';
|
|
||||||
completeDownloadTask(contextTrack.id, false, errorMsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
contextMenu.style.display = 'none';
|
contextMenu.style.display = 'none';
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue