From 492b51388530daf4e032885d33b6cadf8db3db91 Mon Sep 17 00:00:00 2001 From: Dominic DiTaranto Date: Fri, 17 Apr 2026 00:45:51 -0400 Subject: [PATCH] initial commit --- .gitignore | 3 + README.md | 48 ++++++++++++++++ config.py | 21 +++++++ generator.py | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 232 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 config.py create mode 100644 generator.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4882e64 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +feeds/ +mock/ +venv/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..53bfc9e --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +# RSS GENERATOR +This is an rss feed generator with a pseudo TUI interface. This was mainly created for people who are utilizing basic HTML to write a blog. + +While, of course, experienced developers take this simplistic route, a majority of people who are just writing their blogs manually are new to web development. This application is intended to provide the newbies a way to easily generate an RSS feed. Think about the people on neocities or in the tildeverse. + +Because this software is made for new web developer, I provide a very detailed explanation on how to "install" and "run" this "program" below. If you already know what to do, just clone the repo and run the code bruh. + +__Capabilities:__ +1. Generate an RSS feed +2. Add a post entry to an existing RSS feed +3. List all post entries in TUI +4. Edit a post entry +5. Delete a post entry +6. Only saves when you explicitly state, so bulk operation are possible. + + +# Dependencies +- python +- git + +__NOTE__ there are no third party packages used, so you do not need a virtual environment and you do not need to pip install anything! + + +# How To +1. Using the terminal, clone this repository into the base directory of your website. + +`git clone https://git.domdit.com/dominic/rss-generator` + +If you do not have git installed, you should install it on your system. If you cannot install it, you can copy the contents of `generator.py` and `config.py` into a new folder called `rss-generator` inside the base directory of your website. + +__NOTE__ If you are cloning this repo inside an already existing git repo, consider adding this repo as a submodule instead `git submodule add https://git.domdit.com/dominic/rss-generator rss-generator` + +2. Inside the `rss-generator` directory, there is a config file. You must fill out this config file. there are detailed instructions to follow along inside the config file. + +3. Once the config file is filled out and saved, you can now run `python3 generator.py` + +4. If this is the first time running it, it will generate a new rss feed for you and ask you to fill out information for your first (most recent) blog post + +5. You will then be redirected to the action menu, if you just want to save, you can type the number 5 and hit enter. + +6. You can also do other operations like see the list of all of your blog posts, edit a blog post rss entry, or delete a blog post rss entry + +7. changes do not take place until you explicity his save. so if you mess up you can always quit without saving and start over. + +8. Make sure your rss feed looks correct, and is where you want it. If you did not change XML_BASE_PATH, it will be in the base directory of your website + +9. Now that you have an rss feed, make sure you link to it somewhere on your website so people can find it! + diff --git a/config.py b/config.py new file mode 100644 index 0000000..f988e43 --- /dev/null +++ b/config.py @@ -0,0 +1,21 @@ +# ####YOU MUST FILL THESE OUT FOR THE GENERATOR TO WORK################### +# Title of your website, shows in people's RSS feed +TITLE = "国際面倒くさい" + +# The URL to your website "https://www.yourwebsite.com" +URL = "https://jumbo.subte.cc" + +# Description of your website +DESCRIPTION = "mumbling in japanese" + +# Please link back to me :) +GENERATOR = "https://www.domdit.com" + +# Language of your website +LANGUAGE = "en-us" + +# if you want your rss feed somewhere else, like a subdir, specify that here +# example: `feeds` would output your rss feed to www.yoursite.com/feeds/index.xml +# if you leave it None it will be www.yourside.com/index.xml (recommended) +XML_BASE_PATH = "feeds" +# ######################################################################## diff --git a/generator.py b/generator.py new file mode 100644 index 0000000..a7575b0 --- /dev/null +++ b/generator.py @@ -0,0 +1,160 @@ +import os +import sys +import subprocess +import platform +from datetime import datetime +from pathlib import Path +import xml.etree.ElementTree as ET + +from config import TITLE, URL, DESCRIPTION, GENERATOR, LANGUAGE, XML_BASE_PATH + + +class RSSGenerator: + ATOM_NAMESPACE = "HTTP://WWW.W3.ORG/2005/ATOM" + + def __init__(self): + self.now = datetime.now().strftime("%a, %d %b %Y %H:%M:%S %z") + + self.output_path = f"../{XML_BASE_PATH}/index.xml" if XML_BASE_PATH else "../index.xml" + + self.post_title = None + self.post_link = None + self.post_desc = None + self.post_date = self.now + + self.tree = None + self.root = None + self.channel = None + + self.items = [] + + def main(self): + self.clear() + if os.path.exists(self.output_path): + print('RSS feed exists, parsing...') + self.tree = ET.parse(self.output_path) + self.parse_existing_feed() + self.action_screen() + + else: + print('RSS feed does not exist, generating a new one...') + Path("/".join(self.output_path.split('/')[:-1])).mkdir(parents=True, exist_ok=True) + self.generate_new_feed() + self.request_new_post_details() + self.push_new_post() + self.tree = ET.ElementTree(self.root) + self.action_screen() + + def action_screen(self): + result = input("\nWhat would you like to do? \n[1] Add a new entry [2] List all posts [3] Delete an entry\n[4] Edit an entry [5] Save [6] Quit Without Saving\nEnter number: ") + self.clear() + if int(result) == 1: + self.request_new_post_details() + self.push_new_post() + self.action_screen() + + if int(result) == 2: + self.list_posts() + self.action_screen() + + elif int(result) == 3: + self.delete_post() + self.action_screen() + + elif int(result) == 4: + self.edit_post() + self.action_screen() + + elif int(result) == 5: + self.tree.write(self.output_path, encoding='utf-8', xml_declaration=True) + sys.exit(0) + + elif int(result) == 6: + sys.exit(0) + else: + print('Unknown Command!') + self.action_screen() + + def parse_existing_feed(self): + self.root = self.tree.getroot() + self.channel = self.root.find('channel') + + def generate_new_feed(self): + + self.root = ET.Element("rss", {"version": "2.0", "xmlns:atom": self.ATOM_NAMESPACE}) + + self.channel = ET.SubElement(self.root, "channel") + title = ET.SubElement(self.channel, "title") + title.text = TITLE + + link = ET.SubElement(self.channel, "{http://www.w3.org/2005/Atom}link") + link.set("rel", "self") + link.set("href", f"{URL}/{self.output_path}") + link.set("type", "application/atom+xml") + + desc = ET.SubElement(self.channel, "description") + desc.text = DESCRIPTION + + generator = ET.SubElement(self.channel, "generator") + generator.text = GENERATOR + + lang = ET.SubElement(self.channel, "language") + lang.text = LANGUAGE + + def request_new_post_details(self): + self.post_title = input("\nPost Title: ") + self.post_link = input("Post Link: ") + self.post_desc = input("Post Description: ") + + def push_new_post(self): + item = ET.SubElement(self.channel, 'item') + + title = ET.SubElement(item, 'title') + title.text = self.post_title + + link = ET.SubElement(item, 'link') + link.text = self.post_link + + description = ET.SubElement(item, 'description') + description.text = self.post_desc + + def list_posts(self): + print("\nHere is a list of all your posts:") + for idx, item in enumerate(self.channel.findall('item')): + title = item.find('title').text + + print(f"[{idx}] {title}") + + def delete_post(self): + self.list_posts() + + result = input("\nWhich post would you like to delete? Enter number: ") + + for idx, item in enumerate(self.channel.findall('item')): + if idx == int(result): + self.channel.remove(item) + + def edit_post(self): + self.list_posts() + + result = input("\nWhich post would you like to edit? Enter number: ") + + self.request_new_post_details() + + for idx, item in enumerate(self.channel.findall('item')): + if idx == int(result): + item.find('title').text = self.post_title + item.find('description').text = self.post_desc + item.find('link').text = self.post_link + + def clear(self): + system = platform.system().lower() + if system == 'windows': + subprocess.run('cls', shell=True) + else: + subprocess.run('clear', shell=True) + + +if __name__ == '__main__': + rss = RSSGenerator() + rss.main()