- sites/spiders: Haidan/HDDolby/RousiPro/SunnyPT/TNode/TorrentLeech/Yema (+mTorrent wrapper), specialized SiteAdapter, indirect download resolved at download time - sites/user-parsers: SiteParserBase + all 20 MP SiteSchema parsers (lxml XPath via xpath+xmldom), refreshSiteUserData with schema fallback - sites/definitions: zod SiteDefinition schemas, 23 MovieClaw v0.27.0 (MIT) definitions via scripts/mp-sync/movieclaw-import.mjs, registry getSiteDefinition/listSiteDefinitions, NOTICE - scripts/mp-sync: ledger.json (upstream sha256), check.mjs, build-ledger.mjs; docs/porting/mp-sync-ledger.md - license-and-provenance: add copied-mit kind, re-anchor MovieClaw rows to v0.27.0 Co-Authored-By: Claude Opus 5.5 <[email protected]>
59 lines
2.8 KiB
TypeScript
59 lines
2.8 KiB
TypeScript
/**
|
||
* SPDX-License-Identifier: GPL-3.0-only
|
||
* 移植自 MoviePilot(https://github.com/jxxghp/MoviePilot,GPLv3),本文件按 GPLv3 条款提供。
|
||
* @mp-source app/modules/indexer/parser/nexus_project.py @ e6820a8
|
||
*
|
||
* NexusProject 站点用户信息解析器,继承 NexusPHP 通用解析。
|
||
*
|
||
* 函数对照(`NexusProjectSiteUserInfo`):`_parse_site_page` → `_parseSitePage`(兼容 `user_detail.php?uid=` 变种)、
|
||
* `_parse_user_traffic_info` → `_parseUserTrafficInfo`(兼容 `span#user_info` 无 B 后缀的流量文本)。正则逐字保留。
|
||
*/
|
||
import { reSearch } from "./common.ts";
|
||
import { parseHtml } from "./dom.ts";
|
||
import { NexusPhpSiteUserInfo, round3 } from "./nexus-php.ts";
|
||
import { SiteSchema, type SiteSchemaValue } from "./types.ts";
|
||
|
||
export class NexusProjectSiteUserInfo extends NexusPhpSiteUserInfo {
|
||
static override schema: SiteSchemaValue | null = SiteSchema.NexusProject;
|
||
|
||
protected override _parseSitePage(htmlText: string): void {
|
||
const text = this._prepareHtmlText(htmlText);
|
||
let userDetail = reSearch(/userdetails\.php\?id=(\d+)/, text);
|
||
if (userDetail?.[0].trim()) {
|
||
this._userDetailPage = userDetail[0].trim().replace(/^\/+/, "");
|
||
this.userid = userDetail[1]!;
|
||
} else {
|
||
// 兼容部分 NexusProject 变种站点(如 star-space.net)的 p_user/user_detail.php?uid= 用户定位格式
|
||
userDetail = reSearch(/user_detail\.php\?uid=(\d+)/, text);
|
||
if (userDetail?.[0].trim()) {
|
||
this._userDetailPage = userDetail[0].trim().replace(/^\/+/, "");
|
||
this.userid = userDetail[1]!;
|
||
const uname = reSearch(/user_detail\.php\?uid=\d+[^>]*?>\s*<[^>]*>([^<]+)</, text);
|
||
if (uname) this.username = uname[1]!.trim();
|
||
}
|
||
}
|
||
this._torrentSeedingPage = `viewusertorrents.php?id=${this.userid}&show=seeding`;
|
||
}
|
||
|
||
protected override _parseUserTrafficInfo(htmlText: string): void {
|
||
// 兼容 span#user_info / span#user_info_no_hover:"上传:445.11 G" / "下载:29.61 G"(单位无 B 后缀)
|
||
try {
|
||
const html = parseHtml(htmlText);
|
||
if (html) {
|
||
const bodyText = html
|
||
.strings('//span[@id="user_info"]//text() | //span[@id="user_info_no_hover"]//text()')
|
||
.join(" ");
|
||
let m = reSearch(/上传[::]\s*([\d.,]+)\s*([GMKT]?i?B?)/i, bodyText);
|
||
if (m) this.upload = this.numFilesize(`${m[1]!.replaceAll(",", "")} ${m[2]!.toUpperCase()}B`);
|
||
m = reSearch(/下载[::]\s*([\d.,]+)\s*([GMKT]?i?B?)/i, bodyText);
|
||
if (m) this.download = this.numFilesize(`${m[1]!.replaceAll(",", "")} ${m[2]!.toUpperCase()}B`);
|
||
if (this.upload && this.download) this.ratio = round3(this.upload / this.download);
|
||
if (this.upload || this.download) return;
|
||
}
|
||
} catch {
|
||
// 与 MP 一致:吞掉异常回落到通用解析
|
||
}
|
||
super._parseUserTrafficInfo(htmlText);
|
||
}
|
||
}
|