mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 10:14:46 -04:00
Sony T1: Alpha quality driver to support database/collections
This commit is contained in:
commit
ef9144577d
@ -555,7 +555,8 @@ from calibre.devices.irexdr.driver import IREXDR1000, IREXDR800
|
||||
from calibre.devices.jetbook.driver import JETBOOK, MIBUK, JETBOOK_MINI
|
||||
from calibre.devices.kindle.driver import KINDLE, KINDLE2, KINDLE_DX
|
||||
from calibre.devices.nook.driver import NOOK, NOOK_COLOR
|
||||
from calibre.devices.prs505.driver import PRS505, PRST1
|
||||
from calibre.devices.prs505.driver import PRS505
|
||||
from calibre.devices.prst1.driver import PRST1
|
||||
from calibre.devices.user_defined.driver import USER_DEFINED
|
||||
from calibre.devices.android.driver import ANDROID, S60, WEBOS
|
||||
from calibre.devices.nokia.driver import N770, N810, E71X, E52
|
||||
|
@ -299,34 +299,4 @@ class PRS505(USBMS):
|
||||
f.write(metadata.thumbnail[-1])
|
||||
debug_print('Cover uploaded to: %r'%cpath)
|
||||
|
||||
class PRST1(USBMS):
|
||||
name = 'SONY PRST1 and newer Device Interface'
|
||||
gui_name = 'SONY Reader'
|
||||
description = _('Communicate with Sony PRST1 and newer eBook readers')
|
||||
author = 'Kovid Goyal'
|
||||
supported_platforms = ['windows', 'osx', 'linux']
|
||||
|
||||
FORMATS = ['epub', 'lrf', 'lrx', 'rtf', 'pdf', 'txt']
|
||||
VENDOR_ID = [0x054c] #: SONY Vendor Id
|
||||
PRODUCT_ID = [0x05c2]
|
||||
BCD = [0x226]
|
||||
|
||||
VENDOR_NAME = 'SONY'
|
||||
WINDOWS_MAIN_MEM = re.compile(
|
||||
r'(PRS-T1&)'
|
||||
)
|
||||
|
||||
THUMBNAIL_HEIGHT = 217
|
||||
SCAN_FROM_ROOT = True
|
||||
EBOOK_DIR_MAIN = __appname__
|
||||
|
||||
|
||||
def windows_filter_pnp_id(self, pnp_id):
|
||||
return '_LAUNCHER' in pnp_id or '_SETTING' in pnp_id
|
||||
|
||||
def get_carda_ebook_dir(self, for_upload=False):
|
||||
if for_upload:
|
||||
return __appname__
|
||||
return self.EBOOK_DIR_CARD_A
|
||||
|
||||
|
||||
|
6
src/calibre/devices/prst1/__init__.py
Normal file
6
src/calibre/devices/prst1/__init__.py
Normal file
@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Timothy Legge <timlegge at gmail.com> and Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
44
src/calibre/devices/prst1/books.py
Normal file
44
src/calibre/devices/prst1/books.py
Normal file
@ -0,0 +1,44 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Timothy Legge <timlegge at gmail.com>'
|
||||
'''
|
||||
'''
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
from calibre.devices.usbms.books import Book as Book_
|
||||
|
||||
class Book(Book_):
|
||||
|
||||
def __init__(self, bookId, prefix, lpath, title, author, mime, date, thumbnail_name, size=None, other=None):
|
||||
Book_.__init__(self, prefix, lpath)
|
||||
|
||||
self.bookId = bookId
|
||||
self.title = title
|
||||
if not author:
|
||||
self.authors = ['']
|
||||
else:
|
||||
self.authors = [author]
|
||||
|
||||
if not title:
|
||||
self.title = _('Unknown')
|
||||
|
||||
self.mime = mime
|
||||
|
||||
self.size = size # will be set later if None
|
||||
|
||||
try:
|
||||
self.datetime = time.gmtime(os.path.getctime(self.path))
|
||||
except:
|
||||
self.datetime = time.gmtime()
|
||||
|
||||
if thumbnail_name is not None:
|
||||
self.thumbnail = ImageWrapper(thumbnail_name)
|
||||
self.tags = []
|
||||
if other:
|
||||
self.smart_update(other)
|
||||
|
||||
class ImageWrapper(object):
|
||||
def __init__(self, image_path):
|
||||
self.image_path = image_path
|
||||
|
227
src/calibre/devices/prst1/driver.py
Normal file
227
src/calibre/devices/prst1/driver.py
Normal file
@ -0,0 +1,227 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Timothy Legge <timlegge at gmail.com> and Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
'''
|
||||
Device driver for the SONY T1 devices
|
||||
'''
|
||||
|
||||
import os, time, calendar, re
|
||||
|
||||
import sqlite3 as sqlite
|
||||
from contextlib import closing
|
||||
from itertools import cycle
|
||||
from calibre.devices.usbms.driver import USBMS, debug_print
|
||||
from calibre import __appname__, prints
|
||||
from calibre.devices.usbms.books import CollectionsBookList
|
||||
from calibre.devices.usbms.books import BookList
|
||||
from calibre.devices.prst1.books import Book
|
||||
|
||||
class PRST1(USBMS):
|
||||
name = 'SONY PRST1 and newer Device Interface'
|
||||
gui_name = 'SONY Reader'
|
||||
description = _('Communicate with Sony PRST1 and newer eBook readers')
|
||||
author = 'Kovid Goyal'
|
||||
supported_platforms = ['windows', 'osx', 'linux']
|
||||
path_sep = '/'
|
||||
booklist_class = CollectionsBookList
|
||||
|
||||
FORMATS = ['epub', 'pdf', 'txt']
|
||||
CAN_SET_METADATA = ['title', 'authors', 'collections']
|
||||
|
||||
VENDOR_ID = [0x054c] #: SONY Vendor Id
|
||||
PRODUCT_ID = [0x05c2]
|
||||
BCD = [0x226]
|
||||
|
||||
VENDOR_NAME = 'SONY'
|
||||
WINDOWS_MAIN_MEM = re.compile(
|
||||
r'(PRS-T1&)'
|
||||
)
|
||||
|
||||
THUMBNAIL_HEIGHT = 144
|
||||
SCAN_FROM_ROOT = True
|
||||
SUPPORT_SUB_DIRS = True
|
||||
EBOOK_DIR_MAIN = 'Sony_Reader/media/books'
|
||||
|
||||
def windows_filter_pnp_id(self, pnp_id):
|
||||
return '_LAUNCHER' in pnp_id or '_SETTING' in pnp_id
|
||||
|
||||
def get_carda_ebook_dir(self, for_upload=False):
|
||||
if for_upload:
|
||||
return self.EBOOK_DIR_MAIN
|
||||
return self.EBOOK_DIR_CARD_A
|
||||
|
||||
def get_main_ebook_dir(self, for_upload=False):
|
||||
if for_upload:
|
||||
return self.EBOOK_DIR_MAIN
|
||||
return ''
|
||||
|
||||
def books(self, oncard=None, end_session=True):
|
||||
from calibre.ebooks.metadata.meta import path_to_ext
|
||||
|
||||
dummy_bl = BookList(None, None, None)
|
||||
|
||||
if oncard == 'carda' and not self._card_a_prefix:
|
||||
self.report_progress(1.0, _('Getting list of books on device...'))
|
||||
return dummy_bl
|
||||
elif oncard and oncard != 'carda':
|
||||
self.report_progress(1.0, _('Getting list of books on device...'))
|
||||
return dummy_bl
|
||||
|
||||
prefix = self._card_a_prefix if oncard == 'carda' else self._main_prefix
|
||||
|
||||
# get the metadata cache
|
||||
self.booklist_class.rebuild_collections = self.rebuild_collections
|
||||
bl = self.booklist_class(oncard, prefix, self.settings)
|
||||
need_sync = self.parse_metadata_cache(bl, prefix, self.METADATA_CACHE)
|
||||
|
||||
debug_print("SQLite DB Path: " + self.normalize_path(prefix + 'Sony_Reader/database/books.db'))
|
||||
|
||||
with closing(sqlite.connect(self.normalize_path(prefix + 'Sony_Reader/database/books.db'))) as connection:
|
||||
# return bytestrings if the content cannot the decoded as unicode
|
||||
connection.text_factory = lambda x: unicode(x, "utf-8", "ignore")
|
||||
|
||||
cursor = connection.cursor()
|
||||
# Query collections
|
||||
query = 'select books._id, collection.title ' \
|
||||
'from collections ' \
|
||||
'left outer join books ' \
|
||||
'left outer join collection ' \
|
||||
'where collections.content_id = books._id and collections.collection_id = collection._id'
|
||||
cursor.execute (query)
|
||||
|
||||
bl_collections = {}
|
||||
for i, row in enumerate(cursor):
|
||||
bl_collections.setdefault(row[0], [])
|
||||
bl_collections[row[0]].append(row[1])
|
||||
|
||||
# Query books themselves
|
||||
query = 'select _id, file_path, title, author, mime_type, modified_date, thumbnail, file_size ' \
|
||||
'from books'
|
||||
cursor.execute (query)
|
||||
|
||||
# make a dict cache of paths so the lookup in the loop below is faster.
|
||||
bl_cache = {}
|
||||
for idx,b in enumerate(bl):
|
||||
bl_cache[b.lpath] = idx
|
||||
|
||||
changed = False
|
||||
for i, row in enumerate(cursor):
|
||||
#Book(prefix, bookId, lpath, title, author, mime, date, thumbnail_name, size=None, other=None)
|
||||
thumbnail = row[6]
|
||||
if thumbnail is not None:
|
||||
thumbnail = self.normalize_path(prefix + row[6])
|
||||
|
||||
book = Book(row[0], prefix, row[1], row[2], row[3], row[4], row[5], thumbnail, row[7])
|
||||
book.device_collections = bl_collections.get(row[0], None)
|
||||
debug_print('Collections for ' + row[2] + ': ' + str(book.device_collections))
|
||||
bl_cache[row[1]] = None
|
||||
if bl.add_book(book, replace_metadata=True):
|
||||
changed = True
|
||||
|
||||
# Remove books that are no longer in the filesystem. Cache contains
|
||||
# indices into the booklist if book not in filesystem, None otherwise
|
||||
# Do the operation in reverse order so indices remain valid
|
||||
for idx in sorted(bl_cache.itervalues(), reverse=True):
|
||||
if idx is not None:
|
||||
changed = True
|
||||
del bl[idx]
|
||||
|
||||
cursor.close()
|
||||
|
||||
if changed:
|
||||
if oncard == 'carda':
|
||||
self.sync_booklists((None, bl, None))
|
||||
else:
|
||||
self.sync_booklists((bl, None, None))
|
||||
|
||||
return bl
|
||||
|
||||
def sync_booklists(self, booklists, end_session=True):
|
||||
debug_print('PRST1: starting sync_booklists')
|
||||
|
||||
if booklists[0] is not None:
|
||||
booklists[0].rebuild_collections(booklists[0], None)
|
||||
if booklists[1] is not None:
|
||||
booklists[1].rebuild_collections(booklists[1], 'carda')
|
||||
|
||||
USBMS.sync_booklists(self, booklists, end_session=end_session)
|
||||
debug_print('PRST1: finished sync_booklists')
|
||||
|
||||
def rebuild_collections(self, booklist, oncard):
|
||||
collections_attributes = ['tags']
|
||||
debug_print('PRS-T1: starting rebuild_collections')
|
||||
|
||||
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)
|
||||
#debug_print('Collections', collections)
|
||||
|
||||
with closing(sqlite.connect(self.normalize_path(prefix + 'Sony_Reader/database/books.db'))) as connection:
|
||||
cursor = connection.cursor()
|
||||
|
||||
if collections:
|
||||
# Get existing collections
|
||||
query = 'select _id, title ' \
|
||||
'from collection'
|
||||
cursor.execute(query)
|
||||
debug_print('Got Existing Collections')
|
||||
|
||||
categories = {}
|
||||
for i, row in enumerate(cursor):
|
||||
categories[row[1]] = row[0]
|
||||
|
||||
# Get existing books
|
||||
query = 'select file_path, _id ' \
|
||||
'from books'
|
||||
cursor.execute(query)
|
||||
debug_print('Got Existing Books')
|
||||
|
||||
dbBooks = {}
|
||||
for i, row in enumerate(cursor):
|
||||
dbBooks[self.normalize_path(row[0])] = row[1]
|
||||
|
||||
# Process any collections that exist
|
||||
for category, books in collections.items():
|
||||
if categories.get(category, None) is not None:
|
||||
query = 'delete from collections where collection_id = ?'
|
||||
t = (categories[category],)
|
||||
debug_print('Query: ' + query + ' ... ' + str(t))
|
||||
cursor.execute(query, t)
|
||||
|
||||
for book in books:
|
||||
# debug_print(' Title:', book.title, 'category: ', category)
|
||||
if category not in book.device_collections:
|
||||
book.device_collections.append(category)
|
||||
|
||||
if self.normalize_path(book.lpath) not in dbBooks:
|
||||
query = 'insert into books ' \
|
||||
'(title, author, source_id, added_date, modified_date, file_path, file_name, file_size, mime_type, corrupted, prevent_delete) ' \
|
||||
'values (?,?,?,?,?,?,?,?,?,0,0)'
|
||||
t = (book.title, book.authors[0], source_id, time.time() * 1000, calendar.timegm(book.datetime), book.lpath, os.path.basename(book.lpath), book.size, book.mime )
|
||||
cursor.execute(query, t)
|
||||
dbBooks[book.lpath] = cursor.lastrowid
|
||||
debug_print('Inserted Unknown Book: ' + book.title)
|
||||
|
||||
if category not in categories:
|
||||
query = 'insert into collection (title, source_id) values (?,?)'
|
||||
t = (category, source_id)
|
||||
cursor.execute(query, t)
|
||||
categories[category] = cursor.lastrowid
|
||||
debug_print('Inserted Unknown Collection: ' + category)
|
||||
|
||||
query = 'insert into collections (collection_id, content_id) values (?,?)'
|
||||
t = (categories[category], dbBooks[book.lpath])
|
||||
cursor.execute(query, t)
|
||||
debug_print('Inserted Book Into Collection: ' + book.title + ' -> ' + category)
|
||||
|
||||
connection.commit()
|
||||
cursor.close()
|
||||
|
||||
debug_print('PRS-T1: finished rebuild_collections')
|
||||
|
Loading…
x
Reference in New Issue
Block a user