Merge from trunk

This commit is contained in:
Charles Haley 2011-01-16 10:40:42 +00:00
commit 04869f7f5d
15 changed files with 270 additions and 193 deletions

View file

@ -1,5 +1,5 @@
from calibre.web.feeds.recipes import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import BeautifulSoup
#from calibre.ebooks.BeautifulSoup import BeautifulSoup
from urllib import quote
class SportsIllustratedRecipe(BasicNewsRecipe) :
@ -91,7 +91,7 @@ def print_version(self, url) :
# expire : no idea what value to use
# All this comes from the Javascript function that redirects to the print version. It's called PT() and is defined in the file 48.js
def preprocess_html(self, soup):
'''def preprocess_html(self, soup):
header = soup.find('div', attrs = {'class' : 'siv_artheader'})
homeMadeSoup = BeautifulSoup('<html><head></head><body></body></html>')
body = homeMadeSoup.body
@ -115,4 +115,5 @@ def preprocess_html(self, soup):
body.append(para)
return homeMadeSoup
'''

View file

@ -33,6 +33,6 @@ class SNE(USBMS):
STORAGE_CARD_VOLUME_LABEL = 'SNE Storage Card'
EBOOK_DIR_MAIN = EBOOK_DIR_CARD_A = 'Books'
SUPPORTS_SUB_DIRS = True
SUPPORTS_SUB_DIRS = False

View file

