diff --git a/src/calibre/devices/prs505/driver.py b/src/calibre/devices/prs505/driver.py index 023416bdf2..fc92f11dc3 100644 --- a/src/calibre/devices/prs505/driver.py +++ b/src/calibre/devices/prs505/driver.py @@ -99,7 +99,7 @@ class PRS505(USBMS): if self._card_b_prefix is not None: if not write_cache(self._card_b_prefix): self._card_b_prefix = None - + self.booklist_class.rebuild_collections = self.rebuild_collections def get_device_information(self, end_session=True): return (self.gui_name, '', '', '') @@ -156,4 +156,10 @@ class PRS505(USBMS): USBMS.sync_booklists(self, booklists, end_session=end_session) debug_print('PRS505: finished sync_booklists') + def rebuild_collections(self, booklist, oncard): + debug_print('PRS505: started rebuild_collections') + c = self.initialize_XML_cache() + c.rebuild_collections(booklist, {'carda':1, 'cardb':2}.get(oncard, 0)) + c.write() + debug_print('PRS505: finished rebuild_collections') diff --git a/src/calibre/devices/prs505/sony_cache.py b/src/calibre/devices/prs505/sony_cache.py index a704824a3f..9d853fbbd6 100644 --- a/src/calibre/devices/prs505/sony_cache.py +++ b/src/calibre/devices/prs505/sony_cache.py @@ -61,8 +61,7 @@ class XMLCache(object): def __init__(self, paths, prefixes, use_author_sort): if DEBUG: - debug_print('Building XMLCache...') - pprint(paths) + debug_print('Building XMLCache...', paths) self.paths = paths self.prefixes = prefixes self.use_author_sort = use_author_sort @@ -347,6 +346,12 @@ class XMLCache(object): self.fix_ids() debug_print('Finished update XML from JSON') + def rebuild_collections(self, booklist, bl_index): + if bl_index not in self.record_roots: + return + root = self.record_roots[bl_index] + self.update_playlists(bl_index, root, booklist, []) + def update_playlists(self, bl_index, root, booklist, collections_attributes): debug_print('Starting update_playlists', collections_attributes) collections = booklist.get_collections(collections_attributes) diff --git a/src/calibre/devices/usbms/books.py b/src/calibre/devices/usbms/books.py index be154f35c1..996ce683c2 100644 --- a/src/calibre/devices/usbms/books.py +++ b/src/calibre/devices/usbms/books.py @@ -167,3 +167,15 @@ class CollectionsBookList(BookList): books.sort(cmp=lambda x,y:cmp(getter(x), getter(y))) return collections + def rebuild_collections(self, booklist, oncard): + ''' + For each book in the booklist for the card oncard, remove it from all + its current collections, then add it to the collections specified in + device_collections. + + oncard is None for the main memory, carda for card A, cardb for card B, + etc. + + booklist is the object created by the :method:`books` call above. + ''' + pass diff --git a/src/calibre/gui2/actions.py b/src/calibre/gui2/actions.py index a3f8442200..d2049d3925 100644 --- a/src/calibre/gui2/actions.py +++ b/src/calibre/gui2/actions.py @@ -21,6 +21,7 @@ from calibre.utils.filenames import ascii_filename from calibre.gui2.widgets import IMAGE_EXTENSIONS from calibre.gui2.dialogs.metadata_single import MetadataSingleDialog from calibre.gui2.dialogs.metadata_bulk import MetadataBulkDialog +from calibre.gui2.dialogs.tag_list_editor import TagListEditor from calibre.gui2.tools import convert_single_ebook, convert_bulk_ebook, \ fetch_scheduled_recipe, generate_catalog from calibre.constants import preferred_encoding, filesystem_encoding, \ @@ -831,6 +832,21 @@ class EditMetadataAction(object): # {{{ db.set_metadata(dest_id, dest_mi, ignore_errors=False) # }}} + def edit_device_collections(self, view): + model = view.model() + result = model.get_collections_with_ids() + compare = (lambda x,y:cmp(x.lower(), y.lower())) + d = TagListEditor(self, tag_to_match=None, data=result, compare=compare) + d.exec_() + if d.result() == d.Accepted: + to_rename = d.to_rename # dict of new text to old id + to_delete = d.to_delete # list of ids + for text in to_rename: + model.rename_collection(old_id=to_rename[text], new_name=unicode(text)) + for item in to_delete: + model.delete_collection_using_id(item) + self.upload_collections(model.db, view=view) + # }}} class SaveToDiskAction(object): # {{{ diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index 836105aba9..e956eca562 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -294,6 +294,11 @@ class DeviceManager(Thread): # {{{ return self.create_job(self._sync_booklists, done, args=[booklists], description=_('Send metadata to device')) + def upload_collections(self, done, booklist, on_card): + return self.create_job(booklist.rebuild_collections, done, + args=[booklist, on_card], + description=_('Send collections to device')) + def _upload_books(self, files, names, on_card=None, metadata=None): '''Upload books to device: ''' return self.device.upload_books(files, names, on_card, @@ -1234,6 +1239,18 @@ class DeviceMixin(object): # {{{ self.card_a_view.reset() self.card_b_view.reset() + def _upload_collections(self, job, view): + if job.failed: + self.device_job_exception(job) + view.reset() + + def upload_collections(self, booklist, view): + on_card = 'carda' if self.stack.currentIndex() == 2 else \ + 'cardb' if self.stack.currentIndex() == 3 else \ + None + done = partial(self._upload_collections, view=view) + return self.device_manager.upload_collections(done, booklist, on_card) + def upload_books(self, files, names, metadata, on_card=None, memory=None): ''' Upload books to device. diff --git a/src/calibre/gui2/dialogs/tag_list_editor.py b/src/calibre/gui2/dialogs/tag_list_editor.py index 1ec80f4b4a..9cf95f2b62 100644 --- a/src/calibre/gui2/dialogs/tag_list_editor.py +++ b/src/calibre/gui2/dialogs/tag_list_editor.py @@ -1,54 +1,34 @@ __license__ = 'GPL v3' __copyright__ = '2008, Kovid Goyal ' -from functools import partial from PyQt4.QtCore import SIGNAL, Qt from PyQt4.QtGui import QDialog, QListWidgetItem from calibre.gui2.dialogs.tag_list_editor_ui import Ui_TagListEditor from calibre.gui2 import question_dialog, error_dialog -from calibre.ebooks.metadata import title_sort class TagListEditor(QDialog, Ui_TagListEditor): - def __init__(self, window, db, tag_to_match, category): + def __init__(self, window, tag_to_match, data, compare): QDialog.__init__(self, window) Ui_TagListEditor.__init__(self) self.setupUi(self) self.to_rename = {} self.to_delete = [] - self.db = db self.all_tags = {} - self.category = category - if category == 'tags': - result = db.get_tags_with_ids() - compare = (lambda x,y:cmp(x.lower(), y.lower())) - elif category == 'series': - result = db.get_series_with_ids() - compare = (lambda x,y:cmp(title_sort(x).lower(), title_sort(y).lower())) - elif category == 'publisher': - result = db.get_publishers_with_ids() - compare = (lambda x,y:cmp(x.lower(), y.lower())) - else: # should be a custom field - self.cc_label = None - if category in db.field_metadata: - self.cc_label = db.field_metadata[category]['label'] - result = self.db.get_custom_items_with_ids(label=self.cc_label) - else: - result = [] - compare = (lambda x,y:cmp(x.lower(), y.lower())) - for k,v in result: + for k,v in data: self.all_tags[v] = k for tag in sorted(self.all_tags.keys(), cmp=compare): item = QListWidgetItem(tag) item.setData(Qt.UserRole, self.all_tags[tag]) self.available_tags.addItem(item) - items = self.available_tags.findItems(tag_to_match, Qt.MatchExactly) - if len(items) == 1: - self.available_tags.setCurrentItem(items[0]) + if tag_to_match is not None: + items = self.available_tags.findItems(tag_to_match, Qt.MatchExactly) + if len(items) == 1: + self.available_tags.setCurrentItem(items[0]) self.connect(self.delete_button, SIGNAL('clicked()'), self.delete_tags) self.connect(self.rename_button, SIGNAL('clicked()'), self.rename_tag) @@ -62,11 +42,6 @@ class TagListEditor(QDialog, Ui_TagListEditor): item.setText(self.item_before_editing.text()) return if item.text() != self.item_before_editing.text(): - if item.text() in self.all_tags.keys() or item.text() in self.to_rename.keys(): - error_dialog(self, _('Item already used'), - _('The item %s is already used.')%(item.text())).exec_() - item.setText(self.item_before_editing.text()) - return (id,ign) = self.item_before_editing.data(Qt.UserRole).toInt() self.to_rename[item.text()] = id @@ -99,30 +74,3 @@ class TagListEditor(QDialog, Ui_TagListEditor): self.to_delete.append(id) self.available_tags.takeItem(self.available_tags.row(item)) - def accept(self): - rename_func = None - if self.category == 'tags': - rename_func = self.db.rename_tag - delete_func = self.db.delete_tag_using_id - elif self.category == 'series': - rename_func = self.db.rename_series - delete_func = self.db.delete_series_using_id - elif self.category == 'publisher': - rename_func = self.db.rename_publisher - delete_func = self.db.delete_publisher_using_id - else: - rename_func = partial(self.db.rename_custom_item, label=self.cc_label) - delete_func = partial(self.db.delete_custom_item_using_id, label=self.cc_label) - - work_done = False - if rename_func: - for text in self.to_rename: - work_done = True - rename_func(id=self.to_rename[text], new_name=unicode(text)) - for item in self.to_delete: - work_done = True - delete_func(item) - if not work_done: - QDialog.reject(self) - else: - QDialog.accept(self) diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py index b334808d9b..6df1062e68 100644 --- a/src/calibre/gui2/init.py +++ b/src/calibre/gui2/init.py @@ -226,17 +226,22 @@ class LibraryViewMixin(object): # {{{ self.action_show_book_details, self.action_del, add_to_library = None, + edit_device_collections=None, similar_menu=similar_menu) add_to_library = (_('Add books to library'), self.add_books_from_device) + edit_device_collections = (_('Manage collections'), self.edit_device_collections) self.memory_view.set_context_menu(None, None, None, self.action_view, self.action_save, None, None, self.action_del, - add_to_library=add_to_library) + add_to_library=add_to_library, + edit_device_collections=edit_device_collections) self.card_a_view.set_context_menu(None, None, None, self.action_view, self.action_save, None, None, self.action_del, - add_to_library=add_to_library) + add_to_library=add_to_library, + edit_device_collections=edit_device_collections) self.card_b_view.set_context_menu(None, None, None, self.action_view, self.action_save, None, None, self.action_del, - add_to_library=add_to_library) + add_to_library=add_to_library, + edit_device_collections=edit_device_collections) self.library_view.files_dropped.connect(self.files_dropped, type=Qt.QueuedConnection) for func, args in [ @@ -249,8 +254,11 @@ class LibraryViewMixin(object): # {{{ getattr(view, func)(*args) self.memory_view.connect_dirtied_signal(self.upload_booklists) + self.memory_view.connect_upload_collections_signal(self.upload_collections) self.card_a_view.connect_dirtied_signal(self.upload_booklists) + self.card_a_view.connect_upload_collections_signal(self.upload_collections) self.card_b_view.connect_dirtied_signal(self.upload_booklists) + self.card_b_view.connect_upload_collections_signal(self.upload_collections) self.book_on_device(None, reset=True) db.set_book_on_device_func(self.book_on_device) diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 008f024aae..de3f9bad1f 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -857,6 +857,7 @@ class OnDeviceSearch(SearchQueryParser): # {{{ class DeviceBooksModel(BooksModel): # {{{ booklist_dirtied = pyqtSignal() + upload_collections = pyqtSignal(object) def __init__(self, parent): BooksModel.__init__(self, parent) @@ -977,8 +978,8 @@ class DeviceBooksModel(BooksModel): # {{{ x, y = int(self.db[x].size), int(self.db[y].size) return cmp(x, y) def tagscmp(x, y): - x = ','.join(self.db[x].device_collections) - y = ','.join(self.db[y].device_collections) + x = ','.join(getattr(self.db[x], 'device_collections', [])).lower() + y = ','.join(getattr(self.db[y], 'device_collections', [])).lower() return cmp(x, y) def libcmp(x, y): x, y = self.db[x].in_library, self.db[y].in_library @@ -1026,6 +1027,9 @@ class DeviceBooksModel(BooksModel): # {{{ def set_database(self, db): self.custom_columns = {} self.db = db + for book in db: + if book.device_collections is not None: + book.device_collections.sort(cmp=lambda x,y: cmp(x.lower(), y.lower())) self.map = list(range(0, len(db))) def current_changed(self, current, previous): @@ -1079,6 +1083,36 @@ class DeviceBooksModel(BooksModel): # {{{ res.append((r,b)) return res + def get_collections_with_ids(self): + collections = set() + for book in self.db: + if book.device_collections is not None: + collections.update(set(book.device_collections)) + self.collections = [] + result = [] + for i,collection in enumerate(collections): + result.append((i, collection)) + self.collections.append(collection) + return result + + def rename_collection(self, old_id, new_name): + old_name = self.collections[old_id] + for book in self.db: + if book.device_collections is None: + continue + if old_name in book.device_collections: + book.device_collections.remove(old_name) + if new_name not in book.device_collections: + book.device_collections.append(new_name) + + def delete_collection_using_id(self, old_id): + old_name = self.collections[old_id] + for book in self.db: + if book.device_collections is None: + continue + if old_name in book.device_collections: + book.device_collections.remove(old_name) + def indices(self, rows): ''' Return indices into underlying database from rows @@ -1109,7 +1143,7 @@ class DeviceBooksModel(BooksModel): # {{{ elif cname == 'collections': tags = self.db[self.map[row]].device_collections if tags: - return QVariant(', '.join(sorted(tags, key=str.lower))) + return QVariant(', '.join(tags)) elif role == Qt.ToolTipRole and index.isValid(): if self.map[row] in self.indices_to_be_deleted(): return QVariant(_('Marked for deletion')) @@ -1151,14 +1185,17 @@ class DeviceBooksModel(BooksModel): # {{{ return False val = unicode(value.toString()).strip() idx = self.map[row] + if cname == 'collections': + tags = [i.strip() for i in val.split(',')] + tags = [t for t in tags if t] + self.db[idx].device_collections = tags + self.upload_collections.emit(self.db) + return True + if cname == 'title' : self.db[idx].title = val elif cname == 'authors': self.db[idx].authors = string_to_authors(val) - elif cname == 'collections': - tags = [i.strip() for i in val.split(',')] - tags = [t for t in tags if t] - self.db[idx].device_collections = tags self.dataChanged.emit(index, index) self.booklist_dirtied.emit() done = True diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py index 8245c2d188..c0d6792399 100644 --- a/src/calibre/gui2/library/views.py +++ b/src/calibre/gui2/library/views.py @@ -371,7 +371,8 @@ class BooksView(QTableView): # {{{ # Context Menu {{{ def set_context_menu(self, edit_metadata, send_to_device, convert, view, save, open_folder, book_details, delete, - similar_menu=None, add_to_library=None): + similar_menu=None, add_to_library=None, + edit_device_collections=None): self.setContextMenuPolicy(Qt.DefaultContextMenu) self.context_menu = QMenu(self) if edit_metadata is not None: @@ -393,6 +394,9 @@ class BooksView(QTableView): # {{{ if add_to_library is not None: func = partial(add_to_library[1], view=self) self.context_menu.addAction(add_to_library[0], func) + if edit_device_collections is not None: + func = partial(edit_device_collections[1], view=self) + self.context_menu.addAction(edit_device_collections[0], func) def contextMenuEvent(self, event): self.context_menu.popup(event.globalPos()) @@ -505,6 +509,9 @@ class DeviceBooksView(BooksView): # {{{ def connect_dirtied_signal(self, slot): self._model.booklist_dirtied.connect(slot) + def connect_upload_collections_signal(self, func): + self._model.upload_collections.connect(partial(func, view=self)) + def dropEvent(self, *args): error_dialog(self, _('Not allowed'), _('Dropping onto a device is not supported. First add the book to the calibre library.')).exec_() diff --git a/src/calibre/gui2/tag_view.py b/src/calibre/gui2/tag_view.py index daea4e86ea..140b1e1e52 100644 --- a/src/calibre/gui2/tag_view.py +++ b/src/calibre/gui2/tag_view.py @@ -15,6 +15,7 @@ from PyQt4.Qt import Qt, QTreeView, QApplication, pyqtSignal, \ QAbstractItemModel, QVariant, QModelIndex, QMenu, \ QPushButton, QWidget, QItemDelegate +from calibre.ebooks.metadata import title_sort from calibre.gui2 import config, NONE from calibre.utils.config import prefs from calibre.library.field_metadata import TagsIcons @@ -680,9 +681,49 @@ class TagBrowserMixin(object): # {{{ self.tags_view.recount() def do_tags_list_edit(self, tag, category): - d = TagListEditor(self, self.library_view.model().db, tag, category) + db=self.library_view.model().db + if category == 'tags': + result = db.get_tags_with_ids() + compare = (lambda x,y:cmp(x.lower(), y.lower())) + elif category == 'series': + result = db.get_series_with_ids() + compare = (lambda x,y:cmp(title_sort(x).lower(), title_sort(y).lower())) + elif category == 'publisher': + result = db.get_publishers_with_ids() + compare = (lambda x,y:cmp(x.lower(), y.lower())) + else: # should be a custom field + cc_label = None + if category in db.field_metadata: + cc_label = db.field_metadata[category]['label'] + result = self.db.get_custom_items_with_ids(label=cc_label) + else: + result = [] + compare = (lambda x,y:cmp(x.lower(), y.lower())) + + d = TagListEditor(self, tag_to_match=tag, data=result, compare=compare) d.exec_() if d.result() == d.Accepted: + to_rename = d.to_rename # dict of new text to old id + to_delete = d.to_delete # list of ids + rename_func = None + if category == 'tags': + rename_func = db.rename_tag + delete_func = db.delete_tag_using_id + elif category == 'series': + rename_func = db.rename_series + delete_func = db.delete_series_using_id + elif category == 'publisher': + rename_func = db.rename_publisher + delete_func = db.delete_publisher_using_id + else: + rename_func = partial(db.rename_custom_item, label=cc_label) + delete_func = partial(db.delete_custom_item_using_id, label=cc_label) + if rename_func: + for text in to_rename: + rename_func(old_id=to_rename[text], new_name=unicode(text)) + for item in to_delete: + delete_func(item) + # Clean up everything, as information could have changed for many books. self.library_view.model().refresh() self.tags_view.set_new_model() diff --git a/src/calibre/manual/faq.rst b/src/calibre/manual/faq.rst index 974cbf27fc..74da4f4782 100644 --- a/src/calibre/manual/faq.rst +++ b/src/calibre/manual/faq.rst @@ -7,7 +7,7 @@ Frequently Asked Questions .. contents:: Contents :depth: 1 - :local: + :local: E-book Format Conversion ------------------------- @@ -30,7 +30,7 @@ It can convert every input format in the following list, to every output format. What are the best source formats to convert? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -In order of decreasing preference: LIT, MOBI, EPUB, HTML, PRC, RTF, PDB, TXT, PDF +In order of decreasing preference: LIT, MOBI, EPUB, HTML, PRC, RTF, PDB, TXT, PDF Why does the PDF conversion lose some images/tables? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -40,7 +40,7 @@ are also represented as vector diagrams, thus they cannot be extracted. How do I convert a collection of HTML files in a specific order? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In order to convert a collection of HTML files in a specific oder, you have to create a table of contents file. That is, another HTML file that contains links to all the other files in the desired order. Such a file looks like:: - +

