mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 10:44:09 -04:00
Merge from trunk
This commit is contained in:
commit
f2a16a682b
42
resources/recipes/science_based_medicine.recipe
Normal file
42
resources/recipes/science_based_medicine.recipe
Normal 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)
|
||||||
|
|
@ -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
|
||||||
|
@ -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=""):
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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(
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user