mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge from trunk
This commit is contained in:
commit
e8259478f3
@ -6,6 +6,7 @@ class Android_com_pl(BasicNewsRecipe):
|
||||
description = 'Android.com.pl - biggest polish Android site'
|
||||
category = 'Android, mobile'
|
||||
language = 'pl'
|
||||
use_embedded_content=True
|
||||
cover_url =u'http://upload.wikimedia.org/wikipedia/commons/thumb/d/d7/Android_robot.svg/220px-Android_robot.svg.png'
|
||||
oldest_article = 8
|
||||
max_articles_per_feed = 100
|
||||
|
@ -1,6 +1,6 @@
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008-2011, Darko Miletic <darko.miletic at gmail.com>'
|
||||
__copyright__ = '2008-2012, Darko Miletic <darko.miletic at gmail.com>'
|
||||
'''
|
||||
b92.net
|
||||
'''
|
||||
@ -20,13 +20,13 @@ class B92(BasicNewsRecipe):
|
||||
encoding = 'cp1250'
|
||||
language = 'sr'
|
||||
publication_type = 'newsportal'
|
||||
masthead_url = 'http://www.b92.net/images/fp/logo.gif'
|
||||
masthead_url = 'http://b92s.net/v4/img/new-logo.png'
|
||||
extra_css = """
|
||||
@font-face {font-family: "serif1";src:url(res:///opt/sony/ebook/FONT/tt0011m_.ttf)}
|
||||
@font-face {font-family: "sans1";src:url(res:///opt/sony/ebook/FONT/tt0003m_.ttf)}
|
||||
body{font-family: Arial,Helvetica,sans1,sans-serif}
|
||||
.articledescription{font-family: serif1, serif}
|
||||
.article-info2,.article-info1{text-transform: uppercase; font-size: small}
|
||||
img{display: block}
|
||||
.sms{font-weight: bold}
|
||||
"""
|
||||
|
||||
conversion_options = {
|
||||
@ -37,11 +37,17 @@ class B92(BasicNewsRecipe):
|
||||
, 'linearize_tables' : True
|
||||
}
|
||||
|
||||
preprocess_regexps = [(re.compile(u'\u0110'), lambda match: u'\u00D0')]
|
||||
preprocess_regexps = [
|
||||
(re.compile(u'\u0110'), lambda match: u'\u00D0'),
|
||||
(re.compile(r'<html.*?<body>', re.DOTALL|re.IGNORECASE), lambda match: '<html><head><title>something</title></head><body>')
|
||||
]
|
||||
|
||||
keep_only_tags = [dict(attrs={'class':['article-info1','article-text']})]
|
||||
remove_attributes = ['width','height','align','hspace','vspace','border']
|
||||
remove_tags = [dict(name=['embed','link','base','meta'])]
|
||||
remove_attributes = ['width','height','align','hspace','vspace','border','lang','xmlns:fb']
|
||||
remove_tags = [
|
||||
dict(name=['embed','link','base','meta','iframe'])
|
||||
,dict(attrs={'id':'social'})
|
||||
]
|
||||
|
||||
feeds = [
|
||||
(u'Vesti' , u'http://www.b92.net/info/rss/vesti.xml' )
|
||||
|
@ -1,4 +1,5 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup
|
||||
|
||||
class CGM(BasicNewsRecipe):
|
||||
title = u'CGM'
|
||||
@ -17,9 +18,9 @@ class CGM(BasicNewsRecipe):
|
||||
remove_tags_before=dict(id='mainContent')
|
||||
remove_tags_after=dict(name='div', attrs={'class':'fbContainer'})
|
||||
remove_tags=[dict(name='div', attrs={'class':'fbContainer'}),
|
||||
dict(name='p', attrs={'class':['tagCloud', 'galleryAuthor']}),
|
||||
dict(id=['movieShare', 'container'])]
|
||||
feeds = [(u'Informacje', u'http://www.cgm.pl/rss.xml'), (u'Polecamy', u'http://www.cgm.pl/rss,4,news.xml'),
|
||||
dict(name='p', attrs={'class':['tagCloud', 'galleryAuthor']}),
|
||||
dict(id=['movieShare', 'container'])]
|
||||
feeds = [(u'Informacje', u'http://www.cgm.pl/rss.xml'), (u'Polecamy', u'http://www.cgm.pl/rss,4,news.xml'),
|
||||
(u'Recenzje', u'http://www.cgm.pl/rss,1,news.xml')]
|
||||
|
||||
|
||||
@ -33,10 +34,12 @@ class CGM(BasicNewsRecipe):
|
||||
img='http://www.cgm.pl'+img[img.find('url(')+4:img.find(')')]
|
||||
gallery.contents[1].name='img'
|
||||
gallery.contents[1]['src']=img
|
||||
pos = len(gallery.contents)
|
||||
gallery.insert(pos, BeautifulSoup('<br />'))
|
||||
for item in soup.findAll(style=True):
|
||||
del item['style']
|
||||
ad=soup.findAll('a')
|
||||
for r in ad:
|
||||
if 'www.hustla.pl' in r['href'] or 'www.ebilet.pl' in r['href']:
|
||||
if 'www.hustla.pl' in r['href'] or 'www.ebilet.pl' in r['href']:
|
||||
r.extract()
|
||||
return soup
|
||||
return soup
|
||||
|
@ -1,4 +1,5 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
from calibre.ebooks.BeautifulSoup import BeautifulSoup
|
||||
|
||||
class Elektroda(BasicNewsRecipe):
|
||||
title = u'Elektroda'
|
||||
@ -13,3 +14,18 @@ class Elektroda(BasicNewsRecipe):
|
||||
remove_tags_after=dict(name='td', attrs={'class':'spaceRow'})
|
||||
remove_tags=[dict(name='a', attrs={'href':'#top'})]
|
||||
feeds = [(u'Elektroda', u'http://www.elektroda.pl/rtvforum/rss.php')]
|
||||
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
tag=soup.find('span', attrs={'class':'postbody'})
|
||||
if tag:
|
||||
pos = len(tag.contents)
|
||||
tag.insert(pos, BeautifulSoup('<br />'))
|
||||
return soup
|
||||
|
||||
def parse_feeds (self):
|
||||
feeds = BasicNewsRecipe.parse_feeds(self)
|
||||
for feed in feeds:
|
||||
for article in feed.articles[:]:
|
||||
article.title=article.title[article.title.find("::")+3:]
|
||||
return feeds
|
||||
|
@ -13,7 +13,7 @@ class Filmweb_pl(BasicNewsRecipe):
|
||||
remove_empty_feeds=True
|
||||
extra_css = '.hdrBig {font-size:22px;} ul {list-style-type:none; padding: 0; margin: 0;}'
|
||||
remove_tags= [dict(name='div', attrs={'class':['recommendOthers']}), dict(name='ul', attrs={'class':'fontSizeSet'})]
|
||||
keep_only_tags= [dict(name='h1', attrs={'class':'hdrBig'}), dict(name='div', attrs={'class':['newsInfo', 'reviewContent fontSizeCont description']})]
|
||||
keep_only_tags= [dict(name='h1', attrs={'class':['hdrBig', 'hdrEntity']}), dict(name='div', attrs={'class':['newsInfo', 'newsInfoSmall', 'reviewContent description']})]
|
||||
feeds = [(u'Wszystkie newsy', u'http://www.filmweb.pl/feed/news/latest'),
|
||||
(u'News / Filmy w produkcji', 'http://www.filmweb.pl/feed/news/category/filminproduction'),
|
||||
(u'News / Festiwale, nagrody i przeglądy', u'http://www.filmweb.pl/feed/news/category/festival'),
|
||||
|
@ -9,12 +9,12 @@ class Gram_pl(BasicNewsRecipe):
|
||||
oldest_article = 8
|
||||
max_articles_per_feed = 100
|
||||
no_stylesheets= True
|
||||
extra_css = 'h2 {font-style: italic; font-size:20px;}'
|
||||
extra_css = 'h2 {font-style: italic; font-size:20px;} .picbox div {float: left;}'
|
||||
cover_url=u'http://www.gram.pl/www/01/img/grampl_zima.png'
|
||||
remove_tags= [dict(name='p', attrs={'class':['extraText', 'must-log-in']}), dict(attrs={'class':['el', 'headline', 'post-info']}), dict(name='div', attrs={'class':['twojaOcena', 'comment-body', 'comment-author vcard', 'comment-meta commentmetadata', 'tw_button']}), dict(id=['igit_rpwt_css', 'comments', 'reply-title', 'igit_title'])]
|
||||
keep_only_tags= [dict(name='div', attrs={'class':['main', 'arkh-postmetadataheader', 'arkh-postcontent', 'post', 'content', 'news_header', 'news_subheader', 'news_text']}), dict(attrs={'class':['contentheading', 'contentpaneopen']})]
|
||||
feeds = [(u'gram.pl - informacje', u'http://www.gram.pl/feed_news.asp'),
|
||||
(u'gram.pl - publikacje', u'http://www.gram.pl/feed_news.asp?type=articles')]
|
||||
feeds = [(u'Informacje', u'http://www.gram.pl/feed_news.asp'),
|
||||
(u'Publikacje', u'http://www.gram.pl/feed_news.asp?type=articles')]
|
||||
|
||||
def parse_feeds (self):
|
||||
feeds = BasicNewsRecipe.parse_feeds(self)
|
||||
@ -23,3 +23,33 @@ class Gram_pl(BasicNewsRecipe):
|
||||
if 'REKLAMA SKLEP' in article.title.upper() or u'ARTYKUŁ:' in article.title.upper():
|
||||
feed.articles.remove(article)
|
||||
return feeds
|
||||
|
||||
def append_page(self, soup, appendtag):
|
||||
nexturl = appendtag.find('a', attrs={'class':'cpn'})
|
||||
while nexturl:
|
||||
soup2 = self.index_to_soup('http://www.gram.pl'+ nexturl['href'])
|
||||
r=appendtag.find(id='pgbox')
|
||||
if r:
|
||||
r.extract()
|
||||
pagetext = soup2.find(attrs={'class':'main'})
|
||||
r=pagetext.find('h1')
|
||||
if r:
|
||||
r.extract()
|
||||
r=pagetext.find('h2')
|
||||
if r:
|
||||
r.extract()
|
||||
for r in pagetext.findAll('script'):
|
||||
r.extract()
|
||||
pos = len(appendtag.contents)
|
||||
appendtag.insert(pos, pagetext)
|
||||
nexturl = appendtag.find('a', attrs={'class':'cpn'})
|
||||
r=appendtag.find(id='pgbox')
|
||||
if r:
|
||||
r.extract()
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
self.append_page(soup, soup.body)
|
||||
tag=soup.findAll(name='div', attrs={'class':'picbox'})
|
||||
for t in tag:
|
||||
t['style']='float: left;'
|
||||
return soup
|
Binary file not shown.
Before Width: | Height: | Size: 413 B After Width: | Height: | Size: 1.5 KiB |
@ -7,12 +7,12 @@ class naczytniki(BasicNewsRecipe):
|
||||
cover_url = 'http://naczytniki.pl/wp-content/uploads/2010/08/logo_nc28.png'
|
||||
language = 'pl'
|
||||
description ='everything about e-readers'
|
||||
category='readers'
|
||||
category='e-readers'
|
||||
no_stylesheets=True
|
||||
use_embedded_content=False
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
preprocess_regexps = [(re.compile(ur'<p><br><b>Zobacz także:</b></p>.*?</body>', re.DOTALL), lambda match: '</body>') ]
|
||||
remove_tags_after= dict(name='div', attrs={'class':'sociable'})
|
||||
keep_only_tags=[dict(name='div', attrs={'class':'post'})]
|
||||
remove_tags=[dict(name='span', attrs={'class':'comments'}), dict(name='div', attrs={'class':'sociable'})]
|
||||
feeds = [(u'Wpisy', u'http://naczytniki.pl/?feed=rss2')]
|
||||
feeds = [(u'Wpisy', u'http://naczytniki.pl/?feed=rss2')]
|
@ -17,21 +17,8 @@ class Overclock_pl(BasicNewsRecipe):
|
||||
remove_tags=[dict(name='span', attrs={'class':'info'}), dict(attrs={'class':'shareit'})]
|
||||
feeds = [(u'Aktualno\u015bci', u'http://www.overclock.pl/rss.news.xml'), (u'Testy i recenzje', u'http://www.overclock.pl/rss.articles.xml')]
|
||||
|
||||
|
||||
def append_page(self, soup, appendtag):
|
||||
tag=soup.find(id='navigation')
|
||||
if tag:
|
||||
nexturl=tag.findAll('option')
|
||||
tag.extract()
|
||||
for nextpage in nexturl[2:]:
|
||||
soup2 = self.index_to_soup(nextpage['value'])
|
||||
pagetext = soup2.find(id='content')
|
||||
pos = len(appendtag.contents)
|
||||
appendtag.insert(pos, pagetext)
|
||||
rem=appendtag.find(attrs={'alt':'Pierwsza'})
|
||||
if rem:
|
||||
rem.parent.extract()
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
self.append_page(soup, soup.body)
|
||||
return soup
|
||||
def print_version(self, url):
|
||||
if 'articles/show' in url:
|
||||
return url.replace('show', 'showall')
|
||||
else:
|
||||
return url
|
@ -10,5 +10,7 @@ class palmtop_pl(BasicNewsRecipe):
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
no_stylesheets = True
|
||||
|
||||
use_embedded_content=True
|
||||
#remove_tags_before=dict(name='h2')
|
||||
#remove_tags_after=dict(attrs={'class':'entry clearfix'})
|
||||
feeds = [(u'Newsy', u'http://palmtop.pl/feed/atom/')]
|
||||
|
@ -1,31 +1,25 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
class PC_Arena(BasicNewsRecipe):
|
||||
title = u'PCArena'
|
||||
oldest_article = 18300
|
||||
oldest_article = 7
|
||||
max_articles_per_feed = 100
|
||||
__author__ = 'fenuks'
|
||||
description = u'Najnowsze informacje z branży IT - testy, recenzje, aktualności, rankingi, wywiady. Twoje źródło informacji o sprzęcie komputerowym.'
|
||||
category = 'IT'
|
||||
language = 'pl'
|
||||
masthead_url='http://pcarena.pl/public/design/frontend/images/logo.gif'
|
||||
cover_url= 'http://pcarena.pl/public/design/frontend/images/logo.gif'
|
||||
masthead_url='http://pcarena.pl/pcarena/img/logo.png'
|
||||
cover_url= 'http://pcarena.pl/pcarena/img/logo.png'
|
||||
no_stylesheets = True
|
||||
keep_only_tags=[dict(attrs={'class':['artHeader', 'art']})]
|
||||
remove_tags=[dict(attrs={'class':'pages'})]
|
||||
feeds = [(u'Newsy', u'http://pcarena.pl/misc/rss/news'), (u'Artyku\u0142y', u'http://pcarena.pl/misc/rss/articles')]
|
||||
remove_empty_feeds=True
|
||||
#keep_only_tags=[dict(attrs={'class':['artHeader', 'art']})]
|
||||
#remove_tags=[dict(attrs={'class':'pages'})]
|
||||
feeds = [(u'Aktualności', u'http://pcarena.pl/aktualnosci/feeds.rss'), (u'Testy', u'http://pcarena.pl/testy/feeds.rss'), (u'Software', u'http://pcarena.pl/oprogramowanie/feeds.rss'), (u'Poradniki', u'http://pcarena.pl/poradniki/feeds.rss'), (u'Mobile', u'http://pcarena.pl/mobile/feeds.rss')]
|
||||
|
||||
def print_version(self, url):
|
||||
return url.replace('show', 'print')
|
||||
|
||||
def append_page(self, soup, appendtag):
|
||||
tag=soup.find(name='div', attrs={'class':'pagNum'})
|
||||
if tag:
|
||||
nexturl=tag.findAll('a')
|
||||
tag.extract()
|
||||
for nextpage in nexturl[1:]:
|
||||
nextpage= 'http://pcarena.pl' + nextpage['href']
|
||||
soup2 = self.index_to_soup(nextpage)
|
||||
pagetext = soup2.find(attrs={'class':'artBody'})
|
||||
pos = len(appendtag.contents)
|
||||
appendtag.insert(pos, pagetext)
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
self.append_page(soup, soup.body)
|
||||
return soup
|
||||
def image_url_processor(self, baseurl, url):
|
||||
if 'http' not in url:
|
||||
return 'http://pcarena.pl' + url
|
||||
else:
|
||||
return url
|
@ -10,32 +10,11 @@ class PC_Centre(BasicNewsRecipe):
|
||||
masthead_url= 'http://pccentre.pl/views/images/logo.gif'
|
||||
cover_url= 'http://pccentre.pl/views/images/logo.gif'
|
||||
no_stylesheets = True
|
||||
keep_only_tags= [dict(id='content')]
|
||||
remove_tags=[dict(attrs={'class':['ikony r', 'list_of_content', 'dot accordion']}), dict(id='comments')]
|
||||
feeds = [(u'Publikacje', u'http://pccentre.pl/backend.php?mode=a'), (u'Aktualno\u015bci', u'http://pccentre.pl/backend.php'), (u'Sprz\u0119t komputerowy', u'http://pccentre.pl/backend.php?mode=n§ion=2'), (u'Oprogramowanie', u'http://pccentre.pl/backend.php?mode=n§ion=3'), (u'Gry komputerowe i konsole', u'http://pccentre.pl/backend.php?mode=n§ion=4'), (u'Internet', u'http://pccentre.pl/backend.php?mode=n§ion=7'), (u'Bezpiecze\u0144stwo', u'http://pccentre.pl/backend.php?mode=n§ion=5'), (u'Multimedia', u'http://pccentre.pl/backend.php?mode=n§ion=6'), (u'Biznes', u'http://pccentre.pl/backend.php?mode=n§ion=9')]
|
||||
remove_empty_feeds = True
|
||||
#keep_only_tags= [dict(id='content')]
|
||||
#remove_tags=[dict(attrs={'class':['ikony r', 'list_of_content', 'dot accordion']}), dict(id='comments')]
|
||||
remove_tags=[dict(attrs={'class':'logo_print'})]
|
||||
feeds = [(u'Aktualno\u015bci', u'http://pccentre.pl/backend.php'), (u'Publikacje', u'http://pccentre.pl/backend.php?mode=a'), (u'Sprz\u0119t komputerowy', u'http://pccentre.pl/backend.php?mode=n§ion=2'), (u'Oprogramowanie', u'http://pccentre.pl/backend.php?mode=n§ion=3'), (u'Gry komputerowe i konsole', u'http://pccentre.pl/backend.php?mode=n§ion=4'), (u'Internet', u'http://pccentre.pl/backend.php?mode=n§ion=7'), (u'Bezpiecze\u0144stwo', u'http://pccentre.pl/backend.php?mode=n§ion=5'), (u'Multimedia', u'http://pccentre.pl/backend.php?mode=n§ion=6'), (u'Biznes', u'http://pccentre.pl/backend.php?mode=n§ion=9')]
|
||||
|
||||
|
||||
def append_page(self, soup, appendtag):
|
||||
tag=soup.find(name='div', attrs={'class':'pages'})
|
||||
if tag:
|
||||
nexturl=tag.findAll('a')
|
||||
tag.extract()
|
||||
for nextpage in nexturl[:-1]:
|
||||
nextpage= 'http://pccentre.pl' + nextpage['href']
|
||||
soup2 = self.index_to_soup(nextpage)
|
||||
pagetext = soup2.find(id='content')
|
||||
rem=pagetext.findAll(attrs={'class':['subtitle', 'content_info', 'list_of_content', 'pages', 'social2', 'pcc_acc', 'pcc_acc_na']})
|
||||
for r in rem:
|
||||
r.extract()
|
||||
rem=pagetext.findAll(id='comments')
|
||||
for r in rem:
|
||||
r.extract()
|
||||
rem=pagetext.findAll('h1')
|
||||
for r in rem:
|
||||
r.extract()
|
||||
pos = len(appendtag.contents)
|
||||
appendtag.insert(pos, pagetext)
|
||||
|
||||
def preprocess_html(self, soup):
|
||||
self.append_page(soup, soup.body)
|
||||
return soup
|
||||
def print_version(self, url):
|
||||
return url.replace('show', 'print')
|
@ -8,10 +8,11 @@ class Tablety_pl(BasicNewsRecipe):
|
||||
cover_url = 'http://www.tablety.pl/wp-content/themes/kolektyw/img/logo.png'
|
||||
category = 'IT'
|
||||
language = 'pl'
|
||||
use_embedded_content=True
|
||||
oldest_article = 8
|
||||
max_articles_per_feed = 100
|
||||
preprocess_regexps = [(re.compile(ur'<p><strong>Przeczytaj także.*?</a></strong></p>', re.DOTALL), lambda match: ''), (re.compile(ur'<p><strong>Przeczytaj koniecznie.*?</a></strong></p>', re.DOTALL), lambda match: '')]
|
||||
remove_tags_before=dict(name="h1", attrs={'class':'entry-title'})
|
||||
remove_tags_after=dict(name="div", attrs={'class':'snap_nopreview sharing robots-nocontent'})
|
||||
remove_tags=[dict(name='div', attrs={'class':'snap_nopreview sharing robots-nocontent'})]
|
||||
#remove_tags_before=dict(name="h1", attrs={'class':'entry-title'})
|
||||
#remove_tags_after=dict(name="footer", attrs={'class':'entry-footer clearfix'})
|
||||
#remove_tags=[dict(name='footer', attrs={'class':'entry-footer clearfix'}), dict(name='div', attrs={'class':'entry-comment-counter'})]
|
||||
feeds = [(u'Najnowsze posty', u'http://www.tablety.pl/feed/')]
|
||||
|
@ -1,5 +1,5 @@
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
import re
|
||||
|
||||
class AdvancedUserRecipe1312886443(BasicNewsRecipe):
|
||||
title = u'WNP'
|
||||
@ -8,10 +8,11 @@ class AdvancedUserRecipe1312886443(BasicNewsRecipe):
|
||||
description = u'Wirtualny Nowy Przemysł'
|
||||
category = 'economy'
|
||||
language = 'pl'
|
||||
preprocess_regexps = [(re.compile(ur'Czytaj też:.*?</a>', re.DOTALL), lambda match: ''), (re.compile(ur'Czytaj więcej:.*?</a>', re.DOTALL), lambda match: '')]
|
||||
oldest_article = 8
|
||||
max_articles_per_feed = 100
|
||||
no_stylesheets= True
|
||||
keep_only_tags = dict(name='div', attrs={'id':'contentText'})
|
||||
remove_tags=[dict(attrs={'class':'printF'})]
|
||||
feeds = [(u'Wiadomości gospodarcze', u'http://www.wnp.pl/rss/serwis_rss.xml'),
|
||||
(u'Serwis Energetyka - Gaz', u'http://www.wnp.pl/rss/serwis_rss_1.xml'),
|
||||
(u'Serwis Nafta - Chemia', u'http://www.wnp.pl/rss/serwis_rss_2.xml'),
|
||||
@ -19,3 +20,7 @@ class AdvancedUserRecipe1312886443(BasicNewsRecipe):
|
||||
(u'Serwis Górnictwo', u'http://www.wnp.pl/rss/serwis_rss_4.xml'),
|
||||
(u'Serwis Logistyka', u'http://www.wnp.pl/rss/serwis_rss_5.xml'),
|
||||
(u'Serwis IT', u'http://www.wnp.pl/rss/serwis_rss_6.xml')]
|
||||
|
||||
|
||||
def print_version(self, url):
|
||||
return 'http://wnp.pl/drukuj/' +url[url.find(',')+1:]
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1538,6 +1538,7 @@ class StoreWaterstonesUKStore(StoreBase):
|
||||
|
||||
headquarters = 'UK'
|
||||
formats = ['EPUB', 'PDF']
|
||||
affiliate = True
|
||||
|
||||
class StoreWeightlessBooksStore(StoreBase):
|
||||
name = 'Weightless Books'
|
||||
@ -1557,15 +1558,6 @@ class StoreWHSmithUKStore(StoreBase):
|
||||
headquarters = 'UK'
|
||||
formats = ['EPUB', 'PDF']
|
||||
|
||||
class StoreWizardsTowerBooksStore(StoreBase):
|
||||
name = 'Wizards Tower Books'
|
||||
description = u'A science fiction and fantasy publisher. Concentrates mainly on making out-of-print works available once more as e-books, and helping other small presses exploit the e-book market. Also publishes a small number of limited-print-run anthologies with a view to encouraging diversity in the science fiction and fantasy field.'
|
||||
actual_plugin = 'calibre.gui2.store.stores.wizards_tower_books_plugin:WizardsTowerBooksStore'
|
||||
|
||||
drm_free_only = True
|
||||
headquarters = 'UK'
|
||||
formats = ['EPUB', 'MOBI']
|
||||
|
||||
class StoreWoblinkStore(StoreBase):
|
||||
name = 'Woblink'
|
||||
author = u'Tomasz Długosz'
|
||||
@ -1573,7 +1565,7 @@ class StoreWoblinkStore(StoreBase):
|
||||
actual_plugin = 'calibre.gui2.store.stores.woblink_plugin:WoblinkStore'
|
||||
|
||||
headquarters = 'PL'
|
||||
formats = ['EPUB', 'PDF', 'WOBLINK']
|
||||
formats = ['EPUB', 'MOBI', 'PDF', 'WOBLINK']
|
||||
|
||||
class XinXiiStore(StoreBase):
|
||||
name = 'XinXii'
|
||||
@ -1636,7 +1628,6 @@ plugins += [
|
||||
StoreWaterstonesUKStore,
|
||||
StoreWeightlessBooksStore,
|
||||
StoreWHSmithUKStore,
|
||||
StoreWizardsTowerBooksStore,
|
||||
StoreWoblinkStore,
|
||||
XinXiiStore,
|
||||
StoreZixoStore
|
||||
|
@ -13,7 +13,8 @@ from contextlib import closing
|
||||
from PyQt4.Qt import QToolButton
|
||||
|
||||
from calibre.gui2.actions import InterfaceAction
|
||||
from calibre.gui2 import error_dialog, Dispatcher, warning_dialog, gprefs
|
||||
from calibre.gui2 import (error_dialog, Dispatcher, warning_dialog, gprefs,
|
||||
info_dialog)
|
||||
from calibre.gui2.dialogs.progress import ProgressDialog
|
||||
from calibre.utils.config import prefs, tweaks
|
||||
from calibre.utils.date import now
|
||||
@ -30,6 +31,7 @@ class Worker(Thread): # {{{
|
||||
self.progress = progress
|
||||
self.done = done
|
||||
self.delete_after = delete_after
|
||||
self.auto_merged_ids = {}
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
@ -79,6 +81,8 @@ class Worker(Thread): # {{{
|
||||
if prefs['add_formats_to_existing']:
|
||||
identical_book_list = newdb.find_identical_books(mi)
|
||||
if identical_book_list: # books with same author and nearly same title exist in newdb
|
||||
self.auto_merged_ids[x] = _('%s by %s')%(mi.title,
|
||||
mi.format_field('authors')[1])
|
||||
automerged = True
|
||||
seen_fmts = set()
|
||||
for identical_book in identical_book_list:
|
||||
@ -196,6 +200,15 @@ class CopyToLibraryAction(InterfaceAction):
|
||||
self.gui.status_bar.show_message(
|
||||
_('Copied %(num)d books to %(loc)s') %
|
||||
dict(num=len(ids), loc=loc), 2000)
|
||||
if self.worker.auto_merged_ids:
|
||||
books = '\n'.join(self.worker.auto_merged_ids.itervalues())
|
||||
info_dialog(self.gui, _('Auto merged'),
|
||||
_('Some books were automatically merged into existing '
|
||||
'records in the target library. Click Show '
|
||||
'details to see which ones. This behavior is '
|
||||
'controlled by the Auto merge option in '
|
||||
'Preferences->Adding books.'), det_msg=books,
|
||||
show=True)
|
||||
if delete_after and self.worker.processed:
|
||||
v = self.gui.library_view
|
||||
ci = v.currentIndex()
|
||||
|
@ -5,4 +5,3 @@ or asked not to be included in the store integration.
|
||||
* Indigo (http://www.chapters.indigo.ca/).
|
||||
* Libraria Rizzoli (http://libreriarizzoli.corriere.it/).
|
||||
* EPubBuy DE: reason: too much traffic for too little sales
|
||||
* Empik (http://empik.com.pl).
|
||||
|
@ -41,7 +41,9 @@ class AmazonDEKindleStore(StorePlugin):
|
||||
|
||||
counter = max_results
|
||||
with closing(br.open(url, timeout=timeout)) as f:
|
||||
doc = html.fromstring(f.read().decode('latin-1', 'replace'))
|
||||
# doc = html.fromstring(f.read().decode('latin-1', 'replace'))
|
||||
# Apparently amazon Europe is responding in UTF-8 now
|
||||
doc = html.fromstring(f.read())
|
||||
|
||||
data_xpath = '//div[contains(@class, "result") and contains(@class, "product")]'
|
||||
format_xpath = './/span[@class="format"]/text()'
|
||||
@ -65,8 +67,8 @@ class AmazonDEKindleStore(StorePlugin):
|
||||
|
||||
cover_url = ''.join(data.xpath(cover_xpath))
|
||||
|
||||
title = ''.join(data.xpath('.//div[@class="title"]/a/text()'))
|
||||
price = ''.join(data.xpath('.//div[@class="newPrice"]/span/text()'))
|
||||
title = ''.join(data.xpath('.//a[@class="title"]/text()'))
|
||||
price = ''.join(data.xpath('.//span[@class="price"]/text()'))
|
||||
|
||||
author = ''.join(data.xpath('.//div[@class="title"]/span[@class="ptBrand"]/text()'))
|
||||
if author.startswith('von '):
|
||||
|
@ -37,7 +37,9 @@ class AmazonESKindleStore(StorePlugin):
|
||||
|
||||
counter = max_results
|
||||
with closing(br.open(url, timeout=timeout)) as f:
|
||||
doc = html.fromstring(f.read().decode('latin-1', 'replace'))
|
||||
# doc = html.fromstring(f.read().decode('latin-1', 'replace'))
|
||||
# Apparently amazon Europe is responding in UTF-8 now
|
||||
doc = html.fromstring(f.read())
|
||||
|
||||
data_xpath = '//div[contains(@class, "result") and contains(@class, "product")]'
|
||||
format_xpath = './/span[@class="format"]/text()'
|
||||
@ -61,8 +63,8 @@ class AmazonESKindleStore(StorePlugin):
|
||||
|
||||
cover_url = ''.join(data.xpath(cover_xpath))
|
||||
|
||||
title = ''.join(data.xpath('.//div[@class="title"]/a/text()'))
|
||||
price = ''.join(data.xpath('.//div[@class="newPrice"]/span/text()'))
|
||||
title = ''.join(data.xpath('.//a[@class="title"]/text()'))
|
||||
price = ''.join(data.xpath('.//span[@class="price"]/text()'))
|
||||
author = unicode(''.join(data.xpath('.//div[@class="title"]/span[@class="ptBrand"]/text()')))
|
||||
if author.startswith('de '):
|
||||
author = author[3:]
|
||||
|
@ -39,7 +39,7 @@ class AmazonFRKindleStore(StorePlugin):
|
||||
counter = max_results
|
||||
with closing(br.open(url, timeout=timeout)) as f:
|
||||
# doc = html.fromstring(f.read().decode('latin-1', 'replace'))
|
||||
# Apparently amazon.fr is responding in UTF-8 now
|
||||
# Apparently amazon Europe is responding in UTF-8 now
|
||||
doc = html.fromstring(f.read())
|
||||
|
||||
data_xpath = '//div[contains(@class, "result") and contains(@class, "product")]'
|
||||
@ -64,8 +64,8 @@ class AmazonFRKindleStore(StorePlugin):
|
||||
|
||||
cover_url = ''.join(data.xpath(cover_xpath))
|
||||
|
||||
title = ''.join(data.xpath('.//div[@class="title"]/a/text()'))
|
||||
price = ''.join(data.xpath('.//div[@class="newPrice"]/span/text()'))
|
||||
title = ''.join(data.xpath('.//a[@class="title"]/text()'))
|
||||
price = ''.join(data.xpath('.//span[@class="price"]/text()'))
|
||||
author = unicode(''.join(data.xpath('.//div[@class="title"]/span[@class="ptBrand"]/text()')))
|
||||
if author.startswith('de '):
|
||||
author = author[3:]
|
||||
|
@ -37,7 +37,9 @@ class AmazonITKindleStore(StorePlugin):
|
||||
|
||||
counter = max_results
|
||||
with closing(br.open(url, timeout=timeout)) as f:
|
||||
doc = html.fromstring(f.read().decode('latin-1', 'replace'))
|
||||
# doc = html.fromstring(f.read().decode('latin-1', 'replace'))
|
||||
# Apparently amazon Europe is responding in UTF-8 now
|
||||
doc = html.fromstring(f.read())
|
||||
|
||||
data_xpath = '//div[contains(@class, "result") and contains(@class, "product")]'
|
||||
format_xpath = './/span[@class="format"]/text()'
|
||||
@ -61,8 +63,8 @@ class AmazonITKindleStore(StorePlugin):
|
||||
|
||||
cover_url = ''.join(data.xpath(cover_xpath))
|
||||
|
||||
title = ''.join(data.xpath('.//div[@class="title"]/a/text()'))
|
||||
price = ''.join(data.xpath('.//div[@class="newPrice"]/span/text()'))
|
||||
title = ''.join(data.xpath('.//a[@class="title"]/text()'))
|
||||
price = ''.join(data.xpath('.//span[@class="price"]/text()'))
|
||||
author = unicode(''.join(data.xpath('.//div[@class="title"]/span[@class="ptBrand"]/text()')))
|
||||
if author.startswith('di '):
|
||||
author = author[3:]
|
||||
|
@ -38,7 +38,8 @@ class AmazonUKKindleStore(StorePlugin):
|
||||
|
||||
counter = max_results
|
||||
with closing(br.open(url, timeout=timeout)) as f:
|
||||
doc = html.fromstring(f.read().decode('latin-1', 'replace'))
|
||||
# Apparently amazon Europe is responding in UTF-8 now
|
||||
doc = html.fromstring(f.read())
|
||||
|
||||
data_xpath = '//div[contains(@class, "result") and contains(@class, "product")]'
|
||||
format_xpath = './/span[@class="format"]/text()'
|
||||
@ -62,8 +63,8 @@ class AmazonUKKindleStore(StorePlugin):
|
||||
|
||||
cover_url = ''.join(data.xpath(cover_xpath))
|
||||
|
||||
title = ''.join(data.xpath('.//div[@class="title"]/a/text()'))
|
||||
price = ''.join(data.xpath('.//div[@class="newPrice"]/span/text()'))
|
||||
title = ''.join(data.xpath('.//a[@class="title"]/text()'))
|
||||
price = ''.join(data.xpath('.//span[@class="price"]/text()'))
|
||||
|
||||
author = ''.join(data.xpath('.//div[@class="title"]/span[@class="ptBrand"]/text()'))
|
||||
if author.startswith('by '):
|
||||
|
@ -62,7 +62,7 @@ class BNStore(BasicStoreConfig, StorePlugin):
|
||||
|
||||
title = ''.join(data.xpath('.//p[@class="title"]//span[@class="name"]/text()'))
|
||||
author = ', '.join(data.xpath('.//ul[@class="contributors"]//li[position()>1]//a/text()'))
|
||||
price = ''.join(data.xpath('.//table[@class="displayed-formats"]//a[@class="subtle"]/text()'))
|
||||
price = ''.join(data.xpath('.//table[@class="displayed-formats"]//a[contains(@class, "bn-price")]/text()'))
|
||||
|
||||
counter -= 1
|
||||
|
||||
|
@ -7,7 +7,7 @@ __copyright__ = '2011, John Schember <john@nachtimwald.com>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import random
|
||||
import urllib2
|
||||
import urllib
|
||||
from contextlib import closing
|
||||
|
||||
from lxml import html
|
||||
@ -22,7 +22,7 @@ from calibre.gui2.store.search_result import SearchResult
|
||||
from calibre.gui2.store.web_store_dialog import WebStoreDialog
|
||||
|
||||
class DieselEbooksStore(BasicStoreConfig, StorePlugin):
|
||||
|
||||
|
||||
def open(self, parent=None, detail_item=None, external=False):
|
||||
url = 'http://www.diesel-ebooks.com/'
|
||||
|
||||
@ -33,7 +33,7 @@ class DieselEbooksStore(BasicStoreConfig, StorePlugin):
|
||||
|
||||
detail_url = None
|
||||
if detail_item:
|
||||
detail_url = url + detail_item + aff_id
|
||||
detail_url = detail_item + aff_id
|
||||
url = url + aff_id
|
||||
|
||||
if external or self.config.get('open_external', False):
|
||||
@ -45,54 +45,46 @@ class DieselEbooksStore(BasicStoreConfig, StorePlugin):
|
||||
d.exec_()
|
||||
|
||||
def search(self, query, max_results=10, timeout=60):
|
||||
url = 'http://www.diesel-ebooks.com/index.php?page=seek&id[m]=&id[c]=scope%253Dinventory&id[q]=' + urllib2.quote(query)
|
||||
|
||||
url = 'http://www.diesel-ebooks.com/index.php?page=seek&id[m]=&id[c]=scope%253Dinventory&id[q]=' + urllib.quote_plus(query)
|
||||
|
||||
br = browser()
|
||||
|
||||
|
||||
counter = max_results
|
||||
with closing(br.open(url, timeout=timeout)) as f:
|
||||
doc = html.fromstring(f.read())
|
||||
for data in doc.xpath('//div[@class="item clearfix"]'):
|
||||
data = html.fromstring(html.tostring(data))
|
||||
for data in doc.xpath('//div[contains(@class, "item")]'):
|
||||
if counter <= 0:
|
||||
break
|
||||
|
||||
id = ''.join(data.xpath('div[@class="cover"]/a/@href'))
|
||||
if not id or '/item/' not in id:
|
||||
continue
|
||||
a, b, id = id.partition('/item/')
|
||||
|
||||
cover_url = ''.join(data.xpath('div[@class="cover"]//img/@src'))
|
||||
|
||||
title = ''.join(data.xpath('.//div[@class="content"]//h2/text()'))
|
||||
author = ''.join(data.xpath('//div[@class="content"]//div[@class="author"]/a/text()'))
|
||||
title = ''.join(data.xpath('.//div[@class="content"]//h2/a/text()'))
|
||||
author = ''.join(data.xpath('.//div[@class="content"]/span//a/text()'))
|
||||
price = ''
|
||||
price_elem = data.xpath('//td[@class="price"]/text()')
|
||||
price_elem = data.xpath('.//div[@class="price_fat"]//h1/text()')
|
||||
if price_elem:
|
||||
price = price_elem[0]
|
||||
|
||||
formats = ', '.join(data.xpath('.//td[@class="format"]/text()'))
|
||||
formats = ', '.join(data.xpath('.//div[@class="book-info"]//text()')).strip()
|
||||
a, b, formats = formats.partition('Format:')
|
||||
drm = SearchResult.DRM_LOCKED
|
||||
if 'drm free' not in formats.lower():
|
||||
drm = SearchResult.DRM_UNLOCKED
|
||||
|
||||
|
||||
counter -= 1
|
||||
|
||||
|
||||
s = SearchResult()
|
||||
s.cover_url = cover_url
|
||||
s.title = title.strip()
|
||||
s.author = author.strip()
|
||||
s.price = price.strip()
|
||||
s.detail_item = '/item/' + id.strip()
|
||||
s.detail_item = id.strip()
|
||||
s.formats = formats
|
||||
|
||||
yield s
|
||||
s.drm = drm
|
||||
|
||||
def get_details(self, search_result, timeout):
|
||||
url = 'http://www.diesel-ebooks.com/item/'
|
||||
|
||||
br = browser()
|
||||
with closing(br.open(url + search_result.detail_item, timeout=timeout)) as nf:
|
||||
idata = html.fromstring(nf.read())
|
||||
if idata.xpath('boolean(//table[@class="format-info"]//tr[contains(th, "DRM") and contains(td, "No")])'):
|
||||
search_result.drm = SearchResult.DRM_UNLOCKED
|
||||
else:
|
||||
search_result.drm = SearchResult.DRM_LOCKED
|
||||
return True
|
||||
yield s
|
||||
|
@ -60,10 +60,6 @@ class FoylesUKStore(BasicStoreConfig, StorePlugin):
|
||||
continue
|
||||
|
||||
cover_url = ''.join(data.xpath('.//a[@class="Jacket"]/img/@src'))
|
||||
if cover_url:
|
||||
cover_url = 'http://www.foyles.co.uk' + cover_url
|
||||
#print(cover_url)
|
||||
|
||||
title = ''.join(data.xpath('.//a[@class="Title"]/text()'))
|
||||
author = ', '.join(data.xpath('.//span[@class="Author"]/text()'))
|
||||
price = ''.join(data.xpath('./ul/li[@class="Strong"]/text()'))
|
||||
|
@ -68,7 +68,7 @@ class KoboStore(BasicStoreConfig, StorePlugin):
|
||||
cover_url = ''.join(data.xpath('.//div[@class="SearchImageContainer"]//img[1]/@src'))
|
||||
|
||||
title = ''.join(data.xpath('.//div[@class="SCItemHeader"]/h1/a[1]/text()'))
|
||||
author = ''.join(data.xpath('.//div[@class="SCItemSummary"]/span/a[1]/text()'))
|
||||
author = ', '.join(data.xpath('.//div[@class="SCItemSummary"]//span//a/text()'))
|
||||
drm = data.xpath('boolean(.//span[@class="SCAvailibilityFormatsText" and contains(text(), "DRM")])')
|
||||
|
||||
counter -= 1
|
||||
|
@ -57,7 +57,7 @@ class WaterstonesUKStore(BasicStoreConfig, StorePlugin):
|
||||
cover_url = ''.join(data.xpath('.//div[@class="image"]/a/img/@src'))
|
||||
title = ''.join(data.xpath('./div/div/h2/a/text()'))
|
||||
author = ', '.join(data.xpath('.//p[@class="byAuthor"]/a/text()'))
|
||||
price = ''.join(data.xpath('.//p[@class="price"]/span[@class="priceStandard"]/text()'))
|
||||
price = ''.join(data.xpath('.//p[@class="price"]/span[@class="priceRed2"]/text()'))
|
||||
drm = data.xpath('boolean(.//td[@headers="productFormat" and contains(., "DRM")])')
|
||||
pdf = data.xpath('boolean(.//td[@headers="productFormat" and contains(., "PDF")])')
|
||||
epub = data.xpath('boolean(.//td[@headers="productFormat" and contains(., "EPUB")])')
|
||||
|
@ -1,118 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||
|
||||
__license__ = 'GPL 3'
|
||||
__copyright__ = '2011, John Schember <john@nachtimwald.com>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import urllib
|
||||
from contextlib import closing
|
||||
|
||||
from lxml import html
|
||||
|
||||
from PyQt4.Qt import QUrl
|
||||
|
||||
from calibre import browser, url_slash_cleaner
|
||||
from calibre.gui2 import open_url
|
||||
from calibre.gui2.store import StorePlugin
|
||||
from calibre.gui2.store.basic_config import BasicStoreConfig
|
||||
from calibre.gui2.store.search_result import SearchResult
|
||||
from calibre.gui2.store.web_store_dialog import WebStoreDialog
|
||||
|
||||
class WizardsTowerBooksStore(BasicStoreConfig, StorePlugin):
|
||||
|
||||
url = 'http://www.wizardstowerbooks.com/'
|
||||
|
||||
def open(self, parent=None, detail_item=None, external=False):
|
||||
if detail_item:
|
||||
detail_item = self.url + detail_item
|
||||
|
||||
if external or self.config.get('open_external', False):
|
||||
open_url(QUrl(url_slash_cleaner(detail_item)))
|
||||
else:
|
||||
d = WebStoreDialog(self.gui, self.url, parent, detail_item)
|
||||
d.setWindowTitle(self.name)
|
||||
d.set_tags(self.config.get('tags', ''))
|
||||
d.exec_()
|
||||
|
||||
def search(self, query, max_results=10, timeout=60):
|
||||
url = 'http://www.wizardstowerbooks.com/search.html?for=' + urllib.quote(query)
|
||||
|
||||
br = browser()
|
||||
|
||||
counter = max_results
|
||||
with closing(br.open(url, timeout=timeout)) as f:
|
||||
doc = html.fromstring(f.read())
|
||||
if 'search.html' in f.geturl():
|
||||
for data in doc.xpath('//table[@class="gridp"]//td'):
|
||||
if counter <= 0:
|
||||
break
|
||||
|
||||
id = ''.join(data.xpath('.//span[@class="prti"]/a/@href'))
|
||||
id = id.strip()
|
||||
if not id:
|
||||
continue
|
||||
|
||||
cover_url = ''.join(data.xpath('.//div[@class="prim"]/a/img/@src'))
|
||||
cover_url = url_slash_cleaner(self.url + cover_url.strip())
|
||||
|
||||
price = ''.join(data.xpath('.//font[@class="selling_price"]//text()'))
|
||||
price = price.strip()
|
||||
if not price:
|
||||
continue
|
||||
|
||||
title = ''.join(data.xpath('.//span[@class="prti"]/a/b/text()'))
|
||||
author = ''.join(data.xpath('.//p[@class="last"]/text()'))
|
||||
a, b, author = author.partition(' by ')
|
||||
|
||||
counter -= 1
|
||||
|
||||
s = SearchResult()
|
||||
s.cover_url = cover_url
|
||||
s.title = title.strip()
|
||||
s.author = author.strip()
|
||||
s.price = price.strip()
|
||||
s.detail_item = id.strip()
|
||||
s.drm = SearchResult.DRM_UNLOCKED
|
||||
|
||||
yield s
|
||||
# Exact match brought us to the books detail page.
|
||||
else:
|
||||
s = SearchResult()
|
||||
|
||||
cover_url = ''.join(doc.xpath('//div[@id="image"]/a/img[@title="Zoom"]/@src')).strip()
|
||||
s.cover_url = url_slash_cleaner(self.url + cover_url.strip())
|
||||
|
||||
s.title = ''.join(doc.xpath('//form[@name="details"]/h1/text()')).strip()
|
||||
|
||||
authors = doc.xpath('//p[contains(., "Author:")]//text()')
|
||||
author_index = None
|
||||
for i, a in enumerate(authors):
|
||||
if 'author' in a.lower():
|
||||
author_index = i + 1
|
||||
break
|
||||
if author_index is not None and len(authors) > author_index:
|
||||
a = authors[author_index]
|
||||
a = a.replace(u'\xa0', '')
|
||||
s.author = a.strip()
|
||||
|
||||
s.price = ''.join(doc.xpath('//span[@id="price_selling"]//text()')).strip()
|
||||
s.detail_item = f.geturl().replace(self.url, '').strip()
|
||||
s.formats = ', '.join(doc.xpath('//select[@id="N1_"]//option//text()'))
|
||||
s.drm = SearchResult.DRM_UNLOCKED
|
||||
|
||||
yield s
|
||||
|
||||
def get_details(self, search_result, timeout):
|
||||
if search_result.formats:
|
||||
return False
|
||||
|
||||
br = browser()
|
||||
with closing(br.open(url_slash_cleaner(self.url + search_result.detail_item), timeout=timeout)) as nf:
|
||||
idata = html.fromstring(nf.read())
|
||||
|
||||
formats = ', '.join(idata.xpath('//select[@id="N1_"]//option//text()'))
|
||||
search_result.formats = formats.upper()
|
||||
|
||||
return True
|
@ -3,7 +3,7 @@
|
||||
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||
|
||||
__license__ = 'GPL 3'
|
||||
__copyright__ = '2011, Tomasz Długosz <tomek3d@gmail.com>'
|
||||
__copyright__ = '2011-2012, Tomasz Długosz <tomek3d@gmail.com>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import re
|
||||
@ -41,6 +41,11 @@ class WoblinkStore(BasicStoreConfig, StorePlugin):
|
||||
|
||||
def search(self, query, max_results=10, timeout=60):
|
||||
url = 'http://woblink.com/publication?query=' + urllib.quote_plus(query.encode('utf-8'))
|
||||
if max_results > 10:
|
||||
if max_results > 20:
|
||||
url += '&limit=' + str(30)
|
||||
else:
|
||||
url += '&limit=' + str(20)
|
||||
|
||||
br = browser()
|
||||
|
||||
@ -58,15 +63,16 @@ class WoblinkStore(BasicStoreConfig, StorePlugin):
|
||||
cover_url = ''.join(data.xpath('.//td[@class="w10 va-t"]/a[1]/img/@src'))
|
||||
title = ''.join(data.xpath('.//h2[@class="title"]/a[1]/text()'))
|
||||
author = ', '.join(data.xpath('.//p[@class="author"]/a/text()'))
|
||||
price = ''.join(data.xpath('.//div[@class="prices"]/p[1]/span/text()'))
|
||||
price = re.sub('PLN', ' zł', price)
|
||||
price = ''.join(data.xpath('.//div[@class="prices"]/span[1]/span/text()'))
|
||||
price = re.sub('\.', ',', price)
|
||||
formats = ', '.join(data.xpath('.//p[3]/img/@src'))
|
||||
formats = formats[8:-4].upper()
|
||||
if formats == 'EPUB':
|
||||
formats = 'WOBLINK'
|
||||
formats = [ form[8:-4].split('_')[0] for form in data.xpath('.//p[3]/img/@src')]
|
||||
if 'epub' in formats:
|
||||
formats.remove('epub')
|
||||
formats.append('WOBLINK')
|
||||
if 'E Ink' in data.xpath('.//div[@class="prices"]/img/@title'):
|
||||
formats += ', EPUB'
|
||||
formats.insert(0, 'EPUB')
|
||||
if 'pdf' in formats:
|
||||
formats[formats.index('pdf')] = 'PDF'
|
||||
|
||||
counter -= 1
|
||||
|
||||
@ -74,9 +80,9 @@ class WoblinkStore(BasicStoreConfig, StorePlugin):
|
||||
s.cover_url = 'http://woblink.com' + cover_url
|
||||
s.title = title.strip()
|
||||
s.author = author.strip()
|
||||
s.price = price
|
||||
s.price = price + ' zł'
|
||||
s.detail_item = id.strip()
|
||||
s.drm = SearchResult.DRM_LOCKED
|
||||
s.formats = formats
|
||||
s.drm = SearchResult.DRM_UNKNOWN if 'MOBI' in formats else SearchResult.DRM_LOCKED
|
||||
s.formats = ', '.join(formats)
|
||||
|
||||
yield s
|
||||
|
@ -8,7 +8,7 @@ import os, math, re, glob, sys, zipfile
|
||||
from base64 import b64encode
|
||||
from functools import partial
|
||||
|
||||
from PyQt4.Qt import (QSize, QSizePolicy, QUrl, SIGNAL, Qt, QTimer,
|
||||
from PyQt4.Qt import (QSize, QSizePolicy, QUrl, SIGNAL, Qt,
|
||||
QPainter, QPalette, QBrush, QFontDatabase, QDialog,
|
||||
QColor, QPoint, QImage, QRegion, QVariant, QIcon,
|
||||
QFont, pyqtSignature, QAction, QByteArray, QMenu,
|
||||
@ -184,12 +184,10 @@ class Document(QWebPage): # {{{
|
||||
self.misc_config()
|
||||
self.after_load()
|
||||
|
||||
def __init__(self, shortcuts, parent=None, resize_callback=lambda: None,
|
||||
debug_javascript=False):
|
||||
def __init__(self, shortcuts, parent=None, debug_javascript=False):
|
||||
QWebPage.__init__(self, parent)
|
||||
self.setObjectName("py_bridge")
|
||||
self.debug_javascript = debug_javascript
|
||||
self.resize_callback = resize_callback
|
||||
self.current_language = None
|
||||
self.loaded_javascript = False
|
||||
self.js_loader = JavaScriptLoader(
|
||||
@ -259,12 +257,6 @@ class Document(QWebPage): # {{{
|
||||
if self.loaded_javascript:
|
||||
return
|
||||
self.loaded_javascript = True
|
||||
self.javascript(
|
||||
'''
|
||||
window.onresize = function(event) {
|
||||
window.py_bridge.window_resized();
|
||||
}
|
||||
''')
|
||||
self.loaded_lang = self.js_loader(self.mainFrame().evaluateJavaScript,
|
||||
self.current_language, self.hyphenate_default_lang)
|
||||
|
||||
@ -310,10 +302,6 @@ class Document(QWebPage): # {{{
|
||||
def debug(self, msg):
|
||||
prints(msg)
|
||||
|
||||
@pyqtSignature('')
|
||||
def window_resized(self):
|
||||
self.resize_callback()
|
||||
|
||||
def reference_mode(self, enable):
|
||||
self.javascript(('enter' if enable else 'leave')+'_reference_mode()')
|
||||
|
||||
@ -444,7 +432,7 @@ class Document(QWebPage): # {{{
|
||||
def scroll_fraction(self):
|
||||
def fget(self):
|
||||
try:
|
||||
return float(self.ypos)/(self.height-self.window_height)
|
||||
return abs(float(self.ypos)/(self.height-self.window_height))
|
||||
except ZeroDivisionError:
|
||||
return 0.
|
||||
def fset(self, val):
|
||||
@ -516,7 +504,6 @@ class DocumentView(QWebView): # {{{
|
||||
self.initial_pos = 0.0
|
||||
self.to_bottom = False
|
||||
self.document = Document(self.shortcuts, parent=self,
|
||||
resize_callback=self.viewport_resized,
|
||||
debug_javascript=debug_javascript)
|
||||
self.setPage(self.document)
|
||||
self.manager = None
|
||||
@ -1035,13 +1022,9 @@ class DocumentView(QWebView): # {{{
|
||||
return handled
|
||||
|
||||
def resizeEvent(self, event):
|
||||
ret = QWebView.resizeEvent(self, event)
|
||||
QTimer.singleShot(10, self.initialize_scrollbar)
|
||||
return ret
|
||||
|
||||
def viewport_resized(self):
|
||||
if self.manager is not None:
|
||||
self.manager.viewport_resized(self.scroll_fraction)
|
||||
self.manager.viewport_resize_started(event)
|
||||
return QWebView.resizeEvent(self, event)
|
||||
|
||||
def event(self, ev):
|
||||
if ev.type() == ev.Gesture:
|
||||
|
@ -224,6 +224,10 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
self.toc.setVisible(False)
|
||||
self.action_quit = QAction(self)
|
||||
self.addAction(self.action_quit)
|
||||
self.view_resized_timer = QTimer(self)
|
||||
self.view_resized_timer.timeout.connect(self.viewport_resize_finished)
|
||||
self.view_resized_timer.setSingleShot(True)
|
||||
self.resize_in_progress = False
|
||||
qs = [Qt.CTRL+Qt.Key_Q]
|
||||
if isosx:
|
||||
qs += [Qt.CTRL+Qt.Key_W]
|
||||
@ -311,6 +315,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
border-radius: 20px;
|
||||
}
|
||||
''')
|
||||
self.window_mode_changed = None
|
||||
self.toggle_toolbar_action = QAction(_('Show/hide controls'), self)
|
||||
self.toggle_toolbar_action.triggered.connect(self.toggle_toolbars)
|
||||
self.addAction(self.toggle_toolbar_action)
|
||||
@ -441,6 +446,8 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
self.showFullScreen()
|
||||
|
||||
def showFullScreen(self):
|
||||
self.view.document.page_position.save()
|
||||
self.window_mode_changed = 'fullscreen'
|
||||
self.tool_bar.setVisible(False)
|
||||
self.tool_bar2.setVisible(False)
|
||||
self._original_frame_margins = (
|
||||
@ -450,7 +457,6 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
self.centralwidget.layout().setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
super(EbookViewer, self).showFullScreen()
|
||||
QTimer.singleShot(10, self.show_full_screen_label)
|
||||
|
||||
def show_full_screen_label(self):
|
||||
f = self.full_screen_label
|
||||
@ -469,6 +475,8 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
self.view.document.switch_to_fullscreen_mode()
|
||||
|
||||
def showNormal(self):
|
||||
self.view.document.page_position.save()
|
||||
self.window_mode_changed = 'normal'
|
||||
self.esc_full_screen_action.setEnabled(False)
|
||||
self.tool_bar.setVisible(True)
|
||||
self.tool_bar2.setVisible(True)
|
||||
@ -478,7 +486,16 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
self.centralwidget.layout().setContentsMargins(om[0])
|
||||
self.frame.layout().setContentsMargins(om[1])
|
||||
super(EbookViewer, self).showNormal()
|
||||
self.view.document.switch_to_window_mode()
|
||||
|
||||
def handle_window_mode_toggle(self):
|
||||
if self.window_mode_changed:
|
||||
fs = self.window_mode_changed == 'fullscreen'
|
||||
self.window_mode_changed = None
|
||||
if fs:
|
||||
self.show_full_screen_label()
|
||||
else:
|
||||
self.view.document.switch_to_window_mode()
|
||||
self.view.document.page_position.restore()
|
||||
|
||||
def goto(self, ref):
|
||||
if ref:
|
||||
@ -507,6 +524,10 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
def toc_clicked(self, index):
|
||||
item = self.toc_model.itemFromIndex(index)
|
||||
if item.abspath is not None:
|
||||
if not os.path.exists(item.abspath):
|
||||
return error_dialog(self, _('No such location'),
|
||||
_('The location pointed to by this item'
|
||||
' does not exist.'), show=True)
|
||||
url = QUrl.fromLocalFile(item.abspath)
|
||||
if item.fragment:
|
||||
url.setFragment(item.fragment)
|
||||
@ -674,16 +695,28 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
|
||||
self.open_progress_indicator(_('Laying out %s')%self.current_title)
|
||||
self.view.load_path(path, pos=pos)
|
||||
|
||||
def viewport_resized(self, frac):
|
||||
new_page = self.pos.value()
|
||||
if self.current_page is not None:
|
||||
try:
|
||||
frac = float(new_page-self.current_page.start_page)/(self.current_page.pages-1)
|
||||
except ZeroDivisionError:
|
||||
frac = 0
|
||||
self.view.scroll_to(frac, notify=False)
|
||||
def viewport_resize_started(self, event):
|
||||
if not self.resize_in_progress:
|
||||
# First resize, so save the current page position
|
||||
self.resize_in_progress = True
|
||||
if not self.window_mode_changed:
|
||||
# The special handling for window mode changed will already
|
||||
# have saved page position, so only save it if this is not a
|
||||
# mode change
|
||||
self.view.document.page_position.save()
|
||||
|
||||
if self.resize_in_progress:
|
||||
self.view_resized_timer.start(75)
|
||||
|
||||
def viewport_resize_finished(self):
|
||||
# There hasn't been a resize event for some time
|
||||
# restore the current page position.
|
||||
self.resize_in_progress = False
|
||||
if self.window_mode_changed:
|
||||
# This resize is part of a window mode change, special case it
|
||||
self.handle_window_mode_toggle()
|
||||
else:
|
||||
self.set_page_number(frac)
|
||||
self.view.document.page_position.restore()
|
||||
|
||||
def close_progress_indicator(self):
|
||||
self.pi.stop()
|
||||
|
@ -57,12 +57,20 @@ class PagePosition(object):
|
||||
return ans
|
||||
|
||||
def __enter__(self):
|
||||
self._cpos = self.current_pos
|
||||
self.save()
|
||||
|
||||
def __exit__(self, *args):
|
||||
self.restore()
|
||||
|
||||
def save(self):
|
||||
self._cpos = self.current_pos
|
||||
|
||||
def restore(self):
|
||||
if self._cpos is None: return
|
||||
if isinstance(self._cpos, (int, float)):
|
||||
self.document.scroll_fraction = self._cpos
|
||||
else:
|
||||
self.scroll_to_cfi(self._cpos)
|
||||
self._cpos = None
|
||||
|
||||
|
||||
|
@ -953,7 +953,7 @@ class ResultCache(SearchQueryParser): # {{{
|
||||
self.series_col, self.series_sort_col)
|
||||
self._data[id].append(db.book_on_device_string(id))
|
||||
self._data[id].append(self.marked_ids_dict.get(id, None))
|
||||
self._data[id].append(None)
|
||||
self._data[id].append(None) # Series sort column
|
||||
self._map[0:0] = ids
|
||||
self._map_filtered[0:0] = ids
|
||||
|
||||
@ -983,8 +983,8 @@ class ResultCache(SearchQueryParser): # {{{
|
||||
for item in self._data:
|
||||
if item is not None:
|
||||
item.append(db.book_on_device_string(item[0]))
|
||||
item.append(None)
|
||||
item.append(None)
|
||||
# Temp mark and series_sort columns
|
||||
item.extend((None, None))
|
||||
|
||||
marked_col = self.FIELD_MAP['marked']
|
||||
for id_,val in self.marked_ids_dict.iteritems():
|
||||
|
Loading…
x
Reference in New Issue
Block a user