Files
par/docs/mteam.groovy
2026-07-01 11:15:12 +08:00

151 lines
5.7 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.

// M-Team 适配脚本 (mteam)
// 站点类型: mtorrent
// API 基地址: https://api.m-team.io (优先) / https://api.m-team.cc (备用)
final String API_BASE = "https://api.m-team.io"
// ==================== PAR 校验入口 ====================
// content: 访问结果页面内容(JSON 字符串)
// url: 访问结果的 URL
// 返回: [pageName:"xx", fields:[k:v,...]] 或 [pageName:"xx", extracted:[[...]], message:"..."]
Map parse(String content, String url) {
def slurp = new groovy.json.JsonSlurper()
def root = slurp.parseText(content)
// ── 用户信息 ──
if (url.contains('/api/member/profile')) {
def d = root?.data
if (!d) return [pageName: '用户信息', message: 'data 为空']
return buildProfile(d)
}
// ── 搜索 ──
if (url.contains('/api/torrent/search')) {
def items = root?.data?.data ?: []
if (items.isEmpty()) return [pageName: '搜索', message: '无结果']
return buildSearchResults(items)
}
// ── 未匹配 ──
return [pageName: '未知接口', message: "未配置解析: ${url}"]
}
private Map buildProfile(d) {
return [
pageName: '用户信息',
fields: [
id: d.id?.toString(),
username: d.username?.toString(),
uploaded: utils.formatSize(d.uploaded as long),
downloaded: utils.formatSize(d.downloaded as long),
bonus: d.bonus?.toString(),
seeding: d.seeding?.toString(),
seedingSize: utils.formatSize(d.seedingSize as long),
invite: d.memberCount?.invite?.toString(),
]
]
}
private Map buildSearchResults(List items) {
def rows = items.collect { it ->
def st = it.status ?: [:]
return [
title: it.name ?: '',
size: utils.formatSize((it.size ?: 0) as long),
seeders: st.seeders ?: 0,
leechers: st.leechers ?: 0,
grabs: st.timesCompleted ?: 0,
discount: st.discount ?: 'NORMAL',
category: it.category ?: '',
]
}
return [pageName: '搜索', extracted: rows, message: "共 ${rows.size()} 条"]
}
// ==================== mediabot 运行时入口 ====================
Map sync(PluginContext ctx) {
if (!ctx.site.authorization) return [message: "未配置 Token", loginRequired: true]
try {
def resp = apiGet(ctx, "/api/member/profile")
if (resp.statusCode() == 403 || resp.statusCode() == 401)
return [message: "Token 无效", loginRequired: true]
if (resp.statusCode() != 200)
return [message: "HTTP ${resp.statusCode()}", siteUnavailable: true]
def json = new groovy.json.JsonSlurper().parseText(resp.body())
if (json.message != "SUCCESS" || !json.data)
return [message: "响应格式异常"]
def d = json.data
return [
upload: d.uploaded ? (d.uploaded as long) * 1073741824 : null,
download: d.downloaded ? (d.downloaded as long) * 1073741824 : null,
bonus: d.bonus ? d.bonus as double : null,
seeding: d.seeding ? d.seeding as int : null,
seedingSize: d.seedingSize? (d.seedingSize as long) * 1073741824: null,
]
} catch (e) {
return [message: "同步失败: ${e.message}"]
}
}
List search(PluginContext ctx, Map params) {
if (!ctx.site.authorization) return []
try {
def keyword = params.keyword ?: ""
def page = (params.page ?: 1) as int
def body = groovy.json.JsonOutput.toJson([
keyword: keyword, pageNumber: page, pageSize: 50, visible: 1
])
def resp = apiPost(ctx, "/api/torrent/search", body)
if (resp.statusCode() != 200) return []
def json = new groovy.json.JsonSlurper().parseText(resp.body())
def list = json?.data?.data ?: []
return list.collect { item ->
def st = item.status ?: [:]
return [
title: item.name ?: "",
detailUrl: "${ctx.siteUrl}detail/${item.id ?: ''}",
size: (item.size ?: 0) as long,
seeders: (st.seeders ?: 0) as int,
leechers: (st.leechers ?: 0) as int,
grabs: (st.timesCompleted ?: 0) as int,
category: item.category ?: "",
free: st.discount == "FREE" || st.discount == "_2X_FREE",
]
}
} catch (e) {
return []
}
}
// ==================== 工具方法 ====================
private def apiGet(PluginContext ctx, String path) {
return ctx.httpClient.send(
java.net.http.HttpRequest.newBuilder()
.uri(new java.net.URI(API_BASE + path))
.timeout(java.time.Duration.ofSeconds(path.contains('profile') ? 10 : 20))
.header("User-Agent", "Mozilla/5.0")
.header("x-api-key", ctx.site.authorization)
.header("Origin", ctx.siteUrl)
.POST(java.net.http.HttpRequest.BodyPublishers.noBody())
.build(),
java.net.http.HttpResponse.BodyHandlers.ofString())
}
private def apiPost(PluginContext ctx, String path, String body) {
return ctx.httpClient.send(
java.net.http.HttpRequest.newBuilder()
.uri(new java.net.URI(API_BASE + path))
.timeout(java.time.Duration.ofSeconds(20))
.header("User-Agent", "Mozilla/5.0")
.header("x-api-key", ctx.site.authorization)
.header("Content-Type", "application/json")
.POST(java.net.http.HttpRequest.BodyPublishers.ofString(body))
.build(),
java.net.http.HttpResponse.BodyHandlers.ofString())
}