GwR catalog enhancements - Wishlist, improved description layout

This commit is contained in:
GRiker 2010-11-13 14:12:49 -07:00
parent 62e398a3e8
commit 66aa330f12
4 changed files with 183 additions and 99 deletions

View File

@ -81,7 +81,7 @@ p.unread_book {
text-indent:-2em;
}
p.missing_book {
p.wishlist_item {
text-align:left;
margin-top:0px;
margin-bottom:0px;
@ -112,3 +112,14 @@ hr.annotations_divider {
margin-top: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;
}

View File

@ -23,7 +23,9 @@ class PluginWidget(QWidget,Ui_Form):
('generate_recently_added', True),
('note_tag','*'),
('numbers_as_text', False),
('read_tag','+')]
('read_tag','+'),
('wishlist_tag','Wishlist'),
]
# Output synced to the connected device?

View File

@ -42,28 +42,28 @@
</property>
</widget>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Additional note tag prefix:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="3" column="1">
<widget class="QLineEdit" name="note_tag">
<property name="toolTip">
<string extracomment="Default: *"/>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="5" column="1">
<widget class="QLineEdit" name="exclude_genre">
<property name="toolTip">
<string extracomment="Default: \[[\w]*\]"/>
</property>
</widget>
</item>
<item row="4" column="0">
<item row="5" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Regex pattern describing tags to exclude as genres:</string>
@ -76,7 +76,7 @@
</property>
</widget>
</item>
<item row="5" column="1">
<item row="6" column="1">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Regex tips:
@ -88,7 +88,7 @@
</property>
</widget>
</item>
<item row="6" column="0">
<item row="7" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -101,34 +101,44 @@
</property>
</spacer>
</item>
<item row="8" column="0">
<item row="9" column="0">
<widget class="QCheckBox" name="generate_titles">
<property name="text">
<string>Include 'Titles' Section</string>
</property>
</widget>
</item>
<item row="10" column="0">
<item row="11" column="0">
<widget class="QCheckBox" name="generate_recently_added">
<property name="text">
<string>Include 'Recently Added' Section</string>
</property>
</widget>
</item>
<item row="11" column="0">
<item row="12" column="0">
<widget class="QCheckBox" name="numbers_as_text">
<property name="text">
<string>Sort numbers as text</string>
</property>
</widget>
</item>
<item row="9" column="0">
<item row="10" column="0">
<widget class="QCheckBox" name="generate_series">
<property name="text">
<string>Include 'Series' Section</string>
</property>
</widget>
</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>
</widget>
<resources/>

View File

