Start work on migrating get books internal browser to web engine

This commit is contained in:
Kovid Goyal 2019-03-29 13:15:49 +05:30
parent 581c5d8988
commit c8e78749eb
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
7 changed files with 147 additions and 291 deletions

View File

@ -43,6 +43,7 @@ FAKE_PROTOCOL, FAKE_HOST = 'clbr', 'internal.invalid'
VIEWER_APP_UID = 'com.calibre-ebook.viewer'
EDITOR_APP_UID = 'com.calibre-ebook.edit-book'
MAIN_APP_UID = 'com.calibre-ebook.main-gui'
STORE_DIALOG_APP_UID = 'com.calibre-ebook.store-dialog'
try:
preferred_encoding = locale.getpreferredencoding()
codecs.lookup(preferred_encoding)

View File

@ -1,136 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function, unicode_literals
__license__ = 'GPL 3'
__copyright__ = '2011, John Schember <john@nachtimwald.com>'
__docformat__ = 'restructuredtext en'
import os
from PyQt5.Qt import QNetworkCookieJar, QNetworkProxy
from PyQt5.QtWebKitWidgets import QWebView, QWebPage
from calibre import USER_AGENT, get_proxies
from calibre.ebooks import BOOK_EXTENSIONS
from calibre.gui2 import choose_save_file, NO_URL_FORMATTING
from calibre.gui2.ebook_download import show_download_info
from calibre.ptempfile import PersistentTemporaryFile
from calibre.utils.filenames import ascii_filename
from calibre.web import get_download_filename
from polyglot.builtins import unicode_type
from polyglot.urllib import urlparse
class NPWebView(QWebView):
def __init__(self, *args):
QWebView.__init__(self, *args)
self.gui = None
self.tags = ''
self.create_browser = None
self._page = NPWebPage()
self.setPage(self._page)
self.cookie_jar = QNetworkCookieJar()
self.page().networkAccessManager().setCookieJar(self.cookie_jar)
http_proxy = get_proxies().get('http', None)
if http_proxy:
proxy_parts = urlparse(http_proxy)
proxy = QNetworkProxy()
proxy.setType(QNetworkProxy.HttpProxy)
if proxy_parts.username:
proxy.setUser(proxy_parts.username)
if proxy_parts.password:
proxy.setPassword(proxy_parts.password)
if proxy_parts.hostname:
proxy.setHostName(proxy_parts.hostname)
if proxy_parts.port:
proxy.setPort(proxy_parts.port)
self.page().networkAccessManager().setProxy(proxy)
self.page().setForwardUnsupportedContent(True)
self.page().unsupportedContent.connect(self.start_download)
self.page().downloadRequested.connect(self.start_download)
self.page().networkAccessManager().sslErrors.connect(self.ignore_ssl_errors)
def createWindow(self, type):
if type == QWebPage.WebBrowserWindow:
return self
else:
return None
def set_gui(self, gui):
self.gui = gui
def set_tags(self, tags):
self.tags = tags
def start_download(self, request):
if not self.gui:
return
url = unicode_type(request.url().toString(NO_URL_FORMATTING))
cf = self.get_cookies()
filename = get_download_filename(url, cf)
ext = os.path.splitext(filename)[1][1:].lower()
filename = ascii_filename(filename[:60] + '.' + ext)
if ext not in BOOK_EXTENSIONS:
if ext == 'acsm':
from calibre.gui2.dialogs.confirm_delete import confirm
if not confirm('<p>' + _('This e-book is a DRMed EPUB file. '
'You will be prompted to save this file to your '
'computer. Once it is saved, open it with '
'<a href="https://www.adobe.com/solutions/ebook/digital-editions.html">'
'Adobe Digital Editions</a> (ADE).<p>ADE, in turn '
'will download the actual e-book, which will be a '
'.epub file. You can add this book to calibre '
'using "Add Books" and selecting the file from '
'the ADE library folder.'),
'acsm_download', self):
return
name = choose_save_file(self, 'web-store-download-unknown', _('File is not a supported e-book type. Save to disk?'), initial_filename=filename)
if name:
self.gui.download_ebook(url, cf, name, name, False, create_browser=self.create_browser)
else:
show_download_info(filename, self)
self.gui.download_ebook(url, cf, filename, tags=self.tags, create_browser=self.create_browser)
def ignore_ssl_errors(self, reply, errors):
reply.ignoreSslErrors(errors)
def get_cookies(self):
'''
Writes QNetworkCookies to Mozilla cookie .txt file.
:return: The file path to the cookie file.
'''
cf = PersistentTemporaryFile(suffix='.txt')
cf.write('# Netscape HTTP Cookie File\n\n')
for c in self.page().networkAccessManager().cookieJar().allCookies():
cookie = []
domain = unicode_type(c.domain())
cookie.append(domain)
cookie.append('TRUE' if domain.startswith('.') else 'FALSE')
cookie.append(unicode_type(c.path()))
cookie.append('TRUE' if c.isSecure() else 'FALSE')
cookie.append(unicode_type(c.expirationDate().toTime_t()))
cookie.append(unicode_type(c.name()))
cookie.append(unicode_type(c.value()))
cf.write('\t'.join(cookie))
cf.write('\n')
cf.close()
return cf.name
class NPWebPage(QWebPage):
def userAgentForUrl(self, url):
return USER_AGENT

