Skip to content

Commit 80ce4ee

Browse files
committed
Migrate music-metadata-browser to music-metadata
1 parent 8c0b9a8 commit 80ce4ee

File tree

5 files changed

+71
-56
lines changed

5 files changed

+71
-56
lines changed

docs/README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,10 @@ And all the developers and artists, for the following resources:
6565

6666
### JavaScript libraries <!-- {docsify-ignore} -->
6767

68-
* [buffer](https://www.npmjs.com/package/buffer) - Node.js Buffer API, for the browser
6968
* [http-server](https://www.npmjs.com/package/http-server) - a simple zero-configuration command-line http server
7069
* [idb-keyval](https://www.npmjs.com/package/idb-keyval) - super-simple promise-based keyval store implemented with IndexedDB
71-
* [music-metadata-browser](https://www.npmjs.com/package/music-metadata-browser) - stream and file based music metadata parser for the browser
70+
* [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.
7271
* [notie](https://www.npmjs.com/package/notie) - clean and simple notification, input, and selection suite for javascript, with no dependencies
73-
* [process](https://www.npmjs.com/package/process) - process information for node.js and browsers
7472
* [scrollIntoViewIfNeeded 4 everyone](https://gist.github.com/hsablonniere/2581101) - polyfill for non-standard scrollIntoViewIfNeeded() method
7573
* [sortablejs](https://www.npmjs.com/package/sortablejs) - JavaScript library for reorderable drag-and-drop lists
7674
* [webpack](https://www.npmjs.com/package/webpack) - JavaScript module bundler for the browser

package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,14 @@
1212
},
1313
"devDependencies": {
1414
"audiomotion-analyzer": "^4.5.1",
15-
"buffer": "^6.0.3",
1615
"css-loader": "^7.1.2",
1716
"css-minimizer-webpack-plugin": "^7.0.0",
1817
"http-server": "^14.1.1",
1918
"idb-keyval": "^6.2.1",
2019
"js-yaml": "^4.1.0",
2120
"mini-css-extract-plugin": "^2.9.0",
22-
"music-metadata-browser": "^2.5.10",
21+
"music-metadata": "^11.7.1",
2322
"notie": "^4.3.1",
24-
"process": "^0.11.10",
2523
"sortablejs": "^1.15.2",
2624
"style-loader": "^4.0.0",
2725
"webpack": "^5.91.0",

src/index.js

Lines changed: 69 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
import AudioMotionAnalyzer from 'audiomotion-analyzer';
3333
import packageJson from '../package.json';
3434
import * as fileExplorer from './file-explorer.js';
35-
import * as mm from 'music-metadata-browser';
35+
import {parseBlob, parseWebStream} from 'music-metadata';
3636
import './scrollIntoViewIfNeeded-polyfill.js';
3737
import { get, set, del } from 'idb-keyval';
3838
import * as yaml from 'js-yaml';
@@ -2017,7 +2017,7 @@ function keyboardControls( event ) {
20172017
}
20182018

20192019
/**
2020-
* Sets (or removes) the `src` attribute of a audio element and
2020+
* Sets (or removes) the `src` attribute of an audio element and
20212021
* releases any data blob (File System API) previously in use by it
20222022
*
20232023
* @param {object} audio element
@@ -2121,7 +2121,8 @@ function loadGradientIntoCurrentGradient(gradientKey) {
21212121
/**
21222122
* Load a music file from the user's computer
21232123
*/
2124-
function loadLocalFile( obj ) {
2124+
async function loadLocalFile( obj ) {
2125+
21252126
const fileBlob = obj.files[0];
21262127

21272128
if ( fileBlob ) {
@@ -2130,11 +2131,17 @@ function loadLocalFile( obj ) {
21302131
audioEl.dataset.file = fileBlob.name;
21312132
audioEl.dataset.title = parsePath( fileBlob.name ).baseName;
21322133

2133-
// load and play
2134-
loadFileBlob( fileBlob, audioEl, true )
2135-
.then( url => mm.fetchFromUrl( url ) )
2136-
.then( metadata => addMetadata( metadata, audioEl ) )
2137-
.catch( e => {} );
2134+
try {
2135+
// Start both tasks, but only await parseBlob immediately
2136+
const loadTask = loadFileBlob(fileBlob, audioEl, true);
2137+
const metadata = await parseBlob( fileBlob );
2138+
await addMetadata(metadata, audioEl);
2139+
2140+
// Wait for loadTask to complete
2141+
await loadTask;
2142+
} catch( error ) {
2143+
consoleLog("Failed to load local file", error);
2144+
}
21382145
}
21392146
}
21402147

@@ -3295,60 +3302,80 @@ async function retrieveBackgrounds() {
32953302
}
32963303

32973304
/**
3298-
* Retrieve metadata for files in the play queue
3305+
* Retrieve metadata for the first MAX_METADATA_REQUESTS files in the play queue,
3306+
* which have no metadata assigned yet
32993307
*/
33003308
async function retrieveMetadata() {
33013309
// leave when we already have enough concurrent requests pending
3310+
// ToDo:
3311+
// Very arguable way to restrict parallel processing
3312+
// Without calling this to often, leaves items unprocessed
33023313
if ( waitingMetadata >= MAX_METADATA_REQUESTS )
33033314
return;
33043315

3305-
// find the first play queue item for which we haven't retrieved the metadata yet
3306-
const queueItem = Array.from( playlist.children ).find( el => el.dataset.retrieve );
3316+
++waitingMetadata;
33073317

3308-
if ( queueItem ) {
3318+
// Process in parallel
3319+
for ( const queueItem of playlist.children ) {
33093320

3310-
let uri = queueItem.dataset.file,
3311-
revoke = false;
3312-
3313-
waitingMetadata++;
3321+
if (!queueItem.dataset.retrieve) continue;
33143322
delete queueItem.dataset.retrieve;
33153323

3316-
queryMetadata: {
3324+
let metadata;
3325+
let file;
3326+
3327+
try {
33173328
if ( queueItem.handle ) {
3318-
try {
3319-
if ( await queueItem.handle.requestPermission() != 'granted' )
3320-
break queryMetadata;
33213329

3322-
uri = URL.createObjectURL( await queueItem.handle.getFile() );
3323-
revoke = true;
3324-
}
3325-
catch( e ) {
3326-
break queryMetadata;
3327-
}
3328-
}
3330+
// Fetch metadata from File object
3331+
if (await queueItem.handle.requestPermission() !== 'granted')
3332+
return;
33293333

3330-
try {
3331-
const metadata = await mm.fetchFromUrl( uri, { skipPostHeaders: true } );
3332-
if ( metadata ) {
3333-
addMetadata( metadata, queueItem ); // add metadata to play queue item
3334-
syncMetadataToAudioElements( queueItem );
3335-
if ( ! ( metadata.common.picture && metadata.common.picture.length ) ) {
3336-
getFolderCover( queueItem ).then( cover => {
3337-
queueItem.dataset.cover = cover;
3338-
syncMetadataToAudioElements( queueItem );
3339-
});
3334+
file = await queueItem.handle.getFile();
3335+
metadata = await parseBlob(file);
3336+
}
3337+
else
3338+
{
3339+
// Fetch metadata from URI
3340+
const response = await fetch(queueItem.dataset.file);
3341+
if (response.ok) {
3342+
if (response.body?.getReader) {
3343+
const contentType = response.headers.get("Content-Type");
3344+
const contentSize = response.headers.get("Content-Length");
3345+
try {
3346+
metadata = await parseWebStream(response.body, {
3347+
mimeType: contentType,
3348+
size: contentSize ? Number.parseInt(contentSize, 10) : undefined
3349+
}, {skipPostHeaders: true});
3350+
} finally {
3351+
await response.body.cancel();
3352+
}
3353+
} else {
3354+
// Fallback to Blob, in case the HTTP Result cannot be streamed
3355+
metadata = await parseBlob(await response.blob());
33403356
}
3357+
} else {
3358+
consoleLog(`Failed to fetch metadata http-response=${response.status} for url=${queueItem.dataset.file}`, true);
33413359
}
33423360
}
3343-
catch( e ) {}
3361+
}
3362+
catch( e ) {
3363+
consoleLog(`Error converting queued file="${queueItem.dataset.file ?? '?'}" to URI`, e);
3364+
return;
3365+
}
33443366

3345-
if ( revoke )
3346-
URL.revokeObjectURL( uri );
3367+
console.log(`Fetched metadata successful for url=${queueItem.dataset.file}`);
3368+
addMetadata( metadata, queueItem ); // add metadata to play queue item
3369+
3370+
// If no embedded picture, try folder cover
3371+
if ( ! ( metadata.common.picture && metadata.common.picture.length > 0) ) {
3372+
queueItem.dataset.cover = await getFolderCover( queueItem );
33473373
}
33483374

3349-
waitingMetadata--;
3350-
retrieveMetadata(); // call again to continue processing the queue
3375+
syncMetadataToAudioElements( queueItem );
33513376
}
3377+
3378+
--waitingMetadata;
33523379
}
33533380

33543381
/**

webpack.config.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,6 @@ module.exports = {
3636
new MiniCssExtractPlugin({
3737
filename: 'styles.css',
3838
}),
39-
new webpack.ProvidePlugin({
40-
Buffer: ['buffer', 'Buffer'],
41-
process: 'process/browser.js',
42-
}),
4339
],
4440
output: {
4541
filename: pathData => {

webpack.dev.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,6 @@ module.exports = {
3535
},
3636
plugins: [
3737
new webpack.HotModuleReplacementPlugin(),
38-
new webpack.ProvidePlugin({
39-
Buffer: ['buffer', 'Buffer'],
40-
process: 'process/browser.js',
41-
}),
4238
],
4339
output: {
4440
filename: 'audioMotion.js',

0 commit comments

Comments
 (0)