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

Polish 4 #3363

Merged
merged 10 commits into from
Nov 14, 2024
18 changes: 9 additions & 9 deletions API/Controllers/SettingsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,13 +180,6 @@ public async Task<ActionResult<ServerSettingDto>> UpdateSettings(ServerSettingDt
_unitOfWork.SettingsRepository.Update(setting);
}

if (setting.Key == ServerSettingKey.CoverImageSize &&
updateSettingsDto.CoverImageSize + string.Empty != setting.Value)
{
setting.Value = updateSettingsDto.CoverImageSize + string.Empty;
_unitOfWork.SettingsRepository.Update(setting);
}

if (setting.Key == ServerSettingKey.Port && updateSettingsDto.Port + string.Empty != setting.Value)
{
if (OsInfo.IsDocker) continue;
Expand Down Expand Up @@ -260,9 +253,16 @@ public async Task<ActionResult<ServerSettingDto>> UpdateSettings(ServerSettingDt
}

if (setting.Key == ServerSettingKey.EncodeMediaAs &&
updateSettingsDto.EncodeMediaAs + string.Empty != setting.Value)
((int)updateSettingsDto.EncodeMediaAs).ToString() != setting.Value)
{
setting.Value = ((int)updateSettingsDto.EncodeMediaAs).ToString();
_unitOfWork.SettingsRepository.Update(setting);
}

if (setting.Key == ServerSettingKey.CoverImageSize &&
((int)updateSettingsDto.CoverImageSize).ToString() != setting.Value)
{
setting.Value = updateSettingsDto.EncodeMediaAs + string.Empty;
setting.Value = ((int)updateSettingsDto.CoverImageSize).ToString();
_unitOfWork.SettingsRepository.Update(setting);
}

Expand Down
67 changes: 67 additions & 0 deletions API/Data/ManualMigrations/ManualMigrateEncodeSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using API.Entities;
using API.Entities.Enums;
using Flurl.Util;
using Kavita.Common.EnvironmentInfo;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace API.Data.ManualMigrations;

