mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-09-05 23:47:41 +08:00
fix(site): adapt GPW Gazelle seeding
This commit is contained in:
@@ -140,17 +140,41 @@ class GazelleSiteUserInfo(SiteParserBase):
|
|||||||
page_seeding = 0
|
page_seeding = 0
|
||||||
page_seeding_size = 0
|
page_seeding_size = 0
|
||||||
page_seeding_info = []
|
page_seeding_info = []
|
||||||
seeding_sizes = html.xpath(f'//table[contains(@id, "torrent")]//tr[position()>1]/td[{size_col}]')
|
semantic_rows = html.xpath(
|
||||||
seeding_seeders = html.xpath(f'//table[contains(@id, "torrent")]//tr[position()>1]/td[{seeders_col}]/text()')
|
'//table[contains(@id, "torrent")]//tr['
|
||||||
if seeding_sizes and seeding_seeders:
|
'contains(concat(" ", normalize-space(@class), " "), " TableTorrent-rowTitle ")]'
|
||||||
page_seeding = len(seeding_sizes)
|
)
|
||||||
|
if semantic_rows:
|
||||||
for i in range(0, len(seeding_sizes)):
|
# GPW 等现代 Gazelle 页面以语义 class 标记列,且标题单元格带 colspan,
|
||||||
size = size_tools.parse_size(seeding_sizes[i].xpath("string(.)").strip())
|
# 固定列序号无法反映视觉列位置,必须逐行按 class 配对读取。
|
||||||
seeders = int(seeding_seeders[i])
|
for row in semantic_rows:
|
||||||
|
size_cells = row.xpath(
|
||||||
|
'./td[contains(concat(" ", normalize-space(@class), " "), '
|
||||||
|
'" TableTorrent-cellStatSize ")]'
|
||||||
|
)
|
||||||
|
seeder_cells = row.xpath(
|
||||||
|
'./td[contains(concat(" ", normalize-space(@class), " "), '
|
||||||
|
'" TableTorrent-cellStatSeeders ")]'
|
||||||
|
)
|
||||||
|
if not size_cells or not seeder_cells:
|
||||||
|
continue
|
||||||
|
size = size_tools.parse_size(size_cells[0].xpath("string(.)").strip())
|
||||||
|
seeders = text_tools.parse_int(seeder_cells[0].xpath("string(.)").strip())
|
||||||
|
page_seeding += 1
|
||||||
page_seeding_size += size
|
page_seeding_size += size
|
||||||
page_seeding_info.append([seeders, size])
|
page_seeding_info.append([seeders, size])
|
||||||
|
else:
|
||||||
|
seeding_sizes = html.xpath(f'//table[contains(@id, "torrent")]//tr[position()>1]/td[{size_col}]')
|
||||||
|
seeding_seeders = html.xpath(f'//table[contains(@id, "torrent")]//tr[position()>1]/td[{seeders_col}]/text()')
|
||||||
|
if seeding_sizes and seeding_seeders:
|
||||||
|
page_seeding = len(seeding_sizes)
|
||||||
|
|
||||||
|
for i in range(0, len(seeding_sizes)):
|
||||||
|
size = size_tools.parse_size(seeding_sizes[i].xpath("string(.)").strip())
|
||||||
|
seeders = text_tools.parse_int(seeding_seeders[i])
|
||||||
|
|
||||||
|
page_seeding_size += size
|
||||||
|
page_seeding_info.append([seeders, size])
|
||||||
|
|
||||||
if multi_page:
|
if multi_page:
|
||||||
self.seeding += page_seeding
|
self.seeding += page_seeding
|
||||||
|
|||||||
@@ -0,0 +1,140 @@
|
|||||||
|
from app.modules.indexer.parser.gazelle import GazelleSiteUserInfo
|
||||||
|
from app.modules.indexer.spider import SiteSpider
|
||||||
|
|
||||||
|
|
||||||
|
GPW_HTML = """
|
||||||
|
<html><body>
|
||||||
|
<table class="TableTorrent Table" id="torrent_table"><tbody>
|
||||||
|
<tr class="TableTorrent-rowTitle Table-row torrent_checked">
|
||||||
|
<td class="Table-cell is-name" colspan="3">
|
||||||
|
<div class="TableTorrent-title">
|
||||||
|
<span class="TableTorrent-titleActions">
|
||||||
|
<a href="/torrents.php?action=download&id=115362">DL</a>
|
||||||
|
</span>
|
||||||
|
<a href="/torrents.php?id=8064&torrentid=115362">
|
||||||
|
<span class="TorrentTitle">
|
||||||
|
<span class="TorrentTitle-item resolution">1080p</span>
|
||||||
|
<span class="TorrentTitle-item is-releaseGroup">Example-GROUP</span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="Table-cell TableTorrent-cellStat TableTorrent-cellStatTime">
|
||||||
|
<span title="Aug 24 2026, 22:51">today</span>
|
||||||
|
</td>
|
||||||
|
<td class="Table-cell TableTorrent-cellStat TableTorrent-cellStatSize">1.50 GiB</td>
|
||||||
|
<td class="Table-cell TableTorrent-cellStat TableTorrent-cellStatSnatches">12</td>
|
||||||
|
<td class="Table-cell TableTorrent-cellStat TableTorrent-cellStatSeeders u-colorRatio00">1,234</td>
|
||||||
|
<td class="Table-cell TableTorrent-cellStat TableTorrent-cellStatLeechers">2</td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
</body></html>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def _gpw_indexer() -> dict:
|
||||||
|
"""构造与站点资源一致的 GPW 搜索配置。"""
|
||||||
|
detail_selector = 'a[href*="torrents.php?id="][href*="torrentid="]'
|
||||||
|
return {
|
||||||
|
"id": "greatposterwall",
|
||||||
|
"name": "海豹",
|
||||||
|
"domain": "https://greatposterwall.com/",
|
||||||
|
"search": {
|
||||||
|
"paths": [
|
||||||
|
{"path": "torrents.php?searchstr={keyword}", "method": "get"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"torrents": {
|
||||||
|
"list": {
|
||||||
|
"selector": "table#torrent_table > tbody > tr.TableTorrent-rowTitle"
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"id": {
|
||||||
|
"selector": detail_selector,
|
||||||
|
"attribute": "href",
|
||||||
|
"filters": [
|
||||||
|
{"name": "re_search", "args": [r"torrentid=(\d+)", 1]}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"title": {"selector": f"{detail_selector} > span.TorrentTitle"},
|
||||||
|
"details": {"selector": detail_selector, "attribute": "href"},
|
||||||
|
"download": {
|
||||||
|
"selector": 'a[href*="torrents.php?action=download"]',
|
||||||
|
"attribute": "href",
|
||||||
|
},
|
||||||
|
"size": {"selector": "td.TableTorrent-cellStatSize"},
|
||||||
|
"seeders": {"selector": "td.TableTorrent-cellStatSeeders"},
|
||||||
|
"leechers": {"selector": "td.TableTorrent-cellStatLeechers"},
|
||||||
|
"grabs": {"selector": "td.TableTorrent-cellStatSnatches"},
|
||||||
|
"date_elapsed": {
|
||||||
|
"selector": "td.TableTorrent-cellStatTime > span",
|
||||||
|
"attribute": "title",
|
||||||
|
"optional": True,
|
||||||
|
},
|
||||||
|
"date": {
|
||||||
|
"text": "{% if fields['date_elapsed'] %}{{ fields['date_elapsed'] }}{% else %}now{% endif %}",
|
||||||
|
"filters": [{"name": "dateparse", "args": "%b %d %Y, %H:%M"}],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _build_parser() -> GazelleSiteUserInfo:
|
||||||
|
"""构造 Gazelle 用户数据解析器测试实例。"""
|
||||||
|
return GazelleSiteUserInfo(
|
||||||
|
site_name="海豹",
|
||||||
|
url="https://greatposterwall.com/",
|
||||||
|
site_cookie="",
|
||||||
|
apikey=None,
|
||||||
|
token=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_greatposterwall_search_parses_tabletorrent_row(monkeypatch):
|
||||||
|
"""GPW 搜索结果应从 TableTorrent 行提取完整种子信息。"""
|
||||||
|
monkeypatch.setattr(
|
||||||
|
"app.modules.indexer.spider.rust_accel.parse_indexer_torrents",
|
||||||
|
lambda **_: None,
|
||||||
|
)
|
||||||
|
|
||||||
|
results = SiteSpider(_gpw_indexer(), keyword="Example").parse(GPW_HTML)
|
||||||
|
|
||||||
|
assert len(results) == 1
|
||||||
|
assert results[0]["title"] == "1080p Example-GROUP"
|
||||||
|
assert results[0]["page_url"].endswith("torrents.php?id=8064&torrentid=115362")
|
||||||
|
assert results[0]["enclosure"].endswith("torrents.php?action=download&id=115362")
|
||||||
|
assert results[0]["size"] == 1610612736
|
||||||
|
assert results[0]["seeders"] == 1234
|
||||||
|
assert results[0]["peers"] == 2
|
||||||
|
assert results[0]["grabs"] == 12
|
||||||
|
assert results[0]["pubdate"] == "2026-08-24 22:51:00"
|
||||||
|
|
||||||
|
|
||||||
|
def test_greatposterwall_seeding_uses_semantic_stat_cells():
|
||||||
|
"""GPW 标题列使用 colspan 时,做种统计仍应按语义 class 正确配对。"""
|
||||||
|
parser = _build_parser()
|
||||||
|
|
||||||
|
next_page = parser._parse_user_torrent_seeding_info(GPW_HTML)
|
||||||
|
|
||||||
|
assert next_page is None
|
||||||
|
assert parser.seeding == 1
|
||||||
|
assert parser.seeding_size == 1610612736
|
||||||
|
assert parser.seeding_info == [[1234, 1610612736]]
|
||||||
|
|
||||||
|
|
||||||
|
def test_gazelle_seeding_keeps_legacy_column_fallback():
|
||||||
|
"""没有语义 class 的传统 Gazelle 表格仍应按既有列号统计做种。"""
|
||||||
|
parser = _build_parser()
|
||||||
|
html_text = """
|
||||||
|
<table id="torrent_table">
|
||||||
|
<tr><td>Name</td><td>Type</td><td>Time</td><td>Size</td><td>Snatches</td><td>Seeders</td><td>Leechers</td></tr>
|
||||||
|
<tr><td>Example</td><td>Movie</td><td>today</td><td>2 GiB</td><td>3</td><td>45</td><td>1</td></tr>
|
||||||
|
</table>
|
||||||
|
"""
|
||||||
|
|
||||||
|
parser._parse_user_torrent_seeding_info(html_text)
|
||||||
|
|
||||||
|
assert parser.seeding == 1
|
||||||
|
assert parser.seeding_size == 2147483648
|
||||||
|
assert parser.seeding_info == [[45, 2147483648]]
|
||||||
Reference in New Issue
Block a user