Merge from trunk

This commit is contained in:
Charles Haley 2012-01-15 10:13:37 +01:00
commit d68ff2bc3f
13 changed files with 163 additions and 47 deletions

View File

@ -0,0 +1,50 @@
__license__ = 'GPL v3'
__copyright__ = '2012 Levien van Zon <levien@zonnetjes.net>'
'''
Fetch Edge.org conversations
'''
from calibre.web.feeds.news import BasicNewsRecipe
class EdgeConversationRSS(BasicNewsRecipe):
title = u'Edge.org Conversations'
__author__ = 'levien'
language = 'en'
description = '''Edge.org offers "open-minded, free ranging, intellectually
playful ... an unadorned pleasure in curiosity, a collective expression of
wonder at the living and inanimate world ... an ongoing and thrilling
colloquium.'''
oldest_article = 60
max_articles_per_feed = 100
no_stylesheets = True
keep_only_tags = [dict(name='div', attrs={'class':'HomeLeftPannel IMGCTRL'}) ]
remove_tags = [
dict(name='div',attrs={'class':'Logo'})
]
feeds = [(u'Edge RSS', u'http://edge.org/feeds/')]
def print_version(self, url):
return url.replace('conversation/', 'conversation.php?cid=')
def parse_feeds(self):
# Call parent's method.
feeds = BasicNewsRecipe.parse_feeds(self)
# Loop through all feeds.
for feed in feeds:
# Loop through all articles in feed.
for article in feed.articles[:]:
# Remove anything that is not a conversation, and remove PDF files as well...
if not ('CONVERSATION' in article.title):
feed.articles.remove(article)
elif 'pdf' in article.url:
feed.articles.remove(article)
return feeds

View File

@ -22,13 +22,16 @@ class NoviList_hr(BasicNewsRecipe):
language = 'hr' language = 'hr'
remove_empty_feeds = True remove_empty_feeds = True
publication_type = 'newspaper' publication_type = 'newspaper'
needs_subscription = 'required' needs_subscription = True
masthead_url = 'http://novine.novilist.hr/images/system/novilist-logo.jpg' masthead_url = 'http://novine.novilist.hr/images/system/novilist-logo.jpg'
index = 'http://novine.novilist.hr/'
extra_css = """ extra_css = """
body{font-family: Geneva,Arial,Helvetica,Swiss,sans-serif } @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)}
body{font-family: Geneva,Arial,Helvetica,Swiss,sans1,sans-serif }
img{display:block; margin-bottom: 0.4em; margin-top: 0.4em} img{display:block; margin-bottom: 0.4em; margin-top: 0.4em}
.nadnaslov,.podnaslov{font-size: small; text-align: center} .nadnaslov,.podnaslov{font-size: small; display: block; margin-bottom: 1em}
.naslov{font-size: x-large; color: maroon; font-weight: bold} .naslov{font-size: x-large; color: maroon; font-weight: bold; display: block; margin-bottom: 1em;}
p{display: block}
""" """
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')] preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
@ -47,12 +50,12 @@ class NoviList_hr(BasicNewsRecipe):
] ]
remove_tags = [dict(name=['meta', 'link', 'iframe', 'embed', 'object'])] remove_tags = [dict(name=['meta', 'link', 'iframe', 'embed', 'object'])]
remove_attributes=['border', 'lang'] remove_attributes=['border', 'lang', 'size', 'face', 'bgcolor']
def get_browser(self): def get_browser(self):
br = BasicNewsRecipe.get_browser() br = BasicNewsRecipe.get_browser()
if self.username is not None and self.password is not None: if self.username is not None and self.password is not None:
br.open('http://novine.novilist.hr/loginnow.asp') br.open(self.index + 'loginnow.asp')
br.select_form(nr=0) br.select_form(nr=0)
br['username'] = self.username br['username'] = self.username
br['password'] = self.password br['password'] = self.password
@ -62,11 +65,11 @@ class NoviList_hr(BasicNewsRecipe):
def parse_index(self): def parse_index(self):
articles = [] articles = []
count = 0 count = 0
soup = self.index_to_soup('http://novine.novilist.hr/') soup = self.index_to_soup(self.index)
#cover url #cover url
for alink in soup.findAll('a'): for alink in soup.findAll('a'):
if alink['href'].startswith('images/clanci/DOC_'): if alink['href'].startswith('images/clanci/DOC_'):
self.cover_url = 'http://novine.novilist.hr/' + alink['href'] self.cover_url = self.index + alink['href']
#feeds #feeds
for item in soup.findAll('td',attrs={'class':'tocrubrika'}): for item in soup.findAll('td',attrs={'class':'tocrubrika'}):
count = count +1 count = count +1
@ -74,28 +77,24 @@ class NoviList_hr(BasicNewsRecipe):
return articles return articles
aitem = item.a aitem = item.a
section = self.tag_to_string(aitem) section = self.tag_to_string(aitem)
feedlink = 'http://novine.novilist.hr/' + aitem['href'] feedlink = self.index + aitem['href']
feedpage = self.index_to_soup(feedlink) feedpage = self.index_to_soup(feedlink)
self.report_progress(0, _('Fetching feed')+' %s...'%(section)) self.report_progress(0, _('Fetching feed')+' %s...'%(section))
inarts = [] inarts = []
for alink in feedpage.findAll('a',attrs={'class':'naslovlinkdesno'}): for alink in feedpage.findAll('a',attrs={'class':'naslovlinkdesno'}):
url = 'http://novine.novilist.hr/' + alink['href'] url = self.index + alink['href']
title = self.tag_to_string(alink)
date = strftime(self.timefmt)
description = ''
inarts.append({ inarts.append({
'title' :title 'title' :self.tag_to_string(alink)
,'date' :date ,'date' :strftime(self.timefmt)
,'url' :url ,'url' :url
,'description':description ,'description':''
}) })
if self.remove_empty_feeds:
if inarts:
articles.append((section,inarts))
else:
articles.append((section,inarts)) articles.append((section,inarts))
return articles return articles
def print_version(self, url): def print_version(self, url):
return url.replace('?WCI=Rubrike&','?WCI=Pretrazivac&') return url.replace('?WCI=Rubrike&','?WCI=Pretrazivac&')
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
return soup

