diff --git a/API.Tests/Entities/ComicInfoTests.cs b/API.Tests/Entities/ComicInfoTests.cs index 07f4a9918..f92800bea 100644 --- a/API.Tests/Entities/ComicInfoTests.cs +++ b/API.Tests/Entities/ComicInfoTests.cs @@ -11,15 +11,15 @@ public class ComicInfoTests [Theory] [InlineData("G", AgeRating.G)] [InlineData("Everyone", AgeRating.Everyone)] - [InlineData("Mature", AgeRating.Mature)] [InlineData("Teen", AgeRating.Teen)] [InlineData("Adults Only 18+", AgeRating.AdultsOnly)] [InlineData("Early Childhood", AgeRating.EarlyChildhood)] [InlineData("Everyone 10+", AgeRating.Everyone10Plus)] - [InlineData("Mature 15+", AgeRating.Mature15Plus)] + [InlineData("M", AgeRating.Mature)] + [InlineData("MA 15+", AgeRating.Mature15Plus)] [InlineData("Mature 17+", AgeRating.Mature17Plus)] [InlineData("Rating Pending", AgeRating.RatingPending)] - [InlineData("X 18+", AgeRating.X18Plus)] + [InlineData("X18+", AgeRating.X18Plus)] [InlineData("Kids to Adults", AgeRating.KidsToAdults)] [InlineData("NotValid", AgeRating.Unknown)] public void ConvertAgeRatingToEnum_ShouldConvertCorrectly(string input, AgeRating expected) diff --git a/API.Tests/Services/ArchiveServiceTests.cs b/API.Tests/Services/ArchiveServiceTests.cs index 110e5d269..526abde3e 100644 --- a/API.Tests/Services/ArchiveServiceTests.cs +++ b/API.Tests/Services/ArchiveServiceTests.cs @@ -144,6 +144,7 @@ namespace API.Tests.Services [InlineData(new [] {"__MACOSX/cover.jpg", "vol1/page 01.jpg"}, "vol1/page 01.jpg")] [InlineData(new [] {"Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg", "Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg", "Akame ga KILL! ZERO - c060 (v10) - p200 [Digital] [LuCaZ].jpg", "folder.jpg"}, "Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg")] [InlineData(new [] {"001.jpg", "001 - chapter 1/001.jpg"}, "001.jpg")] + [InlineData(new [] {"chapter 1/001.jpg", "chapter 2/002.jpg", "somefile.jpg"}, "somefile.jpg")] public void FindFirstEntry(string[] files, string expected) { var foundFile = ArchiveService.FirstFileEntry(files, string.Empty); diff --git a/API/Controllers/DownloadController.cs b/API/Controllers/DownloadController.cs index e9552ad9e..c253fb9ee 100644 --- a/API/Controllers/DownloadController.cs +++ b/API/Controllers/DownloadController.cs @@ -139,15 +139,6 @@ namespace API.Controllers var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername()); var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(downloadBookmarkDto.Bookmarks.First().SeriesId); - var tempFolder = $"download_{user.Id}_{series.Id}_bookmarks"; - var fullExtractPath = Path.Join(_directoryService.TempDirectory, tempFolder); - if (_directoryService.FileSystem.DirectoryInfo.FromDirectoryName(fullExtractPath).Exists) - { - return BadRequest( - "Server is currently processing this exact download. Please try again in a few minutes."); - } - _directoryService.ExistOrCreate(fullExtractPath); - var bookmarkDirectory = (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.BookmarkDirectory)).Value; var files = (await _unitOfWork.UserRepository.GetAllBookmarksByIds(downloadBookmarkDto.Bookmarks @@ -156,8 +147,7 @@ namespace API.Controllers .Select(b => Parser.Parser.NormalizePath(_directoryService.FileSystem.Path.Join(bookmarkDirectory, b.FileName))); var (fileBytes, _) = await _archiveService.CreateZipForDownload(files, - tempFolder); - _directoryService.ClearAndDeleteDirectory(fullExtractPath); + $"download_{user.Id}_{series.Id}_bookmarks"); return File(fileBytes, DefaultContentType, $"{series.Name} - Bookmarks.zip"); } diff --git a/API/Controllers/SeriesController.cs b/API/Controllers/SeriesController.cs index ec63e3b3e..ad2faeb0f 100644 --- a/API/Controllers/SeriesController.cs +++ b/API/Controllers/SeriesController.cs @@ -83,6 +83,8 @@ namespace API.Controllers var username = User.GetUsername(); _logger.LogInformation("Series {SeriesId} is being deleted by {UserName}", seriesId, username); + var series = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(seriesId); + var chapterIds = (await _unitOfWork.SeriesRepository.GetChapterIdsForSeriesAsync(new []{seriesId})); var result = await _unitOfWork.SeriesRepository.DeleteSeriesAsync(seriesId); @@ -92,6 +94,8 @@ namespace API.Controllers await _unitOfWork.CollectionTagRepository.RemoveTagsWithoutSeries(); await _unitOfWork.CommitAsync(); _taskScheduler.CleanupChapters(chapterIds); + await _messageHub.Clients.All.SendAsync(SignalREvents.SeriesRemoved, + MessageFactory.SeriesRemovedEvent(seriesId, series.Name, series.LibraryId)); } return Ok(result); } diff --git a/API/Data/Metadata/ComicInfo.cs b/API/Data/Metadata/ComicInfo.cs index dfa80c60b..cc7154f93 100644 --- a/API/Data/Metadata/ComicInfo.cs +++ b/API/Data/Metadata/ComicInfo.cs @@ -89,6 +89,33 @@ namespace API.Data.Metadata .SingleOrDefault(t => t.ToDescription().ToUpperInvariant().Equals(value.ToUpperInvariant()), Entities.Enums.AgeRating.Unknown); } + public static void CleanComicInfo(ComicInfo info) + { + if (info == null) return; + + info.Writer = Parser.Parser.CleanAuthor(info.Writer); + info.Colorist = Parser.Parser.CleanAuthor(info.Colorist); + info.Editor = Parser.Parser.CleanAuthor(info.Editor); + info.Inker = Parser.Parser.CleanAuthor(info.Inker); + info.Letterer = Parser.Parser.CleanAuthor(info.Letterer); + info.Penciller = Parser.Parser.CleanAuthor(info.Penciller); + info.Publisher = Parser.Parser.CleanAuthor(info.Publisher); + info.Characters = Parser.Parser.CleanAuthor(info.Characters); + info.Translator = Parser.Parser.CleanAuthor(info.Translator); + info.CoverArtist = Parser.Parser.CleanAuthor(info.CoverArtist); + + + // if (!string.IsNullOrEmpty(info.Web)) + // { + // // ComicVine stores the Issue number in Number field and does not use Volume. + // if (!info.Web.Contains("https://comicvine.gamespot.com/")) return; + // if (info.Volume.Equals("1")) + // { + // info.Volume = Parser.Parser.DefaultVolume; + // } + // } + } + } } diff --git a/API/Entities/Enums/AgeRating.cs b/API/Entities/Enums/AgeRating.cs index 390f5bd24..79cedb22e 100644 --- a/API/Entities/Enums/AgeRating.cs +++ b/API/Entities/Enums/AgeRating.cs @@ -2,6 +2,10 @@ namespace API.Entities.Enums; +/// +/// Represents Age Rating for content. +/// +/// Based on ComicInfo.xml v2.1 https://github.com/anansi-project/comicinfo/blob/main/drafts/v2.1/ComicInfo.xsd public enum AgeRating { [Description("Unknown")] @@ -20,15 +24,15 @@ public enum AgeRating KidsToAdults = 6, [Description("Teen")] Teen = 7, - [Description("Mature 15+")] + [Description("MA 15+")] Mature15Plus = 8, [Description("Mature 17+")] Mature17Plus = 9, - [Description("Mature")] + [Description("M")] Mature = 10, [Description("Adults Only 18+")] AdultsOnly = 11, - [Description("X 18+")] + [Description("X18+")] X18Plus = 12 diff --git a/API/Services/ArchiveService.cs b/API/Services/ArchiveService.cs index 76f7d7283..11042ed34 100644 --- a/API/Services/ArchiveService.cs +++ b/API/Services/ArchiveService.cs @@ -142,10 +142,39 @@ namespace API.Services /// Entry name of match, null if no match public static string? FirstFileEntry(IEnumerable entryFullNames, string archiveName) { - var result = entryFullNames + // First check if there are any files that are not in a nested folder before just comparing by filename. This is needed + // because NaturalSortComparer does not work with paths and doesn't seem 001.jpg as before chapter 1/001.jpg. + var fullNames = entryFullNames .OrderByNatural(c => c.GetFullPathWithoutExtension()) - .Where(path => !(Path.EndsInDirectorySeparator(path) || Parser.Parser.HasBlacklistedFolderInPath(path) || path.StartsWith(Parser.Parser.MacOsMetadataFileStartsWith))) - .FirstOrDefault(path => Parser.Parser.IsImage(path)); + .Where(path => !(Path.EndsInDirectorySeparator(path) || Parser.Parser.HasBlacklistedFolderInPath(path) || path.StartsWith(Parser.Parser.MacOsMetadataFileStartsWith)) && Parser.Parser.IsImage(path)) + .ToList(); + if (fullNames.Count == 0) return null; + + var nonNestedFile = fullNames.Where(entry => (Path.GetDirectoryName(entry) ?? string.Empty).Equals(archiveName)) + .OrderByNatural(c => c.GetFullPathWithoutExtension()) + .FirstOrDefault(); + + if (!string.IsNullOrEmpty(nonNestedFile)) return nonNestedFile; + + // Check the first folder and sort within that to see if we can find a file, else fallback to first file with basic sort. + // Get first folder, then sort within that + var firstDirectoryFile = fullNames.OrderByNatural(Path.GetDirectoryName).FirstOrDefault(); + if (!string.IsNullOrEmpty(firstDirectoryFile)) + { + var firstDirectory = Path.GetDirectoryName(firstDirectoryFile); + if (!string.IsNullOrEmpty(firstDirectory)) + { + var firstDirectoryResult = fullNames.Where(f => firstDirectory.Equals(Path.GetDirectoryName(f))) + .OrderByNatural(Path.GetFileNameWithoutExtension) + .FirstOrDefault(); + + if (!string.IsNullOrEmpty(firstDirectoryResult)) return firstDirectoryResult; + } + } + + var result = fullNames + .OrderByNatural(Path.GetFileNameWithoutExtension) + .FirstOrDefault(); return string.IsNullOrEmpty(result) ? null : result; } @@ -235,6 +264,13 @@ namespace API.Services } // TODO: Refactor CreateZipForDownload to return the temp file so we can stream it from temp + /// + /// + /// + /// + /// Temp folder name to use for preparing the files. Will be created and deleted + /// + /// public async Task> CreateZipForDownload(IEnumerable files, string tempFolder) { var dateString = DateTime.Now.ToShortDateString().Replace("/", "_"); @@ -309,30 +345,6 @@ namespace API.Services return null; } - public static void CleanComicInfo(ComicInfo info) - { - if (info == null) return; - - info.Writer = Parser.Parser.CleanAuthor(info.Writer); - info.Colorist = Parser.Parser.CleanAuthor(info.Colorist); - info.Editor = Parser.Parser.CleanAuthor(info.Editor); - info.Inker = Parser.Parser.CleanAuthor(info.Inker); - info.Letterer = Parser.Parser.CleanAuthor(info.Letterer); - info.Penciller = Parser.Parser.CleanAuthor(info.Penciller); - info.Publisher = Parser.Parser.CleanAuthor(info.Publisher); - info.Characters = Parser.Parser.CleanAuthor(info.Characters); - - // if (!string.IsNullOrEmpty(info.Web)) - // { - // // ComicVine stores the Issue number in Number field and does not use Volume. - // if (!info.Web.Contains("https://comicvine.gamespot.com/")) return; - // if (info.Volume.Equals("1")) - // { - // info.Volume = Parser.Parser.DefaultVolume; - // } - // } - } - /// /// This can be null if nothing is found or any errors occur during access /// @@ -363,7 +375,7 @@ namespace API.Services using var stream = entry.Open(); var serializer = new XmlSerializer(typeof(ComicInfo)); var info = (ComicInfo) serializer.Deserialize(stream); - CleanComicInfo(info); + ComicInfo.CleanComicInfo(info); return info; } @@ -383,7 +395,7 @@ namespace API.Services .Parser .MacOsMetadataFileStartsWith) && Parser.Parser.IsXml(entry.Key))); - CleanComicInfo(info); + ComicInfo.CleanComicInfo(info); return info; } diff --git a/API/Services/Tasks/BackupService.cs b/API/Services/Tasks/BackupService.cs index eaf5d0fda..12f4f1083 100644 --- a/API/Services/Tasks/BackupService.cs +++ b/API/Services/Tasks/BackupService.cs @@ -62,6 +62,8 @@ public class BackupService : IBackupService { _backupFiles.Add(file); } + + } public IEnumerable GetLogFiles(int maxRollingFiles, string logFileName) @@ -114,6 +116,10 @@ public class BackupService : IBackupService await CopyCoverImagesToBackupDirectory(tempDirectory); + await SendProgress(0.5F); + + await CopyBookmarksToBackupDirectory(tempDirectory); + await SendProgress(0.75F); try @@ -154,7 +160,30 @@ public class BackupService : IBackupService // Swallow exception. This can be a duplicate cover being copied as chapter and volumes can share same file. } - if (!_directoryService.GetFiles(outputTempDir).Any()) + if (!_directoryService.GetFiles(outputTempDir, searchOption: SearchOption.AllDirectories).Any()) + { + _directoryService.ClearAndDeleteDirectory(outputTempDir); + } + } + + private async Task CopyBookmarksToBackupDirectory(string tempDirectory) + { + var bookmarkDirectory = + (await _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.BookmarkDirectory)).Value; + + var outputTempDir = Path.Join(tempDirectory, "bookmarks"); + _directoryService.ExistOrCreate(outputTempDir); + + try + { + _directoryService.CopyDirectoryToDirectory(bookmarkDirectory, outputTempDir); + } + catch (IOException) + { + // Swallow exception. + } + + if (!_directoryService.GetFiles(outputTempDir, searchOption: SearchOption.AllDirectories).Any()) { _directoryService.ClearAndDeleteDirectory(outputTempDir); } diff --git a/API/Services/Tasks/ScannerService.cs b/API/Services/Tasks/ScannerService.cs index c3508f541..7c6a51f2c 100644 --- a/API/Services/Tasks/ScannerService.cs +++ b/API/Services/Tasks/ScannerService.cs @@ -227,6 +227,8 @@ public class ScannerService : IScannerService if (library.Folders.Any(f => !_directoryService.IsDriveMounted(f.Path))) { _logger.LogCritical("Some of the root folders for library are not accessible. Please check that drives are connected and rescan. Scan will be aborted"); + await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress, + MessageFactory.ScanLibraryProgressEvent(libraryId, 1F)); return; } @@ -237,6 +239,8 @@ public class ScannerService : IScannerService "Either your mount has been disconnected or you are trying to delete all series in the library. " + "Scan will be aborted. " + "Check that your mount is connected or change the library's root folder and rescan"); + await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress, + MessageFactory.ScanLibraryProgressEvent(libraryId, 1F)); return; } @@ -271,9 +275,9 @@ public class ScannerService : IScannerService await CleanupDbEntities(); - BackgroundJob.Enqueue(() => _metadataService.RefreshMetadata(libraryId, false)); await _messageHub.Clients.All.SendAsync(SignalREvents.ScanLibraryProgress, MessageFactory.ScanLibraryProgressEvent(libraryId, 1F)); + BackgroundJob.Enqueue(() => _metadataService.RefreshMetadata(libraryId, false)); } /// diff --git a/UI/Web/src/app/_services/action-factory.service.ts b/UI/Web/src/app/_services/action-factory.service.ts index 0df929e8f..a0d1609ff 100644 --- a/UI/Web/src/app/_services/action-factory.service.ts +++ b/UI/Web/src/app/_services/action-factory.service.ts @@ -79,7 +79,7 @@ export class ActionFactoryService { this.seriesActions.push({ action: Action.RefreshMetadata, - title: 'Refresh Metadata', + title: 'Refresh Covers', callback: this.dummyCallback, requiresAdmin: true }); @@ -114,7 +114,7 @@ export class ActionFactoryService { this.libraryActions.push({ action: Action.RefreshMetadata, - title: 'Refresh Metadata', + title: 'Refresh Covers', callback: this.dummyCallback, requiresAdmin: true }); diff --git a/UI/Web/src/app/_services/action.service.ts b/UI/Web/src/app/_services/action.service.ts index 8b4235797..66615388c 100644 --- a/UI/Web/src/app/_services/action.service.ts +++ b/UI/Web/src/app/_services/action.service.ts @@ -76,7 +76,7 @@ export class ActionService implements OnDestroy { return; } - if (!await this.confirmService.confirm('Refresh metadata will force all cover images and metadata to be recalculated. This is a heavy operation. Are you sure you don\'t want to perform a Scan instead?')) { + if (!await this.confirmService.confirm('Refresh covers will force all cover images to be recalculated. This is a heavy operation. Are you sure you don\'t want to perform a Scan instead?')) { if (callback) { callback(library); } @@ -141,7 +141,7 @@ export class ActionService implements OnDestroy { * @param callback Optional callback to perform actions after API completes */ async refreshMetdata(series: Series, callback?: SeriesActionCallback) { - if (!await this.confirmService.confirm('Refresh metadata will force all cover images and metadata to be recalculated. This is a heavy operation. Are you sure you don\'t want to perform a Scan instead?')) { + if (!await this.confirmService.confirm('Refresh covers will force all cover images and metadata to be recalculated. This is a heavy operation. Are you sure you don\'t want to perform a Scan instead?')) { if (callback) { callback(series); } diff --git a/UI/Web/src/app/_services/reading-list.service.ts b/UI/Web/src/app/_services/reading-list.service.ts index e520154d6..3ad5255f6 100644 --- a/UI/Web/src/app/_services/reading-list.service.ts +++ b/UI/Web/src/app/_services/reading-list.service.ts @@ -75,7 +75,7 @@ export class ReadingListService { } removeRead(readingListId: number) { - return this.httpClient.post(this.baseUrl + 'readinglist/remove-read?readingListId=' + readingListId, { responseType: 'text' as 'json' }); + return this.httpClient.post(this.baseUrl + 'readinglist/remove-read?readingListId=' + readingListId, {}, { responseType: 'text' as 'json' }); } actionListFilter(action: ActionItem, readingList: ReadingList, isAdmin: boolean) { diff --git a/UI/Web/src/app/admin/manage-library/manage-library.component.ts b/UI/Web/src/app/admin/manage-library/manage-library.component.ts index d7a694ac1..d6e5a2364 100644 --- a/UI/Web/src/app/admin/manage-library/manage-library.component.ts +++ b/UI/Web/src/app/admin/manage-library/manage-library.component.ts @@ -39,14 +39,16 @@ export class ManageLibraryComponent implements OnInit, OnDestroy { // when a progress event comes in, show it on the UI next to library this.hubService.messages$.pipe(takeUntil(this.onDestroy)).subscribe((event) => { if (event.event !== EVENTS.ScanLibraryProgress) return; + + console.log('scan event: ', event.payload); const scanEvent = event.payload as ProgressEvent; - this.scanInProgress[scanEvent.libraryId] = {progress: scanEvent.progress !== 100}; + this.scanInProgress[scanEvent.libraryId] = {progress: scanEvent.progress !== 1}; if (scanEvent.progress === 0) { this.scanInProgress[scanEvent.libraryId].timestamp = scanEvent.eventTime; } - if (this.scanInProgress[scanEvent.libraryId].progress === false && scanEvent.progress === 100) { + if (this.scanInProgress[scanEvent.libraryId].progress === false && scanEvent.progress === 1) { this.libraryService.getLibraries().pipe(take(1)).subscribe(libraries => { const newLibrary = libraries.find(lib => lib.id === scanEvent.libraryId); const existingLibrary = this.libraries.find(lib => lib.id === scanEvent.libraryId); diff --git a/UI/Web/src/app/book-reader/book-reader/book-reader.component.html b/UI/Web/src/app/book-reader/book-reader/book-reader.component.html index fb98db171..05c76eabb 100644 --- a/UI/Web/src/app/book-reader/book-reader/book-reader.component.html +++ b/UI/Web/src/app/book-reader/book-reader/book-reader.component.html @@ -1,4 +1,4 @@ -
+
Skip to main content diff --git a/UI/Web/src/app/book-reader/book-reader/book-reader.component.scss b/UI/Web/src/app/book-reader/book-reader/book-reader.component.scss index 65de3db54..12823f996 100644 --- a/UI/Web/src/app/book-reader/book-reader/book-reader.component.scss +++ b/UI/Web/src/app/book-reader/book-reader/book-reader.component.scss @@ -161,6 +161,7 @@ $primary-color: #0062cc; .reader-container { outline: none; // Only the reading section itself shouldn't receive any outline. We use it to shift focus in fullscreen mode + overflow: auto; } .book-content { diff --git a/UI/Web/src/app/book-reader/book-reader/book-reader.component.ts b/UI/Web/src/app/book-reader/book-reader/book-reader.component.ts index 39e0cc637..74120972e 100644 --- a/UI/Web/src/app/book-reader/book-reader/book-reader.component.ts +++ b/UI/Web/src/app/book-reader/book-reader/book-reader.component.ts @@ -748,11 +748,8 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { this.scrollService.scrollTo(0, this.reader.nativeElement); } - // On fullscreen we need to click the document before arrow keys will scroll down. - if (this.isFullscreen) { - this.renderer.setAttribute(this.reader.nativeElement, 'tabIndex', '0'); - this.reader.nativeElement.focus(); - } + // we need to click the document before arrow keys will scroll down. + this.reader.nativeElement.focus(); } setPageNum(pageNum: number) { @@ -888,6 +885,20 @@ export class BookReaderComponent implements OnInit, AfterViewInit, OnDestroy { } this.renderer.setStyle(this.readingHtml.nativeElement, item[0], item[1], RendererStyleFlags2.Important); }); + + for(let i = 0; i < this.readingHtml.nativeElement.children.length; i++) { + const elem = this.readingHtml.nativeElement.children.item(i); + if (elem?.tagName === 'STYLE') continue; + Object.entries(this.pageStyles).forEach(item => { + if (item[1] == '100%' || item[1] == '0px' || item[1] == 'inherit') { + // Remove the style or skip + this.renderer.removeStyle(elem, item[0]); + return; + } + this.renderer.setStyle(elem, item[0], item[1], RendererStyleFlags2.Important); + }); + + } } } diff --git a/UI/Web/src/app/collections/collection-detail/collection-detail.component.ts b/UI/Web/src/app/collections/collection-detail/collection-detail.component.ts index b32cfc6fe..02f897451 100644 --- a/UI/Web/src/app/collections/collection-detail/collection-detail.component.ts +++ b/UI/Web/src/app/collections/collection-detail/collection-detail.component.ts @@ -151,7 +151,6 @@ export class CollectionDetailComponent implements OnInit, OnDestroy { this.collectionTag = matchingTags[0]; this.tagImage = this.imageService.randomize(this.imageService.getCollectionCoverImage(this.collectionTag.id)); this.titleService.setTitle('Kavita - ' + this.collectionTag.title + ' Collection'); - this.loadPage(); }); } diff --git a/UI/Web/src/app/library-detail/library-detail.component.ts b/UI/Web/src/app/library-detail/library-detail.component.ts index 103cf2ecb..13fc0e885 100644 --- a/UI/Web/src/app/library-detail/library-detail.component.ts +++ b/UI/Web/src/app/library-detail/library-detail.component.ts @@ -93,7 +93,7 @@ export class LibraryDetailComponent implements OnInit, OnDestroy { [this.filterSettings.presets, this.filterSettings.openByDefault] = this.utilityService.filterPresetsFromUrl(this.route.snapshot, this.seriesService.createSeriesFilter()); this.filterSettings.presets.libraries = [this.libraryId]; - this.loadPage(); + //this.loadPage(); } ngOnInit(): void { @@ -140,7 +140,6 @@ export class LibraryDetailComponent implements OnInit, OnDestroy { updateFilter(data: SeriesFilter) { this.filter = data; - console.log('filter: ', this.filter); if (this.pagination !== undefined && this.pagination !== null) { this.pagination.currentPage = 1; this.onPageChange(this.pagination); @@ -171,7 +170,7 @@ export class LibraryDetailComponent implements OnInit, OnDestroy { } onPageChange(pagination: Pagination) { - window.history.replaceState(window.location.href, '', window.location.href.split('?')[0] + '?page=' + this.pagination.currentPage); + window.history.replaceState(window.location.href, '', window.location.href.split('?')[0] + '?' + 'page=' + this.pagination.currentPage); this.loadPage(); } diff --git a/UI/Web/src/app/manga-reader/infinite-scroller/infinite-scroller.component.html b/UI/Web/src/app/manga-reader/infinite-scroller/infinite-scroller.component.html index 6bc608c11..a2c1f61e1 100644 --- a/UI/Web/src/app/manga-reader/infinite-scroller/infinite-scroller.component.html +++ b/UI/Web/src/app/manga-reader/infinite-scroller/infinite-scroller.component.html @@ -26,7 +26,10 @@
- image + image