diff --git a/src/calibre/__init__.py b/src/calibre/__init__.py
index d0437aff59..807ce1def5 100644
--- a/src/calibre/__init__.py
+++ b/src/calibre/__init__.py
@@ -26,12 +26,16 @@ mimetypes.add_type('text/x-sony-bbeb+xml', '.lrs')
mimetypes.add_type('application/xhtml+xml', '.xhtml')
mimetypes.add_type('image/svg+xml', '.svg')
mimetypes.add_type('application/x-sony-bbeb', '.lrf')
+mimetypes.add_type('application/x-sony-bbeb', '.lrx')
mimetypes.add_type('application/x-dtbncx+xml', '.ncx')
mimetypes.add_type('application/adobe-page-template+xml', '.xpgt')
mimetypes.add_type('application/x-font-opentype', '.otf')
mimetypes.add_type('application/x-font-truetype', '.ttf')
mimetypes.add_type('application/oebps-package+xml', '.opf')
mimetypes.add_type('application/ereader', '.pdb')
+mimetypes.add_type('application/mobi', '.mobi')
+mimetypes.add_type('application/mobi', '.prc')
+mimetypes.add_type('application/mobi', '.azw')
guess_type = mimetypes.guess_type
import cssutils
cssutils.log.setLevel(logging.WARN)
diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py
index b6a6141612..d37e241891 100644
--- a/src/calibre/customize/builtins.py
+++ b/src/calibre/customize/builtins.py
@@ -132,13 +132,24 @@ class HTMLMetadataReader(MetadataReaderPlugin):
class MOBIMetadataReader(MetadataReaderPlugin):
name = 'Read MOBI metadata'
- file_types = set(['mobi', 'prc', '.azw'])
+ file_types = set(['mobi', 'prc', 'azw'])
description = _('Read metadata from %s files')%'MOBI'
def get_metadata(self, stream, ftype):
from calibre.ebooks.mobi.reader import get_metadata
return get_metadata(stream)
+
+class TOPAZMetadataReader(MetadataReaderPlugin):
+
+ name = 'Read Topaz metadata'
+ file_types = set(['tpz', 'azw1'])
+ description = _('Read metadata from %s files')%'MOBI'
+
+ def get_metadata(self, stream, ftype):
+ from calibre.ebooks.metadata.topaz import get_metadata
+ return get_metadata(stream)
+
class ODTMetadataReader(MetadataReaderPlugin):
name = 'Read ODT metadata'
diff --git a/src/calibre/devices/kindle/driver.py b/src/calibre/devices/kindle/driver.py
index e35d5f8cd3..14b056944b 100755
--- a/src/calibre/devices/kindle/driver.py
+++ b/src/calibre/devices/kindle/driver.py
@@ -4,9 +4,9 @@ __copyright__ = '2009, John Schember '
Device driver for Amazon's Kindle
'''
-import os
+import os, re
-from calibre.devices.usbms.driver import USBMS
+from calibre.devices.usbms.driver import USBMS, metadata_from_formats
class KINDLE(USBMS):
# Ordered list of supported formats
@@ -29,6 +29,9 @@ class KINDLE(USBMS):
EBOOK_DIR_MAIN = "documents"
EBOOK_DIR_CARD = "documents"
SUPPORTS_SUB_DIRS = True
+
+ WIRELESS_FILE_NAME_PATTERN = re.compile(
+ r'(?P[^-]+)-asin_(?P[a-zA-Z\d]{10,})-type_(?P\w{4})-v_(?P\d+).*')
def delete_books(self, paths, end_session=True):
for path in paths:
@@ -40,6 +43,16 @@ class KINDLE(USBMS):
# Delete the ebook auxiliary file
if os.path.exists(filepath + '.mbp'):
os.unlink(filepath + '.mbp')
+
+ @classmethod
+ def metadata_from_path(cls, path):
+ mi = metadata_from_formats([path])
+ if mi.title == _('Unknown') or ('-asin' in mi.title and '-type' in mi.title):
+ match = cls.WIRELESS_FILE_NAME_PATTERN.match(os.path.basename(path))
+ if match is not None:
+ mi.title = match.group('title')
+ return mi
+
class KINDLE2(KINDLE):
diff --git a/src/calibre/devices/mime.py b/src/calibre/devices/mime.py
index 0035a7b8d7..140c822ca9 100644
--- a/src/calibre/devices/mime.py
+++ b/src/calibre/devices/mime.py
@@ -1,19 +1,20 @@
-__license__ = 'GPL v3'
-__copyright__ = '2009, John Schember '
-'''
-Global Mime mapping of ebook types.
-'''
+from __future__ import with_statement
+__license__ = 'GPL 3'
+__copyright__ = '2009, Kovid Goyal '
+__docformat__ = 'restructuredtext en'
-MIME_MAP = {
- 'azw' : 'application/azw',
- 'epub' : 'application/epub+zip',
- 'html' : 'text/html',
- 'lrf' : 'application/x-sony-bbeb',
- 'lrx' : 'application/x-sony-bbeb',
- 'mobi' : 'application/mobi',
- 'pdf' : 'application/pdf',
- 'prc' : 'application/prc',
- 'rtf' : 'application/rtf',
- 'txt' : 'text/plain',
- }
+from calibre import guess_type
+def _mt(path):
+ mt = guess_type(path)[0]
+ if not mt:
+ mt = 'application/octet-stream'
+ return mt
+
+def mime_type_ext(ext):
+ if not ext.startswith('.'):
+ ext = '.'+ext
+ return _mt('a'+ext)
+
+def mime_type_path(path):
+ return _mt(path)
\ No newline at end of file
diff --git a/src/calibre/devices/usbms/driver.py b/src/calibre/devices/usbms/driver.py
index bf231c1ffe..4285881447 100644
--- a/src/calibre/devices/usbms/driver.py
+++ b/src/calibre/devices/usbms/driver.py
@@ -15,7 +15,7 @@ from calibre.ebooks.metadata import authors_to_string
from calibre.devices.usbms.device import Device
from calibre.devices.usbms.books import BookList, Book
from calibre.devices.errors import FreeSpaceError, PathError
-from calibre.devices.mime import MIME_MAP
+from calibre.devices.mime import mime_type_ext
class File(object):
def __init__(self, path):
@@ -226,14 +226,17 @@ class USBMS(Device):
if not os.path.isdir(path):
os.utime(path, None)
+ @classmethod
+ def metadata_from_path(cls, path):
+ return metadata_from_formats([path])
+
@classmethod
def book_from_path(cls, path):
fileext = path_to_ext(path)
-
- mi = metadata_from_formats([path])
- mime = MIME_MAP[fileext] if fileext in MIME_MAP.keys() else 'Unknown'
-
+ mi = cls.metadata_from_path(path)
+ mime = mime_type_ext(fileext)
authors = authors_to_string(mi.authors)
- return Book(path, mi.title, authors, mime)
+ book = Book(path, mi.title, authors, mime)
+ return book
diff --git a/src/calibre/ebooks/epub/iterator.py b/src/calibre/ebooks/epub/iterator.py
index 82b9aa09ef..8e0936e708 100644
--- a/src/calibre/ebooks/epub/iterator.py
+++ b/src/calibre/ebooks/epub/iterator.py
@@ -118,10 +118,16 @@ class EbookIterator(object):
self.spine = [SpineItem(i.path) for i in self.opf.spine]
cover = self.opf.cover
- if os.path.splitext(self.pathtoebook)[1].lower() in ('.lit', '.mobi', '.prc') and cover:
+ if os.path.splitext(self.pathtoebook)[1].lower() in \
+ ('.lit', '.mobi', '.prc') and cover:
cfile = os.path.join(os.path.dirname(self.spine[0]), 'calibre_ei_cover.html')
open(cfile, 'wb').write(TITLEPAGE%cover)
self.spine[0:0] = [SpineItem(cfile)]
+
+ if self.opf.path_to_html_toc is not None and \
+ self.opf.path_to_html_toc not in self.spine:
+ self.spine.append(SpineItem(self.opf.path_to_html_toc))
+
sizes = [i.character_count for i in self.spine]
self.pages = [math.ceil(i/float(self.CHARACTERS_PER_PAGE)) for i in sizes]
diff --git a/src/calibre/ebooks/metadata/meta.py b/src/calibre/ebooks/metadata/meta.py
index 43053a43b9..de7ac8eeea 100644
--- a/src/calibre/ebooks/metadata/meta.py
+++ b/src/calibre/ebooks/metadata/meta.py
@@ -15,7 +15,7 @@ _METADATA_PRIORITIES = [
'html', 'htm', 'xhtml', 'xhtm',
'rtf', 'fb2', 'pdf', 'prc', 'odt',
'epub', 'lit', 'lrx', 'lrf', 'mobi',
- 'rb', 'imp'
+ 'rb', 'imp', 'azw'
]
# The priorities for loading metadata from different file types
@@ -41,7 +41,9 @@ def metadata_from_formats(formats):
for path, ext in zip(formats, extensions):
with open(path, 'rb') as stream:
try:
- mi.smart_update(get_metadata(stream, stream_type=ext, use_libprs_metadata=True))
+ newmi = get_metadata(stream, stream_type=ext,
+ use_libprs_metadata=True)
+ mi.smart_update(newmi)
except:
continue
if getattr(mi, 'application_id', None) is not None:
@@ -58,7 +60,7 @@ def get_metadata(stream, stream_type='lrf', use_libprs_metadata=False):
if stream_type: stream_type = stream_type.lower()
if stream_type in ('html', 'html', 'xhtml', 'xhtm', 'xml'):
stream_type = 'html'
- if stream_type in ('mobi', 'prc'):
+ if stream_type in ('mobi', 'prc', 'azw'):
stream_type = 'mobi'
if stream_type in ('odt', 'ods', 'odp', 'odg', 'odf'):
stream_type = 'odt'
diff --git a/src/calibre/ebooks/metadata/opf2.py b/src/calibre/ebooks/metadata/opf2.py
index 0cec3e979c..74b6804845 100644
--- a/src/calibre/ebooks/metadata/opf2.py
+++ b/src/calibre/ebooks/metadata/opf2.py
@@ -444,6 +444,7 @@ class OPF(object):
if not hasattr(stream, 'read'):
stream = open(stream, 'rb')
self.basedir = self.base_dir = basedir
+ self.path_to_html_toc = None
raw, self.encoding = xml_to_unicode(stream.read(), strip_encoding_pats=True, resolve_entities=True)
raw = raw[raw.find('<'):]
self.root = etree.fromstring(raw, self.PARSER)
@@ -495,6 +496,7 @@ class OPF(object):
if f:
self.toc.read_ncx_toc(f[0])
else:
+ self.path_to_html_toc = toc
self.toc.read_html_toc(toc)
except:
pass
diff --git a/src/calibre/ebooks/metadata/topaz.py b/src/calibre/ebooks/metadata/topaz.py
new file mode 100644
index 0000000000..55eb9d6e69
--- /dev/null
+++ b/src/calibre/ebooks/metadata/topaz.py
@@ -0,0 +1,40 @@
+from __future__ import with_statement
+__license__ = 'GPL 3'
+__copyright__ = '2009, Kovid Goyal '
+__docformat__ = 'restructuredtext en'
+
+''' Read metadata from Amazon's topaz format '''
+
+def read_record(raw, name):
+ idx = raw.find(name)
+ if idx > -1:
+ length = ord(raw[idx+len(name)])
+ return raw[idx+len(name)+1:idx+len(name)+1+length]
+
+def get_metadata(stream):
+ raw = stream.read(8*1024)
+ if not raw.startswith('TPZ'):
+ raise ValueError('Not a Topaz file')
+ first = raw.find('metadata')
+ if first < 0:
+ raise ValueError('Invalid Topaz file')
+ second = raw.find('metadata', first+10)
+ if second < 0:
+ raise ValueError('Invalid Topaz file')
+ raw = raw[second:second+1000]
+ authors = read_record(raw, 'Authors')
+ if authors:
+ authors = authors.decode('utf-8', 'replace').split(';')
+ else:
+ authors = [_('Unknown')]
+ title = read_record(raw, 'Title')
+ if title:
+ title = title.decode('utf-8', 'replace')
+ else:
+ raise ValueError('No metadata in file')
+ from calibre.ebooks.metadata import MetaInformation
+ return MetaInformation(title, authors)
+
+if __name__ == '__main__':
+ import sys
+ print get_metadata(open(sys.argv[1], 'rb'))
\ No newline at end of file
diff --git a/src/calibre/ebooks/mobi/reader.py b/src/calibre/ebooks/mobi/reader.py
index 85057017a6..3b9085adca 100644
--- a/src/calibre/ebooks/mobi/reader.py
+++ b/src/calibre/ebooks/mobi/reader.py
@@ -92,6 +92,8 @@ class BookHeader(object):
self.sublanguage = 'NEUTRAL'
self.exth_flag, self.exth = 0, None
self.ancient = True
+ self.first_image_index = -1
+ self.mobi_version = 1
else:
self.ancient = False
self.doctype = raw[16:20]
@@ -537,7 +539,7 @@ class MobiReader(object):
os.makedirs(output_dir)
image_index = 0
self.image_names = []
- start = self.book_header.first_image_index
+ start = getattr(self.book_header, 'first_image_index', -1)
if start > self.num_sections or start < 0:
# BAEN PRC files have bad headers
start=0
diff --git a/src/calibre/gui2/add.py b/src/calibre/gui2/add.py
index 2f4ba281fd..948cf4f3af 100644
--- a/src/calibre/gui2/add.py
+++ b/src/calibre/gui2/add.py
@@ -224,7 +224,10 @@ class AddRecursive(Add):
files = _('Books with the same title as the following already '
'exist in the database. Add them anyway?
')
for mi in self.duplicates:
- files += '- '+mi[0].title+'
\n'
+ title = mi[0].title
+ if not isinstance(title, unicode):
+ title = title.decode(preferred_encoding, 'replace')
+ files += '- '+title+'
\n'
d = WarningDialog (_('Duplicates found!'),
_('Duplicates found!'),
files+'
', parent=self._parent)
diff --git a/src/calibre/gui2/dialogs/metadata_single.ui b/src/calibre/gui2/dialogs/metadata_single.ui
index c693cf3eea..8a5fc4f99d 100644
--- a/src/calibre/gui2/dialogs/metadata_single.ui
+++ b/src/calibre/gui2/dialogs/metadata_single.ui
@@ -1,7 +1,8 @@
-
+
+
MetadataSingleDialog
-
-
+
+
0
0
@@ -9,36 +10,36 @@
750
-
-
+
+
0
0
-
+
Edit Meta Information
-
-
+
+
:/images/edit_input.svg:/images/edit_input.svg
-
+
true
-
+
true
-
+
-
-
-
+
+
QFrame::NoFrame
-
+
true
-
-
+
+
0
0
@@ -46,65 +47,65 @@
710
-
-
+
+
0
-
-
-
+
+
800
665
-
+
-
-
-
+
+
Qt::Horizontal
-
-
+
+
-
-
-
+
+
Meta information
-
-
-
-
-
+
+
-
+
+
&Title:
-
+
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
+
title
- -
-
-
+
-
+
+
Change the title of this book
- -
-
-
+
-
+
+
Swap the author and title
-
+
...
-
-
+
+
:/images/swap.svg:/images/swap.svg
-
+
16
16
@@ -112,305 +113,305 @@
- -
-
-
+
-
+
+
&Author(s):
-
+
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
+
authors
- -
-
-
+
-
+
+
Author S&ort:
-
+
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
+
author_sort
- -
-
+
-
+
-
-
-
+
+
Specify how the author(s) of this book should be sorted. For example Charles Dickens should be sorted as Dickens, Charles.
-
-
-
+
+
Automatically create the author sort entry based on the current author entry
-
+
...
-
-
+
+
:/images/auto_author_sort.svg:/images/auto_author_sort.svg
- -
-
-
+
-
+
+
&Rating:
-
+
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
+
rating
- -
-
-
+
-
+
+
Rating of this book. 0-5 stars
-
+
Rating of this book. 0-5 stars
-
+
QAbstractSpinBox::PlusMinus
-
+
stars
-
+
5
- -
-
-
+
-
+
+
&Publisher:
-
+
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
+
publisher
- -
-
-
+
-
+
+
Ta&gs:
-
+
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
+
tags
- -
-
+
-
+
-
-
-
- Tags categorize the book. This is particularly useful while searching. <br><br>They can be any words or phrases, separated by commas.
+
+
+ Tags categorize the book. This is particularly useful while searching. <br><br>They can be any words or phrases, separated by commas.
-
-
-
+
+
Open Tag Editor
-
+
Open Tag Editor
-
-
+
+
:/images/chapters.svg:/images/chapters.svg
- -
-
-
+
-
+
+
&Series:
-
+
Qt::PlainText
-
+
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
+
series
- -
-
-
+
-
+
+
5
-
-
-
-
+
+
+
0
0
-
+
List of known series. You can add new series.
-
+
List of known series. You can add new series.
-
+
true
-
+
QComboBox::InsertAlphabetically
-
+
QComboBox::AdjustToContents
-
-
-
+
+
Remove unused series (Series that have no books)
-
+
...
-
-
+
+
:/images/trash.svg:/images/trash.svg
- -
-
-
+
-
+
+
false
-
+
Series index.
-
+
Series index.
-
+
Book
-
+
1
-
+
10000
- -
-
-
+
-
+
+
IS&BN:
-
+
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
+
isbn
- -
-
+
-
+
- -
-
-
+
-
+
+
true
- -
-
+
-
+
-
-
-
+
+
Comments
-
-
-
-
+
+
-
+
-
-
-
- Fetch metadata from server
+
+
+ &Fetch metadata from server
-
-
+
+
-
-
-
-
+
+
+
0
0
-
+
Available Formats
-
+
-
-
-
-
-
-
-
+
+
-
+
+
+
0
0
-
+
16777215
130
-
+
64
64
@@ -418,19 +419,19 @@
- -
-
-
+
-
+
+
Add a new format for this book to the database
-
+
...
-
-
+
+
:/images/add_book.svg:/images/add_book.svg
-
+
32
32
@@ -438,19 +439,19 @@
- -
-
-
+
-
+
+
Remove the selected formats for this book from the database.
-
+
...
-
-
+
+
:/images/trash.svg:/images/trash.svg
-
+
32
32
@@ -458,19 +459,19 @@
- -
-
-
+
-
+
+
Set the cover for the book from the selected format
-
+
...
-
-
+
+
:/images/book.svg:/images/book.svg
-
+
32
32
@@ -485,96 +486,96 @@
-
-
-
-
+
+
+
0
10
-
+
Book Cover
-
+
-
-
-
-
+
+
+
0
0
-
+
-
- :/images/book.svg
+
+ :/images/book.svg
-
+
true
-
-
-
+
+
6
-
+
QLayout::SetMaximumSize
-
+
0
-
-
-
+
+
Change &cover image:
-
+
cover_path
-
-
-
+
+
6
-
+
0
-
-
-
+
+
true
-
-
-
+
+
Browse for an image to use as the cover of this book.
-
+
...
-
-
+
+
:/images/document_open.svg:/images/document_open.svg
-
-
-
+
+
Reset cover to default
-
+
...
-
-
+
+
:/images/trash.svg:/images/trash.svg
@@ -584,21 +585,21 @@
-
-
+
-
-
-
- Fetch cover image from server
+
+
+ Fetch &cover image from server
-
-
-
+
+
Change the username and/or password for your account at LibraryThing.com
-
- Change password
+
+ Change &password
@@ -619,11 +620,11 @@
-
-
-
+
+
Qt::Horizontal
-
+
QDialogButtonBox::Cancel|QDialogButtonBox::Ok
@@ -666,7 +667,7 @@
button_box
-
+
@@ -675,11 +676,11 @@
MetadataSingleDialog
accept()
-
+
261
710
-
+
157
274
@@ -691,11 +692,11 @@
MetadataSingleDialog
reject()
-
+
329
710
-
+
286
274
diff --git a/src/calibre/gui2/viewer/documentview.py b/src/calibre/gui2/viewer/documentview.py
index b694562d97..161bc69aad 100644
--- a/src/calibre/gui2/viewer/documentview.py
+++ b/src/calibre/gui2/viewer/documentview.py
@@ -450,7 +450,9 @@ class DocumentView(QWebView):
self.manager.scrolled(self.scroll_fraction)
def wheel_event(self, down=True):
- QWebView.wheelEvent(self, QWheelEvent(QPoint(100, 100), (-120 if down else 120), Qt.NoButton, Qt.NoModifier))
+ QWebView.wheelEvent(self,
+ QWheelEvent(QPoint(100, 100), (-120 if down else 120),
+ Qt.NoButton, Qt.NoModifier))
def next_page(self):
if self.document.at_bottom:
@@ -538,6 +540,26 @@ class DocumentView(QWebView):
self.next_page()
elif key in [Qt.Key_PageUp, Qt.Key_Backspace, Qt.Key_Up]:
self.previous_page()
+ elif key in [Qt.Key_Home]:
+ if event.modifiers() & Qt.ControlModifier:
+ if self.manager is not None:
+ self.manager.goto_start()
+ else:
+ self.scroll_to(0)
+ elif key in [Qt.Key_End]:
+ if event.modifiers() & Qt.ControlModifier:
+ if self.manager is not None:
+ self.manager.goto_end()
+ else:
+ self.scroll_to(1)
+ elif key in [Qt.Key_J]:
+ self.wheel_event()
+ elif key in [Qt.Key_K]:
+ self.wheel_event(down=False)
+ elif key in [Qt.Key_H]:
+ self.scroll_by(x=-15)
+ elif key in [Qt.Key_L]:
+ self.scroll_by(x=15)
else:
return QWebView.keyPressEvent(self, event)
diff --git a/src/calibre/gui2/viewer/main.py b/src/calibre/gui2/viewer/main.py
index b05e42f311..3738ba9114 100644
--- a/src/calibre/gui2/viewer/main.py
+++ b/src/calibre/gui2/viewer/main.py
@@ -341,6 +341,12 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
pos = self.history.forward()
if pos is not None:
self.goto_page(pos)
+
+ def goto_start(self):
+ self.goto_page(1)
+
+ def goto_end(self):
+ self.goto_page(self.pos.maximum())
def goto_page(self, new_page):
if self.current_page is not None:
diff --git a/src/calibre/library/server.py b/src/calibre/library/server.py
index 930a644be8..4ba6253819 100644
--- a/src/calibre/library/server.py
+++ b/src/calibre/library/server.py
@@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en'
HTTP server for remote access to the calibre database.
'''
-import sys, textwrap, operator, os, re, logging, subprocess
+import sys, textwrap, operator, os, re, logging
from itertools import repeat
from logging.handlers import RotatingFileHandler
from datetime import datetime
diff --git a/src/calibre/manual/faq.rst b/src/calibre/manual/faq.rst
index 0e5d5fffc8..7ca4b1b876 100644
--- a/src/calibre/manual/faq.rst
+++ b/src/calibre/manual/faq.rst
@@ -123,15 +123,12 @@ turned into a collection on the reader. Note that the PRS-500 does not support c
How do I use |app| with my iPhone?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
First install the Stanza reader on your iPhone from http://www.lexcycle.com . Then,
+
* Set the output format for calibre to EPUB (The output format can be set next to the big red heart)
* 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.
- * Now you should be able to access your books on your iPhone. If not, try the following:
- In the Stanza reader on your iPhone, add a new catalog. The URL of the catalog is of the form
- ``http://10.34.56.89:8080/stanza``, where you should replace the IP address ``10.34.56.89``
- with the IP address of your computer. Stanza will the use the |app| content server to access all the
- EPUB books in your |app| database.
+Now you should be able to access your books on your iPhone.
Library Management
------------------
diff --git a/src/calibre/trac/plugins/download.py b/src/calibre/trac/plugins/download.py
index ff98123f1d..00bea7d65f 100644
--- a/src/calibre/trac/plugins/download.py
+++ b/src/calibre/trac/plugins/download.py
@@ -177,11 +177,11 @@ else:
compatibility='%s works on OS X Tiger and above.'%(__appname__,),
path=MOBILEREAD+file, app=__appname__,
note=Markup(\
- '''
+ u'''
- Before trying to use the command line tools, you must run the app at least once. This will ask you for you password and then setup the symbolic links for the command line tools.
- The app cannot be run from within the dmg. You must drag it to a folder on your filesystem (The Desktop, Applications, wherever).
- - In order for localization of the user interface in your language, select your language in the configuration dialog (by clicking the hammer icon next to the search bar) and select your language.
+ - In order for localization of the user interface in your language, select your language in the preferences (by pressing u\2318+P) and select your language.
'''))
return 'binary.html', data, None
diff --git a/src/calibre/utils/Zeroconf.py b/src/calibre/utils/Zeroconf.py
index 610c353fca..3bdb992685 100755
--- a/src/calibre/utils/Zeroconf.py
+++ b/src/calibre/utils/Zeroconf.py
@@ -933,7 +933,11 @@ class Reaper(threading.Thread):
def run(self):
while 1:
- self.zeroconf.wait(10 * 1000)
+ try:
+ self.zeroconf.wait(10 * 1000)
+ except TypeError: # By Kovid
+ globals()['_GLOBAL_DONE'] = 1
+ return
if globals()['_GLOBAL_DONE']:
return
now = currentTimeMillis()
diff --git a/src/calibre/utils/mdns.py b/src/calibre/utils/mdns.py
index f941446202..033b903e11 100644
--- a/src/calibre/utils/mdns.py
+++ b/src/calibre/utils/mdns.py
@@ -41,7 +41,7 @@ def publish(desc, type, port, properties=None, add_hostname=True):
'''
port = int(port)
server = start_server()
- hostname = socket.gethostname()
+ hostname = socket.gethostname().partition('.')[0]
if add_hostname:
desc += ' (on %s)'%hostname
local_ip = get_external_ip()
@@ -58,40 +58,3 @@ def stop_server():
global _server
if _server is not None:
_server.close()
-
-'''
-class Publish(object):
-
- def __init__(self, desc, name, port, txt=''):
- self.desc = desc
- self.name = name
- self.port = port
- self.txt = txt
-
- def start(self):
- if iswindows:
- return
- if isosx:
- args = ['dns-sd', self.desc, self.name, '.', self.port]
- else:
- args = ['avahi-publish-service', self.desc, self.name, self.port]
- if self.txt:
- args.append(self.txt)
-
- self.process = subprocess.Popen(args)
-
- def stop(self):
- if iswindows:
- pass
- else:
- process = getattr(self, 'process', None)
- if process is not None:
- process.poll()
- if process.returncode is not None:
- process.terminate()
- process.poll()
- if process.returncode is not None:
- process.kill()
-
-def publish(desc, name, port, txt):
-'''
\ No newline at end of file
diff --git a/src/calibre/web/feeds/recipes/recipe_new_scientist.py b/src/calibre/web/feeds/recipes/recipe_new_scientist.py
index b87883ef6b..acd98a8c6e 100644
--- a/src/calibre/web/feeds/recipes/recipe_new_scientist.py
+++ b/src/calibre/web/feeds/recipes/recipe_new_scientist.py
@@ -1,48 +1,69 @@
-#!/usr/bin/env python
-
-__license__ = 'GPL v3'
-__copyright__ = '2008, Darko Miletic '
-'''
-newscientist.com
-'''
-#!/usr/bin/env python
-
-__license__ = 'GPL v3'
-__copyright__ = '2008, Darko Miletic , AprilHare'
-'''
-newscientist.com
-'''
-
-from calibre.web.feeds.news import BasicNewsRecipe
-
-class NewScientist(BasicNewsRecipe):
- title = u'New Scientist - Online News'
- __author__ = 'Darko Miletic'
- description = 'News from Science'
- language = _('English')
- oldest_article = 7
- max_articles_per_feed = 100
- no_stylesheets = True
- use_embedded_content = False
-
- keep_only_tags = [
- dict(name='div' , attrs={'id':'pgtop' })
- ,dict(name='div' , attrs={'id':'maincol' })
- ]
- remove_tags = [
- dict(name='div' , attrs={'class':'hldBd' })
- ,dict(name='div' , attrs={'id':'compnl' })
- ,dict(name='div' , attrs={'id':'artIssueInfo' })
- ]
-
- feeds = [
- (u'Latest Headlines' , u'http://feeds.newscientist.com/science-news' )
- ,(u'Magazine' , u'http://www.newscientist.com/feed/magazine' )
- ,(u'Health' , u'http://www.newscientist.com/feed/view?id=2&type=channel' )
- ,(u'Life' , u'http://www.newscientist.com/feed/view?id=3&type=channel' )
- ,(u'Space' , u'http://www.newscientist.com/feed/view?id=6&type=channel' )
- ,(u'Physics and Mathematics' , u'http://www.newscientist.com/feed/view?id=4&type=channel' )
- ,(u'Environment' , u'http://www.newscientist.com/feed/view?id=1&type=channel' )
- ,(u'Science in Society' , u'http://www.newscientist.com/feed/view?id=5&type=channel' )
- ,(u'Tech' , u'http://www.newscientist.com/feed/view?id=7&type=channel' )
- ]
\ No newline at end of file
+#!/usr/bin/env python
+
+__license__ = 'GPL v3'
+__copyright__ = '2008-2009, AprilHare, Darko Miletic '
+'''
+newscientist.com
+'''
+
+from calibre.web.feeds.news import BasicNewsRecipe
+
+class NewScientist(BasicNewsRecipe):
+ title = 'New Scientist - Online News'
+ __author__ = 'Darko Miletic'
+ description = 'Science news and science articles from New Scientist.'
+ language = _('English')
+ publisher = 'New Scientist'
+ category = 'science news, science articles, science jobs, drugs, cancer, depression, computer software, sex'
+ delay = 3
+ oldest_article = 7
+ max_articles_per_feed = 100
+ no_stylesheets = True
+ use_embedded_content = False
+ remove_javascript = True
+ encoding = 'utf-8'
+
+ html2lrf_options = [
+ '--comment', description
+ , '--category', category
+ , '--publisher', publisher
+ ]
+
+ html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
+
+ keep_only_tags = [dict(name='div', attrs={'id':['pgtop','maincol']})]
+
+ remove_tags = [
+ dict(name='div', attrs={'class':['hldBd','adline','pnl','infotext' ]})
+ ,dict(name='div', attrs={'id' :['compnl','artIssueInfo','artTools']})
+ ,dict(name='p' , attrs={'class':['marker','infotext' ]})
+ ]
+
+ feeds = [
+ (u'Latest Headlines' , u'http://feeds.newscientist.com/science-news' )
+ ,(u'Magazine' , u'http://www.newscientist.com/feed/magazine' )
+ ,(u'Health' , u'http://www.newscientist.com/feed/view?id=2&type=channel' )
+ ,(u'Life' , u'http://www.newscientist.com/feed/view?id=3&type=channel' )
+ ,(u'Space' , u'http://www.newscientist.com/feed/view?id=6&type=channel' )
+ ,(u'Physics and Mathematics' , u'http://www.newscientist.com/feed/view?id=4&type=channel' )
+ ,(u'Environment' , u'http://www.newscientist.com/feed/view?id=1&type=channel' )
+ ,(u'Science in Society' , u'http://www.newscientist.com/feed/view?id=5&type=channel' )
+ ,(u'Tech' , u'http://www.newscientist.com/feed/view?id=7&type=channel' )
+ ]
+
+ def get_article_url(self, article):
+ url = article.get('link', None)
+ raw = article.get('description', None)
+ rsoup = self.index_to_soup(raw)
+ atags = rsoup.findAll('a',href=True)
+ for atag in atags:
+ if atag['href'].startswith('http://res.feedsportal.com/viral/sendemail2.html?'):
+ st, sep, rest = atag['href'].partition('&link=')
+ real_url, sep2, drest = rest.partition('" target=')
+ return real_url
+ return url
+
+ def print_version(self, url):
+ rawurl, sep, params = url.partition('?')
+ return rawurl + '?full=true&print=true'
+
\ No newline at end of file