downloads: use global TempDownloadManager
This way, all temporary downloads will end up in the same directory and everything is cleaned up at program exit, not when the corresponding window is closed.
This commit is contained in:
parent
c060f9e5c2
commit
81b2688c70
@ -47,7 +47,7 @@ from qutebrowser.completion.models import instances as completionmodels
|
|||||||
from qutebrowser.commands import cmdutils, runners, cmdexc
|
from qutebrowser.commands import cmdutils, runners, cmdexc
|
||||||
from qutebrowser.config import style, config, websettings, configexc
|
from qutebrowser.config import style, config, websettings, configexc
|
||||||
from qutebrowser.browser import urlmarks, adblock
|
from qutebrowser.browser import urlmarks, adblock
|
||||||
from qutebrowser.browser.webkit import cookies, cache, history
|
from qutebrowser.browser.webkit import cookies, cache, history, downloads
|
||||||
from qutebrowser.browser.webkit.network import (qutescheme, proxy,
|
from qutebrowser.browser.webkit.network import (qutescheme, proxy,
|
||||||
networkmanager)
|
networkmanager)
|
||||||
from qutebrowser.mainwindow import mainwindow
|
from qutebrowser.mainwindow import mainwindow
|
||||||
@ -438,6 +438,8 @@ def _init_modules(args, crash_handler):
|
|||||||
os.environ.pop('QT_WAYLAND_DISABLE_WINDOWDECORATION', None)
|
os.environ.pop('QT_WAYLAND_DISABLE_WINDOWDECORATION', None)
|
||||||
_maybe_hide_mouse_cursor()
|
_maybe_hide_mouse_cursor()
|
||||||
objreg.get('config').changed.connect(_maybe_hide_mouse_cursor)
|
objreg.get('config').changed.connect(_maybe_hide_mouse_cursor)
|
||||||
|
temp_downloads = downloads.TempDownloadManager(qApp)
|
||||||
|
objreg.register('temporary-downloads', temp_downloads)
|
||||||
|
|
||||||
|
|
||||||
def _init_late_modules(args):
|
def _init_late_modules(args):
|
||||||
@ -711,6 +713,8 @@ class Quitter:
|
|||||||
not restart):
|
not restart):
|
||||||
atexit.register(shutil.rmtree, self._args.basedir,
|
atexit.register(shutil.rmtree, self._args.basedir,
|
||||||
ignore_errors=True)
|
ignore_errors=True)
|
||||||
|
# Delete temp download dir
|
||||||
|
objreg.get('temporary-downloads').cleanup()
|
||||||
# If we don't kill our custom handler here we might get segfaults
|
# If we don't kill our custom handler here we might get segfaults
|
||||||
log.destroy.debug("Deactivating message handler...")
|
log.destroy.debug("Deactivating message handler...")
|
||||||
qInstallMessageHandler(None)
|
qInstallMessageHandler(None)
|
||||||
|
@ -738,20 +738,6 @@ class DownloadManager(QAbstractListModel):
|
|||||||
self._update_timer = usertypes.Timer(self, 'download-update')
|
self._update_timer = usertypes.Timer(self, 'download-update')
|
||||||
self._update_timer.timeout.connect(self.update_gui)
|
self._update_timer.timeout.connect(self.update_gui)
|
||||||
self._update_timer.setInterval(REFRESH_INTERVAL)
|
self._update_timer.setInterval(REFRESH_INTERVAL)
|
||||||
self._tmpdir_obj = None
|
|
||||||
|
|
||||||
def cleanup(self):
|
|
||||||
"""Clean up any temporary files from this manager."""
|
|
||||||
if self._tmpdir_obj is not None:
|
|
||||||
self._tmpdir_obj.cleanup()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def tmpdir(self):
|
|
||||||
"""Lazily create a temporary directory if one is needed."""
|
|
||||||
if self._tmpdir_obj is None:
|
|
||||||
self._tmpdir_obj = tempfile.TemporaryDirectory(
|
|
||||||
prefix='qutebrowser-downloads-')
|
|
||||||
return self._tmpdir_obj
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return utils.get_repr(self, downloads=len(self.downloads))
|
return utils.get_repr(self, downloads=len(self.downloads))
|
||||||
@ -966,17 +952,8 @@ class DownloadManager(QAbstractListModel):
|
|||||||
if filename is not usertypes.OPEN_DOWNLOAD:
|
if filename is not usertypes.OPEN_DOWNLOAD:
|
||||||
download.set_filename(filename)
|
download.set_filename(filename)
|
||||||
return
|
return
|
||||||
# Find the next free filename without causing a race condition
|
tmp_manager = objreg.get('temporary-downloads')
|
||||||
index = 0
|
fobj = tmp_manager.get_tmpfile(suggested_filename)
|
||||||
while True:
|
|
||||||
basename = '{}-{}'.format(index, suggested_filename)
|
|
||||||
path = os.path.join(self.tmpdir.name, basename)
|
|
||||||
try:
|
|
||||||
fobj = open(path, 'xb')
|
|
||||||
except FileExistsError:
|
|
||||||
index += 1
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
download.finished.connect(download.open_file)
|
download.finished.connect(download.open_file)
|
||||||
download.autoclose = True
|
download.autoclose = True
|
||||||
download.set_fileobj(fobj)
|
download.set_fileobj(fobj)
|
||||||
@ -1291,3 +1268,59 @@ class DownloadManager(QAbstractListModel):
|
|||||||
The number of unfinished downloads.
|
The number of unfinished downloads.
|
||||||
"""
|
"""
|
||||||
return sum(1 for download in self.downloads if not download.done)
|
return sum(1 for download in self.downloads if not download.done)
|
||||||
|
|
||||||
|
|
||||||
|
class TempDownloadManager(QObject):
|
||||||
|
|
||||||
|
"""Manager to handle temporary download files.
|
||||||
|
|
||||||
|
The downloads are downloaded to a temporary location and then openened with
|
||||||
|
the system standard application. The temporary files are deleted when
|
||||||
|
qutebrowser is shutdown.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
files: A list of NamedTemporaryFiles of downloaded items.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.files = []
|
||||||
|
self._tmpdir = None
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
"""Clean up any temporary files."""
|
||||||
|
if self._tmpdir is not None:
|
||||||
|
self._tmpdir.cleanup()
|
||||||
|
self._tmpdir = None
|
||||||
|
|
||||||
|
def get_tmpdir(self):
|
||||||
|
"""Return the temporary directory that is used for downloads.
|
||||||
|
|
||||||
|
The directory is created lazily on first access.
|
||||||
|
|
||||||
|
Return:
|
||||||
|
The tempfile.TemporaryDirectory that is used.
|
||||||
|
"""
|
||||||
|
if self._tmpdir is None:
|
||||||
|
self._tmpdir = tempfile.TemporaryDirectory(
|
||||||
|
prefix='qutebrowser-downloads-')
|
||||||
|
return self._tmpdir
|
||||||
|
|
||||||
|
def get_tmpfile(self, suggested_name):
|
||||||
|
"""Return a temporary file in the temporary downloads directory.
|
||||||
|
|
||||||
|
The files are kept as long as qutebrowser is running and automatically
|
||||||
|
cleaned up at program exit.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
suggested_name: str of the "suggested"/original filename. Used as a
|
||||||
|
suffix, so any file extenions are preserved.
|
||||||
|
|
||||||
|
Return:
|
||||||
|
A tempfile.NamedTemporaryFile that should be used to save the file.
|
||||||
|
"""
|
||||||
|
tmpdir = self.get_tmpdir()
|
||||||
|
fobj = tempfile.NamedTemporaryFile(dir=tmpdir.name, delete=False,
|
||||||
|
suffix=suggested_name)
|
||||||
|
self.files.append(fobj)
|
||||||
|
return fobj
|
||||||
|
@ -452,7 +452,6 @@ class MainWindow(QWidget):
|
|||||||
self._save_geometry()
|
self._save_geometry()
|
||||||
log.destroy.debug("Closing window {}".format(self.win_id))
|
log.destroy.debug("Closing window {}".format(self.win_id))
|
||||||
self.tabbed_browser.shutdown()
|
self.tabbed_browser.shutdown()
|
||||||
self._get_object('download-manager').cleanup()
|
|
||||||
|
|
||||||
def closeEvent(self, e):
|
def closeEvent(self, e):
|
||||||
"""Override closeEvent to display a confirmation if needed."""
|
"""Override closeEvent to display a confirmation if needed."""
|
||||||
|
Loading…
Reference in New Issue
Block a user