Skip to content

Commit 82a7ed3

Browse files
authored
Merge pull request #38 from chytanka/develop
Develop
2 parents 9233eb5 + 2beeb4f commit 82a7ed3

File tree

54 files changed

+659
-330
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+659
-330
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
Chytanka supports opening episodes from the following platforms:
1010

1111
- [x] ~~[Blankary](https://blankary.com)~~ (image support has been discontinued)
12-
- [x] [Comick](https://comick.io)
12+
- [x] ~~[Comick](https://comick.io)~~ (baned)
1313
- [x] [Imgur](https://imgur.com)
1414
- [x] [Mangadex](https://mangadex.org)
1515
- [x] [Nhentai](https://nhentai.net)

src/app/app.component.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { Component, HostListener, PLATFORM_ID, WritableSignal, inject, signal } from '@angular/core';
1+
import { Component, HostListener, PLATFORM_ID, WritableSignal, effect, inject, signal } from '@angular/core';
22
import { LangService } from './shared/data-access/lang.service';
33
import { ActivatedRoute } from '@angular/router';
44
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
55
import { environment } from '../environments/environment';
6+
import { DISPLAY_MODES, LinkParserSettingsService } from './link-parser/data-access/link-parser-settings.service';
67

78
const SCALE_GAP = 128;
89

@@ -15,14 +16,16 @@ const SCALE_GAP = 128;
1516
export class AppComponent {
1617
private readonly document = inject(DOCUMENT);
1718
platformId = inject(PLATFORM_ID)
19+
setts = inject(LinkParserSettingsService)
20+
1821

1922
constructor(public lang: LangService, private route: ActivatedRoute) {
2023
this.lang.updateManifest()
2124
this.lang.updateTranslate()
2225

2326
this.route.pathFromRoot[0].queryParams.subscribe(async q => {
2427
const l = q['lang']
25-
28+
2629
if (l) {
2730
this.lang.setLang(l)
2831
}
@@ -37,11 +40,25 @@ export class AppComponent {
3740
console.log(`%c${msg}`, "background-color: #166496; color: #ffd60a; font-size: 4rem; font-family: monospace; padding: 8px 16px");
3841
}
3942

40-
43+
effect(() => {
44+
this.updateDisplayMode();
45+
});
4146
}
4247

4348
ngOnInit() {
4449
this.initScaleDifference();
50+
this.updateDisplayMode();
51+
}
52+
53+
updateDisplayMode() {
54+
if (this.setts.displayMode != undefined) {
55+
for (const mode of DISPLAY_MODES) {
56+
this.document.documentElement.classList.remove(mode);
57+
}
58+
this.document.documentElement.classList.add(this.setts.displayMode() + 'mode');
59+
60+
}
61+
4562
}
4663

4764
@HostListener('window:resize')
Lines changed: 19 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
/// <reference lib="webworker" />
22

3+
// TODO: change to https://github.com/101arrowz/fflate
4+
// because jszip is toooo slow
5+
// https://chatgpt.com/c/68cadcf9-6c28-8329-add8-cb20abaa2f85
6+
37
import JSZip from 'jszip';
8+
import { filterImages, getAcbfFile, getComicInfoFile, processFile, processImagesInBatches } from '../utils';
9+
10+
const metadataFiles = [
11+
{ getter: getComicInfoFile, type: 'comicinfo' },
12+
{ getter: getAcbfFile, type: 'acbf' },
13+
];
414

515
addEventListener('message', ({ data }) => {
616
const arrayBuffer = data.arrayBuffer;
@@ -11,59 +21,19 @@ addEventListener('message', ({ data }) => {
1121
.then(async zip => {
1222
const filesName: string[] = Object.keys(zip.files);
1323

14-
// console.dir(zip.files)
15-
16-
const comicInfoFile = getComicInfoFile(filesName)
17-
18-
if (comicInfoFile) {
19-
const comicinfo = zip.files[comicInfoFile]
20-
await comicinfo.async('text').then(text => { postMessage({ type: 'comicinfo', data: text }); })
21-
}
24+
console.log(filesName);
25+
2226

23-
const acbf = getAcbfFile(filesName)
24-
if (acbf) {
25-
const acbfF = zip.files[acbf]
26-
await acbfF.async('text').then(text => { postMessage({ type: 'acbf', data: text }); })
27+
// metadata
28+
for (const { getter, type } of metadataFiles) {
29+
await processFile(getter(filesName), zip, type);
2730
}
2831

29-
const images = filterImages(filesName).sort()
32+
// images
33+
const images = filterImages(filesName).sort();
3034
postMessage({ type: 'zipopen', data: { count: images.length } });
3135

32-
for (let i = 0; i < images.length; i++) {
33-
const filename = images[i];
34-
35-
await zip.files[filename].async('blob').then(blob => {
36-
const url = URL.createObjectURL(blob);
37-
postMessage({ type: 'file', url: url, index: i });
38-
});
39-
}
40-
36+
await processImagesInBatches(zip, images, 30);
4137

4238
});
43-
});
44-
45-
function filterImages(fileList: Array<string>) {
46-
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp'];
47-
48-
return fileList.filter(file => {
49-
const extension = file.substring(file.lastIndexOf('.')).toLowerCase();
50-
return imageExtensions.includes(extension);
51-
});
52-
}
53-
54-
function getComicInfoFile(fileList: Array<string>) {
55-
const resultArray = fileList.filter(f => f.toLowerCase() == 'comicinfo.xml')
56-
57-
return resultArray.length > 0 ? resultArray[0] : false
58-
}
59-
60-
function getAcbfFile(fileList: Array<string>) {
61-
const imageExtensions = ['.acbf'];
62-
63-
const result = fileList.filter(file => {
64-
const extension = file.substring(file.lastIndexOf('.')).toLowerCase();
65-
return imageExtensions.includes(extension);
66-
})
67-
68-
return result.length > 0 ? result[0] : null;
69-
}
39+
});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export function getComicInfoFile(fileList: Array<string>) {
2+
const resultArray = fileList.filter(f => f.toLowerCase() == 'comicinfo.xml')
3+
4+
return resultArray.length > 0 ? resultArray[0] : false
5+
}
6+
7+
export function getAcbfFile(fileList: Array<string>) {
8+
const imageExtensions = ['.acbf'];
9+
10+
const result = fileList.filter(file => {
11+
const extension = file.substring(file.lastIndexOf('.')).toLowerCase();
12+
return imageExtensions.includes(extension);
13+
})
14+
15+
return result.length > 0 ? result[0] : null;
16+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export function filterImages(fileList: Array<string>) {
2+
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp'];
3+
4+
return fileList.filter(file => {
5+
const extension = file.substring(file.lastIndexOf('.')).toLowerCase();
6+
return imageExtensions.includes(extension);
7+
});
8+
}

src/app/file/utils/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export * from './filter-images';
2+
export * from './comic-metadata-files';
3+
export * from './process-file';
4+
export * from './process-images-in-batches';

src/app/file/utils/process-file.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export async function processFile(
2+
fileName: string | false | null,
3+
zip: any,
4+
type: string
5+
) {
6+
if (!fileName) return;
7+
8+
const file = zip.files[fileName];
9+
if (!file) return;
10+
11+
const text = await file.async('text');
12+
postMessage({ type, data: text });
13+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import JSZip from "jszip";
2+
3+
export async function processImagesInBatches(
4+
zip: JSZip,
5+
images: string[],
6+
batchSize = 20
7+
) {
8+
for (let i = 0; i < images.length; i += batchSize) {
9+
const batch = images.slice(i, i + batchSize);
10+
11+
await Promise.all(
12+
batch.map(async (filename, index) => {
13+
const blob = await zip.files[filename].async('blob');
14+
const url = URL.createObjectURL(blob);
15+
postMessage({
16+
type: 'file',
17+
url,
18+
index: i + index,
19+
});
20+
})
21+
);
22+
}
23+
}

src/app/history/ui/history-list/history-list.component.html

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
@let sites = historyItems() | async;
33

44
@if (sites && sites.length > 0) {
5-
<details>
5+
<details name="history">
66
<summary>
77
<span>SITES HISTORY</span>
88
@if ( sites.length > 0) {
@@ -21,8 +21,8 @@
2121
}
2222

2323
@if (files && files.length > 0) {
24-
<details open>
25-
<summary>
24+
<details open name="history">
25+
<summary [vibrateHaptic]="10">
2626
<span>FILES HISTORY</span> |
2727
<code>{{fileSize() | filesize}}</code> |
2828
<code>{{fileCount()}}</code>
@@ -35,7 +35,7 @@
3535

3636
<div class="wrap">
3737
@for (item of files; track item.sha256;) {
38-
@let ab = item.arrayBuffer;
38+
@let ab = item.arrayBuffer;
3939
<div>
4040
<app-title-card [value]="{
4141
site: (ab) ? ['file', item.format] : '',
@@ -55,5 +55,6 @@
5555
}
5656

5757
@if (files?.length ==0 && sites?.length ==0) {
58-
none
58+
<h2>{{lang.ph().historyEmpty}}</h2>
59+
<p>{{lang.ph().histyryEmptyDesc}}</p>
5960
}

src/app/history/ui/history-list/history-list.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { FileHistoryService } from '../../../file/data-access/file-history.servi
66
@Component({
77
selector: 'app-history-list',
88
templateUrl: './history-list.component.html',
9-
styleUrl: './history-list.component.scss',
9+
styleUrls: ['./history-list.component.scss', '../../../shared/ui/@styles/details.scss'],
1010
standalone: false
1111
})
1212
export class HistoryListComponent {

0 commit comments

Comments
 (0)