Movie poster factory: return a "no poster" pixmap if the poster download failed
[cinaest] / src / poster / movie-poster-factory.vala
index e3224ba..35c4ba2 100644 (file)
@@ -1,3 +1,21 @@
+/* This file is part of Cinaest.
+ *
+ * Copyright (C) 2009 Philipp Zabel
+ *
+ * Cinaest is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Cinaest is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cinaest. If not, see <http://www.gnu.org/licenses/>.
+ */
+
 using GLib;
 
 namespace MoviePoster {
@@ -6,19 +24,38 @@ namespace MoviePoster {
 
        public class Factory : Object {
                private static Factory the_factory = null;
-               private List<Request> requests;
-               dynamic DBus.Object server;
+               internal List<Request> requests;
+               internal dynamic DBus.Object server;
+               internal bool download_posters;
+               private GConf.Client gc;
+               private uint cxnid;
+               private Gdk.Pixbuf poster_failed;
+               private Gdk.Pixbuf icon_failed;
 
                construct {
                        try {
                                var conn = DBus.Bus.get (DBus.BusType.SESSION);
-                               server = conn.get_object ("org.maemo.movieposter.GoogleImages",
-                                                         "/org/maemo/movieposter/GoogleImages",
+                               server = conn.get_object ("org.maemo.movieposter.IMDb",
+                                                         "/org/maemo/movieposter/IMDb",
                                                          "org.maemo.movieposter.Provider");
-                               server.Fetched += this.on_poster_fetched;
+                               server.Fetched.connect (this.on_poster_fetched);
+                               server.Failed.connect (this.on_poster_failed);
                        } catch (Error e) {
-                               warning ("Couldn't connect to Google image downloader: %s\n", e.message);
+                               warning ("Couldn't connect to IMDb poster downloader: %s\n", e.message);
                        }
+                       gc = GConf.Client.get_default ();
+
+                       try {
+                               download_posters = gc.get_bool ("/apps/cinaest/download_posters");
+                               gc.add_dir ("/apps/cinaest", GConf.ClientPreloadType.ONELEVEL);
+                               cxnid = gc.notify_add ("/apps/cinaest/download_posters", on_download_posters_changed);
+                       } catch (Error e) {
+                               stdout.printf ("Error installing GConf notification: %s\n", e.message);
+                       }
+               }
+
+               private static void on_download_posters_changed (GConf.Client gc, uint cxnid, GConf.Entry entry) {
+                       the_factory.download_posters = entry.get_value ().get_bool ();
                }
 
                public static Factory get_instance () {
@@ -30,18 +67,22 @@ namespace MoviePoster {
                public int queue (Movie movie, RequestCallback callback) throws Error {
                        string path = get_path (movie);
 
+                       foreach (Request request in requests)
+                               if (request.movie == movie)
+                                       return 0;
+
                        if (FileUtils.test (path, FileTest.IS_REGULAR)) {
                                // TODO: make this async?
-                               var pixbuf = new Gdk.Pixbuf.from_file_at_size (path, 268, 424);
+                               var pixbuf = new Gdk.Pixbuf.from_file_at_scale (path, 288, 400, true);
                                callback (pixbuf, movie);
-                       } else if (server != null) {
+                       } else if (server != null && download_posters) {
                                var request = new Request ();
 
-                               request.handle = server.fetch (movie.title.down (), movie.year.to_string (), "movie");
+                               request.handle = server.Fetch (movie.title, movie.year.to_string (), "movie");
                                request.movie = movie;
                                request.callback = callback;
-                               request.width = 268;
-                               request.height = 424;
+                               request.width = 288;
+                               request.height = 400;
                                requests.append (request);
                        }
                        return 0;
@@ -50,14 +91,19 @@ namespace MoviePoster {
                public int queue_thumbnail (Movie movie, uint width, uint height, bool cropped, RequestCallback callback) throws Error {
                        string path = get_path_thumbnail (movie);
 
+                       foreach (Request request in requests)
+                               if (request.movie == movie)
+                                       return 0;
+
                        if (FileUtils.test (path, FileTest.IS_REGULAR)) {
                                // TODO: make this async?
-                               var pixbuf = new Gdk.Pixbuf.from_file_at_size (path, (int) width, (int) height);
+                               var pixbuf = new Gdk.Pixbuf.from_file_at_scale (path, (int) width, (int) height, true);
+
                                callback (pixbuf, movie);
-                       } else if (server != null) {
+                       } else if (server != null && download_posters) {
                                var request = new Request ();
 
-                               request.handle = server.fetch_thumbnail (movie.title.down (), movie.year.to_string (), "movie");
+                               request.handle = server.FetchThumbnail (movie.title, movie.year.to_string (), "movie");
                                request.movie = movie;
                                request.callback = callback;
                                request.width = (int) width;
@@ -68,19 +114,63 @@ namespace MoviePoster {
                }
 
                private void on_poster_fetched (dynamic DBus.Object server, int handle, string path) {
-                       foreach (Request request in requests) {
-                               if (request.handle != handle)
-                                       continue;
-                               try {
-                                       var pixbuf = new Gdk.Pixbuf.from_file_at_size (path, request.width, request.height);
-
-                                       requests.remove (request);
-                                       request.callback (pixbuf, request.movie);
-                                       return;
+                       Request request = null;
+                       foreach (Request r in requests) {
+                               if (r.handle == handle) {
+                                       request = r;
+                                       break;
+                               }
+                       }
+                       if (request == null)
+                               return;
+                       try {
+                               var pixbuf = new Gdk.Pixbuf.from_file_at_size (path, request.width, request.height);
+
+                               requests.remove (request);
+                               request.callback (pixbuf, request.movie);
+                               return;
+                       } catch (Error e) {
+                               warning ("Failed to open poster: %s\n", e.message);
+                       }
+               }
+
+               private void on_poster_failed (dynamic DBus.Object server, int handle) {
+                       Request request = null;
+                       foreach (Request r in requests) {
+                               if (r.handle == handle) {
+                                       request = r;
+                                       break;
+                               }
+                       }
+                       if (request == null)
+                               return;
+                       requests.remove (request);
+                       request.callback (failed_poster (request.width, request.height), request.movie);
+               }
+
+               private Gdk.Pixbuf failed_poster (int width, int height) {
+                       if (width == Poster.ICON_WIDTH && height == Poster.ICON_HEIGHT) {
+                               if (icon_failed == null) {
+                                       // An empty icon for the list view
+                                       icon_failed = new Gdk.Pixbuf (Gdk.Colorspace.RGB, true, 8, Poster.ICON_WIDTH, Poster.ICON_HEIGHT);
+                                       icon_failed.fill (0);
+                               }
+                               return icon_failed;
+                       }
+                       if (width == Poster.SMALL_WIDTH && height == Poster.SMALL_HEIGHT) {
+                               if (poster_failed == null) try {
+                                       // Broken image icon for the poster view
+                                       var no_pic = new Gdk.Pixbuf.from_file ("/usr/share/icons/hicolor/64x64/hildon/imageviewer_no_pic.png");
+                                       poster_failed = new Gdk.Pixbuf (Gdk.Colorspace.RGB, true, 8, Poster.SMALL_WIDTH, Poster.SMALL_HEIGHT);
+                                       poster_failed.fill (0);
+                                       no_pic.copy_area (0, 0, no_pic.width, no_pic.height, poster_failed,
+                                                         (Poster.SMALL_WIDTH - no_pic.width) / 2, (Poster.SMALL_HEIGHT - no_pic.height) / 2);
                                } catch (Error e) {
-                                       warning ("Failed to open poster: %s\n", e.message);
+                                       critical ("Missing imageviewer_no_pic icon: %s\n", e.message);
                                }
+                               return poster_failed;
                        }
+                       return null;
                }
 
                public void join () {
@@ -91,6 +181,14 @@ namespace MoviePoster {
 
                public static void factory_clean_cache (int max_size, time_t min_mtime) {
                }
+
+               public void clear_queue () {
+                       if (server != null) {
+                               foreach (Request r in requests)
+                                       server.Unqueue (r.handle);
+                       }
+                       requests = null;
+               }
        }
 
        public class Request {
@@ -101,6 +199,10 @@ namespace MoviePoster {
                public int height;
 
                public void unqueue () {
+                       if (Factory.get_instance ().server != null)
+                               Factory.get_instance ().server.Unqueue (this.handle);
+
+                       Factory.get_instance ().requests.remove (this);
                }
 
                public void join () {