@ejnshtein/nyaasi
Advanced tools
Comparing version 2.2.3 to 3.0.1
@@ -1,27 +0,13 @@ | ||
import { RequestOptions, RequestResult } from '@ejnshtein/smol-request'; | ||
import { AgentOptions, Cookie, NyaaApiRequestResult, NyaaRequestOptions } from '../types'; | ||
import { RequestResult, ResponseType, ResponseTypeMap } from 'smol-request'; | ||
import { AgentOptions, NyaaRequestOptions } from '../types/agent'; | ||
export declare class Agent { | ||
sessionId?: string; | ||
persistentId?: string; | ||
host: string; | ||
apiHost: string; | ||
_cookies: Cookie[]; | ||
sessionId?: string; | ||
constructor({ host, apiHost }?: AgentOptions); | ||
get cookies(): string[]; | ||
setCookies(cookies: Cookie[]): void; | ||
getCookies(): string[]; | ||
login(username: string, password: string, options?: RequestOptions): Promise<boolean>; | ||
static login(username: string, password: string, options?: RequestOptions & { | ||
baseUrl: string; | ||
}): Promise<Cookie[]>; | ||
_onDeleteSession(): Promise<{ | ||
result: string; | ||
}>; | ||
loginWithSession(path: string): Promise<boolean>; | ||
checkLogin(): Promise<boolean>; | ||
saveSession(path: string): Promise<boolean>; | ||
static saveSession(path: string, cookies: string[]): Promise<boolean>; | ||
call(url?: string, options?: {}): Promise<string>; | ||
callApi<T>(url?: string, options?: {}): Promise<NyaaApiRequestResult<T>>; | ||
static call(url: string, options?: NyaaRequestOptions): Promise<RequestResult>; | ||
static callApi<T>(url: string, options?: NyaaRequestOptions): Promise<NyaaApiRequestResult<T>>; | ||
call<K, T extends ResponseType = 'text'>(url?: string, options?: NyaaRequestOptions<T>): Promise<NonNullable<ResponseTypeMap<K>[T]>>; | ||
callApi<T>(url?: string, options?: NyaaRequestOptions<'json'>): Promise<T>; | ||
static call<K, T extends ResponseType = 'text'>(url: string, options?: NyaaRequestOptions<T>): Promise<RequestResult<NonNullable<ResponseTypeMap<K>[T]>>>; | ||
static callApi<T>(url: string, options?: NyaaRequestOptions<'json'>): Promise<T>; | ||
} |
@@ -16,35 +16,7 @@ "use strict"; | ||
exports.Agent = void 0; | ||
const smol_request_1 = __importDefault(require("@ejnshtein/smol-request")); | ||
const deepmerge_1 = __importDefault(require("deepmerge")); | ||
const cheerio_1 = __importDefault(require("cheerio")); | ||
const smol_request_1 = require("smol-request"); | ||
const fs_1 = __importDefault(require("fs")); | ||
const Scraper_1 = require("./Scraper"); | ||
const querystring_1 = require("querystring"); | ||
const { version: packageVersion } = JSON.parse(fs_1.default.readFileSync('./package.json', 'utf-8')); | ||
const parseCookies = (cookies) => cookies.map((cookie) => cookie.split('; ').reduce((cookie, property) => { | ||
switch (true) { | ||
case property.toLowerCase().includes('domain'): { | ||
return Object.assign(Object.assign({}, cookie), { domain: property.split('=').pop() }); | ||
} | ||
case property.toLowerCase().includes('expires'): { | ||
return Object.assign(Object.assign({}, cookie), { expires: new Date(property.split('=').pop()) }); | ||
} | ||
case property.toLowerCase().includes('httponly'): { | ||
return Object.assign(Object.assign({}, cookie), { httponly: true }); | ||
} | ||
case property.includes('='): { | ||
return property.split('=').map((el, i) => { | ||
if (i === 0) { | ||
return el.toLowerCase(); | ||
} | ||
return el; | ||
}); | ||
} | ||
} | ||
return cookie; | ||
}, {})); | ||
const cookiesToString = (cookies) => cookies.map((cookie) => { | ||
const [name] = Object.keys(cookie).filter((key) => !['domain', 'httponly', 'expires', 'path'].includes(key)); | ||
return `${name}=${cookie[name]}`; | ||
}); | ||
const path_1 = __importDefault(require("path")); | ||
const deepmerge_1 = require("./lib/deepmerge"); | ||
const pkg = JSON.parse(fs_1.default.readFileSync(path_1.default.join(__dirname, '..', 'package.json'), 'utf-8')); | ||
class Agent { | ||
@@ -55,115 +27,7 @@ constructor({ host = 'https://nyaa.si', apiHost = 'https://nyaa.si/api' } = {}) { | ||
} | ||
get cookies() { | ||
return cookiesToString(this._cookies); | ||
} | ||
setCookies(cookies) { | ||
this._cookies = cookies | ||
.reduce((cookies, cookie) => { | ||
const [name] = Object.entries(cookie).pop(); | ||
if (cookies.some((cookie) => typeof cookie[name] === 'string')) { | ||
const i = cookies.findIndex((cookie) => cookie[name]); | ||
cookies[i] = cookie; | ||
} | ||
else { | ||
cookies.push(cookie); | ||
} | ||
return cookies; | ||
}, this._cookies || []) | ||
.filter((cookie) => { | ||
if (!cookie.expires) { | ||
return true; | ||
} | ||
return (cookie.expires.getTime() !== 0 || | ||
cookie.expires.getTime() > Date.now()); | ||
}); | ||
} | ||
getCookies() { | ||
return cookiesToString(this._cookies); | ||
} | ||
login(username, password, options) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const cookies = yield Agent.login(username, password, Object.assign({ baseUrl: this.host }, options)); | ||
this.setCookies(cookies); | ||
return this.checkLogin(); | ||
}); | ||
} | ||
static login(username, password, options) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!username || !password) { | ||
throw new Error('Not enough login info.'); | ||
} | ||
const payload = { | ||
username: username, | ||
password: password | ||
}; | ||
const { data: tmpData, headers: tmpHeaders } = yield smol_request_1.default(`${options.baseUrl || 'https://nyaa.si'}/login`); | ||
payload.csrf_token = Scraper_1.getCSRFToken(tmpData); | ||
const tmpCookies = parseCookies(tmpHeaders['set-cookie']); | ||
const { headers, data } = yield smol_request_1.default(`${options.baseUrl || 'https://nyaa.si'}/login`, { | ||
method: 'POST', | ||
headers: { | ||
'User-Agent': `nyaa-api/${packageVersion}`, | ||
'Content-Type': 'application/x-www-form-urlencoded', | ||
Cookie: cookiesToString(tmpCookies).join('; ') | ||
} | ||
}, querystring_1.stringify(payload)); | ||
const cookies = parseCookies(headers['set-cookie']); | ||
if (!cookies.some((cookie) => cookie.session)) { | ||
const errorText = cheerio_1.default.load(data)('div').text(); | ||
if (errorText) { | ||
throw new Error(errorText); | ||
} | ||
throw new Error('Failed to retrieve session id.'); | ||
} | ||
return cookies; | ||
}); | ||
} | ||
_onDeleteSession() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
this.sessionId = null; | ||
yield this.call('/logout'); | ||
return { result: 'logout' }; | ||
}); | ||
} | ||
loginWithSession(path) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const file = yield fs_1.default.promises.readFile(path, 'utf8'); | ||
const cookies = file.split('\n'); | ||
this.setCookies(parseCookies(cookies)); | ||
const isLogin = this.checkLogin(); | ||
return isLogin; | ||
}); | ||
} | ||
checkLogin() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const result = yield this.call('profile'); | ||
const isLogin = Scraper_1.parseProfile(result); | ||
return Boolean(isLogin); | ||
}); | ||
} | ||
saveSession(path) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return Agent.saveSession(path, this.cookies); | ||
}); | ||
} | ||
static saveSession(path, cookies) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
yield fs_1.default.promises.writeFile(path, cookies.join('\n'), 'utf8'); | ||
return true; | ||
}); | ||
} | ||
call(url = '', options = {}) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const result = yield Agent.call(url, deepmerge_1.default.all([ | ||
{ | ||
baseUrl: this.host, | ||
headers: { | ||
Cookie: this.cookies.join('; ') | ||
} | ||
}, | ||
options | ||
])); | ||
if (result.headers['set-cookie']) { | ||
this.setCookies(parseCookies(result.headers['set-cookie'])); | ||
} | ||
const result = yield Agent.call(url, deepmerge_1.deepmerge({ | ||
baseUrl: this.host | ||
}, options)); | ||
return result.data; | ||
@@ -175,5 +39,2 @@ }); | ||
const result = yield Agent.callApi(url, Object.assign({ baseUrl: this.apiHost, responseType: 'json' }, options)); | ||
if (result.status === 'error') { | ||
throw new Error(result.message); | ||
} | ||
return result; | ||
@@ -185,15 +46,8 @@ }); | ||
const finalUrl = `${options.baseUrl || 'https://nyaa.si'}${!(url.startsWith('/') && options.baseUrl.endsWith('/')) && '/'}${url}`; | ||
const finalOptions = deepmerge_1.default.all([ | ||
{ | ||
method: 'GET', | ||
headers: { | ||
'User-Agent': `nyaa-api/${packageVersion}` | ||
} | ||
}, | ||
options | ||
]); | ||
const result = yield smol_request_1.default(finalUrl, finalOptions); | ||
if (result.data.errors) { | ||
throw new Error(result.data.errors[0]); | ||
} | ||
const result = yield smol_request_1.request(finalUrl, deepmerge_1.deepmerge({ | ||
method: 'GET', | ||
headers: { | ||
'User-Agent': `nyaa-api/${pkg.version}` | ||
} | ||
}, options)); | ||
return result; | ||
@@ -204,4 +58,9 @@ }); | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const result = yield Agent.call(`api${!url.startsWith('/') && '/'}${url}`, Object.assign({ responseType: 'json' }, options)); | ||
return result; | ||
const { data: response } = yield Agent.call(url, deepmerge_1.deepmerge({ | ||
baseUrl: 'https://nyaa.si/api' | ||
}, options, { responseType: 'json' })); | ||
if (response.status === 'error') { | ||
throw new Error(response.message); | ||
} | ||
return response.data; | ||
}); | ||
@@ -208,0 +67,0 @@ } |
@@ -5,2 +5,1 @@ export * from './Agent'; | ||
export * as Scraper from './Scraper'; | ||
export * from '../types/index'; |
@@ -30,2 +30,1 @@ "use strict"; | ||
exports.Scraper = __importStar(require("./Scraper")); | ||
__exportStar(require("../types/index"), exports); |
@@ -1,4 +0,4 @@ | ||
import { AgentOptions, GetTorrentOptions, NyaaApiRequestResult, NyaaRequestOptions, SearchOptions } from '../types'; | ||
import { AgentOptions, GetTorrentOptions, NyaaRequestOptions, SearchQuery } from '../types/agent'; | ||
import { Agent } from './Agent'; | ||
import { Profile, SearchResult, ViewTorrent } from '../types/nyaa'; | ||
import { SearchResult, ViewTorrent } from '../types/nyaa'; | ||
export declare class Nyaa { | ||
@@ -8,10 +8,6 @@ options: AgentOptions; | ||
constructor(options?: AgentOptions); | ||
getMe(): Promise<Profile>; | ||
search(query: string, options?: SearchOptions, params?: NyaaRequestOptions): Promise<SearchResult>; | ||
static search(query: string, options?: SearchOptions, params?: NyaaRequestOptions): Promise<SearchResult>; | ||
getTorrent(id: number, options?: GetTorrentOptions): Promise<NyaaApiRequestResult<ViewTorrent>>; | ||
static getTorrent(id: number, options?: GetTorrentOptions, params?: NyaaRequestOptions): Promise<ViewTorrent>; | ||
search(query: string | SearchQuery, options?: NyaaRequestOptions<'text'>): Promise<SearchResult>; | ||
static search(query: string | SearchQuery, options?: NyaaRequestOptions<'text'>): Promise<SearchResult>; | ||
getTorrentAnonymous(id: number, options?: GetTorrentOptions, params?: {}): Promise<ViewTorrent>; | ||
static getTorrentAnonymous(id: number, options?: GetTorrentOptions, params?: NyaaRequestOptions): Promise<ViewTorrent>; | ||
static getTorrentAnonymous(id: number, args?: GetTorrentOptions, options?: NyaaRequestOptions<'text'>): Promise<ViewTorrent>; | ||
} | ||
export default Nyaa; |
104
dist/Nyaa.js
@@ -11,10 +11,8 @@ "use strict"; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Nyaa = void 0; | ||
const deepmerge_1 = __importDefault(require("deepmerge")); | ||
const Scraper_1 = require("./Scraper"); | ||
const Agent_1 = require("./Agent"); | ||
const deepmerge_1 = require("./lib/deepmerge"); | ||
const get_params_1 = require("./lib/get-params"); | ||
const DefaultOptions = { | ||
@@ -25,64 +23,47 @@ host: 'https://nyaa.si', | ||
class Nyaa { | ||
constructor(options) { | ||
this.options = Object.assign({}, DefaultOptions, options); | ||
constructor(options = {}) { | ||
this.options = deepmerge_1.deepmerge(DefaultOptions, options); | ||
this.agent = new Agent_1.Agent(this.options); | ||
} | ||
getMe() { | ||
search(query, options = {}) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const result = yield this.agent.call('profile'); | ||
return Scraper_1.parseProfile(result); | ||
}); | ||
} | ||
search(query, options = { filter: 0, category: '0_0' }, params = {}) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const search = { | ||
q: query, | ||
f: (typeof options.filter !== 'undefined' && options.filter) || 0, | ||
c: (typeof options.filter !== 'undefined' && options.category) || '0_0' | ||
}; | ||
const result = yield this.agent.call('', deepmerge_1.default.all([ | ||
{ | ||
params: search | ||
}, | ||
params | ||
])); | ||
const searchParams = get_params_1.getParams(query); | ||
const result = yield this.agent.call('', deepmerge_1.deepmerge(options, { | ||
params: searchParams | ||
})); | ||
return Scraper_1.parseSearch(result, this.options.host); | ||
}); | ||
} | ||
static search(query, options = { filter: 0, category: '0_0' }, params = {}) { | ||
static search(query, options = {}) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const search = { | ||
q: query, | ||
f: (typeof options.filter !== 'undefined' && options.filter) || 0, | ||
c: (typeof options.filter !== 'undefined' && options.category) || '0_0' | ||
}; | ||
const result = yield Agent_1.Agent.call('', deepmerge_1.default.all([ | ||
{ | ||
params: search | ||
}, | ||
params | ||
])); | ||
return Scraper_1.parseSearch(params.baseUrl || 'https://nyaa.si', result.data); | ||
const searchParams = get_params_1.getParams(query); | ||
const result = yield Agent_1.Agent.call('', deepmerge_1.deepmerge(options, { | ||
params: searchParams | ||
})); | ||
return Scraper_1.parseSearch(result.data, options.baseUrl || 'https://nyaa.si'); | ||
}); | ||
} | ||
getTorrent(id, options = { withComments: false }) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const result = yield this.agent.callApi(`info/${id}`); | ||
if (options.withComments) { | ||
const comments = yield this.agent.call(`view/${id}`); | ||
result.data.comments = Scraper_1.parseComments(comments); | ||
} | ||
return result; | ||
}); | ||
} | ||
static getTorrent(id, options = { withComments: false }, params = {}) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const result = yield Agent_1.Agent.callApi(`info/${id}`, params); | ||
if (options.withComments) { | ||
const comments = yield Agent_1.Agent.call(`view/${id}`, params); | ||
result.data.comments = Scraper_1.parseComments(comments.data); | ||
} | ||
return result.data; | ||
}); | ||
} | ||
// async getTorrent( | ||
// id: number, | ||
// options: GetTorrentOptions = { withComments: false } | ||
// ): Promise<ViewTorrent> { | ||
// const result = await this.agent.callApi<ViewTorrent>(`info/${id}`) | ||
// if (options.withComments) { | ||
// const comments = await this.agent.call(`view/${id}`) | ||
// result.comments = parseComments(comments) | ||
// } | ||
// return result | ||
// } | ||
// static async getTorrent( | ||
// id: number, | ||
// options: GetTorrentOptions = { withComments: false }, | ||
// params: NyaaRequestOptions<'json'> = {} | ||
// ): Promise<ViewTorrent> { | ||
// const result = await Agent.callApi<ViewTorrent>(`info/${id}`, params) | ||
// if (options.withComments) { | ||
// const comments = await Agent.call(`view/${id}`, params) | ||
// result.comments = parseComments(comments.data as string) | ||
// } | ||
// return result | ||
// } | ||
getTorrentAnonymous(id, options = { withComments: false }, params = {}) { | ||
@@ -93,7 +74,7 @@ return __awaiter(this, void 0, void 0, function* () { | ||
} | ||
static getTorrentAnonymous(id, options = { withComments: false }, params = {}) { | ||
static getTorrentAnonymous(id, args = { withComments: false }, options = {}) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const result = yield Agent_1.Agent.call(`view/${id}`, params); | ||
const parsed = Scraper_1.parseTorrent(id, params.baseUrl, result.data); | ||
if (options.withComments) { | ||
const result = yield Agent_1.Agent.call(`view/${id}`, options); | ||
const parsed = Scraper_1.parseTorrent(id, result.data); | ||
if (args.withComments) { | ||
parsed.comments = Scraper_1.parseComments(result.data); | ||
@@ -106,2 +87,1 @@ } | ||
exports.Nyaa = Nyaa; | ||
exports.default = Nyaa; |
@@ -1,4 +0,4 @@ | ||
import RssParser from 'rss-parser'; | ||
import { RSSFile } from '../types/nyaa'; | ||
export declare class NyaaRss { | ||
static get(): Promise<RssParser.Output>; | ||
static get(): Promise<RSSFile[]>; | ||
} |
@@ -17,2 +17,3 @@ "use strict"; | ||
const rss_parser_1 = __importDefault(require("rss-parser")); | ||
const html_entities_1 = require("html-entities"); | ||
const parser = new rss_parser_1.default({ | ||
@@ -30,4 +31,6 @@ customFields: { | ||
'nyaa:remake', | ||
'nyaa:comments', | ||
'description', | ||
'guid' | ||
'guid', | ||
'title' | ||
] | ||
@@ -40,6 +43,20 @@ } | ||
const data = yield parser.parseURL('https://nyaa.si/?page=rss'); | ||
data.items.forEach((el) => { | ||
el.id = Number.parseInt(el.guid.split('/').pop()); | ||
}); | ||
return data; | ||
const rssFiles = data.items.map((el) => ({ | ||
id: Number.parseInt(el.guid.split('/').pop()), | ||
title: html_entities_1.decode(el.title), | ||
guid: el.guid, | ||
description: el.description, | ||
pubDate: new Date(el.pubDate), | ||
seeders: parseInt(el['nyaa:seeders']), | ||
leechers: parseInt(el['nyaa:leechers']), | ||
downloads: parseInt(el['nyaa:downloads']), | ||
infoHash: el['nyaa:infoHash'], | ||
categoryId: el['nyaa:categoryId'], | ||
category: el['nyaa:category'], | ||
size: el['nyaa:size'], | ||
comments: parseInt(el['nyaa:comments']), | ||
trusted: el['nyaa:trusted'], | ||
remake: el['nyaa:remake'] | ||
})); | ||
return rssFiles; | ||
}); | ||
@@ -46,0 +63,0 @@ } |
@@ -1,7 +0,5 @@ | ||
import { Comment, Entry, Profile, SearchResult, ViewTorrent } from '../types/nyaa'; | ||
export declare const getCSRFToken: (html: string) => string; | ||
export declare const parseProfile: (html: string) => Profile; | ||
import { Comment, Entry, SearchResult, ViewTorrent } from '../types/nyaa'; | ||
export declare const parseComments: (html: string) => Comment[]; | ||
export declare const parseSearch: (html: string, host?: string) => SearchResult; | ||
export declare const parseTorrent: (id: number, html: string, host?: string) => ViewTorrent; | ||
export declare const parseTorrent: (id: number, html: string) => ViewTorrent; | ||
export declare function getEntry(entry: string): Entry; |
@@ -6,27 +6,36 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getEntry = exports.parseTorrent = exports.parseSearch = exports.parseComments = exports.parseProfile = exports.getCSRFToken = void 0; | ||
exports.getEntry = exports.parseTorrent = exports.parseSearch = exports.parseComments = void 0; | ||
const url_1 = require("url"); | ||
const cheerio_1 = __importDefault(require("cheerio")); | ||
const bytes_iec_1 = __importDefault(require("bytes-iec")); | ||
const url_1 = require("url"); | ||
exports.getCSRFToken = (html) => { | ||
const selector = cheerio_1.default.load(html); | ||
return selector('#csrf_token').attr('value'); | ||
}; | ||
exports.parseProfile = (html) => { | ||
const selector = cheerio_1.default.load(html); | ||
if (selector('title').text().toLowerCase().includes('redirecting')) { | ||
return null; | ||
} | ||
else { | ||
const profile = { | ||
id: Number.parseInt(selector('body > div > div.row > div.col-sm-10 > dl > dd:nth-child(2)').text()), | ||
username: selector('body > div > h2 > .text-default').text(), | ||
avatar: selector('body > div > div.row > div.col-sm-2 > img').attr('src'), | ||
class: selector('body > div > div.row > div.col-sm-10 > dl > dd:nth-child(4)').text(), | ||
created_at: new Date(selector('body > div > div.row > div.col-sm-10 > dl > dd:nth-child(6)').text()) | ||
}; | ||
return profile; | ||
} | ||
}; | ||
exports.parseComments = (html) => { | ||
// export const getCSRFToken = (html: string): string => { | ||
// const selector = cheerio.load(html) | ||
// return selector('#csrf_token').attr('value') | ||
// } | ||
// export const parseProfile = (html: string): Profile => { | ||
// const selector = cheerio.load(html) | ||
// if (selector('title').text().toLowerCase().includes('redirecting')) { | ||
// return null | ||
// } else { | ||
// const profile = { | ||
// id: Number.parseInt( | ||
// selector( | ||
// 'body > div > div.row > div.col-sm-10 > dl > dd:nth-child(2)' | ||
// ).text() | ||
// ), | ||
// username: selector('body > div > h2 > .text-default').text(), | ||
// avatar: selector('body > div > div.row > div.col-sm-2 > img').attr('src'), | ||
// class: selector( | ||
// 'body > div > div.row > div.col-sm-10 > dl > dd:nth-child(4)' | ||
// ).text(), | ||
// created_at: new Date( | ||
// selector( | ||
// 'body > div > div.row > div.col-sm-10 > dl > dd:nth-child(6)' | ||
// ).text() | ||
// ) | ||
// } | ||
// return profile | ||
// } | ||
// } | ||
const parseComments = (html) => { | ||
const select = cheerio_1.default.load(html); | ||
@@ -51,66 +60,145 @@ return select('#collapse-comments > div.panel') | ||
}; | ||
exports.parseSearch = (html, host = 'https://nyaa.si') => { | ||
const page = cheerio_1.default.load(html); | ||
const table = page('body > div.container > div.table-responsive > table > tbody'); | ||
const files = table | ||
.children('tr') | ||
.map((i, el) => { | ||
const select = cheerio_1.default.load(el); | ||
exports.parseComments = parseComments; | ||
const parseSearch = (html, host = 'https://nyaa.si') => { | ||
const content = cheerio_1.default.load(html); | ||
const parseSearch = (i, el) => { | ||
const tagList = el.childNodes.filter((n) => n.type === 'tag'); | ||
const file_size = tagList | ||
.find((tag, i) => tag.name === 'td' && i === 3) | ||
.children.find((tag) => tag.type === 'text') | ||
.data.trim(); | ||
return { | ||
id: Number.parseInt(select('td:nth-child(2) > a:last-of-type') | ||
.attr('href') | ||
.split('/') | ||
id: parseInt(tagList | ||
.find((tag, i) => tag.name === 'td' && i === 1) | ||
.children.find((tag) => tag.name === 'a') | ||
.attribs.href.split('/') | ||
.pop()), | ||
category: { | ||
label: select('td:nth-child(1) > a').attr('title'), | ||
code: new url_1.URL(select('td:nth-child(1) > a').attr('href'), host).searchParams.get('c') | ||
label: tagList | ||
.find((tag) => tag.name === 'td') | ||
.children.find((tag) => tag.name === 'a').attribs.title, | ||
code: new url_1.URL(host + | ||
tagList | ||
.find((tag) => tag.name === 'td') | ||
.children.find((tag) => tag.name === 'a').attribs.href).searchParams.get('c') | ||
}, | ||
name: select('td:nth-child(2) > a:last-of-type').text().trim(), | ||
name: tagList | ||
.find((tag, i) => tag.name === 'td' && i === 1) | ||
.children.find((tag) => tag.name === 'a' && | ||
(!tag.attribs.class || !tag.attribs.class.includes('comments'))) | ||
.attribs.title.trim(), | ||
links: { | ||
page: select('td:nth-child(2) > a:last-of-type').attr('href'), | ||
file: select('td:nth-child(3) > a').attr('href'), | ||
magnet: select('td:nth-child(3) > a:last-of-type').attr('href') | ||
page: tagList | ||
.find((tag, i) => tag.name === 'td' && i === 1) | ||
.children.find((tag) => tag.name === 'a').attribs.href, | ||
file: tagList | ||
.find((tag, i) => tag.name === 'td' && i === 2) | ||
.children.find((tag) => tag.name === 'a').attribs.href, | ||
magnet: tagList | ||
.find((tag, i) => tag.name === 'td' && i === 2) | ||
.children.find((tag) => tag.name === 'a' && | ||
tag.attribs.href && | ||
tag.attribs.href.startsWith('magnet')).attribs.href | ||
}, | ||
file_size: select('td:nth-child(4)').text(), | ||
file_size_bytes: bytes_iec_1.default.parse(select('td:nth-child(4)').text()), | ||
timestamp: Number.parseInt(select('td:nth-child(5)').attr('data-timestamp')), | ||
file_size, | ||
file_size_bytes: bytes_iec_1.default.parse(file_size), | ||
stats: { | ||
downloaded: Number.parseInt(select('td:nth-child(8)').text()), | ||
seeders: Number.parseInt(select('td:nth-child(6)').text()), | ||
leechers: Number.parseInt(select('td:nth-child(7)').text()) | ||
downloaded: parseInt(tagList | ||
.find((tag, i) => tag.name === 'td' && i === 7) | ||
.children.find((tag) => tag.type === 'text') | ||
.data.trim()), | ||
seeders: parseInt(tagList | ||
.find((tag, i) => tag.name === 'td' && i === 5) | ||
.children.find((tag) => tag.type === 'text') | ||
.data.trim()), | ||
leechers: parseInt(tagList | ||
.find((tag, i) => tag.name === 'td' && i === 6) | ||
.children.find((tag) => tag.type === 'text') | ||
.data.trim()) | ||
}, | ||
timestamp: parseInt(tagList.find((tag, i) => tag.name === 'td' && i === 4).attribs['data-timestamp']), | ||
entry: getEntry(el.attribs.class) | ||
}; | ||
}) | ||
.get(); | ||
const current_page = Number.parseInt(page('body > div.container > div.center > nav > ul').html() | ||
? new url_1.URL(page('body > div.container > div.center > nav > ul > li.active > a').attr('href'), host).searchParams.get('p') | ||
: page('body > div.container > div.center > ul > li.active').text()) || 1; | ||
const last_page = Number.parseInt(page('body > div.container > div.center > nav > ul').html() | ||
? new url_1.URL(page('body > div.container > div.center > nav > ul > li:last-of-type') | ||
}; | ||
const current_page = Number.parseInt(content('body > div.container > div.center > nav > ul').html() | ||
? new url_1.URL(content('body > div.container > div.center > nav > ul > li.active > a').attr('href'), host).searchParams.get('p') | ||
: content('body > div.container > div.center > ul > li.active').text()) || 1; | ||
const last_page = Number.parseInt(content('body > div.container > div.center > nav > ul').html() | ||
? new url_1.URL(content('body > div.container > div.center > nav > ul > li:last-of-type') | ||
.prev() | ||
.children('a') | ||
.attr('href'), host).searchParams.get('p') | ||
: new url_1.URL(page('body > div.container > div.center > ul > li.next') | ||
: new url_1.URL(content('body > div.container > div.center > ul > li.next') | ||
.prev() | ||
.children('a') | ||
.attr('href'), host).searchParams.get('p')) || 1; | ||
return { | ||
const result = { | ||
current_page, | ||
last_page, | ||
files | ||
torrents: content('body > div.container > div.table-responsive > table > tbody') | ||
.children('tr') | ||
.map(parseSearch) | ||
.get() | ||
}; | ||
return result; | ||
// // const table = page( | ||
// // 'body > div.container > div.table-responsive > table > tbody' | ||
// // ) | ||
// const files = table | ||
// .children('tr') | ||
// .map((i, el) => { | ||
// const select = cheerio(el) | ||
// return { | ||
// id: Number.parseInt( | ||
// select('td:nth-child(2) > a:last-of-type') | ||
// .attr('href') | ||
// .split('/') | ||
// .pop() | ||
// ), | ||
// category: { | ||
// label: select('td:nth-child(1) > a').attr('title'), | ||
// code: new URL( | ||
// select('td:nth-child(1) > a').attr('href'), | ||
// host | ||
// ).searchParams.get('c') | ||
// }, | ||
// name: select('td:nth-child(2) > a:last-of-type').text().trim(), | ||
// links: { | ||
// page: select('td:nth-child(2) > a:last-of-type').attr('href'), | ||
// file: select('td:nth-child(3) > a').attr('href'), | ||
// magnet: select('td:nth-child(3) > a:last-of-type').attr('href') | ||
// }, | ||
// file_size: select('td:nth-child(4)').text(), | ||
// file_size_bytes: bytes.parse(select('td:nth-child(4)').text()), | ||
// timestamp: Number.parseInt( | ||
// select('td:nth-child(5)').attr('data-timestamp') | ||
// ), | ||
// stats: { | ||
// downloaded: Number.parseInt(select('td:nth-child(8)').text()), | ||
// seeders: Number.parseInt(select('td:nth-child(6)').text()), | ||
// leechers: Number.parseInt(select('td:nth-child(7)').text()) | ||
// }, | ||
// entry: getEntry(el.attribs.class) | ||
// } | ||
// }) | ||
// .get() | ||
// return { | ||
// current_page, | ||
// last_page, | ||
// files | ||
// } | ||
}; | ||
exports.parseTorrent = (id, html, host = 'https://nyaa.si') => { | ||
const select = cheerio_1.default.load(html); | ||
select('.servers-cost-money1').remove(); | ||
const entryMatch = select('body > div.container > div:first-of-type').attr('class'); | ||
exports.parseSearch = parseSearch; | ||
const parseTorrent = (id, html) => { | ||
const content = cheerio_1.default.load(html); | ||
content('.servers-cost-money1').remove(); | ||
const entryMatch = content('body > div.container > div:first-of-type').attr('class'); | ||
return { | ||
id: id, | ||
name: select('body > div.container > div.panel:first-of-type > div.panel-heading > h3') | ||
name: content('body > div.container > div.panel:first-of-type > div.panel-heading > h3') | ||
.text() | ||
.trim(), | ||
file_size: select('body > div.container > div.panel > div.panel-body > div:nth-child(4) > div:nth-child(2)').html(), | ||
file_size_bytes: bytes_iec_1.default.parse(select('body > div.container > div.panel > div.panel-body > div:nth-child(4) > div:nth-child(2)').html()), | ||
category: select('body > div.container > div.panel > div.panel-body > div:nth-child(1) > div:nth-child(2)') | ||
file_size: content('body > div.container > div.panel > div.panel-body > div:nth-child(4) > div:nth-child(2)').html(), | ||
file_size_bytes: bytes_iec_1.default.parse(content('body > div.container > div.panel > div.panel-body > div:nth-child(4) > div:nth-child(2)').html()), | ||
category: content('body > div.container > div.panel > div.panel-body > div:nth-child(1) > div:nth-child(2)') | ||
.children('a') | ||
@@ -124,12 +212,10 @@ .map((i, el) => ({ | ||
links: { | ||
torrent: host + | ||
select('body > div.container > div.panel > div:last-of-type > a:first-of-type').attr('href'), | ||
magnet: select('body > div.container > div.panel > div:last-of-type > a:last-of-type').attr('href') | ||
torrent: content('body > div.container > div.panel > div:last-of-type > a:first-of-type').attr('href'), | ||
magnet: content('body > div.container > div.panel > div:last-of-type > a:last-of-type').attr('href') | ||
}, | ||
timestamp: Number.parseInt(select('body > div.container > div.panel > div.panel-body > div:nth-child(1) > div:nth-child(4)').attr('data-timestamp')) * 1000, | ||
submitter: select('body > div.container > div.panel > div.panel-body > div:nth-child(2) > div:nth-child(2) > a').html() | ||
timestamp: Number.parseInt(content('body > div.container > div.panel > div.panel-body > div:nth-child(1) > div:nth-child(4)').attr('data-timestamp')) * 1000, | ||
submitter: content('body > div.container > div.panel > div.panel-body > div:nth-child(2) > div:nth-child(2) > a').html() | ||
? { | ||
name: select('body > div.container > div.panel > div.panel-body > div:nth-child(2) > div:nth-child(2) > a').html(), | ||
link: host + | ||
select('body > div.container > div.panel > div.panel-body > div:nth-child(2) > div:nth-child(2) > a').attr('href') | ||
name: content('body > div.container > div.panel > div.panel-body > div:nth-child(2) > div:nth-child(2) > a').html(), | ||
link: content('body > div.container > div.panel > div.panel-body > div:nth-child(2) > div:nth-child(2) > a').attr('href') | ||
} | ||
@@ -140,12 +226,13 @@ : { | ||
}, | ||
description: select('#torrent-description').html(), | ||
info: select('body > div.container > div.panel > div.panel-body > div:nth-child(3) > div:nth-child(2) a').attr('href') || 'No information', | ||
info_hash: select('body > div.container > div.panel > div.panel-body > div:nth-child(5) > div.col-md-5 > kbd').html(), | ||
description: content('#torrent-description').html(), | ||
info: content('body > div.container > div.panel > div.panel-body > div:nth-child(3) > div:nth-child(2) a').attr('href') || 'No information', | ||
info_hash: content('body > div.container > div.panel > div.panel-body > div:nth-child(5) > div.col-md-5 > kbd').html(), | ||
stats: { | ||
seeders: Number.parseInt(select('body > div.container > div.panel > div.panel-body > div:nth-child(2) > div:nth-child(4) > span').html()), | ||
leechers: Number.parseInt(select('body > div.container > div.panel > div.panel-body > div:nth-child(3) > div:nth-child(4) > span').html()), | ||
downloaded: Number.parseInt(select('body > div.container > div.panel > div.panel-body > div:nth-child(4) > div:nth-child(4)').html()) | ||
seeders: Number.parseInt(content('body > div.container > div.panel > div.panel-body > div:nth-child(2) > div:nth-child(4) > span').html()), | ||
leechers: Number.parseInt(content('body > div.container > div.panel > div.panel-body > div:nth-child(3) > div:nth-child(4) > span').html()), | ||
downloaded: Number.parseInt(content('body > div.container > div.panel > div.panel-body > div:nth-child(4) > div:nth-child(4)').html()) | ||
} | ||
}; | ||
}; | ||
exports.parseTorrent = parseTorrent; | ||
function getEntry(entry) { | ||
@@ -152,0 +239,0 @@ switch (entry) { |
{ | ||
"name": "@ejnshtein/nyaasi", | ||
"version": "2.2.3", | ||
"version": "3.0.1", | ||
"description": "Nyaa.si api wrapper for Node written in Typescript", | ||
"main": "./dist/index.js", | ||
"types": "./dist/index.d.ts", | ||
"types": "./types/index.d.ts", | ||
"scripts": { | ||
"build-ts": "tsc", | ||
"lint": "eslint ./src --ext .ts" | ||
"build": "tsc", | ||
"lint": "eslint ./src --ignore-pattern *.test.*", | ||
"lint:fix": "eslint ./src --ignore-pattern *.test.* --fix", | ||
"test": "jest --config jest.json", | ||
"pretest": "npm run build", | ||
"pb": "np", | ||
"build:docs": "typedoc", | ||
"deploy": "npm run build && npm run build:docs && gh-pages -t -d docs -b gh-pages" | ||
}, | ||
@@ -16,4 +22,4 @@ "keywords": [ | ||
"files": [ | ||
"dist/**/*", | ||
"types/**/*" | ||
"dist", | ||
"types" | ||
], | ||
@@ -30,31 +36,34 @@ "type": "commonjs", | ||
"dependencies": { | ||
"@ejnshtein/smol-request": "^1.1.5", | ||
"bytes-iec": "^3.1.0", | ||
"cheerio": "^1.0.0-rc.3", | ||
"deepmerge": "^4.2.2", | ||
"rss-parser": "^3.9.0" | ||
"bytes-iec": "^3.1.1", | ||
"cheerio": "^1.0.0-rc.5", | ||
"html-entities": "^2.0.2", | ||
"rss-parser": "^3.10.0", | ||
"smol-request": "^2.1.1" | ||
}, | ||
"devDependencies": { | ||
"@babel/core": "^7.12.3", | ||
"@babel/preset-typescript": "^7.12.1", | ||
"@types/cheerio": "^0.22.22", | ||
"@types/eslint": "^7.2.4", | ||
"@types/node": "^14.14.6", | ||
"@types/eslint": "^7.2.6", | ||
"@types/node": "^14.14.9", | ||
"@typescript-eslint/eslint-plugin": "^4.6.0", | ||
"@typescript-eslint/parser": "^4.6.0", | ||
"babel-plugin-add-import-extension": "^1.4.3", | ||
"eslint": "^7.12.1", | ||
"eslint-config-prettier": "^6.15.0", | ||
"eslint-config-standard": "^16.0.1", | ||
"domelementtype": "^2.1.0", | ||
"dotenv": "^8.2.0", | ||
"eslint": "^7.17.0", | ||
"eslint-config-prettier": "^7.1.0", | ||
"eslint-config-standard": "^16.0.2", | ||
"eslint-plugin-import": "^2.22.1", | ||
"eslint-plugin-node": "^11.1.0", | ||
"eslint-plugin-prettier": "^3.1.4", | ||
"eslint-plugin-prettier": "^3.3.1", | ||
"eslint-plugin-promise": "^4.2.1", | ||
"eslint-plugin-standard": "^4.0.2", | ||
"husky": "^4.3.0", | ||
"module-alias": "^2.2.2", | ||
"prettier": "^2.1.2", | ||
"standard": "^16.0.1", | ||
"typescript": "^4.0.5" | ||
"eslint-plugin-standard": "^5.0.0", | ||
"husky": "^4.3.7", | ||
"jest": "^26.6.3", | ||
"np": "^7.2.0", | ||
"prettier": "^2.2.1", | ||
"standard": "^16.0.3", | ||
"ts-jest": "^26.4.4", | ||
"typedoc": "^0.19.2", | ||
"typedoc-plugin-nojekyll": "^1.0.1", | ||
"typedoc-plugin-sourcefile-url": "^1.0.6", | ||
"typescript": "^4.1.3" | ||
} | ||
} |
@@ -1,39 +0,4 @@ | ||
import { RequestOptions } from '@ejnshtein/smol-request' | ||
export * from './nyaa' | ||
export * from './agent' | ||
export interface Cookie { | ||
domain?: string | ||
expires?: Date | ||
httponly?: boolean | ||
path?: string | ||
session?: string | ||
} | ||
export interface LoginPayload { | ||
username: string | ||
password: string | ||
csrf_token?: string | ||
} | ||
export type NyaaRequestOptions = RequestOptions & { baseUrl?: string } | ||
export interface NyaaApiRequestResult<T> { | ||
status: string | ||
message?: string | ||
data?: T | ||
} | ||
export interface AgentOptions { | ||
host?: string | ||
apiHost?: string | ||
} | ||
export interface SearchOptions { | ||
filter?: number | ||
category?: string | ||
} | ||
export interface GetTorrentOptions { | ||
withComments?: boolean | ||
} | ||
export * from '../dist/index' |
@@ -48,31 +48,31 @@ export interface Profile { | ||
export interface ApiTorrent { | ||
id: number | ||
name: string | ||
url: string | ||
submitter: string | ||
description: string | ||
information: string | ||
is_complete: boolean | ||
is_remake: boolean | ||
is_trusted: boolean | ||
main_category: string | ||
main_category_id: number | ||
sub_category: string | ||
sub_category_id: number | ||
hash_b32: string | ||
hash_hex: string | ||
files: { | ||
[x: string]: number | ||
} | ||
filesize: number | ||
magnet: string | ||
stats: { | ||
downloads: number | ||
leechers: number | ||
seeders: number | ||
} | ||
creation_date: string | ||
comments?: Comment[] | ||
} | ||
// export interface ApiTorrent { | ||
// id: number | ||
// name: string | ||
// url: string | ||
// submitter: string | ||
// description: string | ||
// information: string | ||
// is_complete: boolean | ||
// is_remake: boolean | ||
// is_trusted: boolean | ||
// main_category: string | ||
// main_category_id: number | ||
// sub_category: string | ||
// sub_category_id: number | ||
// hash_b32: string | ||
// hash_hex: string | ||
// files: { | ||
// [x: string]: number | ||
// } | ||
// filesize: number | ||
// magnet: string | ||
// stats: { | ||
// downloads: number | ||
// leechers: number | ||
// seeders: number | ||
// } | ||
// creation_date: string | ||
// comments?: Comment[] | ||
// } | ||
@@ -109,3 +109,3 @@ export interface ViewTorrent { | ||
export interface SearchFile { | ||
export interface SearchTorrent { | ||
id: number | ||
@@ -130,3 +130,3 @@ category: { | ||
} | ||
entry: 'remake' | 'trusted' | null | ||
entry: Entry | ||
} | ||
@@ -137,3 +137,21 @@ | ||
last_page: number | ||
files: SearchFile[] | ||
torrents: SearchTorrent[] | ||
} | ||
export interface RSSFile { | ||
id: number | ||
title: string | ||
guid: string | ||
description: string | ||
pubDate: Date | ||
seeders: number | ||
leechers: number | ||
downloads: number | ||
infoHash: string | ||
categoryId: string | ||
category: string | ||
size: string | ||
comments: number | ||
trusted: string | ||
remake: string | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
44668
24
1090
24
1
+ Addedhtml-entities@^2.0.2
+ Addedsmol-request@^2.1.1
+ Addedhtml-entities@2.5.2(transitive)
+ Addedsmol-request@2.1.2(transitive)
- Removed@ejnshtein/smol-request@^1.1.5
- Removeddeepmerge@^4.2.2
- Removed@ejnshtein/smol-request@1.1.5(transitive)
- Removeddeepmerge@4.3.1(transitive)
Updatedbytes-iec@^3.1.1
Updatedcheerio@^1.0.0-rc.5
Updatedrss-parser@^3.10.0