5
5
"math"
6
6
"sort"
7
7
"strings"
8
+ "time"
8
9
9
10
"github.com/gdamore/tcell/v2"
10
11
"github.com/rivo/tview"
@@ -33,6 +34,7 @@ type Ui struct {
33
34
playlists []SubsonicPlaylist
34
35
connection * SubsonicConnection
35
36
player * Player
37
+ scrobbleTimer * time.Timer
36
38
}
37
39
38
40
func (ui * Ui ) handleEntitySelected (directoryId string ) {
@@ -465,6 +467,12 @@ func createUi(_ *[]SubsonicIndex, playlists *[]SubsonicPlaylist, connection *Sub
465
467
// Stores the song IDs
466
468
var starIdList = map [string ]struct {}{}
467
469
470
+ // create reused timer to scrobble after delay
471
+ scrobbleTimer := time .NewTimer (0 )
472
+ if ! scrobbleTimer .Stop () {
473
+ <- scrobbleTimer .C
474
+ }
475
+
468
476
ui := Ui {
469
477
app : app ,
470
478
pages : pages ,
@@ -484,6 +492,7 @@ func createUi(_ *[]SubsonicIndex, playlists *[]SubsonicPlaylist, connection *Sub
484
492
playlists : * playlists ,
485
493
connection : connection ,
486
494
player : player ,
495
+ scrobbleTimer : scrobbleTimer ,
487
496
}
488
497
489
498
ui .addStarredToList ()
@@ -499,6 +508,17 @@ func createUi(_ *[]SubsonicIndex, playlists *[]SubsonicPlaylist, connection *Sub
499
508
ui .logList .RemoveItem (0 )
500
509
}
501
510
})
511
+
512
+ case <- scrobbleTimer .C :
513
+ // scrobble submission delay elapsed
514
+ paused , err := ui .player .IsPaused ()
515
+ connection .Logger .Printf ("scrobbler event: paused %v, err %v, qlen %d" , paused , err , len (ui .player .Queue ))
516
+ isPlaying := err == nil && ! paused
517
+ if len (ui .player .Queue ) > 0 && isPlaying {
518
+ // it's still playing, submit it
519
+ currentSong := ui .player .Queue [0 ]
520
+ ui .connection .ScrobbleSubmission (currentSong .Id , true )
521
+ }
502
522
}
503
523
}
504
524
}()
@@ -917,8 +937,35 @@ func (ui *Ui) handleMpvEvents() {
917
937
}
918
938
} else if e .Event_Id == mpv .EVENT_START_FILE {
919
939
ui .player .ReplaceInProgress = false
920
- ui .startStopStatus .SetText ("[::b]stmp: [green]playing " + ui .player .Queue [0 ].Title )
921
940
updateQueueList (ui .player , ui .queueList , ui .starIdList )
941
+
942
+ if len (ui .player .Queue ) > 0 {
943
+ currentSong := ui .player .Queue [0 ]
944
+ ui .startStopStatus .SetText ("[::b]stmp: [green]playing " + currentSong .Title )
945
+
946
+ if ui .connection .Scrobble {
947
+ // scrobble "now playing" event
948
+ ui .connection .ScrobbleSubmission (currentSong .Id , false )
949
+
950
+ // scrobble "submission" after song has been playing a bit
951
+ // see: https://www.last.fm/api/scrobbling
952
+ // A track should only be scrobbled when the following conditions have been met:
953
+ // The track must be longer than 30 seconds. And the track has been played for
954
+ // at least half its duration, or for 4 minutes (whichever occurs earlier.)
955
+ if currentSong .Duration > 30 {
956
+ scrobbleDelay := currentSong .Duration / 2
957
+ if scrobbleDelay > 240 {
958
+ scrobbleDelay = 240
959
+ }
960
+ scrobbleDuration := time .Duration (scrobbleDelay ) * time .Second
961
+
962
+ ui .scrobbleTimer .Reset (scrobbleDuration )
963
+ ui .connection .Logger .Printf ("scrobbler: timer started, %v" , scrobbleDuration )
964
+ } else {
965
+ ui .connection .Logger .Printf ("scrobbler: track too short" )
966
+ }
967
+ }
968
+ }
922
969
} else if e .Event_Id == mpv .EVENT_IDLE || e .Event_Id == mpv .EVENT_NONE {
923
970
continue
924
971
}
0 commit comments