summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common-playbook.yml5
-rw-r--r--roles/bbb/tasks/main.yml10
-rwxr-xr-xroles/bbb/templates/bigbluebutton.yml73
-rw-r--r--roles/bbb/templates/video.yml81
-rw-r--r--roles/caption/tasks/main.yml1
-rw-r--r--roles/lounge/defaults/main.yml4
-rw-r--r--roles/lounge/tasks/main.yml40
-rw-r--r--roles/lounge/templates/error.html37
-rw-r--r--roles/lounge/templates/nginx-site-config63
-rw-r--r--roles/lounge/templates/thelounge.service11
-rw-r--r--roles/media/tasks/main.yml10
-rw-r--r--roles/media/templates/nginx-site-config16
-rw-r--r--roles/obs/tasks/mpv.yml3
-rw-r--r--roles/obs/templates/mpv.conf8
-rw-r--r--roles/pad-proxy/templates/etherpad.nginx.conf3
-rw-r--r--roles/prerec/tasks/main.yml2
-rw-r--r--roles/prerec/templates/Makefile88
-rwxr-xr-xroles/prerec/templates/reencode-in-screen.sh6
-rwxr-xr-xroles/prerec/templates/talk3
-rwxr-xr-xroles/prerec/templates/thumbnail.sh2
-rw-r--r--roles/publish/tasks/main.yml4
21 files changed, 460 insertions, 10 deletions
diff --git a/common-playbook.yml b/common-playbook.yml
index 4b12e4d..9cb44a3 100644
--- a/common-playbook.yml
+++ b/common-playbook.yml
@@ -71,3 +71,8 @@
tags: live
roles:
- live
+- name: Set up lounge
+ hosts: front
+ tags: lounge
+ roles:
+ - lounge
diff --git a/roles/bbb/tasks/main.yml b/roles/bbb/tasks/main.yml
index 1a4b115..017e939 100644
--- a/roles/bbb/tasks/main.yml
+++ b/roles/bbb/tasks/main.yml
@@ -16,3 +16,13 @@
with_file:
- ../../base/files/keys/sachac
- ../../base/files/keys/orga
+- name: Set up video.yml
+ become: true
+ template:
+ src: video.yml
+ dest: /usr/local/bigbluebutton/core/scripts/video.yml
+- name: Set up bigbluebutton.yml
+ become: true
+ template:
+ src: bigbluebutton.yml
+ dest: /usr/local/bigbluebutton/core/scripts/bigbluebutton.yml
diff --git a/roles/bbb/templates/bigbluebutton.yml b/roles/bbb/templates/bigbluebutton.yml
new file mode 100755
index 0000000..beb8ce8
--- /dev/null
+++ b/roles/bbb/templates/bigbluebutton.yml
@@ -0,0 +1,73 @@
+bbb_version: '3.0.9'
+raw_audio_src: /var/freeswitch/meetings
+mediasoup_video_src: /var/mediasoup/recordings
+mediasoup_screenshare_src: /var/mediasoup/screenshare
+webrtc_recorder_video_src: /var/lib/bbb-webrtc-recorder/recordings
+webrtc_recorder_screenshare_src: /var/lib/bbb-webrtc-recorder/screenshare
+webrtc_recorder_audio_src: /var/lib/bbb-webrtc-recorder/audio
+raw_deskshare_src: /var/bigbluebutton/deskshare
+raw_presentation_src: /var/bigbluebutton
+notes_endpoint: http://127.0.0.1:9002/p
+# Specify the notes formats we archive
+# txt, doc and odt are also supported
+notes_formats:
+ - etherpad
+ - html
+ - pdf
+redis_host: 127.0.0.1
+redis_port: 6379
+# Uncomment and set password if redis require it.
+# redis_password: changeme
+
+# redis_workers_host: 127.0.0.1
+# redis_workers_port: 6379
+
+# Set to true to insert recording process status into
+# redis list with key "store_recording_status: true".
+# This is useful if you want to track progress status
+# and have another script process it.
+store_recording_status: false
+# Whether to anonymize the sender of chat messages in the processed
+# recordings. The settings here are the defaults; they can be overridden
+# by passing meta parameters on the meeting create call.
+# meta param: meta_bbb-anonymize-chat (true/false)
+anonymize_chat: false
+# By default only names of viewers are anonymized - if you would also
+# like to anonymize moderators, you can set this to true:
+# meta param: meta_bbb-anonymize-chat-moderators (true/false)
+anonymize_chat_moderators: false
+# By default, recordings assume the Viewer viewpoint (with all locks)
+# so when webcamsOnlyForModerator=true, only moderators webcams are included in recordings.
+# Use this option to ignore locks and assume Moderator viewpoint instead.
+show_moderator_viewpoint: false
+# Sequence of recording steps. Keys are the current step, values
+# are the next step(s). Examples:
+# current_step: next_step
+# "current_step-format": "next_step-format"
+# current_step:
+# - next_step
+# - another_step-format
+steps:
+ archive: "sanity"
+ sanity: "captions"
+ captions:
+ - "process:presentation"
+ - "process:video"
+ "process:presentation": "publish:presentation"
+ "process:video": "publish:video"
+# For PRODUCTION
+log_dir: /var/log/bigbluebutton
+events_dir: /var/bigbluebutton/events
+recording_dir: /var/bigbluebutton/recording
+published_dir: /var/bigbluebutton/published
+captions_dir: /var/bigbluebutton/captions
+playback_host: bbb.emacsverse.org
+playback_protocol: https
+
+# For DEVELOPMENT
+# This allows us to run the scripts manually
+#scripts_dir: /home/ubuntu/dev/bigbluebutton/record-and-playback/core/scripts
+#log_dir: /home/ubuntu/temp/log
+#recording_dir: /home/ubuntu/temp/recording
+#published_dir: /home/ubuntu/temp/published
+#playback_host: bbb.emacsverse.org
diff --git a/roles/bbb/templates/video.yml b/roles/bbb/templates/video.yml
new file mode 100644
index 0000000..461372b
--- /dev/null
+++ b/roles/bbb/templates/video.yml
@@ -0,0 +1,81 @@
+publish_dir: /var/bigbluebutton/published/video
+playback_dir: /usr/local/bigbluebutton/core/playback/video
+# offset applied to audio in the output video file
+# audio_offset = 1000 means that the audio will be delayed by 1000ms
+audio_offset: 0
+
+layout:
+ width: 1280
+ height: 720
+ framerate: 24
+ areas:
+ - name: presentation
+ x: 0
+ y: 0
+ width: 960
+ height: 720
+ - name: webcam
+ x: 960
+ y: 0
+ width: 320
+ height: 720
+ - name: deskshare
+ x: 0
+ y: 0
+ width: 960
+ height: 720
+ pad: true
+nopresentation_layout:
+ width: 1280
+ height: 720
+ framerate: 24
+ areas:
+ - name: webcam
+ x: 0
+ y: 0
+ width: 1280
+ height: 720
+nowebcam_layout:
+ width: 1280
+ height: 720
+ framerate: 24
+ areas:
+ - name: presentation
+ x: 0
+ y: 0
+ width: 1280
+ height: 720
+ - name: deskshare
+ x: 0
+ y: 0
+ width: 1280
+ height: 720
+ pad: true
+formats:
+ #- mimetype: 'video/mp4'
+ # extension: m4v
+ # parameters:
+ # - [ '-c:v', 'copy', # Use working format codec defined in core/lib/recordandplayback/edl/video.rb
+ # '-c:a', 'aac', '-b:a', '128K',
+ # '-f', 'mp4', '-movflags', 'faststart' ]
+ # postprocess: []
+ - mimetype: 'video/webm;codecs="vp09.00.41.08,opus"'
+ extension: webm
+ parameters:
+ # # Default single-pass encode
+ # #- [ '-c:v', 'libvpx-vp9', '-level', '4.1', '-b:v', '1800K', '-minrate', '900K', '-maxrate', '2610K',
+ # # '-crf', '31', '-quality', 'good', '-speed', '2', '-tile-columns', '2', '-threads', '2',
+ # # '-force_key_frames', 'expr:gte(t,n_forced*10)',
+ # # '-c:a', 'libopus', '-b:a', '64K',
+ # # '-f', 'webm' ]
+ # Slower but better quality two-pass encode
+ - [ '-c:v', 'libvpx-vp9', '-level', '4.1', '-b:v', '1800K', '-minrate', '900K', '-maxrate', '2610K',
+ '-crf', '31', '-quality', 'good', '-pass', '1', '-speed', '4', '-tile-columns', '2', '-threads', '2',
+ '-force_key_frames', 'expr:gte(t,n_forced*10)',
+ '-an',
+ '-f', 'webm' ]
+ - [ '-c:v', 'libvpx-vp9', '-level', '4.1', '-b:v', '1800K', '-minrate', '900K', '-maxrate', '2610K',
+ '-crf', '31', '-quality', 'good', '-pass', '2', '-speed', '2', '-tile-columns', '2', '-threads', '2',
+ '-force_key_frames', 'expr:gte(t,n_forced*10)',
+ '-c:a', 'libopus', '-b:a', '64K',
+ '-f', 'webm' ]
diff --git a/roles/caption/tasks/main.yml b/roles/caption/tasks/main.yml
index 96b3198..dbc5454 100644
--- a/roles/caption/tasks/main.yml
+++ b/roles/caption/tasks/main.yml
@@ -22,6 +22,7 @@
- num2words
- name: Set up aeneas
include_tasks: aeneas.yml
+ when: "'aeneas' in ansible_run_tags"
- name: Create group
group:
name: "{{ emacsconf_group }}"
diff --git a/roles/lounge/defaults/main.yml b/roles/lounge/defaults/main.yml
new file mode 100644
index 0000000..26fbaaa
--- /dev/null
+++ b/roles/lounge/defaults/main.yml
@@ -0,0 +1,4 @@
+lounge_domain: chat.emacsconf.org
+irc_network: irc.libera.chat
+irc_port: 6697
+irc_channels: "#emacsconf, #emacsconf-gen, #emacsconf-dev, and #emacsconf-org"
diff --git a/roles/lounge/tasks/main.yml b/roles/lounge/tasks/main.yml
new file mode 100644
index 0000000..8c6593f
--- /dev/null
+++ b/roles/lounge/tasks/main.yml
@@ -0,0 +1,40 @@
+- name: Create directory
+ file:
+ path: /var/www/{{ lounge_domain }}
+ owner: "{{ emacsconf_user }}"
+ group: "{{ emacsconf_group }}"
+ state: directory
+- name: Set up error page
+ template:
+ src: error.html
+ dest: /var/www/{{ lounge_domain }}/error.html
+ mode: 0755
+ owner: "{{ emacsconf_user }}"
+ group: "{{ emacsconf_group }}"
+- name: Create main configuration if needed
+ template:
+ src: nginx-site-config
+ dest: /etc/nginx/sites-available/{{ lounge_domain }}
+- name: Make sure main configuration is enabled
+ file:
+ src: /etc/nginx/sites-available/{{ lounge_domain }}
+ dest: /etc/nginx/sites-enabled/{{ lounge_domain }}
+ owner: "{{ emacsconf_user }}"
+ group: "{{ emacsconf_group }}"
+ force: no
+ state: link
+- name: Reload configuration
+ become: true
+ service:
+ name: nginx
+ state: reloaded
+- name: Install systemd configuration
+ tags: system
+ become: true
+ template:
+ src: thelounge.service
+ dest: /etc/systemd/system/thelounge.service
+ owner: root
+ group: root
+ mode: 0755
+ when: not use_initd
diff --git a/roles/lounge/templates/error.html b/roles/lounge/templates/error.html
new file mode 100644
index 0000000..5e2a093
--- /dev/null
+++ b/roles/lounge/templates/error.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>{{lounge_domain}} currently unavailable</title>
+ <style>
+ body { padding: 20px; font-family: Arial, sans-serif }
+ </style>
+</head>
+<body>
+ <h1>Web-based chat is currently unavailable (code 502)</h1>
+
+ <p>The web-based IRC interface will be available during <a href="https://{{emacsconf_domain}}/{{emacsconf_year}}">{{emacsconf_name}} {{emacsconf_year}}</a>. Please check back then. In the meantime, you can also connect to {{irc_network}}:{{irc_port}} with your favorite IRC client and join {{irc_channels}}.
+
+ <p>This page will refresh when the site is back. You can also check <a href="https://status.emacsconf.org">status.emacsconf.org</a> for updates.</p>
+
+ <noscript>Your browser doesn’t support javascript. Please try refreshing the page manually every few minutes.</noscript>
+
+ <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
+ <script>
+ var retryCurrent = 30, retryMax = 60 * 5;
+ async function check() {
+ let result = await fetch(window.location.href, { method: HEAD }).then(resp => {
+ if (resp.status == 200) {
+ window.location.reload(true);
+ } else if (resp.status == 502) {
+ if (retryCurrent < retryMax) {
+ retryCurrent = Math.min(retryCurrent * 2, retryMax);
+ }
+ setTimeout(check, retryCurrent * 1000);
+ }
+ });
+ }
+ setTimeout(check_response, retryCurrent * 1000);
+ </script>
+</body>
+</html>
diff --git a/roles/lounge/templates/nginx-site-config b/roles/lounge/templates/nginx-site-config
new file mode 100644
index 0000000..cc6aa4d
--- /dev/null
+++ b/roles/lounge/templates/nginx-site-config
@@ -0,0 +1,63 @@
+upstream backend {
+ server 127.0.0.1:9000;
+}
+
+proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=thelounge_cache:10m max_size=3g inactive=120m use_temp_path=off;
+
+
+server {
+ listen 80;
+ listen [::]:80;
+ server_name chat.emacsconf.org;
+
+ include snippets/well-known-acme-challenge.conf;
+
+ location /js-licenses.html { root /var/www/{{lounge_domain}}; }
+
+ location / {
+ return 302 https://$server_name$request_uri;
+ }
+}
+
+server {
+ listen 443 ssl http2;
+ listen [::]:443 ssl http2;
+ server_name {{lounge_domain}};
+
+ include /etc/nginx/tls/{{emacsconf_domain}}.conf;
+
+ location /js-licenses.html { root /var/www/{{lounge_domain}}; }
+ error_page 502 /error.html;
+ location = /error.html {
+ root /var/www/{{lounge_domain}};
+ }
+ location / {
+ proxy_pass http://backend;
+ proxy_http_version 1.1;
+ proxy_set_header Connection "upgrade";
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header X-Forwarded-For $remote_addr;
+ proxy_set_header X-Forwarded-Proto $scheme;
+
+ # by default nginx times out connections in one minute
+ proxy_read_timeout 1d;
+ }
+
+}
+
+#server {
+# listen 443 ssl http2;
+# listen [::]:443 ssl http2;
+# server_name chat.emacsconf.org;
+#
+# include /etc/nginx/tls/emacsconf.org.conf;
+# root /var/www/chat.emacsconf.org;
+#}
+
+server {
+ listen 80;
+ listen [::]:80;
+ server_name chat.emacsconf.com chat.emacsconf.net;
+
+ return 302 $scheme://{{lounge_domain}}$request_uri;
+}
diff --git a/roles/lounge/templates/thelounge.service b/roles/lounge/templates/thelounge.service
new file mode 100644
index 0000000..abc4868
--- /dev/null
+++ b/roles/lounge/templates/thelounge.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=The Lounge IRC Client
+After=network.target
+
+[Service]
+ExecStart=/usr/bin/thelounge start
+User=thelounge
+WorkingDirectory=/var/lib/thelounge
+
+[Install]
+WantedBy=multi-user.target
diff --git a/roles/media/tasks/main.yml b/roles/media/tasks/main.yml
index e9daaef..94f10a3 100644
--- a/roles/media/tasks/main.yml
+++ b/roles/media/tasks/main.yml
@@ -49,11 +49,21 @@
template:
src: nginx-include
dest: /etc/nginx/sites-available/{{ media_server_name }}-{{ emacsconf_year }}-include
+- name: Create 404 page
+ template:
+ src: 404.html
+ dest: /var/www/{{ media_server_name }}/404.html
+
- name: Create main configuration if needed
template:
src: nginx-site-config
dest: /etc/nginx/sites-available/{{ media_server_name }}
force: no
+- name: Make sure 404 line is in main config
+ lineinfile:
+ line: error_page 404 403 /404.html;
+ dest: /etc/nginx/sites-available/{{ media_server_name }}
+ insertafter: "listen 443 ssl http2;"
- name: Make sure main configuration is enabled
file:
src: /etc/nginx/sites-available/{{ media_server_name }}
diff --git a/roles/media/templates/nginx-site-config b/roles/media/templates/nginx-site-config
index ba25cba..f6a83b1 100644
--- a/roles/media/templates/nginx-site-config
+++ b/roles/media/templates/nginx-site-config
@@ -1,7 +1,17 @@
server {
- listen 80;
- server_name {{ media_server_name }};
- root /var/www/{{ media_server_name }};
+ listen 80;
+ server_name {{ media_server_name }};
+ root /var/www/{{ media_server_name }};
+ error_page 404 403 /404.html;
+ location / {
+ add_header Cache-Control "no-store, no-cache, must-revalidate";
+ add_header Pragma "no-cache";
+ expires 0;
+ }
+ types {
+ text/plain org;
+ }
+
location ~* \.vtt$ {
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header Pragma "no-cache";
diff --git a/roles/obs/tasks/mpv.yml b/roles/obs/tasks/mpv.yml
index 4120f8c..c5806a8 100644
--- a/roles/obs/tasks/mpv.yml
+++ b/roles/obs/tasks/mpv.yml
@@ -7,7 +7,8 @@
repo: deb https://non-gnu.uvt.nl/debian {{ ansible_distribution_release }} uvt
- name: Install mpv
apt:
- name: mpv
+ name: mpv=0.38.0+fruit.1
+ allow_downgrade: true
- name: Download MPVC
git:
repo: https://github.com/lwilletts/mpvc.git
diff --git a/roles/obs/templates/mpv.conf b/roles/obs/templates/mpv.conf
index b9efaae..7b708aa 100644
--- a/roles/obs/templates/mpv.conf
+++ b/roles/obs/templates/mpv.conf
@@ -27,6 +27,14 @@ sub-shadow-color=0/1
sub-shadow-offset=1.2
sub-ass-force-style=Kerning=yes
sub-ass-line-spacing=0
+osd-level=3
+osd-bar-align-x=1
+osd-bar-align-y=1
+osd-bar-h=0.1
+osd-bar-w=0.1
+osd-align-x=right
+osd-align-y=bottom
+osd-scale=0.3
[full]
video-zoom=0
diff --git a/roles/pad-proxy/templates/etherpad.nginx.conf b/roles/pad-proxy/templates/etherpad.nginx.conf
index b657b98..2c285af 100644
--- a/roles/pad-proxy/templates/etherpad.nginx.conf
+++ b/roles/pad-proxy/templates/etherpad.nginx.conf
@@ -24,6 +24,9 @@ server {
proxy_buffering off;
proxy_pass http://etherpad_upstream;
}
+ location /emacsconf/?$ {
+ return 301 /p/{{ emacsconf_year }};
+ }
location /p/ {
rewrite ^/p/(.*) /$1 redirect;
}
diff --git a/roles/prerec/tasks/main.yml b/roles/prerec/tasks/main.yml
index a0a3cac..98b7f13 100644
--- a/roles/prerec/tasks/main.yml
+++ b/roles/prerec/tasks/main.yml
@@ -1,9 +1,11 @@
- name: Ensure the directory exists
+ become: true
file:
path: "{{ emacsconf_caption_dir }}/{{ item }}"
state: directory
owner: "{{ emacsconf_user }}"
group: "{{ emacsconf_group }}"
+ recurse: true
loop:
- scripts
- cache
diff --git a/roles/prerec/templates/Makefile b/roles/prerec/templates/Makefile
index f58c5d6..778ae3e 100644
--- a/roles/prerec/templates/Makefile
+++ b/roles/prerec/templates/Makefile
@@ -2,21 +2,41 @@
# To recreate this file, use ansible-playbook -i inventory.yml prod-playbook.yml --tags prerec-make
-VIDEO_EXTS = mp4 mkv webm mov mpv
+.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
+all: reencoded opus main main-opus waveforms.png
reencoded: $(PRERECS_REENCODED)
@@ -26,6 +46,17 @@ 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)))))
@@ -38,7 +69,12 @@ emacsconf-%--reencoded.webm:
reencode-in-screen.sh "$(SOURCE)"
emacsconf-%--reencoded.opus: emacsconf-%--reencoded.webm
- ffmpeg -y -i "$<" -c:a copy "$@"
+ 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 "$@"
@@ -60,11 +96,20 @@ emacsconf-%--main.webm: emacsconf-%--reencoded.webm emacsconf-%--normalized.opus
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
- ffmpeg -y -i "$<" -c:a copy "$@"
+ 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\`." "$<"
@@ -116,3 +161,38 @@ live-dormant:
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 "$@"
diff --git a/roles/prerec/templates/reencode-in-screen.sh b/roles/prerec/templates/reencode-in-screen.sh
index 5c12203..7119572 100755
--- a/roles/prerec/templates/reencode-in-screen.sh
+++ b/roles/prerec/templates/reencode-in-screen.sh
@@ -1,7 +1,11 @@
#!/bin/bash
ORIGINAL=$1
BASE="${ORIGINAL%--original.*}"
-REENCODED="${BASE}--reencoded.webm"
+if [ -n "$2" ]; then
+ REENCODED=$2
+else
+ REENCODED="${BASE}--reencoded.webm"
+fi
SLUG=$(echo "$ORIGINAL" | perl -ne '/^emacsconf-[0-9]*-(.*?)--/ && print $1')
LOCK=".lock-$SLUG"
diff --git a/roles/prerec/templates/talk b/roles/prerec/templates/talk
index fa2e5f0..a9d4cb0 100755
--- a/roles/prerec/templates/talk
+++ b/roles/prerec/templates/talk
@@ -3,6 +3,9 @@
# How to use: talk slug from-status-regexp to-status
# or talk slug to-status
+# Statuses:
+# PLAYING:
+
SLUG="$1"
FROM_STATUS="$2"
TO_STATUS="$3"
diff --git a/roles/prerec/templates/thumbnail.sh b/roles/prerec/templates/thumbnail.sh
index 436979d..1cf7372 100755
--- a/roles/prerec/templates/thumbnail.sh
+++ b/roles/prerec/templates/thumbnail.sh
@@ -1,3 +1,3 @@
#!/bin/bash
# {{ ansible_managed }}
-ffmpeg -i "$1" -vf "thumbnail,scale=400:225" -frames:v 1 $(echo "$1" | sed s/webm/png/ )
+ffmpeg -y -i "$1" -vf "thumbnail,scale=400:225" -frames:v 1 $(echo "$1" | sed s/webm/png/ )
diff --git a/roles/publish/tasks/main.yml b/roles/publish/tasks/main.yml
index 797ac7f..3ea3784 100644
--- a/roles/publish/tasks/main.yml
+++ b/roles/publish/tasks/main.yml
@@ -39,10 +39,14 @@
owner: "{{ emacsconf_user }}"
group: "{{ emacsconf_group }}"
state: directory
+- name: Debug
+ debug:
+ var: emacs_config_dir
- name: Set up Emacs configuration for non-interactive publishing
template:
src: emacsconf-config.el
dest: "{{ emacs_config_dir }}/emacsconf-config.el"
+ force: yes
owner: "{{ emacsconf_user }}"
group: "{{ emacsconf_group }}"
- name: Check if Emacs base configuration already exists