def fetch_images(self):
        """
        Fetch latest pending images.
        """

        image_downloaded = False

        for image in store().find(Image, Image.state == Image.STATE_PENDING).order_by(Desc(Image.id)):
            temp_file = self.manager.generate_img_file(".jpg")

            if self.download_img_file(temp_file[0], image.source_image_url):                
                # os.close(temp_file[0])
                
                WallPaperLog.getInstance().info("Downloaded %s: %s" % (image.source_image_url, temp_file[1]))

                image.image_path = unicode(temp_file[1])
                image.download_time = datetime.now()
                image.state = Image.STATE_DOWNLOADED

                image_downloaded = True
            else:
                # os.close(temp_file[0])
                os.unlink(temp_file[1])
                WallPaperLog.getInstance().info("Failed to download %s" % image.source_image_url)

                image.state = Image.STATE_FAILED

            store().flush()
            store().commit()

        return image_downloaded
    def run(self):
        """
        Thread run callback.
        """

        if self.manager.update_lock is None:
            self.manager.update_lock = threading.Lock()

        if not self.manager.update_lock.acquire(False):
            # is updaing now, just return
            return

        GObject.idle_add(self.ui_controller.start_updating)

        try:
            WallPaperLog.getInstance().info("Get URL...")
            WallPaperLog.getInstance().info("Reconnected.")

            self.fetch_links()
            self.fetch_images()

            self.manager.update_wallpaper()
        finally:
            if store() is not None:
                store().close()

            GObject.idle_add(self.ui_controller.finish_updating)
            self.manager.update_lock.release()
    def update(self):
        """
        Try to download new images and update wallpaper.
        """

        WallPaperLog.getInstance().info('Updating...')
        download_thread = DownloadThread(self, self.ui_controller, self.config)
        download_thread.start()
 def update_gsettings(self, image):
     """
     Update wallpaper image with gsettings.
     """
     WallPaperLog.getInstance().info("image_file = %s" % (image.image_path) )
     max_retry_time = 10;cnt = 0
     while self.get_gsettings_wallpaper() != "file://" + image.image_path and cnt < max_retry_time:
         gsettings = Gio.Settings.new(self.SCHEMA)
         gsettings.set_string(self.KEY, "file://" + image.image_path)
         GObject.idle_add(lambda: self.ui_controller.notify_wallpaper_update(image))
         cnt += 1;sleep(1)
    def update_wallpaper(self):
        """
        Find out the wallpaper image and set it.
        """

        try:
            image = self.get_wallpaper_image()
            if image is not None:
                WallPaperLog.getInstance().info("New wallpaper image: %s" % image.image_path )
                self.update_gsettings(image)
        finally:
            store().close()
    def download_img_file(self, fd, url):
        """
        Download the image of url.
        """

        try:
            img = urlopen(url, timeout=self.config.get_options().timeout)
        except (HTTPError, URLError, IOError, TypeError):
            return False

        try:
            f = os.fdopen(fd, 'w')
            f.write(img.read())
            f.close()
        except (HTTPException, IndexError, socket.error):
            WallPaperLog.getInstance().info("Failed to download image: %s" % url)
            return False

        return True
    def get_wallpaper_image(self):
        """
        Find out the wallpaer image to use based on DB records.
        """

        # if the current_wallpaper is the only image of STATE_DOWNLOADED, then nothing to do
        current_wallpaper = store().find(Image, Image.active_wallpaper == True).any() 

        if store().find(Image,
                        And(Image.state == Image.STATE_DOWNLOADED,
                            Image.active_wallpaper == False)).count() == 0:
            return current_wallpaper

        keep_timestamp = datetime.now() - timedelta(seconds=self.config.get_options().keep)

        # if there's no downloaded image during KEEP duration, then active the latest one
        if store().find(Image,
                        And(Image.state == Image.STATE_DOWNLOADED,
                            Image.download_time >= keep_timestamp)).count() == 0:
            downloaded_images = store().find(Image, Image.state == Image.STATE_DOWNLOADED).order_by(Desc(Image.download_time))
            wallpaper = downloaded_images.first()
            downloaded_images.set(state = Image.STATE_EXPIRED)
            wallpaper.state = Image.STATE_DOWNLOADED

            store().flush()
            store().commit()

            # unlink expired images
            self.delete_expired_images()

            # set the new wallpaper
            # self.active_wallpaper(wallpaper)
            self.update_wallpaper_record(wallpaper)

            return wallpaper

        # unlink all images over KEEP duration
        expired_images = store().find(Image,
                                       And(Image.state == Image.STATE_DOWNLOADED,
                                          Image.download_time < keep_timestamp))
        expired_images.set(state = Image.STATE_EXPIRED)
        store().flush()
        store().commit()            
        self.delete_expired_images()

        # Calcualte the updating cycle
        display_time_per_image = self.calculate_updating_cycle()
        WallPaperLog.getInstance().info("Display time per image: %d" % display_time_per_image.total_seconds() )

        # did the current wallpaper expire?
        if current_wallpaper is not None:
            if current_wallpaper.active_time is None:
                current_wallpaper.active_time = datetime.now()
                store().flush()
                store().commit()
                return current_wallpaper

            if current_wallpaper.active_time >= datetime.now() - display_time_per_image:
                # not expired, nothing to do
                WallPaperLog.getInstance().info("Time till the coming wallpaper switching: %d" % (current_wallpaper.active_time + display_time_per_image - datetime.now()).total_seconds() )
                return current_wallpaper

            current_wallpaper.state = Image.STATE_EXPIRED
            store().flush()
            store().commit()            
            self.delete_expired_images()

        # active the first downloaded image
        image = store().find(Image, Image.state == Image.STATE_DOWNLOADED).order_by(Image.download_time).first()

        if image is None:
            return None

        if image.active_wallpaper == True:
            return image

        # set a new wallpaper
        self.update_wallpaper_record(image)
        return image
    def fetch_links(self):
        """
        Fetch links defined in source_site.
        """
        
        new_link = False

        for site in store().find(SourceSite, SourceSite.active == True):
            WallPaperLog.getInstance().info("Fetching %s" % site.name )

            try:
                page = urlopen(site.url, timeout=self.config.get_options().timeout)
            except (HTTPError, URLError, TypeError):
                WallPaperLog.getInstance().info("Failed to fetch %s" % site.url )
                continue

            try:
                p = parse(page)
                link = p.xpath(site.image_xpath)[0]
            except (HTTPException, IndexError, socket.error):
                WallPaperLog.getInstance().info("Failed to parse image path." )
                continue

            site.last_update = datetime.now()

            store().flush()
            store().commit()

            WallPaperLog.getInstance().info("Got a new image link: %s" % link )

            if store().find(Image, Image.source_image_url == unicode(link)).count() > 0:
                WallPaperLog.getInstance().info("Dulplicated image link: %s" % link)
                continue

            image = Image()
            image.source_site = site
            image.source_image_url = unicode(link)
            image.state = Image.STATE_PENDING
            image.active_wallpaper = False

            try:
                image.source_link = unicode(p.xpath(site.link_xpath)[0])
            except (IndexError, TypeError):
                WallPaperLog.getInstance().info("Failed to parse link.")
                image.source_link = None
                continue

            try:
                image.source_title = unicode(p.xpath(site.title_xpath)[0])
            except (IndexError, TypeError):
                WallPaperLog.getInstance().info("Failed to parse title.")
                image.source_title = None
                continue

            try:
                image.source_description = unicode(p.xpath(site.description_xpath)[0])
            except (IndexError, TypeError):
                WallPaperLog.getInstance().info("Failed to parse decription.")
                image.source_description = None
                continue

            WallPaperLog.getInstance().info("Created a new image object: %s" % image.source_image_url)
            
            store().add(image)
            store().flush()
            store().commit()

            new_link = True

        return new_link