Movie window & poster factory: change movie poster from 268x424 to 288x400
[cinaest] / src / poster / movie-poster-factory.vala
1 /* This file is part of Cinaest.
2  *
3  * Copyright (C) 2009 Philipp Zabel
4  *
5  * Cinaest is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * Cinaest is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Cinaest. If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 using GLib;
20
21 namespace MoviePoster {
22
23         public delegate void RequestCallback (Gdk.Pixbuf movieposter, Movie movie);
24
25         public class Factory : Object {
26                 private static Factory the_factory = null;
27                 internal List<Request> requests;
28                 internal dynamic DBus.Object server;
29                 internal bool download_posters;
30                 private GConf.Client gc;
31                 private uint cxnid;
32
33                 construct {
34                         try {
35                                 var conn = DBus.Bus.get (DBus.BusType.SESSION);
36                                 server = conn.get_object ("org.maemo.movieposter.IMDb",
37                                                           "/org/maemo/movieposter/IMDb",
38                                                           "org.maemo.movieposter.Provider");
39                                 server.Fetched.connect (this.on_poster_fetched);
40                                 server.Failed.connect (this.on_poster_failed);
41                         } catch (Error e) {
42                                 warning ("Couldn't connect to IMDb poster downloader: %s\n", e.message);
43                         }
44                         gc = GConf.Client.get_default ();
45
46                         try {
47                                 download_posters = gc.get_bool ("/apps/cinaest/download_posters");
48                                 gc.add_dir ("/apps/cinaest", GConf.ClientPreloadType.ONELEVEL);
49                                 cxnid = gc.notify_add ("/apps/cinaest/download_posters", on_download_posters_changed);
50                         } catch (Error e) {
51                                 stdout.printf ("Error installing GConf notification: %s\n", e.message);
52                         }
53                 }
54
55                 private static void on_download_posters_changed (GConf.Client gc, uint cxnid, GConf.Entry entry) {
56                         the_factory.download_posters = entry.get_value ().get_bool ();
57                 }
58
59                 public static Factory get_instance () {
60                         if (the_factory == null)
61                                 the_factory = new MoviePoster.Factory ();
62                         return the_factory;
63                 }
64
65                 public int queue (Movie movie, RequestCallback callback) throws Error {
66                         string path = get_path (movie);
67
68                         foreach (Request request in requests)
69                                 if (request.movie == movie)
70                                         return 0;
71
72                         if (FileUtils.test (path, FileTest.IS_REGULAR)) {
73                                 // TODO: make this async?
74                                 var pixbuf = new Gdk.Pixbuf.from_file_at_scale (path, 288, 400, true);
75                                 callback (pixbuf, movie);
76                         } else if (server != null && download_posters) {
77                                 var request = new Request ();
78
79                                 request.handle = server.Fetch (movie.title, movie.year.to_string (), "movie");
80                                 request.movie = movie;
81                                 request.callback = callback;
82                                 request.width = 288;
83                                 request.height = 400;
84                                 requests.append (request);
85                         }
86                         return 0;
87                 }
88
89                 public int queue_thumbnail (Movie movie, uint width, uint height, bool cropped, RequestCallback callback) throws Error {
90                         string path = get_path_thumbnail (movie);
91
92                         foreach (Request request in requests)
93                                 if (request.movie == movie)
94                                         return 0;
95
96                         if (FileUtils.test (path, FileTest.IS_REGULAR)) {
97                                 // TODO: make this async?
98                                 var pixbuf = new Gdk.Pixbuf.from_file_at_scale (path, (int) width, (int) height, true);
99
100                                 callback (pixbuf, movie);
101                         } else if (server != null && download_posters) {
102                                 var request = new Request ();
103
104                                 request.handle = server.FetchThumbnail (movie.title, movie.year.to_string (), "movie");
105                                 request.movie = movie;
106                                 request.callback = callback;
107                                 request.width = (int) width;
108                                 request.height = (int) height;
109                                 requests.append (request);
110                         }
111                         return 0;
112                 }
113
114                 private void on_poster_fetched (dynamic DBus.Object server, int handle, string path) {
115                         Request request = null;
116                         foreach (Request r in requests) {
117                                 if (r.handle == handle) {
118                                         request = r;
119                                         break;
120                                 }
121                         }
122                         if (request == null)
123                                 return;
124                         try {
125                                 var pixbuf = new Gdk.Pixbuf.from_file_at_size (path, request.width, request.height);
126
127                                 requests.remove (request);
128                                 request.callback (pixbuf, request.movie);
129                                 return;
130                         } catch (Error e) {
131                                 warning ("Failed to open poster: %s\n", e.message);
132                         }
133                 }
134
135                 private void on_poster_failed (dynamic DBus.Object server, int handle) {
136                         Request request = null;
137                         foreach (Request r in requests) {
138                                 if (r.handle == handle) {
139                                         request = r;
140                                         break;
141                                 }
142                         }
143                         if (request == null)
144                                 return;
145                         requests.remove (request);
146                 //      request.callback (pixbuf, request.movie);
147                 }
148
149                 public void join () {
150                 }
151
152                 public static void factory_remove (Movie movie) {
153                 }
154
155                 public static void factory_clean_cache (int max_size, time_t min_mtime) {
156                 }
157
158                 public void clear_queue () {
159                         if (server != null) {
160                                 foreach (Request r in requests)
161                                         server.Unqueue (r.handle);
162                         }
163                         requests = null;
164                 }
165         }
166
167         public class Request {
168                 public int handle;
169                 public Movie movie;
170                 public RequestCallback callback;
171                 public int width;
172                 public int height;
173
174                 public void unqueue () {
175                         if (Factory.get_instance ().server != null)
176                                 Factory.get_instance ().server.Unqueue (this.handle);
177
178                         Factory.get_instance ().requests.remove (this);
179                 }
180
181                 public void join () {
182                 }
183         }
184
185         public static bool is_cached (Movie movie) {
186                 string filename = get_path (movie);
187                 if (FileUtils.test (filename, FileTest.IS_REGULAR))
188                         return true;
189                 else
190                         return false;
191         }
192
193         public static string get_path (Movie movie) {
194                 return Path.build_filename (Environment.get_user_cache_dir (), "media-art", "movie-" +
195                                             Checksum.compute_for_string (ChecksumType.MD5, movie.title.down ()) + "-" +
196                                             Checksum.compute_for_string (ChecksumType.MD5, movie.year.to_string ()) + ".jpeg");
197         }
198
199         public static string get_path_thumbnail (Movie movie) {
200                 return Path.build_filename (Environment.get_tmp_dir (), "cinaest-thumbnails", "movie-" +
201                                             Checksum.compute_for_string (ChecksumType.MD5, movie.title.down ()) + "-" +
202                                             Checksum.compute_for_string (ChecksumType.MD5, movie.year.to_string ()) + ".jpeg");
203         }
204 }
205