def deleteEpisode(self, episode): def delete(): episode.delete_episode() self.root.main.episodeUpdated(episode.id) self.update_subset_stats() self.root.mygpo_client.on_delete([episode]) self.root.mygpo_client.flush() self.root.on_episode_deleted(episode) self.root.episode_model.sort() self.confirm_action(_('Delete this episode?'), _('Delete'), delete)
def get_flattr_info(): flattrs, flattred = self._flattr.get_thing_info( episode.payment_url ) if flattred: self.setFlattrButtonText(_('Flattred (%(count)d)') % { 'count': flattrs }) else: self.setFlattrButtonText(_('Flattr this (%(count)d)') % { 'count': flattrs })
def upload_proc(self): self.root.start_progress(_('Uploading subscriptions...')) try: try: self.root.mygpo_client.set_subscriptions([podcast.url for podcast in self.root.podcast_model.get_podcasts()]) except Exception, e: self.root.show_message( '\n'.join((_('Error on upload:'), unicode(e))) ) finally: self.root.end_progress()
def playback_episodes(self, episodes): # We need to create a list, because we run through it more than once episodes = list(Model.sort_episodes_by_pubdate(e for e in episodes if \ e.was_downloaded(and_exists=True) or self.streaming_possible())) try: self.playback_episodes_for_real(episodes) except Exception, e: logger.error('Error in playback!', exc_info=True) self.root.show_message( _('Please check your media player settings in the preferences dialog.'), _('Error opening player'), widget=self.root.toolPreferences )
def request_connection(self): """Request an internet connection Returns True if a connection is available, False otherwise """ if not util.connection_available(): # TODO: Try to request the network connection dialog, and wait # for a connection - if a connection is available, return True self.root.show_message('\n\n'.join((_('No network connection'), _('Please connect to a network, then try again.')))) return False return True
def updateFlattrButtonText(self, qepisode): self.setFlattrButtonText('') if qepisode is None: return episode = qepisode._episode if not episode.payment_url: return if not self._flattr.has_token(): self.setFlattrButtonText(_('Sign in')) return @util.run_in_background def get_flattr_info(): flattrs, flattred = self._flattr.get_thing_info( episode.payment_url ) if flattred: self.setFlattrButtonText(_('Flattred (%(count)d)') % { 'count': flattrs }) else: self.setFlattrButtonText(_('Flattr this (%(count)d)') % { 'count': flattrs })
def on_offer_download_resume(self): if self.resumable_episodes: def download_episodes(): for episode in self.resumable_episodes: qepisode = self.wrap_simple_episode(episode) self.controller.downloadEpisode(qepisode) def delete_episodes(): logger.debug('Deleting incomplete downloads.') common.clean_up_downloads(delete_partial=True) message = _( 'Incomplete downloads from a previous session were found.' ) title = _('Resume') self.controller.confirm_action( message, title, download_episodes, delete_episodes )
def subscribe_proc(self, urls): self.root.start_progress(_('Adding podcasts...')) try: for idx, url in enumerate(urls): print idx, url self.root.start_progress( _('Adding podcasts...') + ' (%d/%d)' % (idx, len(urls)) ) try: podcast = self.root.model.load_podcast( url=url, create=True, max_episodes=self.root.config.max_episodes_per_feed ) podcast.save() self.root.insert_podcast(qml.model.QPodcast(podcast)) except Exception, e: logger.warn('Cannot add pocast: %s', e) # XXX: Visual feedback in the QML UI finally: self.root.end_progress()
def flattrEpisode(self, qepisode): if not qepisode: return episode = qepisode._episode if not episode.payment_url: return if not self._flattr.has_token(): self.root.show_message(_('Sign in to Flattr in the settings.')) return self.root.start_progress(_('Flattring episode...')) @util.run_in_background def flattr_episode(): try: success, message = self._flattr.flattr_url(episode.payment_url) if success: self.updateFlattrButtonText(qepisode) else: self.root.show_message(message) finally: self.root.end_progress()
def merge_proc(self): self.root.start_progress(_('Merging episode actions...')) def find_episode(podcast_url, episode_url, counter): counter['x'] += 1 self.root.start_progress(_('Merging episode actions (%d)') % counter['x']) return self.find_episode(podcast_url, episode_url) try: # Used to "remember" the counter inside find_episode d = {'x': 0} self.root.mygpo_client.process_episode_actions(lambda x, y: find_episode(x, y, d)) finally: self.root.end_progress()
def multiEpisodeAction(self, selected, action): if not selected: return count = len(selected) episodes = map(self.root.episode_model.get_object_by_index, selected) def delete(): for episode in episodes: if not episode.qarchive: episode.delete_episode() self.update_subset_stats() self.root.mygpo_client.on_delete(episodes) self.root.mygpo_client.flush() for episode in episodes: self.root.on_episode_deleted(episode) self.root.episode_model.sort() if action == 'delete': msg = N_( 'Delete %(count)d episode?', 'Delete %(count)d episodes?', count ) % {'count': count} self.confirm_action(msg, _('Delete'), delete) elif action == 'download': for episode in episodes: if episode.qdownloaded: print ' XXX already downloaded' continue self.downloadEpisode(episode) self.root.mygpo_client.on_download(episodes) self.root.mygpo_client.flush() elif action == 'play': for episode in episodes: self.root.enqueue_episode(episode)
def episodeContextMenu(self, episode): menu = [] toggle_new = _('Mark as old') if episode.is_new else _('Mark as new') menu.append(helper.Action(toggle_new, 'episode-toggle-new', episode)) toggle_archive = \ _('Allow deletion') if episode.archive else _('Archive') menu.append(helper.Action( toggle_archive, 'episode-toggle-archive', episode )) if episode.state != gpodder.STATE_DELETED: menu.append(helper.Action(_('Delete'), 'episode-delete', episode)) menu.append(helper.Action( _('Add to play queue'), 'episode-enqueue', episode )) self.show_context_menu(menu)
def thread_func(self, tab, param=None): if tab == TabType.ChannelChooser: url = param if url is None: url = self.getInitialOMPLUrl() if self.is_search_term(url): url = 'http://gpodder.net/search.opml?q=' + urllib.quote(url) model = OpmlListModel(opml.Importer(url)) if model.rowCount() == 0: self.notification( _('The specified URL does not provide any valid OPML podcast items.'), _('No feeds found') ) elif tab == TabType.TopPodcasts: model = OpmlListModel(opml.Importer(my.TOPLIST_OPML)) if model.rowCount() == 0: self.notification( _('The specified URL does not provide any valid OPML podcast items.'), _('No feeds found') ) elif tab == TabType.Youtube: model = OpmlListModel(youtube.find_youtube_channels(param)) if model.rowCount() == 0: self.notification( _('There are no YouTube channels that would match this query.'), _('No channels found') ) self.setModel(tab, model)
def podcastContextMenu(self, podcast): menu = [] if isinstance(podcast, qml.model.EpisodeSubsetView): menu.append(helper.Action(_('Update all'), 'update-all', podcast)) else: menu.append(helper.Action(_('Update'), 'update', podcast)) menu.append(helper.Action( _('Mark episodes as old'), 'mark-as-read', podcast )) menu.append(helper.Action(_('Rename'), 'rename-podcast', podcast)) menu.append(helper.Action( _('Change section'), 'change-section', podcast )) menu.append(helper.Action( _('Unsubscribe'), 'unsubscribe', podcast )) # menu.append(helper.Action( # 'Force update all', 'force-update-all', podcast # )) # menu.append(helper.Action('Force update', 'force-update', podcast)) self.show_context_menu(menu)
def set_podcasts(self, db, podcasts): views = [EpisodeSubsetView(db, self, _("All episodes"), "")] self.set_objects(views + podcasts)
def show_input_dialog(self, message, value='', accept=_('OK'), reject=_('Cancel'), is_text=True): self.main.showInputDialog(message, value, accept, reject, is_text)
def find_episode(podcast_url, episode_url, counter): counter['x'] += 1 self.root.start_progress(_('Merging episode actions (%d)') % counter['x']) return self.find_episode(podcast_url, episode_url)
def progress_callback(title, progress): self.start_progress('%s (%d%%)' % ( _('Loading incomplete downloads'), progress * 100))
def start_progress_callback(count): self.start_progress(_('Loading incomplete downloads'))
def contextMenuResponse(self, index): assert index < len(self.context_menu_actions) action = self.context_menu_actions[index] if action.action == 'update': if not self.request_connection(): return podcast = action.target if not podcast.pause_subscription: podcast.qupdate(finished_callback=self.update_subset_stats) elif action.action == 'force-update': action.target.qupdate(force=True, \ finished_callback=self.update_subset_stats) elif action.action == 'update-all': self.updateAllPodcasts() elif action.action == 'force-update-all': for podcast in self.root.podcast_model.get_objects(): podcast.qupdate( force=True, finished_callback=self.update_subset_stats ) if action.action == 'unsubscribe': def unsubscribe(): action.target.remove_downloaded() action.target.delete() self.root.remove_podcast(action.target) self.confirm_action(_('Remove this podcast and episodes?'), _('Unsubscribe'), unsubscribe) elif action.action == 'episode-toggle-new': action.target.toggle_new() self.root.main.episodeUpdated(action.target.id) self.update_subset_stats() elif action.action == 'episode-toggle-archive': action.target.toggle_archive() self.root.main.episodeUpdated(action.target.id) self.update_subset_stats() elif action.action == 'episode-delete': self.deleteEpisode(action.target) elif action.action == 'episode-enqueue': self.root.enqueue_episode(action.target) elif action.action == 'mark-as-read': for episode in action.target.get_all_episodes(): if not episode.was_downloaded(and_exists=True): episode.mark(is_played=True) action.target.changed.emit() self.update_subset_stats() elif action.action == 'change-section': def section_changer(podcast): section = yield (_('New section name:'), podcast.section, _('Rename')) if section and section != podcast.section: podcast.set_section(section) self.root.resort_podcast_list() self.start_input_dialog(section_changer(action.target)) elif action.action == 'rename-podcast': def title_changer(podcast): title = yield (_('New name:'), podcast.title, _('Rename')) if title and title != podcast.title: podcast.rename(title) self.root.resort_podcast_list() self.start_input_dialog(title_changer(action.target))
def on_entryURL_changed(self, url): if self.is_search_term(url): return _('Search') else: return _('Download')
def processFlattrCode(self, url): if not self._flattr.process_retrieved_code(url): self.root.show_message(_('Could not log in to Flattr.'))
def playback_episodes_for_real(self, episodes): groups = collections.defaultdict(list) for episode in episodes: file_type = episode.file_type() if file_type == 'video' and self.config.videoplayer and \ self.config.videoplayer != 'default': player = self.config.videoplayer elif file_type == 'audio' and self.config.player and \ self.config.player != 'default': player = self.config.player else: player = 'default' # Mark episode as played in the database episode.playback_mark() self.root.mygpo_client.on_playback([episode]) fmt_ids = youtube.get_fmt_ids(self.config.youtube) allow_partial = (player != 'default') filename = episode.get_playback_url(fmt_ids, allow_partial) # Determine the playback resume position - if the file # was played 100%, we simply start from the beginning resume_position = episode.current_position if resume_position == episode.total_time: resume_position = 0 # If Panucci is configured, use D-Bus to call it if player == 'panucci': try: PANUCCI_NAME = 'org.panucci.panucciInterface' PANUCCI_PATH = '/panucciInterface' PANUCCI_INTF = 'org.panucci.panucciInterface' o = gpodder.dbus_session_bus.get_object( PANUCCI_NAME, PANUCCI_PATH ) i = dbus.Interface(o, PANUCCI_INTF) def on_reply(*args): pass def error_handler(filename, err): logger.error('Exception in D-Bus call: %s', str(err)) # Fallback: use the command line client for command in util.format_desktop_command('panucci', \ [filename]): logger.info('Executing: %s', repr(command)) subprocess.Popen(command) on_error = lambda err: error_handler(filename, err) # This method only exists in Panucci > 0.9 ('new Panucci') i.playback_from(filename, resume_position, \ reply_handler=on_reply, error_handler=on_error) continue # This file was handled by the D-Bus call except Exception, e: logger.error('Calling Panucci using D-Bus', exc_info=True) # flattr episode if auto-flattr is enabled if (episode.payment_url and self.config.flattr.token and self.config.flattr.flattr_on_play): success, message = self.flattr.flattr_url(episode.payment_url) self.show_message(message, title=_('Flattr status'), important=not success) groups[player].append(filename)
def section_changer(podcast): section = yield (_('New section name:'), podcast.section, _('Rename')) if section and section != podcast.section: podcast.set_section(section) self.root.resort_podcast_list()
def title_changer(podcast): title = yield (_('New name:'), podcast.title, _('Rename')) if title and title != podcast.title: podcast.rename(title) self.root.resort_podcast_list()
def translate(self, x): return _(x)
def start_progress(self, text=_('Please wait...'), progress=0): self.do_start_progress.emit(text, progress)
def confirm(message, affirmative, callback, negative_callback): args = (message, '', affirmative, _('Cancel'), False) if (yield args): callback() elif negative_callback is not None: negative_callback()