Merge from custcol trunk

This commit is contained in:
Charles Haley 2010-05-11 04:47:22 +01:00
commit 866fda04fe
18 changed files with 260 additions and 25 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1003 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 475 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

View File

@ -0,0 +1,31 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
'''
www.aif.ru
'''
from calibre.web.feeds.news import BasicNewsRecipe
class AIF_ru(BasicNewsRecipe):
title = 'Arguments & Facts - Russian'
__author__ = 'Darko Miletic'
description = 'News from Russia'
publisher = 'AIF'
category = 'news, politics, Russia'
oldest_article = 2
max_articles_per_feed = 100
no_stylesheets = True
use_embedded_content = False
encoding = 'cp1251'
language = 'ru'
publication_type = 'magazine'
extra_css = ' @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: Verdana,Arial,Helvetica,sans1,sans-serif} '
keep_only_tags = [dict(name='div',attrs={'id':'inner'})]
remove_tags = [
dict(name=['iframe','object','link','base','input','img'])
,dict(name='div',attrs={'class':'photo'})
,dict(name='p',attrs={'class':'resizefont'})
]
feeds = [(u'News', u'http://www.aif.ru/rss/all.php')]

View File

@ -0,0 +1,28 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
'''
izvestia.ru
'''
from calibre.web.feeds.news import BasicNewsRecipe
class Izvestia(BasicNewsRecipe):
title = 'Izvestia'
__author__ = 'Darko Miletic'
description = 'News from Russia'
publisher = 'Izvestia'
category = 'news, politics, Russia'
oldest_article = 5
max_articles_per_feed = 100
no_stylesheets = True
use_embedded_content = False
encoding = 'cp1251'
language = 'ru'
publication_type = 'newspaper'
masthead_url = 'http://images.izvestia.ru/izv/sys/logo.gif'
extra_css = ' @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: Verdana,Arial,Helvetica,sans1,sans-serif} '
keep_only_tags = [dict(name='div', attrs={'class':'newsFull'})]
remove_tags = [dict(name=['iframe','object','img','link','base'])]
remove_tags_before = dict(name='h1', attrs={'class':'statya'})
feeds = [(u'Daily edition', u'http://rss.feedsportal.com/c/32171/f/424076/index.rss')]

View File

@ -0,0 +1,42 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
'''
www.kommersant.ru
'''
from calibre.web.feeds.news import BasicNewsRecipe
class Kommersant_ru(BasicNewsRecipe):
title = 'Kommersant'
__author__ = 'Darko Miletic'
description = 'News from Russia'
publisher = 'Kommersant'
category = 'news, politics, Russia'
oldest_article = 5
max_articles_per_feed = 100
no_stylesheets = True
use_embedded_content = False
encoding = 'cp1251'
language = 'ru'
publication_type = 'newspaper'
masthead_url = 'http://www.kommersant.ru/CorpPics/logo_daily_1.gif'
extra_css = ' @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: Arial, sans1, sans-serif} span#ctl00_ContentPlaceHolderStyle_LabelSubTitle{margin-bottom: 1em; display: block} .author{margin-bottom: 1em; display: block} .paragraph{margin-bottom: 1em; display: block} .vvodka{font-weight: bold; margin-bottom: 1em} '
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : language
}
keep_only_tags = [
dict(attrs={'id':'ctl00_ContentPlaceHolderStyle_PanelHeader'})
,dict(attrs={'class':['vvodka','paragraph','author']})
]
remove_tags = [dict(name=['iframe','object','link','img','base'])]
feeds = [(u'Articles', u'http://feeds.kommersant.ru/RSS_Export/RU/daily.xml')]
def print_version(self, url):
return url.replace('doc-rss.aspx','doc.aspx') + '&print=true'

View File

