mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-31 14:33:54 -04:00
KG updates
This commit is contained in:
commit
7d86373781
@ -71,3 +71,5 @@ gui_pubdate_display_format = 'MMM yyyy'
|
|||||||
# order until the title is edited. Double-clicking on a title and hitting return
|
# order until the title is edited. Double-clicking on a title and hitting return
|
||||||
# without changing anything is sufficient to change the sort.
|
# without changing anything is sufficient to change the sort.
|
||||||
title_series_sorting = 'library_order'
|
title_series_sorting = 'library_order'
|
||||||
|
|
||||||
|
|
||||||
|
Binary file not shown.
71
resources/recipes/china_press.recipe
Normal file
71
resources/recipes/china_press.recipe
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class AdvancedUserRecipe1277228948(BasicNewsRecipe):
|
||||||
|
title = u'China Press USA'
|
||||||
|
oldest_article = 7
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
|
||||||
|
__author__ = 'rty'
|
||||||
|
__version__ = '1.0'
|
||||||
|
language = 'zh_CN'
|
||||||
|
pubisher = 'www.chinapressusa.com'
|
||||||
|
description = 'Overseas Chinese Network Newspaper in the USA'
|
||||||
|
category = 'News in Chinese, USA'
|
||||||
|
remove_javascript = True
|
||||||
|
use_embedded_content = False
|
||||||
|
no_stylesheets = True
|
||||||
|
#encoding = 'GB2312'
|
||||||
|
encoding = 'UTF-8'
|
||||||
|
conversion_options = {'linearize_tables':True}
|
||||||
|
masthead_url ='http://www.chinapressusa.com/common/images/logo.gif'
|
||||||
|
extra_css = '''
|
||||||
|
@font-face { font-family: "DroidFont", serif, sans-serif; src: url(res:///system/fonts/DroidSansFallback.ttf); }\n
|
||||||
|
body {
|
||||||
|
margin-right: 8pt;
|
||||||
|
font-family: 'DroidFont', serif;}
|
||||||
|
h1 {font-family: 'DroidFont', serif, sans-serif}
|
||||||
|
.show {font-family: 'DroidFont', serif, sans-serif}
|
||||||
|
'''
|
||||||
|
feeds = [
|
||||||
|
(u'\u65b0\u95fb\u9891\u9053', u'http://news.uschinapress.com/news.xml'),
|
||||||
|
(u'\u534e\u4eba\u9891\u9053', u'http://chinese.uschinapress.com/chinese.xml'),
|
||||||
|
(u'\u8bc4\u8bba\u9891\u9053', u'http://review.uschinapress.com/review.xml'),
|
||||||
|
]
|
||||||
|
keep_only_tags = [
|
||||||
|
dict(name='div', attrs={'class':'show'}),
|
||||||
|
]
|
||||||
|
remove_tags = [
|
||||||
|
# dict(name='table', attrs={'class':'xle'}),
|
||||||
|
dict(name='div', attrs={'class':'time'}),
|
||||||
|
]
|
||||||
|
remove_tags_after = [
|
||||||
|
dict(name='div', attrs={'class':'bank17'}),
|
||||||
|
# dict(name='a', attrs={'class':'ab12'}),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def append_page(self, soup, appendtag, position):
|
||||||
|
pager = soup.find('div',attrs={'id':'displaypagenum'})
|
||||||
|
if pager:
|
||||||
|
nexturl = self.INDEX + pager.a['href']
|
||||||
|
soup2 = self.index_to_soup(nexturl)
|
||||||
|
texttag = soup2.find('div', attrs={'class':'show'})
|
||||||
|
for it in texttag.findAll(style=True):
|
||||||
|
del it['style']
|
||||||
|
newpos = len(texttag.contents)
|
||||||
|
self.append_page(soup2,texttag,newpos)
|
||||||
|
texttag.extract()
|
||||||
|
appendtag.insert(position,texttag)
|
||||||
|
|
||||||
|
|
||||||
|
def preprocess_html(self, soup):
|
||||||
|
mtag = '<meta http-equiv="Content-Language" content="zh-CN"/>\n<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>'
|
||||||
|
soup.head.insert(0,mtag)
|
||||||
|
|
||||||
|
for item in soup.findAll(style=True):
|
||||||
|
del item['style']
|
||||||
|
self.append_page(soup, soup.body, 3)
|
||||||
|
pager = soup.find('div',attrs={'id':'displaypagenum'})
|
||||||
|
if pager:
|
||||||
|
pager.extract()
|
||||||
|
return soup
|
@ -17,7 +17,7 @@ class NYTimes(BasicNewsRecipe):
|
|||||||
title = 'New York Times Top Stories'
|
title = 'New York Times Top Stories'
|
||||||
__author__ = 'GRiker'
|
__author__ = 'GRiker'
|
||||||
language = 'en'
|
language = 'en'
|
||||||
requires_version = (0, 7, 3)
|
requires_version = (0, 7, 5)
|
||||||
description = 'Top Stories from the New York Times'
|
description = 'Top Stories from the New York Times'
|
||||||
|
|
||||||
# List of sections typically included in Top Stories. Use a keyword from the
|
# List of sections typically included in Top Stories. Use a keyword from the
|
||||||
|
@ -13,14 +13,14 @@ Story
|
|||||||
import re, string, time
|
import re, string, time
|
||||||
from calibre import strftime
|
from calibre import strftime
|
||||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup, BeautifulStoneSoup, NavigableString, Tag
|
from calibre.ebooks.BeautifulSoup import BeautifulStoneSoup, NavigableString, Tag
|
||||||
|
|
||||||
class NYTimes(BasicNewsRecipe):
|
class NYTimes(BasicNewsRecipe):
|
||||||
|
|
||||||
title = 'The New York Times'
|
title = 'The New York Times'
|
||||||
__author__ = 'GRiker'
|
__author__ = 'GRiker'
|
||||||
language = 'en'
|
language = 'en'
|
||||||
requires_version = (0, 7, 3)
|
requires_version = (0, 7, 5)
|
||||||
|
|
||||||
description = 'Daily news from the New York Times (subscription version)'
|
description = 'Daily news from the New York Times (subscription version)'
|
||||||
allSectionKeywords = ['The Front Page', 'International','National','Obituaries','Editorials',
|
allSectionKeywords = ['The Front Page', 'International','National','Obituaries','Editorials',
|
||||||
|
@ -36,7 +36,7 @@ class Plugin(_Plugin):
|
|||||||
self.fnames = dict((name, sz) for name, _, sz in self.fsizes if name)
|
self.fnames = dict((name, sz) for name, _, sz in self.fsizes if name)
|
||||||
self.fnums = dict((num, sz) for _, num, sz in self.fsizes if num)
|
self.fnums = dict((num, sz) for _, num, sz in self.fsizes if num)
|
||||||
|
|
||||||
|
# Input profiles {{{
|
||||||
class InputProfile(Plugin):
|
class InputProfile(Plugin):
|
||||||
|
|
||||||
author = 'Kovid Goyal'
|
author = 'Kovid Goyal'
|
||||||
@ -218,6 +218,8 @@ input_profiles = [InputProfile, SonyReaderInput, SonyReader300Input,
|
|||||||
|
|
||||||
input_profiles.sort(cmp=lambda x,y:cmp(x.name.lower(), y.name.lower()))
|
input_profiles.sort(cmp=lambda x,y:cmp(x.name.lower(), y.name.lower()))
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
class OutputProfile(Plugin):
|
class OutputProfile(Plugin):
|
||||||
|
|
||||||
author = 'Kovid Goyal'
|
author = 'Kovid Goyal'
|
||||||
@ -239,6 +241,10 @@ class OutputProfile(Plugin):
|
|||||||
|
|
||||||
# If True output should be optimized for a touchscreen interface
|
# If True output should be optimized for a touchscreen interface
|
||||||
touchscreen = False
|
touchscreen = False
|
||||||
|
touchscreen_news_css = ''
|
||||||
|
# A list of extra (beyond CSS 2.1) modules supported by the device
|
||||||
|
# Format is a cssutils profile dictionary (see iPad for example)
|
||||||
|
extra_css_modules = []
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def tags_to_string(cls, tags):
|
def tags_to_string(cls, tags):
|
||||||
@ -253,18 +259,21 @@ class iPadOutput(OutputProfile):
|
|||||||
screen_size = (768, 1024)
|
screen_size = (768, 1024)
|
||||||
comic_screen_size = (768, 1024)
|
comic_screen_size = (768, 1024)
|
||||||
dpi = 132.0
|
dpi = 132.0
|
||||||
timefmt = '%A, %d %b %Y'
|
extra_css_modules = [
|
||||||
cssutils_addProfile = { 'name':'webkit',
|
{
|
||||||
'props': {
|
'name':'webkit',
|
||||||
'-webkit-border-bottom-left-radius':'{length}',
|
'props': { '-webkit-border-bottom-left-radius':'{length}',
|
||||||
'-webkit-border-bottom-right-radius':'{length}',
|
'-webkit-border-bottom-right-radius':'{length}',
|
||||||
'-webkit-border-top-left-radius':'{length}',
|
'-webkit-border-top-left-radius':'{length}',
|
||||||
'-webkit-border-top-right-radius':'{length}',
|
'-webkit-border-top-right-radius':'{length}',
|
||||||
'-webkit-border-radius': r'{border-width}(\s+{border-width}){0,3}|inherit',
|
'-webkit-border-radius': r'{border-width}(\s+{border-width}){0,3}|inherit',
|
||||||
},
|
},
|
||||||
'macros': {'border-width': '{length}|medium|thick|thin'}}
|
'macros': {'border-width': '{length}|medium|thick|thin'}
|
||||||
|
}
|
||||||
|
]
|
||||||
touchscreen = True
|
touchscreen = True
|
||||||
touchscreen_css = u'''
|
# touchscreen_news_css {{{
|
||||||
|
touchscreen_news_css = u'''
|
||||||
/* hr used in articles */
|
/* hr used in articles */
|
||||||
.caption_divider {
|
.caption_divider {
|
||||||
border:#ccc 1px solid;
|
border:#ccc 1px solid;
|
||||||
@ -328,6 +337,7 @@ class iPadOutput(OutputProfile):
|
|||||||
}
|
}
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
|
||||||
class SonyReaderOutput(OutputProfile):
|
class SonyReaderOutput(OutputProfile):
|
||||||
|
@ -45,8 +45,8 @@ class ANDROID(USBMS):
|
|||||||
'GT-I5700', 'SAMSUNG']
|
'GT-I5700', 'SAMSUNG']
|
||||||
WINDOWS_MAIN_MEM = ['ANDROID_PHONE', 'A855', 'A853', 'INC.NEXUS_ONE',
|
WINDOWS_MAIN_MEM = ['ANDROID_PHONE', 'A855', 'A853', 'INC.NEXUS_ONE',
|
||||||
'__UMS_COMPOSITE', '_MB200', 'MASS_STORAGE', '_-_CARD',
|
'__UMS_COMPOSITE', '_MB200', 'MASS_STORAGE', '_-_CARD',
|
||||||
'PROD_GT-I9000']
|
'PR OD_GT-I9000']
|
||||||
WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'PROD_GT-I9000_CARD']
|
WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'PR OD_GT-I9000_CARD']
|
||||||
|
|
||||||
OSX_MAIN_MEM = 'HTC Android Phone Media'
|
OSX_MAIN_MEM = 'HTC Android Phone Media'
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ from calibre.ebooks.BeautifulSoup import BeautifulSoup
|
|||||||
from calibre.ebooks.metadata import MetaInformation
|
from calibre.ebooks.metadata import MetaInformation
|
||||||
from calibre.ebooks.metadata.epub import set_metadata
|
from calibre.ebooks.metadata.epub import set_metadata
|
||||||
from calibre.library.server.utils import strftime
|
from calibre.library.server.utils import strftime
|
||||||
from calibre.utils.config import Config, ConfigProxy, config_dir
|
from calibre.utils.config import config_dir
|
||||||
from calibre.utils.date import isoformat, now, parse_date
|
from calibre.utils.date import isoformat, now, parse_date
|
||||||
from calibre.utils.logging import Log
|
from calibre.utils.logging import Log
|
||||||
from calibre.utils.zipfile import ZipFile
|
from calibre.utils.zipfile import ZipFile
|
||||||
@ -34,8 +34,15 @@ if isosx:
|
|||||||
if iswindows:
|
if iswindows:
|
||||||
import pythoncom, win32com.client
|
import pythoncom, win32com.client
|
||||||
|
|
||||||
|
class DriverBase(DeviceConfig, DevicePlugin):
|
||||||
|
# Needed for config_widget to work
|
||||||
|
FORMATS = ['epub', 'pdf']
|
||||||
|
|
||||||
class ITUNES(DeviceConfig, DevicePlugin):
|
@classmethod
|
||||||
|
def _config_base_name(cls):
|
||||||
|
return 'iTunes'
|
||||||
|
|
||||||
|
class ITUNES(DriverBase):
|
||||||
'''
|
'''
|
||||||
Calling sequences:
|
Calling sequences:
|
||||||
Initialization:
|
Initialization:
|
||||||
@ -84,16 +91,6 @@ class ITUNES(DeviceConfig, DevicePlugin):
|
|||||||
OPEN_FEEDBACK_MESSAGE = _(
|
OPEN_FEEDBACK_MESSAGE = _(
|
||||||
'Apple device detected, launching iTunes, please wait ...')
|
'Apple device detected, launching iTunes, please wait ...')
|
||||||
|
|
||||||
FORMATS = ['epub','pdf']
|
|
||||||
|
|
||||||
# Configuration
|
|
||||||
HELP_MESSAGE = _('Configure Device')
|
|
||||||
EXTRA_CUSTOMIZATION_MESSAGE = None
|
|
||||||
EXTRA_CUSTOMIZATION_DEFAULT = None
|
|
||||||
MUST_READ_METADATA = False
|
|
||||||
SAVE_TEMPLATE = '{title}'
|
|
||||||
SUPPORTS_SUB_DIRS = False
|
|
||||||
SUPPORTS_USE_AUTHOR_SORT = False
|
|
||||||
|
|
||||||
# Product IDs:
|
# Product IDs:
|
||||||
# 0x1292:iPhone 3G
|
# 0x1292:iPhone 3G
|
||||||
@ -173,7 +170,6 @@ class ITUNES(DeviceConfig, DevicePlugin):
|
|||||||
sources = None
|
sources = None
|
||||||
update_msg = None
|
update_msg = None
|
||||||
update_needed = False
|
update_needed = False
|
||||||
use_series_as_category = False
|
|
||||||
|
|
||||||
# Public methods
|
# Public methods
|
||||||
def add_books_to_metadata(self, locations, metadata, booklists):
|
def add_books_to_metadata(self, locations, metadata, booklists):
|
||||||
@ -522,29 +518,19 @@ class ITUNES(DeviceConfig, DevicePlugin):
|
|||||||
'''
|
'''
|
||||||
return (None,None)
|
return (None,None)
|
||||||
|
|
||||||
def config_widget(self):
|
@classmethod
|
||||||
|
def config_widget(cls):
|
||||||
'''
|
'''
|
||||||
Return a QWidget with settings for the device interface
|
Return a QWidget with settings for the device interface
|
||||||
'''
|
'''
|
||||||
if DEBUG:
|
cw = DriverBase.config_widget()
|
||||||
self.log.info("ITUNES.config_widget()")
|
|
||||||
from calibre.gui2.device_drivers.configwidget import ConfigWidget
|
|
||||||
cw = ConfigWidget(self.settings(), self.FORMATS, self.SUPPORTS_SUB_DIRS,
|
|
||||||
self.MUST_READ_METADATA, self.SUPPORTS_USE_AUTHOR_SORT,
|
|
||||||
self.EXTRA_CUSTOMIZATION_MESSAGE)
|
|
||||||
# Turn off the Save template
|
# Turn off the Save template
|
||||||
cw.opt_save_template.setVisible(False)
|
cw.opt_save_template.setVisible(False)
|
||||||
cw.label.setVisible(False)
|
cw.label.setVisible(False)
|
||||||
|
|
||||||
# Repurpose the checkbox
|
# Repurpose the checkbox
|
||||||
cw.opt_read_metadata.setText("Use Series as Genre in iTunes/iBooks")
|
cw.opt_read_metadata.setText(_("Use Series as Genre in iTunes/iBooks"))
|
||||||
return cw
|
return cw
|
||||||
|
|
||||||
def customization_help(self,gui=False):
|
|
||||||
if DEBUG:
|
|
||||||
self.log.info("ITUNES.customization_help()")
|
|
||||||
return _('Configure Device')
|
|
||||||
|
|
||||||
def delete_books(self, paths, end_session=True):
|
def delete_books(self, paths, end_session=True):
|
||||||
'''
|
'''
|
||||||
Delete books at paths on device.
|
Delete books at paths on device.
|
||||||
@ -774,46 +760,6 @@ class ITUNES(DeviceConfig, DevicePlugin):
|
|||||||
'''
|
'''
|
||||||
self.report_progress = report_progress
|
self.report_progress = report_progress
|
||||||
|
|
||||||
def save_settings(self, settings_widget):
|
|
||||||
'''
|
|
||||||
Should save settings to disk. Takes the widget created in config_widget
|
|
||||||
and saves all settings to disk.
|
|
||||||
'''
|
|
||||||
if DEBUG:
|
|
||||||
self.log.info("ITUNES.save_settings()")
|
|
||||||
proxy = self._configProxy()
|
|
||||||
proxy['format_map'] = settings_widget.format_map()
|
|
||||||
if self.SUPPORTS_SUB_DIRS:
|
|
||||||
proxy['use_subdirs'] = settings_widget.use_subdirs()
|
|
||||||
if not self.MUST_READ_METADATA:
|
|
||||||
proxy['read_metadata'] = settings_widget.read_metadata()
|
|
||||||
if self.SUPPORTS_USE_AUTHOR_SORT:
|
|
||||||
proxy['use_author_sort'] = settings_widget.use_author_sort()
|
|
||||||
if self.EXTRA_CUSTOMIZATION_MESSAGE:
|
|
||||||
ec = unicode(settings_widget.opt_extra_customization.text()).strip()
|
|
||||||
if not ec:
|
|
||||||
ec = None
|
|
||||||
proxy['extra_customization'] = ec
|
|
||||||
st = unicode(settings_widget.opt_save_template.text())
|
|
||||||
proxy['save_template'] = st
|
|
||||||
|
|
||||||
# Snag the read_metadata check box contents on the way by
|
|
||||||
self.use_series_as_category = settings_widget.read_metadata()
|
|
||||||
|
|
||||||
def settings(self):
|
|
||||||
'''
|
|
||||||
Should return an opts object. The opts object should have one attribute
|
|
||||||
`format_map` which is an ordered list of formats for the device.
|
|
||||||
'''
|
|
||||||
if DEBUG:
|
|
||||||
self.log.info("ITUNES.settings()")
|
|
||||||
opts = self._config().parse()
|
|
||||||
|
|
||||||
# Repurpose the read_metadata check box
|
|
||||||
self.use_series_as_category = opts.read_metadata
|
|
||||||
|
|
||||||
return opts
|
|
||||||
|
|
||||||
def sync_booklists(self, booklists, end_session=True):
|
def sync_booklists(self, booklists, end_session=True):
|
||||||
'''
|
'''
|
||||||
Update metadata on device.
|
Update metadata on device.
|
||||||
@ -1129,27 +1075,6 @@ class ITUNES(DeviceConfig, DevicePlugin):
|
|||||||
|
|
||||||
return db_added, lb_added
|
return db_added, lb_added
|
||||||
|
|
||||||
def _config(self):
|
|
||||||
klass = self if isinstance(self, type) else self.__class__
|
|
||||||
c = Config('device_drivers_%s' % klass.__name__, _('settings for device drivers'))
|
|
||||||
c.add_opt('format_map', default=self.FORMATS,
|
|
||||||
help=_('Ordered list of formats the device will accept'))
|
|
||||||
c.add_opt('use_subdirs', default=True,
|
|
||||||
help=_('Place files in sub directories if the device supports them'))
|
|
||||||
c.add_opt('read_metadata', default=True,
|
|
||||||
help=_('Use Series as Genre in iTunes/iBooks'))
|
|
||||||
c.add_opt('use_author_sort', default=False,
|
|
||||||
help=_('Use author sort instead of author'))
|
|
||||||
c.add_opt('save_template', default=self._default_save_template(),
|
|
||||||
help=_('Template to control how books are titled in iTunes/iBooks'))
|
|
||||||
c.add_opt('extra_customization',
|
|
||||||
default=self.EXTRA_CUSTOMIZATION_DEFAULT,
|
|
||||||
help=_('Extra customization'))
|
|
||||||
return c
|
|
||||||
|
|
||||||
def _configProxy(self):
|
|
||||||
return ConfigProxy(self._config())
|
|
||||||
|
|
||||||
def _cover_to_thumb(self, path, metadata, db_added, lb_added, format):
|
def _cover_to_thumb(self, path, metadata, db_added, lb_added, format):
|
||||||
'''
|
'''
|
||||||
assumes pythoncom wrapper for db_added
|
assumes pythoncom wrapper for db_added
|
||||||
@ -1300,11 +1225,6 @@ class ITUNES(DeviceConfig, DevicePlugin):
|
|||||||
|
|
||||||
return this_book
|
return this_book
|
||||||
|
|
||||||
def _default_save_template(self):
|
|
||||||
from calibre.library.save_to_disk import config
|
|
||||||
return self.SAVE_TEMPLATE if self.SAVE_TEMPLATE else \
|
|
||||||
config().parse().send_template
|
|
||||||
|
|
||||||
def _delete_iTunesMetadata_plist(self,fpath):
|
def _delete_iTunesMetadata_plist(self,fpath):
|
||||||
'''
|
'''
|
||||||
Delete the plist file from the file to force recache
|
Delete the plist file from the file to force recache
|
||||||
@ -1776,7 +1696,7 @@ class ITUNES(DeviceConfig, DevicePlugin):
|
|||||||
im = im.resize((int(width),int(height)), PILImage.ANTIALIAS)
|
im = im.resize((int(width),int(height)), PILImage.ANTIALIAS)
|
||||||
thumb = cStringIO.StringIO()
|
thumb = cStringIO.StringIO()
|
||||||
im.convert('RGB').save(thumb,'JPEG')
|
im.convert('RGB').save(thumb,'JPEG')
|
||||||
thumb_data = thmb.getvalue()
|
thumb_data = thumb.getvalue()
|
||||||
os.remove(tmp_thumb)
|
os.remove(tmp_thumb)
|
||||||
thumb.close()
|
thumb.close()
|
||||||
|
|
||||||
@ -2510,7 +2430,7 @@ class ITUNES(DeviceConfig, DevicePlugin):
|
|||||||
|
|
||||||
# Set genre from series if available, else first alpha tag
|
# Set genre from series if available, else first alpha tag
|
||||||
# Otherwise iTunes grabs the first dc:subject from the opf metadata
|
# Otherwise iTunes grabs the first dc:subject from the opf metadata
|
||||||
if self.use_series_as_category and metadata.series:
|
if metadata.series and self.settings().read_metadata:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(" using Series name as Genre")
|
self.log.info(" using Series name as Genre")
|
||||||
if lb_added:
|
if lb_added:
|
||||||
@ -2581,7 +2501,7 @@ class ITUNES(DeviceConfig, DevicePlugin):
|
|||||||
# Otherwise iBooks uses first <dc:subject> from opf
|
# Otherwise iBooks uses first <dc:subject> from opf
|
||||||
# iTunes balks on setting EpisodeNumber, but it sticks (9.1.1.12)
|
# iTunes balks on setting EpisodeNumber, but it sticks (9.1.1.12)
|
||||||
|
|
||||||
if self.use_series_as_category and metadata.series:
|
if metadata.series and self.settings().read_metadata:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(" using Series name as Genre")
|
self.log.info(" using Series name as Genre")
|
||||||
if lb_added:
|
if lb_added:
|
||||||
|
@ -59,7 +59,7 @@ class DevicePlugin(Plugin):
|
|||||||
return cls.__name__
|
return cls.__name__
|
||||||
return cls.name
|
return cls.name
|
||||||
|
|
||||||
|
# Device detection {{{
|
||||||
def test_bcd_windows(self, device_id, bcd):
|
def test_bcd_windows(self, device_id, bcd):
|
||||||
if bcd is None or len(bcd) == 0:
|
if bcd is None or len(bcd) == 0:
|
||||||
return True
|
return True
|
||||||
@ -152,6 +152,7 @@ class DevicePlugin(Plugin):
|
|||||||
return True, dev
|
return True, dev
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
def reset(self, key='-1', log_packets=False, report_progress=None,
|
def reset(self, key='-1', log_packets=False, report_progress=None,
|
||||||
detected_device=None) :
|
detected_device=None) :
|
||||||
@ -372,14 +373,12 @@ class DevicePlugin(Plugin):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def settings(cls):
|
def settings(cls):
|
||||||
'''
|
'''
|
||||||
Should return an opts object. The opts object should have one attribute
|
Should return an opts object. The opts object should have at least one attribute
|
||||||
`format_map` which is an ordered list of formats for the device.
|
`format_map` which is an ordered list of formats for the device.
|
||||||
'''
|
'''
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BookList(list):
|
class BookList(list):
|
||||||
'''
|
'''
|
||||||
A list of books. Each Book object must have the fields:
|
A list of books. Each Book object must have the fields:
|
||||||
|
@ -78,9 +78,6 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
STORAGE_CARD_VOLUME_LABEL = ''
|
STORAGE_CARD_VOLUME_LABEL = ''
|
||||||
STORAGE_CARD2_VOLUME_LABEL = None
|
STORAGE_CARD2_VOLUME_LABEL = None
|
||||||
|
|
||||||
SUPPORTS_SUB_DIRS = False
|
|
||||||
MUST_READ_METADATA = False
|
|
||||||
SUPPORTS_USE_AUTHOR_SORT = False
|
|
||||||
|
|
||||||
EBOOK_DIR_MAIN = ''
|
EBOOK_DIR_MAIN = ''
|
||||||
EBOOK_DIR_CARD_A = ''
|
EBOOK_DIR_CARD_A = ''
|
||||||
|
@ -13,6 +13,10 @@ class DeviceConfig(object):
|
|||||||
EXTRA_CUSTOMIZATION_MESSAGE = None
|
EXTRA_CUSTOMIZATION_MESSAGE = None
|
||||||
EXTRA_CUSTOMIZATION_DEFAULT = None
|
EXTRA_CUSTOMIZATION_DEFAULT = None
|
||||||
|
|
||||||
|
SUPPORTS_SUB_DIRS = False
|
||||||
|
MUST_READ_METADATA = False
|
||||||
|
SUPPORTS_USE_AUTHOR_SORT = False
|
||||||
|
|
||||||
#: If None the default is used
|
#: If None the default is used
|
||||||
SAVE_TEMPLATE = None
|
SAVE_TEMPLATE = None
|
||||||
|
|
||||||
@ -23,9 +27,14 @@ class DeviceConfig(object):
|
|||||||
config().parse().send_template
|
config().parse().send_template
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _config(cls):
|
def _config_base_name(cls):
|
||||||
klass = cls if isinstance(cls, type) else cls.__class__
|
klass = cls if isinstance(cls, type) else cls.__class__
|
||||||
c = Config('device_drivers_%s' % klass.__name__, _('settings for device drivers'))
|
return klass.__name__
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _config(cls):
|
||||||
|
name = cls._config_base_name()
|
||||||
|
c = Config('device_drivers_%s' % name, _('settings for device drivers'))
|
||||||
c.add_opt('format_map', default=cls.FORMATS,
|
c.add_opt('format_map', default=cls.FORMATS,
|
||||||
help=_('Ordered list of formats the device will accept'))
|
help=_('Ordered list of formats the device will accept'))
|
||||||
c.add_opt('use_subdirs', default=True,
|
c.add_opt('use_subdirs', default=True,
|
||||||
|
@ -127,9 +127,8 @@ class Stylizer(object):
|
|||||||
else:
|
else:
|
||||||
head = []
|
head = []
|
||||||
|
|
||||||
# Add optional cssutils parsing profile from output_profile
|
# Add cssutils parsing profiles from output_profile
|
||||||
if hasattr(self.opts.output_profile, 'cssutils_addProfile'):
|
for profile in self.opts.output_profile.extra_css_modules:
|
||||||
profile = self.opts.output_profile.cssutils_addProfile
|
|
||||||
cssutils.profile.addProfile(profile['name'],
|
cssutils.profile.addProfile(profile['name'],
|
||||||
profile['props'],
|
profile['props'],
|
||||||
profile['macros'])
|
profile['macros'])
|
||||||
|
@ -43,6 +43,9 @@
|
|||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item row="4" column="0">
|
||||||
|
@ -10,7 +10,7 @@ from functools import partial
|
|||||||
from binascii import unhexlify
|
from binascii import unhexlify
|
||||||
|
|
||||||
from PyQt4.Qt import QMenu, QAction, QActionGroup, QIcon, SIGNAL, QPixmap, \
|
from PyQt4.Qt import QMenu, QAction, QActionGroup, QIcon, SIGNAL, QPixmap, \
|
||||||
Qt, pyqtSignal, QColor, QPainter
|
Qt, pyqtSignal, QColor, QPainter, QDialog
|
||||||
from PyQt4.QtSvg import QSvgRenderer
|
from PyQt4.QtSvg import QSvgRenderer
|
||||||
|
|
||||||
from calibre.customize.ui import available_input_formats, available_output_formats, \
|
from calibre.customize.ui import available_input_formats, available_output_formats, \
|
||||||
@ -814,7 +814,8 @@ class DeviceMixin(object): # {{{
|
|||||||
if specific:
|
if specific:
|
||||||
d = ChooseFormatDialog(self, _('Choose format to send to device'),
|
d = ChooseFormatDialog(self, _('Choose format to send to device'),
|
||||||
self.device_manager.device.settings().format_map)
|
self.device_manager.device.settings().format_map)
|
||||||
d.exec_()
|
if d.exec_() != QDialog.Accepted:
|
||||||
|
return
|
||||||
if d.format():
|
if d.format():
|
||||||
fmt = d.format().lower()
|
fmt = d.format().lower()
|
||||||
dest, sub_dest = dest.split(':')
|
dest, sub_dest = dest.split(':')
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
<property name="standardButtons" >
|
<property name="standardButtons" >
|
||||||
<set>QDialogButtonBox::Ok</set>
|
<set>QDialogButtonBox::Ok|QDialogButtonBox::Cancel</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -56,7 +56,8 @@ class SearchBox2(QComboBox):
|
|||||||
To use this class:
|
To use this class:
|
||||||
|
|
||||||
* Call initialize()
|
* Call initialize()
|
||||||
* Connect to the search() and cleared() signals from this widget
|
* Connect to the search() and cleared() signals from this widget.
|
||||||
|
* Connect to the cleared() signal to know when the box content changes
|
||||||
* Call search_done() after every search is complete
|
* Call search_done() after every search is complete
|
||||||
* Use clear() to clear back to the help message
|
* Use clear() to clear back to the help message
|
||||||
'''
|
'''
|
||||||
@ -75,6 +76,7 @@ class SearchBox2(QComboBox):
|
|||||||
type=Qt.DirectConnection)
|
type=Qt.DirectConnection)
|
||||||
self.line_edit.mouse_released.connect(self.mouse_released,
|
self.line_edit.mouse_released.connect(self.mouse_released,
|
||||||
type=Qt.DirectConnection)
|
type=Qt.DirectConnection)
|
||||||
|
self.activated.connect(self.history_selected)
|
||||||
self.setEditable(True)
|
self.setEditable(True)
|
||||||
self.help_state = False
|
self.help_state = False
|
||||||
self.as_you_type = True
|
self.as_you_type = True
|
||||||
@ -139,6 +141,9 @@ class SearchBox2(QComboBox):
|
|||||||
|
|
||||||
def key_pressed(self, event):
|
def key_pressed(self, event):
|
||||||
self.normalize_state()
|
self.normalize_state()
|
||||||
|
if self._in_a_search:
|
||||||
|
self.emit(SIGNAL('changed()'))
|
||||||
|
self._in_a_search = False
|
||||||
if event.key() in (Qt.Key_Return, Qt.Key_Enter):
|
if event.key() in (Qt.Key_Return, Qt.Key_Enter):
|
||||||
self.do_search()
|
self.do_search()
|
||||||
self.timer = self.startTimer(self.__class__.INTERVAL)
|
self.timer = self.startTimer(self.__class__.INTERVAL)
|
||||||
@ -154,6 +159,10 @@ class SearchBox2(QComboBox):
|
|||||||
self.timer = None
|
self.timer = None
|
||||||
self.do_search()
|
self.do_search()
|
||||||
|
|
||||||
|
def history_selected(self, text):
|
||||||
|
self.emit(SIGNAL('changed()'))
|
||||||
|
self.do_search()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def smart_text(self):
|
def smart_text(self):
|
||||||
text = unicode(self.currentText()).strip()
|
text = unicode(self.currentText()).strip()
|
||||||
@ -345,6 +354,7 @@ class SearchBoxMixin(object):
|
|||||||
self.search.initialize('main_search_history', colorize=True,
|
self.search.initialize('main_search_history', colorize=True,
|
||||||
help_text=_('Search (For Advanced Search click the button to the left)'))
|
help_text=_('Search (For Advanced Search click the button to the left)'))
|
||||||
self.connect(self.search, SIGNAL('cleared()'), self.search_box_cleared)
|
self.connect(self.search, SIGNAL('cleared()'), self.search_box_cleared)
|
||||||
|
self.connect(self.search, SIGNAL('changed()'), self.search_box_changed)
|
||||||
self.connect(self.clear_button, SIGNAL('clicked()'), self.search.clear)
|
self.connect(self.clear_button, SIGNAL('clicked()'), self.search.clear)
|
||||||
QObject.connect(self.advanced_search_button, SIGNAL('clicked(bool)'),
|
QObject.connect(self.advanced_search_button, SIGNAL('clicked(bool)'),
|
||||||
self.do_advanced_search)
|
self.do_advanced_search)
|
||||||
@ -364,6 +374,9 @@ class SearchBoxMixin(object):
|
|||||||
self.saved_search.clear_to_help()
|
self.saved_search.clear_to_help()
|
||||||
self.set_number_of_books_shown()
|
self.set_number_of_books_shown()
|
||||||
|
|
||||||
|
def search_box_changed(self):
|
||||||
|
self.tags_view.clear()
|
||||||
|
|
||||||
def do_advanced_search(self, *args):
|
def do_advanced_search(self, *args):
|
||||||
d = SearchDialog(self)
|
d = SearchDialog(self)
|
||||||
if d.exec_() == QDialog.Accepted:
|
if d.exec_() == QDialog.Accepted:
|
||||||
|
@ -957,16 +957,19 @@ class LayoutButton(QToolButton):
|
|||||||
|
|
||||||
self.splitter = splitter
|
self.splitter = splitter
|
||||||
splitter.state_changed.connect(self.update_state)
|
splitter.state_changed.connect(self.update_state)
|
||||||
|
self.setCursor(Qt.PointingHandCursor)
|
||||||
|
|
||||||
def set_state_to_show(self, *args):
|
def set_state_to_show(self, *args):
|
||||||
self.setChecked(False)
|
self.setChecked(False)
|
||||||
label =_('Show')
|
label =_('Show')
|
||||||
self.setText(label + ' ' + self.label)
|
self.setText(label + ' ' + self.label)
|
||||||
|
self.setToolTip(self.text())
|
||||||
|
|
||||||
def set_state_to_hide(self, *args):
|
def set_state_to_hide(self, *args):
|
||||||
self.setChecked(True)
|
self.setChecked(True)
|
||||||
label = _('Hide')
|
label = _('Hide')
|
||||||
self.setText(label + ' ' + self.label)
|
self.setText(label + ' ' + self.label)
|
||||||
|
self.setToolTip(self.text())
|
||||||
|
|
||||||
def update_state(self, *args):
|
def update_state(self, *args):
|
||||||
if self.splitter.is_side_index_hidden:
|
if self.splitter.is_side_index_hidden:
|
||||||
|
@ -585,8 +585,8 @@ class BasicNewsRecipe(Recipe):
|
|||||||
self.lrf = options.lrf
|
self.lrf = options.lrf
|
||||||
self.output_profile = options.output_profile
|
self.output_profile = options.output_profile
|
||||||
self.touchscreen = getattr(self.output_profile, 'touchscreen', False)
|
self.touchscreen = getattr(self.output_profile, 'touchscreen', False)
|
||||||
if self.touchscreen and getattr(self.output_profile, 'touchscreen_css',False):
|
if self.touchscreen:
|
||||||
self.extra_css += self.output_profile.touchscreen_css
|
self.template_css += self.output_profile.touchscreen_news_css
|
||||||
|
|
||||||
self.output_dir = os.path.abspath(self.output_dir)
|
self.output_dir = os.path.abspath(self.output_dir)
|
||||||
if options.test:
|
if options.test:
|
||||||
@ -664,7 +664,8 @@ class BasicNewsRecipe(Recipe):
|
|||||||
templ = self.navbar.generate(False, f, a, feed_len,
|
templ = self.navbar.generate(False, f, a, feed_len,
|
||||||
not self.has_single_feed,
|
not self.has_single_feed,
|
||||||
url, __appname__,
|
url, __appname__,
|
||||||
center=self.center_navbar)
|
center=self.center_navbar,
|
||||||
|
extra_css=self.extra_css)
|
||||||
elem = BeautifulSoup(templ.render(doctype='xhtml').decode('utf-8')).find('div')
|
elem = BeautifulSoup(templ.render(doctype='xhtml').decode('utf-8')).find('div')
|
||||||
body.insert(0, elem)
|
body.insert(0, elem)
|
||||||
if self.remove_javascript:
|
if self.remove_javascript:
|
||||||
@ -728,8 +729,6 @@ class BasicNewsRecipe(Recipe):
|
|||||||
timefmt = self.timefmt
|
timefmt = self.timefmt
|
||||||
if self.touchscreen:
|
if self.touchscreen:
|
||||||
templ = templates.TouchscreenIndexTemplate()
|
templ = templates.TouchscreenIndexTemplate()
|
||||||
if getattr(self.output_profile,'timefmt',False):
|
|
||||||
timefmt = self.output_profile.timefmt
|
|
||||||
return templ.generate(self.title, "mastheadImage.jpg", timefmt, feeds,
|
return templ.generate(self.title, "mastheadImage.jpg", timefmt, feeds,
|
||||||
extra_css=css).render(doctype='xhtml')
|
extra_css=css).render(doctype='xhtml')
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user