switched from python to cpp

This commit is contained in:
Benton Edmondson 2022-06-04 23:14:43 -04:00
parent 52d863ecf5
commit 851ba90431
10 changed files with 335 additions and 350 deletions

2
.gitignore vendored
View file

@ -1 +1,3 @@
result result
.vscode
todo.md

BIN
demo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

View file

@ -1,32 +1,45 @@
{ {
"nodes": { "nodes": {
"benpkgs": { "base64-src": {
"inputs": { "flake": false,
"nixpkgs": [
"nixpkgs"
]
},
"locked": { "locked": {
"lastModified": 1638237664, "lastModified": 1468170709,
"narHash": "sha256-9SkZPl1EZ1ezWZoMdhYOzPm2HK0Ca5hkfphjlPNk/FY=", "narHash": "sha256-dt6i1j0rqH7lA+2XXp9KTEhj2GvYueyGrHh9VXBEsbw=",
"owner": "BentonEdmondson", "ref": "master",
"repo": "benpkgs", "rev": "7d5a89229a525452e37504976a73c35fbaf2fe4d",
"rev": "da71a3a488de3ae7ab8daff2c2a9354d2f0464bf", "revCount": 1,
"type": "github" "type": "git",
"url": "https://gist.github.com/f0fd86b6c73063283afe550bc5d77594.git"
}, },
"original": { "original": {
"owner": "BentonEdmondson", "type": "git",
"repo": "benpkgs", "url": "https://gist.github.com/f0fd86b6c73063283afe550bc5d77594.git"
"type": "github" }
},
"gourou-src": {
"flake": false,
"locked": {
"lastModified": 1650729079,
"narHash": "sha256-2ZnuO/fIjSzTK0srFzDAhGNh1hA4lZf3lK4VuFxWXmo=",
"ref": "master",
"rev": "7b6b1471fefb27e79e06e5d686cb8842c539cd0c",
"revCount": 79,
"type": "git",
"url": "git://soutade.fr/libgourou.git"
},
"original": {
"ref": "master",
"type": "git",
"url": "git://soutade.fr/libgourou.git"
} }
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1638198142, "lastModified": 1654230545,
"narHash": "sha256-plU9b8r4St6q4U7VHtG9V7oF8k9fIpfXl/KDaZLuY9k=", "narHash": "sha256-8Vlwf0x8ow6pPOK2a04bT+pxIeRnM1+O0Xv9/CuDzRs=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "8a308775674e178495767df90c419425474582a1", "rev": "236cc2971ac72acd90f0ae3a797f9f83098b17ec",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -36,31 +49,47 @@
"type": "github" "type": "github"
} }
}, },
"rmdrm": { "pugixml-src": {
"inputs": { "flake": false,
"nixpkgs": [
"nixpkgs"
]
},
"locked": { "locked": {
"lastModified": 1638240151, "lastModified": 1644379750,
"narHash": "sha256-2FHEb4xaskyLdS5M/eILue74Idplve9g8FRxg9D1Z/4=", "narHash": "sha256-FLemG9T17n6l7vgb01OmO22BK59jv5uozVHeUnILEEQ=",
"owner": "BentonEdmondson", "owner": "zeux",
"repo": "rmdrm", "repo": "pugixml",
"rev": "c60eaa0c4338be5ee6165f59f2a1816566aba8a0", "rev": "314baf6605143f1e837209008f490e8559529e1c",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "BentonEdmondson", "owner": "zeux",
"repo": "rmdrm", "ref": "latest",
"repo": "pugixml",
"type": "github" "type": "github"
} }
}, },
"root": { "root": {
"inputs": { "inputs": {
"benpkgs": "benpkgs", "base64-src": "base64-src",
"gourou-src": "gourou-src",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"rmdrm": "rmdrm" "pugixml-src": "pugixml-src",
"updfparser-src": "updfparser-src"
}
},
"updfparser-src": {
"flake": false,
"locked": {
"lastModified": 1647424063,
"narHash": "sha256-9dvibKiUbbI4CrmuAaJzlpntT0XdLvdGeC2/WzjlA5U=",
"ref": "master",
"rev": "9d56c1d0b1ce81aae4c8db9d99a8b5d1f7967bcf",
"revCount": 25,
"type": "git",
"url": "git://soutade.fr/updfparser.git"
},
"original": {
"ref": "master",
"type": "git",
"url": "git://soutade.fr/updfparser.git"
} }
} }
}, },