@ -0,0 +1,43 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
'''
www.rian.ru
'''
from calibre.web.feeds.news import BasicNewsRecipe
class RIANovosti(BasicNewsRecipe):
title = 'RIA Novosti - Russian'
__author__ = 'Darko Miletic'
description = 'News from Russia'
publisher = 'RIA'
category = 'news, politics, Russia'
oldest_article = 2
max_articles_per_feed = 100
no_stylesheets = True
use_embedded_content = False
encoding = 'utf8'
language = 'ru'
publication_type = 'newsportal'
masthead_url = 'http://img.beta.rian.ru/images/22868/43/228684314.jpg'
extra_css = ' @font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)} body{font-family: Arial,Helvetica,sans1,sans-serif} '
remove_tags_before = dict(name='h1')
remove_tags_after = dict(name='div', attrs={'class':'text'})
remove_tags = [dict(name=['iframe','object','link','img','base'])]
feeds = [
(u'Frontpage', u'http://www.rian.ru/export/rss2/lenta/index.xml')
,(u'Politics', u'http://www.rian.ru/export/rss2/politics/index.xml')
,(u'World', u'http://www.rian.ru/export/rss2/world/index.xml')
,(u'Economy', u'http://www.rian.ru/export/rss2/economy/index.xml')
,(u'Society', u'http://www.rian.ru/export/rss2/society/index.xml')
,(u'Moscow', u'http://www.rian.ru/export/rss2/moscow/index.xml')
,(u'Defense', u'http://www.rian.ru/export/rss2/defense_safety/index.xml')
,(u'Science', u'http://www.rian.ru/export/rss2/science/index.xml')
,(u'Turism', u'http://www.rian.ru/export/rss2/tourism/index.xml')
,(u'Culture', u'http://www.rian.ru/export/rss2/culture/index.xml')
]
def print_version(self, url):
return url.replace('.html','-print.html')

View File

@ -68,7 +68,7 @@ class PML2PMLZ(FileTypePlugin):
of = self.temporary_file('_plugin_pml2pmlz.pmlz') of = self.temporary_file('_plugin_pml2pmlz.pmlz')
pmlz = zipfile.ZipFile(of.name, 'w') pmlz = zipfile.ZipFile(of.name, 'w')
pmlz.write(pmlfile, os.path.basename(pmlfile)) pmlz.write(pmlfile, os.path.basename(pmlfile), zipfile.ZIP_DEFLATED)
pml_img = os.path.splitext(pmlfile)[0] + '_img' pml_img = os.path.splitext(pmlfile)[0] + '_img'
i_img = os.path.join(os.path.dirname(pmlfile),'images') i_img = os.path.join(os.path.dirname(pmlfile),'images')
@ -450,7 +450,7 @@ 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
from calibre.devices.binatone.driver import README from calibre.devices.binatone.driver import README
from calibre.devices.hanvon.driver import N516, EB511, ALEX from calibre.devices.hanvon.driver import N516, EB511, ALEX, AZBOOKA
from calibre.devices.edge.driver import EDGE from calibre.devices.edge.driver import EDGE
from calibre.devices.teclast.driver import TECLAST_K3 from calibre.devices.teclast.driver import TECLAST_K3
from calibre.devices.sne.driver import SNE from calibre.devices.sne.driver import SNE
@ -538,6 +538,7 @@ plugins += [
ALEX, ALEX,
PALMPRE, PALMPRE,
KOBO, KOBO,
AZBOOKA,
] ]
plugins += [x for x in list(locals().values()) if isinstance(x, type) and \ plugins += [x for x in list(locals().values()) if isinstance(x, type) and \
x.__name__.endswith('MetadataReader')] x.__name__.endswith('MetadataReader')]

View File

@ -27,7 +27,7 @@ class ANDROID(USBMS):
0x18d1 : { 0x4e11 : [0x0100, 0x226], 0x4e12: [0x0100, 0x226]}, 0x18d1 : { 0x4e11 : [0x0100, 0x226], 0x4e12: [0x0100, 0x226]},
# Samsung # Samsung
0x04e8 : { 0x681d : [0x0222], 0x681c : [0x0222]}, 0x04e8 : { 0x681d : [0x0222], 0x681c : [0x0222, 0x0224]},
# Acer # Acer
0x502 : { 0x3203 : [0x0100]}, 0x502 : { 0x3203 : [0x0100]},
@ -38,9 +38,9 @@ class ANDROID(USBMS):
'be used') 'be used')
EXTRA_CUSTOMIZATION_DEFAULT = ', '.join(EBOOK_DIR_MAIN) EXTRA_CUSTOMIZATION_DEFAULT = ', '.join(EBOOK_DIR_MAIN)
VENDOR_NAME = ['HTC', 'MOTOROLA', 'GOOGLE_', 'ANDROID', 'ACER'] VENDOR_NAME = ['HTC', 'MOTOROLA', 'GOOGLE_', 'ANDROID', 'ACER', 'GT-I5700']
WINDOWS_MAIN_MEM = ['ANDROID_PHONE', 'A855', 'A853', 'INC.NEXUS_ONE', WINDOWS_MAIN_MEM = ['ANDROID_PHONE', 'A855', 'A853', 'INC.NEXUS_ONE',
'__UMS_COMPOSITE', '_MB200', 'MASS_STORAGE'] '__UMS_COMPOSITE', '_MB200', 'MASS_STORAGE', '_-_CARD']
OSX_MAIN_MEM = 'HTC Android Phone Media' OSX_MAIN_MEM = 'HTC Android Phone Media'

