Get books: Update store plugin for ebook.nl

Merge branch 'master' of https://github.com/Serized/calibre
This commit is contained in:
Kovid Goyal 2017-07-27 15:45:59 +05:30
commit 76c5cd230e
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 30 additions and 342 deletions

View File

@ -1366,24 +1366,6 @@ class StoreAmazonKindleStore(StoreBase):
affiliate = False affiliate = False
class StoreSonyStore(StoreBase):
name = 'SONY Reader Store'
description = u'SONY Reader books.'
author = 'Kovid Goyal'
actual_plugin = 'calibre.gui2.store.stores.sony_plugin:SonyStore'
headquarters = 'US'
formats = ['SONY']
affiliate = False
class StoreSonyAUStore(StoreSonyStore):
name = 'SONY Reader (Australia) Store'
description = u'SONY Reader books (Australia).'
actual_plugin = 'calibre.gui2.store.stores.sony_au_plugin:SonyStore'
headquarters = 'AU'
class StoreAmazonAUKindleStore(StoreBase): class StoreAmazonAUKindleStore(StoreBase):
name = 'Amazon AU Kindle' name = 'Amazon AU Kindle'
author = u'Kovid Goyal' author = u'Kovid Goyal'
@ -1758,16 +1740,6 @@ class StoreNextoStore(StoreBase):
affiliate = True affiliate = True
class StoreNookUKStore(StoreBase):
name = 'Nook UK'
author = 'Charles Haley'
description = u'Barnes & Noble S.A.R.L, a subsidiary of Barnes & Noble, Inc., a leading retailer of content, digital media and educational products, is proud to bring the award-winning NOOK reading experience and a leading digital bookstore to the UK.' # noqa
actual_plugin = 'calibre.gui2.store.stores.nook_uk_plugin:NookUKStore'
headquarters = 'UK'
formats = ['NOOK']
class StoreOpenBooksStore(StoreBase): class StoreOpenBooksStore(StoreBase):
name = 'Open Books' name = 'Open Books'
description = u'Comprehensive listing of DRM free e-books from a variety of sources provided by users of calibre.' description = u'Comprehensive listing of DRM free e-books from a variety of sources provided by users of calibre.'
@ -1930,14 +1902,12 @@ plugins += [
StoreMillsBoonUKStore, StoreMillsBoonUKStore,
StoreMobileReadStore, StoreMobileReadStore,
StoreNextoStore, StoreNextoStore,
StoreNookUKStore,
StoreOpenBooksStore, StoreOpenBooksStore,
StoreOzonRUStore, StoreOzonRUStore,
StorePragmaticBookshelfStore, StorePragmaticBookshelfStore,
StorePublioStore, StorePublioStore,
StoreRW2010Store, StoreRW2010Store,
StoreSmashwordsStore, StoreSmashwordsStore,
StoreSonyStore, StoreSonyAUStore,
StoreVirtualoStore, StoreVirtualoStore,
StoreWeightlessBooksStore, StoreWeightlessBooksStore,
StoreWHSmithUKStore, StoreWHSmithUKStore,

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import (unicode_literals, division, absolute_import, print_function) from __future__ import (unicode_literals, division, absolute_import, print_function)
store_version = 1 # Needed for dynamic plugin loading store_version = 2 # Needed for dynamic plugin loading
__license__ = 'GPL 3' __license__ = 'GPL 3'
__copyright__ = '2011, John Schember <john@nachtimwald.com>' __copyright__ = '2011, John Schember <john@nachtimwald.com>'
@ -48,32 +48,19 @@ class EBookNLStore(BasicStoreConfig, StorePlugin):
counter = max_results counter = max_results
with closing(br.open(url, timeout=timeout)) as f: with closing(br.open(url, timeout=timeout)) as f:
doc = html.fromstring(f.read()) doc = html.fromstring(f.read())
for data in doc.xpath('//table[contains(@class, "productListing")]/tr'): for data in doc.xpath('//div[@id="books"]/div[@itemtype="http://schema.org/Book"]'):
if counter <= 0: if counter <= 0:
break break
details = data.xpath('./td/div[@class="prodImage"]/a') id = ''.join(data.xpath('./meta[@itemprop="url"]/@content')).strip()
if not details:
continue
details = details[0]
id = ''.join(details.xpath('./@href')).strip()
id = id[id.rfind('/')+1:]
i = id.rfind('?')
if i > 0:
id = id[:i]
if not id: if not id:
continue continue
cover_url = 'http://www.ebook.nl/store/' + ''.join(details.xpath('./img/@src')) cover_url = 'http://www.ebook.nl/store/' + ''.join(data.xpath('.//img[@itemprop="image"]/@src'))
title = ''.join(details.xpath('./img/@title')).strip() title = ''.join(data.xpath('./span[@itemprop="name"]/a/text()')).strip()
author = ''.join(data.xpath('./td/div[@class="prodTitle"]/h3/a/text()')).strip() author = ''.join(data.xpath('./span[@itemprop="author"]/a/text()')).strip()
price = ''.join(data.xpath('./td/div[@class="prodTitle"]/b/text()')) if author == '&nbsp':
pdf = data.xpath('boolean(./td/div[@class="prodTitle"]/' author = ''
'p[contains(text(), "Bestandsformaat: Pdf")])') price = ''.join(data.xpath('.//span[@itemprop="price"]//text()'))
epub = data.xpath('boolean(./td/div[@class="prodTitle"]/'
'p[contains(text(), "Bestandsformaat: ePub")])')
nodrm = data.xpath('boolean(./td/div[@class="prodTitle"]/'
'p[contains(text(), "zonder DRM") or'
' contains(text(), "watermerk")])')
counter -= 1 counter -= 1
s = SearchResult() s = SearchResult()
@ -81,16 +68,27 @@ class EBookNLStore(BasicStoreConfig, StorePlugin):
s.title = title.strip() s.title = title.strip()
s.author = author.strip() s.author = author.strip()
s.price = price s.price = price
if nodrm: s.drm = SearchResult.DRM_UNKNOWN
s.drm = SearchResult.DRM_UNLOCKED
else:
s.drm = SearchResult.DRM_LOCKED
s.detail_item = id s.detail_item = id
formats = []
if epub:
formats.append('ePub')
if pdf:
formats.append('PDF')
s.formats = ','.join(formats)
yield s yield s
def get_details(self, search_result, timeout):
br = browser()
with closing(br.open(search_result.detail_item, timeout=timeout)) as nf:
idata = html.fromstring(nf.read())
formats = []
if idata.xpath('.//div[@id="book_detail_body"]/ul/li[strong[contains(., "Type")]]/span[contains(., "ePub")]'):
if idata.xpath('.//div[@id="book_detail_body"]/ul/li[strong[contains(., "Type")]]/span[contains(., "EPUB3")]'):
formats.append('EPUB3')
else:
formats.append('EPUB')
if idata.xpath('.//div[@id="book_detail_body"]/ul/li[strong[contains(., "Type")]]/span[contains(., "Pdf")]'):
formats.append('PDF')
search_result.formats = ', '.join(formats)
if idata.xpath('.//div[@id="book_detail_body"]/ul/li[strong[contains(., "Type")]]//span[@class="ePubAdobeDRM" or @class="ePubwatermerk" or @class="Pdfwatermark" or @class="PdfAdobeDRM"]'):
search_result.drm = SearchResult.DRM_LOCKED
if idata.xpath('.//div[@id="book_detail_body"]/ul/li[strong[contains(., "Type")]]//span[@class="ePubzonderDRM"]'):
search_result.drm = SearchResult.DRM_UNLOCKED
return True

View File

@ -1,88 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import (unicode_literals, division, absolute_import, print_function)
store_version = 4 # Needed for dynamic plugin loading
__license__ = 'GPL 3'
__copyright__ = '2012, John Schember <john@nachtimwald.com>'
__docformat__ = 'restructuredtext en'
import re
import urllib
from contextlib import closing
from lxml import html
from PyQt5.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 NookUKStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False):
url = 'http://www.nook.com/gb/store'
detail_url = ''
if external or self.config.get('open_external', False):
if detail_item:
url = detail_url + detail_item
open_url(QUrl(url_slash_cleaner(url)))
else:
if detail_item:
detail_url = detail_url + detail_item
else:
detail_url = None
d = WebStoreDialog(self.gui, 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 = u'http://uk.nook.com/s/%s?s%%5Bdref%%5D=1&s%%5Bkeyword%%5D=%s' % (query.replace(' ', '-'), urllib.quote(query))
br = browser()
counter = max_results
with closing(br.open(url, timeout=timeout)) as f:
raw = f.read()
doc = html.fromstring(raw)
for data in doc.xpath('//ul[contains(@class, "product_list")]/li'):
if counter <= 0:
break
id_ = ''.join(data.xpath('.//span[contains(@class, "image")]/a/@href'))
if not id_:
continue
if id_.startswith('/gb'):
id_ = id_[3:]
id_ = 'http://uk.nook.com' + id_.strip()
cover_url = ''.join(data.xpath('.//span[contains(@class, "image")]//img/@data-src'))
title = ''.join(data.xpath('.//div[contains(@class, "title")]//text()')).strip()
if not title:
continue
author = ', '.join(data.xpath('.//div[contains(@class, "contributor")]//a/text()')).strip()
price = ''.join(data.xpath('.//div[contains(@class, "action")]//a//text()')).strip()
price = re.sub(r'[^\d.,£]', '', price)
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_
s.drm = SearchResult.DRM_UNKNOWN
s.formats = 'Nook'
yield s

View File

@ -1,97 +0,0 @@
#!/usr/bin/env python2
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
store_version = 1 # Needed for dynamic plugin loading
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import urllib
from contextlib import closing
from lxml import html, etree
from PyQt5.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 SonyStore(BasicStoreConfig, StorePlugin):
SEARCH_URL = 'https://au.readerstore.sony.com/catalog/search/?query=%s'
STORE_URL = 'https://au.readerstore.sony.com/store/'
def open(self, parent=None, detail_item=None, external=False):
if 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.STORE_URL, parent, detail_item)
d.setWindowTitle(self.name)
d.set_tags(self.config.get('tags', ''))
d.exec_()
else:
open_url(QUrl(self.STORE_URL))
def search(self, query, max_results=10, timeout=60):
url = self.SEARCH_URL % urllib.quote_plus(query)
br = browser()
counter = max_results
with closing(br.open(url, timeout=timeout)) as f:
doc = html.fromstring(f.read())
for item in doc.xpath('//div[@id="searchresult-list"]/descendant::div[contains(@class, "doc-item")]'):
if counter <= 0:
break
s = SearchResult()
s.price = _('Not Available')
p = ''.join(item.xpath('descendant::p[@class="doc-price"]/descendant::span[@itemprop="price"]/text()')).strip()
if p:
s.price = 'AUD ' + p.split('$')[-1]
title = item.xpath('descendant::h3[@class="doc-title"]')
if not title:
continue
title = etree.tostring(title[0], method='text', encoding=unicode)
if not title:
continue
st = item.xpath('descendant::p[@class="doc-subtitle"]')
if st:
st = etree.tostring(st[0], method='text', encoding=unicode)
if st and st.strip():
title = title.strip() + ': ' + st
s.title = title.strip()
aut = item.xpath('descendant::p[@class="doc-author"]')
if not aut:
continue
s.author = etree.tostring(aut[0], method='text', encoding=unicode).strip()
if not s.author:
continue
du = ''.join(item.xpath('descendant::h3[position() = 1 and @class="doc-title"]/descendant::a[position() = 1 and @href]/@href')).strip()
if not du:
continue
detail_url = 'https://au.readerstore.sony.com'+du
s.detail_item = detail_url
counter -= 1
cover_url = ''.join(item.xpath(
'descendant::p[@class="doc-cover" and position() = 1]/'
'descendant::img[position() = 1 and @src]/@src'))
if cover_url:
s.cover_url = url_slash_cleaner(cover_url)
s.drm = SearchResult.DRM_UNKNOWN
s.formats = 'Sony'
yield s

View File

@ -1,95 +0,0 @@
#!/usr/bin/env python2
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
from __future__ import (unicode_literals, division, absolute_import,
print_function)
store_version = 2 # Needed for dynamic plugin loading
__license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import urllib
from contextlib import closing
from lxml import html, etree
from PyQt5.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 SonyStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False):
if detail_item:
if external or self.config.get('open_external', False):
open_url(QUrl(url_slash_cleaner(detail_item)))
else:
d = WebStoreDialog(self.gui, 'http://ebookstore.sony.com', parent, detail_item)
d.setWindowTitle(self.name)
d.set_tags(self.config.get('tags', ''))
d.exec_()
else:
open_url(QUrl('http://ebookstore.sony.com'))
def search(self, query, max_results=10, timeout=60):
url = 'http://ebookstore.sony.com/search?keyword=%s'%urllib.quote_plus(
query)
br = browser()
counter = max_results
with closing(br.open(url, timeout=timeout)) as f:
doc = html.fromstring(f.read())
for item in doc.xpath('//div[contains(@class, "searchResult")]/'
'descendant::li[contains(@class, "hreview")]'):
if counter <= 0:
break
curr = ''.join(item.xpath('descendant::div[@class="pricing"]/p[@class="price money"]/descendant::*[@class="currency"]/@title')).strip()
amt = ''.join(item.xpath('descendant::div[@class="pricing"]/p[@class="price money"]/descendant::*[@class="amount"]/text()')).strip()
s = SearchResult()
s.price = (curr+' '+amt) if (curr and amt) else _('Not Available')
title = item.xpath('descendant::h3[@class="item"]')
if not title:
continue
title = etree.tostring(title[0], method='text',
encoding=unicode)
if not title:
continue
s.title = title.strip()
s.author = ''.join(item.xpath(
'descendant::li[contains(@class, "author")]/'
'a[@class="fn"]/text()')).strip()
if not s.author:
continue
detail_url = ''.join(item.xpath('descendant::h3[@class="item"]'
'/descendant::a[@class="fn" and @href]/@href'))
if not detail_url:
continue
if detail_url.startswith('/'):
detail_url = 'http:'+detail_url
s.detail_item = detail_url
counter -= 1
cover_url = ''.join(item.xpath(
'descendant::li[@class="coverart"]/'
'descendant::img[@src]/@src'))
if cover_url:
if cover_url.startswith('//'):
cover_url = 'http:' + cover_url
elif cover_url.startswith('/'):
cover_url = 'http://ebookstore.sony.com'+cover_url
s.cover_url = url_slash_cleaner(cover_url)
s.drm = SearchResult.DRM_UNKNOWN
s.formats = 'Sony'
yield s