feat: 四类站点默认脚本+无自定义脚本时按siteType自动加载默认模板

This commit is contained in:
mediabot-pt
2026-07-01 14:53:07 +08:00
parent cd13335b4a
commit f2c98582a4
6 changed files with 536 additions and 12 deletions

View File

@@ -0,0 +1,144 @@
// NexusPHP 站点默认脚本
// 适用: PThome / HDSky / OurBits / HDFans / 聆音 等
// 覆盖: 搜索 / 详情 / 用户信息 / 签到
Map parse(String content, String url) {
def doc = jsoup.parse(content)
if (url.contains('/torrents.php')) return parseSearch(doc)
if (url.contains('/details.php')) return parseDetail(doc)
if (url.contains('/attendance.php')) return parseSign(doc)
if (url.contains('/index.php') && !url.contains('?')) return parseUserInfo(doc)
if (url.contains('/usercp.php')) return parseUserPanel(doc)
return [pageName: '未知页面', message: "未配置: ${url}"]
}
private Map parseUserInfo(doc) {
def fields = [:]
def el = utils.selectFirst(doc, '#info_block')
if (el) {
def t = utils.text(el)
def um = t =~ /上传[::]\s*([0-9.]+)\s*(TB|GB|MB|KB|B)?/
def dm = t =~ /下载[::]\s*([0-9.]+)\s*(TB|GB|MB|KB|B)?/
def rm = t =~ /分享率[::]\s*([\d.]+)/
def bm = t =~ /魔力[值::]*\s*([\d,]+)/
if (um) fields.upload = um[0][1] + (um[0][2] ?: '')
if (dm) fields.download = dm[0][1] + (dm[0][2] ?: '')
if (rm) fields.ratio = rm[0][1]
if (bm) fields.bonus = bm[0][1]
}
return [pageName: '用户信息', fields: fields]
}
private Map parseSearch(doc) {
def rows = []
doc.select('table.torrents > tbody > tr:has(td.rowfollow):not(:has(th)):not(:has(.colhead))').each { row ->
def titleEl = utils.selectFirst(row, 'td.embedded a[href*=details]')
def catEl = utils.selectFirst(row, 'td.rowfollow a[href*=cat] img, td.rowfollow a[href*=torrents] img')
def freeEl = utils.selectFirst(row, 'td.rowfollow font.free')
def tds = row.select('td.rowfollow')
rows << [
title: utils.text(titleEl),
detailUrl: utils.attr(titleEl, 'href'),
category: utils.attr(catEl, 'alt'),
free: utils.text(freeEl),
size: tds.size() > 4 ? utils.text(tds.get(4)) : '',
seeders: utils.text(tds.size() > 5 ? tds.get(5) : null),
leechers: utils.text(tds.size() > 6 ? tds.get(6) : null),
completed: utils.text(tds.size() > 7 ? tds.get(7) : null),
publishDate:utils.text(tds.size() > 3 ? tds.get(3) : null),
]
}
return [pageName: '搜索', extracted: rows, message: "共 ${rows.size()} 条"]
}
private Map parseDetail(doc) {
return [pageName: '种子详情', fields: [
title: utils.text(utils.selectFirst(doc, '#top h1, h1')),
subtitle: utils.text(utils.selectFirst(doc, 'td.embedded b')),
size: utils.text(utils.selectFirst(doc, 'td:has(b:contains(大小)) + td, td.rowhead:contains(大小) + td')),
seeders: utils.text(utils.selectFirst(doc, 'td:contains(做种者) + td')),
leechers: utils.text(utils.selectFirst(doc, 'td:contains(下载者) + td')),
]]
}
private Map parseSign(doc) {
def t = utils.text(doc.body())
def matched = t ==~ /.*(签到成功|已签到|重复签到|获得.*魔力值).*/
return [pageName: '签到', fields: [result: t.take(200)], message: matched ? '成功' : '未知']
}
private Map parseUserPanel(doc) {
def fields = [:]
doc.select('td.text').each { td ->
def t = utils.text(td)
if (t.contains('分享率')) fields.shareRate = t.replaceAll(/[^0-9.]/, '')
if (t.contains('魔力')) fields.bonus = t.replaceAll(/[^0-9.,]/, '')
}
return [pageName: '控制面板', fields: fields]
}
Map sync(PluginContext ctx) {
if (!ctx.site.auth) return [message: "未配置认证", loginRequired: true]
try {
def conn = ctx.httpGet('/index.php')
def doc = jsoup.parse(conn.body())
def el = utils.selectFirst(doc, '#info_block')
if (!el) return [message: "未找到用户信息"]
def t = utils.text(el)
def result = [:]
def um = t =~ /上传[::]\s*([0-9.]+)\s*(TB|GB|MB|KB|B)?/
def dm = t =~ /下载[::]\s*([0-9.]+)\s*(TB|GB|MB|KB|B)?/
def rm = t =~ /分享率[::]\s*([\d.]+)/
def bm = t =~ /魔力[值::]*\s*([\d,]+)/
if (um) result.upload = parseTraffic(um[0][1] as double, um[0][2])
if (dm) result.download = parseTraffic(dm[0][1] as double, dm[0][2])
if (rm) result.shareRate = rm[0][1] as double
if (bm) result.bonus = bm[0][1].replace(',','') as double
return result
} catch (e) { return [message: "同步失败: ${e.message}"] }
}
Map sign(PluginContext ctx) {
if (!ctx.site.auth) return [message: "未配置认证", loginRequired: true]
try {
def conn = ctx.httpGet('/attendance.php')
def matched = conn.body() ==~ /.*(签到成功|已签到|重复签到|获得.*魔力值).*/
return [success: matched, message: matched ? '已签到' : '失败']
} catch (e) { return [message: "签到异常: ${e.message}"] }
}
List search(PluginContext ctx, Map params) {
if (!ctx.site.auth) return []
try {
def keyword = params.keyword ?: ''
def page = (params.page ?: 0) as int
def conn = ctx.httpGet("/torrents.php?search=${URLEncoder.encode(keyword,'UTF-8')}&page=${page}")
def doc = jsoup.parse(conn.body())
def rows = []
doc.select('table.torrents > tbody > tr:has(td.rowfollow):not(:has(th)):not(:has(.colhead))').each { row ->
def titleEl = utils.selectFirst(row, 'td.embedded a[href*=details]')
def tds = row.select('td.rowfollow')
rows << [
title: utils.text(titleEl),
detailUrl: "${ctx.siteUrl}${utils.attr(titleEl,'href')}",
size: tds.size() > 4 ? parseHtmlSize(utils.text(tds.get(4))) : 0,
seeders: tds.size() > 5 ? utils.toInt(utils.text(tds.get(5))) ?: 0 : 0,
leechers: tds.size() > 6 ? utils.toInt(utils.text(tds.get(6))) ?: 0 : 0,
grabs: tds.size() > 7 ? utils.toInt(utils.text(tds.get(7))) ?: 0 : 0,
publishDate: tds.size() > 3 ? utils.text(tds.get(3)) : '',
]
}
return rows
} catch (e) { return [] }
}
private long parseTraffic(double val, String unit) {
def m = [B:1,KB:1024,MB:1048576,GB:1073741824,TB:1099511627776]
return (val * (m[unit?.toUpperCase()] ?: 1)) as long
}
private long parseHtmlSize(String s) {
def m = s =~ /([\d.]+)\s*(TB|GB|MB|KB|B)?/
return m ? parseTraffic(m[0][1] as double, m[0][2]) : 0
}