diff --git a/apps/NwaifuAnime/src/app/components/reader/reader.component.html b/apps/NwaifuAnime/src/app/components/reader/reader.component.html
index c925604..d117c31 100644
--- a/apps/NwaifuAnime/src/app/components/reader/reader.component.html
+++ b/apps/NwaifuAnime/src/app/components/reader/reader.component.html
@@ -1,11 +1,11 @@
-
It's reader page
+It's reader page
@if(pages.length > 0){
-
![]()
-
-
-
{{pages[currentPageIndex].slug}} / {{pages.length}}
-
-
- }
+
![]()
+
+
+
{{pages[currentPageIndex]?.slug}} / {{pages.length}}
+
+
+}
\ No newline at end of file
diff --git a/apps/NwaifuAnime/src/app/components/reader/reader.component.ts b/apps/NwaifuAnime/src/app/components/reader/reader.component.ts
index c3a6f7c..a5d69dd 100644
--- a/apps/NwaifuAnime/src/app/components/reader/reader.component.ts
+++ b/apps/NwaifuAnime/src/app/components/reader/reader.component.ts
@@ -1,6 +1,7 @@
import { CommonModule } from "@angular/common";
-import { AfterViewInit, Component } from "@angular/core";
+import { AfterViewInit, Component, ElementRef, ViewChild } from "@angular/core";
import { ActivatedRoute, Router } from "@angular/router";
+import { Observable, map } from "rxjs";
import { Page } from "../../services/parsers/rulib/rulib.chapter.dto";
import { SearchService } from "../../services/search.service";
@@ -14,7 +15,8 @@ import { SearchService } from "../../services/search.service";
export class ReaderComponent implements AfterViewInit {
pages: Page[] = [];
currentPageIndex = 0;
- cachedPages: { [key: number]: Page } = {};
+ cachedPages: { [key: number]: Page & { imageData?: Uint8Array } } = {};
+ @ViewChild('mangaImage') mangaImage!: ElementRef;
constructor(
private route: ActivatedRoute,
@@ -38,44 +40,81 @@ export class ReaderComponent implements AfterViewInit {
loadChapter(url: string, chapter: string, volume: string) {
this.searchService.getChapter(url, chapter, volume).subscribe((data) => {
this.pages = data.data.pages;
- this.loadPage(0);
+ this.loadPage(0); // Загрузить первую страницу при открытии главы
});
}
loadPage(index: number) {
if (index >= 0 && index < this.pages.length) {
this.currentPageIndex = index;
- this.cachePages(index);
-
- if (!this.cachedPages[index]) {
- this.cachedPages[index] = {
- ...this.pages[index],
- url: this.searchService.getImageServer() + this.pages[index].url,
- };
+ this.cachePage(index); // Кэшируем текущую и соседние страницы
+ this.unloadCachedPages(index); // Сгружаем ненужные страницы из кэша
+ if (!this.cachedPages[index]?.imageData) {
+ // Если страница не закэширована, загружаем её
+ this.fetchAndCachePage(index).subscribe(() => {
+ this.updateImage();
+ });
+ } else {
+ // Если страница уже в кэше, просто обновляем изображение
+ this.updateImage();
}
}
}
- cachePages(currentIndex: number) {
- for (let i = 0; i <= currentIndex && i < this.pages.length; i++) {
- if (!this.cachedPages[i]) {
- this.cachedPages[i] = {
- ...this.pages[i],
- url: this.searchService.getImageServer() + this.pages[i].url,
- };
- }
- }
-
- for (let i = currentIndex + 1; i <= currentIndex + 3 && i < this.pages.length; i++) {
- if (!this.cachedPages[i]) {
- this.cachedPages[i] = {
- ...this.pages[i],
- url: this.searchService.getImageServer() + this.pages[i].url,
- };
+ // Кэширование текущей страницы и несколько соседних для ускорения процесса навигации по страницам
+ private cachePage(index: number) {
+ const startIndex = Math.max(0, index - 2);
+ const endIndex = Math.min(this.pages.length - 1, index + 2);
+
+ for (let i = startIndex; i <= endIndex; i++) {
+ if (!this.isPageCached(i)) {
+ this.fetchAndCachePage(i).subscribe(() => {
+ if (i === this.currentPageIndex) {
+ this.updateImage();
+ }
+ });
}
}
}
+ private isPageCached(index: number): boolean {
+ return !!this.cachedPages[index]?.imageData;
+ }
+
+ // Загрузка и сохранение изображения в кэш
+ private fetchAndCachePage(index: number): Observable {
+ return this.searchService
+ .getImageData(this.searchService.getImageServer() + this.pages[index].url)
+ .pipe(
+ map((imageData) => {
+ this.cachedPages[index] = {
+ ...this.pages[index],
+ imageData,
+ };
+ })
+ );
+ }
+
+ // Выгрузка из кэша старых страниц
+ private unloadCachedPages(index: number) {
+ for (const key in this.cachedPages) {
+ const pageIndex = parseInt(key, 10);
+ if (index - pageIndex > 2) {
+ delete this.cachedPages[pageIndex];
+ }
+ }
+ }
+
+ // Обновляем изображение на странице
+ private updateImage() {
+ const currentPage = this.cachedPages[this.currentPageIndex];
+ if (this.mangaImage?.nativeElement && currentPage?.imageData) {
+ const blob = new Blob([currentPage.imageData], { type: 'image/jpeg' });
+ const urlCreator = window.URL || window.webkitURL;
+ this.mangaImage.nativeElement.src = urlCreator.createObjectURL(blob);
+ }
+ }
+
nextPage() {
this.loadPage(this.currentPageIndex + 1);
}
diff --git a/apps/NwaifuAnime/src/app/services/search.service.ts b/apps/NwaifuAnime/src/app/services/search.service.ts
index 8682415..b427bc0 100644
--- a/apps/NwaifuAnime/src/app/services/search.service.ts
+++ b/apps/NwaifuAnime/src/app/services/search.service.ts
@@ -5,12 +5,16 @@ import { IRulibChapterResult } from "./parsers/rulib/rulib.chapter.dto";
import { IRulibChaptersResult } from "./parsers/rulib/rulib.chapters.dto";
import { IRulibDetailResult } from "./parsers/rulib/rulib.detail.dto";
import { Datum } from "./parsers/rulib/rulib.search.dto";
+import { HttpClient } from "@angular/common/http";
@Injectable({ providedIn: "root" })
export class SearchService {
private itemsTerm = new BehaviorSubject([]);
currentItemsTerm = this.itemsTerm.asObservable();
- constructor(private parser: LibSocialParserService) {}
+ constructor(
+ private parser: LibSocialParserService,
+ private http: HttpClient,
+ ) {}
search(query: string) {
this.parser.searchManga(query).subscribe((data) => {
@@ -45,4 +49,13 @@ export class SearchService {
getImageServer() {
return this.parser.imageServer;
}
+
+ getImageData(imageUrl: string): Observable{
+ return this.http.get(imageUrl, {responseType: 'arraybuffer'}).pipe(
+ map((arrayBuffer: ArrayBuffer) => {
+ return new Uint8Array(arrayBuffer);
+ })
+ );
+ }
+
}