mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Pull from trunk
This commit is contained in:
commit
d0c6124938
@ -6,7 +6,7 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
'''
|
'''
|
||||||
Contains various tweaks that affect calibre behavior. Only edit this file if
|
Contains various tweaks that affect calibre behavior. Only edit this file if
|
||||||
you know what you are dong. If you delete this file, it will be recreated from
|
you know what you are doing. If you delete this file, it will be recreated from
|
||||||
defaults.
|
defaults.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@ nspm.rs
|
|||||||
|
|
||||||
import re
|
import re
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
from calibre.ebooks.BeautifulSoup import Tag
|
|
||||||
|
|
||||||
class Nspm(BasicNewsRecipe):
|
class Nspm(BasicNewsRecipe):
|
||||||
title = 'Nova srpska politicka misao'
|
title = 'Nova srpska politicka misao'
|
||||||
|
@ -9,6 +9,7 @@ from threading import Thread
|
|||||||
from calibre import prints
|
from calibre import prints
|
||||||
from calibre.utils.config import OptionParser
|
from calibre.utils.config import OptionParser
|
||||||
from calibre.utils.logging import default_log
|
from calibre.utils.logging import default_log
|
||||||
|
from calibre.utils.titlecase import titlecase
|
||||||
from calibre.customize import Plugin
|
from calibre.customize import Plugin
|
||||||
from calibre.ebooks.metadata.covers import check_for_cover
|
from calibre.ebooks.metadata.covers import check_for_cover
|
||||||
|
|
||||||
@ -384,6 +385,16 @@ def search(title=None, author=None, publisher=None, isbn=None, isbndb_key=None,
|
|||||||
if r.pubdate is None:
|
if r.pubdate is None:
|
||||||
r.pubdate = pubdate
|
r.pubdate = pubdate
|
||||||
|
|
||||||
|
def fix_case(x):
|
||||||
|
if x and x.isupper():
|
||||||
|
x = titlecase(x)
|
||||||
|
return x
|
||||||
|
|
||||||
|
for r in results:
|
||||||
|
r.title = fix_case(r.title)
|
||||||
|
if r.authors:
|
||||||
|
r.authors = list(map(fix_case, r.authors))
|
||||||
|
|
||||||
return results, [(x.name, x.exception, x.tb) for x in fetchers]
|
return results, [(x.name, x.exception, x.tb) for x in fetchers]
|
||||||
|
|
||||||
def get_social_metadata(mi, verbose=0):
|
def get_social_metadata(mi, verbose=0):
|
||||||
|
@ -296,6 +296,17 @@ class AddAction(object): # {{{
|
|||||||
self.library_view.model().db.import_book(MetaInformation(None), [])
|
self.library_view.model().db.import_book(MetaInformation(None), [])
|
||||||
self.library_view.model().books_added(num)
|
self.library_view.model().books_added(num)
|
||||||
|
|
||||||
|
def add_isbns(self, isbns):
|
||||||
|
from calibre.ebooks.metadata import MetaInformation
|
||||||
|
ids = set([])
|
||||||
|
for x in isbns:
|
||||||
|
mi = MetaInformation(None)
|
||||||
|
mi.isbn = x
|
||||||
|
ids.add(self.library_view.model().db.import_book(mi, []))
|
||||||
|
self.library_view.model().books_added(len(isbns))
|
||||||
|
self.do_download_metadata(ids)
|
||||||
|
|
||||||
|
|
||||||
def files_dropped(self, paths):
|
def files_dropped(self, paths):
|
||||||
to_device = self.stack.currentIndex() != 0
|
to_device = self.stack.currentIndex() != 0
|
||||||
self._add_books(paths, to_device)
|
self._add_books(paths, to_device)
|
||||||
@ -342,6 +353,12 @@ class AddAction(object): # {{{
|
|||||||
def add_filesystem_book(self, paths, allow_device=True):
|
def add_filesystem_book(self, paths, allow_device=True):
|
||||||
self._add_filesystem_book(paths, allow_device=allow_device)
|
self._add_filesystem_book(paths, allow_device=allow_device)
|
||||||
|
|
||||||
|
def add_from_isbn(self, *args):
|
||||||
|
from calibre.gui2.dialogs.add_from_isbn import AddFromISBN
|
||||||
|
d = AddFromISBN(self)
|
||||||
|
if d.exec_() == d.Accepted:
|
||||||
|
self.add_isbns(d.isbns)
|
||||||
|
|
||||||
def add_books(self, *args):
|
def add_books(self, *args):
|
||||||
'''
|
'''
|
||||||
Add books from the local filesystem to either the library or the device.
|
Add books from the local filesystem to either the library or the device.
|
||||||
@ -625,6 +642,13 @@ class EditMetadataAction(object): # {{{
|
|||||||
return
|
return
|
||||||
db = self.library_view.model().db
|
db = self.library_view.model().db
|
||||||
ids = [db.id(row.row()) for row in rows]
|
ids = [db.id(row.row()) for row in rows]
|
||||||
|
self.do_download_metadata(ids, covers=covers,
|
||||||
|
set_metadata=set_metadata,
|
||||||
|
set_social_metadata=set_social_metadata)
|
||||||
|
|
||||||
|
def do_download_metadata(self, ids, covers=True, set_metadata=True,
|
||||||
|
set_social_metadata=None):
|
||||||
|
db = self.library_view.model().db
|
||||||
if set_social_metadata is None:
|
if set_social_metadata is None:
|
||||||
get_social_metadata = config['get_social_metadata']
|
get_social_metadata = config['get_social_metadata']
|
||||||
else:
|
else:
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
<item row="2" column="0" colspan="2">
|
<item row="2" column="0" colspan="2">
|
||||||
<widget class="QCheckBox" name="opt_force_max_line_length">
|
<widget class="QCheckBox" name="opt_force_max_line_length">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Force maximum line lenght</string>
|
<string>Force maximum line length</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
40
src/calibre/gui2/dialogs/add_from_isbn.py
Normal file
40
src/calibre/gui2/dialogs/add_from_isbn.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
from PyQt4.Qt import QDialog, QApplication
|
||||||
|
|
||||||
|
from calibre.gui2.dialogs.add_from_isbn_ui import Ui_Dialog
|
||||||
|
from calibre.ebooks.metadata import check_isbn
|
||||||
|
|
||||||
|
class AddFromISBN(QDialog, Ui_Dialog):
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
QDialog.__init__(self, parent)
|
||||||
|
self.setupUi(self)
|
||||||
|
|
||||||
|
self.isbns = []
|
||||||
|
self.paste_button.clicked.connect(self.paste)
|
||||||
|
|
||||||
|
def paste(self, *args):
|
||||||
|
app = QApplication.instance()
|
||||||
|
c = app.clipboard()
|
||||||
|
txt = unicode(c.text()).strip()
|
||||||
|
if txt:
|
||||||
|
old = unicode(self.isbn_box.toPlainText()).strip()
|
||||||
|
new = old + '\n' + txt
|
||||||
|
self.isbn_box.setPlainText(new)
|
||||||
|
|
||||||
|
def accept(self, *args):
|
||||||
|
for line in unicode(self.isbn_box.toPlainText()).strip().splitlines():
|
||||||
|
if line:
|
||||||
|
isbn = check_isbn(line)
|
||||||
|
if isbn is not None:
|
||||||
|
isbn = isbn.upper()
|
||||||
|
if isbn not in self.isbns:
|
||||||
|
self.isbns.append(isbn)
|
||||||
|
QDialog.accept(self, *args)
|
||||||
|
|
90
src/calibre/gui2/dialogs/add_from_isbn.ui
Normal file
90
src/calibre/gui2/dialogs/add_from_isbn.ui
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>Dialog</class>
|
||||||
|
<widget class="QDialog" name="Dialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>678</width>
|
||||||
|
<height>430</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Add books by ISBN</string>
|
||||||
|
</property>
|
||||||
|
<property name="windowIcon">
|
||||||
|
<iconset resource="../../../../resources/images.qrc">
|
||||||
|
<normaloff>:/images/add_book.svg</normaloff>:/images/add_book.svg</iconset>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QPlainTextEdit" name="isbn_box"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string><p>Enter a list of ISBNs in the box to the left, one per line. calibre will automatically create entries for books based on the ISBN and download metadata and covers for them.<p>Any invalid ISBNs in the list will be ignored.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" colspan="2">
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QPushButton" name="paste_button">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Paste from clipboard</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../../../../resources/images.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>Dialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>Dialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
@ -538,8 +538,10 @@ class MainWindowMixin(object):
|
|||||||
self.add_menu.addAction(_('Add books from directories, including '
|
self.add_menu.addAction(_('Add books from directories, including '
|
||||||
'sub directories (Multiple books per directory, assumes every '
|
'sub directories (Multiple books per directory, assumes every '
|
||||||
'ebook file is a different book)'), self.add_recursive_multiple)
|
'ebook file is a different book)'), self.add_recursive_multiple)
|
||||||
|
self.add_menu.addSeparator()
|
||||||
self.add_menu.addAction(_('Add Empty book. (Book entry with no '
|
self.add_menu.addAction(_('Add Empty book. (Book entry with no '
|
||||||
'formats)'), self.add_empty)
|
'formats)'), self.add_empty)
|
||||||
|
self.add_menu.addAction(_('Add from ISBN'), self.add_from_isbn)
|
||||||
self.action_add.setMenu(self.add_menu)
|
self.action_add.setMenu(self.add_menu)
|
||||||
self.action_add.triggered.connect(self.add_books)
|
self.action_add.triggered.connect(self.add_books)
|
||||||
self.action_del.triggered.connect(self.delete_books)
|
self.action_del.triggered.connect(self.delete_books)
|
||||||
|
@ -146,6 +146,7 @@ class SearchBox2(QComboBox):
|
|||||||
self._in_a_search = False
|
self._in_a_search = False
|
||||||
if event.key() in (Qt.Key_Return, Qt.Key_Enter):
|
if event.key() in (Qt.Key_Return, Qt.Key_Enter):
|
||||||
self.do_search()
|
self.do_search()
|
||||||
|
if self.as_you_type:
|
||||||
self.timer.start(1500)
|
self.timer.start(1500)
|
||||||
|
|
||||||
def mouse_released(self, event):
|
def mouse_released(self, event):
|
||||||
|
@ -1673,6 +1673,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
self.data.refresh_ids(self, [id]) # Needed to update format list and size
|
self.data.refresh_ids(self, [id]) # Needed to update format list and size
|
||||||
if notify:
|
if notify:
|
||||||
self.notify('add', [id])
|
self.notify('add', [id])
|
||||||
|
return id
|
||||||
|
|
||||||
def get_top_level_move_items(self):
|
def get_top_level_move_items(self):
|
||||||
items = set(os.listdir(self.library_path))
|
items = set(os.listdir(self.library_path))
|
||||||
|
@ -12,7 +12,7 @@ from ctypes import Structure as _Structure, c_char_p, c_uint, c_void_p, POINTER,
|
|||||||
from tempfile import NamedTemporaryFile
|
from tempfile import NamedTemporaryFile
|
||||||
from StringIO import StringIO
|
from StringIO import StringIO
|
||||||
|
|
||||||
from calibre import iswindows, load_library, CurrentDir, prints
|
from calibre import iswindows, load_library, CurrentDir
|
||||||
from calibre.ptempfile import TemporaryDirectory
|
from calibre.ptempfile import TemporaryDirectory
|
||||||
|
|
||||||
_librar_name = 'libunrar'
|
_librar_name = 'libunrar'
|
||||||
|
@ -247,6 +247,7 @@ You can search for the absence or presence of a field using the special "true" a
|
|||||||
cover:false will give you all books without a cover
|
cover:false will give you all books without a cover
|
||||||
series:true will give you all books that belong to a series
|
series:true will give you all books that belong to a series
|
||||||
comments:false will give you all books with an empty comment
|
comments:false will give you all books with an empty comment
|
||||||
|
format:false will give you all books with no actual files (empty records)
|
||||||
|
|
||||||
Yes/no custom columns are searchable. Searching for ``false``, ``empty``, or ``blank`` will find all books
|
Yes/no custom columns are searchable. Searching for ``false``, ``empty``, or ``blank`` will find all books
|
||||||
with undefined values in the column. Searching for ``true`` will find all books that do not have undefined
|
with undefined values in the column. Searching for ``true`` will find all books that do not have undefined
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user