play 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -0
- data/Gemfile.lock +87 -0
- data/README.md +139 -0
- data/Rakefile +185 -0
- data/bin/play +49 -0
- data/config.ru +10 -0
- data/db/migrate/01_create_schema.rb +55 -0
- data/lib/play.rb +73 -0
- data/lib/play/album.rb +6 -0
- data/lib/play/app.rb +118 -0
- data/lib/play/app/api.rb +110 -0
- data/lib/play/artist.rb +21 -0
- data/lib/play/client.rb +67 -0
- data/lib/play/core_ext/hash.rb +6 -0
- data/lib/play/history.rb +7 -0
- data/lib/play/library.rb +58 -0
- data/lib/play/office.rb +34 -0
- data/lib/play/song.rb +97 -0
- data/lib/play/templates/album_songs.mustache +5 -0
- data/lib/play/templates/artist_songs.mustache +5 -0
- data/lib/play/templates/index.mustache +18 -0
- data/lib/play/templates/layout.mustache +23 -0
- data/lib/play/templates/now_playing.mustache +5 -0
- data/lib/play/templates/play_history.mustache +3 -0
- data/lib/play/templates/profile.mustache +24 -0
- data/lib/play/templates/search.mustache +3 -0
- data/lib/play/templates/show_song.mustache +9 -0
- data/lib/play/templates/song.mustache +21 -0
- data/lib/play/user.rb +59 -0
- data/lib/play/views/album_songs.rb +9 -0
- data/lib/play/views/artist_songs.rb +9 -0
- data/lib/play/views/index.rb +9 -0
- data/lib/play/views/layout.rb +6 -0
- data/lib/play/views/now_playing.rb +17 -0
- data/lib/play/views/play_history.rb +9 -0
- data/lib/play/views/profile.rb +9 -0
- data/lib/play/views/search.rb +9 -0
- data/lib/play/views/show_song.rb +19 -0
- data/lib/play/vote.rb +7 -0
- data/play.gemspec +129 -0
- data/play.yml.example +22 -0
- data/public/css/base.css +129 -0
- data/test/helper.rb +33 -0
- data/test/spec/mini.rb +24 -0
- data/test/test_api.rb +118 -0
- data/test/test_app.rb +57 -0
- data/test/test_artist.rb +15 -0
- data/test/test_client.rb +11 -0
- data/test/test_library.rb +19 -0
- data/test/test_office.rb +26 -0
- data/test/test_play.rb +17 -0
- data/test/test_song.rb +78 -0
- data/test/test_user.rb +21 -0
- metadata +299 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
module Play
|
2
|
+
module Views
|
3
|
+
class ShowSong < Layout
|
4
|
+
def title
|
5
|
+
"#{@song.title} by #{@song.artist.name}"
|
6
|
+
end
|
7
|
+
|
8
|
+
def users
|
9
|
+
@song.votes.group(:user_id).collect do |vote|
|
10
|
+
vote.user
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def plays
|
15
|
+
@song.votes.count
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/play/vote.rb
ADDED
data/play.gemspec
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
## This is the rakegem gemspec template. Make sure you read and understand
|
2
|
+
## all of the comments. Some sections require modification, and others can
|
3
|
+
## be deleted if you don't need them. Once you understand the contents of
|
4
|
+
## this file, feel free to delete any comments that begin with two hash marks.
|
5
|
+
## You can find comprehensive Gem::Specification documentation, at
|
6
|
+
## http://docs.rubygems.org/read/chapter/20
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.specification_version = 2 if s.respond_to? :specification_version=
|
9
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
10
|
+
s.rubygems_version = '1.3.5'
|
11
|
+
|
12
|
+
## Leave these as is they will be modified for you by the rake gemspec task.
|
13
|
+
## If your rubyforge_project name is different, then edit it and comment out
|
14
|
+
## the sub! line in the Rakefile
|
15
|
+
s.name = 'play'
|
16
|
+
s.version = '0.0.1'
|
17
|
+
s.date = '2011-05-05'
|
18
|
+
s.rubyforge_project = 'play'
|
19
|
+
|
20
|
+
## Make sure your summary is short. The description may be as long
|
21
|
+
## as you like.
|
22
|
+
s.summary = "Your company's dj. ►"
|
23
|
+
s.description = "We want to play music at our office. Everyone has their own
|
24
|
+
library on their own machines, and everyone except for me plays shitty music.
|
25
|
+
Play is designed to make office music more palatable."
|
26
|
+
|
27
|
+
## List the primary authors. If there are a bunch of authors, it's probably
|
28
|
+
## better to set the email to an email list or something. If you don't have
|
29
|
+
## a custom homepage, consider using your GitHub URL or the like.
|
30
|
+
s.authors = ["Zach Holman"]
|
31
|
+
s.email = 'github.com@zachholman.com'
|
32
|
+
s.homepage = 'https://github.com/holman/play'
|
33
|
+
|
34
|
+
## This gets added to the $LOAD_PATH so that 'lib/NAME.rb' can be required as
|
35
|
+
## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
|
36
|
+
s.require_paths = %w[lib]
|
37
|
+
|
38
|
+
## If your gem includes any executables, list them here.
|
39
|
+
s.executables = ["play"]
|
40
|
+
s.default_executable = 'play'
|
41
|
+
|
42
|
+
## Specify any RDoc options here. You'll want to add your README and
|
43
|
+
## LICENSE files to the extra_rdoc_files list.
|
44
|
+
#s.rdoc_options = ["--charset=UTF-8"]
|
45
|
+
#s.extra_rdoc_files = %w[README LICENSE]
|
46
|
+
|
47
|
+
## List your runtime dependencies here. Runtime dependencies are those
|
48
|
+
## that are needed for an end user to actually USE your code.
|
49
|
+
s.add_dependency('rack', ["~>1.2.2"])
|
50
|
+
s.add_dependency('sinatra')
|
51
|
+
s.add_dependency('activerecord')
|
52
|
+
s.add_dependency('sqlite3')
|
53
|
+
s.add_dependency('mustache')
|
54
|
+
s.add_dependency('SystemTimer')
|
55
|
+
s.add_dependency('ruby-audioinfo')
|
56
|
+
s.add_dependency('oa-oauth')
|
57
|
+
s.add_dependency('yajl-ruby')
|
58
|
+
s.add_dependency('mysql2')
|
59
|
+
|
60
|
+
## List your development dependencies here. Development dependencies are
|
61
|
+
## those that are only needed during development
|
62
|
+
s.add_development_dependency('running_man')
|
63
|
+
s.add_development_dependency('mocha')
|
64
|
+
|
65
|
+
## Leave this section as-is. It will be automatically generated from the
|
66
|
+
## contents of your Git repository via the gemspec task. DO NOT REMOVE
|
67
|
+
## THE MANIFEST COMMENTS, they are used as delimiters by the task.
|
68
|
+
# = MANIFEST =
|
69
|
+
s.files = %w[
|
70
|
+
Gemfile
|
71
|
+
Gemfile.lock
|
72
|
+
README.md
|
73
|
+
Rakefile
|
74
|
+
bin/play
|
75
|
+
config.ru
|
76
|
+
db/migrate/01_create_schema.rb
|
77
|
+
lib/play.rb
|
78
|
+
lib/play/album.rb
|
79
|
+
lib/play/app.rb
|
80
|
+
lib/play/app/api.rb
|
81
|
+
lib/play/artist.rb
|
82
|
+
lib/play/client.rb
|
83
|
+
lib/play/core_ext/hash.rb
|
84
|
+
lib/play/history.rb
|
85
|
+
lib/play/library.rb
|
86
|
+
lib/play/office.rb
|
87
|
+
lib/play/song.rb
|
88
|
+
lib/play/templates/album_songs.mustache
|
89
|
+
lib/play/templates/artist_songs.mustache
|
90
|
+
lib/play/templates/index.mustache
|
91
|
+
lib/play/templates/layout.mustache
|
92
|
+
lib/play/templates/now_playing.mustache
|
93
|
+
lib/play/templates/play_history.mustache
|
94
|
+
lib/play/templates/profile.mustache
|
95
|
+
lib/play/templates/search.mustache
|
96
|
+
lib/play/templates/show_song.mustache
|
97
|
+
lib/play/templates/song.mustache
|
98
|
+
lib/play/user.rb
|
99
|
+
lib/play/views/album_songs.rb
|
100
|
+
lib/play/views/artist_songs.rb
|
101
|
+
lib/play/views/index.rb
|
102
|
+
lib/play/views/layout.rb
|
103
|
+
lib/play/views/now_playing.rb
|
104
|
+
lib/play/views/play_history.rb
|
105
|
+
lib/play/views/profile.rb
|
106
|
+
lib/play/views/search.rb
|
107
|
+
lib/play/views/show_song.rb
|
108
|
+
lib/play/vote.rb
|
109
|
+
play.gemspec
|
110
|
+
play.yml.example
|
111
|
+
public/css/base.css
|
112
|
+
test/helper.rb
|
113
|
+
test/spec/mini.rb
|
114
|
+
test/test_api.rb
|
115
|
+
test/test_app.rb
|
116
|
+
test/test_artist.rb
|
117
|
+
test/test_client.rb
|
118
|
+
test/test_library.rb
|
119
|
+
test/test_office.rb
|
120
|
+
test/test_play.rb
|
121
|
+
test/test_song.rb
|
122
|
+
test/test_user.rb
|
123
|
+
]
|
124
|
+
# = MANIFEST =
|
125
|
+
|
126
|
+
## Test files will be grabbed from the file list. Make sure the path glob
|
127
|
+
## matches what you actually use.
|
128
|
+
s.test_files = s.files.select { |path| path =~ /^test\/test_.*\.rb/ }
|
129
|
+
end
|
data/play.yml.example
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# This file should get moved to:
|
2
|
+
# ~/.play.yml
|
3
|
+
#
|
4
|
+
# Also you should fill it out.
|
5
|
+
|
6
|
+
path: /path/to/your/music/yo
|
7
|
+
gh_key: github_oauth_key
|
8
|
+
gh_secret: github_oauth_secret
|
9
|
+
office_url: http://example.com/office.macs
|
10
|
+
|
11
|
+
# Database stuffs that we'll pass on to ActiveRecord. Change if you want to. If
|
12
|
+
# you don't want to, you are probably a handsome-looking gentlemen or a
|
13
|
+
# gorgeous lady who knows what they want out of life.
|
14
|
+
db:
|
15
|
+
database: play
|
16
|
+
adapter: mysql2
|
17
|
+
user: user
|
18
|
+
password: password
|
19
|
+
reconnect: true
|
20
|
+
# db:
|
21
|
+
# database: db/play.sqlite3
|
22
|
+
# adapter: sqlite3
|
data/public/css/base.css
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
/*
|
2
|
+
|
3
|
+
dark: 485460
|
4
|
+
3D72AA
|
5
|
+
5E7894
|
6
|
+
438FDF
|
7
|
+
D0E4FA
|
8
|
+
*/
|
9
|
+
|
10
|
+
html{
|
11
|
+
font-family: Helvetica;
|
12
|
+
}
|
13
|
+
body{
|
14
|
+
margin: 0;
|
15
|
+
padding: 0;
|
16
|
+
color: #5E7894;
|
17
|
+
}
|
18
|
+
h1{
|
19
|
+
margin: 1em 10px 0 10px;
|
20
|
+
padding: 0;
|
21
|
+
letter-spacing: -3px;
|
22
|
+
color: #000;
|
23
|
+
}
|
24
|
+
a{
|
25
|
+
color: #5E7894;
|
26
|
+
text-decoration: none;
|
27
|
+
}
|
28
|
+
a:hover{
|
29
|
+
color: #000;
|
30
|
+
}
|
31
|
+
|
32
|
+
.navigation{
|
33
|
+
text-align: right;
|
34
|
+
padding: 2px 10px;
|
35
|
+
font-weight: bold;
|
36
|
+
letter-spacing: -1px;
|
37
|
+
font-size: 1.4em;
|
38
|
+
}
|
39
|
+
.navigation a{
|
40
|
+
color: #485460;
|
41
|
+
padding-left: 10px;
|
42
|
+
text-decoration: none;
|
43
|
+
}
|
44
|
+
.navigation form{
|
45
|
+
display: inline;
|
46
|
+
}
|
47
|
+
.navigation input{
|
48
|
+
vertical-align: top;
|
49
|
+
width: 250px;
|
50
|
+
}
|
51
|
+
.content{
|
52
|
+
padding: 10px;
|
53
|
+
background-color: #D0E4FA;
|
54
|
+
}
|
55
|
+
.gravatar{
|
56
|
+
-webkit-border-radius: 5px;
|
57
|
+
}
|
58
|
+
|
59
|
+
/*
|
60
|
+
* SONGS
|
61
|
+
*/
|
62
|
+
.songs{
|
63
|
+
|
64
|
+
}
|
65
|
+
.song{
|
66
|
+
letter-spacing: -1px;
|
67
|
+
background-color: #D0E4FA;
|
68
|
+
border-top: 2px solid #fff;
|
69
|
+
padding: .5em 10px;
|
70
|
+
font-size: 1.25em;
|
71
|
+
font-weight: bold;
|
72
|
+
}
|
73
|
+
.song a:hover{
|
74
|
+
color: #000 !important;
|
75
|
+
}
|
76
|
+
.song .artist{
|
77
|
+
font-size: 3em;
|
78
|
+
letter-spacing: -5px;
|
79
|
+
}
|
80
|
+
.song .artist a{
|
81
|
+
color: #485460;
|
82
|
+
}
|
83
|
+
.song .title{
|
84
|
+
padding-left: 10px;
|
85
|
+
font-size: 2.2em;
|
86
|
+
letter-spacing: -4px;
|
87
|
+
}
|
88
|
+
.song .album{
|
89
|
+
margin-left: 10px;
|
90
|
+
font-size: 1.1em;
|
91
|
+
letter-spacing: -2px;
|
92
|
+
}
|
93
|
+
.song .album a{
|
94
|
+
color: #438FDF;
|
95
|
+
}
|
96
|
+
.song .controls{
|
97
|
+
float: right;
|
98
|
+
font-size: .75em;
|
99
|
+
margin: -.5em -5px;
|
100
|
+
text-transform: uppercase;
|
101
|
+
}
|
102
|
+
.votes{
|
103
|
+
background-color: #485460;
|
104
|
+
padding: 5px 5px 0px 5px;
|
105
|
+
}
|
106
|
+
.votes img{
|
107
|
+
border: 1px solid #5E7894;
|
108
|
+
}
|
109
|
+
.votes img:hover{
|
110
|
+
border: 1px solid #D0E4FA;
|
111
|
+
}
|
112
|
+
|
113
|
+
/*
|
114
|
+
* PROFILE
|
115
|
+
*/
|
116
|
+
.profile_box{
|
117
|
+
margin-right: 10px;
|
118
|
+
float: left;
|
119
|
+
font-size: 1.1em;
|
120
|
+
}
|
121
|
+
.bio{
|
122
|
+
padding: 15px 0;
|
123
|
+
}
|
124
|
+
.favorite_artists{
|
125
|
+
margin: 0 15px;
|
126
|
+
}
|
127
|
+
.favorite_artists h2{
|
128
|
+
color: #485460;
|
129
|
+
}
|
data/test/helper.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'rubygems'
|
5
|
+
require 'redgreen'
|
6
|
+
require 'leftright'
|
7
|
+
rescue LoadError
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'rack/test'
|
11
|
+
require 'mocha'
|
12
|
+
require 'spec/mini'
|
13
|
+
require 'running_man'
|
14
|
+
require 'running_man/active_record_block'
|
15
|
+
|
16
|
+
ENV['RACK_ENV'] = 'test'
|
17
|
+
|
18
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
19
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
20
|
+
|
21
|
+
require 'play'
|
22
|
+
include Play
|
23
|
+
|
24
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3',
|
25
|
+
:database => ":memory:")
|
26
|
+
ActiveRecord::Migration.verbose = false
|
27
|
+
ActiveRecord::Migrator.migrate("db/migrate")
|
28
|
+
|
29
|
+
RunningMan.setup_on ActiveSupport::TestCase, :ActiveRecordBlock
|
30
|
+
|
31
|
+
def parse_json(json)
|
32
|
+
Yajl.load(json, :symbolize_keys => true)
|
33
|
+
end
|
data/test/spec/mini.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
##
|
2
|
+
# test/spec/mini 5
|
3
|
+
# http://gist.github.com/307649
|
4
|
+
# chris@ozmm.org
|
5
|
+
#
|
6
|
+
def context(*args, &block)
|
7
|
+
return super unless (name = args.first) && block
|
8
|
+
require 'test/unit'
|
9
|
+
klass = Class.new(defined?(ActiveSupport::TestCase) ? ActiveSupport::TestCase : Test::Unit::TestCase) do
|
10
|
+
def self.test(name, &block)
|
11
|
+
define_method("test_#{name.to_s.gsub(/\W/,'_')}", &block) if block
|
12
|
+
end
|
13
|
+
def self.xtest(*args) end
|
14
|
+
def self.context(*args, &block) instance_eval(&block) end
|
15
|
+
def self.setup(&block)
|
16
|
+
define_method(:setup) { self.class.setups.each { |s| instance_eval(&s) } }
|
17
|
+
setups << block
|
18
|
+
end
|
19
|
+
def self.setups; @setups ||= [] end
|
20
|
+
def self.teardown(&block) define_method(:teardown, &block) end
|
21
|
+
end
|
22
|
+
(class << klass; self end).send(:define_method, :name) { name.gsub(/\W/,'_') }
|
23
|
+
klass.class_eval &block
|
24
|
+
end
|
data/test/test_api.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'helper'
|
2
|
+
include Rack::Test::Methods
|
3
|
+
|
4
|
+
def app
|
5
|
+
Play::App
|
6
|
+
end
|
7
|
+
|
8
|
+
context "Api" do
|
9
|
+
fixtures do
|
10
|
+
@artist = Play::Artist.create(:name => "Justice")
|
11
|
+
@album = Play::Album.create(:name => "Cross", :artist => @artist)
|
12
|
+
@song = Play::Song.create(:title => "Stress",
|
13
|
+
:artist => @artist,
|
14
|
+
:album => @album)
|
15
|
+
@user = Play::User.create(:login => 'holman', :alias => 'zach')
|
16
|
+
end
|
17
|
+
|
18
|
+
test "/api/now_playing" do
|
19
|
+
Play.expects(:now_playing).returns(@song)
|
20
|
+
get "/api/now_playing"
|
21
|
+
now_playing = parse_json(last_response.body.strip)
|
22
|
+
assert_equal @artist.name, now_playing[:artist_name]
|
23
|
+
assert_equal @song.title, now_playing[:song_title]
|
24
|
+
assert_equal @album.name, now_playing[:album_name]
|
25
|
+
end
|
26
|
+
|
27
|
+
test "/api requires user_login" do
|
28
|
+
post "/api/add_song", {}
|
29
|
+
user = parse_json(last_response.body.strip)
|
30
|
+
assert user[:error].include?("must supply a valid `user_login`")
|
31
|
+
end
|
32
|
+
|
33
|
+
test "user login check also works for aliases" do
|
34
|
+
post "/api/add_song", {:user_login => 'zach'}
|
35
|
+
user = parse_json(last_response.body.strip)
|
36
|
+
assert !user[:error].include?("must supply a valid `user_login`")
|
37
|
+
end
|
38
|
+
|
39
|
+
test "/api/add_song" do
|
40
|
+
post "/api/add_song", { :song_title => @song.title,
|
41
|
+
:artist_name => @artist.name,
|
42
|
+
:user_login => @user.login }
|
43
|
+
song = parse_json(last_response.body.strip)
|
44
|
+
assert_equal @song.title, song[:song_title]
|
45
|
+
end
|
46
|
+
|
47
|
+
test "/api/add_song without a found artist" do
|
48
|
+
post "/api/add_song", { :song_title => 'Stress',
|
49
|
+
:artist_name => "Ace of Base",
|
50
|
+
:user_login => @user.login }
|
51
|
+
resp = parse_json(last_response.body.strip)
|
52
|
+
assert resp[:error].include?("find that artist")
|
53
|
+
end
|
54
|
+
|
55
|
+
test "/api/add_song without a found song" do
|
56
|
+
post "/api/add_song", { :song_title => "I Saw the Sign",
|
57
|
+
:artist_name => @artist.name,
|
58
|
+
:user_login => @user.login }
|
59
|
+
resp = parse_json(last_response.body.strip)
|
60
|
+
assert resp[:error].include?("find that song")
|
61
|
+
end
|
62
|
+
|
63
|
+
test "/api/add_artist" do
|
64
|
+
post "/api/add_artist", { :artist_name => @artist.name,
|
65
|
+
:user_login => @user.login }
|
66
|
+
song = parse_json(last_response.body.strip)
|
67
|
+
assert_equal @artist.name, song[:artist_name]
|
68
|
+
assert_equal [@song.title], song[:song_titles]
|
69
|
+
end
|
70
|
+
|
71
|
+
test "/api/remove" do
|
72
|
+
post "/api/remove"
|
73
|
+
resp = parse_json(last_response.body.strip)
|
74
|
+
assert resp[:error].include?("hasn't been implemented")
|
75
|
+
end
|
76
|
+
|
77
|
+
test "/api/search artist" do
|
78
|
+
get "/api/search", { :q => @artist.name,
|
79
|
+
:facet => 'artist' }
|
80
|
+
resp = parse_json(last_response.body.strip)
|
81
|
+
assert resp[:song_titles].include?(@song.title)
|
82
|
+
end
|
83
|
+
|
84
|
+
test "/api/search song" do
|
85
|
+
get "/api/search", { :q => @song.title,
|
86
|
+
:facet => 'song' }
|
87
|
+
resp = parse_json(last_response.body.strip)
|
88
|
+
assert resp[:song_titles].include?(@song.title)
|
89
|
+
end
|
90
|
+
|
91
|
+
test "/api/user/add_alias" do
|
92
|
+
post "/api/user/add_alias", { :login => @user.login, :alias => 'zach' }
|
93
|
+
resp = parse_json(last_response.body.strip)
|
94
|
+
assert 'true', resp[:success]
|
95
|
+
assert_equal 'zach', User.first.alias
|
96
|
+
end
|
97
|
+
|
98
|
+
test "/api/import" do
|
99
|
+
Library.stubs(:import_songs).returns('true')
|
100
|
+
post "/api/import"
|
101
|
+
resp = parse_json(last_response.body.strip)
|
102
|
+
assert_equal 'true', resp[:success]
|
103
|
+
end
|
104
|
+
|
105
|
+
test "/api/volume" do
|
106
|
+
Play::Client.expects(:volume).with(3).returns(true)
|
107
|
+
post "/api/volume", {:level => '3'}
|
108
|
+
resp = parse_json(last_response.body.strip)
|
109
|
+
assert_equal 'true', resp[:success]
|
110
|
+
end
|
111
|
+
|
112
|
+
test "/api/pause" do
|
113
|
+
Play::Client.expects(:pause).returns(true)
|
114
|
+
post "/api/pause"
|
115
|
+
resp = parse_json(last_response.body.strip)
|
116
|
+
assert_equal 'true', resp[:success]
|
117
|
+
end
|
118
|
+
end
|