@ -286,7 +286,6 @@ def convert(self, stream, options, file_ext, log,
try:
xml = self.generate_xml(stream.name)
except RtfInvalidCodeException, e:
raise
raise ValueError(_('This RTF file has a feature calibre does not '
'support. Convert it to HTML first and then try it.\n%s')%e)

View file

@ -226,10 +226,6 @@ def parse_rtf(self):
try:
return_value = process_tokens_obj.process_tokens()
except InvalidRtfException, msg:
try:
os.remove(self.__temp_file)
except OSError:
pass
#Check to see if the file is correctly encoded
encode_obj = default_encoding.DefaultEncoding(
in_file = self.__temp_file,
@ -241,14 +237,17 @@ def parse_rtf(self):
check_encoding_obj = check_encoding.CheckEncoding(
bug_handler = RtfInvalidCodeException,
)
enc = encode_obj.get_codepage()
if enc != 'mac_roman':
enc = 'cp' + enc
enc = 'cp' + encode_obj.get_codepage()
msg = 'Exception in token processing'
if check_encoding_obj.check_encoding(self.__file, enc):
file_name = self.__file if isinstance(self.__file, str) \
else self.__file.encode('utf-8')
msg = 'File %s does not appear to be correctly encoded.\n' % file_name
raise InvalidRtfException, msg
try:
os.remove(self.__temp_file)
except OSError:
pass
raise InvalidRtfException, msg
delete_info_obj = delete_info.DeleteInfo(
in_file = self.__temp_file,
copy = self.__copy,

View file

@ -74,9 +74,6 @@ def find_default_encoding(self):
if not self.__datafetched:
self._encoding()
self.__datafetched = True
if self.__platform == 'Macintosh':
code_page = self.__code_page
else:
code_page = 'ansicpg' + self.__code_page
return self.__platform, code_page, self.__default_num
@ -94,49 +91,60 @@ def get_platform(self):
def _encoding(self):
with open(self.__file, 'r') as read_obj:
cpfound = False
if not self.__fetchraw:
for line in read_obj:
self.__token_info = line[:16]
if self.__token_info == 'mi<mk<rtfhed-end':
break
if self.__token_info == 'cw<ri<ansi-codpg':
#cw<ri<ansi-codpg<nu<10000
self.__code_page = line[20:-1] if int(line[20:-1]) \
else '1252'
if self.__token_info == 'cw<ri<macintosh_':
self.__platform = 'Macintosh'
self.__code_page = 'mac_roman'
elif self.__token_info == 'cw<ri<pc________':
self.__platform = 'IBMPC'
self.__code_page = '437'
elif self.__token_info == 'cw<ri<pca_______':
self.__platform = 'OS/2'
self.__code_page = '850'
if self.__token_info == 'cw<ri<ansi-codpg' \
and int(line[20:-1]):
self.__code_page = line[20:-1]
if self.__token_info == 'cw<ri<deflt-font':
self.__default_num = line[20:-1]
cpfound = True
#cw<ri<deflt-font<nu<0
if self.__platform != 'Windows' and \
not cpfound:
if self.__platform == 'Macintosh':
self.__code_page = '10000'
elif self.__platform == 'IBMPC':
self.__code_page = '437'
elif self.__platform == 'OS/2':
self.__code_page = '850'
else:
fenc = re.compile(r'\\(mac|pc|ansi|pca)[\\ \{\}\t\n]+')
fenccp = re.compile(r'\\ansicpg(\d+)[\\ \{\}\t\n]+')
for line in read_obj:
if fenc.search(line):
enc = fenc.search(line).group(1)
if fenccp.search(line):
cp = fenccp.search(line).group(1)
if not int(cp):
self.__code_page = cp
cpfound = True
break
if fenc.search(line):
enc = fenc.search(line).group(1)
if enc == 'mac':
self.__code_page = 'mac_roman'
elif enc == 'pc':
self.__code_page = '437'
elif enc == 'pca':
self.__code_page = '850'
if self.__platform != 'Windows' and \
not cpfound:
if enc == 'mac':
self.__code_page = '10000'
elif enc == 'pc':
self.__code_page = '437'
elif enc == 'pca':
self.__code_page = '850'
# if __name__ == '__main__':
# encode_obj = DefaultEncoding(
# in_file = sys.argv[1],
# bug_handler = Exception,
# check_raw = True,
# )
# print encode_obj.get_codepage()
if __name__ == '__main__':
import sys
encode_obj = DefaultEncoding(
in_file = sys.argv[1],
bug_handler = Exception,
check_raw = True,
)
print encode_obj.get_codepage()

View file

@ -20,7 +20,7 @@
from calibre.ebooks.rtf2xml import copy
class DeleteInfo:
"""Delelet unecessary destination groups"""
"""Delete unecessary destination groups"""
def __init__(self,
in_file ,
bug_handler,
@ -31,17 +31,14 @@ def __init__(self,
self.__bug_handler = bug_handler
self.__copy = copy
self.__write_to = tempfile.mktemp()
self.__run_level = run_level
self.__initiate_allow()
self.__bracket_count= 0
self.__ob_count = 0
self.__cb_count = 0
# self.__after_asterisk = False
# self.__delete = 0
self.__initiate_allow()
self.__ob = 0
self.__write_cb = False
self.__run_level = run_level
self.__found_delete = False
# self.__list = False
def __initiate_allow(self):
"""
@ -57,6 +54,8 @@ def __initiate_allow(self):
'cw<an<annotation',
'cw<cm<comment___',
'cw<it<lovr-table',
# info table
'cw<di<company___',
# 'cw<ls<list______',
)
self.__not_allowable = (
@ -116,7 +115,6 @@ def __asterisk_func(self,line):
"""
# Test for {\*}, in which case don't enter
# delete state
# self.__after_asterisk = False # only enter this function once
self.__found_delete = True
if self.__token_info == 'cb<nu<clos-brack':
if self.__delete_count == self.__cb_count:
@ -128,7 +126,7 @@ def __asterisk_func(self,line):
# not sure what happens here!
# believe I have a '{\*}
if self.__run_level > 3:
msg = 'flag problem\n'
msg = 'Flag problem\n'
raise self.__bug_handler, msg
return True
elif self.__token_info in self.__allowable :
@ -173,8 +171,8 @@ def __list_func(self, line):
Return True for all control words.
Return False otherwise.
"""
if self.__delete_count == self.__cb_count and self.__token_info ==\
'cb<nu<clos-brack':
if self.__delete_count == self.__cb_count and \
self.__token_info == 'cb<nu<clos-brack':
self.__state = 'default'
if self.__write_cb:
self.__write_cb = False
@ -186,32 +184,24 @@ def __list_func(self, line):
return False
def delete_info(self):
"""Main method for handling other methods. Read one line in at
"""Main method for handling other methods. Read one line at
a time, and determine whether to print the line based on the state."""
with open(self.__file, 'r') as read_obj:
with open(self.__write_to, 'w') as self.__write_obj:
for line in read_obj:
#ob<nu<open-brack<0001
to_print = True
self.__token_info = line[:16]
if self.__token_info == 'ob<nu<open-brack':
self.__ob_count = line[-5:-1]
if self.__token_info == 'cb<nu<clos-brack':
self.__cb_count = line[-5:-1]
# Get action to perform
action = self.__state_dict.get(self.__state)
if not action:
sys.stderr.write(_('No action in dictionary state is "%s" \n')
sys.stderr.write('No action in dictionary state is "%s" \n'
% self.__state)
to_print = action(line)
# if self.__after_asterisk:
# to_print = self.__asterisk_func(line)
# elif self.__list:
# self.__in_list_func(line)
# elif self.__delete:
# to_print = self.__delete_func(line)
# else:
# to_print = self.__default_func(line)
if to_print:
# Print if allowed by action
if action(line):
self.__write_obj.write(line)
copy_obj = copy.Copy(bug_handler = self.__bug_handler)
if self.__copy:

View file

@ -15,8 +15,10 @@
# #
# #
#########################################################################
import sys, os, tempfile
import sys, os, tempfile, re
from calibre.ebooks.rtf2xml import copy
class Info:
"""
Make tags for document-information
@ -42,12 +44,14 @@ def __init__(self,
self.__copy = copy
self.__run_level = run_level
self.__write_to = tempfile.mktemp()
def __initiate_values(self):
"""
Initiate all values.
"""
self.__text_string = ''
self.__state = 'before_info_table'
self.rmspace = re.compile(r'\s+')
self.__state_dict = {
'before_info_table': self.__before_info_table_func,
'after_info_table': self.__after_info_table_func,
@ -58,27 +62,49 @@ def __initiate_values(self):
self.__info_table_dict = {
'cw<di<title_____' : (self.__found_tag_with_text_func, 'title'),
'cw<di<author____' : (self.__found_tag_with_text_func, 'author'),
'cw<di<operator__' : (self.__found_tag_with_text_func, 'operator'),
'cw<di<manager___' : (self.__found_tag_with_text_func, 'manager'),
'cw<di<company___' : (self.__found_tag_with_text_func, 'company'),
'cw<di<keywords__' : (self.__found_tag_with_text_func, 'keywords'),
'cw<di<category__' : (self.__found_tag_with_text_func, 'category'),
'cw<di<doc-notes_' : (self.__found_tag_with_text_func, 'doc-notes'),
'cw<di<subject___' : (self.__found_tag_with_text_func, 'subject'),
'cw<di<operator__' : (self.__found_tag_with_text_func, 'operator'),
'cw<di<linkbase__' : (self.__found_tag_with_text_func, 'hyperlink-base'),
'cw<di<create-tim' : (self.__found_tag_with_tokens_func, 'creation-time'),
'cw<di<revis-time' : (self.__found_tag_with_tokens_func, 'revision-time'),
'cw<di<edit-time_' : (self.__single_field_func, 'editing-time'),
'cw<di<revis-time' : (self.__found_tag_with_tokens_func, 'revision-time'),
'cw<di<edit-time_' : (self.__found_tag_with_tokens_func, 'editing-time'),
'cw<di<print-time' : (self.__found_tag_with_tokens_func, 'printing-time'),
'cw<di<backuptime' : (self.__found_tag_with_tokens_func, 'backup-time'),
'cw<di<num-of-wor' : (self.__single_field_func, 'number-of-words'),
'cw<di<num-of-chr' : (self.__single_field_func, 'number-of-characters'),
'cw<di<numofchrws' : (self.__single_field_func, 'number-of-characters-without-space'),
'cw<di<num-of-pag' : (self.__single_field_func, 'number-of-pages'),
'cw<di<version___' : (self.__single_field_func, 'version'),
'cw<di<intern-ver' : (self.__single_field_func, 'internal-version-number'),
'cw<di<internalID' : (self.__single_field_func, 'internal-id-number'),
}
self.__token_dict = {
'year______' : 'year',
'month_____' : 'month',
'day_______' : 'day',
'minute____' : 'minute',
'second____' : 'second',
'revis-time' : 'revision-time',
'create-tim' : 'creation-time',
'edit-time_' : 'editing-time',
'print-time' : 'printing-time',
'backuptime' : 'backup-time',
'num-of-wor' : 'number-of-words',
'num-of-chr' : 'number-of-characters',
'numofchrws' : 'number-of-characters-without-space',
'num-of-pag' : 'number-of-pages',
'version___' : 'version',
'intern-ver' : 'internal-version-number',
'internalID' : 'internal-id-number',
}
def __before_info_table_func(self, line):
"""
Required:
@ -92,6 +118,7 @@ def __before_info_table_func(self, line):
if self.__token_info == 'mi<mk<doc-in-beg':
self.__state = 'in_info_table'
self.__write_obj.write(line)
def __in_info_table_func(self, line):
"""
Requires:
@ -112,6 +139,7 @@ def __in_info_table_func(self, line):
action(line, tag)
else:
self.__write_obj.write(line)
def __found_tag_with_text_func(self, line, tag):
"""
Requires:
@ -126,6 +154,7 @@ def __found_tag_with_text_func(self, line, tag):
"""
self.__tag = tag
self.__state = 'collect_text'
def __collect_text_func(self, line):
"""
Requires:
@ -139,14 +168,17 @@ def __collect_text_func(self, line):
"""
if self.__token_info == 'mi<mk<docinf-end':
self.__state = 'in_info_table'
self.__write_obj.write(
'mi<tg<open______<%s\n'
'tx<nu<__________<%s\n'
'mi<tg<close_____<%s\n' % (self.__tag, self.__text_string, self.__tag)
)
#Don't print empty tags
if len(self.rmspace.sub('',self.__text_string)):
self.__write_obj.write(
'mi<tg<open______<%s\n'
'tx<nu<__________<%s\n'
'mi<tg<close_____<%s\n' % (self.__tag, self.__text_string, self.__tag)
)
self.__text_string = ''
elif line[0:2] == 'tx':
self.__text_string += line[17:-1]
def __found_tag_with_tokens_func(self, line, tag):
"""
Requires:
@ -163,6 +195,7 @@ def __found_tag_with_tokens_func(self, line, tag):
self.__state = 'collect_tokens'
self.__text_string = 'mi<tg<empty-att_<%s' % tag
#mi<tg<empty-att_<page-definition<margin>33\n
def __collect_tokens_func(self, line):
"""
Requires:
@ -194,18 +227,19 @@ def __collect_tokens_func(self, line):
att = line[6:16]
value = line[20:-1]
att_changed = self.__token_dict.get(att)
if att_changed == None:
if att_changed is None:
if self.__run_level > 3:
msg = 'no dictionary match for %s\n' % att
msg = 'No dictionary match for %s\n' % att
raise self.__bug_handler, msg
else:
self.__text_string += '<%s>%s' % (att_changed, value)
def __single_field_func(self, line, tag):
value = line[20:-1]
self.__write_obj.write(
'mi<tg<empty-att_<%s'
'<%s>%s\n' % (tag, tag, value)
'mi<tg<empty-att_<%s<%s>%s\n' % (tag, tag, value)
)
def __after_info_table_func(self, line):
"""
Requires:
@ -217,6 +251,7 @@ def __after_info_table_func(self, line):
the file.
"""
self.__write_obj.write(line)
def fix_info(self):
"""
Requires:
@ -234,20 +269,15 @@ def fix_info(self):
information table, simply write the line to the output file.
"""
self.__initiate_values()
read_obj = open(self.__file, 'r')
self.__write_obj = open(self.__write_to, 'w')
line_to_read = 1
while line_to_read:
line_to_read = read_obj.readline()
line = line_to_read
self.__token_info = line[:16]
action = self.__state_dict.get(self.__state)
if action == None:
sys.stderr.write('no no matching state in module styles.py\n')
sys.stderr.write(self.__state + '\n')
action(line)
read_obj.close()
self.__write_obj.close()
with open(self.__file, 'r') as read_obj:
with open(self.__write_to, 'wb') as self.__write_obj:
for line in read_obj:
self.__token_info = line[:16]
action = self.__state_dict.get(self.__state)
if action is None:
sys.stderr.write('No matching state in module styles.py\n')
sys.stderr.write(self.__state + '\n')
action(line)
copy_obj = copy.Copy(bug_handler = self.__bug_handler)
if self.__copy:
copy_obj.copy_file(self.__write_to, "info.data")

View file

@ -70,7 +70,7 @@ def initiate_token_dict(self):
';' : ('mc', ';', self.ms_sub_func),
# this must be wrong
'-' : ('mc', '-', self.ms_sub_func),
'line' : ('mi', 'hardline-break', self.hardline_func), #calibre
'line' : ('mi', 'hardline-break', self.direct_conv_func), #calibre
# misc => ml
'*' : ('ml', 'asterisk__', self.default_func),
':' : ('ml', 'colon_____', self.default_func),
@ -78,7 +78,6 @@ def initiate_token_dict(self):
'backslash' : ('nu', '\\', self.text_func),
'ob' : ('nu', '{', self.text_func),
'cb' : ('nu', '}', self.text_func),
#'line' : ('nu', ' ', self.text_func), calibre
# paragraph formatting => pf
'page' : ('pf', 'page-break', self.default_func),
'par' : ('pf', 'par-end___', self.default_func),
@ -231,11 +230,15 @@ def initiate_token_dict(self):
'trhdr' : ('tb', 'row-header', self.default_func),
# preamble => pr
# document information => di
# TODO integrate \userprops
'info' : ('di', 'doc-info__', self.default_func),
'title' : ('di', 'title_____', self.default_func),
'author' : ('di', 'author____', self.default_func),
'operator' : ('di', 'operator__', self.default_func),
'title' : ('di', 'title_____', self.default_func),
'manager' : ('di', 'manager___', self.default_func),
'company' : ('di', 'company___', self.default_func),
'keywords' : ('di', 'keywords__', self.default_func),
'category' : ('di', 'category__', self.default_func),
'doccomm' : ('di', 'doc-notes_', self.default_func),
'comment' : ('di', 'doc-notes_', self.default_func),
'subject' : ('di', 'subject___', self.default_func),
@ -244,11 +247,19 @@ def initiate_token_dict(self):
'mo' : ('di', 'month_____', self.default_func),
'dy' : ('di', 'day_______', self.default_func),
'min' : ('di', 'minute____', self.default_func),
'sec' : ('di', 'second____', self.default_func),
'revtim' : ('di', 'revis-time', self.default_func),
'edmins' : ('di', 'edit-time_', self.default_func),
'printim' : ('di', 'print-time', self.default_func),
'buptim' : ('di', 'backuptime', self.default_func),
'nofwords' : ('di', 'num-of-wor', self.default_func),
'nofchars' : ('di', 'num-of-chr', self.default_func),
'nofcharsws' : ('di', 'numofchrws', self.default_func),
'nofpages' : ('di', 'num-of-pag', self.default_func),
'edmins' : ('di', 'edit-time_', self.default_func),
'version' : ('di', 'version___', self.default_func),
'vern' : ('di', 'intern-ver', self.default_func),
'hlinkbase' : ('di', 'linkbase__', self.default_func),
'id' : ('di', 'internalID', self.default_func),
# headers and footers => hf
'headerf' : ('hf', 'head-first', self.default_func),
'headerl' : ('hf', 'head-left_', self.default_func),
@ -605,7 +616,7 @@ def __ms_hex_func(self, pre, token, num):
def ms_sub_func(self, pre, token, num):
return 'tx<mc<__________<%s\n' % token
def hardline_func(self, pre, token, num):
def direct_conv_func(self, pre, token, num):
return 'mi<tg<empty_____<%s\n' % token
def default_func(self, pre, token, num):

View file

@ -27,11 +27,13 @@ def __init__(self,
bug_handler,
copy = None,
run_level = 1,
):
# out_file = None,
):
self.__file = in_file
self.__bug_handler = bug_handler
self.__copy = copy
self.__write_to = tempfile.mktemp()
# self.__out_file = out_file
self.__compile_expressions()
#variables
self.__uc_char = 0
@ -113,6 +115,8 @@ def __unicode_process(self, token):
def __sub_reg_split(self,input_file):
input_file = self.__replace_spchar.mreplace(input_file)
# this is for older RTF
input_file = self.__par_exp.sub('\n\\par \n', input_file)
input_file = self.__ms_hex_exp.sub("\\mshex0\g<1> ", input_file)
input_file = self.__utf_ud.sub("\\{\\uc0 \g<1>\\}", input_file)
#remove \n in bin data
@ -127,7 +131,7 @@ def __sub_reg_split(self,input_file):
# this is for older RTF
#line = re.sub(self.__par_exp, '\\par ', line)
#return filter(lambda x: len(x) > 0, \
#(self.__remove_line.sub('', x) for x in tokens))
#(self.__remove_line.sub('', x) for x in tokens))
def __compile_expressions(self):
SIMPLE_RPL = {
@ -153,8 +157,6 @@ def __compile_expressions(self):
# put a backslash in front of to eliminate special cases and
# make processing easier
"}": "\\}",
# this is for older RTF
r'\\$': '\\par ',
}
self.__replace_spchar = MReplace(SIMPLE_RPL)
#add ;? in case of char following \u
@ -168,10 +170,12 @@ def __compile_expressions(self):
#why keep backslash whereas \is replaced before?
#remove \n from endline char
self.__splitexp = re.compile(r"(\\[{}]|\n|\\[^\s\\{}&]+(?:[ \t\r\f\v])?)")
#this is for old RTF
self.__par_exp = re.compile(r'\\\n+')
# self.__par_exp = re.compile(r'\\$')
#self.__bin_exp = re.compile(r"\\bin(-?\d{1,8}) {0,1}")
#self.__utf_exp = re.compile(r"^\\u(-?\d{3,6})")
#self.__splitexp = re.compile(r"(\\[\\{}]|{|}|\n|\\[^\s\\{}&]+(?:\s)?)")
#self.__par_exp = re.compile(r'\\$')
#self.__remove_line = re.compile(r'\n+')
#self.__mixed_exp = re.compile(r"(\\[a-zA-Z]+\d+)(\D+)")
##self.num_exp = re.compile(r"(\*|:|[a-zA-Z]+)(.*)")
@ -199,7 +203,24 @@ def tokenize(self):
copy_obj = copy.Copy(bug_handler = self.__bug_handler)
if self.__copy:
copy_obj.copy_file(self.__write_to, "tokenize.data")
# if self.__out_file:
# self.__file = self.__out_file
copy_obj.rename(self.__write_to, self.__file)
os.remove(self.__write_to)
#self.__special_tokens = [ '_', '~', "'", '{', '}' ]
#self.__special_tokens = [ '_', '~', "'", '{', '}' ]
# import sys
# def main(args=sys.argv):
# if len(args) < 1:
# print 'No file'
# return
# file = 'data_tokens.txt'
# if len(args) == 3:
# file = args[2]
# to = Tokenize(args[1], Exception, out_file = file)
# to.tokenize()
# if __name__ == '__main__':
# sys.exit(main())

View file

@ -505,7 +505,7 @@ def __init__(self, title=_('Choose Files'),
self.selected_files = []
if mode == QFileDialog.AnyFile:
f = unicode(QFileDialog.getSaveFileName(parent, title, initial_dir, ftext, ""))
if f and os.path.exists(f):
if f:
self.selected_files.append(f)
elif mode == QFileDialog.ExistingFile:
f = unicode(QFileDialog.getOpenFileName(parent, title, initial_dir, ftext, ""))

View file

@ -28,7 +28,7 @@ def generate_catalog(self):
if not ids:
return error_dialog(self.gui, _('No books selected'),
_('No books selected to generate catalog for'),
_('No books selected for catalog generation'),
show=True)
db = self.gui.library_view.model().db
@ -55,9 +55,9 @@ def generate_catalog(self):
def catalog_generated(self, job):
if job.result:
# Search terms nulled catalog results
return error_dialog(self.gui, _('No books found'),
_("No books to catalog\nCheck job details"),
# Error during catalog generation
return error_dialog(self.gui, _('Catalog generation terminated'),
job.result,
show=True)
if job.failed:
return self.gui.job_exception(job)

View file

@ -1144,7 +1144,9 @@ def fset(self, val):
def error(self):
def fget(self):
return self.__error
return property(fget=fget)
def fset(self, val):
self.__error = val
return property(fget=fget,fset=fset)
@dynamic_property
def generateForKindle(self):
def fget(self):
@ -1411,6 +1413,88 @@ def copyResources(self):
except:
pass
def fetchBooksByAuthor(self):
'''
Generate a list of titles sorted by author from the database
return = Success
'''
self.updateProgressFullStep("Sorting database")
'''
# Sort titles case-insensitive, by author
self.booksByAuthor = sorted(self.booksByTitle,
key=lambda x:(x['author_sort'].upper(), x['author_sort'].upper()))
'''
self.booksByAuthor = list(self.booksByTitle)
self.booksByAuthor.sort(self.author_compare)
if False and self.verbose:
self.opts.log.info("fetchBooksByAuthor(): %d books" % len(self.booksByAuthor))
self.opts.log.info(" %-30s %-20s %s" % ('title', 'series', 'series_index'))
for title in self.booksByAuthor:
self.opts.log.info((u" %-30s %-20s%5s " % \
(title['title'][:30],
title['series'][:20] if title['series'] else '',
title['series_index'],
)).encode('utf-8'))
raise SystemExit
# Build the unique_authors set from existing data
authors = [(record['author'], record['author_sort'].capitalize()) for record in self.booksByAuthor]
# authors[] contains a list of all book authors, with multiple entries for multiple books by author
# authors[]: (([0]:friendly [1]:sort))
# unique_authors[]: (([0]:friendly [1]:sort [2]:book_count))
books_by_current_author = 0
current_author = authors[0]
multiple_authors = False
unique_authors = []
for (i,author) in enumerate(authors):
if author != current_author:
# Note that current_author and author are tuples: (friendly, sort)
multiple_authors = True
if author != current_author and i:
# Warn, exit if friendly matches previous, but sort doesn't
if author[0] == current_author[0]:
error_msg = _('''
\n*** Metadata error ***
Inconsistent Author Sort values for Author '{0}', unable to continue building catalog.
Select all books by '{0}', apply correct Author Sort value in Edit Metadata dialog,
then rebuild the catalog.\n''').format(author[0])
self.opts.log.warn(error_msg)
self.error = error_msg
return False
# New author, save the previous author/sort/count
unique_authors.append((current_author[0], icu_title(current_author[1]),
books_by_current_author))
current_author = author
books_by_current_author = 1
elif i==0 and len(authors) == 1:
# Allow for single-book lists
unique_authors.append((current_author[0], icu_title(current_author[1]),
books_by_current_author))
else:
books_by_current_author += 1
else:
# Add final author to list or single-author dataset
if (current_author == author and len(authors) > 1) or not multiple_authors:
unique_authors.append((current_author[0], icu_title(current_author[1]),
books_by_current_author))
if False and self.verbose:
self.opts.log.info("\nfetchBooksByauthor(): %d unique authors" % len(unique_authors))
for author in unique_authors:
self.opts.log.info((u" %-50s %-25s %2d" % (author[0][0:45], author[1][0:20],
author[2])).encode('utf-8'))
self.authors = unique_authors
return True
def fetchBooksByTitle(self):
self.updateProgressFullStep("Fetching database")
@ -1562,90 +1646,9 @@ def fetchBooksByTitle(self):
title['title_sort'][0:40])).decode('mac-roman'))
return True
else:
self.error = _("No books found to catalog.\nCheck 'Excluded books' criteria in E-book options.")
return False
def fetchBooksByAuthor(self):
'''
Generate a list of titles sorted by author from the database
return = Success
'''
self.updateProgressFullStep("Sorting database")
'''
# Sort titles case-insensitive, by author
self.booksByAuthor = sorted(self.booksByTitle,
key=lambda x:(x['author_sort'].upper(), x['author_sort'].upper()))
'''
self.booksByAuthor = list(self.booksByTitle)
self.booksByAuthor.sort(self.author_compare)
if False and self.verbose:
self.opts.log.info("fetchBooksByAuthor(): %d books" % len(self.booksByAuthor))
self.opts.log.info(" %-30s %-20s %s" % ('title', 'series', 'series_index'))
for title in self.booksByAuthor:
self.opts.log.info((u" %-30s %-20s%5s " % \
(title['title'][:30],
title['series'][:20] if title['series'] else '',
title['series_index'],
)).encode('utf-8'))
raise SystemExit
# Build the unique_authors set from existing data
authors = [(record['author'], record['author_sort'].capitalize()) for record in self.booksByAuthor]
# authors[] contains a list of all book authors, with multiple entries for multiple books by author
# authors[]: (([0]:friendly [1]:sort))
# unique_authors[]: (([0]:friendly [1]:sort [2]:book_count))
books_by_current_author = 0
current_author = authors[0]
multiple_authors = False
unique_authors = []
for (i,author) in enumerate(authors):
if author != current_author:
# Note that current_author and author are tuples: (friendly, sort)
multiple_authors = True
if author != current_author and i:
# Warn, exit if friendly matches previous, but sort doesn't
if author[0] == current_author[0]:
error_msg = _('''
\n*** Metadata error ***
Inconsistent Author Sort values for Author '{0}', unable to continue building catalog.
Select all books by '{0}', apply correct Author Sort value in Edit Metadata dialog,
then rebuild the catalog.
*** Terminating catalog generation ***\n''').format(author[0])
self.opts.log.warn(error_msg)
return False
# New author, save the previous author/sort/count
unique_authors.append((current_author[0], icu_title(current_author[1]),
books_by_current_author))
current_author = author
books_by_current_author = 1
elif i==0 and len(authors) == 1:
# Allow for single-book lists
unique_authors.append((current_author[0], icu_title(current_author[1]),
books_by_current_author))
else:
books_by_current_author += 1
else:
# Add final author to list or single-author dataset
if (current_author == author and len(authors) > 1) or not multiple_authors:
unique_authors.append((current_author[0], icu_title(current_author[1]),
books_by_current_author))
if False and self.verbose:
self.opts.log.info("\nfetchBooksByauthor(): %d unique authors" % len(unique_authors))
for author in unique_authors:
self.opts.log.info((u" %-50s %-25s %2d" % (author[0][0:45], author[1][0:20],
author[2])).encode('utf-8'))
self.authors = unique_authors
return True
def fetchBookmarks(self):
'''
Collect bookmarks for catalog entries
@ -5069,6 +5072,8 @@ def run(self, path_to_output, opts, db, notification=DummyReporter()):
abort_after_input_dump=False)
plumber.merge_ui_recommendations(recommendations)
plumber.run()
return 0
# returns to gui2.actions.catalog:catalog_generated()
return None
else:
return 1
# returns to gui2.actions.catalog:catalog_generated()
return catalog.error

View file

@ -693,8 +693,12 @@ def command_catalog(args, dbpath):
}
with plugin:
plugin.run(args[1], opts, get_db(dbpath, opts))
return 0
ret = plugin.run(args[1], opts, get_db(dbpath, opts))
if ret is None:
ret = 0
else:
ret = 1
return ret
# end of GR additions

View file

@ -690,10 +690,10 @@ def get_metadata(self, idx, index_is_id=False, get_cover=False):
mi = Metadata(None)
aut_list = row[fm['au_map']]
if not aut_list:
aut_list = []
if aut_list:
aut_list = [p.split(':::') for p in aut_list.split(':#:') if p]
else:
aut_list = [p.split(':::') for p in aut_list.split(':#:')]
aut_list = []
aum = []
aus = {}
for (author, author_sort) in aut_list:

View file

@ -437,6 +437,15 @@ My antivirus program claims |app| is a virus/trojan?
Your antivirus program is wrong. |app| is a completely open source product. You can actually browse the source code yourself (or hire someone to do it for you) to verify that it is not a virus. Please report the false identification to whatever company you buy your antivirus software from. If the antivirus program is preventing you from downloading/installing |app|, disable it temporarily, install |app| and then re-enable it.
How do I backup |app|?
~~~~~~~~~~~~~~~~~~~~~~~~~~~
The most important thing to backup is the |app| library folder, that contains all your books and metadata. This is the folder you chose for your |app| library when you ran |app| for the first time. You can get the path to the library folder by clicking the |app| icon on the main toolbar. You must backup this complete folder with all its files and sub-folders.
You can switch |app| to using a backed up library folder by simply clicking the |app| icon on the toolbar and choosing your backup library folder.
If you want to backup the |app| configuration/plugins, you have to backup the config directory. You can find this config directory via :guilabel:`Preferences->Miscellaneous`. Note that restoring configuration directories is not officially supported, but should work in most cases. Just copy the contents of the backup directory into the current configuration directory to restore.
How do I use purchased EPUB books with |app|?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Most purchased EPUB books have `DRM <http://wiki.mobileread.com/wiki/DRM>`_. This prevents |app| from opening them. You can still use |app| to store and transfer them to your e-book reader. First, you must authorize your reader on a windows machine with Adobe Digital Editions. Once this is done, EPUB books transferred with |app| will work fine on your reader. When you purchase an epub book from a website, you will get an ".acsm" file. This file should be opened with Adobe Digital Editions, which will then download the actual ".epub" e-book. The e-book file will be stored in the folder "My Digital Editions", from where you can add it to |app|.