--- /dev/null
+#!/usr/bin/ruby
+#
+# * BOOH *
+#
+# A.k.a `Best web-album Of the world, Or your money back, Humerus'.
+#
+# The acronyn sucks, however this is a tribute to Dragon Ball by
+# Akira Toriyama, where the last enemy beaten by heroes of Dragon
+# Ball is named "Boo". But there was already a free software project
+# called Boo, so this one will be it "Booh". Or whatever.
+#
+#
+# Copyright (c) 2004 Guillaume Cottenceau <gc3 at bluewin.ch>
+#
+# This software may be freely redistributed under the terms of the GNU
+# public license version 2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+require 'getoptlong'
+require 'html_merges'
+
+#- options
+$options = [
+ [ '--help', '-h', GetoptLong::NO_ARGUMENT, "Get help message" ],
+
+ [ '--no-check', '-n', GetoptLong::NO_ARGUMENT, "Don't check for needed external programs at startup" ],
+
+ [ '--source', '-s', GetoptLong::REQUIRED_ARGUMENT, "Directory which contains original images/videos as files or subdirs" ],
+ [ '--destination', '-d', GetoptLong::REQUIRED_ARGUMENT, "Directory which will contain the web-album" ],
+ [ '--clean', '-c', GetoptLong::NO_ARGUMENT, "Clean destination directory" ],
+
+ [ '--theme', '-t', GetoptLong::REQUIRED_ARGUMENT, "Select HTML theme to use" ],
+
+ [ '--verbose-level', '-v', GetoptLong::REQUIRED_ARGUMENT, "Set max verbosity level (0: warnings, 1: important messages, " +
+ "2: other messages)" ],
+]
+
+#- default values for some globals
+$theme = 'simple'
+$convert = 'convert -interlace line +profile \"*\"'
+$verbose_level = 2
+
+def usage
+ puts "Usage: #{File.basename($0)} [OPTION]..."
+ $options.each { |ary|
+ printf " %3s, %-15s %s\n", ary[1], ary[0], ary[3]
+ }
+end
+
+def msg(verbose_level, msg)
+ if verbose_level <= $verbose_level
+ if verbose_level == 0
+ warn "Warning: #{msg}"
+ else
+ puts msg
+ end
+ end
+end
+
+def die(msg)
+ puts msg
+ exit 1
+end
+
+def handle_options
+ parser = GetoptLong.new
+ parser.set_options(*$options.collect { |ary| ary[0..2] })
+ begin
+ parser.each_option do |name, arg|
+ case name
+ when '--help'
+ usage
+ exit(0)
+
+ when '--no-check'
+ $no_check = true
+
+ when '--source'
+ $source = arg
+ if !File.directory?($source)
+ die "Argument to --source must be a directory"
+ end
+ when '--destination'
+ $dest = arg
+ if File.exists?($dest) && !File.directory?($dest)
+ die "If --destination exists, it must be a directory"
+ end
+ when '--clean'
+ system("rm -rf #{$dest}")
+
+ when '--theme'
+ $theme = arg
+
+ when '--verbose-level'
+ $verbose_level = arg.to_i
+
+ end
+ end
+ rescue
+ usage
+ exit(1)
+ end
+
+ if !$source
+ die 'Missing --source parameter.'
+ end
+ if !$dest
+ die 'Missing --destination parameter.'
+ end
+end
+
+def check_installation
+ if $no_check
+ return
+ end
+ %w(convert transcode exif).each { |prg|
+ if !system("which #{prg} >/dev/null")
+ die "The `#{prg}' program is typically needed. Re-run with --no-check if you're sure you're fine without it."
+ end
+ }
+end
+
+def replace_line(prefix, keyword, line)
+ begin
+ contents = eval "$#{keyword}"
+ line.sub!(/#{prefix}#{keyword}/, contents)
+ rescue NameError
+ die "No `#{keyword}' found for substitution"
+ end
+end
+
+def build_html_skeleton
+ theme_file = File.open("themes/#{$theme}/skeleton.html").readlines
+ msg 2, "Read theme `#{$theme}'"
+ for line in theme_file
+ while line =~ /~~~(\w+)/
+ replace_line('~~~', $1, line)
+ end
+ end
+ return theme_file
+end
+
+def sys(cmd)
+ msg 1, cmd
+ system(cmd)
+end
+
+def walk_source_dir
+ `find #{$source} -type d`.each { |dir|
+ dir.chomp!
+ msg 2, "Examining #{dir}..."
+ images = Dir["#{dir}/*.{jpg,jpeg,gif,bmp,png}"]
+ msg 2, "\t#{images.length} images"
+ videos = Dir["#{dir}/*.{mov,avi,mpg,mpeg}"]
+ msg 2, "\t#{videos.length} videos"
+
+ dest_dir = dir.sub(/^#{$source}/, $dest)
+ system("mkdir -p #{dest_dir}")
+ msg 2, "Outputting in #{dest_dir}..."
+
+ final_images = []
+ images.each { |img|
+ dest_img = img.sub(/^#{$source}/, $dest).
+ sub(/\.[^\.]+$/, '') + '-704.jpg'
+ final_images << File.basename(dest_img)
+ if !File.exists?(dest_img)
+ sys "#{$convert} -geometry 704x528 #{img} #{dest_img}"
+ end
+ }
+
+ html = $skeleton.collect { |l| l.clone }
+ images4js = final_images.collect { |img| "\"#{img}\"" }.join(', ')
+ for i in html
+ i.sub!(/~~images/, images4js)
+ end
+
+ File.open("#{dest_dir}/index.html", "w").write(html)
+ }
+end
+
+handle_options
+check_installation
+
+$skeleton = build_html_skeleton
+
+walk_source_dir
--- /dev/null
+#!/usr/bin/ruby
+#
+# * BOOH *
+#
+# A.k.a `Best web-album Of the world, Or your money back, Humerus'.
+#
+# The acronyn sucks, however this is a tribute to Dragon Ball by
+# Akira Toriyama, where the last enemy beaten by heroes of Dragon
+# Ball is named "Boo". But there was already a free software project
+# called Boo, so this one will be it "Booh". Or whatever.
+#
+#
+# Copyright (c) 2004 Guillaume Cottenceau <gc3 at bluewin.ch>
+#
+# This software may be freely redistributed under the terms of the GNU
+# public license version 2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+require 'gtk2'
+
+Gtk.init
+
+vbox = Gtk::VBox.new
+
+vbox.pack_start(Gtk::Label.new("booh!"))
+vbox.pack_start(b = Gtk::Button.new("booh :("))
+
+b.signal_connect('clicked') do
+ Gtk.main_quit
+end
+
+w = Gtk::Window.new.add(vbox)
+w.signal_connect('delete-event') do
+ Gtk.main_quit
+end
+
+#w.set_position(Gtk::Window::CENTER)
+
+w.show_all
+
+Gtk.main
--- /dev/null
+#
+# * BOOH *
+#
+# A.k.a `Best web-album Of the world, Or your money back, Humerus'.
+#
+# The acronyn sucks, however this is a tribute to Dragon Ball by
+# Akira Toriyama, where the last enemy beaten by heroes of Dragon
+# Ball is named "Boo". But there was already a free software project
+# called Boo, so this one will be it "Booh". Or whatever.
+#
+#
+# Copyright (c) 2004 Guillaume Cottenceau <gc3 at bluewin.ch>
+#
+# This software may be freely redistributed under the terms of the GNU
+# public license version 2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# holds static data to merge in the html "themes"
+
+$head_code = <<'EOF'
+<link rev="made" href="http://zarb.org/~gc/html/booh.html" />
+<script language="JavaScript1.1" type="text/JavaScript">
+
+var images = new Array(~~images);
+
+var images_ary = new Array();
+var images_loaded = new Array();
+var current = 0;
+var slideshow = 0;
+var slideshow_pause = 3;
+
+for (i = 0; i < images.length; i++) {
+ /* this array will contain 0 if image not yet loaded, 1 when loading,
+ * 2 when complete */
+ images_loaded[i] = 0;
+}
+
+function dbg(t) {
+ document.getElementById('dbg_text').firstChild.data += t + "\n";
+}
+
+/* load image, return 1 if image is finished loading */
+function load(i) {
+ if (images_loaded[i] == 0) {
+ images_ary[i] = new Image();
+ images_ary[i].src = images[i];
+ images_loaded[i] = 1;
+ }
+ if (images_loaded[i] == 1) {
+ if (images_ary[i].complete) {
+ images_loaded[i] = 2;
+ } else {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+function preload() {
+
+ /* favor current image, if user clicked on `last' or something */
+ load(current);
+
+ for (i = 0; i < images.length; i++) {
+ /* don't blindly preload all images at the beginning,
+ * but rather load them one by one, in order to get
+ * next ones faster
+ */
+ if (load(i) == 0) {
+ setTimeout("preload()", 500);
+ return;
+ }
+ }
+}
+
+function init() {
+ preload();
+
+ /* retrieve GET parameters */
+ all_params = location.href.split("?")
+ if (all_params.length > 1) {
+ params = all_params[1].split("&");
+ for (i = 0; i < params.length; i++) {
+ keyvalue = params[i].split("=");
+ if (keyvalue[0] == "slideshow_pause") {
+ slideshow_pause = keyvalue[1];
+ }
+ }
+ }
+}
+
+function update_sensibilities() {
+ if (current == 0) {
+ document.getElementById("b_first").disabled = true;
+ document.getElementById("b_previous").disabled = true;
+ document.getElementById("b_next").disabled = false;
+ document.getElementById("b_last").disabled = false;
+ } else if (current == images.length - 1) {
+ document.getElementById("b_first").disabled = false;
+ document.getElementById("b_previous").disabled = false;
+ document.getElementById("b_next").disabled = true;
+ document.getElementById("b_last").disabled = true;
+ } else {
+ document.getElementById("b_first").disabled = false;
+ document.getElementById("b_previous").disabled = false;
+ document.getElementById("b_next").disabled = false;
+ document.getElementById("b_last").disabled = false;
+ }
+}
+
+function set_cursor_(value, element) {
+
+ if (!element || !element.style) {
+ return;
+ }
+
+ element.style.cursor = value;
+
+ children = element.childNodes;
+ for (i = 0; i < children.length; i++) {
+ set_cursor_(value, children.item[i]);
+ }
+}
+
+function set_cursor(value) {
+ set_cursor_(value, document.getElementById('body'));
+}
+
+function show_current_text() {
+ /* don't show text if image not yet loaded because navigator
+ * won't refresh it during load */
+ if (images_loaded[current] == 2) {
+ eval("document.getElementById('main_text')" +
+ ".firstChild.data = '" + images[current] + "'");
+ set_cursor("default");
+ } else {
+ setTimeout("show_current_text()", 100);
+ set_cursor("wait");
+ }
+}
+
+function display_current() {
+ eval("document.main_img.src = images[" + current + "]");
+ show_current_text();
+ update_sensibilities();
+}
+
+function first() {
+ if (slideshow == 1) {
+ toggle_slideshow();
+ }
+
+ current = 0;
+ display_current();
+}
+
+function next() {
+ if (slideshow == 1) {
+ toggle_slideshow();
+ }
+
+ if (current < images.length - 1) {
+ current++;
+ display_current();
+ }
+}
+
+function previous() {
+ if (slideshow == 1) {
+ toggle_slideshow();
+ }
+
+ if (current > 0) {
+ current--;
+ display_current();
+ }
+}
+
+function last() {
+ if (slideshow == 1) {
+ toggle_slideshow();
+ }
+
+ current = images.length - 1;
+ display_current();
+}
+
+function toggle_slideshow() {
+ if (slideshow == 0) {
+ document.getElementById("b_slideshow").value = "Stop slideshow";
+ slideshow = 1;
+ if (current == images.length - 1) {
+ current = -1;
+ }
+ run_slideshow();
+ } else {
+ document.getElementById("b_slideshow").value = "Run slideshow!";
+ slideshow = 0;
+ }
+}
+
+function run_slideshow() {
+ if (slideshow == 0) {
+ return;
+ }
+
+ if (images_loaded[current + 1] == 2) {
+ current++;
+ display_current();
+ setTimeout("run_slideshow()", slideshow_pause * 1000);
+ } else {
+ setTimeout("run_slideshow()", 500);
+ }
+
+ if (current == images.length - 1) {
+ toggle_slideshow();
+ }
+}
+</script>
+EOF
+
+$body_additions = <<'EOF'
+onload="init()" id="body"
+EOF
+
+$button_first = <<'EOF'
+ <form><input type="button"
+ onclick="first()"
+ value="<<- First"
+ id="b_first"></form>
+EOF
+
+$button_previous = <<'EOF'
+ <form><input type="button"
+ onclick="previous()"
+ value="<- Previous"
+ id="b_previous"></form>
+EOF
+
+$button_next = <<'EOF'
+ <form><input type="button"
+ onclick="next()"
+ value="Next ->"
+ id="b_next"></form>
+EOF
+
+$button_last = <<'EOF'
+ <form><input type="button"
+ onclick="last()"
+ value="Last ->>"
+ id="b_last"></form>
+EOF
+
+$button_slideshow = <<'EOF'
+ <form><input type="button"
+ onclick="toggle_slideshow()"
+ value="Run slideshow!"
+ id="b_slideshow">
+ </form>
+EOF
+
+$image = <<'EOF'
+ <img name="main_img">
+EOF
+
+$caption_additions = <<'EOF'
+ id="main_text"
+EOF
+
+$body_code = <<'EOF'
+ <script language="JavaScript1.1" type="text/JavaScript">
+ display_current();
+ </script>
+EOF
+
--- /dev/null
+#
+# * BOOH *
+#
+# A.k.a `Best web-album Of the world, Or your money back, Humerus'.
+#
+# The acronyn sucks, however this is a tribute to Dragon Ball by
+# Akira Toriyama, where the last enemy beaten by heroes of Dragon
+# Ball is named "Boo". But there was already a free software project
+# called Boo, so this one will be it "Booh". Or whatever.
+#
+#
+# Copyright (c) 2004 Guillaume Cottenceau <gc3 at bluewin.ch>
+#
+# This software may be freely redistributed under the terms of the GNU
+# public license version 2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+#- sizes for "fullscreen" images
+#-
+#- we often will want to have one size to nicely fit 800x600 screens,
+#- one for 1024x768 and one for 1280x1024
+#- it's necessary to fit according to the typical space taken by
+#- widgets defined in the skeleton of the theme
+images_size = [
+ {
+ name => { 'en' => 'Small (for 800x600 screens)' },
+ size => { '550x412' }
+ },
+ {
+ name => { 'en' => 'Medium (for 1024x768 screens)' },
+ size => { '704x528' }
+ },
+ {
+ name => { 'en' => 'Large (for 1280x1024 screens)' },
+ size => { '880x704' }
+ }
+]
--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+
+<head>
+ <title>~~title</title>
+ ~~~head_code
+</head>
+
+<body bgcolor="#FFFFFF" ~~~body_additions>
+
+<table width="100%">
+<tr>
+ <td width="10%"></td>
+ <td width="1%">~~~button_first</td>
+ <td width="3%"></td>
+ <td width="1%">~~~button_previous</td>
+ <td></td>
+ <td width="1%">~~~button_next</td>
+ <td width="3%"></td>
+ <td width="1%">~~~button_last</td>
+ <td width="10%"></td>
+</tr>
+<tr>
+ <td align="center" colspan="9">
+ ~~~image
+ </td>
+</tr>
+<tr>
+ <td align="center" colspan="9">
+ <font size="+1" ~~~caption_additions> </font>
+ </td>
+</tr>
+</table>
+
+~~~body_code
+
+<table width="100%">
+<tr>
+ <td align="center">~~~button_slideshow</td>
+</tr>
+</table>
+
+</body>
+</html>