Initial support for fetching images is added.
* AsyncWorker and ImageDownloader have been taken from SeriesFinale.
They allow asynchronously fetching the images from the Internet
using the url provided from DBus
* The UI displays a placeholder image while the right one is being
fetched
* Images downloaded aren't cached, they are download in /tmp/
* Asynchronous threads aren't canceled if we leave the movie view
before the image is fetched.
###########################################################################
import pygtk
+import os
pygtk.require('2.0')
import gtk
import hildon
import gobject
from maeviesui.util import constants
+from maeviesui.util.asyncworker import AsyncWorker, AsyncItem
+from maeviesui.util.util import image_downloader
from maeviesui.util.moviemanager import MovieManager
class Maevies(hildon.StackableWindow):
def add_movies(self, movie_list):
model = self.get_model()
- model.add(movie_list)
+ if model:
+ model.add(movie_list)
def get_movie_from_path(self, path):
model = self.get_model()
class MovieWindow(hildon.StackableWindow):
+ def _create_movie_image(self, movie):
+ image = gtk.Image()
+ image.set_from_pixbuf(gtk.IconTheme().load_icon('general_video',
+ 256, 0))
+ banner = hildon.hildon_banner_show_information_with_markup(self,
+ 'ignored',
+ 'Fetching movie cover')
+ banner.set_timeout(constants.TIMEOUT_TIME_MILLIS)
+ hildon.hildon_gtk_window_set_progress_indicator(self, True)
+
+ async_item = AsyncItem(image_downloader, (movie.get_images()[0].get_url(), '/tmp/' + movie.get_title()),
+ self._set_downloaded_image, (image,))
+ self.async_worker.queue.put(async_item)
+ self.async_worker.start()
+
+ return image
+
+ def _set_downloaded_image(self, image, target, error):
+ image_file = os.path.abspath(target)
+ image.set_from_pixbuf(gtk.gdk.pixbuf_new_from_file_at_size(image_file,
+ 256,
+ 256))
+ hildon.hildon_gtk_window_set_progress_indicator(self, False)
+
def _create_contents(self, movie):
main_area = hildon.PannableArea()
upper_content = gtk.HBox(False, 40)
upper_content.set_border_width(20)
- image = gtk.Image()
- image.set_from_pixbuf(gtk.IconTheme().load_icon('mediaplayer_default_album',
- 256, 0))
+ image = self._create_movie_image(movie)
side_content = gtk.VBox(False, 30)
def __init__(self, movie):
super(MovieWindow, self).__init__()
+ self.async_worker = AsyncWorker()
self.set_title('Movie info')
self.add(self._create_contents(movie))
self.show_all()
--- /dev/null
+# -*- coding: utf-8 -*-
+
+###########################################################################
+# SeriesFinale
+# Copyright (C) 2009 Joaquim Rocha <jrocha@igalia.com>
+#
+# This program 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.
+#
+# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+from threading import Thread
+import Queue
+import gobject
+import logging
+logging.basicConfig(level=logging.DEBUG)
+
+class AsyncItem(object):
+
+ def __init__(self, target_method, target_method_args, finish_callback=None, finish_callback_args=()):
+ self.target_method = target_method
+ self.target_method_args = target_method_args
+ self.finish_callback = finish_callback
+ self.finish_callback_args = finish_callback_args
+ self.canceled = False
+
+ def run(self):
+ if self.canceled:
+ return
+ results = error = None
+ try:
+ results = self.target_method(*self.target_method_args)
+ except Exception, exception:
+ logging.debug(str(exception))
+ error = exception
+ if self.canceled or not self.finish_callback:
+ return
+ self.finish_callback_args += (results,)
+ self.finish_callback_args += (error,)
+ gobject.idle_add(self.finish_callback, *self.finish_callback_args)
+
+ def cancel(self):
+ self.canceled = True
+
+class AsyncWorker(Thread):
+
+ def __init__(self):
+ Thread.__init__(self)
+ self.queue = Queue.Queue(0)
+ self.stopped = False
+ self.async_item = None
+ self.item_number = -1
+
+ def run(self):
+ while not self.stopped:
+ if self.queue.empty():
+ self.stop()
+ break
+ try:
+ self.async_item = self.queue.get()
+ self.item_number += 1
+ self.async_item.run()
+ self.queue.task_done()
+ self.async_item = None
+ except Exception, exception:
+ logging.debug(str(exception))
+ self.stop()
+
+ def stop(self):
+ self.stopped = True
+ if self.async_item:
+ self.async_item.cancel()
+
os.pardir,
os.pardir,
'data'))
-TIMEOUT_TIME_MILLIS = 500
+TIMEOUT_TIME_MILLIS = 1000
LEFT_ALIGNMENT = 0
CENTER_ALIGNMENT = 0.5
LOREM_IPSUM = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. \
if self.response_received_cb:
self.response_received_cb(movies)
+class MovieImage:
+ def __init__(self, image_struct):
+ self._type, self._url, self._size, self._id = image_struct
+
+ def get_url(self):
+ return self._url
+
+ def get_id(self):
+ return self._id
+
+ def get_size(self):
+ return self._size
+
+ def get_type(self):
+ return self._type
+
class MovieProxy:
def __init__(self, bus, object_path):
self._bus = bus
self.interface = self._create_movie_interface(object_path)
self.fields = ['Title', 'Release date', 'Rating', 'Popularity']
+ self._images = self._retrieve_images()
def _create_movie_interface(self, object_path):
proxy = self._bus.get_object(TMDB_MOVIE_BUS_NAME,
dbus_interface=TMDB_MOVIE_INTERFACE)
return interface
+ def _retrieve_images(self):
+ images = []
+ dbus_images = self.interface.GetImages()
+ for image in dbus_images:
+ images.append(MovieImage(image))
+ return images
+
def get_value(self, field):
if field == 'Title':
return self.get_title()
def get_rating(self):
return self.interface.GetRating()
+ def get_images(self):
+ return self._images
+
def get_released(self):
return self.interface.GetReleased()
--- /dev/null
+# -*- coding: utf-8 -*-
+
+###########################################################################
+# Maevies
+# Copyright (C) 2010 Simón Pena <spenap@gmail.com>
+#
+# This program 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.
+#
+# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+
+import urllib
+import os
+
+def image_downloader(url, save_name):
+ image = urllib.URLopener()
+ path, format = os.path.splitext(url)
+ target = save_name + format
+ temp_target = target + '.tmp'
+ image.retrieve(url, temp_target)
+ os.rename(temp_target, target)
+ return target