diff --git a/README.md b/README.md
index 1980368..8700bf1 100644
--- a/README.md
+++ b/README.md
@@ -5,3 +5,12 @@
Jukebox2 is a communal music player for team environments. Users can upload their own music, and jukebox2 will cycle through it and play a mix.
+
+## getting started
+
+* put your music in music/
+
+## hacking
+
+* use `lein spec spec/jukebox_web/models/xyz_spec.clj` to run a single test suite
+* use `lein ring server-headless` to run the app in development mode
\ No newline at end of file
diff --git a/spec/jukebox_web/models/playlist_spec.clj b/spec/jukebox_web/models/playlist_spec.clj
index 18578aa..a918e37 100644
--- a/spec/jukebox_web/models/playlist_spec.clj
+++ b/spec/jukebox_web/models/playlist_spec.clj
@@ -55,6 +55,16 @@
(playlist/add-song! "user/artist/album/track2.mp3")
(should= first-value (first (playlist/queued-songs))))))
+ (describe "add-album!"
+ (with-test-music-library)
+
+ (it "adds all the songs in this album to the queued songs"
+ (playlist/add-album! "user/artist/album")
+ (should= 2 (count (playlist/queued-songs)))
+ (should= #{(library/file-on-disk "user/artist/album/track.mp3")
+ (library/file-on-disk "user/artist/album/track2.mp3")}
+ (set (map :song (playlist/queued-songs))))))
+
(describe "add-random-song!"
(it "adds a random song to the queued songs"
(should (empty? (playlist/queued-songs)))
diff --git a/src/jukebox_web/controllers/library.clj b/src/jukebox_web/controllers/library.clj
index e60a342..96b33d4 100644
--- a/src/jukebox_web/controllers/library.clj
+++ b/src/jukebox_web/controllers/library.clj
@@ -10,7 +10,7 @@
"upload complete"))
(defn browse-root [request]
- (view/browse request "Music Library" (library/list-directory)))
+ (view/browse request library/*music-library-title* (library/list-directory)))
(defn browse [request]
(let [path (-> request :params :path)
diff --git a/src/jukebox_web/controllers/playlist.clj b/src/jukebox_web/controllers/playlist.clj
index bc833d1..65eb0f1 100644
--- a/src/jukebox_web/controllers/playlist.clj
+++ b/src/jukebox_web/controllers/playlist.clj
@@ -52,6 +52,15 @@
(let [song (-> request :params :song)
user (current-user request)]
(when (user/canAdd? user) (playlist/add-song! song user))
- (if (json/request? ((:headers request) "accept"))
- (json/response (build-playlist user))
- {:status 302 :headers {"Location" "/playlist"}})))
+ (if (json/request? ((:headers request) "accept"))
+ (json/response (build-playlist user))
+ {:status 302 :headers {"Location" "/playlist"}})))
+
+(defn add-album [request]
+ (let [album-directory (-> request :params :album-dir)
+ user (current-user request)]
+ (when (user/canAdd? user)
+ (playlist/add-album! album-directory user))
+ (if (json/request? ((:headers request) "accept"))
+ (json/response (build-playlist user))
+ {:status 302 :headers {"Location" "/playlist"}})))
diff --git a/src/jukebox_web/core.clj b/src/jukebox_web/core.clj
index 59d165d..955f76f 100644
--- a/src/jukebox_web/core.clj
+++ b/src/jukebox_web/core.clj
@@ -27,6 +27,7 @@
(POST "/playlist/add" [] playlist-controller/add)
(DELETE "/playlist/:id/delete" [] playlist-controller/delete)
(GET ["/playlist/add/:song" :song #".*"] [] playlist-controller/add)
+ (GET ["/playlist/add-album/:album-dir" :album-dir #".*"] [] playlist-controller/add-album)
(GET "/player/play" [] player-controller/play)
(GET "/player/pause" [] player-controller/pause)
(GET "/player/skip" [] player-controller/skip)
diff --git a/src/jukebox_web/models/library.clj b/src/jukebox_web/models/library.clj
index 5d13fab..dd072e2 100644
--- a/src/jukebox_web/models/library.clj
+++ b/src/jukebox_web/models/library.clj
@@ -7,6 +7,9 @@
(:use [jukebox-player.tags]
[jukebox-web.util.file :only (strip-slashes relative-uri file-path mkdir-p mv)]))
+;; constants
+;; TODO: earmuffs should denote mutable vars, not constants
+(def *music-library-title* "Music Library")
(def *music-library* "music")
(def *play-counts-model* "play-counts")
(def *skip-counts-model* "skip-counts")
diff --git a/src/jukebox_web/models/playlist.clj b/src/jukebox_web/models/playlist.clj
index 282cf7d..df0a4fd 100644
--- a/src/jukebox_web/models/playlist.clj
+++ b/src/jukebox_web/models/playlist.clj
@@ -56,6 +56,10 @@
(if (< (recent-songs-to-keep) (count @recent-songs-atom))
(swap! recent-songs-atom pop))))
+(defn add-album! [album-directory & [user]]
+ (let [album-songs (library/list-directory album-directory)]
+ (doseq [song album-songs] (add-song! song user))))
+
(defn add-random-song! []
(loop [song (random-song) attempts 0]
(if (or (nil? song) (.contains @recent-songs-atom song))
diff --git a/src/jukebox_web/util/file.clj b/src/jukebox_web/util/file.clj
index fef9cd2..2ab0e95 100644
--- a/src/jukebox_web/util/file.clj
+++ b/src/jukebox_web/util/file.clj
@@ -18,3 +18,4 @@
(defn strip-slashes [string]
(clojure-string/replace-str "/" " " string))
+
diff --git a/src/jukebox_web/views/library.clj b/src/jukebox_web/views/library.clj
index 0c950ed..02470c3 100644
--- a/src/jukebox_web/views/library.clj
+++ b/src/jukebox_web/views/library.clj
@@ -2,7 +2,8 @@
(:require [jukebox-web.views.layout :as layout]
[jukebox-web.models.library :as library]
[jukebox-web.models.user :as user]
- [clojure.string :as string])
+ [clojure.string :as string]
+ [ring.util.codec :as ring-util])
(:use [hiccup core page-helpers]
[hiccup core form-helpers]
[jukebox-player.tags]
@@ -10,9 +11,19 @@
(defn link-or-string [file request]
(if (user/canAdd? (-> request :session :current-user))
- (link-to (str "/playlist/add/" (relative-uri file)) (.getName file) " (" (library/play-count (library/file-on-disk file)) ")")
+ (link-to (str "/playlist/add/" (relative-uri file))
+ (.getName file)
+ " ("
+ (library/play-count (library/file-on-disk file))
+ ")")
(str (.getName file) " (" (library/play-count (library/file-on-disk file)) ")")))
+(defn album-link [album-path user]
+ (when (and (not= album-path library/*music-library-title*)
+ (user/canAdd? user))
+ (link-to (str "/playlist/add-album/" (ring-util/url-encode album-path))
+ "Add Album!")))
+
(defn display-file [file request]
(if (library/track? file)
(link-or-string file request)
@@ -20,8 +31,9 @@
(defn browse [request path files]
(let [parent-path (library/parent-directory path)]
- (layout/main request "browse library"
- [:h3 "Files in " path " (play count)"]
- [:ul
- (if-not (nil? parent-path) [:li (link-to (str "/library/browse/" parent-path) "..")])
- (map #(vector :li (display-file % request)) (sort files))])))
+ (layout/main request "browse library"
+ [:h3 "Files in " path " (play count)"]
+ (album-link path (-> request :session :current-user))
+ [:ul
+ (if-not (nil? parent-path) [:li (link-to (str "/library/browse/" parent-path) "..")])
+ (map #(vector :li (display-file % request)) (sort files))])))