Add Google poster downloader D-Bus service
authorPhilipp Zabel <philipp.zabel@gmail.com>
Tue, 3 Nov 2009 13:37:51 +0000 (14:37 +0100)
committerPhilipp Zabel <philipp.zabel@gmail.com>
Thu, 12 Nov 2009 18:23:24 +0000 (19:23 +0100)
Makefile.am
configure.ac
data/org.maemo.movieposter.GoogleImages.service.in [new file with mode: 0644]
src/poster/google-poster-downloader.vala [new file with mode: 0644]

index 4bb1c09..aabbb5b 100644 (file)
@@ -10,6 +10,7 @@ bin_PROGRAMS = \
         cinaest
 
 libexec_PROGRAMS = \
+       google-poster-downloader \
        imdb-plaintext-downloader
 
 pkglib_LTLIBRARIES = \
@@ -18,7 +19,8 @@ pkglib_LTLIBRARIES = \
 
 dbusservice_DATA = \
        data/org.maemo.cinaest.service \
-       data/org.maemo.cinaest.IMDb.service
+       data/org.maemo.cinaest.IMDb.service \
+       data/org.maemo.movieposter.GoogleImages.service
 
 desktopentry_DATA = \
        data/cinaest.desktop
@@ -135,6 +137,19 @@ imdb_plaintext_downloader_LDADD = ${DBUS_LIBS} ${GIO_LIBS} ${SQLITE3_LIBS} -lz
 ${imdb_plaintext_downloader_SOURCES}: ${imdb_plaintext_downloader_VALASOURCES}
        ${VALAC} -C ${imdb_plaintext_downloader_VALASOURCES} ${imdb_plaintext_downloader_VALAFLAGS}
 
+google_poster_downloader_SOURCES = \
+       src/poster/google-poster-downloader.c
+
+google_poster_downloader_VALASOURCES = \
+       src/poster/google-poster-downloader.vala
+
+google_poster_downloader_VALAFLAGS = --vapidir ./vapi --pkg dbus-glib-1 --pkg gio-2.0
+google_poster_downloader_CFLAGS = ${DBUS_CFLAGS} ${GIO_CFLAGS}
+google_poster_downloader_LDADD = ${DBUS_LIBS} ${GIO_LIBS}
+
+${google_poster_downloader_SOURCES}: ${google_poster_downloader_VALASOURCES}
+       ${VALAC} -C ${google_poster_downloader_VALASOURCES} ${google_poster_downloader_VALAFLAGS}
+
 BUILT_SOURCES = \
        ${cinaest_SOURCES} \
        ${libimdb_plugin_la_SOURCES} \
index 7e52d5b..df89570 100644 (file)
@@ -68,5 +68,6 @@ AC_OUTPUT([
        po/Makefile
        data/org.maemo.cinaest.service
        data/org.maemo.cinaest.IMDb.service
+       data/org.maemo.movieposter.GoogleImages.service
        data/cinaest.desktop
 ])
