mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 10:44:09 -04:00
Pull from trunk
This commit is contained in:
commit
e628399d06
@ -68,16 +68,6 @@
|
||||
- title: "Brand Eins"
|
||||
author: Constantin Hofstetter
|
||||
|
||||
- title: "Winnipeg Free Press"
|
||||
author: buyo
|
||||
|
||||
- title: "Buckmasters in the kitchen, The Walrus Magazine and Kansas City Star"
|
||||
author: Tony Stegall
|
||||
|
||||
- title: "Europa Sur"
|
||||
author: "Darko Miletic"
|
||||
|
||||
|
||||
improved recipes:
|
||||
- Harpers (free)
|
||||
- Danas
|
||||
|
@ -33,9 +33,9 @@ class HBR(BasicNewsRecipe):
|
||||
def get_browser(self):
|
||||
br = BasicNewsRecipe.get_browser(self)
|
||||
br.open(self.LOGIN_URL)
|
||||
br.select_form(name='signInForm')
|
||||
br['signInForm:username'] = self.username
|
||||
br['signInForm:password'] = self.password
|
||||
br.select_form(name='signin-form')
|
||||
br['signin-form:username'] = self.username
|
||||
br['signin-form:password'] = self.password
|
||||
raw = br.submit().read()
|
||||
if 'My Account' not in raw:
|
||||
raise Exception('Failed to login, are you sure your username and password are correct?')
|
||||
|
@ -1,7 +1,7 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Alexander Schremmer <alex@alexanderweb.de>'
|
||||
|
||||
from calibre.resources.recipes import BasicNewsRecipe
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class TazRSSRecipe(BasicNewsRecipe):
|
||||
title = u'Taz.de (die tageszeitung) RSS Feed - German'
|
||||
|
@ -197,7 +197,7 @@ class GetTranslations(Translations):
|
||||
class ISO639(Command):
|
||||
|
||||
description = 'Compile translations for ISO 639 codes'
|
||||
XML = '/usr/lib/python2.6/site-packages/pycountry/databases/iso639.xml'
|
||||
XML = '/usr/lib/python2.7/site-packages/pycountry/databases/iso639.xml'
|
||||
|
||||
def run(self, opts):
|
||||
src = self.XML
|
||||
|
@ -424,7 +424,7 @@ class KOBO(USBMS):
|
||||
paths[source_id] = os.path.join(prefix, *(path.split('/')))
|
||||
return paths
|
||||
|
||||
def update_device_database_collections(self, booklists, collections_attributes):
|
||||
def update_device_database_collections(self, booklists, collections_attributes, oncard):
|
||||
# debug_print('Starting update_device_database_collections', collections_attributes)
|
||||
|
||||
# Force collections_attributes to be 'tags' as no other is currently supported
|
||||
@ -433,14 +433,20 @@ class KOBO(USBMS):
|
||||
|
||||
collections = booklists.get_collections(collections_attributes)
|
||||
# debug_print('Collections', collections)
|
||||
for category, books in collections.items():
|
||||
if category == 'Im_Reading':
|
||||
|
||||
# Create a connection to the sqlite database
|
||||
# Needs to be outside books collection as in the case of removing
|
||||
# the last book from the collection the list of books is empty
|
||||
# and the removal of the last book would not occur
|
||||
connection = sqlite.connect(self._main_prefix + '.kobo/KoboReader.sqlite')
|
||||
cursor = connection.cursor()
|
||||
|
||||
# Reset Im_Reading list in the database
|
||||
query= 'update content set ReadStatus=0, FirstTimeReading = \'true\' where BookID is Null'
|
||||
if oncard == 'carda':
|
||||
query= 'update content set ReadStatus=0, FirstTimeReading = \'true\' where BookID is Null and ContentID like \'file:///mnt/sd/%\''
|
||||
elif oncard != 'carda' and oncard != 'cardb':
|
||||
query= 'update content set ReadStatus=0, FirstTimeReading = \'true\' where BookID is Null and ContentID not like \'file:///mnt/sd/%\''
|
||||
|
||||
try:
|
||||
cursor.execute (query)
|
||||
except:
|
||||
@ -450,6 +456,8 @@ class KOBO(USBMS):
|
||||
# debug_print('Commit: Reset Im_Reading list')
|
||||
connection.commit()
|
||||
|
||||
for category, books in collections.items():
|
||||
if category == 'Im_Reading':
|
||||
for book in books:
|
||||
# debug_print('Title:', book.title, 'lpath:', book.path)
|
||||
book.device_collections = ['Im_Reading']
|
||||
@ -494,12 +502,16 @@ class KOBO(USBMS):
|
||||
|
||||
#debug_print('KOBO: collection fields:', collections)
|
||||
for i, blist in blists.items():
|
||||
self.update_device_database_collections(blist, collections)
|
||||
if i == 0:
|
||||
oncard = 'main'
|
||||
else:
|
||||
oncard = 'carda'
|
||||
self.update_device_database_collections(blist, collections, oncard)
|
||||
|
||||
USBMS.sync_booklists(self, booklists, end_session=end_session)
|
||||
#debug_print('KOBO: finished sync_booklists')
|
||||
|
||||
def rebuild_collections(self, booklist, oncard):
|
||||
collections_attributes = []
|
||||
self.update_device_database_collections(booklist, collections_attributes)
|
||||
self.update_device_database_collections(booklist, collections_attributes, oncard)
|
||||
|
||||
|
@ -216,8 +216,8 @@ class HTMLPreProcessor(object):
|
||||
(re.compile(u'¸\s*(<br.*?>)*\s*C', re.UNICODE), lambda match: u'Ç'),
|
||||
|
||||
# ˛
|
||||
(re.compile(u'˛\s*(<br.*?>)*\s*a', re.UNICODE), lambda match: u'ą'),
|
||||
(re.compile(u'˛\s*(<br.*?>)*\s*A', re.UNICODE), lambda match: u'Ą'),
|
||||
(re.compile(u'\s*˛\s*(<br.*?>)*\s*a', re.UNICODE), lambda match: u'ą'),
|
||||
(re.compile(u'\s*˛\s*(<br.*?>)*\s*A', re.UNICODE), lambda match: u'Ą'),
|
||||
(re.compile(u'˛\s*(<br.*?>)*\s*e', re.UNICODE), lambda match: u'ę'),
|
||||
(re.compile(u'˛\s*(<br.*?>)*\s*E', re.UNICODE), lambda match: u'Ę'),
|
||||
|
||||
|
@ -173,6 +173,8 @@ class EditMetadataAction(InterfaceAction):
|
||||
'''
|
||||
rows = [r.row() for r in \
|
||||
self.gui.library_view.selectionModel().selectedRows()]
|
||||
m = self.gui.library_view.model()
|
||||
ids = [m.id(r) for r in rows]
|
||||
if not rows or len(rows) == 0:
|
||||
d = error_dialog(self.gui, _('Cannot edit metadata'),
|
||||
_('No books selected'))
|
||||
@ -191,6 +193,7 @@ class EditMetadataAction(InterfaceAction):
|
||||
self.gui.tags_view.recount()
|
||||
if self.gui.cover_flow:
|
||||
self.gui.cover_flow.dataChanged()
|
||||
self.gui.library_view.select_rows(ids)
|
||||
|
||||
# Merge books {{{
|
||||
def merge_books(self, safe_merge=False):
|
||||
|
@ -163,7 +163,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
||||
self.s_r_number_of_books = min(7, len(self.ids))
|
||||
for i in range(1,self.s_r_number_of_books+1):
|
||||
w = QtGui.QLabel(self.tabWidgetPage3)
|
||||
w.setText(_('Book %d:'%i))
|
||||
w.setText(_('Book %d:')%i)
|
||||
self.gridLayout1.addWidget(w, i+offset, 0, 1, 1)
|
||||
w = QtGui.QLineEdit(self.tabWidgetPage3)
|
||||
w.setReadOnly(True)
|
||||
@ -220,6 +220,8 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
||||
if val:
|
||||
val.sort(cmp=lambda x,y: cmp(x.lower(), y.lower()))
|
||||
val = val[0]
|
||||
if txt == 'authors':
|
||||
val = val.replace('|', ',')
|
||||
else:
|
||||
val = ''
|
||||
else:
|
||||
@ -303,6 +305,8 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
||||
# The standard tags and authors values want to be lists.
|
||||
# All custom columns are to be strings
|
||||
val = fm['is_multiple'].join(val)
|
||||
elif field == 'authors':
|
||||
val = [v.replace('|', ',') for v in val]
|
||||
else:
|
||||
val = apply_pattern(val)
|
||||
|
||||
|
@ -328,6 +328,9 @@ Future conversion of these books will use the default settings.</string>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
|
@ -751,20 +751,22 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
try:
|
||||
if self.formats_changed:
|
||||
self.sync_formats()
|
||||
title = unicode(self.title.text())
|
||||
title = unicode(self.title.text()).strip()
|
||||
self.db.set_title(self.id, title, notify=False)
|
||||
au = unicode(self.authors.text())
|
||||
au = unicode(self.authors.text()).strip()
|
||||
if au:
|
||||
self.db.set_authors(self.id, string_to_authors(au), notify=False)
|
||||
aus = unicode(self.author_sort.text())
|
||||
aus = unicode(self.author_sort.text()).strip()
|
||||
if aus:
|
||||
self.db.set_author_sort(self.id, aus, notify=False, commit=False)
|
||||
self.db.set_isbn(self.id,
|
||||
re.sub(r'[^0-9a-zA-Z]', '', unicode(self.isbn.text())),
|
||||
re.sub(r'[^0-9a-zA-Z]', '',
|
||||
unicode(self.isbn.text()).strip()),
|
||||
notify=False, commit=False)
|
||||
self.db.set_rating(self.id, 2*self.rating.value(), notify=False,
|
||||
commit=False)
|
||||
self.db.set_publisher(self.id, unicode(self.publisher.currentText()),
|
||||
self.db.set_publisher(self.id,
|
||||
unicode(self.publisher.currentText()).strip(),
|
||||
notify=False, commit=False)
|
||||
self.db.set_tags(self.id, [x.strip() for x in
|
||||
unicode(self.tags.text()).split(',')], notify=False, commit=False)
|
||||
@ -773,7 +775,8 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
commit=False)
|
||||
self.db.set_series_index(self.id, self.series_index.value(),
|
||||
notify=False, commit=False)
|
||||
self.db.set_comment(self.id, unicode(self.comments.toPlainText()),
|
||||
self.db.set_comment(self.id,
|
||||
unicode(self.comments.toPlainText()).strip(),
|
||||
notify=False, commit=False)
|
||||
d = self.pubdate.date()
|
||||
d = qt_to_dt(d)
|
||||
|
@ -479,6 +479,36 @@ class BooksView(QTableView): # {{{
|
||||
sm = self.selectionModel()
|
||||
sm.select(index, sm.ClearAndSelect|sm.Rows)
|
||||
|
||||
def select_rows(self, identifiers, using_ids=True, change_current=True,
|
||||
scroll=True):
|
||||
'''
|
||||
Select rows identified by identifiers. identifiers can be a set of ids,
|
||||
row numbers or QModelIndexes.
|
||||
'''
|
||||
selmode = self.selectionMode()
|
||||
self.setSelectionMode(QAbstractItemView.MultiSelection)
|
||||
try:
|
||||
rows = set([x.row() if hasattr(x, 'row') else x for x in
|
||||
identifiers])
|
||||
if using_ids:
|
||||
rows = set([])
|
||||
identifiers = set(identifiers)
|
||||
m = self.model()
|
||||
for row in range(m.rowCount(QModelIndex())):
|
||||
if m.id(row) in identifiers:
|
||||
rows.add(row)
|
||||
if rows:
|
||||
row = list(sorted(rows))[0]
|
||||
if change_current:
|
||||
self.set_current_row(row, select=False)
|
||||
if scroll:
|
||||
self.scroll_to_row(row)
|
||||
self.clearSelection()
|
||||
for r in rows:
|
||||
self.selectRow(r)
|
||||
finally:
|
||||
self.setSelectionMode(selmode)
|
||||
|
||||
def close(self):
|
||||
self._model.close()
|
||||
|
||||
|
@ -56,7 +56,7 @@ class ContentServer(object):
|
||||
|
||||
def sort(self, items, field, order):
|
||||
field = self.db.data.sanitize_sort_field_name(field)
|
||||
if field not in ('title', 'authors', 'rating', 'timestamp', 'tags', 'size', 'series'):
|
||||
if field not in self.db.field_metadata.field_keys():
|
||||
raise cherrypy.HTTPError(400, '%s is not a valid sort field'%field)
|
||||
keyg = CSSortKeyGenerator([(field, order)], self.db.field_metadata)
|
||||
items.sort(key=keyg, reverse=not order)
|
||||
|
@ -81,7 +81,7 @@ Device Integration
|
||||
|
||||
What devices does |app| support?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
At the moment |app| has full support for the SONY PRS 300/500/505/600/700/900, Barnes & Noble Nook, Cybook Gen 3/Opus, Amazon Kindle 1/2/3/DX/DXG, Entourage Edge, Longshine ShineBook, Ectaco Jetbook, BeBook/BeBook Mini, Irex Illiad/DR1000, Foxit eSlick, PocketBook 360, Italica, eClicto, Iriver Story, Airis dBook, Hanvon N515, Binatone Readme, Teclast K3, SpringDesign Alex, Kobo Reader, various Android phones and the iPhone/iPad. In addition, using the :guilabel:`Save to disk` function you can use it with any ebook reader that exports itself as a USB disk.
|
||||
At the moment |app| has full support for the SONY PRS line, Barnes & Noble Nook, Cybook Gen 3/Opus, Amazon Kindle line, Entourage Edge, Longshine ShineBook, Ectaco Jetbook, BeBook/BeBook Mini, Irex Illiad/DR1000, Foxit eSlick, PocketBook 360, Italica, eClicto, Iriver Story, Airis dBook, Hanvon N515, Binatone Readme, Teclast K3, SpringDesign Alex, Kobo Reader, various Android phones and the iPhone/iPad. In addition, using the :guilabel:`Save to disk` function you can use it with any ebook reader that exports itself as a USB disk.
|
||||
|
||||
How can I help get my device supported in |app|?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
File diff suppressed because it is too large
Load Diff
0
src/calibre/utils/smartypants.py
Executable file → Normal file
0
src/calibre/utils/smartypants.py
Executable file → Normal file
Loading…
x
Reference in New Issue
Block a user