isrc 1.0.2 → 1.0.3

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.
Files changed (5) hide show
  1. checksums.yaml +5 -13
  2. data/lib/isrc.rb +124 -71
  3. data/lib/isrc/version.rb +1 -1
  4. data/spec/isrc_spec.rb +26 -8
  5. metadata +17 -17
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- NjRhOTMyZWJiMzZiNjg5YzVjYTNjNTgzYzk5MTZjMjEyOGM4Njc3Mg==
5
- data.tar.gz: !binary |-
6
- ZmRiYTg5YWQzYTg4OWIzNzU5NDI3YTU5YmQ3OTA5MWVmZWZlMDRkNg==
2
+ SHA1:
3
+ metadata.gz: bd97834b5c09da196ffc4e68c34b6be56cc63ed7
4
+ data.tar.gz: 0159b3fe894a23048a316f50818e3dc83b6fdc97
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- NTk2NDcwMjBlYzIxMmRiM2FjODY0MzNmNGJkODBjZGExYzY3MzJhNjNlNTUx
10
- OGRlMWU3ZTE5MjM3OWNhNWY0ODJlNDYwNWMyOTU4MTNmNmViMjRkZTRhYTQ2
11
- OTIwMTc2YWRiMDJhZjE1NzI0MDU2MTk1OWJmYzhiODNmODMzNTc=
12
- data.tar.gz: !binary |-
13
- YTZiMmFmMDkxNTQ5OWVlNGE0NGJlNmE5ZjUzMzlkNzJlMzRiNTJlYTk4MjM1
14
- MWNhYzIxYTc5NTFjZGZlNmJhYzg3NWJkNjE5Y2E2NTkwMDUxMmFlNGYzYmYx
15
- NDc3OGI1N2NjYmUxYTI0MTdjZDA0NDhlOTBlZTAzYmUwMzBjMzU=
6
+ metadata.gz: da759b2fdeb7f8e97e593002ca9ab2c3aa2f9cfff4f12b68614e1c6a4384c499dc7df87458a8862856dbef0ba8791ef55a0a6b92825fd2a095700e5cbd1184cd
7
+ data.tar.gz: a1c1f55955dbcacca8d21f4c0adadfe179395a478370f3522dfa1e284dba66712b0104d62f0fa31a006e723be055d841a93a53dad5111760d3bc2c1cd583f49a
@@ -9,86 +9,57 @@ module ISRC
9
9
  PPLUK_SESSION_GRAB_URL = 'http://repsearch.ppluk.com/ARSWeb/appmanager/ARS/main'
10
10
  PPLUK_AJAX_SEARCH_URL = 'http://repsearch.ppluk.com/ARSWeb/block/send-receive-updates'
11
11
 
12
+ def self.configure(&block)
13
+ ISRC::Configuration.instance_eval(&block)
14
+ end
15
+
12
16
  class PPLUK
13
17
  def retrieve(opts)
14
- # default options
15
- opts = { :title_size => 2 }.merge(opts)
18
+ # NOTE the online search is a bit funky: adding more to the search make the results worse
19
+ # trying out a three word limit
16
20
 
17
- agent = Mechanize.new
18
- agent.log = Logger.new "mech.log"
19
- agent.user_agent_alias = 'Mac Safari'
21
+ pieces = self.extract_song_peices(opts[:title])
20
22
 
21
- isrc_session_init = agent.get PPLUK_SESSION_GRAB_URL
22
- view_state = self.extract_view_state(isrc_session_init.body)
23
- ice_session, ice_session_count = self.extract_ice_session(isrc_session_init.body)
23
+ # try the first two pieces at first
24
24
 
25
- # add the ice_sessions cookie
26
- ice_cookie = Mechanize::Cookie.new('ice.sessions', "#{ice_session}##{ice_session_count}")
27
- ice_cookie.path = "/"
28
- ice_cookie.domain = "repsearch.ppluk.com"
29
- agent.cookie_jar.add!(ice_cookie)
25
+ # if the song is only one word, submit request with on processing
26
+ if pieces[:all].size == 1
27
+ @matches = self.request(opts)
28
+ elsif pieces[:all].size > 1
29
+ # let's try increasing the number of pieces, starting from 2
30
+ pieces_count = 1
30
31
 
31
- # NOTE the online search is a bit funky: adding more to the search make the results worse
32
- # trying out a three word limit
32
+ begin
33
+ pieces_count += 1
33
34
 
34
- title_pieces = extract_song_peices(opts[:title])
35
- shortened_title = title_pieces.slice(0, [opts[:title_size], title_pieces.size].min).join(' ')
36
-
37
- # puts "Title: #{shortened_title}\nArtist: #{opts[:artist]}"
38
-
39
- begin
40
- isrc_search = agent.post PPLUK_AJAX_SEARCH_URL, {
41
- 'ice.submit.partial' => 'false',
42
- # 'ice.event.target' => 'T400335881332330323192:ars_form:search_button',
43
- # 'ice.event.captured' => 'T400335881332330323192:ars_form:search_button',
44
- # 'ice.event.type' => 'onclick',
45
- # 'ice.event.alt' => 'false',
46
- # 'ice.event.ctrl' => 'false',
47
- # 'ice.event.shift' => 'false',
48
- # 'ice.event.meta' => 'false',
49
- # 'ice.event.x' => '47',
50
- # 'ice.event.y' => '65',
51
- # 'ice.event.left' => 'false',
52
- # 'ice.event.right' => 'false',
53
- 'T5000782701386267377497:ars_form:search_button' => 'Search',
54
- 'T5000782701386267377497:ars_form:isrc_code' => '',
55
- 'T5000782701386267377497:ars_form:rec_title_idx' => '',
56
- 'T5000782701386267377497:ars_form:rec_title' => shortened_title,
57
- 'T5000782701386267377497:ars_form:rec_band_artist_idx' => '',
58
- 'T5000782701386267377497:ars_form:rec_band_artist' => opts[:artist],
59
- 'javax.faces.RenderKitId' => 'ICEfacesRenderKit',
60
- 'javax.faces.ViewState' => view_state,
61
- 'icefacesCssUpdates' => '',
62
- 'T5000782701386267377497:ars_form' => '',
63
- 'ice.session' => ice_session,
64
- 'ice.view' => view_state,
65
- 'ice.focus' => '',
66
-
67
- # the rand is 19 characters long in the browser's HTTP requests
68
- 'rand' => sprintf('%1.17f', rand)
69
- }
70
- rescue Mechanize::ResponseCodeError => e
71
- agent.log.error "Error submitting AJAX request: #{e.page.body}"
72
- end
35
+ shortened_title = pieces[:all].slice(0, pieces_count).join(' ')
73
36
 
74
- # creates an array representation of the table:
75
- # artist, title, isrc, rights holder, released, time
76
- isrc_html = Nokogiri::HTML(isrc_search.body)
77
- @matches = isrc_html.css("table[id='T5000782701386267377497:ars_form:searchResultsTable'] tbody tr").map do |m|
78
- columns = m.css('td')
37
+ @matches = self.request({
38
+ title: shortened_title,
39
+ artist: opts[:artist]
40
+ })
41
+ end while @matches.empty? && pieces[:all].size > pieces_count + 1
79
42
 
80
- # if there is no ISRC don't bother looking
81
- next if columns[2] == 'Not Supplied'
43
+ # given 'Surrender [Original Mix]' the above algorithm will submit the entire title
44
+ # if that didn't work, strip out all meta elements and try greatest to least number of song pieces
82
45
 
83
- # zero length music wont be used
84
- next if columns[-1] == '0:00sec'
46
+ # TODO we shouldn't allow one letter or two letter title requests
47
+ # TODO remove stop words
48
+ # TODO detect when meta == title pieces
85
49
 
86
- columns.map &:text
87
- end
50
+ pieces_count = pieces[:title].size
51
+
52
+ while @matches.empty? && pieces_count > 0
53
+ shortened_title = pieces[:title].slice(0, pieces_count).join(' ')
54
+
55
+ @matches = self.request({
56
+ title: shortened_title,
57
+ artist: opts[:artist]
58
+ })
59
+
60
+ pieces_count -= 1
61
+ end
88
62
 
89
- # if the shortened title did not work, try making it longer
90
- if @matches.empty? && opts[:title_size] < title_pieces.size
91
- self.retrieve(opts.merge({:title_size => opts[:title_size] + 1}))
92
63
  end
93
64
  end
94
65
 
@@ -132,9 +103,20 @@ module ISRC
132
103
 
133
104
  protected
134
105
  def extract_song_peices(title)
135
- title_pieces = title.split(/(\([^)]+\)|\[[^\]]+\])/).reject { |s| s.strip.empty? }
136
- title_pieces[0] = title_pieces[0].split(' ')
137
- title_pieces.flatten
106
+ # this splits a song title into peices:
107
+ # * 'bracket' peice (meta)
108
+ # * 'parenthesis' peice (meta)
109
+ # * song words (title)
110
+
111
+ all_pieces = title.split(/(\([^)]+\)|\[[^\]]+\])/).reject { |s| s.strip.empty? }
112
+ title_pieces = all_pieces.shift.split(' ')
113
+ meta_pieces = all_pieces
114
+
115
+ {
116
+ all: [title_pieces, meta_pieces].flatten,
117
+ meta: meta_pieces,
118
+ title: title_pieces
119
+ }
138
120
  end
