Archive for the ‘Projects’ Category

(on Technorati , Del.icio.us)

open-with for the command-line

Update 2008/11/18: Use xargs ๐Ÿ˜›

Here’s a bash script that you can pipe output into and tell it to run a specific program with the output as arguments. I’ve named it open-with and placed it in my personal script directory: /home/steve/bin/. Look within the script at a couple of the examples for how to use it.

#!/bin/bash
 
PROG=`basename $0`
 
DESC="Read arguments from standard input and run a specified program
with them.  Meant to be used as output for a pipe."
 
 
USAGE="OUTPUT | $PROG \"PROGRAM-NAME [OPTIONS AND ARGUMENTS]\""
 
EXAMPLES="
# List (with details), all the files that include \"downloads\" in their name:
  find /home/ -iname \"*downloads*\" | $PROG \"ls -l\"
 
# Queue all AVI files in current directory in vlc:
  ls *.avi | $PROG vlc
 
# View all time-related icons with eye-of-gnome:
  find /usr/share/icons/gnome/ -iregex \".*[^mul]time.*\" | open-with eog
"
 
function Usage() {
  echo "DESCRIPTION: $DESC" ; echo
  echo "USAGE: $USAGE" ; echo
  echo -n "EXAMPLES: $EXAMPLES"
}
 
