feat(downloads): use taglib-wasm to set tags
taglib supports multiple media formats beyond what was previously supported, this would enable transcoding to other formats without needing to write additional metadata libraries.
This commit is contained in:
parent
c7a4ba194d
commit
50a5b79d70
9 changed files with 391 additions and 1301 deletions
|
|
@ -12,6 +12,7 @@ import { addMetadataToAudio } from './metadata.js';
|
|||
import { DashDownloader } from './dash-downloader.js';
|
||||
import { encodeToMp3, MP3EncodingError } from './mp3-encoder.js';
|
||||
import { ffmpeg } from './ffmpeg.js';
|
||||
import { initTagLib } from './taglib.js';
|
||||
|
||||
export const DASH_MANIFEST_UNAVAILABLE_CODE = 'DASH_MANIFEST_UNAVAILABLE';
|
||||
const TIDAL_V2_TOKEN = 'txNoH4kkV41MfH25';
|
||||
|
|
@ -1109,6 +1110,8 @@ export class LosslessAPI {
|
|||
}
|
||||
|
||||
async downloadTrack(id, quality = 'HI_RES_LOSSLESS', filename, options = {}) {
|
||||
// Initialize taglib in the background.
|
||||
initTagLib().catch(console.error);
|
||||
const { onProgress, track } = options;
|
||||
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -98,6 +98,8 @@ let settingsModule = null;
|
|||
let downloadsModule = null;
|
||||
let metadataModule = null;
|
||||
|
||||
export const managers = {};
|
||||
|
||||
async function loadSettingsModule() {
|
||||
if (!settingsModule) {
|
||||
settingsModule = await import('./settings.js');
|
||||
|
|
@ -496,6 +498,7 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||
window.monochromeScrobbler = scrobbler;
|
||||
const lyricsManager = new LyricsManager(api);
|
||||
ui.lyricsManager = lyricsManager;
|
||||
managers.lyricsManager = lyricsManager;
|
||||
|
||||
// Check browser support for local files
|
||||
const selectLocalBtn = document.getElementById('select-local-folder-btn');
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { DashDownloader } from './dash-downloader.js';
|
|||
import { generateM3U, generateM3U8, generateCUE, generateNFO, generateJSON } from './playlist-generator.js';
|
||||
import { encodeToMp3 } from './mp3-encoder.js';
|
||||
import { ffmpeg } from './ffmpeg.js';
|
||||
import { initTagLib } from './taglib.js';
|
||||
|
||||
const downloadTasks = new Map();
|
||||
const bulkDownloadTasks = new Map();
|
||||
|
|
@ -269,6 +270,9 @@ function removeBulkDownloadTask(notifEl) {
|
|||
}
|
||||
|
||||
async function downloadTrackBlob(track, quality, api, lyricsManager = null, signal = null) {
|
||||
// Initialize taglib in the background.
|
||||
initTagLib().catch(console.error);
|
||||
|
||||
let enrichedTrack = {
|
||||
...track,
|
||||
artist: track.artist || (track.artists && track.artists.length > 0 ? track.artists[0] : null),
|
||||
|
|
|
|||
1191
js/metadata.js
1191
js/metadata.js
File diff suppressed because it is too large
Load diff
29
js/taglib.js
Normal file
29
js/taglib.js
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import { TagLib as _TagLib } from 'taglib-wasm';
|
||||
|
||||
/**
|
||||
* @type {typeof import('taglib-wasm').TagLib}
|
||||
*/
|
||||
export const TagLib = _TagLib;
|
||||
import TagLibWasm from '!/taglib-wasm/dist/taglib-web.wasm?url';
|
||||
|
||||
export { TagLibWasm };
|
||||
|
||||
let tagLib = null;
|
||||
const wasmBinary = fetch(TagLibWasm).then((r) => r.arrayBuffer());
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns {ReturnType<typeof TagLib.initialize>}
|
||||
*/
|
||||
export async function initTagLib() {
|
||||
if (tagLib) return await tagLib;
|
||||
|
||||
tagLib = TagLib.initialize({
|
||||
wasmBinary: await wasmBinary,
|
||||
legacyMode: true,
|
||||
});
|
||||
|
||||
console.log('TagLib initialized', { tagLib: await tagLib, TagLibWasm });
|
||||
|
||||
return await tagLib;
|
||||
}
|
||||
|
|
@ -398,6 +398,9 @@ function resizeImageBlob(blob, size) {
|
|||
|
||||
/**
|
||||
* Fetches and caches cover art as a Blob
|
||||
* @param {Object} api - API instance with getCoverUrl method
|
||||
* @param {string} coverId - ID of the cover art to fetch
|
||||
* @returns {Promise<Blob|null>} - Cover art blob or null if not available
|
||||
*/
|
||||
export async function getCoverBlob(api, coverId) {
|
||||
if (!coverId) return null;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
"homepage": "https://github.com/SamidyFR/monochrome#readme",
|
||||
"devDependencies": {
|
||||
"@neutralinojs/neu": "^11.7.0",
|
||||
"@types/node": "^25.3.3",
|
||||
"eslint": "^9.39.3",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"globals": "^17.4.0",
|
||||
|
|
@ -39,6 +40,7 @@
|
|||
"stylelint": "^16.26.1",
|
||||
"stylelint-config-standard": "^39.0.1",
|
||||
"stylelint-config-standard-scss": "^16.0.0",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.3.1",
|
||||
"vite-plugin-neutralino": "^1.0.3",
|
||||
"vite-plugin-pwa": "^1.2.0"
|
||||
|
|
@ -60,6 +62,7 @@
|
|||
"fuse.js": "^7.1.0",
|
||||
"jose": "^6.1.3",
|
||||
"npm": "^11.11.0",
|
||||
"pocketbase": "^0.26.8"
|
||||
"pocketbase": "^0.26.8",
|
||||
"taglib-wasm": "^0.9.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export default defineConfig(({ mode }) => {
|
|||
base: './',
|
||||
resolve: {
|
||||
alias: {
|
||||
'!': '/node_modules',
|
||||
pocketbase: '/node_modules/pocketbase/dist/pocketbase.es.js',
|
||||
},
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue