179 lines
6.7 KiB
Groovy
179 lines
6.7 KiB
Groovy
// M-Team 适配脚本 (mteam)
|
||
// API 基地址(io 优先,cc 备用)
|
||
final String API_BASE = "https://api.m-team.io"
|
||
|
||
// ==================== PAR 校验入口 ====================
|
||
|
||
Map parse(String content, String url) {
|
||
Map root
|
||
try {
|
||
root = json.readValue(content, Map)
|
||
} catch (e) {
|
||
def msg = e.message instanceof String ? e.message : e.toString()
|
||
return [pageName: '解析失败', message: 'JSON 解析异常: ' + msg]
|
||
}
|
||
|
||
if (url.contains('/api/member/profile'))
|
||
return parseProfile(root?.data)
|
||
|
||
if (url.contains('/api/tracker/myPeerStatistics'))
|
||
return parsePeerStats(root?.data)
|
||
|
||
if (url.contains('/api/torrent/search'))
|
||
return parseSearch(root?.data?.data ?: [])
|
||
|
||
return [pageName: '未知接口', message: "未配置解析: ${url}"]
|
||
}
|
||
|
||
private Map parseProfile(d) {
|
||
if (!d) return [pageName: '用户信息', message: 'data 为空']
|
||
return [
|
||
pageName: '用户信息',
|
||
fields: [
|
||
uid: d.id?.toString(),
|
||
username: d.username?.toString(),
|
||
email: d.email?.toString(),
|
||
upload: utils.formatSize((d.memberCount?.uploaded ?: 0) as long),
|
||
download: utils.formatSize((d.memberCount?.downloaded ?: 0) as long),
|
||
bonus: d.memberCount?.bonus?.toString(),
|
||
shareRate:d.memberCount?.shareRate?.toString(),
|
||
invites: d.invites?.toString(),
|
||
]
|
||
]
|
||
}
|
||
|
||
private Map parsePeerStats(d) {
|
||
if (!d) return [pageName: '做种统计', message: 'data 为空']
|
||
return [
|
||
pageName: '做种统计',
|
||
fields: [
|
||
seeding: d.seederCount?.toString() ?: '0',
|
||
]
|
||
]
|
||
}
|
||
|
||
private Map parseSearch(List items) {
|
||
if (items.isEmpty()) return [pageName: '搜索', message: '无结果']
|
||
def rows = items.collect { it ->
|
||
def st = it.status ?: [:]
|
||
return [
|
||
id: it.id?.toString(),
|
||
title: it.name ?: '',
|
||
subTitle: it.smallDescr ?: '',
|
||
size: utils.formatSize((it.size ?: 0) as long),
|
||
seeders: (st.seeders ?: 0) as int,
|
||
leechers: (st.leechers ?: 0) as int,
|
||
completed: (st.timesCompleted ?: 0) as int,
|
||
category: it.category ?: '',
|
||
free: st.discount ?: 'NORMAL',
|
||
publisher: it.author ?: '',
|
||
cnSub: it.hasChineseSubtitle != null ? it.hasChineseSubtitle.toString() : '',
|
||
standard: it.standard ?: '',
|
||
]
|
||
}
|
||
return [pageName: '搜索', extracted: rows, message: "共 ${rows.size()} 条"]
|
||
}
|
||
|
||
// ==================== mediabot 运行时入口 ====================
|
||
|
||
Map sync(PluginContext ctx) {
|
||
if (!ctx.site.authorization) return [message: "未配置 Token", loginRequired: true]
|
||
try {
|
||
// 用户信息
|
||
def resp = apiPost(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
|
||
def mc = d.memberCount ?: [:]
|
||
def result = [
|
||
upload: mc.uploaded ? (mc.uploaded as long) * 1073741824 : null,
|
||
download: mc.downloaded ? (mc.downloaded as long) * 1073741824 : null,
|
||
bonus: mc.bonus ? mc.bonus as double : null,
|
||
shareRate:mc.shareRate ? mc.shareRate as double : null,
|
||
invites: d.invites ? d.invites as int : null,
|
||
]
|
||
|
||
// 做种统计
|
||
def seedResp = apiPost(ctx, "/api/tracker/myPeerStatistics")
|
||
if (seedResp.statusCode() == 200) {
|
||
def sj = new groovy.json.JsonSlurper().parseText(seedResp.body())
|
||
if (sj?.data?.seederCount != null)
|
||
result.seeding = sj.data.seederCount as int
|
||
}
|
||
|
||
return result
|
||
} catch (e) {
|
||
return [message: "同步失败: ${e.message}"]
|
||
}
|
||
}
|
||
|
||
Map sign(PluginContext ctx) {
|
||
return [message: "M-Team 不支持签到"]
|
||
}
|
||
|
||
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: 100, mode: "normal", 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 [
|
||
id: item.id?.toString(),
|
||
title: item.name ?: "",
|
||
subTitle: item.smallDescr ?: "",
|
||
size: (item.size ?: 0) as long,
|
||
seeders: (st.seeders ?: 0) as int,
|
||
leechers: (st.leechers ?: 0) as int,
|
||
completed: (st.timesCompleted ?: 0) as int,
|
||
publishDate: item.createdDate ?: "",
|
||
category: item.category ?: "",
|
||
free: st.discount == "FREE" || st.discount == "_2X_FREE",
|
||
freeEndTime: st.discountEndTime ?: "",
|
||
publisher: item.author ?: "",
|
||
tags: item.labelsNew?.join(",") ?: "",
|
||
doubanUrl: item.douban ?: "",
|
||
doubanRating: item.doubanRating?.toString() ?: "",
|
||
imdbUrl: item.imdb ?: "",
|
||
cnSub: item.hasChineseSubtitle != null ? item.hasChineseSubtitle.toString() : "",
|
||
standard: item.standard ?: "",
|
||
detailUrl: "${ctx.siteUrl}detail/${item.id ?: ''}",
|
||
]
|
||
}
|
||
} catch (e) {
|
||
return []
|
||
}
|
||
}
|
||
|
||
// ==================== 工具方法 ====================
|
||
|
||
private def apiPost(PluginContext ctx, String path, String body = null) {
|
||
def builder = 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")
|
||
|
||
if (body) builder.POST(java.net.http.HttpRequest.BodyPublishers.ofString(body))
|
||
else builder.POST(java.net.http.HttpRequest.BodyPublishers.noBody())
|
||
|
||
return ctx.httpClient.send(builder.build(),
|
||
java.net.http.HttpResponse.BodyHandlers.ofString())
|
||
}
|