@nemu.pm/tachiyomi-runtime 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -0
- package/dist/async/index.d.ts +15 -0
- package/dist/async/index.d.ts.map +1 -0
- package/dist/async/index.js +122 -0
- package/dist/async/index.js.map +1 -0
- package/dist/async/index.node.d.ts +14 -0
- package/dist/async/index.node.d.ts.map +1 -0
- package/dist/async/index.node.js +318 -0
- package/dist/async/index.node.js.map +1 -0
- package/dist/async/types.d.ts +68 -0
- package/dist/async/types.d.ts.map +1 -0
- package/dist/async/types.js +2 -0
- package/dist/async/types.js.map +1 -0
- package/dist/async/worker.d.ts +36 -0
- package/dist/async/worker.d.ts.map +1 -0
- package/dist/async/worker.js +337 -0
- package/dist/async/worker.js.map +1 -0
- package/dist/http/sync-node.d.ts +19 -0
- package/dist/http/sync-node.d.ts.map +1 -0
- package/dist/http/sync-node.js +99 -0
- package/dist/http/sync-node.js.map +1 -0
- package/dist/http/sync-xhr.d.ts +18 -0
- package/dist/http/sync-xhr.d.ts.map +1 -0
- package/dist/http/sync-xhr.js +68 -0
- package/dist/http/sync-xhr.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +33 -2
- package/src/async/index.node.ts +376 -0
- package/src/async/index.ts +179 -0
- package/src/async/types.ts +89 -0
- package/src/async/worker.ts +391 -0
- package/src/http/sync-node.ts +127 -0
- package/src/http/sync-xhr.ts +85 -0
- package/src/index.ts +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# @nemu.pm/tachiyomi-runtime
|
|
2
|
+
|
|
3
|
+
Runtime for loading and executing Tachiyomi extensions compiled to JavaScript.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add @nemu.pm/tachiyomi-runtime
|
|
9
|
+
# or
|
|
10
|
+
npm install @nemu.pm/tachiyomi-runtime
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { TachiyomiRuntime } from "@nemu.pm/tachiyomi-runtime";
|
|
17
|
+
|
|
18
|
+
const runtime = new TachiyomiRuntime();
|
|
19
|
+
const source = await runtime.loadExtension(extensionCode);
|
|
20
|
+
|
|
21
|
+
const mangas = source.getPopularManga(1);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Documentation
|
|
25
|
+
|
|
26
|
+
See the main repository for full documentation: https://github.com/nemu-pm/tachiyomi-js
|
|
27
|
+
|
|
28
|
+
## License
|
|
29
|
+
|
|
30
|
+
MIT
|
|
31
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { AsyncLoadOptions, LoadedExtension } from "./types";
|
|
2
|
+
import type { ExtensionManifest } from "../types";
|
|
3
|
+
export type { AsyncTachiyomiSource, AsyncLoadOptions, LoadedExtension } from "./types";
|
|
4
|
+
/**
|
|
5
|
+
* Load a Tachiyomi extension asynchronously (browser version)
|
|
6
|
+
*
|
|
7
|
+
* Creates a Web Worker internally to handle sync HTTP.
|
|
8
|
+
* Returns a LoadedExtension that can create sources.
|
|
9
|
+
*
|
|
10
|
+
* @param jsUrl - URL to the compiled extension JavaScript
|
|
11
|
+
* @param manifest - Extension manifest
|
|
12
|
+
* @param options - Proxy URL and preferences configuration
|
|
13
|
+
*/
|
|
14
|
+
export declare function loadExtension(jsUrl: string, manifest: ExtensionManifest, options?: AsyncLoadOptions): Promise<LoadedExtension>;
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/async/index.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAwB,gBAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AACvF,OAAO,KAAK,EAAE,iBAAiB,EAAc,MAAM,UAAU,CAAC;AAG9D,YAAY,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AASvF;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,CAwC1B"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser async runtime
|
|
3
|
+
*
|
|
4
|
+
* Creates a Web Worker internally, exposes clean async API.
|
|
5
|
+
* Consumer doesn't need to manage workers.
|
|
6
|
+
*/
|
|
7
|
+
import * as Comlink from "comlink";
|
|
8
|
+
// Cache loaded extensions (one worker per jsUrl)
|
|
9
|
+
const loadedExtensions = new Map();
|
|
10
|
+
/**
|
|
11
|
+
* Load a Tachiyomi extension asynchronously (browser version)
|
|
12
|
+
*
|
|
13
|
+
* Creates a Web Worker internally to handle sync HTTP.
|
|
14
|
+
* Returns a LoadedExtension that can create sources.
|
|
15
|
+
*
|
|
16
|
+
* @param jsUrl - URL to the compiled extension JavaScript
|
|
17
|
+
* @param manifest - Extension manifest
|
|
18
|
+
* @param options - Proxy URL and preferences configuration
|
|
19
|
+
*/
|
|
20
|
+
export async function loadExtension(jsUrl, manifest, options = {}) {
|
|
21
|
+
const { proxyUrl, preferences } = options;
|
|
22
|
+
// Check cache
|
|
23
|
+
const cached = loadedExtensions.get(jsUrl);
|
|
24
|
+
if (cached) {
|
|
25
|
+
return createLoadedExtension(cached.workerApi, cached.manifest, cached.worker, jsUrl);
|
|
26
|
+
}
|
|
27
|
+
// Create worker
|
|
28
|
+
const worker = new Worker(new URL("./worker.js", import.meta.url), { type: "module" });
|
|
29
|
+
// Wrap with Comlink
|
|
30
|
+
const workerApi = Comlink.wrap(worker);
|
|
31
|
+
// Initialize preferences if provided
|
|
32
|
+
if (preferences) {
|
|
33
|
+
await workerApi.initPreferences(preferences.name, preferences.values);
|
|
34
|
+
}
|
|
35
|
+
// Load extension in worker
|
|
36
|
+
const result = await workerApi.load(jsUrl, manifest, proxyUrl ?? null);
|
|
37
|
+
if (!result.success || !result.manifest) {
|
|
38
|
+
worker.terminate();
|
|
39
|
+
throw new Error(`Failed to load Tachiyomi extension: ${manifest.name}`);
|
|
40
|
+
}
|
|
41
|
+
// Cache
|
|
42
|
+
const ext = { worker, workerApi, manifest: result.manifest };
|
|
43
|
+
loadedExtensions.set(jsUrl, ext);
|
|
44
|
+
return createLoadedExtension(workerApi, result.manifest, worker, jsUrl);
|
|
45
|
+
}
|
|
46
|
+
function createLoadedExtension(workerApi, manifest, worker, jsUrl) {
|
|
47
|
+
const sources = manifest.sources ?? [];
|
|
48
|
+
return {
|
|
49
|
+
manifest,
|
|
50
|
+
sources,
|
|
51
|
+
getSource(sourceId) {
|
|
52
|
+
const sourceInfo = sources.find(s => s.id === sourceId);
|
|
53
|
+
if (!sourceInfo) {
|
|
54
|
+
throw new Error(`Source not found: ${sourceId} in ${manifest.name}`);
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
sourceId,
|
|
58
|
+
sourceInfo,
|
|
59
|
+
manifest,
|
|
60
|
+
// Filter methods
|
|
61
|
+
async getFilterList() {
|
|
62
|
+
return workerApi.getFilterList(sourceId);
|
|
63
|
+
},
|
|
64
|
+
async resetFilters() {
|
|
65
|
+
return workerApi.resetFilters(sourceId);
|
|
66
|
+
},
|
|
67
|
+
async applyFilterState(filterStateJson) {
|
|
68
|
+
return workerApi.applyFilterState(sourceId, filterStateJson);
|
|
69
|
+
},
|
|
70
|
+
// Browse methods
|
|
71
|
+
async getPopularManga(page) {
|
|
72
|
+
return workerApi.getPopularManga(sourceId, page);
|
|
73
|
+
},
|
|
74
|
+
async getLatestUpdates(page) {
|
|
75
|
+
return workerApi.getLatestUpdates(sourceId, page);
|
|
76
|
+
},
|
|
77
|
+
// Search methods
|
|
78
|
+
async searchManga(page, query) {
|
|
79
|
+
return workerApi.searchManga(sourceId, page, query);
|
|
80
|
+
},
|
|
81
|
+
async searchMangaWithFilters(page, query, filterStateJson) {
|
|
82
|
+
return workerApi.searchMangaWithFilters(sourceId, page, query, filterStateJson);
|
|
83
|
+
},
|
|
84
|
+
// Content methods
|
|
85
|
+
async getMangaDetails(mangaUrl) {
|
|
86
|
+
return workerApi.getMangaDetails(sourceId, mangaUrl);
|
|
87
|
+
},
|
|
88
|
+
async getChapterList(mangaUrl) {
|
|
89
|
+
return workerApi.getChapterList(sourceId, mangaUrl);
|
|
90
|
+
},
|
|
91
|
+
async getPageList(chapterUrl) {
|
|
92
|
+
return workerApi.getPageList(sourceId, chapterUrl);
|
|
93
|
+
},
|
|
94
|
+
async fetchImage(pageUrl, pageImageUrl) {
|
|
95
|
+
return workerApi.fetchImage(sourceId, pageUrl, pageImageUrl);
|
|
96
|
+
},
|
|
97
|
+
async getHeaders() {
|
|
98
|
+
return workerApi.getHeaders(sourceId);
|
|
99
|
+
},
|
|
100
|
+
// Preferences methods
|
|
101
|
+
async initPreferences(prefsName, values) {
|
|
102
|
+
await workerApi.initPreferences(prefsName, values);
|
|
103
|
+
},
|
|
104
|
+
async flushPrefChanges() {
|
|
105
|
+
return workerApi.flushPrefChanges();
|
|
106
|
+
},
|
|
107
|
+
async getSettingsSchema() {
|
|
108
|
+
return workerApi.getSettingsSchema(sourceId);
|
|
109
|
+
},
|
|
110
|
+
dispose() {
|
|
111
|
+
// Individual source disposal is a no-op
|
|
112
|
+
// Use LoadedExtension.dispose() to terminate worker
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
},
|
|
116
|
+
dispose() {
|
|
117
|
+
loadedExtensions.delete(jsUrl);
|
|
118
|
+
worker.terminate();
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/async/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AsyncLoadOptions, LoadedExtension } from "./types";
|
|
2
|
+
import type { ExtensionManifest } from "../types";
|
|
3
|
+
export type { AsyncTachiyomiSource, AsyncLoadOptions, LoadedExtension } from "./types";
|
|
4
|
+
/**
|
|
5
|
+
* Load a Tachiyomi extension asynchronously (Node.js/Bun version)
|
|
6
|
+
*
|
|
7
|
+
* No Worker needed - sync HTTP works directly in Node.js.
|
|
8
|
+
*
|
|
9
|
+
* @param jsUrl - URL to the compiled extension JavaScript
|
|
10
|
+
* @param manifest - Extension manifest
|
|
11
|
+
* @param options - Proxy URL and preferences configuration
|
|
12
|
+
*/
|
|
13
|
+
export declare function loadExtension(jsUrl: string, manifest: ExtensionManifest, options?: AsyncLoadOptions): Promise<LoadedExtension>;
|
|
14
|
+
//# sourceMappingURL=index.node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.node.d.ts","sourceRoot":"","sources":["../../src/async/index.node.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAwB,gBAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AACvF,OAAO,KAAK,EAAE,iBAAiB,EAA2B,MAAM,UAAU,CAAC;AAG3E,YAAY,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AA4IvF;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC,CAoC1B"}
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node.js/Bun async runtime
|
|
3
|
+
*
|
|
4
|
+
* No Worker needed - can use sync HTTP directly in Node.js.
|
|
5
|
+
* All methods are still async for API consistency.
|
|
6
|
+
*/
|
|
7
|
+
import { createRuntime } from "../runtime";
|
|
8
|
+
import { createSyncNodeBridge } from "../http/sync-node";
|
|
9
|
+
// ============ Preferences Storage ============
|
|
10
|
+
// SharedPreferences implementation for Kotlin/JS (Node.js version)
|
|
11
|
+
const prefsStorage = new Map();
|
|
12
|
+
let pendingPrefChanges = [];
|
|
13
|
+
class SharedPreferencesImpl {
|
|
14
|
+
constructor(name) {
|
|
15
|
+
this.name = name;
|
|
16
|
+
if (!prefsStorage.has(name)) {
|
|
17
|
+
prefsStorage.set(name, new Map());
|
|
18
|
+
}
|
|
19
|
+
this.data = prefsStorage.get(name);
|
|
20
|
+
}
|
|
21
|
+
getString(key, defValue) {
|
|
22
|
+
const val = this.data.get(key);
|
|
23
|
+
return typeof val === "string" ? val : defValue;
|
|
24
|
+
}
|
|
25
|
+
getBoolean(key, defValue) {
|
|
26
|
+
const val = this.data.get(key);
|
|
27
|
+
return typeof val === "boolean" ? val : defValue;
|
|
28
|
+
}
|
|
29
|
+
getInt(key, defValue) {
|
|
30
|
+
const val = this.data.get(key);
|
|
31
|
+
return typeof val === "number" ? Math.floor(val) : defValue;
|
|
32
|
+
}
|
|
33
|
+
getLong(key, defValue) {
|
|
34
|
+
return this.getInt(key, defValue);
|
|
35
|
+
}
|
|
36
|
+
getFloat(key, defValue) {
|
|
37
|
+
const val = this.data.get(key);
|
|
38
|
+
return typeof val === "number" ? val : defValue;
|
|
39
|
+
}
|
|
40
|
+
getStringSet(key, defValue) {
|
|
41
|
+
const val = this.data.get(key);
|
|
42
|
+
return Array.isArray(val) ? val : defValue;
|
|
43
|
+
}
|
|
44
|
+
getAll() {
|
|
45
|
+
const result = {};
|
|
46
|
+
for (const [k, v] of this.data.entries()) {
|
|
47
|
+
result[k] = v;
|
|
48
|
+
}
|
|
49
|
+
return result;
|
|
50
|
+
}
|
|
51
|
+
contains(key) {
|
|
52
|
+
return this.data.has(key);
|
|
53
|
+
}
|
|
54
|
+
edit() {
|
|
55
|
+
return new SharedPreferencesEditor(this.name, this.data);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
class SharedPreferencesEditor {
|
|
59
|
+
constructor(name, data) {
|
|
60
|
+
this.changes = new Map();
|
|
61
|
+
this.name = name;
|
|
62
|
+
this.data = data;
|
|
63
|
+
}
|
|
64
|
+
putString(key, value) {
|
|
65
|
+
this.changes.set(key, value);
|
|
66
|
+
return this;
|
|
67
|
+
}
|
|
68
|
+
putBoolean(key, value) {
|
|
69
|
+
this.changes.set(key, value);
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
putInt(key, value) {
|
|
73
|
+
this.changes.set(key, Math.floor(value));
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
putLong(key, value) {
|
|
77
|
+
return this.putInt(key, value);
|
|
78
|
+
}
|
|
79
|
+
putFloat(key, value) {
|
|
80
|
+
this.changes.set(key, value);
|
|
81
|
+
return this;
|
|
82
|
+
}
|
|
83
|
+
putStringSet(key, value) {
|
|
84
|
+
this.changes.set(key, value);
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
87
|
+
remove(key) {
|
|
88
|
+
this.changes.set(key, null);
|
|
89
|
+
return this;
|
|
90
|
+
}
|
|
91
|
+
clear() {
|
|
92
|
+
for (const key of this.data.keys()) {
|
|
93
|
+
this.changes.set(key, null);
|
|
94
|
+
}
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
apply() {
|
|
98
|
+
this.commit();
|
|
99
|
+
}
|
|
100
|
+
commit() {
|
|
101
|
+
for (const [key, value] of this.changes) {
|
|
102
|
+
if (value === null) {
|
|
103
|
+
this.data.delete(key);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
this.data.set(key, value);
|
|
107
|
+
}
|
|
108
|
+
pendingPrefChanges.push({ name: this.name, key, value });
|
|
109
|
+
}
|
|
110
|
+
this.changes.clear();
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Expose SharedPreferences factory to Kotlin/JS
|
|
115
|
+
globalThis.getSharedPreferences = (name) => {
|
|
116
|
+
return new SharedPreferencesImpl(name);
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* Load a Tachiyomi extension asynchronously (Node.js/Bun version)
|
|
120
|
+
*
|
|
121
|
+
* No Worker needed - sync HTTP works directly in Node.js.
|
|
122
|
+
*
|
|
123
|
+
* @param jsUrl - URL to the compiled extension JavaScript
|
|
124
|
+
* @param manifest - Extension manifest
|
|
125
|
+
* @param options - Proxy URL and preferences configuration
|
|
126
|
+
*/
|
|
127
|
+
export async function loadExtension(jsUrl, manifest, options = {}) {
|
|
128
|
+
const { proxyUrl, preferences } = options;
|
|
129
|
+
// Initialize preferences if provided
|
|
130
|
+
if (preferences) {
|
|
131
|
+
const prefs = new Map();
|
|
132
|
+
for (const [key, value] of Object.entries(preferences.values)) {
|
|
133
|
+
prefs.set(key, value);
|
|
134
|
+
}
|
|
135
|
+
prefsStorage.set(preferences.name, prefs);
|
|
136
|
+
}
|
|
137
|
+
// Create HTTP bridge
|
|
138
|
+
const httpBridge = createSyncNodeBridge({ proxyUrl });
|
|
139
|
+
const runtime = createRuntime(httpBridge);
|
|
140
|
+
// Fetch extension code
|
|
141
|
+
const response = await fetch(jsUrl);
|
|
142
|
+
if (!response.ok) {
|
|
143
|
+
throw new Error(`Failed to fetch extension: ${response.status} ${response.statusText}`);
|
|
144
|
+
}
|
|
145
|
+
const code = await response.text();
|
|
146
|
+
// Load extension
|
|
147
|
+
const extension = runtime.loadExtension(code);
|
|
148
|
+
const sources = extension.getSources();
|
|
149
|
+
// Update manifest with sources
|
|
150
|
+
const updatedManifest = {
|
|
151
|
+
...manifest,
|
|
152
|
+
sources,
|
|
153
|
+
};
|
|
154
|
+
console.log("[Tachiyomi Node] Loaded, sources:", sources.length, sources.map(s => s.name).slice(0, 5));
|
|
155
|
+
return createLoadedExtension(extension, updatedManifest);
|
|
156
|
+
}
|
|
157
|
+
function createLoadedExtension(extension, manifest) {
|
|
158
|
+
const sources = manifest.sources ?? [];
|
|
159
|
+
return {
|
|
160
|
+
manifest,
|
|
161
|
+
sources,
|
|
162
|
+
getSource(sourceId) {
|
|
163
|
+
const sourceInfo = sources.find(s => s.id === sourceId);
|
|
164
|
+
if (!sourceInfo) {
|
|
165
|
+
throw new Error(`Source not found: ${sourceId} in ${manifest.name}`);
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
sourceId,
|
|
169
|
+
sourceInfo,
|
|
170
|
+
manifest,
|
|
171
|
+
// Filter methods
|
|
172
|
+
async getFilterList() {
|
|
173
|
+
try {
|
|
174
|
+
return extension.getFilterList(sourceId);
|
|
175
|
+
}
|
|
176
|
+
catch (e) {
|
|
177
|
+
console.error("[Tachiyomi Node] getFilterList error:", e);
|
|
178
|
+
return [];
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
async resetFilters() {
|
|
182
|
+
try {
|
|
183
|
+
extension.resetFilters(sourceId);
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
catch (e) {
|
|
187
|
+
console.error("[Tachiyomi Node] resetFilters error:", e);
|
|
188
|
+
return false;
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
async applyFilterState(filterStateJson) {
|
|
192
|
+
try {
|
|
193
|
+
const filterState = JSON.parse(filterStateJson);
|
|
194
|
+
extension.applyFilterState(sourceId, filterState);
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
197
|
+
catch (e) {
|
|
198
|
+
console.error("[Tachiyomi Node] applyFilterState error:", e);
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
// Browse methods
|
|
203
|
+
async getPopularManga(page) {
|
|
204
|
+
try {
|
|
205
|
+
return extension.getPopularManga(sourceId, page);
|
|
206
|
+
}
|
|
207
|
+
catch (e) {
|
|
208
|
+
console.error("[Tachiyomi Node] getPopularManga error:", e);
|
|
209
|
+
return { mangas: [], hasNextPage: false };
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
async getLatestUpdates(page) {
|
|
213
|
+
try {
|
|
214
|
+
return extension.getLatestUpdates(sourceId, page);
|
|
215
|
+
}
|
|
216
|
+
catch (e) {
|
|
217
|
+
console.error("[Tachiyomi Node] getLatestUpdates error:", e);
|
|
218
|
+
return { mangas: [], hasNextPage: false };
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
// Search methods
|
|
222
|
+
async searchManga(page, query) {
|
|
223
|
+
try {
|
|
224
|
+
return extension.searchManga(sourceId, page, query);
|
|
225
|
+
}
|
|
226
|
+
catch (e) {
|
|
227
|
+
console.error("[Tachiyomi Node] searchManga error:", e);
|
|
228
|
+
return { mangas: [], hasNextPage: false };
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
async searchMangaWithFilters(page, query, filterStateJson) {
|
|
232
|
+
try {
|
|
233
|
+
if (filterStateJson && filterStateJson !== "[]") {
|
|
234
|
+
const filterState = JSON.parse(filterStateJson);
|
|
235
|
+
extension.applyFilterState(sourceId, filterState);
|
|
236
|
+
}
|
|
237
|
+
return extension.searchManga(sourceId, page, query);
|
|
238
|
+
}
|
|
239
|
+
catch (e) {
|
|
240
|
+
console.error("[Tachiyomi Node] searchMangaWithFilters error:", e);
|
|
241
|
+
return { mangas: [], hasNextPage: false };
|
|
242
|
+
}
|
|
243
|
+
},
|
|
244
|
+
// Content methods
|
|
245
|
+
async getMangaDetails(mangaUrl) {
|
|
246
|
+
try {
|
|
247
|
+
return extension.getMangaDetails(sourceId, { url: mangaUrl });
|
|
248
|
+
}
|
|
249
|
+
catch (e) {
|
|
250
|
+
console.error("[Tachiyomi Node] getMangaDetails error:", e);
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
async getChapterList(mangaUrl) {
|
|
255
|
+
try {
|
|
256
|
+
return extension.getChapterList(sourceId, { url: mangaUrl });
|
|
257
|
+
}
|
|
258
|
+
catch (e) {
|
|
259
|
+
console.error("[Tachiyomi Node] getChapterList error:", e);
|
|
260
|
+
return [];
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
async getPageList(chapterUrl) {
|
|
264
|
+
try {
|
|
265
|
+
return extension.getPageList(sourceId, { url: chapterUrl });
|
|
266
|
+
}
|
|
267
|
+
catch (e) {
|
|
268
|
+
console.error("[Tachiyomi Node] getPageList error:", e);
|
|
269
|
+
return [];
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
async fetchImage(pageUrl, pageImageUrl) {
|
|
273
|
+
// Always returns base64 bytes (like Mihon's getImage)
|
|
274
|
+
return extension.fetchImage(sourceId, pageUrl, pageImageUrl);
|
|
275
|
+
},
|
|
276
|
+
async getHeaders() {
|
|
277
|
+
try {
|
|
278
|
+
return extension.getHeaders(sourceId);
|
|
279
|
+
}
|
|
280
|
+
catch (e) {
|
|
281
|
+
console.warn("[Tachiyomi Node] getHeaders error:", e);
|
|
282
|
+
return {};
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
// Preferences methods
|
|
286
|
+
async initPreferences(prefsName, values) {
|
|
287
|
+
const prefs = new Map();
|
|
288
|
+
for (const [key, value] of Object.entries(values)) {
|
|
289
|
+
prefs.set(key, value);
|
|
290
|
+
}
|
|
291
|
+
prefsStorage.set(prefsName, prefs);
|
|
292
|
+
},
|
|
293
|
+
async flushPrefChanges() {
|
|
294
|
+
const changes = pendingPrefChanges;
|
|
295
|
+
pendingPrefChanges = [];
|
|
296
|
+
return changes;
|
|
297
|
+
},
|
|
298
|
+
async getSettingsSchema() {
|
|
299
|
+
try {
|
|
300
|
+
const schema = extension.getSettingsSchema(sourceId);
|
|
301
|
+
return schema ? JSON.stringify(schema) : null;
|
|
302
|
+
}
|
|
303
|
+
catch (e) {
|
|
304
|
+
console.error("[Tachiyomi Node] getSettingsSchema error:", e);
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
dispose() {
|
|
309
|
+
// No-op in Node.js - no worker to terminate
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
},
|
|
313
|
+
dispose() {
|
|
314
|
+
// No-op in Node.js - no worker to terminate
|
|
315
|
+
},
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
//# sourceMappingURL=index.node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.node.js","sourceRoot":"","sources":["../../src/async/index.node.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Async runtime types for Tachiyomi sources
|
|
3
|
+
*/
|
|
4
|
+
import type { Manga, Chapter, Page, MangasPage, SourceInfo, ExtensionManifest, FilterState } from "../types";
|
|
5
|
+
/**
|
|
6
|
+
* Async Tachiyomi source interface
|
|
7
|
+
* All methods return Promises for use on main thread
|
|
8
|
+
*/
|
|
9
|
+
export interface AsyncTachiyomiSource {
|
|
10
|
+
readonly sourceId: string;
|
|
11
|
+
readonly sourceInfo: SourceInfo;
|
|
12
|
+
readonly manifest: ExtensionManifest;
|
|
13
|
+
getFilterList(): Promise<FilterState[]>;
|
|
14
|
+
resetFilters(): Promise<boolean>;
|
|
15
|
+
applyFilterState(filterStateJson: string): Promise<boolean>;
|
|
16
|
+
getPopularManga(page: number): Promise<MangasPage>;
|
|
17
|
+
getLatestUpdates(page: number): Promise<MangasPage>;
|
|
18
|
+
searchManga(page: number, query: string): Promise<MangasPage>;
|
|
19
|
+
searchMangaWithFilters(page: number, query: string, filterStateJson: string): Promise<MangasPage>;
|
|
20
|
+
getMangaDetails(mangaUrl: string): Promise<Manga | null>;
|
|
21
|
+
getChapterList(mangaUrl: string): Promise<Chapter[]>;
|
|
22
|
+
getPageList(chapterUrl: string): Promise<Page[]>;
|
|
23
|
+
fetchImage(pageUrl: string, pageImageUrl: string): Promise<string>;
|
|
24
|
+
getHeaders(): Promise<Record<string, string>>;
|
|
25
|
+
initPreferences(prefsName: string, values: Record<string, unknown>): Promise<void>;
|
|
26
|
+
flushPrefChanges(): Promise<Array<{
|
|
27
|
+
name: string;
|
|
28
|
+
key: string;
|
|
29
|
+
value: unknown;
|
|
30
|
+
}>>;
|
|
31
|
+
getSettingsSchema(): Promise<string | null>;
|
|
32
|
+
/** Terminate the source and release resources */
|
|
33
|
+
dispose(): void;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Options for loading an async source
|
|
37
|
+
*/
|
|
38
|
+
export interface AsyncLoadOptions {
|
|
39
|
+
/**
|
|
40
|
+
* Proxy URL base for CORS bypass (browser only)
|
|
41
|
+
* The target URL will be appended (URL-encoded)
|
|
42
|
+
* Example: "https://proxy.example.com/?url="
|
|
43
|
+
*/
|
|
44
|
+
proxyUrl?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Initial preferences values
|
|
47
|
+
*/
|
|
48
|
+
preferences?: {
|
|
49
|
+
name: string;
|
|
50
|
+
values: Record<string, unknown>;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Result of loading an extension
|
|
55
|
+
*/
|
|
56
|
+
export interface LoadedExtension {
|
|
57
|
+
manifest: ExtensionManifest;
|
|
58
|
+
sources: SourceInfo[];
|
|
59
|
+
/**
|
|
60
|
+
* Get an async source by ID
|
|
61
|
+
*/
|
|
62
|
+
getSource(sourceId: string): AsyncTachiyomiSource;
|
|
63
|
+
/**
|
|
64
|
+
* Dispose all sources and terminate worker
|
|
65
|
+
*/
|
|
66
|
+
dispose(): void;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/async/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,KAAK,EACV,KAAK,EACL,OAAO,EACP,IAAI,EACJ,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,WAAW,EACZ,MAAM,UAAU,CAAC;AAElB;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IAGrC,aAAa,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IACxC,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACjC,gBAAgB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAG5D,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACnD,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAGpD,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC9D,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAGlG,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IACzD,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACrD,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACjD,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACnE,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAG9C,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnF,gBAAgB,IAAI,OAAO,CAAC,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC,CAAC;IAClF,iBAAiB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAE5C,iDAAiD;IACjD,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,WAAW,CAAC,EAAE;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACjC,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,OAAO,EAAE,UAAU,EAAE,CAAC;IAEtB;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,oBAAoB,CAAC;IAElD;;OAEG;IACH,OAAO,IAAI,IAAI,CAAC;CACjB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/async/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { MangasPage, Manga, Chapter, Page, FilterState, SourceInfo, ExtensionManifest } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* Worker API exposed via Comlink
|
|
4
|
+
*/
|
|
5
|
+
declare const workerApi: {
|
|
6
|
+
initPreferences(prefsName: string, values: Record<string, unknown>): void;
|
|
7
|
+
flushPrefChanges(): Array<{
|
|
8
|
+
name: string;
|
|
9
|
+
key: string;
|
|
10
|
+
value: unknown;
|
|
11
|
+
}>;
|
|
12
|
+
getSettingsSchema(sourceId: string): string | null;
|
|
13
|
+
load(jsUrl: string, manifestData: ExtensionManifest, proxyUrl: string | null): Promise<{
|
|
14
|
+
success: boolean;
|
|
15
|
+
manifest?: ExtensionManifest;
|
|
16
|
+
}>;
|
|
17
|
+
isLoaded(): boolean;
|
|
18
|
+
getManifest(): ExtensionManifest | null;
|
|
19
|
+
getSources(): SourceInfo[];
|
|
20
|
+
getFilterList(sourceId: string): FilterState[];
|
|
21
|
+
resetFilters(sourceId: string): boolean;
|
|
22
|
+
applyFilterState(sourceId: string, filterStateJson: string): boolean;
|
|
23
|
+
getPopularManga(sourceId: string, page: number): MangasPage;
|
|
24
|
+
getLatestUpdates(sourceId: string, page: number): MangasPage;
|
|
25
|
+
searchManga(sourceId: string, page: number, query: string): MangasPage;
|
|
26
|
+
searchMangaWithFilters(sourceId: string, page: number, query: string, filterStateJson: string): MangasPage;
|
|
27
|
+
getMangaDetails(sourceId: string, mangaUrl: string): Manga | null;
|
|
28
|
+
getChapterList(sourceId: string, mangaUrl: string): Chapter[];
|
|
29
|
+
getPageList(sourceId: string, chapterUrl: string): Page[];
|
|
30
|
+
fetchImage(sourceId: string, pageUrl: string, pageImageUrl: string): string;
|
|
31
|
+
getHeaders(sourceId: string): Record<string, string>;
|
|
32
|
+
};
|
|
33
|
+
/** Type alias for Comlink API */
|
|
34
|
+
export type WorkerApi = typeof workerApi;
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/async/worker.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,UAAU,EACV,KAAK,EACL,OAAO,EACP,IAAI,EACJ,WAAW,EACX,UAAU,EACV,iBAAiB,EAClB,MAAM,UAAU,CAAC;AA4JlB;;GAEG;AACH,QAAA,MAAM,SAAS;+BAGc,MAAM,UAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;wBAQrD,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;gCAM5C,MAAM,GAAG,MAAM,GAAG,IAAI;gBAczC,MAAM,gBACC,iBAAiB,YACrB,MAAM,GAAG,IAAI,GACtB,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAA;KAAE,CAAC;gBAiClD,OAAO;mBAIJ,iBAAiB,GAAG,IAAI;kBAIzB,UAAU,EAAE;4BAMF,MAAM,GAAG,WAAW,EAAE;2BAUvB,MAAM,GAAG,OAAO;+BAWZ,MAAM,mBAAmB,MAAM,GAAG,OAAO;8BAc1C,MAAM,QAAQ,MAAM,GAAG,UAAU;+BAUhC,MAAM,QAAQ,MAAM,GAAG,UAAU;0BAUtC,MAAM,QAAQ,MAAM,SAAS,MAAM,GAAG,UAAU;qCAUrC,MAAM,QAAQ,MAAM,SAAS,MAAM,mBAAmB,MAAM,GAAG,UAAU;8BAehF,MAAM,YAAY,MAAM,GAAG,KAAK,GAAG,IAAI;6BAUxC,MAAM,YAAY,MAAM,GAAG,OAAO,EAAE;0BAUvC,MAAM,cAAc,MAAM,GAAG,IAAI,EAAE;yBAUpC,MAAM,WAAW,MAAM,gBAAgB,MAAM,GAAG,MAAM;yBAQtD,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;CAWrD,CAAC;AAIF,iCAAiC;AACjC,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC"}
|