Skip to content

Commit 23eb6fa

Browse files
committed
Add rip to audio script
1 parent 440b159 commit 23eb6fa

File tree

4 files changed

+161
-3
lines changed

4 files changed

+161
-3
lines changed

roles/base/tasks/03-fs.yaml

+6-3
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
- name: install zfs
44
apt:
55
name:
6-
- zfsutils-linux
7-
- zfs-auto-snapshot
8-
- zfs-zed
6+
# - zfsutils-linux
7+
# - zfs-auto-snapshot
8+
# - zfs-zed
99
- sendemail
10+
- openzfs-zfsutils
11+
- openzfs-zfs-zed
12+
- openzfs-zfs-dkms
1013
state: latest
1114
update_cache: true
1215
cache_valid_time: 3600

roles/media-server/handlers/main.yaml

+11
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,14 @@
5757
with_items:
5858
- myanonamouse.timer
5959
- myanonamouse.service
60+
61+
- name: enable rip-to-audio
62+
systemd:
63+
name: "{{ item }}"
64+
enabled: true
65+
state: "started"
66+
daemon_reload: true
67+
become: true
68+
with_items:
69+
- rip-to-audio.timer
70+
- rip-to-audio.service

roles/media-server/tasks/00-media.yaml

+39
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,45 @@
9797
when: mam_id is defined
9898
notify: enable myanonamouse
9999

100+
- name: create rip-to-audio script
101+
template:
102+
src: rip-to-audio.j2
103+
dest: /usr/local/bin/rip-to-audio
104+
mode: 0777
105+
become: true
106+
107+
- name: setup rip-to-audio service
108+
copy:
109+
content: |
110+
[Unit]
111+
Description=Rip audio
112+
113+
[Service]
114+
Type=oneshot
115+
ExecStart=/usr/local/bin/rip-to-audio '{{ tv_folder }}/Jeopardy!' '{{ audiobooks_folder }}/Jeopardy!'
116+
User={{ ansible_user }}
117+
Restart=no
118+
119+
dest: /etc/systemd/system/rip-to-audio.service
120+
become: true
121+
notify: enable rip-to-audio
122+
123+
- name: setup rip-to-audio timer
124+
copy:
125+
content: |
126+
[Unit]
127+
Description=Rip audio
128+
129+
[Timer]
130+
OnCalendar=daily
131+
Persistent=true
132+
133+
[Install]
134+
WantedBy=timers.target
135+
dest: /etc/systemd/system/rip-to-audio.timer
136+
become: true
137+
notify: enable rip-to-audio
138+
100139
# - name: configure jackett basepath
101140
# replace:
102141
# path: "{{ app_folder }}/jackett/Jackett/ServerConfig.json"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Usage: ./rip-to-audio <SOURCE_DIR> <TARGET_DIR>
4+
#
5+
# - Finds all *.mkv in SOURCE_DIR (recursive).
6+
# - Strips patterns like 'HDTV-720p' from the output filename.
7+
# - Tries to copy audio directly (no re-encode).
8+
# - If that fails, re-encode to AAC (VBR).
9+
# - Uses a .partial file to avoid corrupt final output on interruption.
10+
# - Skips files that already have a corresponding .m4a.
11+
# - Prevents ffmpeg from reading stdin (so it doesn't break the find-loop).
12+
13+
set -euo pipefail
14+
15+
if (( $# < 2 )); then
16+
echo "Usage: $0 <SOURCE_DIR> <TARGET_DIR>"
17+
exit 1
18+
fi
19+
20+
SOURCE_DIR="$1"
21+
TARGET_DIR="$2"
22+
23+
# Make sure ffmpeg is available
24+
if ! command -v ffmpeg &>/dev/null; then
25+
echo "Error: ffmpeg not found."
26+
exit 1
27+
fi
28+
29+
# Remove video-related tags on the file
30+
STRIP_PATTERN='s/\s*HDTV.*//Ig'
31+
32+
# Find all *.mkv files (case-insensitive) and process them one by one.
33+
# We use process substitution (`< <(...)`) so ffmpeg won't consume our loop's stdin.
34+
while IFS= read -r -d '' mkv_file; do
35+
# 1) Compute the relative path within SOURCE_DIR
36+
# e.g.: /path/to/source/sub/Video.HDTV-720p.mkv
37+
# => sub/Video.HDTV-720p.mkv
38+
rel_path="${mkv_file#"$SOURCE_DIR"/}"
39+
40+
# 2) Strip off .mkv to get the "raw" name; we also want to remove the directory part
41+
# so we can apply the sed-based pattern on the filename itself.
42+
dir_part="$(dirname "$rel_path")"
43+
base_no_ext="$(basename "${rel_path%.mkv}")"
44+
45+
# 3) Use sed to remove the 'HDTV-720p' pattern (and minor punctuation around it).
46+
# Adjust this as needed for other patterns like "WEB-1080p" or "BluRay.1080p".
47+
cleaned_name="$(echo "$base_no_ext" | sed -E "$STRIP_PATTERN")"
48+
49+
# 4) Construct final out_file path, ensuring .m4a extension
50+
# e.g.: $TARGET_DIR/sub/Video.m4a
51+
out_file="$TARGET_DIR/$dir_part/$cleaned_name.m4a"
52+
partial_file="$out_file.partial"
53+
54+
# 5) Skip if final output already exists
55+
if [[ -f "$out_file" ]]; then
56+
echo "Skipping (already exists): $out_file"
57+
continue
58+
fi
59+
60+
# 6) Remove stale partial file if present
61+
if [[ -f "$partial_file" ]]; then
62+
echo "Removing stale partial: $partial_file"
63+
rm -f "$partial_file"
64+
fi
65+
66+
# 7) Create output directory if necessary
67+
mkdir -p "$(dirname "$out_file")"
68+
69+
echo "Processing: $mkv_file"
70+
echo " to -> $out_file"
71+
72+
# 8) First, try copying the existing audio track (no re-encode)
73+
# -nostdin => ffmpeg won't read from stdin
74+
# -vn => drop video
75+
# -c:a copy => copy audio bitstream
76+
# -f mp4 => produce an MP4 container (m4a is audio-only MP4)
77+
# -y => overwrite partial file if it exists
78+
set +e # We'll handle ffmpeg failure manually
79+
ffmpeg -nostdin \
80+
-i "$mkv_file" \
81+
-vn -c:a copy \
82+
-f mp4 -y \
83+
"$partial_file"
84+
ffmpeg_status=$?
85+
set -e
86+
87+
if (( ffmpeg_status != 0 )); then
88+
echo "Audio copy failed (unsupported codec?), re-encoding to AAC VBR..."
89+
90+
# 9) Fallback: re-encode to AAC VBR
91+
# -q:a 2 => a typical VBR quality level (range ~0=best to ~5=lower)
92+
ffmpeg -nostdin \
93+
-i "$mkv_file" \
94+
-vn -c:a aac -q:a 2 \
95+
-f mp4 -y \
96+
"$partial_file"
97+
fi
98+
99+
# 10) Move partial to final output if successful
100+
mv "$partial_file" "$out_file"
101+
102+
echo "Done: $out_file"
103+
echo
104+
105+
done < <(find "$SOURCE_DIR" -type f \( -iname "*.mkv" -o -iname "*.mp4" -o -iname "*.avi" -o -iname "*.mov" \) -print0)

0 commit comments

Comments
 (0)