[SSG][Fix] Fix %M to %m. Add -v for logging.
This commit is contained in:
parent
f7582b1b2b
commit
401e1b64f0
70
nova.py
70
nova.py
|
@ -1,4 +1,5 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
# pylint: disable=logging-format-interpolation
|
||||||
"Creates a static site for redacted.life"
|
"Creates a static site for redacted.life"
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
@ -7,6 +8,7 @@ from datetime import datetime
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import os.path as path
|
import os.path as path
|
||||||
|
import logging
|
||||||
import re
|
import re
|
||||||
import subprocess
|
import subprocess
|
||||||
import shutil
|
import shutil
|
||||||
|
@ -36,6 +38,7 @@ class EpisodeList(UserList):
|
||||||
self.output = output
|
self.output = output
|
||||||
self.template = template
|
self.template = template
|
||||||
self.archives = archives
|
self.archives = archives
|
||||||
|
logging.info(f"New EpisodeList: {url=} {output=} {template=} {archives=}")
|
||||||
|
|
||||||
def sort(self, *_args, **_kwargs):
|
def sort(self, *_args, **_kwargs):
|
||||||
"Sorts the EpisodeList"
|
"Sorts the EpisodeList"
|
||||||
|
@ -43,6 +46,7 @@ class EpisodeList(UserList):
|
||||||
|
|
||||||
def generate_thumbnails(self):
|
def generate_thumbnails(self):
|
||||||
"Generates thumbnails for all the videos"
|
"Generates thumbnails for all the videos"
|
||||||
|
logging.info(f"Creating missing directories")
|
||||||
if not path.isdir(self.output + "assets"):
|
if not path.isdir(self.output + "assets"):
|
||||||
os.mkdir(self.output + "assets")
|
os.mkdir(self.output + "assets")
|
||||||
if not path.isdir(self.output + "assets/thumbnails"):
|
if not path.isdir(self.output + "assets/thumbnails"):
|
||||||
|
@ -50,6 +54,7 @@ class EpisodeList(UserList):
|
||||||
for episode in self.data:
|
for episode in self.data:
|
||||||
location = (self.output + "assets/thumbnails/" +
|
location = (self.output + "assets/thumbnails/" +
|
||||||
gen_name(episode.date, episode.slug) + ".jpg")
|
gen_name(episode.date, episode.slug) + ".jpg")
|
||||||
|
logging.info(f"Creating thumbnail for {episode=} at {location}")
|
||||||
episode.store_thumbnail(location)
|
episode.store_thumbnail(location)
|
||||||
|
|
||||||
def generate_rss(self, header):
|
def generate_rss(self, header):
|
||||||
|
@ -58,8 +63,10 @@ class EpisodeList(UserList):
|
||||||
open(self.output + "feed_ogg.rss", "w") as ogg:
|
open(self.output + "feed_ogg.rss", "w") as ogg:
|
||||||
# pylint: disable = invalid-name
|
# pylint: disable = invalid-name
|
||||||
for s, ext in ((mp3, "mp3"), (ogg, "ogg")):
|
for s, ext in ((mp3, "mp3"), (ogg, "ogg")):
|
||||||
|
logging.info(f"Writing header for {ext}")
|
||||||
s.write(header)
|
s.write(header)
|
||||||
for ep in self.data:
|
for ep in self.data:
|
||||||
|
logging.info(f"Writing item for episode {ep} with {ext=}")
|
||||||
s.write("<item>")
|
s.write("<item>")
|
||||||
s.write("\n")
|
s.write("\n")
|
||||||
# Title
|
# Title
|
||||||
|
@ -123,6 +130,7 @@ class EpisodeList(UserList):
|
||||||
s.write("\n")
|
s.write("\n")
|
||||||
s.write("</item>")
|
s.write("</item>")
|
||||||
s.write("\n")
|
s.write("\n")
|
||||||
|
logging.info(f"Writing end for {ext}")
|
||||||
s.write("</channel>")
|
s.write("</channel>")
|
||||||
s.write("\n")
|
s.write("\n")
|
||||||
s.write("</rss>")
|
s.write("</rss>")
|
||||||
|
@ -139,24 +147,27 @@ class EpisodeList(UserList):
|
||||||
|
|
||||||
def generate_site(self, root):
|
def generate_site(self, root):
|
||||||
"Generates the entire site"
|
"Generates the entire site"
|
||||||
# Generate CSS from SCSS
|
logging.info("Generating CSS from SCSS")
|
||||||
subprocess.run(["sass", "--update", f"{root}scss:{root}assets/css"],
|
subprocess.run(["sass", "--update", f"{root}scss:{root}assets/css"],
|
||||||
check=True)
|
check=True)
|
||||||
# Copy the existing assets
|
logging.info("Copy the existing assets")
|
||||||
shutil.copytree(root + "assets", self.output + "assets",
|
shutil.copytree(root + "assets", self.output + "assets",
|
||||||
dirs_exist_ok=True)
|
dirs_exist_ok=True)
|
||||||
# Create the required directories
|
logging.info("Create the required directories")
|
||||||
paths = [
|
paths = [
|
||||||
"assets",
|
"assets",
|
||||||
"assets/audio",
|
"assets/audio",
|
||||||
"assets/videos",
|
"assets/videos",
|
||||||
]
|
]
|
||||||
|
logging.info("Creating missing directories")
|
||||||
for directory in paths:
|
for directory in paths:
|
||||||
if not path.isdir(self.output + directory):
|
if not path.isdir(self.output + directory):
|
||||||
|
logging.info(f"Creating directory {directory}")
|
||||||
os.mkdir(self.output + directory)
|
os.mkdir(self.output + directory)
|
||||||
|
|
||||||
# Render episodes and copy data
|
logging.info("Render episodes and copy data")
|
||||||
for episode in self.data:
|
for episode in self.data:
|
||||||
|
logging.info(f"Rendering episode {episode}")
|
||||||
html = f"{self.output}{gen_name(episode.date, episode.slug)}.html"
|
html = f"{self.output}{gen_name(episode.date, episode.slug)}.html"
|
||||||
thumbnail = ("assets/thumbnails/" +
|
thumbnail = ("assets/thumbnails/" +
|
||||||
gen_name(episode.date, episode.slug) + ".jpg")
|
gen_name(episode.date, episode.slug) + ".jpg")
|
||||||
|
@ -164,14 +175,19 @@ class EpisodeList(UserList):
|
||||||
gen_name(episode.date, episode.slug) + ".mp4")
|
gen_name(episode.date, episode.slug) + ".mp4")
|
||||||
audio = (self.output + "assets/audio/" +
|
audio = (self.output + "assets/audio/" +
|
||||||
gen_name(episode.date, episode.slug) + ".mp3")
|
gen_name(episode.date, episode.slug) + ".mp3")
|
||||||
|
logging.info(f"Copying {episode.video} to {video}")
|
||||||
shutil.copy2(episode.video, video)
|
shutil.copy2(episode.video, video)
|
||||||
|
logging.info(f"Copying {episode.audio}.mp3 to {audio}")
|
||||||
shutil.copy2(episode.audio + ".mp3", audio)
|
shutil.copy2(episode.audio + ".mp3", audio)
|
||||||
|
logging.info(f"Copying {episode.audio}.ogg to {audio}")
|
||||||
shutil.copy2(episode.audio + ".ogg", audio)
|
shutil.copy2(episode.audio + ".ogg", audio)
|
||||||
|
logging.info(f"Writing to {html}")
|
||||||
with open(html, "w") as file:
|
with open(html, "w") as file:
|
||||||
file.write(episode.render(self.template, thumbnail))
|
file.write(episode.render(self.template, thumbnail))
|
||||||
|
|
||||||
last = self.data[-1]
|
last = self.data[-1]
|
||||||
last_name = f"{self.output}{gen_name(last.date, last.slug)}.html"
|
last_name = f"{self.output}{gen_name(last.date, last.slug)}.html"
|
||||||
|
logging.info(f"Copying last one ({last}) to index.html")
|
||||||
shutil.copy2(last_name, self.output + "index.html")
|
shutil.copy2(last_name, self.output + "index.html")
|
||||||
|
|
||||||
|
|
||||||
|
@ -186,6 +202,8 @@ class Episode:
|
||||||
self.audio = audio_src
|
self.audio = audio_src
|
||||||
self.config = config
|
self.config = config
|
||||||
self.length = MP3(audio_src + ".mp3").info.length
|
self.length = MP3(audio_src + ".mp3").info.length
|
||||||
|
logging.info(f"New episode: {date=} {slug=} {title=} {self.video=} "
|
||||||
|
f"{self.audio=} {config=} {self.length=} {self.show_notes=}")
|
||||||
|
|
||||||
def render(self, template, thumbnail_src):
|
def render(self, template, thumbnail_src):
|
||||||
"Renders the Episode with the given template"
|
"Renders the Episode with the given template"
|
||||||
|
@ -200,11 +218,17 @@ class Episode:
|
||||||
"Stores the thumbnail for given image at path"
|
"Stores the thumbnail for given image at path"
|
||||||
args = ["ffmpeg", "-i", self.video, "-ss", "00:00:01.000", "-vframes",
|
args = ["ffmpeg", "-i", self.video, "-ss", "00:00:01.000", "-vframes",
|
||||||
"1", location]
|
"1", location]
|
||||||
|
logging.info(f"Running {' '.join(args)}")
|
||||||
subprocess.run(args, check=False)
|
subprocess.run(args, check=False)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return int(self.length)
|
return int(self.length)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.slug}: {self.title}"
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self)
|
||||||
|
|
||||||
def parse_args():
|
def parse_args():
|
||||||
"Parses arguments"
|
"Parses arguments"
|
||||||
|
@ -212,9 +236,14 @@ def parse_args():
|
||||||
parser.add_argument("input_dir", help="Input directory")
|
parser.add_argument("input_dir", help="Input directory")
|
||||||
parser.add_argument("output_dir", help="Output directory")
|
parser.add_argument("output_dir", help="Output directory")
|
||||||
parser.add_argument("url", help="Base URL of website")
|
parser.add_argument("url", help="Base URL of website")
|
||||||
|
parser.add_argument("--verbose", "-v", action="store_true", help="Verbose Logging")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
input_dir = path.abspath(args.input_dir.rstrip("/")) + "/"
|
input_dir = path.abspath(args.input_dir.rstrip("/")) + "/"
|
||||||
output_dir = path.abspath(args.output_dir.rstrip("/")) + "/"
|
output_dir = path.abspath(args.output_dir.rstrip("/")) + "/"
|
||||||
|
if args.verbose:
|
||||||
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
else:
|
||||||
|
logging.basicConfig()
|
||||||
url = args.url.rstrip("/") + "/"
|
url = args.url.rstrip("/") + "/"
|
||||||
return input_dir, output_dir, url
|
return input_dir, output_dir, url
|
||||||
|
|
||||||
|
@ -248,6 +277,9 @@ def main(args):
|
||||||
"Main method"
|
"Main method"
|
||||||
root = path.dirname(sys.argv[0]).rstrip("/") + "/"
|
root = path.dirname(sys.argv[0]).rstrip("/") + "/"
|
||||||
input_dir, output_dir, url = args
|
input_dir, output_dir, url = args
|
||||||
|
logging.info(f"Input directory: {input_dir}")
|
||||||
|
logging.info(f"Output directory: {output_dir}")
|
||||||
|
logging.info(f"URL: {url}")
|
||||||
|
|
||||||
# Input validation
|
# Input validation
|
||||||
paths = [
|
paths = [
|
||||||
|
@ -256,10 +288,12 @@ def main(args):
|
||||||
input_dir + "videos",
|
input_dir + "videos",
|
||||||
input_dir + "audio",
|
input_dir + "audio",
|
||||||
]
|
]
|
||||||
|
logging.info("Checking if all paths exist.")
|
||||||
if not all(path.isdir((fail := i)) for i in paths):
|
if not all(path.isdir((fail := i)) for i in paths):
|
||||||
print(f"Invalid Input. {fail} is not a directory.", file=sys.stderr)
|
logging.error(f"Invalid Input. {fail} is not a directory.")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
logging.info("Creating output directory if it doesn't exist")
|
||||||
if not path.isdir(output_dir):
|
if not path.isdir(output_dir):
|
||||||
os.mkdir(output_dir)
|
os.mkdir(output_dir)
|
||||||
|
|
||||||
|
@ -268,6 +302,7 @@ def main(args):
|
||||||
autoescape=jinja2.select_autoescape("html")
|
autoescape=jinja2.select_autoescape("html")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logging.info("Creating EpisodeList")
|
||||||
podcast = EpisodeList(
|
podcast = EpisodeList(
|
||||||
url,
|
url,
|
||||||
[],
|
[],
|
||||||
|
@ -277,20 +312,28 @@ def main(args):
|
||||||
)
|
)
|
||||||
|
|
||||||
split = re.compile(r"((?P<date>\d{4}-[01]?\d-[0123]?\d)-(?P<slug>.*).md)")
|
split = re.compile(r"((?P<date>\d{4}-[01]?\d-[0123]?\d)-(?P<slug>.*).md)")
|
||||||
|
logging.info(f"Parsing all files in {input_dir}md")
|
||||||
for file in os.listdir(input_dir + "md"):
|
for file in os.listdir(input_dir + "md"):
|
||||||
|
logging.info(f"File: {file}")
|
||||||
match = split.match(file)
|
match = split.match(file)
|
||||||
|
logging.info(f"Match: {match}")
|
||||||
if not match:
|
if not match:
|
||||||
print(f"Invalid filename: {file}", file=sys.stderr)
|
logging.error(f"Invalid filename: {file}")
|
||||||
continue
|
continue
|
||||||
date = datetime.strptime(match.group("date"), "%Y-%M-%d")
|
date = datetime.strptime(match.group("date"), "%Y-%m-%d")
|
||||||
|
logging.info(f"Date: {date}")
|
||||||
slug = match.group("slug")
|
slug = match.group("slug")
|
||||||
|
logging.info(f"Slug: {slug}")
|
||||||
with open(input_dir + "md/" + file) as episode:
|
with open(input_dir + "md/" + file) as episode:
|
||||||
try:
|
try:
|
||||||
config, show_notes = parse_file(episode)
|
config, show_notes = parse_file(episode)
|
||||||
|
logging.info(f"Config: {config}")
|
||||||
|
logging.info(f"Show Notes: {show_notes}")
|
||||||
except ParseError as err:
|
except ParseError as err:
|
||||||
print(f"Error while parsing file: {file}")
|
logging.error(f"Error while parsing file: {file}")
|
||||||
print(err)
|
logging.error(err)
|
||||||
return 2
|
return 2
|
||||||
|
logging.info("Appending to EpisodeList")
|
||||||
podcast.append(
|
podcast.append(
|
||||||
Episode(
|
Episode(
|
||||||
date,
|
date,
|
||||||
|
@ -303,25 +346,34 @@ def main(args):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
logging.info("Generating subscribe page")
|
||||||
with open(input_dir + "subscribe.json") as subscribe, \
|
with open(input_dir + "subscribe.json") as subscribe, \
|
||||||
open(output_dir + "subscribe.html", "w") as html:
|
open(output_dir + "subscribe.html", "w") as html:
|
||||||
html.write(env.get_template("subscribe.html").render(
|
html.write(env.get_template("subscribe.html").render(
|
||||||
subscribtions=json.load(subscribe)
|
subscribtions=json.load(subscribe)
|
||||||
))
|
))
|
||||||
|
|
||||||
|
logging.info("Generating donate page")
|
||||||
with open(input_dir + "donate.json") as donate, \
|
with open(input_dir + "donate.json") as donate, \
|
||||||
open(output_dir + "donate.html", "w") as html:
|
open(output_dir + "donate.html", "w") as html:
|
||||||
html.write(env.get_template("donate.html").render(
|
html.write(env.get_template("donate.html").render(
|
||||||
donations=json.load(donate)
|
donations=json.load(donate)
|
||||||
))
|
))
|
||||||
|
|
||||||
|
logging.info("Sorting podcasts")
|
||||||
podcast.sort()
|
podcast.sort()
|
||||||
|
logging.info("Generating thumbnails")
|
||||||
podcast.generate_thumbnails()
|
podcast.generate_thumbnails()
|
||||||
|
logging.info("Generating archives pages")
|
||||||
podcast.generate_archives()
|
podcast.generate_archives()
|
||||||
|
logging.info("Generating RSS feeds")
|
||||||
with open(input_dir + "header.rss") as header:
|
with open(input_dir + "header.rss") as header:
|
||||||
podcast.generate_rss(header.read())
|
podcast.generate_rss(header.read())
|
||||||
|
logging.info("Generating Site")
|
||||||
podcast.generate_site(root)
|
podcast.generate_site(root)
|
||||||
|
logging.info("Copying Overrides")
|
||||||
shutil.copytree(input_dir + "overrides", output_dir, dirs_exist_ok=True)
|
shutil.copytree(input_dir + "overrides", output_dir, dirs_exist_ok=True)
|
||||||
|
logging.info("Done")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue