/** * SPDX-License-Identifier: GPL-3.0-only * 移植自 MoviePilot(https://github.com/jxxghp/MoviePilot,GPLv3),本文件按 GPLv3 条款提供。 * @mp-source app/modules/indexer/parser/hddolby.py @ e6820a8 * * HDDolby 用户数据解析器(MP `HDDolbySiteUserInfo`,apikey 模式)。 * 函数对照:`HDDolby_sysRoleList` → `HDDOLBY_SYS_ROLE_LIST`、`_parse_site_page` → `_parseSitePage`(api.<域>)、 * `_parse_logged_in`(恒 True)、`_parse_user_base_info` → `_parseUserBaseInfo`(api/v1/user/data)、 * `_parse_user_torrent_seeding_info` → `_parseUserTorrentSeedingInfo`(api/v1/user/peers)、 * `_pase_unread_msgs` → `_paseUnreadMsgs`(API 只给未读数,正文借 NexusPHP 解析器用 Cookie 读网页)。 * 注:`_user_basic_params = {}` 在 Python 中为假值,故 profile/peers 两个接口实际为 GET(与 MP 一致)。 */ import { type NextPage, SiteParserBase } from "./base.ts"; import { extractDomain, pyFloat, pyInt } from "./common.ts"; import { NexusPhpSiteUserInfo } from "./nexus-php.ts"; import { SiteSchema, type SiteSchemaValue } from "./types.ts"; type Json = Record; /** 用户级别字典(MP `HDDolby_sysRoleList`) */ export const HDDOLBY_SYS_ROLE_LIST: Record = { "0": "Peasant", "1": "User", "2": "Power User", "3": "Elite User", "4": "Crazy User", "5": "Insane User", "6": "Veteran User", "7": "Extreme User", "8": "Ultimate User", "9": "Nexus Master", "10": "VIP", "11": "Retiree", "12": "Helper", "13": "Seeder", "14": "Transferrer", "15": "Uploader", "16": "Torrent Manager", "17": "Forum Moderator", "18": "Coder", "19": "Moderator", "20": "Administrator", "21": "Sysop", "22": "Staff Leader", }; export class HDDolbySiteUserInfo extends SiteParserBase { static override schema: SiteSchemaValue | null = SiteSchema.HDDolby; override requestMode = "apikey" as const; protected _parseSitePage(_htmlText: string): void { this._baseUrl = `https://api.${extractDomain(this._baseUrl)}`; this._userTrafficPage = null; this._userDetailPage = null; this._userBasicPage = "api/v1/user/data"; this._userBasicParams = {}; this._userBasicHeaders = { "Content-Type": "application/json", Accept: "application/json, text/plain, */*" }; this._sysMailUnreadPage = null; this._userMailUnreadPage = null; this._mailUnreadParams = {}; this._torrentSeedingPage = "api/v1/user/peers"; this._torrentSeedingParams = {}; this._torrentSeedingHeaders = { "Content-Type": "application/json", Accept: "application/json, text/plain, */*" }; this._additionHeaders = { "x-api-key": this.apikey ?? "" }; } protected override _parseLoggedIn(_htmlText: unknown): boolean { return true; } protected _parseUserBaseInfo(htmlText: string): void { if (!htmlText) return; const detail = JSON.parse(htmlText) as Json | null; if (detail?.status !== 0) return; const infos = detail.data as Json[] | null; if (!infos?.length) return; const u = infos[0]!; this.userid = u.id == null ? null : String(u.id); this.username = (u.username as string) ?? null; this.userLevel = HDDOLBY_SYS_ROLE_LIST[String(u.class || "1")] ?? null; this.joinAt = (u.added as string) ?? null; this.upload = pyInt(u.uploaded || "0"); this.download = pyInt(u.downloaded || "0"); this.ratio = this.download ? Math.round((this.upload / this.download) * 100) / 100 : 0; this.bonus = pyFloat(u.seedbonus || "0"); this.messageUnread = pyInt(u.unread_messages || "0"); } protected _parseUserTrafficInfo(_htmlText: string): void {} protected _parseUserDetailInfo(_htmlText: string): void {} protected _parseUserTorrentSeedingInfo(htmlText: string, _multiPage = false): NextPage { if (!htmlText) return null; const seedingInfo = JSON.parse(htmlText) as Json | null; if (seedingInfo?.status !== 0) return null; const torrents = (seedingInfo.data ?? []) as Json[]; let pageSeedingSize = 0; const pageSeedingInfo: Array<[number, number]> = []; for (const info of torrents) { const size = Number(info.size ?? 0); const seeder = Number(info.seeders || 1); pageSeedingSize += size; pageSeedingInfo.push([seeder, size]); } this.seeding += torrents.length; this.seedingSize += pageSeedingSize; this.seedingInfo.push(...pageSeedingInfo); return null; } protected _parseMessageUnreadLinks(_htmlText: string, _msgLinks: string[]): NextPage { return null; } protected _parseMessageContent(_htmlText: string): [string | null, string | null, string | null] { return [null, null, null]; } /** API 仅返回未读数量,正文需通过 NexusPHP 网页接口读取(需 Cookie) */ protected override async _paseUnreadMsgs(): Promise { if (!this._siteCookie) return; const nexus = new NexusPhpSiteUserInfo({ ...this._opts, cookie: this._siteCookie }); nexus.messageUnread = this.messageUnread; nexus.messageReadForce = this.messageUnread > 0; await (nexus as unknown as { _paseUnreadMsgs(): Promise })._paseUnreadMsgs(); this.messageUnreadContents = [...nexus.messageUnreadContents]; this.httpErrors.push(...nexus.httpErrors); if (this.messageUnreadContents.length && !this.messageUnread) { this.messageUnread = this.messageUnreadContents.length; } } }