Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add RSS generator and feed #20

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
name: Build emails.json file from README
name: Build email JSON and RSS
on:
workflow_dispatch:
push:
branches: [ main ]
jobs:
update:
name: Update the emails.json file
name: Update the emails.json and emails.rss files
runs-on: ubuntu-latest
steps:
- name: checkout
Expand All @@ -21,6 +21,10 @@ jobs:
run: |
python convert_readme.py

- name: convert json to rss
run: |
python convert_json.py

- name: setup git config
run: |
git config user.name "Quincy Larson Emails Bot"
Expand Down
104 changes: 104 additions & 0 deletions convert_json.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#!/bin/python3

import json
import xml.etree.ElementTree as ET
from xml.dom import minidom

JSON_PATH = "emails.json"
RSS_PATH = "emails.rss"

RSS_CHANNEL_TITLE = "Quincy Larson's Links Worth Your Time"
RSS_CHANNEL_LINK = "https://github.com/freeCodeCamp/awesome-quincy-larson-emails"
RSS_CHANNEL_DESCRIPTION = "RSS feed generated from a historical archive of Quincy's weekly newsletter."


def rss_item(title: str | None = None,
description: str | None = None,
link: str | None = None,
pubDate: str | None = None) -> ET.Element:

item = ET.Element("item")

# RSS 2.0 items require description or title
# https://www.rssboard.org/rss-specification#hrelementsOfLtitemgt
if title is None and description is None:
title = "Untitled"

if title is not None:
item.append(ET.Element("title"))
item[-1].text = title

if description is not None:
item.append(ET.Element("description"))
item[-1].text = description

if link is not None:
item.append(ET.Element("link"))
item[-1].text = link

if pubDate is not None:
item.append(ET.Element("pubDate"))
item[-1].text = pubDate

return item


with open(JSON_PATH, 'rb') as emails_json_file:
json_data: dict = json.load(emails_json_file)


tree = ET.ElementTree(ET.Element("rss", {"version": "2.0"}))

root = tree.getroot()

root.append(ET.Element("channel"))
channel = root[0]

channel.extend([
ET.Element("title"),
ET.Element("link"),
ET.Element("description"),
])

channel[0].text = RSS_CHANNEL_TITLE
channel[1].text = RSS_CHANNEL_LINK
channel[2].text = RSS_CHANNEL_DESCRIPTION

for email in json_data["emails"]:

date = email.get("date")
bonus = email.get("bonus")
quote = email.get("quote")

if bonus is not None:
channel.append(
rss_item(title="Bonus", description=bonus, pubDate=date))

if quote is not None:
quote_author = email.get("quote_author")

if quote_author is not None:
quote += " - " + quote_author

channel.append(
rss_item(title="Quote", description=quote, pubDate=date))

json_links = email.get("links")

for json_link in json_links:

channel.append(rss_item(
description=json_link.get("description"),
link=json_link.get("link"),
pubDate=date,
))

rss = minidom.parseString(
ET.tostring(tree.getroot(), 'utf-8')) \
.toprettyxml(indent=" ")

with open(RSS_PATH, 'w') as emails_rss_file:
emails_rss_file.write(rss)

# verify RSS (XML) is parse-able
ET.ElementTree().parse(RSS_PATH)
Loading