Add archive.org and nextto to the get books stores

This commit is contained in:
Kovid Goyal 2011-05-15 22:04:06 -06:00
commit 5d2a278c4f
4 changed files with 206 additions and 17 deletions

View File

@ -1,4 +1,5 @@
import os.path
# -*- coding: utf-8 -*-
__license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
@ -1094,19 +1095,25 @@ plugins += [LookAndFeel, Behavior, Columns, Toolbar, Search, InputOptions,
# Store plugins {{{
class StoreAmazonKindleStore(StoreBase):
name = 'Amazon Kindle'
description = _('Kindle books from Amazon')
description = _('Kindle books from Amazon.')
actual_plugin = 'calibre.gui2.store.amazon_plugin:AmazonKindleStore'
class StoreAmazonDEKindleStore(StoreBase):
name = 'Amazon DE Kindle'
description = _('Kindle eBooks')
description = _('Kindle books from Amazon.de.')
actual_plugin = 'calibre.gui2.store.amazon_de_plugin:AmazonDEKindleStore'
class StoreAmazonUKKindleStore(StoreBase):
name = 'Amazon UK Kindle'
description = _('Kindle books from Amazon.uk')
description = _('Kindle books from Amazon.uk.')
actual_plugin = 'calibre.gui2.store.amazon_uk_plugin:AmazonUKKindleStore'
class StoreArchiveOrgStore(StoreBase):
name = 'Archive.org'
description = _('Free Books : Download & Streaming : Ebook and Texts Archive : Internet Archive.')
actual_plugin = 'calibre.gui2.store.archive_org_plugin:ArchiveOrgStore'
class StoreBaenWebScriptionStore(StoreBase):
name = 'Baen WebScription'
description = _('Ebooks for readers.')
@ -1119,7 +1126,7 @@ class StoreBNStore(StoreBase):
class StoreBeamEBooksDEStore(StoreBase):
name = 'Beam EBooks DE'
description = _('der eBook Shop')
description = _('Der eBook Shop.')
actual_plugin = 'calibre.gui2.store.beam_ebooks_de_plugin:BeamEBooksDEStore'
class StoreBeWriteStore(StoreBase):
@ -1139,12 +1146,12 @@ class StoreEbookscomStore(StoreBase):
class StoreEPubBuyDEStore(StoreBase):
name = 'EPUBBuy DE'
description = _('EPUBReaders eBook Shop')
description = _('EPUBReaders eBook Shop.')
actual_plugin = 'calibre.gui2.store.epubbuy_de_plugin:EPubBuyDEStore'
class StoreEHarlequinStore(StoreBase):
name = 'eHarlequin'
description = _('entertain, enrich, inspire.')
description = _('Entertain, enrich, inspire.')
actual_plugin = 'calibre.gui2.store.eharlequin_plugin:EHarlequinStore'
class StoreFeedbooksStore(StoreBase):
@ -1154,7 +1161,7 @@ class StoreFeedbooksStore(StoreBase):
class StoreFoylesUKStore(StoreBase):
name = 'Foyles UK'
description = _('Foyles of London, online')
description = _('Foyles of London, online.')
actual_plugin = 'calibre.gui2.store.foyles_uk_plugin:FoylesUKStore'
class StoreGutenbergStore(StoreBase):
@ -1174,9 +1181,14 @@ class StoreManyBooksStore(StoreBase):
class StoreMobileReadStore(StoreBase):
name = 'MobileRead'
description = _('Ebooks handcrafted with the utmost care')
description = _('Ebooks handcrafted with the utmost care.')
actual_plugin = 'calibre.gui2.store.mobileread.mobileread_plugin:MobileReadStore'
class StoreNextoStore(StoreBase):
name = 'Nexto'
description = _('Audiobooki mp3, ebooki, prasa - księgarnia internetowa.')
actual_plugin = 'calibre.gui2.store.nexto_plugin:NextoStore'
class StoreOpenLibraryStore(StoreBase):
name = 'Open Library'
description = _('One web page for every book.')
@ -1189,26 +1201,26 @@ class StoreSmashwordsStore(StoreBase):
class StoreWaterstonesUKStore(StoreBase):
name = 'Waterstones UK'
description = _('Feel every word')
description = _('Feel every word.')
actual_plugin = 'calibre.gui2.store.waterstones_uk_plugin:WaterstonesUKStore'
class StoreWeightlessBooksStore(StoreBase):
name = 'Weightless Books'
description = '(e)Books That Don\'t Weigh You Down'
description = '(e)Books That Don\'t Weigh You Down.'
actual_plugin = 'calibre.gui2.store.weightless_books_plugin:WeightlessBooksStore'
class StoreWizardsTowerBooksStore(StoreBase):
name = 'Wizards Tower Books'
description = 'Wizard\'s Tower Press'
description = 'Wizard\'s Tower Press.'
actual_plugin = 'calibre.gui2.store.wizards_tower_books_plugin:WizardsTowerBooksStore'
plugins += [StoreAmazonKindleStore, StoreAmazonDEKindleStore, StoreAmazonUKKindleStore,
StoreBaenWebScriptionStore, StoreBNStore,
plugins += [StoreArchiveOrgStore, StoreAmazonKindleStore, StoreAmazonDEKindleStore,
StoreAmazonUKKindleStore, StoreBaenWebScriptionStore, StoreBNStore,
StoreBeamEBooksDEStore, StoreBeWriteStore,
StoreDieselEbooksStore, StoreEbookscomStore, StoreEPubBuyDEStore,
StoreEHarlequinStore, StoreFeedbooksStore,
StoreFoylesUKStore, StoreGutenbergStore, StoreKoboStore, StoreManyBooksStore,
StoreMobileReadStore, StoreOpenLibraryStore, StoreSmashwordsStore,
StoreMobileReadStore, StoreNextoStore, StoreOpenLibraryStore, StoreSmashwordsStore,
StoreWaterstonesUKStore, StoreWeightlessBooksStore, StoreWizardsTowerBooksStore]
# }}}

View File

@ -0,0 +1,89 @@
# -*- 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 ArchiveOrgStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False):
url = 'http://www.archive.org/details/texts'
if detail_item:
detail_item = url_slash_cleaner('http://www.archive.org' + detail_item)
if external or self.config.get('open_external', False):
open_url(QUrl(url_slash_cleaner(detail_item if detail_item else url)))
else:
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):
query = query + ' AND mediatype:texts'
url = 'http://www.archive.org/search.php?query=' + urllib.quote(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('//td[@class="hitCell"]'):
if counter <= 0:
break
id = ''.join(data.xpath('.//a[@class="titleLink"]/@href'))
if not id:
continue
title = ''.join(data.xpath('.//a[@class="titleLink"]//text()'))
authors = data.xpath('.//text()')
if not authors:
continue
author = None
for a in authors:
if '-' in a:
author = a.replace('-', ' ').strip()
if author:
break
if not author:
continue
counter -= 1
s = SearchResult()
s.title = title.strip()
s.author = author.strip()
s.price = '$0.00'
s.detail_item = id.strip()
s.drm = SearchResult.DRM_UNLOCKED
yield s
def get_details(self, search_result, timeout):
url = url_slash_cleaner('http://www.archive.org' + search_result.detail_item)
br = browser()
with closing(br.open(url, timeout=timeout)) as nf:
idata = html.fromstring(nf.read())
formats = ', '.join(idata.xpath('//p[@id="dl" and @class="content"]//a/text()'))
search_result.formats = formats.upper()
return True

View File

@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
from __future__ import (unicode_literals, division, absolute_import, print_function)
__license__ = 'GPL 3'
__copyright__ = '2011, Tomasz Długosz <tomek3d@gmail.com>'
__docformat__ = 'restructuredtext en'
import re
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 NextoStore(BasicStoreConfig, StorePlugin):
def open(self, parent=None, detail_item=None, external=False):
pid = '155711'
url = 'http://www.nexto.pl/ebooki_c1015.xml?pid=' + pid
detail_url = None
if detail_item:
book_id = re.search(r'p[0-9]*\.xml\Z', detail_item)
book_id = book_id.group(0).replace('.xml','').replace('p','')
if book_id:
detail_url = 'http://www.nexto.pl/rf/pr?p=' + book_id + '&pid=' + pid
if external or self.config.get('open_external', False):
open_url(QUrl(url_slash_cleaner(detail_url if detail_url else url)))
else:
d = WebStoreDialog(self.gui, url, parent, detail_url)
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.nexto.pl/szukaj.xml?search-clause=' + urllib.quote_plus(query.encode('utf-8')) + '&scid=1015'
br = browser()
counter = max_results
with closing(br.open(url, timeout=timeout)) as f:
doc = html.fromstring(f.read())
for data in doc.xpath('//ul[@class="productslist"]/li'):
if counter <= 0:
break
id = ''.join(data.xpath('.//div[@class="cover_container"]/a[1]/@href'))
if not id:
continue
price = ''.join(data.xpath('.//strong[@class="nprice"]/text()'))
cover_url = ''.join(data.xpath('.//img[@class="cover"]/@src'))
title = ''.join(data.xpath('.//a[@class="title"]/text()'))
formats = ', '.join(data.xpath('.//ul[@class="formats_available"]/li//b/text()'))
DrmFree = re.search(r'bez.DRM', formats)
formats = re.sub(r'\(.+\)', '', formats)
author = ''
with closing(br.open('http://www.nexto.pl/' + id.strip(), timeout=timeout/4)) as nf:
idata = html.fromstring(nf.read())
author = ''.join(idata.xpath('//div[@class="basic_data"]/p[1]/b/a/text()'))
counter -= 1
s = SearchResult()
s.cover_url = cover_url
s.title = title.strip()
s.author = author.strip()
s.price = price
s.detail_item = id.strip()
s.drm = SearchResult.DRM_UNLOCKED if DrmFree else SearchResult.DRM_LOCKED
s.formats = formats.upper().strip()
yield s

View File

@ -9,7 +9,7 @@ __docformat__ = 'restructuredtext en'
import re
from random import shuffle
from PyQt4.Qt import (Qt, QDialog, QTimer, QCheckBox, QVBoxLayout, QIcon)
from PyQt4.Qt import (Qt, QDialog, QTimer, QCheckBox, QVBoxLayout, QIcon, QWidget)
from calibre.gui2 import JSONConfig, info_dialog
from calibre.gui2.progress_indicator import ProgressIndicator
@ -47,14 +47,16 @@ class SearchDialog(QDialog, Ui_Dialog):
# Add check boxes for each store so the user
# can disable searching specific stores on a
# per search basis.
stores_check_widget = QWidget()
stores_group_layout = QVBoxLayout()
self.stores_group.setLayout(stores_group_layout)
stores_check_widget.setLayout(stores_group_layout)
for x in sorted(self.store_plugins.keys(), key=lambda x: x.lower()):
cbox = QCheckBox(x)
cbox.setChecked(True)
stores_group_layout.addWidget(cbox)
setattr(self, 'store_check_' + x, cbox)
stores_group_layout.addStretch()
self.stores_group.setWidget(stores_check_widget)
# Set the search query
self.search_edit.setText(query)