earworm 0.0.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/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