acsm to pdf is working, removed aax for now

This commit is contained in:
benton 2021-12-04 15:58:14 -06:00
parent 98faaa4579
commit 8fd6244db8
7 changed files with 98 additions and 91 deletions

View file

@ -7,43 +7,26 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1633315458, "lastModified": 1638237664,
"narHash": "sha256-CKlsbD3I+CduADnEbPZV+LD4ByQ0RiDy39F3z6DKOQc=", "narHash": "sha256-9SkZPl1EZ1ezWZoMdhYOzPm2HK0Ca5hkfphjlPNk/FY=",
"type": "git",
"url": "file:///home/benton/git/benpkgs"
},
"original": {
"type": "git",
"url": "file:///home/benton/git/benpkgs"
}
},
"inept-epub": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1628616743,
"narHash": "sha256-XNka+o/55SYOtDUXXOTmDvX4Qiqbaz4COq+JZ8MPoe8=",
"owner": "BentonEdmondson", "owner": "BentonEdmondson",
"repo": "inept-epub", "repo": "benpkgs",
"rev": "d6ba98a7159f61e7b77dc17c8c6bb62e193c8831", "rev": "da71a3a488de3ae7ab8daff2c2a9354d2f0464bf",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "BentonEdmondson", "owner": "BentonEdmondson",
"repo": "inept-epub", "repo": "benpkgs",
"type": "github" "type": "github"
} }
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1633080050, "lastModified": 1638198142,
"narHash": "sha256-T9I2WnlUzAIL70dk9V1jqaYk3nypy/cMkWR19S47ZHc=", "narHash": "sha256-plU9b8r4St6q4U7VHtG9V7oF8k9fIpfXl/KDaZLuY9k=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "82155ff501c7622cb2336646bb62f7624261f6d7", "rev": "8a308775674e178495767df90c419425474582a1",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -53,11 +36,31 @@
"type": "github" "type": "github"
} }
}, },
"rmdrm": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1638240151,
"narHash": "sha256-2FHEb4xaskyLdS5M/eILue74Idplve9g8FRxg9D1Z/4=",
"owner": "BentonEdmondson",
"repo": "rmdrm",
"rev": "c60eaa0c4338be5ee6165f59f2a1816566aba8a0",
"type": "github"
},
"original": {
"owner": "BentonEdmondson",
"repo": "rmdrm",
"type": "github"
}
},
"root": { "root": {
"inputs": { "inputs": {
"benpkgs": "benpkgs", "benpkgs": "benpkgs",
"inept-epub": "inept-epub", "nixpkgs": "nixpkgs",
"nixpkgs": "nixpkgs" "rmdrm": "rmdrm"
} }
} }
}, },

View file

