mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Automatically send downloaded news to device. Can be controlled via the config dialog.
This commit is contained in:
parent
f96e9cce0c
commit
0a1f3b4525
@ -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()
|
||||
|
@ -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()):
|
||||
|
@ -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 &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 &news to ebook reader</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" >
|
||||
<widget class="QCheckBox" name="delete_news" >
|
||||
<property name="text" >
|
||||
<string>&Delete news from library when it is sent to reader</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_2" >
|
||||
|
@ -166,6 +166,9 @@ class BooksModel(QAbstractTableModel):
|
||||
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()'''
|
||||
return [ self.index(index.row(), c) for c in range(self.columnCount(None))]
|
||||
@ -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)}
|
||||
|
@ -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()
|
||||
|
||||
############################################################################
|
||||
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user