Automatically send downloaded news to device. Can be controlled via the config dialog.

This commit is contained in:
Kovid Goyal 2008-11-30 20:37:53 -08:00
parent f96e9cce0c
commit 0a1f3b4525
6 changed files with 93 additions and 20 deletions

View File

@ -54,6 +54,8 @@ def _config():
c.add_opt('autolaunch_server', default=False, help=_('Automatically launch content server on application startup'))
c.add_opt('oldest_news', default=60, help=_('Oldest news kept in database'))
c.add_opt('systray_icon', default=True, help=_('Show system tray icon'))
c.add_opt('upload_news_to_device', default=True, help=_('Upload downloaded news to device'))
c.add_opt('delete_news_from_library_on_upload', default=False, help=_('Delete books from library after uploading to device'))
return ConfigProxy(c)
config = _config()

View File

@ -118,6 +118,8 @@ class ConfigDialog(QDialog, Ui_Dialog):
self.password.setText(opts.password if opts.password else '')
self.auto_launch.setChecked(config['autolaunch_server'])
self.systray_icon.setChecked(config['systray_icon'])
self.sync_news.setChecked(config['upload_news_to_device'])
self.delete_news.setChecked(config['delete_news_from_library_on_upload'])
def up_column(self):
idx = self.columns.currentRow()
@ -224,6 +226,8 @@ class ConfigDialog(QDialog, Ui_Dialog):
sc.set('username', unicode(self.username.text()).strip())
sc.set('password', unicode(self.password.text()).strip())
sc.set('port', self.port.value())
config['delete_news_from_library_on_upload'] = self.delete_news.isChecked()
config['upload_news_to_device'] = self.sync_news.isChecked()
of = str(self.output_format.currentText())
fmts = []
for i in range(self.viewer.count()):

View File

@ -374,7 +374,7 @@
</item>
</layout>
</item>
<item row="3" column="0" >
<item row="5" column="0" >
<widget class="QGroupBox" name="groupBox_2" >
<property name="title" >
<string>Toolbar</string>
@ -422,7 +422,7 @@
</layout>
</widget>
</item>
<item row="4" column="0" >
<item row="6" column="0" >
<widget class="QGroupBox" name="groupBox" >
<property name="title" >
<string>Select visible &amp;columns in library view</string>
@ -510,6 +510,20 @@
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QCheckBox" name="sync_news" >
<property name="text" >
<string>Automatically send downloaded &amp;news to ebook reader</string>
</property>
</widget>
</item>
<item row="4" column="0" >
<widget class="QCheckBox" name="delete_news" >
<property name="text" >
<string>&amp;Delete news from library when it is sent to reader</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2" >

View File

@ -165,6 +165,9 @@ class BooksModel(QAbstractTableModel):
def add_books(self, paths, formats, metadata, uris=[], add_duplicates=False):
return self.db.add_books(paths, formats, metadata, uris,
add_duplicates=add_duplicates)
def add_news(self, path, recipe):
return self.db.add_news(path, recipe)
def row_indices(self, index):
''' Return list indices of all cells in index.row()'''
@ -317,14 +320,15 @@ class BooksModel(QAbstractTableModel):
return data
def get_metadata(self, rows):
def get_metadata(self, rows, rows_are_ids=False):
metadata = []
for row in rows:
row = row.row()
au = self.db.authors(row)
tags = self.db.tags(row)
if not rows_are_ids:
rows = [self.db.id(row.row()) for row in rows]
for id in rows:
au = self.db.authors(id, index_is_id=True)
tags = self.db.tags(id, index_is_id=True)
if not au:
au = 'Unknown'
au = _('Unknown')
au = au.split(',')
if len(au) > 1:
t = ', '.join(au[:-1])
@ -336,15 +340,15 @@ class BooksModel(QAbstractTableModel):
tags = []
else:
tags = tags.split(',')
series = self.db.series(row)
series = self.db.series(id, index_is_id=True)
if series is not None:
tags.append(series)
mi = {
'title' : self.db.title(row),
'title' : self.db.title(id, index_is_id=True),
'authors' : au,
'cover' : self.db.cover(row),
'cover' : self.db.cover(id, index_is_id=True),
'tags' : tags,
'comments': self.db.comments(row),
'comments': self.db.comments(id, index_is_id=True),
}
if series is not None:
mi['tag order'] = {series:self.db.books_in_series_of(row)}

View File

