@yamabuki/pixiv-app-api
Version:
Promise base pixiv API client
449 lines • 17.2 kB
JavaScript
"use strict";
var __await = (this && this.__await) || function (v) { return this instanceof __await ? (this.v = v, this) : new __await(v); }
var __asyncGenerator = (this && this.__asyncGenerator) || function (thisArg, _arguments, generator) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var g = generator.apply(thisArg, _arguments || []), i, q = [];
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
function fulfill(value) { resume("next", value); }
function reject(value) { resume("throw", value); }
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const querystring_1 = require("querystring");
const crypto_1 = require("crypto");
const url_1 = require("url");
const axios_1 = __importDefault(require("axios"));
const decamelize_keys_1 = __importDefault(require("decamelize-keys"));
const camelcase_keys_1 = __importDefault(require("camelcase-keys"));
const baseURL = 'https://app-api.pixiv.net/';
// const instance = axios.create({
// baseURL,
// headers: {
// 'App-OS': 'ios',
// 'App-OS-Version': '9.3.3',
// 'App-Version': '6.0.9',
// },
// })
const CLIENT_ID = 'MOBrBDS8blbauoSck0ZfDbtuzpyT';
const CLIENT_SECRET = 'lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj';
const HASH_SECRET = '28c1fdd170a5204386cb1313c7077b34f83e4aaf4aa829ce78c231e05b0bae2c';
const filter = 'for_ios';
class PixivApp {
constructor(
// username?: string,
// password?: string,
httpsAgent, options) {
Object.defineProperty(this, "camelcaseKeys", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "username", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "password", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "refreshToken", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "nextUrl", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "auth", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "instance", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "_once", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
// this.username = username
// this.password = password
this.refreshToken = '';
this.nextUrl = null;
this.auth = null;
this._once = false;
this.instance = axios_1.default.create({
baseURL: baseURL,
headers: {
'App-OS': 'ios',
'App-OS-Version': '9.3.3',
'App-Version': '6.0.9',
},
httpAgent: httpsAgent,
httpsAgent: httpsAgent,
});
if (options) {
this.camelcaseKeys = Boolean(options.camelcaseKeys);
}
else {
this.camelcaseKeys = true;
}
}
async login(
// username?: string,
// password?: string
refreshToken) {
// this.username = username || this.username
// this.password = password || this.password
// if (typeof this.username !== 'string') {
// return Promise.reject(
// new TypeError(
// `Auth is required. Expected a string, got ${typeof this.username}`
// )
// )
// }
// if (typeof this.password !== 'string') {
// return Promise.reject(
// new TypeError(
// `Auth is required. Expected a string, got ${typeof this.password}`
// )
// )
// }
this.refreshToken = refreshToken || this.refreshToken;
if (this.refreshToken == '') {
return Promise.reject(new TypeError(`Auth is required.`));
}
const now_time = new Date();
const local_time = `${now_time.getUTCFullYear()}-${now_time.getUTCMonth() + 1}-${now_time.getUTCDate()}T${now_time
.getUTCHours()
.toString()
.padStart(2, '0')}:${now_time
.getUTCMinutes()
.toString()
.padStart(2, '0')}:${now_time
.getUTCSeconds()
.toString()
.padStart(2, '0')}+00:00`;
const headers = {
"user-agent": "PixivIOSApp/7.7.5 (iOS 13.2.0; iPhone XR)",
"host": "oauth.secure.pixiv.net",
"accept-language": "en_US",
'X-Client-Time': local_time,
'X-Client-Hash': crypto_1.createHash('md5')
.update(Buffer.from(`${local_time}${HASH_SECRET}`, 'utf8'))
.digest('hex'),
"content-type": "application/x-www-form-urlencoded",
"accept-encoding": "gzip"
};
const data = {
clientId: CLIENT_ID,
clientSecret: CLIENT_SECRET,
getSecureUrl: '1',
grantType: '',
username: '',
password: '',
refreshToken: '',
};
// if (this.refreshToken === '') {
// data.grantType = 'password'
// data.username = this.username
// data.password = this.password
// } else {
// data.grantType = 'refresh_token'
// data.refreshToken = this.refreshToken
// }
data.grantType = 'refresh_token';
data.refreshToken = this.refreshToken;
const axiosResponse = await this.instance.post('https://oauth.secure.pixiv.net/auth/token', querystring_1.stringify(decamelize_keys_1.default(data)), { headers });
const { response } = axiosResponse.data;
this.auth = response;
this.refreshToken = axiosResponse.data.response.refresh_token;
this.authToken = response.access_token;
return this.camelcaseKeys
? camelcase_keys_1.default(response, { deep: true })
: response;
}
authInfo() {
return this.camelcaseKeys
? camelcase_keys_1.default(this.auth, {
deep: true,
})
: this.auth;
}
// eslint-disable-next-line class-methods-use-this
set authToken(accessToken) {
this.instance.defaults.headers.common.Authorization = `Bearer ${accessToken}`;
}
hasNext() {
return Boolean(this.nextUrl);
}
next() {
return this.fetch(this.nextUrl);
}
nextQuery() {
// This always returns undefined
// @ts-ignore
return url_1.parse(this.nextUrl, true).params;
}
makeIterable(resp) {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const self = this;
const nextUrl = this.camelcaseKeys ? 'nextUrl' : 'next_url';
return {
[Symbol.asyncIterator]() {
return __asyncGenerator(this, arguments, function* _a() {
yield yield __await(resp);
while (resp[nextUrl]) {
// eslint-disable-next-line require-atomic-updates
resp = yield __await(self.fetch(resp[nextUrl]));
yield yield __await(resp);
}
});
},
};
}
userDetail(id, params) {
params = Object.assign({ userId: id, filter }, params);
return this.fetch('/v1/user/detail', { params });
}
userIllusts(id, params) {
params = Object.assign({ userId: id, type: 'illust', filter }, params);
return this.fetch('/v1/user/illusts', { params });
}
// This endpoint doesn't exist
userFollowAdd(id, params) {
if (!id) {
return Promise.reject(new Error('userId required'));
}
params = Object.assign({ userId: id, restrict: 'public', filter }, params);
return this.fetch('/v1/user/follow/add', { params });
}
// This endpoint doesn't exist
userFollowDelete(id, params) {
if (!id) {
return Promise.reject(new Error('userId required'));
}
params = Object.assign({ userId: id, restrict: 'public', filter }, params);
return this.fetch('/v1/user/follow/delete', { params });
}
userBookmarksIllust(id, params) {
if (!id) {
return Promise.reject(new Error('userId required'));
}
params = Object.assign({ userId: id, restrict: 'public', filter }, params);
return this.fetch('/v1/user/bookmarks/illust', { params });
}
userFollowing(id, params) {
if (!id) {
return Promise.reject(new Error('userId required'));
}
params = Object.assign({ userId: id, restrict: 'public' }, params);
return this.fetch('/v1/user/following', { params });
}
userFollower(id, params) {
if (!id) {
return Promise.reject(new Error('userId required'));
}
params = Object.assign({ userId: id }, params);
return this.fetch('/v1/user/follower', { params });
}
userMypixiv(id, params) {
if (!id) {
return Promise.reject(new Error('userId required'));
}
params = Object.assign({ userId: id }, params);
return this.fetch('/v1/user/mypixiv', { params });
}
// This endpoint doesn't exist
userList(id, params) {
if (!id) {
return Promise.reject(new Error('userId required'));
}
params = Object.assign({ userId: id, filter }, params);
return this.fetch('/v1/user/list', { params });
}
illustDetail(id, params) {
if (!id) {
return Promise.reject(new Error('illustId required'));
}
params = Object.assign({ illustId: id, filter }, params);
return this.fetch('/v1/illust/detail', { params });
}
illustNew(params) {
params = Object.assign({ contentType: 'illust', filter }, params);
return this.fetch('/v1/illust/new', { params });
}
illustFollow(id, params) {
params = Object.assign({ userId: id, restrict: 'public' }, params);
return this.fetch('/v2/illust/follow', { params });
}
illustComments(id, params) {
if (!id) {
return Promise.reject(new Error('illustId required'));
}
params = Object.assign({ illustId: id, includeTotalComments: true }, params);
return this.fetch('/v1/illust/comments', { params });
}
illustRelated(id, params) {
if (!id) {
return Promise.reject(new Error('illustId required'));
}
params = Object.assign({ illustId: id, filter }, params);
return this.fetch('/v2/illust/related', { params });
}
illustRecommended(params) {
params = Object.assign({ contentType: 'illust', includeRankingLabel: true, filter }, params);
return this.fetch('/v1/illust/recommended', { params });
}
illustRecommendedNologin(params) {
params = Object.assign({ includeRankingIllusts: true, filter }, params);
return this.fetch('/v1/illust/recommended-nologin', { params });
}
illustRanking(params) {
params = Object.assign({ mode: 'day', filter }, params);
return this.fetch('/v1/illust/ranking', { params });
}
trendingTagsIllust(params) {
params = Object.assign({ filter }, params);
return this.fetch('/v1/trending-tags/illust', { params });
}
searchIllust(word, params) {
if (!word) {
return Promise.reject(new Error('Word required'));
}
params = Object.assign({ word, searchTarget: 'partial_match_for_tags', sort: 'date_desc', filter }, params);
return this.fetch('/v1/search/illust', { params });
}
searchNovel(word, params) {
if (!word) {
return Promise.reject(new Error('Word required'));
}
params = Object.assign({ word, searchTarget: 'partial_match_for_tags', sort: 'date_desc', filter }, params);
return this.fetch('/v1/search/novel', { params });
}
searchUser(word, params) {
if (!word) {
return Promise.reject(new Error('Word required'));
}
params = Object.assign({ word,
filter }, params);
return this.fetch('/v1/search/user', { params });
}
searchAutoComplete(word) {
if (!word) {
return Promise.reject(new Error('word required'));
}
return this.fetch('/v1/search/autocomplete', { params: { word } });
}
illustBookmarkDetail(id, params) {
if (!id) {
return Promise.reject(new Error('illustId required'));
}
params = Object.assign({ illustId: id }, params);
return this.fetch('/v2/illust/bookmark/detail', { params });
}
illustBookmarkAdd(id, params) {
if (!id) {
return Promise.reject(new Error('illustId required'));
}
params = Object.assign({ illustId: id, restrict: 'public' }, params);
return this.fetch('/v2/illust/bookmark/add', { data: params });
}
illustBookmarkDelete(id, params) {
if (!id) {
return Promise.reject(new Error('illustId required'));
}
params = Object.assign({ illustId: id }, params);
return this.fetch('/v1/illust/bookmark/delete', { data: params });
}
userBookmarkTagsIllust(params) {
params = Object.assign({ restrict: 'public' }, params);
return this.fetch('/v1/user/bookmark-tags/illust', { params });
}
novelRecommended(params) {
params = Object.assign({ includeRankingNovels: true, filter }, params);
return this.fetch('/v1/novel/recommended', { params });
}
// This endpoint doesn't exist
mangaNew(params) {
params = Object.assign({ contentType: 'manga', filter }, params);
return this.fetch('/v1/manga/new', { params });
}
mangaRecommended(params) {
params = Object.assign({ includeRankingLabel: true, filter }, params);
return this.fetch('/v1/manga/recommended', { params });
}
novelRecommendedNologin(params) {
params = Object.assign({ includeRankingNovels: true, filter }, params);
return this.fetch('/v1/novel/recommended-nologin', { params });
}
novelNew(params) {
params = Object.assign({ filter }, params);
return this.fetch('/v1/novel/new', { params });
}
ugoiraMetaData(id, params) {
if (!id) {
return Promise.reject(new Error('illustId required'));
}
params = Object.assign({ illustId: id, filter }, params);
return this.fetch('/v1/ugoira/metadata', { params });
}
async fetch(target, options) {
if (!target) {
return Promise.reject(new Error('url required'));
}
try {
return this._get(target, options);
}
catch (error) {
if (this._once) {
this._once = false;
throw error;
}
await this.login();
this._once = true;
return this._get(target, options);
}
}
async _get(target, options = {}) {
options = options || {};
if (options.data) {
options.method = 'post';
options.headers = {
'Content-Type': 'application/x-www-form-urlencoded',
};
options.data = querystring_1.stringify(decamelize_keys_1.default(options.data));
}
if (options.params) {
options.params = decamelize_keys_1.default(options.params);
}
const { data } = await this.instance(target, options);
this.nextUrl = data && data.next_url ? data.next_url : null;
return this.camelcaseKeys ? camelcase_keys_1.default(data, { deep: true }) : data;
}
}
exports.default = PixivApp;
module.exports.default = PixivApp;
module.exports = PixivApp;
//# sourceMappingURL=index.js.map