load additional data from file now possible

This commit is contained in:
2023-11-18 13:26:49 +01:00
parent 2f57ce7257
commit bfde5cd0ac
4 changed files with 69 additions and 39 deletions

View File

@@ -138,7 +138,13 @@ const sendUpdate = ( update ) => {
connectedClients[ client ].write( 'data: ' + JSON.stringify( { 'type': 'pos', 'data': currentDetails[ 'pos' ] } ) + '\n\n' ); connectedClients[ client ].write( 'data: ' + JSON.stringify( { 'type': 'pos', 'data': currentDetails[ 'pos' ] } ) + '\n\n' );
} }
} else if ( update === 'playingSong' ) { } else if ( update === 'playingSong' ) {
currentDetails[ update ][ 'startTime' ] = new Date().getTime(); if ( !currentDetails[ 'playingSong' ] ) {
currentDetails[ 'playingSong' ] = {};
}
currentDetails[ 'playingSong' ][ 'startTime' ] = new Date().getTime();
for ( let client in connectedClients ) {
connectedClients[ client ].write( 'data: ' + JSON.stringify( { 'type': 'pos', 'data': currentDetails[ 'pos' ] } ) + '\n\n' );
}
} else if ( update === 'isPlaying' ) { } else if ( update === 'isPlaying' ) {
currentDetails[ 'playingSong' ][ 'startTime' ] = new Date().getTime(); currentDetails[ 'playingSong' ][ 'startTime' ] = new Date().getTime();
for ( let client in connectedClients ) { for ( let client in connectedClients ) {

View File

@@ -8,6 +8,8 @@
*/ */
const path = require( 'path' ); const path = require( 'path' );
const fs = require( 'fs' );
const csv = require( 'csv-parser' );
const dialog = require( 'electron' ).dialog; const dialog = require( 'electron' ).dialog;
const analyzeFile = ( filepath ) => { const analyzeFile = ( filepath ) => {
@@ -27,6 +29,8 @@ const analyzeFile = ( filepath ) => {
} ); } );
} else if ( filepath.includes( '.json' ) ) { } else if ( filepath.includes( '.json' ) ) {
resolve( JSON.parse( fs.readFileSync( filepath ) ) ); resolve( JSON.parse( fs.readFileSync( filepath ) ) );
} else {
reject( 'NO_CSV_OR_JSON_FILE' );
} }
} ); } );
} }
@@ -58,14 +62,22 @@ module.exports = ( app ) => {
title: 'Open file with additional data on the songs', title: 'Open file with additional data on the songs',
filters: [ filters: [
{ {
name: 'CSV', extensions: [ '.csv' ], name: 'All supported files (.csv, .json)',
name: 'JSON', extensions: [ '.json' ] extensions: [ 'csv', 'json' ],
},
{
name: 'JSON',
extensions: [ 'json' ],
},
{
name: 'CSV',
extensions: [ 'csv' ],
} }
] ],
} ); } )[ 0 ];
analyzeFile( filepath ).then( analyzedFile => { analyzeFile( filepath ).then( analyzedFile => {
res.send( analyzeFile ); res.send( analyzedFile );
} ).catch( err => { } ).catch( () => {
res.status( 500 ).send( 'no csv / json file' ); res.status( 500 ).send( 'no csv / json file' );
} ) } )
} ); } );

View File

@@ -40,18 +40,19 @@
<div class="player-wrapper"> <div class="player-wrapper">
<div class="player"> <div class="player">
<div class="controls"> <div class="controls">
<span class="material-symbols-outlined control-icon" :class="hasSelectedPlaylist ? 'active': 'inactive'" @click="control( 'previous' )">skip_previous</span> <span class="material-symbols-outlined control-icon" :class="hasFinishedInit ? 'active': 'inactive'" @click="control( 'previous' )">skip_previous</span>
<span class="material-symbols-outlined control-icon" :class="hasSelectedPlaylist ? 'active': 'inactive'" @click="control( 'replay10' )">replay_10</span> <span class="material-symbols-outlined control-icon" :class="hasFinishedInit ? 'active': 'inactive'" @click="control( 'replay10' )">replay_10</span>
<span class="material-symbols-outlined control-icon play-pause" v-if="!isPlaying && hasSelectedPlaylist" @click="control( 'play' )">play_arrow</span> <span class="material-symbols-outlined control-icon play-pause" v-if="!isPlaying && hasSelectedPlaylist" @click="control( 'play' )">play_arrow</span>
<span class="material-symbols-outlined control-icon play-pause" v-else-if="isPlaying && hasSelectedPlaylist" @click="control( 'pause' )">pause</span> <span class="material-symbols-outlined control-icon play-pause" v-else-if="isPlaying && hasSelectedPlaylist" @click="control( 'pause' )">pause</span>
<span class="material-symbols-outlined control-icon play-pause" style="cursor: default;" v-else>play_disabled</span> <span class="material-symbols-outlined control-icon play-pause" style="cursor: default;" v-else>play_disabled</span>
<span class="material-symbols-outlined control-icon" :class="hasSelectedPlaylist ? 'active': 'inactive'" @click="control( 'forward10' )">forward_10</span> <span class="material-symbols-outlined control-icon" :class="hasFinishedInit ? 'active': 'inactive'" @click="control( 'forward10' )">forward_10</span>
<span class="material-symbols-outlined control-icon" :class="hasSelectedPlaylist ? 'active': 'inactive'" @click="control( 'next' )" style="margin-right: 1vw;">skip_next</span> <span class="material-symbols-outlined control-icon" :class="hasFinishedInit ? 'active': 'inactive'" @click="control( 'next' )" style="margin-right: 1vw;">skip_next</span>
<span class="material-symbols-outlined control-icon" :class="hasSelectedPlaylist ? 'active': 'inactive'" v-if="!isShuffleEnabled" @click="control( 'shuffleOn' )">shuffle</span> <span class="material-symbols-outlined control-icon" :class="hasFinishedInit ? 'active': 'inactive'" v-if="!isShuffleEnabled" @click="control( 'shuffleOn' )">shuffle</span>
<span class="material-symbols-outlined control-icon" :class="hasSelectedPlaylist ? 'active': 'inactive'" v-else @click="control( 'shuffleOff' )">shuffle_on</span> <span class="material-symbols-outlined control-icon" :class="hasFinishedInit ? 'active': 'inactive'" v-else @click="control( 'shuffleOff' )">shuffle_on</span>
<span class="material-symbols-outlined control-icon" :class="hasSelectedPlaylist ? 'active': 'inactive'" v-if="repeatMode === 'off'" @click="control( 'repeatOne' )">repeat</span> <span class="material-symbols-outlined control-icon" :class="hasFinishedInit ? 'active': 'inactive'" v-if="repeatMode === 'off'" @click="control( 'repeatOne' )">repeat</span>
<span class="material-symbols-outlined control-icon" :class="hasSelectedPlaylist ? 'active': 'inactive'" v-else-if="repeatMode === 'one'" @click="control( 'repeatAll' )">repeat_one_on</span> <span class="material-symbols-outlined control-icon" :class="hasFinishedInit ? 'active': 'inactive'" v-else-if="repeatMode === 'one'" @click="control( 'repeatAll' )">repeat_one_on</span>
<span class="material-symbols-outlined control-icon" :class="hasSelectedPlaylist ? 'active': 'inactive'" v-else-if="repeatMode === 'all'" @click="control( 'repeatOff' )">repeat_on</span> <span class="material-symbols-outlined control-icon" :class="hasFinishedInit ? 'active': 'inactive'" v-else-if="repeatMode === 'all'" @click="control( 'repeatOff' )">repeat_on</span>
<span class="material-symbols-outlined control-icon" :class="hasSelectedPlaylist ? 'active': 'inactive'" @click="getAdditionalSongInfo()" title="Load additional song information">upload</span>
<div class="control-icon" id="settings"> <div class="control-icon" id="settings">
<span class="material-symbols-outlined">info</span> <span class="material-symbols-outlined">info</span>
<div id="showIP"> <div id="showIP">
@@ -62,7 +63,7 @@
</div> </div>
<div class="song-info"> <div class="song-info">
<div class="song-info-wrapper"> <div class="song-info-wrapper">
<img v-if="hasSelectedPlaylist" :src="playingSong.coverArtURL" class="image"> <img v-if="hasFinishedInit" :src="playingSong.coverArtURL" class="image">
<span class="material-symbols-outlined image" v-else>music_note</span> <span class="material-symbols-outlined image" v-else>music_note</span>
<div class="name"> <div class="name">
<h3>{{ playingSong.title ?? 'No song selected' }}</h3> <h3>{{ playingSong.title ?? 'No song selected' }}</h3>
@@ -76,8 +77,8 @@
</div> </div>
<div class="slider"> <div class="slider">
<progress id="progress-slider" class="progress-slider" :value="sliderProgress" max="1000" @mousedown="( e ) => { setPos( e ) }" <progress id="progress-slider" class="progress-slider" :value="sliderProgress" max="1000" @mousedown="( e ) => { setPos( e ) }"
:class="hasSelectedPlaylist ? '' : 'slider-inactive'"></progress> :class="hasFinishedInit ? '' : 'slider-inactive'"></progress>
<div v-if="hasSelectedPlaylist" id="slider-knob" @mousedown="( e ) => { startMove( e ) }" <div v-if="hasFinishedInit" id="slider-knob" @mousedown="( e ) => { startMove( e ) }"
:style="'left: ' + ( parseInt( originalPos ) + parseInt( sliderPos ) ) + 'px;'"> :style="'left: ' + ( parseInt( originalPos ) + parseInt( sliderPos ) ) + 'px;'">
<div id="slider-knob-style"></div> <div id="slider-knob-style"></div>
</div> </div>

