OPML export

This commit is contained in:
John Doty 2025-09-20 10:52:23 -07:00
parent 07f8de3f99
commit 0fd9cc8bbd
2 changed files with 36 additions and 2 deletions

View file

@ -295,3 +295,19 @@ def serve():
def sync():
local_db = database.Database.local()
database.sync(local_db)
@cli.command(name="export")
@click.argument("opml_file", type=click.File("wb"))
def export_opml(opml_file):
"Export the specified OPML file."
db = database.Database.local()
feeds = db.load_all(feed_limit=0)
if len(feeds) == 0:
click.echo("Not subscribed to any feeds.")
return 0
feeds.sort(key=lambda f: f.title)
opml.write_opml(opml_file, feeds)

View file

@ -1,12 +1,30 @@
import pathlib
import xml.etree.ElementTree
import xml.etree.ElementTree as ET
from . import feed
def parse_opml(opml: str) -> list[str]:
f = xml.etree.ElementTree.fromstring(opml)
f = ET.fromstring(opml)
return [e.attrib["xmlUrl"] for e in f.iterfind(".//*[@xmlUrl]")]
def load_opml(path: pathlib.Path) -> list[str]:
with open(path, "r", encoding="utf-8") as f:
return parse_opml(f.read())
def write_opml(f, feeds: list[feed.Feed]):
root = ET.Element("opml", {"version": "2.0"})
body = ET.SubElement(root, "body")
head = ET.SubElement(root, "head")
title = ET.SubElement(head, "title")
title.text = "Exported from cry"
for feed in feeds:
ET.SubElement(
body,
"outline",
{"type": "rss", "text": feed.title, "xmlUrl": feed.meta.url},
)
ET.ElementTree(root).write(f)