Files
par/par-core/src/main/resources/scripts/default-unit3d.groovy

114 lines
4.8 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.

// UNIT3D 站点默认脚本
// 适用: BLU / TL / ACM 等 UNIT3D 架构站点(HTML + 可选 API)
// 覆盖: 搜索 / 种子详情 / 首页
Map parse(String content, String url) {
def doc = jsoup.parse(content)
if (url.contains('/torrents') && !url.contains('/torrents/')) return parseSearch(doc)
if (url.contains('/torrents/') && url.contains('/')) return parseDetail(doc)
// 尝试 JSON API
if (content.trim().startsWith('{') || content.trim().startsWith('[')) {
try {
def root = json.readValue(content, Map)
if (root?.data) return parseApiData(root?.data, url)
} catch (e) {}
}
if (url.contains('/torrentrss.php') || url.contains('/rss')) return parseRss()
return [pageName: '未知页面', message: "未配置: ${url}"]
}
private Map parseRss() {
return [pageName: 'RSS', message: 'RSS 内容由 Java 层解析']
}
private Map parseApiData(d, url) {
if (url.contains('/user') || url.contains('/profile'))
return [pageName: '用户', fields: [username: d?.username, uploaded: d?.uploaded?.toString(), downloaded: d?.downloaded?.toString()]]
return [pageName: 'API数据', fields: d?.subMap(d.keySet().take(10))]
}
private Map parseSearch(doc) {
def rows = []
doc.select('table.table tbody tr, .torrent-row, div.torrent').each { row ->
def titleEl = utils.selectFirst(row, 'a[href*=torrents]')
def tds = row.select('td')
def size = ''
for (int i = 0; i < tds.size(); i++) {
def t = utils.text(tds.get(i))
if (t =~ /[\d.]+\s*(GB|MB|TB)/) { size = t; break }
}
rows << [
title: utils.text(titleEl),
detailUrl: utils.attr(titleEl, 'href'),
size: size,
seeders: utils.text(utils.selectFirst(row, 'td:nth-child(5), td:has(.text-success)')),
leechers: utils.text(utils.selectFirst(row, 'td:nth-child(6), td:has(.text-danger)')),
uploadDate: utils.text(utils.selectFirst(row, 'td:nth-child(4), time')),
]
}
return [pageName: '搜索', extracted: rows, message: "共 ${rows.size()} 条"]
}
private Map parseDetail(doc) {
return [pageName: '种子详情', fields: [
title: utils.text(utils.selectFirst(doc, 'h1, .torrent-title, .meta-title')),
size: utils.text(utils.selectFirst(doc, 'td:contains(Size) + td, .torrent-size')),
seeders: utils.text(utils.selectFirst(doc, 'td:contains(Seeders) + td, .seeders-count')),
leechers: utils.text(utils.selectFirst(doc, 'td:contains(Leechers) + td, .leechers-count')),
description:utils.text(utils.selectFirst(doc, '.torrent-description, #description')).take(200),
]]
}
Map sync(PluginContext ctx) {
if (!ctx.site.auth) return [message: "未配置认证", loginRequired: true]
try {
def conn = ctx.httpGet('/')
def doc = jsoup.parse(conn.body())
def upEl = utils.selectFirst(doc, '.user-uploaded, span:contains(Upload), dt:contains(Upload) + dd')
def dlEl = utils.selectFirst(doc, '.user-downloaded, span:contains(Download), dt:contains(Download) + dd')
def ratioEl = utils.selectFirst(doc, '.user-ratio, span:contains(Ratio), dt:contains(Ratio) + dd')
def result = [:]
if (upEl) result.upload = parseHtmlSize(utils.text(upEl))
if (dlEl) result.download = parseHtmlSize(utils.text(dlEl))
if (ratioEl) result.shareRate = (utils.text(ratioEl) =~ /([\d.]+)/)[0][1] as double
return result
} catch (e) { return [message: "同步失败: ${e.message}"] }
}
Map sign(PluginContext ctx) {
return [message: "UNIT3D 不支持签到"]
}
List search(PluginContext ctx, Map params) {
if (!ctx.site.auth) return []
try {
def keyword = params.keyword ?: ''
def conn = ctx.httpGet("/torrents?search=${URLEncoder.encode(keyword,'UTF-8')}")
def doc = jsoup.parse(conn.body())
def rows = []
doc.select('table.table tbody tr, .torrent-row').each { row ->
def titleEl = utils.selectFirst(row, 'a[href*=torrents]')
rows << [
title: utils.text(titleEl),
detailUrl: "${ctx.siteUrl}${utils.attr(titleEl,'href')}",
size: parseHtmlSize(utils.text(utils.selectFirst(row, 'td:nth-child(4)'))) ?: 0,
seeders: utils.toInt(utils.text(utils.selectFirst(row, 'td:nth-child(5)'))) ?: 0,
leechers: utils.toInt(utils.text(utils.selectFirst(row, 'td:nth-child(6)'))) ?: 0,
]
}
return rows
} catch (e) { return [] }
}
private long parseHtmlSize(String s) {
if (!s) return 0
def m = s =~ /([\d.]+)\s*(TB|GB|MB|KB|B)?/
if (!m) return 0
def m2 = [B:1,KB:1024,MB:1048576,GB:1073741824,TB:1099511627776]
return ((m[0][1] as double) * (m2[m[0][2]?.toUpperCase()] ?: 1)) as long
}