249 lines
8.4 KiB
Python
249 lines
8.4 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
|
|
# CLI interface for the DeDRM plugin (useable without Calibre, too)
|
|
|
|
from __future__ import absolute_import, print_function
|
|
|
|
# Copyright © 2021 NoDRM
|
|
|
|
OPT_SHORT_TO_LONG = [
|
|
["c", "config"],
|
|
["d", "dest"],
|
|
["e", "extract"],
|
|
["f", "force"],
|
|
["h", "help"],
|
|
["p", "password"],
|
|
["q", "quiet"],
|
|
["t", "test"],
|
|
["u", "username"],
|
|
["v", "verbose"],
|
|
]
|
|
|
|
#@@CALIBRE_COMPAT_CODE@@
|
|
|
|
# Explicitly set the package identifier so we are allowed to import stuff ...
|
|
__package__ = "DeDRM_plugin"
|
|
import os, sys
|
|
|
|
|
|
global _additional_data
|
|
global _additional_params
|
|
global _function
|
|
_additional_data = []
|
|
_additional_params = []
|
|
_function = None
|
|
|
|
def print_fname(f, info):
|
|
print(" " + f.ljust(15) + " " + info)
|
|
|
|
def print_opt(short, long, info):
|
|
if short is None:
|
|
short = " "
|
|
else:
|
|
short = " -" + short
|
|
|
|
if long is None:
|
|
long = " "
|
|
else:
|
|
long = "--" + long.ljust(16)
|
|
|
|
print(short + " " + long + " " + info, file=sys.stderr)
|
|
|
|
def print_std_usage(name, param_string):
|
|
print("Usage: ", file=sys.stderr)
|
|
if "calibre" in sys.modules:
|
|
print(" calibre-debug -r \"DeDRM\" -- "+name+" " + param_string, file=sys.stderr)
|
|
else:
|
|
print(" python3 DeDRM_plugin.zip "+name+" "+param_string, file=sys.stderr)
|
|
|
|
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 "calibre" in sys.modules:
|
|
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("Available functions:")
|
|
print_fname("passhash", "Manage Adobe PassHashes")
|
|
print()
|
|
|
|
# TODO: All parameters that are global should be listed 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 in ["--username", "--password"]:
|
|
used_up = 1
|
|
_additional_params.append(arg)
|
|
if next is None:
|
|
print_err_header()
|
|
print("Missing parameter for argument " + arg, file=sys.stderr)
|
|
sys.exit(1)
|
|
else:
|
|
_additional_params.append(next[0])
|
|
|
|
elif arg in ["--help", "--credits", "--verbose", "--quiet", "--extract"]:
|
|
_additional_params.append(arg)
|
|
|
|
|
|
else:
|
|
print_err_header()
|
|
print("Unknown argument: " + arg, file=sys.stderr)
|
|
sys.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)), file=sys.stderr)
|
|
|
|
if action == "passhash":
|
|
from standalone.passhash import perform_action
|
|
perform_action(params, filenames)
|
|
|
|
else:
|
|
print("ERROR: This feature is still in development. Right now it can't be used yet.", file=sys.stderr)
|
|
|
|
|
|
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 "calibre" in sys.modules:
|
|
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 and "--credits" in _additional_params:
|
|
print_credits()
|
|
sys.exit(0)
|
|
|
|
if _function is None and "--help" in _additional_params:
|
|
print_help()
|
|
sys.exit(0)
|
|
|
|
if _function is None:
|
|
print_help()
|
|
sys.exit(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) |