View File

@ -50,6 +50,20 @@ class ALEX(N516):
EBOOK_DIR_MAIN = 'eBooks' EBOOK_DIR_MAIN = 'eBooks'
SUPPORTS_SUB_DIRS = True SUPPORTS_SUB_DIRS = True
class AZBOOKA(ALEX):
name = 'Azbooka driver'
gui_name = 'Azbooka'
description = _('Communicate with the Azbooka')
VENDOR_NAME = 'LINUX'
WINDOWS_MAIN_MEM = 'FILE-STOR_GADGET'
MAIN_MEMORY_VOLUME_LABEL = 'Azbooka Internal Memory'
EBOOK_DIR_MAIN = ''
class EB511(USBMS): class EB511(USBMS):
name = 'Elonex EB 511 driver' name = 'Elonex EB 511 driver'
gui_name = 'EB 511' gui_name = 'EB 511'

View File

@ -176,6 +176,9 @@ class Stylizer(object):
class_sel_pat = re.compile(r'\.[a-z]+', re.IGNORECASE) class_sel_pat = re.compile(r'\.[a-z]+', re.IGNORECASE)
capital_sel_pat = re.compile(r'h|[A-Z]+') capital_sel_pat = re.compile(r'h|[A-Z]+')
for _, _, cssdict, text, _ in rules: for _, _, cssdict, text, _ in rules:
fl = ':first-letter' in text
if fl:
text = text.replace(':first-letter', '')
try: try:
selector = CSSSelector(text) selector = CSSSelector(text)
except (AssertionError, ExpressionError, etree.XPathSyntaxError, except (AssertionError, ExpressionError, etree.XPathSyntaxError,
@ -202,6 +205,19 @@ class Stylizer(object):
if found: if found:
self.logger.warn('Ignoring case mismatches for CSS selector: %s in %s' self.logger.warn('Ignoring case mismatches for CSS selector: %s in %s'
%(text, item.href)) %(text, item.href))
if fl:
from lxml.builder import ElementMaker
E = ElementMaker(namespace=XHTML_NS)
for elem in matches:
for x in elem.iter():
if x.text:
span = E.span(x.text[0])
span.tail = x.text[1:]
x.text = None
x.insert(0, span)
self.style(span)._update_cssdict(cssdict)
break
else:
for elem in matches: for elem in matches:
self.style(elem)._update_cssdict(cssdict) self.style(elem)._update_cssdict(cssdict)
for elem in xpath(tree, '//h:img[@width or @height]'): for elem in xpath(tree, '//h:img[@width or @height]'):

View File

@ -384,25 +384,25 @@ class Document(QWebPage):
@property @property
def height(self): def height(self):
ans = self.javascript('document.body.offsetHeight', 'int') # contentsSize gives inaccurate results j = self.javascript('document.body.offsetHeight', 'int')
if ans == 0: q = self.mainFrame().contentsSize().height()
ans = self.mainFrame().contentsSize().height() if q == j:
return ans return j
if min(j, q) <= 0:
return max(j, q)
window_height = self.window_height
if j == window_height:
return j if q < 1.2*j else q
return j
@property @property
def width(self): def width(self):
return self.mainFrame().contentsSize().width() # offsetWidth gives inaccurate results return self.mainFrame().contentsSize().width() # offsetWidth gives inaccurate results
def set_bottom_padding(self, amount): def set_bottom_padding(self, amount):
body = self.mainFrame().documentElement().findFirst('body') s = QSize(-1, -1) if amount == 0 else QSize(self.width,
if body.isNull(): self.height+amount)
return self.setPreferredContentsSize(s)
old_padding = unicode(body.styleProperty('padding-bottom',
body.ComputedStyle)).strip()
padding = u'%dpx'%amount
if old_padding != padding:
body.setStyleProperty('padding-bottom', padding + ' !important')
class EntityDeclarationProcessor(object): class EntityDeclarationProcessor(object):
@ -705,13 +705,21 @@ class DocumentView(QWebView):
def next_page(self): def next_page(self):
window_height = self.document.window_height window_height = self.document.window_height
document_height = self.document.height
ddelta = document_height - window_height
#print '\nWindow height:', window_height
#print 'Document height:', self.document.height
delta_y = window_height - 25 delta_y = window_height - 25
if self.document.at_bottom: if self.document.at_bottom or ddelta <= 0:
if self.manager is not None: if self.manager is not None:
self.manager.next_document() self.manager.next_document()
elif ddelta < 25:
self.scroll_by(y=ddelta)
return
else: else:
oopos = self.document.ypos oopos = self.document.ypos
#print '\nOriginal position:', oopos #print 'Original position:', oopos
self.document.set_bottom_padding(0) self.document.set_bottom_padding(0)
opos = self.document.ypos opos = self.document.ypos
#print 'After set padding=0:', self.document.ypos #print 'After set padding=0:', self.document.ypos
@ -722,8 +730,14 @@ class DocumentView(QWebView):
lower_limit = opos + delta_y # Max value of top y co-ord after scrolling lower_limit = opos + delta_y # Max value of top y co-ord after scrolling
max_y = self.document.height - window_height # The maximum possible top y co-ord max_y = self.document.height - window_height # The maximum possible top y co-ord
if max_y < lower_limit: if max_y < lower_limit:
padding = lower_limit - max_y
if padding == window_height:
if self.manager is not None:
self.manager.next_document()
return
#print 'Setting padding to:', lower_limit - max_y #print 'Setting padding to:', lower_limit - max_y
self.document.set_bottom_padding(lower_limit - max_y) self.document.set_bottom_padding(lower_limit - max_y)
#print 'Document height:', self.document.height
max_y = self.document.height - window_height max_y = self.document.height - window_height
lower_limit = min(max_y, lower_limit) lower_limit = min(max_y, lower_limit)
#print 'Scroll to:', lower_limit #print 'Scroll to:', lower_limit

View File

@ -11,7 +11,7 @@
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Ebook Viewer</string> <string>E-book Viewer</string>
</property> </property>
<property name="windowIcon"> <property name="windowIcon">
<iconset resource="../../../../resources/images.qrc"> <iconset resource="../../../../resources/images.qrc">

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,37 @@
#!/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'
''' Design documentation {{{
Storage paradigm {{{
* Agnostic to storage paradigm (i.e. no book per folder assumptions)
* Two separate concepts: A store and collection
A store is a backend, like a sqlite database associated with a path on
the local filesystem, or a cloud based storage solution.
A collection is a user defined group of stores. Most of the logic for
data manipulation sorting/searching/restrictions should be in the collection
class. The collection class should transparently handle the
conversion from store name + id to row number in the collection.
* Not sure how feasible it is to allow many-many maps between stores
and collections.
}}}
Event system {{{
* Comprehensive event system that other components can subscribe to
* Subscribers should be able to temporarily block receiving events
* Should event dispatch be asynchronous?
* Track last modified time for metadata and each format
}}}
}}}'''
# Imports {{{
# }}}

View File

@ -313,7 +313,7 @@ class PostInstall:
with open(os.path.join(base, '95-calibre.rules'), 'wb') as udev: with open(os.path.join(base, '95-calibre.rules'), 'wb') as udev:
self.manifest.append(udev.name) self.manifest.append(udev.name)
udev.write('''# Sony Reader PRS-500\n''' udev.write('''# Sony Reader PRS-500\n'''
'''BUS=="usb", SYSFS{idProduct}=="029b", SYSFS{idVendor}=="054c", MODE="660", GROUP="%s"\n'''%(group,) '''SUBSYSTEMS=="usb", SYSFS{idProduct}=="029b", SYSFS{idVendor}=="054c", MODE="660", GROUP="%s"\n'''%(group,)
) )
except: except:
if self.opts.fatal_errors: if self.opts.fatal_errors:

View File

@ -152,7 +152,7 @@ Linux development environment
used in windows and OS X. Alternatively, you can install |app| from source. Instructions for setting up a development used in windows and OS X. Alternatively, you can install |app| from source. Instructions for setting up a development
environment from source are in the INSTALL file in the source tree. Here we will address using the binary a runtime. environment from source are in the INSTALL file in the source tree. Here we will address using the binary a runtime.
Install the |app| using the binary installer. The opena terminal and change to the previously checked out |app| code directory, for example:: Install the |app| using the binary installer. Then open a terminal and change to the previously checked out |app| code directory, for example::
cd /home/kovid/work/calibre cd /home/kovid/work/calibre