Initial revision
authorgc <gc>
Sat, 5 Mar 2005 10:26:14 +0000 (10:26 +0000)
committergc <gc>
Sat, 5 Mar 2005 10:26:14 +0000 (10:26 +0000)
booh [new file with mode: 0755]
booh-gui [new file with mode: 0755]
html_merges.rb [new file with mode: 0644]
themes/simple/parameters.rb [new file with mode: 0644]
themes/simple/skeleton.html [new file with mode: 0644]

diff --git a/booh b/booh
new file mode 100755 (executable)
index 0000000..f20fe1d
--- /dev/null
+++ b/booh
@@ -0,0 +1,189 @@
+#!/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
diff --git a/booh-gui b/booh-gui
new file mode 100755 (executable)
index 0000000..0cc0ce8
--- /dev/null
+++ b/booh-gui
@@ -0,0 +1,45 @@
+#!/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
diff --git a/html_merges.rb b/html_merges.rb
new file mode 100644 (file)
index 0000000..39e1fcb
--- /dev/null
@@ -0,0 +1,278 @@
+#
+#                         *  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
+
diff --git a/themes/simple/parameters.rb b/themes/simple/parameters.rb
new file mode 100644 (file)
index 0000000..ecaa6fe
--- /dev/null
@@ -0,0 +1,41 @@
+#
+#                         *  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' }
+    }
+]
diff --git a/themes/simple/skeleton.html b/themes/simple/skeleton.html
new file mode 100644 (file)
index 0000000..c0bbb34
--- /dev/null
@@ -0,0 +1,44 @@
+<!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>&nbsp;</font>
+    </td>
+</tr>
+</table>
+
+~~~body_code
+
+<table width="100%">
+<tr>
+    <td align="center">~~~button_slideshow</td>
+</tr>
+</table>
+
+</body>
+</html>