diff --git a/frontend/src/app.js b/frontend/src/app.js index 8d4e841..a90f22f 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -138,8 +138,8 @@ app.get( '/indexDirs', ( req, res ) => { app.get( '/getSongCover', ( req, res ) => { if ( req.query.filename ) { - if ( coverArtIndex[ req.query.filename ] ) { - res.send( coverArtIndex[ req.query.filename ] ); + if ( indexer.getImages( req.query.filename ) ) { + res.send( indexer.getImages( req.query.filename ) ); } else { res.status( 404 ).send( 'No cover image for this file' ); } diff --git a/frontend/src/client/showcase.html b/frontend/src/client/showcase.html index 78afdb1..0982614 100644 --- a/frontend/src/client/showcase.html +++ b/frontend/src/client/showcase.html @@ -16,6 +16,7 @@
music_note +
@@ -33,7 +34,8 @@
music_note - + +
diff --git a/frontend/src/client/showcase.js b/frontend/src/client/showcase.js index e8e089a..d4a4848 100644 --- a/frontend/src/client/showcase.js +++ b/frontend/src/client/showcase.js @@ -148,7 +148,6 @@ createApp( { }, false ); }, handleBackground() { - // TODO: Add hotkeys let colourDetails = []; let colours = []; let differentEnough = true; diff --git a/frontend/src/components/mediaPool.vue b/frontend/src/components/mediaPool.vue index 691769f..e2065eb 100644 --- a/frontend/src/components/mediaPool.vue +++ b/frontend/src/components/mediaPool.vue @@ -2,7 +2,8 @@
- music_note + music_note +
@@ -195,7 +196,6 @@ return { hasLoadedSongs: false, isLoadingSongs: false, - loadCoverArtPreview: true, allSongs: [], songQueue: [], loadedDirs: [], @@ -206,7 +206,8 @@ repeat: false, isShowingFancyView: false, errorOccurredLoading: false, - coverArtSetting: 'api' + coverArtSetting: 'api', + doOverride: false, } }, methods: { @@ -292,7 +293,7 @@ }, indexFiles () { for ( let dir in this.loadedDirs ) { - fetch( 'http://localhost:8081/indexDirs?dir=' + this.loadedDirs[ dir ] + ( this.loadCoverArtPreview ? '&coverart=' + this.coverArtSetting : '' ) ).then( res => { + fetch( 'http://localhost:8081/indexDirs?dir=' + this.loadedDirs[ dir ] + '&coverart=' + this.coverArtSetting + '&doOverride=' + this.doOverride ).then( res => { if ( res.status === 200 ) { this.errorOccurredLoading = false; res.json().then( json => { diff --git a/frontend/src/components/player.vue b/frontend/src/components/player.vue index 6d3cbbb..4e55fac 100644 --- a/frontend/src/components/player.vue +++ b/frontend/src/components/player.vue @@ -19,6 +19,7 @@
music_note +
music_note diff --git a/frontend/src/indexer.js b/frontend/src/indexer.js index 9d339a6..1ddeeed 100644 --- a/frontend/src/indexer.js +++ b/frontend/src/indexer.js @@ -14,7 +14,6 @@ const allowedFileTypes = [ '.mp3', '.wav', '.flac' ]; const csv = require( 'csv-parser' ); const path = require( 'path' ); -let indexedData = {}; let coverArtIndex = {}; module.exports.index = ( req ) => { @@ -25,19 +24,21 @@ module.exports.index = ( req ) => { return; }; ( async() => { - // TODO: Check for songlist.csv or songlist.json file and use the data provided there for each song to override + // Check for songlist.csv or songlist.json file and use the data provided there for each song to override // what was found automatically. If no song title was found in songlist or metadata, use filename - // TODO: Also save found information to those files and don't rerun checks if data is present - if ( dat.includes( 'songlist.csv' ) || dat.includes( 'songlist.json' ) ) { - parseExistingData( dat, req.query.dir ).then( data => { - parseDir( dat, req, data ); - } ); - } else if ( dat.includes( 'songs.json' ) ) { + // additionally check if dir has been indexed (songs.json file) + if ( dat.includes( 'songs.json' ) ) { parseExistingData( dat, req.query.dir ).then( data => { resolve( data ); } ).catch( err => { reject( err ); } ); + } else if ( dat.includes( 'songlist.csv' ) || dat.includes( 'songlist.json' ) ) { + parseExistingData( dat, req.query.dir ).then( data => { + parseDir( dat, req, data ).then( indexedDir => { + resolve( indexedDir ); + } ); + } ); } else { resolve( await parseDir( dat, req ) ); } @@ -46,6 +47,10 @@ module.exports.index = ( req ) => { } ); } +module.exports.getImages = ( filename ) => { + return coverArtIndex[ filename ]; +}; + const parseExistingData = ( dat, dir ) => { return new Promise( ( resolve, reject ) => { if ( dat.includes( 'songs.json' ) ) { @@ -56,12 +61,11 @@ const parseExistingData = ( dat, dir ) => { let results = {}; let pos = 0; fs.createReadStream( path.join( dir + '/songlist.csv' ) ) - .pipe( csv( [ 'name', 'artist', 'dancingStyle', 'tempo' ] ) ) + .pipe( csv() ) .on( 'data', ( data ) => { results[ dir + '/' + dat[ pos ] ] = data; pos += 1; } ).on( 'end', () => { - console.log( results ); resolve( results ); } ); } else if ( dat.includes( 'songlist.json' ) ) { @@ -71,12 +75,11 @@ const parseExistingData = ( dat, dir ) => { } hasCompletedFetching = {}; - +let files = {}; const parseDir = ( dat, req, existingData ) => { - console.log( existingData ); return new Promise( ( resolve, reject ) => { ( async() => { - let files = {}; + files = {}; for ( let file in dat ) { if ( allowedFileTypes.includes( dat[ file ].slice( dat[ file ].indexOf( '.' ), dat[ file ].length ) ) ) { try { @@ -94,7 +97,9 @@ const parseDir = ( dat, req, existingData ) => { 'numberOfChannels': metadata[ 'format' ][ 'numberOfChannels' ], 'container': metadata[ 'format' ][ 'container' ], 'filename': req.query.dir + '/' + dat[ file ], + 'coverArtOrigin': req.query.coverart ?? 'none', } + runReplace( existingData, req.query.dir + '/' + dat[ file ], req.query.doOverride ?? false ); if ( req.query.coverart == 'meta' ) { if ( metadata[ 'common' ][ 'picture' ] ) { files[ req.query.dir + '/' + dat[ file ] ][ 'hasCoverArt' ] = true; @@ -102,28 +107,10 @@ const parseDir = ( dat, req, existingData ) => { } else { files[ req.query.dir + '/' + dat[ file ] ][ 'hasCoverArt' ] = false; } + hasCompletedFetching[ req.query.dir + '/' + dat[ file ] ] = true; } else if ( req.query.coverart == 'api' ) { hasCompletedFetching[ req.query.dir + '/' + dat[ file ] ] = false; - imageFetcher.fetch( 'songs', metadata[ 'common' ][ 'artist' ] + ' ' + metadata[ 'common' ][ 'title' ], ( err, data ) => { - if ( err ) { - files[ req.query.dir + '/' + dat[ file ] ][ 'hasCoverArt' ] = false; - return; - } - if ( data.results.songs ) { - if ( data.results.songs.data ) { - let url = data.results.songs.data[ 0 ].attributes.artwork.url; - url = url.replace( '{w}', data.results.songs.data[ 0 ].attributes.artwork.width ); - url = url.replace( '{h}', data.results.songs.data[ 0 ].attributes.artwork.height ); - console.log( url ); - } else { - files[ req.query.dir + '/' + dat[ file ] ][ 'hasCoverArt' ] = false; - } - } else { - files[ req.query.dir + '/' + dat[ file ] ][ 'hasCoverArt' ] = false; - } - hasCompletedFetching[ req.query.dir + '/' + dat[ file ] ] = true; - } ); - files[ req.query.dir + '/' + dat[ file ] ][ 'hasCoverArt' ] = true; + fetchImages( metadata[ 'common' ][ 'title' ], metadata[ 'common' ][ 'artist' ], metadata[ 'common' ][ 'year' ], req.query.dir, dat[ file ] ); } else { files[ req.query.dir + '/' + dat[ file ] ][ 'hasCoverArt' ] = false; } @@ -134,14 +121,15 @@ const parseDir = ( dat, req, existingData ) => { } } let ok = false; - setInterval( () => { + let waiter = setInterval( () => { for ( let song in hasCompletedFetching ) { if ( !hasCompletedFetching[ song ] ) { ok = false; } } if ( ok ) { - indexedData[ req.query.dir ] = files; + saveToDisk( req.query.dir ); + clearInterval( waiter ); resolve( files ); } ok = true; @@ -150,7 +138,59 @@ const parseDir = ( dat, req, existingData ) => { } ) }; +const runReplace = ( existingData, currentFile, doOverride ) => { + for ( let param in existingData[ currentFile ] ) { + if ( !files[ currentFile ][ param ] || doOverride ) { + files[ currentFile ][ param ] = existingData[ currentFile ][ param ]; + } + } +}; -const saveToDisk = () => { +let imageQueue = []; +let runInterval = null; +const fetchImages = ( title, artist, year, dir, filename ) => { + imageQueue.push( { 'title': title, 'artist': artist, 'year': year, 'dir': dir, 'filename': filename } ); + if ( runInterval === null ) { + runInterval = setInterval( () => { + if ( imageQueue.length > 0 ) { + const cur = imageQueue.reverse().pop(); + imageQueue.reverse(); + runFetch( cur.title, cur.artist, cur.year, cur.dir, cur.filename ); + } else { + clearInterval( runInterval ); + runInterval = null; + } + }, 100 ); + } +}; +const runFetch = ( title, artist, year, dir, filename ) => { + imageFetcher.fetch( 'songs', ( artist ?? '' ) + ' ' + ( title ?? '' ) + ' ' + ( year ?? '' ), ( err, data ) => { + if ( err ) { + files[ dir + '/' + filename ][ 'hasCoverArt' ] = false; + console.error( dir + '/' + filename ); + console.error( err ); + hasCompletedFetching[ dir + '/' + filename ] = true; + return; + } + if ( data.results.songs ) { + if ( data.results.songs.data ) { + let url = data.results.songs.data[ 0 ].attributes.artwork.url; + url = url.replace( '{w}', data.results.songs.data[ 0 ].attributes.artwork.width ); + url = url.replace( '{h}', data.results.songs.data[ 0 ].attributes.artwork.height ); + files[ dir + '/' + filename ][ 'coverArtURL' ] = url; + files[ dir + '/' + filename ][ 'hasCoverArt' ] = true; + } else { + files[ dir + '/' + filename ][ 'hasCoverArt' ] = false; + } + } else { + files[ dir + '/' + filename ][ 'hasCoverArt' ] = false; + } + hasCompletedFetching[ dir + '/' + filename ] = true; + } ); +} + + +const saveToDisk = ( dir ) => { + fs.writeFileSync( path.join( dir + '/songs.json' ), JSON.stringify( files ) ); }; \ No newline at end of file