/// <summary>
/// At some point, encoding settings wrote bad data to the backend, maybe in v0.8.0. This just fixes any bad data.
/// </summary>
public static class ManualMigrateEncodeSettings
{
public static async Task Migrate(DataContext context, ILogger<Program> logger)
{
if (await context.ManualMigrationHistory.AnyAsync(m => m.Name == "ManualMigrateEncodeSettings"))
{
return;
}

logger.LogCritical("Running ManualMigrateEncodeSettings migration - Please be patient, this may take some time. This is not an error");


var encodeAs = await context.ServerSetting.FirstAsync(s => s.Key == ServerSettingKey.EncodeMediaAs);
var coverSize = await context.ServerSetting.FirstAsync(s => s.Key == ServerSettingKey.CoverImageSize);

var encodeMap = new Dictionary<string, string>
{
{ EncodeFormat.WEBP.ToString(), ((int)EncodeFormat.WEBP).ToString() },
{ EncodeFormat.PNG.ToString(), ((int)EncodeFormat.PNG).ToString() },
{ EncodeFormat.AVIF.ToString(), ((int)EncodeFormat.AVIF).ToString() }
};

if (encodeMap.TryGetValue(encodeAs.Value, out var encodedValue))
{
encodeAs.Value = encodedValue;
context.ServerSetting.Update(encodeAs);
}

if (coverSize.Value == "0")
{
coverSize.Value = ((int)CoverImageSize.Default).ToString();
context.ServerSetting.Update(coverSize);
}


if (context.ChangeTracker.HasChanges())
{
await context.SaveChangesAsync();
}

await context.ManualMigrationHistory.AddAsync(new ManualMigrationHistory()
{
Name = "ManualMigrateEncodeSettings",
ProductVersion = BuildInfo.Version.ToString(),
RanAt = DateTime.UtcNow
});
await context.SaveChangesAsync();

logger.LogCritical("Running ManualMigrateEncodeSettings migration - Completed. This is not an error");
}
}
31 changes: 18 additions & 13 deletions API/Helpers/Converters/ServerSettingConverter.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using API.DTOs.Settings;
using API.Entities;
using API.Entities.Enums;
Expand Down Expand Up @@ -33,7 +34,7 @@ public ServerSettingDto Convert(IEnumerable<ServerSetting> source, ServerSetting
destination.LoggingLevel = row.Value;
break;
case ServerSettingKey.Port:
destination.Port = int.Parse(row.Value);
destination.Port = int.Parse(row.Value, CultureInfo.InvariantCulture);
break;
case ServerSettingKey.IpAddresses:
destination.IpAddresses = row.Value;
Expand All @@ -53,11 +54,8 @@ public ServerSettingDto Convert(IEnumerable<ServerSetting> source, ServerSetting
case ServerSettingKey.InstallVersion:
destination.InstallVersion = row.Value;
break;
case ServerSettingKey.EncodeMediaAs:
destination.EncodeMediaAs = Enum.Parse<EncodeFormat>(row.Value);
break;
case ServerSettingKey.TotalBackups:
destination.TotalBackups = int.Parse(row.Value);
destination.TotalBackups = int.Parse(row.Value, CultureInfo.InvariantCulture);
break;
case ServerSettingKey.InstallId:
destination.InstallId = row.Value;
Expand All @@ -66,33 +64,36 @@ public ServerSettingDto Convert(IEnumerable<ServerSetting> source, ServerSetting
destination.EnableFolderWatching = bool.Parse(row.Value);
break;
case ServerSettingKey.TotalLogs:
destination.TotalLogs = int.Parse(row.Value);
destination.TotalLogs = int.Parse(row.Value, CultureInfo.InvariantCulture);
break;
case ServerSettingKey.HostName:
destination.HostName = row.Value;
break;
case ServerSettingKey.CacheSize:
destination.CacheSize = long.Parse(row.Value);
destination.CacheSize = long.Parse(row.Value, CultureInfo.InvariantCulture);
break;
case ServerSettingKey.OnDeckProgressDays:
destination.OnDeckProgressDays = int.Parse(row.Value);
destination.OnDeckProgressDays = int.Parse(row.Value, CultureInfo.InvariantCulture);
break;
case ServerSettingKey.OnDeckUpdateDays:
destination.OnDeckUpdateDays = int.Parse(row.Value);
destination.OnDeckUpdateDays = int.Parse(row.Value, CultureInfo.InvariantCulture);
break;
case ServerSettingKey.CoverImageSize:
destination.CoverImageSize = Enum.Parse<CoverImageSize>(row.Value);
break;
case ServerSettingKey.EncodeMediaAs:
destination.EncodeMediaAs = Enum.Parse<EncodeFormat>(row.Value);
break;
case ServerSettingKey.BackupDirectory:
destination.BookmarksDirectory = row.Value;
break;
case ServerSettingKey.EmailHost:
destination.SmtpConfig ??= new SmtpConfigDto();
destination.SmtpConfig.Host = row.Value;
destination.SmtpConfig.Host = row.Value ?? string.Empty;
break;
case ServerSettingKey.EmailPort:
destination.SmtpConfig ??= new SmtpConfigDto();
destination.SmtpConfig.Port = string.IsNullOrEmpty(row.Value) ? 0 : int.Parse(row.Value);
destination.SmtpConfig.Port = string.IsNullOrEmpty(row.Value) ? 0 : int.Parse(row.Value, CultureInfo.InvariantCulture);
break;
case ServerSettingKey.EmailAuthPassword:
destination.SmtpConfig ??= new SmtpConfigDto();
Expand All @@ -116,18 +117,22 @@ public ServerSettingDto Convert(IEnumerable<ServerSetting> source, ServerSetting
break;
case ServerSettingKey.EmailSizeLimit:
destination.SmtpConfig ??= new SmtpConfigDto();
destination.SmtpConfig.SizeLimit = int.Parse(row.Value);
destination.SmtpConfig.SizeLimit = int.Parse(row.Value, CultureInfo.InvariantCulture);
break;
case ServerSettingKey.EmailCustomizedTemplates:
destination.SmtpConfig ??= new SmtpConfigDto();
destination.SmtpConfig.CustomizedTemplates = bool.Parse(row.Value);
break;
case ServerSettingKey.FirstInstallDate:
destination.FirstInstallDate = DateTime.Parse(row.Value);
destination.FirstInstallDate = DateTime.Parse(row.Value, CultureInfo.InvariantCulture);
break;
case ServerSettingKey.FirstInstallVersion:
destination.FirstInstallVersion = row.Value;
break;
case ServerSettingKey.LicenseKey:
break;
default:
throw new ArgumentOutOfRangeException();
}
}

Expand Down
2 changes: 2 additions & 0 deletions API/Services/ArchiveService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,11 @@ public int GetNumberOfPagesFromArchive(string archivePath)
}
case ArchiveLibrary.NotSupported:
_logger.LogWarning("[GetNumberOfPagesFromArchive] This archive cannot be read: {ArchivePath}. Defaulting to 0 pages", archivePath);
_mediaErrorService.ReportMediaIssue(archivePath, MediaErrorProducer.ArchiveService, "File format not supported", string.Empty);
return 0;
default:
_logger.LogWarning("[GetNumberOfPagesFromArchive] There was an exception when reading archive stream: {ArchivePath}. Defaulting to 0 pages", archivePath);
_mediaErrorService.ReportMediaIssue(archivePath, MediaErrorProducer.ArchiveService, "File format not supported", string.Empty);
return 0;
}
}
Expand Down
1 change: 1 addition & 0 deletions API/Services/MetadataService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ public async Task GenerateCoversForSeries(int libraryId, int seriesId, bool forc
return;
}

