Add transmission for torrent-based ZIM downloads #3
9 changed files with 245 additions and 6 deletions
|
|
@ -40,7 +40,13 @@ Key hosts:
|
|||
|
||||
Use feature branches for all changes. Do not commit directly to main. Commit often while working to preserve progress.
|
||||
|
||||
**IMPORTANT:** Always create feature branches from main to avoid including unrelated commits:
|
||||
|
||||
```bash
|
||||
# Always start from main
|
||||
git checkout main
|
||||
git pull
|
||||
|
||||
# Create a feature branch
|
||||
git checkout -b feature/description-of-change
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
tags: prometheus
|
||||
- role: grafana
|
||||
tags: grafana
|
||||
- role: transmission
|
||||
tags: transmission
|
||||
- role: kiwix
|
||||
tags: kiwix
|
||||
- role: borgmatic
|
||||
|
|
|
|||
|
|
@ -4,8 +4,14 @@ kiwix_zim_dir: /Users/erichblume/code/3rd/kiwix-tools
|
|||
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
|
||||
# Base URL: https://download.kiwix.org/zim/
|
||||
# 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
|
||||
|
|
|
|||
3
ansible/roles/kiwix/meta/main.yml
Normal file
3
ansible/roles/kiwix/meta/main.yml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
dependencies:
|
||||
- role: transmission
|
||||
|
|
@ -5,7 +5,135 @@
|
|||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
- name: Check which ZIM archives exist
|
||||
# --- Transmission-based download logic ---
|
||||
- name: Check transmission daemon is responding
|
||||
ansible.builtin.command: transmission-remote -l
|
||||
register: 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 transmission_check.rc != 0
|
||||
|
||||
# Check if each torrent is already loaded in transmission
|
||||
- name: Check torrent status for each ZIM archive
|
||||
ansible.builtin.shell: |
|
||||
# Look for the torrent by filename (name column in transmission-remote -l)
|
||||
# Output: "not_found", "downloading XX%", or "complete"
|
||||
torrent_line=$(transmission-remote -l | grep -F "{{ item.filename | regex_replace('\\.zim$', '') }}" || true)
|
||||
if [ -z "$torrent_line" ]; then
|
||||
echo "not_found"
|
||||
else
|
||||
# Extract percentage from the Done column (2nd column)
|
||||
pct=$(echo "$torrent_line" | awk '{print $2}')
|
||||
if [ "$pct" = "100%" ]; then
|
||||
echo "complete"
|
||||
else
|
||||
echo "downloading $pct"
|
||||
fi
|
||||
fi
|
||||
args:
|
||||
executable: /bin/bash
|
||||
loop: "{{ kiwix_zim_archives }}"
|
||||
loop_control:
|
||||
label: "{{ item.filename }}"
|
||||
register: torrent_status
|
||||
changed_when: false
|
||||
when: kiwix_use_transmission
|
||||
|
||||
# Add torrents that are not yet loaded
|
||||
- name: Add missing torrents to transmission
|
||||
ansible.builtin.command: >
|
||||
transmission-remote -a "{{ kiwix_torrent_base_url }}/{{ item.item.category }}/{{ item.item.filename }}.torrent"
|
||||
loop: "{{ torrent_status.results | default([]) }}"
|
||||
loop_control:
|
||||
label: "{{ item.item.filename }}"
|
||||
when:
|
||||
- kiwix_use_transmission
|
||||
- item.stdout is defined
|
||||
- item.stdout == "not_found"
|
||||
register: torrent_add
|
||||
changed_when: torrent_add.rc == 0
|
||||
|
||||
# Wait briefly and recheck status for newly added torrents
|
||||
- name: Wait for transmission to register new torrents
|
||||
ansible.builtin.pause:
|
||||
seconds: 5
|
||||
when:
|
||||
- kiwix_use_transmission
|
||||
- torrent_add.changed is defined
|
||||
- torrent_add.changed
|
||||
|
||||
# Recheck all torrent statuses
|
||||
- name: Recheck torrent status after adding
|
||||
ansible.builtin.shell: |
|
||||
torrent_line=$(transmission-remote -l | grep -F "{{ item.filename | regex_replace('\\.zim$', '') }}" || true)
|
||||
if [ -z "$torrent_line" ]; then
|
||||
echo "not_found"
|
||||
else
|
||||
pct=$(echo "$torrent_line" | awk '{print $2}')
|
||||
if [ "$pct" = "100%" ]; then
|
||||
echo "complete"
|
||||
else
|
||||
echo "downloading $pct"
|
||||
fi
|
||||
fi
|
||||
args:
|
||||
executable: /bin/bash
|
||||
loop: "{{ kiwix_zim_archives }}"
|
||||
loop_control:
|
||||
label: "{{ item.filename }}"
|
||||
register: torrent_status_final
|
||||
changed_when: false
|
||||
when: kiwix_use_transmission
|
||||
|
||||
# Check if symlink already exists for completed downloads
|
||||
- name: Check if ZIM symlink exists
|
||||
ansible.builtin.stat:
|
||||
path: "{{ kiwix_zim_dir }}/{{ item.item.filename }}"
|
||||
get_checksum: false
|
||||
loop: "{{ torrent_status_final.results | default([]) }}"
|
||||
loop_control:
|
||||
label: "{{ item.item.filename }}"
|
||||
register: zim_symlink_stat
|
||||
when:
|
||||
- kiwix_use_transmission
|
||||
- item.stdout is defined
|
||||
- item.stdout == "complete"
|
||||
|
||||
# Create symlinks for completed downloads
|
||||
- name: Symlink completed ZIM downloads to kiwix directory
|
||||
ansible.builtin.file:
|
||||
src: "{{ transmission_download_dir }}/{{ item.item.item.filename }}"
|
||||
dest: "{{ kiwix_zim_dir }}/{{ item.item.item.filename }}"
|
||||
state: link
|
||||
loop: "{{ zim_symlink_stat.results | default([]) }}"
|
||||
loop_control:
|
||||
label: "{{ item.item.item.filename | default('unknown') }}"
|
||||
when:
|
||||
- kiwix_use_transmission
|
||||
- item.stat is defined
|
||||
- not item.stat.exists
|
||||
notify: restart kiwix-serve
|
||||
|
||||
# Report on incomplete downloads (informational, no failure)
|
||||
- name: Report incomplete torrent downloads
|
||||
ansible.builtin.debug:
|
||||
msg: "Torrent still downloading: {{ item.item.filename }} ({{ item.stdout }})"
|
||||
loop: "{{ torrent_status_final.results | default([]) }}"
|
||||
loop_control:
|
||||
label: "{{ item.item.filename }}"
|
||||
when:
|
||||
- kiwix_use_transmission
|
||||
- item.stdout is defined
|
||||
- item.stdout != "complete"
|
||||
- item.stdout != "not_found"
|
||||
|
||||
# --- 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
|
||||
|
|
@ -13,19 +141,24 @@
|
|||
loop_control:
|
||||
label: "{{ item.filename }}"
|
||||
register: zim_stat
|
||||
when: not kiwix_use_transmission
|
||||
|
||||
- name: Download missing ZIM archives
|
||||
- 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: "{{ zim_stat.results }}"
|
||||
loop: "{{ zim_stat.results | default([]) }}"
|
||||
loop_control:
|
||||
label: "{{ item.item.filename }}"
|
||||
when: not item.stat.exists
|
||||
label: "{{ item.item.filename | default('unknown') }}"
|
||||
when:
|
||||
- not kiwix_use_transmission
|
||||
- item.stat is defined
|
||||
- not item.stat.exists
|
||||
notify: restart kiwix-serve
|
||||
|
||||
# --- LaunchAgent deployment ---
|
||||
- name: Deploy kiwix-serve LaunchAgent plist
|
||||
ansible.builtin.template:
|
||||
src: kiwix-serve.plist.j2
|
||||
|
|
|
|||
24
ansible/roles/transmission/defaults/main.yml
Normal file
24
ansible/roles/transmission/defaults/main.yml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
# 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
|
||||
3
ansible/roles/transmission/handlers/main.yml
Normal file
3
ansible/roles/transmission/handlers/main.yml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
- name: restart transmission
|
||||
ansible.builtin.command: brew services restart transmission-cli
|
||||
41
ansible/roles/transmission/tasks/main.yml
Normal file
41
ansible/roles/transmission/tasks/main.yml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
- 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
|
||||
|
||||
- name: Stop transmission before config changes
|
||||
ansible.builtin.command: brew services stop transmission-cli
|
||||
register: 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: '0644'
|
||||
notify: restart transmission
|
||||
|
||||
- name: Ensure transmission service is started
|
||||
ansible.builtin.command: brew services start transmission-cli
|
||||
register: brew_start
|
||||
changed_when: "'Successfully started' in brew_start.stdout"
|
||||
failed_when: false
|
||||
21
ansible/roles/transmission/templates/settings.json.j2
Normal file
21
ansible/roles/transmission/templates/settings.json.j2
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"_comment": "{{ ansible_managed }}",
|
||||
"download-dir": "{{ transmission_download_dir }}",
|
||||
"incomplete-dir": "{{ transmission_incomplete_dir }}",
|
||||
"incomplete-dir-enabled": true,
|
||||
"dht-enabled": {{ transmission_dht_enabled | lower }},
|
||||
"pex-enabled": {{ transmission_pex_enabled | lower }},
|
||||
"encryption": {{ transmission_encryption }},
|
||||
"rpc-enabled": {{ transmission_rpc_enabled | lower }},
|
||||
"rpc-port": {{ transmission_rpc_port }},
|
||||
"rpc-bind-address": "{{ transmission_rpc_bind_address }}",
|
||||
"rpc-authentication-required": {{ transmission_rpc_authentication_required | lower }},
|
||||
"rpc-whitelist-enabled": {{ transmission_rpc_whitelist_enabled | lower }},
|
||||
"rpc-whitelist": "{{ transmission_rpc_whitelist }}",
|
||||
"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,
|
||||
"trash-original-torrent-files": false
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue