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
dbaac02e3c
@ -30,6 +30,7 @@ Environment variables
|
||||
* ``CALIBRE_OVERRIDE_DATABASE_PATH`` - allows you to specify the full path to metadata.db. Using this variable you can have metadata.db be in a location other than the library folder. Useful if your library folder is on a networked drive that does not support file locking.
|
||||
* ``CALIBRE_DEVELOP_FROM`` - Used to run from a calibre development environment. See :ref:`develop`.
|
||||
* ``CALIBRE_OVERRIDE_LANG`` - Used to force the language used by the interface (ISO 639 language code)
|
||||
* ``CALIBRE_NO_NATIVE_FILEDIALOGS`` - Causes calibre to not use native file dialogs for selecting files/directories.
|
||||
* ``SYSFS_PATH`` - Use if sysfs is mounted somewhere other than /sys
|
||||
* ``http_proxy`` - Used on linux to specify an HTTP proxy
|
||||
|
||||
|
@ -12,7 +12,11 @@ class AmericanProspect(BasicNewsRecipe):
|
||||
no_stylesheets = True
|
||||
remove_javascript = True
|
||||
|
||||
keep_only_tags = [dict(name='div', attrs={'class':'pad_10L10R'})]
|
||||
remove_tags = [dict(name='form'), dict(name='div', attrs={'class':['bkt_caption','sharebox noprint','badgebox']})]
|
||||
#keep_only_tags = [dict(name='div', attrs={'class':'pad_10L10R'})]
|
||||
#remove_tags = [dict(name='form'), dict(name='div', attrs={'class':['bkt_caption','sharebox noprint','badgebox']})]
|
||||
use_embedded_content = False
|
||||
|
||||
no_stylesheets = True
|
||||
auto_cleanup = True
|
||||
feeds = [(u'Articles', u'feed://www.prospect.org/articles_rss.jsp')]
|
||||
|
||||
|
@ -6,16 +6,15 @@ from calibre.web.feeds.recipes import BasicNewsRecipe
|
||||
class AdvancedUserRecipe1325006965(BasicNewsRecipe):
|
||||
|
||||
title = u'The Sun UK'
|
||||
description = 'A Recipe for The Sun tabloid UK'
|
||||
description = 'Articles from The Sun tabloid UK'
|
||||
__author__ = 'Dave Asbury'
|
||||
# last updated 29/4/12
|
||||
# last updated 15/7/12
|
||||
language = 'en_GB'
|
||||
oldest_article = 1
|
||||
max_articles_per_feed = 15
|
||||
remove_empty_feeds = True
|
||||
no_stylesheets = True
|
||||
#auto_cleanup = True
|
||||
#articles_are_obfuscated = True
|
||||
|
||||
|
||||
masthead_url = 'http://www.thesun.co.uk/sol/img/global/Sun-logo.gif'
|
||||
encoding = 'UTF-8'
|
||||
@ -34,7 +33,7 @@ class AdvancedUserRecipe1325006965(BasicNewsRecipe):
|
||||
|
||||
|
||||
keep_only_tags = [
|
||||
dict(name='h1'),dict(name='h2',attrs={'class' : 'medium centered'}),
|
||||
dict(name='h1'),dict(name='h2',attrs={'class' : ['large','large centered','medium centered','medium']}),dict(name='h3'),
|
||||
dict(name='div',attrs={'class' : 'text-center'}),
|
||||
dict(name='div',attrs={'id' : 'bodyText'})
|
||||
# dict(name='p')
|
||||
@ -72,22 +71,18 @@ class AdvancedUserRecipe1325006965(BasicNewsRecipe):
|
||||
cov2 = str(cov)
|
||||
cov2=cov2[27:-18]
|
||||
#cov2 now is pic url, now go back to original function
|
||||
|
||||
br = browser()
|
||||
br.set_handle_redirect(False)
|
||||
try:
|
||||
br.open_novisit(cov2)
|
||||
cover_url = cov2
|
||||
except:
|
||||
cover_url = random.choice((
|
||||
cover_url = random.choice([
|
||||
'http://img.thesun.co.uk/multimedia/archive/00905/errorpage6_677961a_905507a.jpg'
|
||||
,'http://img.thesun.co.uk/multimedia/archive/00905/errorpage7_677962a_905505a.jpg'
|
||||
,'http://img.thesun.co.uk/multimedia/archive/00905/errorpage5_677960a_905512a.jpg'
|
||||
,'http://img.thesun.co.uk/multimedia/archive/00905/errorpage2_677957a_905502a.jpg'
|
||||
,'http://img.thesun.co.uk/multimedia/archive/00905/errorpage3_677958a_905503a.jpg'
|
||||
))
|
||||
])
|
||||
|
||||
return cover_url
|
||||
|
||||
|
||||
|
||||
|
@ -98,15 +98,6 @@ authors_split_regex = r'(?i),?\s+(and|with)\s+'
|
||||
# categories_use_field_for_author_name = 'author_sort'
|
||||
categories_use_field_for_author_name = 'author'
|
||||
|
||||
#: Completion sort order: choose when to change from lexicographic to ASCII-like
|
||||
# Calibre normally uses locale-dependent lexicographic ordering when showing
|
||||
# completion values. This means that the sort order is correct for the user's
|
||||
# language. However, this can be slow. Performance is improved by switching to
|
||||
# ascii ordering. This tweak controls when that switch happens. Set it to zero
|
||||
# to always use ascii ordering. Set it to something larger than zero to switch
|
||||
# to ascii ordering for performance reasons.
|
||||
completion_change_to_ascii_sorting = 2500
|
||||
|
||||
#: Control partitioning of Tag Browser
|
||||
# When partitioning the tags browser, the format of the subcategory label is
|
||||
# controlled by a template: categories_collapsed_name_template if sorting by
|
||||
@ -525,3 +516,11 @@ default_tweak_format = None
|
||||
# enable_multicharacters_in_tag_browser = False
|
||||
enable_multicharacters_in_tag_browser = True
|
||||
|
||||
#: Do not preselect a completion when editing authors/tags/series/etc.
|
||||
# This means that you can make changes and press Enter and your changes will
|
||||
# not be overwritten by a matching completion. However, if you wish to use the
|
||||
# completions you will now have to press Tab to select one before pressing
|
||||
# Enter. Which technique you prefer will depend on the state of metadata in
|
||||
# your library and your personal editing style.
|
||||
preselect_first_completion = False
|
||||
|
||||
|
@ -23,6 +23,7 @@ MAGICK_PREFIX = '/usr'
|
||||
binary_includes = [
|
||||
'/usr/bin/pdftohtml',
|
||||
'/usr/bin/pdfinfo',
|
||||
'/usr/lib/libglib-2.0.so.0',
|
||||
'/usr/bin/pdftoppm',
|
||||
'/usr/lib/libwmflite-0.2.so.7',
|
||||
'/usr/lib/liblcms.so.1',
|
||||
|
@ -1483,6 +1483,16 @@ class StoreManyBooksStore(StoreBase):
|
||||
headquarters = 'US'
|
||||
formats = ['EPUB', 'FB2', 'JAR', 'LIT', 'LRF', 'MOBI', 'PDB', 'PDF', 'RB', 'RTF', 'TCR', 'TXT', 'ZIP']
|
||||
|
||||
class StoreMillsBoonUKStore(StoreBase):
|
||||
name = 'Mills and Boon UK'
|
||||
author = 'Charles Haley'
|
||||
description = u'"Bring Romance to Life" "[A] hallmark for romantic fiction, recognised around the world."'
|
||||
actual_plugin = 'calibre.gui2.store.stores.mills_boon_uk_plugin:MillsBoonUKStore'
|
||||
|
||||
headquarters = 'UK'
|
||||
formats = ['EPUB']
|
||||
affiliate = True
|
||||
|
||||
class StoreMobileReadStore(StoreBase):
|
||||
name = 'MobileRead'
|
||||
description = u'Ebooks handcrafted with the utmost care.'
|
||||
@ -1646,6 +1656,7 @@ plugins += [
|
||||
StoreLibreDEStore,
|
||||
StoreLitResStore,
|
||||
StoreManyBooksStore,
|
||||
StoreMillsBoonUKStore,
|
||||
StoreMobileReadStore,
|
||||
StoreNextoStore,
|
||||
StoreOpenBooksStore,
|
||||
|
@ -194,7 +194,7 @@ class ANDROID(USBMS):
|
||||
'GENERIC-', 'ZTE', 'MID', 'QUALCOMM', 'PANDIGIT', 'HYSTON',
|
||||
'VIZIO', 'GOOGLE', 'FREESCAL', 'KOBO_INC', 'LENOVO', 'ROCKCHIP',
|
||||
'POCKET', 'ONDA_MID', 'ZENITHIN', 'INGENIC', 'PMID701C', 'PD',
|
||||
'PMP5097C']
|
||||
'PMP5097C', 'MASS', 'NOVO7']
|
||||
WINDOWS_MAIN_MEM = ['ANDROID_PHONE', 'A855', 'A853', 'INC.NEXUS_ONE',
|
||||
'__UMS_COMPOSITE', '_MB200', 'MASS_STORAGE', '_-_CARD', 'SGH-I897',
|
||||
'GT-I9000', 'FILE-STOR_GADGET', 'SGH-T959_CARD', 'SGH-T959', 'SAMSUNG_ANDROID',
|
||||
@ -211,7 +211,8 @@ class ANDROID(USBMS):
|
||||
'XT910', 'BOOK_A10', 'USB_2.0_DRIVER', 'I9100T', 'P999DW',
|
||||
'KTABLET_PC', 'INGENIC', 'GT-I9001_CARD', 'USB_2.0_DRIVER',
|
||||
'GT-S5830L_CARD', 'UNIVERSE', 'XT875', 'PRO', '.KOBO_VOX',
|
||||
'THINKPAD_TABLET', 'SGH-T989', 'YP-G70']
|
||||
'THINKPAD_TABLET', 'SGH-T989', 'YP-G70', 'STORAGE_DEVICE',
|
||||
'ADVANCED']
|
||||
WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'GT-I9000_CARD', 'SGH-I897',
|
||||
'FILE-STOR_GADGET', 'SGH-T959_CARD', 'SGH-T959', 'SAMSUNG_ANDROID', 'GT-P1000_CARD',
|
||||
'A70S', 'A101IT', '7', 'INCREDIBLE', 'A7EB', 'SGH-T849_CARD',
|
||||
|
@ -163,6 +163,7 @@ class EXTHRecord(object):
|
||||
501 : 'cdetype', # 4 chars (PDOC or EBOK)
|
||||
502 : 'lastupdatetime',
|
||||
503 : 'updatedtitle',
|
||||
524 : 'language',
|
||||
}.get(self.type, repr(self.type))
|
||||
|
||||
if (self.name in {'coveroffset', 'thumboffset', 'hasfakecover',
|
||||
|
@ -13,6 +13,7 @@ from calibre.utils.date import parse_date
|
||||
from calibre.ebooks.mobi import MobiError
|
||||
from calibre.ebooks.metadata import MetaInformation, check_isbn
|
||||
from calibre.ebooks.mobi.langcodes import main_language, sub_language, mobi2iana
|
||||
from calibre.utils.localization import canonicalize_lang
|
||||
|
||||
NULL_INDEX = 0xffffffff
|
||||
|
||||
@ -68,6 +69,14 @@ class EXTHHeader(object): # {{{
|
||||
title = content.decode(codec)
|
||||
except:
|
||||
pass
|
||||
elif idx == 524: # Lang code
|
||||
try:
|
||||
lang = content.decode(codec)
|
||||
lang = canonicalize_lang(lang)
|
||||
if lang:
|
||||
self.mi.language = lang
|
||||
except:
|
||||
pass
|
||||
#else:
|
||||
# print 'unknown record', idx, repr(content)
|
||||
if title:
|
||||
@ -201,10 +210,11 @@ class BookHeader(object):
|
||||
self.exth = EXTHHeader(raw[16 + self.length:], self.codec,
|
||||
self.title)
|
||||
self.exth.mi.uid = self.unique_id
|
||||
try:
|
||||
self.exth.mi.language = mobi2iana(langid, sublangid)
|
||||
except:
|
||||
self.log.exception('Unknown language code')
|
||||
if self.exth.mi.is_null('language'):
|
||||
try:
|
||||
self.exth.mi.language = mobi2iana(langid, sublangid)
|
||||
except:
|
||||
self.log.exception('Unknown language code')
|
||||
except:
|
||||
self.log.exception('Invalid EXTH header')
|
||||
self.exth_flag = 0
|
||||
|
@ -297,10 +297,13 @@ class MobiWriter(object):
|
||||
|
||||
# 0x70 - 0x73 : EXTH flags
|
||||
# Bit 6 (0b1000000) being set indicates the presence of an EXTH header
|
||||
# Bit 12 being set indicates the presence of embedded fonts
|
||||
# The purpose of the other bits is unknown
|
||||
exth_flags = 0b1010000
|
||||
if self.is_periodical:
|
||||
exth_flags |= 0b1000
|
||||
if self.resources.has_fonts:
|
||||
exth_flags |= 0b1000000000000
|
||||
record0.write(pack(b'>I', exth_flags))
|
||||
|
||||
# 0x74 - 0x93 : Unknown
|
||||
@ -406,7 +409,10 @@ class MobiWriter(object):
|
||||
# Now change the header fields that need to be different in the MOBI 6
|
||||
# header
|
||||
header_fields['first_resource_record'] = first_image_record
|
||||
header_fields['exth_flags'] = 0b100001010000 # Kinglegen uses this
|
||||
ef = 0b100001010000 # Kinglegen uses this
|
||||
if self.resources.has_fonts:
|
||||
ef |= 0b1000000000000
|
||||
header_fields['exth_flags'] = ef
|
||||
header_fields['fdst_record'] = pack(b'>HH', 1, last_content_record)
|
||||
header_fields['fdst_count'] = 1 # Why not 0? Kindlegen uses 1
|
||||
header_fields['flis_record'] = flis_number
|
||||
|
@ -32,6 +32,7 @@ class Resources(object):
|
||||
self.used_image_indices = set()
|
||||
self.image_indices = set()
|
||||
self.cover_offset = self.thumbnail_offset = None
|
||||
self.has_fonts = False
|
||||
|
||||
self.add_resources(add_fonts)
|
||||
|
||||
@ -109,6 +110,7 @@ class Resources(object):
|
||||
'ttf', 'otf'} and isinstance(item.data, bytes):
|
||||
self.records.append(write_font_record(item.data))
|
||||
self.item_map[item.href] = len(self.records)
|
||||
self.has_fonts = True
|
||||
|
||||
def add_extra_images(self):
|
||||
'''
|
||||
|
@ -12,6 +12,7 @@ from struct import pack
|
||||
from io import BytesIO
|
||||
|
||||
from calibre.ebooks.mobi.utils import utf8_text
|
||||
from calibre.utils.localization import lang_as_iso639_1
|
||||
|
||||
EXTH_CODES = {
|
||||
'creator': 100,
|
||||
@ -35,6 +36,7 @@ EXTH_CODES = {
|
||||
'hasfakecover': 203,
|
||||
'lastupdatetime': 502,
|
||||
'title': 503,
|
||||
'language': 524,
|
||||
}
|
||||
|
||||
COLLAPSE_RE = re.compile(r'[ \t\r\n\v]+')
|
||||
@ -57,6 +59,16 @@ def build_exth(metadata, prefer_author_sort=False, is_periodical=False,
|
||||
else:
|
||||
creators = [unicode(c) for c in items]
|
||||
items = creators
|
||||
elif term == 'rights':
|
||||
try:
|
||||
rights = utf8_text(unicode(metadata.rights[0]))
|
||||
except:
|
||||
rights = b'Unknown'
|
||||
exth.write(pack(b'>II', EXTH_CODES['rights'], len(rights) + 8))
|
||||
exth.write(rights)
|
||||
nrecs += 1
|
||||
continue
|
||||
|
||||
for item in items:
|
||||
data = unicode(item)
|
||||
if term != 'description':
|
||||
@ -68,18 +80,14 @@ def build_exth(metadata, prefer_author_sort=False, is_periodical=False,
|
||||
pass
|
||||
else:
|
||||
continue
|
||||
if term == 'language':
|
||||
d2 = lang_as_iso639_1(data)
|
||||
if d2:
|
||||
data = d2
|
||||
data = utf8_text(data)
|
||||
exth.write(pack(b'>II', code, len(data) + 8))
|
||||
exth.write(data)
|
||||
nrecs += 1
|
||||
if term == 'rights' :
|
||||
try:
|
||||
rights = utf8_text(unicode(metadata.rights[0]))
|
||||
except:
|
||||
rights = b'Unknown'
|
||||
exth.write(pack(b'>II', EXTH_CODES['rights'], len(rights) + 8))
|
||||
exth.write(rights)
|
||||
nrecs += 1
|
||||
|
||||
# Write UUID as ASIN
|
||||
uuid = None
|
||||
@ -132,7 +140,7 @@ def build_exth(metadata, prefer_author_sort=False, is_periodical=False,
|
||||
nrecs += 1
|
||||
|
||||
if be_kindlegen2:
|
||||
vals = {204:201, 205:2, 206:2, 207:35621}
|
||||
vals = {204:201, 205:2, 206:5, 207:0}
|
||||
elif is_periodical:
|
||||
# Pretend to be amazon's super secret periodical generator
|
||||
vals = {204:201, 205:2, 206:0, 207:101}
|
||||
|
@ -277,6 +277,8 @@ class KF8Book(object):
|
||||
self.exth_flags = 0b1010000
|
||||
if writer.opts.mobi_periodical:
|
||||
self.exth_flags |= 0b1000
|
||||
if resources.has_fonts:
|
||||
self.exth_flags |= 0b1000000000000
|
||||
|
||||
self.opts = writer.opts
|
||||
self.start_offset = writer.start_offset
|
||||
|
@ -223,7 +223,8 @@ class PDFWriter(QObject): # {{{
|
||||
if self.cover_data is None:
|
||||
return
|
||||
item_path = os.path.join(self.tmp_path, 'cover.pdf')
|
||||
printer = get_pdf_printer(self.opts, output_file_name=item_path)
|
||||
printer = get_pdf_printer(self.opts, output_file_name=item_path,
|
||||
for_comic=True)
|
||||
self.combine_queue.insert(0, item_path)
|
||||
p = QPixmap()
|
||||
p.loadFromData(self.cover_data)
|
||||
|
@ -573,17 +573,24 @@ class FileDialog(QObject):
|
||||
if not isinstance(initial_dir, basestring):
|
||||
initial_dir = os.path.expanduser(default_dir)
|
||||
self.selected_files = []
|
||||
use_native_dialog = not os.environ.has_key('CALIBRE_NO_NATIVE_FILEDIALOGS')
|
||||
with SanitizeLibraryPath():
|
||||
opts = QFileDialog.Option()
|
||||
if not use_native_dialog:
|
||||
opts |= QFileDialog.DontUseNativeDialog
|
||||
if mode == QFileDialog.AnyFile:
|
||||
f = unicode(QFileDialog.getSaveFileName(parent, title, initial_dir, ftext, ""))
|
||||
f = unicode(QFileDialog.getSaveFileName(parent, title,
|
||||
initial_dir, ftext, "", opts))
|
||||
if f:
|
||||
self.selected_files.append(f)
|
||||
elif mode == QFileDialog.ExistingFile:
|
||||
f = unicode(QFileDialog.getOpenFileName(parent, title, initial_dir, ftext, ""))
|
||||
f = unicode(QFileDialog.getOpenFileName(parent, title,
|
||||
initial_dir, ftext, "", opts))
|
||||
if f and os.path.exists(f):
|
||||
self.selected_files.append(f)
|
||||
elif mode == QFileDialog.ExistingFiles:
|
||||
fs = QFileDialog.getOpenFileNames(parent, title, initial_dir, ftext, "")
|
||||
fs = QFileDialog.getOpenFileNames(parent, title, initial_dir,
|
||||
ftext, "", opts)
|
||||
for f in fs:
|
||||
f = unicode(f)
|
||||
if not f: continue
|
||||
@ -594,7 +601,8 @@ class FileDialog(QObject):
|
||||
if f and os.path.exists(f):
|
||||
self.selected_files.append(f)
|
||||
else:
|
||||
opts = QFileDialog.ShowDirsOnly if mode == QFileDialog.Directory else QFileDialog.Option()
|
||||
if mode == QFileDialog.Directory:
|
||||
opts |= QFileDialog.ShowDirsOnly
|
||||
f = unicode(QFileDialog.getExistingDirectory(parent, title, initial_dir, opts))
|
||||
if os.path.exists(f):
|
||||
self.selected_files.append(f)
|
||||
|
@ -16,7 +16,6 @@ from PyQt4.Qt import (QLineEdit, QAbstractListModel, Qt,
|
||||
from calibre.utils.icu import sort_key
|
||||
from calibre.gui2 import NONE
|
||||
from calibre.gui2.widgets import EnComboBox, LineEditECM
|
||||
from calibre.utils.config_base import tweaks
|
||||
|
||||
class CompleteModel(QAbstractListModel):
|
||||
|
||||
@ -27,7 +26,7 @@ class CompleteModel(QAbstractListModel):
|
||||
|
||||
def set_items(self, items):
|
||||
items = [unicode(x.strip()) for x in items]
|
||||
if len(items) < tweaks['completion_change_to_ascii_sorting']:
|
||||
if len(items) < 2500:
|
||||
self.items = sorted(items, key=sort_key)
|
||||
self.sorting = QCompleter.UnsortedModel
|
||||
else:
|
||||
|
@ -16,6 +16,7 @@ from PyQt4.Qt import (QLineEdit, QAbstractListModel, Qt, pyqtSignal, QObject,
|
||||
from calibre.utils.icu import sort_key, primary_startswith
|
||||
from calibre.gui2 import NONE
|
||||
from calibre.gui2.widgets import EnComboBox, LineEditECM
|
||||
from calibre.utils.config import tweaks
|
||||
|
||||
class CompleteModel(QAbstractListModel): # {{{
|
||||
|
||||
@ -157,8 +158,8 @@ class Completer(QListView): # {{{
|
||||
|
||||
p.setGeometry(pos.x(), pos.y(), w, h)
|
||||
|
||||
if (select_first and not self.currentIndex().isValid() and
|
||||
self.model().rowCount() > 0):
|
||||
if (tweaks['preselect_first_completion'] and select_first and not
|
||||
self.currentIndex().isValid() and self.model().rowCount() > 0):
|
||||
self.setCurrentIndex(self.model().index(0))
|
||||
|
||||
if not p.isVisible():
|
||||
@ -189,12 +190,11 @@ class Completer(QListView): # {{{
|
||||
e.accept()
|
||||
return True
|
||||
return False
|
||||
if key in (Qt.Key_End, Qt.Key_Home, Qt.Key_Up, Qt.Key_Down,
|
||||
Qt.Key_PageUp, Qt.Key_PageDown):
|
||||
if key in (Qt.Key_PageUp, Qt.Key_PageDown):
|
||||
# Let the list view handle these keys
|
||||
return False
|
||||
if key in (Qt.Key_Tab, Qt.Key_Backtab):
|
||||
self.next_match(previous=key == Qt.Key_Backtab)
|
||||
if key in (Qt.Key_Tab, Qt.Key_Backtab, Qt.Key_Up, Qt.Key_Down):
|
||||
self.next_match(previous=key in (Qt.Key_Backtab, Qt.Key_Up))
|
||||
e.accept()
|
||||
return True
|
||||
# Send to widget
|
||||
@ -284,6 +284,8 @@ class LineEdit(QLineEdit, LineEditECM):
|
||||
if self.no_popup: return
|
||||
self.update_completions()
|
||||
select_first = len(self.mcompleter.model().current_prefix) > 0
|
||||
if not select_first:
|
||||
self.mcompleter.setCurrentIndex(QModelIndex())
|
||||
self.complete(select_first=select_first)
|
||||
|
||||
def update_completions(self):
|
||||
|
78
src/calibre/gui2/store/stores/mills_boon_uk_plugin.py
Normal file
78
src/calibre/gui2/store/stores/mills_boon_uk_plugin.py
Normal file
@ -0,0 +1,78 @@
|
||||
# -*- 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 urllib2
|
||||
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 MillsBoonUKStore(BasicStoreConfig, StorePlugin):
|
||||
|
||||
def open(self, parent=None, detail_item=None, external=False):
|
||||
url = 'http://www.awin1.com/awclick.php?mid=1150&id=120917'
|
||||
detail_url = 'http://www.awin1.com/cread.php?awinmid=1150&awinaffid=120917&clickref=&p='
|
||||
|
||||
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:
|
||||
detail_url = None
|
||||
if detail_item:
|
||||
detail_url = url + detail_item
|
||||
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):
|
||||
base_url = 'http://millsandboon.co.uk'
|
||||
url = base_url + '/pages/searchres.htm?search=true&booktypesearch=ebook&first=yes&inputsearch=' + urllib2.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('//div[@class="catProdDiv"]'):
|
||||
if counter <= 0:
|
||||
break
|
||||
id_ = ''.join(data.xpath('.//div[@class="catProdImage"]/div/a/@href')).strip()
|
||||
id_ = base_url + id_[2:]
|
||||
if not id_:
|
||||
continue
|
||||
|
||||
cover_url = ''.join(data.xpath('.//div[@class="catProdImage"]/div/a/img/@src'))
|
||||
cover_url = base_url + cover_url[2:]
|
||||
title = ''.join(data.xpath('.//div[@class="catProdImage"]/div/a/img/@alt')).strip()
|
||||
title = title[23:]
|
||||
author = ''.join(data.xpath('.//div[@class="catProdDetails"]/div[@class="catProdDetails-top"]/p[1]/a/text()'))
|
||||
price = ''.join(data.xpath('.//span[@class="priceBold"]/text()'))
|
||||
format_ = ''.join(data.xpath('.//p[@class="doc-meta-format"]/span[last()]/text()'))
|
||||
drm = SearchResult.DRM_LOCKED
|
||||
|
||||
counter -= 1
|
||||
|
||||
s = SearchResult()
|
||||
s.cover_url = cover_url
|
||||
s.title = title.strip()
|
||||
s.author = author.strip()
|
||||
s.price = price
|
||||
s.detail_item = id_
|
||||
s.drm = drm
|
||||
s.formats = format_
|
||||
|
||||
yield s
|
@ -1096,8 +1096,11 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
identical_book_ids = set([])
|
||||
if mi.authors:
|
||||
try:
|
||||
quathors = mi.authors[:10] # Too many authors causes parsing of
|
||||
# the search expression to fail
|
||||
query = u' and '.join([u'author:"=%s"'%(a.replace('"', '')) for a in
|
||||
mi.authors])
|
||||
quathors])
|
||||
qauthors = mi.authors[10:]
|
||||
except ValueError:
|
||||
return identical_book_ids
|
||||
try:
|
||||
@ -1105,6 +1108,18 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
except:
|
||||
traceback.print_exc()
|
||||
return identical_book_ids
|
||||
if qauthors and book_ids:
|
||||
matches = set()
|
||||
qauthors = {lower(x) for x in qauthors}
|
||||
for book_id in book_ids:
|
||||
aut = self.authors(book_id, index_is_id=True)
|
||||
if aut:
|
||||
aut = {lower(x.replace('|', ',')) for x in
|
||||
aut.split(',')}
|
||||
if aut.issuperset(qauthors):
|
||||
matches.add(book_id)
|
||||
book_ids = matches
|
||||
|
||||
for book_id in book_ids:
|
||||
fbook_title = self.title(book_id, index_is_id=True)
|
||||
fbook_title = fuzzy_title(fbook_title)
|
||||
|
Loading…
x
Reference in New Issue
Block a user