Table of Contents

@@ -60,16 +60,16 @@ Then just add this HTML file to the GUI and use the convert button to create you How do I convert my file containing non-English characters, or smart quotes? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -There are two aspects to this problem: +There are two aspects to this problem: 1. Knowing the encoding of the source file: |app| tries to guess what character encoding your source files use, but often, this is impossible, so you need to tell it what encoding to use. This can be done in the GUI via the :guilabel:`Input character encoding` field in the :guilabel:`Look & Feel` section. The command-line tools all have an :option:`--input-encoding` option. - 2. When adding HTML files to |app|, you may need to tell |app| what encoding the files are in. To do this go to Preferences->Plugins->File Type plugins and customize the HTML2Zip plugin, telling it what encoding your HTML files are in. Now when you add HTML files to |app| they will be correctly processed. HTML files from different sources often have different encodings, so you may have to change this setting repeatedly. A common encoding for many files from the web is ``cp1252`` and I would suggest you try that first. Note that when converting HTML files, leave the input encoding setting mentioned above blank. This is because the HTML2ZIP plugin automatically converts the HTML files to a standard encoding (utf-8). - 3. Embedding fonts: If you are generating an LRF file to read on your SONY Reader, you are limited by the fact that the Reader only supports a few non-English characters in the fonts it comes pre-loaded with. You can work around this problem by embedding a unicode-aware font that supports the character set your file uses into the LRF file. You should embed atleast a serif and a sans-serif font. Be aware that embedding fonts significantly slows down page-turn speed on the reader. + 2. When adding HTML files to |app|, you may need to tell |app| what encoding the files are in. To do this go to Preferences->Plugins->File Type plugins and customize the HTML2Zip plugin, telling it what encoding your HTML files are in. Now when you add HTML files to |app| they will be correctly processed. HTML files from different sources often have different encodings, so you may have to change this setting repeatedly. A common encoding for many files from the web is ``cp1252`` and I would suggest you try that first. Note that when converting HTML files, leave the input encoding setting mentioned above blank. This is because the HTML2ZIP plugin automatically converts the HTML files to a standard encoding (utf-8). + 3. Embedding fonts: If you are generating an LRF file to read on your SONY Reader, you are limited by the fact that the Reader only supports a few non-English characters in the fonts it comes pre-loaded with. You can work around this problem by embedding a unicode-aware font that supports the character set your file uses into the LRF file. You should embed atleast a serif and a sans-serif font. Be aware that embedding fonts significantly slows down page-turn speed on the reader. How do I use some of the advanced features of the conversion tools? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - You can get help on any individual feature of the converters by mousing over it in the GUI or running ``ebook-convert dummy.html .epub -h`` at a terminal. A good place to start is to look at the following demo files that demonstrate some of the advanced features: - * `html-demo.zip `_ + You can get help on any individual feature of the converters by mousing over it in the GUI or running ``ebook-convert dummy.html .epub -h`` at a terminal. A good place to start is to look at the following demo files that demonstrate some of the advanced features: + * `html-demo.zip `_ Device Integration @@ -95,7 +95,7 @@ We just need some information from you: device supports SD cards, insert them. Then connect your device. In calibre go to Preferences->Advanced and click the "Debug device detection" button. This will create some debug output. Copy it to a file and repeat the process, this time with your device disconnected. - * Send both the above outputs to us with the other information and we will write a device driver for your + * Send both the above outputs to us with the other information and we will write a device driver for your device. Once you send us the output for a particular operating system, support for the device in that operating system @@ -104,14 +104,20 @@ will appear in the next release of |app|. How does |app| manage collections on my SONY reader? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -When you send a book to the device, |app| will create collections based on the metadata for that book. By default, collections are created -from tags and series. You can control what metadata is used by going to Preferences->Plugins->Device Interface plugins and customizing -the SONY device interface plugin. +When |app| connects with the device, it retrieves all collections for the books on the device. The collections +of which books are members are shown on the device view. -You can edit collections on the device in the device view in |app| by double clicking or right clicking on the collections field. +When you send a book to the device, |app| will if necessary create new collections based on the metadata for +that book, then add the book to the collections. By default, collections are created from tags and series. You +can control what metadata is used by going to Preferences->Plugins->Device Interface plugins and customizing +the SONY device interface plugin. -|app| will not delete already existing collections on your device. To ensure that the collections are based only on current |app| metadata, -delete and resend the books to the device. +|app| will not delete already existing collections for a book on your device when you resend the book to the +device. To ensure that the collections are based only on current |app| metadata, first delete the books from +the device, and then resend the books. + +You can edit collections on the device in the device view in |app| by double clicking or right clicking on the +collections field. This is the only way to remove a book from a collection. Can I use both |app| and the SONY software to manage my reader? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -141,7 +147,7 @@ simplest is to simply re-name the executable file that launches the library prog Can I use the collections feature of the SONY reader? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |app| has full support for collections. When you add tags to a book's metadata, those tags are turned into collections when you upload the book to the SONY reader. Also, the series information is automatically -turned into a collection on the reader. Note that the PRS-500 does not support collections for books stored on the SD card. The PRS-505 does. +turned into a collection on the reader. Note that the PRS-500 does not support collections for books stored on the SD card. The PRS-505 does. How do I use |app| with my iPad/iPhone/iTouch? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -150,7 +156,7 @@ The easiest way to browse your |app| collection on your Apple device (iPad/iPhon First perform the following steps in |app| - * Set the Preferred Output Format in |app| to EPUB (The output format can be set under Preferences->General) + * Set the Preferred Output Format in |app| to EPUB (The output format can be set under Preferences->General) * Set the output profile to iPad (this will work for iPhone/iPods as well), under Preferences->Conversion->Page Setup * Convert the books you want to read on your iPhone to EPUB format by selecting them and clicking the Convert button. * Turn on the Content Server in |app|'s preferences and leave |app| running. @@ -182,7 +188,7 @@ Can I access my |app| books using the web browser in my Kindle or other reading ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |app| has a *Content Server* that exports the books in |app| as a web page. You can turn it on under -Preferences->Content Server. Then just point the web browser on your device to the computer running +Preferences->Content Server. Then just point the web browser on your device to the computer running the Content Server and you will be able to browse your book collection. For example, if the computer running the server has IP address 63.45.128.5, in the browser, you would type:: @@ -201,8 +207,8 @@ The most likely cause of this is your antivirus program. Try temporarily disabli Why is my device not detected in linux? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -|app| needs your linux kernel to have been setup correctly to detect devices. If your devices are not detected, perform the following tests:: - +|app| needs your linux kernel to have been setup correctly to detect devices. If your devices are not detected, perform the following tests:: + grep SYSFS_DEPRECATED /boot/config-`uname -r` You should see something like ``CONFIG_SYSFS_DEPRECATED_V2 is not set``. @@ -238,7 +244,7 @@ Now this makes it very easy to find for example all science fiction books by Isa ReadStatus -> Genre -> Author -> Series -In |app|, you would instead use tags to mark genre and read status and then just use a simple search query like ``tag:scifi and not tag:read``. |app| even has a nice graphical interface, so you don't need to learn its search language instead you can just click on tags to include or exclude them from the search. +In |app|, you would instead use tags to mark genre and read status and then just use a simple search query like ``tag:scifi and not tag:read``. |app| even has a nice graphical interface, so you don't need to learn its search language instead you can just click on tags to include or exclude them from the search. Why doesn't |app| have a column for foo? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -246,7 +252,7 @@ Why doesn't |app| have a column for foo? How do I move my |app| library from one computer to another? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Simply copy the |app| library folder from the old to the new computer. You can find out what the library folder is by clicking Preferences. The very first item is the path to the library folder. Now on the new computer, start |app| for the first time. It will run the Welcome Wizard asking you for the location of the |app| library. Point it to the previously copied folder. +Simply copy the |app| library folder from the old to the new computer. You can find out what the library folder is by clicking Preferences. The very first item is the path to the library folder. Now on the new computer, start |app| for the first time. It will run the Welcome Wizard asking you for the location of the |app| library. Point it to the previously copied folder. Note that if you are transferring between different types of computers (for example Windows to OS X) then after doing the above you should also go to Preferences->Advanced and click the Check database integrity button. It will warn you about missing files, if any, which you should then transfer by hand. @@ -257,11 +263,11 @@ Content From The Web :depth: 1 :local: -My downloaded news content causes the reader to reset. +My downloaded news content causes the reader to reset. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This is a bug in the SONY firmware. The problem can be mitigated by switching the output format to EPUB -in the configuration dialog. Alternatively, you can use the LRF output format and use the SONY software -to transfer the files to the reader. The SONY software pre-paginates the LRF file, +in the configuration dialog. Alternatively, you can use the LRF output format and use the SONY software +to transfer the files to the reader. The SONY software pre-paginates the LRF file, thereby reducing the number of resets. I obtained a recipe for a news site as a .py file from somewhere, how do I use it? @@ -296,7 +302,7 @@ Take your pick: Why does |app| show only some of my fonts on OS X? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -|app| embeds fonts in ebook files it creates. E-book files support embedding only TrueType (.ttf) fonts. Most fonts on OS X systems are in .dfont format, thus they cannot be embedded. |app| shows only TrueType fonts founf on your system. You can obtain many TrueType fonts on the web. Simply download the .ttf files and add them to the Library/Fonts directory in your home directory. +|app| embeds fonts in ebook files it creates. E-book files support embedding only TrueType (.ttf) fonts. Most fonts on OS X systems are in .dfont format, thus they cannot be embedded. |app| shows only TrueType fonts found on your system. You can obtain many TrueType fonts on the web. Simply download the .ttf files and add them to the Library/Fonts directory in your home directory. |app| is not starting on Windows? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -340,8 +346,8 @@ Most purchased EPUB books have `DRM `_. Thi I want some feature added to |app|. What can I do? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -You have two choices: - 1. Create a patch by hacking on |app| and send it to me for review and inclusion. See `Development `_. +You have two choices: + 1. Create a patch by hacking on |app| and send it to me for review and inclusion. See `Development `_. 2. `Open a ticket `_ (you have to register and login first) and hopefully I will find the time to implement your feature. Can I include |app| on a CD to be distributed with my product/magazine?