Catalog generation: Changes for series sorting

This commit is contained in:
Kovid Goyal 2010-02-06 12:43:11 -07:00
commit b856b40932
6 changed files with 135 additions and 41 deletions

View File

@ -17,14 +17,6 @@ p.author {
font-size:large; font-size:large;
} }
p.series {
margin-top:0em;
margin-bottom:0em;
text-align: left;
text-indent: 1em;
font-size:small;
}
p.tags { p.tags {
margin-top:0em; margin-top:0em;
margin-bottom:0em; margin-bottom:0em;
@ -63,6 +55,14 @@ p.author_index {
text-indent: 0em; text-indent: 0em;
} }
p.series {
text-align: left;
margin-top:0px;
margin-bottom:0px;
margin-left:2em;
text-indent:-2em;
}
p.read_book { p.read_book {
text-align:left; text-align:left;
margin-top:0px; margin-top:0px;

View File

@ -1,14 +1,12 @@
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008-2010, Darko Miletic <darko.miletic at gmail.com>' __copyright__ = '2008-2010, Darko Miletic <darko.miletic at gmail.com>'
''' '''
pagina12.com.ar pagina12.com.ar
''' '''
import re, time import re
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import BeautifulSoup, NavigableString, CData, Tag from calibre.ebooks.BeautifulSoup import BeautifulSoup
class Pagina12(BasicNewsRecipe): class Pagina12(BasicNewsRecipe):
title = 'Pagina - 12' title = 'Pagina - 12'

View File

@ -80,7 +80,7 @@
<widget class="QLabel" name="label_6"> <widget class="QLabel" name="label_6">
<property name="text"> <property name="text">
<string>Regex tips: <string>Regex tips:
- The default regex - \[[\w]*\] - excludes genre tags of the form [tag], e.g., [Amazon Freebie] - The default regex - \[[\w ]*\] - excludes genre tags of the form [tag], e.g., [Amazon Freebie]
- A regex pattern of a single dot excludes all genre tags, generating no Genre Section</string> - A regex pattern of a single dot excludes all genre tags, generating no Genre Section</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">

View File

@ -57,7 +57,8 @@ def gui_catalog(fmt, title, dbspec, ids, out_file_name, sync, fmt_options,
setattr(opts,option, fmt_options[option]) setattr(opts,option, fmt_options[option])
# Fetch and run the plugin for fmt # Fetch and run the plugin for fmt
# Returns 0 if successful, 1 if no catalog built
plugin = plugin_for_catalog_format(fmt) plugin = plugin_for_catalog_format(fmt)
plugin.run(out_file_name, opts, db, notification=notification) return plugin.run(out_file_name, opts, db, notification=notification)

View File

@ -1394,6 +1394,11 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.status_bar.showMessage(_('Generating %s catalog...')%fmt) self.status_bar.showMessage(_('Generating %s catalog...')%fmt)
def catalog_generated(self, job): def catalog_generated(self, job):
if job.result:
# Search terms nulled catalog results
return error_dialog(self, _('No books found'),
_("No books to catalog\nCheck exclude tags"),
show=True)
if job.failed: if job.failed:
return self.job_exception(job) return self.job_exception(job)
id = self.library_view.model().add_catalog(job.catalog_file_path, job.catalog_title) id = self.library_view.model().add_catalog(job.catalog_file_path, job.catalog_title)

View File

@ -996,25 +996,21 @@ class EPUB_MOBI(CatalogPlugin):
# Return -1 if x<y # Return -1 if x<y
# Return 0 if x==y # Return 0 if x==y
# Return 1 if x>y # Return 1 if x>y
#print "x['author_sort']: %s y['author_sort']: %s" % (x['author_sort'],y['author_sort']) # Different authors - sort by author_sort
if x['author_sort'] > y['author_sort']: if x['author_sort'] > y['author_sort']:
return 1 return 1
elif x['author_sort'] < y['author_sort']: elif x['author_sort'] < y['author_sort']:
return -1 return -1
else: else:
# Authors equal # Same author
# Books w/o series go first if x['series'] != y['series']:
if x['series'] > y['series']: # Different series
return 1 if x['title_sort'].lstrip() > y['title_sort'].lstrip():
elif x['series'] < y['series']:
return -1
elif not x['series'] and not y['series']:
if x['title'] > y['title']:
return 1 return 1
else: else:
return -1 return -1
else: else:
# Both books have series # Same series
if x['series'] == y['series']: if x['series'] == y['series']:
if float(x['series_index']) > float(y['series_index']): if float(x['series_index']) > float(y['series_index']):
return 1 return 1
@ -1041,12 +1037,14 @@ class EPUB_MOBI(CatalogPlugin):
if False and self.verbose: if False and self.verbose:
self.opts.log.info("fetchBooksByAuthor(): %d books" % len(self.booksByAuthor)) self.opts.log.info("fetchBooksByAuthor(): %d books" % len(self.booksByAuthor))
self.opts.log.info(" %-40s %-20s %s" % ('title', 'series', 'series_index')) self.opts.log.info(" %-30s %-20s %s" % ('title', 'title_sort','series', 'series_index'))
for title in self.booksByAuthor: for title in self.booksByAuthor:
self.opts.log.info((u" %-40s %-20s %s" % \ self.opts.log.info((u" %-30s %-20s %-20s%5s " % \
(title['title'][0:40], (title['title'][:30],
title['series'][0:20] if title['series'] else '', title['series'][:20] if title['series'] else '',
title['series_index'])).encode('utf-8')) title['series_index'],
)).encode('utf-8'))
raise SystemExit
# Build the unique_authors set from existing data # Build the unique_authors set from existing data
authors = [(record['author'], record['author_sort']) for record in self.booksByAuthor] authors = [(record['author'], record['author_sort']) for record in self.booksByAuthor]
@ -1396,8 +1394,9 @@ class EPUB_MOBI(CatalogPlugin):
dtc = 0 dtc = 0
current_letter = "" current_letter = ""
current_author = "" current_author = ""
current_series = None
# Loop through books_by_author # Loop through booksByAuthor
book_count = 0 book_count = 0
for book in self.booksByAuthor: for book in self.booksByAuthor:
book_count += 1 book_count += 1
@ -1435,11 +1434,23 @@ class EPUB_MOBI(CatalogPlugin):
divTag.insert(dtc,pAuthorTag) divTag.insert(dtc,pAuthorTag)
dtc += 1 dtc += 1
# Check for series
if book['series'] and book['series'] != current_series:
# Start a new series
current_series = book['series']
pSeriesTag = Tag(soup,'p')
pSeriesTag['class'] = "series"
pSeriesTag.insert(0,NavigableString(self.NOT_READ_SYMBOL + book['series']))
divTag.insert(dtc,pSeriesTag)
dtc += 1
if current_series and not book['series']:
current_series = None
# Add books # Add books
pBookTag = Tag(soup, "p") pBookTag = Tag(soup, "p")
ptc = 0 ptc = 0
# Prefix book with read/unread symbol # book with read/unread symbol
if book['read']: if book['read']:
# check mark # check mark
pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL)) pBookTag.insert(ptc,NavigableString(self.READ_SYMBOL))
@ -1454,6 +1465,9 @@ class EPUB_MOBI(CatalogPlugin):
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'])))
# Use series, series index if avail else just title # Use series, series index if avail else just title
if current_series:
aTag.insert(0,escape(book['title'][len(book['series'])+1:]))
else:
aTag.insert(0,escape(book['title'])) aTag.insert(0,escape(book['title']))
pBookTag.insert(ptc, aTag) pBookTag.insert(ptc, aTag)
ptc += 1 ptc += 1
@ -1506,6 +1520,7 @@ class EPUB_MOBI(CatalogPlugin):
divTag.insert(dtc,pIndexTag) divTag.insert(dtc,pIndexTag)
dtc += 1 dtc += 1
current_author = None current_author = None
current_series = None
for new_entry in this_months_list: for new_entry in this_months_list:
if new_entry['author'] != current_author: if new_entry['author'] != current_author:
@ -1522,6 +1537,18 @@ class EPUB_MOBI(CatalogPlugin):
divTag.insert(dtc,pAuthorTag) divTag.insert(dtc,pAuthorTag)
dtc += 1 dtc += 1
# Check for series
if new_entry['series'] and new_entry['series'] != current_series:
# Start a new series
current_series = new_entry['series']
pSeriesTag = Tag(soup,'p')
pSeriesTag['class'] = "series"
pSeriesTag.insert(0,NavigableString(self.NOT_READ_SYMBOL + new_entry['series']))
divTag.insert(dtc,pSeriesTag)
dtc += 1
if current_series and not new_entry['series']:
current_series = None
# Add books # Add books
pBookTag = Tag(soup, "p") pBookTag = Tag(soup, "p")
ptc = 0 ptc = 0
@ -1540,6 +1567,9 @@ class EPUB_MOBI(CatalogPlugin):
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'])))
if current_series:
aTag.insert(0,escape(new_entry['title'][len(new_entry['series'])+1:]))
else:
aTag.insert(0,escape(new_entry['title'])) aTag.insert(0,escape(new_entry['title']))
pBookTag.insert(ptc, aTag) pBookTag.insert(ptc, aTag)
ptc += 1 ptc += 1
@ -1641,6 +1671,7 @@ class EPUB_MOBI(CatalogPlugin):
this_book['author_sort'] = book['author_sort'] this_book['author_sort'] = book['author_sort']
this_book['read'] = book['read'] this_book['read'] = book['read']
this_book['id'] = book['id'] this_book['id'] = book['id']
this_book['series'] = book['series']
normalized_tag = self.genre_tags_dict[friendly_tag] normalized_tag = self.genre_tags_dict[friendly_tag]
genre_tag_list = [key for genre in genre_list for key in genre] genre_tag_list = [key for genre in genre_list for key in genre]
if normalized_tag in genre_tag_list: if normalized_tag in genre_tag_list:
@ -2578,6 +2609,7 @@ class EPUB_MOBI(CatalogPlugin):
dtc = 0 dtc = 0
current_author = '' current_author = ''
current_series = None
for book in books: for book in books:
if book['author'] != current_author: if book['author'] != current_author:
# Start a new author with link # Start a new author with link
@ -2593,6 +2625,19 @@ class EPUB_MOBI(CatalogPlugin):
divTag.insert(dtc,pAuthorTag) divTag.insert(dtc,pAuthorTag)
dtc += 1 dtc += 1
# Check for series
if book['series'] and book['series'] != current_series:
# Start a new series
current_series = book['series']
pSeriesTag = Tag(soup,'p')
pSeriesTag['class'] = "series"
pSeriesTag.insert(0,NavigableString(self.NOT_READ_SYMBOL + book['series']))
divTag.insert(dtc,pSeriesTag)
dtc += 1
if current_series and not book['series']:
current_series = None
# Add books # Add books
pBookTag = Tag(soup, "p") pBookTag = Tag(soup, "p")
ptc = 0 ptc = 0
@ -2609,6 +2654,10 @@ class EPUB_MOBI(CatalogPlugin):
# Add the book title # Add the book title
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'])))
# Use series, series index if avail else just title
if current_series:
aTag.insert(0,escape(book['title'][len(book['series'])+1:]))
else:
aTag.insert(0,escape(book['title'])) aTag.insert(0,escape(book['title']))
pBookTag.insert(ptc, aTag) pBookTag.insert(ptc, aTag)
ptc += 1 ptc += 1
@ -2879,9 +2928,41 @@ class EPUB_MOBI(CatalogPlugin):
return char return char
def markdownComments(self, comments): def markdownComments(self, comments):
''' Convert random comment text to normalized, xml-legal block of <p>s''' '''
Convert random comment text to normalized, xml-legal block of <p>s
'plain text' returns as
<p>plain text</p>
comments = comments.replace('\r', '') 'plain text with <i>minimal</i> <b>markup</b>' returns as
<p>plain text with <i>minimal</i> <b>markup</b></p>
'<p>pre-formatted text</p> returns untouched
'A line of text\n\nFollowed by a line of text' returns as
<p>A line of text</p>
<p>Followed by a line of text</p>
'A line of text.\nA second line of text.\rA third line of text' returns as
<p>A line of text.<br />A second line of text.<br />A third line of text.</p>
'...end of a paragraph.Somehow the break was lost...' returns as
<p>...end of a paragraph.</p>
<p>Somehow the break was lost...</p>
Deprecated HTML returns as HTML via BeautifulSoup()
'''
# Explode lost CRs to \n\n
# Hackish - ignoring sentences ending or beginning in numbers to avoid
# confusion with decimal points.
for lost_cr in re.finditer('([a-z])([\.\?!])([A-Z])',comments):
comments = comments.replace(lost_cr.group(),
'%s%s\n\n%s' % (lost_cr.group(1),
lost_cr.group(2),
lost_cr.group(3)))
# Convert \n\n to <p>s
if re.search('\n\n', comments): if re.search('\n\n', comments):
soup = BeautifulSoup() soup = BeautifulSoup()
split_ps = comments.split('\n\n') split_ps = comments.split('\n\n')
@ -2891,7 +2972,11 @@ class EPUB_MOBI(CatalogPlugin):
pTag.insert(0,p) pTag.insert(0,p)
soup.insert(tsc,pTag) soup.insert(tsc,pTag)
tsc += 1 tsc += 1
else: comments = soup.renderContents()
# Convert solo returns to <br />
comments = re.sub('[\r\n]','<br />', comments)
soup = BeautifulSoup(comments) soup = BeautifulSoup(comments)
result = BeautifulSoup() result = BeautifulSoup()
@ -2924,7 +3009,6 @@ class EPUB_MOBI(CatalogPlugin):
ptc = 0 ptc = 0
# Clean up NavigableStrings for xml # Clean up NavigableStrings for xml
sub_tokens = list(token.contents) sub_tokens = list(token.contents)
sub_soup = BeautifulSoup()
for sub_token in sub_tokens: for sub_token in sub_tokens:
if type(sub_token) is NavigableString: if type(sub_token) is NavigableString:
sub_token.replaceWith(prepare_string_for_xml(sub_token)) sub_token.replaceWith(prepare_string_for_xml(sub_token))
@ -3001,6 +3085,12 @@ class EPUB_MOBI(CatalogPlugin):
'CLI' if opts.cli_environment else 'GUI')) 'CLI' if opts.cli_environment else 'GUI'))
if opts_dict['ids']: if opts_dict['ids']:
log(" Book count: %d" % len(opts_dict['ids'])) log(" Book count: %d" % len(opts_dict['ids']))
# If exclude_genre is blank, assume user wants all genre tags included
if opts.exclude_genre.strip() == '':
opts.exclude_genre = '\[^.\]'
log(" converting empty exclude_genre to '\[^.\]'")
# Display opts # Display opts
keys = opts_dict.keys() keys = opts_dict.keys()
keys.sort() keys.sort()