mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
Catalog generation: Thumbnail caching, wishlist, improved description layout. Fixes #7376 (E-Book Catalog Option Request: Wish List Books)
This commit is contained in:
commit
9ae6c11a28
@ -81,7 +81,7 @@ p.unread_book {
|
|||||||
text-indent:-2em;
|
text-indent:-2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
p.missing_book {
|
p.wishlist_item {
|
||||||
text-align:left;
|
text-align:left;
|
||||||
margin-top:0px;
|
margin-top:0px;
|
||||||
margin-bottom:0px;
|
margin-bottom:0px;
|
||||||
@ -112,3 +112,14 @@ hr.annotations_divider {
|
|||||||
margin-top:0em;
|
margin-top:0em;
|
||||||
margin-bottom:0em;
|
margin-bottom:0em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
td.publisher, td.date {
|
||||||
|
font-weight:bold;
|
||||||
|
text-align:center;
|
||||||
|
}
|
||||||
|
td.rating {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
td.thumbnail img {
|
||||||
|
-webkit-box-shadow: 6px 6px 6px #888;
|
||||||
|
}
|
@ -23,7 +23,9 @@ class PluginWidget(QWidget,Ui_Form):
|
|||||||
('generate_recently_added', True),
|
('generate_recently_added', True),
|
||||||
('note_tag','*'),
|
('note_tag','*'),
|
||||||
('numbers_as_text', False),
|
('numbers_as_text', False),
|
||||||
('read_tag','+')]
|
('read_tag','+'),
|
||||||
|
('wishlist_tag','Wishlist'),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
# Output synced to the connected device?
|
# Output synced to the connected device?
|
||||||
|
@ -42,28 +42,28 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="3" column="0">
|
||||||
<widget class="QLabel" name="label_4">
|
<widget class="QLabel" name="label_4">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Additional note tag prefix:</string>
|
<string>Additional note tag prefix:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="3" column="1">
|
||||||
<widget class="QLineEdit" name="note_tag">
|
<widget class="QLineEdit" name="note_tag">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string extracomment="Default: *"/>
|
<string extracomment="Default: *"/>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="1">
|
<item row="5" column="1">
|
||||||
<widget class="QLineEdit" name="exclude_genre">
|
<widget class="QLineEdit" name="exclude_genre">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string extracomment="Default: \[[\w]*\]"/>
|
<string extracomment="Default: \[[\w]*\]"/>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item row="5" column="0">
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Regex pattern describing tags to exclude as genres:</string>
|
<string>Regex pattern describing tags to exclude as genres:</string>
|
||||||
@ -76,7 +76,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="1">
|
<item row="6" column="1">
|
||||||
<widget class="QLabel" name="label_6">
|
<widget class="QLabel" name="label_6">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Regex tips:
|
<string>Regex tips:
|
||||||
@ -88,7 +88,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="0">
|
<item row="7" column="0">
|
||||||
<spacer name="verticalSpacer">
|
<spacer name="verticalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
@ -101,34 +101,44 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="8" column="0">
|
<item row="9" column="0">
|
||||||
<widget class="QCheckBox" name="generate_titles">
|
<widget class="QCheckBox" name="generate_titles">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Include 'Titles' Section</string>
|
<string>Include 'Titles' Section</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="10" column="0">
|
<item row="11" column="0">
|
||||||
<widget class="QCheckBox" name="generate_recently_added">
|
<widget class="QCheckBox" name="generate_recently_added">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Include 'Recently Added' Section</string>
|
<string>Include 'Recently Added' Section</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="11" column="0">
|
<item row="12" column="0">
|
||||||
<widget class="QCheckBox" name="numbers_as_text">
|
<widget class="QCheckBox" name="numbers_as_text">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Sort numbers as text</string>
|
<string>Sort numbers as text</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="9" column="0">
|
<item row="10" column="0">
|
||||||
<widget class="QCheckBox" name="generate_series">
|
<widget class="QCheckBox" name="generate_series">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Include 'Series' Section</string>
|
<string>Include 'Series' Section</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLineEdit" name="wishlist_tag"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Wishlist tag:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
@ -3,11 +3,10 @@
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2010, Greg Riker <griker at hotmail.com>'
|
__copyright__ = '2010, Greg Riker <griker at hotmail.com>'
|
||||||
|
|
||||||
import datetime, htmlentitydefs, os, re, shutil, codecs
|
import codecs, datetime, htmlentitydefs, os, re, shutil, time, zlib
|
||||||
|
from contextlib import closing
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
from xml.sax.saxutils import escape
|
from xml.sax.saxutils import escape
|
||||||
|
|
||||||
from calibre import prints, prepare_string_for_xml, strftime
|
from calibre import prints, prepare_string_for_xml, strftime
|
||||||
@ -16,8 +15,11 @@ from calibre.customize import CatalogPlugin
|
|||||||
from calibre.customize.conversion import OptionRecommendation, DummyReporter
|
from calibre.customize.conversion import OptionRecommendation, DummyReporter
|
||||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup, BeautifulStoneSoup, Tag, NavigableString
|
from calibre.ebooks.BeautifulSoup import BeautifulSoup, BeautifulStoneSoup, Tag, NavigableString
|
||||||
from calibre.ptempfile import PersistentTemporaryDirectory
|
from calibre.ptempfile import PersistentTemporaryDirectory
|
||||||
|
from calibre.utils.config import config_dir
|
||||||
from calibre.utils.date import isoformat, now as nowf
|
from calibre.utils.date import isoformat, now as nowf
|
||||||
from calibre.utils.logging import default_log as log
|
from calibre.utils.logging import default_log as log
|
||||||
|
from calibre.utils.zipfile import ZipFile, ZipInfo
|
||||||
|
from calibre.utils.magick.draw import thumbnail
|
||||||
|
|
||||||
FIELDS = ['all', 'author_sort', 'authors', 'comments',
|
FIELDS = ['all', 'author_sort', 'authors', 'comments',
|
||||||
'cover', 'formats', 'id', 'isbn', 'ondevice', 'pubdate', 'publisher', 'rating',
|
'cover', 'formats', 'id', 'isbn', 'ondevice', 'pubdate', 'publisher', 'rating',
|
||||||
@ -608,6 +610,12 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
action = None,
|
action = None,
|
||||||
help=_("Tag indicating book has been read.\n" "Default: '%default'\n"
|
help=_("Tag indicating book has been read.\n" "Default: '%default'\n"
|
||||||
"Applies to: ePub, MOBI output formats")),
|
"Applies to: ePub, MOBI output formats")),
|
||||||
|
Option('--wishlist-tag',
|
||||||
|
default='Wishlist',
|
||||||
|
dest='wishlist_tag',
|
||||||
|
action = None,
|
||||||
|
help=_("Tag indicating book to be displayed as wishlist item.\n" "Default: '%default'\n"
|
||||||
|
"Applies to: ePub, MOBI output formats")),
|
||||||
]
|
]
|
||||||
|
|
||||||
class NumberToText(object):
|
class NumberToText(object):
|
||||||
@ -862,6 +870,8 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
self.__booksByDateRead = None
|
self.__booksByDateRead = None
|
||||||
self.__booksByTitle = None
|
self.__booksByTitle = None
|
||||||
self.__booksByTitle_noSeriesPrefix = None
|
self.__booksByTitle_noSeriesPrefix = None
|
||||||
|
self.__cache_dir = os.path.join(config_dir, 'caches', 'catalog')
|
||||||
|
self.__archive_path = os.path.join(self.__cache_dir, "thumbs.zip")
|
||||||
self.__catalogPath = PersistentTemporaryDirectory("_epub_mobi_catalog", prefix='')
|
self.__catalogPath = PersistentTemporaryDirectory("_epub_mobi_catalog", prefix='')
|
||||||
self.__contentDir = os.path.join(self.catalogPath, "content")
|
self.__contentDir = os.path.join(self.catalogPath, "content")
|
||||||
self.__currentStep = 0.0
|
self.__currentStep = 0.0
|
||||||
@ -902,6 +912,18 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
self.__output_profile = profile
|
self.__output_profile = profile
|
||||||
break
|
break
|
||||||
|
|
||||||
|
# Confirm/create thumbs archive
|
||||||
|
if not os.path.exists(self.__cache_dir):
|
||||||
|
self.opts.log.info(" creating new thumb cache '%s'" % self.__cache_dir)
|
||||||
|
os.makedirs(self.__cache_dir)
|
||||||
|
if not os.path.exists(self.__archive_path):
|
||||||
|
self.opts.log.info(" creating thumbnail archive")
|
||||||
|
zfw = ZipFile(self.__archive_path, mode='w')
|
||||||
|
zfw.writestr("Catalog Thumbs Archive",'')
|
||||||
|
zfw.close()
|
||||||
|
else:
|
||||||
|
self.opts.log.info(" existing thumb cache at '%s'" % self.__archive_path)
|
||||||
|
|
||||||
# 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
|
||||||
if self.opts.generate_titles:
|
if self.opts.generate_titles:
|
||||||
self.__totalSteps += 2
|
self.__totalSteps += 2
|
||||||
@ -1322,6 +1344,7 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
this_title = {}
|
this_title = {}
|
||||||
|
|
||||||
this_title['id'] = record['id']
|
this_title['id'] = record['id']
|
||||||
|
this_title['uuid'] = record['uuid']
|
||||||
|
|
||||||
this_title['title'] = self.convertHTMLEntities(record['title'])
|
this_title['title'] = self.convertHTMLEntities(record['title'])
|
||||||
if record['series']:
|
if record['series']:
|
||||||
@ -1635,15 +1658,15 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
aTag.insert(0, title['author'])
|
aTag.insert(0, title['author'])
|
||||||
|
|
||||||
# Prefix author with read|reading|none symbol or missing symbol
|
# Prefix author with read|reading|none symbol or missing symbol
|
||||||
if 'formats' in title and title['formats']:
|
if self.opts.wishlist_tag in title.get('tags', []):
|
||||||
|
authorTag.insert(0, NavigableString(self.MISSING_SYMBOL + " by "))
|
||||||
|
else:
|
||||||
if title['read']:
|
if title['read']:
|
||||||
authorTag.insert(0, NavigableString(self.READ_SYMBOL + " by "))
|
authorTag.insert(0, NavigableString(self.READ_SYMBOL + " by "))
|
||||||
elif self.opts.connected_kindle and title['id'] in self.bookmarked_books:
|
elif self.opts.connected_kindle and title['id'] in self.bookmarked_books:
|
||||||
authorTag.insert(0, NavigableString(self.READING_SYMBOL + " by "))
|
authorTag.insert(0, NavigableString(self.READING_SYMBOL + " by "))
|
||||||
else:
|
else:
|
||||||
authorTag.insert(0, NavigableString(self.NOT_READ_SYMBOL + " by "))
|
authorTag.insert(0, NavigableString(self.NOT_READ_SYMBOL + " by "))
|
||||||
else:
|
|
||||||
authorTag.insert(0, NavigableString(self.MISSING_SYMBOL + " by "))
|
|
||||||
authorTag.insert(1, aTag)
|
authorTag.insert(1, aTag)
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@ -1723,24 +1746,29 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
else:
|
else:
|
||||||
pubdateTag.insert(0,NavigableString('<br/>'))
|
pubdateTag.insert(0,NavigableString('<br/>'))
|
||||||
|
|
||||||
# Insert the rating
|
# Insert the rating, remove if unrated
|
||||||
# Render different ratings chars for epub/mobi
|
# Render different ratings chars for epub/mobi
|
||||||
stars = int(title['rating']) / 2
|
stars = int(title['rating']) / 2
|
||||||
star_string = self.FULL_RATING_SYMBOL * stars
|
|
||||||
empty_stars = self.EMPTY_RATING_SYMBOL * (5 - stars)
|
|
||||||
|
|
||||||
ratingTag = body.find(attrs={'class':'rating'})
|
ratingTag = body.find(attrs={'class':'rating'})
|
||||||
ratingTag.insert(0,NavigableString('%s%s <br/>' % (star_string,empty_stars)))
|
if stars:
|
||||||
|
star_string = self.FULL_RATING_SYMBOL * stars
|
||||||
|
empty_stars = self.EMPTY_RATING_SYMBOL * (5 - stars)
|
||||||
|
ratingTag.insert(0,NavigableString('%s%s <br/>' % (star_string,empty_stars)))
|
||||||
|
else:
|
||||||
|
#ratingLabel = body.find('td',text="Rating").replaceWith("Unrated")
|
||||||
|
ratingTag.insert(0,NavigableString('<br/>'))
|
||||||
|
|
||||||
|
|
||||||
# Insert user notes or remove Notes label. Notes > 1 line will push formatting down
|
# Insert user notes or remove Notes label. Notes > 1 line will push formatting down
|
||||||
if 'notes' in title:
|
if 'notes' in title:
|
||||||
notesTag = body.find(attrs={'class':'notes'})
|
notesTag = body.find(attrs={'class':'notes'})
|
||||||
notesTag.insert(0,NavigableString(title['notes'] + '<br/>'))
|
notesTag.insert(0,NavigableString(title['notes'] + '<br/>'))
|
||||||
else:
|
else:
|
||||||
notes_labelTag = body.find(attrs={'class':'notes_label'})
|
pass
|
||||||
empty_labelTag = Tag(soup, "td")
|
# notes_labelTag = body.find(attrs={'class':'notes_label'})
|
||||||
empty_labelTag.insert(0,NavigableString('<br/>'))
|
# empty_labelTag = Tag(soup, "td")
|
||||||
notes_labelTag.replaceWith(empty_labelTag)
|
# empty_labelTag.insert(0,NavigableString('<br/>'))
|
||||||
|
# notes_labelTag.replaceWith(empty_labelTag)
|
||||||
|
|
||||||
# Insert the blurb
|
# Insert the blurb
|
||||||
if 'description' in title and title['description'] > '':
|
if 'description' in title and title['description'] > '':
|
||||||
@ -1830,8 +1858,12 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
pBookTag = Tag(soup, "p")
|
pBookTag = Tag(soup, "p")
|
||||||
ptc = 0
|
ptc = 0
|
||||||
|
|
||||||
# book with read|reading|unread symbol or missing symbol
|
# book with read|reading|unread symbol or wishlist item
|
||||||
if 'formats' in book and book['formats']:
|
if self.opts.wishlist_tag in book['tags']:
|
||||||
|
pBookTag['class'] = "wishlist_item"
|
||||||
|
pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL))
|
||||||
|
ptc += 1
|
||||||
|
else:
|
||||||
if book['read']:
|
if book['read']:
|
||||||
# check mark
|
# check mark
|
||||||
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
|
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
|
||||||
@ -1846,11 +1878,6 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
pBookTag['class'] = "unread_book"
|
pBookTag['class'] = "unread_book"
|
||||||
pBookTag.insert(ptc,NavigableString(self.NOT_READ_SYMBOL))
|
pBookTag.insert(ptc,NavigableString(self.NOT_READ_SYMBOL))
|
||||||
ptc += 1
|
ptc += 1
|
||||||
else:
|
|
||||||
# missing formats
|
|
||||||
pBookTag['class'] = "missing_book"
|
|
||||||
pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL))
|
|
||||||
ptc += 1
|
|
||||||
|
|
||||||
# Link to book
|
# Link to book
|
||||||
aTag = Tag(soup, "a")
|
aTag = Tag(soup, "a")
|
||||||
@ -2005,8 +2032,12 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
pBookTag = Tag(soup, "p")
|
pBookTag = Tag(soup, "p")
|
||||||
ptc = 0
|
ptc = 0
|
||||||
|
|
||||||
# book with read|reading|unread symbol or missing symbol
|
# book with read|reading|unread symbol or wishlist item
|
||||||
if 'formats' in book and book['formats']:
|
if self.opts.wishlist_tag in book.get('tags', []):
|
||||||
|
pBookTag['class'] = "wishlist_item"
|
||||||
|
pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL))
|
||||||
|
ptc += 1
|
||||||
|
else:
|
||||||
if book['read']:
|
if book['read']:
|
||||||
# check mark
|
# check mark
|
||||||
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
|
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
|
||||||
@ -2021,11 +2052,6 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
pBookTag['class'] = "unread_book"
|
pBookTag['class'] = "unread_book"
|
||||||
pBookTag.insert(ptc,NavigableString(self.NOT_READ_SYMBOL))
|
pBookTag.insert(ptc,NavigableString(self.NOT_READ_SYMBOL))
|
||||||
ptc += 1
|
ptc += 1
|
||||||
else:
|
|
||||||
# missing book
|
|
||||||
pBookTag['class'] = "missing_book"
|
|
||||||
pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL))
|
|
||||||
ptc += 1
|
|
||||||
|
|
||||||
aTag = Tag(soup, "a")
|
aTag = Tag(soup, "a")
|
||||||
aTag['href'] = "book_%d.html" % (int(float(book['id'])))
|
aTag['href'] = "book_%d.html" % (int(float(book['id'])))
|
||||||
@ -2139,8 +2165,12 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
pBookTag = Tag(soup, "p")
|
pBookTag = Tag(soup, "p")
|
||||||
ptc = 0
|
ptc = 0
|
||||||
|
|
||||||
# book with read|reading|unread symbol or missing symbol
|
# book with read|reading|unread symbol or wishlist item
|
||||||
if 'formats' in new_entry and new_entry['formats']:
|
if self.opts.wishlist_tag in new_entry['tags']:
|
||||||
|
pBookTag['class'] = "wishlist_item"
|
||||||
|
pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL))
|
||||||
|
ptc += 1
|
||||||
|
else:
|
||||||
if new_entry['read']:
|
if new_entry['read']:
|
||||||
# check mark
|
# check mark
|
||||||
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
|
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
|
||||||
@ -2155,11 +2185,6 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
pBookTag['class'] = "unread_book"
|
pBookTag['class'] = "unread_book"
|
||||||
pBookTag.insert(ptc,NavigableString(self.NOT_READ_SYMBOL))
|
pBookTag.insert(ptc,NavigableString(self.NOT_READ_SYMBOL))
|
||||||
ptc += 1
|
ptc += 1
|
||||||
else:
|
|
||||||
# missing book
|
|
||||||
pBookTag['class'] = "missing_book"
|
|
||||||
pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL))
|
|
||||||
ptc += 1
|
|
||||||
|
|
||||||
aTag = Tag(soup, "a")
|
aTag = Tag(soup, "a")
|
||||||
aTag['href'] = "book_%d.html" % (int(float(new_entry['id'])))
|
aTag['href'] = "book_%d.html" % (int(float(new_entry['id'])))
|
||||||
@ -2191,8 +2216,12 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
pBookTag = Tag(soup, "p")
|
pBookTag = Tag(soup, "p")
|
||||||
ptc = 0
|
ptc = 0
|
||||||
|
|
||||||
# book with read|reading|unread symbol or missing symbol
|
# book with read|reading|unread symbol or wishlist item
|
||||||
if 'formats' in new_entry and new_entry['formats']:
|
if self.opts.wishlist_tag in new_entry['tags']:
|
||||||
|
pBookTag['class'] = "wishlist_item"
|
||||||
|
pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL))
|
||||||
|
ptc += 1
|
||||||
|
else:
|
||||||
if new_entry['read']:
|
if new_entry['read']:
|
||||||
# check mark
|
# check mark
|
||||||
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
|
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
|
||||||
@ -2207,11 +2236,6 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
pBookTag['class'] = "unread_book"
|
pBookTag['class'] = "unread_book"
|
||||||
pBookTag.insert(ptc,NavigableString(self.NOT_READ_SYMBOL))
|
pBookTag.insert(ptc,NavigableString(self.NOT_READ_SYMBOL))
|
||||||
ptc += 1
|
ptc += 1
|
||||||
else:
|
|
||||||
# missing book
|
|
||||||
pBookTag['class'] = "missing_book"
|
|
||||||
pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL))
|
|
||||||
ptc += 1
|
|
||||||
|
|
||||||
aTag = Tag(soup, "a")
|
aTag = Tag(soup, "a")
|
||||||
aTag['href'] = "book_%d.html" % (int(float(new_entry['id'])))
|
aTag['href'] = "book_%d.html" % (int(float(new_entry['id'])))
|
||||||
@ -2646,8 +2670,12 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
else:
|
else:
|
||||||
book['read'] = False
|
book['read'] = False
|
||||||
|
|
||||||
# book with read|reading|unread symbol or missing symbol
|
# book with read|reading|unread symbol or wishlist item
|
||||||
if 'formats' in book and book['formats']:
|
if self.opts.wishlist_tag in book['tags']:
|
||||||
|
pBookTag['class'] = "wishlist_item"
|
||||||
|
pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL))
|
||||||
|
ptc += 1
|
||||||
|
else:
|
||||||
if book['read']:
|
if book['read']:
|
||||||
# check mark
|
# check mark
|
||||||
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
|
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
|
||||||
@ -2662,11 +2690,6 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
pBookTag['class'] = "unread_book"
|
pBookTag['class'] = "unread_book"
|
||||||
pBookTag.insert(ptc,NavigableString(self.NOT_READ_SYMBOL))
|
pBookTag.insert(ptc,NavigableString(self.NOT_READ_SYMBOL))
|
||||||
ptc += 1
|
ptc += 1
|
||||||
else:
|
|
||||||
# missing book
|
|
||||||
pBookTag['class'] = "missing_book"
|
|
||||||
pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL))
|
|
||||||
ptc += 1
|
|
||||||
|
|
||||||
aTag = Tag(soup, "a")
|
aTag = Tag(soup, "a")
|
||||||
aTag['href'] = "book_%d.html" % (int(float(book['id'])))
|
aTag['href'] = "book_%d.html" % (int(float(book['id'])))
|
||||||
@ -2744,8 +2767,7 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
this_book['title'] = book['title']
|
this_book['title'] = book['title']
|
||||||
this_book['author_sort'] = book['author_sort'].capitalize()
|
this_book['author_sort'] = book['author_sort'].capitalize()
|
||||||
this_book['read'] = book['read']
|
this_book['read'] = book['read']
|
||||||
if 'formats' in book:
|
this_book['tags'] = book['tags']
|
||||||
this_book['formats'] = book['formats']
|
|
||||||
this_book['id'] = book['id']
|
this_book['id'] = book['id']
|
||||||
this_book['series'] = book['series']
|
this_book['series'] = book['series']
|
||||||
normalized_tag = self.genre_tags_dict[friendly_tag]
|
normalized_tag = self.genre_tags_dict[friendly_tag]
|
||||||
@ -4147,8 +4169,15 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
pBookTag = Tag(soup, "p")
|
pBookTag = Tag(soup, "p")
|
||||||
ptc = 0
|
ptc = 0
|
||||||
|
|
||||||
# book with read|reading|unread symbol or missing symbol
|
# book with read|reading|unread symbol or wishlist item
|
||||||
if 'formats' in book and book['formats']:
|
# If this is the wishlist_tag genre, don't show missing symbols
|
||||||
|
# normalized_wishlist_tag = self.genre_tags_dict[self.opts.wishlist_tag]
|
||||||
|
if self.opts.wishlist_tag in book['tags'] and \
|
||||||
|
self.genre_tags_dict[self.opts.wishlist_tag] != genre:
|
||||||
|
pBookTag['class'] = "wishlist_item"
|
||||||
|
pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL))
|
||||||
|
ptc += 1
|
||||||
|
else:
|
||||||
if book['read']:
|
if book['read']:
|
||||||
# check mark
|
# check mark
|
||||||
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
|
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
|
||||||
@ -4163,11 +4192,6 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
pBookTag['class'] = "unread_book"
|
pBookTag['class'] = "unread_book"
|
||||||
pBookTag.insert(ptc,NavigableString(self.NOT_READ_SYMBOL))
|
pBookTag.insert(ptc,NavigableString(self.NOT_READ_SYMBOL))
|
||||||
ptc += 1
|
ptc += 1
|
||||||
else:
|
|
||||||
# missing book
|
|
||||||
pBookTag['class'] = "missing_book"
|
|
||||||
pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL))
|
|
||||||
ptc += 1
|
|
||||||
|
|
||||||
# Add the book title
|
# Add the book title
|
||||||
aTag = Tag(soup, "a")
|
aTag = Tag(soup, "a")
|
||||||
@ -4217,31 +4241,31 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
<table width="100%" border="0">
|
<table width="100%" border="0">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="thumbnail" rowspan="7"></td>
|
<td class="thumbnail" rowspan="7"></td>
|
||||||
<td> </td>
|
<!--td> </td-->
|
||||||
<td> </td>
|
<td> </td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td> </td>
|
<!--td> </td-->
|
||||||
<td> </td>
|
<td> </td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Publisher</td>
|
<!--td>Publisher</td-->
|
||||||
<td class="publisher"></td>
|
<td class="publisher"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Published</td>
|
<!--td>Published</td-->
|
||||||
<td class="date"></td>
|
<td class="date"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Rating</td>
|
<!--td>Rating</td-->
|
||||||
<td class="rating"></td>
|
<td class="rating"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="notes_label">Notes</td>
|
<!--td class="notes_label">Notes</td-->
|
||||||
<td class="notes"></td>
|
<td class="notes"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td> </td>
|
<!--td> </td-->
|
||||||
<td> </td>
|
<td> </td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
@ -4429,15 +4453,45 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
return ' '.join(translated)
|
return ' '.join(translated)
|
||||||
|
|
||||||
def generateThumbnail(self, title, image_dir, thumb_file):
|
def generateThumbnail(self, title, image_dir, thumb_file):
|
||||||
from calibre.utils.magick import Image
|
'''
|
||||||
try:
|
Thumbs are cached with the full cover's crc. If the crc doesn't
|
||||||
img = Image()
|
match, the cover has been changed since the thumb was cached and needs
|
||||||
img.open(title['cover'])
|
to be replaced.
|
||||||
# img, width, height
|
'''
|
||||||
img.thumbnail(self.thumbWidth, self.thumbHeight)
|
|
||||||
img.save(os.path.join(image_dir, thumb_file))
|
# Generate crc for current cover
|
||||||
except:
|
#self.opts.log.info(" generateThumbnail():")
|
||||||
self.opts.log.error("generateThumbnail(): Error with %s" % title['title'])
|
data = open(title['cover'], 'rb').read()
|
||||||
|
cover_crc = hex(zlib.crc32(data))
|
||||||
|
|
||||||
|
# Test cache for uuid
|
||||||
|
with closing(ZipFile(self.__archive_path, mode='r')) as zfr:
|
||||||
|
try:
|
||||||
|
t_info = zfr.getinfo(title['uuid'])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if t_info.comment == cover_crc:
|
||||||
|
# uuid found in cache with matching crc
|
||||||
|
thumb_data = zfr.read(title['uuid'])
|
||||||
|
zfr.extract(title['uuid'],image_dir)
|
||||||
|
os.rename(os.path.join(image_dir,title['uuid']),
|
||||||
|
os.path.join(image_dir,thumb_file))
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
# Save thumb for catalog
|
||||||
|
thumb_data = thumbnail(data,
|
||||||
|
width=self.thumbWidth, height=self.thumbHeight)[-1]
|
||||||
|
with open(os.path.join(image_dir, thumb_file), 'wb') as f:
|
||||||
|
f.write(thumb_data)
|
||||||
|
|
||||||
|
# Save thumb to archive
|
||||||
|
t_info = ZipInfo(title['uuid'],time.localtime()[0:6])
|
||||||
|
t_info.comment = cover_crc
|
||||||
|
zfw = ZipFile(self.__archive_path, mode='a')
|
||||||
|
zfw.writestr(t_info, thumb_data)
|
||||||
|
zfw.close()
|
||||||
|
|
||||||
def getFriendlyGenreTag(self, genre):
|
def getFriendlyGenreTag(self, genre):
|
||||||
# Find the first instance of friendly_tag matching genre
|
# Find the first instance of friendly_tag matching genre
|
||||||
@ -4691,7 +4745,8 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
if key in ['catalog_title','authorClip','connected_kindle','descriptionClip',
|
if key in ['catalog_title','authorClip','connected_kindle','descriptionClip',
|
||||||
'exclude_genre','exclude_tags','note_tag','numbers_as_text',
|
'exclude_genre','exclude_tags','note_tag','numbers_as_text',
|
||||||
'output_profile','read_tag',
|
'output_profile','read_tag',
|
||||||
'search_text','sort_by','sort_descriptions_by_author','sync']:
|
'search_text','sort_by','sort_descriptions_by_author','sync',
|
||||||
|
'wishlist_tag']:
|
||||||
build_log.append(" %s: %s" % (key, opts_dict[key]))
|
build_log.append(" %s: %s" % (key, opts_dict[key]))
|
||||||
|
|
||||||
if opts.verbose:
|
if opts.verbose:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user