mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
Merge from trunk
This commit is contained in:
commit
d68ff2bc3f
50
recipes/edge_conversations.recipe
Normal file
50
recipes/edge_conversations.recipe
Normal 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
|
||||
|
@ -22,13 +22,16 @@ class NoviList_hr(BasicNewsRecipe):
|
||||
language = 'hr'
|
||||
remove_empty_feeds = True
|
||||
publication_type = 'newspaper'
|
||||
needs_subscription = 'required'
|
||||
needs_subscription = True
|
||||
masthead_url = 'http://novine.novilist.hr/images/system/novilist-logo.jpg'
|
||||
index = 'http://novine.novilist.hr/'
|
||||
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}
|
||||
.nadnaslov,.podnaslov{font-size: small; text-align: center}
|
||||
.naslov{font-size: x-large; color: maroon; font-weight: bold}
|
||||
.nadnaslov,.podnaslov{font-size: small; display: block; margin-bottom: 1em}
|
||||
.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')]
|
||||
@ -47,12 +50,12 @@ class NoviList_hr(BasicNewsRecipe):
|
||||
]
|
||||
|
||||
remove_tags = [dict(name=['meta', 'link', 'iframe', 'embed', 'object'])]
|
||||
remove_attributes=['border', 'lang']
|
||||
remove_attributes=['border', 'lang', 'size', 'face', 'bgcolor']
|
||||
|
||||
def get_browser(self):
|
||||
br = BasicNewsRecipe.get_browser()
|
||||
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['username'] = self.username
|
||||
br['password'] = self.password
|
||||
@ -62,11 +65,11 @@ class NoviList_hr(BasicNewsRecipe):
|
||||
def parse_index(self):
|
||||
articles = []
|
||||
count = 0
|
||||
soup = self.index_to_soup('http://novine.novilist.hr/')
|
||||
soup = self.index_to_soup(self.index)
|
||||
#cover url
|
||||
for alink in soup.findAll('a'):
|
||||
if alink['href'].startswith('images/clanci/DOC_'):
|
||||
self.cover_url = 'http://novine.novilist.hr/' + alink['href']
|
||||
self.cover_url = self.index + alink['href']
|
||||
#feeds
|
||||
for item in soup.findAll('td',attrs={'class':'tocrubrika'}):
|
||||
count = count +1
|
||||
@ -74,28 +77,24 @@ class NoviList_hr(BasicNewsRecipe):
|
||||
return articles
|
||||
aitem = item.a
|
||||
section = self.tag_to_string(aitem)
|
||||
feedlink = 'http://novine.novilist.hr/' + aitem['href']
|
||||
feedlink = self.index + aitem['href']
|
||||
feedpage = self.index_to_soup(feedlink)
|
||||
self.report_progress(0, _('Fetching feed')+' %s...'%(section))
|
||||
inarts = []
|
||||
for alink in feedpage.findAll('a',attrs={'class':'naslovlinkdesno'}):
|
||||
url = 'http://novine.novilist.hr/' + alink['href']
|
||||
title = self.tag_to_string(alink)
|
||||
date = strftime(self.timefmt)
|
||||
description = ''
|
||||
url = self.index + alink['href']
|
||||
inarts.append({
|
||||
'title' :title
|
||||
,'date' :date
|
||||
'title' :self.tag_to_string(alink)
|
||||
,'date' :strftime(self.timefmt)
|
||||
,'url' :url
|
||||
,'description':description
|
||||
,'description':''
|
||||
})
|
||||
articles.append((section,inarts))
|
||||
if self.remove_empty_feeds:
|
||||
if inarts:
|
||||
articles.append((section,inarts))
|
||||
else:
|
||||
articles.append((section,inarts))
|
||||
return articles
|
||||
|
||||
def print_version(self, url):
|
||||
return url.replace('?WCI=Rubrike&','?WCI=Pretrazivac&')
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
for item in soup.findAll(style=True):
|
||||
del item['style']
|
||||
return soup
|
||||
|
@ -10,7 +10,10 @@ from math import floor
|
||||
from functools import partial
|
||||
|
||||
warnings.simplefilter('ignore', DeprecationWarning)
|
||||
|
||||
try:
|
||||
os.getcwdu()
|
||||
except:
|
||||
os.chdir(os.path.expanduser('~'))
|
||||
|
||||
from calibre.constants import (iswindows, isosx, islinux, isfrozen,
|
||||
isbsd, preferred_encoding, __appname__, __version__, __author__,
|
||||
|
@ -97,7 +97,7 @@ class POCKETBOOK360(EB600):
|
||||
|
||||
VENDOR_NAME = ['PHILIPS', '__POCKET', 'POCKETBO']
|
||||
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_VOL_PAT = re.compile(r'/Pocket')
|
||||
|
@ -6,6 +6,8 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import re
|
||||
|
||||
from calibre.devices.usbms.driver import USBMS
|
||||
|
||||
class IRIVER_STORY(USBMS):
|
||||
@ -25,7 +27,9 @@ class IRIVER_STORY(USBMS):
|
||||
|
||||
VENDOR_NAME = 'IRIVER'
|
||||
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 = re.compile(r'(%s)&'%('|'.join(WINDOWS_CARD_A_MEM)))
|
||||
|
||||
#OSX_MAIN_MEM = 'Kindle Internal Storage Media'
|
||||
#OSX_CARD_A_MEM = 'Kindle Card Storage Media'
|
||||
|
@ -942,12 +942,12 @@ class Manifest(object):
|
||||
if isinstance(data, etree._Element):
|
||||
ans = xml2str(data, pretty_print=self.oeb.pretty_print)
|
||||
if self.media_type in OEB_DOCS:
|
||||
# Convert self closing div|span|a tags to normally closed
|
||||
# ones, as they are interpreted incorrectly by some browser
|
||||
# based renderers
|
||||
# Convert self closing div|span|a|video|audio|iframe tags
|
||||
# to normally closed ones, as they are interpreted
|
||||
# incorrectly by some browser based renderers
|
||||
ans = re.sub(
|
||||
# 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)
|
||||
return ans
|
||||
if isinstance(data, unicode):
|
||||
|
@ -398,8 +398,8 @@ class CanonicalFragmentIdentifier
|
||||
break
|
||||
|
||||
rect = target.getBoundingClientRect()
|
||||
x = x - rect.x
|
||||
y = y - rect.y
|
||||
x -= rect.left
|
||||
y -= rect.top
|
||||
cdoc = cd
|
||||
cwin = cdoc.defaultView
|
||||
|
||||
|
@ -32,10 +32,12 @@ window_ypos = (pos=null) ->
|
||||
mark_and_reload = (evt) ->
|
||||
# Remove image in case the click was on the image itself, we want the cfi to
|
||||
# be on the underlying element
|
||||
x = evt.clientX
|
||||
y = evt.clientY
|
||||
if evt.button == 2
|
||||
return # Right mouse click, generated only in firefox
|
||||
reset = document.getElementById('reset')
|
||||
if document.elementFromPoint(evt.clientX, evt.clientY) == reset
|
||||
if document.elementFromPoint(x, y) == reset
|
||||
return
|
||||
ms = document.getElementById("marker")
|
||||
if ms
|
||||
@ -43,7 +45,7 @@ mark_and_reload = (evt) ->
|
||||
|
||||
fn = () ->
|
||||
try
|
||||
window.current_cfi = window.cfi.at(evt.clientX, evt.clientY)
|
||||
window.current_cfi = window.cfi.at(x, y)
|
||||
catch err
|
||||
alert("Failed to calculate cfi: #{ err }")
|
||||
return
|
||||
@ -57,6 +59,28 @@ mark_and_reload = (evt) ->
|
||||
setTimeout(fn, 1)
|
||||
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 = ->
|
||||
try
|
||||
window.cfi.is_compatible()
|
||||
@ -64,6 +88,9 @@ window.onload = ->
|
||||
alert(error)
|
||||
return
|
||||
document.onclick = mark_and_reload
|
||||
for iframe in document.getElementsByTagName("iframe")
|
||||
iframe.contentWindow.document.onclick = frame_clicked
|
||||
|
||||
r = location.hash.match(/#(\d*)epubcfi\((.+)\)$/)
|
||||
if r
|
||||
window.current_cfi = r[2]
|
||||
|
30
src/calibre/ebooks/oeb/display/test-cfi/iframe.html
Normal file
30
src/calibre/ebooks/oeb/display/test-cfi/iframe.html
Normal 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>
|
||||
|
||||
|
@ -118,6 +118,10 @@
|
||||
<img src="marker.png" width="150" height="200" alt="Test Image"
|
||||
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>
|
||||
<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
|
||||
@ -125,7 +129,7 @@
|
||||
play (otherwise the click will cause a reload).
|
||||
</p>
|
||||
<video width="320" height="240" controls="controls" preload="auto"
|
||||
src="birds.webm" type="video/webm" />
|
||||
src="birds.webm" type="video/webm"></video>
|
||||
|
||||
</div>
|
||||
<img id="marker" style="position: absolute; display:none; z-index:10"
|
||||
|
@ -179,14 +179,16 @@ class Document(QWebPage): # {{{
|
||||
self.misc_config()
|
||||
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)
|
||||
self.setObjectName("py_bridge")
|
||||
self.debug_javascript = False
|
||||
self.debug_javascript = debug_javascript
|
||||
self.resize_callback = resize_callback
|
||||
self.current_language = None
|
||||
self.loaded_javascript = False
|
||||
self.js_loader = None
|
||||
self.js_loader = JavaScriptLoader(
|
||||
dynamic_coffeescript=self.debug_javascript)
|
||||
|
||||
self.setLinkDelegationPolicy(self.DelegateAllLinks)
|
||||
self.scroll_marks = []
|
||||
@ -252,9 +254,6 @@ class Document(QWebPage): # {{{
|
||||
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.current_language, self.hyphenate_default_lang)
|
||||
|
||||
@ -470,11 +469,10 @@ class DocumentView(QWebView): # {{{
|
||||
magnification_changed = pyqtSignal(object)
|
||||
DISABLED_BRUSH = QBrush(Qt.lightGray, Qt.Dense5Pattern)
|
||||
|
||||
def __init__(self, *args):
|
||||
QWebView.__init__(self, *args)
|
||||
def initialize_view(self, debug_javascript=False):
|
||||
self.flipper = SlideFlip(self)
|
||||
self.is_auto_repeat_event = False
|
||||
self.debug_javascript = False
|
||||
self.debug_javascript = debug_javascript
|
||||
self.shortcuts = Shortcuts(SHORTCUTS, 'shortcuts/viewer')
|
||||
self.self_closing_pat = re.compile(r'<([a-z1-6]+)\s+([^>]+)/>',
|
||||
re.IGNORECASE)
|
||||
@ -483,7 +481,8 @@ class DocumentView(QWebView): # {{{
|
||||
self.initial_pos = 0.0
|
||||
self.to_bottom = False
|
||||
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.manager = None
|
||||
self._reference_mode = False
|
||||
|
@ -39,14 +39,14 @@ class JavaScriptLoader(object):
|
||||
self._cache = {}
|
||||
self._hp_cache = {}
|
||||
|
||||
def __getattr__(self, name):
|
||||
def get(self, name):
|
||||
ans = self._cache.get(name, None)
|
||||
if ans is None:
|
||||
src = self.CS.get(name, None)
|
||||
if src is None:
|
||||
src = self.JS.get(name, None)
|
||||
if src is None:
|
||||
raise AttributeError('No such resource: %s'%name)
|
||||
raise KeyError('No such resource: %s'%name)
|
||||
ans = P(src, data=True,
|
||||
allow_user_override=False).decode('utf-8')
|
||||
else:
|
||||
@ -70,7 +70,7 @@ class JavaScriptLoader(object):
|
||||
|
||||
def __call__(self, evaljs, lang, default_lang):
|
||||
for x in self.ORDER:
|
||||
src = getattr(self, x)
|
||||
src = self.get(x)
|
||||
evaljs(src)
|
||||
|
||||
def lang_name(l):
|
||||
|
@ -175,6 +175,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
def __init__(self, pathtoebook=None, debug_javascript=False, open_at=None):
|
||||
MainWindow.__init__(self, None)
|
||||
self.setupUi(self)
|
||||
self.view.initialize_view(debug_javascript)
|
||||
self.view.magnification_changed.connect(self.magnification_changed)
|
||||
self.show_toc_on_open = False
|
||||
self.current_book_has_toc = False
|
||||
@ -215,7 +216,6 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
self.search.setMinimumWidth(200)
|
||||
self.tool_bar2.insertWidget(self.action_find_next, self.search)
|
||||
self.view.set_manager(self)
|
||||
self.view.document.debug_javascript = debug_javascript
|
||||
self.pi = ProgressIndicator(self)
|
||||
self.toc.setVisible(False)
|
||||
self.action_quit = QAction(self)
|
||||
|
Loading…
x
Reference in New Issue
Block a user