so we can format with CSS
- divTag = soup.find('div',attrs={'id':'authorId'})
- if divTag and divTag.contents[0]:
- tag = Tag(soup, "p")
- tag['class'] = "authorId"
- tag.insert(0, self.fixChars(self.tag_to_string(divTag.contents[0],
- use_alt=False)))
- divTag.replaceWith(tag)
-
- return soup
-
- def populate_article_metadata(self,article,soup,first):
- '''
- Extract author and description from article, add to article metadata
- '''
- def extract_author(soup):
- byline = soup.find('meta',attrs={'name':['byl','CLMST']})
- if byline :
- author = byline['content']
- else :
- # Try for
- byline = soup.find('div', attrs={'class':'byline'})
- if byline:
- author = byline.renderContents()
- else:
- print soup.prettify()
- return None
- return author
-
- def extract_description(soup):
- description = soup.find('meta',attrs={'name':['description','description ']})
- if description :
- return self.massageNCXText(description['content'])
- else:
- # Take first paragraph of article
- articlebody = soup.find('div',attrs={'id':'articlebody'})
- if not articlebody:
- # Try again with class instead of id
- articlebody = soup.find('div',attrs={'class':'articlebody'})
- if not articlebody:
- print 'postprocess_book.extract_description(): Did not find
:'
- print soup.prettify()
- return None
- paras = articlebody.findAll('p')
- for p in paras:
- if p.renderContents() > '' :
- return self.massageNCXText(self.tag_to_string(p,use_alt=False))
- return None
-
- if not article.author:
- article.author = extract_author(soup)
- if not article.summary:
- article.summary = article.text_summary = extract_description(soup)
-
- def strip_anchors(self,soup):
- paras = soup.findAll(True)
- for para in paras:
- aTags = para.findAll('a')
- for a in aTags:
- if a.img is None:
- a.replaceWith(a.renderContents().decode('utf-8','replace'))
- #a.replaceWith(a.renderContents().decode('cp1252','replace'))
- return soup
From 6ba05b0e44f6fb2a52aaae3591b7a78f8bb599f0 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 26 Oct 2010 10:52:42 -0600
Subject: [PATCH 58/69] Fix auto send of news to device with multiple calibre
libraries. The fix means that if you have any pending news to be sent, it
will be ignored after the update. Future news downloads will once again be
automatically sent to the device.
---
src/calibre/gui2/actions/fetch_news.py | 5 ++---
src/calibre/gui2/device.py | 29 +++++++++++++++++++++++---
2 files changed, 28 insertions(+), 6 deletions(-)
diff --git a/src/calibre/gui2/actions/fetch_news.py b/src/calibre/gui2/actions/fetch_news.py
index 98be7cdcb2..5c2a5e9663 100644
--- a/src/calibre/gui2/actions/fetch_news.py
+++ b/src/calibre/gui2/actions/fetch_news.py
@@ -9,7 +9,6 @@ from PyQt4.Qt import Qt
from calibre.gui2 import Dispatcher
from calibre.gui2.tools import fetch_scheduled_recipe
-from calibre.utils.config import dynamic
from calibre.gui2.actions import InterfaceAction
class FetchNewsAction(InterfaceAction):
@@ -60,9 +59,9 @@ class FetchNewsAction(InterfaceAction):
return self.gui.job_exception(job)
id = self.gui.library_view.model().add_news(pt.name, arg)
self.gui.library_view.model().reset()
- sync = dynamic.get('news_to_be_synced', set([]))
+ sync = self.gui.news_to_be_synced
sync.add(id)
- dynamic.set('news_to_be_synced', sync)
+ self.gui.news_to_be_synced = sync
self.scheduler.recipe_downloaded(arg)
self.gui.status_bar.show_message(arg['title'] + _(' fetched.'), 3000)
self.gui.email_news(id)
diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py
index e662c6a5cc..663649c192 100644
--- a/src/calibre/gui2/device.py
+++ b/src/calibre/gui2/device.py
@@ -1102,12 +1102,35 @@ class DeviceMixin(object): # {{{
self.status_bar.show_message(_('Sending catalogs to device.'), 5000)
+ @dynamic_property
+ def news_to_be_synced(self):
+ doc = 'Set of ids to be sent to device'
+ def fget(self):
+ ans = []
+ try:
+ ans = self.library_view.model().db.prefs.get('news_to_be_synced',
+ [])
+ except:
+ import traceback
+ traceback.print_exc()
+ return set(ans)
+
+ def fset(self, ids):
+ try:
+ self.library_view.model().db.prefs.set('news_to_be_synced',
+ list(ids))
+ except:
+ import traceback
+ traceback.print_exc()
+
+ return property(fget=fget, fset=fset, doc=doc)
+
def sync_news(self, send_ids=None, do_auto_convert=True):
if self.device_connected:
del_on_upload = config['delete_news_from_library_on_upload']
settings = self.device_manager.device.settings()
- ids = list(dynamic.get('news_to_be_synced', set([]))) if send_ids is None else send_ids
+ ids = list(self.news_to_be_synced) if send_ids is None else send_ids
ids = [id for id in ids if self.library_view.model().db.has_id(id)]
files, _auto_ids = self.library_view.model().get_preferred_formats_from_ids(
ids, settings.format_map,
@@ -1139,7 +1162,7 @@ class DeviceMixin(object): # {{{
for f in files:
f.deleted_after_upload = del_on_upload
if not files:
- dynamic.set('news_to_be_synced', set([]))
+ self.news_to_be_synced = set([])
return
metadata = self.library_view.model().metadata_for(ids)
names = []
@@ -1153,7 +1176,7 @@ class DeviceMixin(object): # {{{
if mi.cover and os.access(mi.cover, os.R_OK):
mi.thumbnail = self.cover_to_thumbnail(open(mi.cover,
'rb').read())
- dynamic.set('news_to_be_synced', set([]))
+ self.news_to_be_synced = set([])
if config['upload_news_to_device'] and files:
remove = ids if del_on_upload else []
space = { self.location_manager.free[0] : None,
From ae1e165aa30de63c9bf765d41acb9d842ada6bb2 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 26 Oct 2010 10:57:14 -0600
Subject: [PATCH 59/69] Fix #7308 (Updated recipe for CubaDebate)
---
resources/recipes/cubadebate.recipe | 34 +++++++++++++++++++----------
1 file changed, 22 insertions(+), 12 deletions(-)
diff --git a/resources/recipes/cubadebate.recipe b/resources/recipes/cubadebate.recipe
index 88d06d412d..f8887b2672 100644
--- a/resources/recipes/cubadebate.recipe
+++ b/resources/recipes/cubadebate.recipe
@@ -1,9 +1,7 @@
-#!/usr/bin/env python
-
__license__ = 'GPL v3'
-__copyright__ = '2009, Darko Miletic '
+__copyright__ = '2009-2010, Darko Miletic '
'''
-newyorker.com
+cubadebate.cu
'''
from calibre.web.feeds.news import BasicNewsRecipe
@@ -13,32 +11,44 @@ class CubaDebate(BasicNewsRecipe):
__author__ = 'Darko Miletic'
description = 'Contra el Terorismo Mediatico'
oldest_article = 15
- language = 'es'
-
+ language = 'es'
max_articles_per_feed = 100
no_stylesheets = True
use_embedded_content = False
publisher = 'Cubadebate'
category = 'news, politics, Cuba'
encoding = 'utf-8'
- extra_css = ' #BlogTitle{font-size: x-large; font-weight: bold} '
+ masthead_url = 'http://www.cubadebate.cu/wp-content/themes/cubadebate/images/logo.gif'
+ publication_type = 'newsportal'
+ extra_css = """
+ #BlogTitle{font-size: xx-large; font-weight: bold}
+ body{font-family: Verdana, Arial, Tahoma, sans-serif}
+ """
conversion_options = {
'comments' : description
,'tags' : category
- ,'language' : 'es'
+ ,'language' : language
,'publisher' : publisher
- ,'pretty_print': True
}
keep_only_tags = [dict(name='div', attrs={'id':'Outline'})]
remove_tags_after = dict(name='div',attrs={'id':'BlogContent'})
- remove_tags = [dict(name='link')]
+ remove_tags = [
+ dict(name=['link','base','embed','object','meta','iframe'])
+ ,dict(attrs={'id':'addthis_container'})
+ ]
feeds = [(u'Articulos', u'http://www.cubadebate.cu/feed/')]
-
+ remove_attributes=['width','height','lang']
+
def print_version(self, url):
return url + 'print/'
def preprocess_html(self, soup):
- return self.adeify_images(soup)
+ for item in soup.findAll(style=True):
+ del item['style']
+ for item in soup.findAll('img'):
+ if not item.has_key('alt'):
+ item['alt'] = 'image'
+ return soup
From 44c3ba638e538f82251b6e76fc6ab08cf4f82de2 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 26 Oct 2010 13:18:14 -0600
Subject: [PATCH 60/69] Update pdf metadata libraries (poppler/podofo) to
latest versions in windows build
---
setup/extensions.py | 2 +-
setup/installer/windows/notes.rst | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/setup/extensions.py b/setup/extensions.py
index df6f0ffbcd..d520cbf622 100644
--- a/setup/extensions.py
+++ b/setup/extensions.py
@@ -54,7 +54,7 @@ reflow_error = poppler_error if poppler_error else magick_error
pdfreflow_libs = []
if iswindows:
- pdfreflow_libs = ['advapi32', 'User32', 'Gdi32']
+ pdfreflow_libs = ['advapi32', 'User32', 'Gdi32', 'zlib']
extensions = [
diff --git a/setup/installer/windows/notes.rst b/setup/installer/windows/notes.rst
index f41b7215b5..a8ba41e8ff 100644
--- a/setup/installer/windows/notes.rst
+++ b/setup/installer/windows/notes.rst
@@ -213,7 +213,7 @@ It contains correct fonts.conf etc.
poppler
-------------
-In Cmake: disable GTK, Qt, OPenjpeg, zlib, lcms, gtk_tests, qt_tests. Enable qt4, jpeg, png and zlib
+In Cmake: disable GTK, Qt, OPenjpeg, cpp, lcms, gtk_tests, qt_tests. Enable qt4, jpeg, png and zlib
NOTE: poppler must be built as a static library, unless you build the qt4 bindings
From 50151bca5e817bb665a94ac2ee6cdcd2138ca385 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 26 Oct 2010 15:31:10 -0600
Subject: [PATCH 61/69] Fix #7288 (calibre cannot work correctly if the
temporary path contain non-ASCII characters)
---
src/calibre/ebooks/conversion/plumber.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/calibre/ebooks/conversion/plumber.py b/src/calibre/ebooks/conversion/plumber.py
index f520365c1c..9a863d7e66 100644
--- a/src/calibre/ebooks/conversion/plumber.py
+++ b/src/calibre/ebooks/conversion/plumber.py
@@ -14,7 +14,7 @@ from calibre.ebooks.conversion.preprocess import HTMLPreProcessor
from calibre.ptempfile import PersistentTemporaryDirectory
from calibre.utils.date import parse_date
from calibre.utils.zipfile import ZipFile
-from calibre import extract, walk
+from calibre import extract, walk, isbytestring, filesystem_encoding
from calibre.constants import __version__
DEBUG_README=u'''
@@ -77,6 +77,10 @@ class Plumber(object):
:param input: Path to input file.
:param output: Path to output file/directory
'''
+ if isbytestring(input):
+ input = input.decode(filesystem_encoding)
+ if isbytestring(output):
+ output = output.decode(filesystem_encoding)
self.original_input_arg = input
self.input = os.path.abspath(input)
self.output = os.path.abspath(output)
From 19d3a38ee969834ef92e91c2e51fc7c01f1857e2 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 26 Oct 2010 16:00:00 -0600
Subject: [PATCH 62/69] Fix #7306 (Rescaled GIFs are 0 bytes)
---
src/calibre/ebooks/oeb/transforms/rescale.py | 50 +++++---------------
1 file changed, 13 insertions(+), 37 deletions(-)
diff --git a/src/calibre/ebooks/oeb/transforms/rescale.py b/src/calibre/ebooks/oeb/transforms/rescale.py
index 79d4c76487..d73205709b 100644
--- a/src/calibre/ebooks/oeb/transforms/rescale.py
+++ b/src/calibre/ebooks/oeb/transforms/rescale.py
@@ -6,8 +6,6 @@ __license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal '
__docformat__ = 'restructuredtext en'
-import cStringIO
-
from calibre import fit_image
class RescaleImages(object):
@@ -19,13 +17,7 @@ class RescaleImages(object):
self.rescale(qt=is_ok_to_use_qt())
def rescale(self, qt=True):
- from PyQt4.Qt import QImage, Qt
- from calibre.gui2 import pixmap_to_data
- try:
- from PIL import Image as PILImage
- PILImage
- except ImportError:
- import Image as PILImage
+ from calibre.utils.magick.draw import Image
is_image_collection = getattr(self.opts, 'is_image_collection', False)
@@ -35,6 +27,7 @@ class RescaleImages(object):
page_width, page_height = self.opts.dest.width, self.opts.dest.height
page_width -= (self.opts.margin_left + self.opts.margin_right) * self.opts.dest.dpi/72.
page_height -= (self.opts.margin_top + self.opts.margin_bottom) * self.opts.dest.dpi/72.
+
for item in self.oeb.manifest:
if item.media_type.startswith('image'):
ext = item.media_type.split('/')[-1].upper()
@@ -44,42 +37,25 @@ class RescaleImages(object):
raw = item.data
if not raw: continue
- if qt:
- img = QImage(10, 10, QImage.Format_ARGB32_Premultiplied)
- try:
- if not img.loadFromData(raw): continue
- except:
- continue
- width, height = img.width(), img.height()
- else:
- f = cStringIO.StringIO(raw)
- try:
- im = PILImage.open(f)
- except IOError:
- continue
- width, height = im.size
-
+ try:
+ img = Image()
+ img.load(raw)
+ except:
+ continue
+ width, height = img.size
scaled, new_width, new_height = fit_image(width, height,
page_width, page_height)
if scaled:
- data = None
self.log('Rescaling image from %dx%d to %dx%d'%(
width, height, new_width, new_height), item.href)
- if qt:
- img = img.scaled(new_width, new_height,
- Qt.IgnoreAspectRatio, Qt.SmoothTransformation)
- data = pixmap_to_data(img, format=ext)
+ try:
+ img.size = (new_width, new_height)
+ data = img.export(ext.lower())
+ except:
+ self.log.exception('Failed to rescale image')
else:
- try:
- im = im.resize((int(new_width), int(new_height)), PILImage.ANTIALIAS)
- of = cStringIO.StringIO()
- im.convert('RGB').save(of, ext)
- data = of.getvalue()
- except:
- self.log.exception('Failed to rescale image')
- if data is not None:
item.data = data
item.unload_data_from_memory()
From f61d22fd31dd5db0fb2eb3564e07e6054c66ca50 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 26 Oct 2010 16:14:46 -0600
Subject: [PATCH 63/69] Fix #7295 (Unhandled Exception)
---
src/calibre/gui2/dialogs/book_info.py | 7 ++++++-
src/calibre/gui2/library/models.py | 2 ++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/src/calibre/gui2/dialogs/book_info.py b/src/calibre/gui2/dialogs/book_info.py
index e085dcc3e2..cca2abb6e0 100644
--- a/src/calibre/gui2/dialogs/book_info.py
+++ b/src/calibre/gui2/dialogs/book_info.py
@@ -90,10 +90,15 @@ class BookInfo(QDialog, Ui_BookInfo):
row = row.row()
if row == self.current_row:
return
+ info = self.view.model().get_book_info(row)
+ if info is None:
+ # Indicates books was deleted from library, or row numbers have
+ # changed
+ return
+
self.previous_button.setEnabled(False if row == 0 else True)
self.next_button.setEnabled(False if row == self.view.model().rowCount(QModelIndex())-1 else True)
self.current_row = row
- info = self.view.model().get_book_info(row)
self.setWindowTitle(info[_('Title')])
self.title.setText(''+info.pop(_('Title')))
comments = info.pop(_('Comments'), '')
diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py
index 0286acc782..112df3023c 100644
--- a/src/calibre/gui2/library/models.py
+++ b/src/calibre/gui2/library/models.py
@@ -374,6 +374,8 @@ class BooksModel(QAbstractTableModel): # {{{
if isinstance(index, int):
index = self.index(index, 0)
data = self.current_changed(index, None, False)
+ if data is None:
+ return data
row = index.row()
data[_('Title')] = self.db.title(row)
au = self.db.authors(row)
From 08d0cfee131efc661a7466798abd0d8e31c57ffd Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 26 Oct 2010 16:25:51 -0600
Subject: [PATCH 64/69] =?UTF-8?q?Add=20an=20output=20profile=20for=20gener?=
=?UTF-8?q?ic=20tablet=20devices.=20Fixes=20#7289=20(Wetab=20output=20prof?=
=?UTF-8?q?ile=20(Display=20screen:=2011,6=E2=80=9C,=201366=20x=20768=20Pi?=
=?UTF-8?q?xels,=20Color.))?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/calibre/customize/profiles.py | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/src/calibre/customize/profiles.py b/src/calibre/customize/profiles.py
index 27f0805f86..1df2e65f1e 100644
--- a/src/calibre/customize/profiles.py
+++ b/src/calibre/customize/profiles.py
@@ -4,6 +4,7 @@ __license__ = 'GPL 3'
__copyright__ = '2009, Kovid Goyal '
__docformat__ = 'restructuredtext en'
+import sys
from itertools import izip
from xml.sax.saxutils import escape
@@ -417,6 +418,13 @@ class iPadOutput(OutputProfile):
'''
# }}}
+class TabletOutput(iPadOutput):
+ name = 'Tablet'
+ short_name = 'tablet'
+ description = _('Intended for generic tablet devices, does no resizing of images')
+
+ screen_size = (sys.maxint, sys.maxint)
+ comic_screen_size = (sys.maxint, sys.maxint)
class SonyReaderOutput(OutputProfile):
@@ -664,7 +672,7 @@ class BambookOutput(OutputProfile):
output_profiles = [OutputProfile, SonyReaderOutput, SonyReader300Output,
SonyReader900Output, MSReaderOutput, MobipocketOutput, HanlinV3Output,
HanlinV5Output, CybookG3Output, CybookOpusOutput, KindleOutput,
- iPadOutput, KoboReaderOutput,
+ iPadOutput, KoboReaderOutput, TabletOutput,
SonyReaderLandscapeOutput, KindleDXOutput, IlliadOutput,
IRexDR1000Output, IRexDR800Output, JetBook5Output, NookOutput,
BambookOutput, ]
From 51a79f25c799a92a19995e06bd74f4ff348faaa3 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 26 Oct 2010 16:29:26 -0600
Subject: [PATCH 65/69] Fix #7275 (Support for HTC Aria)
---
src/calibre/devices/android/driver.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/calibre/devices/android/driver.py b/src/calibre/devices/android/driver.py
index dd08c745b1..918de28e67 100644
--- a/src/calibre/devices/android/driver.py
+++ b/src/calibre/devices/android/driver.py
@@ -20,7 +20,8 @@ class ANDROID(USBMS):
VENDOR_ID = {
# HTC
0x0bb4 : { 0x0c02 : [0x100, 0x0227], 0x0c01 : [0x100, 0x0227], 0x0ff9
- : [0x0100, 0x0227, 0x0226], 0x0c87: [0x0100, 0x0227, 0x0226]},
+ : [0x0100, 0x0227, 0x0226], 0x0c87: [0x0100, 0x0227, 0x0226],
+ 0xc92 : [0x100]},
# Motorola
0x22b8 : { 0x41d9 : [0x216], 0x2d67 : [0x100], 0x41db : [0x216],
From e83dc0e8003bb39ab45630330a52d89969db0927 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 26 Oct 2010 16:39:17 -0600
Subject: [PATCH 66/69] Fix #7241 ('Generate Cover' cannot support Asian
characters)
---
resources/default_tweaks.py | 8 ++++++++
src/calibre/utils/magick/draw.py | 10 ++++++++--
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/resources/default_tweaks.py b/resources/default_tweaks.py
index 270b7e0b06..0f570bab40 100644
--- a/resources/default_tweaks.py
+++ b/resources/default_tweaks.py
@@ -203,3 +203,11 @@ content_server_wont_display = ['']
# level sorts, and if you are seeing a slowdown, reduce the value of this tweak.
maximum_resort_levels = 5
+# Absolute path to a TTF font file to use as the font for the title and author
+# when generating a default cover. Useful if the default font (Liberation
+# Serif) does not contain glyphs for the language of the books in your library.
+generate_cover_title_font = None
+
+# Absolute path to a TTF font file to use as the font for the footer in the
+# default cover
+generate_cover_foot_font = None
diff --git a/src/calibre/utils/magick/draw.py b/src/calibre/utils/magick/draw.py
index 5c978a27e0..d3cbd58c7d 100644
--- a/src/calibre/utils/magick/draw.py
+++ b/src/calibre/utils/magick/draw.py
@@ -9,6 +9,7 @@ import os
from calibre.utils.magick import Image, DrawingWand, create_canvas
from calibre.constants import __appname__, __version__
+from calibre.utils.config import tweaks
from calibre import fit_image
def normalize_format_name(fmt):
@@ -113,7 +114,9 @@ def add_borders_to_image(img_data, left=0, top=0, right=0, bottom=0,
def create_text_wand(font_size, font_path=None):
if font_path is None:
- font_path = P('fonts/liberation/LiberationSerif-Bold.ttf')
+ font_path = tweaks['generate_cover_title_font']
+ if font_path is None:
+ font_path = P('fonts/liberation/LiberationSerif-Bold.ttf')
ans = DrawingWand()
ans.font = font_path
ans.font_size = font_size
@@ -203,8 +206,11 @@ def create_cover_page(top_lines, logo_path, width=590, height=750,
bottom += line.bottom_margin
bottom -= top_lines[-1].bottom_margin
+ foot_font = tweaks['generate_cover_foot_font']
+ if not foot_font:
+ foot_font = P('fonts/liberation/LiberationMono-Regular.ttf')
vanity = create_text_arc(__appname__ + ' ' + __version__, 24,
- font=P('fonts/liberation/LiberationMono-Regular.ttf'))
+ font=foot_font)
lwidth, lheight = vanity.size
left = int(max(0, (width - lwidth)/2.))
top = height - lheight - 10
From 35008f833f5c0037f1a9896a22af029aebbbf7c4 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 26 Oct 2010 16:46:57 -0600
Subject: [PATCH 67/69] Add driver for Nokia N900
---
src/calibre/devices/nokia/driver.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/calibre/devices/nokia/driver.py b/src/calibre/devices/nokia/driver.py
index f378a656fb..ed10f849d0 100644
--- a/src/calibre/devices/nokia/driver.py
+++ b/src/calibre/devices/nokia/driver.py
@@ -36,15 +36,15 @@ class N770(USBMS):
class N810(N770):
name = 'Nokia 810 Device Interface'
- gui_name = 'Nokia 810'
- description = _('Communicate with the Nokia 810 internet tablet.')
+ gui_name = 'Nokia 810/900'
+ description = _('Communicate with the Nokia 810/900 internet tablet.')
- PRODUCT_ID = [0x96]
+ PRODUCT_ID = [0x96, 0x1c7]
BCD = [0x316]
- WINDOWS_MAIN_MEM = 'N810'
+ WINDOWS_MAIN_MEM = ['N810', 'N900']
- MAIN_MEMORY_VOLUME_LABEL = 'N810 Main Memory'
+ MAIN_MEMORY_VOLUME_LABEL = 'Nokia Tablet Main Memory'
class E71X(USBMS):
From 50f100bee86e35b9cd11e85b0185470a13e75b87 Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 26 Oct 2010 18:21:49 -0600
Subject: [PATCH 68/69] Fix #7271 (Books are deselected after sending to
device)
---
src/calibre/gui2/device.py | 5 +++--
src/calibre/gui2/library/views.py | 31 +++++++++++++++++++++++++++++++
2 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py
index 663649c192..a1f0288050 100644
--- a/src/calibre/gui2/device.py
+++ b/src/calibre/gui2/device.py
@@ -1370,8 +1370,9 @@ class DeviceMixin(object): # {{{
# If it does not, then do it here.
if not self.set_books_in_library(self.booklists(), reset=True):
self.upload_booklists()
- self.book_on_device(None, reset=True)
- self.refresh_ondevice()
+ with self.library_view.preserve_selected_books:
+ self.book_on_device(None, reset=True)
+ self.refresh_ondevice()
view = self.card_a_view if on_card == 'carda' else \
self.card_b_view if on_card == 'cardb' else self.memory_view
diff --git a/src/calibre/gui2/library/views.py b/src/calibre/gui2/library/views.py
index 8f86bf43b8..1c2a541116 100644
--- a/src/calibre/gui2/library/views.py
+++ b/src/calibre/gui2/library/views.py
@@ -22,6 +22,26 @@ from calibre.gui2.library import DEFAULT_SORT
from calibre.constants import filesystem_encoding
from calibre import force_unicode
+class PreserveSelection(object): # {{{
+
+ '''
+ Save the set of selected books at enter time. If at exit time there are no
+ selected books, restore the previous selection.
+ '''
+
+ def __init__(self, view):
+ self.view = view
+ self.selected_ids = []
+
+ def __enter__(self):
+ self.selected_ids = self.view.get_selected_ids()
+
+ def __exit__(self, *args):
+ current = self.view.get_selected_ids()
+ if not current:
+ self.view.select_rows(self.selected_ids, using_ids=True)
+# }}}
+
class BooksView(QTableView): # {{{
files_dropped = pyqtSignal(object)
@@ -58,6 +78,7 @@ class BooksView(QTableView): # {{{
self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setSortingEnabled(True)
self.selectionModel().currentRowChanged.connect(self._model.current_changed)
+ self.preserve_selected_books = PreserveSelection(self)
# {{{ Column Header setup
self.can_add_columns = True
@@ -613,6 +634,16 @@ class BooksView(QTableView): # {{{
sel.select(m.index(row, 0), m.index(row, max_col))
sm.select(sel, sm.ClearAndSelect)
+ def get_selected_ids(self):
+ ans = []
+ m = self.model()
+ for idx in self.selectedIndexes():
+ r = idx.row()
+ i = m.id(r)
+ if i not in ans:
+ ans.append(i)
+ return ans
+
def close(self):
self._model.close()
From 4a4e912662ca2b6f4120b318c2877843e1ee00ca Mon Sep 17 00:00:00 2001
From: Kovid Goyal
Date: Tue, 26 Oct 2010 18:51:17 -0600
Subject: [PATCH 69/69] ...
---
src/calibre/manual/faq.rst | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/src/calibre/manual/faq.rst b/src/calibre/manual/faq.rst
index 220e7ff9e4..ae740947b7 100644
--- a/src/calibre/manual/faq.rst
+++ b/src/calibre/manual/faq.rst
@@ -435,3 +435,33 @@ And since I'm sure someone will ask: The reason adding/saving books are in separ
Finally, the reason calibre keep workers alive and idle instead of launching on demand is to workaround the slow startup time of python processes.
+How do I run parts of |app| like news download and the content server on my own linux server?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+First, you must install |app| onto your linux server. If your server is using a modern linux distro, you should have no problems installing |app| onto it.
+
+.. note::
+ If you bought into the notion that a real server must run a decade old version of Debian, then you will have to jump through a few hoops. First, compile a newer version of glibc (>= 2.10) on your server from source. Then get the |app| linux binary tarball from the |app| google code page for your server architecture. Extract it into :file:`/opt/calibre`. Put your previously compiled glibc into :file:`/opt/calibre` as :file:`libc.so.6`. You can now run the calibre binaries from :file:`/opt/calibre`.
+
+You can run the |app| server via the command::
+
+ /opt/calibre/calibre-server --with-library /path/to/the/library/you/want/to/share
+
+You can download news and convert it into an ebook with the command::
+
+ /opt/calibre/ebook-convert "Title of news source.recipe" outputfile.epub
+
+If you want to generate MOBI, use outputfile.mobi instead.
+
+You can email downloaded news with the command::
+
+ /opt/calibre/calibre-smtp
+
+I leave figuring out the exact command line as an exercise for the reader.
+
+Finally, you can add downloaded news to the |app| library with::
+
+ /opt/calibre/calibredb add --with-library /path/to/library outfile.epub
+
+Remember to read the command line documentatation section of the |app| User Manual to learn more about these, and other commands.
+