yopu 搜索结果同一首歌通常有多个版本,区分方式: - 字母谱:nier-snippet 里 SVG <text> 渲染 chord 字母(G/Em7/C 等) - 功能谱:nier-snippet 里没 SVG <text>,直接 HTML/CSS 显示 1/4/5/6m 按 svgTextCount === 0 优先选第一个功能谱,没功能谱才 fallback 到字母谱。 view 页里没有「谱面样式」「和弦样式」row(要登录 APP 才有),所以这是唯一可行路径。 实测 独家记忆/倔强/Casablanca 三首都拿到正确的功能谱截图。
This commit is contained in:
+28
-12
@@ -55,10 +55,13 @@ def setup_driver(window="1920,5000"):
|
||||
|
||||
|
||||
def find_first_chord_chart(driver, search_url):
|
||||
"""在搜索页找第一个结果(yopu 现在默认全部是和弦谱),返回 view url 和 title。
|
||||
"""在搜索页找最佳的「功能谱」结果。
|
||||
|
||||
旧版 yopu UI 在 .one-line-info 里有「和弦谱」字样可以过滤,
|
||||
新版(svelte 重写后)已经没有,只有调号 (G调/C调/F调)。直接取第一个 a.post-main。
|
||||
yopu 现在搜索结果里同一首歌有多个版本:
|
||||
- 字母谱(chord chart):nier-snippet 里有 SVG <text> 渲染的 chord 字母(G/Em7/C)
|
||||
- 功能谱(数字 / 级数):nier-snippet 里没 SVG <text>(用 HTML/CSS 显示数字 1/4/5)
|
||||
|
||||
我们优先取第一个**功能谱**(svgTextCount === 0),fallback 到第一个字母谱。
|
||||
"""
|
||||
logger.info("loading search: %s", search_url)
|
||||
driver.get(search_url)
|
||||
@@ -72,35 +75,48 @@ def find_first_chord_chart(driver, search_url):
|
||||
var titleEl = p.querySelector('.title-line .title, .title');
|
||||
var subEl = p.querySelector('.title-line .subtitle, .subtitle');
|
||||
var info = p.querySelector('.one-line-info');
|
||||
var snippet = p.querySelector('.nier-snippet');
|
||||
var svgTextCount = snippet ? snippet.querySelectorAll('svg text').length : 0;
|
||||
out.push({
|
||||
href: p.href,
|
||||
title: titleEl ? (titleEl.textContent || '').trim() : '',
|
||||
subtitle: subEl ? (subEl.textContent || '').trim() : '',
|
||||
info: info ? (info.textContent || '').trim() : '',
|
||||
isFunctional: svgTextCount === 0,
|
||||
svgTextCount: svgTextCount,
|
||||
});
|
||||
}
|
||||
return out;
|
||||
""")
|
||||
|
||||
if not hits:
|
||||
logger.warning("no a.post-main found in search results — yopu DOM changed?")
|
||||
logger.warning("no a.post-main found — yopu DOM changed?")
|
||||
return None
|
||||
|
||||
# MVP:直接取第一个。前 N 个一般是同一首歌的不同 key (G/C/F),第一个通常是默认 key。
|
||||
first = hits[0]
|
||||
href = first['href']
|
||||
# 优先功能谱
|
||||
functional = [h for h in hits if h['isFunctional']]
|
||||
if functional:
|
||||
chosen = functional[0]
|
||||
kind = 'functional'
|
||||
else:
|
||||
chosen = hits[0]
|
||||
kind = 'letter-chord (no functional version found)'
|
||||
|
||||
href = chosen['href']
|
||||
if href.startswith('/'):
|
||||
p = urlparse(search_url)
|
||||
href = f"{p.scheme}://{p.netloc}{href}"
|
||||
elif not href.startswith('http'):
|
||||
href = urljoin(search_url, href)
|
||||
logger.info("matched %d/%d hits, picking #1: %s — %s [%s]",
|
||||
1, len(hits), first.get('title'), first.get('subtitle'), first.get('info'))
|
||||
logger.info("[%s] %s — %s [%s] (%d total: %d functional, %d letter)",
|
||||
kind, chosen['title'], chosen['subtitle'], chosen['info'],
|
||||
len(hits), len(functional), len(hits) - len(functional))
|
||||
return {
|
||||
'url': href,
|
||||
'title': first.get('title') or '',
|
||||
'subtitle': first.get('subtitle') or '',
|
||||
'text': first.get('info') or '',
|
||||
'title': chosen.get('title') or '',
|
||||
'subtitle': chosen.get('subtitle') or '',
|
||||
'text': chosen.get('info') or '',
|
||||
'kind': kind,
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user