Merge branch 'master' into dev-adaptive
This commit is contained in:
commit
cd15106eac
14
bin/gpo
14
bin/gpo
|
@ -216,8 +216,8 @@ class gPodderCli(object):
|
|||
self._extensions_episode_download_cb)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _action(self, msg, *args):
|
||||
self._start_action(msg, *args)
|
||||
def _action(self, msg):
|
||||
self._start_action(msg)
|
||||
try:
|
||||
yield
|
||||
self._finish_action()
|
||||
|
@ -271,8 +271,8 @@ class gPodderCli(object):
|
|||
self._info(_('Episode download requested by extensions.'))
|
||||
self._download_episode(episode)
|
||||
|
||||
def _start_action(self, msg, *args):
|
||||
line = util.convert_bytes(msg % args)
|
||||
def _start_action(self, msg):
|
||||
line = util.convert_bytes(msg)
|
||||
if len(line) > self.COLUMNS - 7:
|
||||
line = line[:self.COLUMNS - 7 - 3] + '...'
|
||||
else:
|
||||
|
@ -543,7 +543,7 @@ class gPodderCli(object):
|
|||
return True
|
||||
|
||||
def _update_podcast(self, podcast):
|
||||
with self._action(' %s', podcast.title):
|
||||
with self._action(' %s' % podcast.title):
|
||||
podcast.update()
|
||||
|
||||
def _pending_message(self, count):
|
||||
|
@ -618,7 +618,7 @@ class gPodderCli(object):
|
|||
return True
|
||||
|
||||
def _download_episode(self, episode):
|
||||
with self._action('Downloading %s', episode.title):
|
||||
with self._action('Downloading %s' % episode.title):
|
||||
task = download.DownloadTask(episode, self._config)
|
||||
task.add_progress_callback(self._update_action)
|
||||
task.status = download.DownloadTask.DOWNLOADING
|
||||
|
@ -951,7 +951,7 @@ class gPodderCli(object):
|
|||
def queue_task(x, task):
|
||||
def progress_updated(progress):
|
||||
self._update_action(progress)
|
||||
with self._action(_('Syncing %s'), ep_repr(task.episode)):
|
||||
with self._action(_('Syncing %s') % ep_repr(task.episode)):
|
||||
task.status = sync.SyncTask.DOWNLOADING
|
||||
task.add_progress_callback(progress_updated)
|
||||
task.run()
|
||||
|
|
|
@ -125,7 +125,7 @@ class CurrentTrackTracker(object):
|
|||
('status' not in kwargs or kwargs['status'] == 'Playing') and not
|
||||
subsecond_difference(cur['pos'], kwargs['pos'])):
|
||||
logger.debug('notify Stopped: playback discontinuity:' +
|
||||
'calc: %f observed: %f', cur['pos'], kwargs['pos'])
|
||||
'calc: %r observed: %r', cur['pos'], kwargs['pos'])
|
||||
self.notify_stop()
|
||||
|
||||
if ((kwargs['pos']) == 0 and
|
||||
|
@ -159,7 +159,7 @@ class CurrentTrackTracker(object):
|
|||
if self.status == 'Playing':
|
||||
self.notify_playing()
|
||||
else:
|
||||
logger.debug('notify Stopped: status %s', self.status)
|
||||
logger.debug('notify Stopped: status %r', self.status)
|
||||
self.notify_stop()
|
||||
|
||||
def getinfo(self):
|
||||
|
@ -289,12 +289,20 @@ class MPRISDBusReceiver(object):
|
|||
def query_position(self, sender):
|
||||
proxy = self.bus.get_object(sender, self.PATH_MPRIS)
|
||||
props = dbus.Interface(proxy, self.INTERFACE_PROPS)
|
||||
return props.Get(self.INTERFACE_MPRIS, 'Position')
|
||||
try:
|
||||
pos = props.Get(self.INTERFACE_MPRIS, 'Position')
|
||||
except:
|
||||
pos = None
|
||||
return pos
|
||||
|
||||
def query_status(self, sender):
|
||||
proxy = self.bus.get_object(sender, self.PATH_MPRIS)
|
||||
props = dbus.Interface(proxy, self.INTERFACE_PROPS)
|
||||
return props.Get(self.INTERFACE_MPRIS, 'PlaybackStatus')
|
||||
try:
|
||||
status = props.Get(self.INTERFACE_MPRIS, 'PlaybackStatus')
|
||||
except:
|
||||
status = None
|
||||
return status
|
||||
|
||||
|
||||
class gPodderNotifier(dbus.service.Object):
|
||||
|
|
|
@ -14,12 +14,9 @@ try:
|
|||
import yt_dlp as youtube_dl
|
||||
except:
|
||||
import youtube_dl
|
||||
from youtube_dl.utils import DownloadError, ExtractorError, sanitize_url
|
||||
|
||||
import gpodder
|
||||
from gpodder import download, feedcore, model, registry, youtube
|
||||
from gpodder.util import (mimetype_from_extension, nice_html_description,
|
||||
remove_html_tags)
|
||||
from gpodder import download, feedcore, model, registry, util, youtube
|
||||
|
||||
_ = gpodder.gettext
|
||||
|
||||
|
@ -112,7 +109,7 @@ class YoutubeCustomDownload(download.CustomDownload):
|
|||
os.rename(tempname_with_ext, tempname)
|
||||
dot_ext = try_ext
|
||||
break
|
||||
ext_filetype = mimetype_from_extension(dot_ext)
|
||||
ext_filetype = util.mimetype_from_extension(dot_ext)
|
||||
if ext_filetype:
|
||||
# Youtube weba formats have a webm extension and get a video/webm mime-type
|
||||
# but audio content has no width or height, so change it to audio/webm for correct icon and player
|
||||
|
@ -210,10 +207,10 @@ class YoutubeFeed(model.Feed):
|
|||
episodes = []
|
||||
for en in self._ie_result['entries']:
|
||||
guid = video_guid(en['id'])
|
||||
description = remove_html_tags(en.get('description') or _('No description available'))
|
||||
html_description = nice_html_description(en.get('thumbnail'), description)
|
||||
description = util.remove_html_tags(en.get('description') or _('No description available'))
|
||||
html_description = util.nice_html_description(en.get('thumbnail'), description)
|
||||
if en.get('ext'):
|
||||
mime_type = mimetype_from_extension('.{}'.format(en['ext']))
|
||||
mime_type = util.mimetype_from_extension('.{}'.format(en['ext']))
|
||||
else:
|
||||
mime_type = 'application/octet-stream'
|
||||
if en.get('filesize'):
|
||||
|
@ -326,8 +323,8 @@ class gPodderYoutubeDL(download.CustomDownloader):
|
|||
with youtube_dl.YoutubeDL(opts) as ydl:
|
||||
ydl.process_ie_result(tmp, download=False)
|
||||
new_entries.extend(tmp.get('entries'))
|
||||
except DownloadError as ex:
|
||||
if ex.exc_info[0] == ExtractorError:
|
||||
except youtube_dl.utils.DownloadError as ex:
|
||||
if ex.exc_info[0] == youtube_dl.utils.ExtractorError:
|
||||
# for instance "This video contains content from xyz, who has blocked it on copyright grounds"
|
||||
logger.warning('Skipping %s: %s', e.get('title', ''), ex.exc_info[1])
|
||||
continue
|
||||
|
@ -360,7 +357,7 @@ class gPodderYoutubeDL(download.CustomDownloader):
|
|||
result_type, has_playlist = extract_type(ie_result)
|
||||
while not has_playlist:
|
||||
if result_type in ('url', 'url_transparent'):
|
||||
ie_result['url'] = sanitize_url(ie_result['url'])
|
||||
ie_result['url'] = youtube_dl.utils.sanitize_url(ie_result['url'])
|
||||
if result_type == 'url':
|
||||
logger.debug("extract_info(%s) to get the video list", ie_result['url'])
|
||||
# We have to add extra_info to the results because it may be
|
||||
|
@ -400,6 +397,8 @@ class gPodderYoutubeDL(download.CustomDownloader):
|
|||
return None
|
||||
|
||||
def is_supported_url(self, url):
|
||||
if url is None:
|
||||
return False
|
||||
if self.regex_cache[0].match(url) is not None:
|
||||
return True
|
||||
for r in self.regex_cache[1:]:
|
||||
|
@ -469,12 +468,12 @@ class gPodderExtension:
|
|||
_('Old Youtube-DL'), important=True, widget=ui_object.main_window)
|
||||
|
||||
def on_episodes_context_menu(self, episodes):
|
||||
if not self.container.config.manage_downloads \
|
||||
and not all(e.was_downloaded(and_exists=True) for e in episodes) \
|
||||
and not any(e.downloading for e in episodes):
|
||||
if not self.container.config.manage_downloads and any(e.can_download() for e in episodes):
|
||||
return [(_("Download with Youtube-DL"), self.download_episodes)]
|
||||
|
||||
def download_episodes(self, episodes):
|
||||
episodes = [e for e in episodes if e.can_download()]
|
||||
|
||||
# create a new gPodderYoutubeDL to force using it even if manage_downloads is False
|
||||
downloader = gPodderYoutubeDL(self.container.manager.core.config, self.container.config, force=True)
|
||||
self.gpodder.download_episode_list(episodes, downloader=downloader)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -612,6 +612,18 @@ class DownloadTask(object):
|
|||
|
||||
downloader = property(fget=__get_downloader, fset=__set_downloader)
|
||||
|
||||
def can_queue(self):
|
||||
return self.status in (self.CANCELLED, self.PAUSED, self.FAILED)
|
||||
|
||||
def unpause(self):
|
||||
with self:
|
||||
# Resume a downloading task that was transitioning to paused
|
||||
if self.status == self.PAUSING:
|
||||
self.status = self.DOWNLOADING
|
||||
|
||||
def can_pause(self):
|
||||
return self.status in (self.DOWNLOADING, self.QUEUED)
|
||||
|
||||
def pause(self):
|
||||
with self:
|
||||
# Pause a queued download
|
||||
|
@ -622,11 +634,8 @@ class DownloadTask(object):
|
|||
self.status = self.PAUSING
|
||||
# download rate limited tasks sleep and take longer to transition from the PAUSING state to the PAUSED state
|
||||
|
||||
def unpause(self):
|
||||
with self:
|
||||
# Resume a downloading task that was transitioning to paused
|
||||
if self.status == self.PAUSING:
|
||||
self.status = self.DOWNLOADING
|
||||
def can_cancel(self):
|
||||
return self.status in (self.DOWNLOADING, self.QUEUED, self.PAUSED, self.FAILED)
|
||||
|
||||
def cancel(self):
|
||||
with self:
|
||||
|
@ -639,6 +648,9 @@ class DownloadTask(object):
|
|||
elif self.status == self.DOWNLOADING:
|
||||
self.status = self.CANCELLING
|
||||
|
||||
def can_remove(self):
|
||||
return self.status in (self.CANCELLED, self.FAILED, self.DONE)
|
||||
|
||||
def delete_partial_files(self):
|
||||
temporary_files = [self.tempname]
|
||||
# YoutubeDL creates .partial.* files for adaptive formats
|
||||
|
|
|
@ -321,7 +321,7 @@ class gPodderPreferences(BuilderWidget):
|
|||
result = gpodder.user_extensions.on_preferences()
|
||||
if result:
|
||||
for label, callback in result:
|
||||
self.notebook.append_page(callback(), Gtk.Label(label))
|
||||
self.prefs_stack.add_titled(callback(), label, label)
|
||||
|
||||
def _extensions_select_function(self, selection, model, path, path_currently_selected):
|
||||
return model.get_value(model.get_iter(path), self.C_SHOW_TOGGLE)
|
||||
|
|
|
@ -1264,7 +1264,7 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
|
||||
selection = self.treeAvailable.get_selection()
|
||||
selection.set_mode(Gtk.SelectionMode.MULTIPLE)
|
||||
self.selection_handler_id = selection.connect('changed', self.on_episode_list_selection_changed)
|
||||
self.episode_selection_handler_id = selection.connect('changed', self.on_episode_list_selection_changed)
|
||||
|
||||
self._search_episodes = SearchTreeBar(self.episodes_search_bar,
|
||||
self.entry_search_episodes,
|
||||
|
@ -1287,11 +1287,13 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
self.deck.set_can_swipe_forward(False)
|
||||
self.shownotes_object.set_episodes(eps)
|
||||
|
||||
def init_download_list_treeview(self):
|
||||
# enable multiple selection support
|
||||
self.treeDownloads.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE)
|
||||
self.treeDownloads.set_search_equal_func(TreeViewHelper.make_search_equal_func(DownloadStatusModel))
|
||||
def on_download_list_selection_changed(self, selection):
|
||||
# if self.wNotebook.get_current_page() > 0:
|
||||
# # Update the toolbar buttons
|
||||
# self.play_or_download()
|
||||
pass
|
||||
|
||||
def init_download_list_treeview(self):
|
||||
# columns and renderers for "download progress" tab
|
||||
# First column: [ICON] Episodename
|
||||
column = Gtk.TreeViewColumn(_('Episode'))
|
||||
|
@ -1340,6 +1342,12 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
|
||||
self.treeDownloads.connect('popup-menu', self.treeview_downloads_show_context_menu)
|
||||
|
||||
# enable multiple selection support
|
||||
selection = self.treeDownloads.get_selection()
|
||||
selection.set_mode(Gtk.SelectionMode.MULTIPLE)
|
||||
self.download_selection_handler_id = selection.connect('changed', self.on_download_list_selection_changed)
|
||||
self.treeDownloads.set_search_equal_func(TreeViewHelper.make_search_equal_func(DownloadStatusModel))
|
||||
|
||||
def on_treeview_expose_event(self, treeview, ctx):
|
||||
model = treeview.get_model()
|
||||
if (model is not None and model.get_iter_first() is not None):
|
||||
|
@ -1724,7 +1732,7 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
selection = self.treeDownloads.get_selection()
|
||||
model, paths = selection.get_selected_rows()
|
||||
|
||||
can_queue, can_cancel, can_pause, can_remove, can_force = (True,) * 5
|
||||
can_force, can_queue, can_pause, can_cancel, can_remove = (True,) * 5
|
||||
selected_tasks = [(Gtk.TreeRowReference.new(model, path),
|
||||
model.get_value(model.get_iter(path),
|
||||
DownloadStatusModel.C_TASK)) for path in paths]
|
||||
|
@ -1732,24 +1740,16 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
for row_reference, task in selected_tasks:
|
||||
if task.status != download.DownloadTask.QUEUED:
|
||||
can_force = False
|
||||
if task.status not in (download.DownloadTask.PAUSED,
|
||||
download.DownloadTask.FAILED,
|
||||
download.DownloadTask.CANCELLED):
|
||||
if not task.can_queue():
|
||||
can_queue = False
|
||||
if task.status not in (download.DownloadTask.PAUSED,
|
||||
download.DownloadTask.QUEUED,
|
||||
download.DownloadTask.DOWNLOADING,
|
||||
download.DownloadTask.FAILED):
|
||||
can_cancel = False
|
||||
if task.status not in (download.DownloadTask.QUEUED,
|
||||
download.DownloadTask.DOWNLOADING):
|
||||
if not task.can_pause():
|
||||
can_pause = False
|
||||
if task.status not in (download.DownloadTask.CANCELLED,
|
||||
download.DownloadTask.FAILED,
|
||||
download.DownloadTask.DONE):
|
||||
if not task.can_cancel():
|
||||
can_cancel = False
|
||||
if not task.can_remove():
|
||||
can_remove = False
|
||||
|
||||
return selected_tasks, can_queue, can_cancel, can_pause, can_remove, can_force
|
||||
return selected_tasks, can_force, can_queue, can_pause, can_cancel, can_remove
|
||||
|
||||
def downloads_finished(self, download_tasks_seen):
|
||||
# Separate tasks into downloads & syncs
|
||||
|
@ -1866,10 +1866,7 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
with task:
|
||||
if status == download.DownloadTask.QUEUED:
|
||||
# Only queue task when it's paused/failed/cancelled (or forced)
|
||||
if task.status in (download.DownloadTask.PAUSED,
|
||||
download.DownloadTask.FAILED,
|
||||
download.DownloadTask.CANCELLED) or force_start:
|
||||
|
||||
if task.can_queue() or force_start:
|
||||
# add the task back in if it was already cleaned up
|
||||
# (to trigger this cancel one downloads in the active list, cancel all
|
||||
# other downloads, quickly right click on the cancelled on one to get
|
||||
|
@ -1887,9 +1884,8 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
elif status == download.DownloadTask.PAUSING:
|
||||
task.pause()
|
||||
elif status is None:
|
||||
# Remove the selected task - cancel downloading/queued tasks
|
||||
if task.status in (download.DownloadTask.QUEUED, download.DownloadTask.DOWNLOADING):
|
||||
task.status = download.DownloadTask.CANCELLED
|
||||
if task.can_cancel():
|
||||
task.cancel()
|
||||
path = row_reference.get_path()
|
||||
# path isn't set if the item has already been removed from the list
|
||||
# (to trigger this cancel one downloads in the active list, cancel all
|
||||
|
@ -1923,7 +1919,7 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
return not treeview.is_rubber_banding_active()
|
||||
|
||||
if event is None or event.button == 3:
|
||||
selected_tasks, can_queue, can_cancel, can_pause, can_remove, can_force = \
|
||||
selected_tasks, can_force, can_queue, can_pause, can_cancel, can_remove = \
|
||||
self.downloads_list_get_selection(model, paths)
|
||||
|
||||
|
||||
|
@ -1944,12 +1940,13 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
selected_tasks, download.DownloadTask.QUEUED, force_start=True)
|
||||
else:
|
||||
item = make_menu_item(_('Download'), 'setDownloadQueued',
|
||||
selected_tasks, download.DownloadTask.QUEUED)
|
||||
selected_tasks, download.DownloadTask.QUEUED, can_queue)
|
||||
menu.append_item(item)
|
||||
menu.append_item(make_menu_item(_('Cancel'), 'setDownloadCancelled',
|
||||
selected_tasks, download.DownloadTask.CANCELLING))
|
||||
menu.append_item(make_menu_item(_('Pause'), 'setDownloadPaused',
|
||||
selected_tasks, download.DownloadTask.PAUSING))
|
||||
menu.append_item(make_menu_item(_('Pause'), 'media-playback-pause',
|
||||
selected_tasks,
|
||||
download.DownloadTask.PAUSING, can_pause))
|
||||
rmenu = Gio.Menu()
|
||||
rmenu.append_item(make_menu_item(_('Remove from list'), 'setDownloadRemove',
|
||||
selected_tasks, sensitive=can_remove))
|
||||
|
@ -2434,32 +2431,61 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
self.episode_list_status_changed(episodes)
|
||||
|
||||
def play_or_download(self, current_page=None):
|
||||
(open_instead_of_play, can_play, can_download, can_pause, can_cancel, can_delete) = (False,) * 6
|
||||
# if current_page is None:
|
||||
# current_page = self.wNotebook.get_current_page()
|
||||
# if current_page == 0:
|
||||
if True:
|
||||
(open_instead_of_play, can_play, can_download, can_pause, can_cancel, can_delete) = (False,) * 6
|
||||
|
||||
selection = self.treeAvailable.get_selection()
|
||||
if selection.count_selected_rows() > 0:
|
||||
(model, paths) = selection.get_selected_rows()
|
||||
selection = self.treeAvailable.get_selection()
|
||||
if selection.count_selected_rows() > 0:
|
||||
(model, paths) = selection.get_selected_rows()
|
||||
|
||||
for path in paths:
|
||||
try:
|
||||
episode = model.get_value(model.get_iter(path), EpisodeListModel.C_EPISODE)
|
||||
if episode is None:
|
||||
logger.info('Invalid episode at path %s', str(path))
|
||||
for path in paths:
|
||||
try:
|
||||
episode = model.get_value(model.get_iter(path), EpisodeListModel.C_EPISODE)
|
||||
if episode is None:
|
||||
logger.info('Invalid episode at path %s', str(path))
|
||||
continue
|
||||
except TypeError as te:
|
||||
logger.error('Invalid episode at path %s', str(path))
|
||||
continue
|
||||
except TypeError as te:
|
||||
logger.error('Invalid episode at path %s', str(path))
|
||||
continue
|
||||
|
||||
open_instead_of_play = open_instead_of_play or episode.file_type() not in ('audio', 'video')
|
||||
can_play = can_play or episode.can_play(self.config)
|
||||
can_download = can_download or episode.can_download()
|
||||
can_pause = can_pause or episode.can_pause()
|
||||
can_cancel = can_cancel or episode.can_cancel()
|
||||
can_delete = can_delete or episode.can_delete()
|
||||
open_instead_of_play = open_instead_of_play or episode.file_type() not in ('audio', 'video')
|
||||
can_play = can_play or episode.can_play(self.config)
|
||||
can_download = can_download or episode.can_download()
|
||||
can_pause = can_pause or episode.can_pause()
|
||||
can_cancel = can_cancel or episode.can_cancel()
|
||||
can_delete = can_delete or episode.can_delete()
|
||||
|
||||
self.set_episode_actions(open_instead_of_play, can_play, can_download, can_pause, can_cancel, can_delete)
|
||||
self.set_episode_actions(open_instead_of_play, can_play, can_download, can_pause, can_cancel, can_delete)
|
||||
|
||||
return (open_instead_of_play, can_play, can_download, can_pause, can_cancel, can_delete)
|
||||
return (open_instead_of_play, can_play, can_download, can_pause, can_cancel, can_delete)
|
||||
else:
|
||||
(can_queue, can_pause, can_cancel, can_remove) = (False,) * 4
|
||||
|
||||
selection = self.treeDownloads.get_selection()
|
||||
if selection.count_selected_rows() > 0:
|
||||
(model, paths) = selection.get_selected_rows()
|
||||
|
||||
for path in paths:
|
||||
try:
|
||||
task = model.get_value(model.get_iter(path), 0)
|
||||
if task is None:
|
||||
logger.info('Invalid task at path %s', str(path))
|
||||
continue
|
||||
except TypeError as te:
|
||||
logger.error('Invalid task at path %s', str(path))
|
||||
continue
|
||||
|
||||
can_queue = can_queue or task.can_queue()
|
||||
can_pause = can_pause or task.can_pause()
|
||||
can_cancel = can_cancel or task.can_cancel()
|
||||
can_remove = can_remove or task.can_remove()
|
||||
|
||||
self.set_episode_actions(False, False, can_queue, can_pause, can_cancel, can_remove)
|
||||
|
||||
return (False, False, can_queue, can_pause, can_cancel, can_remove)
|
||||
|
||||
def on_cbMaxDownloads_toggled(self, widget, *args):
|
||||
self.spinMaxDownloads.set_sensitive(self.cbMaxDownloads.get_active())
|
||||
|
@ -2614,7 +2640,7 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
self.treeAvailable.scroll_to_point(0, 0)
|
||||
|
||||
descriptions = self.config.episode_list_descriptions
|
||||
with self.treeAvailable.get_selection().handler_block(self.selection_handler_id):
|
||||
with self.treeAvailable.get_selection().handler_block(self.episode_selection_handler_id):
|
||||
# have to block the on_episode_list_selection_changed handler because
|
||||
# when selecting any channel from All Episodes, on_episode_list_selection_changed
|
||||
# is called once per episode (4k time in my case), causing episode shownotes
|
||||
|
@ -3086,6 +3112,15 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
return '\n'.join(titles) + '\n\n' + message
|
||||
|
||||
def delete_episode_list(self, episodes, confirm=True, callback=None):
|
||||
# if self.wNotebook.get_current_page() > 0:
|
||||
# selection = self.treeDownloads.get_selection()
|
||||
# (model, paths) = selection.get_selected_rows()
|
||||
# selected_tasks = [(Gtk.TreeRowReference.new(model, path),
|
||||
# model.get_value(model.get_iter(path),
|
||||
# DownloadStatusModel.C_TASK)) for path in paths]
|
||||
# self._for_each_task_set_status(selected_tasks, status=None, force_start=False)
|
||||
# return
|
||||
#
|
||||
if not episodes:
|
||||
return False
|
||||
|
||||
|
@ -3910,7 +3945,6 @@ class gPodder(BuilderWidget, dbus.service.Object):
|
|||
for episode in self.get_selected_episodes():
|
||||
if episode.can_pause():
|
||||
episode.download_task.pause()
|
||||
|
||||
self.update_downloads_list()
|
||||
|
||||
def on_episode_download_clicked(self, button):
|
||||
|
|
|
@ -485,20 +485,20 @@ class PodcastEpisode(PodcastModelObject):
|
|||
"""
|
||||
return not self.was_downloaded(and_exists=True) and (
|
||||
not self.download_task
|
||||
or self.download_task.status in (self.download_task.PAUSING, self.download_task.PAUSED, self.download_task.FAILED))
|
||||
or self.download_task.can_queue()
|
||||
or self.download_task.status == self.download_task.PAUSING)
|
||||
|
||||
def can_pause(self):
|
||||
"""
|
||||
gPodder.on_pause_selected_episodes() filters selection with this method.
|
||||
"""
|
||||
return self.download_task and self.download_task.status in (self.download_task.QUEUED, self.download_task.DOWNLOADING)
|
||||
return self.download_task and self.download_task.can_pause()
|
||||
|
||||
def can_cancel(self):
|
||||
"""
|
||||
DownloadTask.cancel() only cancels the following tasks.
|
||||
"""
|
||||
return self.download_task and self.download_task.status in \
|
||||
(self.download_task.DOWNLOADING, self.download_task.QUEUED, self.download_task.PAUSED, self.download_task.FAILED)
|
||||
return self.download_task and self.download_task.can_cancel()
|
||||
|
||||
def can_delete(self):
|
||||
"""
|
||||
|
|
|
@ -779,6 +779,12 @@ class SyncTask(download.DownloadTask):
|
|||
|
||||
episode = property(fget=__get_episode)
|
||||
|
||||
def can_queue(self):
|
||||
return self.status in (self.CANCELLED, self.PAUSED, self.FAILED)
|
||||
|
||||
def can_pause(self):
|
||||
return self.status in (self.DOWNLOADING, self.QUEUED)
|
||||
|
||||
def pause(self):
|
||||
with self:
|
||||
# Pause a queued download
|
||||
|
@ -788,6 +794,9 @@ class SyncTask(download.DownloadTask):
|
|||
elif self.status == self.DOWNLOADING:
|
||||
self.status = self.PAUSING
|
||||
|
||||
def can_cancel(self):
|
||||
return self.status in (self.DOWNLOADING, self.QUEUED, self.PAUSED, self.FAILED)
|
||||
|
||||
def cancel(self):
|
||||
with self:
|
||||
# Cancelling directly is allowed if the task isn't currently downloading
|
||||
|
@ -801,6 +810,9 @@ class SyncTask(download.DownloadTask):
|
|||
self.status = self.CANCELLING
|
||||
self.device.cancel()
|
||||
|
||||
def can_remove(self):
|
||||
return self.status in (self.CANCELLED, self.FAILED, self.DONE)
|
||||
|
||||
def removed_from_list(self):
|
||||
if self.status != self.DONE:
|
||||
self.device.cleanup_task(self)
|
||||
|
|
Loading…
Reference in New Issue