summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNoDRM <[email protected]>2021-12-29 09:26:29 +0100
committerNoDRM <[email protected]>2021-12-29 09:26:29 +0100
commitdbf4b5402614d2f714559f91e7b7d414efa892a5 (patch)
tree99ac8e93dbc2c7dfe77746735c1851280e37c5ba
parent9c40b3ce5a0e2d3f0c74e6a816947a81778a3c4b (diff)
Begin work on standalone version
Now the plugin ZIP file (DeDRM_plugin.zip) can be run with a normal Python interpreter as if it were a Python file (try `python3 DeDRM_plugin.zip --help`). This way I can begin building a standalone version (that can run without Calibre) without having to duplicate a ton of code.
-rw-r--r--DeDRM_plugin/__init__.py81
-rw-r--r--DeDRM_plugin/__main__.py23
-rwxr-xr-xDeDRM_plugin/config.py32
-rwxr-xr-xDeDRM_plugin/erdr2pml.py35
-rw-r--r--DeDRM_plugin/genbook.py23
-rw-r--r--DeDRM_plugin/k4mobidedrm.py28
-rw-r--r--DeDRM_plugin/kfxdedrm.py12
-rwxr-xr-xDeDRM_plugin/prefs.py12
-rw-r--r--DeDRM_plugin/scriptinterface.py18
-rw-r--r--DeDRM_plugin/standalone/__init__.py217
-rw-r--r--DeDRM_plugin/topazextract.py27
-rw-r--r--DeDRM_plugin/utilities.py7
-rw-r--r--DeDRM_plugin/zipfix.py13
13 files changed, 379 insertions, 149 deletions
diff --git a/DeDRM_plugin/__init__.py b/DeDRM_plugin/__init__.py
index ab9bcf7..80f7f28 100644
--- a/DeDRM_plugin/__init__.py
+++ b/DeDRM_plugin/__init__.py
@@ -97,11 +97,19 @@ import sys, os
import time
import traceback
+# Calibre stuff - so we can import from our ZIP without absolute module name
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+
class DeDRMError(Exception):
pass
-from calibre.customize import FileTypePlugin
+try:
+ from calibre.customize import FileTypePlugin
+except:
+ # Allow import without Calibre.
+ class FileTypePlugin:
+ pass
try:
from calibre.constants import iswindows, isosx
@@ -109,7 +117,10 @@ except:
iswindows = sys.platform.startswith('win')
isosx = sys.platform.startswith('darwin')
-from calibre.utils.config import config_dir
+try:
+ from calibre.utils.config import config_dir
+except:
+ config_dir = ""
# Wrap a stream so that output gets flushed immediately
@@ -150,6 +161,10 @@ class DeDRM(FileTypePlugin):
priority = 600
+ def cli_main(self, data):
+ from standalone import main
+ main(data)
+
def initialize(self):
"""
Dynamic modules can't be imported/loaded from a zipfile.
@@ -216,7 +231,7 @@ class DeDRM(FileTypePlugin):
postProcessStart = time.time()
try:
- import calibre_plugins.dedrm.prefs as prefs
+ import prefs
dedrmprefs = prefs.DeDRM_Prefs()
if dedrmprefs["deobfuscate_fonts"] is True:
@@ -224,7 +239,7 @@ class DeDRM(FileTypePlugin):
path_to_ebook = self.checkFonts(path_to_ebook) or path_to_ebook
if dedrmprefs["remove_watermarks"] is True:
- import calibre_plugins.dedrm.epubwatermark as watermark
+ import epubwatermark as watermark
# Remove Tolino's CDP watermark file
path_to_ebook = watermark.removeCDPwatermark(self, path_to_ebook) or path_to_ebook
@@ -251,7 +266,7 @@ class DeDRM(FileTypePlugin):
# It checks if there's fonts that need to be deobfuscated
try:
- import calibre_plugins.dedrm.epubfontdecrypt as epubfontdecrypt
+ import epubfontdecrypt
output = self.temporary_file(".epub").name
ret = epubfontdecrypt.decryptFontsBook(path_to_ebook, output)
@@ -272,7 +287,7 @@ class DeDRM(FileTypePlugin):
def ePubDecrypt(self,path_to_ebook):
# Create a TemporaryPersistent file to work with.
# Check original epub archive for zip errors.
- import calibre_plugins.dedrm.zipfix as zipfix
+ import zipfix
inf = self.temporary_file(".epub")
try:
@@ -284,12 +299,12 @@ class DeDRM(FileTypePlugin):
raise
# import the decryption keys
- import calibre_plugins.dedrm.prefs as prefs
+ import prefs
dedrmprefs = prefs.DeDRM_Prefs()
# import the LCP handler
- import calibre_plugins.dedrm.lcpdedrm as lcpdedrm
+ import lcpdedrm
if (lcpdedrm.isLCPbook(path_to_ebook)):
try:
@@ -304,7 +319,7 @@ class DeDRM(FileTypePlugin):
# Not an LCP book, do the normal EPUB (Adobe) handling.
# import the Adobe ePub handler
- import calibre_plugins.dedrm.ineptepub as ineptepub
+ import ineptepub
if ineptepub.adeptBook(inf.name):
@@ -345,11 +360,11 @@ class DeDRM(FileTypePlugin):
try:
if iswindows or isosx:
- from calibre_plugins.dedrm.ignoblekeyNookStudy import nookkeys
+ from ignoblekeyNookStudy import nookkeys
defaultkeys_study = nookkeys()
else: # linux
- from .wineutils import WineGetKeys
+ from wineutils import WineGetKeys
scriptpath = os.path.join(self.alfdir,"ignoblekeyNookStudy.py")
defaultkeys_study = WineGetKeys(scriptpath, ".b64",dedrmprefs['adobewineprefix'])
@@ -365,7 +380,7 @@ class DeDRM(FileTypePlugin):
if iswindows:
# That's a Windows store app, it won't run on Linux or MacOS anyways.
# No need to waste time running Wine.
- from calibre_plugins.dedrm.ignoblekeyWindowsStore import dump_keys as dump_nook_keys
+ from ignoblekeyWindowsStore import dump_keys as dump_nook_keys
defaultkeys_store = dump_nook_keys(False)
except:
@@ -377,7 +392,7 @@ class DeDRM(FileTypePlugin):
try:
if iswindows:
# Right now this is only implemented for Windows. MacOS support still needs to be added.
- from calibre_plugins.dedrm.adobekey_get_passhash import passhash_keys
+ from adobekey_get_passhash import passhash_keys
defaultkeys_ade, names = passhash_keys()
if isosx:
print("{0} v{1}: Dumping ADE PassHash data is not yet supported on MacOS.".format(PLUGIN_NAME, PLUGIN_VERSION))
@@ -522,11 +537,11 @@ class DeDRM(FileTypePlugin):
try:
if iswindows or isosx:
- from calibre_plugins.dedrm.adobekey import adeptkeys
+ from adobekey import adeptkeys
defaultkeys, defaultnames = adeptkeys()
else: # linux
- from .wineutils import WineGetKeys
+ from wineutils import WineGetKeys
scriptpath = os.path.join(self.alfdir,"adobekey.py")
defaultkeys, defaultnames = WineGetKeys(scriptpath, ".der",dedrmprefs['adobewineprefix'])
@@ -546,7 +561,7 @@ class DeDRM(FileTypePlugin):
# Check for DeACSM keys:
try:
- from calibre_plugins.dedrm.config import checkForDeACSMkeys
+ from config import checkForDeACSMkeys
newkey, newname = checkForDeACSMkeys()
@@ -613,8 +628,8 @@ class DeDRM(FileTypePlugin):
def PDFIneptDecrypt(self, path_to_ebook):
# Sub function to prevent PDFDecrypt from becoming too large ...
- import calibre_plugins.dedrm.prefs as prefs
- import calibre_plugins.dedrm.ineptpdf as ineptpdf
+ import prefs
+ import ineptpdf
dedrmprefs = prefs.DeDRM_Prefs()
book_uuid = None
@@ -688,11 +703,11 @@ class DeDRM(FileTypePlugin):
try:
if iswindows or isosx:
- from calibre_plugins.dedrm.adobekey import adeptkeys
+ from adobekey import adeptkeys
defaultkeys, defaultnames = adeptkeys()
else: # linux
- from .wineutils import WineGetKeys
+ from wineutils import WineGetKeys
scriptpath = os.path.join(self.alfdir,"adobekey.py")
defaultkeys, defaultnames = WineGetKeys(scriptpath, ".der",dedrmprefs['adobewineprefix'])
@@ -712,7 +727,7 @@ class DeDRM(FileTypePlugin):
# Check for DeACSM keys:
try:
- from calibre_plugins.dedrm.config import checkForDeACSMkeys
+ from config import checkForDeACSMkeys
newkey, newname = checkForDeACSMkeys()
@@ -789,8 +804,8 @@ class DeDRM(FileTypePlugin):
def PDFStandardDecrypt(self, path_to_ebook):
# Sub function to prevent PDFDecrypt from becoming too large ...
- import calibre_plugins.dedrm.prefs as prefs
- import calibre_plugins.dedrm.ineptpdf as ineptpdf
+ import prefs
+ import ineptpdf
dedrmprefs = prefs.DeDRM_Prefs()
# Attempt to decrypt PDF with each encryption key (generated or provided).
@@ -836,9 +851,9 @@ class DeDRM(FileTypePlugin):
def PDFDecrypt(self,path_to_ebook):
- import calibre_plugins.dedrm.prefs as prefs
- import calibre_plugins.dedrm.ineptpdf as ineptpdf
- import calibre_plugins.dedrm.lcpdedrm as lcpdedrm
+ import prefs
+ import ineptpdf
+ import lcpdedrm
dedrmprefs = prefs.DeDRM_Prefs()
if (lcpdedrm.isLCPbook(path_to_ebook)):
@@ -881,8 +896,8 @@ class DeDRM(FileTypePlugin):
# Had to move this import here so the custom libs can be
# extracted to the appropriate places beforehand these routines
# look for them.
- import calibre_plugins.dedrm.prefs as prefs
- import calibre_plugins.dedrm.k4mobidedrm as k4mobidedrm
+ import prefs
+ import k4mobidedrm
dedrmprefs = prefs.DeDRM_Prefs()
pids = dedrmprefs['pids']
@@ -905,11 +920,11 @@ class DeDRM(FileTypePlugin):
try:
if iswindows or isosx:
- from calibre_plugins.dedrm.kindlekey import kindlekeys
+ from kindlekey import kindlekeys
defaultkeys = kindlekeys()
else: # linux
- from .wineutils import WineGetKeys
+ from wineutils import WineGetKeys
scriptpath = os.path.join(self.alfdir,"kindlekey.py")
defaultkeys = WineGetKeys(scriptpath, ".k4i",dedrmprefs['kindlewineprefix'])
@@ -949,8 +964,8 @@ class DeDRM(FileTypePlugin):
def eReaderDecrypt(self,path_to_ebook):
- import calibre_plugins.dedrm.prefs as prefs
- import calibre_plugins.dedrm.erdr2pml as erdr2pml
+ import prefs
+ import erdr2pml
dedrmprefs = prefs.DeDRM_Prefs()
# Attempt to decrypt epub with each encryption key (generated or provided).
@@ -1011,7 +1026,7 @@ class DeDRM(FileTypePlugin):
return True
def config_widget(self):
- import calibre_plugins.dedrm.config as config
+ import config
return config.ConfigWidget(self.plugin_path, self.alfdir)
def save_settings(self, config_widget):
diff --git a/DeDRM_plugin/__main__.py b/DeDRM_plugin/__main__.py
new file mode 100644
index 0000000..96b4217
--- /dev/null
+++ b/DeDRM_plugin/__main__.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+# __main__.py for DeDRM_plugin
+# (CLI interface without Calibre)
+# Copyright © 2021 NoDRM
+
+__license__ = 'GPL v3'
+__docformat__ = 'restructuredtext en'
+
+# For revision history see __init__.py
+
+"""
+Run DeDRM plugin without Calibre.
+"""
+
+# Import __init__.py from the standalone folder so we can have all the
+# standalone / non-Calibre code in that subfolder.
+
+import standalone.__init__ as mdata
+import sys
+
+mdata.main(sys.argv) \ No newline at end of file
diff --git a/DeDRM_plugin/config.py b/DeDRM_plugin/config.py
index 9a7c493..4cdb2ea 100755
--- a/DeDRM_plugin/config.py
+++ b/DeDRM_plugin/config.py
@@ -16,19 +16,23 @@ from PyQt5.Qt import (Qt, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QLineEdit,
from PyQt5 import Qt as QtGui
from zipfile import ZipFile
+# Calibre stuff - so we can import from our ZIP without absolute module name
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+
+
# calibre modules and constants.
from calibre.gui2 import (error_dialog, question_dialog, info_dialog, open_url,
choose_dir, choose_files, choose_save_file)
from calibre.utils.config import dynamic, config_dir, JSONConfig
from calibre.constants import iswindows, isosx
-# modules from this plugin's zipfile.
-from calibre_plugins.dedrm.__init__ import PLUGIN_NAME, PLUGIN_VERSION
-from calibre_plugins.dedrm.__init__ import RESOURCE_NAME as help_file_name
-from calibre_plugins.dedrm.utilities import uStrCmp
-import calibre_plugins.dedrm.prefs as prefs
-import calibre_plugins.dedrm.androidkindlekey as androidkindlekey
+from __init__ import PLUGIN_NAME, PLUGIN_VERSION
+from __init__ import RESOURCE_NAME as help_file_name
+from utilities import uStrCmp
+
+import prefs
+import androidkindlekey
def checkForDeACSMkeys():
try:
@@ -868,7 +872,7 @@ class AddBandNKeyDialog(QDialog):
errmsg = "This isn't the correct path, or the data is invalid."
return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
- from calibre_plugins.dedrm.ignoblekeyAndroid import dump_keys
+ from ignoblekeyAndroid import dump_keys
store_result = dump_keys(path_to_ade_data)
if len(store_result) == 0:
@@ -899,7 +903,7 @@ class AddBandNKeyDialog(QDialog):
def accept_ade_dump_passhash(self):
try:
- from calibre_plugins.dedrm.adobekey_get_passhash import passhash_keys
+ from adobekey_get_passhash import passhash_keys
keys, names = passhash_keys()
except:
errmsg = "Failed to grab PassHash keys from ADE."
@@ -940,7 +944,7 @@ class AddBandNKeyDialog(QDialog):
return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
try:
- from calibre_plugins.dedrm.ignoblekeyWindowsStore import dump_keys
+ from ignoblekeyWindowsStore import dump_keys
store_result = dump_keys(False)
except:
errmsg = "Failed to import from Nook Microsoft Store app."
@@ -948,7 +952,7 @@ class AddBandNKeyDialog(QDialog):
try:
# Try the Nook Study app
- from calibre_plugins.dedrm.ignoblekeyNookStudy import nookkeys
+ from ignoblekeyNookStudy import nookkeys
study_result = nookkeys()
except:
errmsg = "Failed to import from Nook Study app."
@@ -1009,7 +1013,7 @@ class AddBandNKeyDialog(QDialog):
return error_dialog(None, "{0} {1}".format(PLUGIN_NAME, PLUGIN_VERSION), errmsg, show=True, show_copy_button=False)
try:
- from calibre_plugins.dedrm.ignoblekeyGenPassHash import generate_key
+ from ignoblekeyGenPassHash import generate_key
self.result_data = generate_key(self.user_name, self.cc_number)
except:
errmsg = "Key generation failed."
@@ -1077,7 +1081,7 @@ class AddEReaderDialog(QDialog):
@property
def key_value(self):
- from calibre_plugins.dedrm.erdr2pml import getuser_key as generate_ereader_key
+ from erdr2pml import getuser_key as generate_ereader_key
return codecs.encode(generate_ereader_key(self.user_name, self.cc_number),'hex')
@property
@@ -1124,7 +1128,7 @@ class AddAdeptDialog():
try:
if iswindows or isosx:
- from calibre_plugins.dedrm.adobekey import adeptkeys
+ from adobekey import adeptkeys
defaultkeys, defaultnames = adeptkeys()
else: # linux
@@ -1220,7 +1224,7 @@ class AddKindleDialog(QDialog):
try:
if iswindows or isosx:
- from calibre_plugins.dedrm.kindlekey import kindlekeys
+ from kindlekey import kindlekeys
defaultkeys = kindlekeys()
else: # linux
diff --git a/DeDRM_plugin/erdr2pml.py b/DeDRM_plugin/erdr2pml.py
index c32431a..70d7b46 100755
--- a/DeDRM_plugin/erdr2pml.py
+++ b/DeDRM_plugin/erdr2pml.py
@@ -2,7 +2,7 @@
# -*- coding: utf-8 -*-
# erdr2pml.py
-# Copyright © 2008-2020 The Dark Reverser, Apprentice Harper et al.
+# Copyright © 2008-2021 The Dark Reverser, Apprentice Harper, noDRM et al.
#
# Changelog
#
@@ -64,16 +64,16 @@
# 0.22 - Unicode and plugin support, different image folders for PMLZ and source
# 0.23 - moved unicode_argv call inside main for Windows DeDRM compatibility
# 1.00 - Added Python 3 compatibility for calibre 5.0
+# 1.01 - Bugfixes for standalone version.
__version__='1.00'
import sys, re
import struct, binascii, getopt, zlib, os, os.path, urllib, tempfile, traceback
-if 'calibre' in sys.modules:
- inCalibre = True
-else:
- inCalibre = False
+# Calibre stuff - so we can import from our ZIP without absolute module name
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+
# Wrap a stream so that output gets flushed immediately
# and also make sure that any unicode strings get
@@ -141,40 +141,25 @@ def unicode_argv():
Des = None
if iswindows:
# first try with pycrypto
- if inCalibre:
- from calibre_plugins.dedrm import pycrypto_des
- else:
- import pycrypto_des
+ import pycrypto_des
Des = pycrypto_des.load_pycrypto()
if Des == None:
# they try with openssl
- if inCalibre:
- from calibre_plugins.dedrm import openssl_des
- else:
- import openssl_des
+ import openssl_des
Des = openssl_des.load_libcrypto()
else:
# first try with openssl
- if inCalibre:
- from calibre_plugins.dedrm import openssl_des
- else:
- import openssl_des
+ import openssl_des
Des = openssl_des.load_libcrypto()
if Des == None:
# then try with pycrypto
- if inCalibre:
- from calibre_plugins.dedrm import pycrypto_des
- else:
- import pycrypto_des
+ import pycrypto_des
Des = pycrypto_des.load_pycrypto()
# if that did not work then use pure python implementation
# of DES and try to speed it up with Psycho
if Des == None:
- if inCalibre:
- from calibre_plugins.dedrm import python_des
- else:
- import python_des
+ import python_des
Des = python_des.Des
# Import Psyco if available
try:
diff --git a/DeDRM_plugin/genbook.py b/DeDRM_plugin/genbook.py
index 6f3f57d..a0e0d0d 100644
--- a/DeDRM_plugin/genbook.py
+++ b/DeDRM_plugin/genbook.py
@@ -35,25 +35,18 @@ import getopt
from struct import pack
from struct import unpack
+# Calibre stuff - so we can import from our ZIP without absolute module name
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+
+
class TpzDRMError(Exception):
pass
# local support routines
-if 'calibre' in sys.modules:
- inCalibre = True
-else:
- inCalibre = False
-
-if inCalibre :
- from calibre_plugins.dedrm import convert2xml
- from calibre_plugins.dedrm import flatxml2html
- from calibre_plugins.dedrm import flatxml2svg
- from calibre_plugins.dedrm import stylexml2css
-else :
- import convert2xml
- import flatxml2html
- import flatxml2svg
- import stylexml2css
+import convert2xml
+import flatxml2html
+import flatxml2svg
+import stylexml2css
# global switch
buildXML = False
diff --git a/DeDRM_plugin/k4mobidedrm.py b/DeDRM_plugin/k4mobidedrm.py
index 4a30535..1a6465b 100644
--- a/DeDRM_plugin/k4mobidedrm.py
+++ b/DeDRM_plugin/k4mobidedrm.py
@@ -72,26 +72,18 @@ import time
import html.entities
import json
+# Calibre stuff - so we can import from our ZIP without absolute module name
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+
+
class DrmException(Exception):
pass
-if 'calibre' in sys.modules:
- inCalibre = True
-else:
- inCalibre = False
-
-if inCalibre:
- from calibre_plugins.dedrm import mobidedrm
- from calibre_plugins.dedrm import topazextract
- from calibre_plugins.dedrm import kgenpids
- from calibre_plugins.dedrm import androidkindlekey
- from calibre_plugins.dedrm import kfxdedrm
-else:
- import mobidedrm
- import topazextract
- import kgenpids
- import androidkindlekey
- import kfxdedrm
+import mobidedrm
+import topazextract
+import kgenpids
+import androidkindlekey
+import kfxdedrm
# Wrap a stream so that output gets flushed immediately
# and also make sure that any unicode strings get
@@ -243,7 +235,7 @@ def GetDecryptedBook(infile, kDatabases, androidFiles, serials, pids, starttime
try:
mb.processBook(totalpids)
except:
- mb.cleanup
+ mb.cleanup()
raise
print("Decryption succeeded after {0:.1f} seconds".format(time.time()-starttime))
diff --git a/DeDRM_plugin/kfxdedrm.py b/DeDRM_plugin/kfxdedrm.py
index 23e46dc..0674d63 100644
--- a/DeDRM_plugin/kfxdedrm.py
+++ b/DeDRM_plugin/kfxdedrm.py
@@ -8,16 +8,18 @@
# 2.1.1 - Whitespace!
-import os
+import os, sys
import shutil
import traceback
import zipfile
from io import BytesIO
-try:
- from ion import DrmIon, DrmIonVoucher
-except:
- from calibre_plugins.dedrm.ion import DrmIon, DrmIonVoucher
+
+# Calibre stuff - so we can import from our ZIP without absolute module name
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+
+from ion import DrmIon, DrmIonVoucher
+
__license__ = 'GPL v3'
diff --git a/DeDRM_plugin/prefs.py b/DeDRM_plugin/prefs.py
index aee4846..ae44213 100755
--- a/DeDRM_plugin/prefs.py
+++ b/DeDRM_plugin/prefs.py
@@ -5,15 +5,15 @@
__license__ = 'GPL v3'
# Standard Python modules.
-import os
+import os, sys
import traceback
-from calibre.utils.config import JSONConfig
+# Calibre stuff - so we can import from our ZIP without absolute module name
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+
-try:
- from calibre_plugins.dedrm.__init__ import PLUGIN_NAME
-except:
- PLUGIN_NAME = "DeDRM"
+from calibre.utils.config import JSONConfig
+from __init__ import PLUGIN_NAME
class DeDRM_Prefs():
def __init__(self):
diff --git a/DeDRM_plugin/scriptinterface.py b/DeDRM_plugin/scriptinterface.py
index 1810237..3351ee7 100644
--- a/DeDRM_plugin/scriptinterface.py
+++ b/DeDRM_plugin/scriptinterface.py
@@ -5,15 +5,19 @@
import sys
import os
+
+# Calibre stuff - so we can import from our ZIP without absolute module name
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+
+
import re
import traceback
-import calibre_plugins.dedrm.ineptepub
-import calibre_plugins.dedrm.ignobleepub
-import calibre_plugins.dedrm.epubtest
-import calibre_plugins.dedrm.zipfix
-import calibre_plugins.dedrm.ineptpdf
-import calibre_plugins.dedrm.erdr2pml
-import calibre_plugins.dedrm.k4mobidedrm
+import ineptepub
+import epubtest
+import zipfix
+import ineptpdf
+import erdr2pml
+import k4mobidedrm
def decryptepub(infile, outdir, rscpath):
errlog = ''
diff --git a/DeDRM_plugin/standalone/__init__.py b/DeDRM_plugin/standalone/__init__.py
new file mode 100644
index 0000000..fceda3b
--- /dev/null
+++ b/DeDRM_plugin/standalone/__init__.py
@@ -0,0 +1,217 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+# CLI interface for the DeDRM plugin (useable without Calibre, too)
+
+# Copyright © 2021 NoDRM
+
+OPT_SHORT_TO_LONG = [
+ ["h", "help"],
+ ["t", "test"],
+ ["v", "verbose"],
+ ["q", "quiet"],
+ ["u", "username"],
+ ["p", "password"],
+ ["d", "dest"],
+ ["f", "force"]
+]
+
+import sys, os
+IS_CALIBRE = False
+if "calibre" in sys.modules:
+ IS_CALIBRE = True
+
+# Explicitly allow importing the parent folder
+sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+# Explicitly set the package identifier so we are allowed to import stuff ...
+__package__ = "DeDRM_plugin"
+
+
+global _additional_data
+global _additional_params
+global _function
+_additional_data = []
+_additional_params = []
+_function = None
+
+def print_err_header():
+ from __init__ import PLUGIN_NAME, PLUGIN_VERSION # type: ignore
+
+ print(PLUGIN_NAME + " v" + PLUGIN_VERSION + " - DRM removal plugin by noDRM")
+ print()
+
+def print_help():
+ from __init__ import PLUGIN_NAME, PLUGIN_VERSION
+ print(PLUGIN_NAME + " v" + PLUGIN_VERSION + " - DRM removal plugin by noDRM")
+ print("Based on DeDRM Calibre plugin by Apprentice Harper, Apprentice Alf and others.")
+ print("See https://github.com/noDRM/DeDRM_tools for more information.")
+ print()
+ if IS_CALIBRE:
+ print("This plugin can be run through Calibre - like you are doing right now - ")
+ print("but it can also be executed with a standalone Python interpreter.")
+ else:
+ print("This plugin can either be imported into Calibre, or be executed directly")
+ print("through Python like you are doing right now.")
+ print()
+ print("TODO: Parameters here ...")
+
+def print_credits():
+ from __init__ import PLUGIN_NAME, PLUGIN_VERSION
+ print(PLUGIN_NAME + " v" + PLUGIN_VERSION + " - Calibre DRM removal plugin by noDRM")
+ print("Based on DeDRM Calibre plugin by Apprentice Harper, Apprentice Alf and others.")
+ print("See https://github.com/noDRM/DeDRM_tools for more information.")
+ print()
+ print("Credits:")
+ print(" - noDRM for the current release of the DeDRM plugin")
+ print(" - Apprentice Alf and Apprentice Harper for the previous versions of the DeDRM plugin")
+ print(" - The Dark Reverser for the Mobipocket and eReader script")
+ print(" - i ♥ cabbages for the Adobe Digital Editions scripts")
+ print(" - Skindle aka Bart Simpson for the Amazon Kindle for PC script")
+ print(" - CMBDTC for Amazon Topaz DRM removal script")
+ print(" - some_updates, clarknova and Bart Simpson for Amazon Topaz conversion scripts")
+ print(" - DiapDealer for the first calibre plugin versions of the tools")
+ print(" - some_updates, DiapDealer, Apprentice Alf and mdlnx for Amazon Kindle/Mobipocket tools")
+ print(" - some_updates for the DeDRM all-in-one Python tool")
+ print(" - Apprentice Alf for the DeDRM all-in-one AppleScript tool")
+
+
+def handle_single_argument(arg, next):
+ used_up = 0
+ global _additional_params
+
+ if arg == "--help":
+ print_help()
+ exit(0)
+
+ elif arg == "--credits":
+ print_credits()
+ exit(0)
+
+ elif arg in ["--username", "--password"]:
+ used_up = 1
+ _additional_params.append(arg)
+ if next is None:
+ print_err_header()
+ print("Missing parameter for argument " + arg)
+ exit(1)
+ else:
+ _additional_params.append(next[0])
+
+ elif arg in ["--verbose", "--quiet"]:
+ _additional_params.append(arg)
+
+
+ else:
+ print_err_header()
+ print("Unknown argument: " + arg)
+ exit(1)
+
+
+ # Used up 0 additional arguments
+ return used_up
+
+
+
+def handle_data(data):
+ global _function
+ global _additional_data
+
+ if _function is None:
+ _function = str(data)
+ else:
+ _additional_data.append(str(data))
+
+def execute_action(action, filenames, params):
+ print("Executing '{0}' on file(s) {1} with parameters {2}".format(action, str(filenames), str(params)))
+
+ print("ERROR: This feature is still in development. Right now it can't be used yet.")
+
+
+def main(argv):
+ arguments = argv
+ skip_opts = False
+
+ # First element is always the ZIP name, remove that.
+ if not arguments[0].lower().endswith(".zip") and not IS_CALIBRE:
+ print("Warning: File name does not end in .zip ...")
+ print(arguments)
+ arguments.pop(0)
+
+ while len(arguments) > 0:
+ arg = arguments.pop(0)
+
+ if arg == "--":
+ skip_opts = True
+ continue
+
+ if not skip_opts:
+ if arg.startswith("--"):
+ # Give the current arg, plus all remaining ones.
+ # Return the number of additional args we used.
+ used = handle_single_argument(arg, arguments)
+ for _ in range(used):
+ # Function returns number of additional arguments that were
+ # "used up" by that argument.
+ # Remove that amount of arguments from the list.
+ try:
+ arguments.pop(0)
+ except:
+ pass
+ continue
+ elif arg.startswith("-"):
+ single_args = list(arg[1:])
+ # single_args is now a list of single chars, for when you call the program like "ls -alR"
+ # with multiple single-letter options combined.
+ while len(single_args) > 0:
+ c = single_args.pop(0)
+
+ # See if we have a long name for that option.
+ for wrapper in OPT_SHORT_TO_LONG:
+ if wrapper[0] == c:
+ c = "--" + wrapper[1]
+ break
+ else:
+ c = "-" + c
+ # c is now the long term (unless there is no long version, then it's the short version).
+
+ if len(single_args) > 0:
+ # If we have more short arguments, the argument for this one must be None.
+ handle_single_argument(c, None)
+ used = 0
+ else:
+ # If not, then there might be parameters for this short argument.
+ used = handle_single_argument(c, arguments)
+
+ for _ in range(used):
+ # Function returns number of additional arguments that were
+ # "used up" by that argument.
+ # Remove that amount of arguments from the list.
+ try:
+ arguments.pop(0)
+ except:
+ pass
+
+ continue
+
+ handle_data(arg)
+
+
+ if _function is None:
+ print_help()
+ return(1)
+
+ # Okay, now actually begin doing stuff.
+ # This function gets told what to do and gets additional data (filenames).
+ # It also receives additional parameters.
+ # The rest of the code will be in different Python files.
+ execute_action(_function, _additional_data, _additional_params)
+
+
+
+
+
+if __name__ == "__main__":
+ # NOTE: This MUST not do anything else other than calling main()
+ # All the code must be in main(), not in here.
+ import sys
+ main(sys.argv) \ No newline at end of file
diff --git a/DeDRM_plugin/topazextract.py b/DeDRM_plugin/topazextract.py
index 55fa2ff..4db5072 100644
--- a/DeDRM_plugin/topazextract.py
+++ b/DeDRM_plugin/topazextract.py
@@ -13,14 +13,16 @@ __version__ = '6.0'
import sys
import os, csv, getopt
+
+# Calibre stuff - so we can import from our ZIP without absolute module name
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+
import zlib, zipfile, tempfile, shutil
import traceback
from struct import pack
from struct import unpack
-try:
- from calibre_plugins.dedrm.alfcrypto import Topaz_Cipher
-except:
- from alfcrypto import Topaz_Cipher
+
+from alfcrypto import Topaz_Cipher
# Wrap a stream so that output gets flushed immediately
# and also make sure that any unicode strings get
@@ -88,12 +90,7 @@ def unicode_argv():
#global switch
debug = False
-if 'calibre' in sys.modules:
- inCalibre = True
- from calibre_plugins.dedrm import kgenpids
-else:
- inCalibre = False
- import kgenpids
+import kgenpids
class DrmException(Exception):
@@ -336,10 +333,7 @@ class TopazBook:
self.createBookDirectory()
self.extractFiles()
print("Successfully Extracted Topaz contents")
- if inCalibre:
- from calibre_plugins.dedrm import genbook
- else:
- import genbook
+ import genbook
rv = genbook.generateBook(self.outdir, raw, fixedimage)
if rv == 0:
@@ -370,10 +364,7 @@ class TopazBook:
self.createBookDirectory()
self.extractFiles()
print("Successfully Extracted Topaz contents")
- if inCalibre:
- from calibre_plugins.dedrm import genbook
- else:
- import genbook
+ import genbook
rv = genbook.generateBook(self.outdir, raw, fixedimage)
if rv == 0:
diff --git a/DeDRM_plugin/utilities.py b/DeDRM_plugin/utilities.py
index 47d6106..1efd8ce 100644
--- a/DeDRM_plugin/utilities.py
+++ b/DeDRM_plugin/utilities.py
@@ -1,7 +1,12 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
-from calibre_plugins.dedrm.ignoblekeyGenPassHash import generate_key
+import sys, os
+# Calibre stuff - so we can import from our ZIP without absolute module name
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+
+
+from ignoblekeyGenPassHash import generate_key
__license__ = 'GPL v3'
diff --git a/DeDRM_plugin/zipfix.py b/DeDRM_plugin/zipfix.py
index 54469d8..079e49a 100644
--- a/DeDRM_plugin/zipfix.py
+++ b/DeDRM_plugin/zipfix.py
@@ -20,14 +20,13 @@ Re-write zip (or ePub) fixing problems with file names (and mimetype entry).
__license__ = 'GPL v3'
__version__ = "1.1"
-import sys
+import sys, os
+
+# Calibre stuff - so we can import from our ZIP without absolute module name
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+
import zlib
-try:
- import zipfilerugged
-except:
- import calibre_plugins.dedrm.zipfilerugged as zipfilerugged
-import os
-import os.path
+import zipfilerugged
import getopt
from struct import unpack