Files
par/docs/pttime.groovy

171 lines
7.0 KiB
Groovy
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// PTTIME 适配脚本
// 内置变量: content, url, jsoup(Jsoup), json(Jackson), utils, http(httpHelper)
// 导入: groovy.json.*, java.net.http.*, com.par.core.adapter.*, com.mediabot.site.*
// ==================== PAR 校验入口 ====================
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 parseIndex(doc)
return [pageName: '未知页面', message: "未配置解析: ${url}"]
}
// ── 首页 / 用户信息 ──
private Map parseIndex(doc) {
def infoEl = doc.selectFirst('#info_block')
if (!infoEl) return [pageName: '首页', message: '未找到用户信息']
def t = infoEl.text()
def fields = [:]
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 =~ /魔力值\([^)]*\)[^0-9]*([\d.,]+)/
def sm = t =~ /⬆\s*(\d+)/
def lm = 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]
if (sm) fields.seeding = sm[0][1]
if (lm) fields.leeching = lm[0][1]
return [pageName: '用户信息', fields: fields, message: fields.isEmpty() ? '未提取到数据' : '解析成功']
}
// ── 搜索(无 tbody, 列索引方式)──
private Map parseSearch(doc) {
def rows = []
doc.select('table.torrents tr:has(td.rowfollow):not(:has(.colhead))').each { row ->
def titleEl = row.selectFirst('td.embedded a.torrentname_title')
if (!titleEl) return
def catEl = row.selectFirst('td.rowfollow span.category')
def freeEl = row.selectFirst('font.promotion')
def tds = row.select('td.rowfollow')
rows << [
title: titleEl.text(),
detailUrl: titleEl.attr('href'),
category: catEl?.attr('title') ?: '',
free: freeEl?.text(),
size: tds.size() > 5 ? tds[5].text() : '',
seeders: tds.size() > 6 ? tds[6].text() : '',
leechers: tds.size() > 7 ? tds[7].text() : '',
completed: tds.size() > 8 ? tds[8].text() : '',
publishDate: tds.size() > 4 ? tds[4].text() : '',
]
}
return [pageName: '搜索', extracted: rows, message: "共 ${rows.size()} 条"]
}
// ── 种子详情 ──
private Map parseDetail(doc) {
def titleEl = doc.selectFirst('a.torrentname_title b, #top h1')
def descEl = doc.selectFirst('td.embedded font[title], #kdescr')
return [pageName: '种子详情', fields: [
title: titleEl?.text(),
description: descEl?.text()?.take(200)
]]
}
// ── 签到 ──
private Map parseSign(doc) {
def t = doc.body().text()
def matched = t ==~ /.*(签到成功|已签到|重复签到|获得.*魔力值).*/
return [pageName: '签到', fields: [result: t.take(200)], message: matched ? '成功' : '未知']
}
// ==================== mediabot 运行时 ====================
Map sign(PluginContext ctx) {
if (!ctx.auth) return [message: '未配置认证', loginRequired: true]
try {
def body = httpGet(ctx, '/attendance.php')
def matched = body ==~ /.*(签到成功|已签到|重复签到|获得.*魔力值).*/
return [success: matched, message: matched ? '已签到' : '失败']
} catch (e) { return [message: "签到异常: ${e.message}"] }
}
Map sync(PluginContext ctx) {
if (!ctx.auth) return [message: '未配置认证', loginRequired: true]
try {
def body = httpGet(ctx, '/index.php')
def doc = Jsoup.parse(body)
def infoEl = doc.selectFirst('#info_block')
if (!infoEl) { ctx.incomplete = true; return [message: '未找到用户信息区域'] }
def t = infoEl.text()
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 =~ /魔力值\([^)]*\)[^0-9]*([\d.,]+)/
def sm = t =~ /⬆\s*(\d+)/
if (um) result.upload = parseTraffic(um[0][1].replace(',','') as double, um[0][2])
if (dm) result.download = parseTraffic(dm[0][1].replace(',','') as double, dm[0][2])
if (rm) result.shareRatio = rm[0][1].replace(',','') as double
if (bm) result.bonus = bm[0][1].replace(',','') as double
if (sm) result.seeding = sm[0][1] as int
if (!result.upload || !result.download) ctx.incomplete = true
return result
} catch (e) { ctx.incomplete = true; return [message: "同步失败: ${e.message}"] }
}
List search(PluginContext ctx, Map params) {
if (!ctx.auth) return []
try {
def keyword = params.keyword ?: ''
def page = (params.page ?: 0) as int
def body = httpGet(ctx, "/torrents.php?search=${URLEncoder.encode(keyword,'UTF-8')}&page=${page}")
def doc = Jsoup.parse(body)
def rows = []
doc.select('table.torrents tr:has(td.rowfollow):not(:has(.colhead))').each { row ->
def titleEl = row.selectFirst('td.embedded a.torrentname_title')
if (!titleEl) return
def tds = row.select('td.rowfollow')
rows << [
title: titleEl.text(),
detailUrl: "${ctx.siteUrl}${titleEl.attr('href')}",
size: tds.size() > 5 ? parseHtmlSize(tds[5].text()) : 0,
seeders: tds.size() > 6 ? (tds[6].text() as int ?: 0) : 0,
leechers: tds.size() > 7 ? (tds[7].text() as int ?: 0) : 0,
grabs: tds.size() > 8 ? (tds[8].text() as int ?: 0) : 0,
]
}
return rows
} catch (e) { return [] }
}
// ==================== HTTP 工具 ====================
private String httpGet(PluginContext ctx, String path) {
def url = ctx.siteUrl.replaceAll('/+\$', '') + '/' + path.replaceAll('^/+', '')
def builder = HttpRequest.newBuilder().uri(java.net.URI.create(url))
.timeout(Duration.ofSeconds(15))
.header('User-Agent', 'MediaBot/1.0')
.GET()
if (ctx.auth) builder.header('Cookie', ctx.auth)
def resp = ctx.httpClient.send(builder.build(), HttpResponse.BodyHandlers.ofString())
ctx.capturedUrl = url
ctx.capturedBody = resp.body()
return resp.body()
}
// ==================== 数字工具 ====================
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)?/
if (!m) return 0
return parseTraffic(m[0][1].replace(',','') as double, m[0][2])
}