@@ -8,6 +8,7 @@ const process = require('process')
8
8
const parseString = require ( 'xml2js' ) . parseString
9
9
const http = require ( 'http' )
10
10
const gongMessage = fs . readFileSync ( 'gong.txt' , 'utf8' ) . split ( '\n' ) . filter ( Boolean ) ;
11
+ const voteMessage = fs . readFileSync ( 'vote.txt' , 'utf8' ) . split ( '\n' ) . filter ( Boolean ) ;
11
12
12
13
config . argv ( )
13
14
. env ( )
@@ -31,9 +32,11 @@ const adminChannel = config.get('adminChannel')
31
32
const gongLimit = config . get ( 'gongLimit' )
32
33
const voteImmuneLimit = config . get ( 'voteImmuneLimit' )
33
34
const voteLimit = config . get ( 'voteLimit' )
35
+ const flushVoteLimit = config . get ( 'flushVoteLimit' )
34
36
const token = config . get ( 'token' )
35
37
const maxVolume = config . get ( 'maxVolume' )
36
38
const market = config . get ( 'market' )
39
+ const voteTimeLimitMinutes = config . get ( 'voteTimeLimitMinutes' )
37
40
const clientId = config . get ( 'spotifyClientId' )
38
41
const clientSecret = config . get ( 'spotifyClientSecret' )
39
42
const searchLimit = config . get ( 'searchLimit' )
@@ -86,7 +89,9 @@ let gongBanned = false
86
89
let gongTrack = '' // What track was a GONG called on
87
90
let voteCounter = 0
88
91
const voteLimitPerUser = 4
92
+ const flushVoteLimitPerUser = 1
89
93
let voteScore = { }
94
+ let flushVoteScore = { }
90
95
91
96
if ( ! token ) {
92
97
throw new Error ( 'SLACK_API_TOKEN is not set' ) ;
@@ -193,7 +198,7 @@ function processInput(text, channel, userName) {
193
198
_gongcheck ( channel , userName )
194
199
break
195
200
case 'voteimmune' :
196
- _voteImmune ( channel , userName )
201
+ _voteImmune ( input , channel , userName )
197
202
break
198
203
case 'vote' :
199
204
case ':star:' :
@@ -216,6 +221,9 @@ function processInput(text, channel, userName) {
216
221
case 'volume' :
217
222
_getVolume ( channel )
218
223
break
224
+ case 'flushvote' :
225
+ _flushvote ( channel , userName )
226
+ break
219
227
case 'size' :
220
228
case 'count' :
221
229
case 'count(list)' :
@@ -281,6 +289,9 @@ function processInput(text, channel, userName) {
281
289
case 'snap' :
282
290
_purgeHalfQueue ( input , channel )
283
291
break
292
+ case 'listimmune' :
293
+ _listImmune ( channel )
294
+ break
284
295
default :
285
296
}
286
297
}
@@ -373,7 +384,7 @@ function _showQueue(channel) {
373
384
if ( item . title === track . title ) {
374
385
tracks . push ( ':notes: ' + '_#' + i + '_ ' + "*" + item . title + "*" + ' by ' + item . artist )
375
386
} else {
376
- tracks . push ( '>_#' + i + '_ ' + item . title + ' by ' + item . artist )
387
+ tracks . push ( '>_#' + i + '_ ' + "_" + item . title + "_" + ' by ' + item . artist )
377
388
}
378
389
}
379
390
)
@@ -412,10 +423,8 @@ function _upNext(channel) {
412
423
function ( item , i ) {
413
424
if ( i === currentIndex ) {
414
425
currentIndex = i
415
- tracks . push ( ':notes: ' + '_#' + i + '_ ' + item . title + ' by ' + item . artist )
416
- } else {
417
- tracks . push ( '>_#' + i + '_ ' + item . title + ' by ' + item . artist )
418
- }
426
+ tracks . push ( '_#' + i + '_ ' + "_" + item . title + "_" + ' by ' + item . artist )
427
+ }
419
428
}
420
429
)
421
430
tracks = tracks . slice ( Math . max ( currentIndex - 5 , 0 ) , Math . min ( currentIndex + 20 , tracks . length ) )
@@ -431,6 +440,55 @@ function _upNext(channel) {
431
440
} )
432
441
}
433
442
443
+
444
+ let voteTimer = null ;
445
+ const voteTimeLimit = voteTimeLimitMinutes * 60 * 1000 ; // Convert minutes to milliseconds
446
+
447
+ function _flushvote ( channel , userName ) {
448
+ logger . info ( '_flushvote...' ) ;
449
+
450
+ if ( ! ( userName in flushVoteScore ) ) {
451
+ flushVoteScore [ userName ] = 0 ;
452
+ }
453
+
454
+ if ( flushVoteScore [ userName ] >= flushVoteLimitPerUser ) {
455
+ _slackMessage ( 'Are you trying to cheat, ' + userName + '? DENIED!' , channel ) ;
456
+ } else {
457
+ flushVoteScore [ userName ] = flushVoteScore [ userName ] + 1 ;
458
+ voteCounter ++ ;
459
+ logger . info ( '1voteCounter: ' + voteCounter ) ;
460
+ logger . info ( '1voteTimer: ' + voteTimer ) ;
461
+ if ( voteCounter === 1 ) {
462
+ // Start the timer on the first vote
463
+ voteTimer = setTimeout ( ( ) => {
464
+ voteCounter = 0 ;
465
+ flushVoteScore = { } ;
466
+ _slackMessage ( 'Voting period ended.' , channel ) ;
467
+ logger . info ( 'Voting period ended... Guess the playlist isn´t that bad after all!!' ) ;
468
+ } , voteTimeLimit ) ;
469
+ _slackMessage ( "Voting period started for a flush of the queue... You have " + voteTimeLimitMinutes + " minutes to gather " + flushVoteLimit + " votes !!" , channel ) ;
470
+ logger . info ( 'Voting period started!!' ) ;
471
+ logger . info ( '3voteCounter: ' + voteCounter ) ;
472
+ logger . info ( '3voteTimer: ' + voteTimer ) ;
473
+ }
474
+
475
+ _slackMessage ( 'This is VOTE ' + "*" + voteCounter + "*" + '/' + flushVoteLimit + ' for a full flush of the playlist!!' , channel ) ;
476
+
477
+ if ( voteCounter >= flushVoteLimit ) {
478
+ clearTimeout ( voteTimer ) ; // Clear the timer if the vote limit is reached
479
+ _slackMessage ( 'The votes have spoken! Flushing the queue...:toilet:' , channel ) ;
480
+ try {
481
+ sonos . flush ( ) ;
482
+ } catch ( error ) {
483
+ logger . error ( 'Error flushing the queue: ' + error ) ;
484
+ }
485
+ voteCounter = 0 ;
486
+ flushVoteScore = { } ;
487
+ }
488
+ }
489
+ }
490
+
491
+
434
492
function _gong ( channel , userName ) {
435
493
logger . info ( '_gong...' )
436
494
_currentTrackTitle ( channel , function ( err , track ) {
@@ -441,7 +499,8 @@ function _gong(channel, userName) {
441
499
442
500
// NOTE: The gongTrack is checked in _currentTrackTitle() so we
443
501
// need to let that go through before checking if gong is banned.
444
- if ( gongBanned ) {
502
+ if ( _isTrackGongBanned ( track ) ) {
503
+ logger . info ( 'Track is gongBanned: ' + track ) ;
445
504
_slackMessage ( 'Sorry ' + userName + ', the people have voted and this track cannot be gonged...' , channel )
446
505
return
447
506
}
@@ -477,43 +536,93 @@ function _gong(channel, userName) {
477
536
} )
478
537
}
479
538
480
- function _voteImmune ( channel , userName ) {
481
- logger . info ( '_voteImmune...' )
482
- _currentTrackTitle ( channel , function ( err , track ) {
483
- if ( err ) {
484
- logger . error ( err ) ( err )
485
- }
486
- logger . info ( '_voteImmune > track: ' + track )
487
539
488
- if ( ! ( userName in voteImmuneScore ) ) {
489
- voteImmuneScore [ userName ] = 0
540
+
541
+ // Global object to store gongBanned status for each track
542
+ const gongBannedTracks = { } ;
543
+
544
+ function _voteImmune ( input , channel , userName ) {
545
+ var voteNb = input [ 1 ] ;
546
+ voteNb = Number ( voteNb ) + 1 ; // Add 1 to match the queue index
547
+ voteNb = String ( voteNb ) ;
548
+ logger . info ( 'voteNb: ' + voteNb ) ;
549
+
550
+ sonos . getQueue ( ) . then ( result => {
551
+ logger . info ( 'Current queue: ' + JSON . stringify ( result , null , 2 ) ) ;
552
+ logger . info ( 'Finding track:' + voteNb ) ;
553
+ let trackFound = false ;
554
+ let voteTrackId = null ;
555
+ let voteTrackName = null ;
556
+
557
+ for ( var i in result . items ) {
558
+ var queueTrack = result . items [ i ] . id ;
559
+ queueTrack = queueTrack . split ( '/' ) [ 1 ] ;
560
+ logger . info ( 'queueTrack: ' + queueTrack ) ;
561
+ if ( voteNb === queueTrack ) {
562
+ voteTrackId = result . items [ i ] . id . split ( '/' ) [ 1 ] ;
563
+ voteTrackName = result . items [ i ] . title ;
564
+ logger . info ( 'voteTrackName: ' + voteTrackName ) ;
565
+ trackFound = true ;
566
+ break ;
567
+ }
490
568
}
491
569
492
- if ( voteImmuneScore [ userName ] >= voteImmuneLimitPerUser ) {
493
- _slackMessage ( 'Are you trying to cheat, ' + userName + '? DENIED!' , channel )
494
- } else {
495
- if ( userName in gongScore ) {
496
- _slackMessage ( 'Changed your mind, ' + userName + '? Well, ok then...' , channel )
570
+ if ( trackFound ) {
571
+ if ( ! ( userName in voteImmuneScore ) ) {
572
+ voteImmuneScore [ userName ] = 0 ;
497
573
}
498
574
499
- voteImmuneScore [ userName ] = voteImmuneScore [ userName ] + 1
500
- voteImmuneCounter ++
501
- _slackMessage ( 'This is VOTE ' + voteImmuneCounter + '/' + voteImmuneLimit + ' for ' + track , channel )
502
- if ( voteImmuneCounter >= voteImmuneLimit ) {
503
- _slackMessage ( 'This track is now immune to GONG! (just this once)' , channel )
504
- voteImmuneCounter = 0
505
- voteImmuneScore = { }
506
- gongBanned = true
575
+ if ( voteImmuneScore [ userName ] >= voteImmuneLimitPerUser ) {
576
+ _slackMessage ( 'Are you trying to cheat, ' + userName + '? DENIED!' , channel ) ;
577
+ } else {
578
+ if ( userName in gongScore ) {
579
+ _slackMessage ( 'Changed your mind, ' + userName + '? Well, ok then...' , channel ) ;
580
+ }
581
+
582
+ voteImmuneScore [ userName ] = voteImmuneScore [ userName ] + 1 ;
583
+ voteImmuneCounter ++ ;
584
+
585
+ _slackMessage ( 'This is VOTE ' + voteImmuneCounter + '/' + voteImmuneLimit + ' for ' + "*" + voteTrackName + "*" , channel ) ;
586
+ if ( voteImmuneCounter >= voteImmuneLimit ) {
587
+ _slackMessage ( 'This track is now immune to GONG! (just this once)' , channel ) ;
588
+ voteImmuneCounter = 0 ;
589
+ voteImmuneScore = { } ;
590
+ gongBannedTracks [ voteTrackName ] = true ; // Mark the track as gongBanned
591
+ }
507
592
}
508
593
}
509
- } )
594
+ } ) ;
510
595
}
511
596
597
+ // Function to check if a track is gongBanned
598
+ function _isTrackGongBanned ( trackName ) {
599
+ return gongBannedTracks [ trackName ] === true ;
600
+ }
601
+
602
+ function _listImmune ( channel ) {
603
+ const gongBannedTracksList = Object . keys ( gongBannedTracks ) ;
604
+ if ( gongBannedTracksList . length === 0 ) {
605
+ _slackMessage ( 'No tracks are currently immune.' , channel ) ;
606
+ } else {
607
+ const message = 'Immune Tracks:\n' + gongBannedTracksList . join ( '\n' ) ;
608
+ _slackMessage ( message , channel ) ;
609
+ }
610
+ }
611
+
612
+
512
613
513
614
// Initialize vote count object
514
615
let trackVoteCount = { } ;
515
616
617
+
516
618
function _vote ( input , channel , userName ) {
619
+
620
+ // Get message
621
+ logger . info ( 'voteMessage.length: ' + voteMessage . length )
622
+ var ran = Math . floor ( Math . random ( ) * voteMessage . length )
623
+ var randomMessage = voteMessage [ ran ]
624
+ logger . info ( 'voteMessage: ' + randomMessage )
625
+
517
626
var voteNb = input [ 1 ] ;
518
627
voteNb = Number ( voteNb ) + 1 ; // Add 1 to match the queue index
519
628
voteNb = String ( voteNb ) ;
@@ -559,10 +668,10 @@ function _vote(input, channel, userName) {
559
668
// Log the vote count for the track
560
669
logger . info ( 'Track ' + voteTrackName + ' has received ' + trackVoteCount [ voteNb ] + ' votes.' ) ;
561
670
562
- _slackMessage ( 'This is VOTE ' + trackVoteCount [ voteNb ] + '/' + voteLimit + ' for ' + voteTrackName , channel ) ;
671
+ _slackMessage ( 'This is VOTE ' + trackVoteCount [ voteNb ] + '/' + voteLimit + ' for ' + "*" + voteTrackName + "*" , channel ) ;
563
672
if ( trackVoteCount [ voteNb ] >= voteLimit ) {
564
673
logger . info ( 'Track ' + voteTrackName + ' has reached the vote limit.' ) ;
565
- _slackMessage ( 'Yea!! This tune totally rocks :star: Lets peg it for the next one in the queue.. moving on up... :rocket: ' , channel ) ;
674
+ _slackMessage ( randomMessage , channel ) ;
566
675
567
676
// Reset the vote count for the track
568
677
voteImmuneCounter = 0 ;
@@ -679,21 +788,23 @@ function _previous(input, channel) {
679
788
function _help ( input , channel ) {
680
789
var message = 'Current commands!\n' +
681
790
' === === === === === === === \n' +
682
- '`add` *text* : Add song to the queue and start playing if idle. Will start with a fresh queue.\n' +
683
- '`addalbum` *text* : Add an album to the queue and start playing if idle. Will start with a fresh queue.\n' +
684
- '`bestof` : *text* : Add topp 10 tracks by the artist\n' +
791
+ '`add` *text* : add song to the queue and start playing if idle. Will start with a fresh queue.\n' +
792
+ '`addalbum` *text* : add an album to the queue and start playing if idle. Will start with a fresh queue.\n' +
793
+ '`bestof` : *text* : add topp 10 tracks by the artist\n' +
685
794
'`status` : show current status of Sonos\n' +
686
795
'`current` : list current track\n' +
687
796
'`search` *text* : search for a track, does NOT add it to the queue\n' +
688
797
'`searchalbum` *text* : search for an album, does NOT add it to the queue\n' +
689
798
'`searchplaylist` *text* : search for a playlist, does NOT add it to the queue\n' +
690
- '`addplaylist` *text* : Add a playlist to the queue and start playing if idle. Will start with a fresh queue.\n' +
691
- '`append` *text* : Append a song to the previous playlist and start playing the same list again.\n' +
692
- '`vote` *number* : Vote for a track to be played next!!! :rocket: \n' +
693
- '`votecheck` : How many votes there are currently, as well as who has voted.\n' +
694
- '`gong` : The current track is bad! ' + gongLimit + ' gongs will skip the track\n' +
695
- '`gongcheck` : How many gong votes there are currently, as well as who has gonged.\n' +
696
- '`voteimmune` : The current track is great! ' + voteImmuneLimit + ' votes will prevent the track from being gonged\n' +
799
+ '`addplaylist` *text* : add a playlist to the queue and start playing if idle. Will start with a fresh queue.\n' +
800
+ '`append` *text* : append a song to the previous playlist and start playing the same list again.\n' +
801
+ '`vote` *number* : vote for a track to be played next!!! :rocket: \n' +
802
+ '`votecheck` : how many votes there are currently, as well as who has voted.\n' +
803
+ '`gong` : current track is bad! ' + gongLimit + ' gongs will skip the track\n' +
804
+ '`gongcheck` : how many gong votes there are currently, as well as who has gonged.\n' +
805
+ '`voteimmune` *number* : vote to make the current track immune to gong. ' + voteImmuneLimit + ' votes will make it immune\n' +
806
+ '`flushvote` : vote to flush the queue. ' + flushVoteLimit + ' votes will flush the queue :toilet: \n' +
807
+ '`upnext` : show the next track to be played\n' +
697
808
'`volume` : view current volume\n' +
698
809
'`list` : list current queue\n'
699
810
@@ -715,7 +826,7 @@ function _help(input, channel) {
715
826
'`blacklist add @username` : add `@username` to the blacklist\n' +
716
827
'`blacklist del @username` : remove `@username` from the blacklist\n'
717
828
}
718
- message += ' === === === = ZenMusic @GitHub === === === ==\n'
829
+ message += ' === === === = SlackONOS @GitHub === === === ==\n'
719
830
_slackMessage ( message , channel )
720
831
}
721
832
@@ -821,27 +932,6 @@ function _normal(input, channel, byPassChannelValidation) {
821
932
} )
822
933
}
823
934
824
-
825
- function _gongplay ( input , channel ) {
826
- const mediaInfo = sonos . avTransportService ( ) . GetMediaInfo ( ) ;
827
- const positionInfo = sonos . avTransportService ( ) . GetPositionInfo ( ) ;
828
- logger . info ( 'Current Position: ' + JSON . stringify ( positionInfo . Track ) ) ;
829
-
830
- sonos . play ( 'https://github.com/htilly/zenmusic/raw/master/sound/gong.mp3' ) . then ( success => {
831
- logger . info ( '--------------- GongPlay!! ------------------' )
832
-
833
- nextToPlay = positionInfo . Track + 1
834
- logger . info ( 'Next to play: ' + nextToPlay )
835
- sonos . selectTrack ( nextToPlay ) . catch ( _debug => {
836
- logger . info ( 'Jumping to next track!.' )
837
- } )
838
- sonos . play ( )
839
-
840
- } ) . catch ( err => {
841
- logger . error ( 'Error occurred ' + err )
842
- } )
843
- }
844
-
845
935
function delay ( ms ) {
846
936
return new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
847
937
}
0 commit comments