# -*- coding: utf-8 -*- # # gPodder - A media aggregator and podcast client # Copyright (c) 2005-2018 The gPodder Team # # gPodder 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. # # gPodder 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 . # # gpodder.dbusproxy - Expose Podcasts over D-Bus # Based on a patch by Iwan van der Kleijn # See also: http://gpodder.org/bug/699 import dbus import dbus.service import gpodder from gpodder import util def safe_str(txt): if txt: return txt.encode() else: return '' def safe_first_line(txt): txt = safe_str(txt) lines = util.remove_html_tags(txt).strip().splitlines() if not lines or lines[0] == '': return '' else: return lines[0] class DBusPodcastsProxy(dbus.service.Object): """ Implements API accessible through D-Bus Methods on DBusPodcastsProxy can be called by D-Bus clients. They implement safe-guards to work safely over D-Bus while having type signatures applied for parameter and return values. """ # DBusPodcastsProxy(lambda: self.channels, self.on_itemUpdate_activate(), self.playback_episodes, self.download_episode_list, bus_name) def __init__(self, get_podcast_list, check_for_updates, playback_episodes, download_episodes, episode_from_uri, bus_name): self._get_podcasts = get_podcast_list self._on_check_for_updates = check_for_updates self._playback_episodes = playback_episodes self._download_episodes = download_episodes self._episode_from_uri = episode_from_uri dbus.service.Object.__init__(self, object_path=gpodder.dbus_podcasts_object_path, bus_name=bus_name) def _get_episode_refs(self, urls): """Get Episode instances associated with URLs""" episodes = [] for p in self._get_podcasts(): for e in p.get_all_episodes(): if e.url in urls: episodes.append(e) return episodes @dbus.service.method(dbus_interface=gpodder.dbus_podcasts, in_signature='', out_signature='a(ssss)') def get_podcasts(self): """Get all podcasts in gPodder's subscription list""" def podcast_to_tuple(podcast): title = safe_str(podcast.title) url = safe_str(podcast.url) description = safe_first_line(podcast.description) cover_file = '' return (title, url, description, cover_file) return [podcast_to_tuple(p) for p in self._get_podcasts()] @dbus.service.method(dbus_interface=gpodder.dbus_podcasts, in_signature='s', out_signature='ss') def get_episode_title(self, url): episode = self._episode_from_uri(url) if episode is not None: return episode.title, episode.channel.title return ('', '') @dbus.service.method(dbus_interface=gpodder.dbus_podcasts, in_signature='s', out_signature='a(sssssbbb)') def get_episodes(self, url): """Return all episodes of the podcast with the given URL""" podcast = None for channel in self._get_podcasts(): if channel.url == url: podcast = channel break if podcast is None: return [] def episode_to_tuple(episode): title = safe_str(episode.title) url = safe_str(episode.url) description = safe_first_line(episode._text_description) filename = safe_str(episode.download_filename) file_type = safe_str(episode.file_type()) is_new = (episode.state == gpodder.STATE_NORMAL and episode.is_new) is_downloaded = episode.was_downloaded(and_exists=True) is_deleted = (episode.state == gpodder.STATE_DELETED) return (title, url, description, filename, file_type, is_new, is_downloaded, is_deleted) return [episode_to_tuple(e) for e in podcast.get_all_episodes()] @dbus.service.method(dbus_interface=gpodder.dbus_podcasts, in_signature='as', out_signature='(bs)') def play_or_download_episode(self, urls): """Play (or download) a list of episodes given by URL""" episodes = self._get_episode_refs(urls) if not episodes: return (0, 'No episodes found') to_playback = [e for e in episodes if e.was_downloaded(and_exists=True)] to_download = [e for e in episodes if e not in to_playback] if to_playback: self._playback_episodes(to_playback) if to_download: self._download_episodes(to_download) return (1, 'Success') @dbus.service.method(dbus_interface=gpodder.dbus_podcasts, in_signature='', out_signature='') def check_for_updates(self): """Check for new episodes or offer subscriptions""" self._on_check_for_updates()