diff --git a/data/org.maemo.movieposter.GoogleImages.service.in b/data/org.maemo.movieposter.GoogleImages.service.in
new file mode 100644 (file)
index 0000000..a455c60
--- /dev/null
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.maemo.movieposter.GoogleImages
+Exec=@libexecdir@/google-poster-downloader
diff --git a/src/poster/google-poster-downloader.vala b/src/poster/google-poster-downloader.vala
new file mode 100644 (file)
index 0000000..d12cacb
--- /dev/null
@@ -0,0 +1,205 @@
+using GLib;
+
+[DBus (name = "org.maemo.movieposter.Provider", signals = "fetched")]
+public interface Provider {
+       public abstract int Fetch (string title, string year, string kind) throws DBus.Error;
+       public abstract int FetchThumbnail (string title, string year, string kind) throws DBus.Error;
+       public signal void fetched (int handle, string path);
+}
+
+// http://live.gnome.org/MediaArtStorageSpec
+
+// Sample implementation of org.maemo.movieposter.Provider that uses Google 
+// images's first result as movie poster. There is of course no certainty 
+// that the first result on Google images is indeed the movie's poster - there
+// are quite a few false positives, especially for non-mainstream movies.
+
+public class GoogleImages : Object, Provider {
+       int fetch_handle;
+
+       public int Fetch (string title, string year, string kind) throws DBus.Error {
+               int handle = fetch_handle++;
+
+               _fetch_async.begin (title, year, kind, false, handle);
+               return handle;
+       }
+
+       public int FetchThumbnail (string title, string year, string kind) throws DBus.Error {
+               int handle = fetch_handle++;
+
+               _fetch_async.begin (title, year, kind, true, handle);
+               return handle;
+       }
+
+       private async void _fetch_async (string title, string year, string kind, bool thumbnail, int handle) {
+               uint u = 0;
+               size_t hread = 0;
+               string [] pieces = title.split (" ", -1);
+               string stitched = "";
+               bool first = true;
+
+               stdout.printf ("Fetching %s \"%s (%s)\" ...\n", kind, title, year);
+
+               if (title == null || title == "")
+                       title = "  ";
+
+               if (year == null || year == "")
+                       year = "  ";
+
+               // Convert the title and year into something that will work for Google images
+
+               while (pieces[u] != null) {
+                       if (!first)
+                               stitched += "+";
+                       stitched += pieces[u];
+                       u++;
+                       first = false;
+               }
+
+               stitched += "+";
+
+               u = 0;
+               first = true;
+               pieces = year.split (" ", -1);
+
+               while (pieces[u] != null) {
+                       if (!first)
+                               stitched += "+";
+                       stitched += pieces[u];
+                       u++;
+                       first = false;
+               }
+
+               stitched += "+movie+poster";
+
+               // Start the query on Google images
+
+               stdout.printf("GET http://images.google.com/images?q=" + Uri.escape_string (stitched, "+", false) + "\n");
+
+               File google_search = File.new_for_uri ("http://images.google.com/images?q=" + Uri.escape_string (stitched, "+", false));
+
+               try {
+                       char [] buffer = new char [40000];
+                       string asstring;
+                       size_t total = 0;
+
+                       // Fetch the first page
+
+                       InputStream stream = google_search.read (null);
+
+                       while (total < 40000) {
+                               hread = yield stream.read_async ((char *)buffer + total, 40000 - total, Priority.DEFAULT_IDLE, null);
+                               total += hread;
+                               if (hread == 0)
+                                       break;
+                       }
+                       buffer[total] = 0;
+
+                       asstring = (string) buffer;
+
+                       // Find the first result
+
+                       string found = null;
+                       int i;
+                       char end;
+                       if (thumbnail) {
+                               do {
+                                       found = asstring.str ("http://t");
+                               } while (found != null && !found.offset (9).has_prefix (".gstatic.com/images?q=tbn"));
+                               i = 0;
+                               end = ' ';
+                       } else {
+                               found = asstring.str ("href=/imgres?imgurl=");
+                               i = 20;
+                               end = '&';
+                       }
+
+                       if (found != null) {
+
+                               StringBuilder url = new StringBuilder ();
+                               long y = found.len();
+
+                               while (found[i] != end && i < y) {
+                                       url.append_unichar (found[i]);
+                                       i++;
+                               }
+
+                               string cache_path;
+
+                               string cache_dir;
+                               if (thumbnail) {
+                                       // FIXME
+                                       cache_dir = Path.build_filename (Environment.get_tmp_dir(), "cinaest-thumbnails");
+                               } else {
+                                       cache_dir = Path.build_filename (Environment.get_user_cache_dir(), "media-art");
+                               }
+
+                               // Define cache path = ~/.album_art/MD5 (down (albumartist)).jpeg
+
+                               cache_path = Path.build_filename (cache_dir, kind + "-" +
+                                                                 Checksum.compute_for_string (
+                                                                                  ChecksumType.MD5, 
+                                                                                  (title).down (), 
+                                                                                  -1) + "-" +
+                                                                 Checksum.compute_for_string (
+                                                                                  ChecksumType.MD5, 
+                                                                                  (year).down (), 
+                                                                                  -1) +
+                                                                  ".jpeg", null);
+
+                               // Make sure the directory .album_arts is available
+                               DirUtils.create_with_parents (cache_dir, 0770);
+
+                               stdout.printf ("GET %s --> %s\n", url.str, cache_path);
+
+                               File online_image = File.new_for_uri (url.str);
+                               File cache_image = File.new_for_path (cache_path + ".part");
+
+                               // Copy from Google images to local cache
+
+                               yield online_image.copy_async (cache_image,
+                                                              FileCopyFlags.NONE,
+                                                              Priority.DEFAULT_IDLE,
+                                                              null,
+                                                              null);
+
+                               FileUtils.rename (cache_path + ".part", cache_path);
+
+                               fetched (handle, cache_path);
+
+                               stdout.printf ("DONE\n");
+                       } else {
+                               stdout.printf ("NOT FOUND\n");
+                       //      stdout.printf ("%s\n", asstring);
+                       }
+
+               } catch (GLib.Error error) {
+                       stderr.printf ("Error: %s\n", error.message);
+               }
+       }
+}
+
+void main () {
+       var loop = new MainLoop (null, false);
+
+       try {
+               var conn = DBus.Bus.get (DBus.BusType.SESSION);
+
+               dynamic DBus.Object bus = conn.get_object ("org.freedesktop.DBus",
+                                                          "/org/freedesktop/DBus",
+                                                          "org.freedesktop.DBus");
+
+               // Try to register service in session bus
+               uint request_name_result = bus.request_name ("org.maemo.movieposter.GoogleImages", (uint) 0);
+
+               if (request_name_result == DBus.RequestNameReply.PRIMARY_OWNER) {
+                       // Start server
+                       var server = new GoogleImages ();
+                       conn.register_object ("/org/maemo/movieposter/GoogleImages", server);
+
+                       loop.run ();
+               }
+       } catch (Error e) {
+               error ("Oops: %s\n", e.message);
+       }
+}