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
ad23762ae6
@ -131,7 +131,7 @@ class ZeitEPUBAbo(BasicNewsRecipe):
|
|||||||
browser.form['pass']=self.password
|
browser.form['pass']=self.password
|
||||||
browser.submit()
|
browser.submit()
|
||||||
# now find the correct file, we will still use the ePub file
|
# now find the correct file, we will still use the ePub file
|
||||||
epublink = browser.find_link(text_regex=re.compile('.*Ausgabe als Datei im ePub-Format.*'))
|
epublink = browser.find_link(text_regex=re.compile('.*Download als Datei im ePub-Format für eReader.*'))
|
||||||
response = browser.follow_link(epublink)
|
response = browser.follow_link(epublink)
|
||||||
self.report_progress(1,_('next step'))
|
self.report_progress(1,_('next step'))
|
||||||
|
|
||||||
|
@ -224,7 +224,7 @@ class TREKSTOR(USBMS):
|
|||||||
FORMATS = ['epub', 'txt', 'pdf']
|
FORMATS = ['epub', 'txt', 'pdf']
|
||||||
|
|
||||||
VENDOR_ID = [0x1e68]
|
VENDOR_ID = [0x1e68]
|
||||||
PRODUCT_ID = [0x0041, 0x0042, 0x0052,
|
PRODUCT_ID = [0x0041, 0x0042, 0x0052, 0x004e,
|
||||||
0x003e # This is for the EBOOK_PLAYER_5M https://bugs.launchpad.net/bugs/792091
|
0x003e # This is for the EBOOK_PLAYER_5M https://bugs.launchpad.net/bugs/792091
|
||||||
]
|
]
|
||||||
BCD = [0x0002]
|
BCD = [0x0002]
|
||||||
|
@ -30,6 +30,8 @@ CONTENT_TAGS = set(['img', 'hr', 'br'])
|
|||||||
|
|
||||||
NOT_VTAGS = HEADER_TAGS | NESTABLE_TAGS | TABLE_TAGS | SPECIAL_TAGS | \
|
NOT_VTAGS = HEADER_TAGS | NESTABLE_TAGS | TABLE_TAGS | SPECIAL_TAGS | \
|
||||||
CONTENT_TAGS
|
CONTENT_TAGS
|
||||||
|
LEAF_TAGS = set(['base', 'basefont', 'frame', 'link', 'meta', 'area', 'br',
|
||||||
|
'col', 'hr', 'img', 'input', 'param'])
|
||||||
PAGE_BREAKS = set(['always', 'left', 'right'])
|
PAGE_BREAKS = set(['always', 'left', 'right'])
|
||||||
|
|
||||||
COLLAPSE = re.compile(r'[ \t\r\n\v]+')
|
COLLAPSE = re.compile(r'[ \t\r\n\v]+')
|
||||||
@ -246,7 +248,17 @@ class MobiMLizer(object):
|
|||||||
last.text = None
|
last.text = None
|
||||||
else:
|
else:
|
||||||
last = bstate.body[-1]
|
last = bstate.body[-1]
|
||||||
|
# We use append instead of addprevious so that inline
|
||||||
|
# anchors in large blocks point to the correct place. See
|
||||||
|
# https://bugs.launchpad.net/calibre/+bug/899831
|
||||||
|
# This could potentially break if inserting an anchor at
|
||||||
|
# this point in the markup is illegal, but I cannot think
|
||||||
|
# of such a case offhand.
|
||||||
|
if barename(last.tag) in LEAF_TAGS:
|
||||||
last.addprevious(anchor)
|
last.addprevious(anchor)
|
||||||
|
else:
|
||||||
|
last.append(anchor)
|
||||||
|
|
||||||
istate.ids.clear()
|
istate.ids.clear()
|
||||||
if not text:
|
if not text:
|
||||||
return
|
return
|
||||||
@ -528,7 +540,11 @@ class MobiMLizer(object):
|
|||||||
old_mim = self.opts.mobi_ignore_margins
|
old_mim = self.opts.mobi_ignore_margins
|
||||||
self.opts.mobi_ignore_margins = False
|
self.opts.mobi_ignore_margins = False
|
||||||
|
|
||||||
if text or tag in CONTENT_TAGS or tag in NESTABLE_TAGS:
|
if (text or tag in CONTENT_TAGS or tag in NESTABLE_TAGS or (
|
||||||
|
# We have an id but no text and no children, the id should still
|
||||||
|
# be added.
|
||||||
|
istate.ids and tag in ('a', 'span', 'i', 'b', 'u') and
|
||||||
|
len(elem)==0)):
|
||||||
self.mobimlize_content(tag, text, bstate, istates)
|
self.mobimlize_content(tag, text, bstate, istates)
|
||||||
for child in elem:
|
for child in elem:
|
||||||
self.mobimlize_elem(child, stylizer, bstate, istates)
|
self.mobimlize_elem(child, stylizer, bstate, istates)
|
||||||
|
@ -18,7 +18,8 @@ from calibre.ebooks.chardet import xml_to_unicode
|
|||||||
from calibre.utils.zipfile import safe_replace
|
from calibre.utils.zipfile import safe_replace
|
||||||
from calibre.utils.config import DynamicConfig
|
from calibre.utils.config import DynamicConfig
|
||||||
from calibre.utils.logging import Log
|
from calibre.utils.logging import Log
|
||||||
from calibre import guess_type, prints, prepare_string_for_xml
|
from calibre import (guess_type, prints, prepare_string_for_xml,
|
||||||
|
xml_replace_entities)
|
||||||
from calibre.ebooks.oeb.transforms.cover import CoverManager
|
from calibre.ebooks.oeb.transforms.cover import CoverManager
|
||||||
from calibre.constants import filesystem_encoding
|
from calibre.constants import filesystem_encoding
|
||||||
|
|
||||||
@ -96,13 +97,19 @@ class EbookIterator(object):
|
|||||||
self.ebook_ext = ext.replace('original_', '')
|
self.ebook_ext = ext.replace('original_', '')
|
||||||
|
|
||||||
def search(self, text, index, backwards=False):
|
def search(self, text, index, backwards=False):
|
||||||
text = text.lower()
|
text = prepare_string_for_xml(text.lower())
|
||||||
pmap = [(i, path) for i, path in enumerate(self.spine)]
|
pmap = [(i, path) for i, path in enumerate(self.spine)]
|
||||||
if backwards:
|
if backwards:
|
||||||
pmap.reverse()
|
pmap.reverse()
|
||||||
for i, path in pmap:
|
for i, path in pmap:
|
||||||
if (backwards and i < index) or (not backwards and i > index):
|
if (backwards and i < index) or (not backwards and i > index):
|
||||||
if text in open(path, 'rb').read().decode(path.encoding).lower():
|
with open(path, 'rb') as f:
|
||||||
|
raw = f.read().decode(path.encoding)
|
||||||
|
try:
|
||||||
|
raw = xml_replace_entities(raw)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if text in raw.lower():
|
||||||
return i
|
return i
|
||||||
|
|
||||||
def find_missing_css_files(self):
|
def find_missing_css_files(self):
|
||||||
|
@ -9,7 +9,7 @@ from PyQt4.Qt import QThread, QObject, Qt, QProgressDialog, pyqtSignal, QTimer
|
|||||||
|
|
||||||
from calibre.gui2.dialogs.progress import ProgressDialog
|
from calibre.gui2.dialogs.progress import ProgressDialog
|
||||||
from calibre.gui2 import (question_dialog, error_dialog, info_dialog, gprefs,
|
from calibre.gui2 import (question_dialog, error_dialog, info_dialog, gprefs,
|
||||||
warning_dialog)
|
warning_dialog, available_width)
|
||||||
from calibre.ebooks.metadata.opf2 import OPF
|
from calibre.ebooks.metadata.opf2 import OPF
|
||||||
from calibre.ebooks.metadata import MetaInformation
|
from calibre.ebooks.metadata import MetaInformation
|
||||||
from calibre.constants import preferred_encoding, filesystem_encoding, DEBUG
|
from calibre.constants import preferred_encoding, filesystem_encoding, DEBUG
|
||||||
@ -244,6 +244,7 @@ class Adder(QObject): # {{{
|
|||||||
def __init__(self, parent, db, callback, spare_server=None):
|
def __init__(self, parent, db, callback, spare_server=None):
|
||||||
QObject.__init__(self, parent)
|
QObject.__init__(self, parent)
|
||||||
self.pd = ProgressDialog(_('Adding...'), parent=parent)
|
self.pd = ProgressDialog(_('Adding...'), parent=parent)
|
||||||
|
self.pd.setMaximumWidth(min(600, int(available_width()*0.75)))
|
||||||
self.spare_server = spare_server
|
self.spare_server = spare_server
|
||||||
self.db = db
|
self.db = db
|
||||||
self.pd.setModal(True)
|
self.pd.setModal(True)
|
||||||
|
@ -25,7 +25,8 @@ from calibre.utils.logging import Log
|
|||||||
|
|
||||||
class BulkConfig(Config):
|
class BulkConfig(Config):
|
||||||
|
|
||||||
def __init__(self, parent, db, preferred_output_format=None):
|
def __init__(self, parent, db, preferred_output_format=None,
|
||||||
|
has_saved_settings=True):
|
||||||
ResizableDialog.__init__(self, parent)
|
ResizableDialog.__init__(self, parent)
|
||||||
|
|
||||||
self.setup_output_formats(db, preferred_output_format)
|
self.setup_output_formats(db, preferred_output_format)
|
||||||
@ -54,6 +55,12 @@ class BulkConfig(Config):
|
|||||||
rb = self.buttonBox.button(self.buttonBox.RestoreDefaults)
|
rb = self.buttonBox.button(self.buttonBox.RestoreDefaults)
|
||||||
rb.setVisible(False)
|
rb.setVisible(False)
|
||||||
self.groups.setMouseTracking(True)
|
self.groups.setMouseTracking(True)
|
||||||
|
if not has_saved_settings:
|
||||||
|
o = self.opt_individual_saved_settings
|
||||||
|
o.setEnabled(False)
|
||||||
|
o.setToolTip(_('None of the selected books have saved conversion '
|
||||||
|
'settings.'))
|
||||||
|
o.setChecked(False)
|
||||||
|
|
||||||
|
|
||||||
def setup_pipeline(self, *args):
|
def setup_pipeline(self, *args):
|
||||||
|
@ -70,7 +70,7 @@ if pictureflow is not None:
|
|||||||
ans = ''
|
ans = ''
|
||||||
except:
|
except:
|
||||||
ans = ''
|
ans = ''
|
||||||
return ans
|
return ans.replace('&', '&&')
|
||||||
|
|
||||||
def subtitle(self, index):
|
def subtitle(self, index):
|
||||||
try:
|
try:
|
||||||
|
@ -5,8 +5,9 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
import os
|
import os, itertools, operator
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
from future_builtins import map
|
||||||
|
|
||||||
from PyQt4.Qt import (QTableView, Qt, QAbstractItemView, QMenu, pyqtSignal,
|
from PyQt4.Qt import (QTableView, Qt, QAbstractItemView, QMenu, pyqtSignal,
|
||||||
QModelIndex, QIcon, QItemSelection, QMimeData, QDrag, QApplication,
|
QModelIndex, QIcon, QItemSelection, QMimeData, QDrag, QApplication,
|
||||||
@ -793,8 +794,13 @@ class BooksView(QTableView): # {{{
|
|||||||
sel = QItemSelection()
|
sel = QItemSelection()
|
||||||
m = self.model()
|
m = self.model()
|
||||||
max_col = m.columnCount(QModelIndex()) - 1
|
max_col = m.columnCount(QModelIndex()) - 1
|
||||||
for row in rows:
|
# Create a range based selector for each set of contiguous rows
|
||||||
sel.select(m.index(row, 0), m.index(row, max_col))
|
# as supplying selectors for each individual row causes very poor
|
||||||
|
# performance if a large number of rows has to be selected.
|
||||||
|
for k, g in itertools.groupby(enumerate(rows), lambda (i,x):i-x):
|
||||||
|
group = list(map(operator.itemgetter(1), g))
|
||||||
|
sel.merge(QItemSelection(m.index(min(group), 0),
|
||||||
|
m.index(max(group), max_col)), sm.Select)
|
||||||
sm.select(sel, sm.ClearAndSelect)
|
sm.select(sel, sm.ClearAndSelect)
|
||||||
|
|
||||||
def get_selected_ids(self):
|
def get_selected_ids(self):
|
||||||
|
@ -252,7 +252,7 @@ class SearchDialog(QDialog, Ui_Dialog):
|
|||||||
# Milliseconds
|
# Milliseconds
|
||||||
self.hang_time = self.config.get('hang_time', 75) * 1000
|
self.hang_time = self.config.get('hang_time', 75) * 1000
|
||||||
|
|
||||||
self.max_results = self.config.get('max_results', 10)
|
self.max_results = self.config.get('max_results', 15)
|
||||||
self.should_open_external = self.config.get('open_external', True)
|
self.should_open_external = self.config.get('open_external', True)
|
||||||
|
|
||||||
# Number of threads to run for each type of operation
|
# Number of threads to run for each type of operation
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
<string>Get Books</string>
|
<string>Get Books</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowIcon">
|
<property name="windowIcon">
|
||||||
<iconset resource="../../../../../resources/images.qrc">
|
<iconset>
|
||||||
<normaloff>:/images/store.png</normaloff>:/images/store.png</iconset>
|
<normaloff>:/images/store.png</normaloff>:/images/store.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
<property name="sizeGripEnabled">
|
<property name="sizeGripEnabled">
|
||||||
@ -82,8 +82,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>173</width>
|
<width>193</width>
|
||||||
<height>106</height>
|
<height>127</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
@ -254,6 +254,19 @@
|
|||||||
<header>widgets.h</header>
|
<header>widgets.h</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>search_edit</tabstop>
|
||||||
|
<tabstop>search</tabstop>
|
||||||
|
<tabstop>results_view</tabstop>
|
||||||
|
<tabstop>store_list</tabstop>
|
||||||
|
<tabstop>select_all_stores</tabstop>
|
||||||
|
<tabstop>select_invert_stores</tabstop>
|
||||||
|
<tabstop>select_none_stores</tabstop>
|
||||||
|
<tabstop>configure</tabstop>
|
||||||
|
<tabstop>open_external</tabstop>
|
||||||
|
<tabstop>close</tabstop>
|
||||||
|
<tabstop>adv_search_button</tabstop>
|
||||||
|
</tabstops>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../../../../../resources/images.qrc"/>
|
<include location="../../../../../resources/images.qrc"/>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -40,9 +40,9 @@ class ChitankaStore(BasicStoreConfig, StorePlugin):
|
|||||||
d.exec_()
|
d.exec_()
|
||||||
|
|
||||||
def search(self, query, max_results=10, timeout=60):
|
def search(self, query, max_results=10, timeout=60):
|
||||||
# check for cyrilic symbols before performing search
|
# check for cyrillic symbols before performing search
|
||||||
uquery = unicode(query.strip(), 'utf-8')
|
uquery = unicode(query.strip(), 'utf-8')
|
||||||
reObj = re.search(u'^[а-яА-Я\\d]{4,}[а-яА-Я\\d\\s]*$', uquery)
|
reObj = re.search(u'^[а-яА-Я\\d\\s]{3,}$', uquery)
|
||||||
if not reObj:
|
if not reObj:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -46,9 +46,9 @@ class eKnigiStore(BasicStoreConfig, StorePlugin):
|
|||||||
d.exec_()
|
d.exec_()
|
||||||
|
|
||||||
def search(self, query, max_results=10, timeout=60):
|
def search(self, query, max_results=10, timeout=60):
|
||||||
# check for cyrilic symbols before performing search
|
# check for cyrillic symbols before performing search
|
||||||
uquery = unicode(query.strip(), 'utf-8')
|
uquery = unicode(query.strip(), 'utf-8')
|
||||||
reObj = re.search(u'^[а-яА-Я\\d]{2,}[а-яА-Я\\d\\s]*$', uquery)
|
reObj = re.search(u'^[а-яА-Я\\d\\s]{2,}$', uquery)
|
||||||
if not reObj:
|
if not reObj:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -112,7 +112,10 @@ def convert_bulk_ebook(parent, queue, db, book_ids, out_format=None, args=[]):
|
|||||||
if total == 0:
|
if total == 0:
|
||||||
return None, None, None
|
return None, None, None
|
||||||
|
|
||||||
d = BulkConfig(parent, db, out_format)
|
has_saved_settings = db.has_conversion_options(book_ids)
|
||||||
|
|
||||||
|
d = BulkConfig(parent, db, out_format,
|
||||||
|
has_saved_settings=has_saved_settings)
|
||||||
if d.exec_() != QDialog.Accepted:
|
if d.exec_() != QDialog.Accepted:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -359,7 +359,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
|
|||||||
'log will be displayed automatically.')%self.gui_debug, show=True)
|
'log will be displayed automatically.')%self.gui_debug, show=True)
|
||||||
|
|
||||||
def esc(self, *args):
|
def esc(self, *args):
|
||||||
self.search.clear()
|
self.clear_button.click()
|
||||||
|
|
||||||
def start_content_server(self, check_started=True):
|
def start_content_server(self, check_started=True):
|
||||||
from calibre.library.server.main import start_threaded_server
|
from calibre.library.server.main import start_threaded_server
|
||||||
|
@ -1085,6 +1085,14 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
|
|||||||
return cPickle.loads(str(data))
|
return cPickle.loads(str(data))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def has_conversion_options(self, ids, format='PIPE'):
|
||||||
|
ids = tuple(ids)
|
||||||
|
if len(ids) > 50000:
|
||||||
|
return True
|
||||||
|
return self.conn.get('''
|
||||||
|
SELECT data FROM conversion_options WHERE book IN %r AND
|
||||||
|
format=? LIMIT 1'''%(ids,), (format,), all=False) is not None
|
||||||
|
|
||||||
def delete_conversion_options(self, id, format, commit=True):
|
def delete_conversion_options(self, id, format, commit=True):
|
||||||
self.conn.execute('DELETE FROM conversion_options WHERE book=? AND format=?',
|
self.conn.execute('DELETE FROM conversion_options WHERE book=? AND format=?',
|
||||||
(id, format.upper()))
|
(id, format.upper()))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user