add support for linux via device serials and reading from device

pull/37/head
Norbert Preining 9 years ago
parent 2e96db6cdc
commit f97bc078db

@ -29,7 +29,7 @@ class ObokDeDRMAction(InterfaceActionBase):
name = PLUGIN_NAME name = PLUGIN_NAME
description = PLUGIN_DESCRIPTION description = PLUGIN_DESCRIPTION
supported_platforms = ['windows', 'osx'] supported_platforms = ['windows', 'osx', 'linux' ]
author = PLUGIN_AUTHORS author = PLUGIN_AUTHORS
version = PLUGIN_VERSION_TUPLE version = PLUGIN_VERSION_TUPLE
minimum_calibre_version = (1, 0, 0) minimum_calibre_version = (1, 0, 0)

@ -79,7 +79,7 @@ class InterfacePluginAction(InterfaceAction):
print ('Running {}'.format(PLUGIN_NAME + ' v' + PLUGIN_VERSION)) print ('Running {}'.format(PLUGIN_NAME + ' v' + PLUGIN_VERSION))
# Get the Kobo Library object (obok v3.01) # Get the Kobo Library object (obok v3.01)
self.library = KoboLibrary() self.library = KoboLibrary(cfg['kobo_serials'])
# Get a list of Kobo titles # Get a list of Kobo titles
books = self.build_book_list() books = self.build_book_list()

