@book000/pixivts 0.55.1 → 0.56.1
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 +115 -19
- package/dist/index.cjs +1321 -0
- package/dist/index.d.cts +1662 -0
- package/dist/index.d.ts +1662 -45
- package/dist/index.js +1308 -65
- package/package.json +35 -72
- package/dist/checks.d.ts +0 -19
- package/dist/checks.d.ts.map +0 -1
- package/dist/checks.js +0 -85
- package/dist/checks.js.map +0 -1
- package/dist/checks.test.d.ts +0 -2
- package/dist/checks.test.d.ts.map +0 -1
- package/dist/checks.test.js +0 -306
- package/dist/checks.test.js.map +0 -1
- package/dist/http-client.d.ts +0 -66
- package/dist/http-client.d.ts.map +0 -1
- package/dist/http-client.js +0 -138
- package/dist/http-client.js.map +0 -1
- package/dist/http-client.test.d.ts +0 -2
- package/dist/http-client.test.d.ts.map +0 -1
- package/dist/http-client.test.js +0 -149
- package/dist/http-client.test.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/options.d.ts +0 -317
- package/dist/options.d.ts.map +0 -1
- package/dist/options.js +0 -222
- package/dist/options.js.map +0 -1
- package/dist/options.test.d.ts +0 -2
- package/dist/options.test.d.ts.map +0 -1
- package/dist/options.test.js +0 -117
- package/dist/options.test.js.map +0 -1
- package/dist/pixiv.d.ts +0 -317
- package/dist/pixiv.d.ts.map +0 -1
- package/dist/pixiv.js +0 -810
- package/dist/pixiv.js.map +0 -1
- package/dist/pixiv.test.d.ts +0 -2
- package/dist/pixiv.test.d.ts.map +0 -1
- package/dist/pixiv.test.js +0 -883
- package/dist/pixiv.test.js.map +0 -1
- package/dist/saving-responses/index.d.ts +0 -130
- package/dist/saving-responses/index.d.ts.map +0 -1
- package/dist/saving-responses/index.js +0 -263
- package/dist/saving-responses/index.js.map +0 -1
- package/dist/saving-responses/index.test.d.ts +0 -2
- package/dist/saving-responses/index.test.d.ts.map +0 -1
- package/dist/saving-responses/index.test.js +0 -468
- package/dist/saving-responses/index.test.js.map +0 -1
- package/dist/saving-responses/response-entity.d.ts +0 -16
- package/dist/saving-responses/response-entity.d.ts.map +0 -1
- package/dist/saving-responses/response-entity.js +0 -101
- package/dist/saving-responses/response-entity.js.map +0 -1
- package/dist/types/endpoints/v1/illust/bookmark/delete.d.ts +0 -14
- package/dist/types/endpoints/v1/illust/bookmark/delete.d.ts.map +0 -1
- package/dist/types/endpoints/v1/illust/bookmark/delete.js +0 -3
- package/dist/types/endpoints/v1/illust/bookmark/delete.js.map +0 -1
- package/dist/types/endpoints/v1/illust/detail.d.ts +0 -25
- package/dist/types/endpoints/v1/illust/detail.d.ts.map +0 -1
- package/dist/types/endpoints/v1/illust/detail.js +0 -20
- package/dist/types/endpoints/v1/illust/detail.js.map +0 -1
- package/dist/types/endpoints/v1/illust/ranking.d.ts +0 -51
- package/dist/types/endpoints/v1/illust/ranking.d.ts.map +0 -1
- package/dist/types/endpoints/v1/illust/ranking.js +0 -40
- package/dist/types/endpoints/v1/illust/ranking.js.map +0 -1
- package/dist/types/endpoints/v1/illust/recommended.d.ts +0 -104
- package/dist/types/endpoints/v1/illust/recommended.d.ts.map +0 -1
- package/dist/types/endpoints/v1/illust/recommended.js +0 -44
- package/dist/types/endpoints/v1/illust/recommended.js.map +0 -1
- package/dist/types/endpoints/v1/illust/series.d.ts +0 -45
- package/dist/types/endpoints/v1/illust/series.d.ts.map +0 -1
- package/dist/types/endpoints/v1/illust/series.js +0 -31
- package/dist/types/endpoints/v1/illust/series.js.map +0 -1
- package/dist/types/endpoints/v1/illust/ugoira/metadata.d.ts +0 -25
- package/dist/types/endpoints/v1/illust/ugoira/metadata.d.ts.map +0 -1
- package/dist/types/endpoints/v1/illust/ugoira/metadata.js +0 -20
- package/dist/types/endpoints/v1/illust/ugoira/metadata.js.map +0 -1
- package/dist/types/endpoints/v1/manga/recommended.d.ts +0 -72
- package/dist/types/endpoints/v1/manga/recommended.d.ts.map +0 -1
- package/dist/types/endpoints/v1/manga/recommended.js +0 -33
- package/dist/types/endpoints/v1/manga/recommended.js.map +0 -1
- package/dist/types/endpoints/v1/novel/bookmark/delete.d.ts +0 -14
- package/dist/types/endpoints/v1/novel/bookmark/delete.d.ts.map +0 -1
- package/dist/types/endpoints/v1/novel/bookmark/delete.js +0 -3
- package/dist/types/endpoints/v1/novel/bookmark/delete.js.map +0 -1
- package/dist/types/endpoints/v1/novel/ranking.d.ts +0 -47
- package/dist/types/endpoints/v1/novel/ranking.d.ts.map +0 -1
- package/dist/types/endpoints/v1/novel/ranking.js +0 -39
- package/dist/types/endpoints/v1/novel/ranking.js.map +0 -1
- package/dist/types/endpoints/v1/novel/recommended.d.ts +0 -72
- package/dist/types/endpoints/v1/novel/recommended.d.ts.map +0 -1
- package/dist/types/endpoints/v1/novel/recommended.js +0 -32
- package/dist/types/endpoints/v1/novel/recommended.js.map +0 -1
- package/dist/types/endpoints/v1/novel/related.d.ts +0 -37
- package/dist/types/endpoints/v1/novel/related.d.ts.map +0 -1
- package/dist/types/endpoints/v1/novel/related.js +0 -24
- package/dist/types/endpoints/v1/novel/related.js.map +0 -1
- package/dist/types/endpoints/v1/search/illust.d.ts +0 -109
- package/dist/types/endpoints/v1/search/illust.d.ts.map +0 -1
- package/dist/types/endpoints/v1/search/illust.js +0 -40
- package/dist/types/endpoints/v1/search/illust.js.map +0 -1
- package/dist/types/endpoints/v1/search/novel.d.ts +0 -103
- package/dist/types/endpoints/v1/search/novel.d.ts.map +0 -1
- package/dist/types/endpoints/v1/search/novel.js +0 -38
- package/dist/types/endpoints/v1/search/novel.js.map +0 -1
- package/dist/types/endpoints/v1/user/bookmarks/illust.d.ts +0 -48
- package/dist/types/endpoints/v1/user/bookmarks/illust.d.ts.map +0 -1
- package/dist/types/endpoints/v1/user/bookmarks/illust.js +0 -31
- package/dist/types/endpoints/v1/user/bookmarks/illust.js.map +0 -1
- package/dist/types/endpoints/v1/user/bookmarks/novel.d.ts +0 -44
- package/dist/types/endpoints/v1/user/bookmarks/novel.d.ts.map +0 -1
- package/dist/types/endpoints/v1/user/bookmarks/novel.js +0 -28
- package/dist/types/endpoints/v1/user/bookmarks/novel.js.map +0 -1
- package/dist/types/endpoints/v1/user/detail.d.ts +0 -44
- package/dist/types/endpoints/v1/user/detail.d.ts.map +0 -1
- package/dist/types/endpoints/v1/user/detail.js +0 -26
- package/dist/types/endpoints/v1/user/detail.js.map +0 -1
- package/dist/types/endpoints/v1/user/follow/add.d.ts +0 -24
- package/dist/types/endpoints/v1/user/follow/add.d.ts.map +0 -1
- package/dist/types/endpoints/v1/user/follow/add.js +0 -3
- package/dist/types/endpoints/v1/user/follow/add.js.map +0 -1
- package/dist/types/endpoints/v1/user/follow/delete.d.ts +0 -14
- package/dist/types/endpoints/v1/user/follow/delete.d.ts.map +0 -1
- package/dist/types/endpoints/v1/user/follow/delete.js +0 -3
- package/dist/types/endpoints/v1/user/follow/delete.js.map +0 -1
- package/dist/types/endpoints/v1/user/following.d.ts +0 -38
- package/dist/types/endpoints/v1/user/following.d.ts.map +0 -1
- package/dist/types/endpoints/v1/user/following.js +0 -26
- package/dist/types/endpoints/v1/user/following.js.map +0 -1
- package/dist/types/endpoints/v1/user/illusts.d.ts +0 -51
- package/dist/types/endpoints/v1/user/illusts.d.ts.map +0 -1
- package/dist/types/endpoints/v1/user/illusts.js +0 -31
- package/dist/types/endpoints/v1/user/illusts.js.map +0 -1
- package/dist/types/endpoints/v1/user/novels.d.ts +0 -43
- package/dist/types/endpoints/v1/user/novels.d.ts.map +0 -1
- package/dist/types/endpoints/v1/user/novels.js +0 -29
- package/dist/types/endpoints/v1/user/novels.js.map +0 -1
- package/dist/types/endpoints/v2/illust/bookmark/add.d.ts +0 -28
- package/dist/types/endpoints/v2/illust/bookmark/add.d.ts.map +0 -1
- package/dist/types/endpoints/v2/illust/bookmark/add.js +0 -3
- package/dist/types/endpoints/v2/illust/bookmark/add.js.map +0 -1
- package/dist/types/endpoints/v2/illust/related.d.ts +0 -48
- package/dist/types/endpoints/v2/illust/related.d.ts.map +0 -1
- package/dist/types/endpoints/v2/illust/related.js +0 -32
- package/dist/types/endpoints/v2/illust/related.js.map +0 -1
- package/dist/types/endpoints/v2/novel/bookmark/add.d.ts +0 -27
- package/dist/types/endpoints/v2/novel/bookmark/add.d.ts.map +0 -1
- package/dist/types/endpoints/v2/novel/bookmark/add.js +0 -3
- package/dist/types/endpoints/v2/novel/bookmark/add.js.map +0 -1
- package/dist/types/endpoints/v2/novel/detail.d.ts +0 -25
- package/dist/types/endpoints/v2/novel/detail.d.ts.map +0 -1
- package/dist/types/endpoints/v2/novel/detail.js +0 -20
- package/dist/types/endpoints/v2/novel/detail.js.map +0 -1
- package/dist/types/endpoints/v2/novel/series.d.ts +0 -49
- package/dist/types/endpoints/v2/novel/series.d.ts.map +0 -1
- package/dist/types/endpoints/v2/novel/series.js +0 -31
- package/dist/types/endpoints/v2/novel/series.js.map +0 -1
- package/dist/types/endpoints/webview/v2/novel.d.ts +0 -21
- package/dist/types/endpoints/webview/v2/novel.d.ts.map +0 -1
- package/dist/types/endpoints/webview/v2/novel.js +0 -18
- package/dist/types/endpoints/webview/v2/novel.js.map +0 -1
- package/dist/types/error-response.d.ts +0 -31
- package/dist/types/error-response.d.ts.map +0 -1
- package/dist/types/error-response.js +0 -3
- package/dist/types/error-response.js.map +0 -1
- package/dist/types/errors.d.ts +0 -7
- package/dist/types/errors.d.ts.map +0 -1
- package/dist/types/errors.js +0 -14
- package/dist/types/errors.js.map +0 -1
- package/dist/types/pixiv-common.d.ts +0 -103
- package/dist/types/pixiv-common.d.ts.map +0 -1
- package/dist/types/pixiv-common.js +0 -68
- package/dist/types/pixiv-common.js.map +0 -1
- package/dist/types/pixiv-illust-series.d.ts +0 -56
- package/dist/types/pixiv-illust-series.d.ts.map +0 -1
- package/dist/types/pixiv-illust-series.js +0 -26
- package/dist/types/pixiv-illust-series.js.map +0 -1
- package/dist/types/pixiv-illust.d.ts +0 -180
- package/dist/types/pixiv-illust.d.ts.map +0 -1
- package/dist/types/pixiv-illust.js +0 -56
- package/dist/types/pixiv-illust.js.map +0 -1
- package/dist/types/pixiv-novel-series.d.ts +0 -84
- package/dist/types/pixiv-novel-series.d.ts.map +0 -1
- package/dist/types/pixiv-novel-series.js +0 -43
- package/dist/types/pixiv-novel-series.js.map +0 -1
- package/dist/types/pixiv-novel.d.ts +0 -131
- package/dist/types/pixiv-novel.d.ts.map +0 -1
- package/dist/types/pixiv-novel.js +0 -44
- package/dist/types/pixiv-novel.js.map +0 -1
- package/dist/types/pixiv-ugoira.d.ts +0 -50
- package/dist/types/pixiv-ugoira.d.ts.map +0 -1
- package/dist/types/pixiv-ugoira.js +0 -34
- package/dist/types/pixiv-ugoira.js.map +0 -1
- package/dist/types/pixiv-user.d.ts +0 -212
- package/dist/types/pixiv-user.d.ts.map +0 -1
- package/dist/types/pixiv-user.js +0 -118
- package/dist/types/pixiv-user.js.map +0 -1
- package/dist/utils.d.ts +0 -3
- package/dist/utils.d.ts.map +0 -1
- package/dist/utils.js +0 -15
- package/dist/utils.js.map +0 -1
- package/dist/utils.test.d.ts +0 -2
- package/dist/utils.test.d.ts.map +0 -1
- package/dist/utils.test.js +0 -15
- package/dist/utils.test.js.map +0 -1
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1321 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/result.ts
|
|
4
|
+
var OkResultImpl = class _OkResultImpl {
|
|
5
|
+
constructor(value) {
|
|
6
|
+
this.value = value;
|
|
7
|
+
}
|
|
8
|
+
isOk = true;
|
|
9
|
+
isErr = false;
|
|
10
|
+
map(fn) {
|
|
11
|
+
return new _OkResultImpl(fn(this.value));
|
|
12
|
+
}
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters, @typescript-eslint/no-unused-vars -- F is part of the public API contract; _fn is intentionally unused (OkResult.mapErr is a no-op)
|
|
14
|
+
mapErr(_fn) {
|
|
15
|
+
return this;
|
|
16
|
+
}
|
|
17
|
+
andThen(fn) {
|
|
18
|
+
return fn(this.value);
|
|
19
|
+
}
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- _onErr is intentionally unused: OkResult.match always calls onOk
|
|
21
|
+
match(onOk, _onErr) {
|
|
22
|
+
return onOk(this.value);
|
|
23
|
+
}
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- _fallback is intentionally unused: OkResult.unwrapOr always returns value
|
|
25
|
+
unwrapOr(_fallback) {
|
|
26
|
+
return this.value;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
var ErrResultImpl = class _ErrResultImpl {
|
|
30
|
+
// eslint-disable-next-line n/handle-callback-err -- 'error' is a stored value, not a Node.js callback error parameter
|
|
31
|
+
constructor(error) {
|
|
32
|
+
this.error = error;
|
|
33
|
+
}
|
|
34
|
+
isOk = false;
|
|
35
|
+
isErr = true;
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters, @typescript-eslint/no-unused-vars -- U is part of the public API contract; _fn is intentionally unused (ErrResult.map is a no-op)
|
|
37
|
+
map(_fn) {
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
mapErr(fn) {
|
|
41
|
+
return new _ErrResultImpl(fn(this.error));
|
|
42
|
+
}
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- _fn is intentionally unused: ErrResult.andThen is a no-op (the success path does not apply)
|
|
44
|
+
andThen(_fn) {
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
match(_onOk, onErr) {
|
|
48
|
+
return onErr(this.error);
|
|
49
|
+
}
|
|
50
|
+
unwrapOr(fallback) {
|
|
51
|
+
return fallback;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
function ok(value) {
|
|
55
|
+
return new OkResultImpl(value);
|
|
56
|
+
}
|
|
57
|
+
function err(error) {
|
|
58
|
+
return new ErrResultImpl(error);
|
|
59
|
+
}
|
|
60
|
+
var ResultAsync = class _ResultAsync {
|
|
61
|
+
_promise;
|
|
62
|
+
constructor(promise) {
|
|
63
|
+
this._promise = promise;
|
|
64
|
+
}
|
|
65
|
+
// PromiseLike contract — makes `await resultAsync` work
|
|
66
|
+
// eslint-disable-next-line unicorn/no-thenable -- ResultAsync intentionally implements PromiseLike to be directly awaitable
|
|
67
|
+
then(onfulfilled, onrejected) {
|
|
68
|
+
return this._promise.then(onfulfilled, onrejected);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Wraps a `Promise<T>` into a `ResultAsync<T, E>`.
|
|
72
|
+
*
|
|
73
|
+
* If the promise rejects, `onError` maps the rejection reason to `E`.
|
|
74
|
+
*
|
|
75
|
+
* @param promise - The promise to wrap
|
|
76
|
+
* @param onError - Error mapper
|
|
77
|
+
*/
|
|
78
|
+
static fromPromise(promise, onError) {
|
|
79
|
+
return new _ResultAsync(
|
|
80
|
+
promise.then(
|
|
81
|
+
(v) => ok(v),
|
|
82
|
+
(error) => err(onError(error))
|
|
83
|
+
)
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Wraps an already-resolved `Result<T, E>` into a `ResultAsync<T, E>`.
|
|
88
|
+
*
|
|
89
|
+
* @param result - The result to wrap
|
|
90
|
+
*/
|
|
91
|
+
static fromResult(result) {
|
|
92
|
+
return new _ResultAsync(Promise.resolve(result));
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Transforms the success value.
|
|
96
|
+
*
|
|
97
|
+
* If the inner result is `Err`, `fn` is not called.
|
|
98
|
+
*
|
|
99
|
+
* @param fn - Synchronous mapper
|
|
100
|
+
*/
|
|
101
|
+
map(fn) {
|
|
102
|
+
return new _ResultAsync(
|
|
103
|
+
// eslint-disable-next-line unicorn/no-array-callback-reference -- r.map(fn) is safe here; fn is a user-supplied mapper, not a DOM/Array method reference
|
|
104
|
+
this._promise.then((r) => r.map(fn))
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Transforms the error value.
|
|
109
|
+
*
|
|
110
|
+
* If the inner result is `Ok`, `fn` is not called.
|
|
111
|
+
*
|
|
112
|
+
* @param fn - Synchronous error mapper
|
|
113
|
+
*/
|
|
114
|
+
mapErr(fn) {
|
|
115
|
+
return new _ResultAsync(
|
|
116
|
+
this._promise.then((r) => r.mapErr(fn))
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Chains another async operation that may fail.
|
|
121
|
+
*
|
|
122
|
+
* If the inner result is `Err`, `fn` is not called.
|
|
123
|
+
*
|
|
124
|
+
* @param fn - Async mapper that returns a `ResultAsync<U, F>`
|
|
125
|
+
*/
|
|
126
|
+
andThen(fn) {
|
|
127
|
+
return new _ResultAsync(
|
|
128
|
+
this._promise.then(async (r) => {
|
|
129
|
+
if (r.isErr) return r;
|
|
130
|
+
const next = fn(r.value);
|
|
131
|
+
if (next instanceof _ResultAsync) {
|
|
132
|
+
return next._promise;
|
|
133
|
+
}
|
|
134
|
+
return next;
|
|
135
|
+
})
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Pattern-matches on success / failure.
|
|
140
|
+
*
|
|
141
|
+
* @param onOk - Called with the success value
|
|
142
|
+
* @param onErr - Called with the error value
|
|
143
|
+
* @returns A `Promise<U>`
|
|
144
|
+
*/
|
|
145
|
+
async match(onOk, onErr) {
|
|
146
|
+
const r = await this._promise;
|
|
147
|
+
if (r.isOk) return onOk(r.value);
|
|
148
|
+
return onErr(r.error);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Returns the success value, or `fallback` if the result is `Err`.
|
|
152
|
+
*
|
|
153
|
+
* @param fallback - The fallback value
|
|
154
|
+
*/
|
|
155
|
+
async unwrapOr(fallback) {
|
|
156
|
+
const r = await this._promise;
|
|
157
|
+
if (r.isOk) return r.value;
|
|
158
|
+
return fallback;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
// src/errors.ts
|
|
163
|
+
var PixivFetchError = class extends Error {
|
|
164
|
+
/** The underlying structured `PixivError`. */
|
|
165
|
+
pixivError;
|
|
166
|
+
constructor(pixivError) {
|
|
167
|
+
super(`pixiv API error: ${pixivError.type}`);
|
|
168
|
+
this.name = "PixivFetchError";
|
|
169
|
+
this.pixivError = pixivError;
|
|
170
|
+
Object.assign(this, pixivError);
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
function rateLimitError(retryAfter) {
|
|
174
|
+
return { type: "rate_limit", retryAfter };
|
|
175
|
+
}
|
|
176
|
+
function authFailedError(status) {
|
|
177
|
+
return { type: "auth_failed", status };
|
|
178
|
+
}
|
|
179
|
+
function networkError(cause) {
|
|
180
|
+
return { type: "network", cause };
|
|
181
|
+
}
|
|
182
|
+
function apiError(status, body) {
|
|
183
|
+
return { type: "api_error", status, body };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// src/paginated.ts
|
|
187
|
+
var PaginatedResultAsync = class _PaginatedResultAsync extends ResultAsync {
|
|
188
|
+
#http;
|
|
189
|
+
#getItems;
|
|
190
|
+
constructor(promise, http, getItems) {
|
|
191
|
+
super(promise);
|
|
192
|
+
this.#http = http;
|
|
193
|
+
this.#getItems = getItems;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Creates a `PaginatedResultAsync` from a `ResultAsync`.
|
|
197
|
+
*
|
|
198
|
+
* @param inner - The first-page result
|
|
199
|
+
* @param http - HTTP client for fetching subsequent pages
|
|
200
|
+
* @param getItems - Extracts item array from a page
|
|
201
|
+
*/
|
|
202
|
+
static fromResultAsync(inner, http, getItems) {
|
|
203
|
+
const promise = Promise.resolve(inner);
|
|
204
|
+
return new _PaginatedResultAsync(promise, http, getItems);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Async generator that yields each page starting from the first.
|
|
208
|
+
*
|
|
209
|
+
* If any page fetch fails, the generator throws a `PixivFetchError`.
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```ts
|
|
213
|
+
* for await (const page of client.illusts.search({ word: 'cat' }).pages()) {
|
|
214
|
+
* console.log(page.illusts.length)
|
|
215
|
+
* }
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
async *pages() {
|
|
219
|
+
const first = await Promise.resolve(this);
|
|
220
|
+
if (first.isErr) throw new PixivFetchError(first.error);
|
|
221
|
+
yield first.value;
|
|
222
|
+
let nextUrl = first.value.next_url;
|
|
223
|
+
while (nextUrl !== null) {
|
|
224
|
+
const pageResult = await this.#http.getAbsolute(nextUrl);
|
|
225
|
+
if (pageResult.isErr) throw new PixivFetchError(pageResult.error);
|
|
226
|
+
yield pageResult.value;
|
|
227
|
+
nextUrl = pageResult.value.next_url;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Async generator that yields individual items across all pages.
|
|
232
|
+
*
|
|
233
|
+
* If any page fetch fails, the generator throws a `PixivFetchError`.
|
|
234
|
+
*
|
|
235
|
+
* @example
|
|
236
|
+
* ```ts
|
|
237
|
+
* for await (const illust of client.illusts.search({ word: 'cat' }).items()) {
|
|
238
|
+
* console.log(illust.title)
|
|
239
|
+
* }
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
242
|
+
async *items() {
|
|
243
|
+
for await (const page of this.pages()) {
|
|
244
|
+
for (const item of this.#getItems(page)) {
|
|
245
|
+
yield item;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
function failedPaginated(error, http, getItems) {
|
|
251
|
+
return new PaginatedResultAsync(
|
|
252
|
+
Promise.resolve(err(error)),
|
|
253
|
+
http,
|
|
254
|
+
getItems
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// src/auth.ts
|
|
259
|
+
var T = Array.from(
|
|
260
|
+
{ length: 64 },
|
|
261
|
+
(_, i) => Math.floor(Math.abs(Math.sin(i + 1)) * 2 ** 32)
|
|
262
|
+
);
|
|
263
|
+
var S = [
|
|
264
|
+
7,
|
|
265
|
+
12,
|
|
266
|
+
17,
|
|
267
|
+
22,
|
|
268
|
+
7,
|
|
269
|
+
12,
|
|
270
|
+
17,
|
|
271
|
+
22,
|
|
272
|
+
7,
|
|
273
|
+
12,
|
|
274
|
+
17,
|
|
275
|
+
22,
|
|
276
|
+
7,
|
|
277
|
+
12,
|
|
278
|
+
17,
|
|
279
|
+
22,
|
|
280
|
+
5,
|
|
281
|
+
9,
|
|
282
|
+
14,
|
|
283
|
+
20,
|
|
284
|
+
5,
|
|
285
|
+
9,
|
|
286
|
+
14,
|
|
287
|
+
20,
|
|
288
|
+
5,
|
|
289
|
+
9,
|
|
290
|
+
14,
|
|
291
|
+
20,
|
|
292
|
+
5,
|
|
293
|
+
9,
|
|
294
|
+
14,
|
|
295
|
+
20,
|
|
296
|
+
4,
|
|
297
|
+
11,
|
|
298
|
+
16,
|
|
299
|
+
23,
|
|
300
|
+
4,
|
|
301
|
+
11,
|
|
302
|
+
16,
|
|
303
|
+
23,
|
|
304
|
+
4,
|
|
305
|
+
11,
|
|
306
|
+
16,
|
|
307
|
+
23,
|
|
308
|
+
4,
|
|
309
|
+
11,
|
|
310
|
+
16,
|
|
311
|
+
23,
|
|
312
|
+
6,
|
|
313
|
+
10,
|
|
314
|
+
15,
|
|
315
|
+
21,
|
|
316
|
+
6,
|
|
317
|
+
10,
|
|
318
|
+
15,
|
|
319
|
+
21,
|
|
320
|
+
6,
|
|
321
|
+
10,
|
|
322
|
+
15,
|
|
323
|
+
21,
|
|
324
|
+
6,
|
|
325
|
+
10,
|
|
326
|
+
15,
|
|
327
|
+
21
|
|
328
|
+
];
|
|
329
|
+
function md5Bytes(bytes) {
|
|
330
|
+
const len = bytes.length;
|
|
331
|
+
bytes.push(128);
|
|
332
|
+
while (bytes.length % 64 !== 56) bytes.push(0);
|
|
333
|
+
const bitLen = len * 8;
|
|
334
|
+
for (let i = 0; i < 8; i++) {
|
|
335
|
+
bytes.push(i < 4 ? bitLen >>> i * 8 & 255 : 0);
|
|
336
|
+
}
|
|
337
|
+
let a = 1732584193;
|
|
338
|
+
let b = 4023233417;
|
|
339
|
+
let c = 2562383102;
|
|
340
|
+
let d = 271733878;
|
|
341
|
+
for (let chunk = 0; chunk < bytes.length; chunk += 64) {
|
|
342
|
+
const M = [];
|
|
343
|
+
for (let w = 0; w < 16; w++) {
|
|
344
|
+
const off = chunk + w * 4;
|
|
345
|
+
M.push(
|
|
346
|
+
bytes[off] | bytes[off + 1] << 8 | bytes[off + 2] << 16 | bytes[off + 3] << 24
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
let aa = a;
|
|
350
|
+
let bb = b;
|
|
351
|
+
let cc = c;
|
|
352
|
+
let dd = d;
|
|
353
|
+
for (let i = 0; i < 64; i++) {
|
|
354
|
+
let f;
|
|
355
|
+
let g;
|
|
356
|
+
if (i < 16) {
|
|
357
|
+
f = bb & cc | ~bb & dd;
|
|
358
|
+
g = i;
|
|
359
|
+
} else if (i < 32) {
|
|
360
|
+
f = dd & bb | ~dd & cc;
|
|
361
|
+
g = (5 * i + 1) % 16;
|
|
362
|
+
} else if (i < 48) {
|
|
363
|
+
f = bb ^ cc ^ dd;
|
|
364
|
+
g = (3 * i + 5) % 16;
|
|
365
|
+
} else {
|
|
366
|
+
f = cc ^ (bb | ~dd);
|
|
367
|
+
g = 7 * i % 16;
|
|
368
|
+
}
|
|
369
|
+
const tmp = dd;
|
|
370
|
+
dd = cc;
|
|
371
|
+
cc = bb;
|
|
372
|
+
const sum = Math.trunc(aa + f + M[g] + T[i]);
|
|
373
|
+
const rotated = sum << S[i] | sum >>> 32 - S[i];
|
|
374
|
+
bb = Math.trunc(bb + rotated);
|
|
375
|
+
aa = tmp;
|
|
376
|
+
}
|
|
377
|
+
a = Math.trunc(a + aa);
|
|
378
|
+
b = Math.trunc(b + bb);
|
|
379
|
+
c = Math.trunc(c + cc);
|
|
380
|
+
d = Math.trunc(d + dd);
|
|
381
|
+
}
|
|
382
|
+
return [a, b, c, d].map(
|
|
383
|
+
(n) => [n & 255, n >>> 8 & 255, n >>> 16 & 255, n >>> 24 & 255].map((byte) => byte.toString(16).padStart(2, "0")).join("")
|
|
384
|
+
).join("");
|
|
385
|
+
}
|
|
386
|
+
function md5(input) {
|
|
387
|
+
const bytes = [];
|
|
388
|
+
for (let i = 0; i < input.length; i++) {
|
|
389
|
+
const code = input.codePointAt(i) ?? 0;
|
|
390
|
+
if (code < 128) {
|
|
391
|
+
bytes.push(code);
|
|
392
|
+
} else if (code < 2048) {
|
|
393
|
+
bytes.push(192 | code >> 6, 128 | code & 63);
|
|
394
|
+
} else {
|
|
395
|
+
bytes.push(
|
|
396
|
+
224 | code >> 12,
|
|
397
|
+
128 | code >> 6 & 63,
|
|
398
|
+
128 | code & 63
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
return md5Bytes(bytes);
|
|
403
|
+
}
|
|
404
|
+
var CLIENT_ID = "MOBrBDS8blbauoSck0ZfDbtuzpyT";
|
|
405
|
+
var CLIENT_SECRET = "lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj";
|
|
406
|
+
var HASH_SECRET = "28c1fdd170a5204386cb1313c7077b34f83e4aaf4aa829ce78c231e05b0bae2c";
|
|
407
|
+
var AUTH_URL = "https://oauth.secure.pixiv.net/auth/token";
|
|
408
|
+
function buildClientHash(localTime) {
|
|
409
|
+
return md5(localTime + HASH_SECRET);
|
|
410
|
+
}
|
|
411
|
+
var AuthManager = class _AuthManager {
|
|
412
|
+
#accessToken;
|
|
413
|
+
#refreshToken;
|
|
414
|
+
userId;
|
|
415
|
+
constructor(credentials) {
|
|
416
|
+
this.#accessToken = credentials.accessToken;
|
|
417
|
+
this.#refreshToken = credentials.refreshToken;
|
|
418
|
+
this.userId = credentials.userId;
|
|
419
|
+
}
|
|
420
|
+
/** Returns the current access token. */
|
|
421
|
+
get accessToken() {
|
|
422
|
+
return this.#accessToken;
|
|
423
|
+
}
|
|
424
|
+
/** Returns the current refresh token. */
|
|
425
|
+
get refreshToken() {
|
|
426
|
+
return this.#refreshToken;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Exchanges the stored refresh token for a fresh access token.
|
|
430
|
+
*
|
|
431
|
+
* Updates the internal credentials on success.
|
|
432
|
+
* Throws if the token endpoint returns a non-200 response.
|
|
433
|
+
*/
|
|
434
|
+
async refresh() {
|
|
435
|
+
const localTime = (/* @__PURE__ */ new Date()).toISOString().replace(/Z$/, "+00:00");
|
|
436
|
+
const headers = {
|
|
437
|
+
"x-client-time": localTime,
|
|
438
|
+
"x-client-hash": buildClientHash(localTime),
|
|
439
|
+
"app-os": "ios",
|
|
440
|
+
"app-os-version": "16.4.1",
|
|
441
|
+
"user-agent": "PixivIOSApp/7.16.9 (iOS 16.4.1; iPad13,4)",
|
|
442
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
443
|
+
};
|
|
444
|
+
const body = new URLSearchParams({
|
|
445
|
+
client_id: CLIENT_ID,
|
|
446
|
+
client_secret: CLIENT_SECRET,
|
|
447
|
+
get_secure_url: "1",
|
|
448
|
+
grant_type: "refresh_token",
|
|
449
|
+
refresh_token: this.#refreshToken
|
|
450
|
+
}).toString();
|
|
451
|
+
const response = await fetch(AUTH_URL, {
|
|
452
|
+
method: "POST",
|
|
453
|
+
headers,
|
|
454
|
+
body
|
|
455
|
+
});
|
|
456
|
+
if (response.status !== 200) {
|
|
457
|
+
throw new Error(
|
|
458
|
+
`Failed to refresh pixiv token: HTTP ${response.status}`
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
const data = await response.json();
|
|
462
|
+
this.#accessToken = data.response.access_token;
|
|
463
|
+
this.#refreshToken = data.response.refresh_token;
|
|
464
|
+
this.userId = data.user.id;
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Creates an `AuthManager` by performing the initial token refresh.
|
|
468
|
+
*
|
|
469
|
+
* @param refreshToken - Pixiv refresh token
|
|
470
|
+
* @returns Initialized `AuthManager`
|
|
471
|
+
*/
|
|
472
|
+
static async login(refreshToken) {
|
|
473
|
+
const manager = new _AuthManager({
|
|
474
|
+
userId: "",
|
|
475
|
+
accessToken: "",
|
|
476
|
+
refreshToken
|
|
477
|
+
});
|
|
478
|
+
await manager.refresh();
|
|
479
|
+
return manager;
|
|
480
|
+
}
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
// src/http.ts
|
|
484
|
+
var DEFAULT_RETRY = { maxRetries: 3, waitMs: 1e4 };
|
|
485
|
+
var BASE_URL = "https://app-api.pixiv.net";
|
|
486
|
+
var DEFAULT_HEADERS = {
|
|
487
|
+
Host: "app-api.pixiv.net",
|
|
488
|
+
"App-OS": "ios",
|
|
489
|
+
"App-OS-Version": "14.6",
|
|
490
|
+
"User-Agent": "PixivIOSApp/7.13.3 (iOS 14.6; iPhone13,2)",
|
|
491
|
+
"Accept-Language": "ja"
|
|
492
|
+
};
|
|
493
|
+
function parseRetryAfter(retryAfter, defaultMs) {
|
|
494
|
+
if (!retryAfter) return defaultMs;
|
|
495
|
+
if (/^\d+$/.test(retryAfter.trim())) {
|
|
496
|
+
return Number.parseInt(retryAfter, 10) * 1e3;
|
|
497
|
+
}
|
|
498
|
+
const retryDate = Date.parse(retryAfter);
|
|
499
|
+
if (!Number.isNaN(retryDate)) {
|
|
500
|
+
return Math.max(0, retryDate - Date.now());
|
|
501
|
+
}
|
|
502
|
+
return defaultMs;
|
|
503
|
+
}
|
|
504
|
+
function headersToRecord(headers) {
|
|
505
|
+
const result = {};
|
|
506
|
+
for (const [key, value] of headers) {
|
|
507
|
+
result[key] = value;
|
|
508
|
+
}
|
|
509
|
+
return result;
|
|
510
|
+
}
|
|
511
|
+
var HttpClient = class {
|
|
512
|
+
#auth;
|
|
513
|
+
#retry;
|
|
514
|
+
#interceptor;
|
|
515
|
+
constructor(auth, options) {
|
|
516
|
+
this.#auth = auth;
|
|
517
|
+
this.#retry = {
|
|
518
|
+
maxRetries: options?.retry?.maxRetries ?? DEFAULT_RETRY.maxRetries,
|
|
519
|
+
waitMs: options?.retry?.waitMs ?? DEFAULT_RETRY.waitMs
|
|
520
|
+
};
|
|
521
|
+
this.#interceptor = options?.onResponse;
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Sends a GET request to the pixiv API.
|
|
525
|
+
*
|
|
526
|
+
* @param path - API endpoint path (e.g. "/v1/illust/detail")
|
|
527
|
+
* @param params - Query parameters as a URLSearchParams instance
|
|
528
|
+
* @returns `ResultAsync<T, PixivError>`
|
|
529
|
+
*/
|
|
530
|
+
get(path, params) {
|
|
531
|
+
const qs = params ? `?${params.toString()}` : "";
|
|
532
|
+
const url = `${BASE_URL}${path}${qs}`;
|
|
533
|
+
return this.#send(url, "GET", path, void 0);
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Sends a POST request to the pixiv API.
|
|
537
|
+
*
|
|
538
|
+
* @param path - API endpoint path (e.g. "/v2/illust/bookmark/add")
|
|
539
|
+
* @param body - URL-encoded request body string
|
|
540
|
+
* @returns `ResultAsync<T, PixivError>`
|
|
541
|
+
*/
|
|
542
|
+
post(path, body) {
|
|
543
|
+
const url = `${BASE_URL}${path}`;
|
|
544
|
+
return this.#send(url, "POST", path, body);
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Fetches a pixiv image URL without an Authorization header.
|
|
548
|
+
*
|
|
549
|
+
* Uses a browser User-Agent and the pixiv Referer, which are required for
|
|
550
|
+
* image CDN access. Retry and interceptor are not applied here.
|
|
551
|
+
*
|
|
552
|
+
* @param imageUrl - Full image URL
|
|
553
|
+
* @returns `ResultAsync<Response, PixivError>`
|
|
554
|
+
*/
|
|
555
|
+
fetchImage(imageUrl) {
|
|
556
|
+
return ResultAsync.fromPromise(
|
|
557
|
+
fetch(imageUrl, {
|
|
558
|
+
headers: {
|
|
559
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36",
|
|
560
|
+
Referer: "https://www.pixiv.net/"
|
|
561
|
+
}
|
|
562
|
+
}),
|
|
563
|
+
networkError
|
|
564
|
+
).andThen((response) => {
|
|
565
|
+
if (!response.ok) {
|
|
566
|
+
return ResultAsync.fromResult(
|
|
567
|
+
err(apiError(response.status, null))
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
return ResultAsync.fromResult(ok(response));
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Sends a request to an absolute URL returned in a `next_url` field.
|
|
575
|
+
*
|
|
576
|
+
* Applies the same retry / interceptor / auth logic as `get()`.
|
|
577
|
+
*
|
|
578
|
+
* @param absoluteUrl - Full URL including query string
|
|
579
|
+
* @returns `ResultAsync<T, PixivError>`
|
|
580
|
+
*/
|
|
581
|
+
getAbsolute(absoluteUrl) {
|
|
582
|
+
let endpoint;
|
|
583
|
+
try {
|
|
584
|
+
endpoint = new URL(absoluteUrl).pathname;
|
|
585
|
+
} catch {
|
|
586
|
+
endpoint = absoluteUrl;
|
|
587
|
+
}
|
|
588
|
+
return this.#send(absoluteUrl, "GET", endpoint, void 0);
|
|
589
|
+
}
|
|
590
|
+
// ---------------------------------------------------------------------------
|
|
591
|
+
// Private helpers
|
|
592
|
+
// ---------------------------------------------------------------------------
|
|
593
|
+
#send(url, method, endpoint, body) {
|
|
594
|
+
return new ResultAsync(this.#sendWithRetry(url, method, endpoint, body));
|
|
595
|
+
}
|
|
596
|
+
async #sendWithRetry(url, method, endpoint, body, allowRefresh = true) {
|
|
597
|
+
const maxRetries = Math.max(0, this.#retry.maxRetries);
|
|
598
|
+
const waitMs = Math.max(0, this.#retry.waitMs);
|
|
599
|
+
let lastRetryAfterMs = 0;
|
|
600
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
601
|
+
const requestHeaders = {
|
|
602
|
+
...DEFAULT_HEADERS,
|
|
603
|
+
Authorization: `Bearer ${this.#auth.accessToken}`,
|
|
604
|
+
...method === "POST" ? { "Content-Type": "application/x-www-form-urlencoded" } : {}
|
|
605
|
+
};
|
|
606
|
+
let response;
|
|
607
|
+
try {
|
|
608
|
+
response = await fetch(url, {
|
|
609
|
+
method,
|
|
610
|
+
headers: requestHeaders,
|
|
611
|
+
body: method === "POST" ? body : void 0
|
|
612
|
+
});
|
|
613
|
+
} catch (fetchError) {
|
|
614
|
+
return err(networkError(fetchError));
|
|
615
|
+
}
|
|
616
|
+
if (response.status === 429) {
|
|
617
|
+
await response.body?.cancel();
|
|
618
|
+
const retryAfterMs = parseRetryAfter(
|
|
619
|
+
response.headers.get("Retry-After"),
|
|
620
|
+
waitMs
|
|
621
|
+
);
|
|
622
|
+
lastRetryAfterMs = retryAfterMs;
|
|
623
|
+
if (attempt < maxRetries) {
|
|
624
|
+
await new Promise((resolve) => setTimeout(resolve, retryAfterMs));
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
return err(rateLimitError(lastRetryAfterMs));
|
|
628
|
+
}
|
|
629
|
+
if (response.status === 401) {
|
|
630
|
+
await response.body?.cancel();
|
|
631
|
+
if (allowRefresh) {
|
|
632
|
+
try {
|
|
633
|
+
await this.#auth.refresh();
|
|
634
|
+
} catch {
|
|
635
|
+
return err(authFailedError(401));
|
|
636
|
+
}
|
|
637
|
+
return this.#sendWithRetry(url, method, endpoint, body, false);
|
|
638
|
+
}
|
|
639
|
+
return err(authFailedError(401));
|
|
640
|
+
}
|
|
641
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
642
|
+
const text = await response.text();
|
|
643
|
+
let data;
|
|
644
|
+
const isJson = contentType.includes("application/json");
|
|
645
|
+
if (isJson) {
|
|
646
|
+
try {
|
|
647
|
+
data = JSON.parse(text);
|
|
648
|
+
} catch {
|
|
649
|
+
data = text;
|
|
650
|
+
}
|
|
651
|
+
} else {
|
|
652
|
+
data = text;
|
|
653
|
+
}
|
|
654
|
+
const responseHeaders = headersToRecord(response.headers);
|
|
655
|
+
if (!response.ok) {
|
|
656
|
+
return err(apiError(response.status, data));
|
|
657
|
+
}
|
|
658
|
+
const httpResponse = {
|
|
659
|
+
data,
|
|
660
|
+
status: response.status,
|
|
661
|
+
responseUrl: response.url || void 0};
|
|
662
|
+
if (this.#interceptor) {
|
|
663
|
+
const record = {
|
|
664
|
+
method,
|
|
665
|
+
endpoint,
|
|
666
|
+
url: response.url || url,
|
|
667
|
+
requestHeaders: JSON.stringify(requestHeaders),
|
|
668
|
+
requestBody: body ?? null,
|
|
669
|
+
responseType: isJson ? "JSON" : "TEXT",
|
|
670
|
+
statusCode: response.status,
|
|
671
|
+
responseHeaders: JSON.stringify(responseHeaders),
|
|
672
|
+
responseBody: isJson ? JSON.stringify(data) : text
|
|
673
|
+
};
|
|
674
|
+
Promise.resolve(this.#interceptor(record)).catch(() => void 0);
|
|
675
|
+
}
|
|
676
|
+
return ok(httpResponse.data);
|
|
677
|
+
}
|
|
678
|
+
return err(rateLimitError(lastRetryAfterMs));
|
|
679
|
+
}
|
|
680
|
+
};
|
|
681
|
+
|
|
682
|
+
// src/params.ts
|
|
683
|
+
function camelToSnake(key) {
|
|
684
|
+
return key.replaceAll(/([A-Z])/g, (m) => `_${m.toLowerCase()}`);
|
|
685
|
+
}
|
|
686
|
+
function toSnakeKeys(obj) {
|
|
687
|
+
const out = {};
|
|
688
|
+
for (const key of Object.keys(obj)) {
|
|
689
|
+
out[camelToSnake(key)] = obj[key];
|
|
690
|
+
}
|
|
691
|
+
return out;
|
|
692
|
+
}
|
|
693
|
+
function buildSearchParams(params) {
|
|
694
|
+
const usp = new URLSearchParams();
|
|
695
|
+
for (const [key, value] of Object.entries(params)) {
|
|
696
|
+
if (value === null || value === void 0) continue;
|
|
697
|
+
if (Array.isArray(value)) {
|
|
698
|
+
for (const item of value) usp.append(key, String(item));
|
|
699
|
+
} else {
|
|
700
|
+
usp.set(key, String(value));
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
return usp;
|
|
704
|
+
}
|
|
705
|
+
function buildParams(params) {
|
|
706
|
+
return buildSearchParams(toSnakeKeys(params));
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// src/resources/illusts.ts
|
|
710
|
+
var IllustResource = class {
|
|
711
|
+
#http;
|
|
712
|
+
constructor(http) {
|
|
713
|
+
this.#http = http;
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* Fetches a single illust by ID.
|
|
717
|
+
* GET /v1/illust/detail
|
|
718
|
+
*
|
|
719
|
+
* @param params - Request parameters
|
|
720
|
+
*/
|
|
721
|
+
detail(params) {
|
|
722
|
+
return this.#http.get(
|
|
723
|
+
"/v1/illust/detail",
|
|
724
|
+
buildParams({ illustId: params.illustId, filter: params.filter ?? "for_ios" })
|
|
725
|
+
);
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* Fetches related illusts for a given illust.
|
|
729
|
+
* GET /v2/illust/related
|
|
730
|
+
*
|
|
731
|
+
* @param params - Request parameters
|
|
732
|
+
*/
|
|
733
|
+
related(params) {
|
|
734
|
+
return PaginatedResultAsync.fromResultAsync(
|
|
735
|
+
this.#http.get(
|
|
736
|
+
"/v2/illust/related",
|
|
737
|
+
buildParams({
|
|
738
|
+
illustId: params.illustId,
|
|
739
|
+
filter: params.filter ?? "for_ios",
|
|
740
|
+
...params.seedIllustIds ? { seedIllustIds: params.seedIllustIds } : {}
|
|
741
|
+
})
|
|
742
|
+
),
|
|
743
|
+
this.#http,
|
|
744
|
+
(page) => page.illusts
|
|
745
|
+
);
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Searches for illusts.
|
|
749
|
+
* GET /v1/search/illust
|
|
750
|
+
*
|
|
751
|
+
* @param params - Request parameters
|
|
752
|
+
*/
|
|
753
|
+
search(params) {
|
|
754
|
+
return PaginatedResultAsync.fromResultAsync(
|
|
755
|
+
this.#http.get(
|
|
756
|
+
"/v1/search/illust",
|
|
757
|
+
buildParams({
|
|
758
|
+
word: params.word,
|
|
759
|
+
searchTarget: params.searchTarget ?? "partial_match_for_tags",
|
|
760
|
+
sort: params.sort ?? "date_desc",
|
|
761
|
+
filter: params.filter ?? "for_ios",
|
|
762
|
+
duration: params.duration,
|
|
763
|
+
startDate: params.startDate,
|
|
764
|
+
endDate: params.endDate,
|
|
765
|
+
searchAiType: params.searchAiType,
|
|
766
|
+
offset: params.offset
|
|
767
|
+
})
|
|
768
|
+
),
|
|
769
|
+
this.#http,
|
|
770
|
+
(page) => page.illusts
|
|
771
|
+
);
|
|
772
|
+
}
|
|
773
|
+
/**
|
|
774
|
+
* Fetches the illust ranking.
|
|
775
|
+
* GET /v1/illust/ranking
|
|
776
|
+
*
|
|
777
|
+
* @param params - Request parameters
|
|
778
|
+
*/
|
|
779
|
+
ranking(params = {}) {
|
|
780
|
+
return PaginatedResultAsync.fromResultAsync(
|
|
781
|
+
this.#http.get(
|
|
782
|
+
"/v1/illust/ranking",
|
|
783
|
+
buildParams({
|
|
784
|
+
mode: params.mode ?? "day",
|
|
785
|
+
filter: params.filter ?? "for_ios",
|
|
786
|
+
date: params.date,
|
|
787
|
+
offset: params.offset
|
|
788
|
+
})
|
|
789
|
+
),
|
|
790
|
+
this.#http,
|
|
791
|
+
(page) => page.illusts
|
|
792
|
+
);
|
|
793
|
+
}
|
|
794
|
+
/**
|
|
795
|
+
* Fetches recommended illusts.
|
|
796
|
+
* GET /v1/illust/recommended
|
|
797
|
+
*
|
|
798
|
+
* @param params - Request parameters
|
|
799
|
+
*/
|
|
800
|
+
recommended(params = {}) {
|
|
801
|
+
return PaginatedResultAsync.fromResultAsync(
|
|
802
|
+
this.#http.get(
|
|
803
|
+
"/v1/illust/recommended",
|
|
804
|
+
buildParams({
|
|
805
|
+
filter: params.filter ?? "for_ios",
|
|
806
|
+
includeRankingLabel: true,
|
|
807
|
+
includeRankingIllusts: true,
|
|
808
|
+
includePrivacyPolicy: true,
|
|
809
|
+
offset: params.offset
|
|
810
|
+
})
|
|
811
|
+
),
|
|
812
|
+
this.#http,
|
|
813
|
+
(page) => page.illusts
|
|
814
|
+
);
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Fetches an illust series.
|
|
818
|
+
* GET /v1/illust/series
|
|
819
|
+
*
|
|
820
|
+
* @param params - Request parameters
|
|
821
|
+
*/
|
|
822
|
+
series(params) {
|
|
823
|
+
return PaginatedResultAsync.fromResultAsync(
|
|
824
|
+
this.#http.get(
|
|
825
|
+
"/v1/illust/series",
|
|
826
|
+
buildParams({
|
|
827
|
+
illustSeriesId: params.illustSeriesId,
|
|
828
|
+
filter: params.filter ?? "for_ios"
|
|
829
|
+
})
|
|
830
|
+
),
|
|
831
|
+
this.#http,
|
|
832
|
+
(page) => page.illusts
|
|
833
|
+
);
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* Adds an illust bookmark.
|
|
837
|
+
* POST /v2/illust/bookmark/add
|
|
838
|
+
*
|
|
839
|
+
* @param params - Request parameters
|
|
840
|
+
*/
|
|
841
|
+
bookmarkAdd(params) {
|
|
842
|
+
const body = buildParams({
|
|
843
|
+
illustId: params.illustId,
|
|
844
|
+
restrict: params.restrict ?? "public",
|
|
845
|
+
...params.tags ? { tags: params.tags } : {}
|
|
846
|
+
});
|
|
847
|
+
return this.#http.post(
|
|
848
|
+
"/v2/illust/bookmark/add",
|
|
849
|
+
body.toString()
|
|
850
|
+
);
|
|
851
|
+
}
|
|
852
|
+
/**
|
|
853
|
+
* Removes an illust bookmark.
|
|
854
|
+
* POST /v1/illust/bookmark/delete
|
|
855
|
+
*
|
|
856
|
+
* @param params - Request parameters
|
|
857
|
+
*/
|
|
858
|
+
bookmarkDelete(params) {
|
|
859
|
+
const body = buildParams({ illustId: String(params.illustId) });
|
|
860
|
+
return this.#http.post(
|
|
861
|
+
"/v1/illust/bookmark/delete",
|
|
862
|
+
body.toString()
|
|
863
|
+
);
|
|
864
|
+
}
|
|
865
|
+
};
|
|
866
|
+
|
|
867
|
+
// src/resources/novels.ts
|
|
868
|
+
var NovelResource = class {
|
|
869
|
+
#http;
|
|
870
|
+
constructor(http) {
|
|
871
|
+
this.#http = http;
|
|
872
|
+
}
|
|
873
|
+
/**
|
|
874
|
+
* Fetches a single novel by ID.
|
|
875
|
+
* GET /v2/novel/detail
|
|
876
|
+
*
|
|
877
|
+
* @param params - Request parameters
|
|
878
|
+
*/
|
|
879
|
+
detail(params) {
|
|
880
|
+
return this.#http.get(
|
|
881
|
+
"/v2/novel/detail",
|
|
882
|
+
buildParams({ novelId: params.novelId })
|
|
883
|
+
);
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* Fetches the WebView HTML for a novel.
|
|
887
|
+
* GET /webview/v2/novel
|
|
888
|
+
*
|
|
889
|
+
* Returns the raw HTML page that the pixiv app renders in a WebView.
|
|
890
|
+
* To extract the plain text, parse the returned HTML (e.g. strip tags).
|
|
891
|
+
*
|
|
892
|
+
* @param params - Request parameters
|
|
893
|
+
*/
|
|
894
|
+
text(params) {
|
|
895
|
+
return this.#http.get(
|
|
896
|
+
"/webview/v2/novel",
|
|
897
|
+
// The webview endpoint uses the query parameter 'id', not 'novel_id'
|
|
898
|
+
buildParams({ id: params.novelId })
|
|
899
|
+
);
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Fetches related novels for a given novel.
|
|
903
|
+
* GET /v1/novel/related
|
|
904
|
+
*
|
|
905
|
+
* @param params - Request parameters
|
|
906
|
+
*/
|
|
907
|
+
related(params) {
|
|
908
|
+
return PaginatedResultAsync.fromResultAsync(
|
|
909
|
+
this.#http.get(
|
|
910
|
+
"/v1/novel/related",
|
|
911
|
+
buildParams({ novelId: params.novelId })
|
|
912
|
+
),
|
|
913
|
+
this.#http,
|
|
914
|
+
(page) => page.novels
|
|
915
|
+
);
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
918
|
+
* Searches for novels.
|
|
919
|
+
* GET /v1/search/novel
|
|
920
|
+
*
|
|
921
|
+
* @param params - Request parameters
|
|
922
|
+
*/
|
|
923
|
+
search(params) {
|
|
924
|
+
return PaginatedResultAsync.fromResultAsync(
|
|
925
|
+
this.#http.get(
|
|
926
|
+
"/v1/search/novel",
|
|
927
|
+
buildParams({
|
|
928
|
+
word: params.word,
|
|
929
|
+
searchTarget: params.searchTarget ?? "partial_match_for_tags",
|
|
930
|
+
sort: params.sort ?? "date_desc",
|
|
931
|
+
filter: params.filter ?? "for_ios",
|
|
932
|
+
duration: params.duration,
|
|
933
|
+
startDate: params.startDate,
|
|
934
|
+
endDate: params.endDate,
|
|
935
|
+
searchAiType: params.searchAiType,
|
|
936
|
+
offset: params.offset
|
|
937
|
+
})
|
|
938
|
+
),
|
|
939
|
+
this.#http,
|
|
940
|
+
(page) => page.novels
|
|
941
|
+
);
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Fetches the novel ranking.
|
|
945
|
+
* GET /v1/novel/ranking
|
|
946
|
+
*
|
|
947
|
+
* @param params - Request parameters
|
|
948
|
+
*/
|
|
949
|
+
ranking(params = {}) {
|
|
950
|
+
return PaginatedResultAsync.fromResultAsync(
|
|
951
|
+
this.#http.get(
|
|
952
|
+
"/v1/novel/ranking",
|
|
953
|
+
buildParams({
|
|
954
|
+
mode: params.mode ?? "day",
|
|
955
|
+
filter: params.filter ?? "for_ios",
|
|
956
|
+
date: params.date,
|
|
957
|
+
offset: params.offset
|
|
958
|
+
})
|
|
959
|
+
),
|
|
960
|
+
this.#http,
|
|
961
|
+
(page) => page.novels
|
|
962
|
+
);
|
|
963
|
+
}
|
|
964
|
+
/**
|
|
965
|
+
* Fetches recommended novels.
|
|
966
|
+
* GET /v1/novel/recommended
|
|
967
|
+
*
|
|
968
|
+
* @param params - Request parameters
|
|
969
|
+
*/
|
|
970
|
+
recommended(params = {}) {
|
|
971
|
+
return PaginatedResultAsync.fromResultAsync(
|
|
972
|
+
this.#http.get(
|
|
973
|
+
"/v1/novel/recommended",
|
|
974
|
+
buildParams({
|
|
975
|
+
filter: params.filter ?? "for_ios",
|
|
976
|
+
includeRankingNovels: true,
|
|
977
|
+
includePrivacyPolicy: true,
|
|
978
|
+
offset: params.offset
|
|
979
|
+
})
|
|
980
|
+
),
|
|
981
|
+
this.#http,
|
|
982
|
+
(page) => page.novels
|
|
983
|
+
);
|
|
984
|
+
}
|
|
985
|
+
/**
|
|
986
|
+
* Fetches a novel series.
|
|
987
|
+
* GET /v2/novel/series
|
|
988
|
+
*
|
|
989
|
+
* @param params - Request parameters
|
|
990
|
+
*/
|
|
991
|
+
series(params) {
|
|
992
|
+
return PaginatedResultAsync.fromResultAsync(
|
|
993
|
+
this.#http.get(
|
|
994
|
+
"/v2/novel/series",
|
|
995
|
+
buildParams({ seriesId: params.seriesId, lastOrder: params.lastOrder })
|
|
996
|
+
),
|
|
997
|
+
this.#http,
|
|
998
|
+
(page) => page.novels
|
|
999
|
+
);
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Adds a novel bookmark.
|
|
1003
|
+
* POST /v2/novel/bookmark/add
|
|
1004
|
+
*
|
|
1005
|
+
* @param params - Request parameters
|
|
1006
|
+
*/
|
|
1007
|
+
bookmarkAdd(params) {
|
|
1008
|
+
const body = buildParams({
|
|
1009
|
+
novelId: params.novelId,
|
|
1010
|
+
restrict: params.restrict ?? "public",
|
|
1011
|
+
...params.tags ? { tags: params.tags } : {}
|
|
1012
|
+
});
|
|
1013
|
+
return this.#http.post(
|
|
1014
|
+
"/v2/novel/bookmark/add",
|
|
1015
|
+
body.toString()
|
|
1016
|
+
);
|
|
1017
|
+
}
|
|
1018
|
+
/**
|
|
1019
|
+
* Removes a novel bookmark.
|
|
1020
|
+
* POST /v1/novel/bookmark/delete
|
|
1021
|
+
*
|
|
1022
|
+
* @param params - Request parameters
|
|
1023
|
+
*/
|
|
1024
|
+
bookmarkDelete(params) {
|
|
1025
|
+
const body = buildParams({ novelId: String(params.novelId) });
|
|
1026
|
+
return this.#http.post(
|
|
1027
|
+
"/v1/novel/bookmark/delete",
|
|
1028
|
+
body.toString()
|
|
1029
|
+
);
|
|
1030
|
+
}
|
|
1031
|
+
};
|
|
1032
|
+
|
|
1033
|
+
// src/resources/users.ts
|
|
1034
|
+
var UserBookmarksResource = class {
|
|
1035
|
+
#http;
|
|
1036
|
+
constructor(http) {
|
|
1037
|
+
this.#http = http;
|
|
1038
|
+
}
|
|
1039
|
+
/**
|
|
1040
|
+
* Fetches a user's bookmarked illusts.
|
|
1041
|
+
* GET /v1/user/bookmarks/illust
|
|
1042
|
+
*
|
|
1043
|
+
* @param params - Request parameters
|
|
1044
|
+
*/
|
|
1045
|
+
illusts(params) {
|
|
1046
|
+
return PaginatedResultAsync.fromResultAsync(
|
|
1047
|
+
this.#http.get(
|
|
1048
|
+
"/v1/user/bookmarks/illust",
|
|
1049
|
+
buildParams({
|
|
1050
|
+
userId: params.userId,
|
|
1051
|
+
restrict: params.restrict ?? "public",
|
|
1052
|
+
filter: params.filter ?? "for_ios",
|
|
1053
|
+
tag: params.tag,
|
|
1054
|
+
maxBookmarkId: params.maxBookmarkId,
|
|
1055
|
+
offset: params.offset
|
|
1056
|
+
})
|
|
1057
|
+
),
|
|
1058
|
+
this.#http,
|
|
1059
|
+
(page) => page.illusts
|
|
1060
|
+
);
|
|
1061
|
+
}
|
|
1062
|
+
/**
|
|
1063
|
+
* Fetches a user's bookmarked novels.
|
|
1064
|
+
* GET /v1/user/bookmarks/novel
|
|
1065
|
+
*
|
|
1066
|
+
* @param params - Request parameters
|
|
1067
|
+
*/
|
|
1068
|
+
novels(params) {
|
|
1069
|
+
return PaginatedResultAsync.fromResultAsync(
|
|
1070
|
+
this.#http.get(
|
|
1071
|
+
"/v1/user/bookmarks/novel",
|
|
1072
|
+
buildParams({
|
|
1073
|
+
userId: params.userId,
|
|
1074
|
+
restrict: params.restrict ?? "public",
|
|
1075
|
+
filter: params.filter ?? "for_ios",
|
|
1076
|
+
tag: params.tag,
|
|
1077
|
+
offset: params.offset
|
|
1078
|
+
})
|
|
1079
|
+
),
|
|
1080
|
+
this.#http,
|
|
1081
|
+
(page) => page.novels
|
|
1082
|
+
);
|
|
1083
|
+
}
|
|
1084
|
+
};
|
|
1085
|
+
var UserResource = class {
|
|
1086
|
+
/** User bookmarks sub-namespace. */
|
|
1087
|
+
bookmarks;
|
|
1088
|
+
#http;
|
|
1089
|
+
constructor(http) {
|
|
1090
|
+
this.#http = http;
|
|
1091
|
+
this.bookmarks = new UserBookmarksResource(http);
|
|
1092
|
+
}
|
|
1093
|
+
/**
|
|
1094
|
+
* Fetches detailed profile information for a user.
|
|
1095
|
+
* GET /v1/user/detail
|
|
1096
|
+
*
|
|
1097
|
+
* @param params - Request parameters
|
|
1098
|
+
*/
|
|
1099
|
+
detail(params) {
|
|
1100
|
+
return this.#http.get(
|
|
1101
|
+
"/v1/user/detail",
|
|
1102
|
+
buildParams({ userId: params.userId, filter: params.filter ?? "for_ios" })
|
|
1103
|
+
);
|
|
1104
|
+
}
|
|
1105
|
+
/**
|
|
1106
|
+
* Fetches illusts posted by a user.
|
|
1107
|
+
* GET /v1/user/illusts
|
|
1108
|
+
*
|
|
1109
|
+
* @param params - Request parameters
|
|
1110
|
+
*/
|
|
1111
|
+
illusts(params) {
|
|
1112
|
+
return PaginatedResultAsync.fromResultAsync(
|
|
1113
|
+
this.#http.get(
|
|
1114
|
+
"/v1/user/illusts",
|
|
1115
|
+
buildParams({
|
|
1116
|
+
userId: params.userId,
|
|
1117
|
+
type: params.type,
|
|
1118
|
+
filter: params.filter ?? "for_ios",
|
|
1119
|
+
offset: params.offset
|
|
1120
|
+
})
|
|
1121
|
+
),
|
|
1122
|
+
this.#http,
|
|
1123
|
+
(page) => page.illusts
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1126
|
+
/**
|
|
1127
|
+
* Fetches novels posted by a user.
|
|
1128
|
+
* GET /v1/user/novels
|
|
1129
|
+
*
|
|
1130
|
+
* @param params - Request parameters
|
|
1131
|
+
*/
|
|
1132
|
+
novels(params) {
|
|
1133
|
+
return PaginatedResultAsync.fromResultAsync(
|
|
1134
|
+
this.#http.get(
|
|
1135
|
+
"/v1/user/novels",
|
|
1136
|
+
buildParams({
|
|
1137
|
+
userId: params.userId,
|
|
1138
|
+
filter: params.filter ?? "for_ios",
|
|
1139
|
+
offset: params.offset
|
|
1140
|
+
})
|
|
1141
|
+
),
|
|
1142
|
+
this.#http,
|
|
1143
|
+
(page) => page.novels
|
|
1144
|
+
);
|
|
1145
|
+
}
|
|
1146
|
+
/**
|
|
1147
|
+
* Fetches the list of users that a user is following.
|
|
1148
|
+
* GET /v1/user/following
|
|
1149
|
+
*
|
|
1150
|
+
* @param params - Request parameters
|
|
1151
|
+
*/
|
|
1152
|
+
following(params) {
|
|
1153
|
+
return PaginatedResultAsync.fromResultAsync(
|
|
1154
|
+
this.#http.get(
|
|
1155
|
+
"/v1/user/following",
|
|
1156
|
+
buildParams({
|
|
1157
|
+
userId: params.userId,
|
|
1158
|
+
restrict: params.restrict ?? "public",
|
|
1159
|
+
offset: params.offset
|
|
1160
|
+
})
|
|
1161
|
+
),
|
|
1162
|
+
this.#http,
|
|
1163
|
+
(page) => page.user_previews
|
|
1164
|
+
);
|
|
1165
|
+
}
|
|
1166
|
+
/**
|
|
1167
|
+
* Follows a user.
|
|
1168
|
+
* POST /v1/user/follow/add
|
|
1169
|
+
*
|
|
1170
|
+
* @param params - Request parameters
|
|
1171
|
+
*/
|
|
1172
|
+
followAdd(params) {
|
|
1173
|
+
const body = buildParams({
|
|
1174
|
+
userId: params.userId,
|
|
1175
|
+
restrict: params.restrict ?? "public"
|
|
1176
|
+
});
|
|
1177
|
+
return this.#http.post(
|
|
1178
|
+
"/v1/user/follow/add",
|
|
1179
|
+
body.toString()
|
|
1180
|
+
);
|
|
1181
|
+
}
|
|
1182
|
+
/**
|
|
1183
|
+
* Unfollows a user.
|
|
1184
|
+
* POST /v1/user/follow/delete
|
|
1185
|
+
*
|
|
1186
|
+
* @param params - Request parameters
|
|
1187
|
+
*/
|
|
1188
|
+
followDelete(params) {
|
|
1189
|
+
const body = buildParams({ userId: String(params.userId) });
|
|
1190
|
+
return this.#http.post(
|
|
1191
|
+
"/v1/user/follow/delete",
|
|
1192
|
+
body.toString()
|
|
1193
|
+
);
|
|
1194
|
+
}
|
|
1195
|
+
};
|
|
1196
|
+
|
|
1197
|
+
// src/resources/manga.ts
|
|
1198
|
+
var MangaResource = class {
|
|
1199
|
+
#http;
|
|
1200
|
+
constructor(http) {
|
|
1201
|
+
this.#http = http;
|
|
1202
|
+
}
|
|
1203
|
+
/**
|
|
1204
|
+
* Fetches recommended manga.
|
|
1205
|
+
* GET /v1/manga/recommended
|
|
1206
|
+
*
|
|
1207
|
+
* @param params - Request parameters
|
|
1208
|
+
*/
|
|
1209
|
+
recommended(params = {}) {
|
|
1210
|
+
return PaginatedResultAsync.fromResultAsync(
|
|
1211
|
+
this.#http.get(
|
|
1212
|
+
"/v1/manga/recommended",
|
|
1213
|
+
buildParams({
|
|
1214
|
+
filter: params.filter ?? "for_ios",
|
|
1215
|
+
includeRankingIllusts: true,
|
|
1216
|
+
includePrivacyPolicy: true,
|
|
1217
|
+
offset: params.offset
|
|
1218
|
+
})
|
|
1219
|
+
),
|
|
1220
|
+
this.#http,
|
|
1221
|
+
(page) => page.illusts
|
|
1222
|
+
);
|
|
1223
|
+
}
|
|
1224
|
+
};
|
|
1225
|
+
|
|
1226
|
+
// src/resources/ugoira.ts
|
|
1227
|
+
var UgoiraResource = class {
|
|
1228
|
+
#http;
|
|
1229
|
+
constructor(http) {
|
|
1230
|
+
this.#http = http;
|
|
1231
|
+
}
|
|
1232
|
+
/**
|
|
1233
|
+
* Fetches ugoira metadata (ZIP URL and per-frame timings).
|
|
1234
|
+
* GET /v1/ugoira/metadata
|
|
1235
|
+
*
|
|
1236
|
+
* @param params - Request parameters
|
|
1237
|
+
*/
|
|
1238
|
+
metadata(params) {
|
|
1239
|
+
return this.#http.get(
|
|
1240
|
+
"/v1/ugoira/metadata",
|
|
1241
|
+
buildParams({ illustId: params.illustId })
|
|
1242
|
+
);
|
|
1243
|
+
}
|
|
1244
|
+
};
|
|
1245
|
+
|
|
1246
|
+
// src/resources/images.ts
|
|
1247
|
+
var ImageResource = class {
|
|
1248
|
+
#http;
|
|
1249
|
+
constructor(http) {
|
|
1250
|
+
this.#http = http;
|
|
1251
|
+
}
|
|
1252
|
+
/**
|
|
1253
|
+
* Fetches a pixiv image.
|
|
1254
|
+
*
|
|
1255
|
+
* Uses a browser User-Agent and Referer (required for pixiv CDN).
|
|
1256
|
+
* No Authorization header is sent.
|
|
1257
|
+
*
|
|
1258
|
+
* @param imageUrl - Full CDN image URL
|
|
1259
|
+
*/
|
|
1260
|
+
fetch(imageUrl) {
|
|
1261
|
+
return this.#http.fetchImage(imageUrl);
|
|
1262
|
+
}
|
|
1263
|
+
};
|
|
1264
|
+
|
|
1265
|
+
// src/client.ts
|
|
1266
|
+
var PixivClient = class _PixivClient {
|
|
1267
|
+
/** Illust API namespace. */
|
|
1268
|
+
illusts;
|
|
1269
|
+
/** Novel API namespace. */
|
|
1270
|
+
novels;
|
|
1271
|
+
/** User API namespace. */
|
|
1272
|
+
users;
|
|
1273
|
+
/** Manga API namespace. */
|
|
1274
|
+
manga;
|
|
1275
|
+
/** Ugoira API namespace. */
|
|
1276
|
+
ugoira;
|
|
1277
|
+
/** Image fetch helpers. */
|
|
1278
|
+
images;
|
|
1279
|
+
#auth;
|
|
1280
|
+
constructor(auth, http) {
|
|
1281
|
+
this.#auth = auth;
|
|
1282
|
+
this.illusts = new IllustResource(http);
|
|
1283
|
+
this.novels = new NovelResource(http);
|
|
1284
|
+
this.users = new UserResource(http);
|
|
1285
|
+
this.manga = new MangaResource(http);
|
|
1286
|
+
this.ugoira = new UgoiraResource(http);
|
|
1287
|
+
this.images = new ImageResource(http);
|
|
1288
|
+
}
|
|
1289
|
+
/**
|
|
1290
|
+
* Numeric user ID of the authenticated account, as a string.
|
|
1291
|
+
*
|
|
1292
|
+
* Available immediately after {@link PixivClient.of} resolves.
|
|
1293
|
+
*/
|
|
1294
|
+
get userId() {
|
|
1295
|
+
return this.#auth.userId;
|
|
1296
|
+
}
|
|
1297
|
+
/**
|
|
1298
|
+
* Creates a PixivClient by refreshing the given token.
|
|
1299
|
+
*
|
|
1300
|
+
* @param refreshToken - Pixiv refresh token
|
|
1301
|
+
* @param options - Optional retry and response interceptor configuration
|
|
1302
|
+
* @returns A fully initialised {@link PixivClient}
|
|
1303
|
+
*/
|
|
1304
|
+
static async of(refreshToken, options) {
|
|
1305
|
+
const auth = await AuthManager.login(refreshToken);
|
|
1306
|
+
const http = new HttpClient(auth, options);
|
|
1307
|
+
return new _PixivClient(auth, http);
|
|
1308
|
+
}
|
|
1309
|
+
};
|
|
1310
|
+
|
|
1311
|
+
exports.PaginatedResultAsync = PaginatedResultAsync;
|
|
1312
|
+
exports.PixivClient = PixivClient;
|
|
1313
|
+
exports.PixivFetchError = PixivFetchError;
|
|
1314
|
+
exports.ResultAsync = ResultAsync;
|
|
1315
|
+
exports.apiError = apiError;
|
|
1316
|
+
exports.authFailedError = authFailedError;
|
|
1317
|
+
exports.err = err;
|
|
1318
|
+
exports.failedPaginated = failedPaginated;
|
|
1319
|
+
exports.networkError = networkError;
|
|
1320
|
+
exports.ok = ok;
|
|
1321
|
+
exports.rateLimitError = rateLimitError;
|