@ -451,6 +451,7 @@ class Main(MainWindow, Ui_MainWindow):
view.resizeColumnsToContents()
view.resizeRowsToContents()
view.resize_on_select = not view.isVisible()
self.sync_news()
############################################################################
@ -636,8 +637,7 @@ class Main(MainWindow, Ui_MainWindow):
view.model().resort(reset=False)
view.model().research()
if memory and memory[1]:
rows = map(self.library_view.model().db.index, memory[1])
self.library_view.model().delete_books(rows)
self.library_view.model().delete_books_by_id(memory[1])
############################################################################
@ -742,6 +742,30 @@ class Main(MainWindow, Ui_MainWindow):
p = p.scaledToHeight(ht, Qt.SmoothTransformation)
return (p.width(), p.height(), pixmap_to_data(p))
def sync_news(self):
if self.device_connected:
ids = list(dynamic.get('news_to_be_synced', set([])))
files = [self.library_view.model().db.format(id, prefs['output_format'], index_is_id=True, as_file=True) for id in ids]
files = [f for f in files if f is not None]
metadata = self.library_view.model().get_metadata(ids, rows_are_ids=True)
names = []
for mi in metadata:
prefix = sanitize_file_name(mi['title'])
if not isinstance(prefix, unicode):
prefix = prefix.decode(preferred_encoding, 'replace')
prefix = ascii_filename(prefix)
names.append('%s_%d%s'%(prefix, id, os.path.splitext(f.name)[1]))
cdata = mi['cover']
if cdata:
mi['cover'] = self.cover_to_thumbnail(cdata)
dynamic.set('news_to_be_synced', set([]))
if config['upload_news_to_device'] and files:
remove = ids if config['delete_news_from_library_on_upload'] else []
on_card = self.location_view.model().free[0] < self.location_view.model().free[1]
self.upload_books(files, names, metadata, on_card=on_card, memory=[[f.name for f in files], remove])
self.status_bar.showMessage(_('Sending news to device.'), 5000)
def sync_to_device(self, on_card, delete_from_library):
rows = self.library_view.selectionModel().selectedRows()
if not self.device_manager or not rows or len(rows) == 0:
@ -780,10 +804,10 @@ class Main(MainWindow, Ui_MainWindow):
gf.append(f)
t = mi['title']
if not t:
t = 'Unknown'
t = _('Unknown')
a = mi['authors']
if not a:
a = 'Unknown'
a = _('Unknown')
prefix = sanitize_file_name(t+' - '+a)
if not isinstance(prefix, unicode):
prefix = prefix.decode(preferred_encoding, 'replace')
@ -854,12 +878,13 @@ class Main(MainWindow, Ui_MainWindow):
if job.exception is not None:
self.job_exception(job)
return
mi = get_metadata(open(pt.name, 'rb'), fmt, use_libprs_metadata=False)
mi.tags = [_('News'), recipe.title]
paths, formats, metadata = [pt.name], [fmt], [mi]
self.library_view.model().add_books(paths, formats, metadata, add_duplicates=True)
id = self.library_view.model().add_news(pt.name, recipe)
sync = dynamic.get('news_to_be_synced', set([]))
sync.add(id)
dynamic.set('news_to_be_synced', sync)
callback(recipe)
self.status_bar.showMessage(recipe.title + _(' fetched.'), 3000)
self.sync_news()
############################################################################

View File

@ -20,6 +20,7 @@ from calibre.library.database import LibraryDatabase
from calibre.library.sqlite import connect, IntegrityError
from calibre.utils.search_query_parser import SearchQueryParser
from calibre.ebooks.metadata import string_to_authors, authors_to_string
from calibre.ebooks.metadata.meta import get_metadata
from calibre.constants import preferred_encoding, iswindows, isosx
@ -1030,6 +1031,29 @@ class LibraryDatabase2(LibraryDatabase):
if notify:
self.notify('metadata', [id])
def add_news(self, path, recipe):
format = os.path.splitext(path)[1][1:].lower()
stream = path if hasattr(path, 'read') else open(path, 'rb')
stream.seek(0)
mi = get_metadata(stream, format, use_libprs_metadata=False)
stream.seek(0)
mi.series_index = 1
mi.tags = [_('News'), recipe.title]
obj = self.conn.execute('INSERT INTO books(title, author_sort) VALUES (?, ?)',
(mi.title, mi.authors[0]))
id = obj.lastrowid
self.data.books_added([id], self.conn)
self.set_path(id, True)
self.conn.commit()
self.set_metadata(id, mi)
self.add_format(id, format, stream, index_is_id=True)
if not hasattr(path, 'read'):
stream.close()
self.conn.commit()
self.data.refresh_ids(self.conn, [id]) # Needed to update format list and size
return id
def add_books(self, paths, formats, metadata, uris=[], add_duplicates=True):
'''
Add a book to the database. The result cache is not updated.