mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge from trunk
This commit is contained in:
commit
ee685cdac8
@ -6,7 +6,7 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
'''
|
'''
|
||||||
Contains various tweaks that affect calibre behavior. Only edit this file if
|
Contains various tweaks that affect calibre behavior. Only edit this file if
|
||||||
you know what you are dong. If you delete this file, it will be recreated from
|
you know what you are doing. If you delete this file, it will be recreated from
|
||||||
defaults.
|
defaults.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
BIN
resources/images/news/la_razon_bo.png
Normal file
BIN
resources/images/news/la_razon_bo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 356 B |
BIN
resources/images/news/los_tiempos_bo.png
Normal file
BIN
resources/images/news/los_tiempos_bo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 464 B |
64
resources/recipes/la_razon_bo.recipe
Normal file
64
resources/recipes/la_razon_bo.recipe
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
|
'''
|
||||||
|
www.la-razon.com
|
||||||
|
'''
|
||||||
|
|
||||||
|
from calibre import strftime
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class LaRazon_Bol(BasicNewsRecipe):
|
||||||
|
title = 'La Razón - Bolivia'
|
||||||
|
__author__ = 'Darko Miletic'
|
||||||
|
description = 'El diario nacional de Bolivia'
|
||||||
|
publisher = 'Praxsis S.R.L.'
|
||||||
|
category = 'news, politics, Bolivia'
|
||||||
|
oldest_article = 1
|
||||||
|
max_articles_per_feed = 200
|
||||||
|
no_stylesheets = True
|
||||||
|
encoding = 'cp1252'
|
||||||
|
use_embedded_content = False
|
||||||
|
language = 'es'
|
||||||
|
publication_type = 'newspaper'
|
||||||
|
delay = 1
|
||||||
|
remove_empty_feeds = True
|
||||||
|
cover_url = strftime('http://www.la-razon.com/portadas/%Y%m%d_LaRazon.jpg')
|
||||||
|
masthead_url = 'http://www.la-razon.com/imagenes/logo.jpg'
|
||||||
|
extra_css = """ body{font-family: Arial,Helvetica,sans-serif }
|
||||||
|
img{margin-bottom: 0.4em}
|
||||||
|
.noticia-titulo{font-family: Georgia,"Times New Roman",Times,serif}
|
||||||
|
.lead{font-weight: bold; font-size: 0.8em}
|
||||||
|
"""
|
||||||
|
|
||||||
|
conversion_options = {
|
||||||
|
'comment' : description
|
||||||
|
, 'tags' : category
|
||||||
|
, 'publisher' : publisher
|
||||||
|
, 'language' : language
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_only_tags = [dict(name='div', attrs={'class':['noticia-titulo','noticia-desarrollo']})]
|
||||||
|
remove_tags = [dict(name=['meta','link','form','iframe','embed','object'])]
|
||||||
|
remove_attributes = ['width','height']
|
||||||
|
|
||||||
|
feeds = [
|
||||||
|
(u'Editorial' , u'http://www.la-razon.com/rss_editorial.php' )
|
||||||
|
,(u'Opinión' , u'http://www.la-razon.com/rss_opinion.php' )
|
||||||
|
,(u'Nacional' , u'http://www.la-razon.com/rss_nacional.php' )
|
||||||
|
,(u'Economia' , u'http://www.la-razon.com/rss_economia.php' )
|
||||||
|
,(u'Ciudades' , u'http://www.la-razon.com/rss_ciudades.php' )
|
||||||
|
,(u'Sociedad' , u'http://www.la-razon.com/rss_sociedad.php' )
|
||||||
|
,(u'Mundo' , u'http://www.la-razon.com/rss_sociedad.php' )
|
||||||
|
,(u'La Revista' , u'http://www.la-razon.com/rss_larevista.php' )
|
||||||
|
,(u'Sociales' , u'http://www.la-razon.com/rss_sociales.php' )
|
||||||
|
,(u'Mia' , u'http://www.la-razon.com/rss_mia.php' )
|
||||||
|
,(u'Marcas' , u'http://www.la-razon.com/rss_marcas.php' )
|
||||||
|
,(u'Escape' , u'http://www.la-razon.com/rss_escape.php' )
|
||||||
|
,(u'El Financiero' , u'http://www.la-razon.com/rss_financiero.php')
|
||||||
|
,(u'Tendencias' , u'http://www.la-razon.com/rss_tendencias.php')
|
||||||
|
]
|
||||||
|
|
||||||
|
def preprocess_html(self, soup):
|
||||||
|
for item in soup.findAll(style=True):
|
||||||
|
del item['style']
|
||||||
|
return soup
|
63
resources/recipes/los_tiempos_bo.recipe
Normal file
63
resources/recipes/los_tiempos_bo.recipe
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
|
'''
|
||||||
|
www.lostiempos.com
|
||||||
|
'''
|
||||||
|
|
||||||
|
from calibre import strftime
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class LosTiempos_Bol(BasicNewsRecipe):
|
||||||
|
title = 'Los Tiempos - Bolivia'
|
||||||
|
__author__ = 'Darko Miletic'
|
||||||
|
description = 'El periódico de mayor circulación en la ciudad de Cochabamba, Bolivia'
|
||||||
|
publisher = 'Los Tiempos'
|
||||||
|
category = 'news, politics, Bolivia'
|
||||||
|
oldest_article = 1
|
||||||
|
max_articles_per_feed = 200
|
||||||
|
no_stylesheets = True
|
||||||
|
encoding = 'cp1252'
|
||||||
|
use_embedded_content = False
|
||||||
|
language = 'es'
|
||||||
|
publication_type = 'newspaper'
|
||||||
|
delay = 1
|
||||||
|
remove_empty_feeds = True
|
||||||
|
cover_url = strftime('http://www.lostiempos.com/media_recortes/%Y/%m/%d/portada_md_1.jpg')
|
||||||
|
masthead_url = 'http://www.lostiempos.com/img_stat/logo_tiempos_sin_beta.jpg'
|
||||||
|
extra_css = """ body{font-family: Arial,Helvetica,sans-serif }
|
||||||
|
img{margin-bottom: 0.4em}
|
||||||
|
h1,.hora,.breadcum,.pie_foto{font-family: Georgia,"Times New Roman",Times,serif}
|
||||||
|
.hora,.breadcum,.pie_foto{font-size: small}
|
||||||
|
.en_gris,.pie_foto{color: #666666}
|
||||||
|
"""
|
||||||
|
|
||||||
|
conversion_options = {
|
||||||
|
'comment' : description
|
||||||
|
, 'tags' : category
|
||||||
|
, 'publisher' : publisher
|
||||||
|
, 'language' : language
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_only_tags = [dict(name='div', attrs={'id':'articulo'})]
|
||||||
|
remove_tags = [
|
||||||
|
dict(name=['meta','link','form','iframe','embed','object','hr'])
|
||||||
|
,dict(attrs={'class':['caja_fonts sin_border_bot','pub']})
|
||||||
|
]
|
||||||
|
remove_attributes = ['width','height']
|
||||||
|
|
||||||
|
feeds = [
|
||||||
|
(u'Nacional' , u'http://www.lostiempos.com/rss/lostiempos-nacional.xml' )
|
||||||
|
,(u'Local' , u'http://www.lostiempos.com/rss/lostiempos-local.xml' )
|
||||||
|
,(u'Deportes' , u'http://www.lostiempos.com/rss/lostiempos-deportes.xml' )
|
||||||
|
,(u'Economía' , u'http://www.lostiempos.com/rss/lostiempos-economia.xml' )
|
||||||
|
,(u'Internacional' , u'http://www.lostiempos.com/rss/lostiempos-internacional.xml' )
|
||||||
|
,(u'Vida y Futuro' , u'http://www.lostiempos.com/rss/lostiempos-vida-y-futuro.xml' )
|
||||||
|
,(u'Tragaluz' , u'http://www.lostiempos.com/rss/lostiempos-tragaluz.xml' )
|
||||||
|
,(u'Opiniones' , u'http://www.lostiempos.com/rss/lostiempos-opiniones.xml' )
|
||||||
|
]
|
||||||
|
|
||||||
|
def preprocess_html(self, soup):
|
||||||
|
for item in soup.findAll(style=True):
|
||||||
|
del item['style']
|
||||||
|
return soup
|
||||||
|
|
@ -6,7 +6,6 @@ nspm.rs
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
from calibre.ebooks.BeautifulSoup import Tag
|
|
||||||
|
|
||||||
class Nspm(BasicNewsRecipe):
|
class Nspm(BasicNewsRecipe):
|
||||||
title = 'Nova srpska politicka misao'
|
title = 'Nova srpska politicka misao'
|
||||||
|
34
resources/recipes/yahoo_news.recipe
Normal file
34
resources/recipes/yahoo_news.recipe
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
import re
|
||||||
|
|
||||||
|
class YahooNews(BasicNewsRecipe):
|
||||||
|
title = 'Yahoo News'
|
||||||
|
__author__ = 'Starson17'
|
||||||
|
description = 'Yahoo-Science'
|
||||||
|
language = 'en'
|
||||||
|
use_embedded_content= False
|
||||||
|
no_stylesheets = True
|
||||||
|
linearize_tables = True
|
||||||
|
oldest_article = 24
|
||||||
|
remove_javascript = True
|
||||||
|
remove_empty_feeds = True
|
||||||
|
max_articles_per_feed = 10
|
||||||
|
|
||||||
|
feeds = [#There are dozens of other feeds at http://news.yahoo.com/rss
|
||||||
|
(u'Top Stories', u'http://rss.news.yahoo.com/rss/topstories'),
|
||||||
|
(u'Science', u'http://rss.news.yahoo.com/rss/science')
|
||||||
|
]
|
||||||
|
|
||||||
|
keep_only_tags = [dict(name='div', attrs={'id':'yn-story'})]
|
||||||
|
|
||||||
|
remove_tags = [dict(name='div', attrs={'class':['hd', 'ft', 'yn-share-social']}),
|
||||||
|
dict(name='div', attrs={'id':['yn-story-minor-media']})]
|
||||||
|
|
||||||
|
preprocess_regexps = [(re.compile(r'<span>Play Video</span>', re.DOTALL),lambda match: '<span></span>')]
|
||||||
|
|
||||||
|
extra_css = '''
|
||||||
|
h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;}
|
||||||
|
h2{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;}
|
||||||
|
p{font-family:Arial,Helvetica,sans-serif;font-size:small;}
|
||||||
|
body{font-family:Helvetica,Arial,sans-serif;font-size:small;}
|
||||||
|
'''
|
@ -19,8 +19,8 @@ class ANDROID(USBMS):
|
|||||||
|
|
||||||
VENDOR_ID = {
|
VENDOR_ID = {
|
||||||
# HTC
|
# HTC
|
||||||
0x0bb4 : { 0x0c02 : [0x100, 0x227], 0x0c01 : [0x100, 0x227], 0x0ff9
|
0x0bb4 : { 0x0c02 : [0x100, 0x0227], 0x0c01 : [0x100, 0x0227], 0x0ff9
|
||||||
: [0x0100, 0x227]},
|
: [0x0100, 0x0227, 0x0226]},
|
||||||
|
|
||||||
# Motorola
|
# Motorola
|
||||||
0x22b8 : { 0x41d9 : [0x216], 0x2d67 : [0x100], 0x41db : [0x216],
|
0x22b8 : { 0x41d9 : [0x216], 0x2d67 : [0x100], 0x41db : [0x216],
|
||||||
|
@ -95,11 +95,11 @@ class ITUNES(DriverBase):
|
|||||||
|
|
||||||
# Product IDs:
|
# Product IDs:
|
||||||
# 0x1291 iPod Touch
|
# 0x1291 iPod Touch
|
||||||
# 0x1292 iPhone 3G
|
|
||||||
# 0x1293 iPod Touch 2G
|
# 0x1293 iPod Touch 2G
|
||||||
|
# 0x1299 iPod Touch 3G
|
||||||
|
# 0x1292 iPhone 3G
|
||||||
# 0x1294 iPhone 3GS
|
# 0x1294 iPhone 3GS
|
||||||
# 0x1297 iPhone 4
|
# 0x1297 iPhone 4
|
||||||
# 0x1299 iPod Touch 3G
|
|
||||||
# 0x129a iPad
|
# 0x129a iPad
|
||||||
VENDOR_ID = [0x05ac]
|
VENDOR_ID = [0x05ac]
|
||||||
PRODUCT_ID = [0x1292,0x1293,0x1294,0x1297,0x1299,0x129a]
|
PRODUCT_ID = [0x1292,0x1293,0x1294,0x1297,0x1299,0x129a]
|
||||||
@ -1029,8 +1029,13 @@ class ITUNES(DriverBase):
|
|||||||
sys.stdout.write("\n")
|
sys.stdout.write("\n")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
# This doesn't seem to work with Device, just Library
|
|
||||||
if False:
|
if False:
|
||||||
|
'''
|
||||||
|
Preferred
|
||||||
|
Disabled because op_status.Tracks never returns a value after adding file
|
||||||
|
This would be the preferred approach (as under OSX)
|
||||||
|
It works in _add_library_book()
|
||||||
|
'''
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
sys.stdout.write(" waiting for handle to added '%s' ..." % metadata.title)
|
sys.stdout.write(" waiting for handle to added '%s' ..." % metadata.title)
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
@ -1044,15 +1049,19 @@ class ITUNES(DriverBase):
|
|||||||
print
|
print
|
||||||
added = op_status.Tracks[0]
|
added = op_status.Tracks[0]
|
||||||
else:
|
else:
|
||||||
# This approach simply scans Library|Books for the book we just added
|
'''
|
||||||
|
Hackish
|
||||||
# Try the calibre metadata first
|
Search Library|Books for the book we just added
|
||||||
|
PDF file name is added title - need to search for base filename w/o extension
|
||||||
|
'''
|
||||||
|
format = fpath.rpartition('.')[2].lower()
|
||||||
|
base_fn = fpath.rpartition(os.sep)[2]
|
||||||
|
base_fn = base_fn.rpartition('.')[0]
|
||||||
db_added = self._find_device_book(
|
db_added = self._find_device_book(
|
||||||
{'title': metadata.title,
|
{ 'title': base_fn if format == 'pdf' else metadata.title,
|
||||||
'author': metadata.authors[0],
|
'author': metadata.authors[0],
|
||||||
'uuid': metadata.uuid,
|
'uuid': metadata.uuid,
|
||||||
'format': fpath.rpartition('.')[2].lower()})
|
'format': format})
|
||||||
|
|
||||||
return db_added
|
return db_added
|
||||||
|
|
||||||
def _add_library_book(self,file, metadata):
|
def _add_library_book(self,file, metadata):
|
||||||
@ -1087,7 +1096,12 @@ class ITUNES(DriverBase):
|
|||||||
sys.stdout.write("\n")
|
sys.stdout.write("\n")
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
if False:
|
if True:
|
||||||
|
'''
|
||||||
|
Preferable
|
||||||
|
Originally disabled because op_status.Tracks never returned a value
|
||||||
|
after adding file. Seems to be working with iTunes 9.2.1.5 06 Aug 2010
|
||||||
|
'''
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
sys.stdout.write(" waiting for handle to added '%s' ..." % metadata.title)
|
sys.stdout.write(" waiting for handle to added '%s' ..." % metadata.title)
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
@ -1100,12 +1114,19 @@ class ITUNES(DriverBase):
|
|||||||
print
|
print
|
||||||
added = op_status.Tracks[0]
|
added = op_status.Tracks[0]
|
||||||
else:
|
else:
|
||||||
# This approach simply scans Library|Books for the book we just added
|
'''
|
||||||
|
Hackish
|
||||||
|
Search Library|Books for the book we just added
|
||||||
|
PDF file name is added title - need to search for base filename w/o extension
|
||||||
|
'''
|
||||||
|
format = file.rpartition('.')[2].lower()
|
||||||
|
base_fn = file.rpartition(os.sep)[2]
|
||||||
|
base_fn = base_fn.rpartition('.')[0]
|
||||||
added = self._find_library_book(
|
added = self._find_library_book(
|
||||||
{ 'title': metadata.title,
|
{ 'title': base_fn if format == 'pdf' else metadata.title,
|
||||||
'author': metadata.author[0],
|
'author': metadata.author[0],
|
||||||
'uuid': metadata.uuid,
|
'uuid': metadata.uuid,
|
||||||
'format': file.rpartition('.')[2].lower()})
|
'format': format})
|
||||||
return added
|
return added
|
||||||
|
|
||||||
def _add_new_copy(self, fpath, metadata):
|
def _add_new_copy(self, fpath, metadata):
|
||||||
@ -1820,7 +1841,6 @@ class ITUNES(DriverBase):
|
|||||||
except:
|
except:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.error(" error generating thumb for '%s', caching empty marker" % book.Name)
|
self.log.error(" error generating thumb for '%s', caching empty marker" % book.Name)
|
||||||
self._dump_hex(data[:32])
|
|
||||||
thumb_data = None
|
thumb_data = None
|
||||||
# Cache the empty cover
|
# Cache the empty cover
|
||||||
zfw.writestr(thumb_path,'None')
|
zfw.writestr(thumb_path,'None')
|
||||||
|
@ -9,6 +9,7 @@ from threading import Thread
|
|||||||
from calibre import prints
|
from calibre import prints
|
||||||
from calibre.utils.config import OptionParser
|
from calibre.utils.config import OptionParser
|
||||||
from calibre.utils.logging import default_log
|
from calibre.utils.logging import default_log
|
||||||
|
from calibre.utils.titlecase import titlecase
|
||||||
from calibre.customize import Plugin
|
from calibre.customize import Plugin
|
||||||
from calibre.ebooks.metadata.covers import check_for_cover
|
from calibre.ebooks.metadata.covers import check_for_cover
|
||||||
|
|
||||||
@ -384,6 +385,16 @@ def search(title=None, author=None, publisher=None, isbn=None, isbndb_key=None,
|
|||||||
if r.pubdate is None:
|
if r.pubdate is None:
|
||||||
r.pubdate = pubdate
|
r.pubdate = pubdate
|
||||||
|
|
||||||
|
def fix_case(x):
|
||||||
|
if x and x.isupper():
|
||||||
|
x = titlecase(x)
|
||||||
|
return x
|
||||||
|
|
||||||
|
for r in results:
|
||||||
|
r.title = fix_case(r.title)
|
||||||
|
if r.authors:
|
||||||
|
r.authors = list(map(fix_case, r.authors))
|
||||||
|
|
||||||
return results, [(x.name, x.exception, x.tb) for x in fetchers]
|
return results, [(x.name, x.exception, x.tb) for x in fetchers]
|
||||||
|
|
||||||
def get_social_metadata(mi, verbose=0):
|
def get_social_metadata(mi, verbose=0):
|
||||||
|
@ -296,6 +296,17 @@ class AddAction(object): # {{{
|
|||||||
self.library_view.model().db.import_book(MetaInformation(None), [])
|
self.library_view.model().db.import_book(MetaInformation(None), [])
|
||||||
self.library_view.model().books_added(num)
|
self.library_view.model().books_added(num)
|
||||||
|
|
||||||
|
def add_isbns(self, isbns):
|
||||||
|
from calibre.ebooks.metadata import MetaInformation
|
||||||
|
ids = set([])
|
||||||
|
for x in isbns:
|
||||||
|
mi = MetaInformation(None)
|
||||||
|
mi.isbn = x
|
||||||
|
ids.add(self.library_view.model().db.import_book(mi, []))
|
||||||
|
self.library_view.model().books_added(len(isbns))
|
||||||
|
self.do_download_metadata(ids)
|
||||||
|
|
||||||
|
|
||||||
def files_dropped(self, paths):
|
def files_dropped(self, paths):
|
||||||
to_device = self.stack.currentIndex() != 0
|
to_device = self.stack.currentIndex() != 0
|
||||||
self._add_books(paths, to_device)
|
self._add_books(paths, to_device)
|
||||||
@ -342,6 +353,12 @@ class AddAction(object): # {{{
|
|||||||
def add_filesystem_book(self, paths, allow_device=True):
|
def add_filesystem_book(self, paths, allow_device=True):
|
||||||
self._add_filesystem_book(paths, allow_device=allow_device)
|
self._add_filesystem_book(paths, allow_device=allow_device)
|
||||||
|
|
||||||
|
def add_from_isbn(self, *args):
|
||||||
|
from calibre.gui2.dialogs.add_from_isbn import AddFromISBN
|
||||||
|
d = AddFromISBN(self)
|
||||||
|
if d.exec_() == d.Accepted:
|
||||||
|
self.add_isbns(d.isbns)
|
||||||
|
|
||||||
def add_books(self, *args):
|
def add_books(self, *args):
|
||||||
'''
|
'''
|
||||||
Add books from the local filesystem to either the library or the device.
|
Add books from the local filesystem to either the library or the device.
|
||||||
@ -625,6 +642,13 @@ class EditMetadataAction(object): # {{{
|
|||||||
return
|
return
|
||||||
db = self.library_view.model().db
|
db = self.library_view.model().db
|
||||||
ids = [db.id(row.row()) for row in rows]
|
ids = [db.id(row.row()) for row in rows]
|
||||||
|
self.do_download_metadata(ids, covers=covers,
|
||||||
|
set_metadata=set_metadata,
|
||||||
|
set_social_metadata=set_social_metadata)
|
||||||
|
|
||||||
|
def do_download_metadata(self, ids, covers=True, set_metadata=True,
|
||||||
|
set_social_metadata=None):
|
||||||
|
db = self.library_view.model().db
|
||||||
if set_social_metadata is None:
|
if set_social_metadata is None:
|
||||||
get_social_metadata = config['get_social_metadata']
|
get_social_metadata = config['get_social_metadata']
|
||||||
else:
|
else:
|
||||||
@ -931,7 +955,7 @@ class SaveToDiskAction(object): # {{{
|
|||||||
lpath = self.library_view.model().db.library_path.replace('/', os.sep)
|
lpath = self.library_view.model().db.library_path.replace('/', os.sep)
|
||||||
if dpath.startswith(lpath):
|
if dpath.startswith(lpath):
|
||||||
return error_dialog(self, _('Not allowed'),
|
return error_dialog(self, _('Not allowed'),
|
||||||
_('You are tying to save files into the calibre '
|
_('You are trying to save files into the calibre '
|
||||||
'library. This can cause corruption of your '
|
'library. This can cause corruption of your '
|
||||||
'library. Save to disk is meant to export '
|
'library. Save to disk is meant to export '
|
||||||
'files from your calibre library elsewhere.'), show=True)
|
'files from your calibre library elsewhere.'), show=True)
|
@ -63,7 +63,7 @@
|
|||||||
<item row="2" column="0" colspan="2">
|
<item row="2" column="0" colspan="2">
|
||||||
<widget class="QCheckBox" name="opt_force_max_line_length">
|
<widget class="QCheckBox" name="opt_force_max_line_length">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Force maximum line lenght</string>
|
<string>Force maximum line length</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
40
src/calibre/gui2/dialogs/add_from_isbn.py
Normal file
40
src/calibre/gui2/dialogs/add_from_isbn.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
from PyQt4.Qt import QDialog, QApplication
|
||||||
|
|
||||||
|
from calibre.gui2.dialogs.add_from_isbn_ui import Ui_Dialog
|
||||||
|
from calibre.ebooks.metadata import check_isbn
|
||||||
|
|
||||||
|
class AddFromISBN(QDialog, Ui_Dialog):
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
QDialog.__init__(self, parent)
|
||||||
|
self.setupUi(self)
|
||||||
|
|
||||||
|
self.isbns = []
|
||||||
|
self.paste_button.clicked.connect(self.paste)
|
||||||
|
|
||||||
|
def paste(self, *args):
|
||||||
|
app = QApplication.instance()
|
||||||
|
c = app.clipboard()
|
||||||
|
txt = unicode(c.text()).strip()
|
||||||
|
if txt:
|
||||||
|
old = unicode(self.isbn_box.toPlainText()).strip()
|
||||||
|
new = old + '\n' + txt
|
||||||
|
self.isbn_box.setPlainText(new)
|
||||||
|
|
||||||
|
def accept(self, *args):
|
||||||
|
for line in unicode(self.isbn_box.toPlainText()).strip().splitlines():
|
||||||
|
if line:
|
||||||
|
isbn = check_isbn(line)
|
||||||
|
if isbn is not None:
|
||||||
|
isbn = isbn.upper()
|
||||||
|
if isbn not in self.isbns:
|
||||||
|
self.isbns.append(isbn)
|
||||||
|
QDialog.accept(self, *args)
|
||||||
|
|
90
src/calibre/gui2/dialogs/add_from_isbn.ui
Normal file
90
src/calibre/gui2/dialogs/add_from_isbn.ui
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Dialog</class>
|
||||||
|
<widget class="QDialog" name="Dialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>678</width>
|
||||||
|
<height>430</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Add books by ISBN</string>
|
||||||
|
</property>
|
||||||
|
<property name="windowIcon">
|
||||||
|
<iconset resource="../../../../resources/images.qrc">
|
||||||
|
<normaloff>:/images/add_book.svg</normaloff>:/images/add_book.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QPlainTextEdit" name="isbn_box"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string><p>Enter a list of ISBNs in the box to the left, one per line. calibre will automatically create entries for books based on the ISBN and download metadata and covers for them.<p>Any invalid ISBNs in the list will be ignored.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" colspan="2">
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QPushButton" name="paste_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Paste from clipboard</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../../../../resources/images.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>Dialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>Dialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
@ -18,7 +18,7 @@ from calibre.gui2 import error_dialog, config, gprefs, \
|
|||||||
open_url, open_local_file, \
|
open_url, open_local_file, \
|
||||||
ALL_COLUMNS, NONE, info_dialog, choose_files, \
|
ALL_COLUMNS, NONE, info_dialog, choose_files, \
|
||||||
warning_dialog, ResizableDialog, question_dialog
|
warning_dialog, ResizableDialog, question_dialog
|
||||||
from calibre.utils.config import prefs
|
from calibre.utils.config import prefs, read_raw_tweaks, write_tweaks
|
||||||
from calibre.ebooks import BOOK_EXTENSIONS
|
from calibre.ebooks import BOOK_EXTENSIONS
|
||||||
from calibre.ebooks.oeb.iterator import is_supported
|
from calibre.ebooks.oeb.iterator import is_supported
|
||||||
from calibre.library.server import server_config
|
from calibre.library.server import server_config
|
||||||
@ -514,8 +514,18 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
|
|||||||
self.opt_toolbar_text.setCurrentIndex(idx)
|
self.opt_toolbar_text.setCurrentIndex(idx)
|
||||||
self.reset_confirmation_button.clicked.connect(self.reset_confirmation)
|
self.reset_confirmation_button.clicked.connect(self.reset_confirmation)
|
||||||
|
|
||||||
|
deft, curt = read_raw_tweaks()
|
||||||
|
self.current_tweaks.setPlainText(curt)
|
||||||
|
self.default_tweaks.setPlainText(deft)
|
||||||
|
self.restore_tweaks_to_default_button.clicked.connect(self.restore_tweaks_to_default)
|
||||||
|
|
||||||
self.category_view.setCurrentIndex(self.category_view.model().index_for_name(initial_category))
|
self.category_view.setCurrentIndex(self.category_view.model().index_for_name(initial_category))
|
||||||
|
|
||||||
|
def restore_tweaks_to_default(self, *args):
|
||||||
|
deft, curt = read_raw_tweaks()
|
||||||
|
self.current_tweaks.setPlainText(deft)
|
||||||
|
|
||||||
|
|
||||||
def reset_confirmation(self):
|
def reset_confirmation(self):
|
||||||
from calibre.gui2 import dynamic
|
from calibre.gui2 import dynamic
|
||||||
for key in dynamic.keys():
|
for key in dynamic.keys():
|
||||||
@ -687,6 +697,22 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
|
|||||||
self.input_order.insertItem(idx-1, self.input_order.takeItem(idx))
|
self.input_order.insertItem(idx-1, self.input_order.takeItem(idx))
|
||||||
self.input_order.setCurrentRow(idx-1)
|
self.input_order.setCurrentRow(idx-1)
|
||||||
|
|
||||||
|
def set_tweaks(self):
|
||||||
|
raw = unicode(self.current_tweaks.toPlainText())
|
||||||
|
raw = re.sub(r'(?m)^#.*fileencoding.*', '# ', raw)
|
||||||
|
try:
|
||||||
|
exec raw
|
||||||
|
except:
|
||||||
|
import traceback
|
||||||
|
error_dialog(self, _('Invalid tweaks'),
|
||||||
|
_('The tweaks you entered are invalid, try resetting the'
|
||||||
|
' tweaks to default and changing them one by one until'
|
||||||
|
' you find the invalid setting.'),
|
||||||
|
det_msg=traceback.format_exc(), show=True)
|
||||||
|
return False
|
||||||
|
write_tweaks(raw)
|
||||||
|
return True
|
||||||
|
|
||||||
def down_input(self):
|
def down_input(self):
|
||||||
idx = self.input_order.currentRow()
|
idx = self.input_order.currentRow()
|
||||||
if idx < self.input_order.count()-1:
|
if idx < self.input_order.count()-1:
|
||||||
@ -852,6 +878,8 @@ class ConfigDialog(ResizableDialog, Ui_Dialog):
|
|||||||
return
|
return
|
||||||
if not self.add_save.save_settings():
|
if not self.add_save.save_settings():
|
||||||
return
|
return
|
||||||
|
if not self.set_tweaks():
|
||||||
|
return
|
||||||
wl = self.opt_worker_limit.value()
|
wl = self.opt_worker_limit.value()
|
||||||
if wl%2 != 0:
|
if wl%2 != 0:
|
||||||
wl += 1
|
wl += 1
|
||||||
|
@ -718,6 +718,16 @@
|
|||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="page_2">
|
<widget class="QWidget" name="page_2">
|
||||||
<layout class="QGridLayout" name="gridLayout_3">
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="tab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>&Miscellaneous</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_9">
|
||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="label_5">
|
<widget class="QLabel" name="label_5">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -741,27 +751,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0" colspan="2">
|
|
||||||
<widget class="QPushButton" name="compact_button">
|
|
||||||
<property name="text">
|
|
||||||
<string>&Check database integrity</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="5" column="0" colspan="2">
|
|
||||||
<widget class="QPushButton" name="button_osx_symlinks">
|
|
||||||
<property name="text">
|
|
||||||
<string>&Install command line tools</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="4" column="0" colspan="2">
|
|
||||||
<widget class="QPushButton" name="button_open_config_dir">
|
|
||||||
<property name="text">
|
|
||||||
<string>Open calibre &configuration directory</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
<item row="1" column="0">
|
||||||
<widget class="QCheckBox" name="opt_enforce_cpu_limit">
|
<widget class="QCheckBox" name="opt_enforce_cpu_limit">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
@ -769,13 +758,155 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0" colspan="2">
|
<item row="2" column="0">
|
||||||
|
<spacer name="verticalSpacer_4">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>79</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" colspan="2">
|
||||||
<widget class="QPushButton" name="device_detection_button">
|
<widget class="QPushButton" name="device_detection_button">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Debug &device detection</string>
|
<string>Debug &device detection</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<spacer name="verticalSpacer_6">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>80</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0" colspan="2">
|
||||||
|
<widget class="QPushButton" name="compact_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Check database integrity</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<spacer name="verticalSpacer_7">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>79</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="0" colspan="2">
|
||||||
|
<widget class="QPushButton" name="button_open_config_dir">
|
||||||
|
<property name="text">
|
||||||
|
<string>Open calibre &configuration directory</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="0">
|
||||||
|
<spacer name="verticalSpacer_8">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>80</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="9" column="0" colspan="2">
|
||||||
|
<widget class="QPushButton" name="button_osx_symlinks">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Install command line tools</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="10" column="0">
|
||||||
|
<spacer name="verticalSpacer_9">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>79</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_2">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>&Tweaks</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_18">
|
||||||
|
<property name="text">
|
||||||
|
<string>Values for the tweaks are shown below. Edit them to change the behavior of calibre</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_6">
|
||||||
|
<property name="title">
|
||||||
|
<string>All available tweaks</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_11">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QPlainTextEdit" name="default_tweaks">
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_7">
|
||||||
|
<property name="title">
|
||||||
|
<string>&Current tweaks</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_10">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QPlainTextEdit" name="current_tweaks"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="restore_tweaks_to_default_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Restore to defaults</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="page_4">
|
<widget class="QWidget" name="page_4">
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>730</width>
|
<width>768</width>
|
||||||
<height>342</height>
|
<height>342</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@ -51,6 +51,9 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="recalc_author_sort">
|
<widget class="QPushButton" name="recalc_author_sort">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Reset all the author sort values to a value automatically generated from the author. Exactly how this value is automatically generated can be controlled via Preferences->Advanced->Tweaks</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Recalculate all author sort values</string>
|
<string>Recalculate all author sort values</string>
|
||||||
</property>
|
</property>
|
||||||
|
@ -538,8 +538,10 @@ class MainWindowMixin(object):
|
|||||||
self.add_menu.addAction(_('Add books from directories, including '
|
self.add_menu.addAction(_('Add books from directories, including '
|
||||||
'sub directories (Multiple books per directory, assumes every '
|
'sub directories (Multiple books per directory, assumes every '
|
||||||
'ebook file is a different book)'), self.add_recursive_multiple)
|
'ebook file is a different book)'), self.add_recursive_multiple)
|
||||||
|
self.add_menu.addSeparator()
|
||||||
self.add_menu.addAction(_('Add Empty book. (Book entry with no '
|
self.add_menu.addAction(_('Add Empty book. (Book entry with no '
|
||||||
'formats)'), self.add_empty)
|
'formats)'), self.add_empty)
|
||||||
|
self.add_menu.addAction(_('Add from ISBN'), self.add_from_isbn)
|
||||||
self.action_add.setMenu(self.add_menu)
|
self.action_add.setMenu(self.add_menu)
|
||||||
self.action_add.triggered.connect(self.add_books)
|
self.action_add.triggered.connect(self.add_books)
|
||||||
self.action_del.triggered.connect(self.delete_books)
|
self.action_del.triggered.connect(self.delete_books)
|
||||||
|
@ -146,6 +146,7 @@ class SearchBox2(QComboBox):
|
|||||||
self._in_a_search = False
|
self._in_a_search = False
|
||||||
if event.key() in (Qt.Key_Return, Qt.Key_Enter):
|
if event.key() in (Qt.Key_Return, Qt.Key_Enter):
|
||||||
self.do_search()
|
self.do_search()
|
||||||
|
if self.as_you_type:
|
||||||
self.timer.start(1500)
|
self.timer.start(1500)
|
||||||
|
|
||||||
def mouse_released(self, event):
|
def mouse_released(self, event):
|
||||||
|
@ -675,9 +675,7 @@ class Wizard(QWizard):
|
|||||||
self.connect(self.library_page, SIGNAL('retranslate()'),
|
self.connect(self.library_page, SIGNAL('retranslate()'),
|
||||||
self.retranslate)
|
self.retranslate)
|
||||||
self.finish_page = FinishPage()
|
self.finish_page = FinishPage()
|
||||||
bt = unicode(self.buttonText(self.FinishButton)).replace('&', '')
|
self.set_finish_text()
|
||||||
t = unicode(self.finish_page.finish_text.text())
|
|
||||||
self.finish_page.finish_text.setText(t%bt)
|
|
||||||
self.kindle_page = KindlePage()
|
self.kindle_page = KindlePage()
|
||||||
self.stanza_page = StanzaPage()
|
self.stanza_page = StanzaPage()
|
||||||
self.word_player_page = WordPlayerPage()
|
self.word_player_page = WordPlayerPage()
|
||||||
@ -702,6 +700,7 @@ class Wizard(QWizard):
|
|||||||
for pid in self.pageIds():
|
for pid in self.pageIds():
|
||||||
page = self.page(pid)
|
page = self.page(pid)
|
||||||
page.retranslateUi(page)
|
page.retranslateUi(page)
|
||||||
|
self.set_finish_text()
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
pages = map(self.page, self.visitedPages())
|
pages = map(self.page, self.visitedPages())
|
||||||
@ -715,6 +714,13 @@ class Wizard(QWizard):
|
|||||||
def completed(self, newloc):
|
def completed(self, newloc):
|
||||||
return QWizard.accept(self)
|
return QWizard.accept(self)
|
||||||
|
|
||||||
|
def set_finish_text(self, *args):
|
||||||
|
bt = unicode(self.buttonText(self.FinishButton)).replace('&', '')
|
||||||
|
t = unicode(self.finish_page.finish_text.text())
|
||||||
|
if '%s' in t:
|
||||||
|
self.finish_page.finish_text.setText(t%bt)
|
||||||
|
|
||||||
|
|
||||||
def wizard(parent=None):
|
def wizard(parent=None):
|
||||||
w = Wizard(parent)
|
w = Wizard(parent)
|
||||||
return w
|
return w
|
||||||
|
@ -15,6 +15,7 @@ from calibre import prepare_string_for_xml
|
|||||||
# Hackish - ignoring sentences ending or beginning in numbers to avoid
|
# Hackish - ignoring sentences ending or beginning in numbers to avoid
|
||||||
# confusion with decimal points.
|
# confusion with decimal points.
|
||||||
lost_cr_pat = re.compile('([a-z])([\.\?!])([A-Z])')
|
lost_cr_pat = re.compile('([a-z])([\.\?!])([A-Z])')
|
||||||
|
lost_cr_exception_pat = re.compile(r'(Ph\.D)|(D\.Phil)|((Dr|Mr|Mrs|Ms)\.[A-Z])')
|
||||||
|
|
||||||
def comments_to_html(comments):
|
def comments_to_html(comments):
|
||||||
'''
|
'''
|
||||||
@ -51,6 +52,8 @@ def comments_to_html(comments):
|
|||||||
return '\n'.join(parts)
|
return '\n'.join(parts)
|
||||||
|
|
||||||
# Explode lost CRs to \n\n
|
# Explode lost CRs to \n\n
|
||||||
|
comments = lost_cr_exception_pat.sub(lambda m: m.group().replace('.',
|
||||||
|
'.\r'), comments)
|
||||||
for lost_cr in lost_cr_pat.finditer(comments):
|
for lost_cr in lost_cr_pat.finditer(comments):
|
||||||
comments = comments.replace(lost_cr.group(),
|
comments = comments.replace(lost_cr.group(),
|
||||||
'%s%s\n\n%s' % (lost_cr.group(1),
|
'%s%s\n\n%s' % (lost_cr.group(1),
|
||||||
|
@ -1673,6 +1673,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
self.data.refresh_ids(self, [id]) # Needed to update format list and size
|
self.data.refresh_ids(self, [id]) # Needed to update format list and size
|
||||||
if notify:
|
if notify:
|
||||||
self.notify('add', [id])
|
self.notify('add', [id])
|
||||||
|
return id
|
||||||
|
|
||||||
def get_top_level_move_items(self):
|
def get_top_level_move_items(self):
|
||||||
items = set(os.listdir(self.library_path))
|
items = set(os.listdir(self.library_path))
|
||||||
|
@ -12,7 +12,7 @@ from ctypes import Structure as _Structure, c_char_p, c_uint, c_void_p, POINTER,
|
|||||||
from tempfile import NamedTemporaryFile
|
from tempfile import NamedTemporaryFile
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
|
|
||||||
from calibre import iswindows, load_library, CurrentDir, prints
|
from calibre import iswindows, load_library, CurrentDir
|
||||||
from calibre.ptempfile import TemporaryDirectory
|
from calibre.ptempfile import TemporaryDirectory
|
||||||
|
|
||||||
_librar_name = 'libunrar'
|
_librar_name = 'libunrar'
|
||||||
|
@ -30,8 +30,8 @@ Environment variables
|
|||||||
Tweaks
|
Tweaks
|
||||||
------------
|
------------
|
||||||
|
|
||||||
Tweaks are small changes that you can specify to control various aspects of |app|'s behavior. You specify them by editing the 2tweaks.py file in the config directory.
|
Tweaks are small changes that you can specify to control various aspects of |app|'s behavior. You can change them by going to Preferences->Advanced->Tweaks.
|
||||||
The default tweaks.py file is reproduced below
|
The default values for the tweaks are reproduced below
|
||||||
|
|
||||||
.. literalinclude:: ../../../resources/default_tweaks.py
|
.. literalinclude:: ../../../resources/default_tweaks.py
|
||||||
|
|
||||||
|
@ -277,7 +277,8 @@ In |app|, you would instead use tags to mark genre and read status and then just
|
|||||||
|
|
||||||
Why doesn't |app| have a column for foo?
|
Why doesn't |app| have a column for foo?
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|app| is designed to have columns for the most frequently and widely used fields. If it does not have a coulmn for your favorite field, you can always add a tag to the book for that piece of information. |app| also supports a general purpose "comments" fields for longer items.
|
|app| is designed to have columns for the most frequently and widely used fields. In addition, you can add any columns you like. Columns can be added via Preferences->Interface.
|
||||||
|
Watch the tutorial `UI Power tips <http://calibre-ebook.com/demo#tutorials>`_ to learn how to create your own columns.
|
||||||
|
|
||||||
How do I move my |app| library from one computer to another?
|
How do I move my |app| library from one computer to another?
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -247,6 +247,7 @@ You can search for the absence or presence of a field using the special "true" a
|
|||||||
cover:false will give you all books without a cover
|
cover:false will give you all books without a cover
|
||||||
series:true will give you all books that belong to a series
|
series:true will give you all books that belong to a series
|
||||||
comments:false will give you all books with an empty comment
|
comments:false will give you all books with an empty comment
|
||||||
|
format:false will give you all books with no actual files (empty records)
|
||||||
|
|
||||||
Yes/no custom columns are searchable. Searching for ``false``, ``empty``, or ``blank`` will find all books
|
Yes/no custom columns are searchable. Searching for ``false``, ``empty``, or ``blank`` will find all books
|
||||||
with undefined values in the column. Searching for ``true`` will find all books that do not have undefined
|
with undefined values in the column. Searching for ``true`` will find all books that do not have undefined
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -703,16 +703,21 @@ if prefs['installation_uuid'] is None:
|
|||||||
prefs['installation_uuid'] = str(uuid.uuid4())
|
prefs['installation_uuid'] = str(uuid.uuid4())
|
||||||
|
|
||||||
# Read tweaks
|
# Read tweaks
|
||||||
def read_tweaks():
|
def read_raw_tweaks():
|
||||||
make_config_dir()
|
make_config_dir()
|
||||||
default_tweaks = P('default_tweaks.py', data=True)
|
default_tweaks = P('default_tweaks.py', data=True)
|
||||||
tweaks_file = os.path.join(config_dir, 'tweaks.py')
|
tweaks_file = os.path.join(config_dir, 'tweaks.py')
|
||||||
if not os.path.exists(tweaks_file):
|
if not os.path.exists(tweaks_file):
|
||||||
with open(tweaks_file, 'wb') as f:
|
with open(tweaks_file, 'wb') as f:
|
||||||
f.write(default_tweaks)
|
f.write(default_tweaks)
|
||||||
|
with open(tweaks_file, 'rb') as f:
|
||||||
|
return default_tweaks, f.read()
|
||||||
|
|
||||||
|
def read_tweaks():
|
||||||
|
default_tweaks, tweaks = read_raw_tweaks()
|
||||||
l, g = {}, {}
|
l, g = {}, {}
|
||||||
try:
|
try:
|
||||||
exec open(tweaks_file, 'rb') in g, l
|
exec tweaks in g, l
|
||||||
except:
|
except:
|
||||||
print 'Failed to load custom tweaks file'
|
print 'Failed to load custom tweaks file'
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
@ -721,6 +726,13 @@ def read_tweaks():
|
|||||||
dl.update(l)
|
dl.update(l)
|
||||||
return dl
|
return dl
|
||||||
|
|
||||||
|
def write_tweaks(raw):
|
||||||
|
make_config_dir()
|
||||||
|
tweaks_file = os.path.join(config_dir, 'tweaks.py')
|
||||||
|
with open(tweaks_file, 'wb') as f:
|
||||||
|
f.write(raw)
|
||||||
|
|
||||||
|
|
||||||
tweaks = read_tweaks()
|
tweaks = read_tweaks()
|
||||||
|
|
||||||
def migrate():
|
def migrate():
|
||||||
|
@ -194,7 +194,7 @@ class Image(_magick.Image): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
def create_canvas(width, height, bgcolor):
|
def create_canvas(width, height, bgcolor='white'):
|
||||||
canvas = Image()
|
canvas = Image()
|
||||||
canvas.create_canvas(int(width), int(height), str(bgcolor))
|
canvas.create_canvas(int(width), int(height), str(bgcolor))
|
||||||
return canvas
|
return canvas
|
||||||
|
Loading…
x
Reference in New Issue
Block a user