diff --git a/apps/NwaifuAnime/src/app/app.routes.ts b/apps/NwaifuAnime/src/app/app.routes.ts index c92235c..58f6c8e 100644 --- a/apps/NwaifuAnime/src/app/app.routes.ts +++ b/apps/NwaifuAnime/src/app/app.routes.ts @@ -1,6 +1,7 @@ import { Route } from "@angular/router"; import { DetailComponent } from "./components/detail/detail.component"; import { HomeComponent } from "./components/home/home.component"; +import { ReaderComponent } from "./components/reader/reader.component"; export const appRoutes: Route[] = [ { @@ -8,4 +9,5 @@ export const appRoutes: Route[] = [ component: HomeComponent, }, { path: "detail", component: DetailComponent }, + { path: "reader", component: ReaderComponent }, ]; diff --git a/apps/NwaifuAnime/src/app/components/detail/detail.component.html b/apps/NwaifuAnime/src/app/components/detail/detail.component.html index eab7076..0c401c0 100644 --- a/apps/NwaifuAnime/src/app/components/detail/detail.component.html +++ b/apps/NwaifuAnime/src/app/components/detail/detail.component.html @@ -1,4 +1,15 @@ -@if (detail_item) { -

{{ detail_item.name }}

-

{{ detail_item.rus_name }}

-} +
+ @if (detail_item) { +

{{ detail_item.name }}

+

{{ detail_item.rus_name }}

+ + @for (chapter of chapters.data; track $index) { +

+ {{ chapter.number }}. {{ chapter.name || "Нет названия" }} +

+ } + + } +
diff --git a/apps/NwaifuAnime/src/app/components/detail/detail.component.ts b/apps/NwaifuAnime/src/app/components/detail/detail.component.ts index 1e2e640..a831ed3 100644 --- a/apps/NwaifuAnime/src/app/components/detail/detail.component.ts +++ b/apps/NwaifuAnime/src/app/components/detail/detail.component.ts @@ -1,6 +1,7 @@ import { CommonModule } from "@angular/common"; import { AfterViewInit, Component } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; +import { IRulibChaptersResult } from "../../services/parsers/rulib/rulib.chapters.dto"; import { Data } from "../../services/parsers/rulib/rulib.detail.dto"; import { SearchService } from "../../services/search.service"; @@ -13,20 +14,41 @@ import { SearchService } from "../../services/search.service"; }) export class DetailComponent implements AfterViewInit { detail_item: Data | null = null; + chapters: IRulibChaptersResult = { data: [] }; constructor( private route: ActivatedRoute, private searchService: SearchService, private router: Router, ) {} + private getDetails(url: string) { + this.searchService.getDetails(url).subscribe((data) => { + this.detail_item = data.data; + }); + this.searchService.getChapters(url).subscribe((data) => { + this.chapters = data; + }); + } + ngAfterViewInit(): void { this.route.queryParams.subscribe((params) => { const url = params["url"]; if (url) { - this.searchService.getDetails(url).subscribe((data) => (this.detail_item = data.data)); + this.getDetails(url); } else { this.router.navigate(["/"]); } }); } + + goToReader() { + //TODO: Not only first chapter + this.router.navigate(["/", "reader"], { + queryParams: { + url: this.detail_item?.slug_url, + chapter: this.chapters.data[0].number, + volume: this.chapters.data[0].volume, + }, + }); + } } diff --git a/apps/NwaifuAnime/src/app/components/header/header.component.html b/apps/NwaifuAnime/src/app/components/header/header.component.html index eeb7895..4740388 100644 --- a/apps/NwaifuAnime/src/app/components/header/header.component.html +++ b/apps/NwaifuAnime/src/app/components/header/header.component.html @@ -2,7 +2,7 @@ class="header fixed flex justify-between w-full p-2 bg-gray-700 md:h-8 h-auto items-center md:flex-row flex-col md:gap-0 gap-3" >
-

NwaifuAnime

+

NwaifuAnime

} diff --git a/apps/NwaifuAnime/src/app/components/reader/reader.component.html b/apps/NwaifuAnime/src/app/components/reader/reader.component.html new file mode 100644 index 0000000..d33d132 --- /dev/null +++ b/apps/NwaifuAnime/src/app/components/reader/reader.component.html @@ -0,0 +1,6 @@ +

It's reader page

+
+ @for (page of pages; track $index) { + + } +
diff --git a/apps/NwaifuAnime/src/app/components/reader/reader.component.less b/apps/NwaifuAnime/src/app/components/reader/reader.component.less new file mode 100644 index 0000000..e69de29 diff --git a/apps/NwaifuAnime/src/app/components/reader/reader.component.ts b/apps/NwaifuAnime/src/app/components/reader/reader.component.ts new file mode 100644 index 0000000..c9c1e17 --- /dev/null +++ b/apps/NwaifuAnime/src/app/components/reader/reader.component.ts @@ -0,0 +1,38 @@ +import { CommonModule } from "@angular/common"; +import { AfterViewInit, Component } from "@angular/core"; +import { ActivatedRoute, Router } from "@angular/router"; +import { Page } from "../../services/parsers/rulib/rulib.chapter.dto"; +import { SearchService } from "../../services/search.service"; + +@Component({ + selector: "app-reader", + templateUrl: "./reader.component.html", + styleUrls: ["./reader.component.less"], + standalone: true, + imports: [CommonModule], +}) +export class ReaderComponent implements AfterViewInit { + pages: Page[] = []; + constructor( + private route: ActivatedRoute, + private router: Router, + private searchService: SearchService, + ) {} + + ngAfterViewInit(): void { + this.route.queryParams.subscribe((params) => { + const url = params["url"]; + const chapter = params["chapter"]; + const volume = params["volume"]; + if (url && chapter && volume) { + this.searchService.getChapter(url, chapter, volume).subscribe((data) => { + this.pages = data.data.pages.map((page) => { + return { ...page, url: this.searchService.getImageServer() + page.url }; + }); + }); + } else { + this.router.navigate(["/"]); + } + }); + } +} diff --git a/apps/NwaifuAnime/src/app/services/parsers/rulib/lib.social.parser.service.ts b/apps/NwaifuAnime/src/app/services/parsers/rulib/lib.social.parser.service.ts index b1ac197..d50c2a2 100644 --- a/apps/NwaifuAnime/src/app/services/parsers/rulib/lib.social.parser.service.ts +++ b/apps/NwaifuAnime/src/app/services/parsers/rulib/lib.social.parser.service.ts @@ -2,6 +2,8 @@ import { HttpClient } from "@angular/common/http"; import { Injectable } from "@angular/core"; import { Observable, catchError, map, throwError } from "rxjs"; import { ESiteUrls } from "../urls"; +import { IRulibChapterResult } from "./rulib.chapter.dto"; +import { IRulibChaptersResult } from "./rulib.chapters.dto"; import { IRulibDetailResult } from "./rulib.detail.dto"; import { IRulibSearchResult } from "./rulib.search.dto"; @@ -13,6 +15,10 @@ export class LibSocialParserService { private readonly url = ESiteUrls.LIB_SOCIAL; constructor(private readonly http: HttpClient) {} + get imageServer() { + return "https://img33.imgslib.link"; + } + searchManga(query: string): Observable { return this.http .get(`${this.url}/api/manga?fields[]=rate_avg&fields[]=rate&q=${query}&site_id[]=1`) @@ -40,4 +46,24 @@ export class LibSocialParserService { }), ); } + + getChapters(url: string): Observable { + return this.http.get(`${this.url}/api/manga/${url}/chapters`).pipe( + map((data) => { + return data as IRulibChaptersResult; + }), + catchError((error) => { + return throwError(() => `Now found ${error}`); + }), + ); + } + + getChapter(url: string, chapter: string, volume: string): Observable { + return this.http + .get(`${this.url}/api/manga/${url}/chapter?number=${chapter}&volume=${volume}`) + .pipe( + map((data) => data as IRulibChapterResult), + catchError((error) => throwError(() => `Now found ${error}`)), + ); + } } diff --git a/apps/NwaifuAnime/src/app/services/parsers/rulib/rulib.chapter.dto.ts b/apps/NwaifuAnime/src/app/services/parsers/rulib/rulib.chapter.dto.ts new file mode 100644 index 0000000..eff79a6 --- /dev/null +++ b/apps/NwaifuAnime/src/app/services/parsers/rulib/rulib.chapter.dto.ts @@ -0,0 +1,62 @@ +export interface IRulibChapterResult { + data: Chapter; +} + +export interface Chapter { + id: number; + type: string; + volume: string; + number: string; + number_secondary: string; + name: string; + slug: string; + branch_id: null; + manga_id: number; + created_at: Date; + moderated: Moderated; + likes_count: number; + teams: Team[]; + pages: Page[]; +} + +export interface Moderated { + id: number; + label: string; +} + +export interface Page { + id: number; + image: string; + slug: number; + external: number; + chunks: number; + chapter_id: number; + created_at: Date; + updated_at: UpdatedAt; + height: number; + width: number; + url: string; + ratio: string; +} + +export enum UpdatedAt { + The0000011130T000000000000Z = "-000001-11-30T00:00:00.000000Z", +} + +export interface Team { + id: number; + slug: string; + slug_url: string; + model: string; + name: string; + cover: Cover; + vk: null; + discord: null; +} + +export interface Cover { + filename: null; + thumbnail: string; + default: string; + md: string; +} diff --git a/apps/NwaifuAnime/src/app/services/parsers/rulib/rulib.chapters.dto.ts b/apps/NwaifuAnime/src/app/services/parsers/rulib/rulib.chapters.dto.ts new file mode 100644 index 0000000..ef486ea --- /dev/null +++ b/apps/NwaifuAnime/src/app/services/parsers/rulib/rulib.chapters.dto.ts @@ -0,0 +1,85 @@ +export interface IRulibChaptersResult { + data: IRulibChapter[]; +} + +export interface IRulibChapter { + id: number; + index: number; + item_number: number; + volume: string; + number: string; + number_secondary: string; + name: string; + branches_count: number; + branches: Branch[]; +} + +export interface Branch { + id: number; + branch_id: null; + created_at: Date; + teams: Team[]; + user: User; +} + +export interface Team { + id: number; + slug: Slug; + slug_url: SlugURL; + model: Model; + name: Name; + cover: Cover; +} + +export interface Cover { + filename: null | string; + thumbnail: Thumbnail; + default: Default; + md: Default; +} + +export enum Default { + StaticImagesPlaceholdersUserAvatarPNG = "/static/images/placeholders/user_avatar.png", + UploadsTeamAnyasyavaCoverJSazXO7JdAKV250X350Jpg = "/uploads/team/anyasyava/cover/jSazXO7JdAKV_250x350.jpg", +} + +export enum Thumbnail { + StaticImagesPlaceholdersUserAvatarPNG = "/static/images/placeholders/user_avatar.png", + UploadsTeamAnyasyavaCoverJSazXO7JdAKVThumbJpg = "/uploads/team/anyasyava/cover/jSazXO7JdAKV_thumb.jpg", +} + +export enum Model { + Team = "team", +} + +export enum Name { + Abame = "abame", + Anyasyava = "ANYASYAVA", + Cabel = "Cabel", + Deadvm = "deadvm", +} + +export enum Slug { + Abame = "abame", + Anyasyava = "anyasyava", + Cabel = "cabel", + Deadvm = "deadvm", +} + +export enum SlugURL { + The13801Anyasyava = "13801--anyasyava", + The33106Abame = "33106--abame", + The42374Cabel = "42374--cabel", + The45635Deadvm = "45635--deadvm", +} + +export interface User { + username: Username; + id: number; +} + +export enum Username { + Deadvm = "deadvm", + Gjunyaa = "gjunyaa ❤️\ud83e\ude79", + Oksas = "oksas", +} diff --git a/apps/NwaifuAnime/src/app/services/search.service.ts b/apps/NwaifuAnime/src/app/services/search.service.ts index 1636d56..8682415 100644 --- a/apps/NwaifuAnime/src/app/services/search.service.ts +++ b/apps/NwaifuAnime/src/app/services/search.service.ts @@ -1,6 +1,8 @@ import { Injectable } from "@angular/core"; import { BehaviorSubject, Observable, map } from "rxjs"; import { LibSocialParserService } from "./parsers/rulib/lib.social.parser.service"; +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"; @@ -23,4 +25,24 @@ export class SearchService { }), ); } + + getChapters(url: string): Observable { + return this.parser.getChapters(url).pipe( + map((data) => { + return data; + }), + ); + } + + getChapter(url: string, chapter: string, volume: string): Observable { + return this.parser.getChapter(url, chapter, volume).pipe( + map((data) => { + return data; + }), + ); + } + + getImageServer() { + return this.parser.imageServer; + } }