Merge from custcol trunk

This commit is contained in:
Charles Haley 2010-05-17 23:35:40 +01:00
commit 6f504a1009
10 changed files with 108 additions and 62 deletions

View File

@ -1,11 +1,10 @@
#!/usr/bin/env python
__license__ = 'GPL v3'
__copyright__ = '2009, Darko Miletic <darko.miletic at gmail.com>'
__copyright__ = '2009-2010, Darko Miletic <darko.miletic at gmail.com>'
'''
www.instapaper.com
'''
import urllib
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe
@ -22,18 +21,15 @@ class Instapaper(BasicNewsRecipe):
max_articles_per_feed = 100
no_stylesheets = True
use_embedded_content = False
remove_javascript = True
needs_subscription = True
INDEX = u'http://www.instapaper.com'
LOGIN = INDEX + u'/user/login'
html2lrf_options = [
'--comment', description
, '--category', category
, '--publisher', publisher
]
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"\noverride_css=" p {text-indent: 0em; margin-top: 0em; margin-bottom: 0.5em} img {margin-top: 0em; margin-bottom: 0.4em}"'
conversion_options = {
'comment' : description
, 'tags' : category
, 'publisher' : publisher
}
feeds = [
(u'Unread articles' , INDEX + u'/u' )
@ -63,7 +59,7 @@ class Instapaper(BasicNewsRecipe):
description = self.tag_to_string(item.div)
atag = item.a
if atag and atag.has_key('href'):
url = self.INDEX + atag['href'] + '/text'
url = atag['href']
title = self.tag_to_string(atag)
date = strftime(self.timefmt)
articles.append({
@ -75,3 +71,6 @@ class Instapaper(BasicNewsRecipe):
totalfeeds.append((feedtitle, articles))
return totalfeeds
def print_version(self, url):
return self.INDEX + '/text?u=' + urllib.quote(url)

View File

@ -23,7 +23,7 @@ class NewYorkReviewOfBooks(BasicNewsRecipe):
no_javascript = True
needs_subscription = True
keep_only_tags = [dict(id='article-body')]
keep_only_tags = [dict(id=['article-body','page-title'])]
remove_tags = [dict(attrs={'class':['article-tools', 'article-links',
'center advertisement']})]

View File

@ -21,7 +21,7 @@ class NewYorkReviewOfBooks(BasicNewsRecipe):
no_stylesheets = True
no_javascript = True
keep_only_tags = [dict(id='article-body')]
keep_only_tags = [dict(id=['article-body', 'page-title'])]
remove_tags = [dict(attrs={'class':['article-tools', 'article-links',
'center advertisement']})]

View File

@ -380,7 +380,9 @@ class BookList(list):
3. size (file size of the book)
4. datetime (a UTC time tuple)
5. path (path on the device to the book)
6. thumbnail (can be None)
6. thumbnail (can be None) thumbnail is either a str/bytes object with the
image data or it should have an attribute image_path that stores an
absolute (platform native) path to the image
7. tags (a list of strings, can be empty).
'''

View File

@ -38,8 +38,10 @@ class Book(MetaInformation):
self.lpath = lpath
self.mime = mime_type_ext(path_to_ext(lpath))
self.size = size # will be set later if None
self.datetime = time.gmtime()
try:
self.datetime = time.gmtime(os.path.getctime(self.path))
except:
self.datetime = time.gmtime()
if other:
self.smart_update(other)

View File

@ -276,18 +276,22 @@ class USBMS(CLI, Device):
# bl = cls.booklist_class()
js = []
need_sync = False
try:
with open(cls.normalize_path(os.path.join(prefix, name)), 'rb') as f:
js = json.load(f, encoding='utf-8')
for item in js:
book = cls.book_class(prefix, item.get('lpath', None))
for key in item.keys():
setattr(book, key, item[key])
bl.append(book)
except:
import traceback
traceback.print_exc()
bl = []
cache_file = cls.normalize_path(os.path.join(prefix, name))
if os.access(cache_file, os.R_OK):
try:
with open(cache_file, 'rb') as f:
js = json.load(f, encoding='utf-8')
for item in js:
book = cls.book_class(prefix, item.get('lpath', None))
for key in item.keys():
setattr(book, key, item[key])
bl.append(book)
except:
import traceback
traceback.print_exc()
bl = []
need_sync = True
else:
need_sync = True
return need_sync

View File

@ -37,8 +37,13 @@ class EPUBInput(InputFormatPlugin):
scheme = item.get(xkey)
if (scheme and scheme.lower() == 'uuid') or \
(item.text and item.text.startswith('urn:uuid:')):
key = str(item.text).rpartition(':')[-1]
key = list(map(ord, uuid.UUID(key).bytes))
try:
key = str(item.text).rpartition(':')[-1]
key = list(map(ord, uuid.UUID(key).bytes))
except:
import traceback
traceback.print_exc()
key = None
try:
root = etree.parse(encfile)
@ -49,7 +54,7 @@ class EPUBInput(InputFormatPlugin):
cr = em.getparent().xpath('descendant::*[contains(name(), "CipherReference")]')[0]
uri = cr.get('URI')
path = os.path.abspath(os.path.join(os.path.dirname(encfile), '..', *uri.split('/')))
if os.path.exists(path):
if key is not None and os.path.exists(path):
self._encrypted_font_uris.append(uri)
self.decrypt_font(key, path)
return True

View File

@ -20,7 +20,7 @@ from calibre.gui2 import config, error_dialog, Dispatcher, dynamic, \
pixmap_to_data, warning_dialog, \
question_dialog
from calibre.ebooks.metadata import authors_to_string, authors_to_sort_string
from calibre import preferred_encoding
from calibre import preferred_encoding, prints
from calibre.utils.filenames import ascii_filename
from calibre.devices.errors import FreeSpaceError
from calibre.utils.smtp import compose_mail, sendmail, extract_email_address, \
@ -88,7 +88,7 @@ class DeviceManager(Thread):
self.connected_device = None
self.ejected_devices = set([])
self.connected_device_is_folder = False
self.folder_connection_path = None
self.folder_connection_requests = Queue.Queue(0)
def report_progress(self, *args):
pass
@ -175,15 +175,20 @@ class DeviceManager(Thread):
def run(self):
while self.keep_going:
if not self.is_device_connected and \
self.folder_connection_path is not None:
f = self.folder_connection_path
self.folder_connection_path = None # Make sure we try this folder only once
folder_path = None
while True:
try:
dev = FOLDER_DEVICE(f)
folder_path = self.folder_connection_requests.get_nowait()
except Queue.Empty:
break
if not folder_path or not os.access(folder_path, os.R_OK):
folder_path = None
if not self.is_device_connected and folder_path is not None:
try:
dev = FOLDER_DEVICE(folder_path)
self.do_connect([[dev, None],], is_folder_device=True)
except:
print 'Unable to open folder as device', f
prints('Unable to open folder as device', folder_path)
traceback.print_exc()
else:
self.detect_device()
@ -226,7 +231,7 @@ class DeviceManager(Thread):
# This will be called on the GUI thread. Because of this, we must store
# information that the scanner thread will use to do the real work.
def connect_to_folder(self, path):
self.folder_connection_path = path
self.folder_connection_requests.put(path)
# This is called on the GUI thread. No problem here, because it calls the
# device driver, telling it to tell the scanner when it passes by that the

View File

@ -29,7 +29,7 @@ from calibre.utils.date import dt_factory, qt_to_dt, isoformat, now
from calibre.utils.pyparsing import ParseException
from calibre.utils.search_query_parser import SearchQueryParser
# Delegates {{{
class RatingDelegate(QStyledItemDelegate):
COLOR = QColor("blue")
SIZE = 16
@ -303,7 +303,9 @@ class CcBoolDelegate(QStyledItemDelegate):
val = 2 if val is None else 1 if not val else 0
editor.setCurrentIndex(val)
class BooksModel(QAbstractTableModel):
# }}}
class BooksModel(QAbstractTableModel): # {{{
about_to_be_sorted = pyqtSignal(object, name='aboutToBeSorted')
sorting_done = pyqtSignal(object, name='sortingDone')
@ -973,13 +975,13 @@ class BooksModel(QAbstractTableModel):
self.db.set(row, column, val)
self.emit(SIGNAL("dataChanged(QModelIndex, QModelIndex)"), \
index, index)
#if column == self.sorted_on[0]:
# self.resort()
return True
def set_search_restriction(self, s):
self.db.data.set_search_restriction(s)
# }}}
class BooksView(TableView):
TIME_FMT = '%d %b %Y'
wrapper = textwrap.TextWrapper(width=20)
@ -1084,6 +1086,11 @@ class BooksView(TableView):
if not self.restore_column_widths():
self.resizeColumnsToContents()
sort_col = self._model.sorted_on[0]
if sort_col in cm:
idx = cm.index(sort_col)
self.horizontalHeader().setSortIndicator(idx, self._model.sorted_on[1])
def set_context_menu(self, edit_metadata, send_to_device, convert, view,
save, open_folder, book_details, delete, similar_menu=None):
self.setContextMenuPolicy(Qt.DefaultContextMenu)
@ -1418,9 +1425,12 @@ class DeviceBooksModel(BooksModel):
data = {}
item = self.db[self.map[current.row()]]
cdata = item.thumbnail
if cdata:
if cdata is not None:
img = QImage()
img.loadFromData(cdata)
if hasattr(cdata, 'image_path'):
img.load(cdata.image_path)
else:
img.loadFromData(cdata)
if img.isNull():
img = self.default_image
data['cover'] = img

View File

@ -348,6 +348,10 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.save_menu.addAction(_('Save to disk in a single directory'))
self.save_menu.addAction(_('Save only %s format to disk')%
prefs['output_format'].upper())
self.save_menu.addAction(
_('Save only %s format to disk in a single directory')%
prefs['output_format'].upper())
self.save_sub_menu = SaveMenu(self)
self.save_menu.addMenu(self.save_sub_menu)
self.connect(self.save_sub_menu, SIGNAL('save_fmt(PyQt_PyObject)'),
@ -376,6 +380,8 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.save_to_single_dir)
QObject.connect(self.save_menu.actions()[2], SIGNAL("triggered(bool)"),
self.save_single_format_to_disk)
QObject.connect(self.save_menu.actions()[3], SIGNAL("triggered(bool)"),
self.save_single_fmt_to_single_dir)
QObject.connect(self.action_view, SIGNAL("triggered(bool)"),
self.view_book)
QObject.connect(self.view_menu.actions()[0],
@ -670,7 +676,8 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.search.setMaximumWidth(self.width()-150)
def connect_to_folder(self):
dir = choose_dir(self, 'Select Device Folder', 'Select folder to open')
dir = choose_dir(self, 'Select Device Folder',
_('Select folder to open as device'))
if dir is not None:
self.device_manager.connect_to_folder(dir)
@ -1809,6 +1816,10 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
def save_to_single_dir(self, checked):
self.save_to_disk(checked, True)
def save_single_fmt_to_single_dir(self, *args):
self.save_to_disk(False, single_dir=True,
single_format=prefs['output_format'])
def save_to_disk(self, checked, single_dir=False, single_format=None):
rows = self.current_view().selectionModel().selectedRows()
if not rows or len(rows) == 0:
@ -2151,14 +2162,25 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
format = d.format()
self.view_format(row, format)
def _view_check(self, num, max_=3):
if num <= max_:
return True
return question_dialog(self, _('Multiple Books Selected'),
_('You are attempting to open %d books. Opening too many '
'books at once can be slow and have a negative effect on the '
'responsiveness of your computer. Once started the process '
'cannot be stopped until complete. Do you wish to continue?'
) % num)
def view_folder(self, *args):
rows = self.current_view().selectionModel().selectedRows()
if self.current_view() is self.library_view:
if not rows or len(rows) == 0:
d = error_dialog(self, _('Cannot open folder'),
_('No book selected'))
d.exec_()
return
if not rows or len(rows) == 0:
d = error_dialog(self, _('Cannot open folder'),
_('No book selected'))
d.exec_()
return
if not self._view_check(len(rows)):
return
for row in rows:
path = self.library_view.model().db.abspath(row.row())
QDesktopServices.openUrl(QUrl.fromLocalFile(path))
@ -2176,14 +2198,8 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self._launch_viewer()
return
if len(rows) >= 3:
if not question_dialog(self, _('Multiple Books Selected'),
_('You are attempting to open %d books. Opening too many '
'books at once can be slow and have a negative effect on the '
'responsiveness of your computer. Once started the process '
'cannot be stopped until complete. Do you wish to continue?'
)% len(rows)):
return
if not self._view_check(len(rows)):
return
if self.current_view() is self.library_view:
for row in rows:
@ -2261,6 +2277,9 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.save_menu.actions()[2].setText(
_('Save only %s format to disk')%
prefs['output_format'].upper())
self.save_menu.actions()[3].setText(
_('Save only %s format to disk in a single directory')%
prefs['output_format'].upper())
self.library_view.model().read_config()
self.library_view.model().refresh()
self.library_view.model().research()