Skip to content

Commit

Permalink
Update the file scrobbler
Browse files Browse the repository at this point in the history
It will now also sync back the resume position when you
pause an episode or a movie. Also, fixed it so it also works on movies.
  • Loading branch information
revam committed Aug 30, 2021
1 parent 700dd82 commit 1d6a5d1
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 30 deletions.
13 changes: 7 additions & 6 deletions Shokofin/API/ShokoAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ private static async Task<Stream> CallApi(string url, string requestType = "GET"
var apiBaseUrl = Plugin.Instance.Configuration.Host;
switch (requestType)
{
case "PATCH":
case "POST":
var response = await _httpClient.PostAsync($"{apiBaseUrl}{url}", new StringContent(""));
return response.StatusCode == HttpStatusCode.OK ? response.Content.ReadAsStreamAsync().Result : null;
Expand Down Expand Up @@ -110,6 +111,12 @@ public static async Task<File> GetFile(string id)
return responseStream != null ? await JsonSerializer.DeserializeAsync<File>(responseStream) : null;
}

public static async Task<bool> ScrobbleFile(string id, bool watched, long? progress)
{
var responseStream = await CallApi($"/api/v3/File/{id}/Scrobble?watched={watched}&resumePosition={progress ?? 0}", "PATCH");
return responseStream != null;
}

public static async Task<IEnumerable<File.FileDetailed>> GetFileByPath(string filename)
{
var responseStream = await CallApi($"/api/v3/File/PathEndsWith/{Uri.EscapeDataString(filename)}");
Expand Down Expand Up @@ -176,12 +183,6 @@ public static async Task<Group> GetGroupFromSeries(string id)
return responseStream != null ? await JsonSerializer.DeserializeAsync<Group>(responseStream) : null;
}

public static async Task<bool> MarkEpisodeWatched(string id)
{
var responseStream = await CallApi($"/api/v3/Episode/{id}/watched/true", "POST");
return responseStream != null;
}

public static async Task<IEnumerable<SeriesSearchResult>> SeriesSearch(string query)
{
var responseStream = await CallApi($"/api/v3/Series/Search/{Uri.EscapeDataString(query)}");
Expand Down
44 changes: 20 additions & 24 deletions Shokofin/Scrobbler.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Threading.Tasks;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Session;
Expand All @@ -12,11 +11,15 @@ namespace Shokofin
public class Scrobbler : IServerEntryPoint
{
private readonly ISessionManager SessionManager;

private readonly ILibraryManager LibraryManager;

private readonly ILogger<Scrobbler> Logger;

public Scrobbler(ISessionManager sessionManager, ILogger<Scrobbler> logger)
public Scrobbler(ISessionManager sessionManager, ILibraryManager libraryManager, ILogger<Scrobbler> logger)
{
SessionManager = sessionManager;
LibraryManager = libraryManager;
Logger = logger;
}

Expand All @@ -28,33 +31,26 @@ public Task RunAsync()

private async void OnPlaybackStopped(object sender, PlaybackStopEventArgs e)
{
if (!Plugin.Instance.Configuration.UpdateWatchedStatus) return;

if (e.Item == null)
{
Logger.LogError("Event details incomplete. Cannot process current media");
// Only sync-back if we enabled the feature in the plugin settings and an item is present
if (!Plugin.Instance.Configuration.UpdateWatchedStatus || e.Item == null)
return;
}

if (!e.Item.HasProviderId("Shoko Episode"))
// Only known episodes and movies have a file id, so if it doesn't have one then it's either urecognized or from another library.
if (!e.Item.HasProviderId("Shoko File"))
{
Logger.LogError("Unrecognized file");
return; // Skip if file does exist in Shoko
Logger.LogWarning("Unable to find a Shoko File Id for item {ItemName}", e.Item.Name);
return;
}

if (e.Item is Episode episode && e.PlayedToCompletion)
{
var episodeId = episode.GetProviderId("Shoko Episode");

Logger.LogInformation("Item is played. Marking as watched on Shoko");
Logger.LogInformation($"{episode.SeriesName} S{episode.Season.IndexNumber}E{episode.IndexNumber} - {episode.Name} ({episodeId})");

var result = await ShokoAPI.MarkEpisodeWatched(episodeId);
if (result)
Logger.LogInformation("Episode marked as watched!");
else
Logger.LogError("Error marking episode as watched!");
}
var fileId = e.Item.GetProviderId("Shoko File");
var watched = e.PlayedToCompletion;
var resumePosition = e.PlaybackPositionTicks ?? 0;
Logger.LogInformation("Playback was stopped. Syncing watch state of file back to Shoko. (File={FileId},Watched={WatchState},ResumePosition={ResumePosition})", fileId, watched, resumePosition);
var result = await ShokoAPI.ScrobbleFile(fileId, watched, resumePosition);
if (result)
Logger.LogInformation("File marked as watched! (File={FileId})", fileId);
else
Logger.LogWarning("An error occured while syncing watch state of file back to Shoko! (File={FileId})", fileId);
}

public void Dispose()
Expand Down

0 comments on commit 1d6a5d1

Please sign in to comment.