188
flake.nix
View file

@ -1,60 +1,150 @@
{ {
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
gourou-src = {
rmdrm.url = "github:BentonEdmondson/rmdrm"; url = "git://soutade.fr/libgourou.git";
rmdrm.inputs.nixpkgs.follows = "nixpkgs"; type = "git";
ref = "master";
benpkgs.url = "github:BentonEdmondson/benpkgs"; flake = false;
benpkgs.inputs.nixpkgs.follows = "nixpkgs"; };
updfparser-src = {
url = "git://soutade.fr/updfparser.git";
type = "git";
ref = "master";
flake = false;
};
base64-src = {
url = "git+https://gist.github.com/f0fd86b6c73063283afe550bc5d77594.git";
flake = false;
};
pugixml-src = {
url = "github:zeux/pugixml/latest";
flake = false;
};
}; };
outputs = flakes: let outputs = flakes: let
nixpkgs = flakes.nixpkgs.legacyPackages.x86_64-linux; self = flakes.self.packages.x86_64-linux;
libgourou-utils = flakes.libgourou-utils.defaultPackage.x86_64-linux; nixpkgs = flakes.nixpkgs.legacyPackages.x86_64-linux.pkgsStatic;
rmdrm = flakes.rmdrm.defaultPackage.x86_64-linux; gourou-src = flakes.gourou-src;
benpkgs = flakes.benpkgs.packages.x86_64-linux; updfparser-src = flakes.updfparser-src;
in { base64-src = flakes.base64-src;
defaultPackage.x86_64-linux = nixpkgs.python3Packages.buildPythonApplication rec { pugixml-src = flakes.pugixml-src;
pname = "knock"; cxx = "${nixpkgs.stdenv.cc}/bin/x86_64-unknown-linux-musl-g++";
version = "1.1.0-alpha"; ar = "${nixpkgs.stdenv.cc.bintools.bintools_bin}/bin/x86_64-unknown-linux-musl-ar";
src = ./.; obj-flags = "-O2 -static";
in rec {
nativeBuildInputs = [ nixpkgs.makeWrapper ]; packages.x86_64-linux.libzip-static = nixpkgs.libzip.overrideAttrs (prev: {
cmakeFlags = (prev.cmakeFlags or []) ++ [
buildInputs = [ "-DBUILD_SHARED_LIBS=OFF"
rmdrm "-DBUILD_EXAMPLES=OFF"
benpkgs.libgourou "-DBUILD_DOC=OFF"
nixpkgs.ffmpeg "-DBUILD_TOOLS=OFF"
"-DBUILD_REGRESS=OFF"
]; ];
outputs = ["out"];
propagatedBuildInputs = [ });
benpkgs.Audible packages.x86_64-linux.base64 = derivation {
nixpkgs.python3Packages.python_magic name = "updfparser";
nixpkgs.python3Packages.xdg system = "x86_64-linux";
nixpkgs.python3Packages.click builder = "${nixpkgs.bash}/bin/bash";
]; PATH = "${nixpkgs.coreutils}/bin";
args = ["-c" ''
format = "other"; mkdir -p $out/include/base64
cp ${base64-src}/Base64.h $out/include/base64/Base64.h
installPhase = '' ''];
mkdir -p $out/bin $out/${nixpkgs.python3.sitePackages}
cp lib/*.py $out/${nixpkgs.python3.sitePackages}
cp src/knock.py $out/bin/knock
wrapProgram $out/bin/knock --prefix PATH : ${nixpkgs.lib.makeBinPath buildInputs}
#'';
meta = {
description = "A CLI tool to convert ACSM files to DRM-free EPUB/PDF files";
homepage = "https://github.com/BentonEdmondson/knock";
license = [ nixpkgs.lib.licenses.gpl3Only ];
maintainers = [{
name = "Benton Edmondson";
email = "bentonedmondson@gmail.com";
}];
# potentially others, but I'm only listed those tested
platforms = [ "x86_64-linux" ];
}; };
packages.x86_64-linux.updfparser = derivation {
name = "updfparser";
system = "x86_64-linux";
builder = "${nixpkgs.bash}/bin/bash";
PATH = "${nixpkgs.coreutils}/bin";
args = [ "-c" ''
${cxx} \
-c ${updfparser-src}/src/*.cpp \
-I ${updfparser-src}/include \
${obj-flags}
mkdir -p $out/lib
${ar} crs $out/lib/libupdfparser.a *.o
'' ];
}; };
packages.x86_64-linux.gourou = derivation {
name = "gourou";
system = "x86_64-linux";
builder = "${nixpkgs.bash}/bin/bash";
PATH = "${nixpkgs.coreutils}/bin";
args = [ "-c" ''
${cxx} \
-c \
${gourou-src}/src/*.cpp \
${pugixml-src}/src/pugixml.cpp \
-I ${self.base64}/include \
-I ${gourou-src}/include \
-I ${pugixml-src}/src \
-I ${updfparser-src}/include \
${obj-flags}
mkdir -p $out/lib $out/debug
${ar} crs $out/lib/libgourou.a *.o
cp *.o $out/debug
'' ];
};
packages.x86_64-linux.utils-common = derivation {
name = "utils-common";
system = "x86_64-linux";
builder = "${nixpkgs.bash}/bin/bash";
PATH = "${nixpkgs.coreutils}/bin";
args = [ "-c" ''
${cxx} \
-c ${gourou-src}/utils/drmprocessorclientimpl.cpp \
${gourou-src}/utils/utils_common.cpp \
-I ${gourou-src}/utils \
-I ${gourou-src}/include \
-I ${pugixml-src}/src \
-I ${nixpkgs.openssl.dev}/include \
-I ${nixpkgs.curl.dev}/include \
-I ${nixpkgs.zlib.dev}/include \
-I ${self.libzip-static}/include \
${obj-flags}
mkdir -p $out/lib
${ar} crs $out/lib/libutils-common.a *.o
'' ];
};
packages.x86_64-linux.knock = derivation {
name = "knock";
system = "x86_64-linux";
builder = "${nixpkgs.bash}/bin/bash";
PATH = "${nixpkgs.coreutils}/bin";
args = [ "-c" ''
mkdir -p $out/bin
${cxx} \
-o $out/bin/knock \
${./src/knock.cpp} \
-Wl,--as-needed -static \
${self.utils-common}/lib/libutils-common.a \
${self.gourou}/lib/libgourou.a \
${self.updfparser}/lib/libupdfparser.a \
-Wl,--start-group \
${self.libzip-static}/lib/libzip.a \
${nixpkgs.libnghttp2}/lib/libnghttp2.a \
${nixpkgs.libidn2.out}/lib/libidn2.a \
${nixpkgs.libunistring}/lib/libunistring.a \
${nixpkgs.libssh2}/lib/libssh2.a \
${nixpkgs.zstd.out}/lib/libzstd.a \
${nixpkgs.zlib}/lib/libz.a \
${nixpkgs.openssl.out}/lib/libcrypto.a \
${nixpkgs.curl.out}/lib/libcurl.a \
${nixpkgs.openssl.out}/lib/libssl.a \
-static-libgcc -static-libstdc++ \
-Wl,--end-group \
-I ${gourou-src}/utils \
-I ${gourou-src}/include \
-I ${pugixml-src}/src \
-I ${nixpkgs.openssl.dev}/include \
-I ${nixpkgs.curl.dev}/include \
-I ${nixpkgs.zlib.dev}/include \
-I ${self.libzip-static}/include
'' ];
};
defaultPackage.x86_64-linux = self.knock;
}; };
} }

View file

@ -1,51 +0,0 @@
from xdg import xdg_config_home
from utils import open_fake_terminal, close_fake_terminal, run
import audible, click, sys
def handle_aax(aax_path):
authcode_path = xdg_config_home().joinpath('knock', 'aax', 'authcode')
# make the config dir if it doesn't exist
authcode_path.parent.mkdir(parents=True, exist_ok=True)
m4b_path = aax_path.with_suffix('.m4b')
if m4b_path.exists():
click.echo(f"Error: {m4b_path} must be moved out of the way or deleted.", err=True)
sys.exit(1)
if not authcode_path.exists():
click.echo('This device does not have an Audible decryption key.')
email = click.prompt("Enter your Audible account's email address")
password = click.prompt("Enter your Audible account's password", hide_input=True)
locale = click.prompt("Enter your locale (e.g. 'us', 'ca', 'jp', etc)")
open_fake_terminal(f'audible.auth.Authenticator.from_login("{email}", "{locale}").get_activation_bytes()')
try:
authcode = audible.auth.Authenticator.from_login(
username=email,
password=password,
locale=locale
).get_activation_bytes()
authcode_path.write_text(authcode)
except Exception as error:
click.echo(error, err=True)
close_fake_terminal(1)
close_fake_terminal(0)
click.echo('Decrypting the file...')
authcode = authcode_path.read_text()
run([
'ffmpeg',
'-activation_bytes', authcode,
'-i', str(aax_path),
'-c', 'copy', str(m4b_path),
'-loglevel', 'error'
])
click.secho(f'DRM-free M4B file created:\n{m4b_path}', fg='green')

View file

@ -1,77 +0,0 @@
from xdg import xdg_config_home
import click, sys, shutil, subprocess, magic
from utils import run
def handle_acsm(acsm_path):
drm_path = acsm_path.with_suffix('.drm')
adobe_dir = xdg_config_home().joinpath('knock', 'acsm')
adobe_dir.mkdir(parents=True, exist_ok=True)
if drm_path.exists():
click.echo(f"Error: {drm_path} must be moved out of the way or deleted.", err=True)
sys.exit(1)
if (
not adobe_dir.joinpath('device.xml').exists()
or not adobe_dir.joinpath('activation.xml').exists()
or not adobe_dir.joinpath('devicesalt').exists()
):
shutil.rmtree(str(adobe_dir))
click.echo('This device is not registered with Adobe.')
email = click.prompt("Enter your Adobe account's email address")
password = click.prompt("Enter your Adobe account's password", hide_input=True)
click.echo('Registering this device with Adobe...')
run(
[
'adept_activate',
'-u', email,
'-O', str(adobe_dir)
],
stdin=password+'\n',
cleanser=lambda:shutil.rmtree(str(adobe_dir))
)
click.echo('Downloading the book from Adobe...')
run([
'acsmdownloader',
'-d', str(adobe_dir.joinpath('device.xml')),
'-a', str(adobe_dir.joinpath('activation.xml')),
'-k', str(adobe_dir.joinpath('devicesalt')),
'-o', str(drm_path),
'-f', str(acsm_path)
])
drm_path_type = magic.from_file(str(drm_path), mime=True)
if drm_path_type == 'application/epub+zip':
file_type = 'epub'
elif drm_path_type == 'application/pdf':
file_type = 'pdf'
else:
click.echo(f'Error: Received file of media type {drm_path_type} from Adobe\' servers.', err=True)
click.echo('Only the following ACSM conversions are currently supported:', err=True)
click.echo(' * ACSM -> EPUB', err=True)
click.echo(' * ACSM -> PDF', err=True)
click.echo('Please open a feature request at:', err=True)
click.echo(f' https://github.com/BentonEdmondson/knock/issues/new?title=Support%20{drm_path_type}%20Files&labels=enhancement', err=True)
sys.exit(1)
output_path = acsm_path.with_suffix('.' + file_type)
if output_path.exists():
drm_path.unlink()
click.echo(f"Error: {output_path} must be moved out of the way or deleted.", err=True)
sys.exit(1)
click.echo('Decrypting the file...')
run([
'rmdrm-' + file_type,
str(adobe_dir.joinpath('activation.xml')),
str(drm_path),
str(output_path)
])
drm_path.unlink()
click.secho(f'DRM-free {file_type.upper()} file created:\n{output_path}', fg='green')

View file

@ -1,45 +0,0 @@
import click, subprocess, sys
# run a command and display output in a styled terminal
# cleanser is called if the command returns a >0 exit code
def run(command: [str], stdin: str = '', cleanser = lambda: None) -> int:
open_fake_terminal(' '.join(command))
result = subprocess.run(
command,
stderr=subprocess.STDOUT,
input=stdin.encode(),
check=False # don't throw Python error if returncode isn't 0
)
close_fake_terminal(result.returncode, cleanser)
return result.returncode
def open_fake_terminal(command: str):
click.secho('', fg='white', bg='black', bold=True, reset=False)
# show command
click.echo(f'knock> {command}')
# remove bold
click.secho('', fg='white', bg='black', bold=False, reset=False)
def close_fake_terminal(exit_code: int, cleanser = lambda: None):
click.secho(f'\nknock[{exit_code}]>', bold=True)
# newline
click.echo('')
if exit_code > 0:
cleanser()
click.echo(f'Error: Command returned error code {exit_code}.', err=True)
sys.exit(1)
def verify_absence_of(file_path):
if m4b_path.exists():
click.echo(f"Error: {file_path} must be moved out of the way or deleted.", err=True)
sys.exit(1)

View file

@ -1,54 +1,20 @@
# Knock # Knock
Perform the following conversions with one command: Convert ACSM files to PDF/EPUBs with one command on Linux ([and MacOS very soon](https://github.com/BentonEdmondson/knock/issues/58)).
* ACSM → EPUB
* ACSM → PDF
* (Soon: AAX → M4B)
![CLI demonstration](demo.png)
*This software does not utilize Adobe Digital Editions nor Wine. It is completely free and open-source software written natively for Linux.* *This software does not utilize Adobe Digital Editions nor Wine. It is completely free and open-source software written natively for Linux.*
## Setup and Installation ## Installation
* For NixOS users, include this flake in your system `flake.nix`. Then run `knock ~/path/to/my-book.acsm` to use. * Download the latest [release](https://github.com/BentonEdmondson/knock/releases). Make sure it is the correct version for your architecture (run `uname -m` to check).
```nix * Rename the binary and make it executable.
{ * Run `knock /path/to/book.acsm` to perform the conversion.
inputs.knock.url = "github:BentonEdmondson/knock";
outputs = { self, knock }: { /* knock.defaultPackage.x86_64-linux is the package */ };
}
```
* For non-NixOS, use the latest [release](https://github.com/BentonEdmondson/knock/releases). It is large because it includes all dependencies, allowing it to run on any system with an x86_64 Linux kernel. It was built using [`nix bundle`](https://nixos.org/manual/nix/unstable/command-ref/new-cli/nix3-bundle.html). Use it by doing the following:
1. Download `knock-version-x86_64-linux` and open a terminal
1. Navigate to the folder within which `knock-version-x86_64-linux` resides (e.g. `cd ~/Downloads`)
1. Run `mv knock-version-x86_64-linux knock` to rename it to `knock`
1. Run `chmod +x knock` to make it executable
1. Run `./knock ~/path/to/my-book.acsm` to convert the ebook
If you receive an error that says something like `./nix/store/...: not found` or `./nix/store/...: No such file or directory` then you might not have user namespaces enabled. Try running the following to fix it:
```
echo "kernel.unprivileged_userns_clone=1" >> /etc/sysctl.conf
sudo reboot
```
If you receive an error that says something like `E_AUTH_FAILED http://adeactivate.adobe.com/adept/SignInDirect xxxx@xxxxxxxx.com CUS05051` then you might have over (at least) 10 digit password for Adobe. Try changing it to 10 digit password and try the command again.
1. Optionally move the executable to `~/bin` (for your user) or `/usr/local/bin/` (for all users) to allow it to run from anywhere (might not work on some distributions)
## Recommended Workflows
Before buying your ebook/audiobook, check if it is available for free on [Project Gutenberg](https://gutenberg.org/) (ebooks) or [LibriVox](https://librivox.org/) (audiobooks).
If you're looking for an ebook reader or audiobook player, I recommend [Foliate](https://johnfactotum.github.io/foliate/) for the former and [Cozy](https://cozy.sh/) for the latter.
## Verified Book Sources ## Verified Book Sources
Knock should work on any ACSM file, but it has been specifically verified to work on ACSM files from the following: Knock should work on any ACSM file, but it has been specifically verified to work on ACSM files purchased [eBooks.com](https://www.ebooks.com/en-us/) and [Kobo](https://www.kobo.com/us/en), among others.
* [eBooks.com](https://www.ebooks.com/en-us/) Before buying your ebook, check if it is available for free on [Project Gutenberg](https://gutenberg.org/).
* [Rakuten Kobo](https://www.kobo.com/us/en)
* [Google Books](https://books.google.com/)
* [Hugendubel.de](https://www.hugendubel.de/de/) (German)
## The Name ## The Name
@ -65,13 +31,26 @@ The name comes from the [D&D 5e spell](https://roll20.net/compendium/dnd5e/Knock
## Dependencies ## Dependencies
* [`libgourou`](http://indefero.soutade.fr/p/libgourou/) for using the ACSM file to download the corresponding encrypted EPUB/PDF file from Adobe's servers There are no userspace runtime dependencies.
* [`rmdrm`](https://github.com/BentonEdmondson/rmdrm/) for decrypting the Adobe ADEPT-encrypted EPUB/PDF files
* [`Audible`](https://github.com/mkb79/Audible) for fetching the Audible decryption key used to decrypt AAX files
* [`ffmpeg`](https://www.ffmpeg.org/) for converting AAX files to M4B files using the Audible decryption key
These are already included in all releases and in the Nix flake of course. ## Building & Contributing
Install [Nix](https://github.com/NixOS/nix) if you don't have it. [Enable flakes](https://nixos.wiki/wiki/Flakes) if you haven't. Run
```
nix build
```
to build and
```
nix flake update
```
to update libraries.
Test books can be found [here](https://www.adobe.com/solutions/ebook/digital-editions/sample-ebook-library.html).
## License ## License
This software is licensed under GPLv3. This software is licensed under GPLv3. The linked libraries have various licenses.

104
src/knock.cpp Normal file
View file

@ -0,0 +1,104 @@
#include <filesystem>
#include "drmprocessorclientimpl.h"
#include "libgourou_common.h"
#include "libgourou.h"
std::string get_data_dir();
void verify_absence(std::string file);
void verify_presence(std::string file);
int main(int argc, char** argv) try {
if (argc != 2) {
throw std::invalid_argument("the ACSM file must be passed as an argument");
}
const std::string acsm_file = argv[1];
verify_presence(acsm_file);
const std::string acsm_stem = acsm_file.substr(0, acsm_file.find_last_of("."));
const std::string drm_file = acsm_stem + ".drm";
const std::string out_file = acsm_stem + ".out";
verify_absence(drm_file);
verify_absence(out_file);
const std::string knock_data = get_data_dir();
DRMProcessorClientImpl client;
gourou::DRMProcessor* processor = gourou::DRMProcessor::createDRMProcessor(
&client,
false, // don't "always generate a new device" (default)
knock_data
);
processor->signIn("anonymous", "");
processor->activateDevice();
std::cout << "downloading the file from Adobe..." << std::endl;
gourou::FulfillmentItem* item = processor->fulfill(acsm_file);
gourou::DRMProcessor::ITEM_TYPE type = processor->download(item, drm_file);
std::cout << "removing DRM from the file..." << std::endl;
std::string ext_file;
std::string file_type;
switch (type) {
case gourou::DRMProcessor::ITEM_TYPE::PDF: {
// for pdfs the function moves the pdf while removing drm
processor->removeDRM(drm_file, out_file, type, nullptr, 0);
std::filesystem::remove(drm_file);
ext_file = acsm_stem + ".pdf";
file_type = "PDF";
break;
}
case gourou::DRMProcessor::ITEM_TYPE::EPUB: {
// for epubs the drm is removed in-place so in == out
processor->removeDRM(drm_file, drm_file, type, nullptr, 0);
std::filesystem::rename(drm_file, out_file);
ext_file = acsm_stem + ".epub";
file_type = "EPUB";
break;
}
}
if (std::filesystem::exists(ext_file)) {
std::cerr
<< "warning: failed to update file extension; " + ext_file + " already exists"
<< std::endl;
ext_file = out_file;
} else {
std::filesystem::rename(out_file, ext_file);
}
std::cout << "DRM-free " + file_type + " file generated at " + ext_file << std::endl;
return 0;
} catch (const gourou::Exception& e) {
std::cerr << "error:\n" << e.what();
return EXIT_FAILURE;
} catch (const std::exception& e) {
std::cerr << "error: " << e.what() << std::endl;
return EXIT_FAILURE;
}
std::string get_data_dir() {
char* xdg_data_home = std::getenv("XDG_DATA_HOME");
std::string knock_data;
if (xdg_data_home != nullptr) {
knock_data = xdg_data_home;
} else {
knock_data = std::string(std::getenv("HOME")) + "/.local/share";
}
knock_data += "/knock/acsm";
return knock_data;
}
void verify_absence(std::string file) {
if (std::filesystem::exists(file)) {
throw std::runtime_error("file " + file + " must be moved out of the way or deleted");
}
}
void verify_presence(std::string file) {
if (!std::filesystem::exists(file)) {
throw std::runtime_error("file " + file + " does not exist");
}
}

View file

@ -1,46 +0,0 @@
#!/usr/bin/env python3
import subprocess, shutil, click
from pathlib import Path
from getpass import getpass
from xdg import xdg_config_home
from handle_acsm import handle_acsm
from handle_aax import handle_aax
@click.command()
@click.argument(
"path",
type=click.Path(
exists=True,
file_okay=True,
dir_okay=False,
readable=True,
resolve_path=True
)
)
def main(path):
path = Path(path)
# make the config dir if it doesn't exist
xdg_config_home().joinpath('knock').mkdir(parents=True, exist_ok=True)
path_type = path.suffix[1:].upper()
if path_type == 'ACSM':
click.echo('Received an ACSM (Adobe) file...')
handle_acsm(path)
#elif path_type == 'AAX':
# click.echo('Received an AAX (Audible) file...')
# handle_aax(path)
else:
click.echo(f'Error: Files of type {path_type} are not supported.\n', err=True)
click.echo('Only the following file types are currently supported:', err=True)
click.echo(' * ACSM (Adobe)\n', err=True)
#click.echo(' * AAX (Audible)\n', err=True)
click.echo('Please open a feature request at:', err=True)
click.echo(f' https://github.com/BentonEdmondson/knock/issues/new?title=Support%20{path_type}%20Files&labels=enhancement', err=True)
sys.exit(1)
if __name__ == "__main__":
main()