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
615f9b8e8f
@ -4,6 +4,65 @@
|
|||||||
# for important features/bug fixes.
|
# for important features/bug fixes.
|
||||||
# Also, each release can have new and improved recipes.
|
# Also, each release can have new and improved recipes.
|
||||||
|
|
||||||
|
- version: 0.7.2
|
||||||
|
date: 2010-06-11
|
||||||
|
|
||||||
|
new features:
|
||||||
|
- title: "The Cover Browser can now be freely resized."
|
||||||
|
description: >
|
||||||
|
"You can now resize the Cover Browser just like the other areas of the user interface by dragging the edge. The Cover Browser now
|
||||||
|
also emphasizes the cetral book cover, making it larger than the others. Also on widescreen monitors the cover browser is now automatically placed
|
||||||
|
to the side of the book list instead of below it."
|
||||||
|
|
||||||
|
- title: "Added tweak to control how titles and series names are sorted"
|
||||||
|
|
||||||
|
- title: "Clicking on row numbers no longer open the viewer. Instead you have to double click"
|
||||||
|
|
||||||
|
bug fixes:
|
||||||
|
- title: "SONY driver: The regression causing slow perfomance has been corrected. Various bug fixes to deal with corner cases"
|
||||||
|
|
||||||
|
- title: "iPad driver: Various bugfixes, should now work much more seamlessly."
|
||||||
|
|
||||||
|
- title: "Fix regression causing calibre to not start if the library path is invalid, because say a drive has been removed"
|
||||||
|
tickets: [5787]
|
||||||
|
|
||||||
|
- title: "Fix regression in 0.7.1 that broke searching in the e-book viewers and for news sources"
|
||||||
|
|
||||||
|
- title: "Fix regressions that caused the Publisher to change when updating Series and floating point custom columns to be rounded to integers."
|
||||||
|
tickets: [5788]
|
||||||
|
|
||||||
|
- title: "Fix regression that broke check database integrity in the presence of custom coulmns or user categories"
|
||||||
|
tickets: [5779]
|
||||||
|
|
||||||
|
- title: "Fix regresison that broke the Email to submenu in the send to device menu"
|
||||||
|
|
||||||
|
- title: "Fix Tag browser re-opening closed tree after editing metadata"
|
||||||
|
tickets: [5744]
|
||||||
|
|
||||||
|
- title: "Conversion pipeline: Handle missing/obsolete input/output profiles gracefully"
|
||||||
|
|
||||||
|
- title: "Fix Adding/Deleting Search does not refresh Left Pane Correctly"
|
||||||
|
tickets: [5751]
|
||||||
|
|
||||||
|
- title: "Content server: Fix serving of CBZ/CBR files to stanza"
|
||||||
|
|
||||||
|
new recipes:
|
||||||
|
- title: Repantes, Haaretz
|
||||||
|
author: Darko Miletic
|
||||||
|
|
||||||
|
- title: CBC Canada
|
||||||
|
author: rty
|
||||||
|
|
||||||
|
|
||||||
|
improved recipes:
|
||||||
|
- The Sun
|
||||||
|
- The Economist
|
||||||
|
- Boston Globe
|
||||||
|
- Honolulu Star Advertiser
|
||||||
|
- SMH
|
||||||
|
- Sueddeutsche
|
||||||
|
- Our Daily Bread
|
||||||
|
|
||||||
- version: 0.7.1
|
- version: 0.7.1
|
||||||
date: 2010-06-04
|
date: 2010-06-04
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 983 B After Width: | Height: | Size: 983 B |
@ -1,5 +1,5 @@
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
|
__copyright__ = '2009-2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
'''
|
'''
|
||||||
www.boston.com
|
www.boston.com
|
||||||
'''
|
'''
|
||||||
@ -7,10 +7,10 @@ www.boston.com
|
|||||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||||
|
|
||||||
class BusinessStandard(BasicNewsRecipe):
|
class BusinessStandard(BasicNewsRecipe):
|
||||||
title = 'Boston'
|
title = 'The Boston Globe'
|
||||||
__author__ = 'Darko Miletic'
|
__author__ = 'Darko Miletic'
|
||||||
description = 'News from Boston'
|
description = 'News from Boston'
|
||||||
oldest_article = 7
|
oldest_article = 2
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
delay = 1
|
delay = 1
|
||||||
@ -19,6 +19,9 @@ class BusinessStandard(BasicNewsRecipe):
|
|||||||
publisher = 'Boston'
|
publisher = 'Boston'
|
||||||
category = 'news, boston, usa, world'
|
category = 'news, boston, usa, world'
|
||||||
language = 'en'
|
language = 'en'
|
||||||
|
publication_type = 'newspaper'
|
||||||
|
masthead_url = 'http://cache.boston.com/images/globe/grslider/the_boston_globe.gif'
|
||||||
|
extra_css = ' body{font-family: Georgia, serif} div#articleBodyTop{display:block} '
|
||||||
|
|
||||||
conversion_options = {
|
conversion_options = {
|
||||||
'comments' : description
|
'comments' : description
|
||||||
@ -27,8 +30,11 @@ class BusinessStandard(BasicNewsRecipe):
|
|||||||
,'publisher' : publisher
|
,'publisher' : publisher
|
||||||
}
|
}
|
||||||
|
|
||||||
keep_only_tags = [dict(name='div', attrs={'class':'story'})]
|
keep_only_tags = [dict(attrs={'id':['INDblogEntry','blogEntry','articleHeader','articleGraphs','galleryShell']})]
|
||||||
remove_tags = [dict(name=['object','link','script','iframe'])]
|
remove_tags = [
|
||||||
|
dict(name=['object','link','script','iframe'])
|
||||||
|
,dict(attrs={'id':['blogheadTools','bdc_emailWidget','tools','relatedContent']})
|
||||||
|
]
|
||||||
|
|
||||||
feeds = [
|
feeds = [
|
||||||
(u'Top Stories' , u'http://feeds.boston.com/boston/topstories' )
|
(u'Top Stories' , u'http://feeds.boston.com/boston/topstories' )
|
||||||
@ -38,12 +44,9 @@ class BusinessStandard(BasicNewsRecipe):
|
|||||||
]
|
]
|
||||||
|
|
||||||
def print_version(self, url):
|
def print_version(self, url):
|
||||||
return url + '?mode=PF'
|
return url + '?page=full'
|
||||||
|
|
||||||
def get_article_url(self, article):
|
def get_article_url(self, article):
|
||||||
rawarticle = article.get('pheedo_origlink', None)
|
rawarticle = article.get('guid', None)
|
||||||
artls, sep, rsep = rawarticle.rpartition('/?')
|
return rawarticle.rpartition('?')[0]
|
||||||
if artls == '':
|
|
||||||
artls = rawarticle.rpartition('?')[0]
|
|
||||||
return artls
|
|
||||||
|
|
||||||
|
@ -88,7 +88,9 @@ class Economist(BasicNewsRecipe):
|
|||||||
continue
|
continue
|
||||||
a = tag.find('a', href=True)
|
a = tag.find('a', href=True)
|
||||||
if a is not None:
|
if a is not None:
|
||||||
url=a['href'].split('?')[0]+'/print'
|
url=a['href']
|
||||||
|
id_ = re.search(r'story_id=(\d+)', url).group(1)
|
||||||
|
url = 'http://www.economist.com/node/%s/print'%id_
|
||||||
if url.startswith('Printer'):
|
if url.startswith('Printer'):
|
||||||
url = '/'+url
|
url = '/'+url
|
||||||
if url.startswith('/'):
|
if url.startswith('/'):
|
||||||
|
@ -1,96 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: cp1252 -*-
|
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
|
|
||||||
'''
|
|
||||||
honoluluadvertiser.com
|
|
||||||
'''
|
|
||||||
|
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
|
||||||
|
|
||||||
class Honoluluadvertiser(BasicNewsRecipe):
|
|
||||||
title = 'Honolulu Advertiser'
|
|
||||||
__author__ = 'Darko Miletic and Sujata Raman'
|
|
||||||
description = "Latest national and local Hawaii sports news from The Honolulu Advertiser."
|
|
||||||
publisher = 'Honolulu Advertiser'
|
|
||||||
category = 'news, Honolulu, Hawaii'
|
|
||||||
oldest_article = 2
|
|
||||||
language = 'en'
|
|
||||||
|
|
||||||
max_articles_per_feed = 100
|
|
||||||
no_stylesheets = True
|
|
||||||
use_embedded_content = False
|
|
||||||
encoding = 'cp1252'
|
|
||||||
remove_javascript = True
|
|
||||||
cover_url = 'http://www.honoluluadvertiser.com/graphics/frontpage/frontpage.jpg'
|
|
||||||
|
|
||||||
html2lrf_options = [
|
|
||||||
'--comment' , description
|
|
||||||
, '--category' , category
|
|
||||||
, '--publisher' , publisher
|
|
||||||
]
|
|
||||||
|
|
||||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
|
||||||
|
|
||||||
keep_only_tags = [dict(name='div', attrs={'class':["hon_article_top","article-bodytext","hon_article_photo","storyphoto","article"]}),
|
|
||||||
dict(name='div', attrs={'id':["storycontentleft","article"]})
|
|
||||||
]
|
|
||||||
|
|
||||||
remove_tags = [dict(name=['object','link','embed']),
|
|
||||||
dict(name='div', attrs={'class':["article-tools","titleBar","invisiblespacer","articleflex-container","hon_newslist","categoryheader","columnframe","subHeadline","poster-container"]}),
|
|
||||||
dict(name='div', attrs={'align':["right"]}),
|
|
||||||
dict(name='div', attrs={'id':["pluckcomments"]}),
|
|
||||||
dict(name='td', attrs={'class':["prepsfacts"]}),
|
|
||||||
dict(name='img', attrs={'height':["1"]}),
|
|
||||||
dict(name='img', attrs={'alt':["Advertisement"]}),
|
|
||||||
dict(name='img', attrs={'src':["/gcicommonfiles/sr/graphics/common/adlabel_horz.gif","/gcicommonfiles/sr/graphics/common/icon_whatsthis.gif",]}),
|
|
||||||
]
|
|
||||||
|
|
||||||
extra_css = '''
|
|
||||||
h1{font-family:Arial,Helvetica,sans-serif; font-size:large; color:#000000; }
|
|
||||||
.hon_article_timestamp{font-family:Arial,Helvetica,sans-serif; font-size:70%; }
|
|
||||||
.postedStoryDate{font-family:Arial,Helvetica,sans-serif; font-size:30%; }
|
|
||||||
.postedDate{font-family:Arial,Helvetica,sans-serif; font-size:30%; }
|
|
||||||
.credit{font-family:Arial,Helvetica,sans-serif; font-size:30%; }
|
|
||||||
.hon_article_top{font-family:Arial,Helvetica,sans-serif; color:#666666; font-size:30%; font-weight:bold;}
|
|
||||||
.grayBackground{font-family:Arial,Helvetica,sans-serif; color:#666666; font-size:30%;}
|
|
||||||
.hon_photocaption{font-family:Arial,Helvetica,sans-serif; font-size:30%; }
|
|
||||||
.photoCaption{font-family:Arial,Helvetica,sans-serif; font-size:30%; }
|
|
||||||
.hon_photocredit{font-family:Arial,Helvetica,sans-serif; font-size:30%; color:#666666;}
|
|
||||||
.storyphoto{font-family:Arial,Helvetica,sans-serif; font-size:30%; color:#666666;}
|
|
||||||
.article-bodytext{font-family:Arial,Helvetica,sans-serif; font-size:xx-small; }
|
|
||||||
.storycontentleft{font-family:Arial,Helvetica,sans-serif; font-size:xx-small; }
|
|
||||||
#article{font-family:Arial,Helvetica,sans-serif; font-size:xx-small; }
|
|
||||||
.contentarea{font-family:Arial,Helvetica,sans-serif; font-size:xx-small; }
|
|
||||||
.storytext{font-family:Verdana,Arial,Helvetica,sans-serif; font-size:xx-small;}
|
|
||||||
.storyHeadline{font-family:Arial,Helvetica,sans-serif; font-size:large; color:#000000; font-weight:bold;}
|
|
||||||
.source{font-family:Arial,Helvetica,sans-serif; color:#333333; font-style: italic; font-weight:bold; }
|
|
||||||
'''
|
|
||||||
|
|
||||||
feeds = [
|
|
||||||
(u'Breaking news', u'http://www.honoluluadvertiser.com/apps/pbcs.dll/section?Category=RSS01&MIME=XML' )
|
|
||||||
,(u'Local news', u'http://www.honoluluadvertiser.com/apps/pbcs.dll/section?Category=RSS02&MIME=XML' )
|
|
||||||
,(u'Sports', u'http://www.honoluluadvertiser.com/apps/pbcs.dll/section?Category=RSS03&MIME=XML' )
|
|
||||||
,(u'Island life', u'http://www.honoluluadvertiser.com/apps/pbcs.dll/section?Category=RSS05&MIME=XML' )
|
|
||||||
,(u'Entertainment', u'http://www.honoluluadvertiser.com/apps/pbcs.dll/section?Category=RSS06&MIME=XML' )
|
|
||||||
,(u'Business', u'http://www.honoluluadvertiser.com/apps/pbcs.dll/section?Category=RSS04&MIME=XML' )
|
|
||||||
]
|
|
||||||
|
|
||||||
def preprocess_html(self, soup):
|
|
||||||
for item in soup.findAll(style=True):
|
|
||||||
del item['style']
|
|
||||||
mtag = '\n<meta http-equiv="Content-Language" content="en"/>\n'
|
|
||||||
soup.head.insert(0,mtag)
|
|
||||||
|
|
||||||
for tag in soup.findAll(name=['span','table','font']):
|
|
||||||
tag.name = 'div'
|
|
||||||
|
|
||||||
return soup
|
|
||||||
|
|
||||||
|
|
||||||
# def print_version(self, url):
|
|
||||||
# ubody, sep, rest = url.rpartition('/-1/')
|
|
||||||
# root, sep2, article_id = ubody.partition('/article/')
|
|
||||||
# return u'http://www.honoluluadvertiser.com/apps/pbcs.dll/article?AID=/' + article_id + '&template=printart'
|
|
||||||
|
|
@ -51,6 +51,7 @@ class LeMondeDiplomatiqueEn(BasicNewsRecipe):
|
|||||||
, dict(name='div',attrs={'class':'notes surlignable'})
|
, dict(name='div',attrs={'class':'notes surlignable'})
|
||||||
]
|
]
|
||||||
remove_tags = [dict(name=['object','link','script','iframe','base'])]
|
remove_tags = [dict(name=['object','link','script','iframe','base'])]
|
||||||
|
remove_attributes = ['height','width']
|
||||||
|
|
||||||
def parse_index(self):
|
def parse_index(self):
|
||||||
articles = []
|
articles = []
|
||||||
@ -72,5 +73,5 @@ class LeMondeDiplomatiqueEn(BasicNewsRecipe):
|
|||||||
,'url' :url
|
,'url' :url
|
||||||
,'description':description
|
,'description':description
|
||||||
})
|
})
|
||||||
return [(soup.head.title.string, articles)]
|
return [(self.title, articles)]
|
||||||
|
|
||||||
|
47
resources/recipes/staradvertiser.recipe
Normal file
47
resources/recipes/staradvertiser.recipe
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2009-2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
|
'''
|
||||||
|
staradvertiser.com
|
||||||
|
'''
|
||||||
|
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class Starbulletin(BasicNewsRecipe):
|
||||||
|
title = 'Honolulu Star Advertiser'
|
||||||
|
__author__ = 'Darko Miletic'
|
||||||
|
description = "Latest national and local Hawaii sports news"
|
||||||
|
publisher = 'Honolulu Star-Advertiser'
|
||||||
|
category = 'news, Honolulu, Hawaii'
|
||||||
|
oldest_article = 2
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
language = 'en'
|
||||||
|
no_stylesheets = True
|
||||||
|
use_embedded_content = False
|
||||||
|
encoding = 'utf8'
|
||||||
|
publication_type = 'newspaper'
|
||||||
|
extra_css = ' body{font-family: Verdana,Arial,Helvetica,sans-serif} h1,.brown,.postCredit{color: #663300} .storyDeck{font-size: 1.2em; font-weight: bold} '
|
||||||
|
|
||||||
|
conversion_options = {
|
||||||
|
'comment' : description
|
||||||
|
, 'tags' : category
|
||||||
|
, 'publisher' : publisher
|
||||||
|
, 'language' : language
|
||||||
|
, 'linearize_tables' : True
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_tags_before = dict(attrs={'id':'storyTitle'})
|
||||||
|
remove_tags_after = dict(name='div', attrs={'class':'storytext'})
|
||||||
|
remove_tags = [
|
||||||
|
dict(name=['object','link'])
|
||||||
|
,dict(attrs={'class':'insideStoryImage'})
|
||||||
|
]
|
||||||
|
|
||||||
|
feeds = [
|
||||||
|
(u'Headlines' , u'http://www.staradvertiser.com/staradvertiser_headlines.rss' )
|
||||||
|
,(u'News' , u'http://www.staradvertiser.com/news/index.rss' )
|
||||||
|
,(u'Sports' , u'http://www.staradvertiser.com/sports/index.rss' )
|
||||||
|
,(u'Features' , u'http://www.staradvertiser.com/features/index.rss' )
|
||||||
|
,(u'Editorials', u'http://www.staradvertiser.com/editorials/index.rss' )
|
||||||
|
,(u'Business' , u'http://www.staradvertiser.com/business/index.rss' )
|
||||||
|
,(u'Travel' , u'http://www.staradvertiser.com/travel/index.rss' )
|
||||||
|
]
|
@ -1,60 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
|
|
||||||
'''
|
|
||||||
starbulletin.com
|
|
||||||
'''
|
|
||||||
|
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
|
||||||
|
|
||||||
class Starbulletin(BasicNewsRecipe):
|
|
||||||
title = 'Honolulu Star-Bulletin'
|
|
||||||
__author__ = 'Darko Miletic'
|
|
||||||
description = "Latest national and local Hawaii sports news"
|
|
||||||
publisher = 'Honolulu Star-Bulletin'
|
|
||||||
category = 'news, Honolulu, Hawaii'
|
|
||||||
oldest_article = 2
|
|
||||||
max_articles_per_feed = 100
|
|
||||||
language = 'en'
|
|
||||||
|
|
||||||
no_stylesheets = True
|
|
||||||
use_embedded_content = False
|
|
||||||
encoding = 'utf8'
|
|
||||||
remove_javascript = True
|
|
||||||
cover_url = 'http://media.starbulletin.com/designimages/spacer.gif'
|
|
||||||
|
|
||||||
html2lrf_options = [
|
|
||||||
'--comment' , description
|
|
||||||
, '--category' , category
|
|
||||||
, '--publisher' , publisher
|
|
||||||
]
|
|
||||||
|
|
||||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
|
||||||
|
|
||||||
keep_only_tags = [ dict(name='div', attrs={'id':'storyColoumn'}) ]
|
|
||||||
|
|
||||||
remove_tags = [
|
|
||||||
dict(name=['object','link'])
|
|
||||||
,dict(name='span', attrs={'id':'printdesc'})
|
|
||||||
,dict(name='div' , attrs={'class':'lightGreyBox storyTools clearAll'})
|
|
||||||
,dict(name='div' , attrs={'id':'breadcrumbs'})
|
|
||||||
]
|
|
||||||
|
|
||||||
feeds = [
|
|
||||||
(u'Headlines', u'http://www.starbulletin.com/starbulletin_headlines.rss' )
|
|
||||||
,(u'News', u'http://www.starbulletin.com/news/index.rss' )
|
|
||||||
,(u'Sports', u'http://www.starbulletin.com/sports/index.rss' )
|
|
||||||
,(u'Features', u'http://www.starbulletin.com/features/index.rss' )
|
|
||||||
,(u'Editorials', u'http://www.starbulletin.com/editorials/index.rss' )
|
|
||||||
,(u'Business', u'http://www.starbulletin.com/business/index.rss' )
|
|
||||||
,(u'Travel', u'http://www.starbulletin.com/travel/index.rss' )
|
|
||||||
]
|
|
||||||
|
|
||||||
def preprocess_html(self, soup):
|
|
||||||
for item in soup.findAll(style=True):
|
|
||||||
del item['style']
|
|
||||||
mtag = '\n<meta http-equiv="Content-Language" content="en"/>\n'
|
|
||||||
soup.head.insert(0,mtag)
|
|
||||||
return soup
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
|||||||
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 AdvancedUserRecipe1268409464(BasicNewsRecipe):
|
class AdvancedUserRecipe1268409464(BasicNewsRecipe):
|
||||||
title = u'The Sun'
|
title = u'The Sun'
|
||||||
@ -14,24 +15,27 @@ class AdvancedUserRecipe1268409464(BasicNewsRecipe):
|
|||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
|
|
||||||
keep_only_tags = [
|
keep_only_tags = [
|
||||||
dict(name='div', attrs={'class':'medium-centered'})
|
dict(id='column-print')
|
||||||
,dict(name='div', attrs={'class':'article'})
|
|
||||||
,dict(name='div', attrs={'class':'clear-left'})
|
|
||||||
,dict(name='div', attrs={'class':'text-center'})
|
|
||||||
]
|
]
|
||||||
|
|
||||||
remove_tags = [
|
remove_tags = [
|
||||||
dict(name='div', attrs={'class':'slideshow'})
|
dict(name='div', attrs={'class':[
|
||||||
,dict(name='div', attrs={'class':'float-left'})
|
'clear text-center small padding-left-right-5 text-999 padding-top-5 padding-bottom-10 grey-solid-line',
|
||||||
,dict(name='div', attrs={'class':'ltbx-slideshow ltbx-btn-ss'})
|
'clear width-625 bg-fff padding-top-10'
|
||||||
,dict(name='a', attrs={'class':'add_a_comment'})
|
]}),
|
||||||
,dict(name='div', attrs={'id':'vxFlashPlayerContent'})
|
dict(name='video'),
|
||||||
,dict(name='div', attrs={'id':'k1006094r1c1t5w380h529'})
|
|
||||||
,dict(name='div', attrs={'id':'tum_login_form_container'})
|
|
||||||
,dict(name='div', attrs={'class':'discHeader'})
|
|
||||||
,dict(name='div', attrs={'class':'margin-bottom-neg-2'})
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def preprocess_html(self, soup):
|
||||||
|
h1 = soup.find('h1')
|
||||||
|
if h1 is not None:
|
||||||
|
text = self.tag_to_string(h1)
|
||||||
|
nh = Tag(soup, 'h1')
|
||||||
|
nh.insert(0, text)
|
||||||
|
h1.replaceWith(nh)
|
||||||
|
|
||||||
|
return soup
|
||||||
|
|
||||||
|
|
||||||
feeds = [(u'News', u'http://www.thesun.co.uk/sol/homepage/feeds/rss/article312900.ece')
|
feeds = [(u'News', u'http://www.thesun.co.uk/sol/homepage/feeds/rss/article312900.ece')
|
||||||
,(u'Sport', u'http://www.thesun.co.uk/sol/homepage/feeds/rss/article247732.ece')
|
,(u'Sport', u'http://www.thesun.co.uk/sol/homepage/feeds/rss/article247732.ece')
|
||||||
|
@ -2,7 +2,7 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
__appname__ = 'calibre'
|
__appname__ = 'calibre'
|
||||||
__version__ = '0.7.1'
|
__version__ = '0.7.2'
|
||||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
@ -445,7 +445,7 @@ from calibre.devices.nook.driver import NOOK
|
|||||||
from calibre.devices.prs505.driver import PRS505
|
from calibre.devices.prs505.driver import PRS505
|
||||||
from calibre.devices.android.driver import ANDROID, S60
|
from calibre.devices.android.driver import ANDROID, S60
|
||||||
from calibre.devices.nokia.driver import N770, N810, E71X
|
from calibre.devices.nokia.driver import N770, N810, E71X
|
||||||
from calibre.devices.eslick.driver import ESLICK
|
from calibre.devices.eslick.driver import ESLICK, EBK52
|
||||||
from calibre.devices.nuut2.driver import NUUT2
|
from calibre.devices.nuut2.driver import NUUT2
|
||||||
from calibre.devices.iriver.driver import IRIVER_STORY
|
from calibre.devices.iriver.driver import IRIVER_STORY
|
||||||
from calibre.devices.binatone.driver import README
|
from calibre.devices.binatone.driver import README
|
||||||
@ -519,6 +519,7 @@ plugins += [
|
|||||||
N810,
|
N810,
|
||||||
COOL_ER,
|
COOL_ER,
|
||||||
ESLICK,
|
ESLICK,
|
||||||
|
EBK52,
|
||||||
NUUT2,
|
NUUT2,
|
||||||
IRIVER_STORY,
|
IRIVER_STORY,
|
||||||
GER2,
|
GER2,
|
||||||
|
@ -14,7 +14,6 @@ from calibre.devices.interface import DevicePlugin
|
|||||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup
|
from calibre.ebooks.BeautifulSoup import BeautifulSoup
|
||||||
from calibre.ebooks.metadata import MetaInformation
|
from calibre.ebooks.metadata import MetaInformation
|
||||||
from calibre.library.server.utils import strftime
|
from calibre.library.server.utils import strftime
|
||||||
from calibre.ptempfile import PersistentTemporaryFile
|
|
||||||
from calibre.utils.config import Config, config_dir
|
from calibre.utils.config import Config, config_dir
|
||||||
from calibre.utils.date import parse_date
|
from calibre.utils.date import parse_date
|
||||||
from calibre.utils.logging import Log
|
from calibre.utils.logging import Log
|
||||||
@ -147,6 +146,7 @@ class ITUNES(DevicePlugin):
|
|||||||
ejected = False
|
ejected = False
|
||||||
iTunes= None
|
iTunes= None
|
||||||
iTunes_media = None
|
iTunes_media = None
|
||||||
|
library_orphans = None
|
||||||
log = Log()
|
log = Log()
|
||||||
manual_sync_mode = False
|
manual_sync_mode = False
|
||||||
path_template = 'iTunes/%s - %s.epub'
|
path_template = 'iTunes/%s - %s.epub'
|
||||||
@ -244,14 +244,13 @@ class ITUNES(DevicePlugin):
|
|||||||
|
|
||||||
# Fetch a list of books from iPod device connected to iTunes
|
# Fetch a list of books from iPod device connected to iTunes
|
||||||
|
|
||||||
# Fetch Library|Books
|
|
||||||
library_books = self._get_library_books()
|
|
||||||
|
|
||||||
if 'iPod' in self.sources:
|
if 'iPod' in self.sources:
|
||||||
booklist = BookList(self.log)
|
booklist = BookList(self.log)
|
||||||
cached_books = {}
|
cached_books = {}
|
||||||
|
|
||||||
if isosx:
|
if isosx:
|
||||||
|
library_books = self._get_library_books()
|
||||||
device_books = self._get_device_books()
|
device_books = self._get_device_books()
|
||||||
book_count = float(len(device_books))
|
book_count = float(len(device_books))
|
||||||
for (i,book) in enumerate(device_books):
|
for (i,book) in enumerate(device_books):
|
||||||
@ -281,11 +280,13 @@ class ITUNES(DevicePlugin):
|
|||||||
|
|
||||||
if self.report_progress is not None:
|
if self.report_progress is not None:
|
||||||
self.report_progress(i+1/book_count, _('%d of %d') % (i+1, book_count))
|
self.report_progress(i+1/book_count, _('%d of %d') % (i+1, book_count))
|
||||||
|
self._purge_orphans(cached_books)
|
||||||
|
|
||||||
elif iswindows:
|
elif iswindows:
|
||||||
try:
|
try:
|
||||||
pythoncom.CoInitialize()
|
pythoncom.CoInitialize()
|
||||||
self.iTunes = win32com.client.Dispatch("iTunes.Application")
|
self.iTunes = win32com.client.Dispatch("iTunes.Application")
|
||||||
|
library_books = self._get_library_books()
|
||||||
device_books = self._get_device_books()
|
device_books = self._get_device_books()
|
||||||
book_count = float(len(device_books))
|
book_count = float(len(device_books))
|
||||||
for (i,book) in enumerate(device_books):
|
for (i,book) in enumerate(device_books):
|
||||||
@ -315,6 +316,7 @@ class ITUNES(DevicePlugin):
|
|||||||
if self.report_progress is not None:
|
if self.report_progress is not None:
|
||||||
self.report_progress(i+1/book_count,
|
self.report_progress(i+1/book_count,
|
||||||
_('%d of %d') % (i+1, book_count))
|
_('%d of %d') % (i+1, book_count))
|
||||||
|
self._purge_orphans(cached_books)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
pythoncom.CoUninitialize()
|
pythoncom.CoUninitialize()
|
||||||
@ -985,7 +987,6 @@ class ITUNES(DevicePlugin):
|
|||||||
connected_device = self.sources['iPod']
|
connected_device = self.sources['iPod']
|
||||||
device = self.iTunes.sources.ItemByName(connected_device)
|
device = self.iTunes.sources.ItemByName(connected_device)
|
||||||
|
|
||||||
dev_books = None
|
|
||||||
added = None
|
added = None
|
||||||
for pl in device.Playlists:
|
for pl in device.Playlists:
|
||||||
if pl.Kind == self.PlaylistKind.index('User') and \
|
if pl.Kind == self.PlaylistKind.index('User') and \
|
||||||
@ -1638,7 +1639,6 @@ class ITUNES(DevicePlugin):
|
|||||||
connected_device = self.sources['iPod']
|
connected_device = self.sources['iPod']
|
||||||
device = self.iTunes.sources.ItemByName(connected_device)
|
device = self.iTunes.sources.ItemByName(connected_device)
|
||||||
|
|
||||||
dev_books = None
|
|
||||||
for pl in device.Playlists:
|
for pl in device.Playlists:
|
||||||
if pl.Kind == self.PlaylistKind.index('User') and \
|
if pl.Kind == self.PlaylistKind.index('User') and \
|
||||||
pl.SpecialKind == self.PlaylistSpecialKind.index('Books'):
|
pl.SpecialKind == self.PlaylistSpecialKind.index('Books'):
|
||||||
@ -1671,11 +1671,13 @@ class ITUNES(DevicePlugin):
|
|||||||
def _get_library_books(self):
|
def _get_library_books(self):
|
||||||
'''
|
'''
|
||||||
Populate a dict of paths from iTunes Library|Books
|
Populate a dict of paths from iTunes Library|Books
|
||||||
|
Windows assumes pythoncom wrapper
|
||||||
'''
|
'''
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info("\n ITUNES._get_library_books()")
|
self.log.info("\n ITUNES._get_library_books()")
|
||||||
|
|
||||||
library_books = {}
|
library_books = {}
|
||||||
|
library_orphans = {}
|
||||||
lib = None
|
lib = None
|
||||||
|
|
||||||
if isosx:
|
if isosx:
|
||||||
@ -1708,15 +1710,14 @@ class ITUNES(DevicePlugin):
|
|||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(" ignoring '%s' of type '%s'" % (book.name(), book.kind()))
|
self.log.info(" ignoring '%s' of type '%s'" % (book.name(), book.kind()))
|
||||||
else:
|
else:
|
||||||
# Remove calibre orphans
|
# Collect calibre orphans - remnants of recipe uploads
|
||||||
|
path = self.path_template % (book.name(), book.artist())
|
||||||
if str(book.description()).startswith(self.description_prefix):
|
if str(book.description()).startswith(self.description_prefix):
|
||||||
if book.location() == appscript.k.missing_value:
|
if book.location() == appscript.k.missing_value:
|
||||||
|
library_orphans[path] = book
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(" found calibre orphan '%s' in Library|Books" % book.name())
|
self.log.info(" found calibre orphan '%s' in Library|Books" % book.name())
|
||||||
#book.delete()
|
|
||||||
#continue
|
|
||||||
|
|
||||||
path = self.path_template % (book.name(), book.artist())
|
|
||||||
library_books[path] = book
|
library_books[path] = book
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(" adding %-30.30s [%s]" % (book.name(), book.kind()))
|
self.log.info(" adding %-30.30s [%s]" % (book.name(), book.kind()))
|
||||||
@ -1729,59 +1730,59 @@ class ITUNES(DevicePlugin):
|
|||||||
|
|
||||||
elif iswindows:
|
elif iswindows:
|
||||||
lib = None
|
lib = None
|
||||||
try:
|
# try:
|
||||||
pythoncom.CoInitialize()
|
# pythoncom.CoInitialize()
|
||||||
self.iTunes = win32com.client.Dispatch("iTunes.Application")
|
# self.iTunes = win32com.client.Dispatch("iTunes.Application")
|
||||||
for source in self.iTunes.sources:
|
for source in self.iTunes.sources:
|
||||||
if source.Kind == self.Sources.index('Library'):
|
if source.Kind == self.Sources.index('Library'):
|
||||||
lib = source
|
lib = source
|
||||||
self.log.info(" Library source: '%s' kind: %s" % (lib.Name, self.Sources[lib.Kind]))
|
self.log.info(" Library source: '%s' kind: %s" % (lib.Name, self.Sources[lib.Kind]))
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
self.log.error(" Library source not found")
|
self.log.error(" Library source not found")
|
||||||
|
|
||||||
if lib is not None:
|
if lib is not None:
|
||||||
lib_books = None
|
lib_books = None
|
||||||
if lib.Playlists is not None:
|
if lib.Playlists is not None:
|
||||||
for pl in lib.Playlists:
|
for pl in lib.Playlists:
|
||||||
if pl.Kind == self.PlaylistKind.index('User') and \
|
if pl.Kind == self.PlaylistKind.index('User') and \
|
||||||
pl.SpecialKind == self.PlaylistSpecialKind.index('Books'):
|
pl.SpecialKind == self.PlaylistSpecialKind.index('Books'):
|
||||||
if DEBUG:
|
|
||||||
self.log.info(" Books playlist: '%s'" % (pl.Name))
|
|
||||||
lib_books = pl.Tracks
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.error(" no Library|Books playlist found")
|
self.log.info(" Books playlist: '%s'" % (pl.Name))
|
||||||
|
lib_books = pl.Tracks
|
||||||
|
break
|
||||||
else:
|
else:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.error(" no Library playlists found")
|
self.log.error(" no Library|Books playlist found")
|
||||||
|
else:
|
||||||
|
if DEBUG:
|
||||||
|
self.log.error(" no Library playlists found")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for book in lib_books:
|
for book in lib_books:
|
||||||
# This may need additional entries for international iTunes users
|
# This may need additional entries for international iTunes users
|
||||||
if book.KindAsString in ['MPEG audio file']:
|
if book.KindAsString in ['MPEG audio file']:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(" ignoring %-30.30s of type '%s'" % (book.Name, book.KindAsString))
|
self.log.info(" ignoring %-30.30s of type '%s'" % (book.Name, book.KindAsString))
|
||||||
else:
|
else:
|
||||||
# Remove calibre orphans
|
path = self.path_template % (book.Name, book.Artist)
|
||||||
if book.Description.startswith(self.description_prefix):
|
|
||||||
if not book.Location:
|
|
||||||
if DEBUG:
|
|
||||||
self.log.info(" found calibre orphan '%s' in Library|Books" % book.Name)
|
|
||||||
#book.Delete()
|
|
||||||
#continue
|
|
||||||
|
|
||||||
path = self.path_template % (book.Name, book.Artist)
|
# Collect calibre orphans
|
||||||
library_books[path] = book
|
if book.Description.startswith(self.description_prefix):
|
||||||
if DEBUG:
|
if not book.Location:
|
||||||
self.log.info(" adding %-30.30s [%s]" % (book.Name, book.KindAsString))
|
library_orphans[path] = book
|
||||||
except:
|
if DEBUG:
|
||||||
if DEBUG:
|
self.log.info(" found calibre orphan '%s' in Library|Books" % book.Name)
|
||||||
self.log.info(" no books in library")
|
|
||||||
finally:
|
|
||||||
pythoncom.CoUninitialize()
|
|
||||||
|
|
||||||
|
library_books[path] = book
|
||||||
|
if DEBUG:
|
||||||
|
self.log.info(" adding %-30.30s [%s]" % (book.Name, book.KindAsString))
|
||||||
|
except:
|
||||||
|
if DEBUG:
|
||||||
|
self.log.info(" no books in library")
|
||||||
|
# finally:
|
||||||
|
# pythoncom.CoUninitialize()
|
||||||
|
self.library_orphans = library_orphans
|
||||||
return library_books
|
return library_books
|
||||||
|
|
||||||
def _get_purchased_book_ids(self):
|
def _get_purchased_book_ids(self):
|
||||||
@ -1904,6 +1905,45 @@ class ITUNES(DevicePlugin):
|
|||||||
self.version[0],self.version[1],self.version[2]))
|
self.version[0],self.version[1],self.version[2]))
|
||||||
self.log.info(" iTunes_media: %s" % self.iTunes_media)
|
self.log.info(" iTunes_media: %s" % self.iTunes_media)
|
||||||
|
|
||||||
|
def _purge_orphans(self,cached_books):
|
||||||
|
'''
|
||||||
|
Scan self.library_orphans for any paths not on device
|
||||||
|
Remove any true orphans from iTunes
|
||||||
|
This occurs when recipes are uploaded in a previous session
|
||||||
|
and the book has since been deleted on the device
|
||||||
|
'''
|
||||||
|
if DEBUG:
|
||||||
|
self.log.info(" ITUNES._purge_orphans")
|
||||||
|
#self.log.info(" cached_books:\n %s" % "\n ".join(cached_books.keys()))
|
||||||
|
|
||||||
|
orphan_paths = {}
|
||||||
|
|
||||||
|
if isosx:
|
||||||
|
for orphan in self.library_orphans:
|
||||||
|
path = self.path_template % (self.library_orphans[orphan].name(),
|
||||||
|
self.library_orphans[orphan].artist())
|
||||||
|
orphan_paths[path] = self.library_orphans[orphan]
|
||||||
|
|
||||||
|
# Scan orphan_paths for paths not found in cached_books
|
||||||
|
for orphan in orphan_paths.keys():
|
||||||
|
if orphan not in cached_books:
|
||||||
|
if DEBUG:
|
||||||
|
self.log.info(" '%s' not found on device, removing from iTunes" % orphan)
|
||||||
|
self.iTunes.delete(orphan_paths[orphan])
|
||||||
|
|
||||||
|
elif iswindows:
|
||||||
|
for orphan in self.library_orphans:
|
||||||
|
path = self.path_template % (self.library_orphans[orphan].Name,
|
||||||
|
self.library_orphans[orphan].Artist)
|
||||||
|
orphan_paths[path] = self.library_orphans[orphan]
|
||||||
|
|
||||||
|
# Scan orphan_paths for paths not found in cached_books
|
||||||
|
for orphan in orphan_paths.keys():
|
||||||
|
if orphan not in cached_books:
|
||||||
|
if DEBUG:
|
||||||
|
self.log.info(" '%s' not found on device, removing from iTunes" % orphan)
|
||||||
|
orphan_paths[orphan].Delete()
|
||||||
|
|
||||||
def _remove_existing_copies(self,path,file,metadata):
|
def _remove_existing_copies(self,path,file,metadata):
|
||||||
'''
|
'''
|
||||||
'''
|
'''
|
||||||
@ -1945,7 +1985,7 @@ class ITUNES(DevicePlugin):
|
|||||||
if isosx:
|
if isosx:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(" deleting %s" % cached_book['dev_book'])
|
self.log.info(" deleting %s" % cached_book['dev_book'])
|
||||||
result = cached_book['dev_book'].delete()
|
cached_book['dev_book'].delete()
|
||||||
|
|
||||||
elif iswindows:
|
elif iswindows:
|
||||||
dev_pl = self._get_device_books_playlist()
|
dev_pl = self._get_device_books_playlist()
|
||||||
@ -1957,7 +1997,7 @@ class ITUNES(DevicePlugin):
|
|||||||
if hit.Name == cached_book['title']:
|
if hit.Name == cached_book['title']:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(" deleting '%s' by %s" % (hit.Name, hit.Artist))
|
self.log.info(" deleting '%s' by %s" % (hit.Name, hit.Artist))
|
||||||
results = hit.Delete()
|
hit.Delete()
|
||||||
break
|
break
|
||||||
|
|
||||||
def _remove_from_iTunes(self, cached_book):
|
def _remove_from_iTunes(self, cached_book):
|
||||||
|
@ -36,4 +36,29 @@ class ESLICK(USBMS):
|
|||||||
|
|
||||||
SUPPORTS_SUB_DIRS = True
|
SUPPORTS_SUB_DIRS = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def can_handle(cls, dev, debug=False):
|
||||||
|
return (dev[3], dev[4]) != ('philips', 'Philips d')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class EBK52(ESLICK):
|
||||||
|
|
||||||
|
name = 'EBK-52 Device Interface'
|
||||||
|
gui_name = 'Sigmatek EBK'
|
||||||
|
description = _('Communicate with the Sigmatek eBook reader.')
|
||||||
|
|
||||||
|
FORMATS = ['epub', 'fb2', 'pdf', 'txt']
|
||||||
|
|
||||||
|
VENDOR_NAME = ''
|
||||||
|
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = 'EBOOK_READER'
|
||||||
|
|
||||||
|
MAIN_MEMORY_VOLUME_LABEL = 'Sigmatek Main Memory'
|
||||||
|
STORAGE_CARD_VOLUME_LABEL = 'Sigmatek Storage Card'
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def can_handle(cls, dev, debug=False):
|
||||||
|
return (dev[3], dev[4]) == ('philips', 'Philips d')
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ from uuid import uuid4
|
|||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
|
|
||||||
from calibre import prints, guess_type, iswindows
|
from calibre import prints, guess_type
|
||||||
from calibre.devices.errors import DeviceError
|
from calibre.devices.errors import DeviceError
|
||||||
from calibre.devices.usbms.driver import debug_print
|
from calibre.devices.usbms.driver import debug_print
|
||||||
from calibre.constants import DEBUG
|
from calibre.constants import DEBUG
|
||||||
@ -47,7 +47,7 @@ def strptime(src):
|
|||||||
src[2] = str(MONTH_MAP[src[2]])
|
src[2] = str(MONTH_MAP[src[2]])
|
||||||
return time.strptime(' '.join(src), '%w, %d %m %Y %H:%M:%S %Z')
|
return time.strptime(' '.join(src), '%w, %d %m %Y %H:%M:%S %Z')
|
||||||
|
|
||||||
def strftime(epoch, zone=time.gmtime):
|
def strftime(epoch, zone=time.localtime):
|
||||||
src = time.strftime("%w, %d %m %Y %H:%M:%S GMT", zone(epoch)).split()
|
src = time.strftime("%w, %d %m %Y %H:%M:%S GMT", zone(epoch)).split()
|
||||||
src[0] = INVERSE_DAY_MAP[int(src[0][:-1])]+','
|
src[0] = INVERSE_DAY_MAP[int(src[0][:-1])]+','
|
||||||
src[2] = INVERSE_MONTH_MAP[int(src[2])]
|
src[2] = INVERSE_MONTH_MAP[int(src[2])]
|
||||||
@ -424,9 +424,6 @@ class XMLCache(object):
|
|||||||
|
|
||||||
def update_text_record(self, record, book, path, bl_index):
|
def update_text_record(self, record, book, path, bl_index):
|
||||||
timestamp = os.path.getmtime(path)
|
timestamp = os.path.getmtime(path)
|
||||||
# Correct for MS DST time 'adjustment'
|
|
||||||
if iswindows and time.daylight:
|
|
||||||
timestamp -= time.altzone - time.timezone
|
|
||||||
date = strftime(timestamp)
|
date = strftime(timestamp)
|
||||||
if date != record.get('date', None):
|
if date != record.get('date', None):
|
||||||
record.set('date', date)
|
record.set('date', date)
|
||||||
|
@ -687,7 +687,7 @@ class DeviceMixin(object):
|
|||||||
self.emailer.send_mails(jobnames,
|
self.emailer.send_mails(jobnames,
|
||||||
Dispatcher(partial(self.emails_sent, remove=remove)),
|
Dispatcher(partial(self.emails_sent, remove=remove)),
|
||||||
attachments, to_s, subjects, texts, attachment_names)
|
attachments, to_s, subjects, texts, attachment_names)
|
||||||
self.status_bar.showMessage(_('Sending email to')+' '+to, 3000)
|
self.status_bar.show_message(_('Sending email to')+' '+to, 3000)
|
||||||
|
|
||||||
auto = []
|
auto = []
|
||||||
if _auto_ids != []:
|
if _auto_ids != []:
|
||||||
@ -748,7 +748,7 @@ class DeviceMixin(object):
|
|||||||
'%s'%errors, show=True
|
'%s'%errors, show=True
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.status_bar.showMessage(_('Sent by email:') + ', '.join(good),
|
self.status_bar.show_message(_('Sent by email:') + ', '.join(good),
|
||||||
5000)
|
5000)
|
||||||
|
|
||||||
def cover_to_thumbnail(self, data):
|
def cover_to_thumbnail(self, data):
|
||||||
@ -787,7 +787,7 @@ class DeviceMixin(object):
|
|||||||
attachments, to_s, subjects, texts, attachment_names)
|
attachments, to_s, subjects, texts, attachment_names)
|
||||||
sent_mails.append(to_s[0])
|
sent_mails.append(to_s[0])
|
||||||
if sent_mails:
|
if sent_mails:
|
||||||
self.status_bar.showMessage(_('Sent news to')+' '+\
|
self.status_bar.show_message(_('Sent news to')+' '+\
|
||||||
', '.join(sent_mails), 3000)
|
', '.join(sent_mails), 3000)
|
||||||
|
|
||||||
def sync_catalogs(self, send_ids=None, do_auto_convert=True):
|
def sync_catalogs(self, send_ids=None, do_auto_convert=True):
|
||||||
@ -846,7 +846,7 @@ class DeviceMixin(object):
|
|||||||
self.upload_books(files, names, metadata,
|
self.upload_books(files, names, metadata,
|
||||||
on_card=on_card,
|
on_card=on_card,
|
||||||
memory=[files, remove])
|
memory=[files, remove])
|
||||||
self.status_bar.showMessage(_('Sending catalogs to device.'), 5000)
|
self.status_bar.show_message(_('Sending catalogs to device.'), 5000)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -909,7 +909,7 @@ class DeviceMixin(object):
|
|||||||
self.upload_books(files, names, metadata,
|
self.upload_books(files, names, metadata,
|
||||||
on_card=on_card,
|
on_card=on_card,
|
||||||
memory=[files, remove])
|
memory=[files, remove])
|
||||||
self.status_bar.showMessage(_('Sending news to device.'), 5000)
|
self.status_bar.show_message(_('Sending news to device.'), 5000)
|
||||||
|
|
||||||
|
|
||||||
def sync_to_device(self, on_card, delete_from_library,
|
def sync_to_device(self, on_card, delete_from_library,
|
||||||
@ -963,7 +963,7 @@ class DeviceMixin(object):
|
|||||||
names.append('%s_%d%s'%(prefix, id, os.path.splitext(f)[1]))
|
names.append('%s_%d%s'%(prefix, id, os.path.splitext(f)[1]))
|
||||||
remove = remove_ids if delete_from_library else []
|
remove = remove_ids if delete_from_library else []
|
||||||
self.upload_books(gf, names, good, on_card, memory=(_files, remove))
|
self.upload_books(gf, names, good, on_card, memory=(_files, remove))
|
||||||
self.status_bar.showMessage(_('Sending books to device.'), 5000)
|
self.status_bar.show_message(_('Sending books to device.'), 5000)
|
||||||
|
|
||||||
auto = []
|
auto = []
|
||||||
if _auto_ids != []:
|
if _auto_ids != []:
|
||||||
|
@ -49,12 +49,12 @@ class BookInfo(QDialog, Ui_BookInfo):
|
|||||||
|
|
||||||
def open_book_path(self, path):
|
def open_book_path(self, path):
|
||||||
if os.sep in unicode(path):
|
if os.sep in unicode(path):
|
||||||
QDesktopServices.openUrl(QUrl('file:'+path))
|
QDesktopServices.openUrl(QUrl.fromLocalFile(path))
|
||||||
else:
|
else:
|
||||||
format = unicode(path)
|
format = unicode(path)
|
||||||
path = self.view.model().db.format_abspath(self.current_row, format)
|
path = self.view.model().db.format_abspath(self.current_row, format)
|
||||||
if path is not None:
|
if path is not None:
|
||||||
QDesktopServices.openUrl(QUrl('file:'+path))
|
QDesktopServices.openUrl(QUrl.fromLocalFile(path))
|
||||||
|
|
||||||
|
|
||||||
def next(self):
|
def next(self):
|
||||||
|
@ -132,6 +132,7 @@ class ToolbarMixin(object): # {{{
|
|||||||
|
|
||||||
self.action_open_containing_folder.setShortcut(Qt.Key_O)
|
self.action_open_containing_folder.setShortcut(Qt.Key_O)
|
||||||
self.addAction(self.action_open_containing_folder)
|
self.addAction(self.action_open_containing_folder)
|
||||||
|
self.action_open_containing_folder.triggered.connect(self.view_folder)
|
||||||
self.action_sync.setShortcut(Qt.Key_D)
|
self.action_sync.setShortcut(Qt.Key_D)
|
||||||
self.action_sync.setEnabled(True)
|
self.action_sync.setEnabled(True)
|
||||||
self.create_device_menu()
|
self.create_device_menu()
|
||||||
@ -231,7 +232,7 @@ class LibraryViewMixin(object): # {{{
|
|||||||
('connect_to_search_box', (self.search,
|
('connect_to_search_box', (self.search,
|
||||||
self.search_done)),
|
self.search_done)),
|
||||||
('connect_to_book_display',
|
('connect_to_book_display',
|
||||||
(self.status_bar.book_info.show_data,)),
|
(self.book_details.show_data,)),
|
||||||
]:
|
]:
|
||||||
for view in (self.library_view, self.memory_view, self.card_a_view, self.card_b_view):
|
for view in (self.library_view, self.memory_view, self.card_a_view, self.card_b_view):
|
||||||
getattr(view, func)(*args)
|
getattr(view, func)(*args)
|
||||||
@ -360,7 +361,7 @@ class LayoutMixin(object): # {{{
|
|||||||
|
|
||||||
if config['gui_layout'] == 'narrow':
|
if config['gui_layout'] == 'narrow':
|
||||||
from calibre.gui2.status import StatusBar
|
from calibre.gui2.status import StatusBar
|
||||||
self.status_bar = StatusBar(self)
|
self.status_bar = self.book_details = StatusBar(self)
|
||||||
self.stack = Stack(self)
|
self.stack = Stack(self)
|
||||||
self.bd_splitter = Splitter('book_details_splitter',
|
self.bd_splitter = Splitter('book_details_splitter',
|
||||||
_('Book Details'), I('book.svg'),
|
_('Book Details'), I('book.svg'),
|
||||||
|
@ -292,7 +292,8 @@ class BooksView(QTableView): # {{{
|
|||||||
old_state['column_positions'][name] = i
|
old_state['column_positions'][name] = i
|
||||||
if name != 'ondevice':
|
if name != 'ondevice':
|
||||||
old_state['column_sizes'][name] = \
|
old_state['column_sizes'][name] = \
|
||||||
max(self.sizeHintForColumn(i), h.sectionSizeHint(i))
|
min(350, max(self.sizeHintForColumn(i),
|
||||||
|
h.sectionSizeHint(i)))
|
||||||
if name == 'timestamp':
|
if name == 'timestamp':
|
||||||
old_state['column_sizes'][name] += 12
|
old_state['column_sizes'][name] += 12
|
||||||
return old_state
|
return old_state
|
||||||
|
@ -53,7 +53,24 @@ def init_qt(args):
|
|||||||
app.setWindowIcon(QIcon(I('library.png')))
|
app.setWindowIcon(QIcon(I('library.png')))
|
||||||
return app, opts, args, actions
|
return app, opts, args, actions
|
||||||
|
|
||||||
def get_library_path():
|
|
||||||
|
def get_default_library_path():
|
||||||
|
fname = _('Calibre Library')
|
||||||
|
if isinstance(fname, unicode):
|
||||||
|
try:
|
||||||
|
fname = fname.encode(filesystem_encoding)
|
||||||
|
except:
|
||||||
|
fname = 'Calibre Library'
|
||||||
|
x = os.path.expanduser('~'+os.sep+fname)
|
||||||
|
if not os.path.exists(x):
|
||||||
|
try:
|
||||||
|
os.makedirs(x)
|
||||||
|
except:
|
||||||
|
x = os.path.expanduser('~')
|
||||||
|
return x
|
||||||
|
|
||||||
|
|
||||||
|
def get_library_path(parent=None):
|
||||||
library_path = prefs['library_path']
|
library_path = prefs['library_path']
|
||||||
if library_path is None: # Need to migrate to new database layout
|
if library_path is None: # Need to migrate to new database layout
|
||||||
base = os.path.expanduser('~')
|
base = os.path.expanduser('~')
|
||||||
@ -73,10 +90,12 @@ def get_library_path():
|
|||||||
try:
|
try:
|
||||||
os.makedirs(library_path)
|
os.makedirs(library_path)
|
||||||
except:
|
except:
|
||||||
error_dialog(None, _('Failed to create library'),
|
error_dialog(parent, _('Failed to create library'),
|
||||||
_('Failed to create calibre library at: %r. Aborting.')%library_path,
|
_('Failed to create calibre library at: %r.')%library_path,
|
||||||
det_msg=traceback.format_exc(), show=True)
|
det_msg=traceback.format_exc(), show=True)
|
||||||
library_path = None
|
library_path = choose_dir(parent, 'choose calibre library',
|
||||||
|
_('Choose a location for your new calibre e-book library'),
|
||||||
|
default_dir=get_default_library_path())
|
||||||
return library_path
|
return library_path
|
||||||
|
|
||||||
class DBRepair(QThread):
|
class DBRepair(QThread):
|
||||||
@ -159,22 +178,9 @@ class GuiRunner(QObject):
|
|||||||
'a new empty library.'),
|
'a new empty library.'),
|
||||||
det_msg=tb, show=True)
|
det_msg=tb, show=True)
|
||||||
if db is None:
|
if db is None:
|
||||||
fname = _('Calibre Library')
|
|
||||||
if isinstance(fname, unicode):
|
|
||||||
try:
|
|
||||||
fname = fname.encode(filesystem_encoding)
|
|
||||||
except:
|
|
||||||
fname = 'Calibre Library'
|
|
||||||
x = os.path.expanduser('~'+os.sep+fname)
|
|
||||||
if not os.path.exists(x):
|
|
||||||
try:
|
|
||||||
os.makedirs(x)
|
|
||||||
except:
|
|
||||||
x = os.path.expanduser('~')
|
|
||||||
candidate = choose_dir(self.splash_screen, 'choose calibre library',
|
candidate = choose_dir(self.splash_screen, 'choose calibre library',
|
||||||
_('Choose a location for your new calibre e-book library'),
|
_('Choose a location for your new calibre e-book library'),
|
||||||
default_dir=x)
|
default_dir=get_default_library_path())
|
||||||
|
|
||||||
if not candidate:
|
if not candidate:
|
||||||
self.initialization_failed()
|
self.initialization_failed()
|
||||||
|
|
||||||
@ -236,8 +242,8 @@ class GuiRunner(QObject):
|
|||||||
if gprefs.get('show_splash_screen', True):
|
if gprefs.get('show_splash_screen', True):
|
||||||
self.show_splash_screen()
|
self.show_splash_screen()
|
||||||
|
|
||||||
self.library_path = get_library_path()
|
self.library_path = get_library_path(parent=self.splash_screen)
|
||||||
if self.library_path is None:
|
if not self.library_path:
|
||||||
self.initialization_failed()
|
self.initialization_failed()
|
||||||
|
|
||||||
self.initialize_db()
|
self.initialize_db()
|
||||||
|
@ -7,8 +7,8 @@ __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
|||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
from PyQt4.Qt import QComboBox, Qt, QLineEdit, QStringList, pyqtSlot, \
|
from PyQt4.Qt import QComboBox, Qt, QLineEdit, QStringList, pyqtSlot, \
|
||||||
pyqtSignal, SIGNAL, QObject, QDialog
|
pyqtSignal, SIGNAL, QObject, QDialog, QCompleter, \
|
||||||
from PyQt4.QtGui import QCompleter
|
QAction, QKeySequence
|
||||||
|
|
||||||
from calibre.gui2 import config
|
from calibre.gui2 import config
|
||||||
from calibre.gui2.dialogs.confirm_delete import confirm
|
from calibre.gui2.dialogs.confirm_delete import confirm
|
||||||
@ -348,8 +348,14 @@ class SearchBoxMixin(object):
|
|||||||
self.do_advanced_search)
|
self.do_advanced_search)
|
||||||
|
|
||||||
self.search.clear()
|
self.search.clear()
|
||||||
self.search.setFocus(Qt.OtherFocusReason)
|
|
||||||
self.search.setMaximumWidth(self.width()-150)
|
self.search.setMaximumWidth(self.width()-150)
|
||||||
|
self.action_focus_search = QAction(self)
|
||||||
|
shortcuts = QKeySequence.keyBindings(QKeySequence.Find)
|
||||||
|
shortcuts = list(shortcuts) + [QKeySequence('/')]
|
||||||
|
self.action_focus_search.setShortcuts(shortcuts)
|
||||||
|
self.action_focus_search.triggered.connect(lambda x:
|
||||||
|
self.search.setFocus(Qt.OtherFocusReason))
|
||||||
|
self.addAction(self.action_focus_search)
|
||||||
|
|
||||||
def search_box_cleared(self):
|
def search_box_cleared(self):
|
||||||
self.tags_view.clear()
|
self.tags_view.clear()
|
||||||
|
@ -61,7 +61,7 @@ class BookInfoDisplay(QWidget):
|
|||||||
pixmap = self.pixmap()
|
pixmap = self.pixmap()
|
||||||
pwidth, pheight = pixmap.width(), pixmap.height()
|
pwidth, pheight = pixmap.width(), pixmap.height()
|
||||||
width, height = fit_image(pwidth, pheight,
|
width, height = fit_image(pwidth, pheight,
|
||||||
pwidth, self.statusbar_height-12)[1:]
|
pwidth, self.statusbar_height-20)[1:]
|
||||||
self.setMaximumHeight(height)
|
self.setMaximumHeight(height)
|
||||||
try:
|
try:
|
||||||
aspect_ratio = pwidth/float(pheight)
|
aspect_ratio = pwidth/float(pheight)
|
||||||
@ -162,17 +162,48 @@ class BookInfoDisplay(QWidget):
|
|||||||
self.updateGeometry()
|
self.updateGeometry()
|
||||||
self.setVisible(True)
|
self.setVisible(True)
|
||||||
|
|
||||||
|
class StatusBarInterface(object):
|
||||||
class StatusBar(QStatusBar):
|
|
||||||
|
|
||||||
resized = pyqtSignal(object)
|
|
||||||
files_dropped = pyqtSignal(object, object)
|
|
||||||
show_book_info = pyqtSignal()
|
|
||||||
|
|
||||||
def initialize(self, systray=None):
|
def initialize(self, systray=None):
|
||||||
self.systray = systray
|
self.systray = systray
|
||||||
self.notifier = get_notifier(systray)
|
self.notifier = get_notifier(systray)
|
||||||
self.book_info = BookInfoDisplay(self.clearMessage)
|
|
||||||
|
def show_message(self, msg, timeout=0):
|
||||||
|
QStatusBar.showMessage(self, msg, timeout)
|
||||||
|
if self.notifier is not None and not config['disable_tray_notification']:
|
||||||
|
if isosx and isinstance(msg, unicode):
|
||||||
|
try:
|
||||||
|
msg = msg.encode(preferred_encoding)
|
||||||
|
except UnicodeEncodeError:
|
||||||
|
msg = msg.encode('utf-8')
|
||||||
|
self.notifier(msg)
|
||||||
|
|
||||||
|
def clear_message(self):
|
||||||
|
QStatusBar.clearMessage(self)
|
||||||
|
|
||||||
|
class BookDetailsInterface(object):
|
||||||
|
|
||||||
|
# These signals must be defined in the class implementing this interface
|
||||||
|
files_dropped = None
|
||||||
|
show_book_info = None
|
||||||
|
|
||||||
|
def reset_info(self):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def show_data(self, data):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
class StatusBar(QStatusBar, StatusBarInterface, BookDetailsInterface):
|
||||||
|
|
||||||
|
files_dropped = pyqtSignal(object, object)
|
||||||
|
show_book_info = pyqtSignal()
|
||||||
|
|
||||||
|
|
||||||
|
resized = pyqtSignal(object)
|
||||||
|
|
||||||
|
def initialize(self, systray=None):
|
||||||
|
StatusBarInterface.initialize(self, systray=systray)
|
||||||
|
self.book_info = BookInfoDisplay(self.clear_message)
|
||||||
self.book_info.setAcceptDrops(True)
|
self.book_info.setAcceptDrops(True)
|
||||||
self.scroll_area = QScrollArea()
|
self.scroll_area = QScrollArea()
|
||||||
self.scroll_area.setWidget(self.book_info)
|
self.scroll_area.setWidget(self.book_info)
|
||||||
@ -192,15 +223,6 @@ class StatusBar(QStatusBar):
|
|||||||
def reset_info(self):
|
def reset_info(self):
|
||||||
self.book_info.show_data({})
|
self.book_info.show_data({})
|
||||||
|
|
||||||
def showMessage(self, msg, timeout=0):
|
def show_data(self, data):
|
||||||
ret = QStatusBar.showMessage(self, msg, timeout)
|
self.book_info.show_data(data)
|
||||||
if self.notifier is not None and not config['disable_tray_notification']:
|
|
||||||
if isosx and isinstance(msg, unicode):
|
|
||||||
try:
|
|
||||||
msg = msg.encode(preferred_encoding)
|
|
||||||
except UnicodeEncodeError:
|
|
||||||
msg = msg.encode('utf-8')
|
|
||||||
self.notifier(msg)
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -223,7 +223,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin,
|
|||||||
|
|
||||||
####################### Setup device detection ########################
|
####################### Setup device detection ########################
|
||||||
self.device_manager = DeviceManager(Dispatcher(self.device_detected),
|
self.device_manager = DeviceManager(Dispatcher(self.device_detected),
|
||||||
self.job_manager, Dispatcher(self.status_bar.showMessage))
|
self.job_manager, Dispatcher(self.status_bar.show_message))
|
||||||
self.device_manager.start()
|
self.device_manager.start()
|
||||||
|
|
||||||
|
|
||||||
@ -256,8 +256,8 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin,
|
|||||||
|
|
||||||
####################### Status Bar #####################
|
####################### Status Bar #####################
|
||||||
self.status_bar.initialize(self.system_tray_icon)
|
self.status_bar.initialize(self.system_tray_icon)
|
||||||
self.status_bar.show_book_info.connect(self.show_book_info)
|
self.book_details.show_book_info.connect(self.show_book_info)
|
||||||
self.status_bar.files_dropped.connect(self.files_dropped_on_book)
|
self.book_details.files_dropped.connect(self.files_dropped_on_book)
|
||||||
|
|
||||||
####################### Setup Toolbar #####################
|
####################### Setup Toolbar #####################
|
||||||
ToolbarMixin.__init__(self)
|
ToolbarMixin.__init__(self)
|
||||||
@ -482,7 +482,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin,
|
|||||||
Dispatcher(self.info_read))
|
Dispatcher(self.info_read))
|
||||||
self.set_default_thumbnail(\
|
self.set_default_thumbnail(\
|
||||||
self.device_manager.device.THUMBNAIL_HEIGHT)
|
self.device_manager.device.THUMBNAIL_HEIGHT)
|
||||||
self.status_bar.showMessage(_('Device: ')+\
|
self.status_bar.show_message(_('Device: ')+\
|
||||||
self.device_manager.device.__class__.get_gui_name()+\
|
self.device_manager.device.__class__.get_gui_name()+\
|
||||||
_(' detected.'), 3000)
|
_(' detected.'), 3000)
|
||||||
self.device_connected = 'device' if not is_folder_device else 'folder'
|
self.device_connected = 'device' if not is_folder_device else 'folder'
|
||||||
@ -503,7 +503,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin,
|
|||||||
dict(version=self.latest_version, device=' '))
|
dict(version=self.latest_version, device=' '))
|
||||||
self.device_info = ' '
|
self.device_info = ' '
|
||||||
if self.current_view() != self.library_view:
|
if self.current_view() != self.library_view:
|
||||||
self.status_bar.reset_info()
|
self.book_details.reset_info()
|
||||||
self.location_view.setCurrentIndex(self.location_view.model().index(0))
|
self.location_view.setCurrentIndex(self.location_view.model().index(0))
|
||||||
self.eject_action.setEnabled(False)
|
self.eject_action.setEnabled(False)
|
||||||
self.refresh_ondevice_info (device_connected = False)
|
self.refresh_ondevice_info (device_connected = False)
|
||||||
@ -861,7 +861,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin,
|
|||||||
to_device = allow_device and self.stack.currentIndex() != 0
|
to_device = allow_device and self.stack.currentIndex() != 0
|
||||||
self._add_books(books, to_device)
|
self._add_books(books, to_device)
|
||||||
if to_device:
|
if to_device:
|
||||||
self.status_bar.showMessage(\
|
self.status_bar.show_message(\
|
||||||
_('Uploading books to device.'), 2000)
|
_('Uploading books to device.'), 2000)
|
||||||
|
|
||||||
|
|
||||||
@ -912,7 +912,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin,
|
|||||||
self.upload_books(paths,
|
self.upload_books(paths,
|
||||||
list(map(ascii_filename, names)),
|
list(map(ascii_filename, names)),
|
||||||
infos, on_card=on_card)
|
infos, on_card=on_card)
|
||||||
self.status_bar.showMessage(
|
self.status_bar.show_message(
|
||||||
_('Uploading books to device.'), 2000)
|
_('Uploading books to device.'), 2000)
|
||||||
if getattr(self._adder, 'number_of_books_added', 0) > 0:
|
if getattr(self._adder, 'number_of_books_added', 0) > 0:
|
||||||
self.library_view.model().books_added(self._adder.number_of_books_added)
|
self.library_view.model().books_added(self._adder.number_of_books_added)
|
||||||
@ -1058,7 +1058,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin,
|
|||||||
job = self.remove_paths(paths)
|
job = self.remove_paths(paths)
|
||||||
self.delete_memory[job] = (paths, view.model())
|
self.delete_memory[job] = (paths, view.model())
|
||||||
view.model().mark_for_deletion(job, rows)
|
view.model().mark_for_deletion(job, rows)
|
||||||
self.status_bar.showMessage(_('Deleting books from device.'), 1000)
|
self.status_bar.show_message(_('Deleting books from device.'), 1000)
|
||||||
|
|
||||||
def remove_paths(self, paths):
|
def remove_paths(self, paths):
|
||||||
return self.device_manager.delete_books(\
|
return self.device_manager.delete_books(\
|
||||||
@ -1424,7 +1424,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin,
|
|||||||
job.catalog_file_path = out
|
job.catalog_file_path = out
|
||||||
job.fmt = fmt
|
job.fmt = fmt
|
||||||
job.catalog_sync, job.catalog_title = sync, title
|
job.catalog_sync, job.catalog_title = sync, title
|
||||||
self.status_bar.showMessage(_('Generating %s catalog...')%fmt)
|
self.status_bar.show_message(_('Generating %s catalog...')%fmt)
|
||||||
|
|
||||||
def catalog_generated(self, job):
|
def catalog_generated(self, job):
|
||||||
if job.result:
|
if job.result:
|
||||||
@ -1440,7 +1440,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin,
|
|||||||
sync = dynamic.get('catalogs_to_be_synced', set([]))
|
sync = dynamic.get('catalogs_to_be_synced', set([]))
|
||||||
sync.add(id)
|
sync.add(id)
|
||||||
dynamic.set('catalogs_to_be_synced', sync)
|
dynamic.set('catalogs_to_be_synced', sync)
|
||||||
self.status_bar.showMessage(_('Catalog generated.'), 3000)
|
self.status_bar.show_message(_('Catalog generated.'), 3000)
|
||||||
self.sync_catalogs()
|
self.sync_catalogs()
|
||||||
if job.fmt not in ['EPUB','MOBI']:
|
if job.fmt not in ['EPUB','MOBI']:
|
||||||
export_dir = choose_dir(self, _('Export Catalog Directory'),
|
export_dir = choose_dir(self, _('Export Catalog Directory'),
|
||||||
@ -1458,7 +1458,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin,
|
|||||||
Dispatcher(self.scheduled_recipe_fetched), func, args=args,
|
Dispatcher(self.scheduled_recipe_fetched), func, args=args,
|
||||||
description=desc)
|
description=desc)
|
||||||
self.conversion_jobs[job] = (temp_files, fmt, arg)
|
self.conversion_jobs[job] = (temp_files, fmt, arg)
|
||||||
self.status_bar.showMessage(_('Fetching news from ')+arg['title'], 2000)
|
self.status_bar.show_message(_('Fetching news from ')+arg['title'], 2000)
|
||||||
|
|
||||||
def scheduled_recipe_fetched(self, job):
|
def scheduled_recipe_fetched(self, job):
|
||||||
temp_files, fmt, arg = self.conversion_jobs.pop(job)
|
temp_files, fmt, arg = self.conversion_jobs.pop(job)
|
||||||
@ -1472,7 +1472,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin,
|
|||||||
sync.add(id)
|
sync.add(id)
|
||||||
dynamic.set('news_to_be_synced', sync)
|
dynamic.set('news_to_be_synced', sync)
|
||||||
self.scheduler.recipe_downloaded(arg)
|
self.scheduler.recipe_downloaded(arg)
|
||||||
self.status_bar.showMessage(arg['title'] + _(' fetched.'), 3000)
|
self.status_bar.show_message(arg['title'] + _(' fetched.'), 3000)
|
||||||
self.email_news(id)
|
self.email_news(id)
|
||||||
self.sync_news()
|
self.sync_news()
|
||||||
|
|
||||||
@ -1552,7 +1552,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin,
|
|||||||
num = len(jobs)
|
num = len(jobs)
|
||||||
|
|
||||||
if num > 0:
|
if num > 0:
|
||||||
self.status_bar.showMessage(_('Starting conversion of %d book(s)') %
|
self.status_bar.show_message(_('Starting conversion of %d book(s)') %
|
||||||
num, 2000)
|
num, 2000)
|
||||||
|
|
||||||
def queue_convert_jobs(self, jobs, changed, bad, rows, previous,
|
def queue_convert_jobs(self, jobs, changed, bad, rows, previous,
|
||||||
@ -1599,7 +1599,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin,
|
|||||||
self.library_view.model().db.add_format(book_id, \
|
self.library_view.model().db.add_format(book_id, \
|
||||||
fmt, data, index_is_id=True)
|
fmt, data, index_is_id=True)
|
||||||
data.close()
|
data.close()
|
||||||
self.status_bar.showMessage(job.description + \
|
self.status_bar.show_message(job.description + \
|
||||||
(' completed'), 2000)
|
(' completed'), 2000)
|
||||||
finally:
|
finally:
|
||||||
for f in temp_files:
|
for f in temp_files:
|
||||||
@ -1802,9 +1802,9 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin,
|
|||||||
self.library_view.set_database(db)
|
self.library_view.set_database(db)
|
||||||
self.tags_view.set_database(db, self.tag_match, self.popularity)
|
self.tags_view.set_database(db, self.tag_match, self.popularity)
|
||||||
self.library_view.model().set_book_on_device_func(self.book_on_device)
|
self.library_view.model().set_book_on_device_func(self.book_on_device)
|
||||||
self.status_bar.clearMessage()
|
self.status_bar.clear_message()
|
||||||
self.search.clear_to_help()
|
self.search.clear_to_help()
|
||||||
self.status_bar.reset_info()
|
self.book_details.reset_info()
|
||||||
self.library_view.model().count_changed()
|
self.library_view.model().count_changed()
|
||||||
prefs['library_path'] = self.library_path
|
prefs['library_path'] = self.library_path
|
||||||
|
|
||||||
@ -1831,7 +1831,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceMixin, ToolbarMixin,
|
|||||||
'''
|
'''
|
||||||
page = 0 if location == 'library' else 1 if location == 'main' else 2 if location == 'carda' else 3
|
page = 0 if location == 'library' else 1 if location == 'main' else 2 if location == 'carda' else 3
|
||||||
self.stack.setCurrentIndex(page)
|
self.stack.setCurrentIndex(page)
|
||||||
self.status_bar.reset_info()
|
self.book_details.reset_info()
|
||||||
for x in ('tb', 'cb'):
|
for x in ('tb', 'cb'):
|
||||||
splitter = getattr(self, x+'_splitter')
|
splitter = getattr(self, x+'_splitter')
|
||||||
splitter.button.setEnabled(location == 'library')
|
splitter.button.setEnabled(location == 'library')
|
||||||
|
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
9513
src/calibre/translations/fo.po
Normal file
9513
src/calibre/translations/fo.po
Normal file
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
@ -31,7 +31,7 @@ class SafeLocalTimeZone(tzlocal):
|
|||||||
def compute_locale_info_for_parse_date():
|
def compute_locale_info_for_parse_date():
|
||||||
try:
|
try:
|
||||||
dt = datetime.strptime('1/5/2000', "%x")
|
dt = datetime.strptime('1/5/2000', "%x")
|
||||||
except ValueError:
|
except:
|
||||||
try:
|
try:
|
||||||
dt = datetime.strptime('1/5/01', '%x')
|
dt = datetime.strptime('1/5/01', '%x')
|
||||||
except:
|
except:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user