mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
merge from trunk
This commit is contained in:
commit
5726f6d700
64
resources/recipes/gulfnews.recipe
Normal file
64
resources/recipes/gulfnews.recipe
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2011, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
|
'''
|
||||||
|
gulfnews.com
|
||||||
|
'''
|
||||||
|
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class GulfNews(BasicNewsRecipe):
|
||||||
|
title = 'Gulf News'
|
||||||
|
__author__ = 'Darko Miletic'
|
||||||
|
description = 'News from United Arab Emirrates, persian gulf and rest of the world'
|
||||||
|
publisher = 'Al Nisr Publishing LLC'
|
||||||
|
category = 'news, politics, UAE, world'
|
||||||
|
oldest_article = 2
|
||||||
|
max_articles_per_feed = 200
|
||||||
|
no_stylesheets = True
|
||||||
|
encoding = 'utf8'
|
||||||
|
use_embedded_content = False
|
||||||
|
language = 'en'
|
||||||
|
remove_empty_feeds = True
|
||||||
|
publication_type = 'newsportal'
|
||||||
|
masthead_url = 'http://gulfnews.com/media/img/gulf_news_logo.jpg'
|
||||||
|
extra_css = """
|
||||||
|
body{font-family: Arial,Helvetica,sans-serif }
|
||||||
|
img{margin-bottom: 0.4em; display:block}
|
||||||
|
h1{font-family: Georgia, 'Times New Roman', Times, serif}
|
||||||
|
ol,ul{list-style: none}
|
||||||
|
.synopsis{font-size: small}
|
||||||
|
.details{font-size: x-small}
|
||||||
|
.image{font-size: xx-small}
|
||||||
|
"""
|
||||||
|
|
||||||
|
conversion_options = {
|
||||||
|
'comment' : description
|
||||||
|
, 'tags' : category
|
||||||
|
, 'publisher' : publisher
|
||||||
|
, 'language' : language
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_tags = [
|
||||||
|
dict(name=['meta','link','object','embed'])
|
||||||
|
,dict(attrs={'class':['quickLinks','ratings']})
|
||||||
|
,dict(attrs={'id':'imageSelector'})
|
||||||
|
]
|
||||||
|
remove_attributes=['lang']
|
||||||
|
keep_only_tags=[
|
||||||
|
dict(name='h1')
|
||||||
|
,dict(attrs={'class':['synopsis','details','image','article']})
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
feeds = [
|
||||||
|
(u'UAE News' , u'http://gulfnews.com/cmlink/1.446094')
|
||||||
|
,(u'Business' , u'http://gulfnews.com/cmlink/1.446098')
|
||||||
|
,(u'Entertainment' , u'http://gulfnews.com/cmlink/1.446095')
|
||||||
|
,(u'Sport' , u'http://gulfnews.com/cmlink/1.446096')
|
||||||
|
,(u'Life' , u'http://gulfnews.com/cmlink/1.446097')
|
||||||
|
]
|
||||||
|
|
||||||
|
def preprocess_html(self, soup):
|
||||||
|
for item in soup.findAll(style=True):
|
||||||
|
del item['style']
|
||||||
|
return soup
|
@ -106,7 +106,7 @@ class PDNOVEL(USBMS):
|
|||||||
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = '__UMS_COMPOSITE'
|
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = '__UMS_COMPOSITE'
|
||||||
THUMBNAIL_HEIGHT = 130
|
THUMBNAIL_HEIGHT = 130
|
||||||
|
|
||||||
EBOOK_DIR_MAIN = 'eBooks'
|
EBOOK_DIR_MAIN = EBOOK_DIR_CARD_A = 'eBooks'
|
||||||
SUPPORTS_SUB_DIRS = False
|
SUPPORTS_SUB_DIRS = False
|
||||||
DELETE_EXTS = ['.jpg', '.jpeg', '.png']
|
DELETE_EXTS = ['.jpg', '.jpeg', '.png']
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Sections to include in catalog. All catalogs include 'Books by Author'.</string>
|
<string>Sections to include in catalog.</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Included sections</string>
|
<string>Included sections</string>
|
||||||
@ -79,13 +79,13 @@
|
|||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QCheckBox" name="generate_authors">
|
<widget class="QCheckBox" name="generate_authors">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>false</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Books by Author</string>
|
<string>Books by Author</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="checked">
|
<property name="checked">
|
||||||
<bool>true</bool>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
535
src/calibre/gui2/metadata/single.py
Normal file
535
src/calibre/gui2/metadata/single.py
Normal file
@ -0,0 +1,535 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
import textwrap, re
|
||||||
|
|
||||||
|
from PyQt4.Qt import QDialogButtonBox, Qt, QTabWidget, QScrollArea, \
|
||||||
|
QVBoxLayout, QIcon, QToolButton, QWidget, QLabel, QGridLayout, \
|
||||||
|
QDoubleSpinBox
|
||||||
|
|
||||||
|
from calibre.gui2 import ResizableDialog
|
||||||
|
from calibre.utils.icu import sort_key
|
||||||
|
from calibre.utils.config import tweaks
|
||||||
|
from calibre.gui2.widgets import EnLineEdit, CompleteComboBox, \
|
||||||
|
EnComboBox
|
||||||
|
from calibre.ebooks.metadata import title_sort, authors_to_string, \
|
||||||
|
string_to_authors
|
||||||
|
|
||||||
|
'''
|
||||||
|
The interface common to all widgets used to set basic metadata
|
||||||
|
class BasicMetadataWidget(object):
|
||||||
|
|
||||||
|
LABEL = "label text"
|
||||||
|
|
||||||
|
def initialize(self, db, id_):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def commit(self, db, id_):
|
||||||
|
return True
|
||||||
|
|
||||||
|
@dynamic_property
|
||||||
|
def current_val(self):
|
||||||
|
def fget(self):
|
||||||
|
return None
|
||||||
|
def fset(self, val):
|
||||||
|
pass
|
||||||
|
return property(fget=fget, fset=fset)
|
||||||
|
'''
|
||||||
|
|
||||||
|
# Title {{{
|
||||||
|
class TitleEdit(EnLineEdit):
|
||||||
|
|
||||||
|
TITLE_ATTR = 'title'
|
||||||
|
COMMIT = True
|
||||||
|
TOOLTIP = _('Change the title of this book')
|
||||||
|
LABEL = _('&Title:')
|
||||||
|
|
||||||
|
def __init__(self, parent):
|
||||||
|
self.dialog = parent
|
||||||
|
EnLineEdit.__init__(self, parent)
|
||||||
|
self.setToolTip(self.TOOLTIP)
|
||||||
|
self.setWhatsThis(self.TOOLTIP)
|
||||||
|
|
||||||
|
def get_default(self):
|
||||||
|
return _('Unknown')
|
||||||
|
|
||||||
|
def initialize(self, db, id_):
|
||||||
|
title = getattr(db, self.TITLE_ATTR)(id_, index_is_id=True)
|
||||||
|
self.current_val = title
|
||||||
|
self.original_val = self.current_val
|
||||||
|
|
||||||
|
def commit(self, db, id_):
|
||||||
|
title = self.current_val
|
||||||
|
if self.COMMIT:
|
||||||
|
getattr(db, 'set_', self.TITLE_ATTR)(id_, title, notify=False)
|
||||||
|
else:
|
||||||
|
getattr(db, 'set_', self.TITLE_ATTR)(id_, title, notify=False,
|
||||||
|
commit=False)
|
||||||
|
return True
|
||||||
|
|
||||||
|
@dynamic_property
|
||||||
|
def current_val(self):
|
||||||
|
|
||||||
|
def fget(self):
|
||||||
|
title = unicode(self.text()).strip()
|
||||||
|
if not title:
|
||||||
|
title = self.get_default()
|
||||||
|
return title
|
||||||
|
|
||||||
|
def fset(self, val):
|
||||||
|
if hasattr(val, 'strip'):
|
||||||
|
val = val.strip()
|
||||||
|
if not val:
|
||||||
|
val = self.get_default()
|
||||||
|
self.setText(val)
|
||||||
|
self.setCursorPosition(0)
|
||||||
|
|
||||||
|
return property(fget=fget, fset=fset)
|
||||||
|
|
||||||
|
class TitleSortEdit(TitleEdit):
|
||||||
|
|
||||||
|
TITLE_ATTR = 'title_sort'
|
||||||
|
COMMIT = False
|
||||||
|
TOOLTIP = _('Specify how this book should be sorted when by title.'
|
||||||
|
' For example, The Exorcist might be sorted as Exorcist, The.')
|
||||||
|
LABEL = _('Title &sort:')
|
||||||
|
|
||||||
|
def __init__(self, parent, title_edit, autogen_button):
|
||||||
|
TitleEdit.__init__(self, parent)
|
||||||
|
self.title_edit = title_edit
|
||||||
|
|
||||||
|
base = self.TOOLTIP
|
||||||
|
ok_tooltip = '<p>' + textwrap.fill(base+'<br><br>'+
|
||||||
|
_(' The green color indicates that the current '
|
||||||
|
'title sort matches the current title'))
|
||||||
|
bad_tooltip = '<p>'+textwrap.fill(base + '<br><br>'+
|
||||||
|
_(' The red color warns that the current '
|
||||||
|
'title sort does not match the current title. '
|
||||||
|
'No action is required if this is what you want.'))
|
||||||
|
self.tooltips = (ok_tooltip, bad_tooltip)
|
||||||
|
|
||||||
|
self.title_edit.textChanged.connect(self.update_state)
|
||||||
|
self.textChanged.connect(self.update_state)
|
||||||
|
|
||||||
|
autogen_button.clicked.connect(self.auto_generate)
|
||||||
|
self.update_state()
|
||||||
|
|
||||||
|
def update_state(self, *args):
|
||||||
|
ts = title_sort(self.title_edit.current_val)
|
||||||
|
normal = ts == self.current_val
|
||||||
|
if normal:
|
||||||
|
col = 'rgb(0, 255, 0, 20%)'
|
||||||
|
else:
|
||||||
|
col = 'rgb(255, 0, 0, 20%)'
|
||||||
|
self.setStyleSheet('QLineEdit { color: black; '
|
||||||
|
'background-color: %s; }'%col)
|
||||||
|
tt = self.tooltips[0 if normal else 1]
|
||||||
|
self.setToolTip(tt)
|
||||||
|
self.setWhatsThis(tt)
|
||||||
|
|
||||||
|
def auto_generate(self, *args):
|
||||||
|
self.current_val = title_sort(self.title_edit.current_val)
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
# Authors {{{
|
||||||
|
class AuthorsEdit(CompleteComboBox):
|
||||||
|
|
||||||
|
TOOLTIP = ''
|
||||||
|
LABEL = _('&Author(s):')
|
||||||
|
|
||||||
|
def __init__(self, parent):
|
||||||
|
self.dialog = parent
|
||||||
|
CompleteComboBox.__init__(self, parent)
|
||||||
|
self.setToolTip(self.TOOLTIP)
|
||||||
|
self.setWhatsThis(self.TOOLTIP)
|
||||||
|
self.setEditable(True)
|
||||||
|
self.setSizeAdjustPolicy(self.AdjustToMinimumContentsLengthWithIcon)
|
||||||
|
|
||||||
|
def get_default(self):
|
||||||
|
return _('Unknown')
|
||||||
|
|
||||||
|
def initialize(self, db, id_):
|
||||||
|
all_authors = db.all_authors()
|
||||||
|
all_authors.sort(key=lambda x : sort_key(x[1]))
|
||||||
|
for i in all_authors:
|
||||||
|
id, name = i
|
||||||
|
name = [name.strip().replace('|', ',') for n in name.split(',')]
|
||||||
|
self.addItem(authors_to_string(name))
|
||||||
|
|
||||||
|
self.set_separator('&')
|
||||||
|
self.set_space_before_sep(True)
|
||||||
|
self.update_items_cache(db.all_author_names())
|
||||||
|
|
||||||
|
au = db.authors(id_, index_is_id=True)
|
||||||
|
if not au:
|
||||||
|
au = _('Unknown')
|
||||||
|
self.current_val = [a.strip().replace('|', ',') for a in au.split(',')]
|
||||||
|
self.original_val = self.current_val
|
||||||
|
|
||||||
|
def commit(self, db, id_):
|
||||||
|
authors = self.current_val
|
||||||
|
db.set_authors(id_, authors, notify=False)
|
||||||
|
return True
|
||||||
|
|
||||||
|
@dynamic_property
|
||||||
|
def current_val(self):
|
||||||
|
|
||||||
|
def fget(self):
|
||||||
|
au = unicode(self.text()).strip()
|
||||||
|
if not au:
|
||||||
|
au = self.get_default()
|
||||||
|
return string_to_authors(au)
|
||||||
|
|
||||||
|
def fset(self, val):
|
||||||
|
if not val:
|
||||||
|
val = [self.get_default()]
|
||||||
|
self.setEditText(' & '.join([x.strip() for x in val]))
|
||||||
|
self.lineEdit().setCursorPosition(0)
|
||||||
|
|
||||||
|
|
||||||
|
return property(fget=fget, fset=fset)
|
||||||
|
|
||||||
|
class AuthorSortEdit(EnLineEdit):
|
||||||
|
|
||||||
|
TOOLTIP = _('Specify how the author(s) of this book should be sorted. '
|
||||||
|
'For example Charles Dickens should be sorted as Dickens, '
|
||||||
|
'Charles.\nIf the box is colored green, then text matches '
|
||||||
|
'the individual author\'s sort strings. If it is colored '
|
||||||
|
'red, then the authors and this text do not match.')
|
||||||
|
LABEL = _('Author s&ort:')
|
||||||
|
|
||||||
|
def __init__(self, parent, authors_edit, autogen_button, db):
|
||||||
|
EnLineEdit.__init__(self, parent)
|
||||||
|
self.authors_edit = authors_edit
|
||||||
|
self.db = db
|
||||||
|
|
||||||
|
base = self.TOOLTIP
|
||||||
|
ok_tooltip = '<p>' + textwrap.fill(base+'<br><br>'+
|
||||||
|
_(' The green color indicates that the current '
|
||||||
|
'author sort matches the current author'))
|
||||||
|
bad_tooltip = '<p>'+textwrap.fill(base + '<br><br>'+
|
||||||
|
_(' The red color indicates that the current '
|
||||||
|
'author sort does not match the current author. '
|
||||||
|
'No action is required if this is what you want.'))
|
||||||
|
self.tooltips = (ok_tooltip, bad_tooltip)
|
||||||
|
|
||||||
|
self.authors_edit.editTextChanged.connect(self.update_state)
|
||||||
|
self.textChanged.connect(self.update_state)
|
||||||
|
|
||||||
|
autogen_button.clicked.connect(self.auto_generate)
|
||||||
|
self.update_state()
|
||||||
|
|
||||||
|
@dynamic_property
|
||||||
|
def current_val(self):
|
||||||
|
|
||||||
|
def fget(self):
|
||||||
|
return unicode(self.text()).strip()
|
||||||
|
|
||||||
|
def fset(self, val):
|
||||||
|
if not val:
|
||||||
|
val = ''
|
||||||
|
self.setText(val.strip())
|
||||||
|
self.setCursorPosition(0)
|
||||||
|
|
||||||
|
return property(fget=fget, fset=fset)
|
||||||
|
|
||||||
|
def update_state(self, *args):
|
||||||
|
au = unicode(self.authors_edit.text())
|
||||||
|
au = re.sub(r'\s+et al\.$', '', au)
|
||||||
|
au = self.db.author_sort_from_authors(string_to_authors(au))
|
||||||
|
|
||||||
|
normal = au == self.current_val
|
||||||
|
if normal:
|
||||||
|
col = 'rgb(0, 255, 0, 20%)'
|
||||||
|
else:
|
||||||
|
col = 'rgb(255, 0, 0, 20%)'
|
||||||
|
self.setStyleSheet('QLineEdit { color: black; '
|
||||||
|
'background-color: %s; }'%col)
|
||||||
|
tt = self.tooltips[0 if normal else 1]
|
||||||
|
self.setToolTip(tt)
|
||||||
|
self.setWhatsThis(tt)
|
||||||
|
|
||||||
|
def auto_generate(self, *args):
|
||||||
|
au = unicode(self.authors_edit.text())
|
||||||
|
au = re.sub(r'\s+et al\.$', '', au)
|
||||||
|
authors = string_to_authors(au)
|
||||||
|
self.current_val = self.db.author_sort_from_authors(authors)
|
||||||
|
|
||||||
|
def initialize(self, db, id_):
|
||||||
|
self.current_val = db.author_sort(id_, index_is_id=True)
|
||||||
|
|
||||||
|
def commit(self, db, id_):
|
||||||
|
aus = self.current_val
|
||||||
|
db.set_author_sort(id_, aus, notify=False, commit=False)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
# Series {{{
|
||||||
|
class SeriesEdit(EnComboBox):
|
||||||
|
|
||||||
|
TOOLTIP = _('List of known series. You can add new series.')
|
||||||
|
LABEL = _('&Series:')
|
||||||
|
|
||||||
|
def __init__(self, parent):
|
||||||
|
EnComboBox.__init__(self, parent)
|
||||||
|
self.dialog = parent
|
||||||
|
self.setSizeAdjustPolicy(
|
||||||
|
self.AdjustToMinimumContentsLengthWithIcon)
|
||||||
|
self.setToolTip(self.TOOLTIP)
|
||||||
|
self.setWhatsThis(self.TOOLTIP)
|
||||||
|
self.setEditable(True)
|
||||||
|
|
||||||
|
@dynamic_property
|
||||||
|
def current_val(self):
|
||||||
|
|
||||||
|
def fget(self):
|
||||||
|
return unicode(self.currentText()).strip()
|
||||||
|
|
||||||
|
def fset(self, val):
|
||||||
|
if not val:
|
||||||
|
val = ''
|
||||||
|
self.setEditText(val.strip())
|
||||||
|
self.setCursorPosition(0)
|
||||||
|
|
||||||
|
return property(fget=fget, fset=fset)
|
||||||
|
|
||||||
|
def initialize(self, db, id_):
|
||||||
|
all_series = db.all_series()
|
||||||
|
all_series.sort(key=lambda x : sort_key(x[1]))
|
||||||
|
series_id = db.series_id(id_, index_is_id=True)
|
||||||
|
idx, c = None, 0
|
||||||
|
for i in all_series:
|
||||||
|
id, name = i
|
||||||
|
if id == series_id:
|
||||||
|
idx = c
|
||||||
|
self.addItem(name)
|
||||||
|
c += 1
|
||||||
|
|
||||||
|
self.lineEdit().setText('')
|
||||||
|
if idx is not None:
|
||||||
|
self.setCurrentIndex(idx)
|
||||||
|
self.original_val = self.current_val
|
||||||
|
|
||||||
|
def commit(self, db, id_):
|
||||||
|
series = self.current_val
|
||||||
|
db.set_series(id_, series, notify=False, commit=True)
|
||||||
|
return True
|
||||||
|
|
||||||
|
class SeriesIndexEdit(QDoubleSpinBox):
|
||||||
|
|
||||||
|
TOOLTIP = ''
|
||||||
|
LABEL = _('&Number:')
|
||||||
|
|
||||||
|
def __init__(self, parent, series_edit):
|
||||||
|
QDoubleSpinBox.__init__(self, parent)
|
||||||
|
self.dialog = parent
|
||||||
|
self.db = self.original_series_name = None
|
||||||
|
self.setMaximum(1000000)
|
||||||
|
self.series_edit = series_edit
|
||||||
|
series_edit.currentIndexChanged.connect(self.enable)
|
||||||
|
series_edit.editTextChanged.connect(self.enable)
|
||||||
|
series_edit.lineEdit().editingFinished.connect(self.increment)
|
||||||
|
self.enable()
|
||||||
|
|
||||||
|
def enable(self, *args):
|
||||||
|
self.setEnabled(bool(self.series_edit.current_val))
|
||||||
|
|
||||||
|
@dynamic_property
|
||||||
|
def current_val(self):
|
||||||
|
|
||||||
|
def fget(self):
|
||||||
|
return self.value()
|
||||||
|
|
||||||
|
def fset(self, val):
|
||||||
|
if val is None:
|
||||||
|
val = 1.0
|
||||||
|
val = float(val)
|
||||||
|
self.setValue(val)
|
||||||
|
|
||||||
|
return property(fget=fget, fset=fset)
|
||||||
|
|
||||||
|
def initialize(self, db, id_):
|
||||||
|
self.db = db
|
||||||
|
if self.series_edit.current_val:
|
||||||
|
val = db.series_index(id_, index_is_id=True)
|
||||||
|
else:
|
||||||
|
val = 1.0
|
||||||
|
self.current_val = val
|
||||||
|
self.original_val = self.current_val
|
||||||
|
self.original_series_name = self.series_edit.original_val
|
||||||
|
|
||||||
|
def commit(self, db, id_):
|
||||||
|
db.set_series_index(id_, self.current_val, notify=False, commit=False)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def increment(self):
|
||||||
|
if self.db is not None:
|
||||||
|
try:
|
||||||
|
series = self.series_edit.current_val
|
||||||
|
if series and series != self.original_series_name:
|
||||||
|
ns = 1.0
|
||||||
|
if tweaks['series_index_auto_increment'] != 'const':
|
||||||
|
ns = self.db.get_next_series_num_for(series)
|
||||||
|
self.current_val = ns
|
||||||
|
self.original_series_name = series
|
||||||
|
except:
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
class BuddyLabel(QLabel):
|
||||||
|
|
||||||
|
def __init__(self, buddy):
|
||||||
|
QLabel.__init__(self, buddy.LABEL)
|
||||||
|
self.setBuddy(buddy)
|
||||||
|
self.setAlignment(Qt.AlignRight|Qt.AlignVCenter)
|
||||||
|
|
||||||
|
class MetadataSingleDialog(ResizableDialog):
|
||||||
|
|
||||||
|
def __init__(self, db, parent=None):
|
||||||
|
self.db = db
|
||||||
|
ResizableDialog.__init__(self, parent)
|
||||||
|
|
||||||
|
def setupUi(self, *args): # {{{
|
||||||
|
self.resize(990, 650)
|
||||||
|
|
||||||
|
self.button_box = QDialogButtonBox(
|
||||||
|
QDialogButtonBox.Ok|QDialogButtonBox.Cancel, Qt.Horizontal,
|
||||||
|
self)
|
||||||
|
self.button_box.accepted.connect(self.accept)
|
||||||
|
self.button_box.rejected.connect(self.reject)
|
||||||
|
|
||||||
|
self.scroll_area = QScrollArea(self)
|
||||||
|
self.scroll_area.setFrameShape(QScrollArea.NoFrame)
|
||||||
|
self.scroll_area.setWidgetResizable(True)
|
||||||
|
self.central_widget = QTabWidget(self)
|
||||||
|
self.scroll_area.setWidget(self.central_widget)
|
||||||
|
|
||||||
|
self.l = QVBoxLayout(self)
|
||||||
|
self.setLayout(self.l)
|
||||||
|
self.l.setMargin(0)
|
||||||
|
self.l.addWidget(self.scroll_area)
|
||||||
|
self.l.addWidget(self.button_box)
|
||||||
|
|
||||||
|
self.setWindowIcon(QIcon(I('edit_input.png')))
|
||||||
|
self.setWindowTitle(_('Edit Meta Information'))
|
||||||
|
|
||||||
|
self.create_basic_metadata_widgets()
|
||||||
|
|
||||||
|
self.do_layout()
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
def create_basic_metadata_widgets(self):
|
||||||
|
self.basic_metadata_widgets = []
|
||||||
|
# Title
|
||||||
|
self.title = TitleEdit(self)
|
||||||
|
self.deduce_title_sort_button = QToolButton(self)
|
||||||
|
self.deduce_title_sort_button.setToolTip(
|
||||||
|
_('Automatically create the title sort entry based on the current '
|
||||||
|
'title entry.\nUsing this button to create title sort will '
|
||||||
|
'change title sort from red to green.'))
|
||||||
|
self.deduce_title_sort_button.setWhatsThis(
|
||||||
|
self.deduce_title_sort_button.toolTip())
|
||||||
|
self.title_sort = TitleSortEdit(self, self.title,
|
||||||
|
self.deduce_title_sort_button)
|
||||||
|
self.basic_metadata_widgets.extend([self.title, self.title_sort])
|
||||||
|
|
||||||
|
# Authors
|
||||||
|
self.authors = AuthorsEdit(self)
|
||||||
|
self.deduce_author_sort_button = QToolButton(self)
|
||||||
|
self.deduce_author_sort_button.setToolTip(_(
|
||||||
|
'Automatically create the author sort entry based on the current'
|
||||||
|
' author entry.\n'
|
||||||
|
'Using this button to create author sort will change author sort from'
|
||||||
|
' red to green.'))
|
||||||
|
self.author_sort = AuthorSortEdit(self, self.authors,
|
||||||
|
self.deduce_author_sort_button, db)
|
||||||
|
self.basic_metadata_widgets.extend([self.authors, self.author_sort])
|
||||||
|
|
||||||
|
self.swap_title_author_button = QToolButton(self)
|
||||||
|
self.swap_title_author_button.setIcon(QIcon(I('swap.png')))
|
||||||
|
self.swap_title_author_button.setToolTip(_(
|
||||||
|
'Swap the author and title'))
|
||||||
|
self.swap_title_author_button.clicked.connect(self.swap_title_author)
|
||||||
|
|
||||||
|
self.series = SeriesEdit(self)
|
||||||
|
self.remove_unused_series_button = QToolButton(self)
|
||||||
|
self.remove_unused_series_button.setToolTip(
|
||||||
|
_('Remove unused series (Series that have no books)') )
|
||||||
|
self.remove_unused_series_button.clicked.connect(self.remove_unused_series)
|
||||||
|
self.series_index = SeriesIndexEdit(self, self.series)
|
||||||
|
self.basic_metadata_widgets.extend([self.series, self.series_index])
|
||||||
|
|
||||||
|
def do_layout(self):
|
||||||
|
self.central_widget.clear()
|
||||||
|
self.tabs = []
|
||||||
|
self.labels = []
|
||||||
|
self.tabs.append(QWidget(self))
|
||||||
|
self.central_widget.addTab(self.tabs[0], _("&Basic metadata"))
|
||||||
|
self.tabs[0].l = l = QVBoxLayout()
|
||||||
|
self.tabs[0].tl = tl = QGridLayout()
|
||||||
|
self.tabs[0].setLayout(l)
|
||||||
|
l.addLayout(tl)
|
||||||
|
|
||||||
|
def create_row(row, one, two, three, col=1, icon='forward.png'):
|
||||||
|
ql = BuddyLabel(one)
|
||||||
|
tl.addWidget(ql, row, col+0, 1, 1)
|
||||||
|
self.labels.append(ql)
|
||||||
|
tl.addWidget(one, row, col+1, 1, 1)
|
||||||
|
if two is not None:
|
||||||
|
tl.addWidget(two, row, col+2, 1, 1)
|
||||||
|
two.setIcon(QIcon(I(icon)))
|
||||||
|
ql = BuddyLabel(three)
|
||||||
|
tl.addWidget(ql, row, col+3, 1, 1)
|
||||||
|
self.labels.append(ql)
|
||||||
|
tl.addWidget(three, row, col+4, 1, 1)
|
||||||
|
|
||||||
|
tl.addWidget(self.swap_title_author_button, 0, 0, 2, 1)
|
||||||
|
|
||||||
|
create_row(0, self.title, self.deduce_title_sort_button, self.title_sort)
|
||||||
|
create_row(1, self.authors, self.deduce_author_sort_button, self.author_sort)
|
||||||
|
create_row(2, self.series, self.remove_unused_series_button,
|
||||||
|
self.series_index, icon='trash.png')
|
||||||
|
|
||||||
|
|
||||||
|
def __call__(self, id_, has_next=False, has_previous=False):
|
||||||
|
self.book_id = id_
|
||||||
|
for widget in self.basic_metadata_widgets:
|
||||||
|
widget.initialize(self.db, id_)
|
||||||
|
|
||||||
|
def swap_title_author(self, *args):
|
||||||
|
title = self.title.current_val
|
||||||
|
self.title.current_val = authors_to_string(self.authors.current_val)
|
||||||
|
self.authors.current_val = string_to_authors(title)
|
||||||
|
self.title_sort.auto_generate()
|
||||||
|
self.author_sort.auto_generate()
|
||||||
|
|
||||||
|
def remove_unused_series(self, *args):
|
||||||
|
self.db.remove_unused_series()
|
||||||
|
idx = self.series.current_val
|
||||||
|
self.series.clear()
|
||||||
|
self.series.initialize(self.db, self.book_id)
|
||||||
|
if idx:
|
||||||
|
for i in range(self.series.count()):
|
||||||
|
if unicode(self.series.itemText(i)) == idx:
|
||||||
|
self.series.setCurrentIndex(i)
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
from PyQt4.Qt import QApplication
|
||||||
|
app = QApplication([])
|
||||||
|
from calibre.library import db
|
||||||
|
db = db()
|
||||||
|
d = MetadataSingleDialog(db)
|
||||||
|
d(db.data[0][0])
|
||||||
|
d.exec_()
|
||||||
|
|
@ -123,6 +123,8 @@ IMAGE_EXTENSIONS = ['jpg', 'jpeg', 'gif', 'png', 'bmp']
|
|||||||
|
|
||||||
class FormatList(QListWidget):
|
class FormatList(QListWidget):
|
||||||
DROPABBLE_EXTENSIONS = BOOK_EXTENSIONS
|
DROPABBLE_EXTENSIONS = BOOK_EXTENSIONS
|
||||||
|
formats_dropped = pyqtSignal(object, object)
|
||||||
|
delete_format = pyqtSignal()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def paths_from_event(cls, event):
|
def paths_from_event(cls, event):
|
||||||
@ -146,15 +148,14 @@ class FormatList(QListWidget):
|
|||||||
def dropEvent(self, event):
|
def dropEvent(self, event):
|
||||||
paths = self.paths_from_event(event)
|
paths = self.paths_from_event(event)
|
||||||
event.setDropAction(Qt.CopyAction)
|
event.setDropAction(Qt.CopyAction)
|
||||||
self.emit(SIGNAL('formats_dropped(PyQt_PyObject,PyQt_PyObject)'),
|
self.formats_dropped.emit(event, paths)
|
||||||
event, paths)
|
|
||||||
|
|
||||||
def dragMoveEvent(self, event):
|
def dragMoveEvent(self, event):
|
||||||
event.acceptProposedAction()
|
event.acceptProposedAction()
|
||||||
|
|
||||||
def keyPressEvent(self, event):
|
def keyPressEvent(self, event):
|
||||||
if event.key() == Qt.Key_Delete:
|
if event.key() == Qt.Key_Delete:
|
||||||
self.emit(SIGNAL('delete_format()'))
|
self.delete_format.emit()
|
||||||
else:
|
else:
|
||||||
return QListWidget.keyPressEvent(self, event)
|
return QListWidget.keyPressEvent(self, event)
|
||||||
|
|
||||||
|
@ -29,7 +29,6 @@ FIELDS = ['all', 'author_sort', 'authors', 'comments',
|
|||||||
'series_index', 'series', 'size', 'tags', 'timestamp', 'title',
|
'series_index', 'series', 'size', 'tags', 'timestamp', 'title',
|
||||||
'uuid']
|
'uuid']
|
||||||
|
|
||||||
|
|
||||||
#Allowed fields for template
|
#Allowed fields for template
|
||||||
TEMPLATE_ALLOWED_FIELDS = [ 'author_sort', 'authors', 'id', 'isbn', 'pubdate',
|
TEMPLATE_ALLOWED_FIELDS = [ 'author_sort', 'authors', 'id', 'isbn', 'pubdate',
|
||||||
'publisher', 'series_index', 'series', 'tags', 'timestamp', 'title', 'uuid' ]
|
'publisher', 'series_index', 'series', 'tags', 'timestamp', 'title', 'uuid' ]
|
||||||
@ -605,43 +604,42 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: ePub, MOBI output formats")),
|
"Applies to: ePub, MOBI output formats")),
|
||||||
Option('--generate-authors',
|
Option('--generate-authors',
|
||||||
default=True,
|
default=False,
|
||||||
dest='generate_authors',
|
dest='generate_authors',
|
||||||
action = 'store_true',
|
action = 'store_true',
|
||||||
help=_("Include 'Authors' section in catalog."
|
help=_("Include 'Authors' section in catalog.\n"
|
||||||
"This switch is ignored - Books By Author section is always generated."
|
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: ePub, MOBI output formats")),
|
"Applies to: ePub, MOBI output formats")),
|
||||||
Option('--generate-descriptions',
|
Option('--generate-descriptions',
|
||||||
default=True,
|
default=False,
|
||||||
dest='generate_descriptions',
|
dest='generate_descriptions',
|
||||||
action = 'store_true',
|
action = 'store_true',
|
||||||
help=_("Include book descriptions in catalog.\n"
|
help=_("Include 'Descriptions' section in catalog.\n"
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: ePub, MOBI output formats")),
|
"Applies to: ePub, MOBI output formats")),
|
||||||
Option('--generate-genres',
|
Option('--generate-genres',
|
||||||
default=True,
|
default=False,
|
||||||
dest='generate_genres',
|
dest='generate_genres',
|
||||||
action = 'store_true',
|
action = 'store_true',
|
||||||
help=_("Include 'Genres' section in catalog.\n"
|
help=_("Include 'Genres' section in catalog.\n"
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: ePub, MOBI output formats")),
|
"Applies to: ePub, MOBI output formats")),
|
||||||
Option('--generate-titles',
|
Option('--generate-titles',
|
||||||
default=True,
|
default=False,
|
||||||
dest='generate_titles',
|
dest='generate_titles',
|
||||||
action = 'store_true',
|
action = 'store_true',
|
||||||
help=_("Include 'Titles' section in catalog.\n"
|
help=_("Include 'Titles' section in catalog.\n"
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: ePub, MOBI output formats")),
|
"Applies to: ePub, MOBI output formats")),
|
||||||
Option('--generate-series',
|
Option('--generate-series',
|
||||||
default=True,
|
default=False,
|
||||||
dest='generate_series',
|
dest='generate_series',
|
||||||
action = 'store_true',
|
action = 'store_true',
|
||||||
help=_("Include 'Series' section in catalog.\n"
|
help=_("Include 'Series' section in catalog.\n"
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: ePub, MOBI output formats")),
|
"Applies to: ePub, MOBI output formats")),
|
||||||
Option('--generate-recently-added',
|
Option('--generate-recently-added',
|
||||||
default=True,
|
default=False,
|
||||||
dest='generate_recently_added',
|
dest='generate_recently_added',
|
||||||
action = 'store_true',
|
action = 'store_true',
|
||||||
help=_("Include 'Recently Added' section in catalog.\n"
|
help=_("Include 'Recently Added' section in catalog.\n"
|
||||||
@ -976,7 +974,7 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
self.__thumbWidth = 0
|
self.__thumbWidth = 0
|
||||||
self.__thumbHeight = 0
|
self.__thumbHeight = 0
|
||||||
self.__title = opts.catalog_title
|
self.__title = opts.catalog_title
|
||||||
self.__totalSteps = 8.0
|
self.__totalSteps = 6.0
|
||||||
self.__useSeriesPrefixInTitlesSection = False
|
self.__useSeriesPrefixInTitlesSection = False
|
||||||
self.__verbose = opts.verbose
|
self.__verbose = opts.verbose
|
||||||
|
|
||||||
@ -1014,17 +1012,21 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
(self.__archive_path, float(cached_thumb_width)))
|
(self.__archive_path, float(cached_thumb_width)))
|
||||||
|
|
||||||
# Tweak build steps based on optional sections: 1 call for HTML, 1 for NCX
|
# Tweak build steps based on optional sections: 1 call for HTML, 1 for NCX
|
||||||
|
incremental_jobs = 0
|
||||||
|
if self.opts.generate_authors:
|
||||||
|
incremental_jobs += 2
|
||||||
if self.opts.generate_titles:
|
if self.opts.generate_titles:
|
||||||
self.__totalSteps += 2
|
incremental_jobs += 2
|
||||||
if self.opts.generate_recently_added:
|
if self.opts.generate_recently_added:
|
||||||
self.__totalSteps += 2
|
incremental_jobs += 2
|
||||||
if self.generateRecentlyRead:
|
if self.generateRecentlyRead:
|
||||||
self.__totalSteps += 2
|
incremental_jobs += 2
|
||||||
if self.opts.generate_series:
|
if self.opts.generate_series:
|
||||||
self.__totalSteps += 2
|
incremental_jobs += 2
|
||||||
if self.opts.generate_descriptions:
|
if self.opts.generate_descriptions:
|
||||||
# +1 thumbs
|
# +1 thumbs
|
||||||
self.__totalSteps += 3
|
incremental_jobs += 3
|
||||||
|
self.__totalSteps += incremental_jobs
|
||||||
|
|
||||||
# Load section list templates
|
# Load section list templates
|
||||||
templates = []
|
templates = []
|
||||||
@ -1358,6 +1360,7 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
if self.opts.generate_descriptions:
|
if self.opts.generate_descriptions:
|
||||||
self.generateThumbnails()
|
self.generateThumbnails()
|
||||||
self.generateHTMLDescriptions()
|
self.generateHTMLDescriptions()
|
||||||
|
if self.opts.generate_authors:
|
||||||
self.generateHTMLByAuthor()
|
self.generateHTMLByAuthor()
|
||||||
if self.opts.generate_titles:
|
if self.opts.generate_titles:
|
||||||
self.generateHTMLByTitle()
|
self.generateHTMLByTitle()
|
||||||
@ -1365,6 +1368,13 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
self.generateHTMLBySeries()
|
self.generateHTMLBySeries()
|
||||||
if self.opts.generate_genres:
|
if self.opts.generate_genres:
|
||||||
self.generateHTMLByTags()
|
self.generateHTMLByTags()
|
||||||
|
# If this is the only Section, and there are no genres, bail
|
||||||
|
if self.opts.section_list == ['Genres'] and not self.genres:
|
||||||
|
error_msg = _("No Genres found to catalog.\nCheck 'Excluded genres'\nin E-book options.\n")
|
||||||
|
self.opts.log.error(error_msg)
|
||||||
|
self.error.append(_('No books available to catalog'))
|
||||||
|
self.error.append(error_msg)
|
||||||
|
return False
|
||||||
if self.opts.generate_recently_added:
|
if self.opts.generate_recently_added:
|
||||||
self.generateHTMLByDateAdded()
|
self.generateHTMLByDateAdded()
|
||||||
if self.generateRecentlyRead:
|
if self.generateRecentlyRead:
|
||||||
@ -1372,6 +1382,7 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
|
|
||||||
self.generateOPF()
|
self.generateOPF()
|
||||||
self.generateNCXHeader()
|
self.generateNCXHeader()
|
||||||
|
if self.opts.generate_authors:
|
||||||
self.generateNCXByAuthor("Authors")
|
self.generateNCXByAuthor("Authors")
|
||||||
if self.opts.generate_titles:
|
if self.opts.generate_titles:
|
||||||
self.generateNCXByTitle("Titles")
|
self.generateNCXByTitle("Titles")
|
||||||
@ -1508,7 +1519,6 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
|
|||||||
for tag in exclude_tags:
|
for tag in exclude_tags:
|
||||||
search_terms.append("tag:=%s" % tag)
|
search_terms.append("tag:=%s" % tag)
|
||||||
search_phrase = "not (%s)" % " or ".join(search_terms)
|
search_phrase = "not (%s)" % " or ".join(search_terms)
|
||||||
|
|
||||||
# If a list of ids are provided, don't use search_text
|
# If a list of ids are provided, don't use search_text
|
||||||
if self.opts.ids:
|
if self.opts.ids:
|
||||||
self.opts.search_text = search_phrase
|
self.opts.search_text = search_phrase
|
||||||
@ -1879,6 +1889,7 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
|
|||||||
# Link to author
|
# Link to author
|
||||||
emTag = Tag(soup, "em")
|
emTag = Tag(soup, "em")
|
||||||
aTag = Tag(soup, "a")
|
aTag = Tag(soup, "a")
|
||||||
|
if self.opts.generate_authors:
|
||||||
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(book['author']))
|
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(book['author']))
|
||||||
aTag.insert(0, NavigableString(book['author']))
|
aTag.insert(0, NavigableString(book['author']))
|
||||||
emTag.insert(0,aTag)
|
emTag.insert(0,aTag)
|
||||||
@ -2149,6 +2160,7 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
|
|||||||
pAuthorTag = Tag(soup, "p")
|
pAuthorTag = Tag(soup, "p")
|
||||||
pAuthorTag['class'] = "author_index"
|
pAuthorTag['class'] = "author_index"
|
||||||
aTag = Tag(soup, "a")
|
aTag = Tag(soup, "a")
|
||||||
|
if self.opts.generate_authors:
|
||||||
aTag['name'] = "%s" % self.generateAuthorAnchor(current_author)
|
aTag['name'] = "%s" % self.generateAuthorAnchor(current_author)
|
||||||
aTag.insert(0,NavigableString(current_author))
|
aTag.insert(0,NavigableString(current_author))
|
||||||
pAuthorTag.insert(0,aTag)
|
pAuthorTag.insert(0,aTag)
|
||||||
@ -2276,6 +2288,7 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
|
|||||||
# Link to author
|
# Link to author
|
||||||
emTag = Tag(soup, "em")
|
emTag = Tag(soup, "em")
|
||||||
aTag = Tag(soup, "a")
|
aTag = Tag(soup, "a")
|
||||||
|
if self.opts.generate_authors:
|
||||||
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(new_entry['author']))
|
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(new_entry['author']))
|
||||||
aTag.insert(0, NavigableString(new_entry['author']))
|
aTag.insert(0, NavigableString(new_entry['author']))
|
||||||
emTag.insert(0,aTag)
|
emTag.insert(0,aTag)
|
||||||
@ -2425,6 +2438,7 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
|
|||||||
# Link to author
|
# Link to author
|
||||||
emTag = Tag(soup, "em")
|
emTag = Tag(soup, "em")
|
||||||
aTag = Tag(soup, "a")
|
aTag = Tag(soup, "a")
|
||||||
|
if self.opts.generate_authors:
|
||||||
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(new_entry['author']))
|
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(new_entry['author']))
|
||||||
aTag.insert(0, NavigableString(new_entry['author']))
|
aTag.insert(0, NavigableString(new_entry['author']))
|
||||||
emTag.insert(0,aTag)
|
emTag.insert(0,aTag)
|
||||||
@ -2473,6 +2487,7 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
|
|||||||
# Link to author
|
# Link to author
|
||||||
emTag = Tag(soup, "em")
|
emTag = Tag(soup, "em")
|
||||||
aTag = Tag(soup, "a")
|
aTag = Tag(soup, "a")
|
||||||
|
if self.opts.generate_authors:
|
||||||
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(new_entry['author']))
|
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(new_entry['author']))
|
||||||
aTag.insert(0, NavigableString(new_entry['author']))
|
aTag.insert(0, NavigableString(new_entry['author']))
|
||||||
emTag.insert(0,aTag)
|
emTag.insert(0,aTag)
|
||||||
@ -2692,6 +2707,7 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
|
|||||||
|
|
||||||
# Link to author
|
# Link to author
|
||||||
aTag = Tag(soup, "a")
|
aTag = Tag(soup, "a")
|
||||||
|
if self.opts.generate_authors:
|
||||||
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor",
|
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor",
|
||||||
self.generateAuthorAnchor(escape(' & '.join(book['authors']))))
|
self.generateAuthorAnchor(escape(' & '.join(book['authors']))))
|
||||||
aTag.insert(0, NavigableString(' & '.join(book['authors'])))
|
aTag.insert(0, NavigableString(' & '.join(book['authors'])))
|
||||||
@ -3074,10 +3090,34 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
|
|||||||
textTag.insert(0, NavigableString(self.title))
|
textTag.insert(0, NavigableString(self.title))
|
||||||
navLabelTag.insert(0, textTag)
|
navLabelTag.insert(0, textTag)
|
||||||
navPointTag.insert(0, navLabelTag)
|
navPointTag.insert(0, navLabelTag)
|
||||||
|
|
||||||
|
if self.opts.generate_authors:
|
||||||
contentTag = Tag(soup, 'content')
|
contentTag = Tag(soup, 'content')
|
||||||
#contentTag['src'] = "content/book_%d.html" % int(self.booksByTitle[0]['id'])
|
|
||||||
contentTag['src'] = "content/ByAlphaAuthor.html"
|
contentTag['src'] = "content/ByAlphaAuthor.html"
|
||||||
navPointTag.insert(1, contentTag)
|
navPointTag.insert(1, contentTag)
|
||||||
|
elif self.opts.generate_titles:
|
||||||
|
contentTag = Tag(soup, 'content')
|
||||||
|
contentTag['src'] = "content/ByAlphaTitle.html"
|
||||||
|
navPointTag.insert(1, contentTag)
|
||||||
|
elif self.opts.generate_series:
|
||||||
|
contentTag = Tag(soup, 'content')
|
||||||
|
contentTag['src'] = "content/BySeries.html"
|
||||||
|
navPointTag.insert(1, contentTag)
|
||||||
|
elif self.opts.generate_genres:
|
||||||
|
contentTag = Tag(soup, 'content')
|
||||||
|
contentTag['src'] = "content/ByGenres.html"
|
||||||
|
navPointTag.insert(1, contentTag)
|
||||||
|
elif self.opts.generate_recently_added:
|
||||||
|
contentTag = Tag(soup, 'content')
|
||||||
|
contentTag['src'] = "content/ByDateAdded.html"
|
||||||
|
navPointTag.insert(1, contentTag)
|
||||||
|
else:
|
||||||
|
sort_descriptions_by = self.booksByAuthor if self.opts.sort_descriptions_by_author \
|
||||||
|
else self.booksByTitle
|
||||||
|
contentTag = Tag(soup, 'content')
|
||||||
|
contentTag['src'] = "content/book_%d.html" % int(sort_descriptions_by[0]['id'])
|
||||||
|
navPointTag.insert(1, contentTag)
|
||||||
|
|
||||||
cmiTag = Tag(soup, '%s' % 'calibre:meta-img')
|
cmiTag = Tag(soup, '%s' % 'calibre:meta-img')
|
||||||
cmiTag['name'] = "mastheadImage"
|
cmiTag['name'] = "mastheadImage"
|
||||||
cmiTag['src'] = "images/mastheadImage.gif"
|
cmiTag['src'] = "images/mastheadImage.gif"
|
||||||
@ -4140,6 +4180,7 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
|
|||||||
pAuthorTag = Tag(soup, "p")
|
pAuthorTag = Tag(soup, "p")
|
||||||
pAuthorTag['class'] = "author_index"
|
pAuthorTag['class'] = "author_index"
|
||||||
aTag = Tag(soup, "a")
|
aTag = Tag(soup, "a")
|
||||||
|
if self.opts.generate_authors:
|
||||||
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(book['author']))
|
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor", self.generateAuthorAnchor(book['author']))
|
||||||
aTag.insert(0, book['author'])
|
aTag.insert(0, book['author'])
|
||||||
pAuthorTag.insert(0,aTag)
|
pAuthorTag.insert(0,aTag)
|
||||||
@ -4371,6 +4412,7 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
|
|||||||
|
|
||||||
# Insert the author link (always)
|
# Insert the author link (always)
|
||||||
aTag = body.find('a', attrs={'class':'author'})
|
aTag = body.find('a', attrs={'class':'author'})
|
||||||
|
if self.opts.generate_authors:
|
||||||
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor",
|
aTag['href'] = "%s.html#%s" % ("ByAlphaAuthor",
|
||||||
self.generateAuthorAnchor(book['author']))
|
self.generateAuthorAnchor(book['author']))
|
||||||
|
|
||||||
@ -4860,6 +4902,8 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
|
|||||||
|
|
||||||
opts.basename = "Catalog"
|
opts.basename = "Catalog"
|
||||||
opts.cli_environment = not hasattr(opts,'sync')
|
opts.cli_environment = not hasattr(opts,'sync')
|
||||||
|
|
||||||
|
# Hard-wired to always sort descriptions by author, with series after non-series
|
||||||
opts.sort_descriptions_by_author = True
|
opts.sort_descriptions_by_author = True
|
||||||
|
|
||||||
build_log = []
|
build_log = []
|
||||||
@ -4898,14 +4942,13 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
|
|||||||
if opts_dict['ids']:
|
if opts_dict['ids']:
|
||||||
build_log.append(" book count: %d" % len(opts_dict['ids']))
|
build_log.append(" book count: %d" % len(opts_dict['ids']))
|
||||||
|
|
||||||
'''
|
|
||||||
sections_list = []
|
sections_list = []
|
||||||
if opts.generate_authors:
|
if opts.generate_authors:
|
||||||
sections_list.append('Authors')
|
sections_list.append('Authors')
|
||||||
'''
|
|
||||||
sections_list = ['Authors']
|
|
||||||
if opts.generate_titles:
|
if opts.generate_titles:
|
||||||
sections_list.append('Titles')
|
sections_list.append('Titles')
|
||||||
|
if opts.generate_series:
|
||||||
|
sections_list.append('Series')
|
||||||
if opts.generate_genres:
|
if opts.generate_genres:
|
||||||
sections_list.append('Genres')
|
sections_list.append('Genres')
|
||||||
if opts.generate_recently_added:
|
if opts.generate_recently_added:
|
||||||
@ -4913,7 +4956,21 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
|
|||||||
if opts.generate_descriptions:
|
if opts.generate_descriptions:
|
||||||
sections_list.append('Descriptions')
|
sections_list.append('Descriptions')
|
||||||
|
|
||||||
|
if not sections_list:
|
||||||
|
if opts.cli_environment:
|
||||||
|
opts.log.warn('*** No Section switches specified, enabling all Sections ***')
|
||||||
|
opts.generate_authors = True
|
||||||
|
opts.generate_titles = True
|
||||||
|
opts.generate_series = True
|
||||||
|
opts.generate_genres = True
|
||||||
|
opts.generate_recently_added = True
|
||||||
|
opts.generate_descriptions = True
|
||||||
|
sections_list = ['Authors','Titles','Series','Genres','Recently Added','Descriptions']
|
||||||
|
else:
|
||||||
|
opts.log.warn('\n*** No enabled Sections, terminating catalog generation ***')
|
||||||
|
return ["No Included Sections","No enabled Sections.\nCheck E-book options tab\n'Included sections'\n"]
|
||||||
build_log.append(u" Sections: %s" % ', '.join(sections_list))
|
build_log.append(u" Sections: %s" % ', '.join(sections_list))
|
||||||
|
opts.section_list = sections_list
|
||||||
|
|
||||||
# Limit thumb_width to 1.0" - 2.0"
|
# Limit thumb_width to 1.0" - 2.0"
|
||||||
try:
|
try:
|
||||||
@ -4948,6 +5005,7 @@ then rebuild the catalog.\n''').format(author[0],author[1],current_author[1])
|
|||||||
|
|
||||||
# Launch the Catalog builder
|
# Launch the Catalog builder
|
||||||
catalog = self.CatalogBuilder(db, opts, self, report_progress=notification)
|
catalog = self.CatalogBuilder(db, opts, self, report_progress=notification)
|
||||||
|
|
||||||
if opts.verbose:
|
if opts.verbose:
|
||||||
log.info(" Begin catalog source generation")
|
log.info(" Begin catalog source generation")
|
||||||
catalog.createDirectoryStructure()
|
catalog.createDirectoryStructure()
|
||||||
|
@ -108,8 +108,8 @@ Follow these steps to find the problem:
|
|||||||
|
|
||||||
* Make sure that you are connecting only a single device to your computer at a time. Do not have another |app| supported device like an iPhone/iPad etc. at the same time.
|
* Make sure that you are connecting only a single device to your computer at a time. Do not have another |app| supported device like an iPhone/iPad etc. at the same time.
|
||||||
* Make sure you are running the latest version of |app|. The latest version can always be downloaded from `the calibre website <http://calibre-ebook.com/download>`_.
|
* Make sure you are running the latest version of |app|. The latest version can always be downloaded from `the calibre website <http://calibre-ebook.com/download>`_.
|
||||||
* Ensure your operating system is seeing the device. That is, the device should be mounted as a disk that you can access using Windows explorer or whatever the file management program on your computer is
|
* Ensure your operating system is seeing the device. That is, the device should be mounted as a disk that you can access using Windows explorer or whatever the file management program on your computer is.
|
||||||
* In calibre, go to Preferences->Plugins->Device Interface plugin and make sure the plugin for your device is enabled.
|
* In calibre, go to Preferences->Plugins->Device Interface plugin and make sure the plugin for your device is enabled, the plugin icon next to it should be green when it is enabled.
|
||||||
* If all the above steps fail, go to Preferences->Miscellaneous and click debug device detection with your device attached and post the output as a ticket on `the calibre bug tracker <http://bugs.calibre-ebook.com>`_.
|
* If all the above steps fail, go to Preferences->Miscellaneous and click debug device detection with your device attached and post the output as a ticket on `the calibre bug tracker <http://bugs.calibre-ebook.com>`_.
|
||||||
|
|
||||||
How does |app| manage collections on my SONY reader?
|
How does |app| manage collections on my SONY reader?
|
||||||
|
Loading…
x
Reference in New Issue
Block a user