summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--emacsconf-erc.el46
-rw-r--r--emacsconf-publish.el5
-rw-r--r--emacsconf-stream.el118
-rw-r--r--emacsconf.el51
4 files changed, 191 insertions, 29 deletions
diff --git a/emacsconf-erc.el b/emacsconf-erc.el
index 2f2fd94..fa2eb47 100644
--- a/emacsconf-erc.el
+++ b/emacsconf-erc.el
@@ -108,7 +108,7 @@ If MESSAGE is not specified, reset the topic to the template."
((string-match "pad" q-and-a)
(erc-send-message (format "%s: Thanks for checking in! The collaborative pad we'll be using for questions is at %s . We'll collect questions and put them there. If you'd like to open it, you can keep an eye on questions. Please let us know if you need help, or if you want to switch to live Q&A." nick (plist-get talk :pad-url))))
((string-match "IRC" q-and-a)
- (erc-send-message (format "%s: Thanks for checking in! Feel free to keep an eye on %s for questions and discussion, and we'll copy things from the pad to there. If the volume gets overwhelming, let us know and we can /msg you questions or add them to the pad. If you'd like to try Q&A over live video or the collaborative pad instead, or if you need help, please let us know." nick
+ (erc-send-message (format "#%s: Thanks for checking in! Feel free to keep an eye on %s for questions and discussion, and we'll copy things from the pad to there. If the volume gets overwhelming, let us know and we can /msg you questions or add them to the pad. If you'd like to try Q&A over live video or the collaborative pad instead, or if you need help, please let us know." nick
(plist-get (emacsconf-get-track (plist-get talk :track)) :channel))))
(t (erc-send-message (format "%s: Thanks for checking in! How would you like to handle Q&A today - live video, the collaborative Etherpad at %s , or IRC (like this)?" nick (plist-get) emacsconf-collaborative-pad))))
(when (functionp 'emacsconf-upcoming-insert-or-update)
@@ -125,10 +125,9 @@ If MESSAGE is not specified, reset the topic to the template."
(defun erc-cmd-READY (&rest filter)
"Notify #emacsconf-org and `emacsconf-streaming-nick' that the speaker is ready."
(let ((talk (emacsconf-find-talk-info filter))
- pronouns pronunciation)
+ pronunciation)
(unless talk (error "Could not find talk"))
- (setq pronouns (plist-get talk :pronouns)
- pronunciation (plist-get talk :pronunciation))
+ (setq pronunciation (plist-get talk :pronunciation))
(emacsconf-erc-with-channels (list emacsconf-erc-org)
(erc-send-message (format "Ready: %s (%s)" (plist-get talk :title) (plist-get talk :speakers))))
(mapc (lambda (nick)
@@ -137,8 +136,7 @@ If MESSAGE is not specified, reset the topic to the template."
emacsconf-nick
(plist-get talk :bbb-room)
(plist-get talk :title)
- (plist-get talk :speakers)
- (or pronouns "")
+ (plist-get talk :speakers-with-pronouns)
(or pronunciation ""))))
(if (listp emacsconf-streaming-nick) emacsconf-streaming-nick (list emacsconf-streaming-nick)))))
@@ -150,22 +148,18 @@ If MESSAGE is not specified, reset the topic to the template."
(when (stringp talk) (setq talk (or (emacsconf-find-talk-info talk) (error "Could not find talk %s" talk))))
;; Announce it in the track's channel
(when (plist-get talk :track)
- (emacsconf-erc-with-channels (list (plist-get talk :channel))
+ (emacsconf-erc-with-channels (list (concat "#" (plist-get talk :channel)))
(erc-cmd-TOPIC (format "%s: %s (%s) pad: %s Q&A: %s | %s"
(plist-get talk :slug)
(plist-get talk :title)
(plist-get talk :speakers)
(plist-get talk :pad-url)
(plist-get talk :qa-info)
- (car (assoc-default (plist-get talk :channel) emacsconf-topic-templates))))
- (erc-send-message (format "---- %s: %s (%s) ----"
+ (car (assoc-default (concat "#" (plist-get talk :channel)) emacsconf-topic-templates))))
+ (erc-send-message (format "---- %s: %s - %s ----"
(plist-get talk :slug)
(plist-get talk :title)
- (string-join
- (delq nil
- (list (plist-get talk :speakers)
- (plist-get talk :pronouns)))
- "; ")))
+ (plist-get talk :speakers-with-pronouns)))
(erc-send-message (concat "Add your notes/questions to the pad: " (plist-get talk :pad-url)))
(cond
((string-match "live" (or (plist-get talk :q-and-a) ""))
@@ -174,7 +168,7 @@ If MESSAGE is not specified, reset the topic to the template."
(erc-send-message "or discuss the talk on IRC (nick: %s)")))))
;; Short announcement in #emacsconf
(emacsconf-erc-with-channels (list emacsconf-erc-hallway emacsconf-erc-org)
- (erc-send-message (format "-- %s track: %s: %s (watch: %s, pad: %s, channel: %s)"
+ (erc-send-message (format "-- %s track: %s: %s (watch: %s, pad: %s, channel: #%s)"
(plist-get talk :track)
(plist-get talk :slug)
(plist-get talk :title)
@@ -186,14 +180,14 @@ If MESSAGE is not specified, reset the topic to the template."
"Announce TALK has started Q&A, but the host has not yet opened it up."
(interactive (list (emacsconf-complete-talk-info)))
(when (stringp talk) (setq talk (or (emacsconf-find-talk-info talk) (error "Could not find talk %s" talk))))
- (emacsconf-erc-with-channels (list (plist-get talk :channel))
+ (emacsconf-erc-with-channels (list (concat "#" (plist-get talk :channel)))
(erc-send-message (format "-- Q&A beginning for \"%s\" (%s) Watch: %s Add notes/questions: %s"
(plist-get talk :title)
(plist-get talk :qa-info)
(plist-get talk :watch-url)
(plist-get talk :pad-url))))
(emacsconf-erc-with-channels (list emacsconf-erc-hallway emacsconf-erc-org)
- (erc-send-message (format "-- Q&A beginning for \"%s\" in the %s track (%s) Watch: %s Add notes/questions: %s . Chat: %s"
+ (erc-send-message (format "-- Q&A beginning for \"%s\" in the %s track (%s) Watch: %s Add notes/questions: %s . Chat: #%s"
(plist-get talk :title)
(plist-get talk :track)
(plist-get talk :qa-info)
@@ -204,14 +198,14 @@ If MESSAGE is not specified, reset the topic to the template."
(defun erc-cmd-NOWOPENQ (talk)
(interactive (list (emacsconf-complete-talk-info)))
(when (stringp talk) (setq talk (or (emacsconf-find-talk-info talk) (error "Could not find talk %s" talk))))
- (emacsconf-erc-with-channels (list (plist-get talk :channel))
+ (emacsconf-erc-with-channels (list (concat "#" (plist-get talk :channel)))
(erc-send-message (format "-- Q&A now open for \"%s\" (%s). Watch: %s Add notes/questions: %s ."
(plist-get talk :title)
(plist-get talk :qa-info)
(plist-get talk :watch-url)
(plist-get talk :pad-url))))
(emacsconf-erc-with-channels (list emacsconf-erc-hallway emacsconf-erc-org)
- (erc-send-message (format "-- Q&A now open for \"%s\" in the %s track (%s). Watch: %s Add notes/questions: %s IRC: %s"
+ (erc-send-message (format "-- Q&A now open for \"%s\" in the %s track (%s). Watch: %s Add notes/questions: %s IRC: #%s"
(plist-get talk :title)
(plist-get talk :track)
(plist-get talk :qa-info)
@@ -222,23 +216,23 @@ If MESSAGE is not specified, reset the topic to the template."
(defun erc-cmd-NOWUNSTREAMEDQ (talk)
(interactive (list (emacsconf-complete-talk-info)))
(when (stringp talk) (setq talk (or (emacsconf-find-talk-info talk) (error "Could not find talk %s" talk))))
- (emacsconf-erc-with-channels (list (plist-get talk :channel))
+ (emacsconf-erc-with-channels (list (concat "#" (plist-get talk :channel)))
(erc-send-message (format "-- Q&A continues off-stream for \"%s\" (%s) Add notes/questions: %s ."
(plist-get talk :title)
(plist-get talk :qa-info)
(plist-get talk :pad-url))))
(emacsconf-erc-with-channels (list emacsconf-erc-hallway emacsconf-erc-org)
- (erc-send-message (format "-- Q&A continues off-stream for \"%s\" in the %s track (%s) Add notes/questions: %s IRC: %s"
+ (erc-send-message (format "-- Q&A continues off-stream for \"%s\" in the %s track (%s) Add notes/questions: %s IRC: #%s"
(plist-get talk :title)
(plist-get talk :track)
(plist-get talk :qa-info)
(plist-get talk :pad-url)
- (plist-get talk :channel)))))
+ (concat "#" (plist-get talk :channel))))))
(defun erc-cmd-NOWDONE (talk)
(interactive (list (emacsconf-complete-talk-info)))
(when (stringp talk) (setq talk (or (emacsconf-find-talk-info talk) (error "Could not find talk %s" talk))))
- (emacsconf-erc-with-channels (list (plist-get talk :channel))
+ (emacsconf-erc-with-channels (list (concat "#" (plist-get talk :channel)))
(erc-send-message (format "-- Q&A finished for \"%s\". Add notes/questions: %s %s"
(plist-get talk :title)
(plist-get talk :pad-url)
@@ -254,12 +248,14 @@ If MESSAGE is not specified, reset the topic to the template."
(defun emacsconf-erc-add-to-todo-hook ()
(interactive)
- (add-hook 'org-after-todo-state-change-hook #'emacsconf-erc-org-after-todo-state-change nil t))
+ (emacsconf-add-org-after-todo-state-change-hook #'emacsconf-erc-org-after-todo-state-change))
+
(defun emacsconf-erc-remove-from-todo-hook ()
(interactive)
- (remove-hook 'org-after-todo-state-change-hook #'emacsconf-erc-org-after-todo-state-change t))
+ (emacsconf-remove-org-after-todo-state-change-hook #'emacsconf-erc-org-after-todo-state-change))
(defun emacsconf-erc-org-after-todo-state-change ()
+ "Announce talk."
(let ((func
(pcase org-state
("PLAYING" #'erc-cmd-NOWPLAYING)
diff --git a/emacsconf-publish.el b/emacsconf-publish.el
index 29551f7..04775e5 100644
--- a/emacsconf-publish.el
+++ b/emacsconf-publish.el
@@ -280,13 +280,12 @@ ${chapter-list}
(let ((extra-info (mapconcat #'identity
(delq nil (list
(unless (string= (plist-get o :pronunciation) "nil") (plist-get o :pronunciation))
- (unless (string= (plist-get o :pronouns) "nil") (plist-get o :pronouns))
(when (plist-get o :irc) (format "IRC: %s" (plist-get o :irc)))
(when (plist-get o :public-email) (format "<mailto:%s>" (plist-get o :public-email)))))
", ")))
- (concat (plist-get o :speakers)
+ (concat (plist-get o :speakers-with-pronouns)
(if (> (length extra-info) 0)
- (concat " (" extra-info ")")
+ (concat " - " extra-info)
""))))
(defun emacsconf-generate-talk-page (o &optional force)
diff --git a/emacsconf-stream.el b/emacsconf-stream.el
new file mode 100644
index 0000000..b09f24c
--- /dev/null
+++ b/emacsconf-stream.el
@@ -0,0 +1,118 @@
+;;; emacsconf-stream.el --- Play files and update streaming information -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2022 Sacha Chua
+
+;; Author: Sacha Chua <sacha@sachachua.com>
+;; Keywords: multimedia
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of 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.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;
+
+;;; Code:
+
+(defvar emacsconf-stream-dir "/data/emacsconf/stream/"
+ "Directory where the stream versions are.
+Files should be in YEAR/video-slug--main.webm and video-slug--main.vtt.")
+(defvar emacsconf-stream-host "res.emacsconf.org")
+
+(defun emacsconf-stream-track-login (track)
+ "Return user@host for the track."
+ (when (plist-get track :track)
+ (setq track (emacsconf-get-track (plist-get track :track))))
+ (concat emacsconf-id "-" (plist-get track :id) "@" emacsconf-stream-host))
+
+(defvar emacsconf-stream-bottom-limit 80
+ "Number of characters for bottom text.")
+
+(defun emacsconf-stream-write-news (track message)
+ (interactive (list (emacsconf-complete-track) (read-string "Message: ")))
+ (with-temp-file (expand-file-name "news.txt" (concat "/ssh:" (emacsconf-stream-track-login track) ":~"))
+ (insert message)))
+
+(defun emacsconf-stream-broadcast (message)
+ (interactive (list (read-string "Message: ")))
+ (mapc (lambda (track) (emacsconf-stream-write-news track message)) emacsconf-tracks))
+
+(defun emacsconf-stream-clear-talk-info (track)
+ (interactive (list (emacsconf-complete-track)))
+ (emacsconf-stream-set-talk-info-from-strings track "" ""))
+
+(defun emacsconf-stream-clear-track (track)
+ (interactive (list (emacsconf-complete-track)))
+ (emacsconf-stream-set-talk-info-from-strings track "" "")
+ (emacsconf-stream-write-news track ""))
+
+(defun emacsconf-stream-clear-all ()
+ (interactive)
+ (mapc #'emacsconf-stream-clear-track emacsconf-tracks))
+
+(defun emacsconf-stream-set-talk-info-from-strings (track url bottom)
+ (interactive (list (emacsconf-complete-track) (read-string "URL: ") (read-string "Bottom: ")))
+ (let* ((home (concat "/ssh:" (emacsconf-stream-track-login track) ":~")))
+ (with-temp-file (expand-file-name "url.txt" home) (insert url))
+ (with-temp-file (expand-file-name "bottom.txt" home) (insert bottom))))
+
+(defun emacsconf-stream-set-talk-info (talk)
+ (interactive (list (emacsconf-complete-talk-info)))
+ (emacsconf-stream-set-talk-info
+ (track (emacsconf-get-track talk))
+ (concat (replace-regexp-in-string "^.*//" "" emacsconf-base-url)
+ (plist-get talk :url))
+ (concat (cond
+ ((or (null (plist-get talk :pronouns)) (string= (plist-get talk :pronouns) "nil"))
+ (plist-get talk :speakers))
+ ((string-match ", " (plist-get talk :pronouns))
+ (plist-get talk :pronouns))
+ (t (format "%s (%s)"
+ (plist-get talk :speakers)
+ (plist-get talk :pronouns))))
+ "\n"
+ (cond
+ ((string-match "live" (plist-get talk :q-and-a))
+ "Q&A: live - see talk page for URL")
+ ((string-match "irc" (plist-get talk :q-and-a))
+ (format "Q&A: IRC (#%s) - speaker nick: %s"
+ (plist-get track :channel)
+ (plist-get talk :irc)))
+ (t "")))))
+
+(defun emacsconf-stream-update-talk-info-org-after-todo-state-change ()
+ "Update talk info."
+ (when (string= org-state "PLAYING")
+ (emacsconf-stream-write-talk-info (emacsconf-get-talk-info-for-subtree))))
+
+(defun emacsconf-stream-play-talk-org-after-todo-state-change ()
+ "Play the talk."
+ (when (string= org-state "PLAYING")
+ (emacsconf-stream-play-video (emacsconf-get-talk-info-for-subtree))))
+
+(defun emacsconf-stream-get-filename (talk)
+ "Return the local filename for the video file for TALK.
+Final files should be stored in /data/emacsconf/stream/YEAR/video-slug--main.webm."
+ (expand-file-name
+ (concat (plist-get talk :video-slug) "--main.webm")
+ (expand-file-name emacsconf-year
+ emacsconf-stream-dir)))
+
+(defun emacsconf-stream-play-video (talk)
+ (interactive (list (emacsconf-complete-talk-info)))
+ (start-process (concat "mpv-" (plist-get talk :slug))
+ "test"
+ "ssh" (emacsconf-stream-track-login talk) "nohup" "~/bin/track-mpv" (emacsconf-stream-get-filename talk) "&"))
+
+(provide 'emacsconf-stream)
+;;; emacsconf-stream.el ends here
diff --git a/emacsconf.el b/emacsconf.el
index 007d653..72fb254 100644
--- a/emacsconf.el
+++ b/emacsconf.el
@@ -26,6 +26,10 @@
(defgroup emacsconf nil "EmacsConf" :group 'multimedia)
+(defcustom emacsconf-id "emacsconf"
+ "ID of conference"
+ :group 'emacsconf
+ :type 'string)
(defcustom emacsconf-name "EmacsConf"
"Name of conference"
:group 'emacsconf
@@ -521,7 +525,16 @@
emacsconf-get-talk-abstract-from-subtree
emacsconf-add-talk-status
emacsconf-add-timezone-conversions
+ emacsconf-add-speakers-with-pronouns
emacsconf-add-live-info))
+(defun emacsconf-add-speakers-with-pronouns (o)
+ (plist-put o :speakers-with-pronouns
+ (cond
+ ((null (plist-get o :pronouns)) (plist-get o :speakers))
+ ((string= (plist-get o :pronouns)) (plist-get o :speakers))
+ ((string-match "(" (plist-get o :pronouns)) (plist-get o :pronouns))
+ (t (format "%s (%s)" (plist-get o :speakers) (plist-get o :pronouns)))))
+ o)
(defun emacsconf-add-live-info (o)
(let ((track (emacsconf-get-track (plist-get o :track))))
@@ -921,6 +934,7 @@
(:name "Development" :color "skyblue" :id "dev" :channel "emacsconf-dev")))
(defun emacsconf-get-track (name)
+ (when (listp name) (setq name (plist-get name :track)))
(seq-find (lambda (track) (or (string= name (plist-get track :name))
(string= name (plist-get track :id))))
emacsconf-tracks))
@@ -933,6 +947,9 @@
info))
emacsconf-tracks))
+(defun emacsconf-complete-track ()
+ (emacsconf-get-track (completing-read "Track: " (mapcar (lambda (o) (plist-get o :name)) emacsconf-tracks))))
+
(defun emacsconf-by-day (info)
(seq-group-by (lambda (o)
(format-time-string "%Y-%m-%d" (plist-get o :start-time) emacsconf-timezone))
@@ -1022,7 +1039,7 @@ Filter by TRACK if given. Use INFO as the list of talks."
(seq-group-by (lambda (o) (plist-get o :speakers))
(or info (emacsconf-active-talks (emacsconf-filter-talks (emacsconf-get-talk-info))))))))
-(defun emacsconf-surround (before text after alternative)
+(defun emacsconf-surround (before text after &optional alternative)
"Concat BEFORE, TEXT, and AFTER if TEXT is specified, or return ALTERNATIVE."
(if (and text (not (string= text "")))
(concat (or before "") text (or after ""))
@@ -1078,5 +1095,37 @@ Filter by TRACK if given. Use INFO as the list of talks."
(recenter)
(undo-boundary))))
+(defun emacsconf-add-org-after-todo-state-change-hook ()
+ "Add FUNC to `org-after-todo-stage-change-hook'."
+ (interactive)
+ (with-current-buffer (find-buffer-visiting emacsconf-org-file)
+ (add-hook 'org-after-todo-state-change-hook #'emacsconf-org-after-todo-state-change nil t)))
+
+(defun emacsconf-remove-org-after-todo-state-change-hook ()
+ "Remove FUNC from `org-after-todo-stage-change-hook'."
+ (interactive)
+ (with-current-buffer (find-buffer-visiting emacsconf-org-file)
+ (remove-hook 'org-after-todo-state-change-hook
+ #'emacsconf-org-after-todo-state-change t)))
+
+(defvar emacsconf-todo-hooks
+ '(
+ emacsconf-stream-play-talk-org-after-todo-state-change ;; play the talk
+ ;; emacsconf-erc-org-after-todo-state-change ;; announce via ERC
+ ;; emacsconf-publish-backstage-org-after-todo-state-change ;; update the backstage index
+ emacsconf-stream-update-talk-info-org-after-todo-state-change ;; write to the talk text
+ )
+ "Functions to run when the todo state changes.")
+
+(defun emacsconf-org-after-todo-state-change ()
+ "Run all the hooks in `emacsconf-todo-hooks'."
+ (run-hooks 'emacsconf-todo-hooks))
+
+(defun emacsconf-broadcast (message)
+ (interactive "MMessage: ")
+ (when (not (string= (or message "") ""))
+ (erc-cmd-BROADCAST message))
+ (emacsconf-stream-broadcast message))
+
(provide 'emacsconf)
;;; emacsconf.el ends here