summaryrefslogtreecommitdiffstats
path: root/2022/organizers-notebook.org
diff options
context:
space:
mode:
Diffstat (limited to '2022/organizers-notebook.org')
-rw-r--r--2022/organizers-notebook.org188
1 files changed, 188 insertions, 0 deletions
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 <ids.txt
+#+end_src
+
+Resource explanation:
+
+- slides_new.xml :: Text chat
+- webcams.webm :: Webcam as video stream, also has audio
+- deskshare.xml :: start and stop time of desktop sharing, if any
+- deskshare.webm :: Shared desktop as video
+- metadata.xml
+
+Probably focus on grabbing the audio first and seeing what's worth keeping
+
+#+begin_src emacs-lisp
+(defun emacsconf-extract-chat (slug speaker)
+ (interactive (list
+ (emacsconf-complete-talk)
+ (completing-read "Speaker: "
+ (seq-uniq
+ (mapcar (lambda (node) (dom-attr node 'name))
+ (dom-by-tag (xml-parse-region (point-min) (point-max)) 'chattimeline)))
+ )))
+ (let ((text
+ (mapconcat (lambda (node)
+ (when (string= (dom-attr node 'target) "chat")
+ (let ((message
+ (replace-regexp-in-string
+ "\\(^[^ +]?\\): " ""
+ (replace-regexp-in-string "<a href=\"\\(.+?\\)\" rel=\"nofollow\"><u>\\(.+?\\)</u></a>"
+ "<\\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