139
121
 
140
122
  def extract_view_state(body)
@@ -151,5 +133,76 @@ module ISRC
151
133
  minutes.to_i * 60 + seconds.to_i
152
134
  end
153
135
 
136
+ def request(opts = {})
137
+ puts "Title: #{opts[:title]}\nArtist: #{opts[:artist]}"
138
+
139
+ agent = Mechanize.new
140
+ # TODO log path needs to be configurable
141
+ agent.log = Logger.new "mech.log"
142
+ agent.user_agent_alias = 'Mac Safari'
143
+
144
+ # grab the main page HTML to pull session vars to make the AJAX request
145
+ isrc_session_init = agent.get(PPLUK_SESSION_GRAB_URL)
146
+ view_state = self.extract_view_state(isrc_session_init.body)
147
+ ice_session, ice_session_count = self.extract_ice_session(isrc_session_init.body)
148
+
149
+ # add the ice_sessions cookie for the AJAX search request
150
+ ice_cookie = Mechanize::Cookie.new('ice.sessions', "#{ice_session}##{ice_session_count}")
151
+ ice_cookie.path = "/"
152
+ ice_cookie.domain = "repsearch.ppluk.com"
153
+ agent.cookie_jar.add!(ice_cookie)
154
+
155
+ begin
156
+ isrc_search = agent.post PPLUK_AJAX_SEARCH_URL, {
157
+ 'ice.submit.partial' => 'false',
158
+ # 'ice.event.target' => 'T400335881332330323192:ars_form:search_button',
159
+ # 'ice.event.captured' => 'T400335881332330323192:ars_form:search_button',
160
+ # 'ice.event.type' => 'onclick',
161
+ # 'ice.event.alt' => 'false',
162
+ # 'ice.event.ctrl' => 'false',
163
+ # 'ice.event.shift' => 'false',
164
+ # 'ice.event.meta' => 'false',
165
+ # 'ice.event.x' => '47',
166
+ # 'ice.event.y' => '65',
167
+ # 'ice.event.left' => 'false',
168
+ # 'ice.event.right' => 'false',
169
+ 'T5000782701386267377497:ars_form:search_button' => 'Search',
170
+ 'T5000782701386267377497:ars_form:isrc_code' => '',
171
+ 'T5000782701386267377497:ars_form:rec_title_idx' => '',
172
+ 'T5000782701386267377497:ars_form:rec_title' => opts[:title],
173
+ 'T5000782701386267377497:ars_form:rec_band_artist_idx' => '',
174
+ 'T5000782701386267377497:ars_form:rec_band_artist' => opts[:artist],
175
+ 'javax.faces.RenderKitId' => 'ICEfacesRenderKit',
176
+ 'javax.faces.ViewState' => view_state,
177
+ 'icefacesCssUpdates' => '',
178
+ 'T5000782701386267377497:ars_form' => '',
179
+ 'ice.session' => ice_session,
180
+ 'ice.view' => view_state,
181
+ 'ice.focus' => '',
182
+
183
+ # the rand is 19 characters long in the browser's HTTP requests
184
+ 'rand' => sprintf('%1.17f', rand)
185
+ }
186
+ rescue Mechanize::ResponseCodeError => e
187
+ agent.log.error "Error submitting AJAX request: #{e.page.body}"
188
+ end
189
+
190
+ # creates an array representation of the table:
191
+ # artist, title, isrc, rights holder, released, time
192
+
193
+ isrc_table = Nokogiri::HTML(isrc_search.body).css("table[id='T5000782701386267377497:ars_form:searchResultsTable'] tbody tr")
194
+ isrc_table.map do |m|
195
+ columns = m.css('td')
196
+
197
+ # if there is no ISRC don't bother looking
198
+ next if columns[2] == 'Not Supplied'
199
+
200
+ # zero length music wont be used
201
+ next if columns[-1] == '0:00sec'
202
+
203
+ columns.map &:text
204
+ end
205
+ end
206
+
154
207
  end
155
208
  end
@@ -1,3 +1,3 @@
1
1
  module ISRC
2
- VERSION = "1.0.2"
2
+ VERSION = "1.0.3"
3
3
  end
@@ -29,6 +29,16 @@ describe ISRC do
29
29
  # however, the length delta is huge
30
30
  end
