jamescallmebrent-earworm 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ .*.swp
2
+ doc
3
+ pkg
@@ -0,0 +1,13 @@
1
+ === 0.0.2
2
+
3
+ * 1 Bugfix
4
+
5
+ * Oop! Forgot a require. Thanks Mike McKay!
6
+ * Added better error messaging. Thanks again to Mike McKay.
7
+
8
+ === 0.0.1 / 2008-08-01
9
+
10
+ * 1 major enhancement
11
+
12
+ * Birthday!
13
+
@@ -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
@@ -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.
@@ -0,0 +1,21 @@
1
+ require 'rubygems'
2
+
3
+ begin
4
+ require 'jeweler'
5
+ Jeweler::Tasks.new do |s|
6
+ s.name = "earworm"
7
+ s.email = "aaronp@rubyforge.org"
8
+ s.homepage = "http://github.com/tenderlove/earworm"
9
+ s.authors = ["Aaron Patterson"]
10
+ s.summary = 'What is that song? Earworm uses libofa and MusicDNS to tell you.'
11
+ s.description = 'Earworm can identify unknown music using MusicDNS and libofa.'
12
+ s.rubyforge_project = 'earworm'
13
+ s.add_dependency('icanhasaudio','>=0.1.1')
14
+ # Jeweler defaults
15
+ s.has_rdoc = false
16
+ end
17
+ rescue LoadError
18
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
19
+ end
20
+
21
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.3
@@ -0,0 +1,34 @@
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
+ begin
9
+ config = YAML.load_file(CONFIG)
10
+ rescue
11
+ raise "Please create a .earworm file in your home directory"
12
+ end
13
+
14
+ (puts("USAGE: #{$0} unknown_file") || exit) unless ARGV[0]
15
+
16
+ begin
17
+ ew = Earworm::Client.new(config['key'])
18
+ rescue
19
+ raise "\n\nYou need to generate a key here: http://www.musicip.com/dns/license.jsp\n then put the key into your .earworm file like this:
20
+ key: 012321312AA\n"
21
+ end
22
+ track =
23
+ if File.exists?(ARGV[0])
24
+ ew.identify(:file => ARGV[0])
25
+ else
26
+ ew.identify(:puid => ARGV[0])
27
+ end
28
+
29
+ puts "Title: #{track.title}" if track.title
30
+ puts "Artist: #{track.artist}" if track.artist
31
+ track.puid_list.each do |puid|
32
+ puts "PUID: #{puid}"
33
+ end
34
+
@@ -0,0 +1,56 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{earworm}
5
+ s.version = "0.0.3"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Aaron Patterson"]
9
+ s.date = %q{2009-07-05}
10
+ s.default_executable = %q{earworm}
11
+ s.description = %q{Earworm can identify unknown music using MusicDNS and libofa.}
12
+ s.email = %q{aaronp@rubyforge.org}
13
+ s.executables = ["earworm"]
14
+ s.extra_rdoc_files = [
15
+ "README.txt"
16
+ ]
17
+ s.files = [
18
+ ".gitignore",
19
+ "History.txt",
20
+ "Manifest.txt",
21
+ "README.txt",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "bin/earworm",
25
+ "earworm.gemspec",
26
+ "lib/earworm.rb",
27
+ "lib/earworm/client.rb",
28
+ "lib/earworm/fingerprint.rb",
29
+ "lib/earworm/puid.rb",
30
+ "lib/earworm/track.rb",
31
+ "lib/earworm_lib.rb",
32
+ "test/test_earworm.rb"
33
+ ]
34
+ s.homepage = %q{http://github.com/tenderlove/earworm}
35
+ s.rdoc_options = ["--charset=UTF-8"]
36
+ s.require_paths = ["lib"]
37
+ s.rubyforge_project = %q{earworm}
38
+ s.rubygems_version = %q{1.3.4}
39
+ s.summary = %q{What is that song? Earworm uses libofa and MusicDNS to tell you.}
40
+ s.test_files = [
41
+ "test/test_earworm.rb"
42
+ ]
43
+
44
+ if s.respond_to? :specification_version then
45
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
46
+ s.specification_version = 3
47
+
48
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
49
+ s.add_runtime_dependency(%q<icanhasaudio>, [">= 0.1.1"])
50
+ else
51
+ s.add_dependency(%q<icanhasaudio>, [">= 0.1.1"])
52
+ end
53
+ else
54
+ s.add_dependency(%q<icanhasaudio>, [">= 0.1.1"])
55
+ end
56
+ end
@@ -0,0 +1,28 @@
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
+ require 'net/http'
11
+ require 'tempfile'
12
+
13
+ module Earworm
14
+ VERSION = '0.0.2'
15
+ URL = 'http://ofa.musicdns.org/ofa/1/track'
16
+ class << self
17
+ def ofa_version
18
+ major = DL.malloc(DL.sizeof('I'))
19
+ minor = DL.malloc(DL.sizeof('I'))
20
+ rev = DL.malloc(DL.sizeof('I'))
21
+ major.struct!('I', 'val')
22
+ minor.struct!('I', 'val')
23
+ rev.struct!('I', 'val')
24
+ EarwormLib.ofa_get_version(major, minor, rev)
25
+ "#{major['val']}.#{minor['val']}.#{rev['val']}"
26
+ end
27
+ end
28
+ 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,122 @@
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
+
22
+ if @thing.is_a?(IO)
23
+ info = wav_info_for(@thing)
24
+ elsif @thing.is_a?(Tempfile)
25
+ tmpfile = case @thing.content_type
26
+ when /mpeg$/
27
+ @hash['fmt'] = 'mp3'
28
+ begin
29
+ require 'id3lib'
30
+ @hash = @hash.merge(id3_info_for(@thing.path))
31
+ rescue LoadError
32
+ end
33
+ decode_mp3(@thing.path)
34
+ when /ogg$/
35
+ @hash['fmt'] = 'ogg'
36
+ decode_ogg(@thing.path)
37
+ else # Assume its a wav file
38
+ @thing.path
39
+ end
40
+ File.open(tmpfile, 'rb') { |f|
41
+ info = wav_info_for(f)
42
+ }
43
+ else
44
+ tmpfile = case @thing
45
+ when /mp3$/
46
+ @hash['fmt'] = 'mp3'
47
+ begin
48
+ require 'id3lib'
49
+ @hash = @hash.merge(id3_info_for(@thing))
50
+ rescue LoadError
51
+ end
52
+ decode_mp3(@thing)
53
+ when /ogg$/
54
+ @hash['fmt'] = 'ogg'
55
+ decode_ogg(@thing)
56
+ else # Assume its a wav file
57
+ @thing
58
+ end
59
+ File.open(tmpfile, 'rb') { |f|
60
+ info = wav_info_for(f)
61
+ }
62
+ end
63
+ @hash['fpt'] = info[:fpt]
64
+ @hash['dur'] = info[:milliseconds]
65
+ @hash
66
+ end
67
+
68
+ def to_s
69
+ to_hash['fpt']
70
+ end
71
+
72
+ private
73
+ def wav_info_for(io)
74
+ header = io.read(4).unpack('N').first
75
+ raise unless header == Audio::MPEG::Encoder::WAV_ID_RIFF
76
+ info = Audio::MPEG::Encoder.parse_wave_header(io)
77
+ bytes_in_seconds = 135 * info[:in_samplerate] * 2 * info[:num_channels]
78
+ read_bytes =
79
+ if info[:bytes_in_seconds] > bytes_in_seconds
80
+ bytes_in_seconds
81
+ else
82
+ info[:bytes_in_seconds]
83
+ end
84
+
85
+ data = io.read(read_bytes)
86
+ info[:fpt] = EarwormLib.ofa_create_print( data,
87
+ 0,
88
+ read_bytes/2,
89
+ info[:in_samplerate], 1)
90
+ info
91
+ end
92
+
93
+ def id3_info_for(filename)
94
+ tag = ID3Lib::Tag.new(filename)
95
+ {
96
+ 'art' => tag.artist,
97
+ 'ttl' => tag.title,
98
+ 'alb' => tag.album,
99
+ 'tnm' => tag.track[/^(\d+)/],
100
+ 'gnr' => tag.genre,
101
+ 'yrr' => tag.year,
102
+ }
103
+ end
104
+
105
+ {
106
+ 'ogg' => Audio::OGG::Decoder,
107
+ 'mp3' => Audio::MPEG::Decoder,
108
+ }.each do |type,klass|
109
+ define_method(:"decode_#{type}") do |filename|
110
+ reader = klass.new
111
+ name = File.join(Dir::tmpdir,
112
+ "#{File.basename(filename, ".#{type}")}.wav")
113
+ File.open(filename, 'rb') { |input|
114
+ File.open(name, 'wb') { |tmpfile|
115
+ reader.decode(input, tmpfile)
116
+ }
117
+ }
118
+ name
119
+ end
120
+ end
121
+ end
122
+ 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,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jamescallmebrent-earworm
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Aaron Patterson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-07-05 00:00:00 -07:00
13
+ default_executable: earworm
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
+ description: Earworm can identify unknown music using MusicDNS and libofa.
26
+ email: aaronp@rubyforge.org
27
+ executables:
28
+ - earworm
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.txt
33
+ files:
34
+ - .gitignore
35
+ - History.txt
36
+ - Manifest.txt
37
+ - README.txt
38
+ - Rakefile
39
+ - VERSION
40
+ - bin/earworm
41
+ - earworm.gemspec
42
+ - lib/earworm.rb
43
+ - lib/earworm/client.rb
44
+ - lib/earworm/fingerprint.rb
45
+ - lib/earworm/puid.rb
46
+ - lib/earworm/track.rb
47
+ - lib/earworm_lib.rb
48
+ - test/test_earworm.rb
49
+ has_rdoc: false
50
+ homepage: http://github.com/tenderlove/earworm
51
+ post_install_message:
52
+ rdoc_options:
53
+ - --charset=UTF-8
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ requirements: []
69
+
70
+ rubyforge_project: earworm
71
+ rubygems_version: 1.2.0
72
+ signing_key:
73
+ specification_version: 3
74
+ summary: What is that song? Earworm uses libofa and MusicDNS to tell you.
75
+ test_files:
76
+ - test/test_earworm.rb