Merge from trunk

This commit is contained in:
Charles Haley 2010-12-14 18:08:47 +00:00
commit f2a16a682b
6 changed files with 87 additions and 17 deletions

View File

@ -0,0 +1,42 @@
#!/usr/bin/env python
import re
from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import Tag
class SBM(BasicNewsRecipe):
title = 'Science Based Medicine'
__author__ = 'BuzzKill'
description = 'Exploring issues and controversies in the relationship between science and medicine'
oldest_article = 5
max_articles_per_feed = 15
no_stylesheets = True
use_embedded_content = False
encoding = 'utf-8'
publisher = 'SBM'
category = 'science, sbm, ebm, blog, pseudoscience'
language = 'en'
lang = 'en-US'
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
, 'language' : lang
, 'pretty_print' : True
}
keep_only_tags = [
dict(name='a', attrs={'title':re.compile(r'Posts by.*', re.DOTALL|re.IGNORECASE)}),
dict(name='div', attrs={'class':'entry'})
]
feeds = [(u'Science Based Medicine', u'http://www.sciencebasedmedicine.org/?feed=rss2')]
def preprocess_html(self, soup):
mtag = Tag(soup,'meta',[('http-equiv','Content-Type'),('context','text/html; charset=utf-8')])
soup.head.insert(0,mtag)
soup.html['lang'] = self.lang
return self.adeify_images(soup)

View File

@ -60,8 +60,8 @@ class ZeitDe(BasicNewsRecipe):
for tag in soup.findAll(name=['ul','li']): for tag in soup.findAll(name=['ul','li']):
tag.name = 'div' tag.name = 'div'
soup.html['xml:lang'] = self.lang soup.html['xml:lang'] = self.language.replace('_', '-')
soup.html['lang'] = self.lang soup.html['lang'] = self.language.replace('_', '-')
mtag = '<meta http-equiv="Content-Type" content="text/html; charset=' + self.encoding + '">' mtag = '<meta http-equiv="Content-Type" content="text/html; charset=' + self.encoding + '">'
soup.head.insert(0,mtag) soup.head.insert(0,mtag)
return soup return soup

View File

@ -36,6 +36,11 @@ class UserFeedback(DeviceError):
self.details = details self.details = details
self.msg = msg self.msg = msg
class OpenFeedback(DeviceError):
def __init__(self, msg):
self.feedback_msg = msg
DeviceError.__init__(self, msg)
class DeviceBusy(ProtocolError): class DeviceBusy(ProtocolError):
""" Raised when device is busy """ """ Raised when device is busy """
def __init__(self, uerr=""): def __init__(self, uerr=""):

View File

@ -216,6 +216,9 @@ class DevicePlugin(Plugin):
an implementation of an implementation of
this function that should serve as a good example for USB Mass storage this function that should serve as a good example for USB Mass storage
devices. devices.
This method can raise an OpenFeedback exception to display a message to
the user.
''' '''
raise NotImplementedError() raise NotImplementedError()

View File

