mr_eko 0.4.3 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: