filtr 0.3
For a variety of reasons I've been using my N810 again, flashing the operating system and reinstalling stuff from scratch. The N810 does not make the Earth move, especially in a world of jail-broken iPhones. Its wireless chip is not terrifically strong, the GPS chip takes forever to establish a signal and the touch screen — let's be honest — makes you pine for Apple.
But it is a pretty reliable workhorse of a device if you approach it with a measure of tolerance (compassion?) and — especially in a world of jail-broken iPhones — there is an impressive wealth of software already written and/or ported to run with little hassle.
Which really means that
installing anything not already in the application
manager
or with a handy click to install
button
on the maemo.org
download pages is also mostly
a pain in the ass but to be fair this is more a by-product
of the Linux/Debian community than it is any individual architecture
astronauts at Nokia. Thank god for Jörg Gronmayer, who maintains a
searchable index of all the various packages and
repositories
that you need to configure to install anything.
The N810's operating system (Maemo) is pure open source as is 99% (100?) of the software that runs on it. I have no beef with commercial software or developers but that something like Maemo came out of an environment that otherwise embraces stuff like Symbian's security model is impressive and refreshing and deserves to be encouraged.
Just for kicks a few months ago I pulled down a copy of ModestMaps from trunk, no less, using Subversion and wouldn't you know it ws-compose.py ran out of the box. Just like that. It blew its brains out trying to do Atkinson filtering but otherwise generating maps and pinwins Just Worked !
Anyway, imagine my surprise when I discovered that someone had actually gone to the trouble of porting ImageMagick, of all things, to run on the N810. Which got me wondering : Would filtr run under Maemo? At its core it is just a glorified shell script that calls a whole bunch of other command line utlities. It took a little bit of wrangling on a Saturday afternoon to satisfy all the dependencie but, lo, it works!
Setting it up is a bit of a chore so here is a step-by-step guide :
- Install the OpenSSH packages that come (listed in the application manager) with the N810 by default, or at least by default with the most recent OS update.
- Install the gainroot
application
. It's just easier and faster than the alternatives.Actually, I am less convinced thatgainroot
— or theroot shell
at all — is even useful. Everything in Maemo is wrapped in the iron hug of sudo so you are probably better off just logging in (via ssh) as root once (yes, root) and adding the ability tosu
up to root to the /etc/sudoers file. At that point, go ahead and update your sshd_config file to disallow logins as root, if that creeps you out (it should).The only caveat if you do disable root login is that you will hold yourself at gun point every time you edit the /etc/sudoers file. If you are sloppy, like me, and make a mistake your N810 will continue to work in its current state butlittle things
like the application manager will be permanently hosed until you reflash the device (becausesudo
will stop working and logging in as root, in order to fix its config file, is disabled).This is the Unix permissions model doing exactly what it was designed to do, by the way. Given that there is no other way to log in to the device as root — say, some obscure (but documented, please) keyboard dance that could be performed at startup (but not without first checking that the default root password had been reset) — then you're left with one of two bad choices : do exactly what I did (or just disable root login altogether) and hope for the best or just leave root logins enabled. And hope for the best.All things considered, I prefer the latter. I had previously written something about making the sshd_config file writable by the default user but, with a moment's reflection, that proved to be little more than window dressing : You can edit the file to your heart's content but without the ability to restart sshd (which requires that you are root after all) it's pretty much moot. It's true that you could just restart the device in order to reflect the changes but assuming that you've chosen decent passwords, the ability to log in doesn't really give a person much but it is does provide a way for you to stop stabbing yourself in the face. You also won't give every other application running as useruser
the ability to silently modify your sshd_config file.So, with all that in mind, moving right along... - Install the wifiinfo application so you
can figure out what your IP address is. That's right,
the N810 has no
ifconfig
command.ifconfig
is also available but it won't be in your default PATH so choose your poison... - Install
Python which is a total nuisance but basically
involves ssh-ing to your N810 as root (see above) and then following the instructions. For whatever reason there is no standard
package
for Python even though all you end up doing is typing to commands in a shell. Once you get over the bad taste in your mouth it's pretty straightforward. - While you're there you might as well install the Python GPS bindings, since they don't come built-in and you're going to be running apt-get, anyway.
- Install ImageMagick. If you've ever had to do this before you will perhaps find some cold comfort knowing that this is actually the easiest part of the process.
- Finally, pull down the most recent version of filtr or at least version 0.3 and higher. filtr is just a shell script and it tries to be smart about knowing where the things it needs to run are located so you should be able to simply uncompress the package and run it as-is.
The big difference between versions 0.23 and 0.3 is that two of the dependencies, written in C, have been replaced with Python versions. Specifically : jhead has been replaced by a short script that uses Gheorghe Milas' jpeg.py to move EXIF data from the source file to the filtr-ed version and md5sum with Nick Craig-Wood's port.
This probably means that filtr itself will be that much slower but, really, who cares and it means that the program will run on more hardware than I have the time or energy to suffer compiling jhead for. Despite the glorious madness of tools like PAMP (or a PHP port for Maemo) Python continues to be the thing that finds its way on to just about every computer, large or small. This probably also means that version 0.31 will check for the faster C applications and then fall back to the Python ones.
That is all. It's not particularly fast, by any means. But it works and that is good and it opens up some interesting possibilities. For example, if I installed the py-inotify libraries (I just did) I could send via Bluetooth or whatever a day's worth of (geotagged) photos to a special directory before going to bed. That would trigger a process to filtr the photos, plot them on a map with ws-pinwin and then use the Moo API to generate postcards. Then wake up in the morning to complete the process (read : enter my credit card number). I'm not actually sure that poor little Python could do all of that under Maemo without completing melting down but, done with a little care and hand-holding, it's definitely possible.
Or something like that. Meanwhile : filtr 0.3
This blog post is full of links.
#filtr03FireDopplGängEaglr
See also : Dan's Twitter API updates, FireEagle and new Flickr API fun for a variation on the theme and a little more detail on some of the Flickr API methods mentioned below.
First, there was filtr
but that's
another story entirely. The point being that I gave up
carrying around a capital-C camera a few years ago choosing
instead to make do with cameraphones and the availability of
cheap, unlimited data-plans in the U.S.
I am mostly lazy and can't really be bothered to shuttle photos around from one device to another only to move them again to the giant device in the sky called Flickr. Before filtr I relied on the upload by email feature to snag a photo and quickly share it with the future-past but the desire to touch up — or filter — the photos before upload meant that I needed to write my own service to accept, process and then finally upload pictures to Flickr using the API.
Which is what I want to talk about. Sort of.
The advantage of an intermediary service is that you can configure it to use the photographs it receives
as triggers for other services. In my case this has always
meant tags and geotags. Sometimes it is easy : It's pretty
clear that I can tag anything that comes through with
cameraphone
. Sometimes it is possible : I can
query a photo's EXIF data for a model number and assign an
appropriate machinetag, say
ph:camera=n82
. Other times, it's just plain
wrong or so not right enough as to be useless : If I
hardcode the tag
for all my
uploads it will probably be right unless I happen to
go out of town for the weekend or otherwise forget to update
the tools.san francisco
Remember: Mostly lazy.
Applications like ZoneTag and Shozu have always had the ability to geotag your
photos using a combination of GPS data and surrounding cell
tower data. ZoneTag even tries to learn what tags are likely
to map
to a given spot but since neither application
have any way to let me massage the actual photo they've never really
fit the bill.
For a short time, I tried to use del.icio.us as a datastore for frequently
photographed places. For example, if I took a photo of
something posted to the
Wall of Rant, in San Francisco's Mission
District, I could add some magic text to the photo that
would tell my intermediary service where the photo was
taken. The text g:wallofrant
would tell the
computer-squirrels to ask the del.icio.us API for all my
posts tags del:bookmark=geo, find the
one titled wallofrant
(Why the title instead of a tag? Who knows, it
was a long time ago...) and then pull out the
geo:lat
and geo:lon
tags and use
them to call the Flickr geotagging API
methods.
This eventually morphed in to sometime completely
different called (drumroll) delicious maps
but that's also another story and the lesson of trying to
use this for photo uploads was (another drumroll, please)
that I am mostly lazy and could never be bothered to add new
photo
places to del.icio.us let alone remember
whether the special code was
or
wall of rant
. So, what to do instead?wallofrant
You're thinking about FireEagle, aren't you? Me too, but back then it was still just a sparkle in Tom's eye so there wasn't any way for my computers to talk to his computers and make beautiful mus^H^H^H I mean, powerful synergies. Sad face. In the meantime, Dopplr launched a public API that allowed you to query for both your current location and where you said you'd be travelling on a specific date.
Angels sing.
So, I wrote Flickr::Upload::Dopplr which piggy-backs on top of the excellent Flickr::Upload and Net::Dopplr Perl libraries, written by Christophe Beauregard and Simon Wistow respectively. If you've ever used Flickr::Upload to upload a photo there isn't much difference except for some extra Dopplr specific arguments that you need to pass to the constuctor. Like this :
use Flickr::Upload::Dopplr; my %dopplr_args = ('auth_token' => 'JONES!!!!', 'tagify' => 'delicious'); my %flickr_args = ('key' => 'OH HAI', 'secret' => 'OH NOES',, 'dopplr' => \%dopplr_args); my $uploadr = Flickr::Upload::Dopplr->new(\%flickr_args); my $photo_id = $uploadr->upload('photo' => "/path/to/photo", 'auth_token' => 'O RLY');
Meanwhile, prior to actually sending the photo to Flickr
the library asks the photo when it was taken by checking the
DateTimeOriginal
EXIF header and then asking
the Dopplr API where you were on that date. (If there is no EXIF data
then the current date is assumed. So it goes.) What comes
back is a big bag of data about the city you said you were
in including its name (tag!), latitude and
longitude (geotag!) and a unique identifier in the Geonames database
(machine tag!) Finally, since Dopplr uses different unique
identifiers for places, the library tries to find a matching
sister location in the Flickrverse using the flickr.places.find API method (profit!).
Because Dopplr deals in day-long chunks of time it can sometimes happen that the space-time tube will eat itself and your photos may end on the other side of the country. That's what happened to me shortly after the official launch of FireEagle and Dopplr happily told it I had a 09:00 AM flight to Austin even though a few short inches of snow in Dallas had paralyzed most of the air travel in and out of Texas that day.
Computers are sometimes dumb that way and I find that I am happier if I don't try to fight it.
The holy grail remains magic-style talk to the cloud
GPS
integration with cameras, to record location data, so it was a pleasant shock to wake
up one morning a couple months ago and see that Nokia had
released a freely available piece of software called Location Tagger. Nokia, and others, have been shipping phones with built-in GPS units for a while now but until recently they've suffered from battery issues
and generally poor integration with other applications, notably the camera. Location Tagger does pretty much what it sounds like : It sits quietly in the background until the camera's shutter button is pressed and then it asks the sky for its location and writes latitude and longitude data to the photo's EXIF data.
The answer is yes. It means you can use (drum solo, please) Flickr::Upload::FireEagle to not only geotag your photos but, in turn, use your photos to update FireEagle itself.
Angels rock out.
It goes without saying that the dynamics between where a
photo says you are, the offset in time engendered
by a service that brokers your location
and what
you really mean get fuzzy and potentially complicated
very quickly. So, this is how it works :
It's a bit involved. The first thing that happens is the photo you're trying to upload is poked for EXIF data, specifically any GPS information and when it was taken (the using *DateTimeOrginal* field). If there is no date information, the current time is assumed. If there is GPS data then the date is tested to see if the photo was taken falls within an allowable window of time. By default, this is (1) hour from "right now". An alternate value may be set by passing an *offset_gps* argument, measured in seconds, to the *upload* method. If the GPS information was added recently enough then FireEagle is queried for your most recent location hierarchy. If the GPS information is more recent than the data stored in the hierarchy (the location with the "best guess" of being correct) then FireEagle is updated with the latitude and longitude recorded in the photo. Moving right along, whether or not we've just updated FireEagle the service is queried for your current location (again). Once the hierarchy has been retrieved, the next step is to try and retrieve a "context" node. Whereas when testing GPS information the "best guess" node is assumed this is not necessarily the case when trying to use FireEagle to add tags. The context node is determined by comparing the photo's date against the *located-at* (or date recorded) attribute for specific items in the FireEagle hierarchy. Since most cameras still don't record GPS information it is necessary to do some work to gues^H^H^H I mean infer how "close" you are to the last recorded location. For example, if it's been more than a couple of hours since you last updated FireEagle you might still be in the same neighbourhood but if it's been more than half a day chances are good that you're been on the move but are still in the same city. The following tests are applied : * First a "best guess" location is queried If it is present and its *located-at* date is less than or equal to an hour, it is the context node. An alternate value may be set by passing a *offset_fireeagle_exact* argument, measured in seconds, to the *upload* method. * Next a location of type "neighborhood" is queried If it is present and its *located-at* date is less than or equal to two hours, it is the context node. An alternate value may be set by passing a *offset_fireeagle_neighbourhood* (or neighborhood) argument, measured in seconds, to the *upload* method. * Next a location of type "locality" is queried If it is present and its *located-at* date is less than or equal to twelve hours, it is the context node. An alternate value may be set by passing a *offset_fireeagle_locality* argument, measured in seconds, to the *upload* method. * If none of those tests pass then... ...there is no context node. Assuming that a context node has been identified *and* there is GPS information stored in the photo, the *flickr.places.findByLatLon* method is called (passing the photo's latitude and longitude) to ensure that the (Flickr) places IDs for both the response and the context node match. If they *don't* match then the context node is destroyed and the following tags are added : places:PLACETYPE=PLACEID; woe:id=WOEID; the name of the location (formatted according to the object's "tagify" rules). On the other hand, if the context node is still around, after all that, then it is used to add tags. At a minimum a fireeagle:id=CONTEXTNODEID tag is added. If the place type for the context node is equal to or more precise than a neighbourhood, the neighbourhood's name is added as a tag. If the place type for the context node is equal to or more precise than a locality, the locality's name is added as a tag as well as fireeagle:id=ID, places:locality=PLACEID and woe:id=WOEID tags. We're almost done : Assuming a context node and no GPS information in the photo, the nodes latitude and longitude are calculated to use as arguments when calling the *flickr.photos.geo.setLocation* method. The coordinates are "calculated" because not every location in the FireEagle hierarchy has a centroid. If no centroid is present then the node's bounding box is used and the centroid is assumed to be the center of the box. The photo's "accuracy" (in Flickr terms) is determined according to the node's place type. Finally, the photo is uploaded (and geotagged if necessary). No really.
Like Flickr::Upload::Dopplr, the FireEagle version simply defines a few extra arguments to the constructor and then hands all heavy lifting off to Simon Wistow's Net::FireEagle library.
<shameless_plug>Please for you to write an extension for the Flickr Uploadr that does the same thing. I am lazy and fear that I will never actually get around to doing it no matter how much I say I want to.</shameless_plug>
The next step is to work through the two libraries, find
the common methods and move them into a base class. So far,
the only name I've been able to come up with is
Flickr::Upload::Locatify
so I would welcome any better
suggestions. Once that's done I'd like to work out how to
structure things so that it is easy for developers to chain a
series a libraries together to read and write location data
across services.
For example, Flickr::Upload::FireDopplr will ... uh, well I'm still working through the possibilities. Ask Dopplr for your current city if the FireEagle/GPS magic returns nothing? Tell Dopplr to create a new trip if the location data inferred from a photo doesn't match your current city? All of the above?
Something like that, anyway.
This blog post is full of links.
#firedopplr