#!/usr/bin/env python3 import argparse import flask import lxml.builder import lxml.etree import miniflux import pydantic import yaml class Config(pydantic.BaseModel): url: str api_key: str limit: int def make_entry(entry): e = lxml.builder.ElementMaker() return e.entry( e.title(entry["title"]), e.id("urn:hash::sha256:{}".format(entry["hash"])), e.link(href=entry["url"]), e.updated(entry["created_at"]), e.author(entry["author"]), e.content(entry["content"]), ) def make_atom(entries): feed = lxml.etree.Element("feed") updated = lxml.etree.SubElement(feed, "updated") updated.text = max(e["created_at"] for e in entries) for entry in entries: feed.append(make_entry(entry)) return feed def make_app(config): app = flask.Flask(__name__) client = miniflux.Client( config.url, api_key=config.api_key, ) @app.route("/starred") def view_starred(): entries = client.get_entries(starred=True, limit=config.limit) feed = make_atom(entries["entries"]) response = flask.make_response( lxml.etree.tostring(feed, pretty_print=True) ) response.headers.set("Content-Type", "application/atom+xml") return response return app def main(): parser = argparse.ArgumentParser() parser.add_argument("--config", default="config.yml") args = parser.parse_args() with open(args.config) as f: config = Config(**yaml.safe_load(f)) app = make_app(config) app.run(host="0.0.0.0") if __name__ == "__main__": main()