@ -3,14 +3,14 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Greg Riker <griker at hotmail.com>'
import datetime, htmlentitydefs, os, re, shutil, codecs
import base64, codecs, cStringIO, datetime, htmlentitydefs, os, re, shutil, time, zlib
from collections import namedtuple
from copy import deepcopy
from PIL import Image as PILImage
from xml.sax.saxutils import escape
from calibre import prints, prepare_string_for_xml, strftime
from calibre import fit_image, prints, prepare_string_for_xml, strftime
from calibre.constants import preferred_encoding
from calibre.customize import CatalogPlugin
from calibre.customize.conversion import OptionRecommendation, DummyReporter
@ -19,6 +19,7 @@ from calibre.ptempfile import PersistentTemporaryDirectory
from calibre.utils.config import config_dir
from calibre.utils.date import isoformat, now as nowf
from calibre.utils.logging import default_log as log
from calibre.utils.zipfile import ZipFile, ZipInfo
FIELDS = ['all', 'author_sort', 'authors', 'comments',
'cover', 'formats', 'id', 'isbn', 'ondevice', 'pubdate', 'publisher', 'rating',
@ -609,6 +610,12 @@ class EPUB_MOBI(CatalogPlugin):
action = None,
help=_("Tag indicating book has been read.\n" "Default: '%default'\n"
"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):
@ -905,21 +912,17 @@ class EPUB_MOBI(CatalogPlugin):
self.__output_profile = profile
break
if False:
# Confirm/create thumbs archive
if not os.path.exists(self.cache_dir):
if DEBUG:
self.log.info(" creating thumb cache '%s'" % self.__cache_dir)
os.makedirs(self.__cache_dir)
if not os.path.exists(self.__archive_path):
self.log.info(" creating thumbnail archive")
zfw = ZipFile(self.archive_path, mode='w')
zfw.writestr("Catalog Thumbs Archive",'')
zfw.close()
else:
if DEBUG:
self.log.info(" existing thumb cache at '%s'" % self.archive_path)
# 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
if self.opts.generate_titles:
@ -1341,6 +1344,7 @@ class EPUB_MOBI(CatalogPlugin):
this_title = {}
this_title['id'] = record['id']
this_title['uuid'] = record['uuid']
this_title['title'] = self.convertHTMLEntities(record['title'])
if record['series']:
@ -1654,15 +1658,15 @@ class EPUB_MOBI(CatalogPlugin):
aTag.insert(0, title['author'])
# Prefix author with read|reading|none symbol or missing symbol
if 'formats' in title and title['formats']:
if self.opts.wishlist_tag in title['tags']:
authorTag.insert(0, NavigableString(self.MISSING_SYMBOL + " by "))
else:
if title['read']:
authorTag.insert(0, NavigableString(self.READ_SYMBOL + " by "))
elif self.opts.connected_kindle and title['id'] in self.bookmarked_books:
authorTag.insert(0, NavigableString(self.READING_SYMBOL + " by "))
else:
authorTag.insert(0, NavigableString(self.NOT_READ_SYMBOL + " by "))
else:
authorTag.insert(0, NavigableString(self.MISSING_SYMBOL + " by "))
authorTag.insert(1, aTag)
'''
@ -1751,7 +1755,7 @@ class EPUB_MOBI(CatalogPlugin):
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")
#ratingLabel = body.find('td',text="Rating").replaceWith("Unrated")
ratingTag.insert(0,NavigableString('<br/>'))
@ -1760,10 +1764,11 @@ class EPUB_MOBI(CatalogPlugin):
notesTag = body.find(attrs={'class':'notes'})
notesTag.insert(0,NavigableString(title['notes'] + '<br/>'))
else:
notes_labelTag = body.find(attrs={'class':'notes_label'})
empty_labelTag = Tag(soup, "td")
empty_labelTag.insert(0,NavigableString('<br/>'))
notes_labelTag.replaceWith(empty_labelTag)
pass
# notes_labelTag = body.find(attrs={'class':'notes_label'})
# empty_labelTag = Tag(soup, "td")
# empty_labelTag.insert(0,NavigableString('<br/>'))
# notes_labelTag.replaceWith(empty_labelTag)
# Insert the blurb
if 'description' in title and title['description'] > '':
@ -1853,8 +1858,12 @@ class EPUB_MOBI(CatalogPlugin):
pBookTag = Tag(soup, "p")
ptc = 0
# book with read|reading|unread symbol or missing symbol
if 'formats' in book and book['formats']:
# book with read|reading|unread symbol or wishlist item
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']:
# check mark
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
@ -1869,11 +1878,6 @@ class EPUB_MOBI(CatalogPlugin):
pBookTag['class'] = "unread_book"
pBookTag.insert(ptc,NavigableString(self.NOT_READ_SYMBOL))
ptc += 1
else:
# missing formats
pBookTag['class'] = "missing_book"
pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL))
ptc += 1
# Link to book
aTag = Tag(soup, "a")
@ -2028,8 +2032,12 @@ class EPUB_MOBI(CatalogPlugin):
pBookTag = Tag(soup, "p")
ptc = 0
# book with read|reading|unread symbol or missing symbol
if 'formats' in book and book['formats']:
# book with read|reading|unread symbol or wishlist item
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']:
# check mark
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
@ -2044,11 +2052,6 @@ class EPUB_MOBI(CatalogPlugin):
pBookTag['class'] = "unread_book"
pBookTag.insert(ptc,NavigableString(self.NOT_READ_SYMBOL))
ptc += 1
else:
# missing book
pBookTag['class'] = "missing_book"
pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL))
ptc += 1
aTag = Tag(soup, "a")
aTag['href'] = "book_%d.html" % (int(float(book['id'])))
@ -2162,8 +2165,12 @@ class EPUB_MOBI(CatalogPlugin):
pBookTag = Tag(soup, "p")
ptc = 0
# book with read|reading|unread symbol or missing symbol
if 'formats' in new_entry and new_entry['formats']:
# book with read|reading|unread symbol or wishlist item
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']:
# check mark
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
@ -2178,11 +2185,6 @@ class EPUB_MOBI(CatalogPlugin):
pBookTag['class'] = "unread_book"
pBookTag.insert(ptc,NavigableString(self.NOT_READ_SYMBOL))
ptc += 1
else:
# missing book
pBookTag['class'] = "missing_book"
pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL))
ptc += 1
aTag = Tag(soup, "a")
aTag['href'] = "book_%d.html" % (int(float(new_entry['id'])))
@ -2214,8 +2216,12 @@ class EPUB_MOBI(CatalogPlugin):
pBookTag = Tag(soup, "p")
ptc = 0
# book with read|reading|unread symbol or missing symbol
if 'formats' in new_entry and new_entry['formats']:
# book with read|reading|unread symbol or wishlist item
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']:
# check mark
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
@ -2230,11 +2236,6 @@ class EPUB_MOBI(CatalogPlugin):
pBookTag['class'] = "unread_book"
pBookTag.insert(ptc,NavigableString(self.NOT_READ_SYMBOL))
ptc += 1
else:
# missing book
pBookTag['class'] = "missing_book"
pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL))
ptc += 1
aTag = Tag(soup, "a")
aTag['href'] = "book_%d.html" % (int(float(new_entry['id'])))
@ -2669,8 +2670,12 @@ class EPUB_MOBI(CatalogPlugin):
else:
book['read'] = False
# book with read|reading|unread symbol or missing symbol
if 'formats' in book and book['formats']:
# book with read|reading|unread symbol or wishlist item
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']:
# check mark
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
@ -2685,11 +2690,6 @@ class EPUB_MOBI(CatalogPlugin):
pBookTag['class'] = "unread_book"
pBookTag.insert(ptc,NavigableString(self.NOT_READ_SYMBOL))
ptc += 1
else:
# missing book
pBookTag['class'] = "missing_book"
pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL))
ptc += 1
aTag = Tag(soup, "a")
aTag['href'] = "book_%d.html" % (int(float(book['id'])))
@ -2767,8 +2767,7 @@ class EPUB_MOBI(CatalogPlugin):
this_book['title'] = book['title']
this_book['author_sort'] = book['author_sort'].capitalize()
this_book['read'] = book['read']
if 'formats' in book:
this_book['formats'] = book['formats']
this_book['tags'] = book['tags']
this_book['id'] = book['id']
this_book['series'] = book['series']
normalized_tag = self.genre_tags_dict[friendly_tag]
@ -4170,8 +4169,15 @@ class EPUB_MOBI(CatalogPlugin):
pBookTag = Tag(soup, "p")
ptc = 0
# book with read|reading|unread symbol or missing symbol
if 'formats' in book and book['formats']:
# book with read|reading|unread symbol or wishlist item
# 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']:
# check mark
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
@ -4186,11 +4192,6 @@ class EPUB_MOBI(CatalogPlugin):
pBookTag['class'] = "unread_book"
pBookTag.insert(ptc,NavigableString(self.NOT_READ_SYMBOL))
ptc += 1
else:
# missing book
pBookTag['class'] = "missing_book"
pBookTag.insert(ptc,NavigableString(self.MISSING_SYMBOL))
ptc += 1
# Add the book title
aTag = Tag(soup, "a")
@ -4240,31 +4241,31 @@ class EPUB_MOBI(CatalogPlugin):
<table width="100%" border="0">
<tr>
<td class="thumbnail" rowspan="7"></td>
<td>&nbsp;</td>
<!--td>&nbsp;</td-->
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<!--td>&nbsp;</td-->
<td>&nbsp;</td>
</tr>
<tr>
<td>Publisher</td>
<!--td>Publisher</td-->
<td class="publisher"></td>
</tr>
<tr>
<td>Published</td>
<!--td>Published</td-->
<td class="date"></td>
</tr>
<tr>
<td>Rating</td>
<!--td>Rating</td-->
<td class="rating"></td>
</tr>
<tr>
<td class="notes_label">Notes</td>
<!--td class="notes_label">Notes</td-->
<td class="notes"></td>
</tr>
<tr>
<td>&nbsp;</td>
<!--td>&nbsp;</td-->
<td>&nbsp;</td>
</tr>
</table>
@ -4452,15 +4453,74 @@ class EPUB_MOBI(CatalogPlugin):
return ' '.join(translated)
def generateThumbnail(self, title, image_dir, thumb_file):
from calibre.utils.magick import Image
try:
img = Image()
img.open(title['cover'])
# img, width, height
img.thumbnail(self.thumbWidth, self.thumbHeight)
img.save(os.path.join(image_dir, thumb_file))
except:
self.opts.log.error("generateThumbnail(): Error with %s" % title['title'])
'''
Thumbs are cached with the full cover's crc. If the crc doesn't
match, the cover has been changed since the thumb was cached and needs
to be replaced.
2010-11-13 switched to PIL library for faster thumb generation
'''
if True:
# Generate crc for current cover
#self.opts.log.info(" generateThumbnail():")
data = open(title['cover'], 'rb')
stream = cStringIO.StringIO()
stream.write(data.read())
cover_crc = hex(zlib.crc32(stream.getvalue()))
stream.close()
# Test cache for uuid
try:
zfr = ZipFile(self.__archive_path, mode='r')
t_info = zfr.getinfo(title['uuid'])
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)
zfr.close()
os.rename(os.path.join(image_dir,title['uuid']),
os.path.join(image_dir,thumb_file))
return
else:
# uuid found in cache, but crc mismatch
zfr.close()
except:
# uuid not found in cache
zfr.close()
# Create a new thumb
im = PILImage.open(title['cover'])
scaled, width, height = fit_image(im.size[0],im.size[1],
self.thumbWidth, self.thumbHeight)
im = im.resize((int(width),int(height)), PILImage.ANTIALIAS)
# Save thumb for catalog
im.convert('RGB').save(os.path.join(image_dir, thumb_file),'JPEG')
# Save thumb to archive
thumb_stream = cStringIO.StringIO()
im.convert('RGB').save(thumb_stream,'JPEG')
thumb_data = thumb_stream.getvalue()
thumb_stream.close()
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()
else:
# non-caching code using ImageMagick
from calibre.utils.magick import Image
try:
img = Image()
img.open(title['cover'])
# img, width, height
img.thumbnail(self.thumbWidth, self.thumbHeight)
img.save(os.path.join(image_dir, thumb_file))
except:
self.opts.log.error("generateThumbnail(): Error with %s" % title['title'])
def getFriendlyGenreTag(self, genre):
# Find the first instance of friendly_tag matching genre
@ -4714,7 +4774,8 @@ class EPUB_MOBI(CatalogPlugin):
if key in ['catalog_title','authorClip','connected_kindle','descriptionClip',
'exclude_genre','exclude_tags','note_tag','numbers_as_text',
'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]))
if opts.verbose: