2 # Copyright: Julien Moutinho <julm+camera@sourcephile.fr>
3 # License: AGPL-3.0-or-later
5 # $ mv 2023/src/02/IMG_20230228_111645{,.fav}.jpg
6 # $ echo >2023/src/02/IMG_20230228_111645.fav.txt "Some HTML <b>comment</b> about the picture"
7 # $ years=2023 months=02 ./index.sh
8 # $ sensible-browser 2023/fav/02/index.html
10 # shellcheck disable=SC2086
16 ffmpeg_
() { local -; set -x; nice
-19 ffmpeg
</dev
/null
-loglevel warning
-stats -report -y "$@"; }
17 magick_
() { local -; set -x; nice
-19 magick
"$@"; }
18 mv_
() { local -; set -x; mv -iv >&2 "$@"; }
20 user
=$(realpath --relative-to .. .)
21 declare -a years
=${years:-$(find * -maxdepth 0 -type d -not -name ".*")}
22 for year
in ${years[@]}; do
23 pushd "$year" >/dev
/null
24 test -d src
|| { popd; continue; }
26 # cp, not ln, because in push.sh --copy-links cannot be used for by-uuid/
27 cp -f --remove-destination -t fav ..
/index.css
28 declare -a months
=${months:-(01 02 03 04 05 06 07 08 09 10 11 12)}
29 for month
in ${months[@]}; do
30 test -d src
/"$month" || { popd; continue; }
32 mkdir -p {tmp
,wip
}/fav
/"$month"
37 <!-- Generator: https://git.sourcephile.fr/julm/camera -->
38 <!-- GenerationDate: $(date -R -d@"$genDate") -->
42 <meta charset="utf-8">
43 <title>camera/$user/$year/$month</title>
44 <link rel="stylesheet" href="../index.css?$genDate">
51 <li><a href='../../..'>camera</a>/ <a href='../..'>$user</a>/ <a href='..'>$year</a>/ $month</li>
57 echo >&2 "$year/$month: processing favorites in chronological order"
58 # Time is encoded in filenames like so: MM/{IMG,VID}_YYYYMMDD_hhmmss.*
59 # hence sorting after the underscore (2nd field, 5th char).
60 (cd src
; find "$month" -name '*.fav.*' -not -name "*.txt") | sort -n -t/ -k2.5
|
62 echo >&2 "$year/$month: processing $year/src/$src"
66 creationDate
=$(printf %s "${src##*/???_}" | sed -e 's/\(....\)\
(..\
)\
(..\
)_\
(..\
)\
(..\
)\
(..\
).
*/\
1-\
2-\
3 \
4:\
5:\
6/')
67 echo "<li id='$id'><div class='item
'>"
68 test -e fav/"$base".uuid ||
69 uuidgen --random >fav/"$base".uuid
70 uuid=$(cat fav/"$base".uuid)
71 mkdir -p fav/"$month"/by-uuid/"$uuid"
75 printf "<source type='image
/avif
' srcset='"
76 for w in {1200,600,300}; do
77 test fav/"$base"."$w"x.avif -nt src/"$src" || {
79 -sampling-factor 4:2:0 -colorspace sRGB \
80 -auto-orient -thumbnail "$w"x -unsharp 0x.5 \
81 fav/"$base"."$w"x.avif
83 printf %s "$name.
${w}x.avif
${w}w
, "
87 test fav/"$base"."$w"x.avif -nt src/"$src" || {
88 magick_ -define jpeg:size=$((w * 2))x src/"$src" \
89 -sampling-factor 4:2:0 -interlace JPEG -colorspace sRGB \
90 -auto-orient -thumbnail "$w"x -unsharp 0x.5 \
93 echo "<source type='image
/jpeg
' srcset='$name.
${w}x.jpg
${w}w
' />"
94 echo "<img src='$name.
${w}x.jpg
' alt='$creationDate' />"
96 dst="$name".1200x.avif
97 ln -fs -t fav/"$month"/by-uuid/"$uuid" ../../"$dst"
100 test fav/"$base".avif -nt src/"$src" || {
101 ffmpeg_ -i src/"$src" \
103 -filter:v format=yuv420p,scale='trunc
(oh
*a
/2)*2:360' \
104 -frames:v 1 -crf 40 \
106 mv_ {wip/,}fav/"$base".avif
109 test tmp/fav/"$base".opus -nt src/"$src" || {
110 ffmpeg_ -i src/"$src" \
111 -map 0:a -c:a libopus -b:a 64k -application voip \
113 mv_ {wip,tmp}/fav/"$base".opus
116 test fav/"$base".360p.av1.webm -nt src/"$src" || {
118 ffmpeg_ -i src/"$src" -i tmp/fav/"$base".opus \
120 -filter:v format=yuv420p,scale='trunc
(oh
*a
/2)*2:360' \
121 -c:v libsvtav1 -crf 40 -g 120 \
123 wip/fav/"$base".360p.av1.webm
124 mv_ {wip/,}fav/"$base".360p.av1.webm
126 dst="$name".360p.av1.webm
127 ln -fs -t fav/"$month"/by-uuid/"$uuid" ../../"$dst"
128 #test fav/"$base".360p.vp9.webm -nt src/"$src" || {
130 # # See https://developers.google.com/media/vp9/settings/vod#recommended_settings
131 # # See https://gist.github.com/mrintrepide/3033c35ee9557e66cff7806f48dbd339
133 # -filter:v format=yuv420p,scale='trunc
(oh
*a
/2)*2:360' \
134 # -c:v libvpx-vp9 -quality good -crf 20 \
135 # -minrate 138k -b:v 276k -maxrate 400k \
136 # -cpu-used 4 -static-thresh 0 -tile-columns 0 -tile-rows 0 -frame-parallel 0 \
137 # -row-mt 1 -aq-mode 0 -auto-alt-ref 6 -lag-in-frames 25 -enable-tpl 1
138 # test -e tmp/fav/"$base".360p.vp9.webm-0.log || {
139 # # FIXME: how to disable h264 debug log?
140 # ffmpeg 2>/dev/null -i src/"$src" \
141 # -map 0:v "$@" -pass 1 -passlogfile wip/fav/"$base".360p.vp9.webm \
144 # mv_ -t tmp/fav/"${base%/*}" wip/fav/"$base".360p.vp9.webm-*.log
146 # ffmpeg -i src/"$src" -i tmp/fav/"$base".opus \
147 # -map 0:v "$@" -pass 2 -passlogfile tmp/fav/"$base".360p.vp9.webm \
148 # -map 1:a -c:a copy \
149 # wip/fav/"$base".360p.vp9.webm
150 # mkdir -p fav/"$month"/by-uuid/"$uuid"
151 # mv_ wip/fav/"$base".360p.vp9.webm fav/"$base".360p.vp9.webm
152 # rm -fv tmp/fav/"$base".360p.vp9.webm-*.log
154 #test fav/"$base".mp4 -nt src/"$src" || {
155 # ffmpeg -i src/"$src" \
156 # -filter:v format=yuv420p \
157 # -c:v libx264 -preset medium -crf 22 \
158 # -tune zerolatency \
159 # -maxrate 1M -bufsize 2M \
160 # -movflags use_metadata_tags +faststart \
161 # -c:a libopus -base:a 64k -application voip \
162 # -filter:v "scale=iw/2:ih/2" \
163 # wip/fav/"$base".mp4
164 # mv_ wip/fav/"$base".mp4 fav/"$base".mp4
166 #orient=$(ffprobe -v 0 -select_streams v:0 -show_entries stream_side_data=rotation -of default=nw=1:nk=1 src/"$src")
167 # class='orient
$orient'
168 echo "<video controls preload=none poster='$name.avif
'>"
169 # See https://jakearchibald.com/2022/html-codecs-parameter-for-av1/
170 # and ffmpeg -i fav/$month/foo.av1.webm -c:v copy -bsf:v trace_headers -f null /dev/null |&
171 # grep -e seq_profile -e seq_level_idx -e seq_tier -e high_bitdepth -e twelve_bit
172 P=0; LL=01; T=M; DD=08
173 echo "<source type='video
/webm
; codecs
=av01.
$P.
$LL$T.
$DD' src='$name.360p.av1.webm
' />"
174 echo "<p><a href='$name.360p.av1.webm
'>$name.360p.av1.webm</a></p>"
177 touch -a src/"$base".txt
178 printf %s "<span class='comment
'>"
179 sed -e '$q;s
/$
/<br \
/>\n/' src/"$base".txt
182 echo "<span class='infos
'>"
183 echo " <span class='creationDate
'>$creationDate</span>"
185 echo "<span class='links
'>"
186 echo " <a class='by
-uuid' href='by
-uuid/$uuid/$dst' title='Lien public vers cette capture
' target='_blank
'>@</a>"
187 echo " <a class='anchor
' href='#$id' title='Ancre vers cette capture'>#</a>"
199 } >tmp
/fav
/"$month"/index.html
200 mv_
-f {tmp
/,}fav
/"$month"/index.html
202 echo >&2 "$year/$month: remove any deleted favorites"
203 (cd fav
; find "$month" -mindepth 1 -type f
-not -name index.html
) |
204 while read -r fav
; do
208 for src
in src
/"$base".fav.
*; do test "${src%.txt}" != "$src" || hasSrc
=set; done
209 test "${hasSrc:+set}" || {
210 echo >&2 "$year/$month: removing $year/fav/$fav"
212 rm -f fav
/"$month"/by
-uuid/*/"${name%.*}".
*
215 rmdir -p 2>/dev
/null fav
/"$month"/by
-uuid/*/ || true
219 rmdir 2>/dev
/null
-p wip
/fav
/* || true