CommonLispでYoutubeAPIを叩く

暇だったからyoutube apiをcommon lispで 叩いてみるかーってことでサクっと書いてみたメモ。書いたの数ヶ月前だから忘れてるけど御愛嬌。


fukamachi/dexadorRudolph-Miller/jonathanはどちらも日本人作者の出来のよいライブラリで非常に使い勝手が良い。

こだわった点は2点

  • generate-url-with-query-parameter: listからquery parameterを生成するmacro
  • json-accessor: jsonへのアクセスを簡単にするmacro

以下はvideo_idから動画詳細を取得する例。記述量少なく簡潔に表現できるのがLispの強みだなぁとつくづく思う。

(ql:quickload :dexador)
(ql:quickload :jonathan)

(defparameter *api-key* "<your-api-key>")
(defparameter *host* "https://www.googleapis.com")
(defparameter *videos-uri* (concatenate 'string *host* "/youtube/v3/videos"))

(defmacro generate-url-with-query-parameter (uri params)
  `(flet ((fmt (accum lst) (format nil "~A~A=~A&" accum (car lst) (cdr lst))))
     (reduce #'fmt ,params :initial-value (format nil "~A?" ,uri))))

(defmacro json-accessor (item keys)
  `(flet ((fn (accum key) (getf accum (|INTERN| key "KEYWORD"))))
     (reduce #'fn ,keys :initial-value ,item)))

(defstruct video
  (id "" :type string)
  (title "" :type string))

(defun get-videos (id part)
  (let* ((res (dex:get (generate-url-with-query-parameter *videos-uri* `(("id" . ,id)
                                                                         ("part" . ,part)
                                                                         ("key" . ,*api-key*)))))
         (json (jonathan:parse res :keywords-to-read '("items")))
         (items (json-accessor json '("items"))))
    (mapcar #'(lambda (item)
                (make-video
                 :id (json-accessor item '("id"))
                 :title (json-accessor item '("snippet" "title"))))
            items)))

(get-videos "up6Nxg17opQ" "id,snippet") ;; (#S(VIDEO :ID "up6Nxg17opQ" :TITLE "Initial D 5th Stage Soundtrack - The Top"))