initial commit

This commit is contained in:
Dominic DiTaranto 2026-04-17 00:45:51 -04:00
commit 492b513885
4 changed files with 232 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
feeds/
mock/
venv/

48
README.md Normal file
View file

@ -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!

21
config.py Normal file
View file

@ -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"
# ########################################################################

160
generator.py Normal file
View file

@ -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()