mr_eko 0.4.3 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,4 +1,3 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- # gem "bassnode-ruby-echonest", :path => "../ruby-echonest"
4
3
  gemspec
data/README.md CHANGED
@@ -16,11 +16,25 @@ Example:
16
16
  # Output a playlist of shorter, up-tempo, danceable, major-keyed songs
17
17
  mreko playlist --preset gym --format pls > sweaty_playlist.pls
18
18
 
19
+ # Output a 30 minute playlist which builds from tempo 120 to 185 BPM. See notes on TimedPlaylists below.
20
+ mreko playlist --timed 1800 --tempo 120 --final 185 > morning_commute.pls
21
+
22
+ # Output an hour-long playlist which gradually decreases in energy.
23
+ mreko playlist --timed 3600 --energy 100 --final 30 > evening_wind_down.pls
24
+
19
25
  Requirements:
20
26
  -------------
21
27
  * [ffmpeg](http://www.ffmpeg.org/download.html) in your path.
22
28
  * an [Echonest API token](http://developer.echonest.com/) which goes here: ~/.mreko/echonest_api.key
23
29
 
30
+ TimedPlaylists:
31
+ ---------------
32
+ TimedPlaylists are different than standard Playlists in that they are both limited by time (surprise!) and are built around one "facet".
33
+ A facet is one of the Playlist options such as tempo, key, energy, mode, etc. You specify the length of the playlist (in seconds), the facet
34
+ upon which the playlist is filtered and sorted, and then the initial and final values for the facet. E.g. a 45 minute playlist which starts in
35
+ Minor key and ends Major:
36
+ mreko playlist --timed 2700 --mode minor --final major
37
+
24
38
  Notes:
25
39
  ------
26
40
  MrEko will make an audio fingerprint of a music file and attempt to use it (along with ID3 tags) to retrieve data from Echonest.
data/bin/mreko CHANGED
@@ -10,15 +10,16 @@ Sequel::Migrator.apply(MrEko.connection, File.join(File.dirname(__FILE__), "..",
10
10
 
11
11
  def parse_options
12
12
 
13
- options = { :format => :text }
13
+ options = { :format => :pls }
14
14
 
15
15
  OptionParser.new do |opts|
16
- opts.banner = "Usage: #{$0} scan|playlist [options]"
16
+ opts.banner = "MrEko version #{MrEko::VERSION}\n"
17
+ opts.banner += "Usage: mreko scan|playlist [options]"
17
18
 
18
19
  opts.separator ""
19
20
  opts.separator "Playlist options:"
20
21
 
21
- opts.on("-p", "--preset NAME", String, "Select a preset. Options are (#{MrEko::Presets::FACTORY.keys.join(', ')})") do |preset|
22
+ opts.on("-p", "--preset NAME", String, "Select a preset. Options are: #{MrEko::Presets::FACTORY.keys.join(', ')}") do |preset|
22
23
  options[:preset] = preset
23
24
  end
24
25
 
@@ -46,6 +47,10 @@ def parse_options
46
47
  options[:loudness] = num
47
48
  end
48
49
 
50
+ opts.on("-k", "--key KEY", "Specify chromatic key (from C to B)") do |key|
51
+ options[:key] = key
52
+ end
53
+
49
54
  opts.on("-o", "--mode MODE", String, "Specify mode (minor or major)") do |mode|
50
55
  unless MrEko::MODES.include?(mode)
51
56
  raise ArgumentError.new("Mode must be #{MrEko::MODES.join(' or ')}")
@@ -53,6 +58,14 @@ def parse_options
53
58
  options[:mode] = mode
54
59
  end
55
60
 
61
+ opts.on("-x", "--timed SEC", "Limit this playlist to a certain length (in seconds).") do |length|
62
+ options[:timed] = length
63
+ end
64
+
65
+ opts.on("-z", "--final VAL", "Sets the ending value of a Timed Playlist") do |val|
66
+ options[:final] = val
67
+ end
68
+
56
69
  opts.on("-f", "--format FORMAT", MrEko::Playlist::FORMATS,
57
70
  "Select output type (#{MrEko::Playlist::FORMATS.join(', ')})") do |format|
58
71
  unless MrEko::Playlist::FORMATS.include?(format)
@@ -65,7 +78,13 @@ def parse_options
65
78
  options[:tags_only] = true
66
79
  end
67
80
 
68
- opts.separator ""
81
+ opts.on("-v", "--version", "Output version") do
82
+ puts MrEko::VERSION
83
+ exit
84
+ end
85
+
86
+ opts.separator "\nNote that if --timed is passed, you may only specify one facet, e.g --tempo. This value will be used as the starting point.
87
+ You must also pass --final to set the final value. So for a 10 min. playlist which starts at 120 BPM and ends at 200 BPM: mr_eko playlist --timed 600 --tempo 120 --final 200\n\n"
69
88
 
70
89
  # No argument, shows at tail. This will print an options summary.
71
90
  opts.on_tail("-h", "--help", "Show this message") do
@@ -97,10 +116,23 @@ when 'scan'
97
116
  files.each do |file|
98
117
  MrEko::Song.create_from_file!(file, options)
99
118
  end
119
+
100
120
  when 'playlist'
101
121
  format = options.delete(:format)
102
- playlist = MrEko::Playlist.create_from_options(options)
122
+
123
+ if length = options.delete(:timed)
124
+ final = options.delete(:final)
125
+ raise ArgumentError.new("You may only provide one facet when creating a Timed Playlist!!") if options.keys.size > 1
126
+
127
+ facet = options.keys.first
128
+ initial = options[facet]
129
+ playlist = MrEko::TimedPlaylist.create(:length => length, :facet => facet, :initial => initial, :final => final)
130
+ else
131
+ playlist = MrEko::Playlist.create_from_options(options)
132
+ end
133
+
103
134
  puts playlist.output(format)
135
+
104
136
  else
105
137
  puts "nothing for #{ARGV[0]}"
106
138
  end
@@ -11,7 +11,7 @@ class MrEko::TimedPlaylist < MrEko::Playlist
11
11
 
12
12
  def initialize(opts={})
13
13
  @facet = opts.delete(:facet)
14
- @length = opts.delete(:length)
14
+ @length = opts.delete(:length).to_i
15
15
 
16
16
  super
17
17
  end
@@ -47,15 +47,19 @@ class MrEko::TimedPlaylist < MrEko::Playlist
47
47
 
48
48
  case facet
49
49
  when :danceability, :energy
50
- @initial = (initial / 100.0)
51
- @final = (final / 100.0)
50
+ @initial = (initial.to_i / 100.0)
51
+ @final = (final.to_i / 100.0)
52
52
  when :mode
53
53
  @initial = MrEko.mode_lookup(initial)
54
54
  @final = MrEko.mode_lookup(final)
55
55
  when :key
56
56
  @initial = MrEko.key_lookup(initial)
57
57
  @final = MrEko.key_lookup(final)
58
+ else
59
+ @initial = initial.to_i
60
+ @final = final.to_i
58
61
  end
62
+
59
63
  end
60
64
 
61
65
  def find_song_groups!(iterations=50)
data/lib/mr_eko.rb CHANGED
@@ -19,7 +19,7 @@ EKO_ENV = ENV['EKO_ENV'] || 'development'
19
19
  Sequel.default_timezone = :utc
20
20
 
21
21
  module MrEko
22
- VERSION = '0.4.3'
22
+ VERSION = '0.5.1'
23
23
  USER_DIR = File.join(ENV['HOME'], ".mreko")
24
24
  FINGERPRINTS_DIR = File.join(USER_DIR, 'fingerprints')
25
25
  LOG_DIR = File.join(USER_DIR, 'logs')
data/mr_eko.gemspec CHANGED
@@ -13,8 +13,8 @@ Gem::Specification.new do |s|
13
13
  ## If your rubyforge_project name is different, then edit it and comment out
14
14
  ## the sub! line in the Rakefile
15
15
  s.name = 'mr_eko'
16
- s.version = '0.4.3'
17
- s.date = '2012-02-12'
16
+ s.version = '0.5.1'
17
+ s.date = '2012-06-03'
18
18
  s.rubyforge_project = 'mr_eko'
19
19
 
20
20
  ## Make sure your summary is short. The description may be as long
@@ -85,23 +85,31 @@ class TimedPlaylistTest < Test::Unit::TestCase
85
85
  end
86
86
  end
87
87
 
88
- # pending, until next time...
89
- #context 'the songs' do
90
- # setup do
91
- # MrEko::Song.delete
92
- # end
93
-
94
- # should "populate the list of songs" do
95
- # 60.times do |i|
96
- # create_song(:tempo => 50 + i , :duration => 1.minutes, :title => "Song #{i}")
97
- # end
98
-
99
- # list = MrEko::TimedPlaylist.new(:length => 30.minutes, :facet => :tempo)
100
- # list.initial = 50
101
- # list.final = 100
102
- # list.save
103
- # end
104
- #end
88
+ context 'the songs' do
89
+ setup do
90
+ MrEko::Song.delete
91
+ @song_count = 40
92
+
93
+ @song_count.times do |i|
94
+ create_song(:tempo => 50 + i , :duration => 1.minutes, :title => "Song #{i}")
95
+ end
96
+
97
+ @list = MrEko::TimedPlaylist.create(:length => 30.minutes, :facet => :tempo, :initial => 50, :final => 100)
98
+ end
99
+
100
+ should "fill the requested duration" do
101
+ assert_equal 30, @list.songs.size
102
+ end
103
+
104
+ should "fit the required constraints" do
105
+ assert @list.songs.all?{ |song| song.tempo >= @list.initial && song.tempo <= @list.final }
106
+ end
107
+
108
+ should "be sorted ascending, by default" do
109
+ sorted = @list.songs.sort_by &:tempo
110
+ assert_equal sorted, @list.songs
111
+ end
112
+ end
105
113
  end
106
114
 
107
115
  end
metadata CHANGED
@@ -1,178 +1,236 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: mr_eko
3
- version: !ruby/object:Gem::Version
4
- version: 0.4.3
3
+ version: !ruby/object:Gem::Version
4
+ hash: 9
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 5
9
+ - 1
10
+ version: 0.5.1
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Ed Hickey
9
14
  autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
- date: 2012-02-12 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
17
+
18
+ date: 2012-06-03 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
15
21
  name: sequel
16
- requirement: &2160313480 !ruby/object:Gem::Requirement
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
17
24
  none: false
18
- requirements:
19
- - - =
20
- - !ruby/object:Gem::Version
21
- version: '3.15'
25
+ requirements:
26
+ - - "="
27
+ - !ruby/object:Gem::Version
28
+ hash: 25
29
+ segments:
30
+ - 3
31
+ - 15
32
+ version: "3.15"
22
33
  type: :runtime
23
- prerelease: false
24
- version_requirements: *2160313480
25
- - !ruby/object:Gem::Dependency
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
26
36
  name: sqlite3-ruby
27
- requirement: &2160312580 !ruby/object:Gem::Requirement
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
28
39
  none: false
29
- requirements:
40
+ requirements:
30
41
  - - ~>
31
- - !ruby/object:Gem::Version
32
- version: '1.3'
42
+ - !ruby/object:Gem::Version
43
+ hash: 9
44
+ segments:
45
+ - 1
46
+ - 3
47
+ version: "1.3"
33
48
  type: :runtime
34
- prerelease: false
35
- version_requirements: *2160312580
36
- - !ruby/object:Gem::Dependency
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
37
51
  name: hashie
38
- requirement: &2160327920 !ruby/object:Gem::Requirement
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
39
54
  none: false
40
- requirements:
41
- - - ! '>='
42
- - !ruby/object:Gem::Version
43
- version: '0'
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
44
62
  type: :runtime
45
- prerelease: false
46
- version_requirements: *2160327920
47
- - !ruby/object:Gem::Dependency
63
+ version_requirements: *id003
64
+ - !ruby/object:Gem::Dependency
48
65
  name: httpclient
49
- requirement: &2160327060 !ruby/object:Gem::Requirement
66
+ prerelease: false
67
+ requirement: &id004 !ruby/object:Gem::Requirement
50
68
  none: false
51
- requirements:
69
+ requirements:
52
70
  - - ~>
53
- - !ruby/object:Gem::Version
54
- version: '2.1'
71
+ - !ruby/object:Gem::Version
72
+ hash: 1
73
+ segments:
74
+ - 2
75
+ - 1
76
+ version: "2.1"
55
77
  type: :runtime
56
- prerelease: false
57
- version_requirements: *2160327060
58
- - !ruby/object:Gem::Dependency
78
+ version_requirements: *id004
79
+ - !ruby/object:Gem::Dependency
59
80
  name: bassnode-ruby-echonest
60
- requirement: &2160326540 !ruby/object:Gem::Requirement
81
+ prerelease: false
82
+ requirement: &id005 !ruby/object:Gem::Requirement
61
83
  none: false
62
- requirements:
63
- - - ! '>='
64
- - !ruby/object:Gem::Version
65
- version: '0'
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ hash: 3
88
+ segments:
89
+ - 0
90
+ version: "0"
66
91
  type: :runtime
67
- prerelease: false
68
- version_requirements: *2160326540
69
- - !ruby/object:Gem::Dependency
92
+ version_requirements: *id005
93
+ - !ruby/object:Gem::Dependency
70
94
  name: json
71
- requirement: &2160325800 !ruby/object:Gem::Requirement
95
+ prerelease: false
96
+ requirement: &id006 !ruby/object:Gem::Requirement
72
97
  none: false
73
- requirements:
74
- - - =
75
- - !ruby/object:Gem::Version
98
+ requirements:
99
+ - - "="
100
+ - !ruby/object:Gem::Version
101
+ hash: 11
102
+ segments:
103
+ - 1
104
+ - 4
105
+ - 6
76
106
  version: 1.4.6
77
107
  type: :runtime
78
- prerelease: false
79
- version_requirements: *2160325800
80
- - !ruby/object:Gem::Dependency
108
+ version_requirements: *id006
109
+ - !ruby/object:Gem::Dependency
81
110
  name: id3lib-ruby
82
- requirement: &2160325140 !ruby/object:Gem::Requirement
111
+ prerelease: false
112
+ requirement: &id007 !ruby/object:Gem::Requirement
83
113
  none: false
84
- requirements:
85
- - - ! '>='
86
- - !ruby/object:Gem::Version
87
- version: '0'
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ hash: 3
118
+ segments:
119
+ - 0
120
+ version: "0"
88
121
  type: :runtime
89
- prerelease: false
90
- version_requirements: *2160325140
91
- - !ruby/object:Gem::Dependency
122
+ version_requirements: *id007
123
+ - !ruby/object:Gem::Dependency
92
124
  name: mocha
93
- requirement: &2160324320 !ruby/object:Gem::Requirement
125
+ prerelease: false
126
+ requirement: &id008 !ruby/object:Gem::Requirement
94
127
  none: false
95
- requirements:
96
- - - =
97
- - !ruby/object:Gem::Version
128
+ requirements:
129
+ - - "="
130
+ - !ruby/object:Gem::Version
131
+ hash: 43
132
+ segments:
133
+ - 0
134
+ - 9
135
+ - 8
98
136
  version: 0.9.8
99
137
  type: :development
100
- prerelease: false
101
- version_requirements: *2160324320
102
- - !ruby/object:Gem::Dependency
138
+ version_requirements: *id008
139
+ - !ruby/object:Gem::Dependency
103
140
  name: shoulda
104
- requirement: &2160323560 !ruby/object:Gem::Requirement
141
+ prerelease: false
142
+ requirement: &id009 !ruby/object:Gem::Requirement
105
143
  none: false
106
- requirements:
144
+ requirements:
107
145
  - - ~>
108
- - !ruby/object:Gem::Version
109
- version: '2.11'
146
+ - !ruby/object:Gem::Version
147
+ hash: 21
148
+ segments:
149
+ - 2
150
+ - 11
151
+ version: "2.11"
110
152
  type: :development
111
- prerelease: false
112
- version_requirements: *2160323560
113
- - !ruby/object:Gem::Dependency
153
+ version_requirements: *id009
154
+ - !ruby/object:Gem::Dependency
114
155
  name: test-unit
115
- requirement: &2160322960 !ruby/object:Gem::Requirement
156
+ prerelease: false
157
+ requirement: &id010 !ruby/object:Gem::Requirement
116
158
  none: false
117
- requirements:
159
+ requirements:
118
160
  - - ~>
119
- - !ruby/object:Gem::Version
120
- version: '2.1'
161
+ - !ruby/object:Gem::Version
162
+ hash: 1
163
+ segments:
164
+ - 2
165
+ - 1
166
+ version: "2.1"
121
167
  type: :development
122
- prerelease: false
123
- version_requirements: *2160322960
124
- - !ruby/object:Gem::Dependency
168
+ version_requirements: *id010
169
+ - !ruby/object:Gem::Dependency
125
170
  name: ruby-debug
126
- requirement: &2160322580 !ruby/object:Gem::Requirement
171
+ prerelease: false
172
+ requirement: &id011 !ruby/object:Gem::Requirement
127
173
  none: false
128
- requirements:
129
- - - ! '>='
130
- - !ruby/object:Gem::Version
131
- version: '0'
174
+ requirements:
175
+ - - ">="
176
+ - !ruby/object:Gem::Version
177
+ hash: 3
178
+ segments:
179
+ - 0
180
+ version: "0"
132
181
  type: :development
133
- prerelease: false
134
- version_requirements: *2160322580
135
- - !ruby/object:Gem::Dependency
182
+ version_requirements: *id011
183
+ - !ruby/object:Gem::Dependency
136
184
  name: autotest
137
- requirement: &2160322120 !ruby/object:Gem::Requirement
185
+ prerelease: false
186
+ requirement: &id012 !ruby/object:Gem::Requirement
138
187
  none: false
139
- requirements:
140
- - - ! '>='
141
- - !ruby/object:Gem::Version
142
- version: '0'
188
+ requirements:
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ hash: 3
192
+ segments:
193
+ - 0
194
+ version: "0"
143
195
  type: :development
144
- prerelease: false
145
- version_requirements: *2160322120
146
- - !ruby/object:Gem::Dependency
196
+ version_requirements: *id012
197
+ - !ruby/object:Gem::Dependency
147
198
  name: pry
148
- requirement: &2160321660 !ruby/object:Gem::Requirement
199
+ prerelease: false
200
+ requirement: &id013 !ruby/object:Gem::Requirement
149
201
  none: false
150
- requirements:
151
- - - ! '>='
152
- - !ruby/object:Gem::Version
153
- version: '0'
202
+ requirements:
203
+ - - ">="
204
+ - !ruby/object:Gem::Version
205
+ hash: 3
206
+ segments:
207
+ - 0
208
+ version: "0"
154
209
  type: :development
155
- prerelease: false
156
- version_requirements: *2160321660
157
- - !ruby/object:Gem::Dependency
210
+ version_requirements: *id013
211
+ - !ruby/object:Gem::Dependency
158
212
  name: yard
159
- requirement: &2160321240 !ruby/object:Gem::Requirement
213
+ prerelease: false
214
+ requirement: &id014 !ruby/object:Gem::Requirement
160
215
  none: false
161
- requirements:
162
- - - ! '>='
163
- - !ruby/object:Gem::Version
164
- version: '0'
216
+ requirements:
217
+ - - ">="
218
+ - !ruby/object:Gem::Version
219
+ hash: 3
220
+ segments:
221
+ - 0
222
+ version: "0"
165
223
  type: :development
166
- prerelease: false
167
- version_requirements: *2160321240
224
+ version_requirements: *id014
168
225
  description: Catalogs music file data and exposes a playlist interface
169
226
  email: bassnode@gmail.com
170
- executables:
227
+ executables:
171
228
  - mreko
172
229
  extensions: []
173
- extra_rdoc_files:
230
+
231
+ extra_rdoc_files:
174
232
  - README.md
175
- files:
233
+ files:
176
234
  - Gemfile
177
235
  - README.md
178
236
  - Rakefile
@@ -214,28 +272,37 @@ files:
214
272
  - test/timed_playlist_test.rb
215
273
  homepage: http://github.com/bassnode/mreko
216
274
  licenses: []
275
+
217
276
  post_install_message:
218
- rdoc_options:
277
+ rdoc_options:
219
278
  - --charset=UTF-8
220
- require_paths:
279
+ require_paths:
221
280
  - lib
222
- required_ruby_version: !ruby/object:Gem::Requirement
281
+ required_ruby_version: !ruby/object:Gem::Requirement
223
282
  none: false
224
- requirements:
225
- - - ! '>='
226
- - !ruby/object:Gem::Version
227
- version: '0'
228
- required_rubygems_version: !ruby/object:Gem::Requirement
283
+ requirements:
284
+ - - ">="
285
+ - !ruby/object:Gem::Version
286
+ hash: 3
287
+ segments:
288
+ - 0
289
+ version: "0"
290
+ required_rubygems_version: !ruby/object:Gem::Requirement
229
291
  none: false
230
- requirements:
231
- - - ! '>='
232
- - !ruby/object:Gem::Version
233
- version: '0'
292
+ requirements:
293
+ - - ">="
294
+ - !ruby/object:Gem::Version
295
+ hash: 3
296
+ segments:
297
+ - 0
298
+ version: "0"
234
299
  requirements: []
300
+
235
301
  rubyforge_project: mr_eko
236
- rubygems_version: 1.8.10
302
+ rubygems_version: 1.8.11
237
303
  signing_key:
238
304
  specification_version: 2
239
305
  summary: Catalogs music file data and exposes a playlist interface
240
306
  test_files: []
307
+
241
308
  has_rdoc: