update external fancy screen

This commit is contained in:
2023-10-30 14:57:35 +01:00
parent 504b2567e3
commit c9687d7406
5 changed files with 213 additions and 266 deletions

View File

@@ -13,16 +13,93 @@ app.use( cors() );
let indexedData = {};
let coverArtIndex = {};
const allowedFileTypes = [ '.mp3', '.wav', '.flac' ]
const allowedFileTypes = [ '.mp3', '.wav', '.flac' ];
let connectedClients = [];
let currentDetails = {
'songQueue': [],
'currentlyPlaying': '',
'pos': 0,
'isPlaying': false
};
let connectedMain = {};
app.get( '/', ( request, response ) => {
response.send( 'Hello world' );
response.sendFile( path.join( __dirname + '/client/showcase.html' ) );
} );
app.get( '/showcase.js', ( req, res ) => {
res.sendFile( path.join( __dirname + '/client/showcase.js' ) );
} );
app.get( '/showcase.css', ( req, res ) => {
res.sendFile( path.join( __dirname + '/client/showcase.css' ) );
} );
app.get( '/clientDisplayNotifier', ( req, res ) => {
res.writeHead( 200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
} );
res.status( 200 );
res.flushHeaders();
let det = { 'type': 'basics', 'data': currentDetails };
res.write( `data: ${ JSON.stringify( det ) }\n\n` );
connectedClients.push( res );
} );
app.get( '/mainNotifier', ( req, res ) => {
const ipRetrieved = req.headers[ 'x-forwarded-for' ];
const ip = ipRetrieved ? ipRetrieved.split( /, / )[ 0 ] : req.connection.remoteAddress;
if ( ip === '::ffff:127.0.0.1' ) {
res.writeHead( 200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
} );
res.status( 200 );
res.flushHeaders();
let det = { 'type': 'basics', 'data': currentDetails };
res.write( `data: ${ JSON.stringify( det ) }\n\n` );
connectedMain = res;
} else {
res.send( 'wrong' );
}
} );
app.post( '/statusUpdate', ( req, res ) => {
if ( req.body.status === 'playingSong' ) {
} else if ( req.body.status === 'isPlaying' ) {
} else if ( req.body.status === 'songQueue' ) {
} else if ( req.body.status === 'pos' ) {
}
} );
app.get( '/clientStatusUpdate/:status', ( req, res ) => {
if ( req.params.status === 'disconnect' ) {
} else if ( req.params.status === 'fullScreenExit' ) {
} else if ( req.params.status === 'inactive' ) {
} else if ( req.params.status === 'reactivated' ) {
}
} );
app.get( '/openSongs', ( req, res ) => {
res.send( '{ "data": [ "/home/janis/Music/KB2022" ] }' );
// res.send( '{ "data": [ "/mnt/storage/SORTED/Music/audio/KB2022" ] }' );
// res.send( '{ "data": [ "/home/janis/Music/KB2022" ] }' );
res.send( '{ "data": [ "/mnt/storage/SORTED/Music/audio/KB2022" ] }' );
// res.send( { 'data': dialog.showOpenDialogSync( { properties: [ 'openDirectory' ], title: 'Open music library folder' } ) } );
} );

View File

