mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
[merge] From Official
This commit is contained in:
commit
523a11c0c2
@ -217,7 +217,7 @@ class DevicePlugin(Plugin):
|
|||||||
'''
|
'''
|
||||||
Unix version of :meth:`can_handle_windows`
|
Unix version of :meth:`can_handle_windows`
|
||||||
|
|
||||||
:param device_info: Is a tupe of (vid, pid, bcd, manufacturer, product,
|
:param device_info: Is a tuple of (vid, pid, bcd, manufacturer, product,
|
||||||
serial number)
|
serial number)
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
@ -2,5 +2,6 @@
|
|||||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2010, Timothy Legge <timlegge at gmail.com> and Kovid Goyal <kovid@kovidgoyal.net>'
|
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
@ -1,9 +0,0 @@
|
|||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2010, Timothy Legge <timlegge at gmail.com>'
|
|
||||||
'''
|
|
||||||
'''
|
|
||||||
|
|
||||||
class ImageWrapper(object):
|
|
||||||
def __init__(self, image_path):
|
|
||||||
self.image_path = image_path
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
|||||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||||
|
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2010, Timothy Legge <timlegge at gmail.com> and Kovid Goyal <kovid@kovidgoyal.net>'
|
__copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@ -10,20 +10,26 @@ Device driver for the SONY T1 devices
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
import os, time, calendar, re
|
import os, time, calendar, re
|
||||||
|
|
||||||
import sqlite3 as sqlite
|
import sqlite3 as sqlite
|
||||||
from contextlib import closing
|
from contextlib import closing
|
||||||
from itertools import cycle
|
|
||||||
from calibre.devices.usbms.driver import USBMS, debug_print
|
from calibre.devices.usbms.driver import USBMS, debug_print
|
||||||
from calibre import __appname__, prints
|
from calibre.devices.usbms.device import USBDevice
|
||||||
from calibre.devices.usbms.books import CollectionsBookList
|
from calibre.devices.usbms.books import CollectionsBookList
|
||||||
from calibre.devices.usbms.books import BookList
|
from calibre.devices.usbms.books import BookList
|
||||||
from calibre.devices.prst1.books import ImageWrapper
|
from calibre.constants import islinux
|
||||||
|
|
||||||
|
DBPATH = 'Sony_Reader/database/books.db'
|
||||||
|
THUMBPATH = 'Sony_Reader/database/cache/books/%s/thumbnail/main_thumbnail.jpg'
|
||||||
|
|
||||||
|
class ImageWrapper(object):
|
||||||
|
def __init__(self, image_path):
|
||||||
|
self.image_path = image_path
|
||||||
|
|
||||||
class PRST1(USBMS):
|
class PRST1(USBMS):
|
||||||
name = 'SONY PRST1 and newer Device Interface'
|
name = 'SONY PRST1 and newer Device Interface'
|
||||||
gui_name = 'SONY Reader'
|
gui_name = 'SONY Reader'
|
||||||
description = _('Communicate with Sony PRST1 and newer eBook readers')
|
description = _('Communicate with the PRST1 and newer SONY eBook readers')
|
||||||
author = 'Kovid Goyal'
|
author = 'Kovid Goyal'
|
||||||
supported_platforms = ['windows', 'osx', 'linux']
|
supported_platforms = ['windows', 'osx', 'linux']
|
||||||
path_sep = '/'
|
path_sep = '/'
|
||||||
@ -41,6 +47,8 @@ class PRST1(USBMS):
|
|||||||
WINDOWS_MAIN_MEM = re.compile(
|
WINDOWS_MAIN_MEM = re.compile(
|
||||||
r'(PRS-T1&)'
|
r'(PRS-T1&)'
|
||||||
)
|
)
|
||||||
|
MAIN_MEMORY_VOLUME_LABEL = 'SONY Reader Main Memory'
|
||||||
|
STORAGE_CARD_VOLUME_LABEL = 'SONY Reader Storage Card'
|
||||||
|
|
||||||
THUMBNAIL_HEIGHT = 144
|
THUMBNAIL_HEIGHT = 144
|
||||||
SUPPORTS_SUB_DIRS = True
|
SUPPORTS_SUB_DIRS = True
|
||||||
@ -51,29 +59,29 @@ class PRST1(USBMS):
|
|||||||
_('Comma separated list of metadata fields '
|
_('Comma separated list of metadata fields '
|
||||||
'to turn into collections on the device. Possibilities include: ')+\
|
'to turn into collections on the device. Possibilities include: ')+\
|
||||||
'series, tags, authors',
|
'series, tags, authors',
|
||||||
_('Upload separate cover thumbnails for books') +
|
_('Upload separate cover thumbnails for books') +
|
||||||
':::'+_('Normally, the SONY readers get the cover image from the'
|
':::'+_('Normally, the SONY readers get the cover image from the'
|
||||||
' ebook file itself. With this option, calibre will send a '
|
' ebook file itself. With this option, calibre will send a '
|
||||||
'separate cover image to the reader, useful if you are '
|
'separate cover image to the reader, useful if you are '
|
||||||
'sending DRMed books in which you cannot change the cover.'),
|
'sending DRMed books in which you cannot change the cover.'),
|
||||||
_('Refresh separate covers when using automatic management') +
|
_('Refresh separate covers when using automatic management') +
|
||||||
':::' +
|
':::' +
|
||||||
_('Set this option to have separate book covers uploaded '
|
_('Set this option to have separate book covers uploaded '
|
||||||
'every time you connect your device. Unset this option if '
|
'every time you connect your device. Unset this option if '
|
||||||
'you have so many books on the reader that performance is '
|
'you have so many books on the reader that performance is '
|
||||||
'unacceptable.'),
|
'unacceptable.'),
|
||||||
_('Preserve cover aspect ratio when building thumbnails') +
|
_('Preserve cover aspect ratio when building thumbnails') +
|
||||||
':::' +
|
':::' +
|
||||||
_('Set this option if you want the cover thumbnails to have '
|
_('Set this option if you want the cover thumbnails to have '
|
||||||
'the same aspect ratio (width to height) as the cover. '
|
'the same aspect ratio (width to height) as the cover. '
|
||||||
'Unset it if you want the thumbnail to be the maximum size, '
|
'Unset it if you want the thumbnail to be the maximum size, '
|
||||||
'ignoring aspect ratio.'),
|
'ignoring aspect ratio.'),
|
||||||
]
|
]
|
||||||
EXTRA_CUSTOMIZATION_DEFAULT = [
|
EXTRA_CUSTOMIZATION_DEFAULT = [
|
||||||
', '.join(['series', 'tags']),
|
', '.join(['series', 'tags']),
|
||||||
False,
|
True,
|
||||||
False,
|
False,
|
||||||
True,
|
True,
|
||||||
]
|
]
|
||||||
|
|
||||||
OPT_COLLECTIONS = 0
|
OPT_COLLECTIONS = 0
|
||||||
@ -103,284 +111,317 @@ class PRST1(USBMS):
|
|||||||
return self.EBOOK_DIR_MAIN
|
return self.EBOOK_DIR_MAIN
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def books(self, oncard=None, end_session=True):
|
def can_handle(self, devinfo, debug=False):
|
||||||
from calibre.ebooks.metadata.meta import path_to_ext
|
if islinux:
|
||||||
|
dev = USBDevice(devinfo)
|
||||||
|
main, carda, cardb = self.find_device_nodes(detected_device=dev)
|
||||||
|
if main is None and carda is None and cardb is None:
|
||||||
|
if debug:
|
||||||
|
print ('\tPRS-T1: Appears to be in non data mode'
|
||||||
|
' or was ejected, ignoring')
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
dummy_bl = BookList(None, None, None)
|
def books(self, oncard=None, end_session=True):
|
||||||
|
dummy_bl = BookList(None, None, None)
|
||||||
|
|
||||||
if oncard == 'carda' and not self._card_a_prefix:
|
if (
|
||||||
self.report_progress(1.0, _('Getting list of books on device...'))
|
(oncard == 'carda' and not self._card_a_prefix) or
|
||||||
return dummy_bl
|
(oncard and oncard != 'carda')
|
||||||
elif oncard and oncard != 'carda':
|
):
|
||||||
self.report_progress(1.0, _('Getting list of books on device...'))
|
self.report_progress(1.0, _('Getting list of books on device...'))
|
||||||
return dummy_bl
|
return dummy_bl
|
||||||
|
|
||||||
prefix = self._card_a_prefix if oncard == 'carda' else self._main_prefix
|
|
||||||
|
|
||||||
# Let parent driver get the books
|
prefix = self._card_a_prefix if oncard == 'carda' else self._main_prefix
|
||||||
self.booklist_class.rebuild_collections = self.rebuild_collections
|
|
||||||
bl = USBMS.books(self, oncard=oncard, end_session=end_session)
|
# Let parent driver get the books
|
||||||
|
self.booklist_class.rebuild_collections = self.rebuild_collections
|
||||||
debug_print("SQLite DB Path: " + self.normalize_path(prefix + 'Sony_Reader/database/books.db'))
|
bl = USBMS.books(self, oncard=oncard, end_session=end_session)
|
||||||
|
|
||||||
with closing(sqlite.connect(self.normalize_path(prefix + 'Sony_Reader/database/books.db'))) as connection:
|
dbpath = self.normalize_path(prefix + DBPATH)
|
||||||
# return bytestrings if the content cannot the decoded as unicode
|
debug_print("SQLite DB Path: " + dbpath)
|
||||||
connection.text_factory = lambda x: unicode(x, "utf-8", "ignore")
|
|
||||||
|
with closing(sqlite.connect(dbpath)) as connection:
|
||||||
|
# Replace undecodable characters in the db instead of erroring out
|
||||||
|
connection.text_factory = lambda x: unicode(x, "utf-8", "replace")
|
||||||
|
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
# Query collections
|
# Query collections
|
||||||
query = 'select books._id, collection.title ' \
|
query = '''
|
||||||
'from collections ' \
|
SELECT books._id, collection.title
|
||||||
'left outer join books ' \
|
FROM collections
|
||||||
'left outer join collection ' \
|
LEFT OUTER JOIN books
|
||||||
'where collections.content_id = books._id and collections.collection_id = collection._id'
|
LEFT OUTER JOIN collection
|
||||||
cursor.execute (query)
|
WHERE collections.content_id = books._id AND
|
||||||
|
collections.collection_id = collection._id
|
||||||
bl_collections = {}
|
'''
|
||||||
for i, row in enumerate(cursor):
|
cursor.execute(query)
|
||||||
bl_collections.setdefault(row[0], [])
|
|
||||||
bl_collections[row[0]].append(row[1])
|
|
||||||
|
|
||||||
for idx,book in enumerate(bl):
|
|
||||||
query = 'select _id, thumbnail from books where file_path = ?'
|
|
||||||
t = (book.lpath,)
|
|
||||||
cursor.execute (query, t)
|
|
||||||
|
|
||||||
for i, row in enumerate(cursor):
|
|
||||||
book.device_collections = bl_collections.get(row[0], None)
|
|
||||||
thumbnail = row[1]
|
|
||||||
if thumbnail is not None:
|
|
||||||
thumbnail = self.normalize_path(prefix + thumbnail)
|
|
||||||
book.thumbnail = ImageWrapper(thumbnail)
|
|
||||||
|
|
||||||
cursor.close()
|
|
||||||
|
|
||||||
return bl
|
bl_collections = {}
|
||||||
|
for i, row in enumerate(cursor):
|
||||||
def set_plugboards(self, plugboards, pb_func):
|
bl_collections.setdefault(row[0], [])
|
||||||
self.plugboards = plugboards
|
bl_collections[row[0]].append(row[1])
|
||||||
self.plugboard_func = pb_func
|
|
||||||
|
for idx, book in enumerate(bl):
|
||||||
def sync_booklists(self, booklists, end_session=True):
|
query = 'SELECT _id, thumbnail FROM books WHERE file_path = ?'
|
||||||
debug_print('PRST1: starting sync_booklists')
|
t = (book.lpath,)
|
||||||
|
cursor.execute (query, t)
|
||||||
opts = self.settings()
|
|
||||||
|
for i, row in enumerate(cursor):
|
||||||
|
book.device_collections = bl_collections.get(row[0], None)
|
||||||
|
thumbnail = row[1]
|
||||||
|
if thumbnail is not None:
|
||||||
|
thumbnail = self.normalize_path(prefix + thumbnail)
|
||||||
|
book.thumbnail = ImageWrapper(thumbnail)
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
return bl
|
||||||
|
|
||||||
|
def set_plugboards(self, plugboards, pb_func):
|
||||||
|
self.plugboards = plugboards
|
||||||
|
self.plugboard_func = pb_func
|
||||||
|
|
||||||
|
def sync_booklists(self, booklists, end_session=True):
|
||||||
|
debug_print('PRST1: starting sync_booklists')
|
||||||
|
|
||||||
|
opts = self.settings()
|
||||||
if opts.extra_customization:
|
if opts.extra_customization:
|
||||||
collections = [x.strip() for x in
|
collections = [x.strip() for x in
|
||||||
opts.extra_customization[self.OPT_COLLECTIONS].split(',')]
|
opts.extra_customization[self.OPT_COLLECTIONS].split(',')]
|
||||||
else:
|
else:
|
||||||
collections = []
|
collections = []
|
||||||
debug_print('PRST1: collection fields:', collections)
|
debug_print('PRST1: collection fields:', collections)
|
||||||
|
|
||||||
if booklists[0] is not None:
|
|
||||||
self.update_device_database(booklists[0], collections, None)
|
|
||||||
if booklists[1] is not None:
|
|
||||||
self.update_device_database(booklists[1], collections, 'carda')
|
|
||||||
|
|
||||||
USBMS.sync_booklists(self, booklists, end_session=end_session)
|
|
||||||
debug_print('PRST1: finished sync_booklists')
|
|
||||||
|
|
||||||
def update_device_database(self, booklist, collections_attributes, oncard):
|
|
||||||
debug_print('PRST1: starting update_device_database')
|
|
||||||
|
|
||||||
plugboard = None
|
|
||||||
if self.plugboard_func:
|
|
||||||
plugboard = self.plugboard_func(self.__class__.__name__, 'device_db', self.plugboards)
|
|
||||||
debug_print("PRST1: Using Plugboard", plugboard)
|
|
||||||
|
|
||||||
prefix = self._card_a_prefix if oncard == 'carda' else self._main_prefix
|
|
||||||
source_id = 1 if oncard == 'carda' else 0
|
|
||||||
debug_print("SQLite DB Path: " + self.normalize_path(prefix + 'Sony_Reader/database/books.db'))
|
|
||||||
|
|
||||||
collections = booklist.get_collections(collections_attributes)
|
|
||||||
|
|
||||||
with closing(sqlite.connect(self.normalize_path(prefix + 'Sony_Reader/database/books.db'))) as connection:
|
|
||||||
self.update_device_books(connection, booklist, source_id, plugboard)
|
|
||||||
self.update_device_collections(connection, booklist, collections, source_id)
|
|
||||||
|
|
||||||
debug_print('PRST1: finished update_device_database')
|
|
||||||
|
|
||||||
def update_device_books(self, connection, booklist, source_id, plugboard):
|
if booklists[0] is not None:
|
||||||
opts = self.settings()
|
self.update_device_database(booklists[0], collections, None)
|
||||||
upload_covers = opts.extra_customization[self.OPT_UPLOAD_COVERS]
|
if booklists[1] is not None:
|
||||||
refresh_covers = opts.extra_customization[self.OPT_REFRESH_COVERS]
|
self.update_device_database(booklists[1], collections, 'carda')
|
||||||
|
|
||||||
cursor = connection.cursor()
|
USBMS.sync_booklists(self, booklists, end_session=end_session)
|
||||||
|
debug_print('PRST1: finished sync_booklists')
|
||||||
# Get existing books
|
|
||||||
query = 'select file_path, _id ' \
|
def update_device_database(self, booklist, collections_attributes, oncard):
|
||||||
'from books'
|
debug_print('PRST1: starting update_device_database')
|
||||||
cursor.execute(query)
|
|
||||||
|
plugboard = None
|
||||||
dbBooks = {}
|
if self.plugboard_func:
|
||||||
for i, row in enumerate(cursor):
|
plugboard = self.plugboard_func(self.__class__.__name__,
|
||||||
lpath = row[0].replace('\\', '/')
|
'device_db', self.plugboards)
|
||||||
dbBooks[lpath] = row[1]
|
debug_print("PRST1: Using Plugboard", plugboard)
|
||||||
|
|
||||||
for book in booklist:
|
prefix = self._card_a_prefix if oncard == 'carda' else self._main_prefix
|
||||||
# Run through plugboard if needed
|
if prefix is None:
|
||||||
if plugboard is not None:
|
# Reader has no sd card inserted
|
||||||
|
return
|
||||||
|
source_id = 1 if oncard == 'carda' else 0
|
||||||
|
|
||||||
|
dbpath = self.normalize_path(prefix + DBPATH)
|
||||||
|
debug_print("SQLite DB Path: " + dbpath)
|
||||||
|
|
||||||
|
collections = booklist.get_collections(collections_attributes)
|
||||||
|
|
||||||
|
with closing(sqlite.connect(dbpath)) as connection:
|
||||||
|
self.update_device_books(connection, booklist, source_id, plugboard)
|
||||||
|
self.update_device_collections(connection, booklist, collections, source_id)
|
||||||
|
|
||||||
|
debug_print('PRST1: finished update_device_database')
|
||||||
|
|
||||||
|
def update_device_books(self, connection, booklist, source_id, plugboard):
|
||||||
|
opts = self.settings()
|
||||||
|
upload_covers = opts.extra_customization[self.OPT_UPLOAD_COVERS]
|
||||||
|
refresh_covers = opts.extra_customization[self.OPT_REFRESH_COVERS]
|
||||||
|
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
# Get existing books
|
||||||
|
query = 'SELECT file_path, _id FROM books'
|
||||||
|
cursor.execute(query)
|
||||||
|
|
||||||
|
db_books = {}
|
||||||
|
for i, row in enumerate(cursor):
|
||||||
|
lpath = row[0].replace('\\', '/')
|
||||||
|
db_books[lpath] = row[1]
|
||||||
|
|
||||||
|
for book in booklist:
|
||||||
|
# Run through plugboard if needed
|
||||||
|
if plugboard is not None:
|
||||||
newmi = book.deepcopy_metadata()
|
newmi = book.deepcopy_metadata()
|
||||||
newmi.template_to_attribute(book, plugboard)
|
newmi.template_to_attribute(book, plugboard)
|
||||||
else:
|
else:
|
||||||
newmi = book
|
newmi = book
|
||||||
|
|
||||||
# Get Metadata We Want
|
|
||||||
lpath = book.lpath
|
|
||||||
author = newmi.authors[0]
|
|
||||||
title = newmi.title
|
|
||||||
|
|
||||||
if lpath not in dbBooks:
|
# Get Metadata We Want
|
||||||
query = 'insert into books ' \
|
lpath = book.lpath
|
||||||
'(title, author, source_id, added_date, modified_date, file_path, file_name, file_size, mime_type, corrupted, prevent_delete) ' \
|
author = newmi.authors[0]
|
||||||
'values (?,?,?,?,?,?,?,?,?,0,0)'
|
title = newmi.title
|
||||||
t = (title, author, source_id, int(time.time() * 1000), calendar.timegm(book.datetime), lpath, os.path.basename(book.lpath), book.size, book.mime )
|
|
||||||
cursor.execute(query, t)
|
|
||||||
book.bookId = cursor.lastrowid
|
|
||||||
if upload_covers:
|
|
||||||
self.upload_book_cover(connection, book, source_id)
|
|
||||||
debug_print('Inserted New Book: ' + book.title)
|
|
||||||
else:
|
|
||||||
query = 'update books ' \
|
|
||||||
'set title = ?, author = ?, modified_date = ?, file_size = ? ' \
|
|
||||||
'where file_path = ?'
|
|
||||||
t = (title, author, calendar.timegm(book.datetime), book.size, lpath)
|
|
||||||
cursor.execute(query, t)
|
|
||||||
book.bookId = dbBooks[lpath]
|
|
||||||
if refresh_covers:
|
|
||||||
self.upload_book_cover(connection, book, source_id)
|
|
||||||
dbBooks[lpath] = None
|
|
||||||
|
|
||||||
for book, bookId in dbBooks.items():
|
|
||||||
if bookId is not None:
|
|
||||||
# Remove From Collections
|
|
||||||
query = 'delete from collections ' \
|
|
||||||
'where content_id = ?'
|
|
||||||
t = (bookId,)
|
|
||||||
cursor.execute(query, t)
|
|
||||||
# Remove from Books
|
|
||||||
query = 'delete from books ' \
|
|
||||||
'where _id = ?'
|
|
||||||
t = (bookId,)
|
|
||||||
cursor.execute(query, t)
|
|
||||||
debug_print('Deleted Book:' + book)
|
|
||||||
|
|
||||||
connection.commit()
|
|
||||||
cursor.close()
|
|
||||||
|
|
||||||
def update_device_collections(self, connection, booklist, collections, source_id):
|
|
||||||
cursor = connection.cursor()
|
|
||||||
|
|
||||||
if collections:
|
|
||||||
# Get existing collections
|
|
||||||
query = 'select _id, title ' \
|
|
||||||
'from collection'
|
|
||||||
cursor.execute(query)
|
|
||||||
|
|
||||||
dbCollections = {}
|
|
||||||
for i, row in enumerate(cursor):
|
|
||||||
dbCollections[row[1]] = row[0]
|
|
||||||
|
|
||||||
for collection, books in collections.items():
|
|
||||||
if collection not in dbCollections:
|
|
||||||
query = 'insert into collection (title, source_id) values (?,?)'
|
|
||||||
t = (collection, source_id)
|
|
||||||
cursor.execute(query, t)
|
|
||||||
dbCollections[collection] = cursor.lastrowid
|
|
||||||
debug_print('Inserted New Collection: ' + collection)
|
|
||||||
|
|
||||||
# Get existing books in collection
|
|
||||||
query = 'select books.file_path, content_id ' \
|
|
||||||
'from collections ' \
|
|
||||||
'left outer join books ' \
|
|
||||||
'where collection_id = ? and books._id = collections.content_id'
|
|
||||||
t = (dbCollections[collection],)
|
|
||||||
cursor.execute(query, t)
|
|
||||||
|
|
||||||
dbBooks = {}
|
if lpath not in db_books:
|
||||||
for i, row in enumerate(cursor):
|
query = '''
|
||||||
dbBooks[row[0]] = row[1]
|
INSERT INTO books
|
||||||
|
(title, author, source_id, added_date, modified_date,
|
||||||
for idx, book in enumerate(books):
|
file_path, file_name, file_size, mime_type, corrupted,
|
||||||
if dbBooks.get(book.lpath, None) is None:
|
prevent_delete)
|
||||||
if collection not in book.device_collections:
|
values (?,?,?,?,?,?,?,?,?,0,0)
|
||||||
book.device_collections.append(collection)
|
'''
|
||||||
query = 'insert into collections (collection_id, content_id, added_order) values (?,?,?)'
|
t = (title, author, source_id, int(time.time() * 1000),
|
||||||
t = (dbCollections[collection], book.bookId, idx)
|
calendar.timegm(book.datetime), lpath,
|
||||||
cursor.execute(query, t)
|
os.path.basename(book.lpath), book.size, book.mime)
|
||||||
debug_print('Inserted Book Into Collection: ' + book.title + ' -> ' + collection)
|
cursor.execute(query, t)
|
||||||
else:
|
book.bookId = cursor.lastrowid
|
||||||
query = 'update collections ' \
|
if upload_covers:
|
||||||
'set added_order = ? ' \
|
self.upload_book_cover(connection, book, source_id)
|
||||||
'where content_id = ? and collection_id = ? '
|
debug_print('Inserted New Book: ' + book.title)
|
||||||
t = (idx, book.bookId, dbCollections[collection])
|
else:
|
||||||
cursor.execute(query, t)
|
query = '''
|
||||||
|
UPDATE books
|
||||||
dbBooks[book.lpath] = None
|
SET title = ?, author = ?, modified_date = ?, file_size = ?
|
||||||
|
WHERE file_path = ?
|
||||||
for bookPath, bookId in dbBooks.items():
|
'''
|
||||||
if bookId is not None:
|
t = (title, author, calendar.timegm(book.datetime), book.size,
|
||||||
query = 'delete from collections ' \
|
lpath)
|
||||||
'where content_id = ? and collection_id = ? '
|
cursor.execute(query, t)
|
||||||
t = (bookId,dbCollections[collection],)
|
book.bookId = db_books[lpath]
|
||||||
cursor.execute(query, t)
|
if refresh_covers:
|
||||||
debug_print('Deleted Book From Collection: ' + bookPath + ' -> ' + collection)
|
self.upload_book_cover(connection, book, source_id)
|
||||||
|
db_books[lpath] = None
|
||||||
dbCollections[collection] = None
|
|
||||||
|
for book, bookId in db_books.items():
|
||||||
for collection, collectionId in dbCollections.items():
|
if bookId is not None:
|
||||||
if collectionId is not None:
|
# Remove From Collections
|
||||||
# Remove Books from Collection
|
query = 'DELETE FROM collections WHERE content_id = ?'
|
||||||
query = 'delete from collections ' \
|
t = (bookId,)
|
||||||
'where collection_id = ?'
|
cursor.execute(query, t)
|
||||||
t = (collectionId,)
|
# Remove from Books
|
||||||
cursor.execute(query, t)
|
query = 'DELETE FROM books where _id = ?'
|
||||||
# Remove Collection
|
t = (bookId,)
|
||||||
query = 'delete from collection ' \
|
cursor.execute(query, t)
|
||||||
'where _id = ?'
|
debug_print('Deleted Book:' + book)
|
||||||
t = (collectionId,)
|
|
||||||
cursor.execute(query, t)
|
connection.commit()
|
||||||
debug_print('Deleted Collection: ' + collection)
|
cursor.close()
|
||||||
|
|
||||||
|
def update_device_collections(self, connection, booklist, collections,
|
||||||
connection.commit()
|
source_id):
|
||||||
cursor.close()
|
cursor = connection.cursor()
|
||||||
|
|
||||||
def rebuild_collections(self, booklist, oncard):
|
if collections:
|
||||||
debug_print('PRST1: starting rebuild_collections')
|
# Get existing collections
|
||||||
|
query = 'SELECT _id, title FROM collection'
|
||||||
opts = self.settings()
|
cursor.execute(query)
|
||||||
|
|
||||||
|
db_collections = {}
|
||||||
|
for i, row in enumerate(cursor):
|
||||||
|
db_collections[row[1]] = row[0]
|
||||||
|
|
||||||
|
for collection, books in collections.items():
|
||||||
|
if collection not in db_collections:
|
||||||
|
query = 'INSERT INTO collection (title, source_id) VALUES (?,?)'
|
||||||
|
t = (collection, source_id)
|
||||||
|
cursor.execute(query, t)
|
||||||
|
db_collections[collection] = cursor.lastrowid
|
||||||
|
debug_print('Inserted New Collection: ' + collection)
|
||||||
|
|
||||||
|
# Get existing books in collection
|
||||||
|
query = '''
|
||||||
|
SELECT books.file_path, content_id
|
||||||
|
FROM collections
|
||||||
|
LEFT OUTER JOIN books
|
||||||
|
WHERE collection_id = ? AND books._id = collections.content_id
|
||||||
|
'''
|
||||||
|
t = (db_collections[collection],)
|
||||||
|
cursor.execute(query, t)
|
||||||
|
|
||||||
|
db_books = {}
|
||||||
|
for i, row in enumerate(cursor):
|
||||||
|
db_books[row[0]] = row[1]
|
||||||
|
|
||||||
|
for idx, book in enumerate(books):
|
||||||
|
if db_books.get(book.lpath, None) is None:
|
||||||
|
if collection not in book.device_collections:
|
||||||
|
book.device_collections.append(collection)
|
||||||
|
query = '''
|
||||||
|
INSERT INTO collections (collection_id, content_id,
|
||||||
|
added_order) values (?,?,?)
|
||||||
|
'''
|
||||||
|
t = (db_collections[collection], book.bookId, idx)
|
||||||
|
cursor.execute(query, t)
|
||||||
|
debug_print('Inserted Book Into Collection: ' +
|
||||||
|
book.title + ' -> ' + collection)
|
||||||
|
else:
|
||||||
|
query = '''
|
||||||
|
UPDATE collections
|
||||||
|
SET added_order = ?
|
||||||
|
WHERE content_id = ? AND collection_id = ?
|
||||||
|
'''
|
||||||
|
t = (idx, book.bookId, db_collections[collection])
|
||||||
|
cursor.execute(query, t)
|
||||||
|
|
||||||
|
db_books[book.lpath] = None
|
||||||
|
|
||||||
|
for bookPath, bookId in db_books.items():
|
||||||
|
if bookId is not None:
|
||||||
|
query = ('DELETE FROM collections '
|
||||||
|
'WHERE content_id = ? AND collection_id = ? ')
|
||||||
|
t = (bookId, db_collections[collection],)
|
||||||
|
cursor.execute(query, t)
|
||||||
|
debug_print('Deleted Book From Collection: ' + bookPath
|
||||||
|
+ ' -> ' + collection)
|
||||||
|
|
||||||
|
db_collections[collection] = None
|
||||||
|
|
||||||
|
for collection, collectionId in db_collections.items():
|
||||||
|
if collectionId is not None:
|
||||||
|
# Remove Books from Collection
|
||||||
|
query = ('DELETE FROM collections '
|
||||||
|
'WHERE collection_id = ?')
|
||||||
|
t = (collectionId,)
|
||||||
|
cursor.execute(query, t)
|
||||||
|
# Remove Collection
|
||||||
|
query = ('DELETE FROM collection '
|
||||||
|
'WHERE _id = ?')
|
||||||
|
t = (collectionId,)
|
||||||
|
cursor.execute(query, t)
|
||||||
|
debug_print('Deleted Collection: ' + collection)
|
||||||
|
|
||||||
|
|
||||||
|
connection.commit()
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
def rebuild_collections(self, booklist, oncard):
|
||||||
|
debug_print('PRST1: starting rebuild_collections')
|
||||||
|
|
||||||
|
opts = self.settings()
|
||||||
if opts.extra_customization:
|
if opts.extra_customization:
|
||||||
collections = [x.strip() for x in
|
collections = [x.strip() for x in
|
||||||
opts.extra_customization[self.OPT_COLLECTIONS].split(',')]
|
opts.extra_customization[self.OPT_COLLECTIONS].split(',')]
|
||||||
else:
|
else:
|
||||||
collections = []
|
collections = []
|
||||||
debug_print('PRST1: collection fields:', collections)
|
debug_print('PRST1: collection fields:', collections)
|
||||||
|
|
||||||
self.update_device_database(booklist, collections, oncard)
|
|
||||||
|
|
||||||
debug_print('PRS-T1: finished rebuild_collections')
|
|
||||||
|
|
||||||
def upload_book_cover(self, connection, book, source_id):
|
|
||||||
debug_print('PRST1: Uploading/Refreshing Cover for ' + book.title)
|
|
||||||
cursor = connection.cursor()
|
|
||||||
|
|
||||||
if book.thumbnail and book.thumbnail[-1]:
|
|
||||||
thumbnailPath = 'Sony_Reader/database/cache/books/' + str(book.bookId) +'/thumbnail/main_thumbnail.jpg'
|
|
||||||
|
|
||||||
prefix = self._main_prefix if source_id is 0 else self._card_a_prefix
|
|
||||||
thumbnailFilePath = os.path.join(prefix, *thumbnailPath.split('/'))
|
|
||||||
thumbnailDirPath = os.path.dirname(thumbnailFilePath)
|
|
||||||
if not os.path.exists(thumbnailDirPath):
|
|
||||||
os.makedirs(thumbnailDirPath)
|
|
||||||
|
|
||||||
with open(thumbnailFilePath, 'wb') as f:
|
self.update_device_database(booklist, collections, oncard)
|
||||||
f.write(book.thumbnail[-1])
|
|
||||||
|
debug_print('PRS-T1: finished rebuild_collections')
|
||||||
query = 'update books ' \
|
|
||||||
'set thumbnail = ?' \
|
def upload_book_cover(self, connection, book, source_id):
|
||||||
'where _id = ? '
|
debug_print('PRST1: Uploading/Refreshing Cover for ' + book.title)
|
||||||
t = (thumbnailPath,book.bookId,)
|
if not book.thumbnail and book.thumbnail[-1]:
|
||||||
cursor.execute(query, t)
|
return
|
||||||
|
cursor = connection.cursor()
|
||||||
cursor.close()
|
|
||||||
|
thumbnail_path = THUMBPATH%book.bookId
|
||||||
|
|
||||||
|
prefix = self._main_prefix if source_id is 0 else self._card_a_prefix
|
||||||
|
thumbnail_file_path = os.path.join(prefix, *thumbnail_path.split('/'))
|
||||||
|
thumbnail_dir_path = os.path.dirname(thumbnail_file_path)
|
||||||
|
if not os.path.exists(thumbnail_dir_path):
|
||||||
|
os.makedirs(thumbnail_dir_path)
|
||||||
|
|
||||||
|
with open(thumbnail_file_path, 'wb') as f:
|
||||||
|
f.write(book.thumbnail[-1])
|
||||||
|
|
||||||
|
query = 'UPDATE books SET thumbnail = ? WHERE _id = ?'
|
||||||
|
t = (thumbnail_path, book.bookId,)
|
||||||
|
cursor.execute(query, t)
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
@ -483,7 +483,7 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
self._card_a_prefix = get_card_prefix('carda')
|
self._card_a_prefix = get_card_prefix('carda')
|
||||||
self._card_b_prefix = get_card_prefix('cardb')
|
self._card_b_prefix = get_card_prefix('cardb')
|
||||||
|
|
||||||
def find_device_nodes(self):
|
def find_device_nodes(self, detected_device=None):
|
||||||
|
|
||||||
def walk(base):
|
def walk(base):
|
||||||
base = os.path.abspath(os.path.realpath(base))
|
base = os.path.abspath(os.path.realpath(base))
|
||||||
@ -507,8 +507,11 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
d, j = os.path.dirname, os.path.join
|
d, j = os.path.dirname, os.path.join
|
||||||
usb_dir = None
|
usb_dir = None
|
||||||
|
|
||||||
|
if detected_device is None:
|
||||||
|
detected_device = self.detected_device
|
||||||
|
|
||||||
def test(val, attr):
|
def test(val, attr):
|
||||||
q = getattr(self.detected_device, attr)
|
q = getattr(detected_device, attr)
|
||||||
return q == val
|
return q == val
|
||||||
|
|
||||||
for x, isfile in walk('/sys/devices'):
|
for x, isfile in walk('/sys/devices'):
|
||||||
@ -596,6 +599,8 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
label = self.STORAGE_CARD2_VOLUME_LABEL
|
label = self.STORAGE_CARD2_VOLUME_LABEL
|
||||||
if not label:
|
if not label:
|
||||||
label = self.STORAGE_CARD_VOLUME_LABEL + ' 2'
|
label = self.STORAGE_CARD_VOLUME_LABEL + ' 2'
|
||||||
|
if not label:
|
||||||
|
label = 'E-book Reader (%s)'%type
|
||||||
extra = 0
|
extra = 0
|
||||||
while True:
|
while True:
|
||||||
q = ' (%d)'%extra if extra else ''
|
q = ' (%d)'%extra if extra else ''
|
||||||
|
Loading…
x
Reference in New Issue
Block a user