# {{ ansible_managed }} # To recreate this file, use ansible-playbook -i inventory.yml prod-playbook.yml --tags prerec-make .ONESHELL: SHELL := /bin/bash # --- Shell Function Definition --- # This function checks a given file ($1) for an audio stream. # It returns the string "audio" if found, or nothing if not found. # This makes the conditional check cleaner. define IS_AUDIO_PRESENT_SCRIPT ffprobe -loglevel error -select_streams a:0 \ -show_entries stream=codec_type \ -of default=noprint_wrappers=1:nokey=1 "$1" endef IS_AUDIO_PRESENT = $(IS_AUDIO_PRESENT_SCRIPT) source_patterns = $(foreach ext,$(VIDEO_EXTS),$(1)--original.$(ext)) ANSWER_EXTS = mp4 mkv mov mpv m4v source_patterns = $(foreach ext,$(VIDEO_EXTS),$(1)--original.$(ext)) answer_patterns = $(foreach ext,$(ANSWER_EXTS),$(1)--answers.$(ext)) PRERECS_ORIGINAL := $(wildcard emacsconf-*--original.*) ANSWERS_ORIGINAL := $(wildcard emacsconf-*--answers.*) ANSWER_PREFIXES := $(shell for f in $(ANSWERS_ORIGINAL); do echo "$${f%--answers.*}"; done) PREFIXES := $(shell for f in $(PRERECS_ORIGINAL); do echo "$${f%--original.*}"; done) ANSWERS_REENCODED := $(addsuffix --answers--reencoded.webm, $(ANSWER_PREFIXES)) PRERECS_REENCODED := $(addsuffix --reencoded.webm, $(PREFIXES)) PRERECS_OPUS := $(addsuffix --reencoded.opus, $(PREFIXES)) PRERECS_MAIN_OPUS := $(addsuffix --main.opus, $(PREFIXES)) PRERECS_MAIN := $(addsuffix --main.webm, $(PREFIXES)) PRERECS_CAPTIONS := $(addsuffix --reencoded.vtt, $(PREFIXES)) PRERECS_FINAL := $(wildcard emacsconf-*--final.webm) WAVEFORMS := $(addsuffix --backstage--waveform.png, $(PREFIXES)) LINODE_BBB_ID := 67329098 .PHONY: all all: reencoded opus main main-opus waveforms.png reencoded: $(PRERECS_REENCODED) opus: $(PRERECS_OPUS) captions: $(PRERECS_CAPTIONS) main: $(PRERECS_MAIN) main-opus: $(PRERECS_MAIN_OPUS) waveforms: $(WAVEFORMS) answers: $(ANSWERS_REENCODED) emacsconf-%--answers--reencoded.webm: SOURCES = $(call answer_patterns, emacsconf-$*) emacsconf-%--answers--reencoded.webm: $(eval SOURCE := $(lastword $(sort $(wildcard $(SOURCES))))) @echo $(SOURCE) $@ emacsconf-%--reencoded.webm: SOURCES = $(call source_patterns, emacsconf-$*) emacsconf-%--reencoded.webm: $(eval SOURCE := $(lastword $(sort $(wildcard $(SOURCES))))) @if [ -z "$(SOURCE)" ]; then \ echo "No source file found for $@"; \ echo "Tried: $(SOURCES)"; \ exit 1; \ fi @echo "Using source: $(SOURCE)" reencode-in-screen.sh "$(SOURCE)" emacsconf-%--reencoded.opus: emacsconf-%--reencoded.webm AUDIO_CHECK=$$( $(call IS_AUDIO_PRESENT, "$<") ) if [ ! -z "$$AUDIO_CHECK" ]; then ffmpeg -y -i "$<" -c:a copy "$@" else ffmpeg -y -f lavfi -i anullsrc=channel_layout=stereo:sample_rate=48000 -t 1 -c:a libopus "$@" fi emacsconf-%--answers.opus: emacsconf-%--answers.webm ffmpeg -y -i "$<" -c:a copy "$@" # emacsconf-%--normalized.opus: emacsconf-%--reencoded.opus # ffmpeg-normalize "$<" -ofmt opus -c:a libopus -o "$@" emacsconf-%--main.webm: emacsconf-%--reencoded.webm emacsconf-%--normalized.opus emacsconf-%--main.vtt ffmpeg -i emacsconf-$*--reencoded.webm -i emacsconf-$*--normalized.opus -i emacsconf-$*--main.vtt \ -map 0:v -map 1:a -c:v copy -c:a copy \ -map 2 -c:s webvtt -y \ $@ emacsconf-%--main.webm: emacsconf-%--reencoded.webm emacsconf-%--normalized.opus ffmpeg -i emacsconf-$*--reencoded.webm -i emacsconf-$*--normalized.opus \ -map 0:v -map 1:a -c:v copy -c:a copy \ -y $@ emacsconf-%--main.webm: emacsconf-%--reencoded.webm cp "$<" "$@" emacsconf-%--main.webm: emacsconf-%--reencoded.webm emacsconf-%--main.vtt cp "$<" "$@" ffmpeg -i emacsconf-$*--reencoded.webm -i emacsconf-$*--main.vtt \ -c:v copy -c:a copy \ -y $@ emacsconf-%--final.webm: emacsconf-%--main.vtt mux-subs.sh "$@" "$<" emacsconf-%--main.opus: emacsconf-%--main.webm AUDIO_CHECK=$$( $(call IS_AUDIO_PRESENT, "$<") ) if [ ! -z "$$AUDIO_CHECK" ]; then \ ffmpeg -y -i "$<" -c:a copy "$@"; \ fi emacsconf-%--reencoded.vtt: emacsconf-%--reencoded.opus whisperx --model large-v3 --align_model WAV2VEC2_ASR_LARGE_LV60K_960H --compute_type int8 --print_progress True --max_line_width 50 --segment_resolution chunk --max_line_count 1 --language en --initial_prompt "Transcribe this talk about Emacs. It may mention Emacs keywords such as Org Mode, Org Roam, Magit, gptel, or chatgpt-shell, or tech keywords such as LLMs. Format function names and keyboard shortcut sequences according to Emacs conventions using Markdown syntax. For example: control h becomes \`C-h\`." "$<" emacsconf-%--backstage--silences.csv: emacsconf-%--reencoded.opus ffmpeg -i "$<" -af silencedetect=noise=-30dB:d=0.5 -f null - 2>&1 | awk '/silence_start/ {start=$$NF} /silence_end/ {print start "," (start + $$NF)}' > "$@" show-files: @echo "Original $(words $(PRERECS_ORIGINAL)):" @echo "$(PRERECS_ORIGINAL)" @echo "Prefixes $(words $(PREFIXES)):" @echo "$(PREFIXES)" @echo "Reencoded $(words $(PRERECS_REENCODED)):" @echo "$(PRERECS_REENCODED)" @echo "Opus $(words $(PRERECS_OPUS)):" @echo "$(PRERECS_OPUS)" bbb-testing: @echo "Resizing BBB node to 8GB 4 core for testing" linode-cli linodes resize $(LINODE_BBB_ID) --type g6-standard-4 --allow_auto_disk_resize false sleep 2m @echo "Booting up" linode-cli linodes boot $(LINODE_BBB_ID) ssh root@bbb.emacsverse.org "cd ~/greenlight-v3; docker compose restart" bbb-dormant: @echo "Shutting down" ssh root@bbb.emacsverse.org "/usr/sbin/shutdown -h now &" || true sleep 30 @echo "Powering off BBB node" linode-cli linodes shutdown $(LINODE_BBB_ID) sleep 30 @echo "Resizing BBB node to nanode, dormant" linode-cli linodes resize $(LINODE_BBB_ID) --type g6-nanode-1 --allow_auto_disk_resize false bbb-prod: @echo "Resizing BBB node to production size" linode-cli linodes resize $(LINODE_BBB_ID) --type g6-dedicated-8 --allow_auto_disk_resize true sleep 2m @echo "Booting up" linode-cli linodes boot $(LINODE_BBB_ID) live-dormant: @echo "Resizing live0 node to nanode, dormant" linode-cli linodes resize 17921960 --type g6-nanode-1 --allow_auto_disk_resize false sleep 120 linode-cli linodes boot 17921960 rsync: rsync -avzue ssh {{ emacsconf_caption_dir }}/cache/ orga@media.emacsconf.org:/var/www/media.emacsconf.org/{{ emacsconf_year }}/backstage/ WAVEFORM_HEIGHT := 240 WAVEFORM_WIDTH := 400 WAVEFORM_VOLUME := 3.0 WAVEFORM_FILTER := "[0:a]aformat=channel_layouts=mono[b];[b]volume=$(WAVEFORM_VOLUME)[a];[a]compand=attacks=0:points=-90/-90|0/0,showwavespic=s=$(WAVEFORM_WIDTH)x$(WAVEFORM_HEIGHT):colors=\#9cf42f[fg];color=s=$(WAVEFORM_WIDTH)x$(WAVEFORM_HEIGHT):color=\#44582c,drawgrid=width=iw/10:height=ih/5:color=\#9cf42f@0.1[bg];[bg][fg]overlay=format=auto[comp];[comp]drawtext=text='$$ID':fontcolor=white:fontsize=24:x=10:y=10:box=1:boxcolor=\#44582c@0.5:boxborderw=5" emacsconf-%--backstage--waveform.png: emacsconf-%--normalized.opus AUDIO_CHECK=$$(ffprobe -loglevel error -select_streams a:0 -show_entries stream=codec_type -of default=noprint_wrappers=1:nokey=1 "$<"); \ ID=$$(echo "$<" | sed 's/--.*//'); \ if [ ! -z "$$AUDIO_CHECK" ]; then \ ffmpeg -i "$<" \ -filter_complex $(WAVEFORM_FILTER) \ -frames:v 1 \ -c:v png \ -update 1 \ -y \ "$@"; \ fi emacsconf-%--backstage--waveform.png: emacsconf-%--reencoded.opus AUDIO_CHECK=$$(ffprobe -loglevel error -select_streams a:0 -show_entries stream=codec_type -of default=noprint_wrappers=1:nokey=1 "$<"); \ ID=$$(echo "$<" | sed 's/--.*//'); \ if [ ! -z "$$AUDIO_CHECK" ]; then \ ffmpeg -i "$<" \ -filter_complex $(WAVEFORM_FILTER) \ -frames:v 1 \ -c:v png \ -update 1 \ -y \ "$@"; \ fi waveforms.png: $(WAVEFORMS) convert $^ +append "$@"