Refactor _receive_configure_event().
[gpodder.git] / src / gpodder / gtkui / services.py
blob8ac25465ef76fad88542c7bdd3bde5519aa92955
1 # -*- coding: utf-8 -*-
3 # gPodder - A media aggregator and podcast client
4 # Copyright (c) 2005-2018 The gPodder Team
6 # gPodder is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # gPodder is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 # gpodder.gtkui.services - UI parts for the services module (2009-08-24)
26 import logging
28 from gi.repository import GdkPixbuf
30 import gpodder
31 from gpodder import coverart, util
32 from gpodder.services import ObservableService
34 _ = gpodder.gettext
36 logger = logging.getLogger(__name__)
39 class CoverDownloader(ObservableService):
40 """
41 This class manages downloading cover art and notification
42 of other parts of the system. Downloading cover art can
43 happen either synchronously via get_cover() or in
44 asynchronous mode via request_cover(). When in async mode,
45 the cover downloader will send the cover via the
46 'cover-available' message (via the ObservableService).
47 """
49 def __init__(self):
50 self.downloader = coverart.CoverDownloader()
51 signal_names = ['cover-available', 'cover-removed']
52 ObservableService.__init__(self, signal_names)
54 def request_cover(self, channel, custom_url=None, avoid_downloading=False):
55 """
56 Sends an asynchronous request to download a
57 cover for the specific channel.
59 After the cover has been downloaded, the
60 "cover-available" signal will be sent with
61 the channel url and new cover as pixbuf.
63 If you specify a custom_url, the cover will
64 be downloaded from the specified URL and not
65 taken from the channel metadata.
67 The optional parameter "avoid_downloading",
68 when true, will make sure we return only
69 already-downloaded covers and return None
70 when we have no cover on the local disk.
71 """
72 logger.debug('cover download request for %s', channel.url)
73 util.run_in_background(lambda: self.__get_cover(channel,
74 custom_url, True, avoid_downloading))
76 def get_cover(self, channel, custom_url=None, avoid_downloading=False):
77 """
78 Sends a synchronous request to download a
79 cover for the specified channel.
81 The cover will be returned to the caller.
83 The custom_url has the same semantics as
84 in request_cover().
86 The optional parameter "avoid_downloading",
87 when true, will make sure we return only
88 already-downloaded covers and return None
89 when we have no cover on the local disk.
90 """
91 (url, pixbuf) = self.__get_cover(channel, custom_url, False, avoid_downloading)
92 return pixbuf
94 def replace_cover(self, channel, custom_url=None):
95 """
96 This is a convenience function that deletes
97 the current cover file and requests a new
98 cover from the URL specified.
99 """
100 self.request_cover(channel, custom_url)
102 def __get_cover(self, channel, url, async_mode=False, avoid_downloading=False):
103 def get_filename():
104 return self.downloader.get_cover(channel.cover_file,
105 url or channel.cover_url, channel.url, channel.title,
106 channel.auth_username, channel.auth_password,
107 not avoid_downloading)
109 if url is not None:
110 filename = get_filename()
111 if filename.startswith(channel.cover_file):
112 logger.info('Replacing cover: %s', filename)
113 util.delete_file(filename)
115 filename = get_filename()
116 pixbuf = None
118 try:
119 pixbuf = GdkPixbuf.Pixbuf.new_from_file(filename)
120 except Exception as e:
121 logger.warning('Cannot load cover art', exc_info=True)
122 if pixbuf is None and filename.startswith(channel.cover_file):
123 logger.info('Deleting broken cover: %s', filename)
124 util.delete_file(filename)
125 filename = get_filename()
126 try:
127 pixbuf = GdkPixbuf.Pixbuf.new_from_file(filename)
128 except Exception as e:
129 logger.warning('Corrupt cover art on server, deleting', exc_info=True)
130 util.delete_file(filename)
132 if async_mode:
133 self.notify('cover-available', channel, pixbuf)
134 else:
135 return (channel.url, pixbuf)