earworm 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,6 @@
1
+ === 0.0.1 / 2008-08-01
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
6
+
data/Manifest.txt ADDED
@@ -0,0 +1,12 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ bin/earworm
6
+ lib/earworm.rb
7
+ lib/earworm/client.rb
8
+ lib/earworm/fingerprint.rb
9
+ lib/earworm/puid.rb
10
+ lib/earworm/track.rb
11
+ lib/earworm_lib.rb
12
+ test/test_earworm.rb
data/README.txt ADDED
@@ -0,0 +1,66 @@
1
+ = earworm
2
+
3
+ * http://earworm.rubyforge.org
4
+
5
+ == DESCRIPTION:
6
+
7
+ Earworm can identify unknown music using MusicDNS and libofa.
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * Identifies mp3, ogg, and wav files.
12
+
13
+ == SYNOPSIS:
14
+
15
+ Identify an unknown audio file:
16
+
17
+ ew = Earworm::Client.new('MY Music DNS Key')
18
+ info = ew.identify(:file => '/home/aaron/unknown.wav')
19
+ puts "#{info.artist_name} - #{info.title}"
20
+
21
+ Fetch info for a PUID:
22
+
23
+ ew = Earworm::Client.new('MY Music DNS Key')
24
+ info = ew.identify(:puid => 'f39d4c68-ab2d-5067-9a1a-c6b45a367906')
25
+ puts "#{info.artist_name} - #{info.title}"
26
+
27
+ == REQUIREMENTS:
28
+
29
+ * {MusicDNS key}[https://secure.musicip.com/dns/index.jsp]
30
+ * libofa
31
+ * icanhasaudio
32
+
33
+ == INSTALL:
34
+
35
+ OS X:
36
+ * sudo port install libogg libvorbis lame libofa
37
+ * gem install earworm
38
+
39
+ Linux:
40
+ * sudo yum install libogg-devel libvorbis-devel lame-devel libofa
41
+ * gem install earworm
42
+
43
+ == LICENSE:
44
+
45
+ (The MIT License)
46
+
47
+ Copyright (c) 2008 {Aaron Patterson}[http://tenderlovemaking.com/]
48
+
49
+ Permission is hereby granted, free of charge, to any person obtaining
50
+ a copy of this software and associated documentation files (the
51
+ 'Software'), to deal in the Software without restriction, including
52
+ without limitation the rights to use, copy, modify, merge, publish,
53
+ distribute, sublicense, and/or sell copies of the Software, and to
54
+ permit persons to whom the Software is furnished to do so, subject to
55
+ the following conditions:
56
+
57
+ The above copyright notice and this permission notice shall be
58
+ included in all copies or substantial portions of the Software.
59
+
60
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
61
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
62
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
63
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
64
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
65
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
66
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+
6
+ $LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
7
+ require 'earworm'
8
+
9
+ Hoe.new('earworm', Earworm::VERSION) do |p|
10
+ p.developer('Aaron Patterson', 'aaronp@rubyforge.org')
11
+ p.extra_deps = [['icanhasaudio', '>=0.1.1']]
12
+ end
13
+
14
+ # vim: syntax=Ruby
data/bin/earworm ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'earworm'
5
+ require 'yaml'
6
+
7
+ CONFIG = File.join(File.expand_path(ENV['HOME']), '.earworm')
8
+ config = YAML.load_file(CONFIG)
9
+
10
+ (puts("USAGE: #{$0} unknown_file") || exit) unless ARGV[0]
11
+
12
+ ew = Earworm::Client.new(config['key'])
13
+ track =
14
+ if File.exists?(ARGV[0])
15
+ ew.identify(:file => ARGV[0])
16
+ else
17
+ ew.identify(:puid => ARGV[0])
18
+ end
19
+
20
+ puts "Title: #{track.title}" if track.title
21
+ puts "Artist: #{track.artist}" if track.artist
22
+ track.puid_list.each do |puid|
23
+ puts "PUID: #{puid}"
24
+ end
25
+
data/lib/earworm.rb ADDED
@@ -0,0 +1,26 @@
1
+ require 'icanhasaudio'
2
+ require 'tempfile'
3
+ require 'earworm_lib'
4
+ require 'earworm/track'
5
+ require 'earworm/puid'
6
+ require 'earworm/fingerprint'
7
+ require 'earworm/client'
8
+ require 'rexml/document'
9
+ require 'rexml/parsers/pullparser'
10
+
11
+ module Earworm
12
+ VERSION = '0.0.1'
13
+ URL = 'http://ofa.musicdns.org/ofa/1/track'
14
+ class << self
15
+ def ofa_version
16
+ major = DL.malloc(DL.sizeof('I'))
17
+ minor = DL.malloc(DL.sizeof('I'))
18
+ rev = DL.malloc(DL.sizeof('I'))
19
+ major.struct!('I', 'val')
20
+ minor.struct!('I', 'val')
21
+ rev.struct!('I', 'val')
22
+ EarwormLib.ofa_get_version(major, minor, rev)
23
+ "#{major['val']}.#{minor['val']}.#{rev['val']}"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,49 @@
1
+ module Earworm
2
+ class Client
3
+ attr_accessor :client_id
4
+ def initialize(client_id)
5
+ @client_id = client_id
6
+ end
7
+
8
+ def identify(options = {})
9
+ post_opts = nil
10
+ if options.key?(:file)
11
+ post_opts = {
12
+ 'cid' => @client_id,
13
+ 'cvr' => "Earworm #{VERSION}",
14
+ 'rmd' => 1,
15
+ 'enc' => '',
16
+ }.merge(Fingerprint.new(options[:file]).to_hash)
17
+ end
18
+ if options.key?(:puid)
19
+ post_opts = {
20
+ 'cid' => @client_id,
21
+ 'cvr' => "Earworm #{VERSION}",
22
+ 'rmd' => 1,
23
+ 'enc' => '',
24
+ }.merge(PUID.new(options[:puid]).to_hash)
25
+ end
26
+ xml = Net::HTTP.post_form(URI.parse(URL), post_opts).body
27
+ parser = REXML::Parsers::PullParser.new(xml)
28
+ track = Track.new
29
+ while parser.has_next?
30
+ thing = parser.pull
31
+ if thing.start_element?
32
+ case thing[0]
33
+ when 'title'
34
+ track.title = parser.pull[0]
35
+ when 'name'
36
+ track.artist_name = parser.pull[0]
37
+ when 'puid'
38
+ track.puid_list << thing[1]['id']
39
+ end
40
+ end
41
+ end
42
+ track
43
+ end
44
+
45
+ def fingerprint(filename)
46
+ Fingerprint.new(filename).to_s
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,102 @@
1
+ module Earworm
2
+ class Fingerprint
3
+ def initialize(thing)
4
+ @thing = thing
5
+ @hash = nil
6
+ end
7
+
8
+ def to_hash
9
+ return @hash if @hash
10
+ info = nil
11
+ @hash = {
12
+ 'art' => 'unknown',
13
+ 'ttl' => 'unknown',
14
+ 'alb' => 'unknown',
15
+ 'tnm' => 0,
16
+ 'gnr' => 'unknown',
17
+ 'yrr' => 0,
18
+ 'brt' => 0,
19
+ 'fmt' => 'wav',
20
+ }
21
+ if @thing.is_a?(IO)
22
+ info = wav_info_for(@thing)
23
+ else
24
+ tmpfile = case @thing
25
+ when /mp3$/
26
+ @hash['fmt'] = 'mp3'
27
+ begin
28
+ require 'id3lib'
29
+ @hash = @hash.merge(id3_info_for(@thing))
30
+ rescue LoadError
31
+ end
32
+ decode_mp3(@thing)
33
+ when /ogg$/
34
+ @hash['fmt'] = 'ogg'
35
+ decode_ogg(@thing)
36
+ else # Assume its a wav file
37
+ @thing
38
+ end
39
+ File.open(tmpfile, 'rb') { |f|
40
+ info = wav_info_for(f)
41
+ }
42
+ end
43
+ @hash['fpt'] = info[:fpt]
44
+ @hash['dur'] = info[:milliseconds]
45
+ @hash
46
+ end
47
+
48
+ def to_s
49
+ to_hash['fpt']
50
+ end
51
+
52
+ private
53
+ def wav_info_for(io)
54
+ header = io.read(4).unpack('N').first
55
+ raise unless header == Audio::MPEG::Encoder::WAV_ID_RIFF
56
+ info = Audio::MPEG::Encoder.parse_wave_header(io)
57
+ bytes_in_seconds = 135 * info[:in_samplerate] * 2 * info[:num_channels]
58
+ read_bytes =
59
+ if info[:bytes_in_seconds] > bytes_in_seconds
60
+ bytes_in_seconds
61
+ else
62
+ info[:bytes_in_seconds]
63
+ end
64
+
65
+ data = io.read(read_bytes)
66
+ info[:fpt] = EarwormLib.ofa_create_print( data,
67
+ 0,
68
+ read_bytes/2,
69
+ info[:in_samplerate], 1)
70
+ info
71
+ end
72
+
73
+ def id3_info_for(filename)
74
+ tag = ID3Lib::Tag.new(filename)
75
+ {
76
+ 'art' => tag.artist,
77
+ 'ttl' => tag.title,
78
+ 'alb' => tag.album,
79
+ 'tnm' => tag.track[/^(\d+)/],
80
+ 'gnr' => tag.genre,
81
+ 'yrr' => tag.year,
82
+ }
83
+ end
84
+
85
+ {
86
+ 'ogg' => Audio::OGG::Decoder,
87
+ 'mp3' => Audio::MPEG::Decoder,
88
+ }.each do |type,klass|
89
+ define_method(:"decode_#{type}") do |filename|
90
+ reader = klass.new
91
+ name = File.join(Dir::tmpdir,
92
+ "#{File.basename(filename, ".#{type}")}.wav")
93
+ File.open(filename, 'rb') { |input|
94
+ File.open(name, 'wb') { |tmpfile|
95
+ reader.decode(input, tmpfile)
96
+ }
97
+ }
98
+ name
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,21 @@
1
+ module Earworm
2
+ class PUID
3
+ def initialize(puid)
4
+ @puid = puid
5
+ end
6
+
7
+ def to_hash
8
+ {
9
+ 'puid' => @puid,
10
+ 'art' => 'unknown',
11
+ 'ttl' => 'unknown',
12
+ 'alb' => 'unknown',
13
+ 'tnm' => 0,
14
+ 'gnr' => 'unknown',
15
+ 'yrr' => 0,
16
+ }
17
+ end
18
+
19
+ def to_s; @puid; end
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ module Earworm
2
+ class Track
3
+ attr_accessor :title, :artist_name, :puid_list
4
+ alias :artist :artist_name
5
+ def initialize
6
+ @title = nil
7
+ @artist_name = nil
8
+ @puid_list = []
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ require 'dl/import'
2
+ module EarwormLib # :nodoc:
3
+ extend DL::Importable
4
+ loaded = false
5
+ libs = %w{ libofa.dylib libofa.so libofa.so.0 }
6
+ dirs = %w{ /opt/local/lib /usr/local/lib }
7
+ libs += libs.map { |lib| dirs.map { |dir| File.join(dir, lib) } }.flatten
8
+ libs.each do |so|
9
+ begin
10
+ dlload(so)
11
+ loaded = true
12
+ break
13
+ rescue
14
+ next
15
+ end
16
+ end
17
+ raise "Please install libofa" unless loaded
18
+
19
+ extern "void ofa_get_version(int *, int *, int *)"
20
+ extern "const char * ofa_create_print(const char *, int, long, int, int)"
21
+ end
@@ -0,0 +1,44 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'earworm'
4
+ require 'yaml'
5
+
6
+ class EarwormTest < Test::Unit::TestCase
7
+ def setup
8
+ settings = YAML.load_file(File.join(ENV['HOME'], '.earworm'))
9
+ assert settings
10
+ assert settings['assets']
11
+ assert settings['key']
12
+ @assets = settings['assets']
13
+ @key = settings['key']
14
+ @mp3 = Dir[@assets + "/*.mp3"].first
15
+ end
16
+
17
+ def test_ofa_version
18
+ assert Earworm.ofa_version
19
+ end
20
+
21
+ def test_fingerprint
22
+ ew = Earworm::Client.new('123')
23
+ key = ew.fingerprint(@mp3)
24
+ assert key
25
+ end
26
+
27
+ def test_identify_file
28
+ ew = Earworm::Client.new(@key)
29
+ info = ew.identify(:file => @mp3)
30
+ assert info
31
+ assert info.artist_name
32
+ assert info.title
33
+ assert info.puid_list.length > 0
34
+ end
35
+
36
+ def test_idenfity_puid
37
+ ew = Earworm::Client.new(@key)
38
+ info = ew.identify(:puid => 'f39d4c68-ab2d-5067-9a1a-c6b45a367906')
39
+ assert info
40
+ assert info.artist_name
41
+ assert info.title
42
+ assert info.puid_list.length > 0
43
+ end
44
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: earworm
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Aaron Patterson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-08-04 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: icanhasaudio
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.1.1
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: hoe
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.7.0
34
+ version:
35
+ description: Earworm can identify unknown music using MusicDNS and libofa.
36
+ email:
37
+ - aaronp@rubyforge.org
38
+ executables:
39
+ - earworm
40
+ extensions: []
41
+
42
+ extra_rdoc_files:
43
+ - History.txt
44
+ - Manifest.txt
45
+ - README.txt
46
+ files:
47
+ - History.txt
48
+ - Manifest.txt
49
+ - README.txt
50
+ - Rakefile
51
+ - bin/earworm
52
+ - lib/earworm.rb
53
+ - lib/earworm/client.rb
54
+ - lib/earworm/fingerprint.rb
55
+ - lib/earworm/puid.rb
56
+ - lib/earworm/track.rb
57
+ - lib/earworm_lib.rb
58
+ - test/test_earworm.rb
59
+ has_rdoc: true
60
+ homepage: http://earworm.rubyforge.org
61
+ post_install_message:
62
+ rdoc_options:
63
+ - --main
64
+ - README.txt
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ version:
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: "0"
78
+ version:
79
+ requirements: []
80
+
81
+ rubyforge_project: earworm
82
+ rubygems_version: 1.2.0
83
+ signing_key:
84
+ specification_version: 2
85
+ summary: Earworm can identify unknown music using MusicDNS and libofa.
86
+ test_files:
87
+ - test/test_earworm.rb