@ -12,7 +12,7 @@ from PyQt4.Qt import QMenu, QAction, QActionGroup, QIcon, SIGNAL, \
from calibre.customize.ui import available_input_formats, available_output_formats, \ from calibre.customize.ui import available_input_formats, available_output_formats, \
device_plugins device_plugins
from calibre.devices.interface import DevicePlugin from calibre.devices.interface import DevicePlugin
from calibre.devices.errors import UserFeedback from calibre.devices.errors import UserFeedback, OpenFeedback
from calibre.gui2.dialogs.choose_format import ChooseFormatDialog from calibre.gui2.dialogs.choose_format import ChooseFormatDialog
from calibre.utils.ipc.job import BaseJob from calibre.utils.ipc.job import BaseJob
from calibre.devices.scanner import DeviceScanner from calibre.devices.scanner import DeviceScanner
@ -122,7 +122,8 @@ def device_name_for_plugboards(device_class):
class DeviceManager(Thread): # {{{ class DeviceManager(Thread): # {{{
def __init__(self, connected_slot, job_manager, open_feedback_slot, sleep_time=2): def __init__(self, connected_slot, job_manager, open_feedback_slot,
open_feedback_msg, sleep_time=2):
''' '''
:sleep_time: Time to sleep between device probes in secs :sleep_time: Time to sleep between device probes in secs
''' '''
@ -143,6 +144,7 @@ class DeviceManager(Thread): # {{{
self.ejected_devices = set([]) self.ejected_devices = set([])
self.mount_connection_requests = Queue.Queue(0) self.mount_connection_requests = Queue.Queue(0)
self.open_feedback_slot = open_feedback_slot self.open_feedback_slot = open_feedback_slot
self.open_feedback_msg = open_feedback_msg
def report_progress(self, *args): def report_progress(self, *args):
pass pass
@ -163,6 +165,9 @@ class DeviceManager(Thread): # {{{
dev.reset(detected_device=detected_device, dev.reset(detected_device=detected_device,
report_progress=self.report_progress) report_progress=self.report_progress)
dev.open() dev.open()
except OpenFeedback, e:
self.open_feedback_msg(dev.get_gui_name(), e.feedback_msg)
continue
except: except:
tb = traceback.format_exc() tb = traceback.format_exc()
if DEBUG or tb not in self.reported_errors: if DEBUG or tb not in self.reported_errors:
@ -594,11 +599,16 @@ class DeviceMixin(object): # {{{
_('Error communicating with device'), ' ') _('Error communicating with device'), ' ')
self.device_error_dialog.setModal(Qt.NonModal) self.device_error_dialog.setModal(Qt.NonModal)
self.device_manager = DeviceManager(Dispatcher(self.device_detected), self.device_manager = DeviceManager(Dispatcher(self.device_detected),
self.job_manager, Dispatcher(self.status_bar.show_message)) self.job_manager, Dispatcher(self.status_bar.show_message),
Dispatcher(self.show_open_feedback))
self.device_manager.start() self.device_manager.start()
if tweaks['auto_connect_to_folder']: if tweaks['auto_connect_to_folder']:
self.connect_to_folder_named(tweaks['auto_connect_to_folder']) self.connect_to_folder_named(tweaks['auto_connect_to_folder'])
def show_open_feedback(self, devname, msg):
self.__of_dev_mem__ = d = info_dialog(self, devname, msg)
d.show()
def auto_convert_question(self, msg, autos): def auto_convert_question(self, msg, autos):
autos = u'\n'.join(map(unicode, map(force_unicode, autos))) autos = u'\n'.join(map(unicode, map(force_unicode, autos)))
return self.ask_a_yes_no_question( return self.ask_a_yes_no_question(

View File

@ -10,7 +10,6 @@ import os, sys, shutil, cStringIO, glob, time, functools, traceback, re
from itertools import repeat from itertools import repeat
from math import floor from math import floor
from Queue import Queue from Queue import Queue
from operator import itemgetter
from PyQt4.QtGui import QImage from PyQt4.QtGui import QImage
@ -1068,7 +1067,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
def get_categories(self, sort='name', ids=None, icon_map=None): def get_categories(self, sort='name', ids=None, icon_map=None):
start = time.time() start = last = time.time()
if icon_map is not None and type(icon_map) != TagsIcons: if icon_map is not None and type(icon_map) != TagsIcons:
raise TypeError('icon_map passed to get_categories must be of type TagIcons') raise TypeError('icon_map passed to get_categories must be of type TagIcons')
if sort not in self.CATEGORY_SORTS: if sort not in self.CATEGORY_SORTS:
@ -1120,12 +1119,14 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
# This saves iterating through field_metadata for each book # This saves iterating through field_metadata for each book
md.append((category, cat['rec_index'], cat['is_multiple'])) md.append((category, cat['rec_index'], cat['is_multiple']))
print 'end phase "collection":', time.time() - start, 'seconds' print 'end phase "collection":', time.time() - last, 'seconds'
last = time.time()
# Now scan every book looking for category items. # Now scan every book looking for category items.
# Code below is duplicated because it shaves off 10% of the loop time # Code below is duplicated because it shaves off 10% of the loop time
id_dex = self.FIELD_MAP['id'] id_dex = self.FIELD_MAP['id']
rating_dex = self.FIELD_MAP['rating'] rating_dex = self.FIELD_MAP['rating']
tag_class = LibraryDatabase2.TCat_Tag
for book in self.data.iterall(): for book in self.data.iterall():
if id_filter and book[id_dex] not in id_filter: if id_filter and book[id_dex] not in id_filter:
continue continue
@ -1140,7 +1141,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
(item_id, sort_val) = tids[cat][val] # let exceptions fly (item_id, sort_val) = tids[cat][val] # let exceptions fly
item = tcategories[cat].get(val, None) item = tcategories[cat].get(val, None)
if not item: if not item:
item = LibraryDatabase2.TCat_Tag(val, sort_val) item = tag_class(val, sort_val)
tcategories[cat][val] = item tcategories[cat][val] = item
item.c += 1 item.c += 1
item.id = item_id item.id = item_id
@ -1156,7 +1157,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
(item_id, sort_val) = tids[cat][val] # let exceptions fly (item_id, sort_val) = tids[cat][val] # let exceptions fly
item = tcategories[cat].get(val, None) item = tcategories[cat].get(val, None)
if not item: if not item:
item = LibraryDatabase2.TCat_Tag(val, sort_val) item = tag_class(val, sort_val)
tcategories[cat][val] = item tcategories[cat][val] = item
item.c += 1 item.c += 1
item.id = item_id item.id = item_id
@ -1166,7 +1167,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
except: except:
prints('get_categories: item', val, 'is not in', cat, 'list!') prints('get_categories: item', val, 'is not in', cat, 'list!')
print 'end phase "books":', time.time() - start, 'seconds' print 'end phase "books":', time.time() - last, 'seconds'
last = time.time()
# Now do news # Now do news
tcategories['news'] = {} tcategories['news'] = {}
@ -1186,11 +1188,13 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
item.set_all(c=r[2], rt=r[2]*r[3], rc=r[2], id=r[0]) item.set_all(c=r[2], rt=r[2]*r[3], rc=r[2], id=r[0])
tcategories['news'][r[1]] = item tcategories['news'][r[1]] = item
print 'end phase "news":', time.time() - start, 'seconds' print 'end phase "news":', time.time() - last, 'seconds'
last = time.time()
# Build the real category list by iterating over the temporary copy # Build the real category list by iterating over the temporary copy
# and building the Tag instances. # and building the Tag instances.
categories = {} categories = {}
tag_class = Tag
for category in tb_cats.keys(): for category in tb_cats.keys():
if category not in tcategories: if category not in tcategories:
continue continue
@ -1232,7 +1236,12 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
# sort the list # sort the list
if sort == 'name': if sort == 'name':
kf = lambda x: sort_key(x.s) if isinstance(x.s, unicode) else x.s def get_sort_key(x):
sk = x.s
if isinstance(sk, unicode):
sk = sort_key(sk)
return sk
kf = get_sort_key
reverse=False reverse=False
elif sort == 'popularity': elif sort == 'popularity':
kf = lambda x: x.c kf = lambda x: x.c
@ -1242,12 +1251,13 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
reverse=True reverse=True
items.sort(key=kf, reverse=reverse) items.sort(key=kf, reverse=reverse)
categories[category] = [Tag(formatter(r.n), count=r.c, id=r.id, categories[category] = [tag_class(formatter(r.n), count=r.c, id=r.id,
avg=avgr(r), sort=r.s, icon=icon, avg=avgr(r), sort=r.s, icon=icon,
tooltip=tooltip, category=category) tooltip=tooltip, category=category)
for r in items] for r in items]
print 'end phase "tags list":', time.time() - start, 'seconds' print 'end phase "tags list":', time.time() - last, 'seconds'
last = time.time()
# Needed for legacy databases that have multiple ratings that # Needed for legacy databases that have multiple ratings that
# map to n stars # map to n stars
@ -1333,8 +1343,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
icon_map['search'] = icon_map['search'] icon_map['search'] = icon_map['search']
categories['search'] = items categories['search'] = items
t = time.time() - start print 'last phase ran in:', time.time() - last, 'seconds'
print 'get_categories ran in:', t, 'seconds' print 'get_categories ran in:', time.time() - start, 'seconds'
return categories return categories