View File

@ -10,7 +10,10 @@ from math import floor
from functools import partial from functools import partial
warnings.simplefilter('ignore', DeprecationWarning) warnings.simplefilter('ignore', DeprecationWarning)
try:
os.getcwdu()
except:
os.chdir(os.path.expanduser('~'))
from calibre.constants import (iswindows, isosx, islinux, isfrozen, from calibre.constants import (iswindows, isosx, islinux, isfrozen,
isbsd, preferred_encoding, __appname__, __version__, __author__, isbsd, preferred_encoding, __appname__, __version__, __author__,

View File

@ -97,7 +97,7 @@ class POCKETBOOK360(EB600):
VENDOR_NAME = ['PHILIPS', '__POCKET', 'POCKETBO'] VENDOR_NAME = ['PHILIPS', '__POCKET', 'POCKETBO']
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = ['MASS_STORGE', 'BOOK_USB_STORAGE', WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = ['MASS_STORGE', 'BOOK_USB_STORAGE',
'POCKET_611_61'] 'OK_POCKET_611_61']
OSX_MAIN_MEM = OSX_CARD_A_MEM = 'Philips Mass Storge Media' OSX_MAIN_MEM = OSX_CARD_A_MEM = 'Philips Mass Storge Media'
OSX_MAIN_MEM_VOL_PAT = re.compile(r'/Pocket') OSX_MAIN_MEM_VOL_PAT = re.compile(r'/Pocket')

View File

@ -6,6 +6,8 @@ __license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import re
from calibre.devices.usbms.driver import USBMS from calibre.devices.usbms.driver import USBMS
class IRIVER_STORY(USBMS): class IRIVER_STORY(USBMS):
@ -25,7 +27,9 @@ class IRIVER_STORY(USBMS):
VENDOR_NAME = 'IRIVER' VENDOR_NAME = 'IRIVER'
WINDOWS_MAIN_MEM = ['STORY', 'STORY_EB05', 'STORY_WI-FI', 'STORY_EB07'] WINDOWS_MAIN_MEM = ['STORY', 'STORY_EB05', 'STORY_WI-FI', 'STORY_EB07']
WINDOWS_MAIN_MEM = re.compile(r'(%s)&'%('|'.join(WINDOWS_MAIN_MEM)))
WINDOWS_CARD_A_MEM = ['STORY', 'STORY_SD'] WINDOWS_CARD_A_MEM = ['STORY', 'STORY_SD']
WINDOWS_CARD_A_MEM = re.compile(r'(%s)&'%('|'.join(WINDOWS_CARD_A_MEM)))
#OSX_MAIN_MEM = 'Kindle Internal Storage Media' #OSX_MAIN_MEM = 'Kindle Internal Storage Media'
#OSX_CARD_A_MEM = 'Kindle Card Storage Media' #OSX_CARD_A_MEM = 'Kindle Card Storage Media'

View File

@ -942,12 +942,12 @@ class Manifest(object):
if isinstance(data, etree._Element): if isinstance(data, etree._Element):
ans = xml2str(data, pretty_print=self.oeb.pretty_print) ans = xml2str(data, pretty_print=self.oeb.pretty_print)
if self.media_type in OEB_DOCS: if self.media_type in OEB_DOCS:
# Convert self closing div|span|a tags to normally closed # Convert self closing div|span|a|video|audio|iframe tags
# ones, as they are interpreted incorrectly by some browser # to normally closed ones, as they are interpreted
# based renderers # incorrectly by some browser based renderers
ans = re.sub( ans = re.sub(
# tag name followed by either a space or a / # tag name followed by either a space or a /
r'<(?P<tag>div|a|span)(?=[\s/])(?P<arg>[^>]*)/>', r'<(?P<tag>div|a|span|video|audio|iframe)(?=[\s/])(?P<arg>[^>]*)/>',
r'<\g<tag>\g<arg>></\g<tag>>', ans) r'<\g<tag>\g<arg>></\g<tag>>', ans)
return ans return ans
if isinstance(data, unicode): if isinstance(data, unicode):

View File

@ -398,8 +398,8 @@ class CanonicalFragmentIdentifier
break break
rect = target.getBoundingClientRect() rect = target.getBoundingClientRect()
x = x - rect.x x -= rect.left
y = y - rect.y y -= rect.top
cdoc = cd cdoc = cd
cwin = cdoc.defaultView cwin = cdoc.defaultView

View File

@ -32,10 +32,12 @@ window_ypos = (pos=null) ->
mark_and_reload = (evt) -> mark_and_reload = (evt) ->
# Remove image in case the click was on the image itself, we want the cfi to # Remove image in case the click was on the image itself, we want the cfi to
# be on the underlying element # be on the underlying element
x = evt.clientX
y = evt.clientY
if evt.button == 2 if evt.button == 2
return # Right mouse click, generated only in firefox return # Right mouse click, generated only in firefox
reset = document.getElementById('reset') reset = document.getElementById('reset')
if document.elementFromPoint(evt.clientX, evt.clientY) == reset if document.elementFromPoint(x, y) == reset
return return
ms = document.getElementById("marker") ms = document.getElementById("marker")
if ms if ms
@ -43,7 +45,7 @@ mark_and_reload = (evt) ->
fn = () -> fn = () ->
try try
window.current_cfi = window.cfi.at(evt.clientX, evt.clientY) window.current_cfi = window.cfi.at(x, y)
catch err catch err
alert("Failed to calculate cfi: #{ err }") alert("Failed to calculate cfi: #{ err }")
return return
@ -57,6 +59,28 @@ mark_and_reload = (evt) ->
setTimeout(fn, 1) setTimeout(fn, 1)
null null
window_scroll_pos = (win) ->
if typeof(win.pageXOffset) == 'number'
x = win.pageXOffset
y = win.pageYOffset
else # IE < 9
if document.body and ( document.body.scrollLeft or document.body.scrollTop )
x = document.body.scrollLeft
y = document.body.scrollTop
else if document.documentElement and ( document.documentElement.scrollLeft or document.documentElement.scrollTop)
y = document.documentElement.scrollTop
x = document.documentElement.scrollLeft
return [x, y]
frame_clicked = (evt) ->
iframe = evt.target.ownerDocument.defaultView.frameElement
# We know that the offset parent of the iframe is body
# So we can easily calculate the event co-ords w.r.t. the browser window
[winx, winy] = window_scroll_pos(window)
x = evt.clientX + iframe.offsetLeft - winx
y = evt.clientY + iframe.offsetTop - winy
mark_and_reload({'clientX':x, 'clientY':y, 'button':evt.button})
window.onload = -> window.onload = ->
try try
window.cfi.is_compatible() window.cfi.is_compatible()
@ -64,6 +88,9 @@ window.onload = ->
alert(error) alert(error)
return return
document.onclick = mark_and_reload document.onclick = mark_and_reload
for iframe in document.getElementsByTagName("iframe")
iframe.contentWindow.document.onclick = frame_clicked
r = location.hash.match(/#(\d*)epubcfi\((.+)\)$/) r = location.hash.match(/#(\d*)epubcfi\((.+)\)$/)
if r if r
window.current_cfi = r[2] window.current_cfi = r[2]

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<title>Testing EPUB CFI</title>
</head>
<body>
<p id="whitespace">But I must explain to you how all this mistaken
idea of denouncing pleasure and praising pain was born and I will
give you a complete account of the system, and expound the actual
teachings of the great explorer of the truth, the master-builder of
human happiness. No one rejects, dislikes, or avoids pleasure
itself, because it is pleasure, but because those who do not know
how to pursue pleasure rationally encounter consequences that are
extremely painful. Nor again is there anyone who <b>loves or
pursues or desires</b> to obtain pain of itself, because it is
pain, but because occasionally circumstances occur in which toil
and pain can procure him some great pleasure. To take a trivial
example, which of us ever undertakes laborious physical exercise,
except to obtain some advantage from it? But who has any right to
find fault with a man who chooses to enjoy a pleasure that has no
annoying consequences, or one who avoids a pain that produces no
resultant pleasure? On the other hand, we denounce with righteous
indignation and dislike men who are so beguiled and demoralized by
the charms of pleasure of the moment, so blinded by desire, that
they cannot foresee</p>
</body>
</html>

View File

@ -118,6 +118,10 @@
<img src="marker.png" width="150" height="200" alt="Test Image" <img src="marker.png" width="150" height="200" alt="Test Image"
style="border: solid 1px black"/> style="border: solid 1px black"/>
<h2>Iframes</h2>
<p>Try clicking anywhere in the iframe below:</p>
<iframe src="iframe.html"></iframe>
<h2>Video</h2> <h2>Video</h2>
<p>Try clicking on this video while it is playing. The page should <p>Try clicking on this video while it is playing. The page should
reload with the video paused at the point it was at when you reload with the video paused at the point it was at when you
@ -125,7 +129,7 @@
play (otherwise the click will cause a reload). play (otherwise the click will cause a reload).
</p> </p>
<video width="320" height="240" controls="controls" preload="auto" <video width="320" height="240" controls="controls" preload="auto"
src="birds.webm" type="video/webm" /> src="birds.webm" type="video/webm"></video>
</div> </div>
<img id="marker" style="position: absolute; display:none; z-index:10" <img id="marker" style="position: absolute; display:none; z-index:10"

View File

@ -179,14 +179,16 @@ class Document(QWebPage): # {{{
self.misc_config() self.misc_config()
self.after_load() self.after_load()
def __init__(self, shortcuts, parent=None, resize_callback=lambda: None): def __init__(self, shortcuts, parent=None, resize_callback=lambda: None,
debug_javascript=False):
QWebPage.__init__(self, parent) QWebPage.__init__(self, parent)
self.setObjectName("py_bridge") self.setObjectName("py_bridge")
self.debug_javascript = False self.debug_javascript = debug_javascript
self.resize_callback = resize_callback self.resize_callback = resize_callback
self.current_language = None self.current_language = None
self.loaded_javascript = False self.loaded_javascript = False
self.js_loader = None self.js_loader = JavaScriptLoader(
dynamic_coffeescript=self.debug_javascript)
self.setLinkDelegationPolicy(self.DelegateAllLinks) self.setLinkDelegationPolicy(self.DelegateAllLinks)
self.scroll_marks = [] self.scroll_marks = []
@ -252,9 +254,6 @@ class Document(QWebPage): # {{{
window.py_bridge.window_resized(); window.py_bridge.window_resized();
} }
''') ''')
if self.js_loader is None:
self.js_loader = JavaScriptLoader(
dynamic_coffeescript=self.debug_javascript)
self.loaded_lang = self.js_loader(self.mainFrame().evaluateJavaScript, self.loaded_lang = self.js_loader(self.mainFrame().evaluateJavaScript,
self.current_language, self.hyphenate_default_lang) self.current_language, self.hyphenate_default_lang)
@ -470,11 +469,10 @@ class DocumentView(QWebView): # {{{
magnification_changed = pyqtSignal(object) magnification_changed = pyqtSignal(object)
DISABLED_BRUSH = QBrush(Qt.lightGray, Qt.Dense5Pattern) DISABLED_BRUSH = QBrush(Qt.lightGray, Qt.Dense5Pattern)
def __init__(self, *args): def initialize_view(self, debug_javascript=False):
QWebView.__init__(self, *args)
self.flipper = SlideFlip(self) self.flipper = SlideFlip(self)
self.is_auto_repeat_event = False self.is_auto_repeat_event = False
self.debug_javascript = False self.debug_javascript = debug_javascript
self.shortcuts = Shortcuts(SHORTCUTS, 'shortcuts/viewer') self.shortcuts = Shortcuts(SHORTCUTS, 'shortcuts/viewer')
self.self_closing_pat = re.compile(r'<([a-z1-6]+)\s+([^>]+)/>', self.self_closing_pat = re.compile(r'<([a-z1-6]+)\s+([^>]+)/>',
re.IGNORECASE) re.IGNORECASE)
@ -483,7 +481,8 @@ class DocumentView(QWebView): # {{{
self.initial_pos = 0.0 self.initial_pos = 0.0
self.to_bottom = False self.to_bottom = False
self.document = Document(self.shortcuts, parent=self, self.document = Document(self.shortcuts, parent=self,
resize_callback=self.viewport_resized) resize_callback=self.viewport_resized,
debug_javascript=debug_javascript)
self.setPage(self.document) self.setPage(self.document)
self.manager = None self.manager = None
self._reference_mode = False self._reference_mode = False

