diff --git a/recipes/newsweek.recipe b/recipes/newsweek.recipe
index a31706e257..0cae4275b0 100644
--- a/recipes/newsweek.recipe
+++ b/recipes/newsweek.recipe
@@ -69,7 +69,11 @@ class Newsweek(BasicNewsRecipe):
for section, shref in self.newsweek_sections():
self.log('Processing section', section, shref)
articles = []
- soups = [self.index_to_soup(shref)]
+ try:
+ soups = [self.index_to_soup(shref)]
+ except:
+ self.log.warn('Section %s not found, skipping'%section)
+ continue
na = soups[0].find('a', rel='next')
if na:
soups.append(self.index_to_soup(self.BASE_URL+na['href']))
diff --git a/setup/translations.py b/setup/translations.py
index 1f026555ec..3a33b7bcc4 100644
--- a/setup/translations.py
+++ b/setup/translations.py
@@ -85,7 +85,7 @@ class Translations(POT):
def mo_file(self, po_file):
locale = os.path.splitext(os.path.basename(po_file))[0]
- return locale, os.path.join(self.DEST, locale, 'LC_MESSAGES', 'messages.mo')
+ return locale, os.path.join(self.DEST, locale, 'messages.mo')
def run(self, opts):
@@ -94,9 +94,8 @@ class Translations(POT):
base = os.path.dirname(dest)
if not os.path.exists(base):
os.makedirs(base)
- if self.newer(dest, f):
- self.info('\tCompiling translations for', locale)
- subprocess.check_call(['msgfmt', '-o', dest, f])
+ self.info('\tCompiling translations for', locale)
+ subprocess.check_call(['msgfmt', '-o', dest, f])
if locale in ('en_GB', 'nds', 'te', 'yi'):
continue
pycountry = self.j(sysconfig.get_python_lib(), 'pycountry',
@@ -123,6 +122,16 @@ class Translations(POT):
shutil.copy2(f, dest)
self.write_stats()
+ self.freeze_locales()
+
+ def freeze_locales(self):
+ zf = self.DEST + '.zip'
+ from calibre import CurrentDir
+ from calibre.utils.zipfile import ZipFile, ZIP_DEFLATED
+ with ZipFile(zf, 'w', ZIP_DEFLATED) as zf:
+ with CurrentDir(self.DEST):
+ zf.add_dir('.')
+ shutil.rmtree(self.DEST)
@property
def stats(self):
diff --git a/src/calibre/ebooks/metadata/book/json_codec.py b/src/calibre/ebooks/metadata/book/json_codec.py
index 1b0768ab69..28bf3178ef 100644
--- a/src/calibre/ebooks/metadata/book/json_codec.py
+++ b/src/calibre/ebooks/metadata/book/json_codec.py
@@ -69,7 +69,7 @@ def object_to_unicode(obj, enc=preferred_encoding):
return obj
def encode_is_multiple(fm):
- if fm.get('is_multiple'):
+ if fm.get('is_multiple', None):
# migrate is_multiple back to a character
fm['is_multiple2'] = fm.get('is_multiple', {})
dt = fm.get('datatype', None)
diff --git a/src/calibre/gui2/actions/delete.py b/src/calibre/gui2/actions/delete.py
index 43465512e0..bef456033b 100644
--- a/src/calibre/gui2/actions/delete.py
+++ b/src/calibre/gui2/actions/delete.py
@@ -94,6 +94,9 @@ class DeleteAction(InterfaceAction):
self.delete_menu.addAction(
_('Remove all formats from selected books, except...'),
self.delete_all_but_selected_formats)
+ self.delete_menu.addAction(
+ _('Remove all formats from selected books'),
+ self.delete_all_formats)
self.delete_menu.addAction(
_('Remove covers from selected books'), self.delete_covers)
self.delete_menu.addSeparator()
@@ -174,6 +177,28 @@ class DeleteAction(InterfaceAction):
if ids:
self.gui.tags_view.recount()
+ def delete_all_formats(self, *args):
+ ids = self._get_selected_ids()
+ if not ids:
+ return
+ if not confirm('
'+_('All formats for the selected books will '
+ 'be deleted from your library.
'
+ 'The book metadata will be kept. Are you sure?')
+ +'
', 'delete_all_formats', self.gui):
+ return
+ db = self.gui.library_view.model().db
+ for id in ids:
+ fmts = db.formats(id, index_is_id=True, verify_formats=False)
+ if fmts:
+ for fmt in fmts.split(','):
+ self.gui.library_view.model().db.remove_format(id, fmt,
+ index_is_id=True, notify=False)
+ self.gui.library_view.model().refresh_ids(ids)
+ self.gui.library_view.model().current_changed(self.gui.library_view.currentIndex(),
+ self.gui.library_view.currentIndex())
+ if ids:
+ self.gui.tags_view.recount()
+
def remove_matching_books_from_device(self, *args):
if not self.gui.device_manager.is_device_connected:
d = error_dialog(self.gui, _('Cannot delete books'),
diff --git a/src/calibre/linux.py b/src/calibre/linux.py
index 9e58d4f638..1686f66b22 100644
--- a/src/calibre/linux.py
+++ b/src/calibre/linux.py
@@ -23,7 +23,6 @@ entry_points = {
'calibre-server = calibre.library.server.main:main',
'lrf2lrs = calibre.ebooks.lrf.lrfparser:main',
'lrs2lrf = calibre.ebooks.lrf.lrs.convert_from:main',
- 'librarything = calibre.ebooks.metadata.library_thing:main',
'calibre-debug = calibre.debug:main',
'calibredb = calibre.library.cli:main',
'calibre-parallel = calibre.utils.ipc.worker:main',
diff --git a/src/calibre/translations/dynamic.py b/src/calibre/translations/dynamic.py
index c1f368ff5a..4d65475ac0 100644
--- a/src/calibre/translations/dynamic.py
+++ b/src/calibre/translations/dynamic.py
@@ -5,10 +5,9 @@ Dynamic language lookup of translations for user-visible strings.
__license__ = 'GPL v3'
__copyright__ = '2008, Marshall T. Vandegrift '
-import os
-
+import cStringIO
from gettext import GNUTranslations
-from calibre.utils.localization import get_lc_messages_path
+from calibre.utils.localization import get_lc_messages_path, ZipFile
__all__ = ['translate']
@@ -21,10 +20,15 @@ def translate(lang, text):
else:
mpath = get_lc_messages_path(lang)
if mpath is not None:
- p = os.path.join(mpath, 'messages.mo')
- if os.path.exists(p):
- trans = GNUTranslations(open(p, 'rb'))
- _CACHE[lang] = trans
+ with ZipFile(P('localization/locales.zip',
+ allow_user_override=False), 'r') as zf:
+ try:
+ buf = cStringIO.StringIO(zf.read(mpath + '/messages.mo'))
+ except:
+ pass
+ else:
+ trans = GNUTranslations(buf)
+ _CACHE[lang] = trans
if trans is None:
return getattr(__builtins__, '_', lambda x: x)(text)
return trans.ugettext(text)
diff --git a/src/calibre/utils/config_base.py b/src/calibre/utils/config_base.py
index 7660370353..345caae384 100644
--- a/src/calibre/utils/config_base.py
+++ b/src/calibre/utils/config_base.py
@@ -223,8 +223,7 @@ class OptionSet(object):
if val is val is True or val is False or val is None or \
isinstance(val, (int, float, long, basestring)):
return repr(val)
- from PyQt4.QtCore import QString
- if isinstance(val, QString):
+ if val.__class__.__name__ == 'QString':
return repr(unicode(val))
pickle = cPickle.dumps(val, -1)
return 'cPickle.loads(%s)'%repr(pickle)
diff --git a/src/calibre/utils/localization.py b/src/calibre/utils/localization.py
index 92e6ea9b5e..a8285ad5a2 100644
--- a/src/calibre/utils/localization.py
+++ b/src/calibre/utils/localization.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
-from __future__ import with_statement
+from __future__ import absolute_import
__license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal '
@@ -8,13 +8,14 @@ __docformat__ = 'restructuredtext en'
import os, locale, re, cStringIO, cPickle
from gettext import GNUTranslations
+from zipfile import ZipFile
_available_translations = None
def available_translations():
global _available_translations
if _available_translations is None:
- stats = P('localization/stats.pickle')
+ stats = P('localization/stats.pickle', allow_user_override=False)
if os.path.exists(stats):
stats = cPickle.load(open(stats, 'rb'))
else:
@@ -49,21 +50,20 @@ def get_lang():
lang = 'en'
return lang
-def messages_path(lang):
- return P('localization/locales/%s/LC_MESSAGES'%lang)
-
def get_lc_messages_path(lang):
hlang = None
- if lang in available_translations():
- hlang = lang
- else:
- xlang = lang.split('_')[0]
- if xlang in available_translations():
- hlang = xlang
- if hlang is not None:
- return messages_path(hlang)
- return None
+ if zf_exists():
+ if lang in available_translations():
+ hlang = lang
+ else:
+ xlang = lang.split('_')[0]
+ if xlang in available_translations():
+ hlang = xlang
+ return hlang
+def zf_exists():
+ return os.path.exists(P('localization/locales.zip',
+ allow_user_override=False))
def set_translators():
# To test different translations invoke as
@@ -79,12 +79,17 @@ def set_translators():
mpath = get_lc_messages_path(lang)
if mpath is not None:
- if buf is None:
- buf = open(os.path.join(mpath, 'messages.mo'), 'rb')
- mpath = mpath.replace(os.sep+'nds'+os.sep, os.sep+'de'+os.sep)
- isof = os.path.join(mpath, 'iso639.mo')
- if os.path.exists(isof):
- iso639 = open(isof, 'rb')
+ with ZipFile(P('localization/locales.zip',
+ allow_user_override=False), 'r') as zf:
+ if buf is None:
+ buf = cStringIO.StringIO(zf.read(mpath + '/messages.mo'))
+ if mpath == 'nds':
+ mpath = 'de'
+ isof = mpath + '/iso639.mo'
+ try:
+ iso639 = cStringIO.StringIO(zf.read(isof))
+ except:
+ pass # No iso639 translations for this lang
if buf is not None:
t = GNUTranslations(buf)