blob: 1e0170d1bffc5fe2431b6b91ed04db23446b2cfe (
plain) (
tree)
|
|
#!/usr/bin/env bash
set -Eeuo pipefail
end="\033[0m"
red="\033[0;31m"
yellow="\033[0;33m"
red() { echo -e "${red}${1}${end}"; }
yellow() { echo -e "${yellow}${1}${end}"; }
TRACKERS='-a udp://tracker.coppersurfer.tk:6969/announce -a udp://tracker.ccc.de:80/announce -a udp://tracker.publicbt.com:80 -a udp://tracker.istole.it:80 -a http://tracker.openbittorrent.com:80/announce -a http://tracker.ipv6tracker.org:80/announce'
# shellcheck disable=2016
AWK_S='
BEGIN {
FRONTMATTER=0
}
/^---$/ {
FRONTMATTER=!FRONTMATTER;
getline; # strip empty line below end of frontmatter
next;
}
FRONTMATTER==0 {
print $0;
}
'
## Constant definitions
jekyll build --future
JSON='_site/site.json'
LANGS=(en pt fr eo) # jp zh es de
IGNORED_PAGES=(site.json sitemap.xml)
## Helper function definitions
slugify() {
echo "${1}" | \
tr '[:upper:]' '[:lower:]' | \
perl -ne 'tr/\000-\177//cd;
s|/|-|g;
s/[^\w\s-.]//g;
s/^\s+|\s+$//g;
s/[-\s.]+/-/g;
print;'
}
contains-element() {
local e match="$1"
shift
for e; do [[ "$e" == "$match" ]] && return 0; done
return 1
}
fail-attr() {
ATTRIBUTE="${1}"
URL="${2}"
red "Undefined '${ATTRIBUTE}' for ${URL}." >&2
exit 1
}
get-lang() {
echo "${1}" | base64 --decode | jq -r .lang
}
get-url() {
# Remove leading / to match more closely the filesystem hierarchy
echo "${1}" | base64 --decode | jq -r .url | sed 's_^/__'
}
get-date() {
echo "${1}" | base64 --decode | jq -r .date | awk '{print $1}'
}
get-x() {
echo "${2}" | base64 --decode | jq -r ".$1"
}
is-ignored() {
URL="$1"
EXTENSION="${URL##*.}"
if contains-element "${URL}" "${IGNORED_PAGES[@]}" || [[ "$EXTENSION" == 'atom' ]]; then
return 0
else
return 1
fi
}
## Assertions
assert-frontmatter() {
F="$1"
DESIRED_LAYOUT="$2"
PREFIX="${3:-}"
EXTENSION="${4:-md}"
LLANG="$(get-lang "$F")"
REF="$(get-x ref "$F")"
URL="$(get-url "$F")"
LAYOUT="$(get-x layout "$F")"
TITLE="$(get-x title "$F")"
[[ -z "${LLANG}" ]] && fail-attr 'lang' "${URL}"
[[ -z "${REF}" ]] && fail-attr 'ref' "${URL}"
[[ -z "${TITLE}" ]] && fail-attr 'title' "${URL}"
if ! contains-element "${LLANG}" "${LANGS[@]}"; then
red "Invalid lang '${LLANG}' in ${URL}." >&2
exit 1
fi
if [[ "${DESIRED_LAYOUT}" != "${LAYOUT}" ]]; then
red "Layout mismatch: expected '${DESIRED_LAYOUT}', got '${LAYOUT}'."
red "Page: ${URL}."
exit 1
fi
if [[ "$PREFIX" = '_podcasts/' ]]; then
AUDIO="$(get-x audio "$F")"
SLUG="$(get-x slug "$F")"
[[ -z "$AUDIO" ]] && fail-attr 'audio' "${URL}"
[[ -z "$SLUG" ]] && fail-attr 'slug' "${URL}"
TITLE_SLUG="$(slugify "$TITLE")"
if [[ "$SLUG" != "$TITLE_SLUG" ]]; then
red "slug and title don't match."
red "slug: '$SLUG'"
red "title slug: '$TITLE_SLUG'"
exit 1
fi
for audiofmt in flac ogg; do
DATE="$(get-date "$F")"
URL_BASENAME="$(basename "$(get-url "$F")")"
AUDIO="resources/podcasts/${DATE}-${SLUG}.$audiofmt"
if [[ ! -f "$AUDIO" ]]; then
red "Missing audio file '$AUDIO'."
exit 1
fi
done
OGG="resources/podcasts/$DATE-$SLUG.ogg"
TORRENT="$OGG.torrent"
WEBSEED="https://euandre.org/$OGG"
if [ ! -f "$TORRENT" ]; then
yellow "Missing torrent $TORRENT, generating..."
NOTES="$(awk "$AWK_S" "_podcasts/$DATE-$SLUG.md")"
# shellcheck disable=2086
mktorrent $TRACKERS \
-f \
-v \
-d \
-c "$NOTES" \
-n "$TITLE.ogg" \
-w "$WEBSEED" \
-o "$TORRENT" \
"$OGG"
fi
fi
if [[ "$PREFIX" = '_screencasts/' ]]; then
VIDEO="$(get-x video "$F")"
SLUG="$(get-x slug "$F")"
[[ -z "$VIDEO" ]] && fail-attr 'video' "${URL}"
[[ -z "$SLUG" ]] && fail-attr 'slug' "${URL}"
TITLE_SLUG="$(slugify "$TITLE")"
if [[ "$SLUG" != "$TITLE_SLUG" ]]; then
red "slug and title don't match."
red "slug: '$SLUG'"
red "title slug: '$TITLE_SLUG'"
exit 1
fi
DATE="$(get-date "$F")"
URL_BASENAME="$(basename "$(get-url "$F")")"
VIDEO="resources/screencasts/${DATE}-${SLUG}.webm"
if [[ ! -f "$VIDEO" ]]; then
red "Missing video file '$VIDEO'."
exit 1
fi
WEBM="resources/screencasts/$DATE-$SLUG.webm"
TORRENT="$WEBM.torrent"
WEBSEED="https://euandre.org/$WEBM"
if [ ! -f "$TORRENT" ]; then
yellow "Missing torrent $TORRENT, generating..."
NOTES="$(awk "$AWK_S" "_screencasts/$DATE-$SLUG.md")"
# shellcheck disable=2086
mktorrent $TRACKERS \
-f \
-v \
-d \
-c "$NOTES" \
-n "$TITLE.webm" \
-w "$WEBSEED" \
-o "$TORRENT" \
"$WEBM"
fi
fi
if [[ "$DESIRED_LAYOUT" != 'page' ]]; then
DATE="$(get-date "$F")"
URL_BASENAME="$(basename "$(get-url "$F")")"
FILE="${PREFIX}${DATE}-${URL_BASENAME%.html}.${EXTENSION}"
[[ -f "${FILE}" ]] || {
red "date/filename mismatch: '${FILE}' does not exist."
exit 1
}
if [[ "$LLANG" = 'en' ]]; then
TITLE_SLUG="$(slugify "$TITLE")"
if [[ "$TITLE_SLUG" != "$REF" ]]; then
red "ref isn't the slug of the title."
red "ref: '$REF'"
red "title slug: '$TITLE_SLUG'"
exit 1
fi
DESIRED_FILE="${PREFIX}${DATE}-${TITLE_SLUG}.${EXTENSION}"
if [[ ! -f "$DESIRED_FILE" ]]; then
red "File can't be guessed from date+slug: '$DESIRED_FILE' does not exist"
exit 1
fi
fi
fi
}
echo Linting pages... >&2
for page in $(jq -r '.pages[] | @base64' "${JSON}"); do
URL="$(get-url "$page")"
if ! is-ignored "${URL}"; then
assert-frontmatter "${page}" 'page'
fi
done
echo Linting articles... >&2
for article in $(jq -r '.articles[] | @base64' "${JSON}"); do
assert-frontmatter "$article" 'post' '_articles/'
done
echo Linting pastebins... >&2
for pastebin in $(jq -r '.pastebins[] | @base64' "${JSON}"); do
assert-frontmatter "$pastebin" 'post' '_pastebins/'
done
echo Linting tils... >&2
for til in $(jq -r '.tils[] | @base64' "${JSON}"); do
assert-frontmatter "$til" 'post' '_tils/'
done
echo Linting slides... >&2
for slide in $(jq -r '.slides[] | @base64' "${JSON}"); do
assert-frontmatter "$slide" 'slides' '_slides/' 'slides'
done
echo Linting podcasts... >&2
for podcast in $(jq -r '.podcasts[] | @base64' "${JSON}"); do
assert-frontmatter "$podcast" 'cast' '_podcasts/'
done
echo Linting screencasts... >&2
for screencast in $(jq -r '.screencasts[] | @base64' "${JSON}"); do
assert-frontmatter "$screencast" 'cast' '_screencasts/'
done
echo Asserting unique refs... >&2
KNOWN_IDS=()
assert-unique-ref() {
TYPE="$2"
for page in $1; do
URL="$(get-url "$page")"
if ! is-ignored "${URL}"; then
LLANG="$(get-lang "$page")"
REF="$(get-x ref "$page")"
ID="${TYPE}:${LLANG}:${REF}"
if contains-element "${ID}" "${KNOWN_IDS[@]}"; then
printf '%s\n' "${KNOWN_IDS[@]}"
red "Duplicated lang:ref match: '${ID}'." >&2
red "Page: ${URL}." >&2
exit 1
fi
KNOWN_IDS+=("${ID}") # printf '%s\n' "${KNOWN_IDS[@]}"
fi
done
}
assert-unique-ref "$(jq -r '.pages[] | @base64' "${JSON}")" 'page'
assert-unique-ref "$(jq -r '.articles[] | @base64' "${JSON}")" 'article'
assert-unique-ref "$(jq -r '.tils[] | @base64' "${JSON}")" 'til'
assert-unique-ref "$(jq -r '.pastebins[] | @base64' "${JSON}")" 'pastebin'
assert-unique-ref "$(jq -r '.slides[] | @base64' "${JSON}")" 'slides'
assert-unique-ref "$(jq -r '.podcasts[] | @base64' "${JSON}")" 'podcasts'
assert-unique-ref "$(jq -r '.screencasts[] | @base64' "${JSON}")" 'screencasts'
echo Done. >&2
|