Sync to trunk.

This commit is contained in:
John Schember 2011-04-18 06:56:53 -04:00
commit 66beba7708
15 changed files with 155 additions and 42 deletions

View File

@ -201,8 +201,9 @@ class ITUNES(DriverBase):
# 0x1294 iPhone 3GS
# 0x1297 iPhone 4
# 0x129a iPad
# 0x12a2 iPad2
VENDOR_ID = [0x05ac]
PRODUCT_ID = [0x1292,0x1293,0x1294,0x1297,0x1299,0x129a]
PRODUCT_ID = [0x1292,0x1293,0x1294,0x1297,0x1299,0x129a,0x12a2]
BCD = [0x01]
# Plugboard ID
@ -421,7 +422,7 @@ class ITUNES(DriverBase):
cached_books[this_book.path] = {
'title':book.name(),
'author':[book.artist()],
'author':book.artist().split(' & '),
'lib_book':library_books[this_book.path] if this_book.path in library_books else None,
'dev_book':book,
'uuid': book.composer()
@ -459,7 +460,7 @@ class ITUNES(DriverBase):
cached_books[this_book.path] = {
'title':book.Name,
'author':book.Artist,
'author':book.artist().split(' & '),
'lib_book':library_books[this_book.path] if this_book.path in library_books else None,
'uuid': book.Composer,
'format': 'pdf' if book.KindAsString.startswith('PDF') else 'epub'
@ -1021,7 +1022,9 @@ class ITUNES(DriverBase):
if isosx:
for (i,file) in enumerate(files):
format = file.rpartition('.')[2].lower()
path = self.path_template % (metadata[i].title, metadata[i].author[0],format)
path = self.path_template % (metadata[i].title,
authors_to_string(metadata[i].authors),
format)
self._remove_existing_copy(path, metadata[i])
fpath = self._get_fpath(file, metadata[i], format, update_md=True)
db_added, lb_added = self._add_new_copy(fpath, metadata[i])
@ -1034,9 +1037,11 @@ class ITUNES(DriverBase):
if DEBUG:
self.log.info("ITUNES.upload_books()")
self.log.info(" adding '%s' by '%s' uuid:%s to self.cached_books" %
( metadata[i].title, metadata[i].author, metadata[i].uuid))
(metadata[i].title,
authors_to_string(metadata[i].authors),
metadata[i].uuid))
self.cached_books[this_book.path] = {
'author': metadata[i].author,
'author': authors_to_string(metadata[i].authors),
'dev_book': db_added,
'format': format,
'lib_book': lb_added,
@ -1055,7 +1060,9 @@ class ITUNES(DriverBase):
for (i,file) in enumerate(files):
format = file.rpartition('.')[2].lower()
path = self.path_template % (metadata[i].title, metadata[i].author[0],format)
path = self.path_template % (metadata[i].title,
authors_to_string(metadata[i].authors),
format)
self._remove_existing_copy(path, metadata[i])
fpath = self._get_fpath(file, metadata[i],format, update_md=True)
db_added, lb_added = self._add_new_copy(fpath, metadata[i])
@ -1075,9 +1082,11 @@ class ITUNES(DriverBase):
if DEBUG:
self.log.info("ITUNES.upload_books()")
self.log.info(" adding '%s' by '%s' uuid:%s to self.cached_books" %
( metadata[i].title, metadata[i].author, metadata[i].uuid))
(metadata[i].title,
authors_to_string(metadata[i].authors),
metadata[i].uuid))
self.cached_books[this_book.path] = {
'author': metadata[i].author[0],
'author': authors_to_string(metadata[i].authors),
'dev_book': db_added,
'format': format,
'lib_book': lb_added,
@ -1190,7 +1199,7 @@ class ITUNES(DriverBase):
base_fn = base_fn.rpartition('.')[0]
db_added = self._find_device_book(
{ 'title': base_fn if format == 'pdf' else metadata.title,
'author': metadata.authors[0],
'author': authors_to_string(metadata.authors),
'uuid': metadata.uuid,
'format': format})
return db_added
@ -1255,7 +1264,7 @@ class ITUNES(DriverBase):
base_fn = base_fn.rpartition('.')[0]
added = self._find_library_book(
{ 'title': base_fn if format == 'pdf' else metadata.title,
'author': metadata.author[0],
'author': authors_to_string(metadata.authors),
'uuid': metadata.uuid,
'format': format})
return added
@ -1314,7 +1323,7 @@ class ITUNES(DriverBase):
with open(metadata.cover,'r+b') as cd:
cover_data = cd.read()
except:
self.problem_titles.append("'%s' by %s" % (metadata.title, metadata.author[0]))
self.problem_titles.append("'%s' by %s" % (metadata.title, authors_to_string(metadata.authors)))
self.log.error(" error scaling '%s' for '%s'" % (metadata.cover,metadata.title))
import traceback
@ -1389,7 +1398,7 @@ class ITUNES(DriverBase):
thumb_path = path.rpartition('.')[0] + '.jpg'
zfw.writestr(thumb_path, thumb)
except:
self.problem_titles.append("'%s' by %s" % (metadata.title, metadata.author[0]))
self.problem_titles.append("'%s' by %s" % (metadata.title, authors_to_string(metadata.authors)))
self.log.error(" error converting '%s' to thumb for '%s'" % (metadata.cover,metadata.title))
finally:
try:
@ -1407,7 +1416,7 @@ class ITUNES(DriverBase):
if DEBUG:
self.log.info(" ITUNES._create_new_book()")
this_book = Book(metadata.title, authors_to_string(metadata.author))
this_book = Book(metadata.title, authors_to_string(metadata.authors))
this_book.datetime = time.gmtime()
this_book.db_id = None
this_book.device_collections = []
@ -2451,7 +2460,7 @@ class ITUNES(DriverBase):
for book in self.cached_books:
if self.cached_books[book]['uuid'] == metadata.uuid or \
(self.cached_books[book]['title'] == metadata.title and \
self.cached_books[book]['author'] == metadata.authors[0]):
self.cached_books[book]['author'] == authors_to_string(metadata.authors)):
self.update_list.append(self.cached_books[book])
self._remove_from_device(self.cached_books[book])
if DEBUG:
@ -2470,7 +2479,7 @@ class ITUNES(DriverBase):
for book in self.cached_books:
if self.cached_books[book]['uuid'] == metadata.uuid or \
(self.cached_books[book]['title'] == metadata.title and \
self.cached_books[book]['author'] == metadata.authors[0]):
self.cached_books[book]['author'] == authors_to_string(metadata.authors)):
self.update_list.append(self.cached_books[book])
self._remove_from_iTunes(self.cached_books[book])
if DEBUG:
@ -2939,13 +2948,13 @@ class ITUNES(DriverBase):
def _xform_metadata_via_plugboard(self, book, format):
''' Transform book metadata from plugboard templates '''
if DEBUG:
self.log.info(" ITUNES._xform_metadata_via_plugboard()")
self.log.info(" ITUNES._xform_metadata_via_plugboard()")
if self.plugboard_func:
pb = self.plugboard_func(self.DEVICE_PLUGBOARD_NAME, format, self.plugboards)
newmi = book.deepcopy_metadata()
newmi.template_to_attribute(book, pb)
if DEBUG:
if pb is not None and DEBUG:
self.log.info(" transforming %s using %s:" % (format, pb))
self.log.info(" title: %s %s" % (book.title, ">>> %s" %
newmi.title if book.title != newmi.title else ''))
@ -3062,7 +3071,7 @@ class ITUNES_ASYNC(ITUNES):
cached_books[this_book.path] = {
'title':library_books[book].name(),
'author':[library_books[book].artist()],
'author':library_books[book].artist().split(' & '),
'lib_book':library_books[book],
'dev_book':None,
'uuid': library_books[book].composer(),
@ -3102,7 +3111,7 @@ class ITUNES_ASYNC(ITUNES):
cached_books[this_book.path] = {
'title':library_books[book].Name,
'author':library_books[book].Artist,
'author':library_books[book].Artist.split(' & '),
'lib_book':library_books[book],
'uuid': library_books[book].Composer,
'format': format
@ -3288,7 +3297,7 @@ class Book(Metadata):
See ebooks.metadata.book.base
'''
def __init__(self,title,author):
Metadata.__init__(self, title, authors=[author])
Metadata.__init__(self, title, authors=author.split(' & '))
@property
def title_sorter(self):

View File

@ -52,6 +52,9 @@ class CHMInput(InputFormatPlugin):
metadata = get_metadata_from_reader(self._chm_reader)
self._chm_reader.CloseCHM()
#print tdir
#from calibre import ipython
#ipython()
odi = options.debug_pipeline
options.debug_pipeline = None

View File

@ -147,7 +147,8 @@ class CHMReader(CHMFile):
if self.hhc_path == '.hhc' and self.hhc_path not in files:
from calibre import walk
for x in walk(output_dir):
if os.path.basename(x).lower() in ('index.htm', 'index.html'):
if os.path.basename(x).lower() in ('index.htm', 'index.html',
'contents.htm', 'contents.html'):
self.hhc_path = os.path.relpath(x, output_dir)
break

View File

@ -17,6 +17,7 @@
#define BUFFER 6000
#define MIN(x, y) ( ((x) < (y)) ? (x) : (y) )
#define MAX(x, y) ( ((x) > (y)) ? (x) : (y) )
typedef unsigned short int Byte;
typedef struct {
@ -53,7 +54,7 @@ cpalmdoc_decompress(PyObject *self, PyObject *args) {
// Map chars to bytes
for (j = 0; j < input_len; j++)
input[j] = (_input[j] < 0) ? _input[j]+256 : _input[j];
output = (char *)PyMem_Malloc(sizeof(char)*BUFFER);
output = (char *)PyMem_Malloc(sizeof(char)*(MAX(BUFFER, 5*input_len)));
if (output == NULL) return PyErr_NoMemory();
while (i < input_len) {

View File

@ -114,8 +114,12 @@ class ISBNMerge(object):
return self.results
def merge_metadata_results(self):
' Merge results with identical title and authors '
def merge_metadata_results(self, merge_on_identifiers=False):
'''
Merge results with identical title and authors or an identical
identifier
'''
# First title/author
groups = {}
for result in self.results:
title = lower(result.title if result.title else '')
@ -135,6 +139,44 @@ class ISBNMerge(object):
result = rgroup[0]
self.results.append(result)
if merge_on_identifiers:
# Now identifiers
groups, empty = {}, []
for result in self.results:
key = set()
for typ, val in result.identifiers.iteritems():
if typ and val:
key.add((typ, val))
if key:
key = frozenset(key)
match = None
for candidate in list(groups):
if candidate.intersection(key):
# We have at least one identifier in common
match = candidate.union(key)
results = groups.pop(candidate)
results.append(result)
groups[match] = results
break
if match is None:
groups[key] = [result]
else:
empty.append(result)
if len(groups) != len(self.results):
self.results = []
for rgroup in groups.itervalues():
rel = [r.average_source_relevance for r in rgroup]
if len(rgroup) > 1:
result = self.merge(rgroup, None, do_asr=False)
result.average_source_relevance = sum(rel)/len(rel)
elif rgroup:
result = rgroup[0]
self.results.append(result)
if empty:
self.results.extend(empty)
self.results.sort(key=attrgetter('average_source_relevance'))
def merge_isbn_results(self):

View File

@ -15,14 +15,17 @@ from calibre.customize.ui import metadata_plugins
from calibre import prints, sanitize_file_name2
from calibre.ebooks.metadata import check_isbn
from calibre.ebooks.metadata.sources.base import (create_log,
get_cached_cover_urls)
get_cached_cover_urls, msprefs)
def isbn_test(isbn):
isbn_ = check_isbn(isbn)
def test(mi):
misbn = check_isbn(mi.isbn)
return misbn and misbn == isbn_
if misbn and misbn == isbn_:
return True
prints('ISBN test failed. Expected: \'%s\' found \'%s\''%(isbn_, misbn))
return False
return test
@ -32,8 +35,11 @@ def title_test(title, exact=False):
def test(mi):
mt = mi.title.lower()
return (exact and mt == title) or \
(not exact and title in mt)
if (exact and mt == title) or \
(not exact and title in mt):
return True
prints('Title test failed. Expected: \'%s\' found \'%s\''%(title, mt))
return False
return test
@ -42,7 +48,22 @@ def authors_test(authors):
def test(mi):
au = set([x.lower() for x in mi.authors])
return au == authors
if msprefs['swap_author_names']:
def revert_to_fn_ln(a):
if ',' not in a:
return a
parts = a.split(',', 1)
t = parts[-1]
parts = parts[:-1]
parts.insert(0, t)
return ' '.join(parts)
au = set([revert_to_fn_ln(x) for x in au])
if au == authors:
return True
prints('Author test failed. Expected: \'%s\' found \'%s\''%(authors, au))
return False
return test

View File

@ -24,7 +24,7 @@ from calibre.translations.dynamic import translate
from calibre.ebooks.chardet import xml_to_unicode
from calibre.ebooks.oeb.entitydefs import ENTITYDEFS
from calibre.ebooks.conversion.preprocess import CSSPreProcessor
from calibre import isbytestring
from calibre import isbytestring, as_unicode
RECOVER_PARSER = etree.XMLParser(recover=True, no_network=True)
@ -643,7 +643,7 @@ class Metadata(object):
return unicode(self.value).encode('ascii', 'xmlcharrefreplace')
def __unicode__(self):
return unicode(self.value)
return as_unicode(self.value)
def to_opf1(self, dcmeta=None, xmeta=None, nsrmap={}):
attrib = {}

View File

@ -648,6 +648,18 @@ def open_url(qurl):
if isfrozen and islinux and paths:
os.environ['LD_LIBRARY_PATH'] = os.pathsep.join(paths)
def get_current_db():
'''
This method will try to return the current database in use by the user as
efficiently as possible, i.e. without constructing duplicate
LibraryDatabase objects.
'''
from calibre.gui2.ui import get_gui
gui = get_gui()
if gui is not None and gui.current_db is not None:
return gui.current_db
from calibre.library import db
return db()
def open_local_file(path):
if iswindows:

View File

@ -17,7 +17,7 @@ from calibre.gui2.actions import InterfaceAction
class GenerateCatalogAction(InterfaceAction):
name = 'Generate Catalog'
action_spec = (_('Create a catalog of the books in your calibre library'), None, None, None)
action_spec = (_('Create a catalog of the books in your calibre library'), 'catalog.png', 'Catalog builder', None)
dont_add_to = frozenset(['menubar-device', 'toolbar-device', 'context-menu-device'])
def generate_catalog(self):

View File

@ -483,8 +483,15 @@ class BookDetails(QWidget): # {{{
self.book_info.show_data(data)
self.cover_view.show_data(data)
self._layout.do_layout(self.rect())
self.setToolTip('<p>'+_('Double-click to open Book Details window') +
'<br><br>' + _('Path') + ': ' + data.get(_('Path'), ''))
try:
sz = self.cover_view.pixmap.size()
except:
sz = QSize(0, 0)
self.setToolTip(
'<p>'+_('Double-click to open Book Details window') +
'<br><br>' + _('Path') + ': ' + data.get(_('Path'), '') +
'<br><br>' + _('Cover size: %dx%d')%(sz.width(), sz.height())
)
def reset_info(self):
self.show_data({})

View File

@ -109,6 +109,8 @@ class BookInfo(QDialog, Ui_BookInfo):
pixmap = pixmap.scaled(new_width, new_height,
Qt.KeepAspectRatio, Qt.SmoothTransformation)
self.cover.set_pixmap(pixmap)
sz = pixmap.size()
self.cover.setToolTip(_('Cover size: %dx%d')%(sz.width(), sz.height()))
def refresh(self, row):
if isinstance(row, QModelIndex):

View File

@ -12,6 +12,7 @@ from zipfile import ZipFile, ZIP_DEFLATED, ZIP_STORED
from PyQt4.Qt import QDialog
from calibre.constants import isosx, iswindows
from calibre.gui2 import open_local_file
from calibre.gui2.dialogs.tweak_epub_ui import Ui_Dialog
from calibre.libunzip import extract as zipextract
@ -42,11 +43,19 @@ class TweakEpub(QDialog, Ui_Dialog):
self.move(parent_loc.x(),parent_loc.y())
def cleanup(self):
if isosx:
try:
import appscript
self.finder = appscript.app('Finder')
self.finder.Finder_windows[os.path.basename(self._exploded)].close()
except:
# appscript fails to load on 10.4
pass
# Delete directory containing exploded ePub
if self._exploded is not None:
shutil.rmtree(self._exploded, ignore_errors=True)
def display_exploded(self):
'''
Generic subprocess launch of native file browser

View File

@ -317,9 +317,8 @@ class BaseToolBar(QToolBar): # {{{
QToolBar.resizeEvent(self, ev)
style = self.get_text_style()
self.setToolButtonStyle(style)
if hasattr(self, 'd_widget'):
if hasattr(self.d_widget, 'filler'):
self.d_widget.filler.setVisible(style != Qt.ToolButtonIconOnly)
if hasattr(self, 'd_widget') and hasattr(self.d_widget, 'filler'):
self.d_widget.filler.setVisible(style != Qt.ToolButtonIconOnly)
def get_text_style(self):
style = Qt.ToolButtonTextUnderIcon

View File

@ -73,13 +73,13 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
choices=sorted(list(choices), key=sort_key))
self.current_font = None
self.current_font = self.initial_font = None
self.change_font_button.clicked.connect(self.change_font)
def initialize(self):
ConfigWidgetBase.initialize(self)
self.current_font = gprefs['font']
self.current_font = self.initial_font = gprefs['font']
self.update_font_display()
def restore_defaults(self):
@ -119,7 +119,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
def commit(self, *args):
rr = ConfigWidgetBase.commit(self, *args)
if self.current_font != gprefs['font']:
if self.current_font != self.initial_font:
gprefs['font'] = self.current_font
QApplication.setFont(self.font_display.font())
rr = True

View File

@ -88,6 +88,11 @@ class SystemTrayIcon(QSystemTrayIcon): # {{{
# }}}
_gui = None
def get_gui():
return _gui
class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
TagBrowserMixin, CoverFlowMixin, LibraryViewMixin, SearchBoxMixin,
SavedSearchBoxMixin, SearchRestrictionMixin, LayoutMixin, UpdateMixin,
@ -97,7 +102,9 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
def __init__(self, opts, parent=None, gui_debug=None):
global _gui
MainWindow.__init__(self, opts, parent=parent, disable_automatic_gc=True)
_gui = self
self.opts = opts
self.device_connected = None
self.gui_debug = gui_debug