#!/usr/bin/env -S uv run --script # /// script # dependencies = [ # "feedgen", # "feedparser", # "md2gemini", # ] # /// # 1. Take a markdown blog post as input, convert it to gemtext. # 2. Update gemlog index. # 3. Update the gemlog Atom feed. import sys from datetime import datetime from pathlib import Path from zoneinfo import ZoneInfo import feedparser from feedgen.feed import FeedGenerator from md2gemini import md2gemini # This is so that Python doesn't yell at me if I forget an argument. Not # likely to happen, but still. if len(sys.argv) != 3: print('Usage: blog2gemlog /path/to/blog/post.md "Blog Post Title"') exit(1) # Set the absolute path to the gemini content directory gemini_dir = Path.home().joinpath( "repos/tildegit.org/hyperreal/hyperreal.coffee/gemini" ) # Get the current date in YYYY-MM-DD format date_now = datetime.now().strftime("%Y-%m-%d") # Read blog post path from sys.argv[1] and ensure it is an absolute path blog_post_path = Path(sys.argv[1]) if not blog_post_path.is_absolute(): print("Supply absolute path to blog post.") exit(1) # Convert the markdown blog post to gemtext with open(blog_post_path, "r") as md_f: content = md2gemini(md_f.read(), frontmatter=True, links="paragraph", md_links=True) # Set the absolute path to the gemlog post gemlog_post_path = gemini_dir.joinpath(f"gemlog/{blog_post_path.stem}.gmi") # Write the gemtext content to the gemlog post path with open(gemlog_post_path, "w") as gmi_f: gmi_f.write(content) # Set the string for the END section of the gemlog post gemlog_end = f"\n\n## END\nLast updated: {date_now}\n\n=> ../gemlog Gemlog archive\n=> ../ hyperreal.coffee" # Append gemlog_end to the end of the gemlog post with open(gemlog_post_path, "a") as gmi_f: gmi_f.write(gemlog_end) # Read the gemlog post file lines into a list with open(gemlog_post_path, "r") as gmi_f: contents = gmi_f.readlines() # Get the gemlog post title from sys.argv[2] gemlog_post_title = str(sys.argv[2]) # Insert the gemlog post title as the level 1 heading on line 1 contents.insert(0, f"# {gemlog_post_title}\n\n") # Write the new contents as a string to the gemlog file with open(gemlog_post_path, "w") as gmi_f: contents = "".join(contents) gmi_f.write(contents) # Read the lines of the gemlog index into a list with open(gemini_dir.joinpath("gemlog/index.gmi"), "r") as index_f: contents = index_f.readlines() # Set the content of the gemlog index entry line gemlog_index_line = f"=> ./{gemlog_post_path.name} {date_now} {gemlog_post_title}\n" # Insert the new gemlog index line into the list on line 6 contents.insert(5, gemlog_index_line) # Write the new contents as a string to the gemlog index file with open(gemini_dir.joinpath("gemlog/index.gmi"), "w") as index_f: contents = "".join(contents) index_f.write(contents) # Get a timezone-aware datetime object from a timestamp of the present moment aware_ts = datetime.fromtimestamp( datetime.timestamp(datetime.now()), tz=ZoneInfo("America/Chicago") ) # Format the timezone-aware datetime object for the element of the # Atom feed updated_ts = aware_ts.strftime("%Y-%m-%dT%H:%M:%S%z") # Instantiate a FeedParserDict object d = feedparser.parse(gemini_dir.joinpath("gemlog/atom.xml")) # Update the element's value to the current timestamp d["updated"] = updated_ts # Define a dictionary for the new Atom feed entry new_entry_dict = { "id": f"gemini://hyperreal.coffee/gemlog/{gemlog_post_path.name}", "title": gemlog_post_title, "updated": updated_ts, "links": [ { "href": f"gemini://hyperreal.coffee/gemlog/{gemlog_post_path.name}", "rel": "alternate", "type": "text/gemini", } ], } # Insert the new Atom feed entry into the FeedParserDict d["entries"].insert(0, new_entry_dict) # Instantiate a FeedGenerator object and set the methods for the feed fg = FeedGenerator() fg.id(d["feed"]["id"]) fg.title(d["feed"]["title"]) fg.updated(d["feed"]["updated"]) fg.link(d["feed"]["links"]) # Reverse the order of d["entries"] so that they are written to the file in # the correct order d["entries"].reverse() # For each entry, add a new entry to the FeedGenerator object for entry in d["entries"]: fe = fg.add_entry() fe.id(entry["id"]) fe.title(entry["title"]) fe.updated(entry["updated"]) fe.link(entry["links"]) # Finally, render the FeedGenerator object as an Atom feed and write it to # the atom.xml file fg.atom_file(gemini_dir.joinpath("gemlog/atom.xml"), pretty=True) # vim: ai et ft=python sts=4 sw=4 ts=4