View File

@@ -22,7 +22,8 @@ const app = Vue.createApp( {
localIP: '', localIP: '',
hasLoadedPlaylists: false, hasLoadedPlaylists: false,
isPreparingToPlay: false, isPreparingToPlay: false,
filenameForAdditionalInfo: '', additionalSongInfo: {},
hasFinishedInit: false,
// slider // slider
offset: 0, offset: 0,
@@ -69,23 +70,12 @@ const app = Vue.createApp( {
this.musicKit.shuffleMode = MusicKit.PlayerShuffleMode.off; this.musicKit.shuffleMode = MusicKit.PlayerShuffleMode.off;
this.musicKit.addEventListener( 'nowPlayingItemDidChange', ( e ) => { this.musicKit.addEventListener( 'nowPlayingItemDidChange', ( e ) => {
this.control( 'play' ); this.control( 'play' );
this.hasFinishedInit = true;
// Assemble this.playingSong // Assemble this.playingSong
// TODO: Also add additional items to queue if there are new // TODO: Also add additional items to queue if there are new
// items that weren't previously shown (limitation of MusicKitJS). // items that weren't previously shown (limitation of MusicKitJS).
if ( e.item ) { if ( e.item ) {
this.playingSong = { this.playingSong = this.songQueue[ this.musicKit.nowPlayingItemIndex ];
'artist': e.item.attributes.artistName,
'title': e.item.attributes.name,
'year': e.item.attributes.releaseDate,
// Think about bpm analysis
// 'bpm': metadata[ 'common' ][ 'bpm' ],
'genre': e.item.attributes.genreNames,
'duration': Math.round( e.item.attributes.durationInMillis / 1000 ),
'filename': this.songQueue[ this.musicKit.nowPlayingItemIndex ].filename,
'coverArtOrigin': 'api',
'hasCoverArt': true,
'queuePos': this.musicKit.nowPlayingItemIndex,
}
let url = e.item.attributes.artwork.url; let url = e.item.attributes.artwork.url;
url = url.replace( '{w}', e.item.attributes.artwork.width ); url = url.replace( '{w}', e.item.attributes.artwork.width );
url = url.replace( '{h}', e.item.attributes.artwork.height ); url = url.replace( '{h}', e.item.attributes.artwork.height );
@@ -144,18 +134,38 @@ const app = Vue.createApp( {
} else return false; } else return false;
}, },
getAdditionalSongInfo() { getAdditionalSongInfo() {
// TODO: Implement if ( Object.keys( this.additionalSongInfo ).length < 1 ) {
if ( this.filenameForAdditionalInfo ) { fetch( '/apple-music/getAdditionalData' ).then( res => {
if ( res.status === 200 ) {
res.json().then( json => {
this.additionalSongInfo = json;
this.handleAdditionalData();
} );
}
} );
}
},
handleAdditionalData () {
if ( Object.keys( this.additionalSongInfo ).length > 0 ) {
for ( let item in this.songQueue ) {
if ( this.additionalSongInfo[ item ] ) {
for ( let d in this.additionalSongInfo[ item ] ) {
if ( !this.songQueue[ item ][ d ] ) {
this.songQueue[ item ][ d ] = this.additionalSongInfo[ item ][ d ];
}
}
}
}
this.playingSong = this.songQueue[ this.musicKit.nowPlayingItemIndex ];
this.sendUpdate( 'songQueue' );
this.sendUpdate( 'playingSong' );
} }
}, },
selectPlaylist( id ) { selectPlaylist( id ) {
this.isPreparingToPlay = true; this.isPreparingToPlay = true;
this.musicKit.setQueue( { playlist: id } ).then( () => { this.musicKit.setQueue( { playlist: id } ).then( () => {
try { try {
this.control( 'play' );
this.loadPlaylist(); this.loadPlaylist();
// TODO: Load additional data from file
this.hasSelectedPlaylist = true; this.hasSelectedPlaylist = true;
this.isPreparingToPlay = false; this.isPreparingToPlay = false;
} catch( err ) { } catch( err ) {
@@ -251,8 +261,9 @@ const app = Vue.createApp( {
url = url.replace( '{w}', songQueue[ item ].attributes.artwork.width ); url = url.replace( '{w}', songQueue[ item ].attributes.artwork.width );
url = url.replace( '{h}', songQueue[ item ].attributes.artwork.height ); url = url.replace( '{h}', songQueue[ item ].attributes.artwork.height );
this.songQueue[ item ][ 'coverArtURL' ] = url; this.songQueue[ item ][ 'coverArtURL' ] = url;
} this.handleAdditionalData();
this.sendUpdate( 'songQueue' ); this.sendUpdate( 'songQueue' );
}
}, },
control( action ) { control( action ) {
if ( action === 'play' ) { if ( action === 'play' ) {