Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2008-01-16

last.fmと連携するなにかを作りたい: 執着篇

| 00:21 | last.fmと連携するなにかを作りたい: 執着篇 - わだばLisperになる を含むブックマーク はてなブックマーク - last.fmと連携するなにかを作りたい: 執着篇 - わだばLisperになる

cl-audioscrobblerをみつけたので、もう自作する必要はないのですが、ちゃんと機能するクライアントをみつけたということもあり、自作のものは一体どの辺がおかしくて認証を通らなかったのかを確かめてみることにしました。

結論からいうと、ケアレスミスで、 md5sum-sequenceが返す#(1 2 3 255 255)のようなベクタを"010203ffff"のような文字列に変換する際に、0でパディングするのを忘れて、"123ffff"としていた、というものでした。なるほど、そりゃ駄目ですわな…。

修正したら自作のものもポストできるようになりました。とりあえず、すっきりした…。

(require :url-rewrite)
(require :drakma)
(require :md5)

(defpackage :last.fm
  (:use #:cl #:drakma #:url-rewrite))

(in-package :last.fm)

(defclass user ()
  ((name :initarg :name :accessor name :initform "")
   (password :initarg :password :accessor password :initform "")))

(defun make-get-scrobbler-uri-string (clientid clientver user)
  (let ((base "http://post.audioscrobbler.com/?hs=true&p=1.1"))
    (concatenate 'string base 
                 "&c=" clientid
                 "&v=" clientver
                 "&u=" user)))

(defun handshake-one (clientid clientver user)
  (http-request 
   (make-get-scrobbler-uri-string clientid clientver user)))
   
(defun decode-handshake-one (clientid clientver user)
  (let ((response 
         (http-request (make-get-scrobbler-uri-string clientid clientver user))))
    (destructuring-bind (uptodatep md5-challenge post-url interval) (ppcre:split "\\n" response)
      (list (string-equal "uptodate" uptodatep)
            md5-challenge
            post-url
            (ppcre:register-groups-bind (wait) ("INTERVAL ([0-9]+)" interval)
              (values (parse-integer wait :junk-allowed 'T)))
            user))))

(defun string-to-md5-string (str)
  (string-downcase 
   (apply #'concatenate 'string
          (map 'list (lambda (x) (format nil "~2,'0,X" x))
               (md5:md5sum-sequence str)))))

(defun make-md5-response (password md5-challange)
  (string-to-md5-string
   (concatenate 'string (string-to-md5-string password) md5-challange)))

(defun current-time-string ()
  (multiple-value-bind (s m h d mo y) (decode-universal-time (get-universal-time) 0)
    (format nil "~D-~2,'0D-~2,'0D ~2,'0D:~2,'0D:~2,'0D" y mo d h m s)))

(defmethod make-submit-uri ((user user) (artist string) (track string) (album string) (length integer))
  (destructuring-bind (uptodatep md5 post-url interval username)
      (decode-handshake-one "tst" "1.0" (name user))
    (declare (ignore uptodatep))
    (values 
     (concatenate 'string 
                  post-url
                  "?u=" username
                  "&s=" (make-md5-response (password user) md5)
                  "&" (url-encode "a[0]") "=" (url-encode artist)
                  "&" (url-encode "b[0]") "=" (url-encode album)
                  "&" (url-encode "t[0]") "=" (url-encode track)
                  "&" (url-encode "m[0]") "=" ;mbid
                  "&" (url-encode "l[0]") "=" (prin1-to-string length)
                  "&" (url-encode "i[0]") "=" (url-encode (current-time-string)))
     interval)))

(defun scrobble-current-song (user &key artist track album length)
  (multiple-value-bind (uri wait)
      (make-submit-uri user
                       artist
                       track
                       album
                       length)
    (sleep wait)
    (http-request uri)))

;; テスト
(setq me (make-instance 'user :name "user" :password "password"))

(print (scrobble-current-song 
        me
	:artist "Bonnie Pink"
	:track "Private Laughter"
	:album "Even So"
	:length 179))