View File

@ -0,0 +1,112 @@
#!/usr/bin/env python2
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
from __future__ import absolute_import, division, print_function, unicode_literals
import json
import os
from base64 import standard_b64decode, standard_b64encode
from PyQt5.Qt import (
QHBoxLayout, QProgressBar, QPushButton, QVBoxLayout, QWidget, pyqtSignal
)
from PyQt5.QtWebEngineWidgets import QWebEngineView
from calibre import url_slash_cleaner
from calibre.constants import STORE_DIALOG_APP_UID, islinux, iswindows
from calibre.gui2 import Application, set_app_uid
from calibre.gui2.main_window import MainWindow
from calibre.ptempfile import reset_base_dir
class View(QWebEngineView):
pass
class Central(QWidget):
home = pyqtSignal()
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.l = l = QVBoxLayout(self)
self.view = v = View(self)
v.loadStarted.connect(self.load_started)
v.loadProgress.connect(self.load_progress)
v.loadFinished.connect(self.load_finished)
l.addWidget(v)
self.h = h = QHBoxLayout()
l.addLayout(h)
self.home_button = b = QPushButton(_('Home'))
b.clicked.connect(self.home)
h.addWidget(b)
self.back_button = b = QPushButton(_('Back'))
b.clicked.connect(v.back)
h.addWidget(b)
self.forward_button = b = QPushButton(_('Forward'))
b.clicked.connect(v.forward)
h.addWidget(b)
self.progress_bar = b = QProgressBar(self)
h.addWidget(b)
def load_started(self):
self.progress_bar.setValue(0)
def load_progress(self, amt):
self.progress_bar.setValue(amt)
def load_finished(self, ok):
self.progress_bar.setValue(100)
class Main(MainWindow):
def __init__(self, data):
MainWindow.__init__(self, None)
self.data = data
self.central = c = Central(self)
c.home.connect(self.go_home)
self.setCentralWidget(c)
@property
def view(self):
return self.central.view
def go_home(self):
self.go_to()
def go_to(self, url=None):
url = url or self.data['base_url']
url = url_slash_cleaner(url)
self.view.load(url)
def main(args):
# Ensure we can continue to function if GUI is closed
os.environ.pop('CALIBRE_WORKER_TEMP_DIR', None)
reset_base_dir()
if iswindows:
# Ensure that all instances are grouped together in the task bar. This
# prevents them from being grouped with viewer/editor process when
# launched from within calibre, as both use calibre-parallel.exe
set_app_uid(STORE_DIALOG_APP_UID)
data = args[-1]
data = json.loads(standard_b64decode(data))
override = 'calibre-ebook-viewer' if islinux else None
app = Application(args, override_program_name=override)
app.exec_()
if __name__ == '__main__':
sample_data = standard_b64encode(
json.dumps({
u'window_title': u'MobileRead',
u'base_url': u'https://www.mobileread.com/',
u'detail_url': u'http://www.mobileread.com/forums/showthread.php?t=54477',
u'tags': u''
})
)
main([sample_data])

View File

