KG revisions

This commit is contained in:
GRiker 2010-05-28 15:26:24 -06:00
commit 4266e94984
21 changed files with 278 additions and 140 deletions

View File

@ -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/')

View File

@ -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)

View 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')]

View File

@ -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):

View File

@ -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=

View 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/')]

View File

@ -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']

View File

@ -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,

View File

@ -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()

View File

@ -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"+\

View File

@ -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'):

View 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'

View 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

View File

@ -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'

View File

@ -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'

View File

@ -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())

View File

@ -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)
# }}}

View File

@ -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):
''' '''

View File

@ -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:

View File

@ -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>

View File

@ -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):