mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
syn to trunk
This commit is contained in:
commit
b5967880b5
@ -2,7 +2,7 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
__appname__ = 'calibre'
|
__appname__ = 'calibre'
|
||||||
__version__ = '0.4.123'
|
__version__ = '0.4.124'
|
||||||
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
|
||||||
'''
|
'''
|
||||||
Various run time constants.
|
Various run time constants.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2009, John Schember <john at nachtimwald.com'
|
||||||
|
|
||||||
'''
|
'''
|
||||||
'''
|
'''
|
||||||
@ -10,30 +10,30 @@ from calibre.devices.interface import BookList as _BookList
|
|||||||
EBOOK_DIR = "eBooks"
|
EBOOK_DIR = "eBooks"
|
||||||
EBOOK_TYPES = ['mobi', 'prc', 'html', 'pdf', 'rtf', 'txt']
|
EBOOK_TYPES = ['mobi', 'prc', 'html', 'pdf', 'rtf', 'txt']
|
||||||
|
|
||||||
class Book(object):
|
class Book(object):
|
||||||
def __init__(self, path, title, authors):
|
def __init__(self, path, title, authors):
|
||||||
self.title = title
|
self.title = title
|
||||||
self.authors = authors
|
self.authors = authors
|
||||||
self.size = os.path.getsize(path)
|
self.size = os.path.getsize(path)
|
||||||
self.datetime = time.gmtime(os.path.getctime(path))
|
self.datetime = time.gmtime(os.path.getctime(path))
|
||||||
self.path = path
|
self.path = path
|
||||||
self.thumbnail = None
|
self.thumbnail = None
|
||||||
self.tags = []
|
self.tags = []
|
||||||
|
|
||||||
@apply
|
@apply
|
||||||
def thumbnail():
|
def thumbnail():
|
||||||
return 0
|
return None
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
""" Return a utf-8 encoded string with title author and path information """
|
""" Return a utf-8 encoded string with title author and path information """
|
||||||
return self.title.encode('utf-8') + " by " + \
|
return self.title.encode('utf-8') + " by " + \
|
||||||
self.authors.encode('utf-8') + " at " + self.path.encode('utf-8')
|
self.authors.encode('utf-8') + " at " + self.path.encode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
class BookList(_BookList):
|
class BookList(_BookList):
|
||||||
def __init__(self, mountpath):
|
def __init__(self, mountpath):
|
||||||
self._mountpath = mountpath
|
self._mountpath = mountpath
|
||||||
_BookList.__init__(self)
|
_BookList.__init__(self)
|
||||||
self.return_books(mountpath)
|
self.return_books(mountpath)
|
||||||
|
|
||||||
def return_books(self, mountpath):
|
def return_books(self, mountpath):
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2009, John Schember <john at nachtimwald.com'
|
||||||
|
|
||||||
'''
|
'''
|
||||||
Device driver for Bookeen's Cybook Gen 3
|
Device driver for Bookeen's Cybook Gen 3
|
||||||
|
@ -309,7 +309,8 @@ class MobiReader(object):
|
|||||||
except:
|
except:
|
||||||
text = ''
|
text = ''
|
||||||
text = ent_pat.sub(entity_to_unicode, text)
|
text = ent_pat.sub(entity_to_unicode, text)
|
||||||
tocobj.add_item(toc.partition('#')[0], a['href'][1:], text)
|
if a['href'].startswith('#'):
|
||||||
|
tocobj.add_item(toc.partition('#')[0], a['href'][1:], text)
|
||||||
if tocobj is not None:
|
if tocobj is not None:
|
||||||
opf.set_toc(tocobj)
|
opf.set_toc(tocobj)
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ add/remove formats
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from PyQt4.QtCore import SIGNAL, QObject, QCoreApplication, Qt
|
from PyQt4.QtCore import SIGNAL, QObject, QCoreApplication, Qt
|
||||||
from PyQt4.QtGui import QPixmap, QListWidgetItem, QErrorMessage, QDialog
|
from PyQt4.QtGui import QPixmap, QListWidgetItem, QErrorMessage, QDialog, QCompleter
|
||||||
|
|
||||||
|
|
||||||
from calibre.gui2 import qstring_to_unicode, error_dialog, file_icon_provider, \
|
from calibre.gui2 import qstring_to_unicode, error_dialog, file_icon_provider, \
|
||||||
@ -33,6 +33,13 @@ class Format(QListWidgetItem):
|
|||||||
QListWidgetItem.__init__(self, file_icon_provider().icon_from_ext(ext),
|
QListWidgetItem.__init__(self, file_icon_provider().icon_from_ext(ext),
|
||||||
text, parent, QListWidgetItem.UserType)
|
text, parent, QListWidgetItem.UserType)
|
||||||
|
|
||||||
|
class AuthorCompleter(QCompleter):
|
||||||
|
|
||||||
|
def __init__(self, db):
|
||||||
|
all_authors = db.all_authors()
|
||||||
|
all_authors.sort(cmp=lambda x, y : cmp(x[1], y[1]))
|
||||||
|
QCompleter.__init__(self, [x[1] for x in all_authors])
|
||||||
|
|
||||||
class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog):
|
class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog):
|
||||||
|
|
||||||
def do_reset_cover(self, *args):
|
def do_reset_cover(self, *args):
|
||||||
@ -171,6 +178,8 @@ class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog):
|
|||||||
self.cover_changed = False
|
self.cover_changed = False
|
||||||
self.cpixmap = None
|
self.cpixmap = None
|
||||||
self.cover.setAcceptDrops(True)
|
self.cover.setAcceptDrops(True)
|
||||||
|
self._author_completer = AuthorCompleter(self.db)
|
||||||
|
self.authors.setCompleter(self._author_completer)
|
||||||
self.connect(self.cover, SIGNAL('cover_changed()'), self.cover_dropped)
|
self.connect(self.cover, SIGNAL('cover_changed()'), self.cover_dropped)
|
||||||
QObject.connect(self.cover_button, SIGNAL("clicked(bool)"), \
|
QObject.connect(self.cover_button, SIGNAL("clicked(bool)"), \
|
||||||
self.select_cover)
|
self.select_cover)
|
||||||
@ -206,8 +215,6 @@ class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog):
|
|||||||
self.authors.setText('')
|
self.authors.setText('')
|
||||||
aus = self.db.author_sort(row)
|
aus = self.db.author_sort(row)
|
||||||
self.author_sort.setText(aus if aus else '')
|
self.author_sort.setText(aus if aus else '')
|
||||||
pub = self.db.publisher(row)
|
|
||||||
self.publisher.setText(pub if pub else '')
|
|
||||||
tags = self.db.tags(row)
|
tags = self.db.tags(row)
|
||||||
self.tags.setText(tags if tags else '')
|
self.tags.setText(tags if tags else '')
|
||||||
rating = self.db.rating(row)
|
rating = self.db.rating(row)
|
||||||
@ -225,8 +232,9 @@ class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog):
|
|||||||
ext = ''
|
ext = ''
|
||||||
size = self.db.sizeof_format(row, ext)
|
size = self.db.sizeof_format(row, ext)
|
||||||
Format(self.formats, ext, size)
|
Format(self.formats, ext, size)
|
||||||
|
|
||||||
|
|
||||||
self.initialize_series()
|
self.initialize_series_and_publisher()
|
||||||
|
|
||||||
self.series_index.setValue(self.db.series_index(row))
|
self.series_index.setValue(self.db.series_index(row))
|
||||||
QObject.connect(self.series, SIGNAL('currentIndexChanged(int)'), self.enable_series_index)
|
QObject.connect(self.series, SIGNAL('currentIndexChanged(int)'), self.enable_series_index)
|
||||||
@ -259,7 +267,7 @@ class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog):
|
|||||||
def cover_dropped(self):
|
def cover_dropped(self):
|
||||||
self.cover_changed = True
|
self.cover_changed = True
|
||||||
|
|
||||||
def initialize_series(self):
|
def initialize_series_and_publisher(self):
|
||||||
all_series = self.db.all_series()
|
all_series = self.db.all_series()
|
||||||
all_series.sort(cmp=lambda x, y : cmp(x[1], y[1]))
|
all_series.sort(cmp=lambda x, y : cmp(x[1], y[1]))
|
||||||
series_id = self.db.series_id(self.row)
|
series_id = self.db.series_id(self.row)
|
||||||
@ -282,6 +290,22 @@ class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog):
|
|||||||
if l:
|
if l:
|
||||||
l.invalidate()
|
l.invalidate()
|
||||||
l.activate()
|
l.activate()
|
||||||
|
|
||||||
|
all_publishers = self.db.all_publishers()
|
||||||
|
all_publishers.sort(cmp=lambda x, y : cmp(x[1], y[1]))
|
||||||
|
publisher_id = self.db.publisher_id(self.row)
|
||||||
|
idx, c = None, 0
|
||||||
|
for i in all_publishers:
|
||||||
|
id, name = i
|
||||||
|
if id == publisher_id:
|
||||||
|
idx = c
|
||||||
|
self.publisher.addItem(name)
|
||||||
|
c += 1
|
||||||
|
|
||||||
|
self.publisher.setEditText('')
|
||||||
|
if idx is not None:
|
||||||
|
self.publisher.setCurrentIndex(idx)
|
||||||
|
|
||||||
|
|
||||||
self.layout().activate()
|
self.layout().activate()
|
||||||
|
|
||||||
@ -337,7 +361,7 @@ class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog):
|
|||||||
isbn = qstring_to_unicode(self.isbn.text())
|
isbn = qstring_to_unicode(self.isbn.text())
|
||||||
title = qstring_to_unicode(self.title.text())
|
title = qstring_to_unicode(self.title.text())
|
||||||
author = string_to_authors(unicode(self.authors.text()))[0]
|
author = string_to_authors(unicode(self.authors.text()))[0]
|
||||||
publisher = qstring_to_unicode(self.publisher.text())
|
publisher = qstring_to_unicode(self.publisher.currentText())
|
||||||
if isbn or title or author or publisher:
|
if isbn or title or author or publisher:
|
||||||
d = FetchMetadata(self, isbn, title, author, publisher, self.timeout)
|
d = FetchMetadata(self, isbn, title, author, publisher, self.timeout)
|
||||||
d.exec_()
|
d.exec_()
|
||||||
@ -347,7 +371,7 @@ class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog):
|
|||||||
self.title.setText(book.title)
|
self.title.setText(book.title)
|
||||||
self.authors.setText(authors_to_string(book.authors))
|
self.authors.setText(authors_to_string(book.authors))
|
||||||
if book.author_sort: self.author_sort.setText(book.author_sort)
|
if book.author_sort: self.author_sort.setText(book.author_sort)
|
||||||
if book.publisher: self.publisher.setText(book.publisher)
|
if book.publisher: self.publisher.setEditText(book.publisher)
|
||||||
if book.isbn: self.isbn.setText(book.isbn)
|
if book.isbn: self.isbn.setText(book.isbn)
|
||||||
summ = book.comments
|
summ = book.comments
|
||||||
if summ:
|
if summ:
|
||||||
@ -386,7 +410,7 @@ class MetadataSingleDialog(QDialog, Ui_MetadataSingleDialog):
|
|||||||
self.db.set_author_sort(self.id, aus, notify=False)
|
self.db.set_author_sort(self.id, aus, notify=False)
|
||||||
self.db.set_isbn(self.id, qstring_to_unicode(self.isbn.text()), notify=False)
|
self.db.set_isbn(self.id, qstring_to_unicode(self.isbn.text()), notify=False)
|
||||||
self.db.set_rating(self.id, 2*self.rating.value(), notify=False)
|
self.db.set_rating(self.id, 2*self.rating.value(), notify=False)
|
||||||
self.db.set_publisher(self.id, qstring_to_unicode(self.publisher.text()), notify=False)
|
self.db.set_publisher(self.id, qstring_to_unicode(self.publisher.currentText()), notify=False)
|
||||||
self.db.set_tags(self.id, qstring_to_unicode(self.tags.text()).split(','), notify=False)
|
self.db.set_tags(self.id, qstring_to_unicode(self.tags.text()).split(','), notify=False)
|
||||||
self.db.set_series(self.id, qstring_to_unicode(self.series.currentText()), notify=False)
|
self.db.set_series(self.id, qstring_to_unicode(self.series.currentText()), notify=False)
|
||||||
self.db.set_series_index(self.id, self.series_index.value(), notify=False)
|
self.db.set_series_index(self.id, self.series_index.value(), notify=False)
|
||||||
|
@ -95,13 +95,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1" >
|
|
||||||
<widget class="QLineEdit" name="authors" >
|
|
||||||
<property name="toolTip" >
|
|
||||||
<string>Change the author(s) of this book. Multiple authors should be separated by an &. If the author name contains an &, use && to represent it.</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="0" >
|
<item row="2" column="0" >
|
||||||
<widget class="QLabel" name="label_8" >
|
<widget class="QLabel" name="label_8" >
|
||||||
<property name="text" >
|
<property name="text" >
|
||||||
@ -111,7 +104,7 @@
|
|||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
</property>
|
</property>
|
||||||
<property name="buddy" >
|
<property name="buddy" >
|
||||||
<cstring>authors</cstring>
|
<cstring>author_sort</cstring>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -185,13 +178,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="1" colspan="2" >
|
|
||||||
<widget class="QLineEdit" name="publisher" >
|
|
||||||
<property name="toolTip" >
|
|
||||||
<string>Change the publisher of this book</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="5" column="0" >
|
<item row="5" column="0" >
|
||||||
<widget class="QLabel" name="label_4" >
|
<widget class="QLabel" name="label_4" >
|
||||||
<property name="text" >
|
<property name="text" >
|
||||||
@ -330,6 +316,16 @@
|
|||||||
<item row="8" column="1" colspan="2" >
|
<item row="8" column="1" colspan="2" >
|
||||||
<widget class="QLineEdit" name="isbn" />
|
<widget class="QLineEdit" name="isbn" />
|
||||||
</item>
|
</item>
|
||||||
|
<item row="4" column="1" >
|
||||||
|
<widget class="QComboBox" name="publisher" >
|
||||||
|
<property name="editable" >
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1" >
|
||||||
|
<widget class="QLineEdit" name="authors" />
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -615,8 +611,8 @@
|
|||||||
<slot>accept()</slot>
|
<slot>accept()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel" >
|
<hint type="sourcelabel" >
|
||||||
<x>257</x>
|
<x>261</x>
|
||||||
<y>646</y>
|
<y>710</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel" >
|
<hint type="destinationlabel" >
|
||||||
<x>157</x>
|
<x>157</x>
|
||||||
@ -631,8 +627,8 @@
|
|||||||
<slot>reject()</slot>
|
<slot>reject()</slot>
|
||||||
<hints>
|
<hints>
|
||||||
<hint type="sourcelabel" >
|
<hint type="sourcelabel" >
|
||||||
<x>325</x>
|
<x>329</x>
|
||||||
<y>646</y>
|
<y>710</y>
|
||||||
</hint>
|
</hint>
|
||||||
<hint type="destinationlabel" >
|
<hint type="destinationlabel" >
|
||||||
<x>286</x>
|
<x>286</x>
|
||||||
|
@ -943,7 +943,11 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
|
|||||||
if index_is_id:
|
if index_is_id:
|
||||||
return self.conn.get('SELECT publisher FROM meta WHERE id=?', (index,), all=False)
|
return self.conn.get('SELECT publisher FROM meta WHERE id=?', (index,), all=False)
|
||||||
return self.data[index][3]
|
return self.data[index][3]
|
||||||
|
|
||||||
|
def publisher_id(self, index, index_is_id=False):
|
||||||
|
id = index if index_is_id else self.id(index)
|
||||||
|
return self.conn.get('SELECT publisher from books_publishers_link WHERE book=?', (id,), all=False)
|
||||||
|
|
||||||
def rating(self, index, index_is_id=False):
|
def rating(self, index, index_is_id=False):
|
||||||
if index_is_id:
|
if index_is_id:
|
||||||
return self.conn.get('SELECT rating FROM meta WHERE id=?', (index,), all=False)
|
return self.conn.get('SELECT rating FROM meta WHERE id=?', (index,), all=False)
|
||||||
@ -1041,6 +1045,14 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
|
|||||||
def all_series(self):
|
def all_series(self):
|
||||||
return [ (i[0], i[1]) for i in \
|
return [ (i[0], i[1]) for i in \
|
||||||
self.conn.get('SELECT id, name FROM series')]
|
self.conn.get('SELECT id, name FROM series')]
|
||||||
|
|
||||||
|
def all_authors(self):
|
||||||
|
return [ (i[0], i[1]) for i in \
|
||||||
|
self.conn.get('SELECT id, name FROM authors')]
|
||||||
|
|
||||||
|
def all_publishers(self):
|
||||||
|
return [ (i[0], i[1]) for i in \
|
||||||
|
self.conn.get('SELECT id, name FROM publishers')]
|
||||||
|
|
||||||
def all_tags(self):
|
def all_tags(self):
|
||||||
return [i[0].strip() for i in self.conn.get('SELECT name FROM tags') if i[0].strip()]
|
return [i[0].strip() for i in self.conn.get('SELECT name FROM tags') if i[0].strip()]
|
||||||
|
@ -143,6 +143,15 @@ Where are the book files stored?
|
|||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
When you first run |app|, it will ask you for a folder in which to store your books. Whenever you add a book to |app|, it will copy the book into that folder. Books in the folder are nicely arranged into sub-folders by Author and Title. Metadata about the books is stored in the file ``metadata.db`` (which is a sqlite database).
|
When you first run |app|, it will ask you for a folder in which to store your books. Whenever you add a book to |app|, it will copy the book into that folder. Books in the folder are nicely arranged into sub-folders by Author and Title. Metadata about the books is stored in the file ``metadata.db`` (which is a sqlite database).
|
||||||
|
|
||||||
|
Why doesn't |app| let me store books in my own directory structure?
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The whole point if |app|'s library management features is that they provide an interface for locating books that is *much* more efficient than any possible directory scheme you could come up with for your collection. Indeed, once you become comfortable using |app|'s interface to find, sort and browse your collection, you wont ever feel the need to hunt through the files on your disk to find a book again. By managing books in its own directory struture of Author -> Title -> Book files, |app| is able to achieve a high level of reliability and standardization.
|
||||||
|
|
||||||
|
Why doesn't |app| have a column for foo?
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|app| is designed to have columns for the most frequently and widely used fields. If it does not have a coulmn for your favorite field, you can always add a tag to the book for that piece of information. |app| also supports a general purpose "comments" fields for longer items.
|
||||||
|
|
||||||
|
|
||||||
Content From The Web
|
Content From The Web
|
||||||
---------------------
|
---------------------
|
||||||
|
@ -133,7 +133,7 @@ to the recipe. Finally, lets replace some of the :term:`CSS` that we disabled ea
|
|||||||
|
|
||||||
With these additions, our recipe has become "production quality", indeed it is very close to the actual recipe used by |app| for the *BBC*, shown below:
|
With these additions, our recipe has become "production quality", indeed it is very close to the actual recipe used by |app| for the *BBC*, shown below:
|
||||||
|
|
||||||
.. literalinclude:: ../web/feeds/recipes/bbc.py
|
.. literalinclude:: ../web/feeds/recipes/recipe_bbc.py
|
||||||
|
|
||||||
This :term:`recipe` explores only the tip of the iceberg when it comes to the power of |app|. To explore more of the abilities of |app| we'll examine a more complex real life example in the next section.
|
This :term:`recipe` explores only the tip of the iceberg when it comes to the power of |app|. To explore more of the abilities of |app| we'll examine a more complex real life example in the next section.
|
||||||
|
|
||||||
|
@ -102,6 +102,8 @@ class Stats:
|
|||||||
|
|
||||||
def get_deviation(self, amounts):
|
def get_deviation(self, amounts):
|
||||||
l = float(len(amounts))
|
l = float(len(amounts))
|
||||||
|
if l == 0:
|
||||||
|
return 0
|
||||||
mean = sum(amounts)/l
|
mean = sum(amounts)/l
|
||||||
return sqrt( sum([i**2 for i in amounts])/l - mean**2 )
|
return sqrt( sum([i**2 for i in amounts])/l - mean**2 )
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user