91 lines
3.2 KiB
Python
91 lines
3.2 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
"""从 TMDB 网页数据解析剧集信息,通过 Emby API 批量更新元数据"""
|
|||
|
|
import re, json, subprocess, sys
|
|||
|
|
|
|||
|
|
# TMDB 数据(从 web_fetch 结果手动整理)
|
|||
|
|
def parse_tmdb(text):
|
|||
|
|
eps = []
|
|||
|
|
# 匹配: 数字\n\n### [集名](...) ... • Xm\n\n 简介 \n [展开]
|
|||
|
|
blocks = re.split(r'\n\s*/tv/82728-bluey/season/\d+/episode/\d+\?language=zh-CN\s*\n', text)
|
|||
|
|
for block in blocks:
|
|||
|
|
m = re.match(r'\s*(\d+)\s*\n\n###\s*\[([^\]]+)\]', block)
|
|||
|
|
if not m:
|
|||
|
|
continue
|
|||
|
|
num = int(m.group(1))
|
|||
|
|
name = m.group(2)
|
|||
|
|
# 找简介:在 • Xm 之后,[展开] 之前
|
|||
|
|
ov_match = re.search(r'•\s*\d+m\s*\n\s*(.*?)\n\s*\[展开\]', block, re.DOTALL)
|
|||
|
|
overview = ov_match.group(1).strip() if ov_match else ""
|
|||
|
|
# 清理简介中的换行
|
|||
|
|
overview = re.sub(r'\s+', ' ', overview)
|
|||
|
|
eps.append({"number": num, "name": name, "overview": overview})
|
|||
|
|
return eps
|
|||
|
|
|
|||
|
|
EMBY = "http://localhost:8096/emby"
|
|||
|
|
KEY = "e3e52b1dcb8b47c39d46b5256bf87081"
|
|||
|
|
SERIES_ID = "10"
|
|||
|
|
SEASON_MAP = {1: "11", 2: "12", 3: "13"}
|
|||
|
|
|
|||
|
|
def ssh_cmd(cmd):
|
|||
|
|
full = f"sshpass -p 'fJ7#vP9s@tL2qX!d' ssh -o StrictHostKeyChecking=no -i /tmp/koipy_key root@155.103.67.95 \"{cmd}\""
|
|||
|
|
r = subprocess.run(full, shell=True, capture_output=True, text=True, timeout=30)
|
|||
|
|
return r.stdout.strip()
|
|||
|
|
|
|||
|
|
def get_episodes(season_id):
|
|||
|
|
out = ssh_cmd(f"curl -s '{EMBY}/Shows/{SERIES_ID}/Episodes?SeasonId={season_id}&api_key={KEY}'")
|
|||
|
|
return json.loads(out).get("Items", [])
|
|||
|
|
|
|||
|
|
def update_episode(item_id, name, overview):
|
|||
|
|
# 用 Emby API 更新 Name 和 Overview
|
|||
|
|
# 需要先 GET 完整 item,修改后 POST 回去
|
|||
|
|
escaped_name = name.replace("'", "'\\''").replace('"', '\\"')
|
|||
|
|
escaped_ov = overview.replace("'", "'\\''").replace('"', '\\"')
|
|||
|
|
|
|||
|
|
cmd = f"""
|
|||
|
|
python3 -c '
|
|||
|
|
import json, urllib.request
|
|||
|
|
url = "{EMBY}/Items/{item_id}?api_key={KEY}"
|
|||
|
|
data = json.loads(urllib.request.urlopen(url).read())
|
|||
|
|
data["Name"] = "{escaped_name}"
|
|||
|
|
data["Overview"] = "{escaped_ov}"
|
|||
|
|
req = urllib.request.Request(url, data=json.dumps(data).encode(), method="POST", headers={{"Content-Type": "application/json"}})
|
|||
|
|
urllib.request.urlopen(req)
|
|||
|
|
print("ok")
|
|||
|
|
'
|
|||
|
|
"""
|
|||
|
|
return ssh_cmd(cmd.strip())
|
|||
|
|
|
|||
|
|
# 读取保存的 TMDB 数据
|
|||
|
|
with open("/Users/jianzhang/.openclaw/workspace/scripts/bluey_tmdb.json") as f:
|
|||
|
|
tmdb_data = json.load(f)
|
|||
|
|
|
|||
|
|
total = 0
|
|||
|
|
for season_num in [1, 2, 3]:
|
|||
|
|
season_id = SEASON_MAP[season_num]
|
|||
|
|
tmdb_eps = tmdb_data.get(str(season_num), [])
|
|||
|
|
emby_eps = get_episodes(season_id)
|
|||
|
|
|
|||
|
|
print(f"\n=== 第{season_num}季 === TMDB: {len(tmdb_eps)}集, Emby: {len(emby_eps)}集")
|
|||
|
|
|
|||
|
|
# 按 IndexNumber 匹配
|
|||
|
|
emby_map = {ep.get("IndexNumber"): ep for ep in emby_eps}
|
|||
|
|
|
|||
|
|
for tmdb_ep in tmdb_eps:
|
|||
|
|
num = tmdb_ep["number"]
|
|||
|
|
name = tmdb_ep["name"]
|
|||
|
|
overview = tmdb_ep["overview"]
|
|||
|
|
|
|||
|
|
if num not in emby_map:
|
|||
|
|
print(f" E{num}: 跳过(Emby中不存在)")
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
emby_ep = emby_map[num]
|
|||
|
|
item_id = emby_ep["Id"]
|
|||
|
|
|
|||
|
|
result = update_episode(item_id, name, overview)
|
|||
|
|
status = "✅" if "ok" in result else f"❌ {result}"
|
|||
|
|
print(f" E{num} {name}: {status}")
|
|||
|
|
total += 1
|
|||
|
|
|
|||
|
|
print(f"\n完成!共更新 {total} 集")
|