diff --git a/docs/README.md b/docs/README.md index 36121f2..26661f3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -65,12 +65,10 @@ And all the developers and artists, for the following resources: ### JavaScript libraries -* [buffer](https://www.npmjs.com/package/buffer) - Node.js Buffer API, for the browser * [http-server](https://www.npmjs.com/package/http-server) - a simple zero-configuration command-line http server * [idb-keyval](https://www.npmjs.com/package/idb-keyval) - super-simple promise-based keyval store implemented with IndexedDB -* [music-metadata-browser](https://www.npmjs.com/package/music-metadata-browser) - stream and file based music metadata parser for the browser +* [music-metadata](https://www.npmjs.com/package/music-metadata) - Metadata parser for audio and video media files. Supports file and stream inputs in Node.js and browser environments, extracting format, tag, and duration information. * [notie](https://www.npmjs.com/package/notie) - clean and simple notification, input, and selection suite for javascript, with no dependencies -* [process](https://www.npmjs.com/package/process) - process information for node.js and browsers * [scrollIntoViewIfNeeded 4 everyone](https://gist.github.com/hsablonniere/2581101) - polyfill for non-standard scrollIntoViewIfNeeded() method * [sortablejs](https://www.npmjs.com/package/sortablejs) - JavaScript library for reorderable drag-and-drop lists * [webpack](https://www.npmjs.com/package/webpack) - JavaScript module bundler for the browser diff --git a/package.json b/package.json index 14f4c25..1134aa8 100644 --- a/package.json +++ b/package.json @@ -13,16 +13,14 @@ }, "devDependencies": { "audiomotion-analyzer": "^4.5.1", - "buffer": "^6.0.3", "css-loader": "^7.1.2", "css-minimizer-webpack-plugin": "^7.0.0", "http-server": "^14.1.1", "idb-keyval": "^6.2.1", "js-yaml": "^4.1.0", "mini-css-extract-plugin": "^2.9.0", - "music-metadata-browser": "^2.5.10", + "music-metadata": "^11.8.3", "notie": "^4.3.1", - "process": "^0.11.10", "sortablejs": "^1.15.2", "style-loader": "^4.0.0", "webpack": "^5.91.0", diff --git a/src/index.js b/src/index.js index a9e4bd5..ff7d499 100644 --- a/src/index.js +++ b/src/index.js @@ -32,7 +32,7 @@ import AudioMotionAnalyzer from 'audiomotion-analyzer'; import packageJson from '../package.json'; import * as fileExplorer from './file-explorer.js'; -import * as mm from 'music-metadata-browser'; +import {parseBlob, parseWebStream} from 'music-metadata'; import './scrollIntoViewIfNeeded-polyfill.js'; import { get, set, del } from 'idb-keyval'; import * as yaml from 'js-yaml'; @@ -1973,7 +1973,7 @@ function keyboardControls( event ) { } /** - * Sets (or removes) the `src` attribute of a audio element and + * Sets (or removes) the `src` attribute of an audio element and * releases any data blob (File System API) previously in use by it * * @param {object} audio element @@ -2077,7 +2077,7 @@ function loadGradientIntoCurrentGradient(gradientKey) { /** * Load a music file from the user's computer */ -function loadLocalFile( obj ) { +async function loadLocalFile( obj ) { const fileBlob = obj.files[0]; if ( fileBlob ) { @@ -2086,11 +2086,17 @@ function loadLocalFile( obj ) { audioEl.dataset.file = fileBlob.name; audioEl.dataset.title = parsePath( fileBlob.name ).baseName; - // load and play - loadFileBlob( fileBlob, audioEl, true ) - .then( url => mm.fetchFromUrl( url ) ) - .then( metadata => addMetadata( metadata, audioEl ) ) - .catch( e => {} ); + try { + // Start both tasks, but only await parseBlob immediately + const loadTask = loadFileBlob(fileBlob, audioEl, true); + const metadata = await parseBlob( fileBlob ); + await addMetadata(metadata, audioEl); + + // Wait for loadTask to complete + await loadTask; + } catch( error ) { + consoleLog("Failed to load local file", error); + } } } @@ -3279,21 +3285,35 @@ async function retrieveMetadata() { break queryMetadata; } } - - try { - const metadata = await mm.fetchFromUrl( uri, { skipPostHeaders: true } ); - if ( metadata ) { - addMetadata( metadata, queueItem ); // add metadata to play queue item - syncMetadataToAudioElements( queueItem ); - if ( ! ( metadata.common.picture && metadata.common.picture.length ) ) { - getFolderCover( queueItem ).then( cover => { - queueItem.dataset.cover = cover; - syncMetadataToAudioElements( queueItem ); - }); + else { + // Fetch metadata from URI + const response = await fetch(queueItem.dataset.file); + if (response.ok) { + try { + let metadata; + if (response.body?.getReader) { + const contentType = response.headers.get("Content-Type"); + const contentSize = response.headers.get("Content-Length"); + try { + metadata = await parseWebStream(response.body, { + mimeType: contentType, + size: contentSize ? Number.parseInt(contentSize, 10) : undefined + }, {skipPostHeaders: true}); + } finally { + await response.body.cancel(); + } + } else { + // Fallback to Blob, in case the HTTP Result cannot be streamed + metadata = await parseBlob(await response.blob()); + } + addMetadata(metadata, queueItem); // add metadata to play queue item + } catch(e) { + consoleLog('Failed to retrieve metadata', e) } + } else { + consoleLog(`Failed to fetch metadata http-response=${response.status} for url=${queueItem.dataset.file}`, true); } } - catch( e ) {} if ( revoke ) URL.revokeObjectURL( uri ); diff --git a/webpack.config.js b/webpack.config.js index f598811..197e572 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -36,10 +36,6 @@ module.exports = { new MiniCssExtractPlugin({ filename: 'styles.css', }), - new webpack.ProvidePlugin({ - Buffer: ['buffer', 'Buffer'], - process: 'process/browser.js', - }), ], output: { filename: pathData => { diff --git a/webpack.dev.js b/webpack.dev.js index 83d74a8..5f6adbd 100644 --- a/webpack.dev.js +++ b/webpack.dev.js @@ -35,10 +35,6 @@ module.exports = { }, plugins: [ new webpack.HotModuleReplacementPlugin(), - new webpack.ProvidePlugin({ - Buffer: ['buffer', 'Buffer'], - process: 'process/browser.js', - }), ], output: { filename: 'audioMotion.js',