mirror of
https://github.com/janishutz/MusicPlayerV2.git
synced 2025-11-25 13:04:23 +00:00
add notifier to apple-music integration
This commit is contained in:
@@ -115,7 +115,7 @@ app.get( '/clientDisplayNotifier', ( req, res ) => {
|
|||||||
app.get( '/mainNotifier', ( req, res ) => {
|
app.get( '/mainNotifier', ( req, res ) => {
|
||||||
const ipRetrieved = req.headers[ 'x-forwarded-for' ];
|
const ipRetrieved = req.headers[ 'x-forwarded-for' ];
|
||||||
const ip = ipRetrieved ? ipRetrieved.split( /, / )[ 0 ] : req.connection.remoteAddress;
|
const ip = ipRetrieved ? ipRetrieved.split( /, / )[ 0 ] : req.connection.remoteAddress;
|
||||||
if ( ip === '::ffff:127.0.0.1' ) {
|
if ( ip === '::ffff:127.0.0.1' || ip === '::1' ) {
|
||||||
res.writeHead( 200, {
|
res.writeHead( 200, {
|
||||||
'Content-Type': 'text/event-stream',
|
'Content-Type': 'text/event-stream',
|
||||||
'Cache-Control': 'no-cache',
|
'Cache-Control': 'no-cache',
|
||||||
@@ -123,7 +123,7 @@ app.get( '/mainNotifier', ( req, res ) => {
|
|||||||
} );
|
} );
|
||||||
res.status( 200 );
|
res.status( 200 );
|
||||||
res.flushHeaders();
|
res.flushHeaders();
|
||||||
let det = { 'type': 'basics', 'data': connectedClients };
|
let det = { 'type': 'basics' };
|
||||||
res.write( `data: ${ JSON.stringify( det ) }\n\n` );
|
res.write( `data: ${ JSON.stringify( det ) }\n\n` );
|
||||||
connectedMain = res;
|
connectedMain = res;
|
||||||
} else {
|
} else {
|
||||||
@@ -199,22 +199,23 @@ app.post( '/statusUpdate', ( req, res ) => {
|
|||||||
} );
|
} );
|
||||||
|
|
||||||
// STATUS UPDATE from the client display to send to main ui
|
// STATUS UPDATE from the client display to send to main ui
|
||||||
const allowedMainUpdates = [ 'disconnect', 'fullScreenStatus', 'visibility' ];
|
// Send update if page is closed
|
||||||
app.get( '/clientStatusUpdate/:status', ( req, res ) => {
|
const allowedMainUpdates = [ 'blur', 'visibility' ];
|
||||||
if ( allowedTypes.includes( req.body.type ) ) {
|
app.post( '/clientStatusUpdate', ( req, res ) => {
|
||||||
|
if ( allowedMainUpdates.includes( req.body.type ) ) {
|
||||||
const ipRetrieved = req.headers[ 'x-forwarded-for' ];
|
const ipRetrieved = req.headers[ 'x-forwarded-for' ];
|
||||||
const ip = ipRetrieved ? ipRetrieved.split( /, / )[ 0 ] : req.connection.remoteAddress;
|
const ip = ipRetrieved ? ipRetrieved.split( /, / )[ 0 ] : req.connection.remoteAddress;
|
||||||
sendClientUpdate( req.body.type, req.body.data, ip );
|
sendClientUpdate( req.body.type, ip );
|
||||||
res.send( 'ok' );
|
res.send( 'ok' );
|
||||||
} else {
|
} else {
|
||||||
res.status( 400 ).send( 'ERR_UNKNOWN_TYPE' );
|
res.status( 400 ).send( 'ERR_UNKNOWN_TYPE' );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
const sendClientUpdate = ( update, data, ip ) => {
|
const sendClientUpdate = ( update, ip ) => {
|
||||||
for ( let main in connectedMain ) {
|
try {
|
||||||
connectedMain[ main ].write( 'data: ' + JSON.stringify( { 'type': update, 'ip': ip, 'data': data } ) + '\n\n' );
|
connectedMain.write( 'data: ' + JSON.stringify( { 'type': update, 'ip': ip } ) + '\n\n' );
|
||||||
}
|
} catch ( err ) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
app.get( '/indexDirs', ( req, res ) => {
|
app.get( '/indexDirs', ( req, res ) => {
|
||||||
|
|||||||
@@ -11,6 +11,14 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
|
<div v-if="isShowingWarning" class="warning">
|
||||||
|
<h3>WARNING!</h3>
|
||||||
|
<p>A client display is being tampered with!</p>
|
||||||
|
<p>A desktop notification with a warning has already been dispatched.</p>
|
||||||
|
<button @click="dismissNotification()">Ok</button>
|
||||||
|
|
||||||
|
<div class="flash"></div>
|
||||||
|
</div>
|
||||||
<div v-if="isPreparingToPlay" class="preparingToPlay">
|
<div v-if="isPreparingToPlay" class="preparingToPlay">
|
||||||
<span class="material-symbols-outlined loading-spinner">autorenew</span>
|
<span class="material-symbols-outlined loading-spinner">autorenew</span>
|
||||||
<h1>Loading player...</h1>
|
<h1>Loading player...</h1>
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ const app = Vue.createApp( {
|
|||||||
isPreparingToPlay: false,
|
isPreparingToPlay: false,
|
||||||
additionalSongInfo: {},
|
additionalSongInfo: {},
|
||||||
hasFinishedInit: false,
|
hasFinishedInit: false,
|
||||||
|
isShowingWarning: false,
|
||||||
|
|
||||||
// For use with playlists that are partially from apple music and
|
// For use with playlists that are partially from apple music and
|
||||||
// local drive
|
// local drive
|
||||||
@@ -290,7 +291,9 @@ const app = Vue.createApp( {
|
|||||||
} );
|
} );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
this.audioPlayer.pause();
|
try {
|
||||||
|
this.audioPlayer.pause();
|
||||||
|
} catch ( err ) {}
|
||||||
} else {
|
} else {
|
||||||
this.audioPlayer.play();
|
this.audioPlayer.play();
|
||||||
this.musicKit.pause();
|
this.musicKit.pause();
|
||||||
@@ -619,6 +622,43 @@ const app = Vue.createApp( {
|
|||||||
const result = await this.musicKit.api.music( '/v1/catalog/ch/search', queryParameters );
|
const result = await this.musicKit.api.music( '/v1/catalog/ch/search', queryParameters );
|
||||||
console.log( result );
|
console.log( result );
|
||||||
} )();
|
} )();
|
||||||
|
},
|
||||||
|
connectToNotifier() {
|
||||||
|
let source = new EventSource( '/mainNotifier', { withCredentials: true } );
|
||||||
|
source.onmessage = ( e ) => {
|
||||||
|
let data;
|
||||||
|
try {
|
||||||
|
data = JSON.parse( e.data );
|
||||||
|
} catch ( err ) {
|
||||||
|
data = { 'type': e.data };
|
||||||
|
}
|
||||||
|
if ( data.type === 'blur' ) {
|
||||||
|
this.isShowingWarning = true;
|
||||||
|
} else if ( data.type === 'visibility' ) {
|
||||||
|
this.isShowingWarning = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
source.onopen = () => {
|
||||||
|
console.log( 'client notifier connected successfully' );
|
||||||
|
};
|
||||||
|
|
||||||
|
let self = this;
|
||||||
|
|
||||||
|
source.addEventListener( 'error', function( e ) {
|
||||||
|
if ( e.eventPhase == EventSource.CLOSED ) source.close();
|
||||||
|
|
||||||
|
if ( e.target.readyState == EventSource.CLOSED ) {
|
||||||
|
console.log( 'disconnected' );
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout( () => {
|
||||||
|
self.connectToNotifier();
|
||||||
|
}, 1000 );
|
||||||
|
}, false );
|
||||||
|
},
|
||||||
|
dismissNotification() {
|
||||||
|
this.isShowingWarning = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@@ -653,6 +693,7 @@ const app = Vue.createApp( {
|
|||||||
} else {
|
} else {
|
||||||
this.initMusicKit();
|
this.initMusicKit();
|
||||||
}
|
}
|
||||||
|
this.connectToNotifier();
|
||||||
fetch( '/getLocalIP' ).then( res => {
|
fetch( '/getLocalIP' ).then( res => {
|
||||||
if ( res.status === 200 ) {
|
if ( res.status === 200 ) {
|
||||||
res.text().then( ip => {
|
res.text().then( ip => {
|
||||||
|
|||||||
@@ -313,3 +313,47 @@ body, html {
|
|||||||
.slider-inactive {
|
.slider-inactive {
|
||||||
cursor: default !important;
|
cursor: default !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 40vw;
|
||||||
|
height: 50vh;
|
||||||
|
font-size: 2vh;
|
||||||
|
background-color: rgb(255, 0, 0);
|
||||||
|
color: white;
|
||||||
|
position: fixed;
|
||||||
|
right: 1vh;
|
||||||
|
top: 1vh;
|
||||||
|
flex-direction: column;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning h3 {
|
||||||
|
font-size: 4vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning .flash {
|
||||||
|
background-color: rgba(255, 0, 0, 0.4);
|
||||||
|
animation: flashing linear infinite 1s;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
position: fixed;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes flashing {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ createApp( {
|
|||||||
micAnalyzer: null,
|
micAnalyzer: null,
|
||||||
beatDetected: false,
|
beatDetected: false,
|
||||||
colorThief: null,
|
colorThief: null,
|
||||||
|
lastDispatch: new Date().getTime() - 5000,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -290,23 +291,41 @@ createApp( {
|
|||||||
return flux;
|
return flux;
|
||||||
},
|
},
|
||||||
notifier() {
|
notifier() {
|
||||||
console.log( 'notifier enabled' );
|
if ( parseInt( this.lastDispatch ) + 5000 < new Date().getTime() ) {
|
||||||
|
|
||||||
|
}
|
||||||
|
Notification.requestPermission();
|
||||||
|
|
||||||
|
console.warn( '[ notifier ]: Status is now enabled \n\n-> Any leaving or tampering with the website will send a notification to the host' );
|
||||||
// Detect if window is currently in focus
|
// Detect if window is currently in focus
|
||||||
window.onblur = () => {
|
window.onblur = () => {
|
||||||
console.log( 'left browser or page' );
|
this.sendNotification( 'blur' );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect key events
|
// Detect if browser window becomes hidden (also with blur event)
|
||||||
window.addEventListener( 'keypress', keyEvent => {
|
document.onvisibilitychange = () => {
|
||||||
console.log( keyEvent.key );
|
if ( document.visibilityState === 'hidden' ) {
|
||||||
|
this.sendNotification( 'visibility' );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
sendNotification( notification ) {
|
||||||
|
let fetchOptions = {
|
||||||
|
method: 'post',
|
||||||
|
body: JSON.stringify( { 'type': notification } ),
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'charset': 'utf-8'
|
||||||
|
},
|
||||||
|
};
|
||||||
|
fetch( '/clientStatusUpdate', fetchOptions ).catch( err => {
|
||||||
|
console.error( err );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// Detect if browser window becomes hidden (also with blur event)
|
new Notification( 'YOU ARE UNDER SURVEILLANCE', {
|
||||||
document.addEventListener( 'visibilitychange', visibilityEvent => {
|
body: 'Please return to the original webpage immediately!',
|
||||||
if ( document.visibilityState === 'hidden' ) {
|
requireInteraction: true,
|
||||||
console.log( 'left page' );
|
} )
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
|||||||
Reference in New Issue
Block a user