Commit d393cc333be5
Changed files (4)
modules/audible-sync.nix
@@ -0,0 +1,182 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+
+with lib;
+
+let
+ cfg = config.services.audible-sync;
+in
+{
+ options.services.audible-sync = {
+ enable = mkEnableOption "Audible to Audiobookshelf sync service";
+
+ user = mkOption {
+ type = types.str;
+ default = "vincent";
+ description = "User to run the sync service as";
+ };
+
+ outputDir = mkOption {
+ type = types.str;
+ default = "/neo/audiobooks";
+ description = "Output directory for converted audiobooks";
+ };
+
+ tempDir = mkOption {
+ type = types.str;
+ default = "/neo/audiobooks/zz_import";
+ description = "Temporary directory for downloads";
+ };
+
+ quality = mkOption {
+ type = types.enum [
+ "best"
+ "high"
+ "normal"
+ ];
+ default = "best";
+ description = "Audio quality for downloads";
+ };
+
+ format = mkOption {
+ type = types.enum [
+ "m4b"
+ "mp3"
+ "m4a"
+ ];
+ default = "m4b";
+ description = "Output format for converted audiobooks";
+ };
+
+ schedule = mkOption {
+ type = types.str;
+ default = "daily";
+ description = "Systemd timer schedule (daily, weekly, etc.)";
+ };
+
+ time = mkOption {
+ type = types.str;
+ default = "03:00";
+ description = "Time of day to run sync (24-hour format)";
+ };
+
+ onCalendar = mkOption {
+ type = types.str;
+ default = "*-*-* 03:00:00";
+ description = "Full OnCalendar specification for systemd timer";
+ };
+
+ notification = {
+ enable = mkEnableOption "notifications via ntfy";
+
+ ntfyUrl = mkOption {
+ type = types.str;
+ default = "https://ntfy.sbr.pm";
+ description = "URL of ntfy server";
+ };
+
+ topic = mkOption {
+ type = types.str;
+ default = "audible-sync";
+ description = "ntfy topic for notifications";
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ # Install the converter tool
+ environment.systemPackages = with pkgs; [
+ audible-converter
+ ];
+
+ # Systemd timer for scheduled sync
+ systemd.timers.audible-sync = {
+ wantedBy = [ "timers.target" ];
+ timerConfig = {
+ OnCalendar = cfg.onCalendar;
+ Persistent = true;
+ RandomizedDelaySec = "10m";
+ };
+ };
+
+ # Systemd service to run the sync
+ systemd.services.audible-sync = {
+ description = "Sync Audible library to Audiobookshelf";
+ after = [ "network-online.target" ];
+ wants = [ "network-online.target" ];
+
+ environment = {
+ AUDIBLE_OUTPUT_DIR = cfg.outputDir;
+ AUDIBLE_TEMP_DIR = cfg.tempDir;
+ AUDIBLE_QUALITY = cfg.quality;
+ AUDIBLE_FORMAT = cfg.format;
+ HOME = "/home/${cfg.user}";
+ };
+
+ serviceConfig = {
+ Type = "oneshot";
+ User = cfg.user;
+ Group = "users";
+
+ # Run the sync command
+ ExecStart = "${pkgs.audible-converter}/bin/audible-converter sync";
+
+ # Notifications on success (if enabled)
+ ExecStartPost = mkIf cfg.notification.enable (
+ pkgs.writeShellScript "audible-sync-notify-success" ''
+ ${pkgs.curl}/bin/curl -H "Title: Audible Sync Complete" \
+ -H "Tags: white_check_mark,books" \
+ -d "Successfully synced Audible library to ${cfg.outputDir}" \
+ ${cfg.notification.ntfyUrl}/${cfg.notification.topic}
+ ''
+ );
+
+ # Ensure directories exist
+ ExecStartPre = pkgs.writeShellScript "audible-sync-prepare" ''
+ mkdir -p "${cfg.outputDir}"
+ mkdir -p "${cfg.tempDir}"
+ '';
+
+ # Note: We keep tempDir intact to reuse downloaded AAX files
+ # and reduce bandwidth usage on subsequent runs
+
+ # Resource limits
+ Nice = 15;
+ IOSchedulingClass = "idle";
+ CPUSchedulingPolicy = "idle";
+
+ # Security hardening
+ PrivateTmp = true;
+ NoNewPrivileges = true;
+ ProtectSystem = "strict";
+ ProtectHome = "read-only";
+ ReadWritePaths = [
+ cfg.outputDir
+ cfg.tempDir
+ ];
+ };
+
+ # Notify on failure (if enabled)
+ onFailure = mkIf cfg.notification.enable [ "audible-sync-failure.service" ];
+ };
+
+ # Failure notification service
+ systemd.services.audible-sync-failure = mkIf cfg.notification.enable {
+ description = "Notify on Audible sync failure";
+ serviceConfig = {
+ Type = "oneshot";
+ ExecStart = pkgs.writeShellScript "audible-sync-notify-failure" ''
+ ${pkgs.curl}/bin/curl -H "Title: Audible Sync Failed" \
+ -H "Priority: high" \
+ -H "Tags: warning,books" \
+ -d "Audible sync failed. Check logs: journalctl -u audible-sync" \
+ ${cfg.notification.ntfyUrl}/${cfg.notification.topic}
+ '';
+ };
+ };
+ };
+}
pkgs/audible-converter/convert.sh
@@ -10,6 +10,7 @@ OUTPUT_DIR="${AUDIBLE_OUTPUT_DIR:-$HOME/audiobooks}"
QUALITY="${AUDIBLE_QUALITY:-best}"
FORMAT="${AUDIBLE_FORMAT:-m4b}"
AUTHCODE="${AUDIBLE_AUTHCODE:-}"
+CLEANUP_ON_EXIT="${AUDIBLE_CLEANUP_ON_EXIT:-false}" # Set to 'true' to auto-cleanup temp files
# Colors for output
RED='\033[0;31m'
@@ -53,11 +54,12 @@ OPTIONS:
-h, --help Show this help message
ENVIRONMENT VARIABLES:
- AUDIBLE_OUTPUT_DIR Output directory for converted books
- AUDIBLE_TEMP_DIR Temporary directory for downloads
- AUDIBLE_QUALITY Audio quality setting
- AUDIBLE_FORMAT Output format
- AUDIBLE_AUTHCODE Activation bytes for AAX DRM removal
+ AUDIBLE_OUTPUT_DIR Output directory for converted books
+ AUDIBLE_TEMP_DIR Temporary directory for downloads (kept by default)
+ AUDIBLE_QUALITY Audio quality setting
+ AUDIBLE_FORMAT Output format
+ AUDIBLE_AUTHCODE Activation bytes for AAX DRM removal
+ AUDIBLE_CLEANUP_ON_EXIT Set to 'true' to auto-delete temp files on exit
EXAMPLES:
# Sync library (download and convert new books)
@@ -108,11 +110,13 @@ setup_dirs() {
mkdir -p "$OUTPUT_DIR"
}
-# Cleanup temporary files
+# Cleanup temporary files (manual or via AUDIBLE_CLEANUP_ON_EXIT=true)
+# By default, we keep temp files to reuse downloaded AAX files on subsequent runs
cleanup() {
if [ -d "$TEMP_DIR" ]; then
- log_info "Cleaning up temporary files..."
+ log_info "Cleaning up temporary files in: $TEMP_DIR"
rm -rf "$TEMP_DIR"
+ log_info "Cleanup complete"
fi
}
@@ -121,7 +125,7 @@ download_all() {
log_info "Exporting library metadata..."
local library_json="$TEMP_DIR/library.json"
- audible library export --output "$library_json"
+ audible library export --format json --output "$library_json"
local total_books
total_books=$(jq length "$library_json")
@@ -347,8 +351,13 @@ main() {
esac
done
- # Trap cleanup on exit
- trap cleanup EXIT
+ # Optionally cleanup on exit (default: keep files for reuse)
+ if [ "$CLEANUP_ON_EXIT" = "true" ]; then
+ log_info "Auto-cleanup enabled (AUDIBLE_CLEANUP_ON_EXIT=true)"
+ trap cleanup EXIT
+ else
+ log_info "Keeping temp files in $TEMP_DIR for reuse (set AUDIBLE_CLEANUP_ON_EXIT=true to auto-delete)"
+ fi
# Check dependencies
check_dependencies
pkgs/audible-converter/README.md
@@ -107,9 +107,10 @@ audible-converter --output ~/audiobooks convert book.aax
Configure defaults using environment variables:
- `AUDIBLE_OUTPUT_DIR` - Output directory for converted books
-- `AUDIBLE_TEMP_DIR` - Temporary directory for downloads
+- `AUDIBLE_TEMP_DIR` - Temporary directory for downloads (kept by default for reuse)
- `AUDIBLE_QUALITY` - Audio quality setting (best, high, normal)
- `AUDIBLE_FORMAT` - Output format (m4b, mp3, m4a)
+- `AUDIBLE_CLEANUP_ON_EXIT` - Set to `true` to auto-delete temp files on exit (default: false)
Example:
@@ -123,9 +124,12 @@ On rhea (with NFS-mounted storage):
```bash
export AUDIBLE_OUTPUT_DIR="/neo/audiobooks"
+export AUDIBLE_TEMP_DIR="/neo/audiobooks/zz_import" # Persistent for reuse
audible-converter sync
```
+**Note**: By default, downloaded AAX files in `AUDIBLE_TEMP_DIR` are **kept** between runs to save bandwidth and time. Only new books will be downloaded on subsequent syncs. Set `AUDIBLE_CLEANUP_ON_EXIT=true` if you want to auto-delete temp files after each run.
+
## Output Structure
Books are automatically organized for Audiobookshelf:
systems/rhea/extra.nix
@@ -10,6 +10,7 @@
imports = [
../common/services/samba.nix
../common/services/homepage.nix
+ ../../modules/audible-sync.nix
];
age.secrets."gandi.env" = {
@@ -469,6 +470,20 @@
group = "users";
openFirewall = true;
};
+ audible-sync = {
+ enable = true;
+ user = "vincent";
+ outputDir = "/neo/audiobooks";
+ tempDir = "/neo/audiobooks/zz_import"; # Keep AAX files for reuse
+ quality = "best";
+ format = "m4b";
+ onCalendar = "*-*-* 03:00:00"; # Daily at 3 AM
+ notification = {
+ enable = true;
+ ntfyUrl = "https://ntfy.sbr.pm";
+ topic = "homelab";
+ };
+ };
transmission = {
enable = true;
user = "vincent";
@@ -613,6 +628,7 @@
lm_sensors
gnumake
audible-converter
+ audible-cli
];
}