Full rewrite

This commit is contained in:
Hadi
2026-08-14 11:14:54 +02:00
parent 22570eb657
commit deda1a9868
510 changed files with 1191 additions and 12242 deletions
+62
View File
@@ -0,0 +1,62 @@
#!/usr/bin/env bash
# Validate wallpaper filenames against the naming convention described in README.md:
# wallpaper-name_tag1_tag2.png
# - name: lowercase letters/digits, words separated by "-"
# - tags: lowercase letters, words separated by "-", tags separated by "_"
# - only .png and .gif are accepted
# - gifs must carry the "animated" tag
# - every gif must have a same-named .png counterpart
set -uo pipefail
wallpapers_dir="wallpapers"
name_re='^[a-z0-9]+(-[a-z0-9]+)*(_[a-z]+(-[a-z]+)*)*$'
status=0
if [[ ! -d "$wallpapers_dir" ]]; then
echo "No $wallpapers_dir directory found, skipping."
exit 0
fi
shopt -s nullglob
for file in "$wallpapers_dir"/*; do
[[ -f "$file" ]] || continue
filename=$(basename "$file")
basename="${filename%.*}"
ext="${filename##*.}"
if [[ "$ext" != "png" && "$ext" != "gif" ]]; then
echo "❌ $filename: only .png and .gif files are accepted"
status=1
continue
fi
if [[ ! "$basename" =~ $name_re ]]; then
echo "❌ $filename: invalid name/tags, expected wallpaper-name_tag1_tag2 (lowercase, '-' separated words, '_' separated tags)"
status=1
continue
fi
if [[ "$ext" == "gif" ]]; then
IFS='_' read -r -a parts <<<"$basename"
has_animated=0
for tag in "${parts[@]:1}"; do
[[ "$tag" == "animated" ]] && has_animated=1
done
if [[ "$has_animated" -eq 0 ]]; then
echo "❌ $filename: gif files must include the 'animated' tag"
status=1
fi
if [[ ! -f "$wallpapers_dir/$basename.png" ]]; then
echo "❌ $filename: missing matching static $basename.png"
status=1
fi
fi
done
if [[ "$status" -eq 0 ]]; then
echo "✅ All wallpaper filenames are valid."
fi
exit "$status"
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/env bash
# Losslessly compress wallpapers before they are committed, so the repo
# doesn't grow larger than it needs to. Only files staged in this commit
# are touched, to keep the hook fast.
set -uo pipefail
wallpapers_dir="wallpapers"
changed=0
if [[ ! -d "$wallpapers_dir" ]]; then
exit 0
fi
if ! command -v oxipng >/dev/null 2>&1; then
echo "❌ oxipng is required but was not found in PATH"
exit 1
fi
if ! command -v gifsicle >/dev/null 2>&1; then
echo "❌ gifsicle is required but was not found in PATH"
exit 1
fi
mapfile -t staged < <(git diff --cached --name-only --diff-filter=ACM -- "$wallpapers_dir")
for file in "${staged[@]}"; do
[[ -f "$file" ]] || continue
ext="${file##*.}"
before=$(stat -c%s "$file")
case "$ext" in
png)
oxipng -o max --strip safe -q "$file" >/dev/null
;;
gif)
gifsicle -O3 --batch "$file"
;;
*)
continue
;;
esac
after=$(stat -c%s "$file")
if [[ "$after" -ne "$before" ]]; then
echo "Compressed $file ($before -> $after bytes)"
git add "$file"
changed=1
fi
done
if [[ "$changed" -eq 1 ]]; then
echo "Image(s) were compressed and re-staged, please commit again."
exit 1
fi
exit 0
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env bash
# Every gif in wallpapers/ must have a same-named static .png counterpart
# (see README.md). This hook generates the missing ones from the gif's
# first frame and stages them, so a commit adding a gif automatically
# gets its png alongside it.
set -uo pipefail
wallpapers_dir="wallpapers"
changed=0
if [[ ! -d "$wallpapers_dir" ]]; then
exit 0
fi
if ! command -v magick >/dev/null 2>&1; then
echo "❌ imagemagick (magick) is required but was not found in PATH"
exit 1
fi
shopt -s nullglob
for gif in "$wallpapers_dir"/*.gif; do
basename="${gif%.gif}"
png="$basename.png"
if [[ -f "$png" ]]; then
continue
fi
echo "Generating $png from $(basename "$gif")"
if ! magick "${gif}[0]" "$png"; then
echo "❌ Failed to generate $png"
exit 1
fi
git add "$png"
changed=1
done
if [[ "$changed" -eq 1 ]]; then
echo "New static png(s) were generated and staged, please commit again."
exit 1
fi
exit 0
+218
View File
@@ -0,0 +1,218 @@
#!/usr/bin/env bash
# Regenerate WALLPAPERS.md (and its 2/3-column variants, and tags/*.md)
# from the contents of wallpapers/.
# When a wallpaper has both a static png and an animated gif (same
# basename), only one row is emitted, previewed with the gif.
set -uo pipefail
wallpapers_dir="wallpapers"
tags_dir="tags"
if [[ ! -d "$wallpapers_dir" ]]; then
exit 0
fi
# Each entry: name<TAB>basename<TAB>preview<TAB>raw_tags(underscore-joined)
build_entries() {
shopt -s nullglob
declare -A seen
for file in "$wallpapers_dir"/*.png "$wallpapers_dir"/*.gif; do
filename=$(basename "$file")
base="${filename%.*}"
[[ -n "${seen[$base]:-}" ]] && continue
seen[$base]=1
preview="$file"
if [[ -f "$wallpapers_dir/$base.gif" ]]; then
preview="$wallpapers_dir/$base.gif"
fi
name="${base%%_*}"
tags=""
if [[ "$base" == *_* ]]; then
tags="${base#*_}"
fi
printf '%s\t%s\t%s\t%s\n' "$name" "$base" "$preview" "$tags"
done | sort -t $'\t' -k1,1
}
mapfile -t entries < <(build_entries)
# Collect the sorted, de-duplicated list of tags, and which entries have them.
declare -A tag_seen
all_tags=()
for entry in "${entries[@]}"; do
IFS=$'\t' read -r _ _ _ tags_raw <<<"$entry"
[[ -z "$tags_raw" ]] && continue
IFS='_' read -ra tokens <<<"$tags_raw"
for t in "${tokens[@]}"; do
if [[ -z "${tag_seen[$t]:-}" ]]; then
tag_seen[$t]=1
all_tags+=("$t")
fi
done
done
mapfile -t sorted_tags < <(printf '%s\n' "${all_tags[@]}" | sort)
entry_has_tag() {
local tags_raw="$1" tag="$2" t
IFS='_' read -ra tokens <<<"$tags_raw"
for t in "${tokens[@]}"; do
[[ "$t" == "$tag" ]] && return 0
done
return 1
}
# tags_links <raw_tags> <tag-link-prefix>
# Turns "foo_bar-baz" into "[foo](<prefix>foo.md), [bar-baz](<prefix>bar-baz.md)"
tags_links() {
local tags_raw="$1" tag_prefix="$2"
[[ -z "$tags_raw" ]] && return
local -a tokens
IFS='_' read -ra tokens <<<"$tags_raw"
local out="" t first=1
for t in "${tokens[@]}"; do
((first)) || out+=", "
first=0
out+="[${t}](${tag_prefix}${t}.md)"
done
printf '%s' "$out"
}
# render_table <cols> <preview-prefix> <tag-link-prefix> <entries...>
render_table() {
local cols="$1" prefix="$2" tag_prefix="$3"
shift 3
local -a items=("$@")
local header="|" sep="|"
local i
for ((i = 0; i < cols; i++)); do
header+=" Preview | Name | Tags |"
sep+="---------|------|------|"
done
echo "$header"
echo "$sep"
local total=${#items[@]}
local idx=0
while ((idx < total)); do
local line="|"
local c
for ((c = 0; c < cols; c++)); do
if ((idx < total)); then
local name base preview tags_raw tags_display
IFS=$'\t' read -r name base preview tags_raw <<<"${items[idx]}"
tags_display="$(tags_links "$tags_raw" "$tag_prefix")"
line+=" ![${base}](${prefix}${preview}) | ${name} | ${tags_display} |"
((idx++))
else
line+=" | | |"
fi
done
echo "$line"
done
}
# render_grid <cols> <preview-prefix> <tag-link-prefix> <entries...>
# Like render_table, but each cell stacks the image with its name and
# tags underneath instead of using separate Name/Tags columns.
render_grid() {
local cols="$1" prefix="$2" tag_prefix="$3"
shift 3
local -a items=("$@")
local header="|" sep="|"
local i
for ((i = 0; i < cols; i++)); do
header+=" |"
sep+=":---:|"
done
echo "$header"
echo "$sep"
local total=${#items[@]}
local idx=0
while ((idx < total)); do
local line="|"
local c
for ((c = 0; c < cols; c++)); do
if ((idx < total)); then
local name base preview tags_raw tags_display cell
IFS=$'\t' read -r name base preview tags_raw <<<"${items[idx]}"
tags_display="$(tags_links "$tags_raw" "$tag_prefix")"
cell="![${base}](${prefix}${preview})<br>${name}"
[[ -n "$tags_display" ]] && cell+="<br>${tags_display}"
line+=" ${cell} |"
((idx++))
else
line+=" |"
fi
done
echo "$line"
done
}
nav_block() {
echo "[1 Column](WALLPAPERS.md) · [2 Columns](WALLPAPERS-2COL.md) · [3 Columns](WALLPAPERS-3COL.md)"
}
tags_block() {
local prefix="$1"
echo "<details>"
echo "<summary>Tags</summary>"
echo
local t
for t in "${sorted_tags[@]}"; do
echo "- [${t}](${prefix}${tags_dir}/${t}.md)"
done
echo
echo "</details>"
}
generate_main() {
local file="$1" cols="$2"
{
echo "# Wallpapers"
echo
nav_block
echo
tags_block ""
echo
if ((cols > 1)); then
render_grid "$cols" "" "${tags_dir}/" "${entries[@]}"
else
render_table "$cols" "" "${tags_dir}/" "${entries[@]}"
fi
} >"$file"
git add "$file"
}
generate_main "WALLPAPERS.md" 1
generate_main "WALLPAPERS-2COL.md" 2
generate_main "WALLPAPERS-3COL.md" 3
rm -rf "$tags_dir"
mkdir -p "$tags_dir"
for t in "${sorted_tags[@]}"; do
tag_items=()
for entry in "${entries[@]}"; do
IFS=$'\t' read -r _ _ _ tags_raw <<<"$entry"
if entry_has_tag "$tags_raw" "$t"; then
tag_items+=("$entry")
fi
done
{
echo "# Tag: ${t}"
echo
echo "[← All wallpapers](../WALLPAPERS.md)"
echo
render_table 1 "../" "" "${tag_items[@]}"
} >"$tags_dir/$t.md"
done
git add "$tags_dir"
echo "Generated WALLPAPERS.md, WALLPAPERS-2COL.md, WALLPAPERS-3COL.md and $tags_dir/"