From 281b0f4a7706d2f89e93fb1678f1d76e06f2c39d Mon Sep 17 00:00:00 2001 From: Sacha Chua Date: Sat, 9 Dec 2023 15:36:40 -0500 Subject: add sorting the playlist --- emacsconf-extract.el | 122 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 95 insertions(+), 27 deletions(-) diff --git a/emacsconf-extract.el b/emacsconf-extract.el index 7fb3e12..ceca898 100644 --- a/emacsconf-extract.el +++ b/emacsconf-extract.el @@ -1070,6 +1070,10 @@ Strategies: (plz 'get "https://youtube.googleapis.com/youtube/v3/channels?part=contentDetails&mine=true" :headers `(("Authorization" . ,(url-oauth-auth "https://youtube.googleapis.com/youtube/v3/"))) :as #'json-read)) + (setq emacsconf-extract-youtube-api-playlists + (plz 'get "https://youtube.googleapis.com/youtube/v3/playlists?part=snippet,contentDetails&mine=true" + :headers `(("Authorization" . ,(url-oauth-auth "https://youtube.googleapis.com/youtube/v3/"))) + :as #'json-read)) (setq emacsconf-extract-youtube-api-categories (plz 'get "https://youtube.googleapis.com/youtube/v3/videoCategories?part=snippet®ionCode=CA" :headers `(("Authorization" . ,(url-oauth-auth "https://youtube.googleapis.com/youtube/v3/"))) @@ -1086,7 +1090,7 @@ Strategies: (defvar emacsconf-extract-youtube-tags '("emacs" "emacsconf")) (defun emacsconf-extract-youtube-object (video-id talk &optional privacy-status) "Format the video object for VIDEO-ID using TALK details." - (setq privacy-status (or privacy-status "unlisted")) + (setq privacy-status (or privacy-status "public")) (let ((properties (emacsconf-publish-talk-video-properties talk 'youtube))) `((id . ,video-id) (kind . "youtube#video") @@ -1098,32 +1102,44 @@ Strategies: ;; Even though I set recordingDetails and status, it doesn't seem to stick. ;; I'll leave this in here in case someone else can figure it out. (recordingDetails (recordingDate . ,(format-time-string "%Y-%m-%dT%TZ" (plist-get talk :start-time) t)))) - (status (privacyStatus . "unlisted") + (status (privacyStatus . ,privacy-status) (license . "creativeCommon"))))) +(defun emacsconf-extract-youtube-get-slug-for-video (video-object) + (let-alist video-object + (cond + ;; not yet renamed + ((string-match (rx (literal emacsconf-id) " " (literal emacsconf-year) " " + (group (1+ (or (syntax word) "-"))) + " ") + .snippet.title) + (match-string 1 .snippet.title)) + ;; renamed, match the description instead + ((string-match (rx (literal emacsconf-base-url) (literal emacsconf-year) "/talks/" + (group (1+ (or (syntax word) "-")))) + .snippet.description) + (match-string 1 .snippet.description)) + (t + (plist-get + (seq-find (lambda (o) (string-match (regexp-quote .snippet.resourceId.videoId) (or (plist-get o :youtube-url) ""))) + (emacsconf-get-talk-info)) + :slug))))) + +(defun emacsconf-extract-youtube-get-talk-for-video (video-object) + (when-let ((slug (emacsconf-extract-youtube-get-slug-for-video video-object))) + (emacsconf-resolve-talk slug))) + (defun emacsconf-extract-youtube-api-update-video (video-object) "Update VIDEO-OBJECT." (let-alist video-object - (let* ((slug (cond - ;; not yet renamed - ((string-match (rx (literal emacsconf-id) " " (literal emacsconf-year) " " - (group (1+ (or (syntax word) "-"))) - " ") - .snippet.title) - (match-string 1 .snippet.title)) - ;; renamed, match the description instead - ((string-match (rx (literal emacsconf-base-url) (literal emacsconf-year) "/talks/" - (group (1+ (or (syntax word) "-")))) - .snippet.description) - (match-string 1 .snippet.description)) - ;; can't find, prompt - (t - (when (string-match (rx (literal emacsconf-id) " " (literal emacsconf-year)) - .snippet.title) - (completing-read (format "Slug for %s: " - .snippet.title) - (seq-map (lambda (o) (plist-get o :slug)) - (emacsconf-publish-prepare-for-display (emacsconf-get-talk-info)))))))) + (let* ((slug (or (emacsconf-extract-youtube-get-slug-for-video video-object) + (when (string-match (rx (literal emacsconf-id) " " (literal emacsconf-year)) + .snippet.title) + (completing-read (format "Slug for %s: " + .snippet.title) + (seq-map (lambda (o) (plist-get o :slug)) + (emacsconf-publish-prepare-for-display (emacsconf-get-talk-info))))))) + (talk (and slug (emacsconf-resolve-talk slug))) (video-id .snippet.resourceId.videoId) (id .id) result) @@ -1136,16 +1152,68 @@ Strategies: :headers `(("Authorization" . ,(url-oauth-auth "https://youtube.googleapis.com/youtube/v3/")) ("Accept" . "application/json") ("Content-Type" . "application/json")) - :body (json-encode (emacsconf-extract-youtube-object video-id (emacsconf-resolve-talk slug)))))))) + :body (json-encode (emacsconf-extract-youtube-object video-id talk))))))) (defun emacsconf-extract-youtube-rename-videos (&optional videos) "Rename videos and set the YOUTUBE_URL property in the Org heading." + (interactive) (let ((info (emacsconf-get-talk-info))) (mapc (lambda (video) - (when (string-match (rx (literal emacsconf-id) " " (literal emacsconf-year))) - (emacsconf-extract-youtube-api-update-video video))) - (assoc-default 'items (or videos emacsconf-extract-youtube-api-videos))))) - + (let-alist video + (when (string-match (rx (literal emacsconf-id) " " (literal emacsconf-year) " ") + .snippet.title) + (emacsconf-extract-youtube-api-update-video video)))) + (assoc-default + 'items + (or videos emacsconf-extract-youtube-api-videos + (plz 'get (concat "https://youtube.googleapis.com/youtube/v3/playlistItems?part=snippet,contentDetails,status&forMine=true&order=date&maxResults=50&playlistId=" + (url-hexify-string + (let-alist (elt (assoc-default 'items emacsconf-extract-youtube-api-channels) 0) + .contentDetails.relatedPlaylists.uploads) + )) + :headers `(("Authorization" . ,(url-oauth-auth "https://youtube.googleapis.com/youtube/v3/"))) + :as #'json-read)))))) + +;; This still needed some tweaking, so maybe next time we'll try just inserting the items into the playlist +(defun emacsconf-extract-youtube-sort-playlist () + (interactive) + (let* ((playlist-info + (seq-find (lambda (o) (let-alist o (string= .snippet.title (concat emacsconf-name " " emacsconf-year)))) + (assoc-default 'items emacsconf-extract-youtube-api-playlists))) + (playlist-items + (assoc-default 'items + (plz 'get (concat "https://youtube.googleapis.com/youtube/v3/playlistItems?part=snippet,contentDetails,status&forMine=true&order=date&maxResults=50&playlistId=" (url-hexify-string (assoc-default 'id playlist-info))) + :headers `(("Authorization" . ,(url-oauth-auth "https://youtube.googleapis.com/youtube/v3/"))) + :as #'json-read))) + (info (emacsconf-publish-prepare-for-display (emacsconf-get-talk-info))) + (slugs (seq-map (lambda (o) (plist-get o :slug)) info)) + last-position) + ;; sort items + (seq-map-indexed (lambda (talk position) + (let ((video-object (seq-find (lambda (video) (string= (plist-get talk :slug) + (emacsconf-extract-youtube-get-slug-for-video video))) + playlist-items))) + (let-alist video-object + (cond + ((null video-object) + (message "Could not find video for %s" (plist-get talk :slug))) + ;; not in the right position, try to move it + ((> .snippet.position position) + (let ((video-id .id) + (playlist-id .snippet.playlistId) + (resource-id .snippet.resourceId)) + (message "Trying to move %s to %d from %d" (plist-get talk :slug) position .snippet.position) + (plz 'put "https://www.googleapis.com/youtube/v3/playlistItems?part=snippet" + :headers `(("Authorization" . ,(url-oauth-auth "https://youtube.googleapis.com/youtube/v3/")) + ("Accept" . "application/json") + ("Content-Type" . "application/json")) + :body (json-encode + `((id . ,video-id) + (snippet + (playlistId . ,playlist-id) + (resourceId . ,resource-id) + (position . ,position))))))))) + )) info))) (provide 'emacsconf-extract) ;;; emacsconf-extract.el ends here -- cgit v1.2.3