mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Change Kobo drivers to use apsw
This reworks both the Kobo and KoboTouch drivers to use apsw instead of sqlite3. While doing this, I have refactored the code for the database connections and getting the versions from the device.
This commit is contained in:
parent
83ba85ef1b
commit
a001db9ef1
@ -13,7 +13,7 @@ class Bookmark(): # {{{
|
|||||||
A simple class fetching bookmark data
|
A simple class fetching bookmark data
|
||||||
kobo-specific
|
kobo-specific
|
||||||
'''
|
'''
|
||||||
def __init__(self, db_path, contentid, path, id, book_format, bookmark_extension):
|
def __init__(self, db_connection, contentid, path, id, book_format, bookmark_extension):
|
||||||
self.book_format = book_format
|
self.book_format = book_format
|
||||||
self.bookmark_extension = bookmark_extension
|
self.bookmark_extension = bookmark_extension
|
||||||
self.book_length = 0 # Not Used
|
self.book_length = 0 # Not Used
|
||||||
@ -23,7 +23,7 @@ class Bookmark(): # {{{
|
|||||||
self.path = path
|
self.path = path
|
||||||
self.timestamp = 0
|
self.timestamp = 0
|
||||||
self.user_notes = None
|
self.user_notes = None
|
||||||
self.db_path = db_path
|
self.db_connection = db_connection
|
||||||
self.contentid = contentid
|
self.contentid = contentid
|
||||||
self.percent_read = 0
|
self.percent_read = 0
|
||||||
self.get_bookmark_data()
|
self.get_bookmark_data()
|
||||||
@ -31,91 +31,93 @@ class Bookmark(): # {{{
|
|||||||
|
|
||||||
def get_bookmark_data(self):
|
def get_bookmark_data(self):
|
||||||
''' Return the timestamp and last_read_location '''
|
''' Return the timestamp and last_read_location '''
|
||||||
import sqlite3 as sqlite
|
|
||||||
user_notes = {}
|
user_notes = {}
|
||||||
self.timestamp = os.path.getmtime(self.path)
|
self.timestamp = os.path.getmtime(self.path)
|
||||||
with closing(sqlite.connect(self.db_path)) 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()
|
cursor = self.db_connection.cursor()
|
||||||
t = (self.contentid,)
|
t = (self.contentid,)
|
||||||
|
|
||||||
kepub_chapter_query = (
|
kepub_chapter_query = (
|
||||||
'SELECT Title, volumeIndex '
|
'SELECT Title, volumeIndex '
|
||||||
'FROM content '
|
'FROM content '
|
||||||
'WHERE ContentID LIKE ? '
|
'WHERE ContentID LIKE ? '
|
||||||
)
|
)
|
||||||
bookmark_query = ('SELECT bm.bookmarkid, bm.ContentID, bm.text, bm.annotation, '
|
bookmark_query = ('SELECT bm.bookmarkid, bm.ContentID, bm.text, bm.annotation, '
|
||||||
'bm.ChapterProgress, bm.StartContainerChildIndex, bm.StartOffset, '
|
'bm.ChapterProgress, bm.StartContainerChildIndex, bm.StartOffset, '
|
||||||
'c.BookTitle, c.TITLE, c.volumeIndex, c.MimeType '
|
'c.BookTitle, c.TITLE, c.volumeIndex, c.MimeType '
|
||||||
'FROM Bookmark bm LEFT OUTER JOIN Content c ON '
|
'FROM Bookmark bm LEFT OUTER JOIN Content c ON '
|
||||||
'c.ContentID = bm.ContentID '
|
'c.ContentID = bm.ContentID '
|
||||||
'WHERE bm.Hidden = "false" '
|
'WHERE bm.Hidden = "false" '
|
||||||
'AND bm.volumeid = ? '
|
'AND bm.volumeid = ? '
|
||||||
'ORDER BY bm.ContentID, bm.chapterprogress')
|
'ORDER BY bm.ContentID, bm.chapterprogress')
|
||||||
cursor.execute(bookmark_query, t)
|
cursor.execute(bookmark_query, t)
|
||||||
|
|
||||||
previous_chapter = 0
|
previous_chapter = 0
|
||||||
bm_count = 0
|
bm_count = 0
|
||||||
for row in cursor:
|
for row in cursor:
|
||||||
current_chapter = row[9]
|
current_chapter = row[9]
|
||||||
chapter_title = row[8]
|
chapter_title = row[8]
|
||||||
# For kepubs on newer firmware, the title needs to come from an 899 row.
|
# For kepubs on newer firmware, the title needs to come from an 899 row.
|
||||||
if not row[10] or row[10] == 'application/xhtml+xml' or row[10] == 'application/x-kobo-epub+zip':
|
if not row[10] or row[10] == 'application/xhtml+xml' or row[10] == 'application/x-kobo-epub+zip':
|
||||||
cursor2 = connection.cursor()
|
cursor2 = self.db_connection.cursor()
|
||||||
kepub_chapter_data = ('{0}-%'.format(row[1]), )
|
kepub_chapter_data = ('{0}-%'.format(row[1]), )
|
||||||
cursor2.execute(kepub_chapter_query, kepub_chapter_data)
|
cursor2.execute(kepub_chapter_query, kepub_chapter_data)
|
||||||
kepub_chapter = cursor2.fetchone()
|
try:
|
||||||
if kepub_chapter:
|
kepub_chapter = cursor2.next()
|
||||||
chapter_title = kepub_chapter[0]
|
chapter_title = kepub_chapter[0]
|
||||||
current_chapter = kepub_chapter[1]
|
current_chapter = kepub_chapter[1]
|
||||||
|
except StopIteration:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
cursor2.close
|
cursor2.close
|
||||||
if previous_chapter == current_chapter:
|
if previous_chapter == current_chapter:
|
||||||
bm_count = bm_count + 1
|
bm_count = bm_count + 1
|
||||||
else:
|
else:
|
||||||
bm_count = 0
|
bm_count = 0
|
||||||
|
|
||||||
text = row[2]
|
text = row[2]
|
||||||
annotation = row[3]
|
annotation = row[3]
|
||||||
|
|
||||||
# A dog ear (bent upper right corner) is a bookmark
|
# A dog ear (bent upper right corner) is a bookmark
|
||||||
if row[5] == row[6] == 0: # StartContainerChildIndex = StartOffset = 0
|
if row[5] == row[6] == 0: # StartContainerChildIndex = StartOffset = 0
|
||||||
e_type = 'Bookmark'
|
e_type = 'Bookmark'
|
||||||
text = row[8]
|
text = row[8]
|
||||||
# highlight is text with no annotation
|
# highlight is text with no annotation
|
||||||
elif text is not None and (annotation is None or annotation == ""):
|
elif text is not None and (annotation is None or annotation == ""):
|
||||||
e_type = 'Highlight'
|
e_type = 'Highlight'
|
||||||
elif text and annotation:
|
elif text and annotation:
|
||||||
e_type = 'Annotation'
|
e_type = 'Annotation'
|
||||||
else:
|
else:
|
||||||
e_type = 'Unknown annotation type'
|
e_type = 'Unknown annotation type'
|
||||||
|
|
||||||
note_id = current_chapter * 1000 + bm_count
|
note_id = current_chapter * 1000 + bm_count
|
||||||
|
|
||||||
# book_title = row[8]
|
# book_title = row[8]
|
||||||
chapter_progress = min(round(float(100*row[4]),2),100)
|
chapter_progress = min(round(float(100*row[4]),2),100)
|
||||||
user_notes[note_id] = dict(id=self.id,
|
user_notes[note_id] = dict(id=self.id,
|
||||||
displayed_location=note_id,
|
displayed_location=note_id,
|
||||||
type=e_type,
|
type=e_type,
|
||||||
text=text,
|
text=text,
|
||||||
annotation=annotation,
|
annotation=annotation,
|
||||||
chapter=current_chapter,
|
chapter=current_chapter,
|
||||||
chapter_title=chapter_title,
|
chapter_title=chapter_title,
|
||||||
chapter_progress=chapter_progress)
|
chapter_progress=chapter_progress)
|
||||||
previous_chapter = current_chapter
|
previous_chapter = current_chapter
|
||||||
# debug_print("e_type:" , e_type, '\t', 'loc: ', note_id, 'text: ', text,
|
# debug_print("e_type:" , e_type, '\t', 'loc: ', note_id, 'text: ', text,
|
||||||
# 'annotation: ', annotation, 'chapter_title: ', chapter_title,
|
# 'annotation: ', annotation, 'chapter_title: ', chapter_title,
|
||||||
# 'chapter_progress: ', chapter_progress, 'date: ')
|
# 'chapter_progress: ', chapter_progress, 'date: ')
|
||||||
|
|
||||||
cursor.execute('select datelastread, ___PercentRead from content '
|
cursor.execute('SELECT datelastread, ___PercentRead '
|
||||||
'where bookid is Null and '
|
'FROM content '
|
||||||
'contentid = ?', t)
|
'WHERE bookid IS NULL '
|
||||||
for row in cursor:
|
'AND ReadStatus > 0 '
|
||||||
self.last_read = row[0]
|
'AND contentid = ?',
|
||||||
self.percent_read = row[1]
|
t)
|
||||||
# print row[1]
|
for row in cursor:
|
||||||
cursor.close()
|
self.last_read = row[0]
|
||||||
|
self.percent_read = row[1]
|
||||||
|
# print row[1]
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
# self.last_read_location = self.last_read - self.pdf_page_offset
|
# self.last_read_location = self.last_read - self.pdf_page_offset
|
||||||
self.user_notes = user_notes
|
self.user_notes = user_notes
|
||||||
|
@ -31,6 +31,7 @@ from calibre.utils.config_base import prefs
|
|||||||
EPUB_EXT = '.epub'
|
EPUB_EXT = '.epub'
|
||||||
KEPUB_EXT = '.kepub'
|
KEPUB_EXT = '.kepub'
|
||||||
|
|
||||||
|
USE_SQLITE3 = False
|
||||||
|
|
||||||
# Implementation of QtQHash for strings. This doesn't seem to be in the Python implementation.
|
# Implementation of QtQHash for strings. This doesn't seem to be in the Python implementation.
|
||||||
def qhash(inputstr):
|
def qhash(inputstr):
|
||||||
@ -64,10 +65,10 @@ class KOBO(USBMS):
|
|||||||
gui_name = 'Kobo Reader'
|
gui_name = 'Kobo Reader'
|
||||||
description = _('Communicate with the Kobo Reader')
|
description = _('Communicate with the Kobo Reader')
|
||||||
author = 'Timothy Legge and David Forrester'
|
author = 'Timothy Legge and David Forrester'
|
||||||
version = (2, 2, 1)
|
version = (2, 3, 0)
|
||||||
|
|
||||||
dbversion = 0
|
dbversion = 0
|
||||||
fwversion = 0
|
fwversion = (0,0,0)
|
||||||
supported_dbversion = 125
|
supported_dbversion = 125
|
||||||
has_kepubs = False
|
has_kepubs = False
|
||||||
|
|
||||||
@ -157,10 +158,49 @@ class KOBO(USBMS):
|
|||||||
def device_database_path(self):
|
def device_database_path(self):
|
||||||
return self.normalize_path(self._main_prefix + '.kobo/KoboReader.sqlite')
|
return self.normalize_path(self._main_prefix + '.kobo/KoboReader.sqlite')
|
||||||
|
|
||||||
|
def device_database_connection(self):
|
||||||
|
if USE_SQLITE3:
|
||||||
|
import sqlite3 as sqlite
|
||||||
|
db_connection = sqlite.connect(self.device_database_path())
|
||||||
|
|
||||||
|
# return bytestrings if the content cannot the decoded as unicode
|
||||||
|
db_connection.text_factory = lambda x: unicode(x, "utf-8", "ignore")
|
||||||
|
else:
|
||||||
|
import apsw
|
||||||
|
db_connection = apsw.Connection(self.device_database_path())
|
||||||
|
|
||||||
|
return db_connection
|
||||||
|
|
||||||
|
def get_database_version(self, connection):
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute('SELECT version FROM dbversion')
|
||||||
|
try:
|
||||||
|
result = cursor.next()
|
||||||
|
dbversion = result[0]
|
||||||
|
except StopIteration:
|
||||||
|
dbversion = 0
|
||||||
|
|
||||||
|
return dbversion
|
||||||
|
|
||||||
|
|
||||||
|
def get_firmware_version(self):
|
||||||
|
# Determine the firmware version
|
||||||
|
try:
|
||||||
|
with lopen(self.normalize_path(self._main_prefix + '.kobo/version'), 'rb') as f:
|
||||||
|
fwversion = f.readline().split(',')[2]
|
||||||
|
fwversion = tuple((int(x) for x in fwversion.split('.')))
|
||||||
|
except:
|
||||||
|
debug_print("Kobo::get_firmware_version - didn't get firmware version from file'")
|
||||||
|
fwversion = (0,0,0)
|
||||||
|
|
||||||
|
return fwversion
|
||||||
|
|
||||||
|
|
||||||
def sanitize_path_components(self, components):
|
def sanitize_path_components(self, components):
|
||||||
invalid_filename_chars_re = re.compile(r'[\/\\\?%\*:;\|\"\'><\$!]', re.IGNORECASE | re.UNICODE)
|
invalid_filename_chars_re = re.compile(r'[\/\\\?%\*:;\|\"\'><\$!]', re.IGNORECASE | re.UNICODE)
|
||||||
return [invalid_filename_chars_re.sub('_', x) for x in components]
|
return [invalid_filename_chars_re.sub('_', x) for x in components]
|
||||||
|
|
||||||
|
|
||||||
def books(self, oncard=None, end_session=True):
|
def books(self, oncard=None, end_session=True):
|
||||||
from calibre.ebooks.metadata.meta import path_to_ext
|
from calibre.ebooks.metadata.meta import path_to_ext
|
||||||
|
|
||||||
@ -180,15 +220,9 @@ class KOBO(USBMS):
|
|||||||
self._card_b_prefix if oncard == 'cardb' \
|
self._card_b_prefix if oncard == 'cardb' \
|
||||||
else self._main_prefix
|
else self._main_prefix
|
||||||
|
|
||||||
# Determine the firmware version
|
self.fwversion = self.get_firmware_version()
|
||||||
try:
|
|
||||||
with lopen(self.normalize_path(self._main_prefix + '.kobo/version'),
|
|
||||||
'rb') as f:
|
|
||||||
self.fwversion = f.readline().split(',')[2]
|
|
||||||
except:
|
|
||||||
self.fwversion = 'unknown'
|
|
||||||
|
|
||||||
if self.fwversion != '1.0' and self.fwversion != '1.4':
|
if not (self.fwversion == (1,0) or self.fwversion == (1,4)):
|
||||||
self.has_kepubs = True
|
self.has_kepubs = True
|
||||||
debug_print('Version of driver: ', self.version, 'Has kepubs:', self.has_kepubs)
|
debug_print('Version of driver: ', self.version, 'Has kepubs:', self.has_kepubs)
|
||||||
debug_print('Version of firmware: ', self.fwversion, 'Has kepubs:', self.has_kepubs)
|
debug_print('Version of firmware: ', self.fwversion, 'Has kepubs:', self.has_kepubs)
|
||||||
@ -293,22 +327,12 @@ class KOBO(USBMS):
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
import sqlite3 as sqlite
|
with closing(self.device_database_connection()) as connection:
|
||||||
with closing(sqlite.connect(
|
|
||||||
self.normalize_path(self._main_prefix +
|
|
||||||
'.kobo/KoboReader.sqlite'))) 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()
|
|
||||||
|
|
||||||
cursor.execute('select version from dbversion')
|
|
||||||
result = cursor.fetchone()
|
|
||||||
self.dbversion = result[0]
|
|
||||||
|
|
||||||
|
self.dbversion = self.get_database_version(connection)
|
||||||
debug_print("Database Version: ", self.dbversion)
|
debug_print("Database Version: ", self.dbversion)
|
||||||
|
|
||||||
|
cursor = connection.cursor()
|
||||||
opts = self.settings()
|
opts = self.settings()
|
||||||
if self.dbversion >= 33:
|
if self.dbversion >= 33:
|
||||||
query= ('select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, '
|
query= ('select Title, Attribution, DateCreated, ContentID, MimeType, ContentType, '
|
||||||
@ -410,13 +434,8 @@ class KOBO(USBMS):
|
|||||||
# 2) volume_shorcover
|
# 2) volume_shorcover
|
||||||
# 2) content
|
# 2) content
|
||||||
|
|
||||||
import sqlite3 as sqlite
|
|
||||||
debug_print('delete_via_sql: ContentID: ', ContentID, 'ContentType: ', ContentType)
|
debug_print('delete_via_sql: ContentID: ', ContentID, 'ContentType: ', ContentType)
|
||||||
with closing(sqlite.connect(self.normalize_path(self._main_prefix +
|
with closing(self.device_database_connection()) as connection:
|
||||||
'.kobo/KoboReader.sqlite'))) 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()
|
cursor = connection.cursor()
|
||||||
t = (ContentID,)
|
t = (ContentID,)
|
||||||
@ -463,8 +482,6 @@ class KOBO(USBMS):
|
|||||||
else:
|
else:
|
||||||
cursor.execute('delete from content where BookID is Null and ContentID =?',t)
|
cursor.execute('delete from content where BookID is Null and ContentID =?',t)
|
||||||
|
|
||||||
connection.commit()
|
|
||||||
|
|
||||||
cursor.close()
|
cursor.close()
|
||||||
if ImageID == None:
|
if ImageID == None:
|
||||||
print "Error condition ImageID was not found"
|
print "Error condition ImageID was not found"
|
||||||
@ -624,7 +641,7 @@ class KOBO(USBMS):
|
|||||||
ContentType = 16
|
ContentType = 16
|
||||||
elif extension == '.rtf' or extension == '.txt' or extension == '.htm' or extension == '.html':
|
elif extension == '.rtf' or extension == '.txt' or extension == '.htm' or extension == '.html':
|
||||||
# print "txt"
|
# print "txt"
|
||||||
if self.fwversion == '1.0' or self.fwversion == '1.4' or self.fwversion == '1.7.4':
|
if self.fwversion == (1,0) or self.fwversion == (1,4) or self.fwversion == (1,7,4):
|
||||||
ContentType = 999
|
ContentType = 999
|
||||||
else:
|
else:
|
||||||
ContentType = 901
|
ContentType = 901
|
||||||
@ -754,21 +771,18 @@ class KOBO(USBMS):
|
|||||||
except:
|
except:
|
||||||
debug_print(' Database Exception: Unable to reset ReadStatus list')
|
debug_print(' Database Exception: Unable to reset ReadStatus list')
|
||||||
raise
|
raise
|
||||||
else:
|
finally:
|
||||||
connection.commit()
|
cursor.close()
|
||||||
# debug_print(' Commit: Reset ReadStatus list')
|
|
||||||
|
|
||||||
cursor.close()
|
|
||||||
|
|
||||||
def set_readstatus(self, connection, ContentID, ReadStatus):
|
def set_readstatus(self, connection, ContentID, ReadStatus):
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
t = (ContentID,)
|
t = (ContentID,)
|
||||||
cursor.execute('select DateLastRead from Content where BookID is Null and ContentID = ?', t)
|
cursor.execute('select DateLastRead from Content where BookID is Null and ContentID = ?', t)
|
||||||
result = cursor.fetchone()
|
try:
|
||||||
if result is None:
|
result = cursor.next()
|
||||||
datelastread = '1970-01-01T00:00:00'
|
|
||||||
else:
|
|
||||||
datelastread = result[0] if result[0] is not None else '1970-01-01T00:00:00'
|
datelastread = result[0] if result[0] is not None else '1970-01-01T00:00:00'
|
||||||
|
except StopIteration:
|
||||||
|
datelastread = '1970-01-01T00:00:00'
|
||||||
|
|
||||||
t = (ReadStatus,datelastread,ContentID,)
|
t = (ReadStatus,datelastread,ContentID,)
|
||||||
|
|
||||||
@ -777,9 +791,7 @@ class KOBO(USBMS):
|
|||||||
except:
|
except:
|
||||||
debug_print(' Database Exception: Unable update ReadStatus')
|
debug_print(' Database Exception: Unable update ReadStatus')
|
||||||
raise
|
raise
|
||||||
else:
|
|
||||||
connection.commit()
|
|
||||||
# debug_print(' Commit: Setting ReadStatus List')
|
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
||||||
def reset_favouritesindex(self, connection, oncard):
|
def reset_favouritesindex(self, connection, oncard):
|
||||||
@ -796,9 +808,8 @@ class KOBO(USBMS):
|
|||||||
debug_print(' Database Exception: Unable to reset Shortlist list')
|
debug_print(' Database Exception: Unable to reset Shortlist list')
|
||||||
if 'no such column' not in str(e):
|
if 'no such column' not in str(e):
|
||||||
raise
|
raise
|
||||||
else:
|
finally:
|
||||||
connection.commit()
|
cursor.close()
|
||||||
# debug_print(' Commit: Reset FavouritesIndex list')
|
|
||||||
|
|
||||||
def set_favouritesindex(self, connection, ContentID):
|
def set_favouritesindex(self, connection, ContentID):
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
@ -811,9 +822,8 @@ class KOBO(USBMS):
|
|||||||
debug_print(' Database Exception: Unable set book as Shortlist')
|
debug_print(' Database Exception: Unable set book as Shortlist')
|
||||||
if 'no such column' not in str(e):
|
if 'no such column' not in str(e):
|
||||||
raise
|
raise
|
||||||
else:
|
finally:
|
||||||
connection.commit()
|
cursor.close()
|
||||||
# debug_print(' Commit: Set FavouritesIndex')
|
|
||||||
|
|
||||||
def update_device_database_collections(self, booklists, collections_attributes, oncard):
|
def update_device_database_collections(self, booklists, collections_attributes, oncard):
|
||||||
debug_print("Kobo:update_device_database_collections - oncard='%s'"%oncard)
|
debug_print("Kobo:update_device_database_collections - oncard='%s'"%oncard)
|
||||||
@ -854,12 +864,7 @@ class KOBO(USBMS):
|
|||||||
# the last book from the collection the list of books is empty
|
# the last book from the collection the list of books is empty
|
||||||
# and the removal of the last book would not occur
|
# and the removal of the last book would not occur
|
||||||
|
|
||||||
import sqlite3 as sqlite
|
with closing(self.device_database_connection()) as connection:
|
||||||
with closing(sqlite.connect(self.normalize_path(self._main_prefix +
|
|
||||||
'.kobo/KoboReader.sqlite'))) as connection:
|
|
||||||
|
|
||||||
# return bytestrings if the content cannot the decoded as unicode
|
|
||||||
connection.text_factory = lambda x: unicode(x, "utf-8", "ignore")
|
|
||||||
|
|
||||||
if collections:
|
if collections:
|
||||||
|
|
||||||
@ -988,25 +993,20 @@ class KOBO(USBMS):
|
|||||||
ContentType = self.get_content_type_from_extension(extension) if extension != '' else self.get_content_type_from_path(filepath)
|
ContentType = self.get_content_type_from_extension(extension) if extension != '' else self.get_content_type_from_path(filepath)
|
||||||
ContentID = self.contentid_from_path(filepath, ContentType)
|
ContentID = self.contentid_from_path(filepath, ContentType)
|
||||||
|
|
||||||
import sqlite3 as sqlite
|
with closing(self.device_database_connection()) as connection:
|
||||||
with closing(sqlite.connect(self.normalize_path(self._main_prefix +
|
|
||||||
'.kobo/KoboReader.sqlite'))) 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()
|
cursor = connection.cursor()
|
||||||
t = (ContentID,)
|
t = (ContentID,)
|
||||||
cursor.execute('select ImageId from Content where BookID is Null and ContentID = ?', t)
|
cursor.execute('select ImageId from Content where BookID is Null and ContentID = ?', t)
|
||||||
result = cursor.fetchone()
|
try:
|
||||||
if result is None:
|
result = cursor.next()
|
||||||
|
# debug_print("ImageId: ", result[0])
|
||||||
|
ImageID = result[0]
|
||||||
|
except StopIteration:
|
||||||
debug_print("No rows exist in the database - cannot upload")
|
debug_print("No rows exist in the database - cannot upload")
|
||||||
return
|
return
|
||||||
else:
|
finally:
|
||||||
ImageID = result[0]
|
cursor.close()
|
||||||
# debug_print("ImageId: ", result[0])
|
|
||||||
|
|
||||||
cursor.close()
|
|
||||||
|
|
||||||
if ImageID != None:
|
if ImageID != None:
|
||||||
path_prefix = '.kobo/images/'
|
path_prefix = '.kobo/images/'
|
||||||
@ -1158,17 +1158,17 @@ class KOBO(USBMS):
|
|||||||
path_map, book_ext = resolve_bookmark_paths(storage, path_map)
|
path_map, book_ext = resolve_bookmark_paths(storage, path_map)
|
||||||
|
|
||||||
bookmarked_books = {}
|
bookmarked_books = {}
|
||||||
for id in path_map:
|
with closing(self.device_database_connection()) as connection:
|
||||||
extension = os.path.splitext(path_map[id])[1]
|
for id in path_map:
|
||||||
ContentType = self.get_content_type_from_extension(extension) if extension != '' else self.get_content_type_from_path(path_map[id])
|
extension = os.path.splitext(path_map[id])[1]
|
||||||
ContentID = self.contentid_from_path(path_map[id], ContentType)
|
ContentType = self.get_content_type_from_extension(extension) if extension != '' else self.get_content_type_from_path(path_map[id])
|
||||||
debug_print("get_annotations - ContentID: ", ContentID, "ContentType: ", ContentType)
|
ContentID = self.contentid_from_path(path_map[id], ContentType)
|
||||||
|
debug_print("get_annotations - ContentID: ", ContentID, "ContentType: ", ContentType)
|
||||||
|
|
||||||
bookmark_ext = extension
|
bookmark_ext = extension
|
||||||
|
|
||||||
db_path = self.normalize_path(self._main_prefix + '.kobo/KoboReader.sqlite')
|
myBookmark = Bookmark(connection, ContentID, path_map[id], id, book_ext[id], bookmark_ext)
|
||||||
myBookmark = Bookmark(db_path, ContentID, path_map[id], id, book_ext[id], bookmark_ext)
|
bookmarked_books[id] = self.UserAnnotation(type='kobo_bookmark', value=myBookmark)
|
||||||
bookmarked_books[id] = self.UserAnnotation(type='kobo_bookmark', value=myBookmark)
|
|
||||||
|
|
||||||
# This returns as job.result in gui2.ui.annotations_fetched(self,job)
|
# This returns as job.result in gui2.ui.annotations_fetched(self,job)
|
||||||
return bookmarked_books
|
return bookmarked_books
|
||||||
@ -1180,7 +1180,7 @@ class KOBO(USBMS):
|
|||||||
#last_read_location = bookmark.last_read_location
|
#last_read_location = bookmark.last_read_location
|
||||||
#timestamp = bookmark.timestamp
|
#timestamp = bookmark.timestamp
|
||||||
percent_read = bookmark.percent_read
|
percent_read = bookmark.percent_read
|
||||||
debug_print("Date: ", bookmark.last_read)
|
debug_print("Kobo::generate_annotation_html - last_read: ", bookmark.last_read)
|
||||||
if bookmark.last_read is not None:
|
if bookmark.last_read is not None:
|
||||||
try:
|
try:
|
||||||
last_read = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(calendar.timegm(time.strptime(bookmark.last_read, "%Y-%m-%dT%H:%M:%S"))))
|
last_read = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(calendar.timegm(time.strptime(bookmark.last_read, "%Y-%m-%dT%H:%M:%S"))))
|
||||||
@ -1188,7 +1188,10 @@ class KOBO(USBMS):
|
|||||||
try:
|
try:
|
||||||
last_read = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(calendar.timegm(time.strptime(bookmark.last_read, "%Y-%m-%dT%H:%M:%S.%f"))))
|
last_read = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(calendar.timegm(time.strptime(bookmark.last_read, "%Y-%m-%dT%H:%M:%S.%f"))))
|
||||||
except:
|
except:
|
||||||
last_read = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(calendar.timegm(time.strptime(bookmark.last_read, "%Y-%m-%dT%H:%M:%SZ"))))
|
try:
|
||||||
|
last_read = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(calendar.timegm(time.strptime(bookmark.last_read, "%Y-%m-%dT%H:%M:%SZ"))))
|
||||||
|
except:
|
||||||
|
last_read = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
|
||||||
else:
|
else:
|
||||||
#self.datetime = time.gmtime()
|
#self.datetime = time.gmtime()
|
||||||
last_read = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
|
last_read = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())
|
||||||
@ -1277,7 +1280,7 @@ class KOBO(USBMS):
|
|||||||
bm = annotation
|
bm = annotation
|
||||||
ignore_tags = set(['Catalog', 'Clippings'])
|
ignore_tags = set(['Catalog', 'Clippings'])
|
||||||
|
|
||||||
if bm.type == 'kobo_bookmark':
|
if bm.type == 'kobo_bookmark' and bm.value.last_read:
|
||||||
mi = db.get_metadata(db_id, index_is_id=True)
|
mi = db.get_metadata(db_id, index_is_id=True)
|
||||||
debug_print("KOBO:add_annotation_to_library - Title: ", mi.title)
|
debug_print("KOBO:add_annotation_to_library - Title: ", mi.title)
|
||||||
user_notes_soup = self.generate_annotation_html(bm.value)
|
user_notes_soup = self.generate_annotation_html(bm.value)
|
||||||
@ -1312,9 +1315,9 @@ class KOBO(USBMS):
|
|||||||
|
|
||||||
class KOBOTOUCH(KOBO):
|
class KOBOTOUCH(KOBO):
|
||||||
name = 'KoboTouch'
|
name = 'KoboTouch'
|
||||||
gui_name = 'Kobo Touch/Glo/Mini/Aura HD'
|
gui_name = 'Kobo Touch/Glo/Mini/Aura HD/Aura H2O/Glo HD/Touch 2'
|
||||||
author = 'David Forrester'
|
author = 'David Forrester'
|
||||||
description = 'Communicate with the Kobo Touch, Glo, Mini and Aura HD ereaders. Based on the existing Kobo driver by %s.' % (KOBO.author)
|
description = 'Communicate with the Kobo Touch, Glo, Mini, Aura HD, Aura H2O, Glo HD and Touch 2ereaders. Based on the existing Kobo driver by %s.' % (KOBO.author)
|
||||||
# icon = I('devices/kobotouch.jpg')
|
# icon = I('devices/kobotouch.jpg')
|
||||||
|
|
||||||
supported_dbversion = 125
|
supported_dbversion = 125
|
||||||
@ -1437,13 +1440,7 @@ class KOBOTOUCH(KOBO):
|
|||||||
else self._main_prefix
|
else self._main_prefix
|
||||||
debug_print("KoboTouch:books - oncard='%s', prefix='%s'"%(oncard, prefix))
|
debug_print("KoboTouch:books - oncard='%s', prefix='%s'"%(oncard, prefix))
|
||||||
|
|
||||||
# Determine the firmware version
|
self.fwversion = self.get_firmware_version()
|
||||||
try:
|
|
||||||
with lopen(self.normalize_path(self._main_prefix + '.kobo/version'), 'rb') as f:
|
|
||||||
self.fwversion = f.readline().split(',')[2]
|
|
||||||
self.fwversion = tuple((int(x) for x in self.fwversion.split('.')))
|
|
||||||
except:
|
|
||||||
self.fwversion = (0,0,0)
|
|
||||||
|
|
||||||
debug_print('Kobo device: %s' % self.gui_name)
|
debug_print('Kobo device: %s' % self.gui_name)
|
||||||
debug_print('Version of driver:', self.version, 'Has kepubs:', self.has_kepubs)
|
debug_print('Version of driver:', self.version, 'Has kepubs:', self.has_kepubs)
|
||||||
@ -1667,25 +1664,18 @@ class KOBOTOUCH(KOBO):
|
|||||||
return bookshelves
|
return bookshelves
|
||||||
|
|
||||||
self.debug_index = 0
|
self.debug_index = 0
|
||||||
import sqlite3 as sqlite
|
|
||||||
with closing(sqlite.connect(self.device_database_path())) as connection:
|
with closing(self.device_database_connection()) as connection:
|
||||||
debug_print("KoboTouch:books - reading device database")
|
debug_print("KoboTouch:books - reading device database")
|
||||||
|
|
||||||
# return bytestrings if the content cannot the decoded as unicode
|
self.dbversion = self.get_database_version(connection)
|
||||||
connection.text_factory = lambda x: unicode(x, "utf-8", "ignore")
|
debug_print("Database Version: ", self.dbversion)
|
||||||
|
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
|
|
||||||
cursor.execute('select version from dbversion')
|
|
||||||
result = cursor.fetchone()
|
|
||||||
self.dbversion = result[0]
|
|
||||||
debug_print("Database Version=%d"%self.dbversion)
|
|
||||||
|
|
||||||
self.bookshelvelist = self.get_bookshelflist(connection)
|
self.bookshelvelist = self.get_bookshelflist(connection)
|
||||||
debug_print("KoboTouch:books - shelf list:", self.bookshelvelist)
|
debug_print("KoboTouch:books - shelf list:", self.bookshelvelist)
|
||||||
|
|
||||||
opts = self.settings()
|
|
||||||
|
|
||||||
columns = 'Title, Attribution, DateCreated, ContentID, MimeType, ContentType, ImageID, ReadStatus'
|
columns = 'Title, Attribution, DateCreated, ContentID, MimeType, ContentType, ImageID, ReadStatus'
|
||||||
if self.dbversion >= 16:
|
if self.dbversion >= 16:
|
||||||
columns += ', ___ExpirationStatus, FavouritesIndex, Accessibility'
|
columns += ', ___ExpirationStatus, FavouritesIndex, Accessibility'
|
||||||
@ -1930,11 +1920,8 @@ class KOBOTOUCH(KOBO):
|
|||||||
# debug_print('KoboTouch:upload_books - result=', result)
|
# debug_print('KoboTouch:upload_books - result=', result)
|
||||||
|
|
||||||
if self.dbversion >= 53:
|
if self.dbversion >= 53:
|
||||||
import sqlite3 as sqlite
|
|
||||||
try:
|
try:
|
||||||
with closing(sqlite.connect(self.normalize_path(self._main_prefix +
|
with closing(self.device_database_connection()) as connection:
|
||||||
'.kobo/KoboReader.sqlite'))) as connection:
|
|
||||||
connection.text_factory = lambda x: unicode(x, "utf-8", "ignore")
|
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
cleanup_query = "DELETE FROM content WHERE ContentID = ? AND Accessibility = 1 AND IsDownloaded = 'false'"
|
cleanup_query = "DELETE FROM content WHERE ContentID = ? AND Accessibility = 1 AND IsDownloaded = 'false'"
|
||||||
|
|
||||||
@ -1954,7 +1941,6 @@ class KOBOTOUCH(KOBO):
|
|||||||
if not self.upload_covers:
|
if not self.upload_covers:
|
||||||
imageID = self.imageid_from_contentid(contentID)
|
imageID = self.imageid_from_contentid(contentID)
|
||||||
self.delete_images(imageID, fname)
|
self.delete_images(imageID, fname)
|
||||||
connection.commit()
|
|
||||||
|
|
||||||
cursor.close()
|
cursor.close()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -2064,13 +2050,10 @@ class KOBOTOUCH(KOBO):
|
|||||||
imageId = super(KOBOTOUCH, self).delete_via_sql(ContentID, ContentType)
|
imageId = super(KOBOTOUCH, self).delete_via_sql(ContentID, ContentType)
|
||||||
|
|
||||||
if self.dbversion >= 53:
|
if self.dbversion >= 53:
|
||||||
import sqlite3 as sqlite
|
|
||||||
debug_print('KoboTouch:delete_via_sql: ContentID="%s"'%ContentID, 'ContentType="%s"'%ContentType)
|
debug_print('KoboTouch:delete_via_sql: ContentID="%s"'%ContentID, 'ContentType="%s"'%ContentType)
|
||||||
try:
|
try:
|
||||||
with closing(sqlite.connect(self.device_database_path())) as connection:
|
with closing(self.device_database_connection()) as connection:
|
||||||
debug_print('KoboTouch:delete_via_sql: have database connection')
|
debug_print('KoboTouch:delete_via_sql: have database connection')
|
||||||
# return bytestrings if the content cannot the decoded as unicode
|
|
||||||
connection.text_factory = lambda x: unicode(x, "utf-8", "ignore")
|
|
||||||
|
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
debug_print('KoboTouch:delete_via_sql: have cursor')
|
debug_print('KoboTouch:delete_via_sql: have cursor')
|
||||||
@ -2101,8 +2084,6 @@ class KOBOTOUCH(KOBO):
|
|||||||
debug_print('KoboTouch:delete_via_sql: delete from Activity')
|
debug_print('KoboTouch:delete_via_sql: delete from Activity')
|
||||||
cursor.execute('delete from Activity where Id =?', t)
|
cursor.execute('delete from Activity where Id =?', t)
|
||||||
|
|
||||||
connection.commit()
|
|
||||||
|
|
||||||
cursor.close()
|
cursor.close()
|
||||||
debug_print('KoboTouch:delete_via_sql: finished SQL')
|
debug_print('KoboTouch:delete_via_sql: finished SQL')
|
||||||
debug_print('KoboTouch:delete_via_sql: After SQL, no exception')
|
debug_print('KoboTouch:delete_via_sql: After SQL, no exception')
|
||||||
@ -2227,11 +2208,7 @@ class KOBOTOUCH(KOBO):
|
|||||||
# the last book from the collection the list of books is empty
|
# the last book from the collection the list of books is empty
|
||||||
# and the removal of the last book would not occur
|
# and the removal of the last book would not occur
|
||||||
|
|
||||||
import sqlite3 as sqlite
|
with closing(self.device_database_connection()) as connection:
|
||||||
with closing(sqlite.connect(self.device_database_path())) as connection:
|
|
||||||
|
|
||||||
# return bytestrings if the content cannot the decoded as unicode
|
|
||||||
connection.text_factory = lambda x: unicode(x, "utf-8", "ignore")
|
|
||||||
|
|
||||||
if self.manage_collections and collections:
|
if self.manage_collections and collections:
|
||||||
# debug_print("KoboTouch:update_device_database_collections - length collections=" + unicode(len(collections)))
|
# debug_print("KoboTouch:update_device_database_collections - length collections=" + unicode(len(collections)))
|
||||||
@ -2427,23 +2404,17 @@ class KOBOTOUCH(KOBO):
|
|||||||
ContentID = self.contentid_from_path(filepath, ContentType)
|
ContentID = self.contentid_from_path(filepath, ContentType)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import sqlite3 as sqlite
|
with closing(self.device_database_connection()) as connection:
|
||||||
with closing(sqlite.connect(self.device_database_path())) 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()
|
cursor = connection.cursor()
|
||||||
t = (ContentID,)
|
t = (ContentID,)
|
||||||
cursor.execute('select ImageId from Content where BookID is Null and ContentID = ?', t)
|
cursor.execute('select ImageId from Content where BookID is Null and ContentID = ?', t)
|
||||||
result = cursor.fetchone()
|
try:
|
||||||
|
result = cursor.next()
|
||||||
if result is None:
|
ImageID = result[0]
|
||||||
|
except StopIteration:
|
||||||
ImageID = self.imageid_from_contentid(ContentID)
|
ImageID = self.imageid_from_contentid(ContentID)
|
||||||
debug_print("KoboTouch:_upload_cover - No rows exist in the database - generated ImageID='%s'" % ImageID)
|
debug_print("KoboTouch:_upload_cover - No rows exist in the database - generated ImageID='%s'" % ImageID)
|
||||||
else:
|
|
||||||
ImageID = result[0]
|
|
||||||
# debug_print("ImageId: ", result[0])
|
|
||||||
|
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
||||||
@ -2527,7 +2498,6 @@ class KOBOTOUCH(KOBO):
|
|||||||
|
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
cursor.execute(query, values)
|
cursor.execute(query, values)
|
||||||
connection.commit()
|
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
||||||
def set_filesize_in_device_database(self, connection, contentID, fpath):
|
def set_filesize_in_device_database(self, connection, contentID, fpath):
|
||||||
@ -2548,7 +2518,11 @@ class KOBOTOUCH(KOBO):
|
|||||||
|
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
cursor.execute(test_query, test_values)
|
cursor.execute(test_query, test_values)
|
||||||
result = cursor.fetchone()
|
try:
|
||||||
|
result = cursor.next()
|
||||||
|
except StopIteration:
|
||||||
|
result = None
|
||||||
|
|
||||||
if result is None:
|
if result is None:
|
||||||
if show_debug:
|
if show_debug:
|
||||||
debug_print(' Did not find a record - new book on device')
|
debug_print(' Did not find a record - new book on device')
|
||||||
@ -2562,7 +2536,6 @@ class KOBOTOUCH(KOBO):
|
|||||||
if show_debug:
|
if show_debug:
|
||||||
debug_print(' Size updated.')
|
debug_print(' Size updated.')
|
||||||
|
|
||||||
connection.commit()
|
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
||||||
# debug_print("KoboTouch:set_filesize_in_device_database - end")
|
# debug_print("KoboTouch:set_filesize_in_device_database - end")
|
||||||
@ -2600,7 +2573,6 @@ class KOBOTOUCH(KOBO):
|
|||||||
cursor.execute(update_query)
|
cursor.execute(update_query)
|
||||||
if self.has_activity_table():
|
if self.has_activity_table():
|
||||||
cursor.execute(delete_activity_query)
|
cursor.execute(delete_activity_query)
|
||||||
connection.commit()
|
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
||||||
debug_print("KoboTouch:delete_empty_bookshelves - end")
|
debug_print("KoboTouch:delete_empty_bookshelves - end")
|
||||||
@ -2647,7 +2619,11 @@ class KOBOTOUCH(KOBO):
|
|||||||
|
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
cursor.execute(test_query, test_values)
|
cursor.execute(test_query, test_values)
|
||||||
result = cursor.fetchone()
|
try:
|
||||||
|
result = cursor.next()
|
||||||
|
except StopIteration:
|
||||||
|
result = None
|
||||||
|
|
||||||
if result is None:
|
if result is None:
|
||||||
if show_debug:
|
if show_debug:
|
||||||
debug_print(' Did not find a record - adding')
|
debug_print(' Did not find a record - adding')
|
||||||
@ -2657,8 +2633,6 @@ class KOBOTOUCH(KOBO):
|
|||||||
debug_print(' Found a record - updating - result=', result)
|
debug_print(' Found a record - updating - result=', result)
|
||||||
cursor.execute(updatequery, update_values)
|
cursor.execute(updatequery, update_values)
|
||||||
|
|
||||||
connection.commit()
|
|
||||||
|
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
||||||
# debug_print("KoboTouch:set_bookshelf - end")
|
# debug_print("KoboTouch:set_bookshelf - end")
|
||||||
@ -2693,7 +2667,11 @@ class KOBOTOUCH(KOBO):
|
|||||||
|
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
cursor.execute(test_query, test_values)
|
cursor.execute(test_query, test_values)
|
||||||
result = cursor.fetchone()
|
try:
|
||||||
|
result = cursor.next()
|
||||||
|
except StopIteration:
|
||||||
|
result = None
|
||||||
|
|
||||||
if result is None:
|
if result is None:
|
||||||
if show_debug:
|
if show_debug:
|
||||||
debug_print(' Did not find a record - adding shelf "%s"' % bookshelf_name)
|
debug_print(' Did not find a record - adding shelf "%s"' % bookshelf_name)
|
||||||
@ -2702,7 +2680,6 @@ class KOBOTOUCH(KOBO):
|
|||||||
debug_print('KoboTouch:check_for_bookshelf - Shelf "%s" is deleted - undeleting. result[2]="%s"' % (bookshelf_name, unicode(result[2])))
|
debug_print('KoboTouch:check_for_bookshelf - Shelf "%s" is deleted - undeleting. result[2]="%s"' % (bookshelf_name, unicode(result[2])))
|
||||||
cursor.execute(updatequery, test_values)
|
cursor.execute(updatequery, test_values)
|
||||||
|
|
||||||
connection.commit()
|
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
||||||
# Update the bookshelf list.
|
# Update the bookshelf list.
|
||||||
@ -2735,7 +2712,6 @@ class KOBOTOUCH(KOBO):
|
|||||||
debug_print('KoboTouch:remove_from_bookshelf values=', values)
|
debug_print('KoboTouch:remove_from_bookshelf values=', values)
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
cursor.execute(query, values)
|
cursor.execute(query, values)
|
||||||
connection.commit()
|
|
||||||
cursor.close()
|
cursor.close()
|
||||||
|
|
||||||
debug_print("KoboTouch:remove_from_bookshelf - end")
|
debug_print("KoboTouch:remove_from_bookshelf - end")
|
||||||
@ -2776,9 +2752,8 @@ class KOBOTOUCH(KOBO):
|
|||||||
except:
|
except:
|
||||||
debug_print(' Database Exception: Unable to set series info')
|
debug_print(' Database Exception: Unable to set series info')
|
||||||
raise
|
raise
|
||||||
else:
|
finally:
|
||||||
connection.commit()
|
cursor.close()
|
||||||
cursor.close()
|
|
||||||
|
|
||||||
if show_debug:
|
if show_debug:
|
||||||
debug_print("KoboTouch:set_series - end")
|
debug_print("KoboTouch:set_series - end")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user