summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSacha Chua <sacha@sachachua.com>2024-12-01 20:02:35 -0500
committerSacha Chua <sacha@sachachua.com>2024-12-01 20:02:35 -0500
commita9525a21833c57aee9591856284e923bbccff029 (patch)
tree6b5d350def40bfc839ee857bf7967119848b0f8e
parent3baa6f53523dd11d0e14904ef62b0a23485fa03e (diff)
downloademacsconf-el-a9525a21833c57aee9591856284e923bbccff029.tar.xz
emacsconf-el-a9525a21833c57aee9591856284e923bbccff029.zip
add prefer_live property
-rw-r--r--emacsconf-pad.el146
-rw-r--r--emacsconf-publish.el152
-rw-r--r--emacsconf-stream.el43
-rw-r--r--emacsconf.el33
4 files changed, 245 insertions, 129 deletions
diff --git a/emacsconf-pad.el b/emacsconf-pad.el
index 7cd5a8f..e3d3692 100644
--- a/emacsconf-pad.el
+++ b/emacsconf-pad.el
@@ -142,7 +142,9 @@ You can find it in $ETHERPAD_PATH/APIKEY.txt"
(format "https://etherpad.wikimedia.org/p/emacsconf-%s-%s"
emacsconf-year
(plist-get o :slug))
- (concat emacsconf-pad-base emacsconf-pad-directory (emacsconf-pad-id o))))
+ (if (and (listp o) (plist-get o :slug))
+ (concat emacsconf-pad-base emacsconf-pad-directory (emacsconf-pad-id o))
+ (concat emacsconf-pad-base o))))
(defvar emacsconf-pad-number-of-next-talks 3 "Integer limiting the number of next talks to link to from the pad.")
@@ -339,6 +341,7 @@ ${next-talk-list}
(defun emacsconf-pad-format-shift-hyperlist (shift info)
(let* ((track (emacsconf-get-track (plist-get shift :track)))
+ (shift-rtmp (seq-find (lambda (entry) (string= (assoc-default "ID" entry) (plist-get shift :id))) emacsconf-rtmp-shifts))
(prefixed (list
:start (plist-get shift :start)
:end (plist-get shift :end)
@@ -353,9 +356,16 @@ ${next-talk-list}
:irc-volunteer (format "<em>%s</em>" (emacsconf-surround "IRC-" (plist-get shift :irc) "" "IRC"))
:track-id (plist-get track :id)
:conf-id emacsconf-id
+ :channel (concat emacsconf-id "-" (plist-get track :id))
:checkin (format "<em>%s</em>" (emacsconf-surround "CHECKIN-" (plist-get shift :checkin) "" "CHECKIN"))
:pad (format "<em>%s</em>" (emacsconf-surround "PAD-" (plist-get shift :pad) "" "PAD"))
:coord (format "<em>%s</em>" (emacsconf-surround "COORD-" (plist-get shift :coord) "" "COORD"))
+ :youtube-rtmp (assoc-default "YouTube" shift-rtmp 'string=)
+ :youtube-studio-url (assoc-default "YouTube URL" shift-rtmp 'string=)
+ :youtube-view-url
+ (replace-regexp-in-string
+ "https://studio\\.youtube\\.com/video/\\([^/]+\\)/livestreaming" "https://youtube.com/live/\\1"
+ (assoc-default "YouTube URL" shift-rtmp 'string=))
:checkin-pad (concat emacsconf-pad-base "checkin-" (downcase (format-time-string "%a" (date-to-time (plist-get shift :start)))))))
(shift-talks
(mapcar (lambda (o) (append prefixed o))
@@ -384,29 +394,29 @@ ${next-talk-list}
<strong>Setup</strong>
<ul>
-<li>[ ] ${checkin}: Open ${checkin-pad}</li>
-<li>[ ] ${irc-volunteer}: Watch the #emacsconf-${track-id} channel and open ${base-url}${year}/talks for links to the pads</li>
-<li>[ ] ${pad}: Open ${base-url}${year}/talks for links to the pads</li>
-<li>[ ] ${coord}: ssh orga@live0.emacsconf.org and run screen-fallbacks; confirm that the streams are showing fallbacks</li>
-<li>[ ] ${stream}: Start recording with OBS
-<li>[ ] Copy the password file if you don't already have it: <strong>scp emacsconf-${track-id}@res.emacsconf.org:~/.vnc/passwd vnc-passwd-${track-id} -p ${ssh-port}</strong></li>
-<li>[ ] Forward your local ports: <strong>ssh emacsconf-${track-id}@res.emacsconf.org -N -L ${vnc-port}:127.0.0.1:${vnc-port} -p ${ssh-port} &</strong></li>
-<li>[ ] Connect via VNC: <strong>xvncviewer 127.0.0.1:${vnc-port} -shared -geometry 1280x720 -passwd vnc-passwd-${track-id} &</strong>
-<ul>
-<li>[? Can't connect to VNC]: ssh emacsconf-${track-id}@res.emacsconf.org -p ${ssh-port} /home/${conf-id}-${track-id}/bin/track-vnc</li>
-<li>[? Can't find OBS]: track-obs</li></ul></li>
-<li>[ ] Start background music via SSH or VNC: <em>music</em>
-<ul><li>[? No audio device]:
-<ul><li><em>pulseaudio -k; pulseaudio --start</em></li>
-<li>quit OBS</li>
-<li><em>track-obs</em></li></ul></li>
-<li>[ ] Start recording (not streaming). (Alt-2, switch to workspace 2; Alt-Shift-2, move something to workspace 2).</li>
-<li>[ ] Watch the stream with MPV on your local system: <strong>mpv https://live0.emacsconf.org/emacsconf/${track-id}.webm &</strong></li>
-<li>[ ] Check 480p by viewing it : <strong>mpv https://live0.emacsconf.org/emacsconf/${track-id}-480p.webm &</strong></li>
-<li>[ ] Confirm that the streaming user has connected to Mumble, is in the ${channel} channel, and can hear what we say on Mumble.</li>
-<li>[ ] Test with a sample video or Q&A session. You can run this command on your local system if you want to do things off-screen: <strong>ssh emacsconf-${track-id}@res.emacsconf.org -p 46668 \"~/bin/track-mpv emacsconf &\"</strong></li>
-<li>[ ] ${stream}: Restart the background music via SSH or VNC: <em>music</em> . The background music should automatically get killed when the talks start, but if it doesn't, you can stop it with: <em>screen -S background -X quit</em></li>
-</ul></li>"
+ <li>[ ] ${checkin}: Open ${checkin-pad}</li>
+ <li>[ ] ${irc-volunteer}: Watch the #emacsconf-${track-id} channel and open ${base-url}${year}/talks for links to the pads</li>
+ <li>[ ] ${pad}: Open ${base-url}${year}/talks for links to the pads</li>
+ <li>[ ] Copy the password file if you don't already have it: <strong>scp emacsconf-${track-id}@res.emacsconf.org:~/.vnc/passwd vnc-passwd-${track-id} -p ${ssh-port}</strong></li>
+ <li>[ ] Forward your local ports: <strong>ssh emacsconf-${track-id}@res.emacsconf.org -N -L ${vnc-port}:127.0.0.1:${vnc-port} -p ${ssh-port} &</strong></li>
+ <li>[ ] Connect via VNC: <strong>xvncviewer 127.0.0.1:${vnc-port} -shared -geometry 1280x720 -passwd vnc-passwd-${track-id} &</strong>
+ <ul>
+ <li>[? Can't connect to VNC]: ssh emacsconf-${track-id}@res.emacsconf.org -p ${ssh-port} /home/${conf-id}-${track-id}/bin/track-vnc</li>
+ <li>[? Can't find OBS]: track-obs</li></ul></li>
+ <li>[ ] Start background music via SSH or VNC: <em>music</em>
+ <ul><li>[? No audio device]:
+ <ul><li><em>pulseaudio -k; pulseaudio --start</em></li>
+ <li>quit OBS</li>
+ <li><em>track-obs</em></li></ul>
+ </li></ul></li>
+ <li>[ ] OBS - Settings - update the RTMP stream key: <strong>${youtube-rtmp}</strong></li>
+ <li>[ ] Start recording AND start streaming. (Alt-2, switch to workspace 2; Alt-Shift-2, move something to workspace 2).</li>
+ <li>[ ] Watch the stream with MPV on your local system: <strong>mpv https://live0.emacsconf.org/emacsconf/${track-id}.webm &</strong></li>
+ <li>[ ] Check 480p by viewing it : <strong>mpv https://live0.emacsconf.org/emacsconf/${track-id}-480p.webm &</strong></li>
+ <li>[ ] Check YouTube: ${youtube-studio-url} and ${youtube-view-url}</li>
+ <li>[ ] Confirm that the streaming user has connected to Mumble, is in the ${channel} channel, and can hear what we say on Mumble.</li>
+ <li>[ ] Test with a sample video or Q&A session. You can run this command on your local system if you want to do things off-screen: <strong>ssh emacsconf-${track-id}@res.emacsconf.org -p 46668 \"~/bin/track-mpv emacsconf &\"</strong></li>
+ <li>[ ] ${stream}: Restart the background music via SSH or VNC: <em>music</em> . The background music should automatically get killed when the talks start, but if it doesn't, you can stop it with: <em>screen -S background -X quit</em></li>"
(if emacsconf-restream-youtube
"<li>[ ] ${coord}: ssh -t orga@live0.emacsconf.org 'screen -S restream-${track-id}-youtube /home/orga/restream-${track-id}-youtube.sh' and then confirm at ${youtube-url}</li>
" "")
@@ -430,7 +440,7 @@ ${next-talk-list}
"</ul>"
"Teardown
<ul>
-<li>[ ] ${stream}: stop recording</li>
+<li>[ ] ${stream}: stop recording and stop streaming</li>
"
(if emacsconf-restream-youtube
"
@@ -442,7 +452,7 @@ ${next-talk-list}
<li>[ ] ${coord}: stop the restream-${track-id}-toobnix screen on live0: <strong>screen -S restream-${track-id}-toobnix -X quit</strong></li>
"
"")
-"
+ "
<li>[ ] ${coord}: update the status page on live.emacsconf.org by changing emacsconf-tracks and calling emacsconf-stream-update-status-page</li>
</ul>"))
)))
@@ -514,7 +524,7 @@ ${bbb-checklist}</li>")
(emacsconf-publish-prepare-for-display (emacsconf-get-talk-info)))))
(mapc
(lambda (day)
- (let ((pad-id (concat "checkin-" (downcase (format-time-string "%a" (plist-get (cadr day) :checkin-time))))))
+ (let ((pad-id (concat "private-" emacsconf-private-pad-prefix "-checkin-" (downcase (format-time-string "%a" (plist-get (cadr day) :checkin-time))))))
(emacsconf-pad-create-pad pad-id)
(emacsconf-pad-set-html
pad-id
@@ -551,7 +561,9 @@ ${bbb-checklist}</li>")
:base-url emacsconf-base-url
:year emacsconf-year
:checkin-list (mapconcat
- (lambda (day) (concat "<li>" emacsconf-pad-base "checkin-"
+ (lambda (day) (concat "<li>" emacsconf-pad-base
+ id
+ "-checkin-"
(downcase (format-time-string "%a" (plist-get (cadr day) :checkin-time)))
"</li>"))
(seq-group-by (lambda (talk)
@@ -561,18 +573,19 @@ ${bbb-checklist}</li>")
"")
:shift-list (mapconcat
(lambda (shift)
- (format "<li>%sprivate-%s-%s-%s</li>"
+ (format "<li>%s%s-%s</li>"
emacsconf-pad-base
- emacsconf-private-pad-prefix
- emacsconf-year
+ id
(plist-get shift :id)))
emacsconf-shifts
"")
:host-list
(mapconcat
(lambda (shift)
- (format "<li>%shost-%s</li>"
+ (format "<li>%sprivate-%s-%s-host-%s</li>"
emacsconf-pad-base
+ emacsconf-private-pad-prefix
+ emacsconf-year
(plist-get shift :id)))
emacsconf-shifts
"")
@@ -589,7 +602,14 @@ ${bbb-checklist}</li>")
<div>Combined shift info:
<ul>${shift-list}</ul></div>
-"))))
+"))
+ (emacsconf-pad-url id)))
+
+(defun emacsconf-pad-shift-hyperlist-id (shift)
+ (format "private-%s-%s-%s"
+ emacsconf-private-pad-prefix
+ emacsconf-year
+ (plist-get (emacsconf-resolve-shift shift) :id)))
(defun emacsconf-pad-prepopulate-shift-hyperlist (shift &optional info)
(interactive (list (completing-read "Shift: "
@@ -598,15 +618,17 @@ ${bbb-checklist}</li>")
(setq shift (seq-find (lambda (o) (string= (plist-get o :id) shift)) emacsconf-shifts)))
(unless info (setq info (emacsconf-publish-prepare-for-display (emacsconf-get-talk-info))))
(let ((info (emacsconf-publish-prepare-for-display (emacsconf-get-talk-info)))
- (pad-id (format "private-%s-%s-%s"
- emacsconf-private-pad-prefix
- emacsconf-year
- (plist-get shift :id))))
+ (pad-id (emacsconf-pad-shift-hyperlist-id shift)))
(emacsconf-pad-create-pad pad-id)
(emacsconf-pad-set-html
pad-id
(emacsconf-pad-format-shift-hyperlist shift info))))
+(defun emacsconf-pad-open-shift-hyperlist (shift)
+ (interactive (list (completing-read "Shift: "
+ (mapcar (lambda (o) (plist-get o :id)) emacsconf-shifts))))
+ (browse-url (emacsconf-pad-url (emacsconf-pad-shift-hyperlist-id shift))))
+
(defun emacsconf-pad-prepopulate-host-hyperlists ()
(interactive)
(mapc #'emacsconf-pad-prepopulate-shift-hyperlist-host emacsconf-shifts))
@@ -618,7 +640,9 @@ ${bbb-checklist}</li>")
(setq shift (seq-find (lambda (o) (string= (plist-get o :id) shift)) emacsconf-shifts)))
(unless info (setq info (emacsconf-publish-prepare-for-display (emacsconf-get-talk-info))))
(let ((info (emacsconf-publish-prepare-for-display (emacsconf-get-talk-info))))
- (let* ((pad-id (format "host-%s"
+ (let* ((pad-id (format "private-%s-%s-host-%s"
+ emacsconf-private-pad-prefix
+ emacsconf-year
(plist-get shift :id)))
(shift-talks
(seq-filter
@@ -667,40 +691,39 @@ ${bbb-checklist}</li>")
talk)
(concat
"${hyperlist-note-info}"
- (cond
- (;; live talk, join BBB
- (null (plist-get talk :video-file))
- "<li><strong>${start-hhmm} ${slug} live talk</strong>: it should play a prerecorded intro, but if it doesn't, join ${bbb-backstage} and introduce talk, then turn it over to speaker for <strong>live talk</strong>: ${expanded-intro} (pronunciation: ${pronunciation})</li>")
- (t ;; prerecorded talk
- "<li>Backup: ${start-hhmm} ${slug}: it should play a prerecorded intro and talk, but if it doesn't, join ${mumble} in Mumble and introduce talk: ${expanded-intro} (pronunciation: ${pronunciation}); then <em>play ${slug}</em></li>"))
+ (if (emacsconf-talk-recorded-p talk)
+ "<li>Backup: ${start-hhmm} ${slug}: it should play a prerecorded intro and talk, but if it doesn't, join ${mumble} in Mumble and introduce talk: ${expanded-intro} (pronunciation: ${pronunciation}); then <em>play ${slug}</em></li>"
+ ;; live talk, join BBB
+ "<li><strong>${start-hhmm} ${slug} live talk</strong>: it should play a prerecorded intro, but if it doesn't, join ${bbb-backstage} (mod code <strong>${bbb-mod-code}</strong> ) and introduce talk, then turn it over to speaker for <strong>live talk</strong>: ${expanded-intro} (pronunciation: ${pronunciation})</li>")
;; Q&A
- (if (and (null (plist-get talk :video-file)) (not (string= (or (plist-get talk :q-and-a) "none") "none")))
+ (if (and (not (emacsconf-talk-prerecorded-p talk))
+ (not (string= (or (plist-get talk :qa-type) "none") "none")))
"<li>Continue in the BBB room for live Q&A because the talk was live</li>"
- (pcase (plist-get talk :q-and-a)
+ (pcase (plist-get talk :qa-type)
((or 'nil "" "none" (rx "after"))
(if (plist-get talk :video-file)
"<li>[ ] ${qa-hhmm} ${slug} Q&A after: Join ${mumble} in Mumble and say that the speaker will follow up with answers on the talk page afterwards. Read questions. ${pad-url}</li>"
""))
- ((rx "IRC")
+ ((rx "irc")
"<li>[ ] ${qa-hhmm} ${slug} Q&A IRC: Join ${mumble} in Mumble. Invite people to put their questions in the ${channel} IRC channel and read questions and answers from there. ${webchat-url} ${pad-url}</li>")
((rx "pad")
"<li>[ ] <strong>${qa-hhmm}</strong> ${slug} Q&A pad: Join ${mumble} in Mumble. Invite people to put their questions in the Etherpad and read questions and answers from there. ${pad-url}</li>")
- ((rx "Mumble")
+ ((rx "mumble")
"<li>[ ] <strong>${qa-hhmm}</strong> ${slug} Q&A mumble: Join ${mumble} in Mumble. Bring the speaker into the right channel if needed. Invite people to put their questions in the Etherpad and read questions and answers from there. ${pad-url} Paste questions into Mumble chat or read them out loud.</li>")
((rx "live")
(concat
- "<li>[ ] <strong>${qa-hhmm} ${slug} Q&A live</strong> (on stream until ${end-of-qa}): Join ${bbb-backstage}. START RECORDING. Invite people to put their questions in the Etherpad, and read questions from there. ${pad-url}</li>
+ "<li>[ ] <strong>${qa-hhmm} ${slug} Q&A live</strong> (on stream until ${end-of-qa}): Join ${bbb-backstage} (mod code <strong>${bbb-mod-code}</strong> ). START RECORDING. Invite people to put their questions in the Etherpad, and read questions from there. ${pad-url}</li>
${open-qa}
"
- (if next-talk
- "
+ (if next-talk
+ "
<li><strong>${next-talk-in-5}</strong> [? Open Q&A is still going on and it's about five minutes before the next talk]
<ul><li>[ ] Let the speaker know about the time and that the Q&A can continue off-stream if people want to join</li></ul></li>
-<li><strong>${next-talk-in-1}</strong> [? Open Q&A is still going on and it's about a minute before the next talk]
+<li><strong>${next-talk-in-2}</strong> [? Open Q&A is still going on and it's about 2 minutes before the next talk]
<ul><li>[ ] Announce that the Q&A will continue if people want to join the BBB room from the talk page, and the stream will now move to the next talk</li></ul></li>
"
- ""))
-)))))))
+ ""))
+ )))))))
(emacsconf-include-next-talks shift-talks 1)
"\n")
"</ul>")))))
@@ -775,7 +798,7 @@ ${bbb-checklist}</li>")
:media-base emacsconf-media-base-url
:mumble (concat emacsconf-id "-" track-id)
:next-talk-in-5 (if next-talk (format-time-string "%-l:%M %p" (time-subtract (plist-get next-talk :start-time) (seconds-to-time 300)) emacsconf-timezone) "")
- :next-talk-in-1 (if next-talk (format-time-string "%-l:%M %p" (time-subtract (plist-get next-talk :start-time) (seconds-to-time 60)) emacsconf-timezone) "")
+ :next-talk-in-2 (if next-talk (format-time-string "%-l:%M %p" (time-subtract (plist-get next-talk :start-time) (seconds-to-time 120)) emacsconf-timezone) "")
:qa-start (format-time-string "%-l:%M %p" (plist-get talk :qa-time) emacsconf-timezone)
:qa-end (if next-talk (format-time-string "%-l:%M %p" (plist-get next-talk :start-time))
"end of shift")
@@ -809,17 +832,17 @@ ${bbb-checklist}</li>")
(concat
(emacsconf-surround "<li><strong>" (plist-get talk :hyperlist-note) "</strong></li>" "")
"<li>Recorded intro: <a href=\"${media-base}${year}/backstage/${file-prefix}--intro.webm\">${media-base}${year}/backstage/${file-prefix}--intro.webm</a>"
- (if (plist-get talk :video-file)
+ (if (emacsconf-talk-recorded-p talk)
"<li>[ ] [? stream didn't auto-play] ${stream}: <em>handle-session ${slug}</em>; if that doesn't work, <em>play ${slug}</em>; if that still doesn't work, <em>track-mpv ~/current/cache/${conf-id}-${year}-${slug}*--intro.webm</em> and <em>track-mpv ~/current/cache/${conf-id}-${year}-${slug}*--main.webm</em></li>"
(concat
"<li>Live talk:<ul>"
"<li>[ ] [? stream didn't auto-join] ${stream}: <a href=\"${bbb-backstage}\">${bbb-backstage}</a></li>"
"<li>[ ] ${host}: Join <a href=\"${bbb-backstage}\">${bbb-backstage}</a> and turn over to speaker.</li></ul></li>"))
- (pcase (or (plist-get talk :q-and-a) "")
+ (pcase (or (plist-get talk :qa-type) "")
((rx "live")
(concat
"<li>Live Q&A start ${qa-start}, on stream until ${qa-end}<ul>
-<li>[ ] ${host}: Join the Q&A room at <a href=\"${bbb-backstage}\">${bbb-backstage}</a> and open the pad at <a href=\"${pad-url}\">${pad-url}</a>; optionally open IRC for ${channel} (<a href=\"${webchat-url}\">${webchat-url}</a>)</li>
+<li>[ ] ${host}: Copy the modcode <strong>${bbb-mod-code}</strong> , join the Q&A room at <a href=\"${bbb-backstage}\">${bbb-backstage}</a>, and open the pad at <a href=\"${pad-url}\">${pad-url}</a>; optionally open IRC for ${channel} (<a href=\"${webchat-url}\">${webchat-url}</a>)</li>
<li>[ ] [? speaker missing?] ${host}: Let #emacsconf-org know so that we can text or call the speaker</li>
<li>[ ] [? stream didn't auto-join?] ${stream}: <em>bbb ${slug}</em>
<ul>
@@ -828,7 +851,7 @@ ${bbb-checklist}</li>")
</ul>
</li>
<li>[ ] ${stream}: Give the host the go-ahead via Mumble or #emacsconf-org</li>
-<li>[ ] ${host}: Start recording and read questions</li>
+<li>[ ] ${host}: Announce that people can join using the URL on the talk page or ask questions on the pad or IRC channel. START RECORDING.</li>
<li>[ ] ${stream}: Adjust the audio levels as needed: ${ssh-audio}</li>
"
(if emacsconf-qa-start-open
@@ -836,11 +859,10 @@ ${bbb-checklist}</li>")
"<li>[ ] ${host}: Decide when to open the Q&A and let ${stream} know</li>
<li>[ ] ${stream}: Update the task status (no visible changes): ${ssh-openq}</li>")
"
-<li>[ ] ${stream}: Confirm BBB redirect at <a href=\"${bbb-redirect}\">${bbb-redirect}</a> goes to BBB room, let host know</li>
-<li>[ ] ${host}: Announce that people can join using the URL on the talk page or ask questions on the pad or IRC channel</li>
+<li>[ ] ${stream}: Confirm BBB redirect at <a href=\"${bbb-redirect}\">${bbb-redirect}</a> goes to BBB room, let host know; backup: <em>ssh orga@media.emacsconf.org \"~/bin/bbb-open ${slug}\"</em></li>
<li>${next-talk-in-5} [? Open Q&A is still going on and it's about five minutes before the next talk]
<ul><li>[ ] ${host}: Let the speaker know about the time and that the Q&A can continue off-stream if people want to join</li></ul></li>
-<li>${next-talk-in-1} [? Open Q&A is still going on and it's about a minute before the next talk]
+<li>${next-talk-in-2} [? Open Q&A is still going on and it's about 2 minutes before the next talk]
<ul><li>[ ] ${host}: Announce that the Q&A will continue if people want to join the BBB room from the talk page, and the stream will now move to the next talk</li></ul></li>
<li>[? Q&A is done early]
<ul>
diff --git a/emacsconf-publish.el b/emacsconf-publish.el
index c42d0ee..5cc9e62 100644
--- a/emacsconf-publish.el
+++ b/emacsconf-publish.el
@@ -261,45 +261,54 @@
(mapconcat
(lambda (o)
(concat
- "<tr>"
- (format
- "<td><a name=\"%s\"></a>"
- (plist-get o :slug))
- (plist-get o :qa-link)
- "</td>"
- "<td>" (if (plist-get o :pad-url)
- (format "<a href=\"%s\" target=\"_blank\" rel=\"noreferrer\">Pad</a>" (plist-get o :pad-url))
- "")
- "</td>"
- "<td>" (format "<a href=\"%s\" target=\"_blank\" rel=\"noreferrer\">Chat</a>" (plist-get o :webchat-url))
- ""
- "</td>"
+ (format "<tr id=\"%s\">" (plist-get o :slug))
"<td>" (format-time-string "%-l:%M" (plist-get o :start-time) emacsconf-timezone) "</td>"
+ "<td><strong>"
+ (cond
+ ((not (emacsconf-talk-recorded-p o))
+ (format-time-string "%-l:%M" (plist-get o :start-time) emacsconf-timezone))
+ ((string-match "live" (plist-get o :qa-type))
+ (format-time-string "%-l:%M" (plist-get o :qa-time) emacsconf-timezone))
+ (t ""))
+ "</strong></td>"
"<td>" (format "<a href=\"%s%s/talks/%s\" target=\"_blank\" rel=\"noreferrer\">%s</a>"
emacsconf-base-url
emacsconf-year
(plist-get o :slug)
(plist-get o :slug))
"</td>"
+ "<td>" (if (emacsconf-talk-recorded-p o) (plist-get o :qa-type) "(live talk)") "</td>"
+ (if (plist-get o :bbb-room)
+ (format "<td><button class=\"copy\" data-copy=\"%s\" data-label=\"Copy mod code\">Copy mod code</button></td>"
+ (plist-get o :bbb-mod-code))
+ "<td></td>")
+ (concat "<td>"
+ (if (plist-get o :bbb-room)
+ (format "<a href=\"%s\" target=\"_blank\" rel=\"noreferrer\">Join Q&A</a>" (plist-get o :bbb-room)
+ ""))
+ "</td>")
+ "<td>" (if (plist-get o :pad-url)
+ (format "<a href=\"%s\" target=\"_blank\" rel=\"noreferrer\">Pad</a>" (plist-get o :pad-url))
+ "")
+ "</td>"
+ "<td>" (format "<a href=\"%s\" target=\"_blank\" rel=\"noreferrer\">Chat</a>" (plist-get o :webchat-url))
+ ""
+ "</td>"
+
"<td>" (or (plist-get o :title) "") "</td>"
+ "<td>" (or (plist-get o :speakers) "") (emacsconf-surround " (" (plist-get o :irc) ")" "") "</td>"
"</tr>"))
info
"\n"))
-(defun emacsconf-publish-res-index ()
+(defun emacsconf-publish-backstage-talk-index ()
"Publish BBB room URLs and pad links for volunteer convenience."
(interactive)
(let* ((emacsconf-publishing-phase 'conference)
(info (mapcar (lambda (o)
(append (list
:url (concat "#" (plist-get o :slug)))
- (if (and (string-match "live" (or (plist-get o :q-and-a) ""))
- (plist-get o :bbb-room))
- (append (list
- :qa-link
- (format "<a href=\"%s\" target=\"_blank\" rel=\"noreferrer\">Join Q&A</a>" (plist-get o :bbb-room)))
- o)
- o)))
+ o))
(emacsconf-publish-prepare-for-display (emacsconf-get-talk-info)))))
(mapc
(lambda (track)
@@ -312,6 +321,7 @@
"<html><head><meta charset=\"utf-8\" /><link rel=\"stylesheet\" href=\"style.css\"></head><body>
<div>"
(let ((emacsconf-use-absolute-url t)
+ (emacsconf-schedule-svg-modify-functions '(emacsconf-schedule-svg-color-by-status))
(emacsconf-base-url ""))
(with-temp-buffer
(svg-print (emacsconf-schedule-svg 800 300 info))
@@ -322,17 +332,19 @@
(mapconcat
(lambda (day)
(format
- "<tr><th colspan=\"6\" style=\"text-align: left\">%s</th></tr>
-<tr><th>Q&A</th><th>Pad</th><th>Chat</th><th>Time</th><th>Slug</th><th>Title</th></tr>
+ "<tr><th colspan=\"7\" style=\"text-align: left\">%s</th></tr>
+<tr><th>Talk start</th><th>BBB start</th><th>Talk ID</th><th>Q&A type</th><th>Mod code</th><th>BBB</th><th>Pad</th><th>Chat</th><th>Title</th><th>Speakers</th></tr>
%s"
(car day) (emacsconf-publish-format-res-talks (cdr day))))
(seq-group-by
(lambda (o) (format-time-string "%A, %b %-e" (plist-get o :start-time)))
track-talks)
"\n")
- "</table></body></html>")))
- (with-temp-file (expand-file-name (format "index-%s.html" (plist-get track :id)) emacsconf-res-dir)
- (insert result))
+ "</table></body>"
+ (with-temp-buffer
+ (insert-file-contents (expand-file-name "include-in-index-footer.html" emacsconf-cache-dir))
+ (buffer-string))
+ "</html>")))
(with-temp-file (expand-file-name (format "index-%s.html" (plist-get track :id)) emacsconf-backstage-dir)
(insert result))))
emacsconf-tracks)))
@@ -489,29 +501,29 @@
" ")
""))))
"[[${meta} title=\"${title}\"]]
-[[${meta} copyright=\"Copyright &copy; ${year} ${speakers}\"]]
-[[!inline pages=\"internal(${year}/info/${slug}-nav)\" raw=\"yes\"]]
+ [[${meta} copyright=\"Copyright &copy ; ${year} ${speakers}\"]]
+ [[!inline pages=\"internal(${year}/info/${slug}-nav)\" raw=\"yes\"]]
-<!-- Initially generated with emacsconf-publish-talk-page and then left alone for manual editing -->
-<!-- You can manually edit this file to update the abstract, add links, etc. --->\n
+ <!-- Initially generated with emacsconf-publish-talk-page and then left alone for manual editing -->
+ <!-- You can manually edit this file to update the abstract, add links, etc. --->\n
-# ${title}
-${speaker-info}
+ # ${title}
+ ${speaker-info}
-[[!inline pages=\"internal(${year}/info/${slug}-before)\" raw=\"yes\"]]
+ [[!inline pages=\"internal(${year}/info/${slug}-before)\" raw=\"yes\"]]
-${abstract-md}
+ ${abstract-md}
-[[!inline pages=\"internal(${year}/info/${slug}-after)\" raw=\"yes\"]]
+ [[!inline pages=\"internal(${year}/info/${slug}-after)\" raw=\"yes\"]]
-[[!inline pages=\"internal(${year}/info/${slug}-nav)\" raw=\"yes\"]]
+ [[!inline pages=\"internal(${year}/info/${slug}-nav)\" raw=\"yes\"]]
-${categories}
-"))))))
+ ${categories}
+ "))))))
(defun emacsconf-publish-talk-p (talk)
"Return non-nil if the talk is ready to be published.
-Talks that are pending review will not be published yet."
+ Talks that are pending review will not be published yet."
(pcase (plist-get talk :status)
('nil nil)
("TODO" nil)
@@ -522,10 +534,10 @@ Talks that are pending review will not be published yet."
(defun emacsconf-publish-talk-pages (emacsconf-info &optional force)
"Populate year/talks/*.md files.
-These should include the nav and schedule files, which will be
-rewritten as needed. After they are generated, they should be all
-right to manually edit to include things like additional
-resources."
+ These should include the nav and schedule files, which will be
+ rewritten as needed. After they are generated, they should be all
+ right to manually edit to include things like additional
+ resources."
(interactive (list (emacsconf-get-talk-info) (> (prefix-numeric-value current-prefix-arg) 1)))
(mapc (lambda (o) (emacsconf-publish-talk-page o force))
(emacsconf-filter-talks emacsconf-info)))
@@ -583,7 +595,7 @@ resources."
(if talk-p
(concat (or (plist-get o :video-time)
(plist-get o :time))
- "-min talk; Q&A: "
+ "-min talk ; Q&A: "
(pcase (plist-get o :qa-type)
("none" "ask questions via Etherpad/IRC; we'll e-mail the speaker and post answers on this wiki page after the conference")
("live" "BigBlueButton conference room")
@@ -592,11 +604,11 @@ resources."
(_ (plist-get o :qa-type)))
(emacsconf-surround " <" (and (member emacsconf-publishing-phase '(schedule conference))
(plist-get o :qa-url)) ">" ""))
- (concat (or (plist-get o :video-time)
- (plist-get o :time)) "-min talk cancelled"))
+ (concat (or (plist-get o :video-time)
+ (plist-get o :time)) "-min talk cancelled"))
:pad-info
(if (and talk-p emacsconf-publish-include-pads (not (and (member emacsconf-publishing-phase '(schedule conference))
- (string= (plist-get o :qa-type) "etherpad"))))
+ (string= (plist-get o :qa-type) "etherpad"))))
(format "Etherpad: <https://pad.emacsconf.org/%s-%s> \n" emacsconf-year (plist-get o :slug))
"")
:irc-info
@@ -1812,6 +1824,7 @@ ${include}
'(:slug :title :speakers :pronouns :pronunciation :url :track :file-prefix
:qa-url
:qa-type
+ :prefer-live
:qa-backstage-url))))
(emacsconf-filter-talks (emacsconf-get-talk-info)))
:tracks
@@ -2063,6 +2076,7 @@ ${include}
(autoload 'subed-parse-file "subed-common")
(defun emacsconf-publish-video-description (talk &optional copy skip-title)
(interactive (list (emacsconf-complete-talk-info) t))
+ (when (stringp talk) (setq talk (emacsconf-resolve-talk talk)))
(let ((chapters (subed-parse-file
(expand-file-name
(concat
@@ -2097,15 +2111,43 @@ ${chapters}You can view this and other resources using free/libre software at ${
This video is available under the terms of the Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.")))
(if copy (kill-new result))
result))
-;; (emacsconf-publish-video-description (emacsconf-find-talk-info "async") t)
-(defun emacsconf-cache-all-video-data ()
- (interactive)
- (mapc
- (lambda (talk)
- (when (plist-get talk :file-prefix)
- (emacsconf-publish-cache-video-data talk)))
- (emacsconf-get-talk-info)))
+(defun emacsconf-publish-youtube-step-through-publishing ()
+ (interactive)
+ (catch 'done
+ (while t
+ (let ((talk (seq-find (lambda (o)
+ (and (string= (plist-get o :status) "TO_STREAM")
+ (not (plist-get o :youtube))
+ (emacsconf-talk-file o "--main.webm")))
+ (emacsconf-publish-prepare-for-display (emacsconf-get-talk-info)))))
+ (unless talk
+ (message "All done so far.")
+ (throw 'done t))
+ (kill-new (emacsconf-talk-file talk "--main.webm"))
+ (message "Video: %s - press any key" (emacsconf-talk-file talk "--main.webm"))
+ (when (eq (read-char) ?q) (throw 'done t))
+ (emacsconf-publish-video-description talk t)
+ (message "Copied description - press any key")
+ (when (eq (read-char) ?q) (throw 'done t))
+ (when (emacsconf-talk-file talk "--main.vtt")
+ (kill-new (emacsconf-talk-file talk "--main.vtt"))
+ (message "Captions: %s - press any key" (emacsconf-talk-file talk "--main.vtt"))
+ (when (eq (read-char) ?q) (throw 'done t)))
+ (emacsconf-set-property-from-slug
+ (plist-get talk :slug)
+ "YOUTUBE"
+ (read-string (format "%s - YouTube URL: " (plist-get talk :scheduled))))))))
+
+ ;; (emacsconf-publish-video-description (emacsconf-find-talk-info "async") t)
+
+ (defun emacsconf-cache-all-video-data ()
+ (interactive)
+ (mapc
+ (lambda (talk)
+ (when (plist-get talk :file-prefix)
+ (emacsconf-publish-cache-video-data talk)))
+ (emacsconf-get-talk-info)))
;; (emacsconf-cache-all-video-data t)
(defvar emacsconf-cache-dir (expand-file-name "cache" (file-name-directory emacsconf-org-file)))
diff --git a/emacsconf-stream.el b/emacsconf-stream.el
index 1b105a3..a1836e8 100644
--- a/emacsconf-stream.el
+++ b/emacsconf-stream.el
@@ -608,7 +608,7 @@ With a prefix argument (\\[universal-argument]), clear the overlay."
(shell-quote-argument (expand-file-name (concat (plist-get talk :slug) ".svg")
dir)))))
(setq prev talk))
- (emacsconf-filter-talks (cdr track)))))
+ (emacsconf-filter-talks (cdr track)))))
by-track)))
@@ -1194,5 +1194,46 @@ If INFO is non-nil, use that as the schedule instead."
(plist-put track :autopilot nil)
(emacsconf-stream-track-ssh track "crontab -r")))
+(defun emacsconf-stream-copy-livestream-description (shift)
+ (interactive (list (completing-read "Shift: " (mapcar (lambda (o) (plist-get o :id)) emacsconf-shifts))))
+ (when (stringp shift) (setq shift (seq-find (lambda (o) (string= (plist-get o :id) shift)) emacsconf-shifts)))
+ (let* ((track-id (when (string-match "-\\([a-z]+?\\)$" (plist-get shift :id)) (match-string 1 (plist-get shift :id))))
+ (desc (emacsconf-replace-plist-in-string
+ (list
+ :track-name (plist-get shift :track)
+ :start (format-time-string "%Y-%m-%d %-l:%M %p %Z (UTC %z)" (date-to-time (plist-get shift :start)))
+ :end (format-time-string "%Y-%m-%d %-l:%M %p %Z (UTC %z)" (date-to-time (plist-get shift :end)))
+ :start-day (format-time-string "%b %-e %a %p" (date-to-time (plist-get shift :start)))
+ :year emacsconf-year
+ :track-id track-id
+ :irc-channels (concat
+ (string-join
+ (seq-keep (lambda (track)
+ (unless (string= (plist-get track :id) track-id)
+ (plist-get track :channel)))
+ emacsconf-tracks)
+ ",")
+ ","
+ (plist-get (emacsconf-get-track track-id) :channel)))
+ "
+${track-name} - ${start-day} EmacsConf ${year}
+
+This for the ${track-name} track of EmacsConf, the conference about the joy of Emacs and Emacs Lisp.
+Start: ${start}
+End: ${end}
+
+Watch using free/open source software: https://live.emacsconf.org/${year}/watch/${track-id}/
+Conference info: https://emacsconf.org/${year}/
+Schedule: https://emacsconf.org/${year}/talks/
+Chat on #emacsconf-${track-id} via https://chat.emacsconf.org/?join=emacsconf,emacsconf-org,emacsconf-accessible,${irc-channels} or irc.libera.chat using your favorite IRC client
+Etherpad: Use the Etherpad links from the talk page; general comments in https://pad.emacsconf.org/${year}
+
+Videos are shared under the terms of the Creative Commons Attribution-ShareAlike 4.0
+International (CC BY-SA 4.0) license. Please observe the guidelines for conduct: https://emacsconf.org/conduct/
+")))
+ (when (called-interactively-p 'any)
+ (kill-new desc))
+ desc))
+
(provide 'emacsconf-stream)
;;; emacsconf-stream.el ends here
diff --git a/emacsconf.el b/emacsconf.el
index 024c176..82ab325 100644
--- a/emacsconf.el
+++ b/emacsconf.el
@@ -571,6 +571,11 @@ If INFO is specified, limit it to that list."
(setq list (cons (match-string-no-properties 0) list)))
(plist-put o :categories (reverse list))))
+(defun emacsconf-talk-recorded-p (talk)
+ "Returns non-nil if TALK will start with a recorded video."
+ (and (not (plist-get talk :prefer-live))
+ (plist-get talk :video-file)))
+
(defun emacsconf-get-talk-info-from-properties (o)
(let ((heading (org-heading-components))
(field-props '(
@@ -602,6 +607,7 @@ If INFO is specified, limit it to that list."
(:prerec-info "PREREC_INFO")
;; Prep
(:bbb-room "ROOM")
+ (:bbb-mod-code "BBB_MOD_CODE")
;; Processing
(:file-prefix "FILE_PREFIX")
(:video-file "VIDEO_FILE")
@@ -612,6 +618,7 @@ If INFO is specified, limit it to that list."
(:youtube-url "YOUTUBE_URL")
(:toobnix-url "TOOBNIX_URL")
(:intro-time "INTRO_TIME")
+ (:prefer-live "PREFER_LIVE")
;; Captioning
(:captioner "CAPTIONER")
(:caption-note "CAPTION_NOTE")
@@ -632,7 +639,7 @@ If INFO is specified, limit it to that list."
(:present "PRESENT")
(:talk-id "TALK_ID") ; use slug instead
(:qa-public "QA_PUBLIC") ; now tracked by the OPEN_Q and UNSTREAMED_Q status
- (:uuid "UUID") ; Pentabarf export
+ (:uuid "UUID") ; Pentabarf export
)))
(apply
'append
@@ -940,10 +947,7 @@ The subheading should match `emacsconf-abstract-heading-regexp'."
(plist-put o :qa-link "none")
(plist-put o :qa-backstage-url (plist-get o :pad-url))))
(plist-put o :recorded-intro
- (let ((filename
- (expand-file-name (concat (plist-get o :slug) ".webm")
- (expand-file-name "intros" emacsconf-stream-asset-dir))))
- (and (file-exists-p filename) filename)))
+ (emacsconf-talk-file o "--intro.webm"))
o))
(defun emacsconf-search-talk-info (search &optional info)
@@ -1045,6 +1049,12 @@ The subheading should match `emacsconf-abstract-heading-regexp'."
"Return the plist for TALK."
(if (stringp talk) (emacsconf-find-talk-info talk info) talk))
+(defun emacsconf-resolve-shift (shift)
+ "Return the plist for SHIFT."
+ (if (stringp shift) (seq-find (lambda (o) (string= (plist-get o :id) shift))
+ emacsconf-shifts)
+ shift))
+
(defun emacsconf-find-talk-info (filter &optional info)
(setq info (or info (emacsconf-filter-talks (emacsconf-get-talk-info))))
(when (stringp filter) (setq filter (list filter)))
@@ -1446,7 +1456,7 @@ If TIMEZONES is a string, split it by commas."
:vnc-display ":5"
:vnc-port "5905"
:autopilot crontab
- :status "online")
+ :status "offline")
(:name "Development" :color "skyblue" :id "dev" :channel "emacsconf-dev"
:watch ,(format "https://live.emacsconf.org/%s/watch/dev/" emacsconf-year)
:webchat-url "https://chat.emacsconf.org/?join=emacsconf,emacsconf-org,emacsconf-accessible,emacsconf-gen,emacsconf-dev"
@@ -1461,7 +1471,7 @@ If TIMEZONES is a string, split it by commas."
:vnc-display ":6"
:vnc-port "5906"
:autopilot crontab
- :status "online")))
+ :status "offline")))
(defun emacsconf-get-track (name)
"Get the track for NAME.
@@ -1526,7 +1536,7 @@ NAME could be a track name, a talk name, or a list."
info))
(defvar emacsconf-shifts
- (list (list :id "sat-am-gen" :track "General" :start "2023-12-02T08:00:00-0500" :end "2023-12-02T12:00:00-0500" :host "zaeph" :streamer "sachac" :checkin "FlowyCoder" :coord "sachac") (list :id "sat-pm-gen" :track "General" :start "2023-12-02T13:00:00-0500" :end "2023-12-02T18:00:00-0500" :host "zaph" :streamer "sachac" :checkin "FlowyCoder" :coord "sachac") (list :id "sat-am-dev" :track "Development" :start "2023-12-02T08:00:00-0500" :end "2023-12-02T12:00:00-0500" :host "bandali" :streamer "sachac" :checkin "FlowyCoder" :coord "sachac") (list :id "sat-pm-dev" :track "Development" :start "2023-12-02T13:00:00-0500" :end "2023-12-02T18:00:00-0500" :host "bandali" :streamer "sachac" :checkin "FlowyCoder" :coord "sachac") (list :id "sun-am-gen" :track "General" :start "2023-12-03T08:00:00-0500" :end "2023-12-03T12:00:00-0500" :host "zaeph" :streamer "sachac" :checkin "FlowyCoder" :coord "sachac") (list :id "sun-pm-gen" :track "General" :start "2023-12-03T13:00:00-0500" :end "2023-12-03T18:00:00-0500" :host "zaeph" :streamer "sachac" :checkin "FlowyCoder" :coord "sachac") (list :id "sun-am-dev" :track "Development" :start "2023-12-03T08:00:00-0500" :end "2023-12-03T12:00:00-0500" :host "bandali" :streamer "sachac" :checkin "FlowyCoder" :coord "sachac") (list :id "sun-pm-dev" :track "Development" :start "2023-12-03T13:00:00-0500" :end "2023-12-03T18:00:00-0500" :host "bandali" :streamer "sachac" :checkin "FlowyCoder" :coord "sachac")))
+ (list (list :id "sat-am-gen" :track "General" :start "2024-12-07T09:00:00-0500" :end "2024-12-07T12:00:00-0500" :host "zaeph" :streamer "sachac" :checkin "sachac" :coord "sachac") (list :id "sat-pm-gen" :track "General" :start "2024-12-07T13:00:00-0500" :end "2024-12-07T17:00:00-0500" :host "zaeph" :streamer "sachac" :checkin "sachac" :coord "sachac") (list :id "sat-am-dev" :track "Development" :start "2024-12-07T10:00:00-0500" :end "2024-12-07T12:00:00-0500" :host "corwin" :streamer "sachac" :checkin "sachac" :coord "sachac") (list :id "sat-pm-dev" :track "Development" :start "2024-12-07T13:00:00-0500" :end "2024-12-07T17:00:00-0500" :host "corwin" :streamer "sachac" :checkin "sachac" :coord "sachac") (list :id "sun-am-gen" :track "General" :start "2024-12-08T09:00:00-0500" :end "2024-12-08T12:00:00-0500" :host "zaeph" :streamer "sachac" :checkin "corwin" :coord "sachac") (list :id "sun-pm-gen" :track "General" :start "2024-12-08T13:00:00-0500" :end "2024-12-08T17:00:00-0500" :host "zaeph" :streamer "sachac" :checkin "corwin" :coord "sachac")))
(defun emacsconf-filter-talks-by-time (start-time end-time info)
"Return talks that are between START-TIME and END-TIME (inclusive) in INFO."
@@ -1817,9 +1827,10 @@ tracks with the ID in the cdr of that list."
(defun emacsconf-add-to-talk-logbook (talk note)
"Add NOTE as a logbook entry for TALK."
(interactive (list (emacsconf-complete-talk) (read-string "Note: ")))
- (save-excursion
- (emacsconf-with-talk-heading talk
- (emacsconf-add-to-logbook note))))
+ (save-window-excursion
+ (save-excursion
+ (emacsconf-with-talk-heading talk
+ (emacsconf-add-to-logbook note)))))
(defun emacsconf-reload ()
"Reload the emacsconf-el modules."