diff --git a/recipes/brand_eins.recipe b/recipes/brand_eins.recipe index 15e1d3ccca..e6fe57b334 100644 --- a/recipes/brand_eins.recipe +++ b/recipes/brand_eins.recipe @@ -3,7 +3,8 @@ __license__ = 'GPL v3' __copyright__ = '2010, Constantin Hofstetter , Steffen Siebert ' -__version__ = '0.98' # 2011-04-10 +__version__ = '0.98' + ''' http://brandeins.de - Wirtschaftsmagazin ''' import re import string @@ -13,8 +14,8 @@ from calibre.web.feeds.recipes import BasicNewsRecipe class BrandEins(BasicNewsRecipe): title = u'brand eins' - __author__ = 'Constantin Hofstetter; Steffen Siebert' - description = u'Wirtschaftsmagazin: Gets the last full issue on default. Set a integer value for the username-field to get older issues: 1 -> the newest (but not complete) issue, 2 -> the last complete issue (default), 3 -> the issue before 2 etc.' + __author__ = 'Constantin Hofstetter' + description = u'Wirtschaftsmagazin' publisher ='brandeins.de' category = 'politics, business, wirtschaft, Germany' use_embedded_content = False @@ -105,10 +106,11 @@ class BrandEins(BasicNewsRecipe): keys = issue_map.keys() keys.sort() keys.reverse() - selected_issue = issue_map[keys[issue-1]] + selected_issue_key = keys[issue - 1] + selected_issue = issue_map[selected_issue_key] url = selected_issue.get('href', False) # Get the title for the magazin - build it out of the title of the cover - take the issue and year; - self.title = "brand eins "+ re.search(r"(?P\d\d\/\d\d\d\d)", selected_issue.find('img').get('title', False)).group('date') + self.title = "brand eins " + selected_issue_key[4:] + "/" + selected_issue_key[0:4] url = 'http://brandeins.de/'+url # url = "http://www.brandeins.de/archiv/magazin/tierisch.html" @@ -161,3 +163,4 @@ class BrandEins(BasicNewsRecipe): current_articles.append({'title': title, 'url': url, 'description': description, 'date':''}) titles_and_articles.append([chapter_title, current_articles]) return titles_and_articles + diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index 36bcbdbfe2..776b04d5f6 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -595,6 +595,7 @@ from calibre.devices.jetbook.driver import JETBOOK, MIBUK, JETBOOK_MINI from calibre.devices.kindle.driver import KINDLE, KINDLE2, KINDLE_DX from calibre.devices.nook.driver import NOOK, NOOK_COLOR from calibre.devices.prs505.driver import PRS505 +from calibre.devices.user_defined.driver import USER_DEFINED from calibre.devices.android.driver import ANDROID, S60 from calibre.devices.nokia.driver import N770, N810, E71X, E52 from calibre.devices.eslick.driver import ESLICK, EBK52 @@ -742,6 +743,7 @@ plugins += [ EEEREADER, NEXTBOOK, ITUNES, + USER_DEFINED, ] plugins += [x for x in list(locals().values()) if isinstance(x, type) and \ x.__name__.endswith('MetadataReader')] diff --git a/src/calibre/customize/ui.py b/src/calibre/customize/ui.py index 151235cef9..3a2d638aab 100644 --- a/src/calibre/customize/ui.py +++ b/src/calibre/customize/ui.py @@ -19,6 +19,7 @@ from calibre.utils.config import (make_config_dir, Config, ConfigProxy, plugin_dir, OptionParser) from calibre.ebooks.epub.fix import ePubFixer from calibre.ebooks.metadata.sources.base import Source +from calibre.constants import DEBUG builtin_names = frozenset([p.name for p in builtin_plugins]) @@ -487,8 +488,9 @@ def initialize_plugins(): plugin = initialize_plugin(plugin, None if isinstance(zfp, type) else zfp) _initialized_plugins.append(plugin) except: - print 'Failed to initialize plugin...' - traceback.print_exc() + print 'Failed to initialize plugin:', repr(zfp) + if DEBUG: + traceback.print_exc() _initialized_plugins.sort(cmp=lambda x,y:cmp(x.priority, y.priority), reverse=True) reread_filetype_plugins() reread_metadata_plugins() diff --git a/src/calibre/devices/__init__.py b/src/calibre/devices/__init__.py index 63b0b89a17..e47cd82b50 100644 --- a/src/calibre/devices/__init__.py +++ b/src/calibre/devices/__init__.py @@ -156,3 +156,60 @@ def debug(ioreg_to_tmp=False, buf=None): sys.stdout = oldo sys.stderr = olde +def device_info(ioreg_to_tmp=False, buf=None): + from calibre.devices.scanner import DeviceScanner, win_pnp_drives + from calibre.constants import iswindows + import re + + res = {} + device_details = {} + device_set = set() + drive_details = {} + drive_set = set() + res['device_set'] = device_set + res['device_details'] = device_details + res['drive_details'] = drive_details + res['drive_set'] = drive_set + + try: + s = DeviceScanner() + s.scan() + devices = (s.devices) + if not iswindows: + devices = [list(x) for x in devices] + for dev in devices: + for i in range(3): + dev[i] = hex(dev[i]) + d = dev[0] + dev[1] + dev[2] + device_set.add(d) + device_details[d] = dev[0:3] + else: + for dev in devices: + vid = re.search('vid_([0-9a-f]*)&', dev) + if vid: + vid = vid.group(1) + pid = re.search('pid_([0-9a-f]*)&', dev) + if pid: + pid = pid.group(1) + rev = re.search('rev_([0-9a-f]*)$', dev) + if rev: + rev = rev.group(1) + d = vid+pid+rev + device_set.add(d) + device_details[d] = (vid, pid, rev) + + drives = win_pnp_drives(debug=False) + for drive,details in drives.iteritems(): + order = 'ORD_' + str(drive.order) + ven = re.search('VEN_([^&]*)&', details) + if ven: + ven = ven.group(1) + prod = re.search('PROD_([^&]*)&', details) + if prod: + prod = prod.group(1) + d = (order, ven, prod) + drive_details[drive] = d + drive_set.add(drive) + finally: + pass + return res diff --git a/src/calibre/devices/android/driver.py b/src/calibre/devices/android/driver.py index 359dae89fe..ca84271778 100644 --- a/src/calibre/devices/android/driver.py +++ b/src/calibre/devices/android/driver.py @@ -62,7 +62,7 @@ class ANDROID(USBMS): 0x502 : { 0x3203 : [0x0100]}, # Dell - 0x413c : { 0xb007 : [0x0100, 0x0224]}, + 0x413c : { 0xb007 : [0x0100, 0x0224, 0x0226]}, # LG 0x1004 : { 0x61cc : [0x100], 0x61ce : [0x100], 0x618e : [0x226] }, @@ -112,7 +112,7 @@ class ANDROID(USBMS): 'MB860', 'MULTI-CARD', 'MID7015A', 'INCREDIBLE', 'A7EB'] WINDOWS_CARD_A_MEM = ['ANDROID_PHONE', 'GT-I9000_CARD', 'SGH-I897', 'FILE-STOR_GADGET', 'SGH-T959', 'SAMSUNG_ANDROID', 'GT-P1000_CARD', - 'A70S', 'A101IT', '7', 'INCREDIBLE', 'A7EB'] + 'A70S', 'A101IT', '7', 'INCREDIBLE', 'A7EB', 'SGH-T849_CARD'] OSX_MAIN_MEM = 'Android Device Main Memory' diff --git a/src/calibre/devices/usbms/deviceconfig.py b/src/calibre/devices/usbms/deviceconfig.py index 3c79652463..3f669f1e24 100644 --- a/src/calibre/devices/usbms/deviceconfig.py +++ b/src/calibre/devices/usbms/deviceconfig.py @@ -94,6 +94,9 @@ class DeviceConfig(object): if isinstance(cls.EXTRA_CUSTOMIZATION_MESSAGE, list): ec = [] for i in range(0, len(cls.EXTRA_CUSTOMIZATION_MESSAGE)): + if config_widget.opt_extra_customization[i] is None: + ec.append(None) + continue if hasattr(config_widget.opt_extra_customization[i], 'isChecked'): ec.append(config_widget.opt_extra_customization[i].isChecked()) else: diff --git a/src/calibre/devices/user_defined/__init__.py b/src/calibre/devices/user_defined/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/calibre/devices/user_defined/driver.py b/src/calibre/devices/user_defined/driver.py new file mode 100644 index 0000000000..c496422255 --- /dev/null +++ b/src/calibre/devices/user_defined/driver.py @@ -0,0 +1,110 @@ +# -*- coding: utf-8 -*- + +__license__ = 'GPL v3' +__copyright__ = '2009, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + +from calibre.devices.usbms.driver import USBMS + +class USER_DEFINED(USBMS): + + name = 'User Defined USB driver' + gui_name = 'User Defined USB Device' + author = 'Kovid Goyal' + supported_platforms = ['windows', 'osx', 'linux'] + + # Ordered list of supported formats + FORMATS = ['epub', 'mobi', 'pdf'] + + VENDOR_ID = 0xFFFF + PRODUCT_ID = 0xFFFF + BCD = None + + EBOOK_DIR_MAIN = '' + EBOOK_DIR_CARD_A = '' + + VENDOR_NAME = [] + WINDOWS_MAIN_MEM = '' + WINDOWS_CARD_A_MEM = '' + + OSX_MAIN_MEM = 'Device Main Memory' + + MAIN_MEMORY_VOLUME_LABEL = 'Device Main Memory' + + SUPPORTS_SUB_DIRS = True + + EXTRA_CUSTOMIZATION_MESSAGE = [ + _('USB Vendor ID (in hex)') + ':::

' + + _('Get this ID using Preferences -> Misc -> Get information to ' + 'set up the user-defined device') + '

', + _('USB Product ID (in hex)')+ ':::

' + + _('Get this ID using Preferences -> Misc -> Get information to ' + 'set up the user-defined device') + '

', + _('USB Revision ID (in hex)')+ ':::

' + + _('Get this ID using Preferences -> Misc -> Get information to ' + 'set up the user-defined device') + '

', + '', + _('Windows main memory vendor string') + ':::

' + + _('This field is used only on windows. ' + 'Get this ID using Preferences -> Misc -> Get information to ' + 'set up the user-defined device') + '

', + _('Windows main memory ID string') + ':::

' + + _('This field is used only on windows. ' + 'Get this ID using Preferences -> Misc -> Get information to ' + 'set up the user-defined device') + '

', + _('Windows card A vendor string') + ':::

' + + _('This field is used only on windows. ' + 'Get this ID using Preferences -> Misc -> Get information to ' + 'set up the user-defined device') + '

', + _('Windows card A ID string') + ':::

' + + _('This field is used only on windows. ' + 'Get this ID using Preferences -> Misc -> Get information to ' + 'set up the user-defined device') + '

', + _('Main memory folder') + ':::

' + + _('Enter the folder where the books are to be stored. This folder ' + 'is prepended to any send_to_device template') + '

', + _('Card A folder') + ':::

' + + _('Enter the folder where the books are to be stored. This folder ' + 'is prepended to any send_to_device template') + '

', + ] + EXTRA_CUSTOMIZATION_DEFAULT = [ + '0x0000', + '0x0000', + '0x0000', + None, + '', + '', + '', + '', + '', + '', + ] + OPT_USB_VENDOR_ID = 0 + OPT_USB_PRODUCT_ID = 1 + OPT_USB_REVISION_ID = 2 + OPT_USB_WINDOWS_MM_VEN_ID = 4 + OPT_USB_WINDOWS_MM_ID = 5 + OPT_USB_WINDOWS_CA_VEN_ID = 6 + OPT_USB_WINDOWS_CA_ID = 7 + OPT_MAIN_MEM_FOLDER = 8 + OPT_CARD_A_FOLDER = 9 + + def initialize(self): + try: + e = self.settings().extra_customization + self.VENDOR_ID = int(e[self.OPT_USB_VENDOR_ID], 16) + self.PRODUCT_ID = int(e[self.OPT_USB_PRODUCT_ID], 16) + self.BCD = [int(e[self.OPT_USB_REVISION_ID], 16)] + if e[self.OPT_USB_WINDOWS_MM_VEN_ID]: + self.VENDOR_NAME.append(e[self.OPT_USB_WINDOWS_MM_VEN_ID]) + if e[self.OPT_USB_WINDOWS_CA_VEN_ID] and \ + e[self.OPT_USB_WINDOWS_CA_VEN_ID] not in self.VENDOR_NAME: + self.VENDOR_NAME.append(e[self.OPT_USB_WINDOWS_CA_VEN_ID]) + self.WINDOWS_MAIN_MEM = e[self.OPT_USB_WINDOWS_MM_ID] + '&' + self.WINDOWS_CARD_A_MEM = e[self.OPT_USB_WINDOWS_CA_ID] + '&' + self.EBOOK_DIR_MAIN = e[self.OPT_MAIN_MEM_FOLDER] + self.EBOOK_DIR_CARD_A = e[self.OPT_CARD_A_FOLDER] + except: + import traceback + traceback.print_exc() + USBMS.initialize(self) diff --git a/src/calibre/ebooks/mobi/reader.py b/src/calibre/ebooks/mobi/reader.py index d9c6853795..3d858864a8 100644 --- a/src/calibre/ebooks/mobi/reader.py +++ b/src/calibre/ebooks/mobi/reader.py @@ -253,6 +253,8 @@ class MobiReader(object): .italic { font-style: italic } + .underline { text-decoration: underline } + .mbp_pagebreak { page-break-after: always; margin: 0; display: block } @@ -601,6 +603,9 @@ class MobiReader(object): elif tag.tag == 'i': tag.tag = 'span' tag.attrib['class'] = 'italic' + elif tag.tag == 'u': + tag.tag = 'span' + tag.attrib['class'] = 'underline' elif tag.tag == 'b': tag.tag = 'span' tag.attrib['class'] = 'bold' diff --git a/src/calibre/ebooks/oeb/base.py b/src/calibre/ebooks/oeb/base.py index 1f71e32548..db83fca496 100644 --- a/src/calibre/ebooks/oeb/base.py +++ b/src/calibre/ebooks/oeb/base.py @@ -1049,8 +1049,8 @@ class Manifest(object): # Remove hyperlinks with no content as they cause rendering # artifacts in browser based renderers - # Also remove empty and tags - for a in xpath(data, '//h:a[@href]|//h:i|//h:b'): + # Also remove empty , and tags + for a in xpath(data, '//h:a[@href]|//h:i|//h:b|//h:u'): if a.get('id', None) is None and a.get('name', None) is None \ and len(a) == 0 and not a.text: remove_elem(a) diff --git a/src/calibre/gui2/actions/view.py b/src/calibre/gui2/actions/view.py index c93e69f0fc..6cf5c5d5af 100644 --- a/src/calibre/gui2/actions/view.py +++ b/src/calibre/gui2/actions/view.py @@ -60,7 +60,7 @@ class ViewAction(InterfaceAction): def build_menus(self, db): self.view_menu.clear() - self.view_menu.addAction(self.qaction) + self.view_menu.addAction(self.view_action) self.view_menu.addAction(self.view_specific_action) self.view_menu.addSeparator() self.view_menu.addAction(self.action_pick_random) diff --git a/src/calibre/gui2/device_drivers/configwidget.py b/src/calibre/gui2/device_drivers/configwidget.py index fc7e16e639..e55a0c6dda 100644 --- a/src/calibre/gui2/device_drivers/configwidget.py +++ b/src/calibre/gui2/device_drivers/configwidget.py @@ -62,8 +62,18 @@ class ConfigWidget(QWidget, Ui_ConfigWidget): if isinstance(extra_customization_message, list): self.opt_extra_customization = [] + if len(extra_customization_message) > 6: + row_func = lambda x, y: ((x/2) * 2) + y + col_func = lambda x: x%2 + else: + row_func = lambda x, y: x*2 + y + col_func = lambda x: 0 + for i, m in enumerate(extra_customization_message): label_text, tt = parse_msg(m) + if not label_text: + self.opt_extra_customization.append(None) + continue if isinstance(settings.extra_customization[i], bool): self.opt_extra_customization.append(QCheckBox(label_text)) self.opt_extra_customization[-1].setToolTip(tt) @@ -75,8 +85,9 @@ class ConfigWidget(QWidget, Ui_ConfigWidget): l.setBuddy(self.opt_extra_customization[i]) l.setWordWrap(True) self.opt_extra_customization[i].setText(settings.extra_customization[i]) - self.extra_layout.addWidget(l) - self.extra_layout.addWidget(self.opt_extra_customization[i]) + self.extra_layout.addWidget(l, row_func(i, 0), col_func(i)) + self.extra_layout.addWidget(self.opt_extra_customization[i], + row_func(i, 1), col_func(i)) else: self.opt_extra_customization = QLineEdit() label_text, tt = parse_msg(extra_customization_message) @@ -86,8 +97,8 @@ class ConfigWidget(QWidget, Ui_ConfigWidget): l.setWordWrap(True) if settings.extra_customization: self.opt_extra_customization.setText(settings.extra_customization) - self.extra_layout.addWidget(l) - self.extra_layout.addWidget(self.opt_extra_customization) + self.extra_layout.addWidget(l, 0, 0) + self.extra_layout.addWidget(self.opt_extra_customization, 1, 0) self.opt_save_template.setText(settings.save_template) diff --git a/src/calibre/gui2/device_drivers/configwidget.ui b/src/calibre/gui2/device_drivers/configwidget.ui index 619d7052e8..92324fd1a7 100644 --- a/src/calibre/gui2/device_drivers/configwidget.ui +++ b/src/calibre/gui2/device_drivers/configwidget.ui @@ -101,7 +101,7 @@ - + diff --git a/src/calibre/gui2/preferences/device_user_defined.py b/src/calibre/gui2/preferences/device_user_defined.py new file mode 100644 index 0000000000..9b193078be --- /dev/null +++ b/src/calibre/gui2/preferences/device_user_defined.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai +from __future__ import with_statement + +__license__ = 'GPL v3' +__copyright__ = '2009, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + + +from PyQt4.Qt import QDialog, QVBoxLayout, QPlainTextEdit, QTimer, \ + QDialogButtonBox, QPushButton, QApplication, QIcon, QMessageBox + +from calibre.constants import iswindows + +def step_dialog(parent, title, msg, det_msg=''): + d = QMessageBox(parent) + d.setWindowTitle(title) + d.setText(msg) + d.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) + return d.exec_() & QMessageBox.Cancel + + +class UserDefinedDevice(QDialog): + + def __init__(self, parent=None): + QDialog.__init__(self, parent) + self._layout = QVBoxLayout(self) + self.setLayout(self._layout) + self.log = QPlainTextEdit(self) + self._layout.addWidget(self.log) + self.log.setPlainText(_('Getting device information')+'...') + self.copy = QPushButton(_('Copy to &clipboard')) + self.copy.setDefault(True) + self.setWindowTitle(_('User-defined device information')) + self.setWindowIcon(QIcon(I('debug.png'))) + self.copy.clicked.connect(self.copy_to_clipboard) + self.ok = QPushButton('&OK') + self.ok.setAutoDefault(False) + self.ok.clicked.connect(self.accept) + self.bbox = QDialogButtonBox(self) + self.bbox.addButton(self.copy, QDialogButtonBox.ActionRole) + self.bbox.addButton(self.ok, QDialogButtonBox.AcceptRole) + self._layout.addWidget(self.bbox) + self.resize(750, 500) + self.bbox.setEnabled(False) + QTimer.singleShot(1000, self.device_info) + + def device_info(self): + try: + from calibre.devices import device_info + r = step_dialog(self.parent(), _('Device Detection'), + _('Ensure your device is disconnected, then press OK')) + if r: + self.close() + return + before = device_info() + r = step_dialog(self.parent(), _('Device Detection'), + _('Ensure your device is connected, then press OK')) + if r: + self.close() + return + after = device_info() + new_drives = after['drive_set'] - before['drive_set'] + new_devices = after['device_set'] - before['device_set'] + res = '' + if (not iswindows or len(new_drives)) and len(new_devices) == 1: + for d in new_devices: + res = _('USB Vendor ID (in hex)') + ': 0x' + \ + after['device_details'][d][0] + '\n' + res += _('USB Product ID (in hex)') + ': 0x' + \ + after['device_details'][d][1] + '\n' + res += _('USB Revision ID (in hex)') + ': 0x' + \ + after['device_details'][d][2] + '\n' + if iswindows: + # sort the drives by the order number + for i,d in enumerate(sorted(new_drives, + key=lambda x: after['drive_details'][x][0])): + if i == 0: + res += _('Windows main memory ID string') + ': ' + \ + after['drive_details'][d][1] + '\n' + res += _('Windows main memory ID string') + ': ' + \ + after['drive_details'][d][2] + '\n' + else: + res += _('Windows card A vendor string') + ': ' + \ + after['drive_details'][d][1] + '\n' + res += _('Windows card A ID string') + ': ' + \ + after['drive_details'][d][2] + '\n' + trailer = _( + 'Copy these values to the clipboard, paste them into an ' + 'editor, then enter them into the USER_DEVICE by ' + 'customizing the device plugin in Preferences->Plugins. ' + 'Remember to also enter the folders where you want the books to ' + 'be put. You must restart calibre for your changes ' + 'to take effect.\n') + self.log.setPlainText(res + '\n\n' + trailer) + finally: + self.bbox.setEnabled(True) + + def copy_to_clipboard(self): + QApplication.clipboard().setText(self.log.toPlainText()) + +if __name__ == '__main__': + app = QApplication([]) + d = UserDefinedDevice() + d.exec_() diff --git a/src/calibre/gui2/preferences/misc.py b/src/calibre/gui2/preferences/misc.py index ead5da4ce4..80bfdffcd8 100644 --- a/src/calibre/gui2/preferences/misc.py +++ b/src/calibre/gui2/preferences/misc.py @@ -30,6 +30,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): r('enforce_cpu_limit', config, restart_required=True) self.device_detection_button.clicked.connect(self.debug_device_detection) self.button_open_config_dir.clicked.connect(self.open_config_dir) + self.user_defined_device_button.clicked.connect(self.user_defined_device) self.button_osx_symlinks.clicked.connect(self.create_symlinks) self.button_osx_symlinks.setVisible(isosx) @@ -38,6 +39,11 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form): d = DebugDevice(self) d.exec_() + def user_defined_device(self, *args): + from calibre.gui2.preferences.device_user_defined import UserDefinedDevice + d = UserDefinedDevice(self) + d.exec_() + def open_config_dir(self, *args): from calibre.utils.config import config_dir open_local_file(config_dir) diff --git a/src/calibre/gui2/preferences/misc.ui b/src/calibre/gui2/preferences/misc.ui index 8b0189b0a1..843f0f01b7 100644 --- a/src/calibre/gui2/preferences/misc.ui +++ b/src/calibre/gui2/preferences/misc.ui @@ -58,7 +58,14 @@ - + + + + Get information to setup the &user defined device + + + + Qt::Vertical diff --git a/src/calibre/library/catalog.py b/src/calibre/library/catalog.py index 717e8e2c6b..aeecc3cfca 100644 --- a/src/calibre/library/catalog.py +++ b/src/calibre/library/catalog.py @@ -8,6 +8,7 @@ from collections import namedtuple from copy import deepcopy from xml.sax.saxutils import escape from lxml import etree +from types import StringType, UnicodeType from calibre import prints, prepare_string_for_xml, strftime from calibre.constants import preferred_encoding, DEBUG @@ -15,13 +16,16 @@ from calibre.customize import CatalogPlugin from calibre.customize.conversion import OptionRecommendation, DummyReporter from calibre.ebooks.BeautifulSoup import BeautifulSoup, BeautifulStoneSoup, Tag, NavigableString from calibre.ebooks.chardet import substitute_entites +from calibre.library.save_to_disk import preprocess_template from calibre.ptempfile import PersistentTemporaryDirectory +from calibre.utils.bibtex import BibTeX from calibre.utils.config import config_dir from calibre.utils.date import format_date, isoformat, is_date_undefined, now as nowf +from calibre.utils.html2text import html2text from calibre.utils.icu import capitalize from calibre.utils.logging import default_log as log -from calibre.utils.zipfile import ZipFile, ZipInfo from calibre.utils.magick.draw import thumbnail +from calibre.utils.zipfile import ZipFile, ZipInfo FIELDS = ['all', 'title', 'author_sort', 'authors', 'comments', 'cover', 'formats','id', 'isbn', 'ondevice', 'pubdate', 'publisher', @@ -303,12 +307,6 @@ class BIBTEX(CatalogPlugin): # {{{ def run(self, path_to_output, opts, db, notification=DummyReporter()): - from types import StringType, UnicodeType - - from calibre.library.save_to_disk import preprocess_template - #Bibtex functions - from calibre.utils.bibtex import BibTeX - def create_bibtex_entry(entry, fields, mode, template_citation, bibtexdict, citation_bibtex=True, calibre_files=True): @@ -365,6 +363,11 @@ class BIBTEX(CatalogPlugin): # {{{ #\n removal item = item.replace(u'\r\n',u' ') item = item.replace(u'\n',u' ') + #html to text + try: + item = html2text(item) + except: + log.warn("Failed to convert comments to text") bibtex_entry.append(u'note = "%s"' % bibtexdict.utf8ToBibtex(item)) elif field == 'isbn' : diff --git a/src/calibre/manual/faq.rst b/src/calibre/manual/faq.rst index 816ce7c496..1c6b65c770 100644 --- a/src/calibre/manual/faq.rst +++ b/src/calibre/manual/faq.rst @@ -100,7 +100,9 @@ Device Integration What devices does |app| support? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -At the moment |app| has full support for the SONY PRS line, Barnes & Noble Nook line, Cybook Gen 3/Opus, Amazon Kindle line, Entourage Edge, Longshine ShineBook, Ectaco Jetbook, BeBook/BeBook Mini, Irex Illiad/DR1000, Foxit eSlick, PocketBook line, Italica, eClicto, Iriver Story, Airis dBook, Hanvon N515, Binatone Readme, Teclast K3 and clones, SpringDesign Alex, Kobo Reader, various Android phones and the iPhone/iPad. In addition, using the :guilabel:`Connect to folder` 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 line, Cybook Gen 3/Opus, Amazon Kindle line, Entourage Edge, Longshine ShineBook, Ectaco Jetbook, BeBook/BeBook Mini, Irex Illiad/DR1000, Foxit eSlick, PocketBook line, Italica, eClicto, Iriver Story, Airis dBook, Hanvon N515, Binatone Readme, Teclast K3 and clones, SpringDesign Alex, Kobo Reader, various Android phones and the iPhone/iPad. In addition, using the :guilabel:`Connect to folder` function you can use it with any ebook reader that exports itself as a USB disk. + +There is also a special ``User Defined`` device plugin that can be used to connect to arbitrary devices that present their memory as disk drives. See the device plugin ``Preferences -> Plugins -> Device Plugins -> User Defined`` and ``Preferences -> Miscelleaneous -> Get information to setup the user defined device`` for more information. How can I help get my device supported in |app|? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -133,6 +135,11 @@ Follow these steps to find the problem: * In calibre, go to Preferences->Plugins->Device Interface plugin and make sure the plugin for your device is enabled, the plugin icon next to it should be green when it is enabled. * If all the above steps fail, go to Preferences->Miscellaneous and click debug device detection with your device attached and post the output as a ticket on `the calibre bug tracker `_. +My device is non-standard or unusual. What can I do to connect to it? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In addition to the :guilabel:`Connect to Folder` function found under the Connect/Share button, |app| provides a ``User Defined`` device plugin that can be used to connect to any USB device that presents that shows up as a disk drive in your operating system. See the device plugin ``Preferences -> Plugins -> Device Plugins -> User Defined`` and ``Preferences -> Miscellaneous -> Get information to setup the user defined device`` for more information. + How does |app| manage collections on my SONY reader? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -468,7 +475,7 @@ If it still wont launch, start a command prompt (press the windows key and R; th Post any output you see in a help message on the `Forum `_. -|app| freeze when I click on anything? +|app| freezes when I click on anything? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There are three possible things I know of, that can cause this: @@ -557,7 +564,7 @@ You have two choices: How is |app| licensed? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -|app| is licensed under the GNU General Public License v3 (an open source license). This means that you are free to redistribute |app| as long as you make the source code available. So if you want to put |app| on a CD with your product, you must also put the |app| source code on the CD. The source code is available for download `from googlecode `_. You are free to use the results of conversions from |app| however you want. You cannot use code, libraries from |app| in your software without maing your software open source. For details, see `The GNU GPL v3 `_. +|app| is licensed under the GNU General Public License v3 (an open source license). This means that you are free to redistribute |app| as long as you make the source code available. So if you want to put |app| on a CD with your product, you must also put the |app| source code on the CD. The source code is available for download `from googlecode `_. You are free to use the results of conversions from |app| however you want. You cannot use code, libraries from |app| in your software without making your software open source. For details, see `The GNU GPL v3 `_. How do I run calibre from my USB stick? ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/calibre/utils/bibtex.py b/src/calibre/utils/bibtex.py index d19a6b05fe..518ec96611 100644 --- a/src/calibre/utils/bibtex.py +++ b/src/calibre/utils/bibtex.py @@ -2905,4 +2905,4 @@ class BibTeX: def bibtex_author_format(self, item): #Format authors for Bibtex compliance (get a list as input) - return self.utf8ToBibtex(u' and'.join([author for author in item])) + return self.utf8ToBibtex(u' and '.join([author for author in item])) diff --git a/src/calibre/utils/titlecase.py b/src/calibre/utils/titlecase.py index bf2f9a78d4..1f153dd5fe 100755 --- a/src/calibre/utils/titlecase.py +++ b/src/calibre/utils/titlecase.py @@ -68,7 +68,7 @@ def titlecase(text): continue match = MAC_MC.match(word) - if match and not match.group(2).startswith('hin'): + if match and not match.group(2)[:3] in ('hin', 'ht'): line.append("%s%s" % (capitalize(match.group(1)), capitalize(match.group(2)))) continue