Created
April 30, 2022 08:08
-
-
Save nikdoof/8bb9de7f91aad8dcca8fb69c1f70f6ac to your computer and use it in GitHub Desktop.
MiniFlux2OPML - a OPML exporter for Miniflux
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
Miniflux2OPML | |
A tool designed to extract a user's OPML file from a Miniflux installation, | |
with added support for outputting the OPML into JSON. | |
Copyright 2022 Andrew Williams | |
License: MIT | |
""" | |
import argparse | |
import json | |
import sys | |
import xml.etree.ElementTree as et | |
from collections import defaultdict | |
from urllib.parse import urljoin | |
import requests | |
__version__ = '1.0.0' | |
def download_opml(url, token): | |
# Use Miniflux's export API endpoint to grab the OPML | |
endpoint = urljoin(url, '/v1/export') | |
headers = {'X-Auth-Token': token} | |
req = requests.get(endpoint, headers=headers) | |
if req.ok: | |
return req.content.decode('utf-8') | |
def parse_opml(fobj): | |
xml_doc = et.fromstring(fobj) | |
return xml2dict(xml_doc) | |
def xml2dict(elem): | |
output = {elem.tag: {} if elem.attrib else None} | |
children = list(elem) | |
if children: | |
dd = defaultdict(list) | |
for dc in map(xml2dict, children): | |
for key, value in dc.items(): | |
dd[key].append(value) | |
output = {elem.tag: {key: value[0] if len(value) == 1 and key != | |
'outline' else value for key, value in dd.items()}} | |
if elem.text: | |
text = elem.text.strip() | |
if children or elem.attrib: | |
if text: | |
output[elem.tag]['#text'] = text | |
else: | |
output[elem.tag] = text | |
if elem.attrib: | |
for key, value in elem.attrib.items(): | |
output[elem.tag]['_' + key] = value | |
return output | |
def main(): | |
parser = argparse.ArgumentParser('miniflux2opml {0}'.format(__version__)) | |
parser.add_argument('--url', '-u', help='URL of the Miniflux instance', required=True) | |
parser.add_argument('--token', '-t', help='Your Miniflux API token', required=True) | |
parser.add_argument('--json', '-j', type=argparse.FileType('w'), help='Path to write the converted JSON OPML file') | |
parser.add_argument('--output', '-o', type=argparse.FileType('w'), help='Path to write the XML OPML file', default=sys.stdout) | |
args = parser.parse_args() | |
opml = download_opml(args.url, args.token) | |
if opml: | |
args.output.write(str(opml)) | |
if args.json: | |
doc = parse_opml(opml) | |
args.json.write(json.dumps(doc)) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment