Merge pull request #115 from jellyfin/ensure-success

This commit is contained in:
Cody Robibero 2022-04-16 17:01:24 -06:00 committed by GitHub
commit 561b7f1765
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -7,6 +7,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Json;
using System.Net.Mime; using System.Net.Mime;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
@ -149,10 +150,7 @@ namespace Trakt.Api
break; break;
} }
using (var response = await PostToTrakt(url, movieData, traktUser, CancellationToken.None).ConfigureAwait(false)) return await PostToTrakt<TraktScrobbleResponse>(url, movieData, traktUser, CancellationToken.None).ConfigureAwait(false);
{
return await JsonSerializer.DeserializeAsync<TraktScrobbleResponse>(response, _jsonOptions).ConfigureAwait(false);
}
} }
/// <summary> /// <summary>
@ -225,22 +223,17 @@ namespace Trakt.Api
var responses = new List<TraktScrobbleResponse>(); var responses = new List<TraktScrobbleResponse>();
foreach (var traktScrobbleEpisode in episodeDatas) foreach (var traktScrobbleEpisode in episodeDatas)
{ {
using (var response = await PostToTrakt(url, traktScrobbleEpisode, traktUser, CancellationToken.None).ConfigureAwait(false)) var response = await PostToTrakt<TraktScrobbleResponse>(url, traktScrobbleEpisode, traktUser, CancellationToken.None).ConfigureAwait(false);
// Response can be empty if episode not found
if (response is not null)
{ {
// Response can be empty if episode not found responses.Add(response);
if (response.Length > 0) }
{ else if (useProviderIds && HasAnyProviderTvIds(episode))
responses.Add(await JsonSerializer.DeserializeAsync<TraktScrobbleResponse>(response, _jsonOptions).ConfigureAwait(false)); {
} // Try scrobbling without IDs
else _logger.LogDebug("Resend episode status update, without episode IDs");
{ responses = await SendEpisodeStatusUpdateAsync(episode, status, traktUser, progressPercent, false).ConfigureAwait(false);
if (useProviderIds && HasAnyProviderTvIds(episode))
{
// Try scrobbling without IDs
_logger.LogDebug("Resend episode status update, without episode IDs");
responses = await SendEpisodeStatusUpdateAsync(episode, status, traktUser, progressPercent, false).ConfigureAwait(false);
}
}
} }
} }
@ -305,10 +298,9 @@ namespace Trakt.Api
{ {
Movies = chunk.ToList() Movies = chunk.ToList()
}; };
using (var response = await PostToTrakt(url, data, traktUser, cancellationToken).ConfigureAwait(false))
{ var response = await PostToTrakt<TraktSyncResponse>(url, data, traktUser, cancellationToken).ConfigureAwait(false);
responses.Add(await JsonSerializer.DeserializeAsync<TraktSyncResponse>(response, _jsonOptions, cancellationToken).ConfigureAwait(false)); responses.Add(response);
}
} }
return responses; return responses;
@ -450,18 +442,15 @@ namespace Trakt.Api
}; };
var url = eventType == EventType.Add ? TraktUris.SyncCollectionAdd : TraktUris.SyncCollectionRemove; var url = eventType == EventType.Add ? TraktUris.SyncCollectionAdd : TraktUris.SyncCollectionRemove;
using (var response = await PostToTrakt(url, data, traktUser, cancellationToken).ConfigureAwait(false)) var response = await PostToTrakt<TraktSyncResponse>(url, data, traktUser, cancellationToken).ConfigureAwait(false);
if (useProviderIDs && response.NotFound.Episodes.Count > 0)
{ {
var tsr = await JsonSerializer.DeserializeAsync<TraktSyncResponse>(response, _jsonOptions, cancellationToken).ConfigureAwait(false); // Send subset of episodes back to trakt.tv to try without ids
if (useProviderIDs && tsr.NotFound.Episodes.Count > 0) _logger.LogDebug("Resend episodes Library update, without episode IDs");
{ await SendLibraryUpdateInternalAsync(FindNotFoundEpisodes(episodes, response), traktUser, eventType, cancellationToken, false).ConfigureAwait(false);
// Send subset of episodes back to trakt.tv to try without ids
_logger.LogDebug("Resend episodes Library update, without episode IDs");
await SendLibraryUpdateInternalAsync(FindNotFoundEpisodes(episodes, tsr), traktUser, eventType, cancellationToken, false).ConfigureAwait(false);
}
return tsr;
} }
return response;
} }
/// <summary> /// <summary>
@ -509,10 +498,7 @@ namespace Trakt.Api
}; };
var url = eventType == EventType.Add ? TraktUris.SyncCollectionAdd : TraktUris.SyncCollectionRemove; var url = eventType == EventType.Add ? TraktUris.SyncCollectionAdd : TraktUris.SyncCollectionRemove;
using (var response = await PostToTrakt(url, data, traktUser, cancellationToken).ConfigureAwait(false)) return await PostToTrakt<TraktSyncResponse>(url, data, traktUser, cancellationToken).ConfigureAwait(false);
{
return await JsonSerializer.DeserializeAsync<TraktSyncResponse>(response, _jsonOptions, cancellationToken).ConfigureAwait(false);
}
} }
/// <summary> /// <summary>
@ -608,18 +594,16 @@ namespace Trakt.Api
}; };
} }
using (var response = await PostToTrakt(TraktUris.SyncRatingsAdd, data, traktUser).ConfigureAwait(false)) var response = await PostToTrakt<TraktSyncResponse>(TraktUris.SyncRatingsAdd, data, traktUser).ConfigureAwait(false);
{
var tsr = await JsonSerializer.DeserializeAsync<TraktSyncResponse>(response, _jsonOptions).ConfigureAwait(false);
if (item is Episode && useEpisodeProviderIDs && tsr.NotFound.Episodes.Count > 0)
{
// Try sync without ids
_logger.LogDebug("Resend episode rating, without episode IDs");
return await SendItemRating(item, rating, traktUser, false).ConfigureAwait(false);
}
return tsr; if (item is Episode && useEpisodeProviderIDs && response.NotFound.Episodes.Count > 0)
{
// Try sync without ids
_logger.LogDebug("Resend episode rating, without episode IDs");
return await SendItemRating(item, rating, traktUser, false).ConfigureAwait(false);
} }
return response;
} }
/// <summary> /// <summary>
@ -629,10 +613,7 @@ namespace Trakt.Api
/// <returns>Task{List{TraktMovie}}.</returns> /// <returns>Task{List{TraktMovie}}.</returns>
public async Task<List<TraktMovie>> SendMovieRecommendationsRequest(TraktUser traktUser) public async Task<List<TraktMovie>> SendMovieRecommendationsRequest(TraktUser traktUser)
{ {
using (var response = await GetFromTrakt(TraktUris.RecommendationsMovies, traktUser).ConfigureAwait(false)) return await GetFromTrakt<List<TraktMovie>>(TraktUris.RecommendationsMovies, traktUser).ConfigureAwait(false);
{
return await JsonSerializer.DeserializeAsync<List<TraktMovie>>(response, _jsonOptions).ConfigureAwait(false);
}
} }
/// <summary> /// <summary>
@ -642,10 +623,7 @@ namespace Trakt.Api
/// <returns>Task{List{TraktShow}}.</returns> /// <returns>Task{List{TraktShow}}.</returns>
public async Task<List<TraktShow>> SendShowRecommendationsRequest(TraktUser traktUser) public async Task<List<TraktShow>> SendShowRecommendationsRequest(TraktUser traktUser)
{ {
using (var response = await GetFromTrakt(TraktUris.RecommendationsShows, traktUser).ConfigureAwait(false)) return await GetFromTrakt<List<TraktShow>>(TraktUris.RecommendationsShows, traktUser).ConfigureAwait(false);
{
return await JsonSerializer.DeserializeAsync<List<TraktShow>>(response, _jsonOptions).ConfigureAwait(false);
}
} }
/// <summary> /// <summary>
@ -655,10 +633,7 @@ namespace Trakt.Api
/// <returns>Task{List{DataContracts.Users.Watched.TraktMovieWatched}}.</returns> /// <returns>Task{List{DataContracts.Users.Watched.TraktMovieWatched}}.</returns>
public async Task<List<DataContracts.Users.Watched.TraktMovieWatched>> SendGetAllWatchedMoviesRequest(TraktUser traktUser) public async Task<List<DataContracts.Users.Watched.TraktMovieWatched>> SendGetAllWatchedMoviesRequest(TraktUser traktUser)
{ {
using (var response = await GetFromTrakt(TraktUris.WatchedMovies, traktUser).ConfigureAwait(false)) return await GetFromTrakt<List<DataContracts.Users.Watched.TraktMovieWatched>>(TraktUris.WatchedMovies, traktUser).ConfigureAwait(false);
{
return await JsonSerializer.DeserializeAsync<List<DataContracts.Users.Watched.TraktMovieWatched>>(response, _jsonOptions).ConfigureAwait(false);
}
} }
/// <summary> /// <summary>
@ -668,10 +643,7 @@ namespace Trakt.Api
/// <returns>Task{List{DataContracts.Users.Watched.TraktShowWatched}}.</returns> /// <returns>Task{List{DataContracts.Users.Watched.TraktShowWatched}}.</returns>
public async Task<List<DataContracts.Users.Watched.TraktShowWatched>> SendGetWatchedShowsRequest(TraktUser traktUser) public async Task<List<DataContracts.Users.Watched.TraktShowWatched>> SendGetWatchedShowsRequest(TraktUser traktUser)
{ {
using (var response = await GetFromTrakt(TraktUris.WatchedShows, traktUser).ConfigureAwait(false)) return await GetFromTrakt<List<DataContracts.Users.Watched.TraktShowWatched>>(TraktUris.WatchedShows, traktUser).ConfigureAwait(false);
{
return await JsonSerializer.DeserializeAsync<List<DataContracts.Users.Watched.TraktShowWatched>>(response, _jsonOptions).ConfigureAwait(false);
}
} }
/// <summary> /// <summary>
@ -681,10 +653,7 @@ namespace Trakt.Api
/// <returns>Task{List{DataContracts.Users.Collection.TraktMovieCollected}}.</returns> /// <returns>Task{List{DataContracts.Users.Collection.TraktMovieCollected}}.</returns>
public async Task<List<DataContracts.Users.Collection.TraktMovieCollected>> SendGetAllCollectedMoviesRequest(TraktUser traktUser) public async Task<List<DataContracts.Users.Collection.TraktMovieCollected>> SendGetAllCollectedMoviesRequest(TraktUser traktUser)
{ {
using (var response = await GetFromTrakt(TraktUris.CollectedMovies, traktUser).ConfigureAwait(false)) return await GetFromTrakt<List<DataContracts.Users.Collection.TraktMovieCollected>>(TraktUris.CollectedMovies, traktUser).ConfigureAwait(false);
{
return await JsonSerializer.DeserializeAsync<List<DataContracts.Users.Collection.TraktMovieCollected>>(response, _jsonOptions).ConfigureAwait(false);
}
} }
/// <summary> /// <summary>
@ -694,10 +663,7 @@ namespace Trakt.Api
/// <returns>Task{List{DataContracts.Users.Collection.TraktShowCollected}}.</returns> /// <returns>Task{List{DataContracts.Users.Collection.TraktShowCollected}}.</returns>
public async Task<List<DataContracts.Users.Collection.TraktShowCollected>> SendGetCollectedShowsRequest(TraktUser traktUser) public async Task<List<DataContracts.Users.Collection.TraktShowCollected>> SendGetCollectedShowsRequest(TraktUser traktUser)
{ {
using (var response = await GetFromTrakt(TraktUris.CollectedShows, traktUser).ConfigureAwait(false)) return await GetFromTrakt<List<DataContracts.Users.Collection.TraktShowCollected>>(TraktUris.CollectedShows, traktUser).ConfigureAwait(false);
{
return await JsonSerializer.DeserializeAsync<List<DataContracts.Users.Collection.TraktShowCollected>>(response, _jsonOptions).ConfigureAwait(false);
}
} }
/// <summary> /// <summary>
@ -745,12 +711,10 @@ namespace Trakt.Api
}; };
var url = seen ? TraktUris.SyncWatchedHistoryAdd : TraktUris.SyncWatchedHistoryRemove; var url = seen ? TraktUris.SyncWatchedHistoryAdd : TraktUris.SyncWatchedHistoryRemove;
using (var response = await PostToTrakt(url, data, traktUser, cancellationToken).ConfigureAwait(false)) var response = await PostToTrakt<TraktSyncResponse>(url, data, traktUser, cancellationToken).ConfigureAwait(false);
if (response != null)
{ {
if (response != null) traktResponses.Add(response);
{
traktResponses.Add(await JsonSerializer.DeserializeAsync<TraktSyncResponse>(response, _jsonOptions, cancellationToken).ConfigureAwait(false));
}
} }
} }
@ -851,18 +815,16 @@ namespace Trakt.Api
var url = seen ? TraktUris.SyncWatchedHistoryAdd : TraktUris.SyncWatchedHistoryRemove; var url = seen ? TraktUris.SyncWatchedHistoryAdd : TraktUris.SyncWatchedHistoryRemove;
using (var response = await PostToTrakt(url, data, traktUser, cancellationToken).ConfigureAwait(false)) var response = await PostToTrakt<TraktSyncResponse>(url, data, traktUser, cancellationToken).ConfigureAwait(false);
{
var tsr = await JsonSerializer.DeserializeAsync<TraktSyncResponse>(response, _jsonOptions, cancellationToken).ConfigureAwait(false);
if (useProviderIDs && tsr.NotFound.Episodes.Count > 0)
{
// Send subset of episodes back to trakt.tv to try without ids
_logger.LogDebug("Resend episodes playstate update, without episode IDs");
await SendEpisodePlaystateUpdatesInternalAsync(FindNotFoundEpisodes(episodeChunk, tsr), traktUser, seen, cancellationToken, false).ConfigureAwait(false);
}
return tsr; if (useProviderIDs && response.NotFound.Episodes.Count > 0)
{
// Send subset of episodes back to trakt.tv to try without ids
_logger.LogDebug("Resend episodes playstate update, without episode IDs");
await SendEpisodePlaystateUpdatesInternalAsync(FindNotFoundEpisodes(episodeChunk, response), traktUser, seen, cancellationToken, false).ConfigureAwait(false);
} }
return response;
} }
private List<Episode> FindNotFoundEpisodes(IEnumerable<Episode> episodeChunk, TraktSyncResponse traktSyncResponse) private List<Episode> FindNotFoundEpisodes(IEnumerable<Episode> episodeChunk, TraktSyncResponse traktSyncResponse)
@ -899,11 +861,7 @@ namespace Trakt.Api
client_id = TraktUris.ClientId client_id = TraktUris.ClientId
}; };
TraktDeviceCode deviceCode; var deviceCode = await PostToTrakt<TraktDeviceCode>(TraktUris.DeviceCode, deviceCodeRequest, null).ConfigureAwait(false);
using (var response = await PostToTrakt(TraktUris.DeviceCode, deviceCodeRequest, null).ConfigureAwait(false))
{
deviceCode = await JsonSerializer.DeserializeAsync<TraktDeviceCode>(response, _jsonOptions).ConfigureAwait(false);
}
// Start polling in the background // Start polling in the background
Plugin.Instance.PollingTasks[traktUser.LinkedMbUserId] = Task.Run(() => PollForAccessToken(deviceCode, traktUser)); Plugin.Instance.PollingTasks[traktUser.LinkedMbUserId] = Task.Run(() => PollForAccessToken(deviceCode, traktUser));
@ -924,7 +882,7 @@ namespace Trakt.Api
client_secret = TraktUris.ClientSecret client_secret = TraktUris.ClientSecret
}; };
await PostToTrakt(TraktUris.RevokeToken, deviceRevokeRequest, traktUser).ConfigureAwait(false); await PostToTrakt<object>(TraktUris.RevokeToken, deviceRevokeRequest, traktUser).ConfigureAwait(false);
} }
/// <summary> /// <summary>
@ -1019,13 +977,12 @@ namespace Trakt.Api
TraktUserAccessToken userAccessToken; TraktUserAccessToken userAccessToken;
try try
{ {
using (var response = await PostToTrakt(TraktUris.AccessToken, data).ConfigureAwait(false)) using var response = await PostToTrakt(TraktUris.AccessToken, data).ConfigureAwait(false);
{ response.EnsureSuccessStatusCode();
#pragma warning disable CA2007 #pragma warning disable CA2007
await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false); await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
#pragma warning restore CA2007 #pragma warning restore CA2007
userAccessToken = await JsonSerializer.DeserializeAsync<TraktUserAccessToken>(stream, _jsonOptions).ConfigureAwait(false); userAccessToken = await JsonSerializer.DeserializeAsync<TraktUserAccessToken>(stream, _jsonOptions).ConfigureAwait(false);
}
} }
catch (HttpRequestException ex) catch (HttpRequestException ex)
{ {
@ -1043,12 +1000,12 @@ namespace Trakt.Api
} }
} }
private Task<Stream> GetFromTrakt(string url, TraktUser traktUser) private Task<T> GetFromTrakt<T>(string url, TraktUser traktUser)
{ {
return GetFromTrakt(url, traktUser, CancellationToken.None); return GetFromTrakt<T>(url, traktUser, CancellationToken.None);
} }
private async Task<Stream> GetFromTrakt(string url, TraktUser traktUser, CancellationToken cancellationToken) private async Task<T> GetFromTrakt<T>(string url, TraktUser traktUser, CancellationToken cancellationToken)
{ {
var httpClient = GetHttpClient(); var httpClient = GetHttpClient();
@ -1062,7 +1019,8 @@ namespace Trakt.Api
try try
{ {
var response = await RetryHttpRequest(async () => await httpClient.GetAsync(url, cancellationToken).ConfigureAwait(false)).ConfigureAwait(false); var response = await RetryHttpRequest(async () => await httpClient.GetAsync(url, cancellationToken).ConfigureAwait(false)).ConfigureAwait(false);
return await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<T>(_jsonOptions, cancellationToken).ConfigureAwait(false);
} }
finally finally
{ {
@ -1090,9 +1048,9 @@ namespace Trakt.Api
} }
} }
private Task<Stream> PostToTrakt(string url, object data, TraktUser traktUser) private Task<T> PostToTrakt<T>(string url, object data, TraktUser traktUser)
{ {
return PostToTrakt(url, data, traktUser, CancellationToken.None); return PostToTrakt<T>(url, data, traktUser, CancellationToken.None);
} }
/// <summary> /// <summary>
@ -1102,7 +1060,7 @@ namespace Trakt.Api
/// <param name="data">The data object.</param> /// <param name="data">The data object.</param>
/// <param name="traktUser">The <see cref="TraktUser"/>.</param> /// <param name="traktUser">The <see cref="TraktUser"/>.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/>.</param>
private async Task<Stream> PostToTrakt( private async Task<T> PostToTrakt<T>(
string url, string url,
object data, object data,
TraktUser traktUser, TraktUser traktUser,
@ -1129,7 +1087,8 @@ namespace Trakt.Api
try try
{ {
var response = await RetryHttpRequest(async () => await httpClient.PostAsync(url, content, cancellationToken).ConfigureAwait(false)).ConfigureAwait(false); var response = await RetryHttpRequest(async () => await httpClient.PostAsync(url, content, cancellationToken).ConfigureAwait(false)).ConfigureAwait(false);
return await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<T>(_jsonOptions, cancellationToken).ConfigureAwait(false);
} }
finally finally
{ {
@ -1145,7 +1104,7 @@ namespace Trakt.Api
try try
{ {
response = await function().ConfigureAwait(false); response = await function().ConfigureAwait(false);
if (response.StatusCode == (HttpStatusCode)429) if (response.StatusCode == HttpStatusCode.TooManyRequests)
{ {
var delay = response.Headers.RetryAfter.Delta ?? TimeSpan.FromSeconds(1); var delay = response.Headers.RetryAfter.Delta ?? TimeSpan.FromSeconds(1);
await Task.Delay(delay).ConfigureAwait(false); await Task.Delay(delay).ConfigureAwait(false);