Add account setup stuff

This commit is contained in:
Florian Bach 2021-09-20 15:05:07 +02:00
parent 4f5f22a63d
commit 1107fe4214
3 changed files with 173 additions and 27 deletions

View File

@ -17,14 +17,15 @@ import subprocess
from calibre.utils.config import config_dir # type: ignore from calibre.utils.config import config_dir # type: ignore
from calibre.constants import iswindows, isosx # type: ignore from calibre.constants import iswindows, isosx # type: ignore
from calibre.gui2 import (question_dialog, error_dialog, info_dialog, choose_save_file) # type: ignore
class DeACSM(FileTypePlugin): class DeACSM(FileTypePlugin):
name = PLUGIN_NAME name = PLUGIN_NAME
description = "Takes an Adobe ACSM file and converts that into a useable EPUB file" description = "Takes an Adobe ACSM file and converts that into a useable EPUB file."
supported_platforms = ['linux'] supported_platforms = ['linux']
author = "Leseratte10" author = "Leseratte10 (Plugin), Grégory Soutadé (libgourou)"
version = PLUGIN_VERSION_TUPLE version = PLUGIN_VERSION_TUPLE
minimum_calibre_version = (5, 0, 0) minimum_calibre_version = (5, 0, 0)
file_types = set(['acsm']) file_types = set(['acsm'])
@ -34,14 +35,7 @@ class DeACSM(FileTypePlugin):
def initialize(self): def initialize(self):
""" """
Dynamic modules can't be imported/loaded from a zipfile. On initialization, make sure the libgourou code is present for compilation.
So this routine will extract the appropriate
library for the target OS and copy it to the 'alfcrypto' subdirectory of
calibre's configuration directory. That 'alfcrypto' directory is then
inserted into the syspath (as the very first entry) in the run function
so the CDLL stuff will work in the alfcrypto.py script.
The extraction only happens once per version of the plugin
Also perform upgrade of preferences once per version
""" """
try: try:
self.pluginsdir = os.path.join(config_dir,"plugins") self.pluginsdir = os.path.join(config_dir,"plugins")
@ -127,11 +121,15 @@ class DeACSM(FileTypePlugin):
print(ret) print(ret)
if not (os.path.exists(outputname)):
error_dialog(None, "ACSM->EPUB failed", "Could not convert ACSM to EPUB:", det_msg=str(ret), show=True, show_copy_button=True)
print("{0} v{1}: Failed, return original ...".format(PLUGIN_NAME, PLUGIN_VERSION))
return path_to_ebook
return outputname return outputname
print("{0} v{1}: Failed, return original ...".format(PLUGIN_NAME, PLUGIN_VERSION))
return path_to_ebook

View File

@ -3,11 +3,14 @@
# pyright: reportUndefinedVariable=false # pyright: reportUndefinedVariable=false
import os, glob, shutil, tarfile, subprocess, time import os, glob, shutil, tarfile, subprocess, time, tempfile, datetime
from lxml import etree
from PyQt5.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit, from PyQt5.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit,
QGroupBox, QPushButton, QListWidget, QListWidgetItem, QGroupBox, QPushButton, QListWidget, QListWidgetItem, QInputDialog,
QAbstractItemView, QIcon, QDialog, QDialogButtonBox, QUrl) QLineEdit, QAbstractItemView, QIcon, QDialog, QDialogButtonBox, QUrl)
from PyQt5 import Qt as QtGui from PyQt5 import Qt as QtGui
from zipfile import ZipFile from zipfile import ZipFile
@ -46,24 +49,168 @@ class ConfigWidget(QWidget):
layout.addWidget(self.button_compile) layout.addWidget(self.button_compile)
ua_group_box = QGroupBox(_('Path to account:'), self) ua_group_box = QGroupBox(_('Account information:'), self)
layout.addWidget(ua_group_box) layout.addWidget(ua_group_box)
ua_group_box_layout = QVBoxLayout() ua_group_box_layout = QVBoxLayout()
ua_group_box.setLayout(ua_group_box_layout) ua_group_box.setLayout(ua_group_box_layout)
self.txtboxUA = QtGui.QLineEdit(self) #self.txtboxUA = QtGui.QLineEdit(self)
self.txtboxUA.setToolTip(_("Enter folder path to account data")) #self.txtboxUA.setToolTip(_("Enter folder path to account data"))
self.txtboxUA.setText(self.tempdeacsmprefs['path_to_account_data']) #self.txtboxUA.setText(self.tempdeacsmprefs['path_to_account_data'])
ua_group_box_layout.addWidget(self.txtboxUA) #ua_group_box_layout.addWidget(self.txtboxUA)
info_string, activated = self.get_account_info()
self.lblAccInfo = QtGui.QLabel(self)
self.lblAccInfo.setText(info_string)
ua_group_box_layout.addWidget(self.lblAccInfo)
if not activated:
self.button_link_account = QtGui.QPushButton(self)
self.button_link_account.setText(_("Link to ADE account"))
self.button_link_account.clicked.connect(self.link_account)
ua_group_box_layout.addWidget(self.button_link_account)
self.button_export_key = QtGui.QPushButton(self) self.button_export_key = QtGui.QPushButton(self)
self.button_export_key.setText(_("Export account key")) self.button_export_key.setText(_("Export account encryption key"))
self.button_export_key.clicked.connect(self.export_key) self.button_export_key.clicked.connect(self.export_key)
self.button_export_key.setEnabled(activated)
ua_group_box_layout.addWidget(self.button_export_key) ua_group_box_layout.addWidget(self.button_export_key)
self.button_export_activation = QtGui.QPushButton(self)
self.button_export_activation.setText(_("Export account activation data"))
self.button_export_activation.clicked.connect(self.export_activation)
self.button_export_activation.setEnabled(activated)
ua_group_box_layout.addWidget(self.button_export_activation)
self.resize(self.sizeHint()) self.resize(self.sizeHint())
def get_account_info(self):
activation_xml_path = os.path.join(self.deacsmprefs["path_to_account_data"], "activation.xml")
device_xml_path = os.path.join(self.deacsmprefs["path_to_account_data"], "device.xml")
container = None
try:
container = etree.parse(activation_xml_path)
containerdev = etree.parse(device_xml_path)
except (FileNotFoundError, OSError) as e:
return "Not authorized for any ADE ID", False
try:
adeptNS = lambda tag: '{%s}%s' % ('http://ns.adobe.com/adept', tag)
usernameXML = container.find(adeptNS("credentials")).find(adeptNS("username"))
devicenameXML = containerdev.find(adeptNS("deviceName"))
ade_type = usernameXML.get('method', "unknown")
ade_mail = usernameXML.text
ade_device_name = devicenameXML.text
return "Authorized with ADE ID ("+ade_type+") " + ade_mail + "\non device " + ade_device_name, True
except:
return "ADE authorization seems to be corrupted", False
def export_activation(self):
pluginsdir = os.path.join(config_dir,"plugins")
maindir = os.path.join(pluginsdir,"DeACSM")
filters = [("ZIP", ["zip"])]
filename = choose_save_file(self, "Export ADE activation files", _("Export ADE activation files"), filters, all_files=False)
print("would export to " + filename)
try:
with ZipFile(filename, 'w') as zipfile:
zipfile.write(os.path.join(self.deacsmprefs["path_to_account_data"], "device.xml"), "device.xml")
zipfile.write(os.path.join(self.deacsmprefs["path_to_account_data"], "activation.xml"), "activation.xml")
zipfile.write(os.path.join(self.deacsmprefs["path_to_account_data"], "devicesalt"), "devicesalt")
except:
return error_dialog(None, "Export failed", "Export failed.", show=True, show_copy_button=False)
def link_account(self):
pluginsdir = os.path.join(config_dir,"plugins")
maindir = os.path.join(pluginsdir,"DeACSM")
verdir = os.path.join(maindir,PLUGIN_VERSION)
mail, ok = QInputDialog.getText(self, "Authorizing ADE account", "Please enter mail address")
passwd, ok = QInputDialog.getText(self, "Authorizing ADE account", "Please enter password", QLineEdit.Password)
import calibre_plugins.deacsm.prefs as prefs # type: ignore
deacsmprefs = prefs.DeACSM_Prefs()
output_dir = tempfile.mkdtemp()
my_env = os.environ.copy()
my_env["LD_LIBRARY_PATH"] = ".:" + my_env["LD_LIBRARY_PATH"]
# Make backup ...
if (os.path.exists(os.path.join(deacsmprefs["path_to_account_data"], "device.xml")) or
os.path.exists(os.path.join(deacsmprefs["path_to_account_data"], "activation.xml")) or
os.path.exists(os.path.join(deacsmprefs["path_to_account_data"], "devicesalt")) ):
try:
currenttime = datetime.datetime.now()
backup_file = "backup_" + str(currenttime.year) + "-" + str(currenttime.month) + "-" + str(currenttime.day) + "_"
backup_file += str(currenttime.hour) + "-" + str(currenttime.minute) + "-" + str(currenttime.second) + ".zip"
with ZipFile(os.path.join(deacsmprefs["path_to_account_data"], backup_file), 'w') as zipfile:
try:
zipfile.write(os.path.join(self.deacsmprefs["path_to_account_data"], "device.xml"), "device.xml")
except:
pass
try:
zipfile.write(os.path.join(self.deacsmprefs["path_to_account_data"], "activation.xml"), "activation.xml")
except:
pass
try:
zipfile.write(os.path.join(self.deacsmprefs["path_to_account_data"], "devicesalt"), "devicesalt")
except:
pass
except:
raise
ret = None
try:
ret = subprocess.run([os.path.join(verdir, "adept_activate"),
"-u", mail,
"-p", passwd,
"-O", output_dir,
"-v"
], capture_output=True, shell=False, cwd=verdir, env=my_env)
print(ret)
except:
return error_dialog(None, "ADE activation failed", "ADE activation failed", det_msg=str(ret), show=True, show_copy_button=True)
try:
shutil.copy(os.path.join(output_dir, "device.xml"), os.path.join(deacsmprefs["path_to_account_data"], "device.xml"))
shutil.copy(os.path.join(output_dir, "activation.xml"), os.path.join(deacsmprefs["path_to_account_data"], "activation.xml"))
shutil.copy(os.path.join(output_dir, "devicesalt"), os.path.join(deacsmprefs["path_to_account_data"], "devicesalt"))
shutil.rmtree(output_dir)
info_dialog(None, "Done", "Authorization successful!", show=True, show_copy_button=False)
except IndexError:
return error_dialog(None, "Authorization failed", "Authorization failed", show=True, det_msg=str(ret), show_copy_button=True)
# update display
info_string, activated = self.get_account_info()
self.lblAccInfo.setText(info_string)
self.button_link_account.setEnabled(False)
self.button_export_key.setEnabled(True)
self.button_export_activation.setEnabled(True)
def export_key(self): def export_key(self):
pluginsdir = os.path.join(config_dir,"plugins") pluginsdir = os.path.join(config_dir,"plugins")
maindir = os.path.join(pluginsdir,"DeACSM") maindir = os.path.join(pluginsdir,"DeACSM")
@ -104,6 +251,8 @@ class ConfigWidget(QWidget):
"-e" "-e"
], capture_output=True, shell=False, cwd=verdir, env=my_env) ], capture_output=True, shell=False, cwd=verdir, env=my_env)
print(ret)
except: except:
return error_dialog(None, "Export failed", "Export failed.", det_msg=str(ret), show=True, show_copy_button=True) return error_dialog(None, "Export failed", "Export failed.", det_msg=str(ret), show=True, show_copy_button=True)
@ -112,10 +261,10 @@ class ConfigWidget(QWidget):
shutil.move(new_key, filename) shutil.move(new_key, filename)
info_dialog(None, "Done", "Key successfully exported", show=True, show_copy_button=False) info_dialog(None, "Done", "Key successfully exported", show=True, show_copy_button=False)
except IndexError: except IndexError:
return error_dialog(None, "Export failed", "Export failed.", det_msg=str(ret), show=True, show_copy_button=True) return error_dialog(None, "Export failed", "Export failed.", show=True, show_copy_button=True)
print(ret)
@ -147,7 +296,7 @@ class ConfigWidget(QWidget):
print(ret2) print(ret2)
try: try:
shutil.copy(os.path.join(verdir, "libgourou", "AAlibgourou.so"), verdir) shutil.copy(os.path.join(verdir, "libgourou", "libgourou.so"), verdir)
shutil.copy(os.path.join(verdir, "libgourou", "utils", "acsmdownloader"), verdir) shutil.copy(os.path.join(verdir, "libgourou", "utils", "acsmdownloader"), verdir)
shutil.copy(os.path.join(verdir, "libgourou", "utils", "adept_activate"), verdir) shutil.copy(os.path.join(verdir, "libgourou", "utils", "adept_activate"), verdir)
info_dialog(None, "Done", "Compiling successful", show=True, show_copy_button=False) info_dialog(None, "Done", "Compiling successful", show=True, show_copy_button=False)
@ -158,7 +307,7 @@ class ConfigWidget(QWidget):
def save_settings(self): def save_settings(self):
self.deacsmprefs.set('path_to_account_data', self.txtboxUA.text()) #self.deacsmprefs.set('path_to_account_data', self.txtboxUA.text())
self.deacsmprefs.writeprefs() self.deacsmprefs.writeprefs()
def load_resource(self, name): def load_resource(self, name):

View File

@ -9,7 +9,6 @@ import traceback
from calibre.utils.config import JSONConfig, config_dir # type: ignore from calibre.utils.config import JSONConfig, config_dir # type: ignore
from calibre_plugins.deacsm.__init__ import PLUGIN_NAME # type: ignore from calibre_plugins.deacsm.__init__ import PLUGIN_NAME # type: ignore
from calibre.constants import isosx, islinux # type: ignore
class DeACSM_Prefs(): class DeACSM_Prefs():