#!/usr/bin/env bash # Copyright: Julien Moutinho # License: AGPL-3.0-or-later # Usage: # $ mv julm/2023/src/02/IMG_20230228_111645{,.fav}.jpg # $ echo >julm/2023/src/02/IMG_20230228_111645.fav.txt "Some HTML comment about the picture" # $ ./index.sh julm/2023/src/02 # $ sensible-browser julm/2023/fav/02/index.html # # NginxConfig: # locations."/julm/perso/camera/" = { # alias = "${root}/julm/perso/camera/"; # basicAuthFile = "/run/credentials/nginx.service/autogeree.net.www.julm.perso.camera.htpasswd"; # }; # # Disable basicAuthFile for by-uuid # locations."~ ^/julm/perso/camera/([0-9]+/[0-9][0-9]/by-uuid/[0-9a-f-]+/.+)$" = { # alias = "${root}/julm/perso/camera/$1"; # }; # shellcheck disable=SC2086 cd "${0%/*}" set -eu shopt -s nullglob ffmpeg_ () { local -; set -x; nice -19 ffmpeg &2 "$@"; } for dir in "$@"; do IFS=/ read -r user year x month x <<<"$dir" test -n "$month" || exec "$0" "$user"/"$year"/src/*/ pushd "$user/$year" >/dev/null test -d src || { popd; continue; } mkdir -p fav # cp, not ln, because in push.sh --copy-links cannot be used for by-uuid/ cp -f --remove-destination -t fav ../../index.css test -d src/"$month" || { popd; continue; } mkdir -p fav/"$month" mkdir -p {tmp,wip}/fav/"$month" { genDate=$(date +%s) cat < camera/$user/$year/$month
    EOF echo >&2 "$dir: processing favorites in chronological order" # Time is encoded in filenames like so: MM/{IMG,VID}_YYYYMMDD_hhmmss.* # hence sorting after the underscore (2nd field, 5th char). (cd src; find "$month" -name '*.fav.*' -not -name "*.txt") | sort -n -t/ -k2.5 | while read -r src; do echo >&2 "$dir: processing $year/src/$src" base=${src%.*} name=${base##*/} id=${name%%.*} creationDate=$(printf %s "${src##*/???_}" | sed -e 's/\(....\)\(..\)\(..\)_\(..\)\(..\)\(..\).*/\1-\2-\3 \4:\5:\6/') echo "
  • " test -e fav/"$base".uuid || uuidgen --random >fav/"$base".uuid uuid=$(cat fav/"$base".uuid) mkdir -p fav/"$month"/by-uuid/"$uuid" case "$src" in *.jpg) echo "" printf "" w=600 test fav/"$base"."$w"x.avif -nt src/"$src" || { magick_ -define jpeg:size=$((w * 2))x src/"$src" \ -sampling-factor 4:2:0 -interlace JPEG -colorspace sRGB \ -auto-orient -thumbnail "$w"x -unsharp 0x.5 \ wip/fav/"$base"."$w"x.jpg mv_ {wip/,}fav/"$base"."$w"x.avif } echo "" echo "$creationDate" echo "" dst="$name".1200x.avif ln -fs -t fav/"$month"/by-uuid/"$uuid" ../../"$dst" ;; *.mp4) test fav/"$base".avif -nt src/"$src" || { ffmpeg_ -i src/"$src" \ -map 0:v \ -filter:v format=yuv420p,scale='trunc(oh*a/2)*2:360' \ -frames:v 1 -crf 40 \ wip/fav/"$base".avif mv_ {wip/,}fav/"$base".avif } need_opus () { test tmp/fav/"$base".opus -nt src/"$src" || { ffmpeg_ -i src/"$src" \ -map 0:a -c:a libopus -b:a 64k -application voip \ wip/fav/"$base".opus mv_ {wip,tmp}/fav/"$base".opus } } test fav/"$base".360p.av1.webm -nt src/"$src" || { need_opus ffmpeg_ -i src/"$src" -i tmp/fav/"$base".opus \ -map 0:v \ -filter:v format=yuv420p,scale='trunc(oh*a/2)*2:360' \ -c:v libsvtav1 -crf 40 -g 120 \ -map 1:a -c:a copy \ wip/fav/"$base".360p.av1.webm mv_ {wip/,}fav/"$base".360p.av1.webm } dst="$name".360p.av1.webm ln -fs -t fav/"$month"/by-uuid/"$uuid" ../../"$dst" #test fav/"$base".360p.vp9.webm -nt src/"$src" || { # need_opus # # See https://developers.google.com/media/vp9/settings/vod#recommended_settings # # See https://gist.github.com/mrintrepide/3033c35ee9557e66cff7806f48dbd339 # set -- \ # -filter:v format=yuv420p,scale='trunc(oh*a/2)*2:360' \ # -c:v libvpx-vp9 -quality good -crf 20 \ # -minrate 138k -b:v 276k -maxrate 400k \ # -cpu-used 4 -static-thresh 0 -tile-columns 0 -tile-rows 0 -frame-parallel 0 \ # -row-mt 1 -aq-mode 0 -auto-alt-ref 6 -lag-in-frames 25 -enable-tpl 1 # test -e tmp/fav/"$base".360p.vp9.webm-0.log || { # # FIXME: how to disable h264 debug log? # ffmpeg 2>/dev/null -i src/"$src" \ # -map 0:v "$@" -pass 1 -passlogfile wip/fav/"$base".360p.vp9.webm \ # -f null \ # /dev/null # mv_ -t tmp/fav/"${base%/*}" wip/fav/"$base".360p.vp9.webm-*.log # } # ffmpeg -i src/"$src" -i tmp/fav/"$base".opus \ # -map 0:v "$@" -pass 2 -passlogfile tmp/fav/"$base".360p.vp9.webm \ # -map 1:a -c:a copy \ # wip/fav/"$base".360p.vp9.webm # mkdir -p fav/"$month"/by-uuid/"$uuid" # mv_ wip/fav/"$base".360p.vp9.webm fav/"$base".360p.vp9.webm # rm -fv tmp/fav/"$base".360p.vp9.webm-*.log #} #test fav/"$base".mp4 -nt src/"$src" || { # ffmpeg -i src/"$src" \ # -filter:v format=yuv420p \ # -c:v libx264 -preset medium -crf 22 \ # -tune zerolatency \ # -maxrate 1M -bufsize 2M \ # -movflags use_metadata_tags +faststart \ # -c:a libopus -base:a 64k -application voip \ # -filter:v "scale=iw/2:ih/2" \ # wip/fav/"$base".mp4 # mv_ wip/fav/"$base".mp4 fav/"$base".mp4 #} #orient=$(ffprobe -v 0 -select_streams v:0 -show_entries stream_side_data=rotation -of default=nw=1:nk=1 src/"$src") # class='orient$orient' echo "" esac touch -a src/"$base".txt printf %s "" sed -e '$q;s/$/
    \n/' src/"$base".txt echo "
    " echo "
    " echo "" echo " $creationDate" echo "" echo "" echo " @" echo " #" echo "" echo "
  • " echo done cat <
EOF } >tmp/fav/"$month"/index.html mv_ -f {tmp/,}fav/"$month"/index.html echo >&2 "$dir: removing any deleted favorites" (cd fav; find "$month" -mindepth 1 -type f -not -name index.html) | while read -r fav; do base=${fav%.fav.*} name=${base##*/} unset hasSrc for src in src/"$base".fav.*; do test "${src%.txt}" != "$src" || hasSrc=set; done test "${hasSrc:+set}" || { echo >&2 "$dir: removing $year/fav/$fav" rm -f fav/"$fav" rm -f fav/"$month"/by-uuid/*/"${name%.*}".* } done rmdir -p 2>/dev/null fav/"$month"/by-uuid/*/ || true rmdir -p 2>/dev/null wip/fav/* || true popd >/dev/null done