From 70bce881088df27dfe2912638ef1d43669011408 Mon Sep 17 00:00:00 2001 From: Sacha Chua Date: Fri, 14 Oct 2022 19:56:29 -0400 Subject: Update pad template, generate watch pages --- emacsconf-pad.el | 82 ++++++++++++-------- emacsconf-publish.el | 208 ++++++++++++++++++++++++++++++++------------------ emacsconf-schedule.el | 84 ++++++++++++++------ emacsconf.el | 12 +++ 4 files changed, 257 insertions(+), 129 deletions(-) diff --git a/emacsconf-pad.el b/emacsconf-pad.el index 1c08721..bf82412 100644 --- a/emacsconf-pad.el +++ b/emacsconf-pad.el @@ -23,7 +23,8 @@ ;; Prepopulate the Etherpad (defcustom emacsconf-pad-base "http://pad.emacsconf.org/" - "Base URL for the Etherpad. Include trailing slash." + "Base URL for the Etherpad. Include trailing slash. +Use \"wikimedia\" to use etherpad.wikimedia.org instead." :group 'emacsconf :type 'string) @@ -122,50 +123,69 @@ You can find it in $ETHERPAD_PATH/APIKEY.txt" (concat emacsconf-pad-slug-base "-" (plist-get o :slug))) (defun emacsconf-pad-url (o) - (concat emacsconf-pad-base emacsconf-pad-directory (emacsconf-pad-id o))) + (if (string= emacsconf-pad-base "wikimedia") + (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)))) (defvar emacsconf-pad-number-of-next-talks 3 "Integer limiting the number of next talks to link to from the pad.") (defun emacsconf-pad-initial-content (o) (emacsconf-replace-plist-in-string - (append (list :base-url emacsconf-base-url - :channel (concat "emacsconf-" (downcase (plist-get o :track))) - :bbb-info - (if (plist-get o :bbb-room) - (concat "
Q&A room: ${bbb-room}
") - "") - :next-talk-list - (if (plist-get o :next-talks) - (concat "
Next talks:\n
") - "") - :irc-nick-details - (if (plist-get o :irc) - (concat "Speaker nick: " (plist-get o :irc) " - ") - "") - :irc-url (concat "https://chat.emacsconf.org/#/connect?join=emacsconf-" (downcase (plist-get o :track)))) - o) - "
+ (append (list :base-url emacsconf-base-url + :channel (concat "emacsconf-" (plist-get (emacsconf-get-track (plist-get o :track)) :id)) + :bbb-info + (if (plist-get o :bbb-room) + (concat "
Q&A room: ${bbb-room}
") + "") + :next-talk-list + (if (plist-get o :next-talks) + (concat "
Next talks:\n
    " + (mapconcat + (lambda (o) + (format "
  • %s: %s %s
  • " + (plist-get o :track) + (plist-get o :title) + (emacsconf-pad-url o))) + (plist-get o :next-talks) + "\n") + "
") + "") + :track-id + (plist-get (emacsconf-get-track (plist-get o :track)) :id) + :watch + (concat emacsconf-base-url emacsconf-year "/watch/" (plist-get (emacsconf-get-track (plist-get o :track)) :id) "/") + :talks + (concat emacsconf-base-url emacsconf-year "/talks/") + :notes + (string-join (make-list 6 "
  • ")) + :questions + (string-join (make-list 6 "
  • Q:
    • A:
  • ")) + :irc-nick-details + (if (plist-get o :irc) + (concat "Speaker nick: " (plist-get o :irc) " - ") + "") + :irc-url (concat "" )) + o) + "
    +
    All talks: ${talks}
    ${title}
    ${base-url}${url} - ${speakers} - Track: ${track}
    ${bbb-info} -
    IRC: ${irc-nick-details}${irc-url} or #${channel} on libera.chat network
    -
    How to watch/participate: ${base-url}${year}
    +
    Watch/participate: ${watch}
    +
    IRC: ${irc-nick-details} https://chat.emacsconf.org/#/connect?join=emacsconf-${track-id} or #emacsconf-${track-id} on libera.chat network
    Guidelines for conduct: ${base-url}conduct
    See end of file for license (CC Attribution-ShareAlike 4.0 + GPLv3 or later)
    ----------------------------------------------------------------
    +
    Notes and links:
    +
      ${notes}
    +
    ----------------------------------------------------------------
    Questions and discussion go here:
    -
    • Q1.
    • Q2.
    • Q3.
    • Q4.
    • Q5.
    • Q6.
    +
      ${questions}
    ----------------------------------------------------------------
    ${next-talk-list} +
    ----------------------------------------------------------------
    This pad will be archived at ${base-url}${url} after the conference.
    Except where otherwise noted, the material on the EmacsConf pad are 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) an later version. Copies of these two licenses are included in the EmacsConf wiki repository, in the COPYING.GPL and COPYING.CC-BY-SA files (https://emacsconf.org/COPYING/)
    diff --git a/emacsconf-publish.el b/emacsconf-publish.el index f1d4b96..7ecaa29 100644 --- a/emacsconf-publish.el +++ b/emacsconf-publish.el @@ -544,8 +544,6 @@ Entries are sorted chronologically, with different tracks interleaved." (plist-get o :include-in-info))) (or info (emacsconf-get-talk-info))) #'emacsconf-sort-by-scheduled))) - (track-colors '(("General" . "#ffdab9") - ("Development" . "#87CEEB"))) (dates (seq-map (lambda (o) (plist-get (cadr o) :start-time)) by-day)) (links (mapcar (lambda (o) @@ -555,61 +553,37 @@ Entries are sorted chronologically, with different tracks interleaved." dates)) (height 150) (width 600)) - (mapconcat (lambda (day) - (let ((day-start (date-to-time - (concat (format-time-string "%Y-%m-%dT09:00" (plist-get (cadr day) :start-time)) - emacsconf-timezone-offset))) - (day-end (date-to-time (concat (format-time-string "%Y-%m-%dT17:00" (plist-get (cadr day) :start-time)) - emacsconf-timezone-offset)))) - ;; (with-temp-file (expand-file-name (concat emacsconf-year "/talks/" - ;; (format-time-string "schedule-%Y-%m-%d.svg" - ;; (plist-get (cadr day) :start-time) - ;; emacsconf-timezone)) - ;; emacsconf-directory) - ;; (let ((height 200) (width 800)) - ;;(svg-print - ;; (emacsconf-schedule-svg-day - ;; (svg-create width height) - ;; (format-time-string "%a" (plist-get (cadr day) :start-time) emacsconf-timezone) - ;; width height - ;; day-start - ;; day-end - ;; (list (seq-filter (lambda (o) (string= (plist-get o :track) "General")) (cdr day)) - ;; (seq-filter (lambda (o) (string= (plist-get o :track) "Development")) (cdr day))) - ;; )))) - (concat - (svg-print - (emacsconf-schedule-svg-day - (svg-create width height) - (format-time-string "%a" (plist-get (cadr day) :start-time) emacsconf-timezone) - width height - day-start - day-end - (list (seq-filter (lambda (o) (string= (plist-get o :track) "General")) (cdr day)) - (seq-filter (lambda (o) (string= (plist-get o :track) "Development")) (cdr day))) - (lambda (o node) - (when (assoc-default (plist-get o :track) track-colors) - (dom-set-attribute node 'fill (assoc-default (plist-get o :track) track-colors))) - node))) - "\n\n" - (if (> (length links) 1) (concat "Jump to: " (string-join links " - ")) "") - (format "\n" - (format-time-string "%Y-%m-%d" - (plist-get (cadr day) :start-time) - emacsconf-timezone)) - (format-time-string "# %A %b %-e, %Y\n" (plist-get (cadr day) :start-time) emacsconf-timezone) - ;; (format "\"Schedule\"/ \n" - ;; emacsconf-year - ;; (format-time-string "%Y-%m-%d" - ;; (plist-get (cadr day) :start-time) - ;; emacsconf-timezone)) - (format "
    \n" - (format-time-string "%FT%T%z" day-start t) - (format-time-string "%FT%T%z" day-end t)) - (emacsconf-format-main-schedule (cdr day)) - "
    "))) - by-day - "\n\n"))) + (mapconcat (lambda (day) + (let ((day-start (date-to-time + (concat (format-time-string "%Y-%m-%dT09:00" (plist-get (cadr day) :start-time)) + emacsconf-timezone-offset))) + (day-end (date-to-time (concat (format-time-string "%Y-%m-%dT17:00" (plist-get (cadr day) :start-time)) + emacsconf-timezone-offset)))) + (concat + (with-temp-buffer + (svg-print + (emacsconf-schedule-svg-day + (svg-create width height) + (format-time-string "%a" (plist-get (cadr day) :start-time) emacsconf-timezone) + width height + day-start + day-end + (emacsconf-by-tracks (cdr day)))) + (buffer-string)) + "\n\n" + (if (> (length links) 1) (concat "Jump to: " (string-join links " - ")) "") + (format "\n" + (format-time-string "%Y-%m-%d" + (plist-get (cadr day) :start-time) + emacsconf-timezone)) + (format-time-string "# %A %b %-e, %Y\n" (plist-get (cadr day) :start-time) emacsconf-timezone) + (format "
    \n" + (format-time-string "%FT%T%z" day-start t) + (format-time-string "%FT%T%z" day-end t)) + (emacsconf-format-main-schedule (cdr day)) + "
    "))) + by-day + "\n\n"))) (defun emacsconf-generate-main-schedule (&optional info) (interactive) @@ -663,19 +637,8 @@ Entries are sorted chronologically, with different tracks interleaved." (apply '+ (mapcar (lambda (info) (string-to-number (plist-get info :duration))) received))))) - -(defun emacsconf-format-main-schedule (info) - (let* ((cancelled (seq-filter (lambda (o) (string= (plist-get o :status) "CANCELLED")) info))) - (concat - (mapconcat - (lambda (o) - (let* ((status (pcase (plist-get o :status) - ("CAPTIONED" "captioned") - ("PREREC_RECEIVED" "received") - ("DONE" "done") - ("STARTED" "now playing") - (_ nil)))) - (format "[[!template id=sched%s%s]]" +(defun emacsconf-publish-sched-directive (o) + (format "[[!template id=sched%s%s]]" (let ((result "") (attrs (append (list @@ -687,7 +650,12 @@ Entries are sorted chronologically, with different tracks interleaved." (list :track (plist-get o :track) :slug (plist-get o :slug) - :status status + :status (pcase (plist-get o :status) + ("CAPTIONED" "captioned") + ("PREREC_RECEIVED" "received") + ("DONE" "done") + ("STARTED" "now playing") + (_ nil)) :time (plist-get o :time) :startutc (format-time-string "%FT%T%z" (plist-get o :start-time) t) :endutc (format-time-string "%FT%T%z" (plist-get o :end-time) t) @@ -707,9 +675,12 @@ Entries are sorted chronologically, with different tracks interleaved." (list :base-url (format "%s%s/" emacsconf-media-base-url emacsconf-year))) (append emacsconf-main-extensions '("--main.webm"))) "")) - "")))) - (emacsconf-active-talks info) - "\n") + ""))) + +(defun emacsconf-format-main-schedule (info) + (let* ((cancelled (seq-filter (lambda (o) (string= (plist-get o :status) "CANCELLED")) info))) + (concat + (mapconcat #'emacsconf-publish-sched-directive o (emacsconf-active-talks info) "\n") "\n" (if (> (length cancelled) 0) (format "
    Cancelled:
      %s
    " @@ -1184,5 +1155,94 @@ Entries are sorted chronologically, with different tracks interleaved." )) +(defmacro emacsconf-publish-with-wiki-change (&rest body) + (declare (indent 0) (debug t)) + `(progn + ,@body + (let ((default-directory emacsconf-directory)) + (magit-stage-modified) + (magit-status-setup-buffer)))) + +(defun emacsconf-publish-watch-pages () + "Update /year/watch pages." + (interactive) + (emacsconf-publish-with-wiki-change + (mapc (lambda (track) + (plist-put track :year emacsconf-year) + (plist-put track :stream (concat emacsconf-stream-base (plist-get track :id) ".webm")) + (plist-put track :480p (concat emacsconf-stream-base (plist-get track :id) "-480p.webm")) + (plist-put track :webchat (concat emacsconf-chat-base "?join=emacsconf-" (plist-get track :id))) + (plist-put track :channel (concat "#emacsconf-" (plist-get track :id)))) + emacsconf-tracks) + (let* ((info (sort (emacsconf-get-talk-info) #'emacsconf-sort-by-scheduled)) + (emacsconf-publishing-phase 'schedule) + (sched (with-temp-buffer (svg-print (emacsconf-schedule-svg 800 300 (emacsconf-get-talk-info))) + (buffer-string)))) + (unless (file-directory-p (expand-file-name "watch" (expand-file-name emacsconf-year emacsconf-directory))) + (make-directory (expand-file-name "watch" (expand-file-name emacsconf-year emacsconf-directory)))) + (with-temp-file (expand-file-name "watch/info.md" (expand-file-name emacsconf-year emacsconf-directory)) + (insert + "\n[[!sidebar content=\"\"]] +# Tracks\n\n" + "\n" + (mapconcat (lambda (track) + (emacsconf-replace-plist-in-string + track + "")) + emacsconf-tracks + "\n") + "
    Watch pageIRC channel (libera.chat)Alternative for streaming playerLow res
    ${name}${channel}${stream}${id}-480p.webm
    \n\n" sched)) + + (mapc (lambda (track) + (with-temp-file (expand-file-name (format "%s/watch/%s.md" + emacsconf-year + (plist-get track :id)) + emacsconf-directory) + (insert + (emacsconf-replace-plist-in-string + (append + (list :links (concat + "Watch - Chat - View schedule - \nStreams: " + (mapconcat (lambda (tr) + (if (string= (plist-get tr :name) (plist-get track :name)) + (format "**%s**" (plist-get track :name)) + (format "%s" + emacsconf-year + (plist-get tr :id) + (plist-get tr :name)))) + emacsconf-tracks + " - ")) + :sched sched + :talks (mapconcat #'emacsconf-publish-sched-directive + (seq-filter (lambda (o) (string= (plist-get o :track) + (plist-get track :name))) + info) + "\n")) + track) + " +[[!inline pages=\"internal(2022/info/watch-announce)\" raw=\"yes\"]] +[[!meta title=\"${name} stream\"]] +[[!sidebar content=\"\"]] + + +${links} +\n +Alternatively, load <${stream}> or <${480p}> (low-res) in a streaming media player such as MPV. + + +${links} + +Chat: [${channel} on libera.chat](${webchat}) + +
    + + +${links} + +${sched}\n + +${talks} +")))) + emacsconf-tracks)))) (provide 'emacsconf-publish) diff --git a/emacsconf-schedule.el b/emacsconf-schedule.el index d0f476f..8d4e75a 100644 --- a/emacsconf-schedule.el +++ b/emacsconf-schedule.el @@ -223,8 +223,8 @@ Each function should take the info and manipulate it as needed, returning the ne (org-entry-put (point) "TIME" (plist-get talk :time))) (emacsconf-filter-talks info))))) - -(defun emacsconf-schedule-svg-track (svg base-x base-y width height start-time end-time info &optional modify-func) +(defvar emacsconf-schedule-svg-modify-functions '(emacsconf-schedule-svg-color-by-track) "Functions to run to modify the display of each item.") +(defun emacsconf-schedule-svg-track (svg base-x base-y width height start-time end-time info) (let ((scale (/ width (float-time (time-subtract end-time start-time))))) (mapc (lambda (o) @@ -238,10 +238,7 @@ Each function should take the info and manipulate it as needed, returning the ne 'a `((href . ,(concat "/" (plist-get o :url))) (title . ,(plist-get o :title))) - (dom-node - 'title - nil - (plist-get o :title)) + (dom-node 'title nil (plist-get o :title)) (let ((node (dom-node 'rect `((x . ,x) @@ -262,24 +259,25 @@ Each function should take the info and manipulate it as needed, returning the ne (or (plist-get o :availability) "")) "lightgray") (t "lightgreen"))))))) - (if modify-func - (funcall modify-func o node) - node)) + (run-hook-with-args + 'emacsconf-schedule-svg-modify-functions + o node) + node) (dom-node 'g - `((transform . ,(format "translate(%d,%d)" - (+ x size -2) (+ y height -2)))) - (dom-node - 'text - '((fill . "black") - (x . 0) - (y . 0) - (font-size . 10) - (transform . "rotate(-90)")) - (svg--encode-text (or (plist-get o :slug) (plist-get o :title))))))))) - info))) - -(defun emacsconf-schedule-svg-day (elem label width height start end tracks &optional modify-func) + `((transform . ,(format "translate(%d,%d)" + (+ x size -2) (+ y height -2)))) + (dom-node + 'text + '((fill . "black") + (x . 0) + (y . 0) + (font-size . 10) + (transform . "rotate(-90)")) + (svg--encode-text (or (plist-get o :slug) (plist-get o :title))))))))) + info))) + +(defun emacsconf-schedule-svg-day (elem label width height start end tracks) (let* ((label-margin 15) (track-height (/ (- height (* 2 label-margin)) (length tracks))) (x 0) (y label-margin) @@ -290,7 +288,7 @@ Each function should take the info and manipulate it as needed, returning the ne (mapc (lambda (track) (emacsconf-schedule-svg-track elem x y width track-height - start end track modify-func) + start end track) (setq y (+ y track-height))) tracks) ;; draw grid @@ -319,7 +317,45 @@ Each function should take the info and manipulate it as needed, returning the ne (setq time (time-add time (seconds-to-time 3600))))) elem)) -(defun emacsconf-schedule-svg (width height days) +(defun emacsconf-by-tracks (info) + (mapcar (lambda (track) + (seq-filter + (lambda (talk) + (string= (plist-get talk :track) (plist-get track :name))) + info)) + emacsconf-tracks)) + +(defun emacsconf-schedule-svg-color-by-track (o node) + (let ((track (emacsconf-get-track (plist-get o :track)))) + (when track + (dom-set-attribute node 'fill (plist-get track :color))))) + +(defun emacsconf-schedule-svg (width height &optional info) + (setq info (or info (emacsconf-get-talk-info))) + (let ((days (seq-group-by (lambda (o) + (format-time-string "%Y-%m-%d" (plist-get o :start-time) emacsconf-timezone)) + (sort (seq-filter (lambda (o) + (or (plist-get o :slug) + (plist-get o :include-in-info))) + info) + #'emacsconf-sort-by-scheduled)))) + (emacsconf-schedule-svg-days + width height + (mapcar (lambda (o) + (let ((start (concat (car o) "T09:00:00" emacsconf-timezone-offset)) + (end (concat (car o) "T17:00:00" emacsconf-timezone-offset))) + (list :label (format-time-string "%A" (date-to-time (car o))) + :start start + :end end + :tracks (mapcar (lambda (track) + (seq-filter + (lambda (talk) + (string= (plist-get talk :track) (plist-get track :name))) + (cdr o))) + emacsconf-tracks)))) + days)))) + +(defun emacsconf-schedule-svg-days (width height days) (let ((svg (svg-create width height :background "white")) (day-height (/ height (length days))) (y 0)) diff --git a/emacsconf.el b/emacsconf.el index 12c5cf3..b850302 100644 --- a/emacsconf.el +++ b/emacsconf.el @@ -75,6 +75,9 @@ :type 'file :group 'emacsconf) +(defvar emacsconf-stream-base "https://live0.emacsconf.org/") +(defvar emacsconf-chat-base "https://chat.emacsconf.org/") + (defcustom emacsconf-download-directory "~/Downloads" "Directory to check for downloaded files." :type 'directory @@ -911,5 +914,14 @@ Include some other things, too, such as emacsconf-year, title, name, email, url, '((emacsconf-pad-api-key . etherpad_api_key) (emacsconf-pad-base . etherpad_url)))))) ;; (emacsconf-ansible-load-vars (expand-file-name "prod-vars.yml" emacsconf-ansible-directory)) +;;; Tracks +(defvar emacsconf-tracks '((:name "General" :color "peachpuff" :id "gen") + (:name "Development" :color "skyblue" :id "dev"))) + +(defun emacsconf-get-track (name) + (seq-find (lambda (track) (string= name (plist-get track :name))) emacsconf-tracks)) + + + (provide 'emacsconf) ;;; emacsconf.el ends here -- cgit v1.2.3