@ -3,15 +3,23 @@ from __future__ import (unicode_literals, division, absolute_import,
print_function) print_function)
try: try:
from PyQt5.Qt import (QWidget, QLabel, QVBoxLayout, QHBoxLayout, QComboBox) from PyQt5.Qt import (Qt, QGroupBox, QListWidget, QLineEdit, QDialogButtonBox, QWidget, QLabel, QDialog, QVBoxLayout, QAbstractItemView, QIcon, QHBoxLayout, QComboBox, QListWidgetItem)
except ImportError: except ImportError:
from PyQt4.Qt import (QWidget, QLabel, QVBoxLayout, QHBoxLayout, QComboBox) from PyQt4.Qt import (Qt, QGroupBox, QListWidget, QLineEdit, QDialogButtonBox, QWidget, QLabel, QDialog, QVBoxLayout, QAbstractItemView, QIcon, QHBoxLayout, QComboBox, QListWidgetItem)
try:
from PyQt5 import Qt as QtGui
except ImportError:
from PyQt4 import QtGui
from calibre.gui2 import (error_dialog, question_dialog, info_dialog, open_url)
from calibre.utils.config import JSONConfig, config_dir from calibre.utils.config import JSONConfig, config_dir
plugin_prefs = JSONConfig('plugins/obok_dedrm_prefs') plugin_prefs = JSONConfig('plugins/obok_dedrm_prefs')
plugin_prefs.defaults['finding_homes_for_formats'] = 'Ask' plugin_prefs.defaults['finding_homes_for_formats'] = 'Ask'
plugin_prefs.defaults['kobo_serials'] = []
from calibre_plugins.dedrm.__init__ import PLUGIN_NAME, PLUGIN_VERSION
from calibre_plugins.obok_dedrm.utilities import (debug_print) from calibre_plugins.obok_dedrm.utilities import (debug_print)
try: try:
debug_print("obok::config.py - loading translations") debug_print("obok::config.py - loading translations")
@ -26,7 +34,10 @@ class ConfigWidget(QWidget):
self.plugin_action = plugin_action self.plugin_action = plugin_action
layout = QVBoxLayout(self) layout = QVBoxLayout(self)
self.setLayout(layout) self.setLayout(layout)
# copy of preferences
self.tmpserials = plugin_prefs['kobo_serials']
combo_label = QLabel(_('When should Obok try to insert EPUBs into existing calibre entries?'), self) combo_label = QLabel(_('When should Obok try to insert EPUBs into existing calibre entries?'), self)
layout.addWidget(combo_label) layout.addWidget(combo_label)
self.find_homes = QComboBox() self.find_homes = QComboBox()
@ -35,6 +46,178 @@ class ConfigWidget(QWidget):
self.find_homes.addItems([_('Ask'), _('Always'), _('Never')]) self.find_homes.addItems([_('Ask'), _('Always'), _('Never')])
index = self.find_homes.findText(plugin_prefs['finding_homes_for_formats']) index = self.find_homes.findText(plugin_prefs['finding_homes_for_formats'])
self.find_homes.setCurrentIndex(index) self.find_homes.setCurrentIndex(index)
self.serials_button = QtGui.QPushButton(self)
self.serials_button.setToolTip(_(u"Click to manage Kobo serial numbers for Kobo ebooks"))
self.serials_button.setText(u"Kobo devices serials")
self.serials_button.clicked.connect(self.edit_serials)
layout.addWidget(self.serials_button)
def edit_serials(self):
d = ManageKeysDialog(self,u"Kobo device serial numbers",self.tmpserials, AddSerialDialog)
d.exec_()
def save_settings(self): def save_settings(self):
plugin_prefs['finding_homes_for_formats'] = unicode(self.find_homes.currentText()) plugin_prefs['finding_homes_for_formats'] = unicode(self.find_homes.currentText())
plugin_prefs['kobo_serials'] = self.tmpserials
class ManageKeysDialog(QDialog):
def __init__(self, parent, key_type_name, plugin_keys, create_key, keyfile_ext = u""):
QDialog.__init__(self,parent)
self.parent = parent
self.key_type_name = key_type_name
self.plugin_keys = plugin_keys
self.create_key = create_key
self.keyfile_ext = keyfile_ext
self.json_file = (keyfile_ext == u"k4i")
self.setWindowTitle("{0} {1}: Manage {2}s".format(PLUGIN_NAME, PLUGIN_VERSION, self.key_type_name))
# Start Qt Gui dialog layout
layout = QVBoxLayout(self)
self.setLayout(layout)
keys_group_box = QGroupBox(_(u"{0}s".format(self.key_type_name)), self)
layout.addWidget(keys_group_box)
keys_group_box_layout = QHBoxLayout()
keys_group_box.setLayout(keys_group_box_layout)
self.listy = QListWidget(self)
self.listy.setToolTip(u"{0}s that will be used to decrypt ebooks".format(self.key_type_name))
self.listy.setSelectionMode(QAbstractItemView.SingleSelection)
self.populate_list()
keys_group_box_layout.addWidget(self.listy)
button_layout = QVBoxLayout()
keys_group_box_layout.addLayout(button_layout)
self._add_key_button = QtGui.QToolButton(self)
self._add_key_button.setIcon(QIcon(I('plus.png')))
self._add_key_button.setToolTip(u"Create new {0}".format(self.key_type_name))
self._add_key_button.clicked.connect(self.add_key)
button_layout.addWidget(self._add_key_button)
self._delete_key_button = QtGui.QToolButton(self)
self._delete_key_button.setToolTip(_(u"Delete highlighted key"))
self._delete_key_button.setIcon(QIcon(I('list_remove.png')))
self._delete_key_button.clicked.connect(self.delete_key)
button_layout.addWidget(self._delete_key_button)
spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
button_layout.addItem(spacerItem)
layout.addSpacing(5)
migrate_layout = QHBoxLayout()
layout.addLayout(migrate_layout)
migrate_layout.addStretch()
self.button_box = QDialogButtonBox(QDialogButtonBox.Close)
self.button_box.rejected.connect(self.close)
migrate_layout.addWidget(self.button_box)
self.resize(self.sizeHint())
def populate_list(self):
if type(self.plugin_keys) == dict:
for key in self.plugin_keys.keys():
self.listy.addItem(QListWidgetItem(key))
else:
for key in self.plugin_keys:
self.listy.addItem(QListWidgetItem(key))
def add_key(self):
d = self.create_key(self)
d.exec_()
if d.result() != d.Accepted:
# New key generation cancelled.
return
new_key_value = d.key_value
if new_key_value in self.plugin_keys:
info_dialog(None, "{0} {1}: Duplicate {2}".format(PLUGIN_NAME, PLUGIN_VERSION,self.key_type_name),
u"This {0} is already in the list of {0}s has not been added.".format(self.key_type_name), show=True)
return
self.plugin_keys.append(d.key_value)
self.listy.clear()
self.populate_list()
def rename_key(self):
if not self.listy.currentItem():
errmsg = u"No {0} selected to rename. Highlight a keyfile first.".format(self.key_type_name)
r = error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION),
_(errmsg), show=True, show_copy_button=False)
return
d = RenameKeyDialog(self)
d.exec_()
if d.result() != d.Accepted:
# rename cancelled or moot.
return
keyname = unicode(self.listy.currentItem().text())
if not question_dialog(self, "{0} {1}: Confirm Rename".format(PLUGIN_NAME, PLUGIN_VERSION), u"Do you really want to rename the {2} named <strong>{0}</strong> to <strong>{1}</strong>?".format(keyname,d.key_name,self.key_type_name), show_copy_button=False, default_yes=False):
return
self.plugin_keys[d.key_name] = self.plugin_keys[keyname]
del self.plugin_keys[keyname]
self.listy.clear()
self.populate_list()
def delete_key(self):
if not self.listy.currentItem():
return
keyname = unicode(self.listy.currentItem().text())
if not question_dialog(self, "{0} {1}: Confirm Delete".format(PLUGIN_NAME, PLUGIN_VERSION), u"Do you really want to delete the {1} <strong>{0}</strong>?".format(keyname, self.key_type_name), show_copy_button=False, default_yes=False):
return
self.plugin_keys.remove(keyname)
self.listy.clear()
self.populate_list()
class AddSerialDialog(QDialog):
def __init__(self, parent=None,):
QDialog.__init__(self, parent)
self.parent = parent
self.setWindowTitle(u"{0} {1}: Add New eInk Kobo Serial Number".format(PLUGIN_NAME, PLUGIN_VERSION))
layout = QVBoxLayout(self)
self.setLayout(layout)
data_group_box = QGroupBox(u"", self)
layout.addWidget(data_group_box)
data_group_box_layout = QVBoxLayout()
data_group_box.setLayout(data_group_box_layout)
key_group = QHBoxLayout()
data_group_box_layout.addLayout(key_group)
key_group.addWidget(QLabel(u"EInk Kobo Serial Number:", self))
self.key_ledit = QLineEdit("", self)
self.key_ledit.setToolTip(u"Enter an eInk Kobo serial number. EInk Kobo serial numbers are 13 characters long and usually start with a 'N'. Kobo Serial Numbers are case-sensitive, so be sure to enter the upper and lower case letters unchanged.")
key_group.addWidget(self.key_ledit)
self.button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
self.button_box.accepted.connect(self.accept)
self.button_box.rejected.connect(self.reject)
layout.addWidget(self.button_box)
self.resize(self.sizeHint())
@property
def key_name(self):
return unicode(self.key_ledit.text()).strip()
@property
def key_value(self):
return unicode(self.key_ledit.text()).strip()
def accept(self):
if len(self.key_name) == 0 or self.key_name.isspace():
errmsg = u"Please enter an eInk Kindle Serial Number or click Cancel in the dialog."
return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
if len(self.key_name) != 13:
errmsg = u"EInk Kobo Serial Numbers must be 13 characters long. This is {0:d} characters long.".format(len(self.key_name))
return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
QDialog.accept(self)

