Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kavita+ Tweaks #2595

Merged
merged 10 commits into from
Jan 9, 2024
14 changes: 7 additions & 7 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Bug Report
description: Create a report to help us improve
title: ""
title: "Bug Title Here" # Add a title field
labels: ["needs-triage"]
assignees:
body:
Expand All @@ -16,7 +16,7 @@ body:
id: what-happened
attributes:
label: What happened?
description: Also tell us, what steps you took so we can try to reproduce.
description: Also tell us what steps you took so we can try to reproduce.
placeholder: Tell us what you see!
value: ""
validations:
Expand Down Expand Up @@ -52,7 +52,7 @@ body:
- type: dropdown
id: desktop-OS
attributes:
label: If issue being seen on Desktop, what OS are you running where you see the issue?
label: If the issue is being seen on Desktop, what OS are you running where you see the issue?
multiple: false
options:
- Windows
Expand All @@ -61,7 +61,7 @@ body:
- type: dropdown
id: desktop-browsers
attributes:
label: If issue being seen in the UI, what browsers are you seeing the problem on?
label: If the issue is being seen in the UI, what browsers are you seeing the problem on?
multiple: true
options:
- Firefox
Expand All @@ -71,15 +71,15 @@ body:
- type: dropdown
id: mobile-OS
attributes:
label: If issue being seen on Mobile, what OS are you running where you see the issue?
label: If the issue is being seen on Mobile, what OS are you running where you see the issue?
multiple: false
options:
- Android
- iOS
- type: dropdown
id: mobile-browsers
attributes:
label: If issue being seen on UI, what browsers are you seeing the problem on?
label: If the issue is being seen on the UI, what browsers are you seeing the problem on?
multiple: true
options:
- Firefox
Expand All @@ -97,7 +97,7 @@ body:
attributes:
label: Additional Notes
description: Any other information about the issue not covered in this form?
placeholder: e.g. Running Kavita on a raspberry pi, updating from X version, using LSIO container, etc
placeholder: e.g. Running Kavita on a Raspberry Pi, updating from X version, using LSIO container, etc
value: ""
validations:
required: true
4 changes: 2 additions & 2 deletions API.Benchmark/API.Benchmark.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.11" />
<PackageReference Include="BenchmarkDotNet.Annotations" Version="0.13.11" />
<PackageReference Include="BenchmarkDotNet" Version="0.13.12" />
<PackageReference Include="BenchmarkDotNet.Annotations" Version="0.13.12" />
<PackageReference Include="NSubstitute" Version="5.1.0" />
</ItemGroup>

