jesseward / jellyfin-plugin-lastfm

LastFM plugin for the Jellyfin media system. Fork of the Emby Last.FM plug-in
178 stars 11 forks source link

Scrobbles not submitted when cast to device. #27

Closed OdinGitDat closed 3 years ago

OdinGitDat commented 3 years ago

The device in question is an instance of KGT1/jellyfin-discord-music-bot. I have raised an issue on that repo (KGT1/jellyfin-discord-music-bot#7) as well where this has not been solved yet. At this point I'm not sure if it's an issue with that repo or thisone.

Currently played information is successfully submitted and visible, but when playback ends no scrobble is submitted.

Here is what happens when the discord bot plays songs:

[20:48:34] [INF] [19] Jellyfin.Plugin.Lastfm.ServerEntryPoint: Odinoss is now playing artist=Chaos Face, track=Flatland, album=Doom Ride,
[20:44:05] [INF] [40] Jellyfin.Plugin.Lastfm.ServerEntryPoint: Odinoss is now playing artist=Chaos Face, track=Body Hammer, album=Doom Ride,
[20:38:45] [INF] [19] Jellyfin.Plugin.Lastfm.ServerEntryPoint: Odinoss is now playing artist=Chaos Face, track=Scanner, album=Doom Ride,
[20:29:29] [INF] [129] Jellyfin.Plugin.Lastfm.ServerEntryPoint: Odinoss is now playing artist=Chaos Face, track=Crash, album=Doom Ride,
[20:17:47] [INF] [129] Jellyfin.Plugin.Lastfm.ServerEntryPoint: Odinoss is now playing artist=Chaos Face, track=Subhuman, album=Doom Ride

This is what happens when the web client plays songs:

[20:57:15] [INF] [129] Jellyfin.Plugin.Lastfm.ServerEntryPoint: Odinoss is now playing artist=ZelooperZ, track=Paint Ain't Mine, album=Gremlin,
[20:59:14] [INF] [89] Jellyfin.Plugin.Lastfm.ServerEntryPoint: Odinoss played artist=ZelooperZ, track=Paint Ain't Mine, album=Gremlin,
[20:59:15] [INF] [90] Jellyfin.Plugin.Lastfm.ServerEntryPoint: Odinoss is now playing artist=ZelooperZ, track=Extravaganza Live, album=Gremlin,
[21:00:28] [INF] [25] Jellyfin.Plugin.Lastfm.ServerEntryPoint: Odinoss played artist=ZelooperZ, track=Extravaganza Live, album=Gremlin,
[21:00:28] [INF] [52] Jellyfin.Plugin.Lastfm.ServerEntryPoint: Odinoss is now playing artist=ZelooperZ, track=Style for Sale, album=Gremlin,
[21:01:36] [INF] [68] Jellyfin.Plugin.Lastfm.ServerEntryPoint: Odinoss played artist=ZelooperZ, track=Style for Sale, album=Gremlin,
[21:01:36] [INF] [22] Jellyfin.Plugin.Lastfm.ServerEntryPoint: Odinoss is now playing artist=ZelooperZ, track=Dj Freaky Zhit, album=Gremlin,
[21:03:45] [INF] [12] Jellyfin.Plugin.Lastfm.ServerEntryPoint: Odinoss played artist=ZelooperZ, track=Dj Freaky Zhit, album=Gremlin,
[21:03:46] [INF] [109] Jellyfin.Plugin.Lastfm.ServerEntryPoint: Odinoss is now playing artist=ZelooperZ, track=Bounce, album=Gremlin,
[21:04:48] [INF] [38] Jellyfin.Plugin.Lastfm.ServerEntryPoint: Odinoss played artist=ZelooperZ, track=Bounce, album=Gremlin,
[21:04:49] [INF] [38] Jellyfin.Plugin.Lastfm.ServerEntryPoint: Odinoss is now playing artist=ZelooperZ, track=Hyphen, album=Gremlin,
[21:07:06] [INF] [40] Jellyfin.Plugin.Lastfm.ServerEntryPoint: Odinoss played artist=ZelooperZ, track=Hyphen, album=Gremlin,
[21:07:07] [INF] [60] Jellyfin.Plugin.Lastfm.ServerEntryPoint: Odinoss is now playing artist=ZelooperZ, track=Lost Me, album=Gremlin
CutterXYZ commented 3 years ago

Same problem when playing music from Gelli.

According to the last.fm API documentation a track is supposed to be submitted when playback reaches 50% not 100% (the lack of confirmation of the track ending shouldn't matter).

When is a scrobble a scrobble?

A track should only be scrobbled when the following conditions have been met:

  • The track must be longer than 30 seconds.
  • And the track has been played for at least half its duration, or for 4 minutes (whichever occurs earlier.)

https://www.last.fm/api/scrobbling#when-is-a-scrobble-a-scrobble

m0ngr31 commented 3 years ago

What I found when I was writing Jellyamp is that in addition to sending the progress, it needs to tell it when it has stopped. The plugin will decide to scrobble or not.

jesseward commented 3 years ago

hey @OdinGitDat @CutterXYZ @m0ngr31 , thanks for logging this issue and providing some background regarding the LastFM API specs and how other plugins are handling this.

This plugin tracks audio playing events by binding to a pair of core Jellyfin events that are triggered by Jellyfin core. These are documented at PlaybackProgressEventArgs API .

| PlaybackProgressEventArgs
|--> PlaybackStartEventArgs # Plugins  can trap this event when a media file is started.. LastFM plugin will send the "now playing" call to LastFM API
.--> PlaybackStopEventArgs # This event fires to plugins on media stop. This plugin will hit the Last.FM scrobble API when this event is fired.

As @m0ngr31 mentioned, if the application that is playing the media file doesn't fire the PlaybackStopEvent, the plugin subsystem will not be aware of state changes within Jellyfin.

The logic that captures this event in this plugin can be found ServerEntryPoint.cs

        private async void PlaybackStopped(object sender, PlaybackStopEventArgs e)
        {
            // We only care about audio
            if (!(e.Item is Audio))
                return;

            var item = e.Item as Audio;

            // Make sure the track has been fully played
            if (!e.PlayedToCompletion)
            {
                return;
            }

            // Played to completion will sometimes be true even if the track has only played 10% so check the playback ourselfs (it must use the app settings or something)
            // Make sure 80% of the track has been played back
            if (e.PlaybackPositionTicks == null)
            {
                _logger.LogDebug("Playback ticks for {0} is null", item.Name);
                return;
            }

            var playPercent = ((double)e.PlaybackPositionTicks / item.RunTimeTicks) * 100;
            if (playPercent < 80)
            {
                _logger.LogDebug("'{0}' only played {1}%, not scrobbling", item.Name, playPercent);
                return;
            }

Based on the above logic and referencing the Last.FM scrobbling guidelines provided by @CutterXYZ [ref] there are some changes that could be made to align with Last.FM's requirements. These changes may not fix the issues you're seeing, as it is possible that the trigger is not being fired, but the following should be fixed regardless.

A track should only be scrobbled when the following conditions have been met:

  • The track must be longer than 30 seconds.
  • And the track has been played for at least half its duration, or for 4 minutes (whichever occurs earlier.)

The following should be removed since PlayedToCompletion isn't a requirement to scrobble...

            // Make sure the track has been fully played
            if (!e.PlayedToCompletion)
            {
                return;
            }

and the following should assert that: the song length > 30 seconds and playPercent > 50 OR song has played for > 4 minutes before scrobbling.

            var playPercent = ((double)e.PlaybackPositionTicks / item.RunTimeTicks) * 100;
            if (playPercent < 80)
            {
                _logger.LogDebug("'{0}' only played {1}%, not scrobbling", item.Name, playPercent);
                return;
            }
jesseward commented 3 years ago

closing this ticket as the original issue is due to the behaviour of the client. I have also pushed changes to the plugin that make scrobble rules more strict as per last.fm API.