View File

@ -39,14 +39,14 @@ class JavaScriptLoader(object):
self._cache = {} self._cache = {}
self._hp_cache = {} self._hp_cache = {}
def __getattr__(self, name): def get(self, name):
ans = self._cache.get(name, None) ans = self._cache.get(name, None)
if ans is None: if ans is None:
src = self.CS.get(name, None) src = self.CS.get(name, None)
if src is None: if src is None:
src = self.JS.get(name, None) src = self.JS.get(name, None)
if src is None: if src is None:
raise AttributeError('No such resource: %s'%name) raise KeyError('No such resource: %s'%name)
ans = P(src, data=True, ans = P(src, data=True,
allow_user_override=False).decode('utf-8') allow_user_override=False).decode('utf-8')
else: else:
@ -70,7 +70,7 @@ class JavaScriptLoader(object):
def __call__(self, evaljs, lang, default_lang): def __call__(self, evaljs, lang, default_lang):
for x in self.ORDER: for x in self.ORDER:
src = getattr(self, x) src = self.get(x)
evaljs(src) evaljs(src)
def lang_name(l): def lang_name(l):

View File

@ -175,6 +175,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
def __init__(self, pathtoebook=None, debug_javascript=False, open_at=None): def __init__(self, pathtoebook=None, debug_javascript=False, open_at=None):
MainWindow.__init__(self, None) MainWindow.__init__(self, None)
self.setupUi(self) self.setupUi(self)
self.view.initialize_view(debug_javascript)
self.view.magnification_changed.connect(self.magnification_changed) self.view.magnification_changed.connect(self.magnification_changed)
self.show_toc_on_open = False self.show_toc_on_open = False
self.current_book_has_toc = False self.current_book_has_toc = False
@ -215,7 +216,6 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.search.setMinimumWidth(200) self.search.setMinimumWidth(200)
self.tool_bar2.insertWidget(self.action_find_next, self.search) self.tool_bar2.insertWidget(self.action_find_next, self.search)
self.view.set_manager(self) self.view.set_manager(self)
self.view.document.debug_javascript = debug_javascript
self.pi = ProgressIndicator(self) self.pi = ProgressIndicator(self)
self.toc.setVisible(False) self.toc.setVisible(False)
self.action_quit = QAction(self) self.action_quit = QAction(self)