More documentation and some more refactoring
This commit is contained in:
parent
df334500a9
commit
4a0650bc7d
1 changed files with 176 additions and 122 deletions
|
|
@ -45,6 +45,11 @@ public enum ScrobbleProvider
|
||||||
|
|
||||||
public interface IScrobblingService
|
public interface IScrobblingService
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An automated job that will run against all user's tokens and validate if they are still active
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This service can validate without license check as the task which calls will be guarded</remarks>
|
||||||
|
/// <returns></returns>
|
||||||
Task CheckExternalAccessTokens();
|
Task CheckExternalAccessTokens();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -56,9 +61,39 @@ public interface IScrobblingService
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <remarks>Returns true if there is no license present</remarks>
|
/// <remarks>Returns true if there is no license present</remarks>
|
||||||
Task<bool> HasTokenExpired(int userId, ScrobbleProvider provider);
|
Task<bool> HasTokenExpired(int userId, ScrobbleProvider provider);
|
||||||
|
/// <summary>
|
||||||
|
/// Create, or update a non-processed, <see cref="ScrobbleEventType.ScoreUpdated"/> event, for the given series
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
/// <param name="seriesId"></param>
|
||||||
|
/// <param name="rating"></param>
|
||||||
|
/// <returns></returns>
|
||||||
Task ScrobbleRatingUpdate(int userId, int seriesId, float rating);
|
Task ScrobbleRatingUpdate(int userId, int seriesId, float rating);
|
||||||
|
/// <summary>
|
||||||
|
/// NOP, until hardcover support has been worked out
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
/// <param name="seriesId"></param>
|
||||||
|
/// <param name="reviewTitle"></param>
|
||||||
|
/// <param name="reviewBody"></param>
|
||||||
|
/// <returns></returns>
|
||||||
Task ScrobbleReviewUpdate(int userId, int seriesId, string? reviewTitle, string reviewBody);
|
Task ScrobbleReviewUpdate(int userId, int seriesId, string? reviewTitle, string reviewBody);
|
||||||
|
/// <summary>
|
||||||
|
/// Create, or update a non-processed, <see cref="ScrobbleEventType.ChapterRead"/> event, for the given series
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
/// <param name="seriesId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
Task ScrobbleReadingUpdate(int userId, int seriesId);
|
Task ScrobbleReadingUpdate(int userId, int seriesId);
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an <see cref="ScrobbleEventType.AddWantToRead"/> or <see cref="ScrobbleEventType.RemoveWantToRead"/> for
|
||||||
|
/// the given series
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
/// <param name="seriesId"></param>
|
||||||
|
/// <param name="onWantToRead"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <remarks>Only the result of both WantToRead types is send to K+</remarks>
|
||||||
Task ScrobbleWantToReadUpdate(int userId, int seriesId, bool onWantToRead);
|
Task ScrobbleWantToReadUpdate(int userId, int seriesId, bool onWantToRead);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -70,7 +105,7 @@ public interface IScrobblingService
|
||||||
public Task ClearProcessedEvents();
|
public Task ClearProcessedEvents();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Makes K+ requests for all non-processed events until rate limits are reached
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[DisableConcurrentExecution(60 * 60 * 60)]
|
[DisableConcurrentExecution(60 * 60 * 60)]
|
||||||
|
|
@ -97,10 +132,19 @@ public class ScrobbleSyncContext
|
||||||
/// Final events list if all AddTo- and RemoveWantToRead would be processed sequentially
|
/// Final events list if all AddTo- and RemoveWantToRead would be processed sequentially
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public required List<ScrobbleEvent> Decisions {get; init;}
|
public required List<ScrobbleEvent> Decisions {get; init;}
|
||||||
|
/// <summary>
|
||||||
|
/// K+ license
|
||||||
|
/// </summary>
|
||||||
public required string License { get; init; }
|
public required string License { get; init; }
|
||||||
|
/// <summary>
|
||||||
|
/// Maps userId to left over request amount
|
||||||
|
/// </summary>
|
||||||
public required Dictionary<int, int> RateLimits { get; init; }
|
public required Dictionary<int, int> RateLimits { get; init; }
|
||||||
|
|
||||||
public List<AppUser> Users { get; set; }
|
/// <summary>
|
||||||
|
/// All users being scrobbled for
|
||||||
|
/// </summary>
|
||||||
|
public List<AppUser> Users { get; set; } = [];
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Amount fo already processed events
|
/// Amount fo already processed events
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -130,7 +174,7 @@ public class ScrobblingService : IScrobblingService
|
||||||
public const string AniListCharacterWebsite = "https://anilist.co/character/";
|
public const string AniListCharacterWebsite = "https://anilist.co/character/";
|
||||||
|
|
||||||
|
|
||||||
private static readonly Dictionary<string, int> WeblinkExtractionMap = new Dictionary<string, int>()
|
private static readonly Dictionary<string, int> WeblinkExtractionMap = new()
|
||||||
{
|
{
|
||||||
{AniListWeblinkWebsite, 0},
|
{AniListWeblinkWebsite, 0},
|
||||||
{MalWeblinkWebsite, 0},
|
{MalWeblinkWebsite, 0},
|
||||||
|
|
@ -644,7 +688,7 @@ public class ScrobblingService : IScrobblingService
|
||||||
.ToImmutableHashSet();
|
.ToImmutableHashSet();
|
||||||
|
|
||||||
var errors = (await _unitOfWork.ScrobbleRepository.GetScrobbleErrors())
|
var errors = (await _unitOfWork.ScrobbleRepository.GetScrobbleErrors())
|
||||||
.Where(e => e.Comment == "Unknown Series" || e.Comment == UnknownSeriesErrorMessage || e.Comment == AccessTokenErrorMessage)
|
.Where(e => e.Comment is "Unknown Series" or UnknownSeriesErrorMessage or AccessTokenErrorMessage)
|
||||||
.Select(e => e.SeriesId)
|
.Select(e => e.SeriesId)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
|
@ -727,7 +771,7 @@ public class ScrobblingService : IScrobblingService
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var eventsWithoutAnilistToken = (await _unitOfWork.ScrobbleRepository.GetEvents())
|
var eventsWithoutAnilistToken = (await _unitOfWork.ScrobbleRepository.GetEvents())
|
||||||
.Where(e => !e.IsProcessed && !e.IsErrored)
|
.Where(e => e is { IsProcessed: false, IsErrored: false })
|
||||||
.Where(e => string.IsNullOrEmpty(e.AppUser.AniListAccessToken));
|
.Where(e => string.IsNullOrEmpty(e.AppUser.AniListAccessToken));
|
||||||
|
|
||||||
_unitOfWork.ScrobbleRepository.Remove(eventsWithoutAnilistToken);
|
_unitOfWork.ScrobbleRepository.Remove(eventsWithoutAnilistToken);
|
||||||
|
|
@ -901,15 +945,11 @@ public class ScrobblingService : IScrobblingService
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessEvents(IEnumerable<ScrobbleEvent> events, ScrobbleSyncContext ctx, Func<ScrobbleEvent, Task<ScrobbleDto>> createEvent)
|
private async Task<bool> ValidateUserToken(ScrobbleEvent evt)
|
||||||
{
|
{
|
||||||
foreach (var evt in events.Where(CanProcessScrobbleEvent))
|
if (!TokenService.HasTokenExpired(evt.AppUser.AniListAccessToken))
|
||||||
{
|
return true;
|
||||||
_logger.LogDebug("Processing Scrobble Events: {Count} / {Total}", ctx.ProgressCounter, ctx.TotalCount);
|
|
||||||
ctx.ProgressCounter++;
|
|
||||||
|
|
||||||
if (TokenService.HasTokenExpired(evt.AppUser.AniListAccessToken))
|
|
||||||
{
|
|
||||||
_unitOfWork.ScrobbleRepository.Attach(new ScrobbleError
|
_unitOfWork.ScrobbleRepository.Attach(new ScrobbleError
|
||||||
{
|
{
|
||||||
Comment = "AniList token has expired and needs rotating. Scrobbling wont work until then",
|
Comment = "AniList token has expired and needs rotating. Scrobbling wont work until then",
|
||||||
|
|
@ -918,30 +958,57 @@ public class ScrobblingService : IScrobblingService
|
||||||
SeriesId = evt.SeriesId
|
SeriesId = evt.SeriesId
|
||||||
});
|
});
|
||||||
await _unitOfWork.CommitAsync();
|
await _unitOfWork.CommitAsync();
|
||||||
continue;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (evt.Series.IsBlacklisted || evt.Series.DontMatch)
|
private async Task<bool> ValidateSeriesCanBeScrobbled(ScrobbleEvent evt)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Series {SeriesName} ({SeriesId}) can't be matched and thus cannot scrobble this event", evt.Series.Name, evt.SeriesId);
|
if (evt.Series is { IsBlacklisted: false, DontMatch: false })
|
||||||
_unitOfWork.ScrobbleRepository.Attach(new ScrobbleError()
|
return true;
|
||||||
|
|
||||||
|
_logger.LogInformation("Series {SeriesName} ({SeriesId}) can't be matched and thus cannot scrobble this event",
|
||||||
|
evt.Series.Name, evt.SeriesId);
|
||||||
|
|
||||||
|
_unitOfWork.ScrobbleRepository.Attach(new ScrobbleError
|
||||||
{
|
{
|
||||||
Comment = UnknownSeriesErrorMessage,
|
Comment = UnknownSeriesErrorMessage,
|
||||||
Details = $"User: {evt.AppUser.UserName} Series: {evt.Series.Name}",
|
Details = $"User: {evt.AppUser.UserName} Series: {evt.Series.Name}",
|
||||||
LibraryId = evt.LibraryId,
|
LibraryId = evt.LibraryId,
|
||||||
SeriesId = evt.SeriesId
|
SeriesId = evt.SeriesId
|
||||||
});
|
});
|
||||||
|
|
||||||
evt.IsErrored = true;
|
evt.IsErrored = true;
|
||||||
evt.ErrorDetails = UnknownSeriesErrorMessage;
|
evt.ErrorDetails = UnknownSeriesErrorMessage;
|
||||||
evt.ProcessDateUtc = DateTime.UtcNow;
|
evt.ProcessDateUtc = DateTime.UtcNow;
|
||||||
_unitOfWork.ScrobbleRepository.Update(evt);
|
_unitOfWork.ScrobbleRepository.Update(evt);
|
||||||
await _unitOfWork.CommitAsync();
|
await _unitOfWork.CommitAsync();
|
||||||
|
return false;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ScrobbleDto NormalizeScrobbleData(ScrobbleDto data)
|
||||||
|
{
|
||||||
|
// We need to handle the encoding and changing it to the old one until we can update the API layer to handle these
|
||||||
|
// which could happen in v0.8.3
|
||||||
|
if (data.VolumeNumber is Parser.SpecialVolumeNumber or Parser.DefaultChapterNumber)
|
||||||
|
data.VolumeNumber = 0;
|
||||||
|
|
||||||
|
if (data.ChapterNumber is Parser.DefaultChapterNumber)
|
||||||
|
data.ChapterNumber = 0;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ProcessEvents(IEnumerable<ScrobbleEvent> events, ScrobbleSyncContext ctx, Func<ScrobbleEvent, Task<ScrobbleDto>> createEvent)
|
||||||
|
{
|
||||||
|
foreach (var evt in events.Where(CanProcessScrobbleEvent))
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Processing Scrobble Events: {Count} / {Total}", ctx.ProgressCounter, ctx.TotalCount);
|
||||||
|
ctx.ProgressCounter++;
|
||||||
|
|
||||||
|
if (!await ValidateUserToken(evt)) continue;
|
||||||
|
if (!await ValidateSeriesCanBeScrobbled(evt)) continue;
|
||||||
|
|
||||||
var count = await SetAndCheckRateLimit(ctx.RateLimits, evt.AppUser, ctx.License);
|
var count = await SetAndCheckRateLimit(ctx.RateLimits, evt.AppUser, ctx.License);
|
||||||
ctx.RateLimits[evt.AppUserId] = count;
|
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
{
|
{
|
||||||
if (ctx.Users.Count == 1) break;
|
if (ctx.Users.Count == 1) break;
|
||||||
|
|
@ -950,19 +1017,10 @@ public class ScrobblingService : IScrobblingService
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var data = await createEvent(evt);
|
var data = NormalizeScrobbleData(await createEvent(evt));
|
||||||
// We need to handle the encoding and changing it to the old one until we can update the API layer to handle these
|
|
||||||
// which could happen in v0.8.3
|
|
||||||
if (data.VolumeNumber is Parser.SpecialVolumeNumber or Parser.DefaultChapterNumber)
|
|
||||||
{
|
|
||||||
data.VolumeNumber = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.ChapterNumber is Parser.DefaultChapterNumber)
|
|
||||||
{
|
|
||||||
data.ChapterNumber = 0;
|
|
||||||
}
|
|
||||||
ctx.RateLimits[evt.AppUserId] = await PostScrobbleUpdate(data, ctx.License, evt);
|
ctx.RateLimits[evt.AppUserId] = await PostScrobbleUpdate(data, ctx.License, evt);
|
||||||
|
|
||||||
evt.IsProcessed = true;
|
evt.IsProcessed = true;
|
||||||
evt.ProcessDateUtc = DateTime.UtcNow;
|
evt.ProcessDateUtc = DateTime.UtcNow;
|
||||||
_unitOfWork.ScrobbleRepository.Update(evt);
|
_unitOfWork.ScrobbleRepository.Update(evt);
|
||||||
|
|
@ -1118,6 +1176,9 @@ public class ScrobblingService : IScrobblingService
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region BackFill
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This will backfill events from existing progress history, ratings, and want to read for users that have a valid license
|
/// This will backfill events from existing progress history, ratings, and want to read for users that have a valid license
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -1137,35 +1198,52 @@ public class ScrobblingService : IScrobblingService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var libAllowsScrobbling = (await _unitOfWork.LibraryRepository.GetLibrariesAsync())
|
var libAllowsScrobbling = (await _unitOfWork.LibraryRepository.GetLibrariesAsync())
|
||||||
.ToDictionary(lib => lib.Id, lib => lib.AllowScrobbling);
|
.ToDictionary(lib => lib.Id, lib => lib.AllowScrobbling);
|
||||||
|
|
||||||
var userIds = (await _unitOfWork.UserRepository.GetAllUsersAsync())
|
var userIds = (await _unitOfWork.UserRepository.GetAllUsersAsync())
|
||||||
.Where(l => userId == 0 || userId == l.Id)
|
.Where(l => userId == 0 || userId == l.Id)
|
||||||
|
.Where(u => !u.HasRunScrobbleEventGeneration)
|
||||||
.Select(u => u.Id);
|
.Select(u => u.Id);
|
||||||
|
|
||||||
foreach (var uId in userIds)
|
foreach (var uId in userIds)
|
||||||
{
|
{
|
||||||
var wantToRead = await _unitOfWork.SeriesRepository.GetWantToReadForUserAsync(uId);
|
await CreateEventsFromExistingHistoryForUser(uId, libAllowsScrobbling);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates wantToRead, rating, reviews, and series progress events for the suer
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="userId"></param>
|
||||||
|
/// <param name="libAllowsScrobbling"></param>
|
||||||
|
private async Task CreateEventsFromExistingHistoryForUser(int userId, Dictionary<int, bool> libAllowsScrobbling)
|
||||||
|
{
|
||||||
|
var wantToRead = await _unitOfWork.SeriesRepository.GetWantToReadForUserAsync(userId);
|
||||||
foreach (var wtr in wantToRead)
|
foreach (var wtr in wantToRead)
|
||||||
{
|
{
|
||||||
if (!libAllowsScrobbling[wtr.LibraryId]) continue;
|
if (!libAllowsScrobbling[wtr.LibraryId]) continue;
|
||||||
await ScrobbleWantToReadUpdate(uId, wtr.Id, true);
|
await ScrobbleWantToReadUpdate(userId, wtr.Id, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
var ratings = await _unitOfWork.UserRepository.GetSeriesWithRatings(uId);
|
var ratings = await _unitOfWork.UserRepository.GetSeriesWithRatings(userId);
|
||||||
foreach (var rating in ratings)
|
foreach (var rating in ratings)
|
||||||
{
|
{
|
||||||
if (!libAllowsScrobbling[rating.Series.LibraryId]) continue;
|
if (!libAllowsScrobbling[rating.Series.LibraryId]) continue;
|
||||||
await ScrobbleRatingUpdate(uId, rating.SeriesId, rating.Rating);
|
await ScrobbleRatingUpdate(userId, rating.SeriesId, rating.Rating);
|
||||||
}
|
}
|
||||||
|
|
||||||
var seriesWithProgress = await _unitOfWork.SeriesRepository.GetSeriesDtoForLibraryIdAsync(0, uId,
|
var reviews = await _unitOfWork.UserRepository.GetSeriesWithReviews(userId);
|
||||||
new UserParams(), new FilterDto()
|
foreach (var review in reviews.Where(r => !string.IsNullOrEmpty(r.Review)))
|
||||||
{
|
{
|
||||||
ReadStatus = new ReadStatus()
|
if (!libAllowsScrobbling[review.Series.LibraryId]) continue;
|
||||||
|
await ScrobbleReviewUpdate(userId, review.SeriesId, string.Empty, review.Review!);
|
||||||
|
}
|
||||||
|
|
||||||
|
var seriesWithProgress = await _unitOfWork.SeriesRepository.GetSeriesDtoForLibraryIdAsync(0, userId,
|
||||||
|
new UserParams(), new FilterDto
|
||||||
|
{
|
||||||
|
ReadStatus = new ReadStatus
|
||||||
{
|
{
|
||||||
Read = true,
|
Read = true,
|
||||||
InProgress = true,
|
InProgress = true,
|
||||||
|
|
@ -1174,14 +1252,13 @@ public class ScrobblingService : IScrobblingService
|
||||||
Libraries = libAllowsScrobbling.Keys.Where(k => libAllowsScrobbling[k]).ToList()
|
Libraries = libAllowsScrobbling.Keys.Where(k => libAllowsScrobbling[k]).ToList()
|
||||||
});
|
});
|
||||||
|
|
||||||
foreach (var series in seriesWithProgress)
|
foreach (var series in seriesWithProgress.Where(series => series.PagesRead > 0))
|
||||||
{
|
{
|
||||||
if (!libAllowsScrobbling[series.LibraryId]) continue;
|
if (!libAllowsScrobbling[series.LibraryId]) continue;
|
||||||
if (series.PagesRead <= 0) continue; // Since we only scrobble when things are higher, we can
|
await ScrobbleReadingUpdate(userId, series.Id);
|
||||||
await ScrobbleReadingUpdate(uId, series.Id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(uId);
|
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(userId);
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
user.HasRunScrobbleEventGeneration = true;
|
user.HasRunScrobbleEventGeneration = true;
|
||||||
|
|
@ -1189,7 +1266,6 @@ public class ScrobblingService : IScrobblingService
|
||||||
await _unitOfWork.CommitAsync();
|
await _unitOfWork.CommitAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public async Task CreateEventsFromExistingHistoryForSeries(int seriesId)
|
public async Task CreateEventsFromExistingHistoryForSeries(int seriesId)
|
||||||
{
|
{
|
||||||
|
|
@ -1200,8 +1276,7 @@ public class ScrobblingService : IScrobblingService
|
||||||
|
|
||||||
_logger.LogInformation("Creating Scrobbling events for Series {SeriesName}", series.Name);
|
_logger.LogInformation("Creating Scrobbling events for Series {SeriesName}", series.Name);
|
||||||
|
|
||||||
var userIds = (await _unitOfWork.UserRepository.GetAllUsersAsync())
|
var userIds = (await _unitOfWork.UserRepository.GetAllUsersAsync()).Select(u => u.Id);
|
||||||
.Select(u => u.Id);
|
|
||||||
|
|
||||||
foreach (var uId in userIds)
|
foreach (var uId in userIds)
|
||||||
{
|
{
|
||||||
|
|
@ -1219,33 +1294,20 @@ public class ScrobblingService : IScrobblingService
|
||||||
await ScrobbleRatingUpdate(uId, rating.SeriesId, rating.Rating);
|
await ScrobbleRatingUpdate(uId, rating.SeriesId, rating.Rating);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle progress updates for the specific series
|
// Handle review specific to the series
|
||||||
var seriesProgress = await _unitOfWork.SeriesRepository.GetSeriesDtoForLibraryIdAsync(
|
var reviews = await _unitOfWork.UserRepository.GetSeriesWithReviews(uId);
|
||||||
series.LibraryId,
|
foreach (var review in reviews.Where(r => r.SeriesId == seriesId && !string.IsNullOrEmpty(r.Review)))
|
||||||
uId,
|
|
||||||
new UserParams(),
|
|
||||||
new FilterDto
|
|
||||||
{
|
{
|
||||||
ReadStatus = new ReadStatus
|
await ScrobbleReviewUpdate(uId, review.SeriesId, string.Empty, review.Review!);
|
||||||
{
|
}
|
||||||
Read = true,
|
|
||||||
InProgress = true,
|
|
||||||
NotRead = false
|
|
||||||
},
|
|
||||||
Libraries = new List<int> { series.LibraryId },
|
|
||||||
SeriesNameQuery = series.Name
|
|
||||||
});
|
|
||||||
|
|
||||||
foreach (var progress in seriesProgress.Where(progress => progress.Id == seriesId))
|
// Handle progress updates for the specific series
|
||||||
{
|
await ScrobbleReadingUpdate(uId, seriesId);
|
||||||
if (progress.PagesRead > 0)
|
|
||||||
{
|
|
||||||
await ScrobbleReadingUpdate(uId, progress.Id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes all events (active) that are tied to a now-on hold series
|
/// Removes all events (active) that are tied to a now-on hold series
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -1254,12 +1316,9 @@ public class ScrobblingService : IScrobblingService
|
||||||
public async Task ClearEventsForSeries(int userId, int seriesId)
|
public async Task ClearEventsForSeries(int userId, int seriesId)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Clearing Pre-existing Scrobble events for Series {SeriesId} by User {AppUserId} as Series is now on hold list", seriesId, userId);
|
_logger.LogInformation("Clearing Pre-existing Scrobble events for Series {SeriesId} by User {AppUserId} as Series is now on hold list", seriesId, userId);
|
||||||
var events = await _unitOfWork.ScrobbleRepository.GetUserEventsForSeries(userId, seriesId);
|
|
||||||
foreach (var scrobble in events)
|
|
||||||
{
|
|
||||||
_unitOfWork.ScrobbleRepository.Remove(scrobble);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var events = await _unitOfWork.ScrobbleRepository.GetUserEventsForSeries(userId, seriesId);
|
||||||
|
_unitOfWork.ScrobbleRepository.Remove(events);
|
||||||
await _unitOfWork.CommitAsync();
|
await _unitOfWork.CommitAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1277,19 +1336,15 @@ public class ScrobblingService : IScrobblingService
|
||||||
await _unitOfWork.CommitAsync();
|
await _unitOfWork.CommitAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static bool CanProcessScrobbleEvent(ScrobbleEvent readEvent)
|
private static bool CanProcessScrobbleEvent(ScrobbleEvent readEvent)
|
||||||
{
|
{
|
||||||
var userProviders = GetUserProviders(readEvent.AppUser);
|
var userProviders = GetUserProviders(readEvent.AppUser);
|
||||||
switch (readEvent.Series.Library.Type)
|
switch (readEvent.Series.Library.Type)
|
||||||
{
|
{
|
||||||
case LibraryType.Manga when MangaProviders.Intersect(userProviders).Any():
|
case LibraryType.Manga when MangaProviders.Intersect(userProviders).Any():
|
||||||
case LibraryType.Comic when
|
case LibraryType.Comic when ComicProviders.Intersect(userProviders).Any():
|
||||||
ComicProviders.Intersect(userProviders).Any():
|
case LibraryType.Book when BookProviders.Intersect(userProviders).Any():
|
||||||
case LibraryType.Book when
|
case LibraryType.LightNovel when LightNovelProviders.Intersect(userProviders).Any():
|
||||||
BookProviders.Intersect(userProviders).Any():
|
|
||||||
case LibraryType.LightNovel when
|
|
||||||
LightNovelProviders.Intersect(userProviders).Any():
|
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -1304,7 +1359,6 @@ public class ScrobblingService : IScrobblingService
|
||||||
return providers;
|
return providers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private async Task<int> SetAndCheckRateLimit(IDictionary<int, int> userRateLimits, AppUser user, string license)
|
private async Task<int> SetAndCheckRateLimit(IDictionary<int, int> userRateLimits, AppUser user, string license)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(user.AniListAccessToken)) return 0;
|
if (string.IsNullOrEmpty(user.AniListAccessToken)) return 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue