Files
par/docs/mteam.groovy

179 lines
6.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)
// 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())
}