@ -244,7 +244,7 @@ class KoboLibrary(object):
written by the Kobo Desktop Edition application, including the list written by the Kobo Desktop Edition application, including the list
of books, their titles, and the user's encryption key(s).""" of books, their titles, and the user's encryption key(s)."""
def __init__ (self): def __init__ (self, serials = []):
print u"Obok v{0}\nCopyright © 2012-2015 Physisticated et al.".format(__version__) print u"Obok v{0}\nCopyright © 2012-2015 Physisticated et al.".format(__version__)
if sys.platform.startswith('win'): if sys.platform.startswith('win'):
if sys.getwindowsversion().major > 5: if sys.getwindowsversion().major > 5:
@ -254,13 +254,20 @@ class KoboLibrary(object):
self.kobodir = os.path.join(self.kobodir, 'Kobo', 'Kobo Desktop Edition') self.kobodir = os.path.join(self.kobodir, 'Kobo', 'Kobo Desktop Edition')
elif sys.platform.startswith('darwin'): elif sys.platform.startswith('darwin'):
self.kobodir = os.path.join(os.environ['HOME'], 'Library', 'Application Support', 'Kobo', 'Kobo Desktop Edition') self.kobodir = os.path.join(os.environ['HOME'], 'Library', 'Application Support', 'Kobo', 'Kobo Desktop Edition')
elif sys.platform.startswith('linux'):
# TODO TODO TODO needs change - fixed path to mount point
self.kobodir = '/media/norbert/KOBOeReader/.kobo'
self.bookdir = os.path.join(self.kobodir, 'kepub') self.bookdir = os.path.join(self.kobodir, 'kepub')
kobodb = os.path.join(self.kobodir, 'Kobo.sqlite') if sys.platform.startswith('linux'):
kobodb = os.path.join(self.kobodir, 'KoboReader.sqlite')
else:
kobodb = os.path.join(self.kobodir, 'Kobo.sqlite')
self.__sqlite = sqlite3.connect(kobodb) self.__sqlite = sqlite3.connect(kobodb)
self.__cursor = self.__sqlite.cursor() self.__cursor = self.__sqlite.cursor()
self._userkeys = [] self._userkeys = []
self._books = [] self._books = []
self._volumeID = [] self._volumeID = []
self._serials = serials
def close (self): def close (self):
"""Closes the database used by the library.""" """Closes the database used by the library."""
@ -319,6 +326,9 @@ class KoboLibrary(object):
for m in matches: for m in matches:
# print "m:",m[0] # print "m:",m[0]
macaddrs.append(m[0].upper()) macaddrs.append(m[0].upper())
elif sys.platform.startswith('linux'):
macaddrs.extend(self._serials)
return macaddrs return macaddrs
def __getuserids (self): def __getuserids (self):
@ -486,7 +496,7 @@ def cli_main():
lib = KoboLibrary() lib = KoboLibrary()
for i, book in enumerate(lib.books): for i, book in enumerate(lib.books):
print ('%d: %s' % (i + 1, book.title)) print ('%d: %s' % (i + 1, book.title)).encode('ascii', 'ignore')
num_string = raw_input("Convert book number... ") num_string = raw_input("Convert book number... ")
try: try:

Loading…
Cancel
Save