From 4dac85ef27c35d526edcb5c6bc1965bb26f84472 Mon Sep 17 00:00:00 2001 From: Sacha Chua Date: Sat, 12 Dec 2020 00:52:38 -0500 Subject: More tweaks to code --- 2020/organizers-notebook.org | 413 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 370 insertions(+), 43 deletions(-) (limited to '2020/organizers-notebook.org') diff --git a/2020/organizers-notebook.org b/2020/organizers-notebook.org index d69c4d2d..5e5a3b41 100644 --- a/2020/organizers-notebook.org +++ b/2020/organizers-notebook.org @@ -1,12 +1,14 @@ #+todo: TODO(t) INPROGRESS(i) | DONE(d) CANCELLED(c) #+OPTIONS: h:6 -#+PROPERTY: header-args :results silent :exports code +#+PROPERTY: header-args :results silent :exports code :tangle yes #+begin_export md [[!toc levels=4]] #+end_export +[[elisp:(progn (org-md-export-to-markdown) (org-babel-tangle))][Export and tangle]] + * Tasks ** Manually transcribe Either subtitles (with timestamps) or a text transcript (no timestamps) is perfectly okay. @@ -69,32 +71,26 @@ organizers-notebook.org back to the repo. - [ ] [[./subtitles/emacsconf-2020--41-opening-remarks-autogen.sbv]] - [ ] [[./subtitles/emacsconf-2020--42-closing-remarks-autogen.sbv]] -** DONE Create tasks for each of the subtitles - CLOSED: [2020-12-09 Wed 15:42] - :LOGBOOK: - - State "DONE" from "TODO" [2020-12-09 Wed 15:42] - :END: -** DONE Link compressed videos on each talk page - CLOSED: [2020-12-09 Wed 15:42] - :LOGBOOK: - - State "DONE" from "TODO" [2020-12-09 Wed 15:42] - :END: +* Assumptions and settings + +Note that re-evaluating a defvar won't change the value, so if you want to change the value after this is already loaded, use =(setq ...)=. + #+begin_src emacs-lisp - (mapc (lambda (o) - (if (string-match "\\(emacsconf-2020--\\([0-9]+\\).*?\\)-vp9-q56-original-audio\\.webm" o) - (let ((talk-id (match-string 2 o)) - (base (match-string 1 o))) - (find-file (expand-file-name (concat talk-id ".md") "~/vendor/emacsconf-wiki/2020/info")) - (goto-char (point-min)) - (when (re-search-forward base nil t) - (forward-line 1) - (beginning-of-line) - (unless (looking-at "\\[Download") - (insert (format "[Download compressed %s.webm video (%s)](https://media.emacsconf.org/2020/%s)\n" - (if (string-match "questions" o) "Q&A " "") - (file-size-human-readable (file-attribute-size (file-attributes o))) - (file-name-nondirectory o)))))))) - (directory-files "~/vendor/emacsconf-original-audio" t "webm")) +(defvar conf/buffer-minutes 3 "Number of minutes to use as a buffer between talks.") +(defvar conf/timezones '("EST" "America/Los_Angeles" "UTC" "CET" "Asia/Singapore") "List of timezones") +(defvar conf/autogenerate-talk-pages nil "Set this to t at the beginning of the conference, when we're still autogenerating individual talk pages. +Otherwise you might overwrite hand-edited talk pages.") +(defvar conf/collaborative-pad "https://etherpad.wikimedia.org/p/emacsconf-2020" "URL of collaborative pad.") +(defvar conf/streaming-nick "bandali" "IRC nick of main organizer in charge of streaming.") +(defvar conf/topic-templates nil "List of (channel topic-template) entries for mass-setting channel topics.") +(defvar conf/rooms '(("A" "http://example.org?room=a") + ("B" "http://example.org?room=b") + ("C" "http://example.org?room=c")) + "List of (code join-url) entries. Room codes should be uppercase.") ; actually set this in organizers' wiki index.org +(setq conf/topic-templates + '(("#emacsconf" "EmacsConf 2020 is over, thanks for joining! | Subscribe to https://lists.gnu.org/mailman/listinfo/emacsconf-discuss for updates") + ("#emacsconf-accessible" "EmacsConf 2020 is over. Thanks for making it more accessible! | Subscribe to https://lists.gnu.org/mailman/listinfo/emacsconf-discuss for updates") + ("#emacsconf-org" "EmacsConf2020 is over, thanks for joining! | Dedicated channel for EmacsConf organizers and speakers | this is intended as an internal, low-traffic channel; for main discussion around EmacsConf, please join #emacsconf | Subscribe to https://lists.gnu.org/mailman/listinfo/emacsconf-discuss for updates"))) #+end_src * Workflows @@ -106,6 +102,333 @@ STREAM - main organizer, CHECK - secondary organizer or volunteer, PAD - organiz - Collect e-mail addresses of accepted speakers into a list for easy pasting into Bcc (organizers' private wiki) - See submissions.org for Org scheduling code; 3 minutes of buffer was okay last time, but more would be better for Q&A; opening remarks time could be trimmed +**** Code for scheduling +#+begin_src emacs-lisp :exports code :results none +(defun conf/get-talk-info () + (let (talk results) + (org-map-entries (lambda () + (let ((heading (org-heading-components))) + (cond + ((and (elt heading 2) (or (null talk) + (<= (car heading) + (plist-get talk :level)))) ;; has a todo, therefore is a talk + (when talk (setq results (cons talk results))) + (setq talk (list + :type 'talk + :title (elt heading 4) + :talk-id (org-entry-get (point) "TALK_ID") + :status (elt heading 2) + :level (car heading) + :scheduled (org-entry-get (point) "SCHEDULED") + :duration (org-entry-get (point) "DURATION") + :time (org-entry-get (point) "MIN_TIME") + :speakers (org-entry-get (point) "NAME")))) + ((string-match "^ *Talk information *$" (elt heading 4)) + (plist-put talk :info + (org-export-as 'md t nil t))) + ((or (null talk) (< (car heading) (plist-get talk :level))) ;; heading above + (when talk + (setq results (cons talk results)) + (setq talk nil)) + (setq results (cons + (list :type 'headline + :level (car heading) + :speakers (org-entry-get (point) "NAME") + :duration (org-entry-get (point) "DURATION") + :talk-id (org-entry-get (point) "TALK_ID") + :title (elt heading 4) + :scheduled (org-entry-get (point) "SCHEDULED")) + results)))))) + nil 'tree) + (when talk (setq results (cons talk results))) + (reverse results))) + +(defun conf/filter-talks (list) + "Return only talk info in LIST." + (seq-filter + (lambda (talk) (eq (plist-get talk :type) 'talk)) + list)) + +(defun conf/get-talk-info-from-file (&optional filename) + (with-temp-buffer + (insert-file-contents (or filename "submissions.org")) + (org-mode) + (org-show-all) + (goto-char (point-min)) + (goto-char (org-find-property "ID" "talks")) + (conf/get-talk-info))) + + +(defun conf/find-talk (filter &optional info) + (setq info (or info (conf/filter-talks conf/info))) + (when (stringp filter) (setq filter (list filter))) + (or (seq-find (lambda (o) (string= (plist-get o :talk-id) (car filter))) info) + (seq-find (lambda (o) + (let ((case-fold-search t) + (all (mapconcat (lambda (f) (plist-get o f)) '(:title :speakers :talk-id) " "))) + (null (seq-contains-p + (mapcar (lambda (condition) (string-match condition all)) filter) + nil)))) + info))) + +(defun conf/goto-talk-id (id) + (goto-char (org-find-property "TALK_ID" id))) + +(defun conf/assign-ids () + "Assign numeric talk IDs." + (interactive) + (goto-char (point-min)) + ;; Determine the maximum ID assigned so far + (let ((id + (1+ + (apply 'max + (or (mapcar + 'string-to-number + (org-map-entries + (lambda () + (let ((org-trust-scanner-tags t)) + (org-entry-get (point) "TALK_ID"))) "TALK_ID>0" 'file)) + '(0)))))) + (goto-char (point-min)) + (while (re-search-forward "^ *:NAME: " nil t) + (unless (org-entry-get (point) "TALK_ID") + (org-set-property "TALK_ID" (format "%02d" id)) + (org-set-property "CUSTOM_ID" (format "talk%02d" id)) + (setq id (1+ id)))))) + +(defun conf/update-talks () + "Update times, tables, and schedules." + (interactive) + (save-excursion + (conf/update-times) + (conf/update-tables) + (conf/update-schedules))) + +(defun conf/update-times () + "Check whether we need more time or less time based on TARGET_TIME and MIN_TIME_SUM." + (goto-char (point-min)) + (org-map-entries + (lambda () + (when (org-entry-get (point) "TARGET_TIME") + (conf/org-sum-min-time-in-subtree) + (org-entry-put + (point) + "DIFFERENCE" + (let ((diff + (- + (string-to-number (org-entry-get (point) "TARGET_TIME")) + (string-to-number (org-entry-get (point) "MIN_TIME_SUM"))))) + (cond + ((> diff 0) (format "Extra: %d" diff)) + ((< diff 0) (format "Needs: %d" (- diff))) + (t "")))))) nil 'file)) + +(defun conf/update-tables () + "Update the time checks and table reports." + (goto-char (point-min)) + (while (re-search-forward "#\\+CALL: check_time()" nil t) + (org-ctrl-c-ctrl-c)) + (goto-char (point-min)) + (while (re-search-forward "#\\+BEGIN: columnview" nil t) + (org-ctrl-c-ctrl-c))) + +(defun conf/update-schedules () + "Schedule the talks based on the MIN_TIME and 3 minutes of buffer. +Talks with a FIXED_TIME property are not moved." + (interactive) + (goto-char (org-find-exact-headline-in-buffer "Talks")) + (let (current-time scheduled end-time duration (buffer (seconds-to-time (* conf/buffer-minutes 60)))) ;; assumption: 3 minutes between talks + (org-map-entries (lambda () + (if (org-entry-get (point) "FIXED_TIME") + (setq current-time (org-get-scheduled-time (point)))) + (when (org-entry-get (point) "MIN_TIME") + (setq duration (* (string-to-number (org-entry-get (point) "MIN_TIME")) 60) + end-time (time-add current-time (seconds-to-time duration))) + (org-set-property "SCHEDULED" (format "%s-%s" (org-format-time-string "%Y-%m-%d %H:%M" current-time) + (org-format-time-string "%H:%M" end-time))) + (setq current-time (time-add end-time buffer)))) + nil 'tree))) + +(defun conf/org-sum-min-time-in-subtree () + "Add up all the MIN_TIME properties of headings underneath the current one +The total is written to the MIN_TIME_SUM property of this heading" + (interactive) + (org-entry-put + (point) + "MIN_TIME_SUM" + (save-excursion + (format "%d" + (apply + '+ + (mapcar 'string-to-number + (delq nil + (org-map-entries + (lambda () (org-entry-get (point) "MIN_TIME")) nil 'tree)))))))) + +#+end_src + +**** Generate schedule file + + #+begin_src emacs-lisp :results none :eval yes :exports code :tangle "conf.el" + (defun conf/format-talk-link (talk) + (and talk (if (plist-get talk :talk-id) + (format "%s" + (plist-get talk :talk-id) + (plist-get talk :title)) + (plist-get talk :title)))) + + (defun conf/format-talk-info-as-schedule (info) + (format "%s
" + (mapconcat + (lambda (o) + (let* ((time-fmt "%l:%M %p") + (timestamp (org-timestamp-from-string (plist-get o :scheduled))) + (start (if timestamp (format-time-string time-fmt (org-timestamp-to-time (org-timestamp-split-range timestamp))) "")) + (end (if timestamp (format-time-string time-fmt (org-timestamp-to-time (org-timestamp-split-range timestamp t))) "")) + (title (plist-get o :title)) + (speakers (plist-get o :speakers))) + (if (eq (plist-get o :type) 'headline) + (format "%s" + (if (plist-get o :talk-id) + (conf/format-talk-link o) + title)) + (format "~%s~%s%s%s" + start end (conf/format-talk-link o) speakers)))) + (cdr info) "\n"))) + + (defun conf/filter-talks (info) + (seq-filter (lambda (o) (plist-get o :talk-id)) info)) + + (defun conf/split-out-talk-information () + (interactive) + (let ((talks (conf/filter-talks conf/info))) + (mapc (lambda (o) + (with-temp-buffer + (insert + (format "# %s\n%s\n\n%s" + (plist-get o :title) + (plist-get o :speakers) + (plist-get o :info))) + (write-file (expand-file-name (format "%s.md" (plist-get o :talk-id)) "info")))) + talks))) + + (defun conf/format-talk-pages (info) + (let* ((talks (conf/filter-talks info)) + (next-talks (cdr talks)) + (prev-talks (cons nil talks))) + (mapc (lambda (o) + (with-temp-buffer + (let* ((timestamp (org-timestamp-from-string (plist-get o :scheduled))) + (next-talk (conf/format-talk-link (pop next-talks))) + (prev-talk (conf/format-talk-link (pop prev-talks))) + (schedule (mapconcat + (lambda (tz) + (format "%s - %s" + (format-time-string "%A, %b %e %Y, ~%l:%M %p" + (org-timestamp-to-time (org-timestamp-split-range timestamp)) tz) + (format-time-string "%l:%M %p %Z" + (org-timestamp-to-time (org-timestamp-split-range timestamp t)) tz))) + conf/timezones + " \n")) + (nav-links (format "Back to the [[schedule]] \n%s%s" + (if prev-talk (format "Previous: %s \n" prev-talk) "") + (if next-talk (format "Next: %s \n" next-talk) "")))) + (insert (format "[[%s title=\"%s\"]] + [[%s copyright=\"Copyright © 2020 %s\"]] + + \n + + %s + + [[!inline pages=\"internal(2020/info/%s)\" raw=\"yes\"]] + + %s + + %s + + " + "!meta" + (replace-regexp-in-string "\"" "\\\\\"" (plist-get o :title)) + "!meta" + (plist-get o :speakers) + nav-links + (plist-get o :talk-id) + schedule + nav-links))) + (write-file (format "talks/%s.md" (plist-get o :talk-id))))) + talks))) + + (defun conf/generate-pad-template () + (interactive) + (let ((talks (conf/filter-talks conf/info))) + (with-current-buffer (find-file "pad-template.md") + (erase-buffer) + (insert + (concat + "Conference info, how to watch/participate: + Code of conduct: + + " + (mapconcat + (lambda (o) + (format "**%s** + Speaker(s): %s + Talk page: + + ,*Questions:* + + ,* Put your questions here, most recent on top + ,* sample text + + ,*Links:* + + ,* sample text + ,* sample text + + ,*Other notes:* + + ,* sample text + ,* sample text +
+
+ " (plist-get o :title) (plist-get o :speakers) (plist-get o :talk-id))) talks " \n \n"))) + (save-buffer)))) + + (defun conf/generate-talks-page () + (let ((info conf/info)) + (with-temp-buffer + (find-file "talk-details.md") + (erase-buffer) + (insert (format "%s
DurationTitleSpeakers
" + (mapconcat + (lambda (o) + (let* ((title (plist-get o :title)) + (speakers (plist-get o :speakers))) + (if (null (plist-get o :talk-id)) + (format "%s" (conf/format-talk-link o)) + (format "%s%s%s" + (plist-get o :duration) + (conf/format-talk-link o) + (plist-get o :speakers))))) + info "\n"))) + (save-buffer)))) + + (defun conf/generate-schedule-files (&optional filename) + (interactive) + (with-temp-buffer + (insert (conf/format-talk-info-as-schedule conf/info)) + (write-file "schedule-details.md")) + (when conf/autogenerate-talk-pages (conf/format-talk-pages conf/info))) + #+end_src + +Set the info based on submissions.org. + +#+begin_src emacs-lisp +(setq conf/info (conf/get-talk-info-from-file "submissions.org")) +#+end_src + + #+RESULTS: + *** Before the conference - Do tech checks and get alternative ways to contact speakers (phone number? IRC nick? Something that goes ding?) @@ -219,20 +542,7 @@ STREAM - main organizer, CHECK - secondary organizer or volunteer, PAD - organiz ***** Load data #+begin_src emacs-lisp :results silent - (defvar conf/collaborative-pad "https://etherpad.wikimedia.org/p/emacsconf-2020" "URL of collaborative pad.") - (defvar conf/topic-templates nil "List of (channel topic-template) entries for mass-setting channel topics.") - (defvar conf/streaming-nick "bandali" "IRC nick of main organizer in charge of streaming.") - "List of (code join-url) entries, one for each meeting room.") ;; Set this in a private file - (defvar conf/channels nil "List of IRC channels for broadcasts.") - (defvar conf/info nil "List of plists with the following keys: `:talk-id', `:name', `:speakers', and other info.") ; Set from submissions.org - (setq conf/topic-templates - '(("#emacsconf" "EmacsConf 2020 is over, thanks for joining! | Subscribe to https://lists.gnu.org/mailman/listinfo/emacsconf-discuss for updates") - ("#emacsconf-accessible" "EmacsConf 2020 is over. Thanks for making it more accessible! | Subscribe to https://lists.gnu.org/mailman/listinfo/emacsconf-discuss for updates") - ("#emacsconf-org" "EmacsConf2020 is over, thanks for joining! | Dedicated channel for EmacsConf organizers and speakers | this is intended as an internal, low-traffic channel; for main discussion around EmacsConf, please join #emacsconf | Subscribe to https://lists.gnu.org/mailman/listinfo/emacsconf-discuss for updates"))) - (defvar conf/rooms '(("A" "http://example.org?room=a") - ("B" "http://example.org?room=b") - ("C" "http://example.org?room=c")) - "List of (code join-url) entries. Room codes should be uppercase.") ; set from organizers' wiki index.org + (defvar conf/info nil "List of plists with the following keys: `:talk-id', `:name', `:speakers', and other info.") ; Set from submissions.org #+end_src ***** Announce topics @@ -299,7 +609,7 @@ STREAM - main organizer, CHECK - secondary organizer or volunteer, PAD - organiz (defun erc-cmd-BROADCAST (&rest message) "Say MESSAGE in all the conference channels." - (conf/erc-with-channels conf/channels + (conf/erc-with-channels (mapcar 'car conf/topic-templates) (erc-send-message (s-join " " message)))) #+end_src @@ -399,7 +709,7 @@ Another collaborative pad Usage: compress-video.sh input-filename.webm output-filename.webm - #+begin_src sh :tangle compress-video.sh + #+begin_src sh :eval no :tangle compress-video.sh Q=56 nice ffmpeg -y -i $1 -c:v libvpx-vp9 -b:v 0 -crf $Q -aq-mode 2 -an -tile-columns 0 -tile-rows 0 -frame-parallel 0 -cpu-used 8 -auto-alt-ref 1 -lag-in-frames 25 -g 999 -pass 1 -f webm -threads 8 /dev/null && nice ffmpeg -y -i $1 -c:v libvpx-vp9 -b:v 0 -crf $Q -c:a copy -tile-columns 2 -tile-rows 2 -frame-parallel 0 -cpu-used -5 -auto-alt-ref 1 -lag-in-frames 25 -pass 2 -g 999 -threads 8 $2 @@ -407,7 +717,7 @@ Another collaborative pad Here's the original version which compresses audio too. Usage: compress-video-compressed-audio.sh input-filename.webm output-filename.webm - #+begin_src sh :tangle compress-video-compressed-audio.sh + #+begin_src sh :eval no :tangle compress-video-compressed-audio.sh Q=56 nice ffmpeg -y -i $1 -c:v libvpx-vp9 -b:v 0 -crf $Q -aq-mode 2 -an -tile-columns 0 -tile-rows 0 -frame-parallel 0 -cpu-used 8 -auto-alt-ref 1 -lag-in-frames 25 -g 999 -pass 1 -f webm -threads 8 /dev/null && nice ffmpeg -y -i $1 -c:v libvpx-vp9 -b:v 0 -crf $Q -aq-mode 2 -c:a libopus -b:a 12k -tile-columns 2 -tile-rows 2 -frame-parallel 0 -cpu-used -5 -auto-alt-ref 1 -lag-in-frames 25 -pass 2 -g 999 -threads 8 $2 @@ -463,6 +773,23 @@ Take advantage of provided scripts or autogenerated files ssh front 'sudo -iu ikiwiki ikiwiki --setup ~ikiwiki/emacsconf.setup' #+end_src + +** COMMENT Copyright & License + + Copyright (C) 2020 Sacha Chua + + The EmacsConf 2020 organizers' notebook is part of the EmacsConf + wiki, and is dual-licensed under the terms of the Creative Commons + Attribution-ShareAlike 4.0 International Public License; and the GNU + General Public License as published by the Free Software Foundation, + either version 3 of the License, or (at your option) any later + version. + + A copy of these two licenses is available on the EmacsConf wiki, in + the [[https://emacsconf.org/COPYING.CC-BY-SA][COPYING.CC-BY-SA]] and [[https://emacsconf.org/COPYING.GPL][COPYING.GPL]] files. + +** COMMENT Local variables + # Local Variables: # org-indent-mode: t # org-indent-indentation-per-level: 2 -- cgit v1.2.3