First debugging implementation of downloads
This commit is contained in:
parent
71bc640131
commit
7dd5b1b94e
@ -53,6 +53,7 @@ from qutebrowser.commands.managers import CommandManager, SearchManager
|
|||||||
from qutebrowser.config.iniparsers import ReadWriteConfigParser
|
from qutebrowser.config.iniparsers import ReadWriteConfigParser
|
||||||
from qutebrowser.config.lineparser import LineConfigParser
|
from qutebrowser.config.lineparser import LineConfigParser
|
||||||
from qutebrowser.browser.cookies import CookieJar
|
from qutebrowser.browser.cookies import CookieJar
|
||||||
|
from qutebrowser.browser.downloads import DownloadManager
|
||||||
from qutebrowser.utils.message import MessageBridge
|
from qutebrowser.utils.message import MessageBridge
|
||||||
from qutebrowser.utils.misc import (get_standard_dir, actute_warning,
|
from qutebrowser.utils.misc import (get_standard_dir, actute_warning,
|
||||||
get_qt_args)
|
get_qt_args)
|
||||||
@ -132,6 +133,7 @@ class Application(QApplication):
|
|||||||
self.networkmanager = NetworkManager(self.cookiejar)
|
self.networkmanager = NetworkManager(self.cookiejar)
|
||||||
self.commandmanager = CommandManager()
|
self.commandmanager = CommandManager()
|
||||||
self.searchmanager = SearchManager()
|
self.searchmanager = SearchManager()
|
||||||
|
self.downloadmanager = DownloadManager()
|
||||||
self.mainwindow = MainWindow()
|
self.mainwindow = MainWindow()
|
||||||
|
|
||||||
self.modeman.mainwindow = self.mainwindow
|
self.modeman.mainwindow = self.mainwindow
|
||||||
@ -386,6 +388,9 @@ class Application(QApplication):
|
|||||||
cmd.update_completion.connect(completer.on_update_completion)
|
cmd.update_completion.connect(completer.on_update_completion)
|
||||||
completer.change_completed_part.connect(cmd.on_change_completed_part)
|
completer.change_completed_part.connect(cmd.on_change_completed_part)
|
||||||
|
|
||||||
|
# downloads
|
||||||
|
tabs.start_download.connect(self.downloadmanager.fetch)
|
||||||
|
|
||||||
def _recover_pages(self):
|
def _recover_pages(self):
|
||||||
"""Try to recover all open pages.
|
"""Try to recover all open pages.
|
||||||
|
|
||||||
|
88
qutebrowser/browser/downloads.py
Normal file
88
qutebrowser/browser/downloads.py
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
# Copyright 2014 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||||
|
#
|
||||||
|
# This file is part of qutebrowser.
|
||||||
|
#
|
||||||
|
# qutebrowser 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.
|
||||||
|
#
|
||||||
|
# qutebrowser 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 qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
"""Download manager."""
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
from PyQt5.QtCore import pyqtSlot, QObject
|
||||||
|
|
||||||
|
from qutebrowser.utils.log import downloads as logger
|
||||||
|
|
||||||
|
|
||||||
|
class DownloadManager(QObject):
|
||||||
|
|
||||||
|
"""Manager for running downloads."""
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
self.downloads = []
|
||||||
|
|
||||||
|
def _get_filename(self, reply):
|
||||||
|
"""Get a suitable filename to download a file to.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
reply: The QNetworkReply to get a filename for."""
|
||||||
|
filename = None
|
||||||
|
# First check if the Content-Disposition header has a filename
|
||||||
|
# attribute.
|
||||||
|
if reply.hasRawHeader('Content-Disposition'):
|
||||||
|
header = reply.rawHeader('Content-Disposition')
|
||||||
|
data = header.split(':', maxsplit=1)[1].strip()
|
||||||
|
for pair in data.split(';'):
|
||||||
|
if '=' in pair:
|
||||||
|
key, value = pair.split('=')
|
||||||
|
if key == 'filename':
|
||||||
|
filename = value.strip('"')
|
||||||
|
break
|
||||||
|
# Then try to get filename from url
|
||||||
|
if not filename:
|
||||||
|
filename = reply.url().path()
|
||||||
|
# If that fails as well, use a fallback
|
||||||
|
if not filename:
|
||||||
|
filename = 'qutebrowser-download'
|
||||||
|
return os.path.basename(filename)
|
||||||
|
|
||||||
|
@pyqtSlot('QNetworkReply')
|
||||||
|
def fetch(self, reply):
|
||||||
|
"""Download a QNetworkReply to disk.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
reply: The QNetworkReply to download.
|
||||||
|
"""
|
||||||
|
filename = self._get_filename(reply)
|
||||||
|
logger.debug("fetch: {} -> {}".format(reply.url(), filename))
|
||||||
|
reply.downloadProgress.connect(self.on_download_progress)
|
||||||
|
reply.readyRead.connect(self.on_ready_read)
|
||||||
|
reply.finished.connect(self.on_finished)
|
||||||
|
|
||||||
|
@pyqtSlot(int, int)
|
||||||
|
def on_download_progress(self, done, total):
|
||||||
|
if total == -1:
|
||||||
|
perc = '???'
|
||||||
|
else:
|
||||||
|
perc = 100 * done / total
|
||||||
|
logger.debug("{}% done".format(perc))
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def on_ready_read(self):
|
||||||
|
logger.debug("readyread")
|
||||||
|
self.sender().readAll()
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def on_finished(self):
|
||||||
|
logger.debug("finished")
|
@ -18,7 +18,7 @@
|
|||||||
"""The main browser widgets."""
|
"""The main browser widgets."""
|
||||||
|
|
||||||
import sip
|
import sip
|
||||||
from PyQt5.QtCore import QCoreApplication
|
from PyQt5.QtCore import QCoreApplication, pyqtSignal, pyqtSlot
|
||||||
from PyQt5.QtNetwork import QNetworkReply
|
from PyQt5.QtNetwork import QNetworkReply
|
||||||
from PyQt5.QtWidgets import QFileDialog
|
from PyQt5.QtWidgets import QFileDialog
|
||||||
from PyQt5.QtPrintSupport import QPrintDialog
|
from PyQt5.QtPrintSupport import QPrintDialog
|
||||||
@ -39,8 +39,13 @@ class BrowserPage(QWebPage):
|
|||||||
Attributes:
|
Attributes:
|
||||||
_extension_handlers: Mapping of QWebPage extensions to their handlers.
|
_extension_handlers: Mapping of QWebPage extensions to their handlers.
|
||||||
network_access_manager: The QNetworkAccessManager used.
|
network_access_manager: The QNetworkAccessManager used.
|
||||||
|
|
||||||
|
Signals:
|
||||||
|
start_download: Emitted when a file should be downloaded.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
start_download = pyqtSignal('QNetworkReply*')
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
self._extension_handlers = {
|
self._extension_handlers = {
|
||||||
@ -50,6 +55,7 @@ class BrowserPage(QWebPage):
|
|||||||
self.setNetworkAccessManager(
|
self.setNetworkAccessManager(
|
||||||
QCoreApplication.instance().networkmanager)
|
QCoreApplication.instance().networkmanager)
|
||||||
self.printRequested.connect(self.on_print_requested)
|
self.printRequested.connect(self.on_print_requested)
|
||||||
|
self.downloadRequested.connect(self.on_download_requested)
|
||||||
|
|
||||||
def _handle_errorpage(self, opt, out):
|
def _handle_errorpage(self, opt, out):
|
||||||
"""Display an error page if needed.
|
"""Display an error page if needed.
|
||||||
@ -118,6 +124,17 @@ class BrowserPage(QWebPage):
|
|||||||
printdiag = QPrintDialog()
|
printdiag = QPrintDialog()
|
||||||
printdiag.open(lambda: frame.print(printdiag.printer()))
|
printdiag.open(lambda: frame.print(printdiag.printer()))
|
||||||
|
|
||||||
|
@pyqtSlot('QNetworkRequest')
|
||||||
|
def on_download_requested(self, request):
|
||||||
|
"""Called when the user wants to download a link.
|
||||||
|
|
||||||
|
Emit:
|
||||||
|
start_download: Emitted with the QNetworkReply associated with the
|
||||||
|
passed request.
|
||||||
|
"""
|
||||||
|
reply = self.networkAccessManager().get(request)
|
||||||
|
self.start_download.emit(reply)
|
||||||
|
|
||||||
def userAgentForUrl(self, url):
|
def userAgentForUrl(self, url):
|
||||||
"""Override QWebPage::userAgentForUrl to customize the user agent."""
|
"""Override QWebPage::userAgentForUrl to customize the user agent."""
|
||||||
ua = config.get('network', 'user-agent')
|
ua = config.get('network', 'user-agent')
|
||||||
|
@ -66,6 +66,7 @@ init = getLogger('init')
|
|||||||
signals = getLogger('signals')
|
signals = getLogger('signals')
|
||||||
hints = getLogger('hints')
|
hints = getLogger('hints')
|
||||||
keyboard = getLogger('keyboard')
|
keyboard = getLogger('keyboard')
|
||||||
|
downloads = getLogger('downloads')
|
||||||
js = getLogger('js')
|
js = getLogger('js')
|
||||||
qt = getLogger('qt')
|
qt = getLogger('qt')
|
||||||
|
|
||||||
|
@ -72,6 +72,8 @@ class TabbedBrowser(TabWidget):
|
|||||||
resized: Emitted when the browser window has resized, so the completion
|
resized: Emitted when the browser window has resized, so the completion
|
||||||
widget can adjust its size to it.
|
widget can adjust its size to it.
|
||||||
arg: The new size.
|
arg: The new size.
|
||||||
|
start_download: Emitted when any tab wants to start downloading
|
||||||
|
something.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cur_progress = pyqtSignal(int)
|
cur_progress = pyqtSignal(int)
|
||||||
@ -82,6 +84,7 @@ class TabbedBrowser(TabWidget):
|
|||||||
cur_link_hovered = pyqtSignal(str, str, str)
|
cur_link_hovered = pyqtSignal(str, str, str)
|
||||||
cur_scroll_perc_changed = pyqtSignal(int, int)
|
cur_scroll_perc_changed = pyqtSignal(int, int)
|
||||||
cur_load_status_changed = pyqtSignal(str)
|
cur_load_status_changed = pyqtSignal(str)
|
||||||
|
start_download = pyqtSignal('QNetworkReply*')
|
||||||
hint_strings_updated = pyqtSignal(list)
|
hint_strings_updated = pyqtSignal(list)
|
||||||
shutdown_complete = pyqtSignal()
|
shutdown_complete = pyqtSignal()
|
||||||
quit = pyqtSignal()
|
quit = pyqtSignal()
|
||||||
@ -150,6 +153,9 @@ class TabbedBrowser(TabWidget):
|
|||||||
# hintmanager
|
# hintmanager
|
||||||
tab.hintmanager.hint_strings_updated.connect(self.hint_strings_updated)
|
tab.hintmanager.hint_strings_updated.connect(self.hint_strings_updated)
|
||||||
tab.hintmanager.openurl.connect(self.cmd.openurl)
|
tab.hintmanager.openurl.connect(self.cmd.openurl)
|
||||||
|
# downloads
|
||||||
|
tab.page().unsupportedContent.connect(self.start_download)
|
||||||
|
tab.page().start_download.connect(self.start_download)
|
||||||
# misc
|
# misc
|
||||||
tab.titleChanged.connect(self.on_title_changed)
|
tab.titleChanged.connect(self.on_title_changed)
|
||||||
tab.iconChanged.connect(self.on_icon_changed)
|
tab.iconChanged.connect(self.on_icon_changed)
|
||||||
|
Loading…
Reference in New Issue
Block a user