mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 10:14:46 -04:00
Add an option for maximum size of covers transmitted via the content server
This commit is contained in:
parent
e76b1ab174
commit
f04b6da557
@ -1,7 +1,7 @@
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
from PyQt4.QtGui import QDialog, QListWidgetItem
|
from PyQt4.Qt import QDialog, QListWidgetItem, SIGNAL
|
||||||
|
|
||||||
from calibre.gui2 import file_icon_provider
|
from calibre.gui2 import file_icon_provider
|
||||||
from calibre.gui2.dialogs.choose_format_ui import Ui_ChooseFormatDialog
|
from calibre.gui2.dialogs.choose_format_ui import Ui_ChooseFormatDialog
|
||||||
@ -12,6 +12,7 @@ class ChooseFormatDialog(QDialog, Ui_ChooseFormatDialog):
|
|||||||
QDialog.__init__(self, window)
|
QDialog.__init__(self, window)
|
||||||
Ui_ChooseFormatDialog.__init__(self)
|
Ui_ChooseFormatDialog.__init__(self)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
|
self.connect(self.formats, SIGNAL('activated(QModelIndex)'), lambda i: self.accept())
|
||||||
|
|
||||||
self.msg.setText(msg)
|
self.msg.setText(msg)
|
||||||
for format in formats:
|
for format in formats:
|
||||||
|
@ -126,6 +126,7 @@ class ConfigDialog(QDialog, Ui_Dialog):
|
|||||||
lambda s: self.password.setEchoMode(self.password.Normal if s == Qt.Checked else self.password.Password))
|
lambda s: self.password.setEchoMode(self.password.Normal if s == Qt.Checked else self.password.Password))
|
||||||
self.password.setEchoMode(self.password.Password)
|
self.password.setEchoMode(self.password.Password)
|
||||||
opts = server_config().parse()
|
opts = server_config().parse()
|
||||||
|
self.max_cover_size.setText(opts.max_cover)
|
||||||
self.port.setValue(opts.port)
|
self.port.setValue(opts.port)
|
||||||
self.username.setText(opts.username)
|
self.username.setText(opts.username)
|
||||||
self.password.setText(opts.password if opts.password else '')
|
self.password.setText(opts.password if opts.password else '')
|
||||||
@ -221,6 +222,10 @@ class ConfigDialog(QDialog, Ui_Dialog):
|
|||||||
self.directory_list.takeItem(idx)
|
self.directory_list.takeItem(idx)
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
|
mcs = unicode(self.max_cover_size.text()).strip()
|
||||||
|
if not re.match(r'\d+x\d+', mcs):
|
||||||
|
error_dialog(self, _('Invalid size'), _('The size %s is invalid. must be of the form widthxheight')%mcs).exec_()
|
||||||
|
return
|
||||||
config['use_roman_numerals_for_series_number'] = bool(self.roman_numerals.isChecked())
|
config['use_roman_numerals_for_series_number'] = bool(self.roman_numerals.isChecked())
|
||||||
config['new_version_notification'] = bool(self.new_version_notification.isChecked())
|
config['new_version_notification'] = bool(self.new_version_notification.isChecked())
|
||||||
prefs['network_timeout'] = int(self.timeout.value())
|
prefs['network_timeout'] = int(self.timeout.value())
|
||||||
@ -246,6 +251,7 @@ class ConfigDialog(QDialog, Ui_Dialog):
|
|||||||
sc.set('username', unicode(self.username.text()).strip())
|
sc.set('username', unicode(self.username.text()).strip())
|
||||||
sc.set('password', unicode(self.password.text()).strip())
|
sc.set('password', unicode(self.password.text()).strip())
|
||||||
sc.set('port', self.port.value())
|
sc.set('port', self.port.value())
|
||||||
|
sc.set('max_cover', mcs)
|
||||||
config['delete_news_from_library_on_upload'] = self.delete_news.isChecked()
|
config['delete_news_from_library_on_upload'] = self.delete_news.isChecked()
|
||||||
config['upload_news_to_device'] = self.sync_news.isChecked()
|
config['upload_news_to_device'] = self.sync_news.isChecked()
|
||||||
of = str(self.output_format.currentText())
|
of = str(self.output_format.currentText())
|
||||||
|
@ -675,13 +675,33 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="1" >
|
<item row="4" column="1" >
|
||||||
<widget class="QCheckBox" name="show_server_password" >
|
<widget class="QCheckBox" name="show_server_password" >
|
||||||
<property name="text" >
|
<property name="text" >
|
||||||
<string>&Show password</string>
|
<string>&Show password</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="3" column="1" >
|
||||||
|
<widget class="QLineEdit" name="max_cover_size" >
|
||||||
|
<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="3" column="0" >
|
||||||
|
<widget class="QLabel" name="label_3" >
|
||||||
|
<property name="text" >
|
||||||
|
<string>Max. &cover size:</string>
|
||||||
|
</property>
|
||||||
|
<property name="buddy" >
|
||||||
|
<cstring>max_cover_size</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -28,4 +28,6 @@ def server_config(defaults=None):
|
|||||||
help=_('Username for access. By default, it is: %default'))
|
help=_('Username for access. By default, it is: %default'))
|
||||||
c.add_opt('develop', ['--develop'], default=False,
|
c.add_opt('develop', ['--develop'], default=False,
|
||||||
help='Development mode. Server automatically restarts on file changes and serves code files (html, css, js) from the file system instead of calibre\'s resource system.')
|
help='Development mode. Server automatically restarts on file changes and serves code files (html, css, js) from the file system instead of calibre\'s resource system.')
|
||||||
|
c.add_opt('max_cover', ['--max-cover'], default='600x800',
|
||||||
|
help=_('The maximum size for displayed covers'))
|
||||||
return c
|
return c
|
||||||
|
@ -14,7 +14,7 @@ from datetime import datetime
|
|||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
import cherrypy
|
import cherrypy
|
||||||
from PIL import Image
|
from PyQt4.Qt import QImage, QApplication, QByteArray, Qt, QBuffer
|
||||||
|
|
||||||
from calibre.constants import __version__, __appname__
|
from calibre.constants import __version__, __appname__
|
||||||
from calibre.utils.genshi.template import MarkupTemplate
|
from calibre.utils.genshi.template import MarkupTemplate
|
||||||
@ -112,6 +112,8 @@ class LibraryServer(object):
|
|||||||
item
|
item
|
||||||
break
|
break
|
||||||
self.opts = opts
|
self.opts = opts
|
||||||
|
self.max_cover_width, self.max_cover_height = \
|
||||||
|
map(int, self.opts.max_cover.split('x'))
|
||||||
|
|
||||||
cherrypy.config.update({
|
cherrypy.config.update({
|
||||||
'log.screen' : opts.develop,
|
'log.screen' : opts.develop,
|
||||||
@ -179,27 +181,37 @@ class LibraryServer(object):
|
|||||||
cherrypy.engine.exit()
|
cherrypy.engine.exit()
|
||||||
|
|
||||||
def get_cover(self, id, thumbnail=False):
|
def get_cover(self, id, thumbnail=False):
|
||||||
cover = self.db.cover(id, index_is_id=True, as_file=True)
|
cover = self.db.cover(id, index_is_id=True, as_file=False)
|
||||||
if cover is None:
|
if cover is None:
|
||||||
cover = cStringIO.StringIO(server_resources['default_cover.jpg'])
|
cover = server_resources['default_cover.jpg']
|
||||||
cherrypy.response.headers['Content-Type'] = 'image/jpeg'
|
cherrypy.response.headers['Content-Type'] = 'image/jpeg'
|
||||||
path = getattr(cover, 'name', False)
|
path = getattr(cover, 'name', False)
|
||||||
updated = datetime.utcfromtimestamp(os.stat(path).st_mtime) if path and os.access(path, os.R_OK) else build_time
|
updated = datetime.utcfromtimestamp(os.stat(path).st_mtime) if path and os.access(path, os.R_OK) else build_time
|
||||||
cherrypy.response.headers['Last-Modified'] = self.last_modified(updated)
|
cherrypy.response.headers['Last-Modified'] = self.last_modified(updated)
|
||||||
if not thumbnail:
|
|
||||||
return cover.read()
|
|
||||||
try:
|
try:
|
||||||
im = Image.open(cover)
|
if QApplication.instance() is None:
|
||||||
width, height = im.size
|
QApplication([])
|
||||||
scaled, width, height = fit_image(width, height, 80, 60)
|
|
||||||
|
im = QImage()
|
||||||
|
im.loadFromData(cover)
|
||||||
|
if im.isNull():
|
||||||
|
raise cherrypy.HTTPError(404, 'No valid cover found')
|
||||||
|
width, height = im.width(), im.height()
|
||||||
|
scaled, width, height = fit_image(width, height,
|
||||||
|
60 if thumbnail else self.max_cover_width,
|
||||||
|
80 if thumbnail else self.max_cover_height)
|
||||||
if not scaled:
|
if not scaled:
|
||||||
return cover.read()
|
return cover
|
||||||
im.thumbnail((width, height))
|
im = im.scaled(width, height, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
||||||
o = cStringIO.StringIO()
|
ba = QByteArray()
|
||||||
im.save(o, 'JPEG')
|
buf = QBuffer(ba)
|
||||||
return o.getvalue()
|
buf.open(QBuffer.WriteOnly)
|
||||||
|
im.save(buf, 'PNG')
|
||||||
|
return str(ba.data())
|
||||||
except Exception, err:
|
except Exception, err:
|
||||||
raise cherrypy.HTTPError(404, 'failed to generate thumbnail: %s'%err)
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
raise cherrypy.HTTPError(404, 'Failed to generate cover: %s'%err)
|
||||||
|
|
||||||
def get_format(self, id, format):
|
def get_format(self, id, format):
|
||||||
format = format.upper()
|
format = format.upper()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user