Source/SourceKind、UserRole、SubscriptionMatch 三个 enum 改用 values_callable 保证 PG 看到 'rss' / 'owner' / 'any' 等小写 value,而非 'RSS' 大写 name。 seed_sources 同步改为显式字符串。
116 lines
3.1 KiB
Python
116 lines
3.1 KiB
Python
"""种子:导入 MVP 5 源。
|
|
|
|
- Reuters World
|
|
- BBC World
|
|
- Al Jazeera
|
|
- NHK World
|
|
- DW
|
|
|
|
RSS 链接为公开 feed,实际链接可能变更;若 fetch 失败,先看 /admin/health。
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import sys
|
|
|
|
from sqlalchemy import select
|
|
from sqlalchemy.dialects.postgresql import insert as pg_insert
|
|
from sqlalchemy.exc import IntegrityError
|
|
|
|
from app.database import AsyncSessionLocal
|
|
from app.models.source import Source
|
|
|
|
# 用字符串避免 SQLAlchemy 把 enum 写成 name(大写)而非 value(小写)
|
|
SEEDS = [
|
|
{
|
|
"name": "Reuters World",
|
|
"slug": "reuters-world",
|
|
"kind": "rss",
|
|
"url": "https://feeds.reuters.com/Reuters/worldNews",
|
|
"region": "global",
|
|
"language_src": "en",
|
|
"priority": 90,
|
|
"fetch_interval_min": 30,
|
|
"translate_to": "zh",
|
|
"enabled": True,
|
|
},
|
|
{
|
|
"name": "BBC World",
|
|
"slug": "bbc-world",
|
|
"kind": "rss",
|
|
"url": "https://feeds.bbci.co.uk/news/world/rss.xml",
|
|
"region": "global",
|
|
"language_src": "en",
|
|
"priority": 85,
|
|
"fetch_interval_min": 30,
|
|
"translate_to": "zh",
|
|
"enabled": True,
|
|
},
|
|
{
|
|
"name": "Al Jazeera",
|
|
"slug": "aljazeera",
|
|
"kind": "rss",
|
|
"url": "https://www.aljazeera.com/xml/rss/all.xml",
|
|
"region": "mena",
|
|
"language_src": "en",
|
|
"priority": 80,
|
|
"fetch_interval_min": 45,
|
|
"translate_to": "zh",
|
|
"enabled": True,
|
|
},
|
|
{
|
|
"name": "NHK World",
|
|
"slug": "nhk-world",
|
|
"kind": "rss",
|
|
"url": "https://www3.nhk.or.jp/rss/news/cat0.xml",
|
|
"region": "asia",
|
|
"language_src": "en",
|
|
"priority": 70,
|
|
"fetch_interval_min": 60,
|
|
"translate_to": "zh",
|
|
"enabled": True,
|
|
},
|
|
{
|
|
"name": "DW (Deutsche Welle)",
|
|
"slug": "dw",
|
|
"kind": "rss",
|
|
"url": "https://rss.dw.com/xml/rss-en-all",
|
|
"region": "eu",
|
|
"language_src": "en",
|
|
"priority": 70,
|
|
"fetch_interval_min": 60,
|
|
"translate_to": "zh",
|
|
"enabled": True,
|
|
},
|
|
]
|
|
|
|
|
|
async def main() -> int:
|
|
async with AsyncSessionLocal() as session:
|
|
inserted = 0
|
|
for row in SEEDS:
|
|
stmt = (
|
|
pg_insert(Source)
|
|
.values(**row)
|
|
.on_conflict_do_nothing(index_elements=["slug"])
|
|
.returning(Source.id)
|
|
)
|
|
try:
|
|
r = await session.execute(stmt)
|
|
rid = r.scalar_one_or_none()
|
|
if rid is not None:
|
|
inserted += 1
|
|
print(f" + {row['slug']} (id={rid})")
|
|
else:
|
|
print(f" = {row['slug']} (already exists)")
|
|
except IntegrityError as e:
|
|
print(f" ! {row['slug']}: {e}", file=sys.stderr)
|
|
await session.rollback()
|
|
await session.commit()
|
|
print(f"seeded {inserted} new source(s)")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(asyncio.run(main()))
|