Update soundtest
[grml-scripts.git] / usr_bin / twebgal
1 #!/bin/bash
2 # Filename:      twebgal
3 # Purpose:       create a tiny webgallery using CSS-features
4 # Authors:       Wolfgang Scheicher <worf@grml.org>
5 # Bug-Reports:   see http://grml.org/bugs/
6 # License:       This file is licensed under the GPL v2.
7 # Latest change: Mon Apr 25 10:38:00 CEST 2005 [worf]
8 ################################################################################
9
10 # Defaults
11 DISPLAY_GEOMETRY=640x480
12 THUMBNAIL_GEOMETRY=150x150
13 PREVIEW_GEOMETRY=250x250
14 THUMBNAIL_QUALITY=75
15
16 PARENT_DIR="Übergeordnetes Verzeichnis"
17
18 PATH=$PATH:/usr/X11R6/bin:/usr/bin
19 DATADIR=".tmp"
20 LOG=".tmp/log"
21 VERBOSE="/dev/null"
22 OPTS=$*
23 OLDIFS=$IFS
24 IFS="
25 "
26
27 THUMBNAILS=("$DISPLAY_GEOMETRY" "$THUMBNAIL_GEOMETRY")
28 FILE_EXTENSIONS=("jpg" "png" "gif")
29 REQUIRED=("jpegtran" "convert" "identify" "find" "tr" "sed" "awk" "grep")
30
31 ##############################################################
32
33 create_sample_config () {
34 # sample config with some default values
35 #
36 if [ -f description ] ; then
37   DST=/dev/stdout
38   echo "description file allready exists!"
39 else
40   echo "creating example description file"
41   DST="./description"
42 fi
43 echo -e "# Gallery Config File\n#
44 # Title for this Directory
45 TITLE=\"${PWD##*/}\"\n
46 # Optional Comment
47 COMMENT=\"\"\n
48 # this parameters affect the dir list in the parent directory:
49 # thumbnail to show
50 THUMB=\"$(find_all_images | head -n 1 )\"\n
51 # Index to sort dirs by.
52 # You might want to use some date for chronological order
53 INDEX=\"$(date +%F)\"\n" > $DST
54 if [[ -z $STYLESHEET ]] ; then
55 echo -e "# Stylesheet
56 # This will be used for all subdirs as well
57 STYLESHEET=\"stylesheet.css\"" >> $DST
58 fi
59 }
60
61 ##############################################################
62
63 init_gallery () {
64 # create datadir and check for required apps
65 #
66   mkdir -p ${DATADIR}
67   echo -n "" > ${LOG}
68   for app in "${REQUIRED[@]}" ; do
69     if which $app 2>/dev/null >/dev/null ; then
70       true
71     else
72       echo "ERROR: $app not found!"
73       exit;
74     fi
75   done
76   if [[ -f description ]] ; then source "description"; fi
77   STYLESHEET=$( find_stylesheet )
78 }
79
80 parent_dir () {
81 # adds a "../ if it is not a absolute path or a url"
82 # otherwise returns the same string again
83   if [[ "${1::1}" == "/" ]] ; then
84     echo "$1"
85   elif [[ "${1::7}" == "http://" ]] ; then
86     echo "$1"
87   elif [[ ! -z $1 ]] ; then
88     echo "../${1}"
89   fi
90 }
91
92 find_stylesheet () {
93 # searches parent dirs recursively for a stylesheet
94 # until it reaches the root dir
95   if [[ -f description ]] ; then source "description"; fi
96   if [[ -z $STYLESHEET ]] ; then
97     if [[ ! "$PWD" == "/" ]] ; then
98       cd ..
99       parent_dir $( find_stylesheet )
100     fi
101   else
102     echo $STYLESHEET
103   fi
104 }
105
106 ##############################################################
107
108 find_all_images() {
109 # returns a list of all (supported) Images in the current dir
110 #
111   for ext in "${FILE_EXTENSIONS[@]}" ; do
112     find *.${ext} -maxdepth 0 2> /dev/null
113   done
114 }
115
116 find_all_dirs() {
117 # Searches all dirs and lists them,
118 # sorted by the INDEX field in the description file
119 #
120   DIRS="$(find * -maxdepth 0 -type d)"
121   for DIR in $DIRS ; do
122     ( INDEX="_"
123     if [[ -f ${DIR}/description ]] ; then source "${DIR}/description"; fi
124     echo "${INDEX} ${DIR}" )
125   done | sort | sed -e "s/^\S*\s//"
126 }
127
128 ##############################################################
129
130 prune() {
131 # deletes old thumbnails and html files
132 # temporarily creates a filelist
133 #
134   if [[ "$RECURSIVE" == "true" ]] ; then
135     ALL_DIRS=( $(find_all_dirs) )
136     for DIR in "${ALL_DIRS[@]}"; do
137       ( IFS=$OLDIFS && cd "$DIR" && $0 $OPTS ; )
138     done
139   fi
140   echo "->  ${PWD}"
141   if [[ -d "${DATADIR}" ]] ; then
142     find_all_images > "${DATADIR}/filelist"
143     for GEOMETRY in "${THUMBNAILS[@]}"; do
144       (
145       [[ -d "${DATADIR}/${GEOMETRY}" ]] &&
146       cd "${DATADIR}/${GEOMETRY}" &&
147       find_all_images |
148       awk 'NR==FNR {a[$0];next}
149            !($0 in a)' ../filelist - |
150       while read line ; do
151         echo "rm ${DATADIR}/${GEOMETRY}/${line}"
152         rm "${line}"
153       done
154       )
155     done
156     (
157     cd "${DATADIR}/" &&
158     find *.html -maxdepth 0 2> /dev/null |
159     awk 'NR==FNR {a[$0];next}
160          {sub(/\.html$/,"",$0)}
161          !($0 in a)' filelist - |
162     while read line ; do
163       echo "rm ${DATADIR}/${line}.html"
164       rm "${line}.html"
165     done
166     )
167     rm "${DATADIR}/filelist"
168   fi
169 }
170
171 ##############################################################
172
173 build_thumbnail() {
174 # generates thumbnails
175 # time of modification is set to that of the original and used
176 # to check if existing thumbs need updating
177 # orientation in the exif-header is used to rotate generated images
178 #
179   for GEOMETRY in "${THUMBNAILS[@]}"; do
180     mkdir -p "$DATADIR/$GEOMETRY" || exit
181     echo -ne "($GEOMETRY"
182     DST="$DATADIR/$GEOMETRY/$FILE"
183     SKIP=false
184      if [[ -e $DST ]]; then
185       if [[ $(stat -c "%Y" $FILE) == $(stat -c "%Y" $DST) ]]; then
186         SKIP=true
187         echo -n " skip"
188       else
189         echo -n " D"
190         rm $DST
191       fi
192     else
193       echo -n "  "
194     fi
195
196     if [[ $SKIP == "false" ]]; then
197       ORIENTATION=""
198       ORIENTATION=$(identify -format "%[EXIF:Orientation]" "$FILE")
199       if [[ "$ORIENTATION" == "6" ]]; then
200         echo -n "TR"
201         convert -quality $THUMBNAIL_QUALITY -rotate 90 -geometry "$GEOMETRY+0+0>" "$FILE" "$DST"
202       elif [[ "$ORIENTATION" == "8" ]]; then
203         echo -n "TL"
204         convert -quality $THUMBNAIL_QUALITY -rotate 270 -geometry "$GEOMETRY+0+0>" "$FILE" "$DST"
205       else
206         echo -n "T "
207         convert -quality $THUMBNAIL_QUALITY -geometry "$GEOMETRY+0+0>" "$FILE" "$DST"
208       fi
209       if [[ "${FILE##*.}" == "jpg" ]]; then
210         echo -n "O"
211         jpegtran -copy none -optimize -progressive "$DST" > "$DST.tmp"
212         mv -f "$DST.tmp" "$DST"
213       else
214         echo -n " "
215       fi
216       touch -m --reference=$FILE $DST
217     fi
218     echo -n ") "
219   done
220 }
221
222 build_html() {
223 # generates the HTML
224
225   echo -n "(html"
226
227   THUMBGEOMETRY=$(identify -format "%wx%h" "$DATADIR/$THUMBNAIL_GEOMETRY/${FILE}")
228   THUMBWIDTH=${THUMBGEOMETRY%x*}
229   THUMBHEIGHT=${THUMBGEOMETRY#*x}
230
231   THUMBT=$(((156 - $THUMBHEIGHT )/2 ))
232   THUMBB=$(((157 - $THUMBHEIGHT )/2 ))
233   THUMBL=$(((156 - $THUMBWIDTH  )/2 ))
234   THUMBR=$(((157 - $THUMBWIDTH  )/2 ))
235
236   TITLE=$FILE
237   COMMENT=$(identify -format "%c" "${FILE}" | tr '\n' ' ')
238   THUMBNAIL=$DATADIR/$THUMBNAIL_GEOMETRY/${FILE}
239   THIS_HTML=$DATADIR/${FILE}.html
240
241   html_header > ${THIS_HTML}
242
243 echo "<div class=\"gallerynav\">
244 ${FILE}&nbsp;&nbsp;&nbsp;&nbsp;
245 <a href=\"../index.html\">Index</a>&nbsp;&nbsp;&nbsp;&nbsp;<a href=\"${LAST}.html\">&lt;&lt;&lt;</a>&nbsp;${CURRENT}/${IMAGE_COUNT}&nbsp;<a href=\"${NEXT}.html\">&gt;&gt;&gt;</a>
246 </div>
247
248 <div class=\"cont\">
249 <center>
250 <a href=\"../${FILE}\"><img alt=\"${DISPLAY_GEOMETRY}/${FILE}\" src=\"${DISPLAY_GEOMETRY}/${FILE}\" /></a>
251 </center><br />
252 " >> $THIS_HTML
253
254 identify -format "<table>
255 <tr><td>Auflösung:</td><td>%wx%h</td></tr>
256 <tr><td>Dateigröße:</td><td>%b</td></tr>
257 <tr><td>Camera:</td><td>%[EXIF:Model]</td></tr>
258 <tr><td>Datum/Zeit:</td><td>%[EXIF:DateTime]</td></tr>
259 <tr><td>Kommentar:</td><td>%c</td></tr>
260 </table>" ${FILE} >> $THIS_HTML
261
262 echo "</div>" >> $THIS_HTML
263 html_foot >> $THIS_HTML
264
265 echo "<a href=\"$THIS_HTML\"><img alt=\"Thumbnail\" src=\"$THUMBNAIL\" style=\"width:${THUMBWIDTH}px; height:${THUMBHEIGHT}px; margin: ${THUMBT}px ${THUMBR}px ${THUMBB}px ${THUMBL}px;\" title=\"${COMMENT}\" /><br />$FILE</a>" >> index.html
266
267 echo -en ")"
268 }
269
270 ##############################################################
271
272 start_index () {
273 # generates the upper part of the index page
274 # containing the list of subdirs
275 # which are recursively processed from here too
276 #
277   TITLE="${TITLE=${PWD##*/}}"
278   html_header > index.html
279   echo "<div class=\"cont\">" >> index.html
280   echo "<h1>${TITLE}</h1>" >> index.html
281   echo "<ul>" >> index.html
282   echo "<li class=\"back\"><b><a href=\"../index.html\">${PARENT_DIR}</a></b></li>" >> index.html
283   ALL_DIRS=( $(find_all_dirs) )
284   for DIR in "${ALL_DIRS[@]}"; do
285   ( TITLE="${DIR}"; THUMB=""; INDEX=""; COMMENT=""
286     if [[ -f ${DIR}/description ]] ; then source "${DIR}/description"; fi
287     echo "<li class=\"dir\"><a class=\"tooltip\" href=\"${DIR}/index.html\"><b>${TITLE}</b>" >> index.html
288
289     if [[ ! "${THUMB}${COMMENT}" == "" ]]; then
290       if [[ "${COMMENT}" == "" ]]; then
291         echo "<span><table><tr><td><img alt=\"Thumbnail\" src=\"${DIR}/${DATADIR}/thumb.${THUMB##*.}\" /></tr></table></span>" >> index.html
292       elif [[ "${THUMB}" == "" ]]; then
293         echo "<span><table><tr><td>${COMMENT}</td></tr></table></span>" >> index.html
294       else
295         echo "<span><table><tr><td><img alt=\"Thumbnail\" src=\"${DIR}/${DATADIR}/thumb.${THUMB##*.}\" /></td><td></td><td></td><td>${COMMENT}</td></tr></table></span>" >> index.html
296       fi
297     fi
298     echo "</a></li>" >> index.html
299     if [[ "$RECURSIVE" == "true" ]] ; then
300       ( STYLESHEET="$(parent_dir ${STYLESHEET})"
301         IFS=$OLDIFS && cd "$DIR" && $0 $OPTS ; )
302     fi
303   )
304   done
305 echo "
306 </ul>
307 ${COMMENT}
308 <div class=\"gallery\">
309 <div class=\"spacer\"></div>
310 " >> index.html
311 }
312
313 finish_index () {
314 echo "
315 <div class=\"spacer\"></div>
316 </div>
317 </div>
318 " >> index.html
319 html_foot >> index.html
320 }
321
322 ##############################################################
323
324 create_sample_stylesheet () {
325 if [ -f stylesheet.css ] ; then
326   echo "stylesheet.css allready exists!"
327   exit 1
328 fi
329 cat << EOF > stylesheet.css
330 a {text-decoration:none;}
331
332 div.gallery img {border: 2px inset #aaa; margin:3px;}
333 div.gallery a {color:#000; border: 2px outset #aaa; text-decoration:none; text-align:center; float:left; padding:3px; margin:4px; background-color:#ddd;}
334 div.gallery a:hover {color:#333; border: 2px outset #ccc; background-color:#eee;}
335 div.spacer {clear: both;}
336 div.gallerynav {text-align: center; margin: 0px; padding:0em 0.3em 0em 0.3em;}
337
338 a.tooltip, a.tooltip:link, a.tooltip:visited, a.tooltip:active  { position: relative; }
339 a.tooltip span {display: none}
340 a:hover.tooltip span {display: block; position: absolute; top: 2.5em; left: 1.5em; z-index: 100; color: #000; padding: 3px; border:1px solid #000; background: #ffc; }
341 EOF
342 }
343
344 ##############################################################
345
346 html_header () {
347 echo "<html>
348 <head>
349 <title>${TITLE}</title>
350 <link rel=\"stylesheet\" type=\"text/css\" href=\"${STYLESHEET}\" />
351 </head>
352 <body>
353 "
354 }
355
356 html_foot () {
357 echo "</body>
358 </html>
359 "
360 }
361
362
363 ##############################################################
364
365 build_gallery() {
366 # generates the whole thing, puts everything together
367
368   ALL_IMAGES=( $(find_all_images) )
369   IMAGE_COUNT=${#ALL_IMAGES[@]}
370   start_index
371   (
372   STYLESHEET="$(parent_dir ${STYLESHEET})"
373   echo "-> ${TITLE}"
374   CURRENT="0"
375   FILE="../index"
376   for file in "${ALL_IMAGES[@]}" "../index" ; do
377     NEXT="$file"
378     if [[ "$FILE" != "../index" ]]; then
379       echo -ne "$FILE\t"
380       build_thumbnail
381       build_html
382       echo ""
383     fi
384     CURRENT="$(( ${CURRENT} + 1 ))"
385     LAST="$FILE"
386     FILE="$file"
387   done
388   if [[ ! -z "${THUMB}" ]] ; then
389     echo -ne "preview thumbnail from ${THUMB}\t"
390     THUMBNAILS=("$PREVIEW_GEOMETRY")
391     FILE="${THUMB}"
392     [ -e "${DATADIR}/thumb.${THUMB##*.}" ] && mv "${DATADIR}/thumb.${THUMB##*.}" "${DATADIR}/${PREVIEW_GEOMETRY}/${THUMB}"
393     build_thumbnail &&
394     mv "${DATADIR}/${PREVIEW_GEOMETRY}/${THUMB}" "${DATADIR}/thumb.${THUMB##*.}"
395     echo
396   fi
397   ) | tee -a $LOG >> $VERBOSE
398   finish_index
399   echo " $IMAGE_COUNT Image(s) in ${TITLE}"
400 }
401
402 ##############################################################
403
404 init_gallery
405
406 while getopts "vdsrp-:" OPT ; do
407   case $OPT in
408     v) VERBOSE=/dev/stdout
409        ;;
410     d) create_sample_config
411        exit 0
412        ;;
413     s) create_sample_stylesheet
414        exit 0
415        ;;
416     r) RECURSIVE="true"
417        ;;
418     p) prune
419        exit 0
420        ;;
421     ?) # wrong argument
422        echo -n "ERROR: Missing argument for option \"$OPTARG\". "
423        exit 1
424        ;;
425     *) # wrong option
426        echo -n "ERROR: Unknown option \"$OPTARG\". "
427        exit 1
428        ;;
429   esac
430 done
431 shift $(($OPTIND -1))
432
433 build_gallery 2>${DATADIR}/errors
434 if [ -s ${DATADIR}/errors ]; then
435   echo -e "\nWARNING: there were errors. see .tmp/errors"
436 else
437   rm .tmp/errors
438 fi
439
440 ## END OF FILE #################################################################