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

4
.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": {
"benpkgs": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"base64-src": {
"flake": false,
"locked": {
"lastModified": 1638237664,
"narHash": "sha256-9SkZPl1EZ1ezWZoMdhYOzPm2HK0Ca5hkfphjlPNk/FY=",
"owner": "BentonEdmondson",
"repo": "benpkgs",
"rev": "da71a3a488de3ae7ab8daff2c2a9354d2f0464bf",
"type": "github"
"lastModified": 1468170709,
"narHash": "sha256-dt6i1j0rqH7lA+2XXp9KTEhj2GvYueyGrHh9VXBEsbw=",
"ref": "master",
"rev": "7d5a89229a525452e37504976a73c35fbaf2fe4d",
"revCount": 1,
"type": "git",
"url": "https://gist.github.com/f0fd86b6c73063283afe550bc5d77594.git"
},
"original": {
"owner": "BentonEdmondson",
"repo": "benpkgs",
"type": "github"
"type": "git",
"url": "https://gist.github.com/f0fd86b6c73063283afe550bc5d77594.git"
}
},
"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": {
"locked": {
"lastModified": 1638198142,
"narHash": "sha256-plU9b8r4St6q4U7VHtG9V7oF8k9fIpfXl/KDaZLuY9k=",
"lastModified": 1654230545,
"narHash": "sha256-8Vlwf0x8ow6pPOK2a04bT+pxIeRnM1+O0Xv9/CuDzRs=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "8a308775674e178495767df90c419425474582a1",
"rev": "236cc2971ac72acd90f0ae3a797f9f83098b17ec",
"type": "github"
},
"original": {
@ -36,31 +49,47 @@
"type": "github"
}
},
"rmdrm": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"pugixml-src": {
"flake": false,
"locked": {
"lastModified": 1638240151,
"narHash": "sha256-2FHEb4xaskyLdS5M/eILue74Idplve9g8FRxg9D1Z/4=",
"owner": "BentonEdmondson",
"repo": "rmdrm",
"rev": "c60eaa0c4338be5ee6165f59f2a1816566aba8a0",
"lastModified": 1644379750,
"narHash": "sha256-FLemG9T17n6l7vgb01OmO22BK59jv5uozVHeUnILEEQ=",
"owner": "zeux",
"repo": "pugixml",
"rev": "314baf6605143f1e837209008f490e8559529e1c",
"type": "github"
},
"original": {
"owner": "BentonEdmondson",
"repo": "rmdrm",
"owner": "zeux",
"ref": "latest",
"repo": "pugixml",
"type": "github"
}
},
"root": {
"inputs": {
"benpkgs": "benpkgs",
"base64-src": "base64-src",
"gourou-src": "gourou-src",
"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"
}
}
},

190
flake.nix
View file

@ -1,60 +1,150 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
rmdrm.url = "github:BentonEdmondson/rmdrm";
rmdrm.inputs.nixpkgs.follows = "nixpkgs";
benpkgs.url = "github:BentonEdmondson/benpkgs";
benpkgs.inputs.nixpkgs.follows = "nixpkgs";
gourou-src = {
url = "git://soutade.fr/libgourou.git";
type = "git";
ref = "master";
flake = false;
};
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
nixpkgs = flakes.nixpkgs.legacyPackages.x86_64-linux;
libgourou-utils = flakes.libgourou-utils.defaultPackage.x86_64-linux;
rmdrm = flakes.rmdrm.defaultPackage.x86_64-linux;
benpkgs = flakes.benpkgs.packages.x86_64-linux;
in {
defaultPackage.x86_64-linux = nixpkgs.python3Packages.buildPythonApplication rec {
pname = "knock";
version = "1.1.0-alpha";
src = ./.;
nativeBuildInputs = [ nixpkgs.makeWrapper ];
buildInputs = [
rmdrm
benpkgs.libgourou
nixpkgs.ffmpeg
self = flakes.self.packages.x86_64-linux;
nixpkgs = flakes.nixpkgs.legacyPackages.x86_64-linux.pkgsStatic;
gourou-src = flakes.gourou-src;
updfparser-src = flakes.updfparser-src;
base64-src = flakes.base64-src;
pugixml-src = flakes.pugixml-src;
cxx = "${nixpkgs.stdenv.cc}/bin/x86_64-unknown-linux-musl-g++";
ar = "${nixpkgs.stdenv.cc.bintools.bintools_bin}/bin/x86_64-unknown-linux-musl-ar";
obj-flags = "-O2 -static";
in rec {
packages.x86_64-linux.libzip-static = nixpkgs.libzip.overrideAttrs (prev: {
cmakeFlags = (prev.cmakeFlags or []) ++ [
"-DBUILD_SHARED_LIBS=OFF"
"-DBUILD_EXAMPLES=OFF"
"-DBUILD_DOC=OFF"
"-DBUILD_TOOLS=OFF"
"-DBUILD_REGRESS=OFF"
];
propagatedBuildInputs = [
benpkgs.Audible
nixpkgs.python3Packages.python_magic
nixpkgs.python3Packages.xdg
nixpkgs.python3Packages.click
];
format = "other";
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" ];
};
outputs = ["out"];
});
packages.x86_64-linux.base64 = derivation {
name = "updfparser";
system = "x86_64-linux";
builder = "${nixpkgs.bash}/bin/bash";
PATH = "${nixpkgs.coreutils}/bin";
args = ["-c" ''
mkdir -p $out/include/base64
cp ${base64-src}/Base64.h $out/include/base64/Base64.h
''];
};
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
Perform the following conversions with one command:
* ACSM → EPUB
* ACSM → PDF
* (Soon: AAX → M4B)
![CLI demonstration](demo.png)
Convert ACSM files to PDF/EPUBs with one command on Linux ([and MacOS very soon](https://github.com/BentonEdmondson/knock/issues/58)).
*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.
```nix
{
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.
* 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).
* Rename the binary and make it executable.
* Run `knock /path/to/book.acsm` to perform the conversion.
## 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/)
* [Rakuten Kobo](https://www.kobo.com/us/en)
* [Google Books](https://books.google.com/)
* [Hugendubel.de](https://www.hugendubel.de/de/) (German)
Before buying your ebook, check if it is available for free on [Project Gutenberg](https://gutenberg.org/).
## The Name
@ -65,13 +31,26 @@ The name comes from the [D&D 5e spell](https://roll20.net/compendium/dnd5e/Knock
## 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
* [`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
There are no userspace runtime dependencies.
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
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()