fic-archive/new.py

950 lines
72 KiB
Python

import datetime,os
from importlib import import_module
from bs4 import BeautifulSoup
def classgen(string):
return string.replace(" ","").replace("#","").replace("-","").replace("ç","c").replace("","").replace("é","e").replace("(","").replace(")","").replace(":","").lower()
def stringno(theno):
if theno < 10:
return "00" + str(theno)
elif theno < 100:
return "0" + str(theno)
else:
return str(theno)
ficcount = 999
ficlist = []
while ficcount > 0:
ficcount -= 1
ficcountstring = stringno(ficcount)
if os.path.exists("files/originalsmeta/" + ficcountstring + ".py"):
ficfile = "files.originalsmeta." + ficcountstring
fileread = import_module(ficfile)
try:
if fileread.revealdate <= datetime.datetime.now():
goahead = True
else:
goahead = False
except:
goahead = True
if goahead == True:
ficdict = {}
ficdict["id"] = ficcount
if fileread.showtitle:
ficdict["title"] = fileread.title
if fileread.language == "fr":
ficdict["french"] = "original"
else:
ficdict["french"] = False
sumwords = 0
for instalment in fileread.datewords:
sumwords = sumwords + instalment["words"]
ficdict["totalwords"] = sumwords
ficdict["startdate"] = fileread.datewords[0]["date"]
ficdict["latestdate"] = fileread.datewords[-1]["date"]
try:
ficdict["approxdate"] = fileread.approxdate
except:
pass
if len(fileread.datewords) > 1:
ficdict["chaptered"] = True
else:
ficdict["chaptered"] = False
try:
ficdict["completion"] = fileread.status
except:
ficdict["completion"] = "complete"
ficdict["fandoms"] = []
for fandom in fileread.fandom:
if fandom == "FF15":
ficdict["fandoms"].append("Final Fantasy XV")
elif fandom == "FF16":
ficdict["fandoms"].append("Final Fantasy XVI")
elif fandom == "FF4":
ficdict["fandoms"].append("Final Fantasy IV")
elif fandom == "FF6":
ficdict["fandoms"].append("Final Fantasy VI")
elif fandom == "FF7":
ficdict["fandoms"].append("Final Fantasy VII")
elif fandom == "FF8":
ficdict["fandoms"].append("Final Fantasy VIII")
elif fandom == "FF9":
ficdict["fandoms"].append("Final Fantasy IX")
elif fandom == "FFX":
ficdict["fandoms"].append("Final Fantasy X")
elif fandom == "LOTR":
ficdict["fandoms"].append("Lord Of The Rings")
else:
ficdict["fandoms"].append(fandom)
ficlist.append(ficdict)
ficdict["charmain"] = []
try:
for character in fileread.charpov:
ficdict["charmain"].append(character)
except:
pass
try:
for character in fileread.charmain:
ficdict["charmain"].append(character)
except:
pass
ficdict["charsec"] = []
try:
for character in fileread.charsecondary:
ficdict["charsec"].append(character)
except:
pass
try:
ficdict["ships"] = []
for ship in fileread.ship:
if ship != None:
ficdict["ships"].append(ship.replace("/"," × "))
except:
pass
if fileread.genre[0] == "slash" or fileread.genre[0] == "bl" or fileread.genre[0] == "yaoi":
ficdict["type"] = "BL"
elif fileread.genre[0] == "femslash" or fileread.genre[0] == "gl" or fileread.genre[0] == "yuri":
ficdict["type"] = "GL"
elif fileread.genre[0] == "het":
ficdict["type"] = "hetero"
else:
ficdict["type"] = "gen"
try:
if len(fileread.genre) > 1 and fileread.genre[1] != "slash":
ficdict["genre"] = fileread.genre[1]
else:
if fileread.time == "pre-canon" or fileread.time == "mid-canon" or fileread.time == "post-canon" or fileread.time == "AU":
ficdict["genre"] = fileread.time
except:
pass
try:
ficdict["summary"] = fileread.summary
except:
pass
try:
if fileread.eventname == "bethefirst":
ficdict["event"] = "Be The First"
elif fileread.eventname == "challengeonthebigbridge":
ficdict["event"] = "Challenge On The Big Bridge"
elif fileread.eventname == "fffc":
ficdict["event"] = "Froday Flash Fiction Challenge"
elif fileread.eventname == "intoabar":
ficdict["event"] = "Into A Bar"
elif fileread.eventname == "candyheartsex":
ficdict["event"] = "Candy Hearts Exchange"
elif fileread.eventname == "chocolateboxcomm":
ficdict["event"] = "Chocolate Box"
elif fileread.eventname == "multifandomdrabble":
ficdict["event"] = "Multifandom Drabble"
elif fileread.eventname == "press-start-comm":
ficdict["event"] = "Press Start"
elif fileread.eventname == "raremaleslashex":
ficdict["event"] = "Rare Male Slash Exchange"
elif fileread.eventname == "seasonsofdrabbles":
ficdict["event"] = "Seasons Of Drabbles"
elif fileread.eventname == "yuletide":
ficdict["event"] = "Yuletide"
elif fileread.eventname == "ffprompts":
ficdict["event"] = "Final Fantasy Prompts"
elif fileread.eventname == "no-true-pair":
ficdict["event"] = "No True Pair"
elif fileread.eventname == "threesentenceficathon":
ficdict["event"] = "Three-Sentence Ficathon"
elif fileread.eventname == "100words":
ficdict["event"] = "100 Words"
elif fileread.eventname == "drabble-zone":
ficdict["event"] = "The Weekly Drabble Zone"
else:
ficdict["event"] = fileread.eventname
ficdict["eventtype"] = fileread.event
except:
pass
try:
ficdict["prompt"] = fileread.prompt
except:
ficdict["prompt"] = False
if fileread.locked:
ficdict["locked"] = True
else:
ficdict["locked"] = False
if fileread.epub:
ficdict["epub"] = True
else:
ficdict["epub"] = False
if fileread.pdf:
ficdict["pdf"] = True
else:
ficdict["pdf"] = False
try:
if int((str(fileread.warnstring))[1]) == 3:
ficdict["sex"] = "lemon"
elif int((str(fileread.warnstring))[1]) == 2:
ficdict["sex"] = "lime"
elif int((str(fileread.warnstring))[1]) == 1:
ficdict["sex"] = "ref"
elif int((str(fileread.warnstring))[1]) == 0:
ficdict["sex"] = None
if int((str(fileread.warnstring))[2]) == 2:
ficdict["death"] = "death"
elif int((str(fileread.warnstring))[2]) == 1:
ficdict["death"] = "ref"
elif int((str(fileread.warnstring))[2]) == 0:
ficdict["death"] = None
if int((str(fileread.warnstring))[3]) == 2:
ficdict["mh"] = "mh"
elif int((str(fileread.warnstring))[3]) == 1:
ficdict["mh"] = "ref"
elif int((str(fileread.warnstring))[3]) == 0:
ficdict["mh"] = None
if int((str(fileread.warnstring))[4]) == 2:
ficdict["bigotry"] = "bigotry"
elif int((str(fileread.warnstring))[4]) == 1:
ficdict["bigotry"] = "ref"
elif int((str(fileread.warnstring))[4]) == 0:
ficdict["bigotry"] = None
if int((str(fileread.warnstring))[5]) == 2:
ficdict["vomiting"] = "vomiting"
elif int((str(fileread.warnstring))[5]) == 1:
ficdict["vomiting"] = "ref"
elif int((str(fileread.warnstring))[5]) == 0:
ficdict["vomiting"] = None
if int((str(fileread.warnstring))[6]) == 2:
ficdict["consent"] = "consent"
elif int((str(fileread.warnstring))[6]) == 1:
ficdict["consent"] = "ref"
elif int((str(fileread.warnstring))[6]) == 0:
ficdict["consent"] = None
if int((str(fileread.warnstring))[7]) == 2:
ficdict["underage"] = "underage"
elif int((str(fileread.warnstring))[7]) == 1:
ficdict["underage"] = "ref"
elif int((str(fileread.warnstring))[7]) == 0:
ficdict["underage"] = None
if int((str(fileread.warnstring))[8]) == 2:
ficdict["incest"] = "incest"
elif int((str(fileread.warnstring))[8]) == 1:
ficdict["incest"] = "ref"
elif int((str(fileread.warnstring))[8]) == 0:
ficdict["incest"] = None
if int((str(fileread.warnstring))[9]) == 2:
ficdict["amp"] = "amp"
elif int((str(fileread.warnstring))[9]) == 1:
ficdict["amp"] = "ref"
elif int((str(fileread.warnstring))[9]) == 0:
ficdict["amp"] = None
except:
ficdict["sex"] = None
ficdict["death"] = None
ficdict["mh"] = None
ficdict["bigotry"] = None
ficdict["vomiting"] = None
ficdict["consent"] = None
ficdict["underage"] = None
ficdict["incest"] = None
ficdict["amp"] = None
try:
transid = stringno(fileread.translation)
if os.path.exists("files/translationsmeta/" + transid + ".py"):
transfile = "files.translationsmeta." + transid
transread = import_module(transfile)
ficdict["transid"] = int(transid)
if transread.showtitle:
ficdict["transtitle"] = transread.title
if transread.language == "fr":
ficdict["french"] = "translation"
transwords = 0
for instalment in transread.datewords:
transwords = transwords + instalment["words"]
ficdict["transwords"] = transwords
ficdict["transstartdate"] = transread.datewords[0]["date"]
ficdict["translatestdate"] = transread.datewords[-1]["date"]
ficdict["transsummary"] = transread.summary
except:
pass
try:
if len(fileread.comments) > 0:
ficdict["comments"] = fileread.comments
else:
ficdict["comments"] = False
except:
ficdict["comments"] = False
try:
ficdict["cssoverride"] = fileread.cssoverride
except:
pass
ficlist = sorted(ficlist,key=lambda d: d["latestdate"],reverse=True)
fandoms = []
challenges = []
exchanges = []
promptmemes = []
years = []
for fic in ficlist:
for fandom in fic["fandoms"]:
fandoms.append(fandom)
years.append(int(datetime.datetime.strftime(fic["latestdate"],"%Y")))
try:
if fic["eventtype"] == "challenge":
challenges.append(fic["event"])
elif fic["eventtype"] == "exchange" or fic["eventtype"] == "ao3exchange":
exchanges.append(fic["event"])
elif fic["eventtype"] == "prompt":
promptmemes.append(fic["event"])
except:
pass
fandoms = sorted(list(dict.fromkeys(fandoms)),key=str.casefold)
challenges = sorted(list(dict.fromkeys(challenges)),key=str.casefold)
exchanges = sorted(list(dict.fromkeys(exchanges)),key=str.casefold)
promptmemes = sorted(list(dict.fromkeys(promptmemes)),key=str.casefold)
years = sorted(list(dict.fromkeys(years)),reverse=True)
if not os.path.isdir("build/masterlist"):
os.mkdir("build/masterlist")
output = open("build/masterlist/index.html", "w")
output.write("<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>praze • Fanfiction</title>\n <meta property=\"og:title\" content=\"praze • Fanfiction\">\n <meta property=\"og:type\" content=\"website\">\n <meta property=\"og:image\" content=\"https://tre.praze.net/ab.png\">\n <meta property=\"og:url\" content=\"https://tre.praze.net/fic/masterlist\">\n <meta name=\"description\" property=\"og:description\" content=\"Fanfiction on tre.praze.net\">\n <meta property=\"og:locale\" content=\"en_GB\">\n <meta property=\"og:site_name\" content=\"tre.praze.net\">\n <meta name=\"fediverse:creator\" content=\"@tre@praze.net\">\n <link rel=\"webmention\" href=\"https://webmention.io/tre.praze.net/webmention\">\n <link rel=\"stylesheet\" href=\"/new.css\">\n <link rel=\"stylesheet\" href=\"/fic/fic.css\">\n <link rel=\"me\" href=\"https://kes.praze.net/@tre\">\n <link rel=\"alternate\" type=\"application/rss+xml\" title=\"tre.praze.net\" href=\"/feed.xml\">\n <meta name=\"theme-color\" content=\"#f2f2f2\" />\n <style>\n div.fic {\n margin: 20px auto;\n }\n main input:checked + label {\n text-decoration: underline;\n }\n form:has([value=\"french\"]:checked) ~ div.fic:not(.lang-french),")
for fandom in fandoms:
if fandom != "OW":
output.write("\n form:has([value=\"" + classgen(fandom) + "\"]:checked) ~ div.fic:not(.fandom-" + classgen(fandom) + "),")
for challenge in challenges:
output.write("\n form:has([value=\"" + classgen(challenge) + "\"]:checked) ~ div.fic:not(.event-" + classgen(challenge) + "),")
for exchange in exchanges:
output.write("\n form:has([value=\"" + classgen(exchange) + "\"]:checked) ~ div.fic:not(.event-" + classgen(exchange) + "),")
for promptmeme in promptmemes:
output.write("\n form:has([value=\"" + classgen(promptmeme) + "\"]:checked) ~ div.fic:not(.event-" + classgen(promptmeme) + "),")
for year in years:
output.write("\n form:has([value=\"" + str(year) + "\"]:checked) ~ div.fic:not(.date-" + str(year) + "),")
output.write("\n form:has([value=\"unprompted\"]:checked) ~ div.fic:not(.unprompted),\n form:has([value=\"crossover\"]:checked) ~ div.fic:not(.fandom-crossover),\n form:has([value=\"ow\"]:checked) ~ div.fic:not(.fandom-ow),\n form:has([value=\"nolemons\"]:checked) ~ div.fic:has(span.lemon),\n form:has([value=\"nolimes\"]:checked) ~ div.fic:has(span.lime),\n form:has([value=\"lemonlime\"]:checked) ~ div.fic:not(:has(span.lime:not(.reference))),\n form:has([value=\"drabble\"]:checked) ~ div.fic:not(.format-drabble),\n form:has([value=\"drabblefam\"]:checked) ~ div.fic:not(.format-drabblefam),\n form:has([value=\"three\"]:checked) ~ div.fic:not(.format-three),\n form:has([value=\"oneshot\"]:checked) ~ div.fic:not(.format-oneshot),\n form:has([value=\"chaptered\"]:checked) ~ div.fic:not(.format-chaptered),\n form:has([value=\"unusual\"]:checked) ~ div.fic:not(.format-unusual),\n form:has([value=\"unpassword\"]:checked) ~ div.fic.locked,\n form:has([value=\"gen\"]:checked) ~ div.fic:not(:has(span.ship.gen)),\n form:has([value=\"bl\"]:checked) ~ div.fic:not(:has(span.ship.bl)),\n form:has([value=\"gl\"]:checked) ~ div.fic:not(:has(span.ship.gl)),\n form:has([value=\"hetero\"]:checked) ~ div.fic:not(:has(span.ship.hetero)) {\n display: none;\n }\n span.minor {\n font-size: 0em;\n }\n span.minor:before {\n content: \"\";\n font-size: 1rem;\n }\n span.minor:hover {\n font-size: 0.7rem;\n }\n span.minor:hover:before {\n content: \"\";\n }\n </style>\n </head>\n <body>\n <nav>\n <input type=\"checkbox\" id=\"toggle\" name=\"toggle\">\n <label class=\"toggle-btn\" for=\"toggle\">Menu</label>\n <ul>\n <li>Fundamentals\n <ul>\n <li><a href=\"/\">Home</a></li>\n <li><a href=\"/about\">About + listings</a></li>\n <li><a href=\"/follow\">Follow</a></li>\n <li><a href=\"/feed.xml\">Changelog</a> <a href=\"/feed.xml\"><span class=\"rss\"></span></a></li>\n <li><a href=\"/sitemap.xml\">Sitemap</a></li>\n <li><a href=\"/siteroll\">Siteroll</a></li>\n </ul>\n </li>\n <li>Projects\n <ul>\n <li>Fanfiction <a href=\"/fic/feed.xml\"><span class=\"rss\"></span></a></li>\n <li><a href=\"/music\">Music</a></li>\n <li><a href=\"/notes\">Journal</a></li>\n <li><a href=\"/trackers\">Trackers</a></li>\n <li><a href=\"https://git.praze.net/tre\" target=\"_blank\">Code</a> <a href=\"https://git.praze.net/tre.rss\"><span class=\"rss\"></span></a></li>\n <li><a href=\"https://img.praze.net\" target=\"_blank\">Photos</a> <a href=\"https://img.praze.net/feed.php\"><span class=\"rss\"></span></a></li>\n </ul>\n </li>\n <li>Fan content\n <ul>\n <li><a href=\"/ffx\">FFX</a></li>\n <li><a href=\"/xvi\">FF16</a></li>\n <li><a href=\"https://morgan.praze.net\" target=\"_blank\">Dermot Morgan</a> <a href=\"https://morgan.praze.net/feed.xml\"><span class=\"rss\"></span></a></li>\n </ul>\n </li>\n <li>Misc.\n <ul>\n <li><a href=\"https://tcg.praze.net\" target=\"_blank\">TCG</a></li>\n <li><a href=\"https://links.praze.net\" target=\"_blank\">Bookmarks</a> <a href=\"https://links.praze.net/feed/rss\"><span class=\"rss\"></span></a></li>\n <li><a href=\"https://kes.praze.net/@tre\" target=\"_blank\">Fediverse</a> <a href=\"https://kes.praze.net/@tre/feed.rss\"><span class=\"rss\"></span></a></li>\n </ul>\n </li>\n </ul>\n </nav>\n <div>\n <main>\n <section>\n <h1>Masterlist</h1>\n <p>Here’s a filterable list of all my fanfiction. Click on the ID number for a fic to read it, leave a comment, or download as a PDF or EPUB. Some fics will have slight inaccuracies in metadata for the time being, browse at your own risk!</p>\n <form>\n <label for=\"fandoms\"><b>Fandom:</b></label>\n <select name=\"fandoms\" id=\"fandoms\">\n <option value=\"allfandoms\" selected>All</option>")
for fandom in fandoms:
if fandom != "OW":
output.write("\n <option value=\"" + classgen(fandom) + "\">" + fandom + "</option>")
output.write("\n <option value=\"crossover\">Crossovers</option>\n <option value=\"ow\">Original</option>\n </select>\n </form>\n <form>\n <label for=\"events\"><b>Written for event:</b></label>\n <select name=\"events\" id=\"events\">\n <option value=\"allevents\" selected>Any</option>\n <option value=\"unprompted\">None</option>\n <optgroup label=\"Challenges\">")
for challenge in challenges:
output.write("\n <option value=\"" + classgen(challenge) + "\">" + challenge + "</option>")
output.write("\n </optgroup>\n <optgroup label=\"Exchanges\">")
for exchange in exchanges:
output.write("\n <option value=\"" + classgen(exchange) + "\">" + exchange + "</option>")
output.write("\n </optgroup>\n <optgroup label=\"Prompt memes\">")
for promptmeme in promptmemes:
output.write("\n <option value=\"" + classgen(promptmeme) + "\">" + promptmeme + "</option>")
output.write("\n </optgroup>\n </select>\n </form>\n <form>\n <label for=\"years\"><b>Posted/last updated:</b></label>\n <select name=\"years\" id=\"years\">\n <option value=\"allyears\" selected>Any year</option>")
for year in years:
output.write("\n <option value=\"" + str(year) + "\">" + str(year) + "</option>")
output.write("\n </select>\n </form>\n <form>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"alllangs\" value=\"alllangs\" checked>\n <label for=\"alllangs\"><b>All languages</b></label>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"french\" value=\"french\">\n <label for=\"french\">Disponibles en fran&ccedil;ais</label>\n </form>\n <form>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"allratings\" value=\"allratings\" checked>\n <label for=\"allratings\"><b>All ratings</b></label>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"nolemons\" value=\"nolemons\">\n <label for=\"nolemons\">Hide sexually explicit fics</label>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"nolimes\" value=\"nolimes\">\n <label for=\"nolimes\">Hide fics with any sexual content</label>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"lemonlime\" value=\"lemonlime\">\n <label for=\"lemonlime\">Show only fics with sexual content</label>\n </form>\n <form>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"allcategories\" value=\"allcategories\" checked>\n <label for=\"allcategories\"><b>All categories</b></label>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"gen\" value=\"gen\">\n <label for=\"gen\">Gen</label>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"bl\" value=\"bl\">\n <label for=\"bl\"><span class=\"bl\">BL</span></label>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"gl\" value=\"gl\">\n <label for=\"gl\"><span class=\"gl\">GL</span></label>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"hetero\" value=\"hetero\">\n <label for=\"hetero\"><span class=\"hetero\">Hetero</span></label>\n </form>\n <form>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"allformats\" value=\"allformats\" checked>\n <label for=\"allformats\"><b>All formats</b></label>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"drabble\" value=\"drabble\">\n <label for=\"drabble\">Drabbles (100 words)</label>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"three\" value=\"three\">\n <label for=\"three\">Three sentence-ish</label>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"drabblefam\" value=\"drabblefam\">\n <label for=\"drabblefam\">Drabble family</label>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"oneshot\" value=\"oneshot\">\n <label for=\"oneshot\">Oneshots</label>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"chaptered\" value=\"chaptered\">\n <label for=\"chaptered\">Chaptered fics</label>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"unusual\" value=\"unusual\">\n <label for=\"unusual\">Unusual formats</label>\n </form>\n <form>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"password\" value=\"password\">\n <label for=\"password\"><b>Include password-protected</b></label>\n <input name=\"filter\" class=\"input\" type=\"radio\" id=\"unpassword\" value=\"unpassword\" checked>\n <label for=\"unpassword\">Exclude password-protected</label>\n </form>\n <details>\n <summary>Key to symbols</summary>\n <ul>\n <li><span class=\"warning lemon lime\">🍋</span>&nbsp;&ndash; explicit sexual content</li>\n <li><span class=\"warning lime\">🍋</span>&nbsp;&ndash; non-explicit sexual content</li>\n <li><span class=\"warning\">💀</span>&nbsp;&ndash; death</li>\n <li><span class=\"warning\">😢</span>&nbsp;&ndash; mental health themes (may include self-injury, suicidal ideation, suicide attempts)</li>\n <li><span class=\"warning\">🚫</span>&nbsp;&ndash; in-universe bigotry</li>\n <li><span class=\"warning\">🤢</span>&nbsp;&ndash; vomiting</li>\n <li><span class=\"warning\">⛔</span>&nbsp;&ndash; consent issues</li>\n <li><span class=\"warning\">👶</span>&nbsp;&ndash; underage sexual activity according to modern UK law</li>\n <li><span class=\"warning\">🦎</span>&nbsp;&ndash; incest</li>\n <li><span class=\"warning\">🦶</span>&nbsp;&ndash; amputation</li>\n </ul>\n <p>When a warning is shown in greyscale, this means there are references to the relevant theme but no on-screen portrayal.</p>\n </details>")
for fic in ficlist:
output.write("\n<div class=\"fic lang-english")
if fic["french"]:
output.write(" lang-french")
for fandom in fic["fandoms"]:
output.write(" fandom-" + classgen(fandom))
if len(fic["fandoms"]) > 1:
output.write(" fandom-crossover")
three = False
if fic["pdf"] == False:
output.write(" format-unusual") # ok for now …
elif fic["chaptered"]:
output.write(" format-chaptered")
else:
try:
if fic["event"] == "Three-Sentence Ficathon":
output.write(" format-three")
three = True
except:
pass
if three == False:
if fic["totalwords"] == 100:
output.write(" format-drabble")
elif fic["totalwords"] % 100 == 0:
output.write(" format-drabblefam")
else:
output.write(" format-oneshot")
try:
output.write(" event-" + classgen(fic["event"]))
except:
output.write(" unprompted")
output.write(" date-" + (datetime.datetime.strftime(fic["latestdate"],"%Y")))
if fic["locked"]:
output.write(" locked")
output.write("\">\n<h2>n° <a href=\"/fic/" + stringno(fic["id"]) + "\">" + stringno(fic["id"]) + "</a>")
try:
output.write("/<a href=\"/fic/" + stringno(fic["transid"]) + "\">" + stringno(fic["transid"]) + "</a>")
except:
pass
titles = 0
try:
if fic["title"]:
titles += 1
except:
pass
try:
if fic["transtitle"]:
titles += 1
except:
pass
if titles > 0:
output.write(": ")
try:
output.write(fic["title"])
except:
pass
if titles > 1:
output.write("/")
try:
output.write(fic["transtitle"])
except:
pass
if fic["locked"]:
output.write(" 🔒")
output.write("</h2>\n<ul>\n<li>")
try:
if fic["transid"]:
if fic["french"] == "original":
output.write("French: ")
elif fic["french"] == "translation":
output.write("English: ")
except:
pass
thewords = fic["totalwords"]
output.write(str(f"{thewords:,}" + " words, "))
try:
output.write(fic["approxdate"])
except:
output.write("<code>" + datetime.datetime.strftime(fic["startdate"],"%Y-%m-%d") + "</code>")
if fic["completion"] == "incomplete":
output.write("–present")
elif fic["latestdate"] != fic["startdate"]:
output.write("–<code>" + datetime.datetime.strftime(fic["latestdate"],"%Y-%m-%d") + "</code>")
if fic["completion"] == "abandoned":
output.write(" (abandoned)")
output.write("</li>")
try:
if fic["transid"]:
output.write("\n<li>")
if fic["french"] == "original":
output.write("English: ")
elif fic["french"] == "translation":
output.write("French: ")
output.write(str(fic["transwords"]) + " words, <code>" + datetime.datetime.strftime(fic["transstartdate"],"%Y-%m-%d") + "</code>")
if fic["translatestdate"] != fic["transstartdate"]:
output.write("–<code>" + datetime.datetime.strftime(fic["translatestdate"],"%Y-%m-%d") + "</code>")
output.write("</li>")
except:
pass
output.write("\n<li><b>" + "</b>, <b>".join(fic["fandoms"]) + "</b>")
if len(fic["charmain"]) > 0:
output.write(", " + ", ".join(fic["charmain"]))
if len(fic["charsec"]) > 0:
output.write(", <span class=\"minor\">" + ", ".join(fic["charsec"]) + "</span>")
output.write("</li>\n<li><span class=\"ship " + fic["type"].lower() + "\"")
if fic["type"] != "gen":
try:
output.write(" title=\"" + ", ".join(fic["ships"]) + "\"")
except:
pass
output.write(">" + fic["type"] + "</span>")
try:
output.write(", " + fic["genre"])
except:
pass
if fic["sex"] == "lemon":
output.write(" <span class=\"warning lemon lime\" title=\"explicit sexual content\">🍋</span>")
elif fic["sex"] == "lime":
output.write(" <span class=\"warning lime\" title=\"non-explicit sexual content\">🍋</span>")
elif fic["sex"] == "ref":
output.write(" <span class=\"warning lime reference\" title=\"references to sex\">🍋</span>")
if fic["death"] == "death":
output.write(" <span class=\"warning\" title=\"character death\">💀</span>")
elif fic["death"] == "ref":
output.write(" <span class=\"warning reference\" title=\"references to death\">💀</span>")
if fic["mh"] == "mh":
output.write(" <span class=\"warning\" title=\"mental health themes\">😢</span>")
elif fic["mh"] == "ref":
output.write(" <span class=\"warning reference\" title=\"references to mental health\">😢</span>")
if fic["bigotry"] == "bigotry":
output.write(" <span class=\"warning\" title=\"in-universe bigotry\">🚫</span>")
elif fic["bigotry"] == "ref":
output.write(" <span class=\"warning reference\" title=\"references to bigotry\">🚫</span>")
if fic["vomiting"] == "vomiting":
output.write(" <span class=\"warning\" title=\"vomiting\">🤢</span>")
elif fic["vomiting"] == "ref":
output.write(" <span class=\"warning reference\" title=\"references to vomiting\">🤢</span>")
if fic["consent"] == "consent":
output.write(" <span class=\"warning\" title=\"consent issues\">⛔</span>")
elif fic["consent"] == "ref":
output.write(" <span class=\"warning reference\" title=\"references to consent issues\">⛔</span>")
if fic["underage"] == "underage":
output.write(" <span class=\"warning\" title=\"underage sexual activity\">👶</span>")
elif fic["underage"] == "ref":
output.write(" <span class=\"warning reference\" title=\"references to underage sexual activity\">👶</span>")
if fic["incest"] == "incest":
output.write(" <span class=\"warning\" title=\"incest\">🦶</span>")
elif fic["incest"] == "ref":
output.write(" <span class=\"warning reference\" title=\"references to incest\">🦎</span>")
if fic["amp"] == "amp":
output.write(" <span class=\"warning\" title=\"amputation\">🦶</span>")
elif fic["amp"] == "ref":
output.write(" <span class=\"warning reference\" title=\"references to amputation\">🦎</span>")
output.write("</li>")
try:
output.write("\n<li>Written for <b>" + fic["event"] + "</b>.")
if fic["prompt"]:
output.write(" Prompt: <i>" + fic["prompt"] + "</i>.")
output.write("</li>")
except:
pass
output.write("\n</ul>")
thesummary = ""
try:
thesummary += fic["summary"]
except:
pass
try:
thesummary += " " + fic["transsummary"]
except:
pass
if len(thesummary) > 0:
output.write("\n<blockquote>\n<p>" + thesummary + "</p>\n</blockquote>")
output.write("\n</div>")
output.write("\n <p>If no fics are showing here, try removing some of the filters.</p>\n </section>\n </main>\n <footer>\n <ul>\n <li><a href=\"/fic\">back to fic pages</a></li>\n </ul>\n </footer>\n </div>\n <a href=\"/\"><img src=\"/a.png\" style=\"position:fixed;bottom:2px;right:2px;\" title=\"home\"></a></body>\n</html>")
for fic in ficlist:
if not os.path.isdir("build/" + stringno(fic["id"])):
os.mkdir("build/" + stringno(fic["id"]))
ficpage = open("build/" + stringno(fic["id"]) + "/index.html", "w")
ficpage.write("<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>praze • Fanfiction</title>\n <meta property=\"og:title\" content=\"praze • Fanfiction\">\n <meta property=\"og:type\" content=\"website\">\n <meta property=\"og:image\" content=\"https://tre.praze.net/ab.png\">\n <meta property=\"og:url\" content=\"https://tre.praze.net/fic/" + stringno(fic["id"]) + "\">\n <meta name=\"description\" property=\"og:description\" content=\"Fanfiction on tre.praze.net\">\n <meta property=\"og:locale\" content=\"en_GB\">\n <meta property=\"og:site_name\" content=\"tre.praze.net\">\n <meta name=\"fediverse:creator\" content=\"@tre@praze.net\">\n <link rel=\"webmention\" href=\"https://webmention.io/tre.praze.net/webmention\">\n <link rel=\"stylesheet\" href=\"/new.css\">\n <link rel=\"stylesheet\" href=\"/fic/fic.css\">\n")
try:
for override in fic["cssoverride"]:
ficpage.write(" <link rel=\"stylesheet\" href=\"" + override + "\">\n")
except:
ficpage.write(" <link rel=\"stylesheet\" href=\"/fic/tufte-embed.css\">\n")
ficpage.write(" <link rel=\"me\" href=\"https://kes.praze.net/@tre\">\n <link rel=\"alternate\" type=\"application/rss+xml\" title=\"tre.praze.net\" href=\"/feed.xml\">\n <meta name=\"theme-color\" content=\"#f2f2f2\" />\n <style>\n span.minor {\n font-size: 0.7rem;\n }\n </style>\n </head>\n <body>\n <nav>\n <input type=\"checkbox\" id=\"toggle\" name=\"toggle\">\n <label class=\"toggle-btn\" for=\"toggle\">Menu</label>\n <ul>\n <li>Fundamentals\n <ul>\n <li><a href=\"/\">Home</a></li>\n <li><a href=\"/about\">About + listings</a></li>\n <li><a href=\"/follow\">Follow</a></li>\n <li><a href=\"/feed.xml\">Changelog</a> <a href=\"/feed.xml\"><span class=\"rss\"></span></a></li>\n <li><a href=\"/sitemap.xml\">Sitemap</a></li>\n <li><a href=\"/siteroll\">Siteroll</a></li>\n </ul>\n </li>\n <li>Projects\n <ul>\n <li>Fanfiction <a href=\"/fic/feed.xml\"><span class=\"rss\"></span></a></li>\n <li><a href=\"/music\">Music</a></li>\n <li><a href=\"/notes\">Journal</a></li>\n <li><a href=\"/trackers\">Trackers</a></li>\n <li><a href=\"https://git.praze.net/tre\" target=\"_blank\">Code</a> <a href=\"https://git.praze.net/tre.rss\"><span class=\"rss\"></span></a></li>\n <li><a href=\"https://img.praze.net\" target=\"_blank\">Photos</a> <a href=\"https://img.praze.net/feed.php\"><span class=\"rss\"></span></a></li>\n </ul>\n </li>\n <li>Fan content\n <ul>\n <li><a href=\"/ffx\">FFX</a></li>\n <li><a href=\"/xvi\">FF16</a></li>\n <li><a href=\"https://morgan.praze.net\" target=\"_blank\">Dermot Morgan</a> <a href=\"https://morgan.praze.net/feed.xml\"><span class=\"rss\"></span></a></li>\n </ul>\n </li>\n <li>Misc.\n <ul>\n <li><a href=\"https://tcg.praze.net\" target=\"_blank\">TCG</a></li>\n <li><a href=\"https://links.praze.net\" target=\"_blank\">Bookmarks</a> <a href=\"https://links.praze.net/feed/rss\"><span class=\"rss\"></span></a></li>\n <li><a href=\"https://kes.praze.net/@tre\" target=\"_blank\">Fediverse</a> <a href=\"https://kes.praze.net/@tre/feed.rss\"><span class=\"rss\"></span></a></li>\n </ul>\n </li>\n </ul>\n </nav>\n <div>\n <main class=\"h-entry\">\n<section>\n<h1 class=\"p-name\">fic n° " + stringno(fic["id"]))
try:
ficpage.write(": " + fic["title"])
except:
pass
if fic["locked"]:
ficpage.write(" 🔒")
ficpage.write("</h1>\n<div class=\"e-content\">\n<ul>\n<li>")
thewords = fic["totalwords"]
ficpage.write(str(f"{thewords:,}" + " words, "))
try:
ficpage.write(fic["approxdate"])
except:
ficpage.write("<code><time class=\"dt-published\" datetime=\"" + datetime.datetime.strftime(fic["startdate"],"%Y-%m-%d") + " 00:00:00\">" + datetime.datetime.strftime(fic["startdate"],"%Y-%m-%d") + "</time></code>")
if fic["completion"] == "incomplete":
ficpage.write("–<time class=\"dt-updated\" datetime=\"" + datetime.datetime.strftime(fic["latestdate"],"%Y-%m-%d") + " 00:00:00\">present</time>")
elif fic["latestdate"] != fic["startdate"]:
ficpage.write("–<code><time class=\"dt-published\" datetime=\"" + datetime.datetime.strftime(fic["latestdate"],"%Y-%m-%d") + " 00:00:00\">" + datetime.datetime.strftime(fic["latestdate"],"%Y-%m-%d") + "</time></code>")
if fic["completion"] == "abandoned":
ficpage.write(" (abandoned)")
ficpage.write("</li>\n<li><b>" + "</b>, <b>".join(fic["fandoms"]) + "</b>")
if len(fic["charmain"]) > 0:
ficpage.write(", " + ", ".join(fic["charmain"]))
if len(fic["charsec"]) > 0:
ficpage.write(", <span class=\"minor\">" + ", ".join(fic["charsec"]) + "</span>")
ficpage.write("</li>\n<li><span class=\"ship " + fic["type"].lower() + "\"")
if fic["type"] != "gen":
try:
ficpage.write(" title=\"" + ", ".join(fic["ships"]) + "\"")
except:
pass
ficpage.write(">" + fic["type"] + "</span>")
try:
ficpage.write(", " + fic["genre"])
except:
pass
if fic["sex"] == "lemon":
ficpage.write(" <span class=\"warning lemon lime\" title=\"explicit sexual content\">🍋</span>")
elif fic["sex"] == "lime":
ficpage.write(" <span class=\"warning lime\" title=\"non-explicit sexual content\">🍋</span>")
elif fic["sex"] == "ref":
ficpage.write(" <span class=\"warning lime reference\" title=\"references to sex\">🍋</span>")
if fic["death"] == "death":
ficpage.write(" <span class=\"warning\" title=\"character death\">💀</span>")
elif fic["death"] == "ref":
ficpage.write(" <span class=\"warning reference\" title=\"references to death\">💀</span>")
if fic["mh"] == "mh":
ficpage.write(" <span class=\"warning\" title=\"mental health themes\">😢</span>")
elif fic["mh"] == "ref":
ficpage.write(" <span class=\"warning reference\" title=\"references to mental health\">😢</span>")
if fic["bigotry"] == "bigotry":
ficpage.write(" <span class=\"warning\" title=\"in-universe bigotry\">🚫</span>")
elif fic["bigotry"] == "ref":
ficpage.write(" <span class=\"warning reference\" title=\"references to bigotry\">🚫</span>")
if fic["vomiting"] == "vomiting":
ficpage.write(" <span class=\"warning\" title=\"vomiting\">🤢</span>")
elif fic["vomiting"] == "ref":
ficpage.write(" <span class=\"warning reference\" title=\"references to vomiting\">🤢</span>")
if fic["consent"] == "consent":
ficpage.write(" <span class=\"warning\" title=\"consent issues\">⛔</span>")
elif fic["consent"] == "ref":
ficpage.write(" <span class=\"warning reference\" title=\"references to consent issues\">⛔</span>")
if fic["underage"] == "underage":
ficpage.write(" <span class=\"warning\" title=\"underage sexual activity\">👶</span>")
elif fic["underage"] == "ref":
ficpage.write(" <span class=\"warning reference\" title=\"references to underage sexual activity\">👶</span>")
if fic["incest"] == "incest":
ficpage.write(" <span class=\"warning\" title=\"incest\">🦶</span>")
elif fic["incest"] == "ref":
ficpage.write(" <span class=\"warning reference\" title=\"references to incest\">🦎</span>")
if fic["amp"] == "amp":
ficpage.write(" <span class=\"warning\" title=\"amputation\">🦶</span>")
elif fic["amp"] == "ref":
ficpage.write(" <span class=\"warning reference\" title=\"references to amputation\">🦎</span>")
ficpage.write("</li>")
try:
ficpage.write("\n<li>Written for <b>" + fic["event"] + "</b>.")
if fic["prompt"]:
ficpage.write(" Prompt: <i>" + fic["prompt"] + "</i>.")
ficpage.write("</li>")
except:
pass
try:
if fic["transid"]:
ficpage.write("\n<li>")
if fic["french"] == "translation":
ficpage.write("French")
elif fic["french"] == "original":
ficpage.write("English")
ficpage.write(" version: <a href=\"/fic/" + stringno(fic["transid"]) + "\">" + stringno(fic["transid"]) + "</a></li>")
except:
pass
allowcomments = False
havecomments = False
commentlink = False
if "Final Fantasy X" in fic["fandoms"]:
allowcomments = True
else:
timeelapsed = datetime.datetime.now() - fic["latestdate"]
if timeelapsed.days < 730:
allowcomments = True
if fic["comments"]:
havecomments = True
if allowcomments or havecomments:
commentlink = True
if fic["locked"]:
commentlink = False
ficpage.write("\n<li>Download: <a href=\"https://tre.praze.net/fic/secret/" + stringno(fic["id"]) + ".html\">HTML</a>")
if fic["pdf"] or fic["epub"]:
ficpage.write("")
elif fic["pdf"] or fic["epub"]:
ficpage.write("\n<li>")
if fic["pdf"] or fic["epub"]:
ficpage.write("Download: ")
if fic["pdf"]:
ficpage.write("<a href=\"https://tre.praze.net/fic/")
if fic["locked"]:
ficpage.write("secret")
else:
ficpage.write("files")
ficpage.write("/" + stringno(fic["id"]) + ".pdf\" target=\"_blank\">PDF</a>")
if fic["epub"]:
ficpage.write("")
if fic["epub"]:
ficpage.write("<a href=\"https://tre.praze.net/fic/")
if fic["locked"]:
ficpage.write("secret")
else:
ficpage.write("files")
ficpage.write("/" + stringno(fic["id"]) + ".epub\" target=\"_blank\">EPUB</a>")
if fic["pdf"] or fic["epub"]:
if fic["locked"]:
ficpage.write(" (authentication required)")
if fic["locked"] or fic["pdf"] or fic["epub"]:
ficpage.write("</li>")
if commentlink:
ficpage.write("\n<li><a href=\"#commentsection\">Jump to comments</a></li>")
ficpage.write("\n</ul>")
thesummary = ""
try:
ficpage.write("\n<blockquote class=\"p-summary\">\n<p>" + fic["summary"] + "</p>\n</blockquote>")
except:
pass
ficpage.write("\n</section>\n")
if fic["locked"]:
ficpage.write("<section id=\"passwarn\"><p>Fic is password-protected.</p></section>\n")
else:
with open("build/files/" + stringno(fic["id"]) + ".html") as fichtml:
ficsoup = BeautifulSoup(fichtml,"html.parser")
soupfic = ficsoup.find("div",{"id":"workskin"})
if soupfic == None:
soupfic = ficsoup.find("article")
ficpage.write(str(soupfic) + "\n")
ficpage.write("</div>\n")
if fic["id"] > 261:
ficpage.write("<section><p><i>You may be able to find this fic on the fediverse by searching for <code>https://fed.brid.gy/r/https://tre.praze.net/fic/" + stringno(fic["id"]) + "/</code> in your fediverse client.</i></p></section>")
if allowcomments or havecomments:
ficpage.write("<section id=\"commentsection\">\n")
if allowcomments:
ficpage.write("<div class=\"comments submission\">\n<h2>Comments</h2>\n<noscript>\n<p><b>JavaScript is unavailable.</b> Please <a href=\"mailto:tre@praze.net\">email me</a> any comments.</p>\n</noscript>\n<p class=\"jsonly\">You can comment on this fic if you like. Comments will be posted below after moderation. All comments are anonymous and email addresses, if provided, will <b>not</b> be published.</p>\n<form id=\"theform\" onsubmit=\"sendContact(event)\" class=\"jsonly\">\n<details id=\"legend\">\n<summary>Old emoticons I stole from the wayback machine</summary>\n<div>\n<figure><img src=\"/legend/animesweat.gif\"><figcaption><code>:animesweat:</code></figcaption></figure>\n<figure><img src=\"/legend/aww.gif\"><figcaption><code>:aww:</code></figcaption></figure>\n<figure><img src=\"/legend/biggrin.gif\"><figcaption><code>:biggrin:</code></figcaption></figure>\n<figure><img src=\"/legend/blankstare.gif\"><figcaption><code>:blankstare:</code></figcaption></figure>\n<figure><img src=\"/legend/bleh.gif\"><figcaption><code>:bleh:</code></figcaption></figure>\n<figure><img src=\"/legend/boogie.gif\"><figcaption><code>:boogie:</code></figcaption></figure>\n<figure><img src=\"/legend/bounce.gif\"><figcaption><code>:bounce:</code></figcaption></figure>\n<figure><img src=\"/legend/bow.gif\"><figcaption><code>:bow:</code></figcaption></figure>\n<figure><img src=\"/legend/bump.gif\"><figcaption><code>:bump:</code></figcaption></figure>\n<figure><img src=\"/legend/cd.gif\"><figcaption><code>:cd:</code></figcaption></figure>\n<figure><img src=\"/legend/clap.gif\"><figcaption><code>:clap:</code></figcaption></figure>\n<figure><img src=\"/legend/confused.gif\"><figcaption><code>:confused:</code></figcaption></figure>\n<figure><img src=\"/legend/cool.gif\"><figcaption><code>:cool:</code></figcaption></figure>\n<figure><img src=\"/legend/dance.gif\"><figcaption><code>:dance:</code></figcaption></figure>\n<figure><img src=\"/legend/dead.gif\"><figcaption><code>:dead:</code></figcaption></figure>\n<figure><img src=\"/legend/eager.gif\"><figcaption><code>:eager:</code></figcaption></figure>\n<figure><img src=\"/legend/eek.gif\"><figcaption><code>:eek:</code></figcaption></figure>\n<figure><img src=\"/legend/giggle.gif\"><figcaption><code>:giggle:</code></figcaption></figure>\n<figure><img src=\"/legend/headbang.gif\"><figcaption><code>:headbang:</code></figcaption></figure>\n<figure><img src=\"/legend/la.gif\"><figcaption><code>:la:</code></figcaption></figure>\n<figure><img src=\"/legend/lmao.gif\"><figcaption><code>:lmao:</code></figcaption></figure>\n<figure><img src=\"/legend/meow.gif\"><figcaption><code>:meow:</code></figcaption></figure>\n<figure><img src=\"/legend/ninja.gif\"><figcaption><code>:ninja:</code></figcaption></figure>\n<figure><img src=\"/legend/nod.gif\"><figcaption><code>:nod:</code></figcaption></figure>\n<figure><img src=\"/legend/ohnoes.gif\"><figcaption><code>:ohnoes:</code></figcaption></figure>\n<figure><img src=\"/legend/razz.gif\"><figcaption><code>:razz:</code></figcaption></figure>\n<figure><img src=\"/legend/rofl.gif\"><figcaption><code>:rofl:</code></figcaption></figure>\n<figure><img src=\"/legend/sad.gif\"><figcaption><code>:sad:</code></figcaption></figure>\n<figure><img src=\"/legend/shrug.gif\"><figcaption><code>:shrug:</code></figcaption></figure>\n<figure><img src=\"/legend/smile.gif\"><figcaption><code>:smile:</code></figcaption></figure>\n<figure><img src=\"/legend/tombstone.gif\"><figcaption><code>:tombstone:</code></figcaption></figure>\n<figure><img src=\"/legend/tongue.gif\"><figcaption><code>:tongue:</code></figcaption></figure>\n<figure><img src=\"/legend/typing.gif\"><figcaption><code>:typing:</code></figcaption></figure>\n<figure><img src=\"/legend/wave.gif\"><figcaption><code>:wave:</code></figcaption></figure>\n<figure><img src=\"/legend/wink.gif\"><figcaption><code>:wink:</code></figcaption></figure>\n<figure><img src=\"/legend/winkrazz.gif\"><figcaption><code>:winkrazz:</code></figcaption></figure>\n<figure><img src=\"/legend/woot.gif\"><figcaption><code>:woot:</code></figcaption></figure>\n<figure><img src=\"/legend/worry.gif\"><figcaption><code>:worry:</code></figcaption></figure>\n<figure><img src=\"/legend/worship.gif\"><figcaption><code>:worship:</code></figcaption></figure>\n<figure><img src=\"/legend/xd.gif\"><figcaption><code>:xd:</code></figcaption></figure>\n</div>\n</details>\n<textarea id=\"messageInput\" rows=\"5\" maxlength=\"4800\" required placeholder=\"Your comment (include whatever markup [or down] you like)\"></textarea>\n<input type=\"email\" id=\"emailInput\" placeholder=\"Email address (if you want email notification of reply)\">\n<button type=\"submit\">Submit</button>\n</form>\n</div>\n")
else:
ficpage.write("<div class=\"comments submission\">\n<h2>Comments</h2>\n<p>Archived comments are included below. My replies have not been archived.</p>\n</div>\n")
if havecomments:
commno = 1
for comment in fic["comments"]:
ficpage.write("<div class=\"comments\">\n<h2>n° " + str(commno))
try:
ficpage.write(" [chapter " + str(comment["chapter"]) + "]")
except:
pass
try:
if comment["site"] != "praze":
ficpage.write(" (archived from ")
if comment["site"] == "ao3":
ficpage.write("archiveofourown.org")
elif comment["site"] == "lj":
ficpage.write("livejournal.com")
elif comment["site"] == "dw":
ficpage.write("dreamwidth.org")
elif comment["site"] == "discord":
ficpage.write("discord.com")
ficpage.write(")")
except:
pass
ficpage.write("</h2>\n<p class=\"commenttime\"><code>" + datetime.datetime.strftime(comment["date"],"%Y-%m-%d") + "</code></p>\n<p>" + comment["text"] + "</p>\n")
try:
if len(comment["reply"]) > 0:
ficpage.write("<div class=\"reply\">\n<p><span class=\"replystring\">reply: </span>" + comment["reply"] + "</p>\n</div>\n")
except:
pass
ficpage.write("</div>\n")
commno += 1
ficpage.write("</section>\n")
ficpage.write("<div id=\"federation\" hidden=\"from-humans\">\n<a class=\"u-bridgy-fed\" href=\"https://fed.brid.gy/\"></a>\n<a rel=\"author\" class=\"p-author h-card\" href=\"/\">Mez<img class=\"u-photo\" src=\"/ab.png\"></a>\n<a class=\"u-url\" href=\"/fic/" + stringno(fic["id"]) + "/\"></a>\n")
for fandom in fic["fandoms"]:
ficpage.write("<span class=\"p-category\">" + fandom + "</span>\n")
ficpage.write("</div>\n </main>\n <footer>\n <ul>\n <li><a href=\"/fic\">back to fic pages</a></li>\n </ul>\n </footer>\n </div>\n <a href=\"/\"><img src=\"/a.png\" style=\"position:fixed;bottom:2px;right:2px;\" title=\"home\"></a>\n")
if allowcomments:
ficpage.write("<script>\nasync function sendContact(ev) {\nev.preventDefault();\nconst thePage = window.location.href;\nconst senderAddress = document.getElementById('emailInput').value;\nconst senderMessage = document.getElementById('messageInput').value;\nconst gtsUrl = 'https://kes.praze.net/api/v1/statuses';\nconst response = await fetch(gtsUrl, {\nmethod: 'POST',\nheaders: {\n'Content-Type': 'application/json',\n'Authorization': 'Bearer OTBKMDFMMJMTMZNKYY0ZMGQZLWJJMJUTYJE0MMY5ZJK3NJU4',\n},\nbody: JSON.stringify({'status' : 'new comment on ' + thePage + ' (' + senderAddress + ')\\n\\n' + senderMessage}),\n});\nif (response.ok) {\nalert('Comment submitted, thank you!');\n} else {\nalert('This is fucked, sorry. Email me instead, whatever at praze dot net!');\n}\ndocument.getElementById(\"theform\").reset();\n}\n</script>\n")
ficpage.write(" </body>\n</html>")
ficpage.close()
try:
if fic["transid"]:
maketrans = True
except:
maketrans = False
if maketrans:
if not os.path.isdir("build/" + stringno(fic["transid"])):
os.mkdir("build/" + stringno(fic["transid"]))
transpage = open("build/" + stringno(fic["transid"]) + "/index.html", "w")
transpage.write("<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>praze • Fanfiction</title>\n <meta property=\"og:title\" content=\"praze • Fanfiction\">\n <meta property=\"og:type\" content=\"website\">\n <meta property=\"og:image\" content=\"https://tre.praze.net/ab.png\">\n <meta property=\"og:url\" content=\"https://tre.praze.net/fic/" + stringno(fic["id"]) + "\">\n <meta name=\"description\" property=\"og:description\" content=\"Fanfiction on tre.praze.net\">\n <meta property=\"og:locale\" content=\"en_GB\">\n <meta property=\"og:site_name\" content=\"tre.praze.net\">\n <meta name=\"fediverse:creator\" content=\"@tre@praze.net\">\n <link rel=\"webmention\" href=\"https://webmention.io/tre.praze.net/webmention\">\n <link rel=\"stylesheet\" href=\"/new.css\">\n <link rel=\"stylesheet\" href=\"/fic/fic.css\">\n")
try:
for override in fic["cssoverride"]:
transpage.write(" <link rel=\"stylesheet\" href=\"" + override + "\">\n")
except:
transpage.write(" <link rel=\"stylesheet\" href=\"/fic/tufte-embed.css\">\n")
transpage.write(" <link rel=\"me\" href=\"https://kes.praze.net/@tre\">\n <link rel=\"alternate\" type=\"application/rss+xml\" title=\"tre.praze.net\" href=\"/feed.xml\">\n <meta name=\"theme-color\" content=\"#f2f2f2\" />\n <style>\n span.minor {\n font-size: 0.7rem;\n }\n </style>\n </head>\n <body>\n <nav>\n <input type=\"checkbox\" id=\"toggle\" name=\"toggle\">\n <label class=\"toggle-btn\" for=\"toggle\">Menu</label>\n <ul>\n <li>Fundamentals\n <ul>\n <li><a href=\"/\">Home</a></li>\n <li><a href=\"/about\">About + listings</a></li>\n <li><a href=\"/follow\">Follow</a></li>\n <li><a href=\"/feed.xml\">Changelog</a> <a href=\"/feed.xml\"><span class=\"rss\"></span></a></li>\n <li><a href=\"/sitemap.xml\">Sitemap</a></li>\n <li><a href=\"/siteroll\">Siteroll</a></li>\n </ul>\n </li>\n <li>Projects\n <ul>\n <li>Fanfiction <a href=\"/fic/feed.xml\"><span class=\"rss\"></span></a></li>\n <li><a href=\"/music\">Music</a></li>\n <li><a href=\"/notes\">Journal</a></li>\n <li><a href=\"/trackers\">Trackers</a></li>\n <li><a href=\"https://git.praze.net/tre\" target=\"_blank\">Code</a> <a href=\"https://git.praze.net/tre.rss\"><span class=\"rss\"></span></a></li>\n <li><a href=\"https://img.praze.net\" target=\"_blank\">Photos</a> <a href=\"https://img.praze.net/feed.php\"><span class=\"rss\"></span></a></li>\n </ul>\n </li>\n <li>Fan content\n <ul>\n <li><a href=\"/ffx\">FFX</a></li>\n <li><a href=\"/xvi\">FF16</a></li>\n <li><a href=\"https://morgan.praze.net\" target=\"_blank\">Dermot Morgan</a> <a href=\"https://morgan.praze.net/feed.xml\"><span class=\"rss\"></span></a></li>\n </ul>\n </li>\n <li>Misc.\n <ul>\n <li><a href=\"https://tcg.praze.net\" target=\"_blank\">TCG</a></li>\n <li><a href=\"https://links.praze.net\" target=\"_blank\">Bookmarks</a> <a href=\"https://links.praze.net/feed/rss\"><span class=\"rss\"></span></a></li>\n <li><a href=\"https://kes.praze.net/@tre\" target=\"_blank\">Fediverse</a> <a href=\"https://kes.praze.net/@tre/feed.rss\"><span class=\"rss\"></span></a></li>\n </ul>\n </li>\n </ul>\n </nav>\n <div>\n <main class=\"h-entry\">\n<section>\n<h1 class=\"p-name\">fic n° " + stringno(fic["transid"]))
try:
transpage.write(": " + fic["transtitle"])
except:
pass
if fic["locked"]:
transpage.write(" 🔒")
transpage.write("</h1>\n<ul>\n<div class=\"e-content\">\n<li>")
thewords = fic["transwords"]
transpage.write(str(f"{thewords:,}" + " words, ") + "<code><time class=\"dt-published\" datetime=\"" + datetime.datetime.strftime(fic["transstartdate"],"%Y-%m-%d") + " 00:00:00\">" + datetime.datetime.strftime(fic["transstartdate"],"%Y-%m-%d") + "</time></code>")
if fic["completion"] == "incomplete":
transpage.write("–<time class=\"dt-updated\" datetime=\"" + datetime.datetime.strftime(fic["translatestdate"],"%Y-%m-%d") + " 00:00:00\">present</time>")
elif fic["translatestdate"] != fic["transstartdate"]:
transpage.write("–<code><time class=\"dt-published\" datetime=\"" + datetime.datetime.strftime(fic["translatestdate"],"%Y-%m-%d") + " 00:00:00\">" + datetime.datetime.strftime(fic["translatestdate"],"%Y-%m-%d") + "</time></code>")
if fic["completion"] == "abandoned":
transpage.write(" (abandoned)")
transpage.write("</li>\n<li><b>" + "</b>, <b>".join(fic["fandoms"]) + "</b>")
if len(fic["charmain"]) > 0:
transpage.write(", " + ", ".join(fic["charmain"]))
if len(fic["charsec"]) > 0:
transpage.write(", <span class=\"minor\">" + ", ".join(fic["charsec"]) + "</span>")
transpage.write("</li>\n<li><span class=\"ship " + fic["type"].lower() + "\"")
if fic["type"] != "gen":
try:
transpage.write(" title=\"" + ", ".join(fic["ships"]) + "\"")
except:
pass
transpage.write(">" + fic["type"] + "</span>")
try:
transpage.write(", " + fic["genre"])
except:
pass
if fic["sex"] == "lemon":
transpage.write(" <span class=\"warning lemon lime\" title=\"explicit sexual content\">🍋</span>")
elif fic["sex"] == "lime":
transpage.write(" <span class=\"warning lime\" title=\"non-explicit sexual content\">🍋</span>")
elif fic["sex"] == "ref":
transpage.write(" <span class=\"warning lime reference\" title=\"references to sex\">🍋</span>")
if fic["death"] == "death":
transpage.write(" <span class=\"warning\" title=\"character death\">💀</span>")
elif fic["death"] == "ref":
transpage.write(" <span class=\"warning reference\" title=\"references to death\">💀</span>")
if fic["mh"] == "mh":
transpage.write(" <span class=\"warning\" title=\"mental health themes\">😢</span>")
elif fic["mh"] == "ref":
transpage.write(" <span class=\"warning reference\" title=\"references to mental health\">😢</span>")
if fic["bigotry"] == "bigotry":
transpage.write(" <span class=\"warning\" title=\"in-universe bigotry\">🚫</span>")
elif fic["bigotry"] == "ref":
transpage.write(" <span class=\"warning reference\" title=\"references to bigotry\">🚫</span>")
if fic["vomiting"] == "vomiting":
transpage.write(" <span class=\"warning\" title=\"vomiting\">🤢</span>")
elif fic["vomiting"] == "ref":
transpage.write(" <span class=\"warning reference\" title=\"references to vomiting\">🤢</span>")
if fic["consent"] == "consent":
transpage.write(" <span class=\"warning\" title=\"consent issues\">⛔</span>")
elif fic["consent"] == "ref":
transpage.write(" <span class=\"warning reference\" title=\"references to consent issues\">⛔</span>")
if fic["underage"] == "underage":
transpage.write(" <span class=\"warning\" title=\"underage sexual activity\">👶</span>")
elif fic["underage"] == "ref":
transpage.write(" <span class=\"warning reference\" title=\"references to underage sexual activity\">👶</span>")
if fic["incest"] == "incest":
transpage.write(" <span class=\"warning\" title=\"incest\">🦶</span>")
elif fic["incest"] == "ref":
transpage.write(" <span class=\"warning reference\" title=\"references to incest\">🦎</span>")
if fic["amp"] == "amp":
transpage.write(" <span class=\"warning\" title=\"amputation\">🦶</span>")
elif fic["amp"] == "ref":
transpage.write(" <span class=\"warning reference\" title=\"references to amputation\">🦎</span>")
transpage.write("</li>")
try:
transpage.write("\n<li>Written for <b>" + fic["event"] + "</b>.")
if fic["prompt"]:
transpage.write(" Prompt: <i>" + fic["prompt"] + "</i>.")
transpage.write("</li>")
except:
pass
transpage.write("\n<li>")
if fic["french"] == "original":
transpage.write("French")
elif fic["french"] == "translation":
transpage.write("English")
transpage.write(" version: <a href=\"/fic/" + stringno(fic["id"]) + "\">" + stringno(fic["id"]) + "</a></li>")
allowcomments = False
havecomments = False
commentlink = False
if "Final Fantasy X" in fic["fandoms"]:
allowcomments = True
else:
timeelapsed = datetime.datetime.now() - fic["translatestdate"]
if timeelapsed.days < 730:
allowcomments = True
if fic["comments"]:
havecomments = True
if allowcomments or havecomments:
commentlink = True
if fic["locked"]:
commentlink = False
transpage.write("\n<li>Download: <a href=\"https://tre.praze.net/fic/secret/" + stringno(fic["transid"]) + ".html\">HTML</a>")
if fic["pdf"] or fic["epub"]:
transpage.write("")
elif fic["pdf"] or fic["epub"]:
transpage.write("\n<li>")
if fic["pdf"] or fic["epub"]:
transpage.write("Download: ")
if fic["pdf"]:
transpage.write("<a href=\"https://tre.praze.net/fic/")
if fic["locked"]:
transpage.write("secret")
else:
transpage.write("files")
transpage.write("/" + stringno(fic["transid"]) + ".pdf\" target=\"_blank\">PDF</a>")
if fic["epub"]:
transpage.write("")
if fic["epub"]:
transpage.write("<a href=\"https://tre.praze.net/fic/")
if fic["locked"]:
transpage.write("secret")
else:
transpage.write("files")
transpage.write("/" + stringno(fic["transid"]) + ".epub\" target=\"_blank\">EPUB</a>")
if fic["pdf"] or fic["epub"]:
if fic["locked"]:
transpage.write(" (authentication required)")
if fic["locked"] or fic["pdf"] or fic["epub"]:
transpage.write("</li>")
if commentlink:
transpage.write("\n<li><a href=\"#commentsection\">Jump to comments</a></li>")
transpage.write("\n</ul>")
thesummary = ""
try:
transpage.write("\n<blockquote class=\"p-summary\">\n<p>" + fic["transsummary"] + "</p>\n</blockquote>")
except:
pass
transpage.write("\n</section>\n")
if fic["locked"]:
transpage.write("<section id=\"passwarn\"><p>Fic is password-protected.</p></section>\n")
else:
with open("build/files/" + stringno(fic["transid"]) + ".html") as fichtml:
ficsoup = BeautifulSoup(fichtml,"html.parser")
soupfic = ficsoup.find("div",{"id":"workskin"})
if soupfic == None:
soupfic = ficsoup.find("article")
transpage.write(str(soupfic) + "\n")
transpage.write("</div>\n")
if fic["transid"] > 261:
ficpage.write("<section><p><i>You may be able to find this fic on the fediverse by searching for <code>https://fed.brid.gy/r/https://tre.praze.net/fic/" + stringno(fic["transid"]) + "/</code> in your fediverse client.</i></p></section>")
if allowcomments or havecomments:
transpage.write("<section id=\"commentsection\">\n")
if allowcomments:
transpage.write("<div class=\"comments submission\">\n<h2>Comments</h2>\n<noscript>\n<p><b>JavaScript is unavailable.</b> Please <a href=\"mailto:tre@praze.net\">email me</a> any comments.</p>\n</noscript>\n<p class=\"jsonly\">You can comment on this fic if you like. Comments will be posted below after moderation. All comments are anonymous and email addresses, if provided, will <b>not</b> be published.</p>\n<form id=\"theform\" onsubmit=\"sendContact(event)\" class=\"jsonly\">\n<details id=\"legend\">\n<summary>Old emoticons I stole from the wayback machine</summary>\n<div>\n<figure><img src=\"/legend/animesweat.gif\"><figcaption><code>:animesweat:</code></figcaption></figure>\n<figure><img src=\"/legend/aww.gif\"><figcaption><code>:aww:</code></figcaption></figure>\n<figure><img src=\"/legend/biggrin.gif\"><figcaption><code>:biggrin:</code></figcaption></figure>\n<figure><img src=\"/legend/blankstare.gif\"><figcaption><code>:blankstare:</code></figcaption></figure>\n<figure><img src=\"/legend/bleh.gif\"><figcaption><code>:bleh:</code></figcaption></figure>\n<figure><img src=\"/legend/boogie.gif\"><figcaption><code>:boogie:</code></figcaption></figure>\n<figure><img src=\"/legend/bounce.gif\"><figcaption><code>:bounce:</code></figcaption></figure>\n<figure><img src=\"/legend/bow.gif\"><figcaption><code>:bow:</code></figcaption></figure>\n<figure><img src=\"/legend/bump.gif\"><figcaption><code>:bump:</code></figcaption></figure>\n<figure><img src=\"/legend/cd.gif\"><figcaption><code>:cd:</code></figcaption></figure>\n<figure><img src=\"/legend/clap.gif\"><figcaption><code>:clap:</code></figcaption></figure>\n<figure><img src=\"/legend/confused.gif\"><figcaption><code>:confused:</code></figcaption></figure>\n<figure><img src=\"/legend/cool.gif\"><figcaption><code>:cool:</code></figcaption></figure>\n<figure><img src=\"/legend/dance.gif\"><figcaption><code>:dance:</code></figcaption></figure>\n<figure><img src=\"/legend/dead.gif\"><figcaption><code>:dead:</code></figcaption></figure>\n<figure><img src=\"/legend/eager.gif\"><figcaption><code>:eager:</code></figcaption></figure>\n<figure><img src=\"/legend/eek.gif\"><figcaption><code>:eek:</code></figcaption></figure>\n<figure><img src=\"/legend/giggle.gif\"><figcaption><code>:giggle:</code></figcaption></figure>\n<figure><img src=\"/legend/headbang.gif\"><figcaption><code>:headbang:</code></figcaption></figure>\n<figure><img src=\"/legend/la.gif\"><figcaption><code>:la:</code></figcaption></figure>\n<figure><img src=\"/legend/lmao.gif\"><figcaption><code>:lmao:</code></figcaption></figure>\n<figure><img src=\"/legend/meow.gif\"><figcaption><code>:meow:</code></figcaption></figure>\n<figure><img src=\"/legend/ninja.gif\"><figcaption><code>:ninja:</code></figcaption></figure>\n<figure><img src=\"/legend/nod.gif\"><figcaption><code>:nod:</code></figcaption></figure>\n<figure><img src=\"/legend/ohnoes.gif\"><figcaption><code>:ohnoes:</code></figcaption></figure>\n<figure><img src=\"/legend/razz.gif\"><figcaption><code>:razz:</code></figcaption></figure>\n<figure><img src=\"/legend/rofl.gif\"><figcaption><code>:rofl:</code></figcaption></figure>\n<figure><img src=\"/legend/sad.gif\"><figcaption><code>:sad:</code></figcaption></figure>\n<figure><img src=\"/legend/shrug.gif\"><figcaption><code>:shrug:</code></figcaption></figure>\n<figure><img src=\"/legend/smile.gif\"><figcaption><code>:smile:</code></figcaption></figure>\n<figure><img src=\"/legend/tombstone.gif\"><figcaption><code>:tombstone:</code></figcaption></figure>\n<figure><img src=\"/legend/tongue.gif\"><figcaption><code>:tongue:</code></figcaption></figure>\n<figure><img src=\"/legend/typing.gif\"><figcaption><code>:typing:</code></figcaption></figure>\n<figure><img src=\"/legend/wave.gif\"><figcaption><code>:wave:</code></figcaption></figure>\n<figure><img src=\"/legend/wink.gif\"><figcaption><code>:wink:</code></figcaption></figure>\n<figure><img src=\"/legend/winkrazz.gif\"><figcaption><code>:winkrazz:</code></figcaption></figure>\n<figure><img src=\"/legend/woot.gif\"><figcaption><code>:woot:</code></figcaption></figure>\n<figure><img src=\"/legend/worry.gif\"><figcaption><code>:worry:</code></figcaption></figure>\n<figure><img src=\"/legend/worship.gif\"><figcaption><code>:worship:</code></figcaption></figure>\n<figure><img src=\"/legend/xd.gif\"><figcaption><code>:xd:</code></figcaption></figure>\n</div>\n</details>\n<textarea id=\"messageInput\" rows=\"5\" maxlength=\"4800\" required placeholder=\"Your comment (include whatever markup [or down] you like)\"></textarea>\n<input type=\"email\" id=\"emailInput\" placeholder=\"Email address (if you want email notification of reply)\">\n<button type=\"submit\">Submit</button>\n</form>\n</div>\n")
else:
transpage.write("<div class=\"comments submission\">\n<h2>Comments</h2>\n<p>Archived comments are included below. My replies have not been archived.</p>\n</div>\n")
if havecomments:
commno = 1
for comment in fic["comments"]:
transpage.write("<div class=\"comments\">\n<h2>n° " + str(commno))
try:
transpage.write(" [chapter " + str(comment["chapter"]) + "]")
except:
pass
try:
if comment["site"] != "praze":
transpage.write(" (archived from ")
if comment["site"] == "ao3":
transpage.write("archiveofourown.org")
elif comment["site"] == "lj":
transpage.write("livejournal.com")
elif comment["site"] == "dw":
transpage.write("dreamwidth.org")
elif comment["site"] == "discord":
transpage.write("discord.com")
transpage.write(")")
except:
pass
transpage.write("</h2>\n<p class=\"commenttime\"><code>" + datetime.datetime.strftime(comment["date"],"%Y-%m-%d") + "</code></p>\n<p>" + comment["text"] + "</p>\n")
try:
if len(comment["reply"]) > 0:
transpage.write("<div class=\"reply\">\n<p><span class=\"replystring\">reply: </span>" + comment["reply"] + "</p>\n</div>\n")
except:
pass
transpage.write("</div>\n")
commno += 1
transpage.write("</section>\n")
transpage.write("<div id=\"federation\" hidden=\"from-humans\">\n<a class=\"u-bridgy-fed\" href=\"https://fed.brid.gy/\"></a>\n<a rel=\"author\" class=\"p-author h-card\" href=\"/\">Mez<img class=\"u-photo\" src=\"/ab.png\"></a>\n<a class=\"u-url\" href=\"/fic/" + stringno(fic["transid"]) + "/\"></a>\n")
for fandom in fic["fandoms"]:
transpage.write("<span class=\"p-category\">" + fandom + "</span>\n")
transpage.write("</div>\n </main>\n <footer>\n <ul>\n <li><a href=\"/fic\">back to fic pages</a></li>\n </ul>\n </footer>\n </div>\n <a href=\"/\"><img src=\"/a.png\" style=\"position:fixed;bottom:2px;right:2px;\" title=\"home\"></a>\n")
if allowcomments:
transpage.write("<script>\nasync function sendContact(ev) {\nev.preventDefault();\nconst thePage = window.location.href;\nconst senderAddress = document.getElementById('emailInput').value;\nconst senderMessage = document.getElementById('messageInput').value;\nconst gtsUrl = 'https://kes.praze.net/api/v1/statuses';\nconst response = await fetch(gtsUrl, {\nmethod: 'POST',\nheaders: {\n'Content-Type': 'application/json',\n'Authorization': 'Bearer OTBKMDFMMJMTMZNKYY0ZMGQZLWJJMJUTYJE0MMY5ZJK3NJU4',\n},\nbody: JSON.stringify({'status' : 'new comment on ' + thePage + ' (' + senderAddress + ')\\n\\n' + senderMessage}),\n});\nif (response.ok) {\nalert('Comment submitted, thank you!');\n} else {\nalert('This is fucked, sorry. Email me instead, whatever at praze dot net!');\n}\ndocument.getElementById(\"theform\").reset();\n}\n</script>\n")
transpage.write(" </body>\n</html>")
transpage.close()