Features: feed CRUD, per-feed ntfy target (incl. private servers), Telegram/webhook channels, keyword filters, image attachments, per-feed intervals, OPML import/export, notification history & stats, users with roles, admin alerts, RU/EN i18n, light/dark theme, notification preview, history search, activity chart. Dockerized. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+57
@@ -0,0 +1,57 @@
|
||||
"""OPML import/export for feed subscriptions."""
|
||||
from __future__ import annotations
|
||||
|
||||
from xml.etree import ElementTree as ET
|
||||
|
||||
from .models import Feed
|
||||
|
||||
|
||||
def export_opml(feeds: list[Feed]) -> str:
|
||||
"""Render feeds as an OPML 2.0 document."""
|
||||
opml = ET.Element("opml", version="2.0")
|
||||
head = ET.SubElement(opml, "head")
|
||||
ET.SubElement(head, "title").text = "RSS → ntfy subscriptions"
|
||||
body = ET.SubElement(opml, "body")
|
||||
for feed in feeds:
|
||||
attrs = {
|
||||
"type": "rss",
|
||||
"text": feed.title or feed.url,
|
||||
"title": feed.title or feed.url,
|
||||
"xmlUrl": feed.url,
|
||||
}
|
||||
# Stash the ntfy topic so a re-import keeps the routing.
|
||||
if feed.ntfy_topic:
|
||||
attrs["ntfyTopic"] = feed.ntfy_topic
|
||||
if feed.ntfy_server:
|
||||
attrs["ntfyServer"] = feed.ntfy_server
|
||||
ET.SubElement(body, "outline", attrs)
|
||||
return '<?xml version="1.0" encoding="UTF-8"?>\n' + ET.tostring(
|
||||
opml, encoding="unicode"
|
||||
)
|
||||
|
||||
|
||||
def parse_opml(content: str) -> list[dict]:
|
||||
"""Extract feed definitions from an OPML document.
|
||||
|
||||
Returns a list of dicts ready to build Feed rows. Raises ValueError on
|
||||
malformed XML.
|
||||
"""
|
||||
try:
|
||||
root = ET.fromstring(content)
|
||||
except ET.ParseError as exc:
|
||||
raise ValueError(f"Некорректный OPML: {exc}") from exc
|
||||
|
||||
feeds: list[dict] = []
|
||||
for outline in root.iter("outline"):
|
||||
url = outline.get("xmlUrl") or outline.get("xmlurl")
|
||||
if not url:
|
||||
continue
|
||||
feeds.append(
|
||||
{
|
||||
"url": url.strip(),
|
||||
"title": (outline.get("title") or outline.get("text") or "").strip(),
|
||||
"ntfy_topic": (outline.get("ntfyTopic") or "").strip(),
|
||||
"ntfy_server": (outline.get("ntfyServer") or "").strip(),
|
||||
}
|
||||
)
|
||||
return feeds
|
||||
Reference in New Issue
Block a user