@@ -168,7 +168,7 @@ function parseSearch(items) {
var row = {
id : it . id !== undefined && it . id !== null ? String ( it . id ) : '' ,
title : it . name || '' ,
subT itle : it . smallDescr || '' ,
subt itle : it . smallDescr || '' ,
size : size ,
seeders : _ _toInt ( st . seeders ) ,
leechers : _ _toInt ( st . leechers ) ,
@@ -355,4 +355,92 @@ function download(input) {
} catch ( e ) {
return { error : String ( ( e && e . message ) || e ) , url : url } ;
}
}
}
// ===================== 能力: rss( RSS/Atom 解析)=====================
// ctx: { baseUrl, feedUrl }
// mteam 没有通用 RSS 端点 (签名算法不可预知), 用户需从 /rss 页面复制完整 RSS URL,
// 填到 RssSubscription.Url 字段 (→ ctx.feedUrl).
// NexusPHP 类站点: getrss.php / torrentrss.php 两种命名, 脚本 rss() 里兼容.
// 返回: [{ title, detailUrl, downloadUrl, description, pubDate, guid }] 或 { error }
function rss ( ctx ) {
var base = String ( ctx . baseUrl || '' ) . replace ( /\/+$/ , '' ) ;
var apiUrl = String ( ctx . apiUrl || ( base ? base + '/api' : '' ) ) . replace ( /\/+$/ , '' ) ;
var url = ctx . feedUrl ? String ( ctx . feedUrl ) : '' ;
// 用户没手动填 feedUrl → 尝试 POST /rss/genlink 自动生成
if ( ! url && apiUrl ) {
var apiKey = ctx . apiKey || ctx . xApiKey ;
var genResult = _ _apiPost ( apiUrl , '/rss/genlink' , { } , apiKey ) ;
if ( genResult && genResult . code === 0 && genResult . data ) {
var d = genResult . data ;
if ( typeof d === 'string' && d . length > 0 ) {
url = d ;
} else if ( typeof d === 'object' && d !== null ) {
url = d . url || d . link || d . rssUrl || d . feedUrl || d . linkUrl || '' ;
}
}
}
if ( ! url ) return { error : 'rss_url_required' , hint : '请从 /rss 页面复制完整 RSS URL 到 RssSubscription, 或确认 Cookie/apiKey 有效' } ;
var xml ;
try {
xml = http . get ( url ) ;
} catch ( e ) {
return { error : String ( ( e && e . message ) || e ) , url : url } ;
}
if ( ! xml ) return { error : 'empty_feed' , url : url } ;
var items = [ ] ;
function tag ( block , name ) {
var m = block . match ( new RegExp ( '<' + name + '[^>]*>([\\s\\S]*?)<\\/' + name + '>' , 'i' ) ) ;
return m ? m [ 1 ] . replace ( /<!\[CDATA\[([\s\S]*?)\]\]>/g , '$1' ) . trim ( ) : '' ;
}
// RSS 2.0: <item>
var blocks = xml . match ( /<item[\s\S]*?<\/item>/gi ) ;
if ( blocks ) {
for ( var i = 0 ; i < blocks . length ; i ++ ) {
var b = blocks [ i ] ;
var encMatch = b . match ( /<enclosure[^>]*>/i ) ;
var encUrl = '' ;
if ( encMatch ) {
var u = encMatch [ 0 ] . match ( /url=["'']([^"'']*)["'']/i ) ;
if ( u ) encUrl = u [ 1 ] ;
}
items . push ( {
title : tag ( b , 'title' ) ,
detailUrl : tag ( b , 'link' ) ,
downloadUrl : encUrl || tag ( b , 'link' ) ,
description : tag ( b , 'description' ) ,
pubDate : tag ( b , 'pubDate' ) ,
guid : tag ( b , 'guid' ) || tag ( b , 'link' )
} ) ;
}
}
// Atom: <entry>
var atomBlocks = xml . match ( /<entry[\s\S]*?<\/entry>/gi ) ;
if ( atomBlocks ) {
for ( var j = 0 ; j < atomBlocks . length ; j ++ ) {
var a = atomBlocks [ j ] ;
var linkMatch = a . match ( /<link[^>]*href=["'']([^"'']*)["''][^>]*>/i ) ;
var link = linkMatch ? linkMatch [ 1 ] : tag ( a , 'link' ) ;
items . push ( {
title : tag ( a , 'title' ) ,
detailUrl : link ,
downloadUrl : link ,
description : tag ( a , 'summary' ) || tag ( a , 'content' ) ,
pubDate : tag ( a , 'updated' ) || tag ( a , 'published' ) ,
guid : tag ( a , 'id' ) || link
} ) ;
}
}
if ( items . length === 0 ) {
return { error : 'no_items_parsed' , url : url , hint : 'RSS/Atom 格式未识别' } ;
}
return items ;
}