mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
sync with Kovid's branch
This commit is contained in:
commit
9e6c33961d
@ -20,6 +20,7 @@ class Aksiyon (BasicNewsRecipe):
|
|||||||
auto_cleanup = True
|
auto_cleanup = True
|
||||||
cover_img_url = 'http://www.aksiyon.com.tr/aksiyon/images/aksiyon/top-page/aksiyon_top_r2_c1.jpg'
|
cover_img_url = 'http://www.aksiyon.com.tr/aksiyon/images/aksiyon/top-page/aksiyon_top_r2_c1.jpg'
|
||||||
masthead_url = 'http://aksiyon.com.tr/aksiyon/images/aksiyon/top-page/aksiyon_top_r2_c1.jpg'
|
masthead_url = 'http://aksiyon.com.tr/aksiyon/images/aksiyon/top-page/aksiyon_top_r2_c1.jpg'
|
||||||
|
ignore_duplicate_articles = { 'title', 'url' }
|
||||||
remove_empty_feeds= True
|
remove_empty_feeds= True
|
||||||
feeds = [
|
feeds = [
|
||||||
( u'KAPAK', u'http://www.aksiyon.com.tr/aksiyon/rss?sectionId=26'),
|
( u'KAPAK', u'http://www.aksiyon.com.tr/aksiyon/rss?sectionId=26'),
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -8,19 +8,19 @@ Fetch sueddeutsche.de
|
|||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
class Sueddeutsche(BasicNewsRecipe):
|
class Sueddeutsche(BasicNewsRecipe):
|
||||||
|
|
||||||
title = u'Süddeutsche.de' # 2012-01-26 AGe Correct Title
|
title = u'Süddeutsche.de'
|
||||||
description = 'News from Germany, Access to online content' # 2012-01-26 AGe
|
description = 'News from Germany, Access to online content'
|
||||||
__author__ = 'Oliver Niesner and Armin Geller' #Update AGe 2012-01-26
|
__author__ = 'Oliver Niesner and Armin Geller' #Update AGe 2012-12-05
|
||||||
publisher = u'Süddeutsche Zeitung' # 2012-01-26 AGe add
|
publisher = u'Süddeutsche Zeitung'
|
||||||
category = 'news, politics, Germany' # 2012-01-26 AGe add
|
category = 'news, politics, Germany'
|
||||||
timefmt = ' [%a, %d %b %Y]' # 2012-01-26 AGe add %a
|
timefmt = ' [%a, %d %b %Y]'
|
||||||
oldest_article = 7
|
oldest_article = 7
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
language = 'de'
|
language = 'de'
|
||||||
encoding = 'utf-8'
|
encoding = 'utf-8'
|
||||||
publication_type = 'newspaper' # 2012-01-26 add
|
publication_type = 'newspaper'
|
||||||
cover_source = 'http://www.sueddeutsche.de/verlag' # 2012-01-26 AGe add from Darko Miletic paid content source
|
cover_source = 'http://www.sueddeutsche.de/verlag' # 2012-01-26 AGe add from Darko Miletic paid content source
|
||||||
masthead_url = 'http://www.sueddeutsche.de/static_assets/build/img/sdesiteheader/logo_homepage.441d531c.png' # 2012-01-26 AGe add
|
masthead_url = 'http://www.sueddeutsche.de/static_assets/img/sdesiteheader/logo_standard.a152b0df.png' # 2012-12-05 AGe add
|
||||||
|
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
@ -40,9 +40,9 @@ class Sueddeutsche(BasicNewsRecipe):
|
|||||||
(u'Sport', u'http://suche.sueddeutsche.de/query/%23/sort/-docdatetime/drilldown/%C2%A7ressort%3A%5ESport%24?output=rss'),
|
(u'Sport', u'http://suche.sueddeutsche.de/query/%23/sort/-docdatetime/drilldown/%C2%A7ressort%3A%5ESport%24?output=rss'),
|
||||||
(u'Leben', u'http://suche.sueddeutsche.de/query/%23/sort/-docdatetime/drilldown/%C2%A7ressort%3A%5ELeben%24?output=rss'),
|
(u'Leben', u'http://suche.sueddeutsche.de/query/%23/sort/-docdatetime/drilldown/%C2%A7ressort%3A%5ELeben%24?output=rss'),
|
||||||
(u'Karriere', u'http://suche.sueddeutsche.de/query/%23/sort/-docdatetime/drilldown/%C2%A7ressort%3A%5EKarriere%24?output=rss'),
|
(u'Karriere', u'http://suche.sueddeutsche.de/query/%23/sort/-docdatetime/drilldown/%C2%A7ressort%3A%5EKarriere%24?output=rss'),
|
||||||
(u'Bildung', u'http://rss.sueddeutsche.de/rss/bildung'), #2012-01-26 AGe New
|
(u'Bildung', u'http://rss.sueddeutsche.de/rss/bildung'),
|
||||||
(u'Gesundheit', u'http://rss.sueddeutsche.de/rss/gesundheit'), #2012-01-26 AGe New
|
(u'Gesundheit', u'http://rss.sueddeutsche.de/rss/gesundheit'),
|
||||||
(u'Stil', u'http://rss.sueddeutsche.de/rss/stil'), #2012-01-26 AGe New
|
(u'Stil', u'http://rss.sueddeutsche.de/rss/stil'),
|
||||||
(u'München & Region', u'http://suche.sueddeutsche.de/query/%23/sort/-docdatetime/drilldown/%C2%A7ressort%3A%5EMünchen&Region%24?output=rss'),
|
(u'München & Region', u'http://suche.sueddeutsche.de/query/%23/sort/-docdatetime/drilldown/%C2%A7ressort%3A%5EMünchen&Region%24?output=rss'),
|
||||||
(u'Bayern', u'http://suche.sueddeutsche.de/query/%23/sort/-docdatetime/drilldown/%C2%A7ressort%3A%5EBayern%24?output=rss'),
|
(u'Bayern', u'http://suche.sueddeutsche.de/query/%23/sort/-docdatetime/drilldown/%C2%A7ressort%3A%5EBayern%24?output=rss'),
|
||||||
(u'Medien', u'http://suche.sueddeutsche.de/query/%23/sort/-docdatetime/drilldown/%C2%A7ressort%3A%5EMedien%24?output=rss'),
|
(u'Medien', u'http://suche.sueddeutsche.de/query/%23/sort/-docdatetime/drilldown/%C2%A7ressort%3A%5EMedien%24?output=rss'),
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '4 February 2011, desUBIKado'
|
__copyright__ = '4 February 2011, desUBIKado'
|
||||||
__author__ = 'desUBIKado'
|
__author__ = 'desUBIKado'
|
||||||
__version__ = 'v0.08'
|
__version__ = 'v0.09'
|
||||||
__date__ = '30, June 2012'
|
__date__ = '02, December 2012'
|
||||||
'''
|
'''
|
||||||
http://www.weblogssl.com/
|
http://www.weblogssl.com/
|
||||||
'''
|
'''
|
||||||
@ -37,6 +37,7 @@ class weblogssl(BasicNewsRecipe):
|
|||||||
,(u'Xataka Mexico', u'http://feeds.weblogssl.com/xatakamx')
|
,(u'Xataka Mexico', u'http://feeds.weblogssl.com/xatakamx')
|
||||||
,(u'Xataka M\xf3vil', u'http://feeds.weblogssl.com/xatakamovil')
|
,(u'Xataka M\xf3vil', u'http://feeds.weblogssl.com/xatakamovil')
|
||||||
,(u'Xataka Android', u'http://feeds.weblogssl.com/xatakandroid')
|
,(u'Xataka Android', u'http://feeds.weblogssl.com/xatakandroid')
|
||||||
|
,(u'Xataka Windows', u'http://feeds.weblogssl.com/xatakawindows')
|
||||||
,(u'Xataka Foto', u'http://feeds.weblogssl.com/xatakafoto')
|
,(u'Xataka Foto', u'http://feeds.weblogssl.com/xatakafoto')
|
||||||
,(u'Xataka ON', u'http://feeds.weblogssl.com/xatakaon')
|
,(u'Xataka ON', u'http://feeds.weblogssl.com/xatakaon')
|
||||||
,(u'Xataka Ciencia', u'http://feeds.weblogssl.com/xatakaciencia')
|
,(u'Xataka Ciencia', u'http://feeds.weblogssl.com/xatakaciencia')
|
||||||
@ -80,19 +81,31 @@ class weblogssl(BasicNewsRecipe):
|
|||||||
|
|
||||||
keep_only_tags = [dict(name='div', attrs={'id':'infoblock'}),
|
keep_only_tags = [dict(name='div', attrs={'id':'infoblock'}),
|
||||||
dict(name='div', attrs={'class':'post'}),
|
dict(name='div', attrs={'class':'post'}),
|
||||||
dict(name='div', attrs={'id':'blog-comments'})
|
dict(name='div', attrs={'id':'blog-comments'}),
|
||||||
|
dict(name='div', attrs={'class':'container'}) #m.xataka.com
|
||||||
]
|
]
|
||||||
|
|
||||||
remove_tags = [dict(name='div', attrs={'id':'comment-nav'})]
|
remove_tags = [dict(name='div', attrs={'id':'comment-nav'}),
|
||||||
|
dict(name='menu', attrs={'class':'social-sharing'}), #m.xataka.com
|
||||||
|
dict(name='section' , attrs={'class':'comments'}), #m.xataka.com
|
||||||
|
dict(name='div' , attrs={'class':'article-comments'}), #m.xataka.com
|
||||||
|
dict(name='nav' , attrs={'class':'article-taxonomy'}) #m.xataka.com
|
||||||
|
]
|
||||||
|
|
||||||
|
remove_tags_after = dict(name='section' , attrs={'class':'comments'})
|
||||||
|
|
||||||
def print_version(self, url):
|
def print_version(self, url):
|
||||||
return url.replace('http://www.', 'http://m.')
|
return url.replace('http://www.', 'http://m.')
|
||||||
|
|
||||||
preprocess_regexps = [
|
preprocess_regexps = [
|
||||||
# Para poner una linea en blanco entre un comentario y el siguiente
|
# Para poner una linea en blanco entre un comentario y el siguiente
|
||||||
(re.compile(r'<li id="c', re.DOTALL|re.IGNORECASE), lambda match: '<br><br><li id="c')
|
(re.compile(r'<li id="c', re.DOTALL|re.IGNORECASE), lambda match: '<br><br><li id="c'),
|
||||||
|
# Para ver las imágenes en las noticias de m.xataka.com
|
||||||
|
(re.compile(r'<noscript>', re.DOTALL|re.IGNORECASE), lambda m: ''),
|
||||||
|
(re.compile(r'</noscript>', re.DOTALL|re.IGNORECASE), lambda m: '')
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
# Para sustituir el video incrustado de YouTube por una imagen
|
# Para sustituir el video incrustado de YouTube por una imagen
|
||||||
|
|
||||||
def preprocess_html(self, soup):
|
def preprocess_html(self, soup):
|
||||||
@ -108,14 +121,16 @@ class weblogssl(BasicNewsRecipe):
|
|||||||
|
|
||||||
# Para obtener la url original del articulo a partir de la de "feedsportal"
|
# Para obtener la url original del articulo a partir de la de "feedsportal"
|
||||||
# El siguiente código es gracias al usuario "bosplans" de www.mobileread.com
|
# El siguiente código es gracias al usuario "bosplans" de www.mobileread.com
|
||||||
# http://www.mobileread.com/forums/sho...d.php?t=130297
|
# http://www.mobileread.com/forums/showthread.php?t=130297
|
||||||
|
|
||||||
def get_article_url(self, article):
|
def get_article_url(self, article):
|
||||||
link = article.get('link', None)
|
link = article.get('link', None)
|
||||||
if link is None:
|
if link is None:
|
||||||
return article
|
return article
|
||||||
|
# if link.split('/')[-4]=="xataka2":
|
||||||
|
# return article.get('feedburner_origlink', article.get('link', article.get('guid')))
|
||||||
if link.split('/')[-4]=="xataka2":
|
if link.split('/')[-4]=="xataka2":
|
||||||
return article.get('feedburner_origlink', article.get('link', article.get('guid')))
|
return article.get('guid', None)
|
||||||
if link.split('/')[-1]=="story01.htm":
|
if link.split('/')[-1]=="story01.htm":
|
||||||
link=link.split('/')[-2]
|
link=link.split('/')[-2]
|
||||||
a=['0B','0C','0D','0E','0F','0G','0N' ,'0L0S','0A']
|
a=['0B','0C','0D','0E','0F','0G','0N' ,'0L0S','0A']
|
||||||
|
@ -9,15 +9,15 @@ class Zaman (BasicNewsRecipe):
|
|||||||
__author__ = u'thomass'
|
__author__ = u'thomass'
|
||||||
oldest_article = 2
|
oldest_article = 2
|
||||||
max_articles_per_feed =50
|
max_articles_per_feed =50
|
||||||
# no_stylesheets = True
|
no_stylesheets = True
|
||||||
#delay = 1
|
#delay = 1
|
||||||
#use_embedded_content = False
|
use_embedded_content = False
|
||||||
encoding = 'ISO 8859-9'
|
encoding = 'utf-8'
|
||||||
publisher = 'Zaman'
|
publisher = 'Feza Gazetecilik'
|
||||||
category = 'news, haberler,TR,gazete'
|
category = 'news, haberler,TR,gazete'
|
||||||
language = 'tr'
|
language = 'tr'
|
||||||
publication_type = 'newspaper '
|
publication_type = 'newspaper '
|
||||||
extra_css = '.buyukbaslik{font-weight: bold; font-size: 18px;color:#0000FF}'#body{ font-family: Verdana,Helvetica,Arial,sans-serif } .introduction{font-weight: bold} .story-feature{display: block; padding: 0; border: 1px solid; width: 40%; font-size: small} .story-feature h2{text-align: center; text-transform: uppercase} '
|
extra_css = 'h1{text-transform: capitalize; font-weight: bold; font-size: 22px;color:#0000FF} p{text-align:justify} ' #.introduction{font-weight: bold} .story-feature{display: block; padding: 0; border: 1px solid; width: 40%; font-size: small} .story-feature h2{text-align: center; text-transform: uppercase} '
|
||||||
conversion_options = {
|
conversion_options = {
|
||||||
'tags' : category
|
'tags' : category
|
||||||
,'language' : language
|
,'language' : language
|
||||||
@ -26,25 +26,26 @@ class Zaman (BasicNewsRecipe):
|
|||||||
}
|
}
|
||||||
cover_img_url = 'https://fbcdn-profile-a.akamaihd.net/hprofile-ak-snc4/188140_81722291869_2111820_n.jpg'
|
cover_img_url = 'https://fbcdn-profile-a.akamaihd.net/hprofile-ak-snc4/188140_81722291869_2111820_n.jpg'
|
||||||
masthead_url = 'http://medya.zaman.com.tr/extentions/zaman.com.tr/img/section/logo-section.png'
|
masthead_url = 'http://medya.zaman.com.tr/extentions/zaman.com.tr/img/section/logo-section.png'
|
||||||
|
ignore_duplicate_articles = { 'title', 'url' }
|
||||||
|
auto_cleanup = False
|
||||||
|
remove_empty_feeds= True
|
||||||
|
|
||||||
|
|
||||||
#keep_only_tags = [dict(name='div', attrs={'id':[ 'news-detail-content']}), dict(name='td', attrs={'class':['columnist-detail','columnist_head']}) ]
|
#keep_only_tags = [dict(name='div', attrs={'id':[ 'contentposition19']})]#,dict(name='div', attrs={'id':[ 'xxx']}),dict(name='div', attrs={'id':[ 'xxx']}),dict(name='div', attrs={'id':[ 'xxx']}),dict(name='div', attrs={'id':[ 'xxx']}),dict(name='div', attrs={'id':[ 'xxx']}),dict(name='div', attrs={'id':[ 'xxx']}),dict(name='div', attrs={'id':[ 'news-detail-content']}), dict(name='td', attrs={'class':['columnist-detail','columnist_head']}), ]
|
||||||
remove_tags = [ dict(name='img', attrs={'src':['http://medya.zaman.com.tr/zamantryeni/pics/zamanonline.gif']})]#,dict(name='div', attrs={'class':['radioEmbedBg','radyoProgramAdi']}),dict(name='a', attrs={'class':['webkit-html-attribute-value webkit-html-external-link']}),dict(name='table', attrs={'id':['yaziYorumTablosu']}),dict(name='img', attrs={'src':['http://medya.zaman.com.tr/pics/paylas.gif','http://medya.zaman.com.tr/extentions/zaman.com.tr/img/columnist/ma-16.png']})
|
remove_tags = [ dict(name='img', attrs={'src':['http://cmsmedya.zaman.com.tr/images/logo/logo.bmp']}),dict(name='hr', attrs={'class':['interactive-hr']})]# remove_tags = [ dict(name='div', attrs={'class':[ 'detayUyari']}),dict(name='div', attrs={'class':[ 'detayYorum']}),dict(name='div', attrs={'class':[ 'addthis_toolbox addthis_default_style ']}),dict(name='div', attrs={'id':[ 'tumYazi']})]#,dict(name='div', attrs={'id':[ 'xxx']}),dict(name='div', attrs={'id':[ 'xxx']}),dict(name='div', attrs={'id':[ 'xxx']}),dict(name='div', attrs={'id':[ 'xxx']}),dict(name='div', attrs={'id':[ 'xxx']}),dict(name='div', attrs={'id':[ 'xxx']}),dict(name='img', attrs={'src':['http://medya.zaman.com.tr/zamantryeni/pics/zamanonline.gif']}),dict(name='div', attrs={'class':['radioEmbedBg','radyoProgramAdi']}),dict(name='a', attrs={'class':['webkit-html-attribute-value webkit-html-external-link']}),dict(name='table', attrs={'id':['yaziYorumTablosu']}),dict(name='img', attrs={'src':['http://medya.zaman.com.tr/pics/paylas.gif','http://medya.zaman.com.tr/extentions/zaman.com.tr/img/columnist/ma-16.png']}),dict(name='div', attrs={'id':[ 'news-detail-gallery']}),dict(name='div', attrs={'id':[ 'news-detail-title-bottom-part']}),dict(name='div', attrs={'id':[ 'news-detail-news-paging-main']})]#
|
||||||
|
|
||||||
|
|
||||||
#remove_attributes = ['width','height']
|
#remove_attributes = ['width','height']
|
||||||
remove_empty_feeds= True
|
remove_empty_feeds= True
|
||||||
|
|
||||||
feeds = [
|
feeds = [
|
||||||
( u'Anasayfa', u'http://www.zaman.com.tr/anasayfa.rss'),
|
( u'Manşet', u'http://www.zaman.com.tr/manset.rss'),
|
||||||
( u'Son Dakika', u'http://www.zaman.com.tr/sondakika.rss'),
|
|
||||||
#( u'En çok Okunanlar', u'http://www.zaman.com.tr/max_all.rss'),
|
|
||||||
#( u'Manşet', u'http://www.zaman.com.tr/manset.rss'),
|
|
||||||
( u'Gündem', u'http://www.zaman.com.tr/gundem.rss'),
|
|
||||||
( u'Yazarlar', u'http://www.zaman.com.tr/yazarlar.rss'),
|
( u'Yazarlar', u'http://www.zaman.com.tr/yazarlar.rss'),
|
||||||
( u'Politika', u'http://www.zaman.com.tr/politika.rss'),
|
( u'Politika', u'http://www.zaman.com.tr/politika.rss'),
|
||||||
( u'Ekonomi', u'http://www.zaman.com.tr/ekonomi.rss'),
|
( u'Ekonomi', u'http://www.zaman.com.tr/ekonomi.rss'),
|
||||||
( u'Dış Haberler', u'http://www.zaman.com.tr/dishaberler.rss'),
|
( u'Dış Haberler', u'http://www.zaman.com.tr/dishaberler.rss'),
|
||||||
|
( u'Son Dakika', u'http://www.zaman.com.tr/sondakika.rss'),
|
||||||
|
( u'Gündem', u'http://www.zaman.com.tr/gundem.rss'),
|
||||||
( u'Yorumlar', u'http://www.zaman.com.tr/yorumlar.rss'),
|
( u'Yorumlar', u'http://www.zaman.com.tr/yorumlar.rss'),
|
||||||
( u'Röportaj', u'http://www.zaman.com.tr/roportaj.rss'),
|
( u'Röportaj', u'http://www.zaman.com.tr/roportaj.rss'),
|
||||||
( u'Dizi Yazı', u'http://www.zaman.com.tr/dizi.rss'),
|
( u'Dizi Yazı', u'http://www.zaman.com.tr/dizi.rss'),
|
||||||
@ -59,8 +60,9 @@ class Zaman (BasicNewsRecipe):
|
|||||||
( u'Cuma Eki', u'http://www.zaman.com.tr/cuma.rss'),
|
( u'Cuma Eki', u'http://www.zaman.com.tr/cuma.rss'),
|
||||||
( u'Cumaertesi Eki', u'http://www.zaman.com.tr/cumaertesi.rss'),
|
( u'Cumaertesi Eki', u'http://www.zaman.com.tr/cumaertesi.rss'),
|
||||||
( u'Pazar Eki', u'http://www.zaman.com.tr/pazar.rss'),
|
( u'Pazar Eki', u'http://www.zaman.com.tr/pazar.rss'),
|
||||||
|
( u'En çok Okunanlar', u'http://www.zaman.com.tr/max_all.rss'),
|
||||||
|
( u'Anasayfa', u'http://www.zaman.com.tr/anasayfa.rss'),
|
||||||
|
|
||||||
]
|
]
|
||||||
def print_version(self, url):
|
def print_version(self, url):
|
||||||
return url.replace('http://www.zaman.com.tr/haber.do?haberno=', 'http://www.zaman.com.tr/yazdir.do?haberno=')
|
return url.replace('http://www.zaman.com.tr/newsDetail_getNewsById.action?newsId=', 'http://www.zaman.com.tr/newsDetail_openPrintPage.action?newsId=')
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 62 KiB |
@ -39,18 +39,6 @@ class Win32(WinBase):
|
|||||||
def msi64(self):
|
def msi64(self):
|
||||||
return installer_name('msi', is64bit=True)
|
return installer_name('msi', is64bit=True)
|
||||||
|
|
||||||
def sign_msi(self):
|
|
||||||
import xattr
|
|
||||||
print ('Signing installers ...')
|
|
||||||
sign64 = False
|
|
||||||
msi64 = self.msi64
|
|
||||||
if os.path.exists(msi64) and 'user.signed' not in xattr.list(msi64):
|
|
||||||
subprocess.check_call(['scp', msi64, self.VM_NAME +
|
|
||||||
':build/%s/%s'%(__appname__, msi64)])
|
|
||||||
sign64 = True
|
|
||||||
subprocess.check_call(['ssh', self.VM_NAME, '~/sign.sh'], shell=False)
|
|
||||||
return sign64
|
|
||||||
|
|
||||||
def do_dl(self, installer, errmsg):
|
def do_dl(self, installer, errmsg):
|
||||||
subprocess.check_call(('scp',
|
subprocess.check_call(('scp',
|
||||||
'%s:build/%s/%s'%(self.VM_NAME, __appname__, installer), 'dist'))
|
'%s:build/%s/%s'%(self.VM_NAME, __appname__, installer), 'dist'))
|
||||||
@ -62,14 +50,8 @@ class Win32(WinBase):
|
|||||||
installer = self.installer()
|
installer = self.installer()
|
||||||
if os.path.exists('build/winfrozen'):
|
if os.path.exists('build/winfrozen'):
|
||||||
shutil.rmtree('build/winfrozen')
|
shutil.rmtree('build/winfrozen')
|
||||||
sign64 = self.sign_msi()
|
|
||||||
if sign64:
|
|
||||||
self.do_dl(self.msi64, 'Failed to d/l signed 64 bit installer')
|
|
||||||
import xattr
|
|
||||||
xattr.set(self.msi64, 'user.signed', 'true')
|
|
||||||
|
|
||||||
self.do_dl(installer, 'Failed to freeze')
|
self.do_dl(installer, 'Failed to freeze')
|
||||||
|
|
||||||
installer = 'dist/%s-portable-installer-%s.exe'%(__appname__, __version__)
|
installer = 'dist/%s-portable-installer-%s.exe'%(__appname__, __version__)
|
||||||
self.do_dl(installer, 'Failed to get portable installer')
|
self.do_dl(installer, 'Failed to get portable installer')
|
||||||
|
|
||||||
|
@ -91,6 +91,7 @@ class Win32Freeze(Command, WixMixIn):
|
|||||||
if not is64bit:
|
if not is64bit:
|
||||||
self.build_portable()
|
self.build_portable()
|
||||||
self.build_portable_installer()
|
self.build_portable_installer()
|
||||||
|
self.sign_installers()
|
||||||
|
|
||||||
def remove_CRT_from_manifests(self):
|
def remove_CRT_from_manifests(self):
|
||||||
'''
|
'''
|
||||||
@ -488,6 +489,17 @@ class Win32Freeze(Command, WixMixIn):
|
|||||||
|
|
||||||
subprocess.check_call([LZMA + r'\bin\elzma.exe', '-9', '--lzip', name])
|
subprocess.check_call([LZMA + r'\bin\elzma.exe', '-9', '--lzip', name])
|
||||||
|
|
||||||
|
def sign_installers(self):
|
||||||
|
self.info('Signing installers...')
|
||||||
|
files = glob.glob(self.j('dist', '*.msi')) + glob.glob(self.j('dist',
|
||||||
|
'*.exe'))
|
||||||
|
if not files:
|
||||||
|
raise ValueError('No installers found')
|
||||||
|
subprocess.check_call(['signtool.exe', 'sign', '/a', '/d',
|
||||||
|
'calibre - E-book management', '/du',
|
||||||
|
'http://calibre-ebook.com', '/t',
|
||||||
|
'http://timestamp.verisign.com/scripts/timstamp.dll'] + files)
|
||||||
|
|
||||||
def add_dir_to_zip(self, zf, path, prefix=''):
|
def add_dir_to_zip(self, zf, path, prefix=''):
|
||||||
'''
|
'''
|
||||||
Add a directory recursively to the zip file with an optional prefix.
|
Add a directory recursively to the zip file with an optional prefix.
|
||||||
|
14526
setup/iso_639/ms.po
14526
setup/iso_639/ms.po
File diff suppressed because it is too large
Load Diff
@ -148,10 +148,10 @@ def print_basic_debug_info(out=None):
|
|||||||
out = functools.partial(prints, file=out)
|
out = functools.partial(prints, file=out)
|
||||||
import platform
|
import platform
|
||||||
from calibre.constants import (__appname__, get_version, isportable, isosx,
|
from calibre.constants import (__appname__, get_version, isportable, isosx,
|
||||||
isfrozen)
|
isfrozen, is64bit)
|
||||||
out(__appname__, get_version(), 'Portable' if isportable else '',
|
out(__appname__, get_version(), 'Portable' if isportable else '',
|
||||||
'isfrozen:', isfrozen)
|
'isfrozen:', isfrozen, 'is64bit:', is64bit)
|
||||||
out(platform.platform(), platform.system())
|
out(platform.platform(), platform.system(), platform.architecture())
|
||||||
out(platform.system_alias(platform.system(), platform.release(),
|
out(platform.system_alias(platform.system(), platform.release(),
|
||||||
platform.version()))
|
platform.version()))
|
||||||
out('Python', platform.python_version())
|
out('Python', platform.python_version())
|
||||||
|
@ -232,7 +232,7 @@ class ANDROID(USBMS):
|
|||||||
'THINKPAD_TABLET', 'SGH-T989', 'YP-G70', 'STORAGE_DEVICE',
|
'THINKPAD_TABLET', 'SGH-T989', 'YP-G70', 'STORAGE_DEVICE',
|
||||||
'ADVANCED', 'SGH-I727', 'USB_FLASH_DRIVER', 'ANDROID',
|
'ADVANCED', 'SGH-I727', 'USB_FLASH_DRIVER', 'ANDROID',
|
||||||
'S5830I_CARD', 'MID7042', 'LINK-CREATE', '7035', 'VIEWPAD_7E',
|
'S5830I_CARD', 'MID7042', 'LINK-CREATE', '7035', 'VIEWPAD_7E',
|
||||||
'NOVO7', 'MB526', '_USB#WYK7MSF8KE']
|
'NOVO7', 'MB526', '_USB#WYK7MSF8KE', 'TABLET_PC']
|
||||||
WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'GT-I9000_CARD', 'SGH-I897',
|
WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'GT-I9000_CARD', 'SGH-I897',
|
||||||
'FILE-STOR_GADGET', 'SGH-T959_CARD', 'SGH-T959', 'SAMSUNG_ANDROID', 'GT-P1000_CARD',
|
'FILE-STOR_GADGET', 'SGH-T959_CARD', 'SGH-T959', 'SAMSUNG_ANDROID', 'GT-P1000_CARD',
|
||||||
'A70S', 'A101IT', '7', 'INCREDIBLE', 'A7EB', 'SGH-T849_CARD',
|
'A70S', 'A101IT', '7', 'INCREDIBLE', 'A7EB', 'SGH-T849_CARD',
|
||||||
@ -243,7 +243,7 @@ class ANDROID(USBMS):
|
|||||||
'FILE-CD_GADGET', 'GT-I9001_CARD', 'USB_2.0', 'XT875',
|
'FILE-CD_GADGET', 'GT-I9001_CARD', 'USB_2.0', 'XT875',
|
||||||
'UMS_COMPOSITE', 'PRO', '.KOBO_VOX', 'SGH-T989_CARD', 'SGH-I727',
|
'UMS_COMPOSITE', 'PRO', '.KOBO_VOX', 'SGH-T989_CARD', 'SGH-I727',
|
||||||
'USB_FLASH_DRIVER', 'ANDROID', 'MID7042', '7035', 'VIEWPAD_7E',
|
'USB_FLASH_DRIVER', 'ANDROID', 'MID7042', '7035', 'VIEWPAD_7E',
|
||||||
'NOVO7', 'ADVANCED']
|
'NOVO7', 'ADVANCED', 'TABLET_PC']
|
||||||
|
|
||||||
OSX_MAIN_MEM = 'Android Device Main Memory'
|
OSX_MAIN_MEM = 'Android Device Main Memory'
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -2357,6 +2357,8 @@ class KOBOTOUCH(KOBO):
|
|||||||
update_query = 'UPDATE content SET Series=?, SeriesNumber==? where BookID is Null and ContentID = ?'
|
update_query = 'UPDATE content SET Series=?, SeriesNumber==? where BookID is Null and ContentID = ?'
|
||||||
if book.series is None:
|
if book.series is None:
|
||||||
update_values = (None, None, book.contentID, )
|
update_values = (None, None, book.contentID, )
|
||||||
|
elif book.series_index is None: # This should never happen, but...
|
||||||
|
update_values = (book.series, None, book.contentID, )
|
||||||
else:
|
else:
|
||||||
update_values = (book.series, "%g"%book.series_index, book.contentID, )
|
update_values = (book.series, "%g"%book.series_index, book.contentID, )
|
||||||
|
|
||||||
|
@ -54,6 +54,8 @@ def synchronous(tlockname):
|
|||||||
|
|
||||||
class ConnectionListener (Thread):
|
class ConnectionListener (Thread):
|
||||||
|
|
||||||
|
NOT_SERVICED_COUNT = 6
|
||||||
|
|
||||||
def __init__(self, driver):
|
def __init__(self, driver):
|
||||||
Thread.__init__(self)
|
Thread.__init__(self)
|
||||||
self.daemon = True
|
self.daemon = True
|
||||||
@ -78,8 +80,8 @@ class ConnectionListener (Thread):
|
|||||||
|
|
||||||
if not self.driver.connection_queue.empty():
|
if not self.driver.connection_queue.empty():
|
||||||
queue_not_serviced_count += 1
|
queue_not_serviced_count += 1
|
||||||
if queue_not_serviced_count >= 3:
|
if queue_not_serviced_count >= self.NOT_SERVICED_COUNT:
|
||||||
self.driver._debug('queue not serviced')
|
self.driver._debug('queue not serviced', queue_not_serviced_count)
|
||||||
try:
|
try:
|
||||||
sock = self.driver.connection_queue.get_nowait()
|
sock = self.driver.connection_queue.get_nowait()
|
||||||
s = self.driver._json_encode(
|
s = self.driver._json_encode(
|
||||||
@ -1281,10 +1283,10 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
|
|||||||
self._close_listen_socket()
|
self._close_listen_socket()
|
||||||
return message
|
return message
|
||||||
else:
|
else:
|
||||||
while i < 100: # try up to 100 random port numbers
|
while i < 100: # try 9090 then up to 99 random port numbers
|
||||||
i += 1
|
i += 1
|
||||||
port = self._attach_to_port(self.listen_socket,
|
port = self._attach_to_port(self.listen_socket,
|
||||||
random.randint(8192, 32000))
|
9090 if i == 1 else random.randint(8192, 32000))
|
||||||
if port != 0:
|
if port != 0:
|
||||||
break
|
break
|
||||||
if port == 0:
|
if port == 0:
|
||||||
|
@ -74,11 +74,12 @@ def remove_kindlegen_markup(parts):
|
|||||||
part = "".join(srcpieces)
|
part = "".join(srcpieces)
|
||||||
parts[i] = part
|
parts[i] = part
|
||||||
|
|
||||||
# we can safely remove all of the Kindlegen generated data-AmznPageBreak tags
|
# we can safely remove all of the Kindlegen generated data-AmznPageBreak
|
||||||
|
# attributes
|
||||||
find_tag_with_AmznPageBreak_pattern = re.compile(
|
find_tag_with_AmznPageBreak_pattern = re.compile(
|
||||||
r'''(<[^>]*\sdata-AmznPageBreak=[^>]*>)''', re.IGNORECASE)
|
r'''(<[^>]*\sdata-AmznPageBreak=[^>]*>)''', re.IGNORECASE)
|
||||||
within_tag_AmznPageBreak_position_pattern = re.compile(
|
within_tag_AmznPageBreak_position_pattern = re.compile(
|
||||||
r'''\sdata-AmznPageBreak=['"][^'"]*['"]''')
|
r'''\sdata-AmznPageBreak=['"]([^'"]*)['"]''')
|
||||||
|
|
||||||
for i in xrange(len(parts)):
|
for i in xrange(len(parts)):
|
||||||
part = parts[i]
|
part = parts[i]
|
||||||
@ -86,10 +87,8 @@ def remove_kindlegen_markup(parts):
|
|||||||
for j in range(len(srcpieces)):
|
for j in range(len(srcpieces)):
|
||||||
tag = srcpieces[j]
|
tag = srcpieces[j]
|
||||||
if tag.startswith('<'):
|
if tag.startswith('<'):
|
||||||
for m in within_tag_AmznPageBreak_position_pattern.finditer(tag):
|
srcpieces[j] = within_tag_AmznPageBreak_position_pattern.sub(
|
||||||
replacement = ''
|
lambda m:' style="page-break-after:%s"'%m.group(1), tag)
|
||||||
tag = within_tag_AmznPageBreak_position_pattern.sub(replacement, tag, 1)
|
|
||||||
srcpieces[j] = tag
|
|
||||||
part = "".join(srcpieces)
|
part = "".join(srcpieces)
|
||||||
parts[i] = part
|
parts[i] = part
|
||||||
|
|
||||||
|
@ -44,6 +44,18 @@ def locate_beg_end_of_tag(ml, aid):
|
|||||||
return plt, pgt
|
return plt, pgt
|
||||||
return 0, 0
|
return 0, 0
|
||||||
|
|
||||||
|
def reverse_tag_iter(block):
|
||||||
|
''' Iterate over all tags in block in reverse order, i.e. last tag
|
||||||
|
to first tag. '''
|
||||||
|
end = len(block)
|
||||||
|
while True:
|
||||||
|
pgt = block.rfind(b'>', 0, end)
|
||||||
|
if pgt == -1: break
|
||||||
|
plt = block.rfind(b'<', 0, pgt)
|
||||||
|
if plt == -1: break
|
||||||
|
yield block[plt:pgt+1]
|
||||||
|
end = plt
|
||||||
|
|
||||||
class Mobi8Reader(object):
|
class Mobi8Reader(object):
|
||||||
|
|
||||||
def __init__(self, mobi6_reader, log):
|
def __init__(self, mobi6_reader, log):
|
||||||
@ -275,13 +287,12 @@ class Mobi8Reader(object):
|
|||||||
return '%s/%s'%(fi.type, fi.filename), idtext
|
return '%s/%s'%(fi.type, fi.filename), idtext
|
||||||
|
|
||||||
def get_id_tag(self, pos):
|
def get_id_tag(self, pos):
|
||||||
# find the correct tag by actually searching in the destination
|
# Find the first tag with a named anchor (name or id attribute) before
|
||||||
# textblock at position
|
# pos
|
||||||
fi = self.get_file_info(pos)
|
fi = self.get_file_info(pos)
|
||||||
if fi.num is None and fi.start is None:
|
if fi.num is None and fi.start is None:
|
||||||
raise ValueError('No file contains pos: %d'%pos)
|
raise ValueError('No file contains pos: %d'%pos)
|
||||||
textblock = self.parts[fi.num]
|
textblock = self.parts[fi.num]
|
||||||
id_map = []
|
|
||||||
npos = pos - fi.start
|
npos = pos - fi.start
|
||||||
pgt = textblock.find(b'>', npos)
|
pgt = textblock.find(b'>', npos)
|
||||||
plt = textblock.find(b'<', npos)
|
plt = textblock.find(b'<', npos)
|
||||||
@ -290,28 +301,15 @@ class Mobi8Reader(object):
|
|||||||
if plt == npos or pgt < plt:
|
if plt == npos or pgt < plt:
|
||||||
npos = pgt + 1
|
npos = pgt + 1
|
||||||
textblock = textblock[0:npos]
|
textblock = textblock[0:npos]
|
||||||
# find id links only inside of tags
|
id_re = re.compile(br'''<[^>]+\sid\s*=\s*['"]([^'"]+)['"]''')
|
||||||
# inside any < > pair find all "id=' and return whatever is inside
|
name_re = re.compile(br'''<\s*a\s*\sname\s*=\s*['"]([^'"]+)['"]''')
|
||||||
# the quotes
|
for tag in reverse_tag_iter(textblock):
|
||||||
id_pattern = re.compile(br'''<[^>]*\sid\s*=\s*['"]([^'"]*)['"][^>]*>''',
|
m = id_re.match(tag) or name_re.match(tag)
|
||||||
re.IGNORECASE)
|
if m is not None:
|
||||||
for m in re.finditer(id_pattern, textblock):
|
return m.group(1)
|
||||||
id_map.append((m.start(), m.group(1)))
|
|
||||||
|
|
||||||
if not id_map:
|
# No tag found, link to start of file
|
||||||
# Found no id in the textblock, link must be to top of file
|
return b''
|
||||||
return b''
|
|
||||||
# if npos is before first id= inside a tag, return the first
|
|
||||||
if npos < id_map[0][0]:
|
|
||||||
return id_map[0][1]
|
|
||||||
# if npos is after the last id= inside a tag, return the last
|
|
||||||
if npos > id_map[-1][0]:
|
|
||||||
return id_map[-1][1]
|
|
||||||
# otherwise find last id before npos
|
|
||||||
for i, item in enumerate(id_map):
|
|
||||||
if npos < item[0]:
|
|
||||||
return id_map[i-1][1]
|
|
||||||
return id_map[0][1]
|
|
||||||
|
|
||||||
def create_guide(self):
|
def create_guide(self):
|
||||||
guide = Guide()
|
guide = Guide()
|
||||||
|
@ -320,13 +320,11 @@ class OEBReader(object):
|
|||||||
self.logger.warn(u'Spine item %r not found' % idref)
|
self.logger.warn(u'Spine item %r not found' % idref)
|
||||||
continue
|
continue
|
||||||
item = manifest.ids[idref]
|
item = manifest.ids[idref]
|
||||||
spine.add(item, elem.get('linear'))
|
if item.media_type.lower() in OEB_DOCS and hasattr(item.data, 'xpath'):
|
||||||
for item in spine:
|
spine.add(item, elem.get('linear'))
|
||||||
if item.media_type.lower() not in OEB_DOCS:
|
else:
|
||||||
if not hasattr(item.data, 'xpath'):
|
self.oeb.log.warn('The item %s is not a XML document.'
|
||||||
self.oeb.log.warn('The item %s is not a XML document.'
|
' Removing it from spine.'%item.href)
|
||||||
' Removing it from spine.'%item.href)
|
|
||||||
spine.remove(item)
|
|
||||||
if len(spine) == 0:
|
if len(spine) == 0:
|
||||||
raise OEBError("Spine is empty")
|
raise OEBError("Spine is empty")
|
||||||
self._spine_add_extra()
|
self._spine_add_extra()
|
||||||
|
@ -114,7 +114,9 @@ class DetectStructure(object):
|
|||||||
|
|
||||||
def find_matches(expr, doc):
|
def find_matches(expr, doc):
|
||||||
try:
|
try:
|
||||||
return XPath(expr)(doc)
|
ans = XPath(expr)(doc)
|
||||||
|
len(ans)
|
||||||
|
return ans
|
||||||
except:
|
except:
|
||||||
self.log.warn('Invalid chapter expression, ignoring: %s'%expr)
|
self.log.warn('Invalid chapter expression, ignoring: %s'%expr)
|
||||||
return []
|
return []
|
||||||
@ -203,7 +205,9 @@ class DetectStructure(object):
|
|||||||
|
|
||||||
def find_matches(expr, doc):
|
def find_matches(expr, doc):
|
||||||
try:
|
try:
|
||||||
return XPath(expr)(doc)
|
ans = XPath(expr)(doc)
|
||||||
|
len(ans)
|
||||||
|
return ans
|
||||||
except:
|
except:
|
||||||
self.log.warn('Invalid ToC expression, ignoring: %s'%expr)
|
self.log.warn('Invalid ToC expression, ignoring: %s'%expr)
|
||||||
return []
|
return []
|
||||||
|
@ -27,10 +27,10 @@ def get_custom_size(opts):
|
|||||||
custom_size = None
|
custom_size = None
|
||||||
if opts.custom_size != None:
|
if opts.custom_size != None:
|
||||||
width, sep, height = opts.custom_size.partition('x')
|
width, sep, height = opts.custom_size.partition('x')
|
||||||
if height != '':
|
if height:
|
||||||
try:
|
try:
|
||||||
width = int(width)
|
width = float(width)
|
||||||
height = int(height)
|
height = float(height)
|
||||||
custom_size = (width, height)
|
custom_size = (width, height)
|
||||||
except:
|
except:
|
||||||
custom_size = None
|
custom_size = None
|
||||||
|
@ -72,8 +72,8 @@ class LibreDEStore(BasicStoreConfig, StorePlugin):
|
|||||||
mobi = details.xpath(
|
mobi = details.xpath(
|
||||||
'boolean(.//span[@class="bindername" and contains(text(), "mobipocket")]/text())')
|
'boolean(.//span[@class="bindername" and contains(text(), "mobipocket")]/text())')
|
||||||
|
|
||||||
cover_url = ''.join(data.xpath('.//div[@class="coverImg"]/a/img/@src'))
|
cover_url = ''.join(data.xpath('.//div[@class="coverimg"]/a/img/@src'))
|
||||||
price = ''.join(data.xpath('.//span[@class="preis"]/text()')).replace('*', '').strip()
|
price = ''.join(data.xpath('.//div[@class="preis"]/text()')).replace('*', '').strip()
|
||||||
|
|
||||||
counter -= 1
|
counter -= 1
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ from PyQt4.Qt import (QThread, pyqtSignal, Qt, QUrl, QDialog, QGridLayout,
|
|||||||
import mechanize
|
import mechanize
|
||||||
|
|
||||||
from calibre.constants import (__appname__, __version__, iswindows, isosx,
|
from calibre.constants import (__appname__, __version__, iswindows, isosx,
|
||||||
isportable)
|
isportable, is64bit)
|
||||||
from calibre import browser, prints, as_unicode
|
from calibre import browser, prints, as_unicode
|
||||||
from calibre.utils.config import prefs
|
from calibre.utils.config import prefs
|
||||||
from calibre.gui2 import config, dynamic, open_url
|
from calibre.gui2 import config, dynamic, open_url
|
||||||
@ -19,6 +19,13 @@ URL = 'http://status.calibre-ebook.com/latest'
|
|||||||
NO_CALIBRE_UPDATE = '-0.0.0'
|
NO_CALIBRE_UPDATE = '-0.0.0'
|
||||||
VSEP = '|'
|
VSEP = '|'
|
||||||
|
|
||||||
|
def get_download_url():
|
||||||
|
which = ('portable' if isportable else 'windows' if iswindows
|
||||||
|
else 'osx' if isosx else 'linux')
|
||||||
|
if which == 'windows' and is64bit:
|
||||||
|
which += '64'
|
||||||
|
return 'http://calibre-ebook.com/download_' + which
|
||||||
|
|
||||||
def get_newest_version():
|
def get_newest_version():
|
||||||
br = browser()
|
br = browser()
|
||||||
req = mechanize.Request(URL)
|
req = mechanize.Request(URL)
|
||||||
@ -116,10 +123,7 @@ class UpdateNotification(QDialog):
|
|||||||
config.set('new_version_notification', bool(self.cb.isChecked()))
|
config.set('new_version_notification', bool(self.cb.isChecked()))
|
||||||
|
|
||||||
def accept(self):
|
def accept(self):
|
||||||
url = ('http://calibre-ebook.com/download_' +
|
open_url(QUrl(get_download_url()))
|
||||||
('portable' if isportable else 'windows' if iswindows
|
|
||||||
else 'osx' if isosx else 'linux'))
|
|
||||||
open_url(QUrl(url))
|
|
||||||
|
|
||||||
QDialog.accept(self)
|
QDialog.accept(self)
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2012, Kovid Goyal <kovid@kovidgoyal.net>'
|
__copyright__ = '2012, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
@ -12,6 +12,7 @@ from calibre.customize import CatalogPlugin
|
|||||||
from calibre.library.catalogs import FIELDS
|
from calibre.library.catalogs import FIELDS
|
||||||
from calibre.customize.conversion import DummyReporter
|
from calibre.customize.conversion import DummyReporter
|
||||||
|
|
||||||
|
|
||||||
class CSV_XML(CatalogPlugin):
|
class CSV_XML(CatalogPlugin):
|
||||||
'CSV/XML catalog generator'
|
'CSV/XML catalog generator'
|
||||||
|
|
||||||
@ -22,27 +23,27 @@ class CSV_XML(CatalogPlugin):
|
|||||||
supported_platforms = ['windows', 'osx', 'linux']
|
supported_platforms = ['windows', 'osx', 'linux']
|
||||||
author = 'Greg Riker'
|
author = 'Greg Riker'
|
||||||
version = (1, 0, 0)
|
version = (1, 0, 0)
|
||||||
file_types = set(['csv','xml'])
|
file_types = set(['csv', 'xml'])
|
||||||
|
|
||||||
cli_options = [
|
cli_options = [
|
||||||
Option('--fields',
|
Option('--fields',
|
||||||
default = 'all',
|
default='all',
|
||||||
dest = 'fields',
|
dest='fields',
|
||||||
action = None,
|
action=None,
|
||||||
help = _('The fields to output when cataloging books in the '
|
help=_('The fields to output when cataloging books in the '
|
||||||
'database. Should be a comma-separated list of fields.\n'
|
'database. Should be a comma-separated list of fields.\n'
|
||||||
'Available fields: %(fields)s,\n'
|
'Available fields: %(fields)s,\n'
|
||||||
'plus user-created custom fields.\n'
|
'plus user-created custom fields.\n'
|
||||||
'Example: %(opt)s=title,authors,tags\n'
|
'Example: %(opt)s=title,authors,tags\n'
|
||||||
"Default: '%%default'\n"
|
"Default: '%%default'\n"
|
||||||
"Applies to: CSV, XML output formats")%dict(
|
"Applies to: CSV, XML output formats") % dict(
|
||||||
fields=', '.join(FIELDS), opt='--fields')),
|
fields=', '.join(FIELDS), opt='--fields')),
|
||||||
|
|
||||||
Option('--sort-by',
|
Option('--sort-by',
|
||||||
default = 'id',
|
default='id',
|
||||||
dest = 'sort_by',
|
dest='sort_by',
|
||||||
action = None,
|
action=None,
|
||||||
help = _('Output field to sort on.\n'
|
help=_('Output field to sort on.\n'
|
||||||
'Available fields: author_sort, id, rating, size, timestamp, title_sort\n'
|
'Available fields: author_sort, id, rating, size, timestamp, title_sort\n'
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: CSV, XML output formats"))]
|
"Applies to: CSV, XML output formats"))]
|
||||||
@ -97,7 +98,7 @@ class CSV_XML(CatalogPlugin):
|
|||||||
for entry in data:
|
for entry in data:
|
||||||
entry['ondevice'] = db.catalog_plugin_on_device_temp_mapping[entry['id']]['ondevice']
|
entry['ondevice'] = db.catalog_plugin_on_device_temp_mapping[entry['id']]['ondevice']
|
||||||
|
|
||||||
fm = {x:db.field_metadata.get(x, {}) for x in fields}
|
fm = {x: db.field_metadata.get(x, {}) for x in fields}
|
||||||
|
|
||||||
if self.fmt == 'csv':
|
if self.fmt == 'csv':
|
||||||
outfile = codecs.open(path_to_output, 'w', 'utf8')
|
outfile = codecs.open(path_to_output, 'w', 'utf8')
|
||||||
@ -113,7 +114,7 @@ class CSV_XML(CatalogPlugin):
|
|||||||
outstr = []
|
outstr = []
|
||||||
for field in fields:
|
for field in fields:
|
||||||
if field.startswith('#'):
|
if field.startswith('#'):
|
||||||
item = db.get_field(entry['id'],field,index_is_id=True)
|
item = db.get_field(entry['id'], field, index_is_id=True)
|
||||||
elif field == 'library_name':
|
elif field == 'library_name':
|
||||||
item = current_library
|
item = current_library
|
||||||
elif field == 'title_sort':
|
elif field == 'title_sort':
|
||||||
@ -129,7 +130,7 @@ class CSV_XML(CatalogPlugin):
|
|||||||
for format in item:
|
for format in item:
|
||||||
fmt_list.append(format.rpartition('.')[2].lower())
|
fmt_list.append(format.rpartition('.')[2].lower())
|
||||||
item = ', '.join(fmt_list)
|
item = ', '.join(fmt_list)
|
||||||
elif field in ['authors','tags']:
|
elif field in ['authors', 'tags']:
|
||||||
item = ', '.join(item)
|
item = ', '.join(item)
|
||||||
elif field == 'isbn':
|
elif field == 'isbn':
|
||||||
# Could be 9, 10 or 13 digits
|
# Could be 9, 10 or 13 digits
|
||||||
@ -137,20 +138,20 @@ class CSV_XML(CatalogPlugin):
|
|||||||
elif field in ['pubdate', 'timestamp']:
|
elif field in ['pubdate', 'timestamp']:
|
||||||
item = isoformat(item)
|
item = isoformat(item)
|
||||||
elif field == 'comments':
|
elif field == 'comments':
|
||||||
item = item.replace(u'\r\n',u' ')
|
item = item.replace(u'\r\n', u' ')
|
||||||
item = item.replace(u'\n',u' ')
|
item = item.replace(u'\n', u' ')
|
||||||
elif fm.get(field, {}).get('datatype', None) == 'rating' and item:
|
elif fm.get(field, {}).get('datatype', None) == 'rating' and item:
|
||||||
item = u'%.2g'%(item/2.0)
|
item = u'%.2g' % (item / 2.0)
|
||||||
|
|
||||||
# Convert HTML to markdown text
|
# Convert HTML to markdown text
|
||||||
if type(item) is unicode:
|
if type(item) is unicode:
|
||||||
opening_tag = re.search('<(\w+)(\x20|>)',item)
|
opening_tag = re.search('<(\w+)(\x20|>)', item)
|
||||||
if opening_tag:
|
if opening_tag:
|
||||||
closing_tag = re.search('<\/%s>$' % opening_tag.group(1), item)
|
closing_tag = re.search('<\/%s>$' % opening_tag.group(1), item)
|
||||||
if closing_tag:
|
if closing_tag:
|
||||||
item = html2text(item)
|
item = html2text(item)
|
||||||
|
|
||||||
outstr.append(u'"%s"' % unicode(item).replace('"','""'))
|
outstr.append(u'"%s"' % unicode(item).replace('"', '""'))
|
||||||
|
|
||||||
outfile.write(u','.join(outstr) + u'\n')
|
outfile.write(u','.join(outstr) + u'\n')
|
||||||
outfile.close()
|
outfile.close()
|
||||||
@ -165,14 +166,14 @@ class CSV_XML(CatalogPlugin):
|
|||||||
|
|
||||||
for field in fields:
|
for field in fields:
|
||||||
if field.startswith('#'):
|
if field.startswith('#'):
|
||||||
val = db.get_field(r['id'],field,index_is_id=True)
|
val = db.get_field(r['id'], field, index_is_id=True)
|
||||||
if not isinstance(val, (str, unicode)):
|
if not isinstance(val, (str, unicode)):
|
||||||
val = unicode(val)
|
val = unicode(val)
|
||||||
item = getattr(E, field.replace('#','_'))(val)
|
item = getattr(E, field.replace('#', '_'))(val)
|
||||||
record.append(item)
|
record.append(item)
|
||||||
|
|
||||||
for field in ('id', 'uuid', 'publisher', 'rating', 'size',
|
for field in ('id', 'uuid', 'publisher', 'rating', 'size',
|
||||||
'isbn','ondevice', 'identifiers'):
|
'isbn', 'ondevice', 'identifiers'):
|
||||||
if field in fields:
|
if field in fields:
|
||||||
val = r[field]
|
val = r[field]
|
||||||
if not val:
|
if not val:
|
||||||
@ -180,7 +181,7 @@ class CSV_XML(CatalogPlugin):
|
|||||||
if not isinstance(val, (str, unicode)):
|
if not isinstance(val, (str, unicode)):
|
||||||
if (fm.get(field, {}).get('datatype', None) ==
|
if (fm.get(field, {}).get('datatype', None) ==
|
||||||
'rating' and val):
|
'rating' and val):
|
||||||
val = u'%.2g'%(val/2.0)
|
val = u'%.2g' % (val / 2.0)
|
||||||
val = unicode(val)
|
val = unicode(val)
|
||||||
item = getattr(E, field)(val)
|
item = getattr(E, field)(val)
|
||||||
record.append(item)
|
record.append(item)
|
||||||
@ -227,4 +228,3 @@ class CSV_XML(CatalogPlugin):
|
|||||||
with open(path_to_output, 'w') as f:
|
with open(path_to_output, 'w') as f:
|
||||||
f.write(etree.tostring(root, encoding='utf-8',
|
f.write(etree.tostring(root, encoding='utf-8',
|
||||||
xml_declaration=True, pretty_print=True))
|
xml_declaration=True, pretty_print=True))
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
from __future__ import (unicode_literals, division, absolute_import,
|
from __future__ import (unicode_literals, division, absolute_import,
|
||||||
print_function)
|
print_function)
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2012, Kovid Goyal <kovid@kovidgoyal.net>'
|
__copyright__ = '2012, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
@ -21,6 +21,7 @@ from calibre.utils.localization import get_lang
|
|||||||
|
|
||||||
Option = namedtuple('Option', 'option, default, dest, action, help')
|
Option = namedtuple('Option', 'option, default, dest, action, help')
|
||||||
|
|
||||||
|
|
||||||
class EPUB_MOBI(CatalogPlugin):
|
class EPUB_MOBI(CatalogPlugin):
|
||||||
'ePub catalog generator'
|
'ePub catalog generator'
|
||||||
|
|
||||||
@ -30,29 +31,29 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
minimum_calibre_version = (0, 7, 40)
|
minimum_calibre_version = (0, 7, 40)
|
||||||
author = 'Greg Riker'
|
author = 'Greg Riker'
|
||||||
version = (1, 0, 0)
|
version = (1, 0, 0)
|
||||||
file_types = set(['azw3','epub','mobi'])
|
file_types = set(['azw3', 'epub', 'mobi'])
|
||||||
|
|
||||||
THUMB_SMALLEST = "1.0"
|
THUMB_SMALLEST = "1.0"
|
||||||
THUMB_LARGEST = "2.0"
|
THUMB_LARGEST = "2.0"
|
||||||
|
|
||||||
cli_options = [Option('--catalog-title', # {{{
|
cli_options = [Option('--catalog-title', # {{{
|
||||||
default = 'My Books',
|
default='My Books',
|
||||||
dest = 'catalog_title',
|
dest='catalog_title',
|
||||||
action = None,
|
action=None,
|
||||||
help = _('Title of generated catalog used as title in metadata.\n'
|
help=_('Title of generated catalog used as title in metadata.\n'
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: AZW3, ePub, MOBI output formats")),
|
"Applies to: AZW3, ePub, MOBI output formats")),
|
||||||
Option('--cross-reference-authors',
|
Option('--cross-reference-authors',
|
||||||
default=False,
|
default=False,
|
||||||
dest='cross_reference_authors',
|
dest='cross_reference_authors',
|
||||||
action = 'store_true',
|
action='store_true',
|
||||||
help=_("Create cross-references in Authors section for books with multiple authors.\n"
|
help=_("Create cross-references in Authors section for books with multiple authors.\n"
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: AZW3, ePub, MOBI output formats")),
|
"Applies to: AZW3, ePub, MOBI output formats")),
|
||||||
Option('--debug-pipeline',
|
Option('--debug-pipeline',
|
||||||
default=None,
|
default=None,
|
||||||
dest='debug_pipeline',
|
dest='debug_pipeline',
|
||||||
action = None,
|
action=None,
|
||||||
help=_("Save the output from different stages of the conversion "
|
help=_("Save the output from different stages of the conversion "
|
||||||
"pipeline to the specified "
|
"pipeline to the specified "
|
||||||
"directory. Useful if you are unsure at which stage "
|
"directory. Useful if you are unsure at which stage "
|
||||||
@ -62,7 +63,7 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
Option('--exclude-genre',
|
Option('--exclude-genre',
|
||||||
default='\[.+\]|^\+$',
|
default='\[.+\]|^\+$',
|
||||||
dest='exclude_genre',
|
dest='exclude_genre',
|
||||||
action = None,
|
action=None,
|
||||||
help=_("Regex describing tags to exclude as genres.\n"
|
help=_("Regex describing tags to exclude as genres.\n"
|
||||||
"Default: '%default' excludes bracketed tags, e.g. '[Project Gutenberg]', and '+', the default tag for read books.\n"
|
"Default: '%default' excludes bracketed tags, e.g. '[Project Gutenberg]', and '+', the default tag for read books.\n"
|
||||||
"Applies to: AZW3, ePub, MOBI output formats")),
|
"Applies to: AZW3, ePub, MOBI output formats")),
|
||||||
@ -82,63 +83,63 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
Option('--generate-authors',
|
Option('--generate-authors',
|
||||||
default=False,
|
default=False,
|
||||||
dest='generate_authors',
|
dest='generate_authors',
|
||||||
action = 'store_true',
|
action='store_true',
|
||||||
help=_("Include 'Authors' section in catalog.\n"
|
help=_("Include 'Authors' section in catalog.\n"
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: AZW3, ePub, MOBI output formats")),
|
"Applies to: AZW3, ePub, MOBI output formats")),
|
||||||
Option('--generate-descriptions',
|
Option('--generate-descriptions',
|
||||||
default=False,
|
default=False,
|
||||||
dest='generate_descriptions',
|
dest='generate_descriptions',
|
||||||
action = 'store_true',
|
action='store_true',
|
||||||
help=_("Include 'Descriptions' section in catalog.\n"
|
help=_("Include 'Descriptions' section in catalog.\n"
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: AZW3, ePub, MOBI output formats")),
|
"Applies to: AZW3, ePub, MOBI output formats")),
|
||||||
Option('--generate-genres',
|
Option('--generate-genres',
|
||||||
default=False,
|
default=False,
|
||||||
dest='generate_genres',
|
dest='generate_genres',
|
||||||
action = 'store_true',
|
action='store_true',
|
||||||
help=_("Include 'Genres' section in catalog.\n"
|
help=_("Include 'Genres' section in catalog.\n"
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: AZW3, ePub, MOBI output formats")),
|
"Applies to: AZW3, ePub, MOBI output formats")),
|
||||||
Option('--generate-titles',
|
Option('--generate-titles',
|
||||||
default=False,
|
default=False,
|
||||||
dest='generate_titles',
|
dest='generate_titles',
|
||||||
action = 'store_true',
|
action='store_true',
|
||||||
help=_("Include 'Titles' section in catalog.\n"
|
help=_("Include 'Titles' section in catalog.\n"
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: AZW3, ePub, MOBI output formats")),
|
"Applies to: AZW3, ePub, MOBI output formats")),
|
||||||
Option('--generate-series',
|
Option('--generate-series',
|
||||||
default=False,
|
default=False,
|
||||||
dest='generate_series',
|
dest='generate_series',
|
||||||
action = 'store_true',
|
action='store_true',
|
||||||
help=_("Include 'Series' section in catalog.\n"
|
help=_("Include 'Series' section in catalog.\n"
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: AZW3, ePub, MOBI output formats")),
|
"Applies to: AZW3, ePub, MOBI output formats")),
|
||||||
Option('--generate-recently-added',
|
Option('--generate-recently-added',
|
||||||
default=False,
|
default=False,
|
||||||
dest='generate_recently_added',
|
dest='generate_recently_added',
|
||||||
action = 'store_true',
|
action='store_true',
|
||||||
help=_("Include 'Recently Added' section in catalog.\n"
|
help=_("Include 'Recently Added' section in catalog.\n"
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: AZW3, ePub, MOBI output formats")),
|
"Applies to: AZW3, ePub, MOBI output formats")),
|
||||||
Option('--genre-source-field',
|
Option('--genre-source-field',
|
||||||
default='Tags',
|
default='Tags',
|
||||||
dest='genre_source_field',
|
dest='genre_source_field',
|
||||||
action = None,
|
action=None,
|
||||||
help=_("Source field for Genres section.\n"
|
help=_("Source field for Genres section.\n"
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: AZW3, ePub, MOBI output formats")),
|
"Applies to: AZW3, ePub, MOBI output formats")),
|
||||||
Option('--header-note-source-field',
|
Option('--header-note-source-field',
|
||||||
default='',
|
default='',
|
||||||
dest='header_note_source_field',
|
dest='header_note_source_field',
|
||||||
action = None,
|
action=None,
|
||||||
help=_("Custom field containing note text to insert in Description header.\n"
|
help=_("Custom field containing note text to insert in Description header.\n"
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: AZW3, ePub, MOBI output formats")),
|
"Applies to: AZW3, ePub, MOBI output formats")),
|
||||||
Option('--merge-comments-rule',
|
Option('--merge-comments-rule',
|
||||||
default='::',
|
default='::',
|
||||||
dest='merge_comments_rule',
|
dest='merge_comments_rule',
|
||||||
action = None,
|
action=None,
|
||||||
help=_("#<custom field>:[before|after]:[True|False] specifying:\n"
|
help=_("#<custom field>:[before|after]:[True|False] specifying:\n"
|
||||||
" <custom field> Custom field containing notes to merge with Comments\n"
|
" <custom field> Custom field containing notes to merge with Comments\n"
|
||||||
" [before|after] Placement of notes with respect to Comments\n"
|
" [before|after] Placement of notes with respect to Comments\n"
|
||||||
@ -148,7 +149,7 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
Option('--output-profile',
|
Option('--output-profile',
|
||||||
default=None,
|
default=None,
|
||||||
dest='output_profile',
|
dest='output_profile',
|
||||||
action = None,
|
action=None,
|
||||||
help=_("Specifies the output profile. In some cases, an output profile is required to optimize the catalog for the device. For example, 'kindle' or 'kindle_dx' creates a structured Table of Contents with Sections and Articles.\n"
|
help=_("Specifies the output profile. In some cases, an output profile is required to optimize the catalog for the device. For example, 'kindle' or 'kindle_dx' creates a structured Table of Contents with Sections and Articles.\n"
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: AZW3, ePub, MOBI output formats")),
|
"Applies to: AZW3, ePub, MOBI output formats")),
|
||||||
@ -164,14 +165,14 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
Option('--use-existing-cover',
|
Option('--use-existing-cover',
|
||||||
default=False,
|
default=False,
|
||||||
dest='use_existing_cover',
|
dest='use_existing_cover',
|
||||||
action = 'store_true',
|
action='store_true',
|
||||||
help=_("Replace existing cover when generating the catalog.\n"
|
help=_("Replace existing cover when generating the catalog.\n"
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
"Applies to: AZW3, ePub, MOBI output formats")),
|
"Applies to: AZW3, ePub, MOBI output formats")),
|
||||||
Option('--thumb-width',
|
Option('--thumb-width',
|
||||||
default='1.0',
|
default='1.0',
|
||||||
dest='thumb_width',
|
dest='thumb_width',
|
||||||
action = None,
|
action=None,
|
||||||
help=_("Size hint (in inches) for book covers in catalog.\n"
|
help=_("Size hint (in inches) for book covers in catalog.\n"
|
||||||
"Range: 1.0 - 2.0\n"
|
"Range: 1.0 - 2.0\n"
|
||||||
"Default: '%default'\n"
|
"Default: '%default'\n"
|
||||||
@ -199,7 +200,7 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
if opts.connected_device['name'] and 'kindle' in opts.connected_device['name'].lower():
|
if opts.connected_device['name'] and 'kindle' in opts.connected_device['name'].lower():
|
||||||
opts.connected_kindle = True
|
opts.connected_kindle = True
|
||||||
if opts.connected_device['serial'] and \
|
if opts.connected_device['serial'] and \
|
||||||
opts.connected_device['serial'][:4] in ['B004','B005']:
|
opts.connected_device['serial'][:4] in ['B004', 'B005']:
|
||||||
op = "kindle_dx"
|
op = "kindle_dx"
|
||||||
else:
|
else:
|
||||||
op = "kindle"
|
op = "kindle"
|
||||||
@ -209,7 +210,7 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
opts.output_profile = op
|
opts.output_profile = op
|
||||||
|
|
||||||
opts.basename = "Catalog"
|
opts.basename = "Catalog"
|
||||||
opts.cli_environment = not hasattr(opts,'sync')
|
opts.cli_environment = not hasattr(opts, 'sync')
|
||||||
|
|
||||||
# Hard-wired to always sort descriptions by author, with series after non-series
|
# Hard-wired to always sort descriptions by author, with series after non-series
|
||||||
opts.sort_descriptions_by_author = True
|
opts.sort_descriptions_by_author = True
|
||||||
@ -278,14 +279,14 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
opts.generate_genres = True
|
opts.generate_genres = True
|
||||||
opts.generate_recently_added = True
|
opts.generate_recently_added = True
|
||||||
opts.generate_descriptions = True
|
opts.generate_descriptions = True
|
||||||
sections_list = ['Authors','Titles','Series','Genres','Recently Added','Descriptions']
|
sections_list = ['Authors', 'Titles', 'Series', 'Genres', 'Recently Added', 'Descriptions']
|
||||||
else:
|
else:
|
||||||
opts.log.warn('\n*** No enabled Sections, terminating catalog generation ***')
|
opts.log.warn('\n*** No enabled Sections, terminating catalog generation ***')
|
||||||
return ["No Included Sections","No enabled Sections.\nCheck E-book options tab\n'Included sections'\n"]
|
return ["No Included Sections", "No enabled Sections.\nCheck E-book options tab\n'Included sections'\n"]
|
||||||
if opts.fmt == 'mobi' and sections_list == ['Descriptions']:
|
if opts.fmt == 'mobi' and sections_list == ['Descriptions']:
|
||||||
warning = _("\n*** Adding 'By Authors' Section required for MOBI output ***")
|
warning = _("\n*** Adding 'By Authors' Section required for MOBI output ***")
|
||||||
opts.log.warn(warning)
|
opts.log.warn(warning)
|
||||||
sections_list.insert(0,'Authors')
|
sections_list.insert(0, 'Authors')
|
||||||
opts.generate_authors = True
|
opts.generate_authors = True
|
||||||
|
|
||||||
opts.log(u" Sections: %s" % ', '.join(sections_list))
|
opts.log(u" Sections: %s" % ', '.join(sections_list))
|
||||||
@ -294,14 +295,14 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
# Limit thumb_width to 1.0" - 2.0"
|
# Limit thumb_width to 1.0" - 2.0"
|
||||||
try:
|
try:
|
||||||
if float(opts.thumb_width) < float(self.THUMB_SMALLEST):
|
if float(opts.thumb_width) < float(self.THUMB_SMALLEST):
|
||||||
log.warning("coercing thumb_width from '%s' to '%s'" % (opts.thumb_width,self.THUMB_SMALLEST))
|
log.warning("coercing thumb_width from '%s' to '%s'" % (opts.thumb_width, self.THUMB_SMALLEST))
|
||||||
opts.thumb_width = self.THUMB_SMALLEST
|
opts.thumb_width = self.THUMB_SMALLEST
|
||||||
if float(opts.thumb_width) > float(self.THUMB_LARGEST):
|
if float(opts.thumb_width) > float(self.THUMB_LARGEST):
|
||||||
log.warning("coercing thumb_width from '%s' to '%s'" % (opts.thumb_width,self.THUMB_LARGEST))
|
log.warning("coercing thumb_width from '%s' to '%s'" % (opts.thumb_width, self.THUMB_LARGEST))
|
||||||
opts.thumb_width = self.THUMB_LARGEST
|
opts.thumb_width = self.THUMB_LARGEST
|
||||||
opts.thumb_width = "%.2f" % float(opts.thumb_width)
|
opts.thumb_width = "%.2f" % float(opts.thumb_width)
|
||||||
except:
|
except:
|
||||||
log.error("coercing thumb_width from '%s' to '%s'" % (opts.thumb_width,self.THUMB_SMALLEST))
|
log.error("coercing thumb_width from '%s' to '%s'" % (opts.thumb_width, self.THUMB_SMALLEST))
|
||||||
opts.thumb_width = "1.0"
|
opts.thumb_width = "1.0"
|
||||||
|
|
||||||
# eval prefix_rules if passed from command line
|
# eval prefix_rules if passed from command line
|
||||||
@ -331,13 +332,13 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
keys.sort()
|
keys.sort()
|
||||||
build_log.append(" opts:")
|
build_log.append(" opts:")
|
||||||
for key in keys:
|
for key in keys:
|
||||||
if key in ['catalog_title','author_clip','connected_kindle','creator',
|
if key in ['catalog_title', 'author_clip', 'connected_kindle', 'creator',
|
||||||
'cross_reference_authors','description_clip','exclude_book_marker',
|
'cross_reference_authors', 'description_clip', 'exclude_book_marker',
|
||||||
'exclude_genre','exclude_tags','exclusion_rules', 'fmt',
|
'exclude_genre', 'exclude_tags', 'exclusion_rules', 'fmt',
|
||||||
'genre_source_field', 'header_note_source_field','merge_comments_rule',
|
'genre_source_field', 'header_note_source_field', 'merge_comments_rule',
|
||||||
'output_profile','prefix_rules','read_book_marker',
|
'output_profile', 'prefix_rules', 'read_book_marker',
|
||||||
'search_text','sort_by','sort_descriptions_by_author','sync',
|
'search_text', 'sort_by', 'sort_descriptions_by_author', 'sync',
|
||||||
'thumb_width','use_existing_cover','wishlist_tag']:
|
'thumb_width', 'use_existing_cover', 'wishlist_tag']:
|
||||||
build_log.append(" %s: %s" % (key, repr(opts_dict[key])))
|
build_log.append(" %s: %s" % (key, repr(opts_dict[key])))
|
||||||
if opts.verbose:
|
if opts.verbose:
|
||||||
log('\n'.join(line for line in build_log))
|
log('\n'.join(line for line in build_log))
|
||||||
@ -370,8 +371,8 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
"""
|
"""
|
||||||
GENERATE_DEBUG_EPUB = False
|
GENERATE_DEBUG_EPUB = False
|
||||||
if GENERATE_DEBUG_EPUB:
|
if GENERATE_DEBUG_EPUB:
|
||||||
catalog_debug_path = os.path.join(os.path.expanduser('~'),'Desktop','Catalog debug')
|
catalog_debug_path = os.path.join(os.path.expanduser('~'), 'Desktop', 'Catalog debug')
|
||||||
setattr(opts,'debug_pipeline',os.path.expanduser(catalog_debug_path))
|
setattr(opts, 'debug_pipeline', os.path.expanduser(catalog_debug_path))
|
||||||
|
|
||||||
dp = getattr(opts, 'debug_pipeline', None)
|
dp = getattr(opts, 'debug_pipeline', None)
|
||||||
if dp is not None:
|
if dp is not None:
|
||||||
@ -381,11 +382,13 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
if opts.output_profile and opts.output_profile.startswith("kindle"):
|
if opts.output_profile and opts.output_profile.startswith("kindle"):
|
||||||
recommendations.append(('output_profile', opts.output_profile,
|
recommendations.append(('output_profile', opts.output_profile,
|
||||||
OptionRecommendation.HIGH))
|
OptionRecommendation.HIGH))
|
||||||
recommendations.append(('book_producer',opts.output_profile,
|
recommendations.append(('book_producer', opts.output_profile,
|
||||||
OptionRecommendation.HIGH))
|
OptionRecommendation.HIGH))
|
||||||
if opts.fmt == 'mobi':
|
if opts.fmt == 'mobi':
|
||||||
recommendations.append(('no_inline_toc', True,
|
recommendations.append(('no_inline_toc', True,
|
||||||
OptionRecommendation.HIGH))
|
OptionRecommendation.HIGH))
|
||||||
|
recommendations.append(('verbose', 2,
|
||||||
|
OptionRecommendation.HIGH))
|
||||||
|
|
||||||
# Use existing cover or generate new cover
|
# Use existing cover or generate new cover
|
||||||
cpath = None
|
cpath = None
|
||||||
@ -432,14 +435,13 @@ class EPUB_MOBI(CatalogPlugin):
|
|||||||
from calibre.ebooks.epub import initialize_container
|
from calibre.ebooks.epub import initialize_container
|
||||||
from calibre.ebooks.tweak import zip_rebuilder
|
from calibre.ebooks.tweak import zip_rebuilder
|
||||||
from calibre.utils.zipfile import ZipFile
|
from calibre.utils.zipfile import ZipFile
|
||||||
input_path = os.path.join(catalog_debug_path,'input')
|
input_path = os.path.join(catalog_debug_path, 'input')
|
||||||
epub_shell = os.path.join(catalog_debug_path,'epub_shell.zip')
|
epub_shell = os.path.join(catalog_debug_path, 'epub_shell.zip')
|
||||||
initialize_container(epub_shell, opf_name='content.opf')
|
initialize_container(epub_shell, opf_name='content.opf')
|
||||||
with ZipFile(epub_shell, 'r') as zf:
|
with ZipFile(epub_shell, 'r') as zf:
|
||||||
zf.extractall(path=input_path)
|
zf.extractall(path=input_path)
|
||||||
os.remove(epub_shell)
|
os.remove(epub_shell)
|
||||||
zip_rebuilder(input_path, os.path.join(catalog_debug_path,'input.epub'))
|
zip_rebuilder(input_path, os.path.join(catalog_debug_path, 'input.epub'))
|
||||||
|
|
||||||
# returns to gui2.actions.catalog:catalog_generated()
|
# returns to gui2.actions.catalog:catalog_generated()
|
||||||
return catalog.error
|
return catalog.error
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -22,6 +22,7 @@ from calibre.library.comments import comments_to_html
|
|||||||
from calibre.library.server import custom_fields_to_display
|
from calibre.library.server import custom_fields_to_display
|
||||||
from calibre.library.field_metadata import category_icon_map
|
from calibre.library.field_metadata import category_icon_map
|
||||||
from calibre.library.server.utils import quote, unquote
|
from calibre.library.server.utils import quote, unquote
|
||||||
|
from calibre.ebooks.metadata.sources.identify import urls_from_identifiers
|
||||||
|
|
||||||
def xml(*args, **kwargs):
|
def xml(*args, **kwargs):
|
||||||
ans = prepare_string_for_xml(*args, **kwargs)
|
ans = prepare_string_for_xml(*args, **kwargs)
|
||||||
@ -823,6 +824,16 @@ class BrowseServer(object):
|
|||||||
if field in ('title', 'formats') or not args.get(field, False) \
|
if field in ('title', 'formats') or not args.get(field, False) \
|
||||||
or not m['name']:
|
or not m['name']:
|
||||||
continue
|
continue
|
||||||
|
if field == 'identifiers':
|
||||||
|
urls = urls_from_identifiers(mi.get(field, {}))
|
||||||
|
links = [u'<a class="details_category_link" target="_new" href="%s" title="%s:%s">%s</a>' % (url, id_typ, id_val, name)
|
||||||
|
for name, id_typ, id_val, url in urls]
|
||||||
|
links = u', '.join(links)
|
||||||
|
if links:
|
||||||
|
fields.append((m['name'], u'<strong>%s: </strong>%s'%(
|
||||||
|
_('Ids'), links)))
|
||||||
|
continue
|
||||||
|
|
||||||
if m['datatype'] == 'rating':
|
if m['datatype'] == 'rating':
|
||||||
r = u'<strong>%s: </strong>'%xml(m['name']) + \
|
r = u'<strong>%s: </strong>'%xml(m['name']) + \
|
||||||
render_rating(mi.get(field)/2.0, self.opts.url_prefix,
|
render_rating(mi.get(field)/2.0, self.opts.url_prefix,
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user