# Quick check to see it's being called correctly, if not, print Usage and exit
if [ ${#@} -ne 1 ]
then
	Usage
	exit
fi
 
files=()						# empty array
while read -r					# read from stdin
do
	files+=( "$REPLY" )			# add result of read to array
done
 
# assume $1 is a valid program
$1 "${files[@]}"				# pass arguments to specified program

Motivation

You’re sitting at the command line and have a list of images (in different locations) that you would like to browse. Most image viewers let you iterate over a set of images, but only within the same directory. What would be great is if they accepted input from stdin through a pipe!

$ cat my_list_of_images | my_image_viewer

I didn’t find anything that did that, but using the open-with script, you can do something similar:

$ cat my_list_of_images | open-with my_image_viewer


Browsing a select list of images is actually kind of nice. It’s like a playlist for your image viewer – a viewlist. ๐Ÿ™‚ Anyway, I’m sure there’s some problems with this script. Feel free to provide suggestions in the comments. But I certainly don’t want to look at it for a while….

I hate shell scripting

With a passion. It’s not a great surprise… many programmers do. I’m willing to go on record and state that I hate it even more than PERL programming. I rarely do it, and when I decide to try something that seems like it would be simple, it turns out taking forever due mostly to quirks. The rest of this post is a bit about how I went about writing this script, which ended up being mostly given to me by some #bash gurus on IRC. And it’s a bit of a rant.

Although not many GUI programs seem to accept stdin as input, most accept filenames as arguments:

$ eog image1.jpg image2.jpg image3.jpg "/home/steve/image seven.jpg"

So I figured I would just have to convert the list of images into an acceptable format: quoted, absolute filenames, separated by space. Doing this depends entirely on the format the list is currently in, but it’s likely a list of unquoted filenames separated by newlines:

/home/steve/image1.jpg
/home/steve/my images/wow.jpg
/tmp/anotherimage.png

For me, my test list looked like this:

/usr/share/icons/gnome/48x48/stock/generic/stock_timezone.png
/usr/share/icons/gnome/16x16/stock/generic/stock_timezone.png
/usr/share/icons/gnome/16x16/stock/generic/stock_timer.png
/usr/share/icons/gnome/16x16/stock/generic/stock_timer_stopped.png
/usr/share/icons/gnome/16x16/stock/form/stock_form-time-field.png
/usr/share/icons/gnome/24x24/stock/generic/stock_timezone.png
/usr/share/icons/gnome/24x24/stock/generic/stock_timer.png
/usr/share/icons/gnome/24x24/stock/generic/stock_timer_stopped.png
/usr/share/icons/gnome/24x24/stock/form/stock_form-time-field.png

I was looking for icons of clocks or representations of time, and I obtained that list using find:

$ find /usr/share/icons/gnome/ -iregex ".*[^mul]time.*"

So I can’t pipe it into my image viewer, but I can use the output as the command-line arguments if I change the newlines to spaces. find has an option for formatting the output which is perfect:

$ find /usr/share/icons/gnome/ -iregex ".*[^mul]time.*" -printf "'%p' "
'/usr/share/icons/gnome/48x48/stock/generic/stock_timezone.png' '/usr/share/icons/gnome/16x16/stock/generic/stock_timezone.png' '/usr/share/icons/gnome/16x16/stock/generic/stock_timer.png' '/usr/share/icons/gnome/16x16/stock/generic/stock_timer_stopped.png' '/usr/share/icons/gnome/16x16/stock/form/stock_form-time-field.png' '/usr/share/icons/gnome/24x24/stock/generic/stock_timezone.png' '/usr/share/icons/gnome/24x24/stock/generic/stock_timer.png' '/usr/share/icons/gnome/24x24/stock/generic/stock_timer_stopped.png' '/usr/share/icons/gnome/24x24/stock/form/stock_form-time-field.png'

That’s great for me, because I’m using find. But not very useful if I’m not, so I wanted something more generic. Of course, there are many ways to do this, and again, I’m by no means a command-line guru. But here’s how I started:

$ find /usr/share/icons/gnome/ -iregex ".*[^mul]time.*" | sed -e 's/^/"/' | sed -e :a -e '$!N;s/\n/" /; ta' | tr '\n' '"'

This wrapped the lines in double-quotes and join them together with a space in between. The find command is the same as before, minus the formatting because that’s what I was trying to find an alternative to. The output of find is piped into sed, which adds a " at the beginning of each line. This output is then sent to another sed which replaces the newline character at the end of each line with a closing double-quote and a space, joining all lines into a single line. Finally, that output is piped into tr which replaces the one remaining newline with a final double-quote.

If the files don’t include spaces or other troublesome characters (mine didn’t), then you could get away with simply changing the newlines into spaces. But again, I wanted something generic.

$ find /usr/share/icons/gnome/ -iregex ".*[^mul]time.*" | tr '\n' ' '

Anyway, now that we have something that creates the desired input, we just have to wrap it in back-ticks and put the whole mess as the argument to the image viewer! In my case, I’m using eye-of-gnome (or eog).

$ eog `find /usr/share/icons/gnome/ -iregex ".*[^mul]time.*" | sed -e 's/^/"/' | sed -e :a -e '$!N;s/\n/" /; ta' | tr '\n' '"'`

Wait a second. That doesn’t actually work. Why not? Running the backtick contents by itself seemed to produce the correct output. Copying this output verbatim as arguments to eog worked as expected. The problem was that when the quoted arguments were manually entered on the command-line, bash (silently) escapes the filenames, removing the quotes, adding backslashes before space,s etc. But when the pipeline is wrapped in backticks, the result is not escaped, and eog complains about not being able to find files that begin with quotes. Fine. I was not about to write a bash “escape” script – something like that should already exist, right? And it should be built in to bash! Perhaps it’s even called “escape“. Well, if there exists such a built-in, I couldn’t find it. But I had to be going about this the wrong way. Heading over to IRC, it was kind of difficult to explain the problem, but ferret eventually gave me the meat of the script above:

files=(); while read -r; do files+=( "$REPLY" ); done < <(find /usr/share/icons/gnome/ -iregex ".*[^mul]time.*"); eog "${files[@]}"

It worked! I thanked him and began studying it. There were still a couple things I didn’t understand:

  • Why two angle brackets with a space between them? I understand the first one is probably redirecting input, but I don’t understand that one next to the opening parenthesis.
    Answer: The <(command) actually puts command‘s output in a temporary file and produces that filename. So <(command) becomes tempfile. (Thanks, kojiro.)
  • If I open some video or audio files in totem using open-with, there’s an odd delay. Using vlc doesn’t produce a delay, however.

And to think this was originally going to be a micro-blog post in Twitter and identi.ca. Wow. It’s safe to say I still hate shell scripting. ๐Ÿ™‚

Rhythmbox Plugin: Jump to Playing 0.3(.1)

Update 2012-01-29 – Deprecated:
Brief: This plugin has been deprecated. For future versions and updates, please go here.

Less Brief:If you’re using a newer version of Rhythmbox, you’ll need a newer version of this plugin. I’m not sure exactly which RB version the plugin format changed, but I am currently using Rhythmbox 2.90.1 on Ubuntu 11.10 and this plugin no longer works. However, Timo Loewe has ported jump-to-playing to Rhythmbox 3, all properly hosted and everything! Get it and any future updates here (https://github.com/dmo60/JumpToPlaying). This is the version I’m now using. Thanks, Timo! ๐Ÿ˜€

– – – – –

The following pertains to the deprecated version of the plugin…

– – – – –

This plugin will display the View : Jump to Playing Song link as a button in the toolbar and/or as link in the Browserโ€™s context menu. Other Rhythmbox plugins can be found here.

Screenshots


Using a future version of Rhythmbox – patch here – the menu item will appear in a plugin placeholder, above Properties. Otherwise, it will appear at the bottom, like previous versions.


From version 0.3, the Open Folder plugin will also be placed in the plugin placeholder.

Changes Since 0.2

Just a couple small changes since 0.2.

  • Selecting the context menu option in the preferences will now display the link in PodcastView and PlaylistView popups, as well as BrowserView and QueuePlaylistView.
  • Assuming the patch on bug 557152 is applied, this will place the context menu items in a plugin placeholder and allow the Preferences to remain the last menu item.
  • Update (Nov 10 2008): Modified version of patch has been applied to RB development trunk, so the next version of Rhythmbox will have this update. Yay! Version 0.3.1 of jump-to-playing is to account for the modifications. Please use it. ๐Ÿ™‚

Download

jump-to-playing-0.3.tar.gz jump-to-playing-0.3.1.tar.gz
Browse the Source: Here
Grab the Source: bzr branch "http://stevenbrown.ca/src/jump-to-playing/"

Installation

  1. Extract the jump-to-playing folder into your ~/.gnome2/rhythmbox/plugins/ directory (or ~/.local/share/rhythmbox/plugins/ directory, if the .gnome2 directory doesn’t exist). Completely replace any previous versions.
  2. (Re)Start Rhythmbox and enable the plugin in Edit : Plugins.

Todo

From my previous post.

  • the gconf keys in gconf-editor say they have no schema. The main pluginsโ€™ keys have a schema and donโ€™t give a warning. Definitely not serious, though.
  • it currently adds/removes the ui string when the options are toggled in the configure dialog. I have a feeling it might be better to only add/remove them in the activation/deactivation, and just hide/show here. Maybe faster?
  • it currently hides the browser button in small display mode. That has nothing to do with the jump-to-playing button. That should be in core, if it was decided that was the desired behaviour.
  • to hide the buttons in the small display, it checks the value at activation, and it connects to the View menuโ€™s toggleButtonโ€™s โ€œtoggledโ€ signal. So whenever itโ€™s toggled, the gconf value for the small display mode is checked, but I think thereโ€™s a delay sometimes. Pushing Ctrl D quickly a few times may result in incorrect UI presented. I remember deciding that this is due to a delay set on the gconf callback to overcome some other bugโ€ฆ.

All patches are welcome! ๐Ÿ™‚

Update 2008/10/26: Added screenshot, descriptions to screenshots, and link to main plugin page.

Update 2008/11/10: Added link to version 0.3.1 and added description.

Update 2010/12/08: Added alternative installation directory.

Jump-to-Playing Rhythmbox Plugin TODO

I haven’t looked at the plugin for a while, but I’ve been meaning to reproduce my “todo” list for it that I wrote on the rb-dev list a while back.

  • the gconf keys in gconf-editor say they have no schema. The main plugins’ keys have a schema and don’t give a warning. Definitely not serious, though.
  • it currently adds/removes the ui string when the options are toggled in the configure dialog. I have a feeling it might be better to only add/remove them in the activation/deactivation, and just hide/show here. Maybe faster?
  • it currently hides the browser button in small display mode. That has nothing to do with the jump-to-playing button. That should be in core, if it was decided that was the desired behaviour.
  • to hide the buttons in the small display, it checks the value at activation, and it connects to the View menu’s toggleButton’s “toggled” signal. So whenever it’s toggled, the gconf value for the small display mode is checked, but I think there’s a delay sometimes. Pushing Ctrl D quickly a few times may result in incorrect UI presented. I remember deciding that this is due to a delay set on the gconf callback to overcome some other bug….
  • in the context menus, ‘Properties’ should really be the last item. They need a placeholder put in the UI core. UPDATE: I’ve filed a bug with a patch attached here. Jump-to-Playing and other plugins will need to be updated when the patch is applied. I’ve just done it on my local copy w/Rhythmbox HEAD…. Looks like this:
    Before (red) and After (green) applying the patch and using an updated plugin

    Before (red) and After (green) applying the patch and using an updated plugin

  • Show the context menu item in PodcastView and PlaylistView popups, as well. I’ve added this in my local copy, already. Maybe I should just bump the version and release….

GNOME 3.0 Ideas (Intelligent Desktop)

This is based off of a Summer of Code application I made in 2007, titled “Intelligent Desktop.” Recent discussions have reminded me to at least blog about it. And given my current employment status, I have the time. ๐Ÿ™‚

Note: You may also be interested in File List Applet filelistapplet.

Messy Desk

The desktop – this gigantic area of screen real-estate – is a mess. Some people use their desktop to dump random files that they’re working on, or have recently downloaded. Others work tirelessly to keep the pretty background picture visible with minimal icon clutter. Still others find the Desktop useless because it fills up with icons too easily. In the Nautilus Desktop (GNOME’s default), icons can get placed on top of one another either by a bug in placement or simply because there is no space left, which really deters from the usability. Personally, I clump different themed files/folders into the corners of my desktop. When a file is added to the desktop procedurally, there is no obvious place to put it and thus no obvious place to look for it. This is compounded if there is a “hole” in one of my “icon clumps,” in which case the hole may be filled with the new icon making it extremely difficult to locate by both file name and screen location. I recently gave up on having mounted drives displayed on the desktop. Anything dynamic fails miserably as their location changes each time, and sometimes they even end up overlapping other icons. In any case, it seems the desktop requires maintenance to work, when it really shouldn’t.

An Intelligent Desktop would overcome icon clutter automatically and intelligently. It would also be a starting point to looking at potential benefits of a more dynamic desktop view. I’ll explain what I mean by this in a second. This is NOT that silly little notification that your desktop has old/unused icons on it.

Automatically Sorted, Categorized, Updated and Easily Searched

The desktop is a useful place to dump files, but retrieving them is a pain. In fact, browsing the desktop for that particular file (or folder) is a pain without a lot of maintenance. My idea requires an always-visible, on-the-desktop set of UI elements that I will call the Desktop Action Window (DAW). The easiest way to think of the DAW is as a sidebar for the desktop. (Don’t stand up quite yet, sidebar haters.) But rather than the DAW being a collection of meta-information or unrelated widgets, think of it as a controller to the desktop view (formerly just a desktop). Performing actions on the desktop via the DAW simply creates a new view of the desktop. The original/default view that is customized by the user will always be available. If you think in terms of Model-View-Controller, the current desktop is essentially everything. With the DAW, the DAW becomes the controller, the desktop viewing area becomes the view, and the model is partially hidden. The DAW should allow easy management of multiple views of the desktop, some automatic (Images, Movies, Recently Modified), some static (Default, Custom).

And you shouldn’t be concerned about a sizable widget infringing on your carefully chosen background, there are ways around that: the DAW could be hidden when no mouse movement on the desktop occurs (like the controls of a photo slide show), it could be semi transparent until the mouse is over it, it’s location could be customized, etc.

Some quick ideas for different actions in the DAW include:

  • An automatically generated list of types of files on the Desktop. Selecting one of them displays all icons of that type.
  • A text entry for string pattern matching.
  • Ability to easily hide all icons, except ‘always visible icons.’
  • Ability to have custom views displaying only icons that user specifies.
  • Ability to easily open file manager and display all files
  • Some form of icon pager or scrollable desktop view to allow for arbitrary numbers of icons to be displayed per view.
  • Ability to view and manipulate an arbitrary folder, such as Home, in the same way.

Mockups

This is where I stop the prose and leave you with a couple mockups. The “Overflow” view could probably be replaced with “New” or “Recent” for recently modified files. Anytime new files/folders/launchers have been added, the button could be flashing to grab the user’s attention. Better not to alter the default view at all, I think.

Update 2008/12/04: I’ve started implementing what I was thinking about with the automatic view filter as a GNOME panel applet. Check out File List Applet.

WordPress Upgrade Script

Even though the WordPress upgrade is easy, it’s troublesome. So I wrote a script to do it for me. Yep. There’s lots of these out there. And a lot of hosts (including mine) have a one-click install/update thing. But for some reason, I decided to write my own script. In python. Got to use a bunch of modules I’ve never used before, so it was a good experience.

How to Use

Run this script from the directory that contains your wordpress directory, on your server. I think it requires Python version 2.3. I ran it with 2.3.5. Use python -V to check the version. There’s two methods to run it.

With Prompts

1: Be prompted to push the Enter key to continue at each major step. Nice for the first time.

python wp-upgrade.py

Example output:

python ../src/wp-upgrade/wp-upgrade.py 
Current WordPress Version: '2.5'
Newest WordPress Version:  2.6.1
Downloading wordpress-2.6.1.tar.gz ...
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
Create working wordpress directory... 
			[[Press Enter to Continue]]
 
Update Wordpress root contents...  
			[[Press Enter to Continue]]
 
'/tmp/tmprpJTKu/wordpress' -> 'wordpress.working'
wp-trackback.php,  wp-config-sample.php,  wp-settings.php,  wp-rss2.php,  readme.html,  index.php,  wp-links-opml.php,  wp-pass.php,  wp-feed.php,  wp-register.php,  wp-rdf.php,  wp-rss.php,  wp-commentsrss2.php,  license.txt,  wp-comments-post.php,  wp-blog-header.php,  wp-load.php,  wp-mail.php,  wp-atom.php,  wp-cron.php,  wp-app.php,  xmlrpc.php,  wp-login.php,  
Replace wp-admin and wp-includes... 
			[[Press Enter to Continue]]
 
 
Update default themes and plugins...  
			[[Press Enter to Continue]]
 
'/tmp/tmprpJTKu/wordpress/wp-content' -> 'wordpress.working/wp-content'
index.php,  
'/tmp/tmprpJTKu/wordpress/wp-content/plugins' -> 'wordpress.working/wp-content/plugins'
akismet,  hello.php,  
'/tmp/tmprpJTKu/wordpress/wp-content/themes' -> 'wordpress.working/wp-content/themes'
default,  classic,  
 
Backup original, Rename working....
			[[Press Enter to Continue]]
 
 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
### VISIT 'http://stevenbrown.ca/blog/wordpress/wp-admin/upgrade.php' in your browser. ###
After that, you're All Done!
Go re-enable all your plugins and make sure everything works.
If you need to, you can always roll back by renaming the backup to 'wordpress'.
 
 
			[[Press Enter to Continue]]

Without Prompts

2. Do everything without a prompt. Do this by passing the -q option. The -q is for quiet and prints the same messages, but doesn’t wait for the user to press Enter. Blasts through the whole upgrade in one step.

python wp-upgrade.py -q

Example output would be the same as the above, minus the “[[Push Enter to Continue]]” bits.

What’s it do?

If you look at the above output, which is from my own site, you can see what it does. It will compare your installed wordpress version and to the latest available from http://www.wordpress.org. If your version is older, it will download the new one, extract it, perform the appropriate steps to update the old one. Note that the default themes and plugins will be overwritten, which is fine as long as you didn’t customize them. After it’s done, your wordpress directory should be up-to-date (you just have to visit the upgrade page), and you should have a wordpress 2.5 backup containing the directory as it was before running the script (and 2.5 would be the appropriate version). Also, there’s two variables you will (probably) want to customize: wpsite and wpdir. That’s it, basically.

Download

Browse the source and download the script here.

python treeview toggle

Had this post sitting around. Seems finished. May be helpful to someone. /me waves Wand of Publish +1

I was confused when I was playing around with this basic concept: adding a toggle widget to the treeview in pygtk. The reason for this is an inconsistency in the api model – or at least how I perceived it. With a regular toggle button, you create the widget and can manipulate it once it is drawn. The checkmark is toggled and the “toggled” signal is emitted. I only connect a signal handler to the toggled signal after. However, following this same logic, I created a list with a column of toggle widgets and tried clicking them… but nothing happened. The problem here was the toggled value was linked to the list’s data, and the data wasn’t actually changing. Even though the toggle signal was being emitted, the checkmark wasn’t being toggled because the data wasn’t changing, so I thought there was a problem with my code and the signal wasn’t being emitted. But actually, it would make more sense if it was a “clicked” signal that was being emitted, not the “toggled” signal.

Example source code:

#!/usr/bin/env python
 
# example basictreeviewtoggle.py
 
import pygtk
pygtk.require('2.0')
import gtk
import gobject
 
class BasicTreeViewToggleExample:
 
    # close the window and quit
    def delete_event(self, widget, event, data=None):
        gtk.main_quit()
        return False
 
    def column_toggled(self, cell, path, model):
        # get toggled iter, and value at column 0
        iter = model.get_iter((int(path),))
        val = model.get_value(iter, 0)
 
        # toggle the value
        val = not val
 
        # set new value
        model.set(iter, 0, val)
 
 
    def __init__(self):
        # create a new window
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_title("Basic TreeView Toggle Example")
        self.window.set_size_request(200, 200)
        self.window.connect("delete_event", self.delete_event)
 
        # create a ListStore with two columns to use as the model
        self.model = gtk.ListStore(gobject.TYPE_BOOLEAN, str)
 
        # create some list items
        for item in range(5):
            self.model.append([False, 'item %i' % item])
 
        # create the TreeView using the model
        self.view = gtk.TreeView(self.model)
 
        # create a CellRendererText to render the data
        self.cellrenderer_text = gtk.CellRendererText()
        self.cellrenderer_toggle = gtk.CellRendererToggle()
        self.cellrenderer_toggle.connect('toggled', self.column_toggled, self.model)
 
        # create the TreeViewColumns to display the data
        self.tvcolumntext = gtk.TreeViewColumn('TreeViewColumn 1')
        self.tvcolumntoggle = gtk.TreeViewColumn('tog', self.cellrenderer_toggle, active=0)
 
        # add the TreeViewColumns to the TreeView
        self.view.append_column(self.tvcolumntoggle)
        self.view.append_column(self.tvcolumntext)
 
 
 
 
        # add the cell to the tvcolumn and allow it to expand
        self.tvcolumntoggle.pack_start(self.cellrenderer_toggle, False)
        self.tvcolumntext.pack_start(self.cellrenderer_text, True)
 
 
        # set the cell "text" attribute to column 0 - retrieve text
        # from that column in treestore
        self.tvcolumntext.add_attribute(self.cellrenderer_text, 'text', 1)
 
 
 
        # make it searchable
        self.view.set_search_column(1)
 
        # Allow sorting on the column
        self.tvcolumntext.set_sort_column_id(1)
 
        # Allow drag and drop reordering of rows
        self.view.set_reorderable(True)
 
        self.sw = gtk.ScrolledWindow()
        self.sw.add(self.view)
        self.window.add(self.sw)
 
        self.window.show_all()
 
def main():
    gtk.main()
 
if __name__ == "__main__":
    tvexample = BasicTreeViewToggleExample()
    main()

Creating a DVD Slideshow in Linux

For my brother’s wedding, about a week ago, my sister wanted to do a slideshow for them. She’s done this before and she’s known for spending lots of time making very nice, emotional slideshows with carefully chosen pictures and music. Previously, she would count in her head while manually switch the slides with a traditional projector. (We have a lot of great family photos that are only on slides.) Anyway, she figured she’d use computers this time around and my assistance was “enlisted.” I kept thinking, “If only I had a Mac, I’m sure this would be easy….” But it turns out there’s a reasonable command-line program available on Linux that is just a little cumbersome (mostly because it’s command-line tool for something that really needs to be visual) – but works quite well: dvd-slideshow. I’m going to go over what I did, mention some quirks and how to work around them.

First, install dvd-slideshow (a set of command-line tools).

sudo aptitude install dvd-slideshow

You may want to get the latest version from the webpage and manually install that.

Update: While writing this, I have since discovered “slcreator” which looks like it would fill in the glaringly absent graphical component of dvd-slideshow. Though it hasn’t been updated for quite a long time…. it’s definitely worth investigating before going through the manual process yourself.

Step 1: Organize your digitized photos within a directory

Since my sister was the creative force behind this, she needed to see the photos as she was deciding on the order. Nautilus thumbnails were good enough, so I simply showed her how to rename files and made suggestions for organizing them by name (like naming a photo “12a.jpg” if you want the photo to be in between “12.jpg” and “13.jpg”). This worked in Nautilus, but in the next step, the ordering would be changed to 12a.jpg, 12.jpg, 13.jpg – which is probably a bug in dir2slideshow. (You could work around this by always using a single letter after the number.)

Step 2: Generate input file from images directory and customize

dir2slideshow -o output_directory -t seconds_per_picture -c crossfade_seconds images_directory

This will output a text file in the output_directory that contains all the images in the images_directory with specified transition and duration times. The order of the pictures should be how it is listed by name in your file browser, minus the bug I mentioned earlier. You can manually edit this file and then pass it to dvd-slideshow.

Multiple Directories:
My sister had arranged photos in multiple directories, each consisting of a theme (childhood, Halloween, travel, etc) and a specific song to go with it. So I just generated multiple input files with appropriate names, worked on individual sections, and eventually copied them all into a master input file keeping the desired order.

Adding Music and Silence:
Another bug I encountered was getting music to fade out at the correct time. In the input file, the format for adding music is this: audiofile:track:effect1:effect1_params:effect2:effect2_params . So I had my_sad_song.mp3:1:fadein:0:fadeout:5 saying I wanted it to spend 5 seconds fading out. Additionally, I wanted about 10 seconds of silence at the very end. Your are supposedly able to specify silence:duration_in_seconds but at the end of the slideshow, it wasn’t forcing the song to fade out in time to include that amount of silence – it seemed to be ignoring it at the end if there was no more photos. I got around this by creating a small file of silence, silence.wav, and using that instead of the built-in silence option.

Nice looking fonts
Another quirk I encountered was terrible looking fonts with the built-in title:duration:thought_provoking_title. I didn’t want to spend too long looking at the cause of this, so I just created some title images in the Gimp.

Step 3: Generate the Slideshow

dvd-slideshow -mp2 -nomenu -o tmp/working -f tmp/ALL.txt

The mp2 option is required to avoid an error message and has worked on all DVD players I’ve heard of, so far. The nomenu option is for creating a DVD with no menu – I just wanted it to start playing the slideshow when the disc is inserted into the player. The o option specifies the output directory and the f option specifies the input file created earlier. Once this finishes (it might take a while) you should have a DVD .vob (MPEG2) file and an xml file in the output directory.

Debugging:
I like to see how the final product will look, so I chose not to use the L (low quality) option for debugging. Instead, I created a smaller input file with specifically what I wanted to test. When I was happy with the test, I copied the changes into my master input file.

Step 4: Create the DVD Filesystem

dvd-menu -f tmp/working/ALL.xml -nomenu -mp2 -o tmp/working-dvd

This will output a folder dvd_fs in the output folder (tmp/working-dvd) containing VIDEO_TS and AUDIO_TS directories with the required files for a proper DVD.

Adding Content:
This is where you optionally add more files to the DVD. For me, I added two folders, Music containing the music used in the slideshow and Photos containing the photos used in the slideshow. A good idea would also be to add the source file and commands used to create the DVD and then you are distributing the source. ๐Ÿ˜‰

Step 5: Make an ISO to burn

mkisofs -dvd-video -udf -o ~/Desktop/slideshow.iso tmp/working-dvd/dvd_fs

This creates an ISO called slideshow.iso on the desktop.

Step 6: Burn the ISO

There’s many ways to burn an ISO, but just use Nautilus: right click on the icon on your desktop and select Write to Disc…. That’s it! Test it out in your DVD player.

References

Lots more info about specific commands and useful examples can be found at the dvd-slideshow’s documentation page.

Playing Video from your Linux PC on your Wii

Maybe you’ve watched youtube videos on your Wii using the Internet Channel or the promo videos on the Nintendo Channel and you thought it would be cool to watch other videos from your (Linux) PC. I know I did. But I wasn’t sure if it would be possible in a reasonable quality. Since then, I’ve decided the quality was unacceptable for me… But I’ll try to quickly document what I did for others.

You basically have two options: Put a decompressed copy of your video on your SD card and watch it in the Photo Channel OR watch it streaming from your PC over your network via the Internet Channel (like youtube).

1. Playing it directly off your SD card

Instructions for how to convert the video to play in the Photo Channel can be found here:
http://icculus.org/~dolson/wii-video-conversion.html
HOWEVER, 3/4 of an hour of decent quality video will cost 1+ gigabytes, due to the format. The quality will be maintained, but unless you have a 2GB card and/or small videos, this may not be feasible. I couldn’t get my 45min (350MB originally, I think) file to fit on my 1GB SD card in the appropriate format, so I gave up on this method. I was more interested in browsing multiple files on my PC, anyways.

On to the other option….

2. Stream it from your computer

For this method, you need a few more things:

  • A home PC accessible from the network via your Wii
  • Videos you want to play need to be converted to Flash video (FLV). To do this, you will need ffmpeg.
  • sudo aptitude install ffmpeg
  • Web server running on your home PC. I’m using Apache on an Ubuntu PC.
  • sudo aptitude install apache2 apache2-utils

Most of what follows can be configured, but I’m going to try and follow what’s default in Ubuntu (if I can remember correctly).

To keep things clean, I enabled user directories. To do this, you must enable the userdir mod in apache:

sudo a2enmod userdir

What are user directories?

This is a directory (usually called “public_html”) that every user can use to publish things (like webpages) on the webserver from their home directory. For me, my home directory is /home/steve/ so my user directory is /home/steve/public_html/ . It is optional, so I have to create it if it doesn’t already exist.

mkdir ~/public_html/

When accessing these user directories via a web browser (Internet Channel), you must enter your Home PC’s IP address, followed by a tilde (~) and your username.

"http://your.pc's.ip.address/~username/"

So accessing my public_html directory is done as follows: http://192.168.0.99/~steve/ . (Note that 192.168.0.99 is a private IP address and unless your computer is set up on your local network with the same IP AND your username is “steve”, this won’t work for you. ๐Ÿ˜‰ )

Test it, and make sure you’ve installed Apache and set up user directories correctly.

Flash Video Player

Now you need a compatible flash player to embed into your webpage. Wii’s Internet Channel is based on Opera, and includes Flash version…. 7?! Doh! Newer FLV players won’t work! Also, Full-screen mode isn’t possible so you want the video to be as large as possible, or to be easily zoomed in and centred – yup, it’s a pain. The best player I found for this was FLV Player, but feel free to look around for more. ๐Ÿ˜‰ Now put your player of choice (I chose player_flv_maxi.swf) in public_html somewhere so that it can be included in your webpage.

Example Preparing Video

An example command for converting your video to FLV using ffmpeg:

ffmpeg -i input_video.avi -ar 22050 -b 1280 -s 320x240 output.flv

Example Webpage

An example of an html page containing a video:

< !DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
 
	<title>Wii Video Test</title>
 
	<style type="text/css">
		body { background-color: #000; padding: 0 20px; color:#000; font: 13px/18px Arial, sans-serif; }
		a { color: #360; }
		h3 { padding-top: 20px; }
	</style>
 
</head>
<body>
 
    <object type="application/x-shockwave-flash" data="player_flv_maxi.swf" width="624" height="352">
        <param name="movie" value="player_flv.swf_maxi" />
        <param name="allowFullScreen" value="true" />
        <param name="FlashVars" value="flv=my_converted_video.flv&amp;autoload=1" />
    </object>
 
</body>
</html>

Note: both player_flv_maxi.swf and my_converted_video.flv must be in the same directory as this html page. For testing purposes, call this index.html and put it in your public_html directory.

That’s it, I think. Again, I wasn’t really satisfied with the compression of FLVs and the frame rate of bigger videos, so I ended up not using either of these two methods. I suppose a media PC, Apple TV, or PS3 or something would be better suited – none of which I have. ๐Ÿ™‚

Related

AttrDict Python Module

I’ve been doing quite a bit of Python hacking in my recent free time. A couple days ago, I had the desire for a dictionary that I could access key values just like object attribute names. For example, in the dictionary d={'key':'value'}, I wanted to be able to use d.key to return 'value'. I thought this would be a common desire and probably already exists (and might even be built-in somehow), so I went on to #python and asked the folk there. Nobody knew of anything. So I set off to write my own. I called it AttrDict.

Yesterday, I found something similar already exists. It’s called ObDict. Similar? Very! ๐Ÿ˜› But different enough that I continued mine… and have a somewhat complete python module of my own. So far it’s been a nice opportunity to learn more about Python objects and use the unittest module for unit testing.

It’s not 100% coverage of the dict interface, but it’s pretty close and I think it’s usable enough that I can slap a quick release together and work on other stuff. Bugs/patches/testing/suggestions welcome.

Update:

Wooops, forgot to write a bit more about it. Here’s the docstring from the module:

Simple extension of the built-in dictionary so that dictionary keys are mirrored
as object attributes. This is for convenience. You can do things like this:

d = dict() #standard dict, for comparison
a = AttrDict() #

d[‘ok’] = ‘this is ok’
d.ok -> AttributeError raised
d.ok = ‘test’ -> AttributeError raised

You cannot assign attributes to standard Python dicts.

a[‘ok’] = ‘this is ok’
a.ok -> ‘this is ok’ #attribute is automatically created
a.ok = ‘changed’
a[‘ok’] -> ‘changed’ #and the dict value is automatically updated
a.ok2 = ‘new value’ #adding new attribute, ok2
a[‘ok2’] -> ‘new value’ #dict key is automatically created

This introduces a limitation on the dictionary keys such
that they must be strings and provide valid Python syntax for accessing.

For example:

{‘123′:’valid’} #is a valid dictionary

but

mydict.123 #is not valid Python syntax.

Attempting to create a key that cannot be accessed through an attribute name
will raise an AttributeError Exception.

This module has not been built for optmization. Some of the method
documentation has been taken from Python’s dict documentation. For more info
on a particular method, refer to that. I’ve tried to mirror the effects of
the standard dict as closely as possible.

Recent Geekiness

Hmmm… I’ve been pretty quiet on the blog front. Better write something. Show some sign of life. Well, officially 2 weeks of not being gainfully employed and I’ve been making pretty good use of the time, I think! (I know, you’d expect more blog posts from someone who has more time – I’m weird). Even though I haven’t been blogging much, I *have* kept fairly active in Twitter, so if you follow that, it’s kind of like my mini-blog.

So what have I been doing? Naturally, most of my time has been spent on the computer. I finished a tool (written in Python) that I had started in the last week of employment – both for personal satisfaction and for the benefit of a (ex) colleague. I think it will be useful, and that makes me happy. ๐Ÿ™‚

Warning: the following is quite long and geeky. Feel free to skip to the end.

Distributions and Open Source 3D

I’ve done a lot of poking around with my computer, fixing lots of problems (and creating a few others). The most serious of these problems was my wireless connection, which appeared to die somewhat suddenly. I ended up trying multiple other Linux distributions over the course of resolving it. OpenSUSE had a nice polish to it, but I found the interface kind of cluttered. They seem to use their YaST back-end for everything configuration-related. Fedora 9 was really well organized and pretty, I was generally very impressed. But the best thing about Fedora 9? 3D acceleration worked when I booted it up! Even on the live CD! Not only that, but because of Fedora’s “Free” motto, this was the open source (ATI Radeon) driver! WHAT?! I couldn’t even get the proprietary (Catalyst) driver to work on Ubuntu!

Obviously, I had to do some more research. I found out that Fedora runs a lot of software that hasn’t been released as “stable” quite yet. Well guess what I’m running on my Ubuntu now? That same software. I’ve noticed my computer crash a few times when I leave certain other experimental software running for a while, but other than that, it’s stable enough for me to keep and enjoy the perks of 3D every now and then. But I certainly can’t advise it unless you’re willing to suffer the consequences – of which, there could definitely be. (I can’t use the closed source drivers, they somehow break my computer.) You could make a bootable thumb drive to test it out first. I did. Start here.

Performance, Games, and Screencasting

I guess I should talk about that. I read someone say the performance of the open source driver (radeon) is about 40% of the closed source driver (fglrx). 3D effects on the desktop work pretty good, but I can’t play FPSs (First Person Shooters) like Sauerbraten – an open source Quake-like game. In fact, I can barely play “Extreme Tux Racer.” Kinda sad. ๐Ÿ™ But I can play Neverball and CriticalMass! ๐Ÿ™‚ Oh, and I can kind of play Frets on Fire, an open source Guitar Hero clone (has a pretty funny tutorial). So the open source drivers aren’t as feature complete or as high performance as the closed source ones, but since AMD/ATI have become more open, releasing documentation and helping out the community, the open source drivers have been quickly closing the gap. This is very exciting for me. ๐Ÿ™‚

Anyway, enough of that.. I spent a lot of time playing around with 3d and getting my wireless to work again. And the primary solution to my wireless problem? Turning the wireless router upside down. It still cuts out every now and then, but it’s mostly solid now (although maybe a bit slower, due to some buggy drivers). yay. No Internet makes Steven cry. (I really wish I could run a cable to my room….)

I resolved connection problems with my printer (yet again). Oh, and I also set up mic recording and tested making screencasts. I want to use Istanbul, but it seems to have more problems and fewer options than gtk-recordMyDesktop. I was considering making screencasts, as video tutorials for introducing people to GNOME or other simple things. I’ve written down a few ideas, but I’m not sure where that will go. I would like to do it as a kind of mini series with a bit of polish, but I’d have to look into the somewhat shady world of Linux video editing.

Packaging

For some reason (perhaps I’m a bit of a masochist) I decided to learn about Debian packaging (creating those lovely .deb files that us Ubuntu users find so handy). My pain was further enhanced by choosing to package a library (Clutter), rather than a normal application. I found the documentation available to be overly verbose and not particularly plentiful – I suppose I wanted something concise and never found it. When I had finally produced two packages (the lib binary and the accompanying dev package) I could install on my system, I didn’t bother because a few other libs depended on the library I was updating, and I was tired of packaging. And I didn’t really want to create an even more unstable system. ^.^ But even though I didn’t use my packages (which I’m sure were far from “Debian” standards) I found the whole thing quite educational and I’m glad I went through it. I have a new respect for package maintainers and perhaps I can now package my own software (if I get around to writing something worth packaging). ๐Ÿ™‚

The non (less?) Geeky

Aside from all that geeky stuff, I’ve been spending a bit of time with friends and family, and doing lots of rollerblading. Played RockBand at Jeremy’s birthday on 360. Sung til everyone’s ears bled. Drums are fun. That game is seriously fun. It just came out for Wii, but I think I will wait for the next Guitar Hero which promises even more and should be out in Fall. More is better, right? I like more. Oh and I still have to push out that blog post about my roadtrip….