@@ -0,0 +1,94 @@
.material-symbols-outlined {
font-variation-settings:
'FILL' 0,
'wght' 400,
'GRAD' 0,
'opsz' 24
}
.voting-wrapper {
display: flex;
justify-content: center;
align-items: center;
flex-direction: row;
}
.voting {
border-radius: 500px;
border: 1px black solid;
font-size: 150%;
cursor: pointer;
}
.voting-counter {
margin: 0;
font-size: 150%;
margin-left: 10px;
margin-right: 10px;
}
body {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.content {
justify-content: flex-start;
}
.input {
width: 30vw;
padding: 20px;
border-radius: 20px;
border: none;
margin-bottom: 1vh;
margin-top: 5px;
}
.entry {
border: black 2px solid;
padding: 1% 10%;
width: 40vw;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.selected {
background-color: green;
}
.comment {
width: 50%;
text-align: center;
}
.wrapper {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-bottom: 5vh;
}
.bottom-bar {
position: fixed;
width: 100%;
margin: 0;
background-color: lightgray;
left: 0;
bottom: 0;
display: flex;
justify-content: center;
padding: 0;
padding-top: 0.5vh;
padding-bottom: 5vh,
}
.content {
display: block !important;
}

View File

@@ -8,107 +8,12 @@
<title>Showcase - MusicPlayerV2</title>
<link rel="stylesheet" href="/showcase.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
<style>
.material-symbols-outlined {
font-variation-settings:
'FILL' 0,
'wght' 400,
'GRAD' 0,
'opsz' 24
}
.voting-wrapper {
display: flex;
justify-content: center;
align-items: center;
flex-direction: row;
}
.voting {
border-radius: 500px;
border: 1px black solid;
font-size: 150%;
cursor: pointer;
}
.voting-counter {
margin: 0;
font-size: 150%;
margin-left: 10px;
margin-right: 10px;
}
body {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
}
.content {
justify-content: flex-start;
}
.input {
width: 30vw;
padding: 20px;
border-radius: 20px;
border: none;
margin-bottom: 1vh;
margin-top: 5px;
}
.entry {
border: black 2px solid;
padding: 1% 10%;
width: 40vw;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.selected {
background-color: green;
}
.comment {
width: 50%;
text-align: center;
}
.wrapper {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-bottom: 5vh;
}
.bottom-bar {
position: fixed;
width: 100%;
margin: 0;
background-color: lightgray;
left: 0;
bottom: 0;
display: flex;
justify-content: center;
padding: 0;
padding-top: 0.5vh;
padding-bottom: 5vh,
}
.content {
display: block !important;
}
</style>
</head>
<body>
<div class="content" id="app">
<div class="wrapper" v-if="hasLoaded">
<img :src="" alt="">
<h1>Ok</h1>
<!-- <img :src="" alt=""> -->
</div>
<div v-else>
<h1>Loading...</h1>
@@ -116,6 +21,6 @@
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="/js/voting.js"></script>
<script src="/showcase.js"></script>
</body>
</html>

View File

@@ -5,179 +5,50 @@ createApp( {
data() {
return {
hasLoaded: false,
songs: {},
playingSong: {}
};
},
computed: {
orderedVotes() {
if ( this.sorting === 'oldest' ) {
return Object.values( this.entries );
} else if ( this.sorting === 'newest' ) {
const ent = Object.keys( this.entries ).reverse();
let ret = [];
for ( let entry in ent ) {
ret.push( this.entries[ ent[ entry ] ] );
}
return ret;
} else {
let ent = Object.keys( this.entries ).sort( ( a, b ) => {
if ( this.sorting === 'nameUp' ) {
return this.entries[ a ].title.localeCompare( this.entries[ b ].title );
} else if ( this.sorting === 'nameDown' ) {
return this.entries[ b ].title.localeCompare( this.entries[ a ].title );
} else if ( this.sorting === 'mostVoted' ) {
return this.entries[ b ].count - this.entries[ a ].count;
} else if ( this.sorting === 'leastVoted' ) {
return this.entries[ a ].count - this.entries[ b ].count;
}
} );
let ret = [];
for ( let entry in ent ) {
ret.push( this.entries[ ent[ entry ] ] );
}
return ret;
}
}
},
methods: {
getData() {
fetch( '/voting/get/' + location.pathname.substring( 8 ) ).then( response => {
response.json().then( data => {
this.fingerprint();
this.entries = data;
let fetchOptions = {
method: 'post',
body: JSON.stringify( { 'fingerprint': this.userIdentifier } ),
headers: {
'Content-Type': 'application/json',
'charset': 'utf-8'
},
connect() {
let source = new EventSource( '/clientDisplayNotifier', { withCredentials: true } );
let self = this;
source.onmessage = ( e ) => {
let data;
try {
data = JSON.parse( e.data );
} catch ( err ) {
data = { 'type': e.data };
}
if ( data.type === 'basics' ) {
console.log( 'basics' );
console.log( data.data );
} else if ( data.type === 'pos' ) {
} else if ( data.type === 'isPlaying' ) {
} else if ( data.type === 'songQueue' ) {
} else if ( data.type === 'currentlyPlaying' ) {
}
};
fetch( '/voting/getVotedOn/' + location.pathname.substring( 8 ), fetchOptions ).then( res => {
if ( res.status === 200 ) {
res.json().then( json => {
this.votedOn = JSON.parse( localStorage.getItem( 'itemsVotedOn' ) ?? '{}' );
for ( let el in json ) {
if ( json[ el ] === 1 ) {
this.votedOn[ json[ el ] ] = 'up';
} else if ( json[ el ] === -1 ) {
this.votedOn[ json[ el ] ] = 'down';
}
}
localStorage.setItem( 'itemsVotedOn', JSON.stringify( this.votedOn ) );
this.hasLoadedVotes = true;
} );
}
} );
} );
} );
fetch( '/voting/getDetails/' + location.pathname.substring( 8 ) ).then( response => {
response.json().then( data => {
this.votingDetails = data;
this.hasLoadedBasics = true;
} );
} );
},
save() {
if ( this.newSuggestion.comment && this.newSuggestion.title ) {
let alreadyExists = false;
for ( let el in this.entries ) {
if ( this.entries[ el ][ 'title' ].toLocaleLowerCase() === this.newSuggestion.title.toLocaleLowerCase() ) {
alreadyExists = true;
}
}
if ( !alreadyExists ) {
let fetchOptions = {
method: 'post',
body: JSON.stringify( this.newSuggestion ),
headers: {
'Content-Type': 'application/json',
'charset': 'utf-8'
},
source.onopen = () => {
this.hasLoaded = true;
};
fetch( '/voting/add/' + location.pathname.substring( 8 ), fetchOptions ).then( response => {
if ( response.status === 418 ) {
alert( 'One or more of the words in either your description or title is on our blocklist. Please make sure that you are not using any words that are NSFW, racist or similar.' );
} else if ( response.status !== 200 ) {
alert( 'there was an error updating' );
} else {
this.closePopup();
this.getData();
source.addEventListener( 'error', function( e ) {
if ( e.eventPhase == EventSource.CLOSED ) source.close();
if ( e.target.readyState == EventSource.CLOSED ) {
console.log( 'disconnected' );
}
} );
this.closePopup();
this.getData();
} else {
alert( 'An entry with this name exists already. Please vote on that entry.' );
}
} else {
alert( 'Not all required fields are filled out!' );
}
},
fingerprint() {
// I am forced to do this because there are idiots in this world
// https://stackoverflow.com/questions/27247806/generate-unique-id-for-each-device
if ( !this.userIdentifier ) {
const navigator_info = window.navigator;
const screen_info = window.screen;
let uid = navigator_info.mimeTypes.length;
uid += navigator_info.userAgent.replace( /\D+/g, '' );
uid += navigator_info.plugins.length;
uid += screen_info.height || '';
uid += screen_info.width || '';
uid += screen_info.pixelDepth || '';
this.userIdentifier = uid;
}
},
vote( type, suggestionID ) {
this.fingerprint();
let voteType = type;
let didDeactivate = false;
if ( this.votedOn[ suggestionID ] === type ) {
didDeactivate = true;
if ( type === 'up' ) {
voteType = 'down';
} else {
voteType = 'up';
}
} else if ( this.votedOn[ suggestionID ] ) {
return;
}
let fetchOptions = {
method: 'post',
body: JSON.stringify( { 'voteType': voteType, 'id': suggestionID, 'fingerprint': this.userIdentifier } ),
headers: {
'Content-Type': 'application/json',
'charset': 'utf-8'
},
};
fetch( '/voting/vote/' + location.pathname.substring( 8 ), fetchOptions ).then( response => {
if ( response.status === 409 ) {
alert( 'You have already voted on this!' );
} else if ( response.status !== 200 ) {
alert( 'there was an error updating' );
} else {
this.votedOn[ suggestionID ] = didDeactivate ? undefined : voteType;
localStorage.setItem( 'itemsVotedOn', JSON.stringify( this.votedOn ) );
this.getData();
}
} );
},
closePopup() {
// eslint-disable-next-line no-undef
$( '#popup' ).fadeOut( 500 );
// eslint-disable-next-line no-undef
$( 'body' ).removeClass( 'menuOpen' );
this.getData();
},
addSuggestion () {
// eslint-disable-next-line no-undef
$( '#popup' ).fadeIn( 500 );
// eslint-disable-next-line no-undef
$( 'body' ).addClass( 'menuOpen' );
}, false );
},
},
mounted() {
this.getData();
this.connect();
}
} ).mount( '#app' );