added artist.getevent, fixed bugs, refactoring

master
Abhinav Sarkar 2010-07-24 16:27:03 +05:30
parent a23ed90304
commit a3aa43060e
2 changed files with 220 additions and 83 deletions

View File

@ -8,9 +8,6 @@
[clojure.contrib.import-static] [clojure.contrib.import-static]
[clojure.contrib.logging])) [clojure.contrib.logging]))
(import-static java.lang.Integer parseInt)
(import-static java.lang.Double parseDouble)
;;;;;;;;;; Basic ;;;;;;;;;; ;;;;;;;;;; Basic ;;;;;;;;;;
(def #^{:private true} (def #^{:private true}
@ -25,12 +22,35 @@
(def #^{:private true} guid-pattern (def #^{:private true} guid-pattern
#"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$") #"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$")
(def #^{:private true} sdf (defn- safe-parse-int [n]
(if (nil? n)
nil
(try
(Integer/parseInt n)
(catch NumberFormatException nfe nil))))
(defn- safe-parse-double [n]
(if (nil? n)
nil
(try
(Double/parseDouble n)
(catch NumberFormatException nfe nil))))
(defn- struct? [obj] (instance? clojure.lang.PersistentStructMap obj))
(def #^{:private true} sdftz
(doto (SimpleDateFormat. "EEE, dd MMMM yyyy HH:mm:ss +0000") (doto (SimpleDateFormat. "EEE, dd MMMM yyyy HH:mm:ss +0000")
(.setTimeZone (TimeZone/getTimeZone "GMT")))) (.setTimeZone (TimeZone/getTimeZone "GMT"))))
(def #^{:private true} sdf
(doto (SimpleDateFormat. "EEE, dd MMMM yyyy HH:mm:ss")
(.setTimeZone (TimeZone/getTimeZone "GMT"))))
(defn- parse-date [date-str] (defn- parse-date [date-str]
(.parse sdf date-str)) (try
(.parse sdftz date-str)
(catch java.text.ParseException e
(.parse sdf date-str))))
(defn- remove-nil-values [m] (defn- remove-nil-values [m]
(apply hash-map (apply concat (filter #(not (nil? (fnext %))) m)))) (apply hash-map (apply concat (filter #(not (nil? (fnext %))) m))))
@ -63,8 +83,11 @@
(get-file-content cache url)))) (get-file-content cache url))))
(defn- get-data [params] (defn- get-data [params]
(let [url (create-url params)] (let [url (create-url params)
(-> url get-url read-json keywordize-keys))) data (-> url get-url read-json keywordize-keys)]
(if (-> data :error nil?)
data
(throw (IllegalArgumentException. (data :message))))))
(defn- create-get-obj-fn [fixed-params parse-fn] (defn- create-get-obj-fn [fixed-params parse-fn]
(fn [more-params] (fn [more-params]
@ -77,10 +100,28 @@
((apply create-obj-fn (extract-obj-id-fields-fn obj)) field-kw) ((apply create-obj-fn (extract-obj-id-fields-fn obj)) field-kw)
field-val)))) field-val))))
(defn- create-parse-one-or-more-fn [parse-one-fn extractor-fn]
(fn [data]
(let [one-or-more (extractor-fn data)]
(do
(debug (str "parsing: " data))
(if (map? one-or-more)
(vector (parse-one-fn one-or-more))
(vec (map parse-one-fn one-or-more)))))))
(defn- create-parse-string-or-list-fn [obj-from-name-fn extractor-fn]
(fn [data]
(let [string-or-list (extractor-fn data)]
(if (string? string-or-list)
(vector (obj-from-name-fn string-or-list))
(vec (map obj-from-name-fn string-or-list))))))
;;;;;;;;;; forward declaration ;;;;;;;;;; ;;;;;;;;;; forward declaration ;;;;;;;;;;
(declare bio-struct artist-struct tag-struct album-struct user-struct (declare bio-struct artist-struct tag-struct album-struct user-struct
track-struct) track-struct event-struct venue-struct location-struct)
(declare artist-from-name tag-from-name)
;;;;;;;;;; Bio/Wiki ;;;;;;;;;; ;;;;;;;;;; Bio/Wiki ;;;;;;;;;;
@ -92,8 +133,73 @@
(struct (struct
bio-struct bio-struct
(-> data :published parse-date) (-> data :published parse-date)
(-> data :summary) (data :summary)
(-> data :content)))) (data :content))))
;;;;;;;;;; Location ;;;;;;;;;;
(defstruct location-struct
:latitude :longitude :street :postalcode :city :country)
(defn- parse-location [data]
(do
(debug (str "parse-location: " data))
(struct location-struct
(-> data :geo:point :geo:lat safe-parse-double)
(-> data :geo:point :geo:long safe-parse-double)
(data :street)
(data :postalcode)
(data :city)
(data :country))))
;;;;;;;;;; Venue ;;;;;;;;;;
(defstruct venue-struct
:id :name :location :url :website :phonenumber)
(defn- parse-venue [data]
(do
(debug (str "parse-venue: " data))
(struct venue-struct
(data :id)
(data :name)
(-> data :location parse-location)
(data :url)
(data :website)
(data :phonenumber))))
;;;;;;;;;; Event ;;;;;;;;;;
(defstruct event-struct
:id :title :artists :headliner :venue :start :description
:attendence :reviews :tag :url :website :cancelled :tags)
(def #^{:private true} parse-event-artists
(create-parse-string-or-list-fn
#(artist-from-name %) #(-> % :artists :artist)))
(def #^{:private true} parse-event-tags
(create-parse-string-or-list-fn
#(tag-from-name %) #(-> % :tags :tag)))
(defn- parse-event [data]
(do
(debug (str "parse-event: " data))
(struct event-struct
(data :id)
(data :title)
(parse-event-artists data)
(artist-from-name (-> data :artists :headliner))
(-> data :venue parse-venue)
(-> data :startDate parse-date)
(data :description)
(-> data :attendence safe-parse-int)
(-> data :reviews safe-parse-int)
(data :tag)
(data :url)
(data :website)
(= 1 (-> data :cancelled safe-parse-int))
(parse-event-tags data))))
;;;;;;;;;; Artist ;;;;;;;;;; ;;;;;;;;;; Artist ;;;;;;;;;;
@ -105,18 +211,26 @@
(debug (str "parse-artist: " data)) (debug (str "parse-artist: " data))
(struct (struct
artist-struct artist-struct
(-> data :artist :name) (data :name)
(-> data :artist :url) (data :artist :url)
(-> data :artist :mbid) (data :mbid)
(= 1 (-> data :artist :streamable parseInt)) (= 1 (-> data :streamable safe-parse-int))
(-> data :artist :stats :listeners parseInt) (-> data :stats :listeners safe-parse-int)
(-> data :artist :stats :playcount parseInt) (-> data :stats :playcount safe-parse-int)
(-> data :artist :bio parse-bio)))) (-> data :bio parse-bio))))
(defn- artist-from-name [artst-name]
(struct-map artist-struct :name artst-name))
;;;;;;;;;; artist.getinfo ;;;;;;;;;; ;;;;;;;;;; artist.getinfo ;;;;;;;;;;
(defn- parse-artist-getinfo [data]
(do
(debug (str "parse-artist-getinfo: " data))
(-> data :artist parse-artist)))
(def #^{:private true} (def #^{:private true}
get-artist (create-get-obj-fn {:method "artist.getinfo"} parse-artist)) get-artist (create-get-obj-fn {:method "artist.getinfo"} parse-artist-getinfo))
(defmulti artist (defmulti artist
(fn [artist-or-mbid & _] (fn [artist-or-mbid & _]
@ -139,25 +253,24 @@
;;;;;;;;;; artist.getsimilar ;;;;;;;;;; ;;;;;;;;;; artist.getsimilar ;;;;;;;;;;
(defn- parse-artist-similar [data] (defn- parse-artist-similar-1 [data]
(do (struct-map artist-struct
(debug (str "parse-artist-similar: " data)) :name (data :name)
(vec :url (data :url)
(map :mbid (data :mbid)
#(struct-map artist-struct :streamable (= 1 (-> data :streamable safe-parse-int))
:name (% :name) :match (-> data :match safe-parse-double)))
:url (% :url)
:mbid (% :mbid) (def #^{:private true} parse-artist-similar
:streamable (= 1 (-> % :streamable parseInt)) (create-parse-one-or-more-fn
:match (-> % :match parseDouble)) parse-artist-similar-1
(-> data :similarartists :artist))))) #(-> % :similarartists :artist)))
(def #^{:private true} get-artist-similar (def #^{:private true} get-artist-similar
(create-get-obj-fn {:method "artist.getsimilar"} parse-artist-similar)) (create-get-obj-fn {:method "artist.getsimilar"} parse-artist-similar))
(defn- artist-or-name [artst-or-name & _] (defn- artist-or-name [artst-or-name & _]
(if (instance? clojure.lang.PersistentStructMap artst-or-name) (if (struct? artst-or-name) :artist :name))
:artist :name))
(defmulti artist-similar artist-or-name) (defmulti artist-similar artist-or-name)
@ -173,11 +286,11 @@
;;;;;;;;;; artist.gettoptags ;;;;;;;;;; ;;;;;;;;;; artist.gettoptags ;;;;;;;;;;
(defn- parse-artist-toptags [data]
(do (def #^{:private true} parse-artist-toptags
(debug (str "parse-artist-toptags: " data)) (create-parse-one-or-more-fn
(vec (map #(struct tag-struct (% :name) (% :url)) #(struct tag-struct (% :name) (% :url))
(-> data :toptags :tag))))) #(-> % :toptags :tag)))
(def #^{:private true} get-artist-toptags (def #^{:private true} get-artist-toptags
(create-get-obj-fn {:method "artist.gettoptags"} parse-artist-toptags)) (create-get-obj-fn {:method "artist.gettoptags"} parse-artist-toptags))
@ -192,22 +305,22 @@
;;;;;;;;;; artist.gettopalbums ;;;;;;;;;; ;;;;;;;;;; artist.gettopalbums ;;;;;;;;;;
(defn- parse-artist-topalbums [data] (defn- parse-artist-topalbums-1 [data]
(do (struct-map album-struct
(debug (str "parse-artist-topalbums: " data)) :name (data :name)
(vec :url (data :url)
(map :mbid (data :mbid)
#(struct-map album-struct :artist (struct-map artist-struct
:name (% :name) :name (-> data :artist :name)
:url (% :url) :url (-> data :artist :url)
:mbid (% :mbid) :mbid (-> data :artist :mbid))
:artist (struct-map artist-struct :playcount (-> data :playcount safe-parse-int)
:name (-> % :artist :name) :rank (safe-parse-int ((data (keyword "@attr")) :rank))))
:url (-> % :artist :url)
:mbid (-> % :artist :mbid)) (def #^{:private true} parse-artist-topalbums
:playcount (-> % :playcount parseInt) (create-parse-one-or-more-fn
:rank (parseInt ((% (keyword "@attr")) :rank))) parse-artist-topalbums-1
(-> data :topalbums :album))))) #(-> % :topalbums :album)))
(def #^{:private true} get-artist-topalbums (def #^{:private true} get-artist-topalbums
(create-get-obj-fn {:method "artist.gettopalbums"} parse-artist-topalbums)) (create-get-obj-fn {:method "artist.gettopalbums"} parse-artist-topalbums))
@ -222,17 +335,17 @@
;;;;;;;;;; artist.gettopfans ;;;;;;;;;; ;;;;;;;;;; artist.gettopfans ;;;;;;;;;;
(defn- parse-artist-topfans [data] (defn- parse-artist-topfans-1 [data]
(do (struct-map user-struct
(debug (str "parse-artist-topfans: " data)) :name (data :name)
(vec :url (data :url)
(map :realname (data :realname)
#(struct-map user-struct :weight (-> data :weight safe-parse-int)))
:name (% :name)
:url (% :url) (def #^{:private true} parse-artist-topfans
:realname (% :realname) (create-parse-one-or-more-fn
:weight (-> % :weight parseInt)) parse-artist-topfans-1
(-> data :topfans :user))))) #(-> % :topfans :user)))
(def #^{:private true} get-artist-topfans (def #^{:private true} get-artist-topfans
(create-get-obj-fn {:method "artist.gettopfans"} parse-artist-topfans)) (create-get-obj-fn {:method "artist.gettopfans"} parse-artist-topfans))
@ -247,24 +360,24 @@
;;;;;;;;;; artist.gettoptracks ;;;;;;;;;; ;;;;;;;;;; artist.gettoptracks ;;;;;;;;;;
(defn- parse-artist-toptracks [data] (defn- parse-artist-toptracks-1 [data]
(do (struct-map track-struct
(debug (str "parse-artist-toptracks: " data)) :name (data :name)
(vec :url (data :url)
(map :mbid (data :mbid)
#(struct-map track-struct :artist (struct-map artist-struct
:name (% :name) :name (-> data :artist :name)
:url (% :url) :url (-> data :artist :url)
:mbid (% :mbid) :mbid (-> data :artist :mbid))
:artist (struct-map artist-struct :playcount (-> data :playcount safe-parse-int)
:name (-> % :artist :name) :listeners (-> data :listeners safe-parse-int)
:url (-> % :artist :url) :streamable (= 1 (-> data :streamable :#text safe-parse-int))
:mbid (-> % :artist :mbid)) :streamable-full (= 1 (-> data :streamable :fulltrack safe-parse-int))))
:playcount (-> % :playcount parseInt)
:listeners (-> % :listeners parseInt) (def #^{:private true} parse-artist-toptracks
:streamable (= 1 (-> % :streamable :#text parseInt)) (create-parse-one-or-more-fn
:streamable-full (= 1 (-> % :streamable :fulltrack parseInt))) parse-artist-toptracks-1
(-> data :toptracks :track))))) #(-> % :toptracks :track)))
(def #^{:private true} get-artist-toptracks (def #^{:private true} get-artist-toptracks
(create-get-obj-fn {:method "artist.gettoptracks"} parse-artist-toptracks)) (create-get-obj-fn {:method "artist.gettoptracks"} parse-artist-toptracks))
@ -277,10 +390,34 @@
(defmethod artist-toptracks :name [artist-name] (defmethod artist-toptracks :name [artist-name]
(get-artist-toptracks {:artist artist-name})) (get-artist-toptracks {:artist artist-name}))
;;;;;;;;;; artist.getevents ;;;;;;;;;;
(def #^{:private true} parse-artist-events
(create-parse-one-or-more-fn
parse-event
#(-> % :events :event)))
(def #^{:private true} get-artist-events
(create-get-obj-fn {:method "artist.getevents"} parse-artist-events))
(defmulti artist-events artist-or-name)
(defmethod artist-events :artist [artst]
(-> artst :name artist-events))
(defmethod artist-events :name [artist-name]
(get-artist-events {:artist artist-name}))
;;;;;;;;;; Tag ;;;;;;;;;; ;;;;;;;;;; Tag ;;;;;;;;;;
(defstruct tag-struct :name :url) (defstruct tag-struct :name :url)
(defn- tag-from-name [tag-name]
(struct tag-struct
tag-name
(.toString (URI. "http" "www.last.fm" (str "/tag/" tag-name) nil nil))))
;;;;;;;;;; Album ;;;;;;;;;; ;;;;;;;;;; Album ;;;;;;;;;;
(defstruct album-struct :name :url :mbid :artist :playcount) (defstruct album-struct :name :url :mbid :artist :playcount)

View File

@ -7,4 +7,4 @@ log4j.appender.A1=org.apache.log4j.ConsoleAppender
# A1 uses PatternLayout. # A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern= %-5p %c - %m%n log4j.appender.A1.layout.ConversionPattern= %-5p %c - %m%n%n