Expand Down
6 changes: 3 additions & 3 deletions API.Tests/API.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="NSubstitute" Version="5.1.0" />
<PackageReference Include="System.IO.Abstractions.TestingHelpers" Version="20.0.4" />
<PackageReference Include="TestableIO.System.IO.Abstractions.Wrappers" Version="20.0.4" />
<PackageReference Include="xunit" Version="2.6.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.5">
<PackageReference Include="xunit" Version="2.6.5" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
Expand Down
1 change: 1 addition & 0 deletions API.Tests/Parser/MangaParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ public void ParseSeriesTest(string filename, string expected)
[InlineData("Accel World Chapter 001 Volume 002", "1")]
[InlineData("Bleach 001-003", "1-3")]
[InlineData("Accel World Volume 2", "0")]
[InlineData("Historys Strongest Disciple Kenichi_v11_c90-98", "90-98")]
public void ParseChaptersTest(string filename, string expected)
{
Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseChapter(filename));
Expand Down
30 changes: 15 additions & 15 deletions API/API.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0">
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand All @@ -63,26 +63,26 @@
<PackageReference Include="ExCSS" Version="4.2.4" />
<PackageReference Include="Flurl" Version="3.0.7" />
<PackageReference Include="Flurl.Http" Version="3.2.4" />
<PackageReference Include="Hangfire" Version="1.8.6" />
<PackageReference Include="Hangfire" Version="1.8.7" />
<PackageReference Include="Hangfire.InMemory" Version="0.6.0" />
<PackageReference Include="Hangfire.MaximumConcurrentExecutions" Version="1.1.0" />
<PackageReference Include="Hangfire.MemoryStorage.Core" Version="1.4.0" />
<PackageReference Include="Hangfire.Storage.SQLite" Version="0.3.4" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.54" />
<PackageReference Include="Hangfire.Storage.SQLite" Version="0.4.0" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.57" />
<PackageReference Include="MarkdownDeep.NET.Core" Version="1.5.0.4" />
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.6" />
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.7" />
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.0" />
<PackageReference Include="MimeTypeMapOfficial" Version="1.0.17" />
<PackageReference Include="Nager.ArticleNumber" Version="1.0.7" />
<PackageReference Include="NetVips" Version="2.4.0" />
<PackageReference Include="NetVips.Native" Version="8.15.0" />
<PackageReference Include="NReco.Logging.File" Version="1.1.7" />
<PackageReference Include="NReco.Logging.File" Version="1.2.0" />
<PackageReference Include="Serilog" Version="3.1.1" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.0" />
<PackageReference Include="Serilog.Enrichers.Thread" Version="3.2.0-dev-00752" />
Expand All @@ -92,17 +92,17 @@
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Serilog.Sinks.SignalR.Core" Version="0.1.2" />
<PackageReference Include="SharpCompress" Version="0.34.2" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.1" />
<PackageReference Include="SharpCompress" Version="0.35.0" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.2" />
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.15.0.81779">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="7.0.12" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.0.3" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="8.0.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.1.2" />
<PackageReference Include="System.IO.Abstractions" Version="20.0.4" />
<PackageReference Include="System.Drawing.Common" Version="8.0.0" />
<PackageReference Include="System.Drawing.Common" Version="8.0.1" />
<PackageReference Include="VersOne.Epub" Version="3.3.1" />
</ItemGroup>

Expand Down
27 changes: 21 additions & 6 deletions API/Controllers/ScrobblingController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,27 @@ public ScrobblingController(IUnitOfWork unitOfWork, IScrobblingService scrobblin
_localizationService = localizationService;
}

/// <summary>
/// Get the current user's AniList token
/// </summary>
/// <returns></returns>
[HttpGet("anilist-token")]
public async Task<ActionResult> GetAniListToken()
{
// Validate the license

var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
if (user == null) return Unauthorized();

return Ok(user.AniListAccessToken);
}

/// <summary>
/// Update the current user's AniList token
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[HttpPost("update-anilist-token")]
public async Task<ActionResult> UpdateAniListToken(AniListUpdateDto dto)
{
// Validate the license

var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
if (user == null) return Unauthorized();

Expand All @@ -71,6 +76,11 @@ public async Task<ActionResult> UpdateAniListToken(AniListUpdateDto dto)
return Ok();
}

/// <summary>
/// Checks if the current Scrobbling token for the given Provider has expired for the current user
/// </summary>
/// <param name="provider"></param>
/// <returns></returns>
[HttpGet("token-expired")]
public async Task<ActionResult<bool>> HasTokenExpired(ScrobbleProvider provider)
{
Expand Down Expand Up @@ -159,15 +169,20 @@ public async Task<ActionResult> AddHold(int seriesId)
var user = await _unitOfWork.UserRepository.GetUserByIdAsync(User.GetUserId(), AppUserIncludes.ScrobbleHolds);
if (user == null) return Unauthorized();
if (user.ScrobbleHolds.Any(s => s.SeriesId == seriesId))
return Ok(await _localizationService.Translate(User.GetUserId(), "nothing-to-do"));
return Ok(await _localizationService.Translate(user.Id, "nothing-to-do"));

var seriesHold = new ScrobbleHoldBuilder().WithSeriesId(seriesId).Build();
var seriesHold = new ScrobbleHoldBuilder()
.WithSeriesId(seriesId)
.Build();
user.ScrobbleHolds.Add(seriesHold);
_unitOfWork.UserRepository.Update(user);
try
{
_unitOfWork.UserRepository.Update(user);
await _unitOfWork.CommitAsync();

// When a hold is placed on a series, clear any pre-existing Scrobble Events
await _scrobblingService.ClearEventsForSeries(user.Id, seriesId);
return Ok();
}
catch (DbUpdateConcurrencyException ex)
Expand Down
10 changes: 6 additions & 4 deletions API/Data/Repositories/ScrobbleEventRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public interface IScrobbleRepository
Task ClearScrobbleErrors();
Task<bool> HasErrorForSeries(int seriesId);
Task<ScrobbleEvent?> GetEvent(int userId, int seriesId, ScrobbleEventType eventType);
Task<IEnumerable<ScrobbleEventDto>> GetUserEvents(int userId);
Task<IEnumerable<ScrobbleEvent>> GetUserEventsForSeries(int userId, int seriesId);
Task<PagedList<ScrobbleEventDto>> GetUserEvents(int userId, ScrobbleEventFilter filter, UserParams pagination);
}