31
31
 
32
+ it "handles results with brackets" do
33
+ isrc.retrieve artist: 'Curiosity Killed The Cat', title: 'Down to Earth'
34
+ isrc.match(time:'03:54')[:isrc].should == 'GBF088600037'
35
+ end
36
+
37
+ it 'handles a mixed version of a song when there is not a mixed version listed' do
38
+ isrc.retrieve artist:'Kings of Leon', title: 'Use Somebody (Chew Fu Festival Fix)'
39
+ isrc.match(time:'5:37')[:isrc].should == 'USRC10800301'
40
+ end
41
+
32
42
  it "handles edge cases that don't make sense" do
33
43
  isrc.retrieve artist:'Toni Braxton', title:'Youre Making me High'
34
44
  isrc.match(time:'4:12')[:isrc].should == 'USLF29600183'
@@ -49,17 +59,22 @@ describe ISRC do
49
59
  end
50
60
 
51
61
  context "song title processing" do
52
- it "should handle bracket mixes" do
53
- pieces = isrc.send(:extract_song_peices, "Surrender [Original Mix]")
54
- pieces.size.should == 2
55
- pieces.last.should == "[Original Mix]"
62
+ context 'of brackets' do
63
+ it "should parse them correctly with a one word song" do
64
+ pieces = isrc.send(:extract_song_peices, "Surrender [Original Mix]")
65
+ pieces[:all].size.should == 2
66
+ pieces[:all].last.should == "[Original Mix]"
67
+ pieces[:meta].size.should == 1
68
+ end
56
69
  end
57
70
 
58
71
  context 'of parenthesis' do
59
72
  it "should count parenthesis as a single song peice" do
60
73
  pieces = isrc.send(:extract_song_peices, "Want Me (Like Water) (New Vocal Mix No 1)")
61
- pieces.size.should == 4
62
- pieces.last.should == '(New Vocal Mix No 1)'
74
+ pieces[:all].size.should == 4
75
+ pieces[:all].last.should == '(New Vocal Mix No 1)'
76
+ pieces[:meta].size.should == 2
77
+ pieces[:title].size.should == 2
63
78
  end
64
79
 
65
80
  it "should handle a single word song with parenthesis" do
@@ -70,13 +85,16 @@ describe ISRC do
70
85
  isrc.retrieve artist:'Frank Sinatra', title: 'Chicago (Digitally Remastered)'
71
86
  isrc.match(time:'2:14')[:isrc].should == 'USCA20300966'
72
87
  # or USCA29800388; they are basically the same
88
+
89
+ # Bagatelle in A minor, WoO 59 -`Für Elise` by Bella Davidovich...
73
90
  end
74
91
  end
75
92
 
76
93
  it "should handle a standard multi-word title" do
77
94
  pieces = isrc.send(:extract_song_peices, "Take Your Time")
78
- pieces.size.should == 3
79
- pieces.last.should == "Time"
95
+ pieces[:all].size.should == 3
96
+ pieces[:title].size.should == 3
97
+ pieces[:title].last.should == "Time"
80
98
  end
81
99
 
82
100
  end
metadata CHANGED
@@ -1,83 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: isrc
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Bianco
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-27 00:00:00.000000000 Z
11
+ date: 2014-03-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ! '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ! '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: nokogiri
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ! '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ! '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: mechanize
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ! '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ! '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ! '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ! '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: guard
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ! '>='
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ! '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  description: Pull ISRC codes from PPLK UK's database
@@ -87,8 +87,8 @@ executables: []
87
87
  extensions: []
88
88
  extra_rdoc_files: []
89
89
  files:
90
- - .gitignore
91
- - .rspec
90
+ - ".gitignore"
91
+ - ".rspec"
92
92
  - Gemfile
93
93
  - Guardfile
94
94
  - LICENSE
@@ -110,17 +110,17 @@ require_paths:
110
110
  - lib
111
111
  required_ruby_version: !ruby/object:Gem::Requirement
112
112
  requirements:
113
- - - ! '>='
113
+ - - ">="
114
114
  - !ruby/object:Gem::Version
115
115
  version: '0'
116
116
  required_rubygems_version: !ruby/object:Gem::Requirement
117
117
  requirements:
118
- - - ! '>='
118
+ - - ">="
119
119
  - !ruby/object:Gem::Version
120
120
  version: '0'
121
121
  requirements: []
122
122
  rubyforge_project:
123
- rubygems_version: 2.1.11
123
+ rubygems_version: 2.2.0
124
124
  signing_key:
125
125
  specification_version: 4
126
126
  summary: Pull ISRC codes from PPLK UK's database