diff --git a/ansible/roles/devpi/defaults/main.yml b/ansible/roles/devpi/defaults/main.yml
deleted file mode 100644
index 0fc0569..0000000
--- a/ansible/roles/devpi/defaults/main.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-devpi_port: 3141
-devpi_serverdir: /Users/erichblume/devpi
-devpi_log_dir: /Users/erichblume/Library/Logs
-devpi_host: 0.0.0.0 # Listen on all interfaces for Tailscale
-devpi_outside_url: https://pypi.tail8d86e.ts.net # URL for Tailscale proxy
-devpi_secretfile: /Users/erichblume/devpi/.secret # Persistent auth secret
diff --git a/ansible/roles/devpi/handlers/main.yml b/ansible/roles/devpi/handlers/main.yml
deleted file mode 100644
index 7e29c43..0000000
--- a/ansible/roles/devpi/handlers/main.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-- name: Reload devpi
- ansible.builtin.shell: |
- launchctl unload ~/Library/LaunchAgents/mcquack.eblume.devpi.plist 2>/dev/null || true
- launchctl load ~/Library/LaunchAgents/mcquack.eblume.devpi.plist
- changed_when: true
diff --git a/ansible/roles/devpi/tasks/main.yml b/ansible/roles/devpi/tasks/main.yml
deleted file mode 100644
index 2c6d03e..0000000
--- a/ansible/roles/devpi/tasks/main.yml
+++ /dev/null
@@ -1,55 +0,0 @@
----
-# Note: devpi is installed via mise (pipx/uvx), not managed here.
-#
-# ONE-TIME SETUP (before running ansible):
-#
-# 1. Add to ~/.config/mise/config.toml on indri:
-#
-# [tools]
-# "pipx:devpi-server" = { version = "latest", uvx = "true", uvx_args = "--with devpi-web" }
-# "pipx:devpi-client" = { version = "latest", uvx = "true" }
-#
-# 2. Install: mise install
-#
-# 3. Initialize with root password (generate password in 1password):
-# mise x -- devpi-init --serverdir {{ devpi_serverdir }} --root-passwd YOUR_PASSWORD
-#
-# 4. Run ansible to deploy LaunchAgent
-#
-# 5. Set up Tailscale service (see management log)
-
-- name: Ensure devpi data directory exists
- ansible.builtin.file:
- path: "{{ devpi_serverdir }}"
- state: directory
- mode: '0755'
-
-- name: Generate devpi secret file if not exists
- ansible.builtin.shell: |
- openssl rand -hex 32 > "{{ devpi_secretfile }}"
- args:
- creates: "{{ devpi_secretfile }}"
-
-- name: Ensure devpi secret file has secure permissions
- ansible.builtin.file:
- path: "{{ devpi_secretfile }}"
- mode: '0600'
-
-- name: Deploy devpi LaunchAgent plist
- ansible.builtin.template:
- src: devpi.plist.j2
- dest: ~/Library/LaunchAgents/mcquack.eblume.devpi.plist
- mode: '0644'
- notify: Reload devpi
-
-- name: Check if devpi LaunchAgent is loaded
- ansible.builtin.command: launchctl list mcquack.eblume.devpi
- register: devpi_launchctl_check
- changed_when: false
- failed_when: false
-
-- name: Load devpi LaunchAgent if not loaded
- ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.devpi.plist
- when: devpi_launchctl_check.rc != 0
- changed_when: true
- failed_when: false
diff --git a/ansible/roles/devpi/templates/devpi.plist.j2 b/ansible/roles/devpi/templates/devpi.plist.j2
deleted file mode 100644
index b2ed6aa..0000000
--- a/ansible/roles/devpi/templates/devpi.plist.j2
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
-
- KeepAlive
-
- Label
- mcquack.eblume.devpi
- EnvironmentVariables
-
- PATH
- /opt/homebrew/bin:/usr/bin:/bin
-
- ProgramArguments
-
- /opt/homebrew/opt/mise/bin/mise
- x
- --
- devpi-server
- --serverdir
- {{ devpi_serverdir }}
- --host
- {{ devpi_host }}
- --port
- {{ devpi_port }}
- --outside-url
- {{ devpi_outside_url }}
- --secretfile
- {{ devpi_secretfile }}
-
- RunAtLoad
-
- StandardErrorPath
- {{ devpi_log_dir }}/mcquack.devpi.err.log
- StandardOutPath
- {{ devpi_log_dir }}/mcquack.devpi.out.log
-
-
diff --git a/ansible/roles/devpi_metrics/defaults/main.yml b/ansible/roles/devpi_metrics/defaults/main.yml
deleted file mode 100644
index d1aa18b..0000000
--- a/ansible/roles/devpi_metrics/defaults/main.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-devpi_metrics_url: http://localhost:3141/+status
-devpi_metrics_dir: /opt/homebrew/var/node_exporter/textfile
-devpi_metrics_script: /Users/erichblume/bin/devpi-metrics
-devpi_metrics_interval: 60 # seconds between metric collection
-devpi_metrics_log_dir: /opt/homebrew/var/log
diff --git a/ansible/roles/devpi_metrics/handlers/main.yml b/ansible/roles/devpi_metrics/handlers/main.yml
deleted file mode 100644
index 81bfd1d..0000000
--- a/ansible/roles/devpi_metrics/handlers/main.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-- name: Reload devpi-metrics
- ansible.builtin.shell: |
- launchctl unload ~/Library/LaunchAgents/mcquack.eblume.devpi-metrics.plist 2>/dev/null || true
- launchctl load ~/Library/LaunchAgents/mcquack.eblume.devpi-metrics.plist
- changed_when: true
diff --git a/ansible/roles/devpi_metrics/meta/main.yml b/ansible/roles/devpi_metrics/meta/main.yml
deleted file mode 100644
index b05a43b..0000000
--- a/ansible/roles/devpi_metrics/meta/main.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-# Role ordering is controlled by indri.yml playbook - do not add dependencies here
-# (Ansible's tag accumulation prevents proper deduplication when using meta dependencies)
-dependencies: []
diff --git a/ansible/roles/devpi_metrics/tasks/main.yml b/ansible/roles/devpi_metrics/tasks/main.yml
deleted file mode 100644
index b267648..0000000
--- a/ansible/roles/devpi_metrics/tasks/main.yml
+++ /dev/null
@@ -1,37 +0,0 @@
----
-- name: Ensure metrics directory exists
- ansible.builtin.file:
- path: "{{ devpi_metrics_dir }}"
- state: directory
- mode: '0755'
-
-- name: Ensure log directory exists
- ansible.builtin.file:
- path: "{{ devpi_metrics_log_dir }}"
- state: directory
- mode: '0755'
-
-- name: Deploy devpi-metrics script
- ansible.builtin.template:
- src: devpi-metrics.sh.j2
- dest: "{{ devpi_metrics_script }}"
- mode: '0755'
-
-- name: Deploy devpi-metrics LaunchAgent plist
- ansible.builtin.template:
- src: devpi-metrics.plist.j2
- dest: ~/Library/LaunchAgents/mcquack.eblume.devpi-metrics.plist
- mode: '0644'
- notify: Reload devpi-metrics
-
-- name: Check if devpi-metrics LaunchAgent is loaded
- ansible.builtin.command: launchctl list mcquack.eblume.devpi-metrics
- register: devpi_metrics_launchctl_check
- changed_when: false
- failed_when: false
-
-- name: Load devpi-metrics LaunchAgent if not loaded
- ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.devpi-metrics.plist
- when: devpi_metrics_launchctl_check.rc != 0
- changed_when: true
- failed_when: false
diff --git a/ansible/roles/devpi_metrics/templates/devpi-metrics.plist.j2 b/ansible/roles/devpi_metrics/templates/devpi-metrics.plist.j2
deleted file mode 100644
index a8141df..0000000
--- a/ansible/roles/devpi_metrics/templates/devpi-metrics.plist.j2
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
- Label
- mcquack.eblume.devpi-metrics
- ProgramArguments
-
- {{ devpi_metrics_script }}
-
- StartInterval
- {{ devpi_metrics_interval }}
- RunAtLoad
-
- StandardErrorPath
- {{ devpi_metrics_log_dir }}/mcquack.devpi-metrics.err.log
- StandardOutPath
- {{ devpi_metrics_log_dir }}/mcquack.devpi-metrics.out.log
-
-
diff --git a/ansible/roles/devpi_metrics/templates/devpi-metrics.sh.j2 b/ansible/roles/devpi_metrics/templates/devpi-metrics.sh.j2
deleted file mode 100644
index 2a1141d..0000000
--- a/ansible/roles/devpi_metrics/templates/devpi-metrics.sh.j2
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/bin/bash
-# {{ ansible_managed }}
-# Collects devpi-server metrics for node_exporter textfile collector
-
-set -euo pipefail
-
-STATUS_URL="{{ devpi_metrics_url }}"
-OUTPUT_FILE="{{ devpi_metrics_dir }}/devpi.prom"
-TEMP_FILE="${OUTPUT_FILE}.tmp"
-
-# Fetch status JSON
-status_json=$(curl -s -H "Accept: application/json" "$STATUS_URL" 2>/dev/null)
-
-if [ -z "$status_json" ] || ! echo "$status_json" | jq -e '.result' >/dev/null 2>&1; then
- echo "Failed to fetch devpi status" >&2
- exit 1
-fi
-
-# Start output file
-cat > "$TEMP_FILE" << 'HEADER'
-# HELP devpi_up devpi-server is up and responding
-# TYPE devpi_up gauge
-devpi_up 1
-
-HEADER
-
-# Extract serial number using jq
-serial=$(echo "$status_json" | jq -r '.result.serial // empty')
-if [ -n "$serial" ]; then
- cat >> "$TEMP_FILE" << EOF
-# HELP devpi_serial Current changelog serial number
-# TYPE devpi_serial gauge
-devpi_serial $serial
-
-EOF
-fi
-
-# Parse metrics array using jq - format is ["name", "type", value]
-echo "$status_json" | jq -r '.result.metrics[]? | @json' | while read -r metric_json; do
- name=$(echo "$metric_json" | jq -r '.[0]')
- type=$(echo "$metric_json" | jq -r '.[1]')
- value=$(echo "$metric_json" | jq -r '.[2]')
-
- # Write metric in Prometheus format
- cat >> "$TEMP_FILE" << EOF
-# HELP $name devpi metric
-# TYPE $name $type
-$name $value
-
-EOF
-done
-
-# Atomic move
-mv "$TEMP_FILE" "$OUTPUT_FILE"
diff --git a/ansible/roles/kiwix/defaults/main.yml b/ansible/roles/kiwix/defaults/main.yml
deleted file mode 100644
index 41f3abb..0000000
--- a/ansible/roles/kiwix/defaults/main.yml
+++ /dev/null
@@ -1,131 +0,0 @@
----
-kiwix_serve_bin: /Users/erichblume/code/3rd/kiwix-tools/kiwix-serve
-kiwix_zim_dir: /Users/erichblume/code/3rd/kiwix-tools
-kiwix_bin_dir: /Users/erichblume/.local/bin
-kiwix_port: 5501
-kiwix_log_dir: /Users/erichblume/Library/Logs
-
-# Transmission integration
-# When enabled, ZIM archives are downloaded via BitTorrent instead of direct HTTP
-kiwix_use_transmission: true
-kiwix_torrent_base_url: "https://download.kiwix.org/zim"
-
-# ZIM archives to download and serve
-# Each item needs: category, filename
-# Torrent URL: {{ kiwix_torrent_base_url }}/{{ category }}/{{ filename }}.torrent
-kiwix_zim_archives:
- # Wikipedia - Top 1M articles with images (43G)
- - category: wikipedia
- filename: wikipedia_en_top1m_maxi_2025-09.zim
-
- ## Other Wikipedia options:
- # - category: wikipedia
- # filename: wikipedia_en_all_maxi_2025-08.zim # 111G - Full English Wikipedia
- # - category: wikipedia
- # filename: wikipedia_en_top_maxi_2025-12.zim # 7.6G - Top 100K articles
-
- # Project Gutenberg - Public domain books (72G)
- - category: gutenberg
- filename: gutenberg_en_all_2023-08.zim
-
- ## Newer Gutenberg (much larger, unclear why):
- # - category: gutenberg
- # filename: gutenberg_en_all_2025-11.zim # 206G - Full collection (2025)
-
- # iFixit - Repair guides (3.3G)
- - category: ifixit
- filename: ifixit_en_all_2025-12.zim
-
- # Stack Exchange
- - category: stack_exchange
- filename: superuser.com_en_all_2025-12.zim # 3.7G
- # - category: stack_exchange
- # filename: serverfault.com_en_all_2025-12.zim # 1.5G
- # - category: stack_exchange
- # filename: askubuntu.com_en_all_2025-12.zim # 2.6G
- # - category: stack_exchange
- # filename: unix.stackexchange.com_en_all_2025-12.zim # 1.2G
- - category: stack_exchange
- filename: math.stackexchange.com_en_all_2025-12.zim # 6.9G
- # - category: stack_exchange
- # filename: stackoverflow.com_en_all_2023-11.zim # 75G - Full StackOverflow
-
- # LibreTexts - Open educational resources
- - category: libretexts
- filename: libretexts.org_en_bio_2025-01.zim # 2.1G
- - category: libretexts
- filename: libretexts.org_en_chem_2025-01.zim # 2.0G
- - category: libretexts
- filename: libretexts.org_en_eng_2025-01.zim # 647M
- - category: libretexts
- filename: libretexts.org_en_math_2025-01.zim # 744M
- - category: libretexts
- filename: libretexts.org_en_phys_2025-01.zim # 464M
- - category: libretexts
- filename: libretexts.org_en_human_2025-01.zim # 3.5G
-
- # DevDocs - Programming documentation
- - category: devdocs
- filename: devdocs_en_bash_2026-01.zim
- - category: devdocs
- filename: devdocs_en_c_2026-01.zim
- - category: devdocs
- filename: devdocs_en_click_2026-01.zim
- - category: devdocs
- filename: devdocs_en_cmake_2026-01.zim
- - category: devdocs
- filename: devdocs_en_cpp_2026-01.zim
- - category: devdocs
- filename: devdocs_en_css_2026-01.zim
- - category: devdocs
- filename: devdocs_en_django-rest-framework_2026-01.zim
- - category: devdocs
- filename: devdocs_en_django_2026-01.zim
- - category: devdocs
- filename: devdocs_en_docker_2026-01.zim
- - category: devdocs
- filename: devdocs_en_duckdb_2026-01.zim
- - category: devdocs
- filename: devdocs_en_fish_2026-01.zim
- - category: devdocs
- filename: devdocs_en_gcc_2026-01.zim
- - category: devdocs
- filename: devdocs_en_git_2026-01.zim
- - category: devdocs
- filename: devdocs_en_go_2026-01.zim
- - category: devdocs
- filename: devdocs_en_godot_2026-01.zim
- - category: devdocs
- filename: devdocs_en_hammerspoon_2026-01.zim
- - category: devdocs
- filename: devdocs_en_homebrew_2026-01.zim
- - category: devdocs
- filename: devdocs_en_javascript_2026-01.zim
- - category: devdocs
- filename: devdocs_en_kubectl_2026-01.zim
- - category: devdocs
- filename: devdocs_en_kubernetes_2026-01.zim
- - category: devdocs
- filename: devdocs_en_latex_2026-01.zim
- - category: devdocs
- filename: devdocs_en_lua_2026-01.zim
- - category: devdocs
- filename: devdocs_en_markdown_2026-01.zim
- - category: devdocs
- filename: devdocs_en_nginx_2026-01.zim
- - category: devdocs
- filename: devdocs_en_nix_2026-01.zim
- - category: devdocs
- filename: devdocs_en_postgresql_2026-01.zim
- - category: devdocs
- filename: devdocs_en_python_2026-01.zim
- - category: devdocs
- filename: devdocs_en_redis_2026-01.zim
- - category: devdocs
- filename: devdocs_en_sqlite_2026-01.zim
- - category: devdocs
- filename: devdocs_en_typescript_2026-01.zim
- - category: devdocs
- filename: devdocs_en_werkzeug_2026-01.zim
- - category: devdocs
- filename: devdocs_en_zig_2026-01.zim
diff --git a/ansible/roles/kiwix/handlers/main.yml b/ansible/roles/kiwix/handlers/main.yml
deleted file mode 100644
index ef6e408..0000000
--- a/ansible/roles/kiwix/handlers/main.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-- name: Restart kiwix-serve
- ansible.builtin.shell: |
- launchctl unload ~/Library/LaunchAgents/mcquack.eblume.kiwix-serve.plist 2>/dev/null || true
- launchctl load ~/Library/LaunchAgents/mcquack.eblume.kiwix-serve.plist
- changed_when: true
diff --git a/ansible/roles/kiwix/meta/main.yml b/ansible/roles/kiwix/meta/main.yml
deleted file mode 100644
index b05a43b..0000000
--- a/ansible/roles/kiwix/meta/main.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-# Role ordering is controlled by indri.yml playbook - do not add dependencies here
-# (Ansible's tag accumulation prevents proper deduplication when using meta dependencies)
-dependencies: []
diff --git a/ansible/roles/kiwix/tasks/main.yml b/ansible/roles/kiwix/tasks/main.yml
deleted file mode 100644
index 85a09a2..0000000
--- a/ansible/roles/kiwix/tasks/main.yml
+++ /dev/null
@@ -1,119 +0,0 @@
----
-- name: Ensure kiwix ZIM directory exists
- ansible.builtin.file:
- path: "{{ kiwix_zim_dir }}"
- state: directory
- mode: '0755'
-
-- name: Ensure kiwix bin directory exists
- ansible.builtin.file:
- path: "{{ kiwix_bin_dir }}"
- state: directory
- mode: '0755'
-
-# --- Deploy management scripts ---
-- name: Deploy kiwix torrent sync script
- ansible.builtin.template:
- src: kiwix-sync-torrents.sh.j2
- dest: "{{ kiwix_bin_dir }}/kiwix-sync-torrents.sh"
- mode: '0755'
- when: kiwix_use_transmission
-
-- name: Deploy kiwix symlink script
- ansible.builtin.template:
- src: kiwix-symlink-zims.sh.j2
- dest: "{{ kiwix_bin_dir }}/kiwix-symlink-zims.sh"
- mode: '0755'
- when: kiwix_use_transmission
-
-- name: Deploy kiwix torrent list
- ansible.builtin.template:
- src: kiwix-torrents.txt.j2
- dest: "{{ kiwix_bin_dir }}/kiwix-torrents.txt"
- mode: '0644'
- when: kiwix_use_transmission
-
-# --- Transmission-based torrent management ---
-- name: Check transmission daemon is responding
- ansible.builtin.command: transmission-remote -l
- register: kiwix_transmission_check
- changed_when: false
- failed_when: false
- when: kiwix_use_transmission
-
-- name: Fail if transmission is not running
- ansible.builtin.fail:
- msg: "Transmission daemon is not responding. Ensure transmission role ran successfully."
- when: kiwix_use_transmission and kiwix_transmission_check.rc != 0
-
-- name: Sync ZIM torrents to transmission
- ansible.builtin.command: "{{ kiwix_bin_dir }}/kiwix-sync-torrents.sh {{ kiwix_bin_dir }}/kiwix-torrents.txt"
- register: kiwix_torrent_sync
- changed_when: "'Added:' in kiwix_torrent_sync.stdout"
- when: kiwix_use_transmission
-
-# --- Symlink completed ZIM files ---
-- name: Symlink completed ZIM files to kiwix directory
- ansible.builtin.command: "{{ kiwix_bin_dir }}/kiwix-symlink-zims.sh {{ transmission_download_dir }} {{ kiwix_zim_dir }}"
- register: kiwix_symlink_result
- changed_when: "'Linked:' in kiwix_symlink_result.stdout"
- when: kiwix_use_transmission
- notify: Restart kiwix-serve
-
-# --- Fallback: Direct HTTP download (original behavior) ---
-- name: Check which ZIM archives exist (direct download mode)
- ansible.builtin.stat:
- path: "{{ kiwix_zim_dir }}/{{ item.filename }}"
- get_checksum: false
- loop: "{{ kiwix_zim_archives }}"
- loop_control:
- label: "{{ item.filename }}"
- register: kiwix_zim_stat
- when: not kiwix_use_transmission
-
-- name: Download missing ZIM archives (direct download mode)
- ansible.builtin.get_url:
- url: "https://download.kiwix.org/zim/{{ item.item.category }}/{{ item.item.filename }}"
- dest: "{{ kiwix_zim_dir }}/{{ item.item.filename }}"
- mode: '0644'
- timeout: 3600
- loop: "{{ kiwix_zim_stat.results | default([]) }}"
- loop_control:
- label: "{{ item.item.filename | default('unknown') }}"
- when:
- - not kiwix_use_transmission
- - item.stat is defined
- - not item.stat.exists
- notify: Restart kiwix-serve
-
-# --- Determine which archives are available ---
-- name: Find available ZIM archives in kiwix directory
- ansible.builtin.find:
- paths: "{{ kiwix_zim_dir }}"
- patterns: "*.zim"
- file_type: any # includes symlinks
- register: kiwix_available_zim_files
-
-- name: Build list of available archive filenames
- ansible.builtin.set_fact:
- kiwix_available_archives: "{{ kiwix_available_zim_files.files | map(attribute='path') | map('basename') | list }}"
-
-# --- LaunchAgent deployment ---
-- name: Deploy kiwix-serve LaunchAgent plist
- ansible.builtin.template:
- src: kiwix-serve.plist.j2
- dest: ~/Library/LaunchAgents/mcquack.eblume.kiwix-serve.plist
- mode: '0644'
- notify: Restart kiwix-serve
-
-- name: Check if kiwix-serve LaunchAgent is loaded
- ansible.builtin.command: launchctl list mcquack.eblume.kiwix-serve
- register: kiwix_launchctl_check
- changed_when: false
- failed_when: false
-
-- name: Load kiwix-serve LaunchAgent if not loaded
- ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.kiwix-serve.plist
- when: kiwix_launchctl_check.rc != 0
- changed_when: true
- failed_when: false
diff --git a/ansible/roles/kiwix/templates/kiwix-serve.plist.j2 b/ansible/roles/kiwix/templates/kiwix-serve.plist.j2
deleted file mode 100644
index 26a61d1..0000000
--- a/ansible/roles/kiwix/templates/kiwix-serve.plist.j2
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
- KeepAlive
-
- Label
- mcquack.eblume.kiwix-serve
- ProgramArguments
-
- {{ kiwix_serve_bin }}
- --port={{ kiwix_port }}
-{% for filename in kiwix_available_archives %}
- {{ kiwix_zim_dir }}/{{ filename }}
-{% endfor %}
-
- RunAtLoad
-
- StandardErrorPath
- {{ kiwix_log_dir }}/mcquack.kiwix-serve.err.log
- StandardOutPath
- {{ kiwix_log_dir }}/mcquack.kiwix-serve.out.log
-
-
diff --git a/ansible/roles/kiwix/templates/kiwix-symlink-zims.sh.j2 b/ansible/roles/kiwix/templates/kiwix-symlink-zims.sh.j2
deleted file mode 100644
index 29e7630..0000000
--- a/ansible/roles/kiwix/templates/kiwix-symlink-zims.sh.j2
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/bash
-# Symlink completed ZIM files from download directory to kiwix directory
-set -euo pipefail
-
-SOURCE_DIR="${1:-}"
-TARGET_DIR="${2:-}"
-
-if [[ -z "$SOURCE_DIR" || -z "$TARGET_DIR" ]]; then
- echo "Usage: $0 " >&2
- exit 1
-fi
-
-if [[ ! -d "$SOURCE_DIR" ]]; then
- echo "Error: Source directory not found: $SOURCE_DIR" >&2
- exit 1
-fi
-
-if [[ ! -d "$TARGET_DIR" ]]; then
- echo "Error: Target directory not found: $TARGET_DIR" >&2
- exit 1
-fi
-
-created=0
-skipped=0
-
-# Find all .zim files in source directory
-for zim_file in "$SOURCE_DIR"/*.zim; do
- # Handle case where no .zim files exist
- [[ -e "$zim_file" ]] || continue
-
- filename=$(basename "$zim_file")
- target_path="$TARGET_DIR/$filename"
-
- if [[ -e "$target_path" || -L "$target_path" ]]; then
- ((skipped++)) || true
- else
- ln -s "$zim_file" "$target_path"
- echo "Linked: $filename"
- ((created++)) || true
- fi
-done
-
-echo "Symlink complete: $created created, $skipped already present"
-
-# Exit with special code if new symlinks were created (for ansible changed detection)
-if [[ $created -gt 0 ]]; then
- exit 0
-else
- exit 0
-fi
diff --git a/ansible/roles/kiwix/templates/kiwix-sync-torrents.sh.j2 b/ansible/roles/kiwix/templates/kiwix-sync-torrents.sh.j2
deleted file mode 100644
index 4a293b3..0000000
--- a/ansible/roles/kiwix/templates/kiwix-sync-torrents.sh.j2
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/bin/bash
-# Sync ZIM archive torrents to transmission
-# Reads torrent URLs from stdin or file, adds any missing to transmission
-set -euo pipefail
-
-TORRENT_LIST="${1:-}"
-
-if [[ -z "$TORRENT_LIST" ]]; then
- echo "Usage: $0 " >&2
- exit 1
-fi
-
-if [[ ! -f "$TORRENT_LIST" ]]; then
- echo "Error: Torrent list file not found: $TORRENT_LIST" >&2
- exit 1
-fi
-
-# Get current torrents from transmission (extract names, skip header/footer)
-# Note: Use sed '$d' instead of head -n -1 for macOS compatibility
-current_torrents=$(transmission-remote -l 2>/dev/null | tail -n +2 | sed '$d' | awk '{print $NF}' || true)
-
-added=0
-skipped=0
-
-while IFS= read -r torrent_url || [[ -n "$torrent_url" ]]; do
- # Skip empty lines and comments
- [[ -z "$torrent_url" || "$torrent_url" =~ ^# ]] && continue
-
- # Extract base name from URL (remove .torrent extension and path)
- base_name=$(basename "$torrent_url" .torrent)
- # Also try without .zim in case transmission reports it differently
- base_without_zim="${base_name%.zim}"
-
- # Check if already in transmission
- if echo "$current_torrents" | grep -qF "$base_without_zim"; then
- ((skipped++)) || true
- else
- if transmission-remote -a "$torrent_url" 2>/dev/null; then
- echo "Added: $base_name"
- ((added++)) || true
- else
- echo "Warning: Failed to add $torrent_url" >&2
- fi
- fi
-done < "$TORRENT_LIST"
-
-echo "Sync complete: $added added, $skipped already present"
diff --git a/ansible/roles/kiwix/templates/kiwix-torrents.txt.j2 b/ansible/roles/kiwix/templates/kiwix-torrents.txt.j2
deleted file mode 100644
index fcc4b4e..0000000
--- a/ansible/roles/kiwix/templates/kiwix-torrents.txt.j2
+++ /dev/null
@@ -1,5 +0,0 @@
-# ZIM archive torrent URLs for kiwix
-# Generated by ansible - do not edit manually
-{% for archive in kiwix_zim_archives %}
-{{ kiwix_torrent_base_url }}/{{ archive.category }}/{{ archive.filename }}.torrent
-{% endfor %}
diff --git a/ansible/roles/node_exporter/defaults/main.yml b/ansible/roles/node_exporter/defaults/main.yml
deleted file mode 100644
index a8f3e63..0000000
--- a/ansible/roles/node_exporter/defaults/main.yml
+++ /dev/null
@@ -1,2 +0,0 @@
----
-node_exporter_textfile_dir: /opt/homebrew/var/node_exporter/textfile
diff --git a/ansible/roles/node_exporter/handlers/main.yml b/ansible/roles/node_exporter/handlers/main.yml
deleted file mode 100644
index fa0c59b..0000000
--- a/ansible/roles/node_exporter/handlers/main.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-- name: Restart node_exporter
- ansible.builtin.command: brew services restart node_exporter
- listen: Restart node_exporter
- changed_when: true
diff --git a/ansible/roles/node_exporter/tasks/main.yml b/ansible/roles/node_exporter/tasks/main.yml
deleted file mode 100644
index 55c0398..0000000
--- a/ansible/roles/node_exporter/tasks/main.yml
+++ /dev/null
@@ -1,22 +0,0 @@
----
-# Note: node_exporter is installed via homebrew manually.
-# This role manages the args file to enable textfile collector.
-
-- name: Create textfile collector directory
- ansible.builtin.file:
- path: "{{ node_exporter_textfile_dir }}"
- state: directory
- mode: '0755'
-
-- name: Configure node_exporter args
- ansible.builtin.template:
- src: node_exporter.args.j2
- dest: /opt/homebrew/etc/node_exporter.args
- mode: '0644'
- notify: Restart node_exporter
-
-- name: Ensure node_exporter service is started
- ansible.builtin.command: brew services start node_exporter
- register: node_exporter_brew_start
- changed_when: "'Successfully started' in node_exporter_brew_start.stdout"
- failed_when: false
diff --git a/ansible/roles/node_exporter/templates/node_exporter.args.j2 b/ansible/roles/node_exporter/templates/node_exporter.args.j2
deleted file mode 100644
index be763d0..0000000
--- a/ansible/roles/node_exporter/templates/node_exporter.args.j2
+++ /dev/null
@@ -1 +0,0 @@
---collector.textfile.directory={{ node_exporter_textfile_dir }}
diff --git a/ansible/roles/podman/handlers/main.yml b/ansible/roles/podman/handlers/main.yml
deleted file mode 100644
index 89a6a94..0000000
--- a/ansible/roles/podman/handlers/main.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-# No handlers currently - podman machine start is unreliable via Ansible
-# See known issue in tasks/main.yml
diff --git a/ansible/roles/podman/tasks/main.yml b/ansible/roles/podman/tasks/main.yml
deleted file mode 100644
index e1bb78f..0000000
--- a/ansible/roles/podman/tasks/main.yml
+++ /dev/null
@@ -1,58 +0,0 @@
----
-# Podman installation and machine setup for indri
-# Used as container runtime for minikube
-#
-# KNOWN ISSUE: podman machine init/start has reliability issues when run via
-# Ansible/SSH. The machine sometimes gets stuck in "Starting" state due to a
-# race condition (see https://github.com/containers/podman/issues/16945).
-# Additionally, Apple Hypervisor may require GUI session context.
-#
-# WORKAROUND: If the machine fails to start via Ansible, manually run on indri:
-# podman machine rm -f podman-machine-default
-# podman machine init --cpus 4 --memory 8192 --disk-size 220
-# podman machine start
-#
-# TODO: Investigate proper LaunchAgent or other solution for reliable automation.
-
-- name: Install podman via homebrew
- community.general.homebrew:
- name: podman
- state: present
-
-- name: Check if podman machine exists
- ansible.builtin.command:
- cmd: podman machine list --format json
- register: podman_machine_list
- changed_when: false
- check_mode: false # Safe to run in check mode - read-only
-
-- name: Initialize podman machine (if not exists)
- ansible.builtin.command:
- cmd: podman machine init --cpus 4 --memory 8192 --disk-size 220
- register: podman_init
- changed_when: podman_init.rc == 0
- failed_when: podman_init.rc not in [0, 125] # 125 = already exists
- when: podman_machine_list.stdout == '[]'
-
-- name: Check if podman machine is running
- ansible.builtin.command:
- cmd: podman machine list --format "{{ '{{' }}.Running{{ '}}' }}"
- register: podman_running
- changed_when: false
- check_mode: false # Safe to run in check mode - read-only
-
-- name: Start podman machine (if stopped)
- ansible.builtin.command:
- cmd: podman machine start
- register: podman_start
- changed_when: "'started successfully' in podman_start.stdout"
- failed_when: false # Don't fail - see known issue above
- when: "'true' not in podman_running.stdout"
-
-- name: Warn if podman machine failed to start
- ansible.builtin.debug:
- msg: "WARNING: podman machine may not have started. Run 'podman machine start' manually on indri if needed."
- when:
- - "'true' not in podman_running.stdout"
- - podman_start is defined
- - podman_start.rc != 0 or "'started successfully' not in podman_start.stdout"
diff --git a/ansible/roles/transmission/defaults/main.yml b/ansible/roles/transmission/defaults/main.yml
deleted file mode 100644
index 6eb9391..0000000
--- a/ansible/roles/transmission/defaults/main.yml
+++ /dev/null
@@ -1,24 +0,0 @@
----
-# Homebrew's transmission-cli service uses this config directory
-transmission_config_dir: /opt/homebrew/var/transmission
-
-# Download directories
-transmission_download_dir: /Users/erichblume/transmission
-transmission_incomplete_dir: /Users/erichblume/transmission/.incomplete
-
-# RPC settings (local only - no authentication needed)
-transmission_rpc_enabled: true
-transmission_rpc_port: 9091
-transmission_rpc_bind_address: "127.0.0.1"
-transmission_rpc_authentication_required: false
-transmission_rpc_whitelist_enabled: true
-transmission_rpc_whitelist: "127.0.0.1"
-
-# Speed limits (KB/s, 0 = unlimited)
-transmission_speed_limit_down: 0
-transmission_speed_limit_up: 100
-
-# P2P settings
-transmission_dht_enabled: true
-transmission_pex_enabled: true
-transmission_encryption: 1 # 0=prefer unencrypted, 1=prefer encrypted, 2=require encrypted
diff --git a/ansible/roles/transmission/handlers/main.yml b/ansible/roles/transmission/handlers/main.yml
deleted file mode 100644
index db948a4..0000000
--- a/ansible/roles/transmission/handlers/main.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-- name: Restart transmission
- ansible.builtin.command: brew services restart transmission-cli
- changed_when: true
diff --git a/ansible/roles/transmission/tasks/main.yml b/ansible/roles/transmission/tasks/main.yml
deleted file mode 100644
index f264b0d..0000000
--- a/ansible/roles/transmission/tasks/main.yml
+++ /dev/null
@@ -1,52 +0,0 @@
----
-- name: Install transmission-cli via homebrew
- community.general.homebrew:
- name: transmission-cli
- state: present
-
-- name: Ensure transmission download directory exists
- ansible.builtin.file:
- path: "{{ transmission_download_dir }}"
- state: directory
- mode: '0755'
-
-- name: Ensure transmission incomplete directory exists
- ansible.builtin.file:
- path: "{{ transmission_incomplete_dir }}"
- state: directory
- mode: '0755'
-
-- name: Remove old config directory (was deployed to wrong location)
- ansible.builtin.file:
- path: ~/.config/transmission-daemon
- state: absent
-
-# Note: transmission must be stopped before modifying settings.json
-# otherwise it may overwrite our changes on shutdown
-- name: Check if settings.json needs updating
- ansible.builtin.template:
- src: settings.json.j2
- dest: "{{ transmission_config_dir }}/settings.json"
- mode: '0600'
- check_mode: true
- register: transmission_settings_check
-
-- name: Stop transmission before config changes
- ansible.builtin.command: brew services stop transmission-cli
- when: transmission_settings_check.changed
- register: transmission_brew_stop
- changed_when: false
- failed_when: false
-
-- name: Deploy transmission settings.json
- ansible.builtin.template:
- src: settings.json.j2
- dest: "{{ transmission_config_dir }}/settings.json"
- mode: '0600'
- notify: Restart transmission
-
-- name: Ensure transmission service is started
- ansible.builtin.command: brew services start transmission-cli
- register: transmission_brew_start
- changed_when: "'Successfully started' in transmission_brew_start.stdout"
- failed_when: false
diff --git a/ansible/roles/transmission/templates/settings.json.j2 b/ansible/roles/transmission/templates/settings.json.j2
deleted file mode 100644
index 36b0513..0000000
--- a/ansible/roles/transmission/templates/settings.json.j2
+++ /dev/null
@@ -1,89 +0,0 @@
-{#
- RPC is required for transmission-remote CLI to manage torrents.
- Config is secure: bound to localhost only, no auth needed.
-
- rpc-password uses a static hash starting with '{' so transmission
- recognizes it as pre-hashed and won't regenerate it on restart.
- Without this, transmission writes a new hash each startup causing
- perpetual ansible diffs.
-#}
-{
- "_comment": "{{ ansible_managed }}",
- "alt-speed-down": 50,
- "alt-speed-enabled": false,
- "alt-speed-time-begin": 540,
- "alt-speed-time-day": 127,
- "alt-speed-time-enabled": false,
- "alt-speed-time-end": 1020,
- "alt-speed-up": 50,
- "announce-ip": "",
- "announce-ip-enabled": false,
- "anti-brute-force-enabled": false,
- "anti-brute-force-threshold": 100,
- "bind-address-ipv4": "0.0.0.0",
- "bind-address-ipv6": "::",
- "blocklist-enabled": false,
- "blocklist-url": "http://www.example.com/blocklist",
- "cache-size-mb": 4,
- "default-trackers": "",
- "dht-enabled": {{ transmission_dht_enabled | lower }},
- "download-dir": "{{ transmission_download_dir }}",
- "download-queue-enabled": true,
- "download-queue-size": 5,
- "encryption": {{ transmission_encryption }},
- "idle-seeding-limit": 30,
- "idle-seeding-limit-enabled": false,
- "incomplete-dir": "{{ transmission_incomplete_dir }}",
- "incomplete-dir-enabled": true,
- "lpd-enabled": true,
- "message-level": 4,
- "peer-congestion-algorithm": "",
- "peer-limit-global": 200,
- "peer-limit-per-torrent": 50,
- "peer-port": 51413,
- "peer-port-random-high": 65535,
- "peer-port-random-low": 49152,
- "peer-port-random-on-start": false,
- "peer-socket-tos": "le",
- "pex-enabled": {{ transmission_pex_enabled | lower }},
- "port-forwarding-enabled": true,
- "preallocation": 1,
- "prefetch-enabled": true,
- "queue-stalled-enabled": true,
- "queue-stalled-minutes": 30,
- "ratio-limit": 2,
- "ratio-limit-enabled": false,
- "rename-partial-files": false,
- "rpc-authentication-required": {{ transmission_rpc_authentication_required | lower }},
- "rpc-bind-address": "{{ transmission_rpc_bind_address }}",
- "rpc-enabled": {{ transmission_rpc_enabled | lower }},
- "rpc-host-whitelist": "",
- "rpc-host-whitelist-enabled": true,
- "rpc-password": "{00000000000000000000000000000000000000000000000e",
- "rpc-port": {{ transmission_rpc_port }},
- "rpc-socket-mode": "0750",
- "rpc-url": "/transmission/",
- "rpc-username": "",
- "rpc-whitelist": "{{ transmission_rpc_whitelist }}",
- "rpc-whitelist-enabled": {{ transmission_rpc_whitelist_enabled | lower }},
- "scrape-paused-torrents-enabled": true,
- "script-torrent-added-enabled": false,
- "script-torrent-added-filename": "",
- "script-torrent-done-enabled": false,
- "script-torrent-done-filename": "",
- "script-torrent-done-seeding-enabled": false,
- "script-torrent-done-seeding-filename": "",
- "seed-queue-enabled": false,
- "seed-queue-size": 10,
- "speed-limit-down": {{ transmission_speed_limit_down }},
- "speed-limit-down-enabled": {{ (transmission_speed_limit_down > 0) | lower }},
- "speed-limit-up": {{ transmission_speed_limit_up }},
- "speed-limit-up-enabled": {{ (transmission_speed_limit_up > 0) | lower }},
- "start-added-torrents": true,
- "tcp-enabled": true,
- "torrent-added-verify-mode": "fast",
- "trash-original-torrent-files": false,
- "umask": "022",
- "upload-slots-per-torrent": 8,
- "utp-enabled": true
-}
diff --git a/ansible/roles/transmission_metrics/defaults/main.yml b/ansible/roles/transmission_metrics/defaults/main.yml
deleted file mode 100644
index 9e9e2b0..0000000
--- a/ansible/roles/transmission_metrics/defaults/main.yml
+++ /dev/null
@@ -1,7 +0,0 @@
----
-transmission_metrics_rpc_host: 127.0.0.1
-transmission_metrics_rpc_port: 9091
-transmission_metrics_dir: /opt/homebrew/var/node_exporter/textfile
-transmission_metrics_script: /Users/erichblume/bin/transmission-metrics
-transmission_metrics_interval: 60 # seconds between metric collection
-transmission_metrics_log_dir: /opt/homebrew/var/log
diff --git a/ansible/roles/transmission_metrics/handlers/main.yml b/ansible/roles/transmission_metrics/handlers/main.yml
deleted file mode 100644
index 5e4d922..0000000
--- a/ansible/roles/transmission_metrics/handlers/main.yml
+++ /dev/null
@@ -1,6 +0,0 @@
----
-- name: Reload transmission-metrics
- ansible.builtin.shell: |
- launchctl unload ~/Library/LaunchAgents/mcquack.eblume.transmission-metrics.plist 2>/dev/null || true
- launchctl load ~/Library/LaunchAgents/mcquack.eblume.transmission-metrics.plist
- changed_when: true
diff --git a/ansible/roles/transmission_metrics/meta/main.yml b/ansible/roles/transmission_metrics/meta/main.yml
deleted file mode 100644
index b05a43b..0000000
--- a/ansible/roles/transmission_metrics/meta/main.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-# Role ordering is controlled by indri.yml playbook - do not add dependencies here
-# (Ansible's tag accumulation prevents proper deduplication when using meta dependencies)
-dependencies: []
diff --git a/ansible/roles/transmission_metrics/tasks/main.yml b/ansible/roles/transmission_metrics/tasks/main.yml
deleted file mode 100644
index 31323c9..0000000
--- a/ansible/roles/transmission_metrics/tasks/main.yml
+++ /dev/null
@@ -1,26 +0,0 @@
----
-- name: Deploy transmission metrics collection script
- ansible.builtin.template:
- src: transmission-metrics.sh.j2
- dest: "{{ transmission_metrics_script }}"
- mode: '0755'
- notify: Reload transmission-metrics
-
-- name: Deploy transmission-metrics LaunchAgent plist
- ansible.builtin.template:
- src: transmission-metrics.plist.j2
- dest: ~/Library/LaunchAgents/mcquack.eblume.transmission-metrics.plist
- mode: '0644'
- notify: Reload transmission-metrics
-
-- name: Check if transmission-metrics LaunchAgent is loaded
- ansible.builtin.command: launchctl list mcquack.eblume.transmission-metrics
- register: transmission_metrics_launchctl_check
- changed_when: false
- failed_when: false
-
-- name: Load transmission-metrics LaunchAgent if not loaded
- ansible.builtin.command: launchctl load ~/Library/LaunchAgents/mcquack.eblume.transmission-metrics.plist
- when: transmission_metrics_launchctl_check.rc != 0
- changed_when: true
- failed_when: false
diff --git a/ansible/roles/transmission_metrics/templates/transmission-metrics.plist.j2 b/ansible/roles/transmission_metrics/templates/transmission-metrics.plist.j2
deleted file mode 100644
index a68e0c8..0000000
--- a/ansible/roles/transmission_metrics/templates/transmission-metrics.plist.j2
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
-
- Label
- mcquack.eblume.transmission-metrics
- EnvironmentVariables
-
- PATH
- /opt/homebrew/bin:/usr/bin:/bin
-
- ProgramArguments
-
- {{ transmission_metrics_script }}
-
- StartInterval
- {{ transmission_metrics_interval }}
- RunAtLoad
-
- StandardErrorPath
- {{ transmission_metrics_log_dir }}/transmission-metrics.err.log
- StandardOutPath
- {{ transmission_metrics_log_dir }}/transmission-metrics.out.log
-
-
diff --git a/ansible/roles/transmission_metrics/templates/transmission-metrics.sh.j2 b/ansible/roles/transmission_metrics/templates/transmission-metrics.sh.j2
deleted file mode 100644
index 0e394af..0000000
--- a/ansible/roles/transmission_metrics/templates/transmission-metrics.sh.j2
+++ /dev/null
@@ -1,120 +0,0 @@
-#!/bin/bash
-# {{ ansible_managed }}
-# Collects transmission-daemon metrics for node_exporter textfile collector
-
-set -euo pipefail
-
-RPC_URL="http://{{ transmission_metrics_rpc_host }}:{{ transmission_metrics_rpc_port }}/transmission/rpc"
-OUTPUT_FILE="{{ transmission_metrics_dir }}/transmission.prom"
-TEMP_FILE="${OUTPUT_FILE}.tmp"
-
-# Get session ID (required for transmission RPC)
-# Note: transmission doesn't support HEAD requests, so we make a request and parse
-# the 409 response headers. We use sed to stop at the blank line (which has \r) before body.
-get_session_id() {
- curl -s -i "$RPC_URL" 2>/dev/null | sed '/^\r$/q' | grep -i '^X-Transmission-Session-Id:' | awk '{print $2}' | tr -d '\r'
-}
-
-# Make RPC request
-rpc_request() {
- local method="$1"
- local args="${2:-}"
- local session_id
- session_id=$(get_session_id)
-
- if [ -z "$session_id" ]; then
- echo "Failed to get session ID" >&2
- return 1
- fi
-
- local payload
- if [ -n "$args" ]; then
- payload="{\"method\": \"$method\", \"arguments\": $args}"
- else
- payload="{\"method\": \"$method\"}"
- fi
-
- curl -s "$RPC_URL" \
- -H "X-Transmission-Session-Id: $session_id" \
- -H "Content-Type: application/json" \
- -d "$payload"
-}
-
-# Get session stats
-session_stats=$(rpc_request "session-stats")
-
-if [ -z "$session_stats" ] || ! echo "$session_stats" | grep -q '"result":"success"'; then
- echo "Failed to get session stats" >&2
- exit 1
-fi
-
-# Extract values using grep/sed (avoiding jq dependency)
-extract_json_int() {
- echo "$1" | grep -o "\"$2\":[0-9]*" | head -1 | sed "s/\"$2\"://"
-}
-
-# Session stats
-download_speed=$(extract_json_int "$session_stats" "downloadSpeed")
-upload_speed=$(extract_json_int "$session_stats" "uploadSpeed")
-torrents_active=$(extract_json_int "$session_stats" "activeTorrentCount")
-torrents_paused=$(extract_json_int "$session_stats" "pausedTorrentCount")
-torrents_total=$(extract_json_int "$session_stats" "torrentCount")
-
-# Cumulative stats
-downloaded_bytes=$(echo "$session_stats" | grep -o '"cumulative-stats":{[^}]*}' | grep -o '"downloadedBytes":[0-9]*' | sed 's/"downloadedBytes"://')
-uploaded_bytes=$(echo "$session_stats" | grep -o '"cumulative-stats":{[^}]*}' | grep -o '"uploadedBytes":[0-9]*' | sed 's/"uploadedBytes"://')
-seconds_active=$(echo "$session_stats" | grep -o '"cumulative-stats":{[^}]*}' | grep -o '"secondsActive":[0-9]*' | sed 's/"secondsActive"://')
-
-# Get total size of all torrents
-torrent_info=$(rpc_request "torrent-get" '{"fields": ["totalSize"]}')
-total_size_bytes=0
-if echo "$torrent_info" | grep -q '"result":"success"'; then
- # Sum all totalSize values
- total_size_bytes=$(echo "$torrent_info" | grep -o '"totalSize":[0-9]*' | sed 's/"totalSize"://' | awk '{sum += $1} END {print sum}')
-fi
-
-# Write metrics
-cat > "$TEMP_FILE" << EOF
-# HELP transmission_download_speed_bytes Current download speed in bytes per second
-# TYPE transmission_download_speed_bytes gauge
-transmission_download_speed_bytes ${download_speed:-0}
-
-# HELP transmission_upload_speed_bytes Current upload speed in bytes per second
-# TYPE transmission_upload_speed_bytes gauge
-transmission_upload_speed_bytes ${upload_speed:-0}
-
-# HELP transmission_torrents_active Number of active torrents
-# TYPE transmission_torrents_active gauge
-transmission_torrents_active ${torrents_active:-0}
-
-# HELP transmission_torrents_paused Number of paused torrents
-# TYPE transmission_torrents_paused gauge
-transmission_torrents_paused ${torrents_paused:-0}
-
-# HELP transmission_torrents_total Total number of torrents
-# TYPE transmission_torrents_total gauge
-transmission_torrents_total ${torrents_total:-0}
-
-# HELP transmission_torrents_size_bytes Total size of all torrents in bytes
-# TYPE transmission_torrents_size_bytes gauge
-transmission_torrents_size_bytes ${total_size_bytes:-0}
-
-# HELP transmission_downloaded_bytes_total Total bytes downloaded (cumulative)
-# TYPE transmission_downloaded_bytes_total counter
-transmission_downloaded_bytes_total ${downloaded_bytes:-0}
-
-# HELP transmission_uploaded_bytes_total Total bytes uploaded (cumulative)
-# TYPE transmission_uploaded_bytes_total counter
-transmission_uploaded_bytes_total ${uploaded_bytes:-0}
-
-# HELP transmission_seconds_active_total Total seconds transmission has been active
-# TYPE transmission_seconds_active_total counter
-transmission_seconds_active_total ${seconds_active:-0}
-
-# HELP transmission_up Transmission daemon is up and responding
-# TYPE transmission_up gauge
-transmission_up 1
-EOF
-
-# Atomic move
-mv "$TEMP_FILE" "$OUTPUT_FILE"