mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Preferences widget for content server
This commit is contained in:
parent
dde4363846
commit
4a78f15205
@ -775,8 +775,17 @@ class Email(PreferencesPlugin):
|
|||||||
name_order = 1
|
name_order = 1
|
||||||
config_widget = 'calibre.gui2.preferences.emailp'
|
config_widget = 'calibre.gui2.preferences.emailp'
|
||||||
|
|
||||||
|
class Server(PreferencesPlugin):
|
||||||
|
name = 'Server'
|
||||||
|
gui_name = _('Sharing over the net')
|
||||||
|
category = 'Sharing'
|
||||||
|
gui_category = _('Sharing')
|
||||||
|
category_order = 4
|
||||||
|
name_order = 2
|
||||||
|
config_widget = 'calibre.gui2.preferences.server'
|
||||||
|
|
||||||
plugins += [LookAndFeel, Behavior, Columns, Toolbar, InputOptions,
|
plugins += [LookAndFeel, Behavior, Columns, Toolbar, InputOptions,
|
||||||
CommonOptions, OutputOptions, Adding, Saving, Sending, Email]
|
CommonOptions, OutputOptions, Adding, Saving, Sending, Email, Server]
|
||||||
|
|
||||||
#}}}
|
#}}}
|
||||||
|
|
||||||
|
@ -175,9 +175,10 @@ class ConfigWidgetBase(QWidget, ConfigWidgetInterface):
|
|||||||
self.settings = {}
|
self.settings = {}
|
||||||
|
|
||||||
def register(self, name, config_obj, gui_name=None, choices=None,
|
def register(self, name, config_obj, gui_name=None, choices=None,
|
||||||
restart_required=False, setting=Setting):
|
restart_required=False, empty_string_is_None=True, setting=Setting):
|
||||||
setting = setting(name, config_obj, self, gui_name=gui_name,
|
setting = setting(name, config_obj, self, gui_name=gui_name,
|
||||||
choices=choices, restart_required=restart_required)
|
choices=choices, restart_required=restart_required,
|
||||||
|
empty_string_is_None=empty_string_is_None)
|
||||||
return self.register_setting(setting)
|
return self.register_setting(setting)
|
||||||
|
|
||||||
def register_setting(self, setting):
|
def register_setting(self, setting):
|
||||||
@ -229,7 +230,7 @@ def test_widget(category, name, gui=None):
|
|||||||
def set_widget(self, w): self.w = w
|
def set_widget(self, w): self.w = w
|
||||||
def accept(self):
|
def accept(self):
|
||||||
try:
|
try:
|
||||||
self.w.commit()
|
self.restart_required = self.w.commit()
|
||||||
except AbortCommit:
|
except AbortCommit:
|
||||||
return
|
return
|
||||||
QDialog.accept(self)
|
QDialog.accept(self)
|
||||||
@ -259,10 +260,8 @@ def test_widget(category, name, gui=None):
|
|||||||
mygui = True
|
mygui = True
|
||||||
w.genesis(gui)
|
w.genesis(gui)
|
||||||
w.initialize()
|
w.initialize()
|
||||||
restart_required = False
|
d.exec_()
|
||||||
if d.exec_() == QDialog.Accepted:
|
if getattr(d, 'restart_required', False):
|
||||||
restart_required = w.commit()
|
|
||||||
if restart_required:
|
|
||||||
from calibre.gui2 import warning_dialog
|
from calibre.gui2 import warning_dialog
|
||||||
warning_dialog(gui, 'Restart required', 'Restart required', show=True)
|
warning_dialog(gui, 'Restart required', 'Restart required', show=True)
|
||||||
if mygui:
|
if mygui:
|
||||||
|
129
src/calibre/gui2/preferences/server.py
Normal file
129
src/calibre/gui2/preferences/server.py
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
from PyQt4.Qt import Qt, QUrl, QDialog, QSize, QVBoxLayout, QLabel, \
|
||||||
|
QPlainTextEdit, QDialogButtonBox
|
||||||
|
|
||||||
|
from calibre.gui2.preferences import ConfigWidgetBase, test_widget
|
||||||
|
from calibre.gui2.preferences.server_ui import Ui_Form
|
||||||
|
from calibre.utils.search_query_parser import saved_searches
|
||||||
|
from calibre.library.server import server_config
|
||||||
|
from calibre.utils.config import ConfigProxy
|
||||||
|
from calibre.gui2 import error_dialog, config, open_url, warning_dialog
|
||||||
|
|
||||||
|
class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
||||||
|
|
||||||
|
def genesis(self, gui):
|
||||||
|
self.gui = gui
|
||||||
|
self.proxy = ConfigProxy(server_config())
|
||||||
|
db = self.db = gui.library_view.model().db
|
||||||
|
self.server = self.gui.content_server
|
||||||
|
|
||||||
|
r = self.register
|
||||||
|
|
||||||
|
r('port', self.proxy)
|
||||||
|
r('username', self.proxy)
|
||||||
|
r('password', self.proxy)
|
||||||
|
r('max_cover', self.proxy)
|
||||||
|
r('max_opds_items', self.proxy)
|
||||||
|
r('max_opds_ungrouped_items', self.proxy)
|
||||||
|
|
||||||
|
self.show_server_password.stateChanged[int].connect(
|
||||||
|
lambda s: self.opt_password.setEchoMode(
|
||||||
|
self.opt_password.Normal if s == Qt.Checked
|
||||||
|
else self.opt_password.Password))
|
||||||
|
self.opt_password.setEchoMode(self.opt_password.Password)
|
||||||
|
|
||||||
|
restrictions = sorted(saved_searches().names(),
|
||||||
|
cmp=lambda x,y: cmp(x.lower(), y.lower()))
|
||||||
|
choices = [('', '')] + [(x, x) for x in restrictions]
|
||||||
|
r('cs_restriction', db.prefs, choices=choices)
|
||||||
|
|
||||||
|
self.start_button.setEnabled(not getattr(self.server, 'is_running', False))
|
||||||
|
self.test_button.setEnabled(not self.start_button.isEnabled())
|
||||||
|
self.stop_button.setDisabled(self.start_button.isEnabled())
|
||||||
|
self.start_button.clicked.connect(self.start_server)
|
||||||
|
self.stop_button.clicked.connect(self.stop_server)
|
||||||
|
self.test_button.clicked.connect(self.test_server)
|
||||||
|
self.view_logs.clicked.connect(self.view_server_logs)
|
||||||
|
|
||||||
|
r('autolaunch_server', config)
|
||||||
|
|
||||||
|
def set_server_options(self):
|
||||||
|
c = self.proxy
|
||||||
|
c.set('port', self.opt_port.value())
|
||||||
|
c.set('username', unicode(self.opt_username.text()).strip())
|
||||||
|
p = unicode(self.opt_password.text()).strip()
|
||||||
|
if not p:
|
||||||
|
p = None
|
||||||
|
c.set('password', p)
|
||||||
|
|
||||||
|
def start_server(self):
|
||||||
|
self.set_server_options()
|
||||||
|
from calibre.library.server.main import start_threaded_server
|
||||||
|
self.server = start_threaded_server(self.db, server_config().parse())
|
||||||
|
while not self.server.is_running and self.server.exception is None:
|
||||||
|
time.sleep(1)
|
||||||
|
if self.server.exception is not None:
|
||||||
|
error_dialog(self, _('Failed to start content server'),
|
||||||
|
unicode(self.server.exception)).exec_()
|
||||||
|
return
|
||||||
|
self.start_button.setEnabled(False)
|
||||||
|
self.test_button.setEnabled(True)
|
||||||
|
self.stop_button.setEnabled(True)
|
||||||
|
|
||||||
|
def stop_server(self):
|
||||||
|
from calibre.library.server.main import stop_threaded_server
|
||||||
|
stop_threaded_server(self.server)
|
||||||
|
self.server = None
|
||||||
|
self.start_button.setEnabled(True)
|
||||||
|
self.test_button.setEnabled(False)
|
||||||
|
self.stop_button.setEnabled(False)
|
||||||
|
|
||||||
|
def test_server(self):
|
||||||
|
open_url(QUrl('http://127.0.0.1:'+str(self.opt_port.value())))
|
||||||
|
|
||||||
|
def view_server_logs(self):
|
||||||
|
from calibre.library.server import log_access_file, log_error_file
|
||||||
|
d = QDialog(self)
|
||||||
|
d.resize(QSize(800, 600))
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
d.setLayout(layout)
|
||||||
|
layout.addWidget(QLabel(_('Error log:')))
|
||||||
|
el = QPlainTextEdit(d)
|
||||||
|
layout.addWidget(el)
|
||||||
|
try:
|
||||||
|
el.setPlainText(open(log_error_file, 'rb').read().decode('utf8', 'replace'))
|
||||||
|
except IOError:
|
||||||
|
el.setPlainText('No error log found')
|
||||||
|
layout.addWidget(QLabel(_('Access log:')))
|
||||||
|
al = QPlainTextEdit(d)
|
||||||
|
layout.addWidget(al)
|
||||||
|
try:
|
||||||
|
al.setPlainText(open(log_access_file, 'rb').read().decode('utf8', 'replace'))
|
||||||
|
except IOError:
|
||||||
|
al.setPlainText('No access log found')
|
||||||
|
bx = QDialogButtonBox(QDialogButtonBox.Ok)
|
||||||
|
layout.addWidget(bx)
|
||||||
|
bx.accepted.connect(d.accept)
|
||||||
|
d.show()
|
||||||
|
|
||||||
|
def commit(self):
|
||||||
|
ConfigWidgetBase.commit(self)
|
||||||
|
warning_dialog(self, _('Restart needed'),
|
||||||
|
_('You need to restart the server for changes to'
|
||||||
|
' take effect'), show=True)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
from PyQt4.Qt import QApplication
|
||||||
|
app = QApplication([])
|
||||||
|
test_widget('Sharing', 'Server')
|
||||||
|
|
261
src/calibre/gui2/preferences/server.ui
Normal file
261
src/calibre/gui2/preferences/server.ui
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Form</class>
|
||||||
|
<widget class="QWidget" name="Form">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>641</width>
|
||||||
|
<height>563</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_5">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_10">
|
||||||
|
<property name="text">
|
||||||
|
<string>Server &port:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_port</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QSpinBox" name="opt_port">
|
||||||
|
<property name="maximum">
|
||||||
|
<number>65535</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>8080</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_11">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Username:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_username</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="opt_username"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_12">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Password:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_password</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLineEdit" name="opt_password">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>If you leave the password blank, anyone will be able to access your book collection using the web interface.</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QLineEdit" name="opt_max_cover">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>The maximum size (widthxheight) for displayed covers. Larger covers are resized. </string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Max. &cover size:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_max_cover</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QCheckBox" name="show_server_password">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Show password</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label_15">
|
||||||
|
<property name="text">
|
||||||
|
<string>Max. &OPDS items per query:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_max_opds_items</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="QSpinBox" name="opt_max_opds_items">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>10</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>10000</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="1">
|
||||||
|
<widget class="QSpinBox" name="opt_max_opds_ungrouped_items">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>25</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>1000000</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QLabel" name="label_16">
|
||||||
|
<property name="text">
|
||||||
|
<string>Max. OPDS &ungrouped items:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>opt_max_opds_ungrouped_items</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="0">
|
||||||
|
<widget class="QLabel" name="label_164">
|
||||||
|
<property name="text">
|
||||||
|
<string>Restriction (saved search) to apply:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="1">
|
||||||
|
<widget class="QComboBox" name="opt_cs_restriction">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>This restriction (based on a saved search) will restrict the books the content server makes available to those matching the search. This setting is per library (i.e. you can have a different restriction per library).</string>
|
||||||
|
</property>
|
||||||
|
<property name="sizeAdjustPolicy">
|
||||||
|
<enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
|
||||||
|
</property>
|
||||||
|
<property name="minimumContentsLength">
|
||||||
|
<number>20</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="start_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Start Server</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="stop_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>St&op Server</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="test_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Test Server</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_9">
|
||||||
|
<property name="text">
|
||||||
|
<string>calibre contains a network server that allows you to access your book collection using a browser from anywhere in the world. Any changes to the settings will only take effect after a server restart.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="opt_autolaunch_server">
|
||||||
|
<property name="text">
|
||||||
|
<string>Run server &automatically on startup</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="view_logs">
|
||||||
|
<property name="text">
|
||||||
|
<string>View &server logs</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>36</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_13">
|
||||||
|
<property name="text">
|
||||||
|
<string><p>Remember to leave calibre running as the server only runs as long as calibre is running.
|
||||||
|
<p>Stanza should see your calibre collection automatically. If not, try adding the URL http://myhostname:8080 as a new catalog in the Stanza reader on your iPhone. Here myhostname should be the fully qualified hostname or the IP address of the computer calibre is running on.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>37</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
Loading…
x
Reference in New Issue
Block a user