@ -1,57 +1,36 @@
# -*- coding: utf-8 -*-
#!/usr/bin/env python2
# vim:fileencoding=utf-8
# License: GPLv3 Copyright: 2019, Kovid Goyal <kovid at kovidgoyal.net>
from __future__ import absolute_import, division, print_function, unicode_literals
__license__ = 'GPL 3'
__copyright__ = '2011, John Schember <john@nachtimwald.com>'
__docformat__ = 'restructuredtext en'
from PyQt5.Qt import QDialog, QUrl
from calibre import url_slash_cleaner
from calibre.gui2.store.web_store_dialog_ui import Ui_Dialog
import json
from base64 import standard_b64encode
class WebStoreDialog(QDialog, Ui_Dialog):
class WebStoreDialog(object):
def __init__(self, gui, base_url, parent=None, detail_url=None, create_browser=None):
QDialog.__init__(self, parent=parent)
self.setupUi(self)
self.gui = gui
self.base_url = base_url
self.detail_url = detail_url
self.create_browser = create_browser
self.window_title = None
self.tags = None
self.view.set_gui(self.gui)
self.view.create_browser = create_browser
self.view.loadStarted.connect(self.load_started)
self.view.loadProgress.connect(self.load_progress)
self.view.loadFinished.connect(self.load_finished)
self.home.clicked.connect(self.go_home)
self.reload.clicked.connect(self.view.reload)
self.back.clicked.connect(self.view.back)
self.go_home(detail_url=detail_url)
def setWindowTitle(self, title):
self.window_title = title
def set_tags(self, tags):
self.view.set_tags(tags)
self.tags = tags
def load_started(self):
self.progress.setValue(0)
def load_progress(self, val):
self.progress.setValue(val)
def load_finished(self, ok=True):
self.progress.setValue(100)
def go_home(self, checked=False, detail_url=None):
if detail_url:
url = detail_url
else:
url = self.base_url
# Reduce redundant /'s because some stores
# (Feedbooks) and server frameworks (cherrypy)
# choke on them.
url = url_slash_cleaner(url)
self.view.load(QUrl(url))
def exec_(self):
data = {'base_url': self.base_url, 'detail_url': self.detail_url, 'window_title': self.window_title, 'tags': self.tags}
data = json.dumps(data)
if not isinstance(data, bytes):
data = data.encode('utf-8')
data = standard_b64encode(data)
if isinstance(data, bytes):
data = data.decode('ascii')
args = ['store-dialog', data]
self.gui.job_manager.launch_gui_app(args[0], kwargs={'args':args})

View File

@ -1,110 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Dialog</class>
<widget class="QDialog" name="Dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>962</width>
<height>656</height>
</rect>
</property>
<property name="windowTitle">
<string/>
</property>
<property name="sizeGripEnabled">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="5">
<widget class="QFrame" name="frame">
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="NPWebView" name="view">
<property name="url">
<url>
<string>about:blank</string>
</url>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="home">
<property name="text">
<string>Home</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="reload">
<property name="text">
<string>Reload</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QProgressBar" name="progress">
<property name="value">
<number>0</number>
</property>
<property name="format">
<string>%p%</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="back">
<property name="text">
<string>Back</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QPushButton" name="close">
<property name="text">
<string>&amp;Close</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>NPWebView</class>
<extends>QWidget</extends>
<header>calibre/gui2/store/web_control.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>close</sender>
<signal>clicked()</signal>
<receiver>Dialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>917</x>
<y>635</y>
</hint>
<hint type="destinationlabel">
<x>480</x>
<y>327</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -81,6 +81,13 @@ def ebook_viewer(args=sys.argv):
main(args)
def store_dialog(args=sys.argv):
detach_gui()
init_dbus()
from calibre.gui2.store.web_store import main
main(args)
def gui_ebook_edit(path=None, notify=None):
' For launching the editor from inside calibre '
init_dbus()

View File

@ -29,6 +29,9 @@ PARALLEL_FUNCS = {
'ebook-edit' :
('calibre.gui_launch', 'gui_ebook_edit', None),
'store-dialog' :
('calibre.gui_launch', 'store_dialog', None),
'render_pages' :
('calibre.ebooks.comic.input', 'render_pages', 'notification'),