Expand Down Expand Up @@ -127,16 +127,17 @@ public async Task<bool> HasErrorForSeries(int seriesId)
return await _context.ScrobbleEvent.FirstOrDefaultAsync(e =>
e.AppUserId == userId && e.SeriesId == seriesId && e.ScrobbleEventType == eventType);
}
public async Task<IEnumerable<ScrobbleEventDto>> GetUserEvents(int userId)

public async Task<IEnumerable<ScrobbleEvent>> GetUserEventsForSeries(int userId, int seriesId)
{
return await _context.ScrobbleEvent
.Where(e => e.AppUserId == userId)
.Where(e => e.AppUserId == userId && !e.IsProcessed)
.Include(e => e.Series)
.OrderBy(e => e.LastModifiedUtc)
.AsSplitQuery()
.ProjectTo<ScrobbleEventDto>(_mapper.ConfigurationProvider)
.ToListAsync();
}

public async Task<PagedList<ScrobbleEventDto>> GetUserEvents(int userId, ScrobbleEventFilter filter, UserParams pagination)
{
var query = _context.ScrobbleEvent
Expand All @@ -146,6 +147,7 @@ public async Task<PagedList<ScrobbleEventDto>> GetUserEvents(int userId, Scrobbl
.WhereIf(!string.IsNullOrEmpty(filter.Query), s =>
EF.Functions.Like(s.Series.Name, $"%{filter.Query}%")
)
.WhereIf(!filter.IncludeReviews, e => e.ScrobbleEventType != ScrobbleEventType.Review)
.AsSplitQuery()
.ProjectTo<ScrobbleEventDto>(_mapper.ConfigurationProvider);

Expand Down
4 changes: 4 additions & 0 deletions API/Entities/Scrobble/ScrobbleEventFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,8 @@ public class ScrobbleEventFilter
/// A query to search against
/// </summary>
public string Query { get; set; }
/// <summary>
/// Include reviews in the result - Note: Review Scrobbling is disabled
/// </summary>
public bool IncludeReviews { get; set; } = false;
}
61 changes: 41 additions & 20 deletions API/Services/Plus/ScrobblingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public interface IScrobblingService
[AutomaticRetry(Attempts = 3, OnAttemptsExceeded = AttemptsExceededAction.Delete)]
Task ProcessUpdatesSinceLastSync();
Task CreateEventsFromExistingHistory(int userId = 0);
Task ClearEventsForSeries(int userId, int seriesId);
}

public class ScrobblingService : IScrobblingService
Expand Down Expand Up @@ -542,6 +543,26 @@ public async Task CreateEventsFromExistingHistory(int userId = 0)
}
}

/// <summary>
/// Removes all events (active) that are tied to a now-on hold series
/// </summary>
/// <param name="userId"></param>
/// <param name="seriesId"></param>
public async Task ClearEventsForSeries(int userId, int seriesId)
{
_logger.LogInformation("Clearing Pre-existing Scrobble events for Series {SeriesId} by User {UserId} 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);
}

await _unitOfWork.CommitAsync();
}

/// <summary>
/// Removes all events that have been processed that are 7 days old
/// </summary>
[DisableConcurrentExecution(60 * 60 * 60)]
[AutomaticRetry(Attempts = 3, OnAttemptsExceeded = AttemptsExceededAction.Delete)]
public async Task ClearProcessedEvents()
Expand Down Expand Up @@ -594,10 +615,10 @@ public async Task ProcessUpdatesSinceLastSync()
.Where(e => librariesWithScrobbling.Contains(e.LibraryId))
.Where(e => !errors.Contains(e.SeriesId))
.ToList();
var reviewEvents = (await _unitOfWork.ScrobbleRepository.GetByEvent(ScrobbleEventType.Review))
.Where(e => librariesWithScrobbling.Contains(e.LibraryId))
.Where(e => !errors.Contains(e.SeriesId))
.ToList();
// var reviewEvents = (await _unitOfWork.ScrobbleRepository.GetByEvent(ScrobbleEventType.Review))
// .Where(e => librariesWithScrobbling.Contains(e.LibraryId))
// .Where(e => !errors.Contains(e.SeriesId))
// .ToList();
var decisions = addToWantToRead
.GroupBy(item => new { item.SeriesId, item.AppUserId })
.Select(group => new
Expand All @@ -624,7 +645,7 @@ public async Task ProcessUpdatesSinceLastSync()
await SetAndCheckRateLimit(userRateLimits, user, license.Value);
}

var totalProgress = readEvents.Count + decisions.Count + ratingEvents.Count + decisions.Count + reviewEvents.Count;
var totalProgress = readEvents.Count + decisions.Count + ratingEvents.Count + decisions.Count;// + reviewEvents.Count;

_logger.LogInformation("Found {TotalEvents} Scrobble Events", totalProgress);
try
Expand Down Expand Up @@ -671,21 +692,21 @@ await _unitOfWork.AppUserProgressRepository.GetHighestFullyReadChapterForSeries(
Year = evt.Series.Metadata.ReleaseYear
}));

progressCounter = await ProcessEvents(reviewEvents, userRateLimits, usersToScrobble.Count, progressCounter,
totalProgress, evt => Task.FromResult(new ScrobbleDto()
{
Format = evt.Format,
AniListId = evt.AniListId,
MALId = (int?) evt.MalId,
ScrobbleEventType = evt.ScrobbleEventType,
AniListToken = evt.AppUser.AniListAccessToken,
SeriesName = evt.Series.Name,
LocalizedSeriesName = evt.Series.LocalizedName,
Rating = evt.Rating,
Year = evt.Series.Metadata.ReleaseYear,
ReviewBody = evt.ReviewBody,
ReviewTitle = evt.ReviewTitle
}));
// progressCounter = await ProcessEvents(reviewEvents, userRateLimits, usersToScrobble.Count, progressCounter,
// totalProgress, evt => Task.FromResult(new ScrobbleDto()
// {
// Format = evt.Format,
// AniListId = evt.AniListId,
// MALId = (int?) evt.MalId,
// ScrobbleEventType = evt.ScrobbleEventType,
// AniListToken = evt.AppUser.AniListAccessToken,
// SeriesName = evt.Series.Name,
// LocalizedSeriesName = evt.Series.LocalizedName,
// Rating = evt.Rating,
// Year = evt.Series.Metadata.ReleaseYear,
// ReviewBody = evt.ReviewBody,
// ReviewTitle = evt.ReviewTitle
// }));

progressCounter = await ProcessEvents(decisions, userRateLimits, usersToScrobble.Count, progressCounter,
totalProgress, evt => Task.FromResult(new ScrobbleDto()
Expand Down
3 changes: 2 additions & 1 deletion API/Services/Tasks/Scanner/Parser/DefaultParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public DefaultParser(IDirectoryService directoryService)
// If library type is Image or this is not a cover image in a non-image library, then use dedicated parsing mechanism
if (type == LibraryType.Image || Parser.IsImage(filePath))
{
// TODO: We can move this up one level
return ParseImage(filePath, rootPath, ret);
}

Expand Down Expand Up @@ -78,7 +79,7 @@ public DefaultParser(IDirectoryService directoryService)
var edition = Parser.ParseEdition(fileName);
if (!string.IsNullOrEmpty(edition))
{
ret.Series = Parser.CleanTitle(ret.Series.Replace(edition, ""), type is LibraryType.Comic);
ret.Series = Parser.CleanTitle(ret.Series.Replace(edition, string.Empty), type is LibraryType.Comic);
ret.Edition = edition;
}

Expand Down
Loading
Loading