Bugfixes + Potential iOS Webtoon Reader Fix (#2650)
This commit is contained in:
parent
56fa393cf0
commit
f660a1cd06
25 changed files with 157 additions and 197 deletions
|
@ -7,12 +7,8 @@ using System.Net;
|
|||
using System.Threading.Tasks;
|
||||
using API.Data;
|
||||
using API.DTOs.Email;
|
||||
using API.Entities.Enums;
|
||||
using Flurl.Http;
|
||||
using Kavita.Common;
|
||||
using Kavita.Common.EnvironmentInfo;
|
||||
using MailKit.Security;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using MimeKit;
|
||||
|
||||
|
@ -38,7 +34,6 @@ public interface IEmailService
|
|||
Task<bool> SendForgotPasswordEmail(PasswordResetEmailDto dto);
|
||||
Task<bool> SendFilesToEmail(SendToDto data);
|
||||
Task<EmailTestResultDto> SendTestEmail(string adminEmail);
|
||||
Task<bool> IsDefaultEmailService();
|
||||
Task SendEmailChangeEmail(ConfirmationEmailDto data);
|
||||
bool IsValidEmail(string email);
|
||||
}
|
||||
|
@ -47,7 +42,6 @@ public class EmailService : IEmailService
|
|||
{
|
||||
private readonly ILogger<EmailService> _logger;
|
||||
private readonly IUnitOfWork _unitOfWork;
|
||||
private readonly IDownloadService _downloadService;
|
||||
private readonly IDirectoryService _directoryService;
|
||||
|
||||
private const string TemplatePath = @"{0}.html";
|
||||
|
@ -57,11 +51,10 @@ public class EmailService : IEmailService
|
|||
public const string DefaultApiUrl = "https://email.kavitareader.com";
|
||||
|
||||
|
||||
public EmailService(ILogger<EmailService> logger, IUnitOfWork unitOfWork, IDownloadService downloadService, IDirectoryService directoryService)
|
||||
public EmailService(ILogger<EmailService> logger, IUnitOfWork unitOfWork, IDirectoryService directoryService)
|
||||
{
|
||||
_logger = logger;
|
||||
_unitOfWork = unitOfWork;
|
||||
_downloadService = downloadService;
|
||||
_directoryService = directoryService;
|
||||
}
|
||||
|
||||
|
@ -114,14 +107,6 @@ public class EmailService : IEmailService
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
[Obsolete]
|
||||
public async Task<bool> IsDefaultEmailService()
|
||||
{
|
||||
return (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.EmailServiceUrl))!.Value!
|
||||
.Equals(DefaultApiUrl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an email that has a link that will finalize an Email Change
|
||||
/// </summary>
|
||||
|
|
|
@ -36,7 +36,7 @@ internal class ExternalMetadataIdsDto
|
|||
public MediaFormat? PlusMediaFormat { get; set; } = MediaFormat.Unknown;
|
||||
}
|
||||
|
||||
internal class SeriesDetailPlusAPIDto
|
||||
internal class SeriesDetailPlusApiDto
|
||||
{
|
||||
public IEnumerable<MediaRecommendationDto> Recommendations { get; set; }
|
||||
public IEnumerable<UserReviewDto> Reviews { get; set; }
|
||||
|
@ -108,7 +108,7 @@ public class ExternalMetadataService : IExternalMetadataService
|
|||
if (!needsRefresh)
|
||||
{
|
||||
// Convert into DTOs and return
|
||||
return await SerializeExternalSeriesDetail(seriesId, externalSeriesMetadata, user, series);
|
||||
return await SerializeExternalSeriesDetail(seriesId, series.LibraryId, user);
|
||||
}
|
||||
|
||||
try
|
||||
|
@ -123,7 +123,7 @@ public class ExternalMetadataService : IExternalMetadataService
|
|||
.WithHeader("Content-Type", "application/json")
|
||||
.WithTimeout(TimeSpan.FromSeconds(Configuration.DefaultTimeOutSecs))
|
||||
.PostJsonAsync(new PlusSeriesDtoBuilder(series).Build())
|
||||
.ReceiveJson<SeriesDetailPlusAPIDto>();
|
||||
.ReceiveJson<SeriesDetailPlusApiDto>();
|
||||
|
||||
|
||||
// Clear out existing results
|
||||
|
@ -149,7 +149,7 @@ public class ExternalMetadataService : IExternalMetadataService
|
|||
// Recommendations
|
||||
|
||||
externalSeriesMetadata.ExternalRecommendations ??= new List<ExternalRecommendation>();
|
||||
var recs = await ProcessRecommendations(series, user!, result.Recommendations, externalSeriesMetadata);
|
||||
var recs = await ProcessRecommendations(series, user, result.Recommendations, externalSeriesMetadata);
|
||||
|
||||
externalSeriesMetadata.LastUpdatedUtc = DateTime.UtcNow;
|
||||
externalSeriesMetadata.AverageExternalRating = (int) externalSeriesMetadata.ExternalRatings
|
||||
|
@ -161,14 +161,12 @@ public class ExternalMetadataService : IExternalMetadataService
|
|||
|
||||
await _unitOfWork.CommitAsync();
|
||||
|
||||
var ret = new SeriesDetailPlusDto()
|
||||
return new SeriesDetailPlusDto()
|
||||
{
|
||||
Recommendations = recs,
|
||||
Ratings = result.Ratings,
|
||||
Reviews = result.Reviews
|
||||
};
|
||||
|
||||
return ret;
|
||||
}
|
||||
catch (FlurlHttpException ex)
|
||||
{
|
||||
|
@ -185,46 +183,9 @@ public class ExternalMetadataService : IExternalMetadataService
|
|||
return null;
|
||||
}
|
||||
|
||||
private async Task<SeriesDetailPlusDto?> SerializeExternalSeriesDetail(int seriesId, ExternalSeriesMetadata externalSeriesMetadata,
|
||||
AppUser user, Series series)
|
||||
private async Task<SeriesDetailPlusDto?> SerializeExternalSeriesDetail(int seriesId, int libraryId, AppUser user)
|
||||
{
|
||||
var seriesIdsOnServer = externalSeriesMetadata.ExternalRecommendations
|
||||
.Where(r => r.SeriesId is > 0)
|
||||
.Select(s => (int) s.SeriesId!)
|
||||
.ToList();
|
||||
|
||||
var ownedSeries = (await _unitOfWork.SeriesRepository.GetSeriesDtoForIdsAsync(seriesIdsOnServer, user.Id))
|
||||
.ToList();
|
||||
var canSeeExternalSeries = user is {AgeRestriction: AgeRating.NotApplicable} &&
|
||||
await _unitOfWork.UserRepository.IsUserAdminAsync(user);
|
||||
var externalSeries = new List<ExternalSeriesDto>();
|
||||
if (canSeeExternalSeries)
|
||||
{
|
||||
externalSeries = externalSeriesMetadata.ExternalRecommendations
|
||||
.Where(r => r.SeriesId is null or 0)
|
||||
.Select(r => _mapper.Map<ExternalSeriesDto>(r))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
var ret = await _unitOfWork.ExternalSeriesMetadataRepository.GetSeriesDetailPlusDto(seriesId, series.LibraryId, user);
|
||||
|
||||
return new SeriesDetailPlusDto()
|
||||
{
|
||||
Ratings = externalSeriesMetadata.ExternalRatings.Select(r => _mapper.Map<RatingDto>(r)),
|
||||
Reviews = externalSeriesMetadata.ExternalReviews.OrderByDescending(r => r.Score).Select(r =>
|
||||
{
|
||||
var review = _mapper.Map<UserReviewDto>(r);
|
||||
review.SeriesId = seriesId;
|
||||
review.LibraryId = series.LibraryId;
|
||||
review.IsExternal = true;
|
||||
return review;
|
||||
}),
|
||||
Recommendations = new RecommendationDto()
|
||||
{
|
||||
ExternalSeries = externalSeries,
|
||||
OwnedSeries = ownedSeries
|
||||
}
|
||||
};
|
||||
return await _unitOfWork.ExternalSeriesMetadataRepository.GetSeriesDetailPlusDto(seriesId, libraryId, user);
|
||||
}
|
||||
|
||||
private async Task<ExternalSeriesMetadata> GetExternalSeriesMetadataForSeries(int seriesId, Series series)
|
||||
|
@ -249,8 +210,6 @@ public class ExternalMetadataService : IExternalMetadataService
|
|||
OwnedSeries = new List<SeriesDto>()
|
||||
};
|
||||
|
||||
var canSeeExternalSeries = user is {AgeRestriction: AgeRating.NotApplicable} &&
|
||||
await _unitOfWork.UserRepository.IsUserAdminAsync(user);
|
||||
// NOTE: This can result in a series being recommended that shares the same name but different format
|
||||
foreach (var rec in recs)
|
||||
{
|
||||
|
@ -276,7 +235,6 @@ public class ExternalMetadataService : IExternalMetadataService
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!canSeeExternalSeries) continue;
|
||||
// We can show this based on user permissions
|
||||
if (string.IsNullOrEmpty(rec.Name) || string.IsNullOrEmpty(rec.SiteUrl) || string.IsNullOrEmpty(rec.CoverUrl)) continue;
|
||||
recDto.ExternalSeries.Add(new ExternalSeriesDto()
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace API.Services;
|
|||
public interface ISeriesService
|
||||
{
|
||||
Task<SeriesDetailDto> GetSeriesDetail(int seriesId, int userId);
|
||||
Task<bool> UpdateSeriesMetadata(UpdateSeriesMetadataDto updateSeriesMetadataDto, int userId = 0);
|
||||
Task<bool> UpdateSeriesMetadata(UpdateSeriesMetadataDto updateSeriesMetadataDto);
|
||||
Task<bool> UpdateRating(AppUser user, UpdateSeriesRatingDto updateSeriesRatingDto);
|
||||
Task<bool> DeleteMultipleSeries(IList<int> seriesIds);
|
||||
Task<bool> UpdateRelatedSeries(UpdateRelatedSeriesDto dto);
|
||||
|
@ -111,9 +111,8 @@ public class SeriesService : ISeriesService
|
|||
/// Updates the Series Metadata.
|
||||
/// </summary>
|
||||
/// <param name="updateSeriesMetadataDto"></param>
|
||||
/// <param name="userId">If 0, does not bust any cache</param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> UpdateSeriesMetadata(UpdateSeriesMetadataDto updateSeriesMetadataDto, int userId = 0)
|
||||
public async Task<bool> UpdateSeriesMetadata(UpdateSeriesMetadataDto updateSeriesMetadataDto)
|
||||
{
|
||||
var hasWebLinksChanged = false;
|
||||
try
|
||||
|
@ -315,10 +314,10 @@ public class SeriesService : ISeriesService
|
|||
_logger.LogError(ex, "There was an issue cleaning up DB entries. This may happen if Komf is spamming updates. Nightly cleanup will work");
|
||||
}
|
||||
|
||||
if (hasWebLinksChanged && userId > 0)
|
||||
if (hasWebLinksChanged)
|
||||
{
|
||||
_logger.LogDebug("Clearing cache as series weblinks may have changed");
|
||||
await _cacheProvider.RemoveAsync(MetadataController.CacheKey + seriesId + userId);
|
||||
await _cacheProvider.RemoveAsync(MetadataController.CacheKey + seriesId);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -543,7 +543,7 @@ public static class Parser
|
|||
{
|
||||
// Historys Strongest Disciple Kenichi_v11_c90-98.zip, ...c90.5-100.5
|
||||
new Regex(
|
||||
@"(\b|_)(c|ch)(\.?\s?)(?<Chapter>(\d+(\.\d)?)(-\d+(\.\d)?)?)",
|
||||
@"(\b|_)(c|ch)(\.?\s?)(?<Chapter>(\d+(\.\d)?)(-c?\d+(\.\d)?)?)",
|
||||
MatchOptions, RegexTimeout),
|
||||
// [Suihei Kiki]_Kasumi_Otoko_no_Ko_[Taruby]_v1.1.zip
|
||||
new Regex(
|
||||
|
@ -761,6 +761,11 @@ public static class Parser
|
|||
var from = RemoveLeadingZeroes(tokens[0]);
|
||||
if (tokens.Length != 2) return from;
|
||||
|
||||
// Occasionally users will use c01-c02 instead of c01-02, clean any leftover c
|
||||
if (tokens[1].StartsWith("c", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
tokens[1] = tokens[1].Replace("c", string.Empty, StringComparison.InvariantCultureIgnoreCase);
|
||||
}
|
||||
var to = RemoveLeadingZeroes(hasPart ? AddChapterPart(tokens[1]) : tokens[1]);
|
||||
return $"{from}-{to}";
|
||||
}
|
||||
|
|
|
@ -752,6 +752,8 @@ public class ProcessSeries : IProcessSeries
|
|||
.Where(s => !string.IsNullOrEmpty(s))
|
||||
.Select(s => s.Trim())
|
||||
);
|
||||
|
||||
// For each weblink, try to parse out some MetadataIds and store in the Chapter directly for matching (CBL)
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(comicInfo.Isbn))
|
||||
|
|
|
@ -48,6 +48,7 @@ public interface IVersionUpdaterService
|
|||
Task<UpdateNotificationDto?> CheckForUpdate();
|
||||
Task PushUpdate(UpdateNotificationDto update);
|
||||
Task<IEnumerable<UpdateNotificationDto>> GetAllReleases();
|
||||
Task<int> GetNumberOfReleasesBehind();
|
||||
}
|
||||
|
||||
public class VersionUpdaterService : IVersionUpdaterService
|
||||
|
@ -87,6 +88,12 @@ public class VersionUpdaterService : IVersionUpdaterService
|
|||
return updates.Select(CreateDto).Where(d => d != null)!;
|
||||
}
|
||||
|
||||
public async Task<int> GetNumberOfReleasesBehind()
|
||||
{
|
||||
var updates = await GetAllReleases();
|
||||
return updates.TakeWhile(update => update.UpdateVersion != update.CurrentVersion).Count();
|
||||
}
|
||||
|
||||
private UpdateNotificationDto? CreateDto(GithubReleaseMetadata? update)
|
||||
{
|
||||
if (update == null || string.IsNullOrEmpty(update.Tag_Name)) return null;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue