Apply the PEP8 blank line standards to the entire codebase

This commit is contained in:
Kovid Goyal 2016-10-11 11:39:08 +05:30
parent 9306c28228
commit e333001d31
1116 changed files with 6256 additions and 3 deletions

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Aabenraa
'''
class AabenraaLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Aabenraa'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Aarhus
'''
class AarhusLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Aarhus'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Aarhus Midt
'''
class AarhusmidtLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Aarhus Midt'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Aarhus Nord
'''
class AarhusnordLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Aarhus Nord'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Aarhus Syd
'''
class AarhussydLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Aarhus Syd'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Aarhus Ves
'''
class AarhusvestLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Aarhus Ves'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Albertslund Posten
'''
class AlbertslundLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Albertslund Posten'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Allerød Nyt: RSS feed: Seneste nyt - alleroed.lokalavisen.dk
'''
class AlleroedLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Allerød Nyt - alleroed.lokalavisen.dk'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Alt om DATA, Datatid TechLife - Download, test, antivirus, netværk
'''
class WwwAltomdata_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Alt om DATA, Datatid TechLife - Download, test, antivirus, netværk'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Amagerbladet
'''
class Amagerbladet_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Amagerbladet'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Avisen.dk
'''
class WwwAvisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Avisen.dk'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
City Avisen
'''
class CityAvisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'City Avisen'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Computerworld.dk
'''
class WwwComputerworld_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Computerworld.dk'

View File

@ -1,5 +1,6 @@
from calibre.web.feeds.news import BasicNewsRecipe
class AdvancedUserRecipe(BasicNewsRecipe):
title = u'Contropiano'
oldest_article = 7

View File

@ -3,6 +3,7 @@
from __future__ import unicode_literals, division, absolute_import, print_function
from calibre.web.feeds.news import BasicNewsRecipe
class AdvancedUserRecipe1468055030(BasicNewsRecipe):
title = 'DataNews'
__author__ = 'oCkz7bJ_'

View File

@ -4,6 +4,7 @@ from __future__ import unicode_literals, division, absolute_import, print_functi
import re
from calibre.web.feeds.news import BasicNewsRecipe
class AdvancedUserRecipe1467571059(BasicNewsRecipe):
title = 'De Standaard'
__author__ = 'Darko Miletic, Aimylios, oCkz7bJ_'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
DjurslandsPosten
'''
class DjurslandsPosten_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'DjurslandsPosten'

View File

@ -9,6 +9,7 @@ __copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
DR.dk
'''
class DRNyheder(BasicNewsRecipe):
title = 'DR Nyheder'
__author__ = 'Darko Miletic'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Adresseavisen Ebeltoft
'''
class EbeltoftLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Adresseavisen Ebeltoft'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Egedal
'''
class EgedalLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Egedal'

View File

@ -6,6 +6,7 @@ eluniversal.com.mx
from calibre.web.feeds.news import BasicNewsRecipe
class ElUniversal(BasicNewsRecipe):
title = 'El Universal'
__author__ = 'Darko Miletic'

View File

@ -6,6 +6,7 @@ http://www.eltribuno.info/salta/edicion_impresa.aspx
from calibre.web.feeds.news import BasicNewsRecipe
class ElTribunoSaltaImpreso(BasicNewsRecipe):
title = 'El Tribuno Salta'
__author__ = 'Darko Miletic'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Erhvervs&#149;Avisen: RSS feed: Seneste nyt - erhvervsavisen.dk
'''
class Erhvervsavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Erhvervs Avisen'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Esbjerg: RSS feed: Seneste nyt - esbjerg.lokalavisen.dk
'''
class EsbjergLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Esbjerg'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Favrskov Avisen
'''
class FavrskovAvisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Favrskov Avisen'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Favrskovposten
'''
class FavrskovLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Favrskovposten'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Folkebladet
'''
class Folkebladet_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Folkebladet'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Folkebladet Djursland
'''
class FolkebladetDjursland_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Folkebladet Djursland'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
folketidende.dk
'''
class Folketidende_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'folketidende.dk'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Uge-Nyt
'''
class FredensborgLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Uge-Nyt'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Fredericia
'''
class FredericiaLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Fredericia'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Frederiksberg Bladet
'''
class FrederiksbergBladet_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Frederiksberg Bladet'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Frederikssund
'''
class FrederikssundLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Frederikssund'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Furesø Avis
'''
class FuresoeLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Furesø Avis'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Villabyerne
'''
class GentofteLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Villabyerne'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Grenaa
'''
class GrenaaLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Grenaa'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Ugeposten Gribskov
'''
class GribskovLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Ugeposten Gribskov'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Haderslev
'''
class HaderslevLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Haderslev'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Halsnæs Avis
'''
class HalsnaesLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Halsnæs Avis'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Hillerød Posten
'''
class HilleroedLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Hillerød Posten'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Ugebladet
'''
class HoersholmLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Ugebladet'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Hornsherred
'''
class HornsherredLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Hornsherred'

View File

@ -3,6 +3,7 @@
from __future__ import unicode_literals, division, absolute_import, print_function
from calibre.web.feeds.news import BasicNewsRecipe
class Hvidovre_Avis_dk(BasicNewsRecipe):
title = 'Hvidovre avis'
language = 'da'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Hvidovre Avis
'''
class HvidovreLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Hvidovre Avis'

View File

@ -6,6 +6,8 @@ from calibre.web.feeds.news import BasicNewsRecipe
'''
Ingeniøren.dk
'''
class Ing_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Ingeniøren'

View File

@ -12,6 +12,7 @@ http://www.jotdown.es/
import re
from calibre.web.feeds.news import BasicNewsRecipe
class jotdown(BasicNewsRecipe):
author = 'desUBIKado'
description = 'Revista digital con magníficos y extensos artículos'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
JydskeVestkysten | JV.dk | jv.dk
'''
class WwwJv_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'JydskeVestkysten | JV.dk | jv.dk'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Kalø Vig
'''
class KaloevigLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Kalø Vig'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Kgs. Enghave Bladet
'''
class KgsEnghaveBladet_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Kgs. Enghave Bladet'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lørdagsavisen
'''
class KoegeLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lørdagsavisen'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Kolding
'''
class KoldingLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Kolding'

View File

@ -3,6 +3,7 @@
from __future__ import unicode_literals, division, absolute_import, print_function
from calibre.web.feeds.news import BasicNewsRecipe
class KristeligtDagblad(BasicNewsRecipe):
title = 'Kristeligt Dagblad'
language = 'da'

View File

@ -4,6 +4,7 @@ __author__ = 'Daniele Forsi'
from calibre.web.feeds.recipes import BasicNewsRecipe
class LeScienze(BasicNewsRecipe):
title = 'Le Scienze'
description = 'Edizione italiana di Scientific American'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Det grønne område
'''
class Lyngby_taarbaekLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Det grønne område'

View File

@ -7,6 +7,7 @@ www.nakedcapitalism.com
from calibre.web.feeds.news import BasicNewsRecipe
class nakedcapitalism(BasicNewsRecipe):
title = 'Naked Capitalism'
__author__ = 'Darko Miletic'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Nørrebro Nordvest bladet
'''
class Minby_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Nørrebro Nordvest bladet'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Norddjurs
'''
class NorddjursLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Norddjurs'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Nordjyske.dk
'''
class Nordjyske_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Nordjyske.dk'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Odense
'''
class OdenseLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Odense'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Østerbro Avis
'''
class OesterbroAvis_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Østerbro Avis'

View File

@ -1,6 +1,7 @@
import re
from calibre.web.feeds.news import BasicNewsRecipe
class AdvancedUserRecipe1359406781(BasicNewsRecipe):
title = u'Private Eye'
publication_type = 'magazine'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Din avis Randers
'''
class RandersLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Din avis Randers'

View File

@ -14,6 +14,7 @@ import lxml
from lxml.builder import E
respekt_url = 'http://www.respekt.cz'
class respektRecipe(BasicNewsRecipe):
__author__ = 'Tomáš Hnyk'
publisher = u'Respekt Publishing a. s.'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Roskilde Avis
'''
class RoskildeLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Roskilde Avis'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Rudersdal Avis
'''
class RudersdalLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Rudersdal Avis'

View File

@ -7,6 +7,7 @@ sciencedaily.com
from calibre.web.feeds.news import BasicNewsRecipe
class ScienceDaily(BasicNewsRecipe):
title = u'ScienceDaily'
__author__ = u'Darko Miletic'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Skanderborg
'''
class SkanderborgLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Skanderborg'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
sn.dk
'''
class Sn_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'sn.dk'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Sønderborg
'''
class SoenderborgLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Sønderborg'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Adresseavisen Syddjurs
'''
class SyddjursLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Adresseavisen Syddjurs'

View File

@ -9,11 +9,13 @@ http://www.theaustralian.news.com.au/
from calibre.web.feeds.news import BasicNewsRecipe
def classes(classes):
q = frozenset(classes.split(' '))
return dict(attrs={
'class': lambda x: x and frozenset(x.split()).intersection(q)})
class DailyTelegraph(BasicNewsRecipe):
title = u'The Australian'
__author__ = u'Kovid Goyal'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Valby Bladet
'''
class ValbyBladet_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Valby Bladet'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Vanløse Bladet
'''
class VanloeseBladet_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Vanløse Bladet'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Varde
'''
class VardeLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Varde'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Lokalavisen Vejle
'''
class VejleLokalavisen_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Lokalavisen Vejle'

View File

@ -7,6 +7,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
Vesterbro Bladet
'''
class VesterbroBladet_dk(BasicNewsRecipe):
__author__ = 'CoderAllan.github.com'
title = 'Vesterbro Bladet'

View File

@ -11,6 +11,7 @@ http://www.weblogssl.com/
import re
from calibre.web.feeds.news import BasicNewsRecipe
class weblogssl(BasicNewsRecipe):
__author__ = 'desUBIKado'
description = u'Weblogs colectivos dedicados a seguir la actualidad sobre tecnologia, entretenimiento, estilos de vida, motor, deportes y economia.'

View File

@ -1,4 +1,4 @@
[flake8]
max-line-length = 160
builtins = _,dynamic_property,__,P,I,lopen,icu_lower,icu_upper,icu_title,ngettext
ignore = E12,E203,E22,E231,E241,E301,E302,E304,E401,E402,E731,W391
ignore = E12,E203,E22,E231,E241,E401,E402,E731,W391

View File

@ -10,12 +10,14 @@ import sys, os, json, subprocess, errno, hashlib
from setup import Command, build_cache_dir
import __builtin__
def set_builtins(builtins):
for x in builtins:
if not hasattr(__builtin__, x):
setattr(__builtin__, x, True)
yield x
class Message:
def __init__(self, filename, lineno, msg):
@ -24,6 +26,7 @@ class Message:
def __str__(self):
return '%s:%s: %s' % (self.filename, self.lineno, self.msg)
class Check(Command):
description = 'Check for errors in the calibre source code'

View File

@ -29,18 +29,22 @@ if False:
winerror, win32api, isbsd, config_dir
_mt_inited = False
def _init_mimetypes():
global _mt_inited
import mimetypes
mimetypes.init([P('mime.types')])
_mt_inited = True
def guess_type(*args, **kwargs):
import mimetypes
if not _mt_inited:
_init_mimetypes()
return mimetypes.guess_type(*args, **kwargs)
def guess_all_extensions(*args, **kwargs):
import mimetypes
if not _mt_inited:
@ -57,17 +61,20 @@ def guess_extension(*args, **kwargs):
ext = '.pdb'
return ext
def get_types_map():
import mimetypes
if not _mt_inited:
_init_mimetypes()
return mimetypes.types_map
def to_unicode(raw, encoding='utf-8', errors='strict'):
if isinstance(raw, unicode):
return raw
return raw.decode(encoding, errors)
def patheq(p1, p2):
p = os.path
d = lambda x : p.normcase(p.normpath(p.realpath(p.normpath(x))))
@ -75,6 +82,7 @@ def patheq(p1, p2):
return False
return d(p1) == d(p2)
def unicode_path(path, abs=False):
if isinstance(path, bytes):
path = path.decode(filesystem_encoding)
@ -82,6 +90,7 @@ def unicode_path(path, abs=False):
path = os.path.abspath(path)
return path
def osx_version():
if isosx:
import platform
@ -90,6 +99,7 @@ def osx_version():
if m:
return int(m.group(1)), int(m.group(2)), int(m.group(3))
def confirm_config_name(name):
return name + '_again'
@ -97,6 +107,7 @@ _filename_sanitize = re.compile(r'[\xae\0\\|\?\*<":>\+/]')
_filename_sanitize_unicode = frozenset([u'\\', u'|', u'?', u'*', u'<',
u'"', u':', u'>', u'+', u'/'] + list(map(unichr, xrange(32))))
def sanitize_file_name(name, substitute='_', as_unicode=False):
'''
Sanitize the filename `name`. All invalid characters are replaced by `substitute`.
@ -125,6 +136,7 @@ def sanitize_file_name(name, substitute='_', as_unicode=False):
one = '_' + one[1:]
return one
def sanitize_file_name_unicode(name, substitute='_'):
'''
Sanitize the filename `name`. All invalid characters are replaced by `substitute`.
@ -151,6 +163,7 @@ def sanitize_file_name_unicode(name, substitute='_'):
one = '_' + one[1:]
return one
def sanitize_file_name2(name, substitute='_'):
'''
Sanitize filenames removing invalid chars. Keeps unicode names as unicode
@ -160,6 +173,7 @@ def sanitize_file_name2(name, substitute='_'):
return sanitize_file_name(name, substitute=substitute)
return sanitize_file_name_unicode(name, substitute=substitute)
def prints(*args, **kwargs):
'''
Print unicode arguments safely by encoding them to preferred_encoding
@ -227,9 +241,11 @@ def prints(*args, **kwargs):
count += len(sep)
return count
class CommandLineError(Exception):
pass
def setup_cli_handlers(logger, level):
import logging
if os.environ.get('CALIBRE_WORKER', None) is not None and logger.handlers:
@ -261,6 +277,7 @@ def load_library(name, cdll):
return cdll.LoadLibrary(name)
return cdll.LoadLibrary(name+'.so')
def filename_to_utf8(name):
'''Return C{name} encoded in utf8. Unhandled characters are replaced. '''
if isinstance(name, unicode):
@ -268,6 +285,7 @@ def filename_to_utf8(name):
codec = 'cp1252' if iswindows else 'utf8'
return name.decode(codec, 'replace').encode('utf8')
def extract(path, dir):
extractor = None
# First use the file header to identify its type
@ -292,6 +310,7 @@ def extract(path, dir):
raise Exception('Unknown archive type')
extractor(path, dir)
def get_proxies(debug=True):
from urllib import getproxies
proxies = getproxies()
@ -315,6 +334,7 @@ def get_proxies(debug=True):
prints('Using proxies:', proxies)
return proxies
def get_parsed_proxy(typ='http', debug=True):
proxies = get_proxies(debug)
proxy = proxies.get(typ, None)
@ -346,6 +366,7 @@ def get_parsed_proxy(typ='http', debug=True):
prints('Using http proxy', str(ans))
return ans
def get_proxy_info(proxy_scheme, proxy_string):
'''
Parse all proxy information from a proxy string (as returned by
@ -372,6 +393,7 @@ def get_proxy_info(proxy_scheme, proxy_string):
USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko'
USER_AGENT_MOBILE = 'Mozilla/5.0 (Windows; U; Windows CE 5.1; rv:1.8.1a3) Gecko/20060610 Minimo/0.016'
def random_user_agent(choose=None):
try:
ua_list = random_user_agent.ua_list
@ -398,6 +420,7 @@ def random_user_agent(choose=None):
]
return random.choice(ua_list) if choose is None else ua_list[choose]
def browser(honor_time=True, max_time=2, mobile_browser=False, user_agent=None, use_robust_parser=False, verify_ssl_certificates=True):
'''
Create a mechanize browser for web scraping. The browser handles cookies,
@ -431,6 +454,7 @@ def browser(honor_time=True, max_time=2, mobile_browser=False, user_agent=None,
return opener
def fit_image(width, height, pwidth, pheight):
'''
Fit image in box of width pwidth and height pheight.
@ -453,6 +477,7 @@ def fit_image(width, height, pwidth, pheight):
return scaled, int(width), int(height)
class CurrentDir(object):
def __init__(self, path, workaround_temp_folder_permissions=False):
@ -481,6 +506,8 @@ class CurrentDir(object):
_ncpus = None
def detect_ncpus():
"""Detects the number of effective CPUs in the system"""
global _ncpus
@ -502,18 +529,22 @@ def detect_ncpus():
relpath = os.path.relpath
_spat = re.compile(r'^the\s+|^a\s+|^an\s+', re.IGNORECASE)
def english_sort(x, y):
'''
Comapare two english phrases ignoring starting prepositions.
'''
return cmp(_spat.sub('', x), _spat.sub('', y))
def walk(dir):
''' A nice interface to os.walk '''
for record in os.walk(dir):
for f in record[-1]:
yield os.path.join(record[0], f)
def strftime(fmt, t=None):
''' A version of strftime that returns unicode strings and tries to handle dates
before 1900 '''
@ -542,12 +573,14 @@ def strftime(fmt, t=None):
ans = ans.replace('_early year hack##', str(orig_year))
return ans
def my_unichr(num):
try:
return safe_chr(num)
except (ValueError, OverflowError):
return u'?'
def entity_to_unicode(match, exceptions=[], encoding='cp1252',
result_exceptions={}):
'''
@ -606,12 +639,15 @@ xml_entity_to_unicode = partial(entity_to_unicode, result_exceptions={
'>' : '&gt;',
'&' : '&amp;'})
def replace_entities(raw, encoding='cp1252'):
return _ent_pat.sub(partial(entity_to_unicode, encoding=encoding), raw)
def xml_replace_entities(raw, encoding='cp1252'):
return _ent_pat.sub(partial(xml_entity_to_unicode, encoding=encoding), raw)
def prepare_string_for_xml(raw, attribute=False):
raw = _ent_pat.sub(entity_to_unicode, raw)
raw = raw.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
@ -619,9 +655,11 @@ def prepare_string_for_xml(raw, attribute=False):
raw = raw.replace('"', '&quot;').replace("'", '&apos;')
return raw
def isbytestring(obj):
return isinstance(obj, (str, bytes))
def force_unicode(obj, enc=preferred_encoding):
if isbytestring(obj):
try:
@ -639,6 +677,7 @@ def force_unicode(obj, enc=preferred_encoding):
obj = obj.decode('utf-8')
return obj
def as_unicode(obj, enc=preferred_encoding):
if not isbytestring(obj):
try:
@ -650,12 +689,14 @@ def as_unicode(obj, enc=preferred_encoding):
obj = repr(obj)
return force_unicode(obj, enc=enc)
def url_slash_cleaner(url):
'''
Removes redundant /'s from url's.
'''
return re.sub(r'(?<!:)/{2,}', '/', url)
def human_readable(size, sep=' '):
""" Convert a size in bytes into a human readable form """
divisor, suffix = 1, "B"
@ -670,6 +711,7 @@ def human_readable(size, sep=' '):
size = size[:-2]
return size + sep + suffix
def remove_bracketed_text(src,
brackets={u'(':u')', u'[':u']', u'{':u'}'}):
from collections import Counter
@ -688,10 +730,12 @@ def remove_bracketed_text(src,
buf.append(char)
return u''.join(buf)
def ipython(user_ns=None):
from calibre.utils.ipython import ipython
ipython(user_ns=user_ns)
def fsync(fileobj):
fileobj.flush()
os.fsync(fileobj.fileno())

View File

@ -45,6 +45,8 @@ win32api = importlib.import_module('win32api') if iswindows else None
fcntl = None if iswindows else importlib.import_module('fcntl')
_osx_ver = None
def get_osx_version():
global _osx_ver
if _osx_ver is None:
@ -77,12 +79,14 @@ else:
DEBUG = False
def debug():
global DEBUG
DEBUG = True
_cache_dir = None
def _get_cache_dir():
confcache = os.path.join(config_dir, u'caches')
if isportable:
@ -114,6 +118,7 @@ def _get_cache_dir():
candidate = confcache
return candidate
def cache_dir():
global _cache_dir
if _cache_dir is None:
@ -122,6 +127,7 @@ def cache_dir():
# plugins {{{
class Plugins(collections.Mapping):
def __init__(self):
@ -231,6 +237,7 @@ else:
print 'No write acces to', config_dir, 'using a temporary dir instead'
import tempfile, atexit
config_dir = tempfile.mkdtemp(prefix='calibre-config-')
def cleanup_cdir():
try:
import shutil
@ -240,6 +247,7 @@ else:
atexit.register(cleanup_cdir)
# }}}
def get_version():
'''Return version string for display to user '''
dv = os.environ.get('CALIBRE_DEVELOP_FROM', None)
@ -253,11 +261,13 @@ def get_version():
return v
def get_portable_base():
'Return path to the directory that contains calibre-portable.exe or None'
if isportable:
return os.path.dirname(os.path.dirname(os.environ['CALIBRE_PORTABLE_BUILD']))
def get_unicode_windows_env_var(name):
import ctypes
name = unicode(name)
@ -268,6 +278,7 @@ def get_unicode_windows_env_var(name):
ctypes.windll.kernel32.GetEnvironmentVariableW(name, buf, n)
return buf.value
def get_windows_username():
'''
Return the user name of the currently loggen in user as a unicode string.
@ -288,6 +299,7 @@ def get_windows_username():
return get_unicode_windows_env_var(u'USERNAME')
def get_windows_temp_path():
import ctypes
n = ctypes.windll.kernel32.GetTempPathW(0, None)
@ -298,6 +310,7 @@ def get_windows_temp_path():
ans = buf.value
return ans if ans else None
def get_windows_user_locale_name():
import ctypes
k32 = ctypes.windll.kernel32
@ -310,6 +323,7 @@ def get_windows_user_locale_name():
number_formats = None
def get_windows_number_formats():
# This can be changed to use localeconv() once we switch to Visual Studio
# 2015 as localeconv() in that version has unicode variants for all strings.

View File

@ -17,6 +17,7 @@ elif isosx:
class PluginNotFound(ValueError):
pass
class InvalidPlugin(ValueError):
pass
@ -312,6 +313,7 @@ class Plugin(object): # {{{
# }}}
class FileTypePlugin(Plugin): # {{{
'''
A plugin that is associated with a particular set of file types.
@ -392,6 +394,7 @@ class FileTypePlugin(Plugin): # {{{
# }}}
class MetadataReaderPlugin(Plugin): # {{{
'''
A plugin that implements reading metadata from a set of file types.
@ -422,6 +425,7 @@ class MetadataReaderPlugin(Plugin): # {{{
return None
# }}}
class MetadataWriterPlugin(Plugin): # {{{
'''
A plugin that implements reading metadata from a set of file types.
@ -453,6 +457,7 @@ class MetadataWriterPlugin(Plugin): # {{{
# }}}
class CatalogPlugin(Plugin): # {{{
'''
A plugin that implements a catalog generator.
@ -580,6 +585,7 @@ class CatalogPlugin(Plugin): # {{{
# }}}
class InterfaceActionBase(Plugin): # {{{
supported_platforms = ['windows', 'osx', 'linux']
@ -607,6 +613,7 @@ class InterfaceActionBase(Plugin): # {{{
# }}}
class PreferencesPlugin(Plugin): # {{{
'''
@ -666,6 +673,7 @@ class PreferencesPlugin(Plugin): # {{{
# }}}
class StoreBase(Plugin): # {{{
supported_platforms = ['windows', 'osx', 'linux']
@ -715,6 +723,7 @@ class StoreBase(Plugin): # {{{
# }}}
class ViewerPlugin(Plugin): # {{{
type = _('Viewer')
@ -774,6 +783,7 @@ class ViewerPlugin(Plugin): # {{{
# }}}
class EditBookToolPlugin(Plugin): # {{{
type = _('Edit Book Tool')
@ -781,6 +791,7 @@ class EditBookToolPlugin(Plugin): # {{{
# }}}
class LibraryClosedPlugin(Plugin): # {{{
'''
LibraryClosedPlugins are run when a library is closed, either at shutdown,

View File

@ -15,6 +15,7 @@ plugins = []
# To archive plugins {{{
class PML2PMLZ(FileTypePlugin):
name = 'PML to PMLZ'
author = 'John Schember'
@ -45,6 +46,7 @@ class PML2PMLZ(FileTypePlugin):
return of.name
class TXT2TXTZ(FileTypePlugin):
name = 'TXT to TXTZ'
author = 'John Schember'
@ -124,6 +126,8 @@ plugins += [HTML2ZIP, PML2PMLZ, TXT2TXTZ, ArchiveExtract,]
# }}}
# Metadata reader plugins {{{
class ComicMetadataReader(MetadataReaderPlugin):
name = 'Read comic metadata'
@ -164,6 +168,7 @@ class ComicMetadataReader(MetadataReaderPlugin):
mi.cover_data = (ext.lower(), data)
return mi
class CHMMetadataReader(MetadataReaderPlugin):
name = 'Read CHM metadata'
@ -187,6 +192,7 @@ class EPUBMetadataReader(MetadataReaderPlugin):
return get_quick_metadata(stream)
return get_metadata(stream)
class FB2MetadataReader(MetadataReaderPlugin):
name = 'Read FB2 metadata'
@ -197,6 +203,7 @@ class FB2MetadataReader(MetadataReaderPlugin):
from calibre.ebooks.metadata.fb2 import get_metadata
return get_metadata(stream)
class HTMLMetadataReader(MetadataReaderPlugin):
name = 'Read HTML metadata'
@ -207,6 +214,7 @@ class HTMLMetadataReader(MetadataReaderPlugin):
from calibre.ebooks.metadata.html import get_metadata
return get_metadata(stream)
class HTMLZMetadataReader(MetadataReaderPlugin):
name = 'Read HTMLZ metadata'
@ -218,6 +226,7 @@ class HTMLZMetadataReader(MetadataReaderPlugin):
from calibre.ebooks.metadata.extz import get_metadata
return get_metadata(stream)
class IMPMetadataReader(MetadataReaderPlugin):
name = 'Read IMP metadata'
@ -229,6 +238,7 @@ class IMPMetadataReader(MetadataReaderPlugin):
from calibre.ebooks.metadata.imp import get_metadata
return get_metadata(stream)
class LITMetadataReader(MetadataReaderPlugin):
name = 'Read LIT metadata'
@ -239,6 +249,7 @@ class LITMetadataReader(MetadataReaderPlugin):
from calibre.ebooks.metadata.lit import get_metadata
return get_metadata(stream)
class LRFMetadataReader(MetadataReaderPlugin):
name = 'Read LRF metadata'
@ -249,6 +260,7 @@ class LRFMetadataReader(MetadataReaderPlugin):
from calibre.ebooks.lrf.meta import get_metadata
return get_metadata(stream)
class LRXMetadataReader(MetadataReaderPlugin):
name = 'Read LRX metadata'
@ -259,6 +271,7 @@ class LRXMetadataReader(MetadataReaderPlugin):
from calibre.ebooks.metadata.lrx import get_metadata
return get_metadata(stream)
class MOBIMetadataReader(MetadataReaderPlugin):
name = 'Read MOBI metadata'
@ -269,6 +282,7 @@ class MOBIMetadataReader(MetadataReaderPlugin):
from calibre.ebooks.metadata.mobi import get_metadata
return get_metadata(stream)
class ODTMetadataReader(MetadataReaderPlugin):
name = 'Read ODT metadata'
@ -279,6 +293,7 @@ class ODTMetadataReader(MetadataReaderPlugin):
from calibre.ebooks.metadata.odt import get_metadata
return get_metadata(stream)
class DocXMetadataReader(MetadataReaderPlugin):
name = 'Read DOCX metadata'
@ -289,6 +304,7 @@ class DocXMetadataReader(MetadataReaderPlugin):
from calibre.ebooks.metadata.docx import get_metadata
return get_metadata(stream)
class OPFMetadataReader(MetadataReaderPlugin):
name = 'Read OPF metadata'
@ -299,6 +315,7 @@ class OPFMetadataReader(MetadataReaderPlugin):
from calibre.ebooks.metadata.opf import get_metadata
return get_metadata(stream)[0]
class PDBMetadataReader(MetadataReaderPlugin):
name = 'Read PDB metadata'
@ -310,6 +327,7 @@ class PDBMetadataReader(MetadataReaderPlugin):
from calibre.ebooks.metadata.pdb import get_metadata
return get_metadata(stream)
class PDFMetadataReader(MetadataReaderPlugin):
name = 'Read PDF metadata'
@ -322,6 +340,7 @@ class PDFMetadataReader(MetadataReaderPlugin):
return get_quick_metadata(stream)
return get_metadata(stream)
class PMLMetadataReader(MetadataReaderPlugin):
name = 'Read PML metadata'
@ -333,6 +352,7 @@ class PMLMetadataReader(MetadataReaderPlugin):
from calibre.ebooks.metadata.pml import get_metadata
return get_metadata(stream)
class RARMetadataReader(MetadataReaderPlugin):
name = 'Read RAR metadata'
@ -343,6 +363,7 @@ class RARMetadataReader(MetadataReaderPlugin):
from calibre.ebooks.metadata.rar import get_metadata
return get_metadata(stream)
class RBMetadataReader(MetadataReaderPlugin):
name = 'Read RB metadata'
@ -354,6 +375,7 @@ class RBMetadataReader(MetadataReaderPlugin):
from calibre.ebooks.metadata.rb import get_metadata
return get_metadata(stream)
class RTFMetadataReader(MetadataReaderPlugin):
name = 'Read RTF metadata'
@ -364,6 +386,7 @@ class RTFMetadataReader(MetadataReaderPlugin):
from calibre.ebooks.metadata.rtf import get_metadata
return get_metadata(stream)
class SNBMetadataReader(MetadataReaderPlugin):
name = 'Read SNB metadata'
@ -375,6 +398,7 @@ class SNBMetadataReader(MetadataReaderPlugin):
from calibre.ebooks.metadata.snb import get_metadata
return get_metadata(stream)
class TOPAZMetadataReader(MetadataReaderPlugin):
name = 'Read Topaz metadata'
@ -385,6 +409,7 @@ class TOPAZMetadataReader(MetadataReaderPlugin):
from calibre.ebooks.metadata.topaz import get_metadata
return get_metadata(stream)
class TXTMetadataReader(MetadataReaderPlugin):
name = 'Read TXT metadata'
@ -396,6 +421,7 @@ class TXTMetadataReader(MetadataReaderPlugin):
from calibre.ebooks.metadata.txt import get_metadata
return get_metadata(stream)
class TXTZMetadataReader(MetadataReaderPlugin):
name = 'Read TXTZ metadata'
@ -407,6 +433,7 @@ class TXTZMetadataReader(MetadataReaderPlugin):
from calibre.ebooks.metadata.extz import get_metadata
return get_metadata(stream)
class ZipMetadataReader(MetadataReaderPlugin):
name = 'Read ZIP metadata'
@ -424,6 +451,7 @@ plugins += [x for x in list(locals().values()) if isinstance(x, type) and
# Metadata writer plugins {{{
class EPUBMetadataWriter(MetadataWriterPlugin):
name = 'Set EPUB metadata'
@ -442,6 +470,7 @@ class EPUBMetadataWriter(MetadataWriterPlugin):
return _('Enter {0} below to have the EPUB metadata writer plugin not'
' add cover images to EPUB files that have no existing cover image.').format(h)
class FB2MetadataWriter(MetadataWriterPlugin):
name = 'Set FB2 metadata'
@ -452,6 +481,7 @@ class FB2MetadataWriter(MetadataWriterPlugin):
from calibre.ebooks.metadata.fb2 import set_metadata
set_metadata(stream, mi, apply_null=self.apply_null)
class HTMLZMetadataWriter(MetadataWriterPlugin):
name = 'Set HTMLZ metadata'
@ -463,6 +493,7 @@ class HTMLZMetadataWriter(MetadataWriterPlugin):
from calibre.ebooks.metadata.extz import set_metadata
set_metadata(stream, mi)
class LRFMetadataWriter(MetadataWriterPlugin):
name = 'Set LRF metadata'
@ -473,6 +504,7 @@ class LRFMetadataWriter(MetadataWriterPlugin):
from calibre.ebooks.lrf.meta import set_metadata
set_metadata(stream, mi)
class MOBIMetadataWriter(MetadataWriterPlugin):
name = 'Set MOBI metadata'
@ -484,6 +516,7 @@ class MOBIMetadataWriter(MetadataWriterPlugin):
from calibre.ebooks.metadata.mobi import set_metadata
set_metadata(stream, mi)
class PDBMetadataWriter(MetadataWriterPlugin):
name = 'Set PDB metadata'
@ -495,6 +528,7 @@ class PDBMetadataWriter(MetadataWriterPlugin):
from calibre.ebooks.metadata.pdb import set_metadata
set_metadata(stream, mi)
class PDFMetadataWriter(MetadataWriterPlugin):
name = 'Set PDF metadata'
@ -506,6 +540,7 @@ class PDFMetadataWriter(MetadataWriterPlugin):
from calibre.ebooks.metadata.pdf import set_metadata
set_metadata(stream, mi)
class RTFMetadataWriter(MetadataWriterPlugin):
name = 'Set RTF metadata'
@ -516,6 +551,7 @@ class RTFMetadataWriter(MetadataWriterPlugin):
from calibre.ebooks.metadata.rtf import set_metadata
set_metadata(stream, mi)
class TOPAZMetadataWriter(MetadataWriterPlugin):
name = 'Set TOPAZ metadata'
@ -527,6 +563,7 @@ class TOPAZMetadataWriter(MetadataWriterPlugin):
from calibre.ebooks.metadata.topaz import set_metadata
set_metadata(stream, mi)
class TXTZMetadataWriter(MetadataWriterPlugin):
name = 'Set TXTZ metadata'
@ -538,6 +575,7 @@ class TXTZMetadataWriter(MetadataWriterPlugin):
from calibre.ebooks.metadata.extz import set_metadata
set_metadata(stream, mi)
class DocXMetadataWriter(MetadataWriterPlugin):
name = 'Set DOCX metadata'
@ -790,180 +828,215 @@ plugins += [GoogleBooks, GoogleImages, Amazon, Edelweiss, OpenLibrary, ISBNDB, O
# Interface Actions {{{
class ActionAdd(InterfaceActionBase):
name = 'Add Books'
actual_plugin = 'calibre.gui2.actions.add:AddAction'
description = _('Add books to calibre or the connected device')
class ActionFetchAnnotations(InterfaceActionBase):
name = 'Fetch Annotations'
actual_plugin = 'calibre.gui2.actions.annotate:FetchAnnotationsAction'
description = _('Fetch annotations from a connected Kindle (experimental)')
class ActionGenerateCatalog(InterfaceActionBase):
name = 'Generate Catalog'
actual_plugin = 'calibre.gui2.actions.catalog:GenerateCatalogAction'
description = _('Generate a catalog of the books in your calibre library')
class ActionConvert(InterfaceActionBase):
name = 'Convert Books'
actual_plugin = 'calibre.gui2.actions.convert:ConvertAction'
description = _('Convert books to various ebook formats')
class ActionPolish(InterfaceActionBase):
name = 'Polish Books'
actual_plugin = 'calibre.gui2.actions.polish:PolishAction'
description = _('Fine tune your ebooks')
class ActionEditToC(InterfaceActionBase):
name = 'Edit ToC'
actual_plugin = 'calibre.gui2.actions.toc_edit:ToCEditAction'
description = _('Edit the Table of Contents in your books')
class ActionDelete(InterfaceActionBase):
name = 'Remove Books'
actual_plugin = 'calibre.gui2.actions.delete:DeleteAction'
description = _('Delete books from your calibre library or connected device')
class ActionEmbed(InterfaceActionBase):
name = 'Embed Metadata'
actual_plugin = 'calibre.gui2.actions.embed:EmbedAction'
description = _('Embed updated metadata into the actual book files in your calibre library')
class ActionEditMetadata(InterfaceActionBase):
name = 'Edit Metadata'
actual_plugin = 'calibre.gui2.actions.edit_metadata:EditMetadataAction'
description = _('Edit the metadata of books in your calibre library')
class ActionView(InterfaceActionBase):
name = 'View'
actual_plugin = 'calibre.gui2.actions.view:ViewAction'
description = _('Read books in your calibre library')
class ActionFetchNews(InterfaceActionBase):
name = 'Fetch News'
actual_plugin = 'calibre.gui2.actions.fetch_news:FetchNewsAction'
description = _('Download news from the internet in ebook form')
class ActionQuickview(InterfaceActionBase):
name = 'Show Quickview'
actual_plugin = 'calibre.gui2.actions.show_quickview:ShowQuickviewAction'
description = _('Show a list of related books quickly')
class ActionTagMapper(InterfaceActionBase):
name = 'Tag Mapper'
actual_plugin = 'calibre.gui2.actions.tag_mapper:TagMapAction'
description = _('Filter/transform the tags for books in the library')
class ActionTemplateTester(InterfaceActionBase):
name = 'Template Tester'
actual_plugin = 'calibre.gui2.actions.show_template_tester:ShowTemplateTesterAction'
description = _('Show an editor for testing templates')
class ActionSaveToDisk(InterfaceActionBase):
name = 'Save To Disk'
actual_plugin = 'calibre.gui2.actions.save_to_disk:SaveToDiskAction'
description = _('Export books from your calibre library to the hard disk')
class ActionShowBookDetails(InterfaceActionBase):
name = 'Show Book Details'
actual_plugin = 'calibre.gui2.actions.show_book_details:ShowBookDetailsAction'
description = _('Show book details in a separate popup')
class ActionRestart(InterfaceActionBase):
name = 'Restart'
actual_plugin = 'calibre.gui2.actions.restart:RestartAction'
description = _('Restart calibre')
class ActionOpenFolder(InterfaceActionBase):
name = 'Open Folder'
actual_plugin = 'calibre.gui2.actions.open:OpenFolderAction'
description = _('Open the folder that contains the book files in your'
' calibre library')
class ActionSendToDevice(InterfaceActionBase):
name = 'Send To Device'
actual_plugin = 'calibre.gui2.actions.device:SendToDeviceAction'
description = _('Send books to the connected device')
class ActionConnectShare(InterfaceActionBase):
name = 'Connect Share'
actual_plugin = 'calibre.gui2.actions.device:ConnectShareAction'
description = _('Send books via email or the web also connect to iTunes or'
' folders on your computer as if they are devices')
class ActionHelp(InterfaceActionBase):
name = 'Help'
actual_plugin = 'calibre.gui2.actions.help:HelpAction'
description = _('Browse the calibre User Manual')
class ActionPreferences(InterfaceActionBase):
name = 'Preferences'
actual_plugin = 'calibre.gui2.actions.preferences:PreferencesAction'
description = _('Customize calibre')
class ActionSimilarBooks(InterfaceActionBase):
name = 'Similar Books'
actual_plugin = 'calibre.gui2.actions.similar_books:SimilarBooksAction'
description = _('Easily find books similar to the currently selected one')
class ActionChooseLibrary(InterfaceActionBase):
name = 'Choose Library'
actual_plugin = 'calibre.gui2.actions.choose_library:ChooseLibraryAction'
description = _('Switch between different calibre libraries and perform'
' maintenance on them')
class ActionAddToLibrary(InterfaceActionBase):
name = 'Add To Library'
actual_plugin = 'calibre.gui2.actions.add_to_library:AddToLibraryAction'
description = _('Copy books from the device to your calibre library')
class ActionEditCollections(InterfaceActionBase):
name = 'Edit Collections'
actual_plugin = 'calibre.gui2.actions.edit_collections:EditCollectionsAction'
description = _('Edit the collections in which books are placed on your device')
class ActionMatchBooks(InterfaceActionBase):
name = 'Match Books'
actual_plugin = 'calibre.gui2.actions.match_books:MatchBookAction'
description = _('Match book on the devices to books in the library')
class ActionCopyToLibrary(InterfaceActionBase):
name = 'Copy To Library'
actual_plugin = 'calibre.gui2.actions.copy_to_library:CopyToLibraryAction'
description = _('Copy a book from one calibre library to another')
class ActionTweakEpub(InterfaceActionBase):
name = 'Tweak ePub'
actual_plugin = 'calibre.gui2.actions.tweak_epub:TweakEpubAction'
description = _('Edit ebooks in the epub or azw3 formats')
class ActionUnpackBook(InterfaceActionBase):
name = 'Unpack Book'
actual_plugin = 'calibre.gui2.actions.unpack_book:UnpackBookAction'
description = _('Make small changes to epub or htmlz files in your calibre library')
class ActionNextMatch(InterfaceActionBase):
name = 'Next Match'
actual_plugin = 'calibre.gui2.actions.next_match:NextMatchAction'
description = _('Find the next or previous match when searching in '
'your calibre library in highlight mode')
class ActionPickRandom(InterfaceActionBase):
name = 'Pick Random Book'
actual_plugin = 'calibre.gui2.actions.random:PickRandomAction'
description = _('Choose a random book from your calibre library')
class ActionSortBy(InterfaceActionBase):
name = 'Sort By'
actual_plugin = 'calibre.gui2.actions.sort:SortByAction'
description = _('Sort the list of books')
class ActionMarkBooks(InterfaceActionBase):
name = 'Mark Books'
actual_plugin = 'calibre.gui2.actions.mark_books:MarkBooksAction'
description = _('Temporarily mark books')
class ActionStore(InterfaceActionBase):
name = 'Store'
author = 'John Schember'
@ -981,6 +1054,7 @@ class ActionStore(InterfaceActionBase):
from calibre.gui2.store.config.store import save_settings as save
save(config_widget)
class ActionPluginUpdater(InterfaceActionBase):
name = 'Plugin Updater'
author = 'Grant Drake'
@ -1001,6 +1075,7 @@ plugins += [ActionAdd, ActionFetchAnnotations, ActionGenerateCatalog,
# Preferences Plugins {{{
class LookAndFeel(PreferencesPlugin):
name = 'Look & Feel'
icon = I('lookfeel.png')
@ -1013,6 +1088,7 @@ class LookAndFeel(PreferencesPlugin):
description = _('Adjust the look and feel of the calibre interface'
' to suit your tastes')
class Behavior(PreferencesPlugin):
name = 'Behavior'
icon = I('config.png')
@ -1024,6 +1100,7 @@ class Behavior(PreferencesPlugin):
config_widget = 'calibre.gui2.preferences.behavior'
description = _('Change the way calibre behaves')
class Columns(PreferencesPlugin):
name = 'Custom Columns'
icon = I('column.png')
@ -1035,6 +1112,7 @@ class Columns(PreferencesPlugin):
config_widget = 'calibre.gui2.preferences.columns'
description = _('Add/remove your own columns to the calibre book list')
class Toolbar(PreferencesPlugin):
name = 'Toolbar'
icon = I('wizard.png')
@ -1047,6 +1125,7 @@ class Toolbar(PreferencesPlugin):
description = _('Customize the toolbars and context menus, changing which'
' actions are available in each')
class Search(PreferencesPlugin):
name = 'Search'
icon = I('search.png')
@ -1058,6 +1137,7 @@ class Search(PreferencesPlugin):
config_widget = 'calibre.gui2.preferences.search'
description = _('Customize the way searching for books works in calibre')
class InputOptions(PreferencesPlugin):
name = 'Input Options'
icon = I('arrow-down.png')
@ -1074,6 +1154,7 @@ class InputOptions(PreferencesPlugin):
self.config_widget = 'calibre.gui2.preferences.conversion:InputOptions'
return PreferencesPlugin.create_widget(self, *args, **kwargs)
class CommonOptions(PreferencesPlugin):
name = 'Common Options'
icon = I('convert.png')
@ -1085,6 +1166,7 @@ class CommonOptions(PreferencesPlugin):
config_widget = 'calibre.gui2.preferences.conversion:CommonOptions'
description = _('Set conversion options common to all formats')
class OutputOptions(PreferencesPlugin):
name = 'Output Options'
icon = I('arrow-up.png')
@ -1096,6 +1178,7 @@ class OutputOptions(PreferencesPlugin):
config_widget = 'calibre.gui2.preferences.conversion:OutputOptions'
description = _('Set conversion options specific to each output format')
class Adding(PreferencesPlugin):
name = 'Adding'
icon = I('add_book.png')
@ -1108,6 +1191,7 @@ class Adding(PreferencesPlugin):
description = _('Control how calibre reads metadata from files when '
'adding books')
class Saving(PreferencesPlugin):
name = 'Saving'
icon = I('save.png')
@ -1120,6 +1204,7 @@ class Saving(PreferencesPlugin):
description = _('Control how calibre exports files from its database '
'to disk when using Save to disk')
class Sending(PreferencesPlugin):
name = 'Sending'
icon = I('sync.png')
@ -1132,6 +1217,7 @@ class Sending(PreferencesPlugin):
description = _('Control how calibre transfers files to your '
'ebook reader')
class Plugboard(PreferencesPlugin):
name = 'Plugboard'
icon = I('plugboard.png')
@ -1143,6 +1229,7 @@ class Plugboard(PreferencesPlugin):
config_widget = 'calibre.gui2.preferences.plugboard'
description = _('Change metadata fields before saving/sending')
class TemplateFunctions(PreferencesPlugin):
name = 'TemplateFunctions'
icon = I('template_funcs.png')
@ -1154,6 +1241,7 @@ class TemplateFunctions(PreferencesPlugin):
config_widget = 'calibre.gui2.preferences.template_functions'
description = _('Create your own template functions')
class Email(PreferencesPlugin):
name = 'Email'
icon = I('mail.png')
@ -1166,6 +1254,7 @@ class Email(PreferencesPlugin):
description = _('Setup sharing of books via email. Can be used '
'for automatic sending of downloaded news to your devices')
class Server(PreferencesPlugin):
name = 'Server'
icon = I('network-server.png')
@ -1179,6 +1268,7 @@ class Server(PreferencesPlugin):
'give you access to your calibre library from anywhere, '
'on any device, over the internet')
class MetadataSources(PreferencesPlugin):
name = 'Metadata download'
icon = I('download-metadata.png')
@ -1190,6 +1280,7 @@ class MetadataSources(PreferencesPlugin):
config_widget = 'calibre.gui2.preferences.metadata_sources'
description = _('Control how calibre downloads ebook metadata from the net')
class IgnoredDevices(PreferencesPlugin):
name = 'Ignored Devices'
icon = I('reader.png')
@ -1215,6 +1306,7 @@ class Plugins(PreferencesPlugin):
description = _('Add/remove/customize various bits of calibre '
'functionality')
class Tweaks(PreferencesPlugin):
name = 'Tweaks'
icon = I('tweaks.png')
@ -1226,6 +1318,7 @@ class Tweaks(PreferencesPlugin):
config_widget = 'calibre.gui2.preferences.tweaks'
description = _('Fine tune how calibre behaves in various contexts')
class Keyboard(PreferencesPlugin):
name = 'Keyboard'
icon = I('keyboard-prefs.png')
@ -1237,6 +1330,7 @@ class Keyboard(PreferencesPlugin):
config_widget = 'calibre.gui2.preferences.keyboard'
description = _('Customize the keyboard shortcuts used by calibre')
class Misc(PreferencesPlugin):
name = 'Misc'
icon = I('exec.png')
@ -1256,6 +1350,8 @@ plugins += [LookAndFeel, Behavior, Columns, Toolbar, Search, InputOptions,
# }}}
# Store plugins {{{
class StoreAmazonKindleStore(StoreBase):
name = 'Amazon Kindle'
description = u'Kindle books from Amazon.'
@ -1265,6 +1361,7 @@ class StoreAmazonKindleStore(StoreBase):
formats = ['KINDLE']
affiliate = False
class StoreSonyStore(StoreBase):
name = 'SONY Reader Store'
description = u'SONY Reader books.'
@ -1275,12 +1372,14 @@ class StoreSonyStore(StoreBase):
formats = ['SONY']
affiliate = False
class StoreSonyAUStore(StoreSonyStore):
name = 'SONY Reader (Australia) Store'
description = u'SONY Reader books (Australia).'
actual_plugin = 'calibre.gui2.store.stores.sony_au_plugin:SonyStore'
headquarters = 'AU'
class StoreAmazonAUKindleStore(StoreBase):
name = 'Amazon AU Kindle'
author = u'Kovid Goyal'
@ -1290,6 +1389,7 @@ class StoreAmazonAUKindleStore(StoreBase):
headquarters = 'AU'
formats = ['KINDLE']
class StoreAmazonCAKindleStore(StoreBase):
name = 'Amazon CA Kindle'
author = u'Kovid Goyal'
@ -1299,6 +1399,7 @@ class StoreAmazonCAKindleStore(StoreBase):
headquarters = 'CA'
formats = ['KINDLE']
class StoreAmazonINKindleStore(StoreBase):
name = 'Amazon IN Kindle'
author = u'Kovid Goyal'
@ -1308,6 +1409,7 @@ class StoreAmazonINKindleStore(StoreBase):
headquarters = 'IN'
formats = ['KINDLE']
class StoreAmazonDEKindleStore(StoreBase):
name = 'Amazon DE Kindle'
author = 'Kovid Goyal'
@ -1317,6 +1419,7 @@ class StoreAmazonDEKindleStore(StoreBase):
headquarters = 'DE'
formats = ['KINDLE']
class StoreAmazonFRKindleStore(StoreBase):
name = 'Amazon FR Kindle'
author = 'Kovid Goyal'
@ -1326,6 +1429,7 @@ class StoreAmazonFRKindleStore(StoreBase):
headquarters = 'FR'
formats = ['KINDLE']
class StoreAmazonITKindleStore(StoreBase):
name = 'Amazon IT Kindle'
author = 'Kovid Goyal'
@ -1335,6 +1439,7 @@ class StoreAmazonITKindleStore(StoreBase):
headquarters = 'IT'
formats = ['KINDLE']
class StoreAmazonESKindleStore(StoreBase):
name = 'Amazon ES Kindle'
author = 'Kovid Goyal'
@ -1344,6 +1449,7 @@ class StoreAmazonESKindleStore(StoreBase):
headquarters = 'ES'
formats = ['KINDLE']
class StoreAmazonUKKindleStore(StoreBase):
name = 'Amazon UK Kindle'
author = 'Kovid Goyal'
@ -1353,6 +1459,7 @@ class StoreAmazonUKKindleStore(StoreBase):
headquarters = 'UK'
formats = ['KINDLE']
class StoreArchiveOrgStore(StoreBase):
name = 'Archive.org'
description = u'An Internet library offering permanent access for researchers, historians, scholars, people with disabilities, and the general public to historical collections that exist in digital format.' # noqa
@ -1362,6 +1469,7 @@ class StoreArchiveOrgStore(StoreBase):
headquarters = 'US'
formats = ['DAISY', 'DJVU', 'EPUB', 'MOBI', 'PDF', 'TXT']
class StoreBubokPublishingStore(StoreBase):
name = 'Bubok Spain'
description = u'Bubok Publishing is a publisher, library and store of books of authors from all around the world. They have a big amount of books of a lot of topics' # noqa
@ -1371,6 +1479,7 @@ class StoreBubokPublishingStore(StoreBase):
headquarters = 'ES'
formats = ['EPUB', 'PDF']
class StoreBubokPortugalStore(StoreBase):
name = 'Bubok Portugal'
description = u'Bubok Publishing Portugal is a publisher, library and store of books of authors from Portugal. They have a big amount of books of a lot of topics' # noqa
@ -1380,6 +1489,7 @@ class StoreBubokPortugalStore(StoreBase):
headquarters = 'PT'
formats = ['EPUB', 'PDF']
class StoreBaenWebScriptionStore(StoreBase):
name = 'Baen Ebooks'
description = u'Sci-Fi & Fantasy brought to you by Jim Baen.'
@ -1389,6 +1499,7 @@ class StoreBaenWebScriptionStore(StoreBase):
headquarters = 'US'
formats = ['EPUB', 'LIT', 'LRF', 'MOBI', 'RB', 'RTF', 'ZIP']
class StoreBNStore(StoreBase):
name = 'Barnes and Noble'
description = u'The world\'s largest book seller. As the ultimate destination for book lovers, Barnes & Noble.com offers an incredible array of content.'
@ -1397,6 +1508,7 @@ class StoreBNStore(StoreBase):
headquarters = 'US'
formats = ['NOOK']
class StoreBeamEBooksDEStore(StoreBase):
name = 'Beam EBooks DE'
author = 'Charles Haley'
@ -1408,6 +1520,7 @@ class StoreBeamEBooksDEStore(StoreBase):
formats = ['EPUB', 'MOBI', 'PDF']
affiliate = True
class StoreBiblioStore(StoreBase):
name = u'Библио.бг'
author = 'Alex Stanev'
@ -1417,6 +1530,7 @@ class StoreBiblioStore(StoreBase):
headquarters = 'BG'
formats = ['EPUB, PDF']
class StoreCdpStore(StoreBase):
name = 'Cdp.pl'
author = u'Tomasz Długosz'
@ -1428,6 +1542,7 @@ class StoreCdpStore(StoreBase):
formats = ['EPUB', 'MOBI', 'PDF']
affiliate = True
class StoreChitankaStore(StoreBase):
name = u'Моята библиотека'
author = 'Alex Stanev'
@ -1438,6 +1553,7 @@ class StoreChitankaStore(StoreBase):
headquarters = 'BG'
formats = ['FB2', 'EPUB', 'TXT', 'SFB']
class StoreEbookNLStore(StoreBase):
name = 'eBook.nl'
description = u'De eBookwinkel van Nederland'
@ -1447,6 +1563,7 @@ class StoreEbookNLStore(StoreBase):
formats = ['EPUB', 'PDF']
affiliate = False
class StoreEbookpointStore(StoreBase):
name = 'Ebookpoint'
author = u'Tomasz Długosz'
@ -1458,6 +1575,7 @@ class StoreEbookpointStore(StoreBase):
formats = ['EPUB', 'MOBI', 'PDF']
affiliate = True
class StoreEbookscomStore(StoreBase):
name = 'eBooks.com'
description = u'Sells books in multiple electronic formats in all categories. Technical infrastructure is cutting edge, robust and scalable, with servers in the US and Europe.' # noqa
@ -1467,6 +1585,7 @@ class StoreEbookscomStore(StoreBase):
formats = ['EPUB', 'LIT', 'MOBI', 'PDF']
affiliate = True
class StoreEbooksGratuitsStore(StoreBase):
name = 'EbooksGratuits.com'
description = u'Ebooks Libres et Gratuits'
@ -1486,6 +1605,7 @@ class StoreEbooksGratuitsStore(StoreBase):
# formats = ['EPUB', 'PDF']
# affiliate = True
class StoreEKnigiStore(StoreBase):
name = u'еКниги'
author = 'Alex Stanev'
@ -1496,6 +1616,7 @@ class StoreEKnigiStore(StoreBase):
formats = ['EPUB', 'PDF', 'HTML']
affiliate = True
class StoreEmpikStore(StoreBase):
name = 'Empik'
author = u'Tomasz Długosz'
@ -1506,6 +1627,7 @@ class StoreEmpikStore(StoreBase):
formats = ['EPUB', 'MOBI', 'PDF']
affiliate = True
class StoreFeedbooksStore(StoreBase):
name = 'Feedbooks'
description = u'Feedbooks is a cloud publishing and distribution service, connected to a large ecosystem of reading systems and social networks. Provides a variety of genres from independent and classic books.' # noqa
@ -1514,6 +1636,7 @@ class StoreFeedbooksStore(StoreBase):
headquarters = 'FR'
formats = ['EPUB', 'MOBI', 'PDF']
class StoreGoogleBooksStore(StoreBase):
name = 'Google Books'
description = u'Google Books'
@ -1522,6 +1645,7 @@ class StoreGoogleBooksStore(StoreBase):
headquarters = 'US'
formats = ['EPUB', 'PDF', 'TXT']
class StoreGutenbergStore(StoreBase):
name = 'Project Gutenberg'
description = u'The first producer of free ebooks. Free in the United States because their copyright has expired. They may not be free of copyright in other countries. Readers outside of the United States must check the copyright laws of their countries before downloading or redistributing our ebooks.' # noqa
@ -1531,6 +1655,7 @@ class StoreGutenbergStore(StoreBase):
headquarters = 'US'
formats = ['EPUB', 'HTML', 'MOBI', 'PDB', 'TXT']
class StoreKoboStore(StoreBase):
name = 'Kobo'
description = u'With over 2.3 million eBooks to browse we have engaged readers in over 200 countries in Kobo eReading. Our eBook listings include New York Times Bestsellers, award winners, classics and more!' # noqa
@ -1540,6 +1665,7 @@ class StoreKoboStore(StoreBase):
formats = ['EPUB']
affiliate = True
class StoreKoobeStore(StoreBase):
name = 'Koobe'
author = u'Tomasz Długosz'
@ -1551,6 +1677,7 @@ class StoreKoobeStore(StoreBase):
formats = ['EPUB', 'MOBI', 'PDF']
affiliate = True
class StoreLegimiStore(StoreBase):
name = 'Legimi'
author = u'Tomasz Długosz'
@ -1561,6 +1688,7 @@ class StoreLegimiStore(StoreBase):
formats = ['EPUB', 'PDF', 'MOBI']
affiliate = True
class StoreLibreDEStore(StoreBase):
name = 'ebook.de'
author = 'Charles Haley'
@ -1571,6 +1699,7 @@ class StoreLibreDEStore(StoreBase):
formats = ['EPUB', 'PDF']
affiliate = True
class StoreLitResStore(StoreBase):
name = 'LitRes'
description = u'ebooks from LitRes.ru'
@ -1582,6 +1711,7 @@ class StoreLitResStore(StoreBase):
formats = ['EPUB', 'TXT', 'RTF', 'HTML', 'FB2', 'LRF', 'PDF', 'MOBI', 'LIT', 'ISILO3', 'JAR', 'RB', 'PRC']
affiliate = True
class StoreManyBooksStore(StoreBase):
name = 'ManyBooks'
description = u'Public domain and creative commons works from many sources.'
@ -1591,6 +1721,7 @@ class StoreManyBooksStore(StoreBase):
headquarters = 'US'
formats = ['EPUB', 'FB2', 'JAR', 'LIT', 'LRF', 'MOBI', 'PDB', 'PDF', 'RB', 'RTF', 'TCR', 'TXT', 'ZIP']
class StoreMillsBoonUKStore(StoreBase):
name = 'Mills and Boon UK'
author = 'Charles Haley'
@ -1601,6 +1732,7 @@ class StoreMillsBoonUKStore(StoreBase):
formats = ['EPUB']
affiliate = True
class StoreMobileReadStore(StoreBase):
name = 'MobileRead'
description = u'Ebooks handcrafted with the utmost care.'
@ -1610,6 +1742,7 @@ class StoreMobileReadStore(StoreBase):
headquarters = 'CH'
formats = ['EPUB', 'IMP', 'LRF', 'LIT', 'MOBI', 'PDF']
class StoreNextoStore(StoreBase):
name = 'Nexto'
author = u'Tomasz Długosz'
@ -1620,6 +1753,7 @@ class StoreNextoStore(StoreBase):
formats = ['EPUB', 'MOBI', 'PDF']
affiliate = True
class StoreNookUKStore(StoreBase):
name = 'Nook UK'
author = 'Charles Haley'
@ -1629,6 +1763,7 @@ class StoreNookUKStore(StoreBase):
headquarters = 'UK'
formats = ['NOOK']
class StoreOpenBooksStore(StoreBase):
name = 'Open Books'
description = u'Comprehensive listing of DRM free ebooks from a variety of sources provided by users of calibre.'
@ -1637,6 +1772,7 @@ class StoreOpenBooksStore(StoreBase):
drm_free_only = True
headquarters = 'US'
class StoreOzonRUStore(StoreBase):
name = 'OZON.ru'
description = u'ebooks from OZON.ru'
@ -1648,6 +1784,7 @@ class StoreOzonRUStore(StoreBase):
formats = ['TXT', 'PDF', 'DJVU', 'RTF', 'DOC', 'JAR', 'FB2']
affiliate = True
class StorePragmaticBookshelfStore(StoreBase):
name = 'Pragmatic Bookshelf'
description = u'The Pragmatic Bookshelf\'s collection of programming and tech books avaliable as ebooks.'
@ -1657,6 +1794,7 @@ class StorePragmaticBookshelfStore(StoreBase):
headquarters = 'US'
formats = ['EPUB', 'MOBI', 'PDF']
class StorePublioStore(StoreBase):
name = 'Publio'
description = u'Publio.pl to księgarnia internetowa, w której mogą Państwo nabyć e-booki i audiobooki.'
@ -1667,6 +1805,7 @@ class StorePublioStore(StoreBase):
formats = ['EPUB', 'MOBI', 'PDF']
affiliate = True
class StoreRW2010Store(StoreBase):
name = 'RW2010'
description = u'Polski serwis self-publishingowy. Pliki PDF, EPUB i MOBI. Maksymalna cena utworu nie przekracza u nas 10 złotych!'
@ -1677,6 +1816,7 @@ class StoreRW2010Store(StoreBase):
headquarters = 'PL'
formats = ['EPUB', 'MOBI', 'PDF']
class StoreSmashwordsStore(StoreBase):
name = 'Smashwords'
description = u'An ebook publishing and distribution platform for ebook authors, publishers and readers. Covers many genres and formats.'
@ -1687,6 +1827,7 @@ class StoreSmashwordsStore(StoreBase):
formats = ['EPUB', 'HTML', 'LRF', 'MOBI', 'PDB', 'RTF', 'TXT']
affiliate = True
class StoreVirtualoStore(StoreBase):
name = 'Virtualo'
author = u'Tomasz Długosz'
@ -1697,6 +1838,7 @@ class StoreVirtualoStore(StoreBase):
formats = ['EPUB', 'MOBI', 'PDF']
affiliate = True
class StoreWaterstonesUKStore(StoreBase):
name = 'Waterstones UK'
author = 'Charles Haley'
@ -1707,6 +1849,7 @@ class StoreWaterstonesUKStore(StoreBase):
formats = ['EPUB', 'PDF']
affiliate = False
class StoreWeightlessBooksStore(StoreBase):
name = 'Weightless Books'
description = u'An independent DRM-free ebooksite devoted to ebooks of all sorts.'
@ -1716,6 +1859,7 @@ class StoreWeightlessBooksStore(StoreBase):
headquarters = 'US'
formats = ['EPUB', 'HTML', 'LIT', 'MOBI', 'PDF']
class StoreWHSmithUKStore(StoreBase):
name = 'WH Smith UK'
author = 'Charles Haley'
@ -1725,6 +1869,7 @@ class StoreWHSmithUKStore(StoreBase):
headquarters = 'UK'
formats = ['EPUB', 'PDF']
class StoreWolneLekturyStore(StoreBase):
name = 'Wolne Lektury'
author = u'Tomasz Długosz'
@ -1734,6 +1879,7 @@ class StoreWolneLekturyStore(StoreBase):
headquarters = 'PL'
formats = ['EPUB', 'MOBI', 'PDF', 'TXT', 'FB2']
class StoreWoblinkStore(StoreBase):
name = 'Woblink'
author = u'Tomasz Długosz'
@ -1744,6 +1890,7 @@ class StoreWoblinkStore(StoreBase):
formats = ['EPUB', 'MOBI', 'PDF', 'WOBLINK']
affiliate = True
class XinXiiStore(StoreBase):
name = 'XinXii'
description = ''

View File

@ -7,6 +7,7 @@ import re, os, shutil
from calibre import CurrentDir
from calibre.customize import Plugin
class ConversionOption(object):
'''
@ -46,6 +47,7 @@ class ConversionOption(object):
long_switch=self.long_switch, short_switch=self.short_switch,
choices=self.choices)
class OptionRecommendation(object):
LOW = 1
MED = 2
@ -82,6 +84,7 @@ class OptionRecommendation(object):
repr(self.recommended_value) +
' is not a string or a number')
class DummyReporter(object):
def __init__(self):
@ -90,6 +93,7 @@ class DummyReporter(object):
def __call__(self, percent, msg=''):
pass
def gui_configuration_widget(name, parent, get_option_by_name,
get_option_help, db, book_id, for_output=True):
import importlib

View File

@ -39,6 +39,8 @@ class Plugin(_Plugin):
self.height_pts = self.height * 72./self.dpi
# Input profiles {{{
class InputProfile(Plugin):
author = 'Kovid Goyal'
@ -64,6 +66,7 @@ class SonyReaderInput(InputProfile):
fbase = 12
fsizes = [7.5, 9, 10, 12, 15.5, 20, 22, 24]
class SonyReader300Input(SonyReaderInput):
name = 'Sony Reader 300'
@ -72,6 +75,7 @@ class SonyReader300Input(SonyReaderInput):
dpi = 200
class SonyReader900Input(SonyReaderInput):
author = 'John Schember'
@ -81,6 +85,7 @@ class SonyReader900Input(SonyReaderInput):
screen_size = (584, 978)
class MSReaderInput(InputProfile):
name = 'Microsoft Reader'
@ -92,6 +97,7 @@ class MSReaderInput(InputProfile):
fbase = 13
fsizes = [10, 11, 13, 16, 18, 20, 22, 26]
class MobipocketInput(InputProfile):
name = 'Mobipocket Books'
@ -105,6 +111,7 @@ class MobipocketInput(InputProfile):
fbase = 18
fsizes = [14, 14, 16, 18, 20, 22, 24, 26]
class HanlinV3Input(InputProfile):
name = 'Hanlin V3'
@ -117,6 +124,7 @@ class HanlinV3Input(InputProfile):
fbase = 16
fsizes = [12, 12, 14, 16, 18, 20, 22, 24]
class HanlinV5Input(HanlinV3Input):
name = 'Hanlin V5'
@ -127,6 +135,7 @@ class HanlinV5Input(HanlinV3Input):
screen_size = (584, 754)
dpi = 200
class CybookG3Input(InputProfile):
name = 'Cybook G3'
@ -139,6 +148,7 @@ class CybookG3Input(InputProfile):
fbase = 16
fsizes = [12, 12, 14, 16, 18, 20, 22, 24]
class CybookOpusInput(InputProfile):
author = 'John Schember'
@ -152,6 +162,7 @@ class CybookOpusInput(InputProfile):
fbase = 16
fsizes = [12, 12, 14, 16, 18, 20, 22, 24]
class KindleInput(InputProfile):
name = 'Kindle'
@ -164,6 +175,7 @@ class KindleInput(InputProfile):
fbase = 16
fsizes = [12, 12, 14, 16, 18, 20, 22, 24]
class IlliadInput(InputProfile):
name = 'Illiad'
@ -175,6 +187,7 @@ class IlliadInput(InputProfile):
fbase = 12
fsizes = [7.5, 9, 10, 12, 15.5, 20, 22, 24]
class IRexDR1000Input(InputProfile):
author = 'John Schember'
@ -188,6 +201,7 @@ class IRexDR1000Input(InputProfile):
fbase = 16
fsizes = [12, 14, 16, 18, 20, 22, 24]
class IRexDR800Input(InputProfile):
author = 'Eric Cronin'
@ -200,6 +214,7 @@ class IRexDR800Input(InputProfile):
fbase = 16
fsizes = [12, 14, 16, 18, 20, 22, 24]
class NookInput(InputProfile):
author = 'John Schember'
@ -222,6 +237,7 @@ input_profiles.sort(cmp=lambda x,y:cmp(x.name.lower(), y.name.lower()))
# }}}
class OutputProfile(Plugin):
author = 'Kovid Goyal'
@ -424,6 +440,7 @@ class iPadOutput(OutputProfile):
'''
# }}}
class iPad3Output(iPadOutput):
screen_size = comic_screen_size = (2048, 1536)
@ -433,6 +450,7 @@ class iPad3Output(iPadOutput):
description = _('Intended for the iPad 3 and similar devices with a '
'resolution of 1536x2048')
class TabletOutput(iPadOutput):
name = 'Tablet'
short_name = 'tablet'
@ -441,6 +459,7 @@ class TabletOutput(iPadOutput):
screen_size = (10000, 10000)
comic_screen_size = (10000, 10000)
class SamsungGalaxy(TabletOutput):
name = 'Samsung Galaxy'
short_name = 'galaxy'
@ -448,6 +467,7 @@ class SamsungGalaxy(TabletOutput):
'a resolution of 600x1280')
screen_size = comic_screen_size = (600, 1280)
class NookHD(TabletOutput):
name = 'Nook HD+'
short_name = 'nook_hd_plus'
@ -455,6 +475,7 @@ class NookHD(TabletOutput):
'a resolution of 1280x1920')
screen_size = comic_screen_size = (1280, 1920)
class SonyReaderOutput(OutputProfile):
name = 'Sony Reader'
@ -485,6 +506,7 @@ class KoboReaderOutput(OutputProfile):
fbase = 12
fsizes = [7.5, 9, 10, 12, 15.5, 20, 22, 24]
class SonyReader300Output(SonyReaderOutput):
author = 'John Schember'
@ -494,6 +516,7 @@ class SonyReader300Output(SonyReaderOutput):
dpi = 200
class SonyReader900Output(SonyReaderOutput):
author = 'John Schember'
@ -504,6 +527,7 @@ class SonyReader900Output(SonyReaderOutput):
screen_size = (600, 999)
comic_screen_size = screen_size
class SonyReaderT3Output(SonyReaderOutput):
author = 'Kovid Goyal'
@ -522,6 +546,7 @@ class GenericEink(SonyReaderOutput):
description = _('Suitable for use with any e-ink device')
epub_periodical_format = None
class GenericEinkLarge(GenericEink):
name = 'Generic e-ink large'
@ -531,6 +556,7 @@ class GenericEinkLarge(GenericEink):
screen_size = (600, 999)
comic_screen_size = screen_size
class GenericEinkHD(GenericEink):
name = 'Generic e-ink HD'
@ -550,6 +576,7 @@ class JetBook5Output(OutputProfile):
screen_size = (480, 640)
dpi = 168.451
class SonyReaderLandscapeOutput(SonyReaderOutput):
name = 'Sony Reader Landscape'
@ -561,6 +588,7 @@ class SonyReaderLandscapeOutput(SonyReaderOutput):
screen_size = (784, 1012)
comic_screen_size = (784, 1012)
class MSReaderOutput(OutputProfile):
name = 'Microsoft Reader'
@ -572,6 +600,7 @@ class MSReaderOutput(OutputProfile):
fbase = 13
fsizes = [10, 11, 13, 16, 18, 20, 22, 26]
class MobipocketOutput(OutputProfile):
name = 'Mobipocket Books'
@ -585,6 +614,7 @@ class MobipocketOutput(OutputProfile):
fbase = 18
fsizes = [14, 14, 16, 18, 20, 22, 24, 26]
class HanlinV3Output(OutputProfile):
name = 'Hanlin V3'
@ -597,6 +627,7 @@ class HanlinV3Output(OutputProfile):
fbase = 16
fsizes = [12, 12, 14, 16, 18, 20, 22, 24]
class HanlinV5Output(HanlinV3Output):
name = 'Hanlin V5'
@ -605,6 +636,7 @@ class HanlinV5Output(HanlinV3Output):
dpi = 200
class CybookG3Output(OutputProfile):
name = 'Cybook G3'
@ -618,6 +650,7 @@ class CybookG3Output(OutputProfile):
fbase = 16
fsizes = [12, 12, 14, 16, 18, 20, 22, 24]
class CybookOpusOutput(SonyReaderOutput):
author = 'John Schember'
@ -632,6 +665,7 @@ class CybookOpusOutput(SonyReaderOutput):
epub_periodical_format = None
class KindleOutput(OutputProfile):
name = 'Kindle'
@ -651,6 +685,7 @@ class KindleOutput(OutputProfile):
mobi_ems_per_blockquote = 2.0
class KindleDXOutput(OutputProfile):
name = 'Kindle DX'
@ -668,6 +703,7 @@ class KindleDXOutput(OutputProfile):
ratings_char = u'\u2605'
mobi_ems_per_blockquote = 2.0
class KindlePaperWhiteOutput(KindleOutput):
name = 'Kindle PaperWhite'
@ -679,6 +715,7 @@ class KindlePaperWhiteOutput(KindleOutput):
dpi = 212.0
comic_screen_size = screen_size
class KindleVoyageOutput(KindleOutput):
name = 'Kindle Voyage'
@ -691,6 +728,7 @@ class KindleVoyageOutput(KindleOutput):
dpi = 300.0
comic_screen_size = screen_size
class KindlePaperWhite3Output(KindleVoyageOutput):
name = 'Kindle PaperWhite 3'
@ -713,6 +751,7 @@ class KindleFireOutput(KindleDXOutput):
dpi = 169.0
comic_screen_size = (570, 1016)
class IlliadOutput(OutputProfile):
name = 'Illiad'
@ -725,6 +764,7 @@ class IlliadOutput(OutputProfile):
fbase = 12
fsizes = [7.5, 9, 10, 12, 15.5, 20, 22, 24]
class IRexDR1000Output(OutputProfile):
author = 'John Schember'
@ -739,6 +779,7 @@ class IRexDR1000Output(OutputProfile):
fbase = 16
fsizes = [12, 14, 16, 18, 20, 22, 24]
class IRexDR800Output(OutputProfile):
author = 'Eric Cronin'
@ -753,6 +794,7 @@ class IRexDR800Output(OutputProfile):
fbase = 16
fsizes = [12, 14, 16, 18, 20, 22, 24]
class NookOutput(OutputProfile):
author = 'John Schember'
@ -767,6 +809,7 @@ class NookOutput(OutputProfile):
fbase = 16
fsizes = [12, 12, 14, 16, 18, 20, 22, 24]
class NookColorOutput(NookOutput):
name = 'Nook Color'
short_name = 'nook_color'
@ -776,6 +819,7 @@ class NookColorOutput(NookOutput):
comic_screen_size = (594, 900)
dpi = 169
class PocketBook900Output(OutputProfile):
author = 'Chris Lockfort'
@ -787,6 +831,7 @@ class PocketBook900Output(OutputProfile):
dpi = 150.0
comic_screen_size = screen_size
class PocketBookPro912Output(OutputProfile):
author = 'Daniele Pizzolli'

View File

@ -24,9 +24,11 @@ from calibre.constants import DEBUG
builtin_names = frozenset([p.name for p in builtin_plugins])
class NameConflict(ValueError):
pass
def _config():
c = Config('customize')
c.add_opt('plugins', default={}, help=_('Installed plugins'))
@ -58,6 +60,7 @@ def load_plugin(path_to_zip_file): # {{{
# Enable/disable plugins {{{
def disable_plugin(plugin_or_name):
x = getattr(plugin_or_name, 'name', plugin_or_name)
plugin = find_plugin(x)
@ -71,6 +74,7 @@ def disable_plugin(plugin_or_name):
ep.remove(x)
config['enabled_plugins'] = ep
def enable_plugin(plugin_or_name):
x = getattr(plugin_or_name, 'name', plugin_or_name)
dp = config['disabled_plugins']
@ -81,6 +85,7 @@ def enable_plugin(plugin_or_name):
ep.add(x)
config['enabled_plugins'] = ep
def restore_plugin_state_to_default(plugin_or_name):
x = getattr(plugin_or_name, 'name', plugin_or_name)
dp = config['disabled_plugins']
@ -96,6 +101,7 @@ default_disabled_plugins = set([
'Overdrive', 'Douban Books', 'OZON.ru', 'Edelweiss', 'Google Images', 'Big Book Search',
])
def is_disabled(plugin):
if plugin.name in config['enabled_plugins']:
return False
@ -111,6 +117,7 @@ _on_preprocess = {}
_on_postprocess = {}
_on_postadd = []
def reread_filetype_plugins():
global _on_import
global _on_postimport
@ -171,6 +178,7 @@ run_plugins_on_preprocess = functools.partial(_run_filetype_plugins,
run_plugins_on_postprocess = functools.partial(_run_filetype_plugins,
occasion='postprocess')
def run_plugins_on_postimport(db, book_id, fmt):
customization = config['plugin_customization']
fmt = fmt.lower()
@ -186,6 +194,7 @@ def run_plugins_on_postimport(db, book_id, fmt):
plugin.name)
traceback.print_exc()
def run_plugins_on_postadd(db, book_id, fmt_map):
customization = config['plugin_customization']
for plugin in _on_postadd:
@ -203,22 +212,28 @@ def run_plugins_on_postadd(db, book_id, fmt_map):
# }}}
# Plugin customization {{{
def customize_plugin(plugin, custom):
d = config['plugin_customization']
d[plugin.name] = custom.strip()
config['plugin_customization'] = d
def plugin_customization(plugin):
return config['plugin_customization'].get(plugin.name, '')
# }}}
# Input/Output profiles {{{
def input_profiles():
for plugin in _initialized_plugins:
if isinstance(plugin, InputProfile):
yield plugin
def output_profiles():
for plugin in _initialized_plugins:
if isinstance(plugin, OutputProfile):
@ -227,6 +242,7 @@ def output_profiles():
# Interface Actions # {{{
def interface_actions():
customization = config['plugin_customization']
for plugin in _initialized_plugins:
@ -238,6 +254,7 @@ def interface_actions():
# Preferences Plugins # {{{
def preferences_plugins():
customization = config['plugin_customization']
for plugin in _initialized_plugins:
@ -248,6 +265,8 @@ def preferences_plugins():
# }}}
# Library Closed Plugins # {{{
def available_library_closed_plugins():
customization = config['plugin_customization']
for plugin in _initialized_plugins:
@ -256,6 +275,7 @@ def available_library_closed_plugins():
plugin.site_customization = customization.get(plugin.name, '')
yield plugin
def has_library_closed_plugins():
for plugin in _initialized_plugins:
if isinstance(plugin, LibraryClosedPlugin):
@ -266,6 +286,7 @@ def has_library_closed_plugins():
# Store Plugins # {{{
def store_plugins():
customization = config['plugin_customization']
for plugin in _initialized_plugins:
@ -273,17 +294,20 @@ def store_plugins():
plugin.site_customization = customization.get(plugin.name, '')
yield plugin
def available_store_plugins():
for plugin in store_plugins():
if not is_disabled(plugin):
yield plugin
def stores():
stores = set([])
for plugin in store_plugins():
stores.add(plugin.name)
return stores
def available_stores():
stores = set([])
for plugin in available_store_plugins():
@ -295,6 +319,8 @@ def available_stores():
# Metadata read/write {{{
_metadata_readers = {}
_metadata_writers = {}
def reread_metadata_plugins():
global _metadata_readers
global _metadata_writers
@ -308,6 +334,7 @@ def reread_metadata_plugins():
for ft in plugin.file_types:
_metadata_writers[ft].append(plugin)
def metadata_readers():
ans = set([])
for plugins in _metadata_readers.values():
@ -315,6 +342,7 @@ def metadata_readers():
ans.add(plugin)
return ans
def metadata_writers():
ans = set([])
for plugins in _metadata_writers.values():
@ -322,6 +350,7 @@ def metadata_writers():
ans.add(plugin)
return ans
class QuickMetadata(object):
def __init__(self):
@ -335,6 +364,7 @@ class QuickMetadata(object):
quick_metadata = QuickMetadata()
class ApplyNullMetadata(object):
def __init__(self):
@ -348,6 +378,7 @@ class ApplyNullMetadata(object):
apply_null_metadata = ApplyNullMetadata()
class ForceIdentifiers(object):
def __init__(self):
@ -361,6 +392,7 @@ class ForceIdentifiers(object):
force_identifiers = ForceIdentifiers()
def get_file_type_metadata(stream, ftype):
mi = MetaInformation(None, None)
@ -380,6 +412,7 @@ def get_file_type_metadata(stream, ftype):
continue
return mi
def set_file_type_metadata(stream, mi, ftype, report_error=None):
ftype = ftype.lower().strip()
if ftype in _metadata_writers:
@ -401,6 +434,7 @@ def set_file_type_metadata(stream, mi, ftype, report_error=None):
else:
report_error(mi, ftype, traceback.format_exc())
def can_set_metadata(ftype):
ftype = ftype.lower().strip()
for plugin in _metadata_writers.get(ftype, ()):
@ -412,6 +446,7 @@ def can_set_metadata(ftype):
# Add/remove plugins {{{
def add_plugin(path_to_zip_file):
make_config_dir()
plugin = load_plugin(path_to_zip_file)
@ -429,6 +464,7 @@ def add_plugin(path_to_zip_file):
initialize_plugins()
return plugin
def remove_plugin(plugin_or_name):
name = getattr(plugin_or_name, 'name', plugin_or_name)
plugins = config['plugins']
@ -453,11 +489,13 @@ def remove_plugin(plugin_or_name):
# Input/Output format plugins {{{
def input_format_plugins():
for plugin in _initialized_plugins:
if isinstance(plugin, InputFormatPlugin):
yield plugin
def plugin_for_input_format(fmt):
customization = config['plugin_customization']
for plugin in input_format_plugins():
@ -465,6 +503,7 @@ def plugin_for_input_format(fmt):
plugin.site_customization = customization.get(plugin.name, None)
return plugin
def all_input_formats():
formats = set()
for plugin in input_format_plugins():
@ -472,6 +511,7 @@ def all_input_formats():
formats.add(format)
return formats
def available_input_formats():
formats = set()
for plugin in input_format_plugins():
@ -487,6 +527,7 @@ def output_format_plugins():
if isinstance(plugin, OutputFormatPlugin):
yield plugin
def plugin_for_output_format(fmt):
customization = config['plugin_customization']
for plugin in output_format_plugins():
@ -494,6 +535,7 @@ def plugin_for_output_format(fmt):
plugin.site_customization = customization.get(plugin.name, None)
return plugin
def available_output_formats():
formats = set([])
for plugin in output_format_plugins():
@ -505,11 +547,13 @@ def available_output_formats():
# Catalog plugins {{{
def catalog_plugins():
for plugin in _initialized_plugins:
if isinstance(plugin, CatalogPlugin):
yield plugin
def available_catalog_formats():
formats = set([])
for plugin in catalog_plugins():
@ -518,6 +562,7 @@ def available_catalog_formats():
formats.add(format)
return formats
def plugin_for_catalog_format(fmt):
for plugin in catalog_plugins():
if fmt.lower() in plugin.file_types:
@ -526,6 +571,8 @@ def plugin_for_catalog_format(fmt):
# }}}
# Device plugins {{{
def device_plugins(include_disabled=False):
for plugin in _initialized_plugins:
if isinstance(plugin, DevicePlugin):
@ -536,6 +583,7 @@ def device_plugins(include_disabled=False):
plugin.do_delayed_plugin_initialization()
yield plugin
def disabled_device_plugins():
for plugin in _initialized_plugins:
if isinstance(plugin, DevicePlugin):
@ -545,6 +593,8 @@ def disabled_device_plugins():
# }}}
# Metadata sources2 {{{
def metadata_plugins(capabilities):
capabilities = frozenset(capabilities)
for plugin in all_metadata_plugins():
@ -552,6 +602,7 @@ def metadata_plugins(capabilities):
not is_disabled(plugin):
yield plugin
def all_metadata_plugins():
for plugin in _initialized_plugins:
if isinstance(plugin, Source):
@ -559,6 +610,8 @@ def all_metadata_plugins():
# }}}
# Viewer plugins {{{
def all_viewer_plugins():
for plugin in _initialized_plugins:
if isinstance(plugin, ViewerPlugin):
@ -566,6 +619,8 @@ def all_viewer_plugins():
# }}}
# Editor plugins {{{
def all_edit_book_tool_plugins():
for plugin in _initialized_plugins:
if isinstance(plugin, EditBookToolPlugin):
@ -576,6 +631,7 @@ def all_edit_book_tool_plugins():
_initialized_plugins = []
def initialize_plugin(plugin, path_to_zip_file):
try:
p = plugin(path_to_zip_file)
@ -587,10 +643,12 @@ def initialize_plugin(plugin, path_to_zip_file):
raise InvalidPlugin((_('Initialization of plugin %s failed with traceback:')
%tb) + '\n'+tb)
def has_external_plugins():
'True if there are updateable (zip file based) plugins'
return bool(config['plugins'])
def initialize_plugins(perf=False):
global _initialized_plugins
_initialized_plugins = []
@ -638,6 +696,7 @@ def initialize_plugins(perf=False):
initialize_plugins()
def initialized_plugins():
for plugin in _initialized_plugins:
yield plugin
@ -646,6 +705,7 @@ def initialized_plugins():
# CLI {{{
def build_plugin(path):
from calibre import prints
from calibre.ptempfile import PersistentTemporaryFile
@ -663,6 +723,7 @@ def build_plugin(path):
os.remove(t.name)
prints(u'Plugin updated:', plugin.name, plugin.version)
def option_parser():
parser = OptionParser(usage=_('''\
%prog options
@ -687,6 +748,7 @@ def option_parser():
help=_('Disable the named plugin'))
return parser
def main(args=sys.argv):
parser = option_parser()
if len(args) < 2:

View File

@ -20,6 +20,7 @@ from calibre.customize import (Plugin, numeric_version, platform,
# python 2.x that prevents importing from zip files in locations whose paths
# have non ASCII characters
def get_resources(zfp, name_or_list_of_names):
'''
Load resources from the plugin zip file
@ -48,6 +49,7 @@ def get_resources(zfp, name_or_list_of_names):
return ans
def get_icons(zfp, name_or_list_of_names):
'''
Load icons from the plugin zip file
@ -83,6 +85,7 @@ def get_icons(zfp, name_or_list_of_names):
_translations_cache = {}
def load_translations(namespace, zfp):
null = object()
trans = _translations_cache.get(zfp, null)
@ -109,6 +112,7 @@ def load_translations(namespace, zfp):
namespace['_'] = trans.ugettext
namespace['ngettext'] = trans.ungettext
class PluginLoader(object):
def __init__(self):

View File

@ -9,6 +9,7 @@ __docformat__ = 'restructuredtext en'
SPOOL_SIZE = 30*1024*1024
def _get_next_series_num_for_list(series_indices, unwrap=True):
from calibre.utils.config_base import tweaks
from math import ceil, floor
@ -39,6 +40,7 @@ def _get_next_series_num_for_list(series_indices, unwrap=True):
return float(tweaks['series_index_auto_increment'])
return 1.0
def _get_series_values(val):
import re
series_index_pat = re.compile(r'(.*)\s+\[([.0-9]+)\]$')
@ -54,6 +56,7 @@ def _get_series_values(val):
pass
return (val, None)
def get_data_as_dict(self, prefix=None, authors_as_string=False, ids=None, convert_to_local_tz=True):
'''
Return all metadata stored in the database as a dict. Includes paths to

View File

@ -12,20 +12,25 @@ from future_builtins import map
from calibre.ebooks import BOOK_EXTENSIONS
def splitext(path):
key, ext = os.path.splitext(path)
return key, ext[1:].lower()
def formats_ok(formats):
return len(formats) > 0
def path_ok(path):
return not os.path.isdir(path) and os.access(path, os.R_OK)
def compile_glob(pat):
import fnmatch
return re.compile(fnmatch.translate(pat), flags=re.I)
def compile_rule(rule):
mt = rule['match_type']
if 'with' in mt:
@ -45,6 +50,7 @@ def compile_rule(rule):
ans = lambda filename: not func(filename)
return ans, rule['action'] == 'add'
def filter_filename(compiled_rules, filename):
for q, action in compiled_rules:
if q(filename):
@ -52,6 +58,7 @@ def filter_filename(compiled_rules, filename):
_metadata_extensions = None
def metadata_extensions():
# Set of all known book extensions + OPF (the OPF is used to read metadata,
# but not actually added)
@ -60,6 +67,7 @@ def metadata_extensions():
_metadata_extensions = frozenset(map(unicode, BOOK_EXTENSIONS)) | {'opf'}
return _metadata_extensions
def listdir(root, sort_by_mtime=False):
items = (os.path.join(root, x) for x in os.listdir(root))
if sort_by_mtime:
@ -74,12 +82,14 @@ def listdir(root, sort_by_mtime=False):
if path_ok(path):
yield path
def allow_path(path, ext, compiled_rules):
ans = filter_filename(compiled_rules, os.path.basename(path))
if ans is None:
ans = ext in metadata_extensions()
return ans
def find_books_in_directory(dirpath, single_book_per_directory, compiled_rules=(), listdir_impl=listdir):
dirpath = os.path.abspath(dirpath)
if single_book_per_directory:
@ -101,6 +111,7 @@ def find_books_in_directory(dirpath, single_book_per_directory, compiled_rules=(
if formats_ok(formats):
yield list(formats.itervalues())
def import_book_directory_multiple(db, dirpath, callback=None,
added_ids=None, compiled_rules=()):
from calibre.ebooks.metadata.meta import metadata_from_formats
@ -121,6 +132,7 @@ def import_book_directory_multiple(db, dirpath, callback=None,
break
return duplicates
def import_book_directory(db, dirpath, callback=None, added_ids=None, compiled_rules=()):
from calibre.ebooks.metadata.meta import metadata_from_formats
dirpath = os.path.abspath(dirpath)
@ -140,6 +152,7 @@ def import_book_directory(db, dirpath, callback=None, added_ids=None, compiled_r
if callable(callback):
callback(mi.title)
def recursive_import(db, root, single_book_per_directory=True,
callback=None, added_ids=None, compiled_rules=()):
root = os.path.abspath(root)
@ -156,6 +169,7 @@ def recursive_import(db, root, single_book_per_directory=True,
break
return duplicates
def add_catalog(cache, path, title, dbapi=None):
from calibre.ebooks.metadata.book.base import Metadata
from calibre.ebooks.metadata.meta import get_metadata
@ -189,6 +203,7 @@ def add_catalog(cache, path, title, dbapi=None):
return db_id, new_book_added
def add_news(cache, path, arg, dbapi=None):
from calibre.ebooks.metadata.meta import get_metadata
from calibre.utils.date import utcnow

View File

@ -65,6 +65,7 @@ class DynamicFilter(object): # {{{
self.ids = frozenset(ids)
# }}}
class DBPrefs(dict): # {{{
'Store preferences as key:value pairs in the db'
@ -160,6 +161,8 @@ class DBPrefs(dict): # {{{
# }}}
# Extra collators {{{
def pynocase(one, two, encoding='utf-8'):
if isbytestring(one):
try:
@ -173,11 +176,13 @@ def pynocase(one, two, encoding='utf-8'):
pass
return cmp(one.lower(), two.lower())
def _author_to_author_sort(x):
if not x:
return ''
return author_to_author_sort(x.replace('|', ','))
def icu_collator(s1, s2):
return cmp(sort_key(force_unicode(s1, 'utf-8')),
sort_key(force_unicode(s2, 'utf-8')))
@ -185,6 +190,8 @@ def icu_collator(s1, s2):
# }}}
# Unused aggregators {{{
def Concatenate(sep=','):
'''String concatenation aggregator for sqlite'''
@ -199,6 +206,7 @@ def Concatenate(sep=','):
return ([], step, finalize)
def SortedConcatenate(sep=','):
'''String concatenation aggregator for sqlite, sorted by supplied index'''
@ -213,6 +221,7 @@ def SortedConcatenate(sep=','):
return ({}, step, finalize)
def IdentifiersConcat():
'''String concatenation aggregator for the identifiers map'''
@ -224,6 +233,7 @@ def IdentifiersConcat():
return ([], step, finalize)
def AumSortedConcatenate():
'''String concatenation aggregator for the author sort map'''
@ -244,6 +254,7 @@ def AumSortedConcatenate():
# }}}
class Connection(apsw.Connection): # {{{
BUSY_TIMEOUT = 10000 # milliseconds
@ -304,6 +315,7 @@ class Connection(apsw.Connection): # {{{
# }}}
class DB(object):
PATH_LIMIT = 40 if iswindows else 100
@ -1626,6 +1638,7 @@ class DB(object):
def get_custom_book_data(self, name, book_ids, default=None):
book_ids = frozenset(book_ids)
def safe_load(val):
try:
return json.loads(val, object_hook=from_json)

View File

@ -13,9 +13,11 @@ from threading import Thread, Event
from calibre import prints
from calibre.ebooks.metadata.opf2 import metadata_to_opf
class Abort(Exception):
pass
class MetadataBackup(Thread):
'''
Continuously backup changed metadata into OPF files

View File

@ -35,20 +35,24 @@ from calibre.utils.config import prefs, tweaks
from calibre.utils.date import now as nowf, utcnow, UNDEFINED_DATE
from calibre.utils.icu import sort_key
def api(f):
f.is_cache_api = True
return f
def read_api(f):
f = api(f)
f.is_read_api = True
return f
def write_api(f):
f = api(f)
f.is_read_api = False
return f
def wrap_simple(lock, func):
@wraps(func)
def call_func_with_lock(*args, **kwargs):
@ -62,6 +66,7 @@ def wrap_simple(lock, func):
return func(*args, **kwargs)
return call_func_with_lock
def run_import_plugins(path_or_stream, fmt):
fmt = fmt.lower()
if hasattr(path_or_stream, 'seek'):
@ -74,6 +79,7 @@ def run_import_plugins(path_or_stream, fmt):
path = path_or_stream
return run_plugins_on_import(path, fmt)
def _add_newbook_tag(mi):
tags = prefs['new_book_tags']
if tags:
@ -86,6 +92,7 @@ def _add_newbook_tag(mi):
dynamic_category_preferences = frozenset({'grouped_search_make_user_categories', 'grouped_search_terms', 'user_categories'})
class Cache(object):
'''
@ -804,6 +811,7 @@ class Cache(object):
path = self._field_for('path', book_id).replace('/', os.sep)
except:
return ()
def verify(fmt):
try:
name = self.fields['formats'].format_fname(book_id, fmt)
@ -918,6 +926,7 @@ class Cache(object):
return virtual_fields[fm.get(field, field)].sort_keys_for_books(get_metadata, lang_map)
if is_series:
idx_func = self.fields[idx].sort_keys_for_books(get_metadata, lang_map)
def skf(book_id):
return (func(book_id), idx_func(book_id))
return skf
@ -2160,6 +2169,7 @@ class Cache(object):
if progress is not None:
progress(_('Completed'), total, total)
def import_library(library_key, importer, library_path, progress=None, abort=None):
from calibre.db.backend import DB
metadata = importer.metadata[library_key]

View File

@ -17,6 +17,7 @@ from calibre.utils.icu import sort_key, collation_order
CATEGORY_SORTS = ('name', 'popularity', 'rating') # This has to be a tuple not a set
class Tag(object):
__slots__ = ('name', 'original_name', 'id', 'count', 'state', 'is_hierarchical',
@ -51,6 +52,7 @@ class Tag(object):
def __repr__(self):
return str(self)
def find_categories(field_metadata):
for category, cat in field_metadata.iteritems():
if (cat['is_category'] and cat['kind'] not in {'user', 'search'}):
@ -59,6 +61,7 @@ def find_categories(field_metadata):
cat['display'].get('make_category', False)):
yield (category, cat['is_multiple'].get('cache_to_list', None), True)
def create_tag_class(category, fm):
cat = fm[category]
dt = cat['datatype']
@ -77,6 +80,7 @@ def create_tag_class(category, fm):
return partial(Tag, use_sort_as_name=use_sort_as_name,
is_editable=is_editable, category=category)
def clean_user_categories(dbcache):
user_cats = dbcache.pref('user_categories', {})
new_cats = {}
@ -108,6 +112,7 @@ category_sort_keys[True]['name'] = \
category_sort_keys[False]['name'] = \
lambda x:sort_key(x.sort or x.name)
def get_categories(dbcache, sort='name', book_ids=None, first_letter_sort=False):
if sort not in CATEGORY_SORTS:
raise ValueError('sort ' + sort + ' not a valid value')

View File

@ -14,6 +14,7 @@ from calibre.ptempfile import remove_dir
from calibre.utils.filenames import remove_dir_if_empty
from calibre.utils.recycle_bin import delete_tree, delete_file
class DeleteService(Thread):
''' Provide a blocking file delete implementation with support for the
@ -136,6 +137,8 @@ class DeleteService(Thread):
shutil.rmtree(tdir)
__ds = None
def delete_service():
global __ds
if __ds is None:
@ -143,12 +146,14 @@ def delete_service():
__ds.start()
return __ds
def shutdown(timeout=20):
global __ds
if __ds is not None:
__ds.shutdown(timeout)
__ds = None
def has_jobs():
global __ds
if __ds is not None:

View File

@ -21,17 +21,20 @@ from calibre.utils.icu import sort_key
from calibre.utils.date import UNDEFINED_DATE, clean_date_for_sort, parse_date
from calibre.utils.localization import calibre_langcode_to_name
def bool_sort_key(bools_are_tristate):
return (lambda x:{True: 1, False: 2, None: 3}.get(x, 3)) if bools_are_tristate else lambda x:{True: 1, False: 2, None: 2}.get(x, 2)
IDENTITY = lambda x: x
class InvalidLinkTable(Exception):
def __init__(self, name):
Exception.__init__(self, name)
self.field_name = name
class Field(object):
is_many = False
@ -166,6 +169,7 @@ class Field(object):
ans.append(c)
return ans
class OneToOneField(Field):
def for_book(self, book_id, default_value=None):
@ -193,6 +197,7 @@ class OneToOneField(Field):
for book_id in candidates:
yield cbm.get(book_id, default_value), {book_id}
class CompositeField(OneToOneField):
is_composite = True
@ -339,6 +344,7 @@ class CompositeField(OneToOneField):
ans.add(book_id)
return ans
class OnDeviceField(OneToOneField):
def __init__(self, name, table, bools_are_tristate):
@ -403,6 +409,7 @@ class OnDeviceField(OneToOneField):
for val, book_ids in val_map.iteritems():
yield val, book_ids
class LazySortMap(object):
__slots__ = ('default_sort_key', 'sort_key_func', 'id_map', 'cache')
@ -469,6 +476,7 @@ class ManyToOneField(Field):
except KeyError:
raise InvalidLinkTable(self.name)
class ManyToManyField(Field):
is_many = True
@ -534,6 +542,7 @@ class ManyToManyField(Field):
except KeyError:
raise InvalidLinkTable(self.name)
class IdentifiersField(ManyToManyField):
def for_book(self, book_id, default_value=None):
@ -569,6 +578,7 @@ class IdentifiersField(ManyToManyField):
ans.append(c)
return ans
class AuthorsField(ManyToManyField):
def author_data(self, author_id):
@ -588,6 +598,7 @@ class AuthorsField(ManyToManyField):
return ' & '.join(self.table.asort_map[k] for k in
self.table.book_col_map[book_id])
class FormatsField(ManyToManyField):
def for_book(self, book_id, default_value=None):
@ -618,6 +629,7 @@ class FormatsField(ManyToManyField):
ans.append(c)
return ans
class LazySeriesSortMap(object):
__slots__ = ('default_sort_key', 'sort_key_func', 'id_map', 'cache')
@ -638,12 +650,14 @@ class LazySeriesSortMap(object):
val = self.cache[(item_id, lang)] = self.default_sort_key
return val
class SeriesField(ManyToOneField):
def sort_keys_for_books(self, get_metadata, lang_map):
sso = tweaks['title_series_sorting']
ssk = self._sort_key
ts = title_sort
def sk(val, lang):
return ssk(ts(val, order=sso, lang=lang))
sk_map = LazySeriesSortMap(self._default_sort_key, sk, self.table.id_map)
@ -718,6 +732,7 @@ class TagsField(ManyToManyField):
ans.append(c)
return ans
def create_field(name, table, bools_are_tristate):
cls = {
ONE_ONE: OneToOneField,

View File

@ -23,6 +23,7 @@ Speeds up calibre startup with large libraries/libraries on a network share,
with a composite custom column.
'''
def resolved(f):
@wraps(f)
def wrapper(self, *args, **kwargs):
@ -32,6 +33,7 @@ def resolved(f):
return f(self, *args, **kwargs)
return wrapper
class MutableBase(object):
@resolved
@ -87,6 +89,7 @@ class FormatMetadata(MutableBase, MutableMapping):
except:
pass
class FormatsList(MutableBase, MutableSequence):
def __init__(self, formats, format_metadata):
@ -106,6 +109,7 @@ class FormatsList(MutableBase, MutableSequence):
ga = object.__getattribute__
sa = object.__setattr__
def simple_getter(field, default_value=None):
def func(dbref, book_id, cache):
try:
@ -116,6 +120,7 @@ def simple_getter(field, default_value=None):
return ret
return func
def pp_getter(field, postprocess, default_value=None):
def func(dbref, book_id, cache):
try:
@ -126,6 +131,7 @@ def pp_getter(field, postprocess, default_value=None):
return ret
return func
def adata_getter(field):
def func(dbref, book_id, cache):
try:
@ -140,6 +146,7 @@ def adata_getter(field):
return {adata[i]['name']:adata[i][k] for i in author_ids}
return func
def dt_getter(field):
def func(dbref, book_id, cache):
try:
@ -150,6 +157,7 @@ def dt_getter(field):
return ret
return func
def item_getter(field, default_value=None, key=0):
def func(dbref, book_id, cache):
try:
@ -163,6 +171,7 @@ def item_getter(field, default_value=None, key=0):
return default_value
return func
def fmt_getter(field):
def func(dbref, book_id, cache):
try:
@ -179,6 +188,7 @@ def fmt_getter(field):
return format_metadata
return func
def approx_fmts_getter(dbref, book_id, cache):
try:
return cache['formats']
@ -187,6 +197,7 @@ def approx_fmts_getter(dbref, book_id, cache):
cache['formats'] = ret = list(db.field_for('formats', book_id))
return ret
def series_index_getter(field='series'):
def func(dbref, book_id, cache):
try:
@ -202,6 +213,7 @@ def series_index_getter(field='series'):
return ret
return func
def has_cover_getter(dbref, book_id, cache):
try:
return cache['has_cover']
@ -211,6 +223,8 @@ def has_cover_getter(dbref, book_id, cache):
return ret
fmt_custom = lambda x:list(x) if isinstance(x, tuple) else x
def custom_getter(field, dbref, book_id, cache):
try:
return cache[field]
@ -219,6 +233,7 @@ def custom_getter(field, dbref, book_id, cache):
cache[field] = ret = fmt_custom(db.field_for(field, book_id))
return ret
def composite_getter(mi, field, dbref, book_id, cache, formatter, template_cache):
try:
return cache[field]
@ -239,6 +254,7 @@ def composite_getter(mi, field, dbref, book_id, cache, formatter, template_cache
return 'ERROR WHILE EVALUATING: %s' % field
return ret
def virtual_libraries_getter(dbref, book_id, cache):
try:
return cache['virtual_libraries']
@ -248,6 +264,7 @@ def virtual_libraries_getter(dbref, book_id, cache):
ret = cache['virtual_libraries'] = ', '.join(vls)
return ret
def user_categories_getter(proxy_metadata):
cache = ga(proxy_metadata, '_cache')
try:
@ -293,6 +310,7 @@ for field in ('formats', 'format_metadata'):
getters[field] = fmt_getter(field)
# }}}
class ProxyMetadata(Metadata):
def __init__(self, db, book_id, formatter=None):

View File

@ -24,6 +24,7 @@ from calibre.db.write import clean_identifier, get_series_values
from calibre.utils.date import utcnow
from calibre.utils.search_query_parser import set_saved_searches
def cleanup_tags(tags):
tags = [x.strip().replace(',', ';') for x in tags if x.strip()]
tags = [x.decode(preferred_encoding, 'replace')
@ -36,6 +37,7 @@ def cleanup_tags(tags):
ans.append(tag)
return ans
def create_backend(
library_path, default_prefs=None, read_only=False,
progress_callback=lambda x, y:True, restore_all_prefs=False,
@ -45,6 +47,7 @@ def create_backend(
progress_callback=progress_callback,
load_user_formatter_functions=load_user_formatter_functions)
class LibraryDatabase(object):
''' Emulate the old LibraryDatabase2 interface '''
@ -748,6 +751,7 @@ for prop in ('author_sort', 'authors', 'comment', 'comments', 'publisher', 'max_
def getter(prop):
fm = {'comment':'comments', 'metadata_last_modified':
'last_modified', 'title_sort':'sort', 'max_size':'size'}.get(prop, prop)
def func(self, index, index_is_id=False):
return self.get_property(index, index_is_id=index_is_id, loc=self.FIELD_MAP[fm])
return func
@ -793,6 +797,7 @@ for field in (
if has_case_change:
field = field[1:]
acc = field == 'series'
def func(self, book_id, val, notify=True, commit=True, allow_case_change=acc):
ret = self.new_api.set_field(field, {book_id:val}, allow_case_change=allow_case_change)
if notify:
@ -804,6 +809,7 @@ for field in (
else:
null_field = field in {'title', 'sort', 'uuid'}
retval = (True if field == 'sort' else None)
def func(self, book_id, val, notify=True, commit=True):
if not val and null_field:
return (False if field == 'sort' else None)
@ -857,6 +863,7 @@ LibraryDatabase.get_author_id = MT(
for field in ('tags', 'series', 'publishers', 'ratings', 'languages'):
def getter(field):
fname = field[:-1] if field in {'publishers', 'ratings'} else field
def func(self):
return [[tid, tag] for tid, tag in self.new_api.get_id_map(fname).iteritems()]
return func
@ -865,6 +872,7 @@ for field in ('tags', 'series', 'publishers', 'ratings', 'languages'):
for field in ('author', 'tag', 'series'):
def getter(field):
field = field if field == 'series' else (field+'s')
def func(self, item_id):
return self.new_api.get_item_name(field, item_id)
return func
@ -873,6 +881,7 @@ for field in ('author', 'tag', 'series'):
for field in ('publisher', 'series', 'tag'):
def getter(field):
fname = 'tags' if field == 'tag' else field
def func(self, item_id):
self.new_api.remove_items(fname, (item_id,))
return func
@ -888,6 +897,7 @@ for func in (
def getter(func):
if func.startswith('!'):
func = func[1:]
def meth(self, include_composites=True):
return getattr(self.field_metadata, func)(include_composites=include_composites)
elif func == 'search_term_to_field_key':

View File

@ -11,6 +11,7 @@ import traceback, sys
from threading import Lock, Condition, current_thread
from calibre.utils.config_base import tweaks
class LockingError(RuntimeError):
is_locking_error = True
@ -19,9 +20,11 @@ class LockingError(RuntimeError):
RuntimeError.__init__(self, msg)
self.locking_debug_msg = extra
class DowngradeLockError(LockingError):
pass
def create_locks():
'''
Return a pair of locks: (read_lock, write_lock)
@ -48,6 +51,7 @@ def create_locks():
wrapper = DebugRWLockWrapper if tweaks.get('newdb_debug_locking', False) else RWLockWrapper
return wrapper(l), wrapper(l, is_shared=False)
class SHLock(object): # {{{
'''
Shareable lock class. Used to implement the Multiple readers-single writer
@ -207,6 +211,7 @@ class SHLock(object): # {{{
# }}}
class RWLockWrapper(object):
def __init__(self, shlock, is_shared=True):
@ -225,6 +230,7 @@ class RWLockWrapper(object):
def owns_lock(self):
return self._shlock.owns_lock()
class DebugRWLockWrapper(RWLockWrapper):
def __init__(self, *args, **kwargs):
@ -249,6 +255,7 @@ class DebugRWLockWrapper(RWLockWrapper):
__enter__ = acquire
__exit__ = release
class SafeReadLock(object):
def __init__(self, read_lock):

View File

@ -22,6 +22,7 @@ NON_EBOOK_EXTENSIONS = frozenset([
'opf', 'swp', 'swo'
])
class Restorer(Cache):
def __init__(self, library_path, default_prefs=None, restore_all_prefs=False, progress_callback=lambda x, y:True):
@ -35,6 +36,7 @@ class Restorer(Cache):
def no_op(self, *args, **kwargs):
pass
class Restore(Thread):
def __init__(self, library_path, progress_callback=None):

View File

@ -12,6 +12,7 @@ import os
from calibre import prints
from calibre.utils.date import isoformat, DEFAULT_DATE
class SchemaUpgrade(object):
def __init__(self, db, library_path, field_metadata):
@ -421,6 +422,7 @@ class SchemaUpgrade(object):
'Cache has_cover'
self.db.execute('ALTER TABLE books ADD COLUMN has_cover BOOL DEFAULT 0')
data = self.db.get('SELECT id,path FROM books', all=True)
def has_cover(path):
if path:
path = os.path.join(self.library_path, path.replace('/', os.sep),

Some files were not shown because too many files have changed in this diff Show More