// TODO: Cache this because it's called a lot during scans
var settings = await _unitOfWork.SettingsRepository.GetSettingsDtoAsync();
var encodeFormat = settings.EncodeMediaAs;
var coverImageSize = settings.CoverImageSize;
Expand Down
1 change: 1 addition & 0 deletions API/Services/ReadingItemService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ public ReadingItemService(IArchiveService archiveService, IBookService bookServi
/// <returns></returns>
public int GetNumberOfPages(string filePath, MangaFormat format)
{

switch (format)
{
case MangaFormat.Archive:
Expand Down
1 change: 1 addition & 0 deletions API/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ public void Configure(IApplicationBuilder app, IBackgroundJobClient backgroundJo
await ManualMigrateRemovePeople.Migrate(dataContext, logger);
await MigrateDuplicateDarkTheme.Migrate(dataContext, logger);
await ManualMigrateUnscrobbleBookLibraries.Migrate(dataContext, logger);
await ManualMigrateEncodeSettings.Migrate(dataContext, logger);

// Update the version in the DB after all migrations are run
var installVersion = await unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallVersion);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ <h4>{{t('title')}}</h4>
<div class="col-auto">
@if(!isLoading && allLibraries.length > 0) {
<span class="form-check float-end">
<input id="select-all" type="checkbox" class="form-check-input"
<input id="lib--select-all" type="checkbox" class="form-check-input"
[ngModel]="selectAll" (change)="toggleAll()" [indeterminate]="hasSomeSelected">
<label for="select-all" class="form-check-label">{{selectAll ? t('deselect-all') : t('select-all')}}</label>
<label for="lib--select-all" class="form-check-label">{{selectAll ? t('deselect-all') : t('select-all')}}</label>
</span>
}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,20 @@ import {ToastrService} from 'ngx-toastr';
import {debounceTime, distinctUntilChanged, filter, switchMap, take, tap} from 'rxjs';
import {SettingsService} from '../settings.service';
import {ServerSettings} from '../_models/server-settings';
import {
NgbAlert,
NgbTooltip
} from '@ng-bootstrap/ng-bootstrap';
import {AsyncPipe, NgTemplateOutlet, TitleCasePipe} from '@angular/common';
import {translate, TranslocoModule} from "@jsverse/transloco";
import {SafeHtmlPipe} from "../../_pipes/safe-html.pipe";
import {ManageMediaIssuesComponent} from "../manage-media-issues/manage-media-issues.component";
import {SettingItemComponent} from "../../settings/_components/setting-item/setting-item.component";
import {SettingSwitchComponent} from "../../settings/_components/setting-switch/setting-switch.component";
import {DefaultValuePipe} from "../../_pipes/default-value.pipe";
import {BytesPipe} from "../../_pipes/bytes.pipe";
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
import {CardActionablesComponent} from "../../_single-module/card-actionables/card-actionables.component";

@Component({
selector: 'app-manage-email-settings',
templateUrl: './manage-email-settings.component.html',
styleUrls: ['./manage-email-settings.component.scss'],
standalone: true,
selector: 'app-manage-email-settings',
templateUrl: './manage-email-settings.component.html',
styleUrls: ['./manage-email-settings.component.scss'],
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ReactiveFormsModule, NgbTooltip, NgTemplateOutlet, TranslocoModule, SafeHtmlPipe,
ManageMediaIssuesComponent, TitleCasePipe, NgbAlert, SettingItemComponent, SettingSwitchComponent, DefaultValuePipe, BytesPipe, AsyncPipe, CardActionablesComponent]
imports: [ReactiveFormsModule, TranslocoModule, SettingItemComponent, SettingSwitchComponent, DefaultValuePipe, BytesPipe]
})
export class ManageEmailSettingsComponent implements OnInit {

Expand Down Expand Up @@ -55,8 +46,8 @@ export class ManageEmailSettingsComponent implements OnInit {

// Automatically save settings as we edit them
this.settingsForm.valueChanges.pipe(
debounceTime(300),
distinctUntilChanged(),
debounceTime(100),
filter(_ => this.settingsForm.valid),
takeUntilDestroyed(this.destroyRef),
switchMap(_ => {
Expand All @@ -65,7 +56,6 @@ export class ManageEmailSettingsComponent implements OnInit {
}),
tap(settings => {
this.serverSettings = settings;
this.resetForm();
this.cdRef.markForCheck();
})
).subscribe();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ <h4>{{t('title')}}</h4>
<div class="col-auto">
@if(selectedRoles.length > 0) {
<span class="form-check float-end">
<input id="select-all" type="checkbox" class="form-check-input"
<input id="role--select-all" type="checkbox" class="form-check-input"
[ngModel]="selectAll" (change)="toggleAll()" [indeterminate]="hasSomeSelected">
<label for="select-all" class="form-check-label">{{selectAll ? t('deselect-all') : t('select-all')}}</label>
<label for="role--select-all" class="form-check-label">{{selectAll ? t('deselect-all') : t('select-all')}}</label>
</span>
}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,21 +133,6 @@ export class AllSeriesComponent implements OnInit {
});
}

@HostListener('document:keydown.shift', ['$event'])
handleKeypress(event: KeyboardEvent) {
if (event.key === KEY_CODES.SHIFT) {
this.bulkSelectionService.isShiftDown = true;
}
}

@HostListener('document:keyup.shift', ['$event'])
handleKeyUp(event: KeyboardEvent) {
if (event.key === KEY_CODES.SHIFT) {
this.bulkSelectionService.isShiftDown = false;
}
}


updateFilter(data: FilterEvent) {
if (data.filterV2 === undefined) return;
this.filter = data.filterV2;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,20 +100,6 @@ export class BookmarksComponent implements OnInit {
}


@HostListener('document:keydown.shift', ['$event'])
handleKeypress(event: KeyboardEvent) {
if (event.key === KEY_CODES.SHIFT) {
this.bulkSelectionService.isShiftDown = true;
}
}

@HostListener('document:keyup.shift', ['$event'])
handleKeyUp(event: KeyboardEvent) {
if (event.key === KEY_CODES.SHIFT) {
this.bulkSelectionService.isShiftDown = false;
}
}

async handleAction(action: ActionItem<Series>, series: Series) {
switch (action.action) {
case(Action.Delete):
Expand Down
18 changes: 16 additions & 2 deletions UI/Web/src/app/cards/bulk-operations/bulk-operations.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
DestroyRef,
DestroyRef, HostListener,
inject,
Input,
OnInit
Expand All @@ -14,6 +14,7 @@ import {AsyncPipe, DecimalPipe, NgStyle} from "@angular/common";
import {TranslocoModule} from "@jsverse/transloco";
import {NgbTooltip} from "@ng-bootstrap/ng-bootstrap";
import {CardActionablesComponent} from "../../_single-module/card-actionables/card-actionables.component";
import {KEY_CODES} from "../../shared/_services/utility.service";

@Component({
selector: 'app-bulk-operations',
Expand Down Expand Up @@ -55,7 +56,20 @@ export class BulkOperationsComponent implements OnInit {
public readonly bulkSelectionService = inject(BulkSelectionService);
protected readonly Action = Action;

constructor() { }
@HostListener('document:keydown.shift', ['$event'])
handleKeypress(event: KeyboardEvent) {
if (event.key === KEY_CODES.SHIFT) {
this.bulkSelectionService.isShiftDown = true;
}
// TODO: See if we can figure out a select all (Ctrl+A) by having each method handle the event or pass all the data into this component.
}

@HostListener('document:keyup.shift', ['$event'])
handleKeyUp(event: KeyboardEvent) {
if (event.key === KEY_CODES.SHIFT) {
this.bulkSelectionService.isShiftDown = false;
}
}

ngOnInit(): void {
this.bulkSelectionService.actions$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(actions => {
Expand Down
Loading
Loading