diff options
| author | Sacha Chua <sacha@sachachua.com> | 2022-09-22 10:01:35 -0400 | 
|---|---|---|
| committer | Sacha Chua <sacha@sachachua.com> | 2022-09-22 10:01:35 -0400 | 
| commit | a640801ad9c6b57000e4c733b4fe007ab46dffe7 (patch) | |
| tree | 18dbbf991ea7da690a0f8fe644e829b87d99b73d /2022/organizers-notebook.org | |
| parent | a31c25c4ca16024e32bb16b57d1d93ba9d10e726 (diff) | |
| download | emacsconf-wiki-a640801ad9c6b57000e4c733b4fe007ab46dffe7.tar.xz emacsconf-wiki-a640801ad9c6b57000e4c733b4fe007ab46dffe7.zip | |
Copy the code for extracting QA recordings
Diffstat (limited to '')
| -rw-r--r-- | 2022/organizers-notebook.org | 188 | 
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 | 