@ -2,37 +2,37 @@
inputs = { inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
inept-epub.url = "github:BentonEdmondson/inept-epub"; rmdrm.url = "github:BentonEdmondson/rmdrm";
inept-epub.inputs.nixpkgs.follows = "nixpkgs"; rmdrm.inputs.nixpkgs.follows = "nixpkgs";
benpkgs.url = "git+file:///home/benton/git/benpkgs"; benpkgs.url = "github:BentonEdmondson/benpkgs";
benpkgs.inputs.nixpkgs.follows = "nixpkgs"; benpkgs.inputs.nixpkgs.follows = "nixpkgs";
}; };
outputs = { self, ... }@flakes: let outputs = flakes: let
nixpkgs = flakes.nixpkgs.legacyPackages.x86_64-linux; nixpkgs = flakes.nixpkgs.legacyPackages.x86_64-linux;
libgourou-utils = flakes.libgourou-utils.defaultPackage.x86_64-linux; libgourou-utils = flakes.libgourou-utils.defaultPackage.x86_64-linux;
inept-epub = flakes.inept-epub.defaultPackage.x86_64-linux; rmdrm = flakes.rmdrm.defaultPackage.x86_64-linux;
benpkgs = flakes.benpkgs.packages.x86_64-linux; benpkgs = flakes.benpkgs.packages.x86_64-linux;
in { in {
defaultPackage.x86_64-linux = nixpkgs.python3Packages.buildPythonApplication rec { defaultPackage.x86_64-linux = nixpkgs.python3Packages.buildPythonApplication rec {
pname = "knock"; pname = "knock";
version = "1.0.0-alpha"; version = "1.1.0-alpha";
src = ./.; src = ./.;
nativeBuildInputs = [ nixpkgs.makeWrapper ]; nativeBuildInputs = [ nixpkgs.makeWrapper ];
buildInputs = [ buildInputs = [
inept-epub rmdrm
benpkgs.libgourou benpkgs.libgourou
nixpkgs.ffmpeg nixpkgs.ffmpeg
]; ];
propagatedBuildInputs = [ propagatedBuildInputs = [
benpkgs.Audible
nixpkgs.python3Packages.python_magic nixpkgs.python3Packages.python_magic
nixpkgs.python3Packages.xdg nixpkgs.python3Packages.xdg
nixpkgs.python3Packages.click nixpkgs.python3Packages.click
benpkgs.Audible
]; ];
format = "other"; format = "other";
@ -42,10 +42,10 @@
cp lib/*.py $out/${nixpkgs.python3.sitePackages} cp lib/*.py $out/${nixpkgs.python3.sitePackages}
cp src/knock.py $out/bin/knock cp src/knock.py $out/bin/knock
wrapProgram $out/bin/knock --prefix PATH : ${nixpkgs.lib.makeBinPath buildInputs} wrapProgram $out/bin/knock --prefix PATH : ${nixpkgs.lib.makeBinPath buildInputs}
''; #'';
meta = { meta = {
description = "A CLI tool to convert ACSM files to DRM-free EPUB files"; description = "A CLI tool to convert ACSM files to DRM-free EPUB/PDF files";
homepage = "https://github.com/BentonEdmondson/knock"; homepage = "https://github.com/BentonEdmondson/knock";
license = [ nixpkgs.lib.licenses.gpl3Only ]; license = [ nixpkgs.lib.licenses.gpl3Only ];
maintainers = [{ maintainers = [{

View file

@ -48,4 +48,4 @@ def handle_aax(aax_path):
'-loglevel', 'error' '-loglevel', 'error'
]) ])
click.secho(f'DRM-free M4B file created:\n{aax_path.with_suffix(".m4b")}', fg='green') click.secho(f'DRM-free M4B file created:\n{m4b_path}', fg='green')

View file

@ -1,5 +1,5 @@
from xdg import xdg_config_home from xdg import xdg_config_home
import click, sys, shutil, subprocess import click, sys, shutil, subprocess, magic
from utils import run from utils import run
def handle_acsm(acsm_path): def handle_acsm(acsm_path):
@ -24,7 +24,7 @@ def handle_acsm(acsm_path):
run( run(
[ [
'adept-register', 'adept_activate',
'-u', email, '-u', email,
'-O', str(adobe_dir) '-O', str(adobe_dir)
], ],
@ -35,7 +35,7 @@ def handle_acsm(acsm_path):
click.echo('Downloading the book from Adobe...') click.echo('Downloading the book from Adobe...')
run([ run([
'adept-download', 'acsmdownloader',
'-d', str(adobe_dir.joinpath('device.xml')), '-d', str(adobe_dir.joinpath('device.xml')),
'-a', str(adobe_dir.joinpath('activation.xml')), '-a', str(adobe_dir.joinpath('activation.xml')),
'-k', str(adobe_dir.joinpath('devicesalt')), '-k', str(adobe_dir.joinpath('devicesalt')),
@ -45,11 +45,11 @@ def handle_acsm(acsm_path):
drm_path_type = magic.from_file(str(drm_path), mime=True) drm_path_type = magic.from_file(str(drm_path), mime=True)
if drm_path_type == 'application/epub+zip': if drm_path_type == 'application/epub+zip':
file_type = 'EPUB' file_type = 'epub'
elif drm_path_type == 'application/pdf': elif drm_path_type == 'application/pdf':
file_type = 'PDF' file_type = 'pdf'
else: else:
click.echo(f'Error: Received file of media type {drm_path_type}.', err=True) 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('Only the following ACSM conversions are currently supported:', err=True)
click.echo(' * ACSM -> EPUB', err=True) click.echo(' * ACSM -> EPUB', err=True)
click.echo(' * ACSM -> PDF', err=True) click.echo(' * ACSM -> PDF', err=True)
@ -57,20 +57,21 @@ def handle_acsm(acsm_path):
click.echo(f' https://github.com/BentonEdmondson/knock/issues/new?title=Support%20{drm_path_type}%20Files&labels=enhancement', 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) sys.exit(1)
output_file = acsm_path.with_suffix(file_type) output_path = acsm_path.with_suffix('.' + file_type)
if output_file.exists(): if output_path.exists():
click.echo(f"Error: {output_file} must be moved out of the way or deleted.", err=True) drm_path.unlink()
click.echo(f"Error: {output_path} must be moved out of the way or deleted.", err=True)
sys.exit(1) sys.exit(1)
click.echo('Decrypting the file...') click.echo('Decrypting the file...')
run([ run([
'inept-' + file_type.lower(), 'rmdrm-' + file_type,
str(adobe_dir.joinpath('activation.xml')), str(adobe_dir.joinpath('activation.xml')),
str(drm_path), str(drm_path),
str(output_file) str(output_path)
]) ])
drm_path.unlink() drm_path.unlink()
click.secho(f'DRM-free {file_type} file created:\n{output_file}', fg='green') click.secho(f'DRM-free {file_type.upper()} file created:\n{output_path}', fg='green')

View file

@ -38,3 +38,8 @@ def close_fake_terminal(exit_code: int, cleanser = lambda: None):
cleanser() cleanser()
click.echo(f'Error: Command returned error code {exit_code}.', err=True) click.echo(f'Error: Command returned error code {exit_code}.', err=True)
sys.exit(1) 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,22 +1,25 @@
# Knock # Knock
Convert ACSM files to DRM-free EPUB files using one command. Perform the following conversions with one command:
* ACSM → EPUB
* ACSM → PDF
* (Soon: AAX → M4B)
![CLI demonstration](demo.png) ![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 ## Setup and Installation
1. Create a free Adobe account [here](https://account.adobe.com) if you do not already have one. * For NixOS users, include this flake in your system `flake.nix`. Then run `knock ~/path/to/my-book.acsm` to use.
1. Install the software.
* For NixOS, include this flake in your system `flake.nix`. Then run `knock ~/path/to/my-book.acsm` to use.
```nix ```nix
inputs.knock.url = github:BentonEdmondson/knock {
outputs = { self, knock }: { /* knock.defaultPackage.x86_64-linux is the package */ } 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: * 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-x8664-linux` and open a terminal 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. 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 `mv knock-version-x86_64-linux knock` to rename it to `knock`
1. Run `chmod +x knock` to make it executable 1. Run `chmod +x knock` to make it executable
@ -29,27 +32,23 @@ This software does not utilize Adobe Digital Editions nor Wine. It is completely
sudo reboot sudo reboot
``` ```
1. Enter in your Adobe email and password when prompted
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) 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 EPUB files from the following: Knock should work on any ACSM file, but it has been specifically verified to work on ACSM files from the following:
* [eBooks.com](https://www.ebooks.com/en-us/) * [eBooks.com](https://www.ebooks.com/en-us/)
* [Rakuten Kobo](https://www.kobo.com/us/en) * [Rakuten Kobo](https://www.kobo.com/us/en)
* [Google Books](https://books.google.com/) * [Google Books](https://books.google.com/)
* [Hugendubel.de](https://www.hugendubel.de/de/) (German) * [Hugendubel.de](https://www.hugendubel.de/de/) (German)
The resulting EPUB file can be read with any EPUB reader.
## Legality
[It's Perfectly Legal to Tell People How to Remove DRM](https://gizmodo.com/its-perfectly-legal-to-tell-people-how-to-remove-drm-1670223538) (Gizmodo)
**Do not use this software for piracy; this software is not intended for piracy.** This software exists to allow readers to *legally* purchase and then legally and *freely* read ebooks. I suspect that the significant prevalence of ebook piracy is caused in large part by the restrictions put on legally purchased ebooks. This software exists to *incentivize* the legal purchase of ebooks by enabling their unrestricted and legal consumption.
## The Name ## The Name
The name comes from the [D&D 5e spell](https://roll20.net/compendium/dnd5e/Knock#content) for freeing locked items: The name comes from the [D&D 5e spell](https://roll20.net/compendium/dnd5e/Knock#content) for freeing locked items:
@ -65,11 +64,13 @@ The name comes from the [D&D 5e spell](https://roll20.net/compendium/dnd5e/Knock
## Dependencies ## Dependencies
* [`libgourou-utils`](https://github.com/BentonEdmondson/libgourou-utils) for using the ACSM file to download the corresponding encrypted EPUB file from Adobe's servers * [`libgourou`](http://indefero.soutade.fr/p/libgourou/) for using the ACSM file to download the corresponding encrypted EPUB/PDF file from Adobe's servers
* [`inept-epub`](https://github.com/BentonEdmondson/inept-epub/) for decrypting the EPUB file * [`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. These are already included in all releases and in the Nix flake of course.
## License ## License
This software is licensed under GPLv3 because one of its dependencies is licensed under GPLv3. This software is licensed under GPLv3.

View file

@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import subprocess, magic, shutil, click import subprocess, shutil, click
from pathlib import Path from pathlib import Path
from getpass import getpass from getpass import getpass
from xdg import xdg_config_home from xdg import xdg_config_home
@ -8,9 +8,6 @@ from xdg import xdg_config_home
from handle_acsm import handle_acsm from handle_acsm import handle_acsm
from handle_aax import handle_aax from handle_aax import handle_aax
__version__ = "1.0.0-alpha"
@click.version_option()
@click.command() @click.command()
@click.argument( @click.argument(
"path", "path",
@ -33,14 +30,14 @@ def main(path):
if path_type == 'ACSM': if path_type == 'ACSM':
click.echo('Received an ACSM (Adobe) file...') click.echo('Received an ACSM (Adobe) file...')
handle_acsm(path) handle_acsm(path)
elif path_type == 'AAX': #elif path_type == 'AAX':
click.echo('Received an AAX (Audible) file...') # click.echo('Received an AAX (Audible) file...')
handle_aax(path) # handle_aax(path)
else: else:
click.echo(f'Error: Files of type {path_type} are not supported.\n', err=True) 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('Only the following file types are currently supported:', err=True)
click.echo(' * ACSM (Adobe)\n', err=True) click.echo(' * ACSM (Adobe)\n', err=True)
click.echo(' * AAX (Audible)\n', err=True) #click.echo(' * AAX (Audible)\n', err=True)
click.echo('Please open a feature request at:', 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) click.echo(f' https://github.com/BentonEdmondson/knock/issues/new?title=Support%20{path_type}%20Files&labels=enhancement', err=True)
sys.exit(1) sys.exit(1)