@@ -8,6 +8,7 @@ const process = require('process')
88const parseString = require ( 'xml2js' ) . parseString
99const http = require ( 'http' )
1010const gongMessage = fs . readFileSync ( 'gong.txt' , 'utf8' ) . split ( '\n' ) . filter ( Boolean ) ;
11+ const voteMessage = fs . readFileSync ( 'vote.txt' , 'utf8' ) . split ( '\n' ) . filter ( Boolean ) ;
1112
1213config . argv ( )
1314 . env ( )
@@ -31,9 +32,11 @@ const adminChannel = config.get('adminChannel')
3132const gongLimit = config . get ( 'gongLimit' )
3233const voteImmuneLimit = config . get ( 'voteImmuneLimit' )
3334const voteLimit = config . get ( 'voteLimit' )
35+ const flushVoteLimit = config . get ( 'flushVoteLimit' )
3436const token = config . get ( 'token' )
3537const maxVolume = config . get ( 'maxVolume' )
3638const market = config . get ( 'market' )
39+ const voteTimeLimitMinutes = config . get ( 'voteTimeLimitMinutes' )
3740const clientId = config . get ( 'spotifyClientId' )
3841const clientSecret = config . get ( 'spotifyClientSecret' )
3942const searchLimit = config . get ( 'searchLimit' )
@@ -86,7 +89,9 @@ let gongBanned = false
8689let gongTrack = '' // What track was a GONG called on
8790let voteCounter = 0
8891const voteLimitPerUser = 4
92+ const flushVoteLimitPerUser = 1
8993let voteScore = { }
94+ let flushVoteScore = { }
9095
9196if ( ! token ) {
9297 throw new Error ( 'SLACK_API_TOKEN is not set' ) ;
@@ -193,7 +198,7 @@ function processInput(text, channel, userName) {
193198 _gongcheck ( channel , userName )
194199 break
195200 case 'voteimmune' :
196- _voteImmune ( channel , userName )
201+ _voteImmune ( input , channel , userName )
197202 break
198203 case 'vote' :
199204 case ':star:' :
@@ -216,6 +221,9 @@ function processInput(text, channel, userName) {
216221 case 'volume' :
217222 _getVolume ( channel )
218223 break
224+ case 'flushvote' :
225+ _flushvote ( channel , userName )
226+ break
219227 case 'size' :
220228 case 'count' :
221229 case 'count(list)' :
@@ -281,6 +289,9 @@ function processInput(text, channel, userName) {
281289 case 'snap' :
282290 _purgeHalfQueue ( input , channel )
283291 break
292+ case 'listimmune' :
293+ _listImmune ( channel )
294+ break
284295 default :
285296 }
286297 }
@@ -373,7 +384,7 @@ function _showQueue(channel) {
373384 if ( item . title === track . title ) {
374385 tracks . push ( ':notes: ' + '_#' + i + '_ ' + "*" + item . title + "*" + ' by ' + item . artist )
375386 } else {
376- tracks . push ( '>_#' + i + '_ ' + item . title + ' by ' + item . artist )
387+ tracks . push ( '>_#' + i + '_ ' + "_" + item . title + "_" + ' by ' + item . artist )
377388 }
378389 }
379390 )
@@ -412,10 +423,8 @@ function _upNext(channel) {
412423 function ( item , i ) {
413424 if ( i === currentIndex ) {
414425 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+ }
419428 }
420429 )
421430 tracks = tracks . slice ( Math . max ( currentIndex - 5 , 0 ) , Math . min ( currentIndex + 20 , tracks . length ) )
@@ -431,6 +440,55 @@ function _upNext(channel) {
431440 } )
432441}
433442
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+
434492function _gong ( channel , userName ) {
435493 logger . info ( '_gong...' )
436494 _currentTrackTitle ( channel , function ( err , track ) {
@@ -441,7 +499,8 @@ function _gong(channel, userName) {
441499
442500 // NOTE: The gongTrack is checked in _currentTrackTitle() so we
443501 // 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 ) ;
445504 _slackMessage ( 'Sorry ' + userName + ', the people have voted and this track cannot be gonged...' , channel )
446505 return
447506 }
@@ -477,43 +536,93 @@ function _gong(channel, userName) {
477536 } )
478537}
479538
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 )
487539
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+ }
490568 }
491569
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 ;
497573 }
498574
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+ }
507592 }
508593 }
509- } )
594+ } ) ;
510595}
511596
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+
512613
513614// Initialize vote count object
514615let trackVoteCount = { } ;
515616
617+
516618function _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+
517626 var voteNb = input [ 1 ] ;
518627 voteNb = Number ( voteNb ) + 1 ; // Add 1 to match the queue index
519628 voteNb = String ( voteNb ) ;
@@ -559,10 +668,10 @@ function _vote(input, channel, userName) {
559668 // Log the vote count for the track
560669 logger . info ( 'Track ' + voteTrackName + ' has received ' + trackVoteCount [ voteNb ] + ' votes.' ) ;
561670
562- _slackMessage ( 'This is VOTE ' + trackVoteCount [ voteNb ] + '/' + voteLimit + ' for ' + voteTrackName , channel ) ;
671+ _slackMessage ( 'This is VOTE ' + trackVoteCount [ voteNb ] + '/' + voteLimit + ' for ' + "*" + voteTrackName + "*" , channel ) ;
563672 if ( trackVoteCount [ voteNb ] >= voteLimit ) {
564673 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 ) ;
566675
567676 // Reset the vote count for the track
568677 voteImmuneCounter = 0 ;
@@ -679,21 +788,23 @@ function _previous(input, channel) {
679788function _help ( input , channel ) {
680789 var message = 'Current commands!\n' +
681790 ' === === === === === === === \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' +
685794 '`status` : show current status of Sonos\n' +
686795 '`current` : list current track\n' +
687796 '`search` *text* : search for a track, does NOT add it to the queue\n' +
688797 '`searchalbum` *text* : search for an album, does NOT add it to the queue\n' +
689798 '`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' +
697808 '`volume` : view current volume\n' +
698809 '`list` : list current queue\n'
699810
@@ -715,7 +826,7 @@ function _help(input, channel) {
715826 '`blacklist add @username` : add `@username` to the blacklist\n' +
716827 '`blacklist del @username` : remove `@username` from the blacklist\n'
717828 }
718- message += ' === === === = ZenMusic @GitHub === === === ==\n'
829+ message += ' === === === = SlackONOS @GitHub === === === ==\n'
719830 _slackMessage ( message , channel )
720831}
721832
@@ -821,27 +932,6 @@ function _normal(input, channel, byPassChannelValidation) {
821932 } )
822933}
823934
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-
845935function delay ( ms ) {
846936 return new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
847937}
0 commit comments