AtlatestRepositorysigil-youtube

sigil-youtube / tree / src / youtubeplaylist.sgl

1;;; (youtube playlist) - YouTube playlist management.
2;;;
3;;; CRUD operations for playlists and playlist items.
4;;; Write operations cost 50 quota units each; reads cost 1 unit.
5;;;
6;;; Tip: The uploads playlist for a channel is always
7;;; "UU" + channel_id (without the "UC" prefix).
8;;; Using playlistItems.list on this is much cheaper than search.list.
9
10(define-library (youtube playlist)
11 (import (sigil core)
12 (sigil dict)
13 (sigil string)
14 (sigil struct)
15 (sigil json)
16 (only (sigil http) build-query-string)
17 (sigil http client)
18 (youtube))
20 (export ;; Records
21 youtube-playlist
22 youtube-playlist?
23 youtube-playlist-id
24 youtube-playlist-title
25 youtube-playlist-description
26 youtube-playlist-item-count
27 youtube-playlist-privacy-status
29 youtube-playlist-item
30 youtube-playlist-item?
31 youtube-playlist-item-id
32 youtube-playlist-item-video-id
33 youtube-playlist-item-title
34 youtube-playlist-item-position
36 ;; Parsing
37 parse-playlist
38 parse-playlist-item
40 ;; Playlist operations
41 youtube-playlists
42 youtube-playlists-by-channel
43 youtube-create-playlist
44 youtube-update-playlist
45 youtube-delete-playlist
47 ;; Playlist item operations
48 youtube-playlist-items
49 youtube-add-to-playlist
50 youtube-remove-from-playlist
51 youtube-reorder-playlist-item)
53 (begin
55 ;; ---------------------------------------------------------------
56 ;; Records
57 ;; ---------------------------------------------------------------
59 (define-struct youtube-playlist
60 (id)
61 (title default: "")
62 (description default: "")
63 (item-count default: 0)
64 (privacy-status default: "public"))
66 (define-struct youtube-playlist-item
67 (id)
68 (video-id default: "")
69 (title default: "")
70 (position default: 0))
72 ;; ---------------------------------------------------------------
73 ;; Parsing
74 ;; ---------------------------------------------------------------
76 ;;; Parse a playlist resource into a youtube-playlist record.
77 (define (parse-playlist data)
78 (let ((snippet (dict-ref data snippet: #{}))
79 (content (dict-ref data contentDetails: #{}))
80 (status (dict-ref data status: #{})))
81 (youtube-playlist
82 id: (dict-ref data id:)
83 title: (dict-ref snippet title: "")
84 description: (dict-ref snippet description: "")
85 item-count: (dict-ref content itemCount: 0)
86 privacy-status: (dict-ref status privacyStatus: "public"))))
88 ;;; Parse a playlistItem resource into a youtube-playlist-item record.
89 (define (parse-playlist-item data)
90 (let ((snippet (dict-ref data snippet: #{})))
91 (let ((resource-id (dict-ref snippet resourceId: #{})))
92 (youtube-playlist-item
93 id: (dict-ref data id:)
94 video-id: (dict-ref resource-id videoId: "")
95 title: (dict-ref snippet title: "")
96 position: (dict-ref snippet position: 0)))))
98 ;; ---------------------------------------------------------------
99 ;; Playlist operations
100 ;; ---------------------------------------------------------------
102 ;; Shared list-playlists implementation.
103 (define (list-playlists-internal client filter-params . rest)
104 (let ((opts (if (null? rest) #{} (car rest))))
105 (let* ((params (maybe-add-api-key client
106 (append
107 (list (cons "part" "snippet,contentDetails,status"))
108 filter-params
109 (list (cons "maxResults"
110 (number->string
111 (dict-ref opts max-results: 25)))
112 (cons "pageToken"
113 (dict-ref opts page-token: #f))))))
114 (url (string-append
115 (youtube-api-url client "playlists")
116 (build-query-string params)))
117 (data (youtube-get/json client url))
118 (items (dict-ref data items: #[])))
119 (array->list (array-map parse-playlist items)))))
121 ;;; List playlists for the authenticated user.
122 ;;; Optional opts dict: max-results (default 25), page-token.
123 ;;; Quota cost: 1 unit.
124 (define (youtube-playlists client . rest)
125 (apply list-playlists-internal client
126 (list (cons "mine" "true")) rest))
128 ;;; List playlists for a specific channel.
129 ;;; Quota cost: 1 unit.
130 (define (youtube-playlists-by-channel client channel-id . rest)
131 (apply list-playlists-internal client
132 (list (cons "channelId" channel-id)) rest))
134 ;;; Create a new playlist.
135 ;;; Quota cost: 50 units.
136 (define (youtube-create-playlist client title . rest)
137 (let ((opts (if (null? rest) #{} (car rest))))
138 (let* ((description (dict-ref opts description: ""))
139 (privacy (dict-ref opts privacy-status: "public"))
140 (body #{ snippet:
141 #{ title: title
142 description: description }
143 status:
144 #{ privacyStatus: privacy } })
145 (url (string-append
146 (youtube-api-url client "playlists")
147 (build-query-string
148 (list (cons "part" "snippet,status")))))
149 (result (youtube-post/json client url body)))
150 (parse-playlist result))))
152 ;;; Update a playlist's metadata.
153 ;;; All fields (title:, description:, privacy-status:) are required since
154 ;;; YouTube's PUT replaces the entire resource. Fetch first if you only
155 ;;; want to change one field.
156 ;;; Quota cost: 50 units.
157 (define (youtube-update-playlist client playlist-id title description
158 privacy-status)
159 (let* ((body #{ id: playlist-id
160 snippet:
161 #{ title: title
162 description: description }
163 status:
164 #{ privacyStatus: privacy-status } })
165 (url (string-append
166 (youtube-api-url client "playlists")
167 (build-query-string
168 (list (cons "part" "snippet,status")))))
169 (result (youtube-put/json client url body)))
170 (parse-playlist result)))
172 ;;; Delete a playlist.
173 ;;; Quota cost: 50 units.
174 (define (youtube-delete-playlist client playlist-id)
175 (let ((url (string-append
176 (youtube-api-url client "playlists")
177 (build-query-string
178 (list (cons "id" playlist-id))))))
179 (youtube-delete/json client url)))
181 ;; ---------------------------------------------------------------
182 ;; Playlist item operations
183 ;; ---------------------------------------------------------------
185 ;;; List items in a playlist.
186 ;;; Returns a list of youtube-playlist-item records.
187 ;;; Optional opts dict:
188 ;;; max-results: number (default: 50, max: 50)
189 ;;; page-token: pagination token
190 ;;;
191 ;;; Quota cost: 1 unit per page.
192 (define (youtube-playlist-items client playlist-id . rest)
193 (let ((opts (if (null? rest) #{} (car rest))))
194 (let* ((params (maybe-add-api-key client
195 (list (cons "part" "snippet,contentDetails")
196 (cons "playlistId" playlist-id)
197 (cons "maxResults"
198 (number->string
199 (dict-ref opts max-results: 50)))
200 (cons "pageToken"
201 (dict-ref opts page-token: #f)))))
202 (url (string-append
203 (youtube-api-url client "playlistItems")
204 (build-query-string params)))
205 (data (youtube-get/json client url))
206 (items (dict-ref data items: #[])))
207 (array->list (array-map parse-playlist-item items)))))
209 ;;; Add a video to a playlist.
210 ;;; Optional position parameter specifies the 0-based index.
211 ;;; Quota cost: 50 units.
212 (define (youtube-add-to-playlist client playlist-id video-id . rest)
213 (let ((position (if (null? rest) #f (car rest))))
214 (let* ((snippet #{ playlistId: playlist-id
215 resourceId:
216 #{ kind: "youtube#video"
217 videoId: video-id } })
218 (snippet (if position
219 (dict-set snippet position: position)
220 snippet))
221 (body #{ snippet: snippet })
222 (url (string-append
223 (youtube-api-url client "playlistItems")
224 (build-query-string
225 (list (cons "part" "snippet")))))
226 (result (youtube-post/json client url body)))
227 (parse-playlist-item result))))
229 ;;; Remove an item from a playlist by playlist item ID.
230 ;;; Note: this requires the playlist *item* ID, not the video ID.
231 ;;; Get item IDs from youtube-playlist-items.
232 ;;; Quota cost: 50 units.
233 (define (youtube-remove-from-playlist client item-id)
234 (let ((url (string-append
235 (youtube-api-url client "playlistItems")
236 (build-query-string
237 (list (cons "id" item-id))))))
238 (youtube-delete/json client url)))
240 ;;; Reorder a playlist item by updating its position.
241 ;;; item-id: the playlist item ID
242 ;;; playlist-id: the playlist this item belongs to
243 ;;; video-id: the video ID of this item
244 ;;; new-position: the new 0-based position
245 ;;; Quota cost: 50 units.
246 (define (youtube-reorder-playlist-item client item-id playlist-id
247 video-id new-position)
248 (let* ((body #{ id: item-id
249 snippet:
250 #{ playlistId: playlist-id
251 resourceId:
252 #{ kind: "youtube#video"
253 videoId: video-id }
254 position: new-position } })
255 (url (string-append
256 (youtube-api-url client "playlistItems")
257 (build-query-string
258 (list (cons "part" "snippet")))))
259 (result (youtube-put/json client url body)))
260 (parse-playlist-item result)))
262 ))