mr_eko 0.6.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +2 -2
- data/lib/mr_eko/song.rb +6 -29
- data/lib/mr_eko/tag_parser.rb +22 -0
- data/lib/mr_eko.rb +3 -2
- data/mr_eko.gemspec +5 -2
- data/test/data/unicode.mp3 +0 -0
- data/test/song_test.rb +3 -27
- data/test/tag_parser_test.rb +21 -0
- data/test/test.rb +5 -0
- metadata +6 -3
data/README.md
CHANGED
@@ -11,10 +11,10 @@ Example:
|
|
11
11
|
mreko scan jakob-semaphore.mp3 pelican-drought.mp3
|
12
12
|
|
13
13
|
# Output a PLS playlist of fast, minor-key music
|
14
|
-
mreko playlist --tempo '>120' --mode minor
|
14
|
+
mreko playlist --tempo '>120' --mode minor > rainy_day_suicidal_playlist.pls
|
15
15
|
|
16
16
|
# Output a playlist of shorter, up-tempo, danceable, major-keyed songs
|
17
|
-
mreko playlist --preset gym
|
17
|
+
mreko playlist --preset gym > sweaty_playlist.pls
|
18
18
|
|
19
19
|
# Output a 30 minute playlist which builds from tempo 120 to 185 BPM. See notes on TimedPlaylists below.
|
20
20
|
mreko playlist --timed 1800 --tempo 120 --final 185 > morning_commute.pls
|
data/lib/mr_eko/song.rb
CHANGED
@@ -72,14 +72,14 @@ class MrEko::Song < Sequel::Model
|
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
|
-
# Parses the file's ID3 tags
|
75
|
+
# Parses the file's ID3 tags
|
76
76
|
#
|
77
77
|
# @param [String] The file path
|
78
|
-
# @return [
|
78
|
+
# @return [MrEko::TagParser::Result]
|
79
79
|
def self.parse_id3_tags(filename)
|
80
80
|
log "Parsing ID3 tags"
|
81
81
|
|
82
|
-
|
82
|
+
MrEko::TagParser.parse(filename)
|
83
83
|
end
|
84
84
|
|
85
85
|
|
@@ -89,7 +89,8 @@ class MrEko::Song < Sequel::Model
|
|
89
89
|
# @return [MrEko::Song]
|
90
90
|
def self.catalog_via_tags(filename, opts={})
|
91
91
|
tags = parse_id3_tags(filename)
|
92
|
-
|
92
|
+
|
93
|
+
return unless tags.reject{ |k, v| v.blank? }.size >= REQUIRED_ID3_TAGS.size
|
93
94
|
|
94
95
|
md5 = opts[:md5] || MrEko.md5(filename)
|
95
96
|
begin
|
@@ -98,7 +99,7 @@ class MrEko::Song < Sequel::Model
|
|
98
99
|
:bucket => 'audio_summary',
|
99
100
|
:limit => 1).songs.first
|
100
101
|
rescue => e
|
101
|
-
log "BAD TAGS? #{tags.
|
102
|
+
log "BAD TAGS? #{tags.inspect} #{filename}"
|
102
103
|
log e.message
|
103
104
|
log e.backtrace.join("\n")
|
104
105
|
return
|
@@ -126,13 +127,6 @@ class MrEko::Song < Sequel::Model
|
|
126
127
|
end if analysis
|
127
128
|
end
|
128
129
|
|
129
|
-
def self.has_required_tags?(tags)
|
130
|
-
found = REQUIRED_ID3_TAGS.inject([]) do |present, meth|
|
131
|
-
present << tags.send(meth)
|
132
|
-
end
|
133
|
-
|
134
|
-
found.compact.size == REQUIRED_ID3_TAGS.size ? true : false
|
135
|
-
end
|
136
130
|
|
137
131
|
# Using the Echonest Musical Fingerprint lib in the hopes
|
138
132
|
# of sidestepping the mp3 upload process.
|
@@ -218,21 +212,4 @@ class MrEko::Song < Sequel::Model
|
|
218
212
|
File.expand_path File.join(MrEko::FINGERPRINTS_DIR, "#{md5}.json")
|
219
213
|
end
|
220
214
|
|
221
|
-
# @param [Array<ID3Lib::Tag>]
|
222
|
-
# @return [Array<ID3Lib::Tag>]
|
223
|
-
def self.clean_tags(tags)
|
224
|
-
|
225
|
-
(REQUIRED_ID3_TAGS + [:album]).each do |rt|
|
226
|
-
tag = tags.send(rt).to_s
|
227
|
-
if tag.encoding != Encoding::UTF_8
|
228
|
-
decoded = tag.encode
|
229
|
-
else
|
230
|
-
decoded = tag
|
231
|
-
end
|
232
|
-
|
233
|
-
tags.send("#{rt}=", decoded)
|
234
|
-
end
|
235
|
-
|
236
|
-
tags
|
237
|
-
end
|
238
215
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class MrEko::TagParser
|
2
|
+
|
3
|
+
def self.parse(filename)
|
4
|
+
TagLib::FileRef.open(filename, false) do |file|
|
5
|
+
tag = file.tag
|
6
|
+
result = Result.new
|
7
|
+
result.artist = tag.artist
|
8
|
+
result.title = tag.title
|
9
|
+
result.album = tag.album
|
10
|
+
|
11
|
+
result
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
class Result < Hash
|
17
|
+
include Hashie::Extensions::MethodAccess
|
18
|
+
include Hashie::Extensions::IndifferentAccess
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
data/lib/mr_eko.rb
CHANGED
@@ -9,7 +9,7 @@ require 'sequel/extensions/migration'
|
|
9
9
|
require "logger"
|
10
10
|
require "hashie"
|
11
11
|
require "digest/md5"
|
12
|
-
require '
|
12
|
+
require 'taglib'
|
13
13
|
require "echonest"
|
14
14
|
begin
|
15
15
|
require 'debugger'
|
@@ -22,7 +22,7 @@ EKO_ENV = ENV['EKO_ENV'] || 'development'
|
|
22
22
|
Sequel.default_timezone = :utc
|
23
23
|
|
24
24
|
module MrEko
|
25
|
-
VERSION = '0.6.
|
25
|
+
VERSION = '0.6.1'
|
26
26
|
USER_DIR = File.join(ENV['HOME'], ".mreko")
|
27
27
|
FINGERPRINTS_DIR = File.join(USER_DIR, 'fingerprints')
|
28
28
|
LOG_DIR = File.join(USER_DIR, 'logs')
|
@@ -144,3 +144,4 @@ require "mr_eko/playlist"
|
|
144
144
|
require "mr_eko/timed_playlist"
|
145
145
|
require "mr_eko/song"
|
146
146
|
require "mr_eko/playlist_entry"
|
147
|
+
require "mr_eko/tag_parser"
|
data/mr_eko.gemspec
CHANGED
@@ -13,7 +13,7 @@ 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.6.
|
16
|
+
s.version = '0.6.1'
|
17
17
|
s.date = '2013-08-13'
|
18
18
|
s.rubyforge_project = 'mr_eko'
|
19
19
|
|
@@ -51,7 +51,7 @@ Gem::Specification.new do |s|
|
|
51
51
|
s.add_dependency('httpclient', "~> 2.1")
|
52
52
|
s.add_dependency('bassnode-ruby-echonest')
|
53
53
|
s.add_dependency('json', "= 1.4.6")
|
54
|
-
s.add_dependency('
|
54
|
+
s.add_dependency('taglib-ruby')
|
55
55
|
|
56
56
|
## List your development dependencies here. Development dependencies are
|
57
57
|
## those that are only needed during development
|
@@ -101,13 +101,16 @@ Gem::Specification.new do |s|
|
|
101
101
|
lib/mr_eko/playlist_entry.rb
|
102
102
|
lib/mr_eko/presets.rb
|
103
103
|
lib/mr_eko/song.rb
|
104
|
+
lib/mr_eko/tag_parser.rb
|
104
105
|
lib/mr_eko/timed_playlist.rb
|
105
106
|
mr_eko.gemspec
|
106
107
|
test/data/tagless.mp3
|
107
108
|
test/data/they_want_a_test.mp3
|
109
|
+
test/data/unicode.mp3
|
108
110
|
test/mr_eko_test.rb
|
109
111
|
test/playlist_test.rb
|
110
112
|
test/song_test.rb
|
113
|
+
test/tag_parser_test.rb
|
111
114
|
test/test.rb
|
112
115
|
test/timed_playlist_test.rb
|
113
116
|
]
|
Binary file
|
data/test/song_test.rb
CHANGED
@@ -1,9 +1,6 @@
|
|
1
1
|
require 'ostruct'
|
2
2
|
class SongTest < Test::Unit::TestCase
|
3
3
|
|
4
|
-
TEST_MP3 = File.join(File.dirname(__FILE__), 'data', 'they_want_a_test.mp3')
|
5
|
-
TAGLESS_MP3 = File.join(File.dirname(__FILE__), 'data', 'tagless.mp3')
|
6
|
-
|
7
4
|
def enmfp_data_stub(overrides={})
|
8
5
|
opts = {
|
9
6
|
'code' => '98ouhajsnd081oi2he0da8sdoihjasdi2y9e8aASD3e8yaushdjQWD',
|
@@ -100,12 +97,12 @@ class SongTest < Test::Unit::TestCase
|
|
100
97
|
|
101
98
|
context 'catalog_via_tags' do
|
102
99
|
|
103
|
-
context 'for a mp3 with no
|
100
|
+
context 'for a mp3 with no ID3 tag information' do
|
104
101
|
|
105
102
|
setup do
|
106
103
|
@mp3 = MrEko::Song.parse_id3_tags(TAGLESS_MP3)
|
107
|
-
|
108
|
-
|
104
|
+
assert_nil @mp3.artist
|
105
|
+
assert_nil @mp3.title
|
109
106
|
end
|
110
107
|
|
111
108
|
should 'return nil' do
|
@@ -132,25 +129,4 @@ class SongTest < Test::Unit::TestCase
|
|
132
129
|
end
|
133
130
|
end
|
134
131
|
|
135
|
-
context 'cleaning encoded ID3 tags' do
|
136
|
-
|
137
|
-
should "decode iTunes' encoded tags" do
|
138
|
-
dm = 'Dead Meadow'.encode(Encoding::UCS_2BE, Encoding::UTF_8)
|
139
|
-
tag_stub = OpenStruct.new(:artist => dm, :title => 'Good Moaning')
|
140
|
-
ID3Lib::Tag.expects(:new).once.returns(tag_stub)
|
141
|
-
parsed_tags = MrEko::Song.parse_id3_tags(TEST_MP3)
|
142
|
-
|
143
|
-
assert_equal "Dead Meadow", parsed_tags.artist
|
144
|
-
end
|
145
|
-
|
146
|
-
should "not alter the tags when they aren't encoded" do
|
147
|
-
tag_stub = OpenStruct.new(:artist => 'Dead Meadow', :title => 'Good Moaning')
|
148
|
-
ID3Lib::Tag.expects(:new).once.returns(tag_stub)
|
149
|
-
|
150
|
-
parsed = MrEko::Song.parse_id3_tags(TEST_MP3)
|
151
|
-
|
152
|
-
assert_equal parsed.artist, 'Dead Meadow'
|
153
|
-
assert_equal parsed.title, 'Good Moaning'
|
154
|
-
end
|
155
|
-
end
|
156
132
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class TagParserTest < Test::Unit::TestCase
|
2
|
+
|
3
|
+
context 'parse' do
|
4
|
+
|
5
|
+
should 'return an abject with the tags' do
|
6
|
+
parser = MrEko::TagParser.parse(TEST_MP3)
|
7
|
+
|
8
|
+
assert_equal 'Swamp Rooters', parser.artist
|
9
|
+
assert_equal 'Swamp Cat Rag', parser.title
|
10
|
+
assert_equal 'Misc', parser.album
|
11
|
+
end
|
12
|
+
|
13
|
+
should 'handles files without tags' do
|
14
|
+
parser = MrEko::TagParser.parse(TAGLESS_MP3)
|
15
|
+
|
16
|
+
assert_nil parser.artist
|
17
|
+
assert_nil parser.title
|
18
|
+
assert_nil parser.album
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/test/test.rb
CHANGED
@@ -13,6 +13,11 @@ end
|
|
13
13
|
|
14
14
|
class Test::Unit::TestCase
|
15
15
|
|
16
|
+
TEST_MP3 = File.join(File.dirname(__FILE__), 'data', 'they_want_a_test.mp3')
|
17
|
+
TAGLESS_MP3 = File.join(File.dirname(__FILE__), 'data', 'tagless.mp3')
|
18
|
+
UNICODE_MP3 = File.join(File.dirname(__FILE__), 'data', 'unicode.mp3')
|
19
|
+
|
20
|
+
|
16
21
|
# Could be fleshed out some more.
|
17
22
|
def sequel_dataset_stub
|
18
23
|
data = mock()
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mr_eko
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -108,7 +108,7 @@ dependencies:
|
|
108
108
|
- !ruby/object:Gem::Version
|
109
109
|
version: 1.4.6
|
110
110
|
- !ruby/object:Gem::Dependency
|
111
|
-
name:
|
111
|
+
name: taglib-ruby
|
112
112
|
requirement: !ruby/object:Gem::Requirement
|
113
113
|
none: false
|
114
114
|
requirements:
|
@@ -276,13 +276,16 @@ files:
|
|
276
276
|
- lib/mr_eko/playlist_entry.rb
|
277
277
|
- lib/mr_eko/presets.rb
|
278
278
|
- lib/mr_eko/song.rb
|
279
|
+
- lib/mr_eko/tag_parser.rb
|
279
280
|
- lib/mr_eko/timed_playlist.rb
|
280
281
|
- mr_eko.gemspec
|
281
282
|
- test/data/tagless.mp3
|
282
283
|
- test/data/they_want_a_test.mp3
|
284
|
+
- test/data/unicode.mp3
|
283
285
|
- test/mr_eko_test.rb
|
284
286
|
- test/playlist_test.rb
|
285
287
|
- test/song_test.rb
|
288
|
+
- test/tag_parser_test.rb
|
286
289
|
- test/test.rb
|
287
290
|
- test/timed_playlist_test.rb
|
288
291
|
homepage: http://github.com/bassnode/mreko
|
@@ -300,7 +303,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
300
303
|
version: '0'
|
301
304
|
segments:
|
302
305
|
- 0
|
303
|
-
hash:
|
306
|
+
hash: -723694834172722563
|
304
307
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
305
308
|
none: false
|
306
309
|
requirements:
|