mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
KG revisions
This commit is contained in:
commit
4266e94984
@ -1,38 +1,47 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
|
||||||
'''
|
'''
|
||||||
bbc.co.uk
|
news.bbc.co.uk
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
import re
|
||||||
|
from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||||
|
|
||||||
class BBC(BasicNewsRecipe):
|
class BBC(BasicNewsRecipe):
|
||||||
title = u'The BBC'
|
title = 'The BBC'
|
||||||
__author__ = 'Kovid Goyal ans Sujata Raman'
|
__author__ = 'Darko Miletic'
|
||||||
description = 'Global news and current affairs from the British Broadcasting Corporation'
|
description = 'Global news and current affairs from the British Broadcasting Corporation'
|
||||||
language = 'en'
|
oldest_article = 2
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
no_stylesheets = True
|
||||||
|
#delay = 1
|
||||||
|
use_embedded_content = False
|
||||||
|
encoding = 'utf8'
|
||||||
|
publisher = 'BBC'
|
||||||
|
category = 'news, UK, world'
|
||||||
|
language = 'en_GB'
|
||||||
|
publication_type = 'newsportal'
|
||||||
|
extra_css = ' 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} '
|
||||||
|
preprocess_regexps = [(re.compile(r'<!--.*?-->', re.DOTALL), lambda m: '')]
|
||||||
|
|
||||||
no_stylesheets = True
|
conversion_options = {
|
||||||
remove_tags = [dict(name='div', attrs={'class':'footer'}),
|
'comments' : description
|
||||||
{'id' : ['popstory','blq-footer']},
|
,'tags' : category
|
||||||
{'class' : ['arrup','links','relatedbbcsites','arr','promobottombg','bbccom_visibility_hidden', 'sharesb', 'sib606', 'mvtb', 'storyextra', 'sidebar1', 'bbccom_text','promotopbg', 'gppromo','promotopbg','bbccom_display_none']},
|
,'language' : language
|
||||||
]
|
,'publisher' : publisher
|
||||||
|
,'linearize_tables': True
|
||||||
|
}
|
||||||
|
|
||||||
keep_only_tags = [dict(name='div', attrs={'class':'mainwrapper'})]
|
keep_only_tags = [
|
||||||
|
dict(attrs={'id' :['meta-information','story-body']})
|
||||||
extra_css = '''
|
,dict(attrs={'class':['mxb' ,'storybody' ]})
|
||||||
body{font-family:Arial,Helvetica,sans-serif; font-size:small; align:left}
|
]
|
||||||
h1{font-size:large;}
|
remove_tags = [
|
||||||
.sh{font-size:large; font-weight:bold}
|
dict(name=['object','link','table'])
|
||||||
.cap{font-size:xx-small; }
|
,dict(attrs={'class':['caption','caption full-width','story-actions','hidden','sharesb','audioInStoryC']})
|
||||||
.lu{font-size:xx-small; }
|
]
|
||||||
.ds{font-size:xx-small; }
|
remove_tags_after = dict(attrs={'class':'sharesb'})
|
||||||
.mvb{font-size:xx-small;}
|
remove_attributes = ['width','height']
|
||||||
.by1{font-size:x-small; color:#666666}
|
|
||||||
.byd{font-size:x-small;}
|
|
||||||
'''
|
|
||||||
|
|
||||||
feeds = [
|
feeds = [
|
||||||
('News Front Page', 'http://newsrss.bbc.co.uk/rss/newsonline_world_edition/front_page/rss.xml'),
|
('News Front Page', 'http://newsrss.bbc.co.uk/rss/newsonline_world_edition/front_page/rss.xml'),
|
||||||
@ -50,22 +59,3 @@ class BBC(BasicNewsRecipe):
|
|||||||
('Africa', 'http://newsrss.bbc.co.uk/rss/newsonline_world_edition/africa/rss.xml'),
|
('Africa', 'http://newsrss.bbc.co.uk/rss/newsonline_world_edition/africa/rss.xml'),
|
||||||
]
|
]
|
||||||
|
|
||||||
def postprocess_html(self, soup, first):
|
|
||||||
|
|
||||||
for tag in soup.findAll(name= 'img', alt=""):
|
|
||||||
tag.extract()
|
|
||||||
|
|
||||||
for item in soup.findAll(align = "right"):
|
|
||||||
del item['align']
|
|
||||||
|
|
||||||
for tag in soup.findAll(name=['table', 'tr', 'td']):
|
|
||||||
tag.name = 'div'
|
|
||||||
|
|
||||||
return soup
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# def print_version(self, url):
|
|
||||||
# return url.replace('http://', 'http://newsvote.bbc.co.uk/mpapps/pagetools/print/')
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ __copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
|
|||||||
'''
|
'''
|
||||||
news.bbc.co.uk
|
news.bbc.co.uk
|
||||||
'''
|
'''
|
||||||
|
import re
|
||||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||||
|
|
||||||
class BBC(BasicNewsRecipe):
|
class BBC(BasicNewsRecipe):
|
||||||
@ -18,22 +18,28 @@ class BBC(BasicNewsRecipe):
|
|||||||
encoding = 'utf8'
|
encoding = 'utf8'
|
||||||
publisher = 'BBC'
|
publisher = 'BBC'
|
||||||
category = 'news, UK, world'
|
category = 'news, UK, world'
|
||||||
language = 'en'
|
language = 'en_GB'
|
||||||
extra_css = ' body{ font-family: sans-serif; } .headline{font-size: xx-large; font-weight: bold} .ibox{display: block; margin: 20px 50px; padding: 10px; border: 1px solid } '
|
publication_type = 'newsportal'
|
||||||
|
extra_css = ' 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} '
|
||||||
|
preprocess_regexps = [(re.compile(r'<!--.*?-->', re.DOTALL), lambda m: '')]
|
||||||
conversion_options = {
|
conversion_options = {
|
||||||
'comments' : description
|
'comments' : description
|
||||||
,'tags' : category
|
,'tags' : category
|
||||||
,'language' : language
|
,'language' : language
|
||||||
,'publisher' : publisher
|
,'publisher' : publisher
|
||||||
|
,'linearize_tables': True
|
||||||
}
|
}
|
||||||
|
|
||||||
remove_tags_before = dict(name='div',attrs={'class':'headline'})
|
keep_only_tags = [
|
||||||
remove_tags_after = dict(name='div', attrs={'class':'footer'})
|
dict(attrs={'id' :['meta-information','story-body']})
|
||||||
remove_tags = [
|
,dict(attrs={'class':['mxb' ,'storybody' ]})
|
||||||
dict(name=['object','link','script','iframe'])
|
|
||||||
,dict(name='div', attrs={'class':'footer'})
|
|
||||||
]
|
]
|
||||||
|
remove_tags = [
|
||||||
|
dict(name=['object','link','table','img'])
|
||||||
|
,dict(attrs={'class':['caption','caption full-width','story-actions','hidden','sharesb','audioInStoryC']})
|
||||||
|
]
|
||||||
|
remove_tags_after = dict(attrs={'class':'sharesb'})
|
||||||
|
remove_attributes = ['width','height']
|
||||||
|
|
||||||
feeds = [
|
feeds = [
|
||||||
('News Front Page', 'http://newsrss.bbc.co.uk/rss/newsonline_world_edition/front_page/rss.xml'),
|
('News Front Page', 'http://newsrss.bbc.co.uk/rss/newsonline_world_edition/front_page/rss.xml'),
|
||||||
@ -51,10 +57,3 @@ class BBC(BasicNewsRecipe):
|
|||||||
('Africa', 'http://newsrss.bbc.co.uk/rss/newsonline_world_edition/africa/rss.xml'),
|
('Africa', 'http://newsrss.bbc.co.uk/rss/newsonline_world_edition/africa/rss.xml'),
|
||||||
]
|
]
|
||||||
|
|
||||||
def print_version(self, url):
|
|
||||||
emp,sep,rstrip = url.partition('http://')
|
|
||||||
return 'http://newsvote.bbc.co.uk/mpapps/pagetools/print/' + rstrip
|
|
||||||
|
|
||||||
def get_article_url(self, article):
|
|
||||||
return article.get('guid', None)
|
|
||||||
|
|
||||||
|
24
resources/recipes/las_vegas_review.recipe
Normal file
24
resources/recipes/las_vegas_review.recipe
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class AdvancedUserRecipe1274742400(BasicNewsRecipe):
|
||||||
|
|
||||||
|
title = u'Las Vegas Review Journal'
|
||||||
|
__author__ = 'Joel'
|
||||||
|
language = 'en'
|
||||||
|
|
||||||
|
oldest_article = 7
|
||||||
|
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
|
||||||
|
feeds = [
|
||||||
|
(u'News', u'http://www.lvrj.com/news.rss'),
|
||||||
|
(u'Business', u'http://www.lvrj.com/business.rss'),
|
||||||
|
(u'Living', u'http://www.lvrj.com/living.rss'),
|
||||||
|
(u'Opinion', u'http://www.lvrj.com/opinion.rss'),
|
||||||
|
(u'Neon', u'http://www.lvrj.com/neon.rss'),
|
||||||
|
(u'Image', u'http://www.lvrj.com/image.rss'),
|
||||||
|
(u'Home & Garden', u'http://www.lvrj.com/home_and_garden.rss'),
|
||||||
|
(u'Furniture & Design', u'http://www.lvrj.com/furniture_and_design.rss'),
|
||||||
|
(u'Drive', u'http://www.lvrj.com/drive.rss'),
|
||||||
|
(u'Real Estate', u'http://www.lvrj.com/real_estate.rss'),
|
||||||
|
(u'Sports', u'http://www.lvrj.com/sports.rss')]
|
@ -10,13 +10,13 @@ import time
|
|||||||
from calibre import entity_to_unicode
|
from calibre import entity_to_unicode
|
||||||
from calibre.web.feeds.recipes import BasicNewsRecipe
|
from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag, NavigableString, \
|
from calibre.ebooks.BeautifulSoup import BeautifulSoup, Tag, NavigableString, \
|
||||||
Comment, BeautifulStoneSoup
|
Comment, BeautifulStoneSoup
|
||||||
|
|
||||||
class NYTimes(BasicNewsRecipe):
|
class NYTimes(BasicNewsRecipe):
|
||||||
|
|
||||||
title = 'New York Times Top Stories'
|
title = 'New York Times Top Stories'
|
||||||
__author__ = 'GRiker'
|
__author__ = 'GRiker'
|
||||||
language = 'en'
|
language = _('English')
|
||||||
description = 'Top Stories from the New York Times'
|
description = 'Top Stories from the New York Times'
|
||||||
|
|
||||||
# List of sections typically included in Top Stories. Use a keyword from the
|
# List of sections typically included in Top Stories. Use a keyword from the
|
||||||
@ -388,6 +388,10 @@ class NYTimes(BasicNewsRecipe):
|
|||||||
return ans
|
return ans
|
||||||
|
|
||||||
def preprocess_html(self, soup):
|
def preprocess_html(self, soup):
|
||||||
|
# Skip ad pages before actual article
|
||||||
|
skip_tag = soup.find(True, {'name':'skip'})
|
||||||
|
if skip_tag is not None:
|
||||||
|
soup = self.index_to_soup(skip_tag.parent['href'])
|
||||||
return self.strip_anchors(soup)
|
return self.strip_anchors(soup)
|
||||||
|
|
||||||
def postprocess_html(self,soup, True):
|
def postprocess_html(self,soup, True):
|
||||||
|
@ -82,6 +82,7 @@ class NYTimes(BasicNewsRecipe):
|
|||||||
'articleExtras',
|
'articleExtras',
|
||||||
'articleInline',
|
'articleInline',
|
||||||
'blog_sidebar',
|
'blog_sidebar',
|
||||||
|
'businessSearchBar',
|
||||||
'cCol',
|
'cCol',
|
||||||
'entertainmentSearchBar',
|
'entertainmentSearchBar',
|
||||||
'footer',
|
'footer',
|
||||||
@ -286,9 +287,14 @@ class NYTimes(BasicNewsRecipe):
|
|||||||
raw = self.browser.open('http://www.nytimes.com'+content).read()
|
raw = self.browser.open('http://www.nytimes.com'+content).read()
|
||||||
return BeautifulSoup(raw.decode('cp1252', 'replace'))
|
return BeautifulSoup(raw.decode('cp1252', 'replace'))
|
||||||
'''
|
'''
|
||||||
|
# Skip ad pages before actual article
|
||||||
|
skip_tag = soup.find(True, {'name':'skip'})
|
||||||
|
if skip_tag is not None:
|
||||||
|
soup = self.index_to_soup(skip_tag.parent['href'])
|
||||||
return self.strip_anchors(soup)
|
return self.strip_anchors(soup)
|
||||||
|
|
||||||
def postprocess_html(self,soup, True):
|
def postprocess_html(self,soup, True):
|
||||||
|
print "\npostprocess_html()\n"
|
||||||
|
|
||||||
if self.one_picture_per_article:
|
if self.one_picture_per_article:
|
||||||
# Remove all images after first
|
# Remove all images after first
|
||||||
@ -411,6 +417,7 @@ class NYTimes(BasicNewsRecipe):
|
|||||||
return soup
|
return soup
|
||||||
|
|
||||||
def postprocess_book(self, oeb, opts, log) :
|
def postprocess_book(self, oeb, opts, log) :
|
||||||
|
print "\npostprocess_book()\n"
|
||||||
|
|
||||||
def extract_byline(href) :
|
def extract_byline(href) :
|
||||||
# <meta name="byline" content=
|
# <meta name="byline" content=
|
||||||
|
31
resources/recipes/trv.recipe
Normal file
31
resources/recipes/trv.recipe
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2010, Vadim Dyadkin dyadkin@lns.pnpi.spb.ru'
|
||||||
|
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class Trv(BasicNewsRecipe):
|
||||||
|
|
||||||
|
|
||||||
|
title = u'\u0422\u0440\u043e\u0438\u0446\u043a\u0438\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442'
|
||||||
|
language = 'ru'
|
||||||
|
__author__ = 'Vadim Dyadkin'
|
||||||
|
oldest_article = 30
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
recursion = 4
|
||||||
|
no_stylesheets = True
|
||||||
|
simultaneous_downloads = 1
|
||||||
|
|
||||||
|
keep_only_tags = [dict(name='h1'),
|
||||||
|
dict(name='div', attrs={'id' : 'content'})
|
||||||
|
]
|
||||||
|
|
||||||
|
remove_tags = [dict(name='div', attrs={'class' : ['dateright',
|
||||||
|
'postmeta', 'adsense-post', 'comments', 'nocomments', 'widgetarea',
|
||||||
|
'breadcrumb']}), {'id' : ['sidebar', 'l_sidebar', 'r_sidebar', 'footer',
|
||||||
|
'homepageright0']}, {'style' : 'clear:both;'},
|
||||||
|
dict(name='ul'),
|
||||||
|
dict(name='h2')
|
||||||
|
]
|
||||||
|
|
||||||
|
feeds = [(u'\u0422\u0440\u043e\u0438\u0446\u043a\u0438\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442',
|
||||||
|
u'http://trv-science.ru/feed/')]
|
@ -16,13 +16,15 @@ class Wired(BasicNewsRecipe):
|
|||||||
publisher = 'Conde Nast Digital'
|
publisher = 'Conde Nast Digital'
|
||||||
category = 'news, games, IT, gadgets'
|
category = 'news, games, IT, gadgets'
|
||||||
oldest_article = 32
|
oldest_article = 32
|
||||||
|
delay = 1
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
encoding = 'utf-8'
|
encoding = 'utf-8'
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
masthead_url = 'http://www.wired.com/images/home/wired_logo.gif'
|
masthead_url = 'http://www.wired.com/images/home/wired_logo.gif'
|
||||||
language = 'en'
|
language = 'en'
|
||||||
extra_css = ' body{font-family: sans-serif} .entryDescription li {display: inline; list-style-type: none} '
|
publication_type = 'magazine'
|
||||||
|
extra_css = ' body{font-family: Arial,Verdana,sans-serif} .entryDescription li {display: inline; list-style-type: none} '
|
||||||
index = 'http://www.wired.com/magazine/'
|
index = 'http://www.wired.com/magazine/'
|
||||||
|
|
||||||
preprocess_regexps = [(re.compile(r'<meta name="Title".*<title>', re.DOTALL|re.IGNORECASE),lambda match: '<title>')]
|
preprocess_regexps = [(re.compile(r'<meta name="Title".*<title>', re.DOTALL|re.IGNORECASE),lambda match: '<title>')]
|
||||||
@ -38,6 +40,8 @@ class Wired(BasicNewsRecipe):
|
|||||||
remove_tags = [
|
remove_tags = [
|
||||||
dict(name=['object','embed','iframe','link'])
|
dict(name=['object','embed','iframe','link'])
|
||||||
,dict(name='div', attrs={'class':['podcast_storyboard','tweetmeme_button']})
|
,dict(name='div', attrs={'class':['podcast_storyboard','tweetmeme_button']})
|
||||||
|
,dict(attrs={'id':'ff_bottom_nav'})
|
||||||
|
,dict(name='a',attrs={'href':'http://www.wired.com/app'})
|
||||||
]
|
]
|
||||||
remove_attributes = ['height','width']
|
remove_attributes = ['height','width']
|
||||||
|
|
||||||
@ -72,17 +76,18 @@ class Wired(BasicNewsRecipe):
|
|||||||
farticles = []
|
farticles = []
|
||||||
for item in features.findAll('div',attrs={'class':'section'}):
|
for item in features.findAll('div',attrs={'class':'section'}):
|
||||||
divurl = item.find('div',attrs={'class':'feature-header'})
|
divurl = item.find('div',attrs={'class':'feature-header'})
|
||||||
divdesc = item.find('div',attrs={'class':'feature-text'})
|
if divurl:
|
||||||
url = 'http://www.wired.com' + divurl.a['href']
|
divdesc = item.find('div',attrs={'class':'feature-text'})
|
||||||
title = self.tag_to_string(divurl.a)
|
url = 'http://www.wired.com' + divurl.a['href']
|
||||||
description = self.tag_to_string(divdesc)
|
title = self.tag_to_string(divurl.a)
|
||||||
date = strftime(self.timefmt)
|
description = self.tag_to_string(divdesc)
|
||||||
farticles.append({
|
date = strftime(self.timefmt)
|
||||||
'title' :title
|
farticles.append({
|
||||||
,'date' :date
|
'title' :title
|
||||||
,'url' :url
|
,'date' :date
|
||||||
,'description':description
|
,'url' :url
|
||||||
})
|
,'description':description
|
||||||
|
})
|
||||||
totalfeeds.append(('Featured Articles', farticles))
|
totalfeeds.append(('Featured Articles', farticles))
|
||||||
#department feeds
|
#department feeds
|
||||||
departments = ['rants','start','test','play','found']
|
departments = ['rants','start','test','play','found']
|
||||||
|
@ -444,7 +444,7 @@ from calibre.devices.kindle.driver import KINDLE, KINDLE2, KINDLE_DX
|
|||||||
from calibre.devices.nook.driver import NOOK
|
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
|
from calibre.devices.nokia.driver import N770, N810, E71X
|
||||||
from calibre.devices.eslick.driver import ESLICK
|
from calibre.devices.eslick.driver import ESLICK
|
||||||
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
|
||||||
@ -453,8 +453,9 @@ from calibre.devices.hanvon.driver import N516, EB511, ALEX, AZBOOKA, THEBOOK
|
|||||||
from calibre.devices.edge.driver import EDGE
|
from calibre.devices.edge.driver import EDGE
|
||||||
from calibre.devices.teclast.driver import TECLAST_K3, NEWSMY, IPAPYRUS
|
from calibre.devices.teclast.driver import TECLAST_K3, NEWSMY, IPAPYRUS
|
||||||
from calibre.devices.sne.driver import SNE
|
from calibre.devices.sne.driver import SNE
|
||||||
from calibre.devices.misc import PALMPRE, KOBO, AVANT
|
from calibre.devices.misc import PALMPRE, AVANT
|
||||||
from calibre.devices.folder_device.driver import FOLDER_DEVICE_FOR_CONFIG
|
from calibre.devices.folder_device.driver import FOLDER_DEVICE_FOR_CONFIG
|
||||||
|
from calibre.devices.kobo.driver import KOBO
|
||||||
|
|
||||||
from calibre.ebooks.metadata.fetch import GoogleBooks, ISBNDB, Amazon
|
from calibre.ebooks.metadata.fetch import GoogleBooks, ISBNDB, Amazon
|
||||||
from calibre.library.catalog import CSV_XML, EPUB_MOBI
|
from calibre.library.catalog import CSV_XML, EPUB_MOBI
|
||||||
@ -514,6 +515,7 @@ plugins += [
|
|||||||
ANDROID,
|
ANDROID,
|
||||||
S60,
|
S60,
|
||||||
N770,
|
N770,
|
||||||
|
E71X,
|
||||||
N810,
|
N810,
|
||||||
COOL_ER,
|
COOL_ER,
|
||||||
ESLICK,
|
ESLICK,
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
'''
|
# -*- coding: utf-8 -*-
|
||||||
Device driver for iTunes
|
|
||||||
|
|
||||||
GRiker
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2010, Gregory Riker'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
22 May 2010
|
|
||||||
'''
|
import cStringIO, os, re, shutil, sys, time, zipfile
|
||||||
import atexit, cStringIO, datetime, os, re, shutil, sys, time, zipfile
|
|
||||||
|
|
||||||
from calibre.constants import DEBUG
|
from calibre.constants import DEBUG
|
||||||
from calibre import fit_image
|
from calibre import fit_image
|
||||||
@ -13,43 +13,32 @@ from calibre.constants import isosx, iswindows
|
|||||||
from calibre.devices.interface import DevicePlugin
|
from calibre.devices.interface import DevicePlugin
|
||||||
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, cleanup
|
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
|
||||||
|
from calibre.devices.errors import UserFeedback
|
||||||
|
|
||||||
from PIL import Image as PILImage, TarIO
|
from PIL import Image as PILImage
|
||||||
|
|
||||||
if isosx:
|
if isosx:
|
||||||
import appscript, osax
|
import appscript
|
||||||
|
|
||||||
if iswindows:
|
#if iswindows:
|
||||||
import win32com.client
|
# import win32com.client
|
||||||
|
|
||||||
class UserInteractionRequired(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class UserFeedback(Exception):
|
|
||||||
INFO = 0
|
|
||||||
WARN = 1
|
|
||||||
ERROR = 2
|
|
||||||
|
|
||||||
def __init__(self, msg, details, level):
|
|
||||||
Exception.__init__(self, msg)
|
|
||||||
self.level = level
|
|
||||||
self.details = details
|
|
||||||
self.msg = msg
|
|
||||||
|
|
||||||
class ITUNES(DevicePlugin):
|
class ITUNES(DevicePlugin):
|
||||||
|
|
||||||
name = 'Apple device interface'
|
name = 'Apple device interface'
|
||||||
gui_name = 'Apple device'
|
gui_name = 'Apple device'
|
||||||
icon = I('devices/ipad.png')
|
icon = I('devices/ipad.png')
|
||||||
description = _('Communicate with iBooks through iTunes.')
|
description = _('Communicate with iBooks through iTunes.')
|
||||||
supported_platforms = ['windows','osx']
|
supported_platforms = ['osx']
|
||||||
author = 'GRiker'
|
author = 'GRiker'
|
||||||
driver_version = '0.1'
|
driver_version = '0.1'
|
||||||
|
|
||||||
OPEN_FEEDBACK_MESSAGE = _('Apple device detected, launching iTunes')
|
OPEN_FEEDBACK_MESSAGE = _(
|
||||||
|
'Apple device detected, launching iTunes, please wait...')
|
||||||
|
|
||||||
FORMATS = ['epub']
|
FORMATS = ['epub']
|
||||||
|
|
||||||
@ -356,7 +345,7 @@ class ITUNES(DevicePlugin):
|
|||||||
# Init the iTunes source list
|
# Init the iTunes source list
|
||||||
names = [s.name() for s in self.iTunes.sources()]
|
names = [s.name() for s in self.iTunes.sources()]
|
||||||
kinds = [str(s.kind()).rpartition('.')[2] for s in self.iTunes.sources()]
|
kinds = [str(s.kind()).rpartition('.')[2] for s in self.iTunes.sources()]
|
||||||
self.sources = sources = dict(zip(kinds,names))
|
self.sources = dict(zip(kinds,names))
|
||||||
|
|
||||||
# Check to see if Library|Books out of sync with Device|Books
|
# Check to see if Library|Books out of sync with Device|Books
|
||||||
if 'iPod' in self.sources and self.presync:
|
if 'iPod' in self.sources and self.presync:
|
||||||
@ -711,7 +700,6 @@ class ITUNES(DevicePlugin):
|
|||||||
'''
|
'''
|
||||||
if 'iPod' in self.sources:
|
if 'iPod' in self.sources:
|
||||||
device = self.sources['iPod']
|
device = self.sources['iPod']
|
||||||
device_books = []
|
|
||||||
if 'Books' in self.iTunes.sources[device].playlists.name():
|
if 'Books' in self.iTunes.sources[device].playlists.name():
|
||||||
return self.iTunes.sources[device].playlists['Books'].file_tracks()
|
return self.iTunes.sources[device].playlists['Books'].file_tracks()
|
||||||
|
|
||||||
|
@ -22,9 +22,20 @@ class DeviceError(ProtocolError):
|
|||||||
""" Raised when device is not found """
|
""" Raised when device is not found """
|
||||||
def __init__(self, msg=None):
|
def __init__(self, msg=None):
|
||||||
if msg is None:
|
if msg is None:
|
||||||
msg = "Unable to find SONY Reader. Is it connected?"
|
msg = "Unable to find SONY Reader. Is it connected?"
|
||||||
ProtocolError.__init__(self, msg)
|
ProtocolError.__init__(self, msg)
|
||||||
|
|
||||||
|
class UserFeedback(DeviceError):
|
||||||
|
INFO = 0
|
||||||
|
WARN = 1
|
||||||
|
ERROR = 2
|
||||||
|
|
||||||
|
def __init__(self, msg, details, level):
|
||||||
|
Exception.__init__(self, msg)
|
||||||
|
self.level = level
|
||||||
|
self.details = details
|
||||||
|
self.msg = msg
|
||||||
|
|
||||||
class DeviceBusy(ProtocolError):
|
class DeviceBusy(ProtocolError):
|
||||||
""" Raised when device is busy """
|
""" Raised when device is busy """
|
||||||
def __init__(self, uerr=""):
|
def __init__(self, uerr=""):
|
||||||
@ -57,8 +68,8 @@ class ControlError(ProtocolError):
|
|||||||
self.query = query
|
self.query = query
|
||||||
self.response = response
|
self.response = response
|
||||||
ProtocolError.__init__(self, desc)
|
ProtocolError.__init__(self, desc)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if self.query and self.response:
|
if self.query and self.response:
|
||||||
return "Got unexpected response:\n" + \
|
return "Got unexpected response:\n" + \
|
||||||
"query:\n"+str(self.query.query)+"\n"+\
|
"query:\n"+str(self.query.query)+"\n"+\
|
||||||
|
@ -47,6 +47,10 @@ class DevicePlugin(Plugin):
|
|||||||
# Used by gui2.ui:annotations_fetched() and devices.kindle.driver:get_annotations()
|
# Used by gui2.ui:annotations_fetched() and devices.kindle.driver:get_annotations()
|
||||||
UserAnnotation = namedtuple('Annotation','type, value')
|
UserAnnotation = namedtuple('Annotation','type, value')
|
||||||
|
|
||||||
|
#: GUI displays this as a message if not None. Useful if opening can take a
|
||||||
|
#: long time
|
||||||
|
OPEN_FEEDBACK_MESSAGE = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_gui_name(cls):
|
def get_gui_name(cls):
|
||||||
if hasattr(cls, 'gui_name'):
|
if hasattr(cls, 'gui_name'):
|
||||||
|
9
src/calibre/devices/kobo/__init__.py
Normal file
9
src/calibre/devices/kobo/__init__.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
|
||||||
|
|
31
src/calibre/devices/kobo/driver.py
Normal file
31
src/calibre/devices/kobo/driver.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
from calibre.devices.usbms.driver import USBMS
|
||||||
|
|
||||||
|
class KOBO(USBMS):
|
||||||
|
|
||||||
|
name = 'Kobo Reader Device Interface'
|
||||||
|
gui_name = 'Kobo Reader'
|
||||||
|
description = _('Communicate with the Kobo Reader')
|
||||||
|
author = 'Kovid Goyal'
|
||||||
|
|
||||||
|
supported_platforms = ['windows', 'osx', 'linux']
|
||||||
|
|
||||||
|
# Ordered list of supported formats
|
||||||
|
FORMATS = ['epub', 'pdf']
|
||||||
|
|
||||||
|
VENDOR_ID = [0x2237]
|
||||||
|
PRODUCT_ID = [0x4161]
|
||||||
|
BCD = [0x0110]
|
||||||
|
|
||||||
|
VENDOR_NAME = 'KOBO_INC'
|
||||||
|
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = '.KOBOEREADER'
|
||||||
|
|
||||||
|
EBOOK_DIR_MAIN = ''
|
||||||
|
SUPPORTS_SUB_DIRS = True
|
||||||
|
|
@ -28,27 +28,6 @@ class PALMPRE(USBMS):
|
|||||||
|
|
||||||
EBOOK_DIR_MAIN = 'E-books'
|
EBOOK_DIR_MAIN = 'E-books'
|
||||||
|
|
||||||
class KOBO(USBMS):
|
|
||||||
|
|
||||||
name = 'Kobo Reader Device Interface'
|
|
||||||
gui_name = 'Kobo Reader'
|
|
||||||
description = _('Communicate with the Kobo Reader')
|
|
||||||
author = 'Kovid Goyal'
|
|
||||||
|
|
||||||
supported_platforms = ['windows', 'osx', 'linux']
|
|
||||||
|
|
||||||
# Ordered list of supported formats
|
|
||||||
FORMATS = ['epub', 'pdf']
|
|
||||||
|
|
||||||
VENDOR_ID = [0x2237]
|
|
||||||
PRODUCT_ID = [0x4161]
|
|
||||||
BCD = [0x0110]
|
|
||||||
|
|
||||||
VENDOR_NAME = 'KOBO_INC'
|
|
||||||
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = '.KOBOEREADER'
|
|
||||||
|
|
||||||
EBOOK_DIR_MAIN = ''
|
|
||||||
SUPPORTS_SUB_DIRS = True
|
|
||||||
|
|
||||||
class AVANT(USBMS):
|
class AVANT(USBMS):
|
||||||
name = 'Booq Avant Device Interface'
|
name = 'Booq Avant Device Interface'
|
||||||
|
@ -45,3 +45,25 @@ class N810(N770):
|
|||||||
WINDOWS_MAIN_MEM = 'N810'
|
WINDOWS_MAIN_MEM = 'N810'
|
||||||
|
|
||||||
MAIN_MEMORY_VOLUME_LABEL = 'N810 Main Memory'
|
MAIN_MEMORY_VOLUME_LABEL = 'N810 Main Memory'
|
||||||
|
|
||||||
|
class E71X(USBMS):
|
||||||
|
|
||||||
|
name = 'Nokia E71X device interface'
|
||||||
|
gui_name = 'Nokia E71X'
|
||||||
|
description = 'Communicate with the Nokia E71X'
|
||||||
|
author = 'Kovid Goyal'
|
||||||
|
supported_platforms = ['windows', 'linux', 'osx']
|
||||||
|
|
||||||
|
VENDOR_ID = [0x421]
|
||||||
|
PRODUCT_ID = [0x1a0]
|
||||||
|
BCD = [0x100]
|
||||||
|
|
||||||
|
|
||||||
|
FORMATS = ['mobi', 'prc']
|
||||||
|
|
||||||
|
EBOOK_DIR_MAIN = 'eBooks'
|
||||||
|
SUPPORTS_SUB_DIRS = True
|
||||||
|
|
||||||
|
VENDOR_NAME = 'NOKIA'
|
||||||
|
WINDOWS_MAIN_MEM = 'S60'
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ class EPUBInput(InputFormatPlugin):
|
|||||||
encfile = os.path.abspath(os.path.join('META-INF', 'encryption.xml'))
|
encfile = os.path.abspath(os.path.join('META-INF', 'encryption.xml'))
|
||||||
opf = None
|
opf = None
|
||||||
for f in walk(u'.'):
|
for f in walk(u'.'):
|
||||||
if f.lower().endswith('.opf'):
|
if f.lower().endswith('.opf') and '__MACOSX' not in f:
|
||||||
opf = os.path.abspath(f)
|
opf = os.path.abspath(f)
|
||||||
break
|
break
|
||||||
path = getattr(stream, 'name', 'stream')
|
path = getattr(stream, 'name', 'stream')
|
||||||
@ -146,6 +146,10 @@ class EPUBInput(InputFormatPlugin):
|
|||||||
self.rationalize_cover(opf, log)
|
self.rationalize_cover(opf, log)
|
||||||
|
|
||||||
self.optimize_opf_parsing = opf
|
self.optimize_opf_parsing = opf
|
||||||
|
for x in opf.itermanifest():
|
||||||
|
if x.get('media-type', '') == 'application/x-dtbook+xml':
|
||||||
|
raise ValueError(
|
||||||
|
'EPUB files with DTBook markup are not supported')
|
||||||
|
|
||||||
with open('content.opf', 'wb') as nopf:
|
with open('content.opf', 'wb') as nopf:
|
||||||
nopf.write(opf.render())
|
nopf.write(opf.render())
|
||||||
|
@ -106,7 +106,7 @@ class EPUBOutput(OutputFormatPlugin):
|
|||||||
recommendations = set([('pretty_print', True, OptionRecommendation.HIGH)])
|
recommendations = set([('pretty_print', True, OptionRecommendation.HIGH)])
|
||||||
|
|
||||||
|
|
||||||
def workaround_webkit_quirks(self):
|
def workaround_webkit_quirks(self): # {{{
|
||||||
from calibre.ebooks.oeb.base import XPath
|
from calibre.ebooks.oeb.base import XPath
|
||||||
for x in self.oeb.spine:
|
for x in self.oeb.spine:
|
||||||
root = x.data
|
root = x.data
|
||||||
@ -120,8 +120,9 @@ class EPUBOutput(OutputFormatPlugin):
|
|||||||
for pre in XPath('//h:pre')(body):
|
for pre in XPath('//h:pre')(body):
|
||||||
if not pre.text and len(pre) == 0:
|
if not pre.text and len(pre) == 0:
|
||||||
pre.tag = 'div'
|
pre.tag = 'div'
|
||||||
|
# }}}
|
||||||
|
|
||||||
def upshift_markup(self):
|
def upshift_markup(self): # {{{
|
||||||
'Upgrade markup to comply with XHTML 1.1 where possible'
|
'Upgrade markup to comply with XHTML 1.1 where possible'
|
||||||
from calibre.ebooks.oeb.base import XPath
|
from calibre.ebooks.oeb.base import XPath
|
||||||
for x in self.oeb.spine:
|
for x in self.oeb.spine:
|
||||||
@ -135,6 +136,7 @@ class EPUBOutput(OutputFormatPlugin):
|
|||||||
for u in XPath('//h:u')(root):
|
for u in XPath('//h:u')(root):
|
||||||
u.tag = 'span'
|
u.tag = 'span'
|
||||||
u.set('style', 'text-decoration:underline')
|
u.set('style', 'text-decoration:underline')
|
||||||
|
# }}}
|
||||||
|
|
||||||
def convert(self, oeb, output_path, input_plugin, opts, log):
|
def convert(self, oeb, output_path, input_plugin, opts, log):
|
||||||
self.log, self.opts, self.oeb = log, opts, oeb
|
self.log, self.opts, self.oeb = log, opts, oeb
|
||||||
@ -161,8 +163,10 @@ class EPUBOutput(OutputFormatPlugin):
|
|||||||
self.workaround_sony_quirks()
|
self.workaround_sony_quirks()
|
||||||
|
|
||||||
if self.oeb.toc.count() == 0:
|
if self.oeb.toc.count() == 0:
|
||||||
self.log.warn('This EPUB file has no Table of Contents. It will '
|
self.log.warn('This EPUB file has no Table of Contents. '
|
||||||
'not validate via epubcheck')
|
'Creating a default TOC')
|
||||||
|
first = iter(self.oeb.spine).next()
|
||||||
|
self.oeb.toc.add(_('Start'), first.href)
|
||||||
|
|
||||||
from calibre.ebooks.oeb.base import OPF
|
from calibre.ebooks.oeb.base import OPF
|
||||||
identifiers = oeb.metadata['identifier']
|
identifiers = oeb.metadata['identifier']
|
||||||
@ -202,7 +206,7 @@ class EPUBOutput(OutputFormatPlugin):
|
|||||||
self.log.info('EPUB extracted to', opts.extract_to)
|
self.log.info('EPUB extracted to', opts.extract_to)
|
||||||
epub.close()
|
epub.close()
|
||||||
|
|
||||||
def encrypt_fonts(self, uris, tdir, uuid):
|
def encrypt_fonts(self, uris, tdir, uuid): # {{{
|
||||||
from binascii import unhexlify
|
from binascii import unhexlify
|
||||||
|
|
||||||
key = re.sub(r'[^a-fA-F0-9]', '', uuid)
|
key = re.sub(r'[^a-fA-F0-9]', '', uuid)
|
||||||
@ -247,6 +251,7 @@ class EPUBOutput(OutputFormatPlugin):
|
|||||||
ans += (u'\n'.join(fonts)).encode('utf-8')
|
ans += (u'\n'.join(fonts)).encode('utf-8')
|
||||||
ans += '\n</encryption>'
|
ans += '\n</encryption>'
|
||||||
return ans
|
return ans
|
||||||
|
# }}}
|
||||||
|
|
||||||
def condense_ncx(self, ncx_path):
|
def condense_ncx(self, ncx_path):
|
||||||
if not self.opts.pretty_print:
|
if not self.opts.pretty_print:
|
||||||
@ -259,7 +264,7 @@ class EPUBOutput(OutputFormatPlugin):
|
|||||||
compressed = etree.tostring(tree.getroot(), encoding='utf-8')
|
compressed = etree.tostring(tree.getroot(), encoding='utf-8')
|
||||||
open(ncx_path, 'wb').write(compressed)
|
open(ncx_path, 'wb').write(compressed)
|
||||||
|
|
||||||
def workaround_ade_quirks(self):
|
def workaround_ade_quirks(self): # {{{
|
||||||
'''
|
'''
|
||||||
Perform various markup transforms to get the output to render correctly
|
Perform various markup transforms to get the output to render correctly
|
||||||
in the quirky ADE.
|
in the quirky ADE.
|
||||||
@ -388,8 +393,9 @@ class EPUBOutput(OutputFormatPlugin):
|
|||||||
else:
|
else:
|
||||||
self.oeb.log.warn('No stylesheet found')
|
self.oeb.log.warn('No stylesheet found')
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
def workaround_sony_quirks(self):
|
def workaround_sony_quirks(self): # {{{
|
||||||
'''
|
'''
|
||||||
Perform toc link transforms to alleviate slow loading.
|
Perform toc link transforms to alleviate slow loading.
|
||||||
'''
|
'''
|
||||||
@ -436,3 +442,6 @@ class EPUBOutput(OutputFormatPlugin):
|
|||||||
|
|
||||||
if self.oeb.toc:
|
if self.oeb.toc:
|
||||||
simplify_toc_entry(self.oeb.toc)
|
simplify_toc_entry(self.oeb.toc)
|
||||||
|
|
||||||
|
# }}}
|
||||||
|
|
||||||
|
@ -21,7 +21,9 @@ from calibre.utils.logging import Log
|
|||||||
from calibre import guess_type, prints
|
from calibre import guess_type, prints
|
||||||
from calibre.ebooks.oeb.transforms.cover import CoverManager
|
from calibre.ebooks.oeb.transforms.cover import CoverManager
|
||||||
|
|
||||||
TITLEPAGE = CoverManager.SVG_TEMPLATE.decode('utf-8').replace('__ar__', 'none')
|
TITLEPAGE = CoverManager.SVG_TEMPLATE.decode('utf-8').replace(\
|
||||||
|
'__ar__', 'none').replace('__viewbox__', '0 0 600 800'
|
||||||
|
).replace('__width__', '600').replace('__height__', '800')
|
||||||
|
|
||||||
def character_count(html):
|
def character_count(html):
|
||||||
'''
|
'''
|
||||||
|
@ -81,6 +81,8 @@ class DeviceJob(BaseJob):
|
|||||||
|
|
||||||
class DeviceManager(Thread):
|
class DeviceManager(Thread):
|
||||||
|
|
||||||
|
open_feedback = pyqtSignal(object)
|
||||||
|
|
||||||
def __init__(self, connected_slot, job_manager, sleep_time=2):
|
def __init__(self, connected_slot, job_manager, sleep_time=2):
|
||||||
'''
|
'''
|
||||||
:sleep_time: Time to sleep between device probes in secs
|
:sleep_time: Time to sleep between device probes in secs
|
||||||
@ -114,6 +116,8 @@ class DeviceManager(Thread):
|
|||||||
|
|
||||||
def do_connect(self, connected_devices, is_folder_device):
|
def do_connect(self, connected_devices, is_folder_device):
|
||||||
for dev, detected_device in connected_devices:
|
for dev, detected_device in connected_devices:
|
||||||
|
if dev.OPEN_FEEDBACK_MESSAGE is not None:
|
||||||
|
self.open_feedback.emit(dev.OPEN_FEEDBACK_MESSAGE)
|
||||||
dev.reset(detected_device=detected_device,
|
dev.reset(detected_device=detected_device,
|
||||||
report_progress=self.report_progress)
|
report_progress=self.report_progress)
|
||||||
try:
|
try:
|
||||||
|
@ -335,7 +335,9 @@ Future conversion of these books will use the default settings.</string>
|
|||||||
<tabstop>tags</tabstop>
|
<tabstop>tags</tabstop>
|
||||||
<tabstop>remove_tags</tabstop>
|
<tabstop>remove_tags</tabstop>
|
||||||
<tabstop>series</tabstop>
|
<tabstop>series</tabstop>
|
||||||
|
<tabstop>autonumber_series</tabstop>
|
||||||
<tabstop>remove_format</tabstop>
|
<tabstop>remove_format</tabstop>
|
||||||
|
<tabstop>swap_title_and_author</tabstop>
|
||||||
<tabstop>button_box</tabstop>
|
<tabstop>button_box</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources>
|
<resources>
|
||||||
|
@ -30,6 +30,7 @@ from calibre.ptempfile import PersistentTemporaryFile
|
|||||||
from calibre.utils.config import prefs, dynamic
|
from calibre.utils.config import prefs, dynamic
|
||||||
from calibre.utils.ipc.server import Server
|
from calibre.utils.ipc.server import Server
|
||||||
from calibre.utils.search_query_parser import saved_searches
|
from calibre.utils.search_query_parser import saved_searches
|
||||||
|
from calibre.devices.errors import UserFeedback
|
||||||
from calibre.gui2 import warning_dialog, choose_files, error_dialog, \
|
from calibre.gui2 import warning_dialog, choose_files, error_dialog, \
|
||||||
question_dialog,\
|
question_dialog,\
|
||||||
pixmap_to_data, choose_dir, \
|
pixmap_to_data, choose_dir, \
|
||||||
@ -234,6 +235,8 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
####################### 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)
|
self.job_manager)
|
||||||
|
self.device_manager.open_feedback.connect(self.status.showMessage,
|
||||||
|
type=Qt.QueuedConnection)
|
||||||
self.device_manager.start()
|
self.device_manager.start()
|
||||||
|
|
||||||
|
|
||||||
@ -2327,6 +2330,14 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
'''
|
'''
|
||||||
Handle exceptions in threaded device jobs.
|
Handle exceptions in threaded device jobs.
|
||||||
'''
|
'''
|
||||||
|
if isinstance(getattr(job, 'exception', None), UserFeedback):
|
||||||
|
ex = job.exception
|
||||||
|
func = {UserFeedback.ERROR:error_dialog,
|
||||||
|
UserFeedback.WARNING:warning_dialog,
|
||||||
|
UserFeedback.INFO:info_dialog}[ex.level]
|
||||||
|
return func(self, _('Failed'), ex.msg, det_msg=ex.details if
|
||||||
|
ex.details else '', show=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if 'Could not read 32 bytes on the control bus.' in \
|
if 'Could not read 32 bytes on the control bus.' in \
|
||||||
unicode(job.details):
|
unicode(job.details):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user