From 2b0e400a4a83beba1525693d542fd2bbaa568805 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 3 Nov 2009 14:37:51 +0100 Subject: [PATCH] Add Google poster downloader D-Bus service --- Makefile.am | 17 +- configure.ac | 1 + data/org.maemo.movieposter.GoogleImages.service.in | 3 + src/poster/google-poster-downloader.vala | 205 ++++++++++++++++++++ 4 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 data/org.maemo.movieposter.GoogleImages.service.in create mode 100644 src/poster/google-poster-downloader.vala diff --git a/Makefile.am b/Makefile.am index 4bb1c09..aabbb5b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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} \ diff --git a/configure.ac b/configure.ac index 7e52d5b..df89570 100644 --- a/configure.ac +++ b/configure.ac @@ -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 index 0000000..a455c60 --- /dev/null +++ b/data/org.maemo.movieposter.GoogleImages.service.in @@ -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 index 0000000..d12cacb --- /dev/null +++ b/src/poster/google-poster-downloader.vala @@ -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); + } +} -- 1.7.9.5