From a640801ad9c6b57000e4c733b4fe007ab46dffe7 Mon Sep 17 00:00:00 2001 From: Sacha Chua Date: Thu, 22 Sep 2022 10:01:35 -0400 Subject: Copy the code for extracting QA recordings --- 2022/organizers-notebook.org | 188 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) (limited to '2022/organizers-notebook.org') diff --git a/2022/organizers-notebook.org b/2022/organizers-notebook.org index 3ece421b..21bd976d 100644 --- a/2022/organizers-notebook.org +++ b/2022/organizers-notebook.org @@ -621,6 +621,194 @@ Exceptions: ** After the conference *** Send thanks [[*Thank you, next steps][Thank you, next steps]] +*** Extract the opening and closing remarks +*** Extract the Q&A recordings, trimming as needed +From https://bbb.emacsverse.org/b/admins/recordings +#+begin_src js2 :eval no :tangle no +console.log([...document.querySelectorAll('.email-link')].map((o) => '| ' + o.closest('tr').querySelector('time').getAttribute('datetime') + ' | ' + o.closest('tr').querySelector('#recording-text').innerHTML.trim() + ' | ' + o.getAttribute('data-pres-link').trim() + ' |').join('\n')) +#+end_src + +Make an ~ids.txt~ with the IDs extracted from BBB. + +In the same directory: +#+begin_src bash :eval no +while read p; do + mkdir -p "$p"; + cd "$p"; + wget "https://bbb.emacsverse.org/presentation/${p}/slides_new.xml" \ + "https://bbb.emacsverse.org/presentation/${p}/video/webcams.webm" \ + "https://bbb.emacsverse.org/presentation/${p}/deskshare.xml" \ + "https://bbb.emacsverse.org/presentation/${p}/deskshare/deskshare.webm" \ + "https://bbb.emacsverse.org/presentation/${p}/metadata.xml" + cd ..; +done \\(.+?\\)" + "<\\1>" (dom-attr node 'message))))) + (if (string-match speaker (dom-attr node 'name)) + (format "- %s: %s\n" speaker message) + (format "- %s\n" message))))) + (dom-by-tag (xml-parse-region (point-min) (point-max)) 'chattimeline) + ""))) + (emacsconf-edit-wiki-page slug) + (if (re-search-forward "# Discussion" nil t) + (progn + (goto-char (match-end 0)) + (insert "\n\n")) + (goto-char (point-max))) + (kill-new text))) +;; TODO: Combine lines from same nick, or identify speakers with anon1/2/etc. +(defun emacsconf-extract-chat-from-dired () + (interactive) + (find-file (expand-file-name "slides_new.xml" (dired-get-file-for-visit))) + (call-interactively 'emacsconf-extract-chat)) +#+end_src + +#+begin_src emacs-lisp :eval no +(defun emacsconf-make-webcams-deskshare-spans (deskshare start-ms stop-ms strategy source-dir) + (let ((secs (/ start-ms 1000.0)) + (webcam-video (expand-file-name "webcams.webm" source-dir)) + (deskshare-video (expand-file-name "deskshare.webm" source-dir)) + spans) + (mapc (lambda (o) + (unless (or (= secs (string-to-number (dom-attr o 'start_timestamp))) + (= (string-to-number (dom-attr o 'start_timestamp)) 0) + (> secs (/ stop-ms 1000.0))) + (setq spans (cons (list :source webcam-video + :start-ms (* secs 1000) + :stop-ms + (* 1000 + (if (eq strategy 'test) + (+ secs 3) + (max secs (string-to-number (dom-attr o 'start_timestamp)))))) + spans))) + (when (and (<= (string-to-number (dom-attr o 'start_timestamp)) + (/ stop-ms 1000.0)) + (>= (string-to-number (dom-attr o 'stop_timestamp)) + (/ start-ms 1000.0))) + (setq spans (cons (list :source deskshare-video + :start-ms (max (* 1000 (string-to-number (dom-attr o 'start_timestamp))) + start-ms) + :stop-ms + (if (eq strategy 'test) + (* 1000 (+ (string-to-number (dom-attr o 'start_timestamp)) 3)) + (min (* 1000 (string-to-number (dom-attr o 'stop_timestamp))) + stop-ms))) + spans)) + (setq secs (string-to-number (dom-attr o 'stop_timestamp))))) + (dom-by-tag deskshare 'event)) + (unless (>= (floor (* secs 1000)) stop-ms) + (setq spans (cons (list :source webcam-video + :start-ms (* 1000 secs) + :stop-ms (if (eq strategy 'test) + (* 1000 (+ secs 3)) + stop-ms)) + spans))) + (if (eq strategy 'test) + `((video ,@(reverse spans)) + (audio ,@(mapcar (lambda (o) + (list :source webcam-video + :start-ms (plist-get o :start-ms) + :stop-ms (plist-get o :stop-ms))) + (reverse spans)))) + `((video ,@(nreverse spans)) + (audio (:source ,webcam-video :start-ms ,start-ms :stop-ms ,stop-ms)))))) + +(defun emacsconf-get-ffmpeg-to-splice-webcam-and-recording (slug start-ms stop-ms info &optional strategy) + "Return FFMPEG command for slicing. +Strategies: +- 'fast-cut-start-keyframe - find the keyframe before the start ms and cut from there, doing a fast copy. +- 'start-keyframe-and-reencode - find the keyframe before the start ms and cut from there, reencoding. +- 'cut-and-concat - seek to the keyframe before, slowly find the start-ms, reencode the snippet, and then do a fast copy of the remaining. May have encoding errors. +- default: copy from start-ms to stop-ms, reencoding. +" + (let* ((source-dir (expand-file-name (concat "../questions/by-slug/" slug) emacsconf-captions-directory)) + (video-slug (plist-get (seq-find (lambda (o) (string= (plist-get o :slug) slug)) info) :video-slug)) + (output (expand-file-name (concat video-slug "--answers.webm") emacsconf-captions-directory)) + (webcam-video (expand-file-name "webcams.webm" source-dir))) + (if (file-exists-p (expand-file-name "deskshare.webm" source-dir)) + ;; Has deskshare + (let* ((deskshare (xml-parse-file (expand-file-name "deskshare.xml" source-dir))) + (final-size (compile-media-max-dimensions + (expand-file-name "deskshare.webm" source-dir) + (expand-file-name "webcams.webm" source-dir))) + (duration (compile-media-get-file-duration-ms (expand-file-name "webcams.webm" source-dir))) + (spans (emacsconf-make-webcams-deskshare-spans deskshare start-ms stop-ms strategy source-dir)) + (compile-media-output-video-width (car final-size)) + (compile-media-output-video-height (cdr final-size))) + (compile-media-get-command spans output)) + ;; Just webcams + (compile-media-get-command + (compile-media-split-tracks + (list (list :source webcam-video :start-ms start-ms :stop-ms stop-ms))) + output)))) +#+end_src + +Make a table of the form + +#+NAME: QA_RECORDINGS +| Start | End | Slug | Notes | URL | Timestamp | +|-------+-----+------+-------+-----+-----------| + +#+begin_src emacs-lisp :var qa=QA_RECORDINGS :eval no :dir="videos/" +(defun emacsconf-process-qa-recordings (qa dir) +;; (setq conf-qa-recordings qa) +;; (memoize 'conf-ffmpeg-get-closest-keyframe-in-msecs) +;; (memoize 'conf-ffmpeg-get-keyframes-between) +;; (memoize 'conf-video-dimensions) +;; (memoize 'compile-media-get-file-duration-ms) +;; (memoize-restore 'conf-ffmpeg-get-keyframes-around) + +(let ((info (emacsconf-get-talk-info))) + (replace-regexp-in-string + "captions/" "answers-slow/" + (replace-regexp-in-string + dir "" + (string-join + (nreverse + (sort + (delq nil + (mapcar + (lambda (o) + (when (> (length (car o)) 0) + (emacsconf-get-ffmpeg-to-splice-webcam-and-recording + (elt o 2) + (compile-media-timestamp-to-msecs (elt o 0)) + (compile-media-timestamp-to-msecs (elt o 1)) + info))) +; (seq-take qa 2) + qa + )) + (lambda (a b) (string-match "trim" a)))) + "\n"))))) +#+end_src + *** Update the wiki *** Update captions -- cgit v1.2.3