under_fire 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bb1de4137e3e56a58f163f7410cd950f0c9353be
4
- data.tar.gz: 86cc6bc36b6ae0b03d190627e7efdbbdfa37cd27
3
+ metadata.gz: 5e1d93ad915cfe697878585aedf307b541a00865
4
+ data.tar.gz: d1cda0cfee2c6b7ef2e661de7a2c2405b543d438
5
5
  SHA512:
6
- metadata.gz: cf75d52b9dc93330343d74dd287bf48d39a86a2af86045ecd7bfc6417d1bc68f7819b754735ba9b177114583c4cc121c80b39d96dfff5880e2e7307e1c6bf13a
7
- data.tar.gz: e1ec64051f8a67670dbf316495e8db128338d098943e73edb5cc7bef784812e58142450e799c27d613e0887496cf147f14a1be1d78932e42a72f91d8be13f39e
6
+ metadata.gz: f56978420c9b2efca82e1525d927f5247deb5781ab3751454e0148386314fd709290686a1f6c0cd90c13f59c4291d9c27b62d5303f30642ae21410a52ab47e8c
7
+ data.tar.gz: 2f4f939608621eb84705b0acdad307c0dc1c89280f1fbb2bd22db730e262148684447609b5d268940b9d8e44795f60b40f129a3086a5b20de3aa0865c99d685f
data/.ackrc ADDED
@@ -0,0 +1 @@
1
+ --type=ruby
data/Changelog ADDED
@@ -0,0 +1,2 @@
1
+ * Extracted toc_reader to its own gem (cdtoc).
2
+
data/README.md CHANGED
@@ -1,3 +1,144 @@
1
1
  # UnderFire
2
2
 
3
- Wraps Gracenote's API in Ruby goodness. Still under development.
3
+ Wraps Gracenote's Web API in Ruby goodness. UnderFire provides two interfaces: a client to use from your projects and a command line interface.
4
+
5
+ ## Installation
6
+
7
+ ```ruby
8
+ gem install under_fire
9
+ ```
10
+ or in your gemfile:
11
+
12
+ ```ruby
13
+ gem 'under_fire'
14
+
15
+ ```
16
+ ## Registration
17
+
18
+ Before using UnderFire, you need to obtain a `client_id` and `user_id` from Gracenote as described below.
19
+
20
+ ### Obtain client_id
21
+
22
+ -To obtain a client_id, visit http://developer.gracenote.com and register yourself for a developer account. Once your account is created, go to "My Apps" and create a new app. Finaly, open your new app from your My Apps page to obtain your "Client ID for Mobile Client, Web API, and eyeQ".
23
+
24
+ -Now on your computer you need to add your `client_id` to your environment. On OSX or Linux you can do this by adding the following line to your `.bashrc`, `.zshrc` or wherever you prefer to set your environment variables:
25
+
26
+ ```shell
27
+ export GRACENOTE_CLIENT_ID=your-client_id-here
28
+
29
+ ```
30
+ After doing this, open a new terminal or type the following at the command prompt:
31
+
32
+ ```
33
+ source ~/.bashrc
34
+
35
+ ```
36
+ or
37
+
38
+ ```
39
+ source ~/.zshrc
40
+
41
+ ```
42
+
43
+ To test this out type the following in your terinal:
44
+
45
+ ```
46
+ echo $GRACENOTE_CLIENT_ID
47
+
48
+ ```
49
+
50
+ ### Obtain user_id
51
+
52
+ -Now you're ready to use UnderFire's register task to obtain your `user_id`. At the command prompt, type:
53
+
54
+ ```
55
+ under-fire register -c `echo $GRACENOTE_CLIENT_ID`
56
+
57
+ ```
58
+ Copy your `user_id` from the output and add to your environment by entering the folloing in your `.bashrc` or `.zshrc` as you did with your `client_id` above:
59
+
60
+ ```shell
61
+ export GRACENOTE_USER_ID=your-user_id-here
62
+
63
+ ```
64
+ Once again, ensure that your current environment is up to date by opening a new terminal or sourcing the appropriate config file.
65
+
66
+ Now you're ready to get started.
67
+
68
+ ## Usage
69
+
70
+ ### Command line
71
+
72
+ UnderFire provides a command line interface (CLI) that makes it easy to explore the Gracenote Web API or combine with other UNIX tools in shell scripts. If you followed the registration instructions above, you've already used the CLI's registration task.
73
+
74
+ Here are some other things you can do:
75
+
76
+ Look up the album called "Armed Forces":
77
+
78
+ ```
79
+ under-fire album -t "Armed Forces"
80
+
81
+ ```
82
+
83
+
84
+ Look up "Armed Forces", fetch its cover art, and save it as "armed-forces.jpg in the current folder:
85
+
86
+ ```
87
+ under-fire album -t "Armed Forces" | grep url | awk '{ print $2 }' | xargs under-fire cover -f "armed-forces.jpg" -u
88
+
89
+ ```
90
+ For more information:
91
+
92
+ ```
93
+ under-fire -h
94
+
95
+ ```
96
+ If you want to search by a cd's table of contents, you need to provide the offset for each track on a given CD. To make things easy, I wrote a little gem called `cdtoc`. Just install this in the usual way:
97
+
98
+ ```
99
+ gem install cdtoc
100
+
101
+ ```
102
+
103
+ Then:
104
+
105
+ ```
106
+ $ cdtoc | xargs under-fire -o
107
+
108
+ ```
109
+
110
+ ### Programming API
111
+
112
+ If you're familiar with the Gracenote API, you'll note that I have renamed the commands to make it easier to differentiate between them and to stay with idiomatic Ruby. So, for example, Gracenote's "ALBUM_SEARCH" is called `find_album`.
113
+
114
+ All requests, with the exception of `fetch_cover`, return an APIResponse class, which provides `to_h` and `to_s` methods. You will probably find the `to_h` method most convenient.
115
+
116
+ ```ruby
117
+
118
+ require 'under_fire/client'
119
+
120
+ # First, get a client instance
121
+ client = UnderFire::Client.new
122
+
123
+ # Search by track title
124
+ client.find_album(:track_title => 'Paranoid Android')
125
+
126
+ # or use either SINGLE_BEST or SINGLE_BEST_COVER
127
+ # SINGLE_BEST: returns the single best result as decided by Gracenote.
128
+ # SINGLE_BEST_COVER: same as above, but also returns cover URL. Currently this is the default.
129
+
130
+ album = client.find_album(:track_title => 'Paranoid Android', :mode => 'SINGLE_BEST')
131
+
132
+ # use query response to fetch the album cover.
133
+ client.fetch_cover(album, "OK_Computer_cover.jpg")
134
+
135
+ # The following searches by Gracenote album id or track id:
136
+ album = client.fetch_album(:gn_id => '86372321-2C7F28ADC369EB90E53A7F6CA3A70D56')
137
+
138
+ # If you want to limit your response to one album, use one of the two modes described above.
139
+
140
+ ```
141
+
142
+ ## Roadmap
143
+
144
+ More convenient APIResponse class that wraps artists and albums in their own classes.
@@ -7,7 +7,7 @@ module UnderFire
7
7
  # @see https://developer.gracenote.com/sites/default/files/web/html/index.html#Music%20Web%20API/ALBUM_FETCH.html#_Toc344907262
8
8
  #
9
9
  # @example
10
- # search = UnderFire::Album_Fetch.new(:gn_id => '86372321-2C7F28ADC369EB90E53A7F6CA3A70D56')
10
+ # search = UnderFire::Album_Fetch.new(:gn_id => '86372321-2C7F28ADC369EB90E53A7F6CA3A70D56')
11
11
  # search.query => Response = The Beatles, Help!
12
12
  class AlbumFetch < BaseQuery
13
13
  # @return [String] XML string for query.
@@ -18,30 +18,30 @@ module UnderFire
18
18
 
19
19
  # @return [String] Gracenote ID for album
20
20
  attr_accessor :gn_id
21
-
21
+
22
22
  # Requires album :gn_id or track :gn_id
23
23
  #
24
24
  # @param [Hash] args the arguments for Album_Fetch
25
25
  # @option args [String] :gn_id Gracenote ID of album or track
26
- # @option args [String] :mode Either 'SINGLE_BEST' or 'SINGLE_BEST_COVER'
26
+ # @option args [String] :mode Either 'SINGLE_BEST' or 'SINGLE_BEST_COVER'
27
27
  # (Only needed if track :gn_id used)
28
28
  def initialize(args)
29
29
  super args
30
30
  @parameters = args.reject {|k,v| k == :mode}
31
31
  parameters.each do |k,v| send("#{k}=", v) end
32
- @query = build_query
32
+ @query = build_query
33
33
  end
34
-
34
+
35
35
  # Builds ALBUM_FETCH-specific part of ALBUM_FETCH query and adds it to the base query
36
36
  # common to all query types. Called by constructor.
37
37
  #
38
38
  # @return [String] XML string for ALBUM_FETCH query.
39
39
  def build_query
40
40
  build_base_query do |builder|
41
- builder.query(cmd: "ALBUM_FETCH"){
42
- builder.mode "SINGLE_BEST_COVER"
41
+ builder.QUERY(cmd: "ALBUM_FETCH"){
42
+ builder.MODE "SINGLE_BEST_COVER"
43
43
  parameters.each do |k,v|
44
- builder.gn_id gn_id
44
+ builder.GN_ID gn_id
45
45
  end
46
46
  }
47
47
  end
@@ -2,20 +2,20 @@ require 'under_fire/base_query'
2
2
  require 'builder'
3
3
 
4
4
  module UnderFire
5
- # Builds XML for Gracenote's ALBUM_SEARCH query.
5
+ # Builds XML for Gracenote's ALBUM_SEARCH query.
6
6
  #
7
7
  # @see https://developer.gracenote.com/sites/default/files/web/html/index.html#Music%20Web%20API/ALBUM_SEARCH.html#_Toc344907249
8
- #
8
+ #
9
9
  # @example
10
10
  # search = UnderFire::AlbumSearch.new(:artist => 'Radiohead')
11
11
  # search.query #=> XML for Gracenote ALBUM_SEARCH query for albums by Radiohead.
12
- #
12
+ #
13
13
  # search = UnderFire::AlbumSearch.new(:track_title = > 'Paranoid Android',
14
14
  # :artist => 'Radiohead',
15
15
  # :mode => 'SINGLE_BEST_COVER')
16
- # search.query #=> XML for ALBUM_SEARCH
17
- #
18
- #
16
+ # search.query #=> XML for ALBUM_SEARCH
17
+ #
18
+ #
19
19
  class AlbumSearch < BaseQuery
20
20
  # @return [String] XML string for query.
21
21
  attr_reader :query
@@ -28,12 +28,12 @@ module UnderFire
28
28
 
29
29
  # @return [String]
30
30
  attr_accessor :track_title
31
-
31
+
32
32
  # @return [String]
33
33
  attr_accessor :album_title
34
-
34
+
35
35
  # At least one of :artist, :track_title, :album_title is required (:mode is optional).
36
- #
36
+ #
37
37
  # @param [Hash] args the arguments for an Album_Search.
38
38
  # @option args [String] :artist Name of the artist.
39
39
  # @option args [String] :track_title Name of the song/track.
@@ -52,10 +52,10 @@ module UnderFire
52
52
  # @return [String] XML string for ALBUM_SEARCH query.
53
53
  def build_query
54
54
  build_base_query do |builder|
55
- builder.query(cmd: "ALBUM_SEARCH"){
56
- builder.mode "SINGLE_BEST_COVER"
55
+ builder.QUERY(CMD: "ALBUM_SEARCH"){
56
+ builder.MODE "SINGLE_BEST_COVER"
57
57
  parameters.each do |k,v|
58
- builder.text(v, type: k.to_s.upcase)
58
+ builder.TEXT(v, TYPE: k.to_s.upcase)
59
59
  end
60
60
  }
61
61
  end
@@ -12,12 +12,12 @@ module UnderFire
12
12
  class AlbumTOCSearch < BaseQuery
13
13
  # @return [String] CD Table of contents.
14
14
  attr_reader :toc
15
-
15
+
16
16
  # @return [String] XML string for ALBUM_TOC query.
17
17
  attr_reader :query
18
18
 
19
19
  # :toc is required (:mode is optional).
20
- #
20
+ #
21
21
  # @param [Hash] args arguments to create an ALBUM_TOC query.
22
22
  # @option [String] :toc CD table of contents (space-separated list of track start frames)
23
23
  # @option [String] :mode Either 'SINGLE_BEST' or 'SINGLE_BEST_COVER'
@@ -33,10 +33,10 @@ module UnderFire
33
33
  # @return [String] XML string for ALBUM_TOC query.
34
34
  def build_query
35
35
  build_base_query do |builder|
36
- builder.query(cmd: "ALBUM_TOC"){
37
- builder.mode mode
38
- builder.toc {
39
- builder.offsets toc
36
+ builder.QUERY(CMD: "ALBUM_TOC"){
37
+ builder.MODE mode
38
+ builder.TOC {
39
+ builder.OFFSETS toc.to_s
40
40
  }
41
41
  }
42
42
  end
@@ -26,9 +26,9 @@ module UnderFire
26
26
  req.body = query
27
27
  req['Content-Type'] = 'application/xml'
28
28
  res = http.request(req)
29
- res
29
+ res
30
30
  end
31
-
31
+
32
32
  # @param [String] url URL that points to file.
33
33
  # @param [String] filename Filename and path for saving downloaded file.
34
34
  def self.get_file(url, filename)
@@ -36,7 +36,7 @@ module UnderFire
36
36
 
37
37
  Net::HTTP.start(uri.host, uri.port) do |http|
38
38
  request = Net::HTTP::Get.new uri
39
-
39
+
40
40
  http.request request do |response|
41
41
  open filename, 'w' do |io|
42
42
  response.read_body do |chunk|
@@ -5,12 +5,12 @@ module UnderFire
5
5
  class APIResponse
6
6
  # @return [Hash] Response as Hash.
7
7
  attr_reader :response
8
-
8
+
9
9
  # @param [String] response XML string.
10
10
  def initialize(response)
11
11
  @response = parse_response(response)
12
12
  end
13
-
13
+
14
14
  # @return [Hash] Hash representation of response.
15
15
  def to_h
16
16
  response[:responses]
@@ -26,8 +26,8 @@ module UnderFire
26
26
  response[:responses][:response][:@status] == 'OK'
27
27
  end
28
28
 
29
- private
30
-
29
+ private
30
+
31
31
  # Recursively walks nested hash structure to return string representation.
32
32
  # @return [String] Flat string representation of nest Hash.
33
33
  def recursive_to_s(hash)
@@ -6,23 +6,27 @@ module UnderFire
6
6
  class BaseQuery
7
7
  # @return [String]
8
8
  attr_reader :mode
9
-
9
+
10
+ # @return [UnderFire::Configuration]
11
+ attr_reader :config
12
+
10
13
  # @param [String] mode Either 'SINGLE_BEST' or 'SINGLE_BEST_COVER' (defaults to 'SINGLE_BEST_COVER').
11
14
  def initialize(mode="SINGLE_BEST_COVER")
12
15
  @mode = mode || "SINGLE_BEST_COVER"
16
+ @config = Configuration.instance
13
17
  end
14
18
 
15
19
  # @yield [Builder] builder object used by subclass's build_query method.
16
20
  def build_base_query(&block)
17
21
  builder = Builder::XmlMarkup.new
18
- builder.queries {
19
- builder.auth {
20
- builder.client Configuration.client_id
21
- builder.user Configuration.user_id
22
+ builder.QUERIES {
23
+ builder.AUTH {
24
+ builder.CLIENT config.client_id
25
+ builder.USER config.user_id
22
26
  }
23
- builder.lang "eng"
24
- builder.country "canada"
25
- builder.app_info %Q{app="under-fire #{VERSION}", os="#{RUBY_PLATFORM}"}
27
+ builder.LANG "eng"
28
+ builder.COUNTRY "canada"
29
+ builder.APP_INFO %Q{APP="under-fire #{VERSION}", OS="#{RUBY_PLATFORM}"}
26
30
  yield builder
27
31
  }
28
32
  end
@@ -1,25 +1,28 @@
1
1
  require 'thor'
2
2
  require 'under_fire/api_request'
3
- require 'under_fire/api_response'
4
- require 'under_fire/album_toc_search'
5
- require 'under_fire/album_search'
6
- require 'under_fire/toc_reader'
3
+ require 'under_fire/client'
7
4
 
8
5
  module UnderFire
9
6
  # Command Line interface
10
7
  class CLI < Thor
11
8
  include UnderFire
12
9
 
10
+ attr_reader :config, :client
11
+
13
12
  def initialize(*)
14
13
  super
14
+ @config = Configuration.instance
15
+ @client = Client.new()
15
16
  end
16
17
 
17
- desc "toc", "Uses `discid` to get a CD's table of contents and then " +
18
- "uses the TOC to query Gracenote for album information."
18
+ desc "toc", "Use provided offsets to query Gracenote for album information."
19
+ method_option :offsets,
20
+ :aliases => '-o',
21
+ :desc => "Specify cd table of contents offsets",
22
+ :required => true,
23
+ :type => :array
19
24
  def toc
20
- search = AlbumTOCSearch.new(:toc => TOCReader.read)
21
- response = APIRequest.post(search.query, Configuration.api_url)
22
- say APIResponse.new(response.body).to_s
25
+ say client.find_by_toc(options[:offsets])
23
26
  end
24
27
 
25
28
  desc "album", "Queries Gracenote with album <title>, <song> title, or <artist> name"
@@ -36,31 +39,47 @@ module UnderFire
36
39
  :desc => "Specify artist name",
37
40
  :required => false
38
41
  def album
39
- search = AlbumSearch.new(options)
40
- request = APIRequest.post(search.query, Configuration.api_url)
41
- say APIResponse.new(request.body).to_s
42
+ say client.find_album(options)
42
43
  end
43
-
44
- desc "id", "Fetches album info using given Gracenote ID."
45
- method_option :gn_id, :aliases => ['-i', '--id'], :required => true,
44
+
45
+ desc "id", "Not yet implemented"
46
+ method_option :gn_id,
47
+ :aliases => ['-i', '--id'],
48
+ :required => true,
46
49
  :desc => "Gracenote album or song GN_ID"
47
50
  def id
48
- search = AlbumFetch.new(options)
49
- request = APIRequest.post(search.query, Configuration.api_url)
50
- say APIResponse.new(request.body).to_s
51
- end
51
+ puts "Not implemented"
52
+ end
52
53
 
53
54
  desc "cover", "Gets cover from Gracenote."
54
- method_option :url, :aliases => '-u', :required => true,
55
+ method_option :url,
56
+ :aliases => '-u',
57
+ :required => true,
55
58
  :desc => "URL provided by Gracenote for downloading cover image."
56
- method_option :file_name, :aliases => '-f', :required => false,
57
- :desc => "File name for saving image."
59
+ method_option :file_name,
60
+ :aliases => '-f',
61
+ :required => false,
62
+ :desc => "File name for saving image.",
63
+ :default => ""
64
+ method_option :verbose,
65
+ :aliases => '-v',
66
+ :type => :boolean,
67
+ :required => false,
68
+ :default => false
58
69
  def cover
59
- say "Fetching cover"
70
+ say "Fetching cover" if options[:verbose]
60
71
  url = options[:url]
61
72
  file_name = options[:file_name].empty? ? "cover.jpg" : options[:file_name]
62
73
  APIRequest.get_file(url, file_name)
63
- say "saved #{file_name} in #{File.dirname __FILE__}"
74
+ say "saved #{file_name} in #{File.dirname __FILE__}" if options[:verbose]
75
+ end
76
+
77
+ desc "register", "Registers user with client_id."
78
+ method_option :client_id,
79
+ :aliases => '-c',
80
+ :required => true
81
+ def register
82
+ say client.register(options[:client_id])
64
83
  end
65
84
  end
66
85
  end
@@ -4,7 +4,6 @@ require 'under_fire/album_fetch'
4
4
  require 'under_fire/api_request'
5
5
  require 'under_fire/api_response'
6
6
  require 'under_fire/configuration'
7
- require 'under_fire/toc_reader'
8
7
 
9
8
  require 'pry'
10
9
 
@@ -14,9 +13,9 @@ module UnderFire
14
13
  # @example
15
14
  # client = UnderFire::Client.new
16
15
  # client.album_search(:artist => 'Miles Davis') #=> lots of results
17
- #
16
+ #
18
17
  # client = UnderFire::Client.new
19
- # client.find_by_toc
18
+ # client.find_by_toc space_delimited_toc_offsets
20
19
  class Client
21
20
  include UnderFire
22
21
 
@@ -24,18 +23,19 @@ module UnderFire
24
23
  attr_reader :api_url
25
24
 
26
25
  def initialize
27
- @api_url = Configuration.api_url
26
+ @api_url = Configuration.instance.api_url
28
27
  end
29
28
 
30
- # Searches for album using TOC of CD in drive.
31
- # @return [APIResponse]
29
+ # Searches for album using provided toc offsets.
30
+ # @return [APIResponse]
32
31
  # @see UnderFire::AlbumTOCSearch
33
- def find_by_toc
34
- search = AlbumTOCSearch.new(get_toc)
32
+ def find_by_toc(*offsets)
33
+ offsets = offsets.join(" ")
34
+ search = AlbumTOCSearch.new(:toc => offsets)
35
35
  response = APIRequest.post(search.query, api_url)
36
36
  APIResponse.new(response.body)
37
37
  end
38
-
38
+
39
39
  # Finds album using one or more of :artist, :track_title and :album_title
40
40
  # @return [APIResponse]
41
41
  # @see UnderFire::AlbumSearch Description of arguments.
@@ -44,7 +44,7 @@ module UnderFire
44
44
  response = APIRequest.post(search.query, api_url)
45
45
  APIResponse.new(response.body)
46
46
  end
47
-
47
+
48
48
  # Fetches album with given album :gn_id or track :gn_id
49
49
  # @return [APIResponse]
50
50
  # @see UnderFire::AlbumFetch Description of arguments.
@@ -54,19 +54,24 @@ module UnderFire
54
54
  APIResponse.new(response.body)
55
55
  end
56
56
 
57
+ # Registers user with given client_id
58
+ # @return [APIResponse]
59
+ # @see UnderFire::Registration Description of arguments
60
+ def register(client_id)
61
+ search = Registration.new(client_id)
62
+ response = APIRequest.post(search.query, api_url)
63
+ APIResponse.new(response.body)
64
+ end
65
+
57
66
  # Fetches cover art using results of query.
58
67
  # @param [APIResponse] response
59
- def fetch_cover(response)
68
+ def fetch_cover(response, file_name)
60
69
  res = response.to_h
61
70
  response_url = res['RESPONSE']['ALBUM']['URL']
62
71
  title = res['RESPONSE']['ALBUM']['TITLE']
63
- APIRequest.get_file(response_url, "#{title}-cover.jpeg")
64
- end
65
-
66
- private
72
+ file_name = file_name || "#{title}-cover.jpg"
67
73
 
68
- def get_toc
69
- TOCReader.read
74
+ APIRequest.get_file(response_url, filename)
70
75
  end
71
76
  end
72
77
  end
@@ -1,30 +1,38 @@
1
+ require 'singleton'
2
+
1
3
  module UnderFire
2
- # Configuration information. Currently stored as environment variables.
3
- module Configuration
4
+ # Configuration information.
5
+ class Configuration
6
+ include Singleton
7
+
8
+ attr_reader :config_info
9
+
10
+ def initialize
11
+ @config_info = load_config
12
+ end
13
+
4
14
  # Gracenote client id stored in environment variable.
5
15
  # @return [String]
6
16
  def client_id
7
- ENV['GRACENOTE_CLIENT_ID']
17
+ config_info.fetch(:client_id, nil).to_s
8
18
  end
9
19
 
10
20
  # Part of client id before the hyphen (used by api_url).
11
21
  # @return [String]
12
22
  def client_id_string
13
- ci_string, _ = ENV['GRACENOTE_CLIENT_ID'].split('-')
14
- ci_string
23
+ client_id.split('-')[0]
15
24
  end
16
25
 
17
26
  # Part of client id after hyphen
18
27
  # @return [String]
19
28
  def client_tag
20
- _, ct = ENV['GRACENOTE_CLIENT_ID'].split('-')
21
- ct
29
+ client_id.split('-')[1]
22
30
  end
23
31
 
24
- # Gracenote user id stored as environment variable.
32
+ # Gracenote user id
25
33
  # @return [String]
26
34
  def user_id
27
- ENV['GRACENOTE_USER_ID']
35
+ config_info.fetch(:user_id, nil).to_s
28
36
  end
29
37
 
30
38
  # Gracenote API url for use in queries.
@@ -33,7 +41,27 @@ module UnderFire
33
41
  "https://c#{client_id_string}.web.cddbp.net/webapi/xml/1.0/"
34
42
  end
35
43
 
36
- module_function :client_id, :client_tag, :api_url, :user_id,
37
- :client_id_string
44
+ # Returns true if user has a user_id
45
+ # @return [Boolean]
46
+ def authorized?
47
+ user_id != nil
48
+ end
49
+
50
+ # Returns true if user has a client_id and user_id
51
+ # @return [Boolean]
52
+ def configured?
53
+ client_id != nil && !authorized?
54
+ end
55
+
56
+ def reset
57
+ initialize
58
+ end
59
+
60
+ private
61
+
62
+ def load_config
63
+ {:client_id => ENV['GRACENOTE_CLIENT_ID'],
64
+ :user_id => ENV['GRACENOTE_USER_ID']}
65
+ end
38
66
  end
39
67
  end
@@ -6,21 +6,26 @@ module UnderFire
6
6
  #
7
7
  # @see https://developer.gracenote.com/sites/default/files/web/html/index.html#Music%20Web%20API/Registration%20and%20Authentication.html#_Toc344907213
8
8
  class Registration
9
- # @return [String] XML string for query
9
+ # @return [String] XML string for query
10
10
  attr_reader :query
11
-
12
- def initialize
11
+
12
+ # @return [String] Gracenote Client ID
13
+ attr_reader :client_id
14
+
15
+ # @param [String] client_id Gracenote Client ID.
16
+ def initialize(client_id)
17
+ @client_id = client_id
13
18
  @query = build_query
14
19
  end
15
-
20
+
16
21
  # Builds XML for REGISTRATION query.
17
22
  #
18
23
  # @return [String] XML string for REGISTRATION
19
24
  def build_query
20
25
  builder = Builder::XmlMarkup.new
21
- xml = builder.queries {
22
- builder.query(cmd: 'REGISTER'){
23
- builder.client UnderFire::Configuration.client_id
26
+ xml = builder.QUERIES {
27
+ builder.QUERY(CMD: 'REGISTER'){
28
+ builder.CLIENT client_id
24
29
  }
25
30
  }
26
31
  xml
@@ -6,5 +6,5 @@ module UnderFire
6
6
  # MINOR version when you add functionality in a backwards-compatible manner, and
7
7
  # PATCH version when you make backwards-compatible bug fixes.
8
8
  # Refer to: http://semver.org/
9
- VERSION = "0.6.1"
9
+ VERSION = "0.7.0"
10
10
  end
@@ -0,0 +1,3 @@
1
+ ---
2
+ user_id: 12354534
3
+ client_id: 1252545-34543523452345
@@ -0,0 +1,78 @@
1
+
2
+ <RESPONSES>
3
+ <RESPONSE STATUS="OK">
4
+ <ALBUM><GN_ID>86372321-2C7F28ADC369EB90E53A7F6CA3A70D56</GN_ID>
5
+ <ARTIST>The Beatles</ARTIST>
6
+ <TITLE>Help!</TITLE>
7
+ <PKG_LANG>ENG</PKG_LANG>
8
+ <GENRE NUM="61364" ID="25332">60&apos;s Rock</GENRE>
9
+ <TRACK_COUNT>13</TRACK_COUNT>
10
+ <TRACK>
11
+ <TRACK_NUM>1</TRACK_NUM>
12
+ <GN_ID>86372322-05CF584F3265FA67F3E0C18987973C21</GN_ID>
13
+ <TITLE>Help!</TITLE>
14
+ </TRACK>
15
+ <TRACK>
16
+ <TRACK_NUM>2</TRACK_NUM>
17
+ <GN_ID>86372323-CA2905A4F82908C761E28472D3991EDF</GN_ID>
18
+ <TITLE>The Night Before</TITLE>
19
+ </TRACK>
20
+ <TRACK>
21
+ <TRACK_NUM>3</TRACK_NUM>
22
+ <GN_ID>86372324-10C31E8C4C6F7B841A045FF6434AB1B0</GN_ID>
23
+ <TITLE>You&apos;ve Got To Hide Your Love Away</TITLE>
24
+ </TRACK>
25
+ <TRACK>
26
+ <TRACK_NUM>4</TRACK_NUM>
27
+ <GN_ID>86372325-60EE527589C23B2F648156AD400FF857</GN_ID>
28
+ <TITLE>I Need You</TITLE>
29
+ </TRACK>
30
+ <TRACK>
31
+ <TRACK_NUM>5</TRACK_NUM>
32
+ <GN_ID>86372326-8DAA1AC1B819C66A28E2CD0EAD9D8222</GN_ID>
33
+ <TITLE>Another Girl</TITLE>
34
+ </TRACK>
35
+ <TRACK>
36
+ <TRACK_NUM>6</TRACK_NUM>
37
+ <GN_ID>86372327-E0DC3EC15ACDFE8E6880329970F82B78</GN_ID>
38
+ <TITLE>You&apos;re Going To Lose That Girl</TITLE>
39
+ </TRACK>
40
+ <TRACK>
41
+ <TRACK_NUM>7</TRACK_NUM>
42
+ <GN_ID>86372328-CD35818A7400061D8BC4C08D32E0BB38</GN_ID>
43
+ <TITLE>Ticket To Ride</TITLE>
44
+ </TRACK>
45
+ <TRACK>
46
+ <TRACK_NUM>8</TRACK_NUM>
47
+ <GN_ID>86372329-50EB4C1E500F3F6C895D0F8C48B9663D</GN_ID>
48
+ <TITLE>Act Naturally</TITLE>
49
+ </TRACK>
50
+ <TRACK>
51
+ <TRACK_NUM>9</TRACK_NUM>
52
+ <GN_ID>86372330-E6FA805C5DBA2E571935B0B8A7978862</GN_ID>
53
+ <TITLE>It&apos;s Only Love</TITLE>
54
+ </TRACK>
55
+ <TRACK>
56
+ <TRACK_NUM>10</TRACK_NUM>
57
+ <GN_ID>86372331-3F0E4CF181963FB330FF2001775F0FE1</GN_ID>
58
+ <TITLE>You Like Me Too Much</TITLE>
59
+ </TRACK>
60
+ <TRACK>
61
+ <TRACK_NUM>11</TRACK_NUM>
62
+ <GN_ID>86372332-5744350BE1E7DF380118F4BD93A98AA4</GN_ID>
63
+ <TITLE>Tell Me What You See</TITLE>
64
+ </TRACK>
65
+ <TRACK>
66
+ <TRACK_NUM>12</TRACK_NUM>
67
+ <GN_ID>86372333-79F674F3FBB538148DEF9ECF56AD4180</GN_ID>
68
+ <TITLE>I&apos;ve Just Seen A Face</TITLE>
69
+ </TRACK>
70
+ <TRACK>
71
+ <TRACK_NUM>13</TRACK_NUM>
72
+ <GN_ID>86372334-6EF61C66E4FE46B76C79D697159F0B97</GN_ID>
73
+ <TITLE>Yesterday</TITLE>
74
+ </TRACK>
75
+ <URL TYPE="COVERART" SIZE="MEDIUM">http://web.content.cddbp.net/cds/2.0?id=28088C817AD817CB&amp;client=866304&amp;class=cover&amp;origin=front&amp;size=medium&amp;type=image/jpeg&amp;tag=02-KSYB0rRmIy4UaXsdI4xheDiM0wIntXI9vxq0J9-tYN8uImMSkQ8hg</URL>
76
+ </ALBUM>
77
+ </RESPONSE>
78
+ </RESPONSES>
@@ -5,40 +5,27 @@ require 'ox'
5
5
  module UnderFire
6
6
  describe AlbumFetch do
7
7
  subject {AlbumFetch.new(:gn_id => '7F28ADC369EB90E53A7F6CA3A70D56V')}
8
-
9
- let(:xml){
10
- '<queries>'+
11
- '<auth>'+
12
- '<client>1234454</client>'+
13
- '<user>2353452345243545-454351435kj435j345434</user>'+
14
- '</auth>'+
15
- '<lang>eng</lang>'+
16
- '<country>canada</country>'+
17
- '<query cmd="album_fetch">'+
18
- '<gn_id>7F28ADC369EB90E53A7F6CA3A70D56V</gn_id>'+
19
- '</query>'+
20
- '</queries>'}
21
8
 
22
9
  before do
23
- ENV['GRACENOTE_CLIENT_ID'] = '1234454'
24
- ENV['GRACENOTE_USER_ID'] = '2353452345243545-454351435kj435j345434'
10
+ ENV['UF_CONFIG_PATH'] = File.expand_path('spec/fixtures/.ufrc')
11
+ @config = UnderFire::Configuration.instance
25
12
  end
26
13
 
27
14
  describe "instantiation" do
28
15
  it "accepts an album GN_ID as input" do
29
- AlbumFetch.new(:gn_id => '7F28ADC369EB90E53A7F6CA3A70D56V').must_be_kind_of UnderFire::AlbumFetch
16
+ AlbumFetch.new(:gn_id => '7F28ADC369EB90E53A7F6CA3A70D56V').must_be_kind_of UnderFire::AlbumFetch
30
17
  end
31
18
  end
32
19
 
33
20
  describe "#query" do
34
-
21
+
35
22
  it "returns properly formed xml" do
36
23
  #`Ox.load` returns Ox::ParseError if xml is malformed
37
24
  Ox.load(subject.query).must_be_kind_of Ox::Element
38
25
  end
39
-
26
+
40
27
  it "returns the correct xml query" do
41
- subject.query.must_include "gn_id"
28
+ subject.query.must_include "GN_ID"
42
29
  subject.query.must_include "ALBUM_FETCH"
43
30
  subject.query.must_include "7F28ADC369EB90E53A7F6CA3A70D56V"
44
31
  end
@@ -8,21 +8,9 @@ module UnderFire
8
8
  artist: "Radiohead",
9
9
  track_title: "Paranoid Android",
10
10
  album_title: "OK Computer")}
11
- let(:xml){
12
- '<queries><auth><client>1234454</client>'+
13
- '<user>2353452345243545-454351435kj435j345434</user></auth>'+
14
- '<lang>eng</lang><country>canada</country>'+
15
- '<query cmd="ALBUM_SEARCH">'+
16
- '<mode>SINGLE_BEST_COVER</mode>'+
17
- '<text type="ALBUM_TITLE">OK Computer</text>'+
18
- '<text type="TRACK_TITLE">Paranoid Android</text>'+
19
- '<text type="ARTIST">Radiohead</text>'+
20
- '</query></queries>'
21
- }
22
11
 
23
12
  before do
24
- ENV['GRACENOTE_CLIENT_ID'] = '1234454'
25
- ENV['GRACENOTE_USER_ID'] = '2353452345243545-454351435kj435j345434'
13
+ ENV['UF_CONFIG_PATH'] = File.expand_path('spec/fixtures/.ufrc')
26
14
  end
27
15
 
28
16
  it "accepts a hash of arguments" do
@@ -35,6 +23,11 @@ module UnderFire
35
23
  Ox.load(subject.query).must_be_kind_of Ox::Element
36
24
  end
37
25
 
26
+ it "returns xml with an auth element" do
27
+ subject.query.must_include "<AUTH>"
28
+ subject.query.must_include "</AUTH>"
29
+ end
30
+
38
31
  describe "with all fields" do
39
32
  it "returns the correct xml query" do
40
33
  subject.query.must_include "Radiohead"
@@ -8,18 +8,9 @@ module UnderFire
8
8
  "110612 122590 132127 141685"}
9
9
  subject {AlbumTOCSearch.new(toc: toc)}
10
10
 
11
- let(:xml){
12
- '<queries><auth><client>1234454</client>'+
13
- '<user>2353452345243545-454351435kj435j345434</user></auth>'+
14
- '<lang>eng</lang><country>canada</country>'+
15
- '<query cmd="ALBUM_TOC">'+
16
- '<mode>SINGLE_BEST_COVER</mode>'+
17
- '<toc><offsets>' + toc + '</offsets></toc>'+
18
- '</query></queries>'}
19
-
20
11
  before do
21
- ENV['GRACENOTE_CLIENT_ID'] = '1234454'
22
- ENV['GRACENOTE_USER_ID'] = '2353452345243545-454351435kj435j345434'
12
+ ENV['UF_CONFIG_PATH'] = File.expand_path('spec/fixtures/.ufrc')
13
+ @config = UnderFire::Configuration.instance
23
14
  end
24
15
 
25
16
 
@@ -0,0 +1,49 @@
1
+ require_relative '../../spec_helper'
2
+ require 'rr'
3
+
4
+ module UnderFire
5
+ describe CLI do
6
+ before do
7
+ @cli = CLI.new
8
+ @stdout_old = $stdout
9
+ @stdin_old = $stdin
10
+ $stdout = StringIO.new
11
+ $stdin = StringIO.new
12
+ end
13
+
14
+ after do
15
+ $stdout = @stdout_old
16
+ $stdin = @stdin_old
17
+ end
18
+
19
+ # describe "#register" do
20
+ # before do
21
+ # response_body = '<RESPONSES><RESPONSE STATUS="OK"><USER>user_id_string</USER></RESPONSE><RESPONSES>'
22
+ # stub_request(:post, "https://c.web.cddbp.net/webapi/xml/1.0/").
23
+ # with(:body => "<QUERIES><QUERY cmd=\"REGISTER\"><CLIENT></CLIENT></QUERY></QUERIES>",
24
+ # :headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Content-Type'=>'application/xml', 'User-Agent'=>'Ruby'}).
25
+ # to_return(:status => 200, :body => response_body, :headers => {})
26
+ # stub.proxy(APIResponse).new(response_body) do |res|
27
+ # stub(res).success? { true }
28
+ # stub(res).to_h { { :response => { :user => "adfadsfasa-aq34rqfafafsfdasf"}}}
29
+ # end
30
+ # end
31
+
32
+ # it "works" do
33
+ # mock($stdout).puts "\nIn order to proceed, please obtain a Gracenote Client ID."
34
+ # mock($stdout).puts "\nTo obtain a Client ID:"
35
+ # mock($stdout).puts " 1) Register at http://developer.gracenote.com."
36
+ # mock($stdout).puts " 2) Click on Add a New App."
37
+ # mock($stdout).puts " 3) Obtain your 'Client ID for Mobile Client, Web API, and eyeQ'"
38
+ # mock($stdout).puts " from the App Details."
39
+ # mock($stdout).print "\nPlease press [Enter] once you have a Client ID. "
40
+ # mock($stdout).print "Enter your client id: "
41
+ # mock($stdin).gets {"2352352452454"}
42
+ # mock($stdin).gets
43
+ # mock($stdout).puts "Saved client_id to /home/jason/.ufrc"
44
+ # mock($stdout).puts "Saved user_id to /home/jason/.ufrc"
45
+ # @cli.register
46
+ # end
47
+ # end
48
+ end
49
+ end
@@ -1,18 +1,45 @@
1
1
  require_relative '../../spec_helper'
2
+ require 'pry'
2
3
 
3
4
  module UnderFire
4
5
  describe Configuration do
6
+ let(:base_dir){File.expand_path(__FILE__ + "/../../..")}
7
+ let(:config_file){File.join(base_dir, 'fixtures/.ufrc')}
8
+
5
9
  before do
6
- ENV['GRACENOTE_CLIENT_ID'] = "12345668"
7
- ENV['GRACENOTE_USER_ID'] = "1432145345-13413554646D35134"
10
+ ENV["GRACENOTE_USER_ID"] = "12354534"
11
+ ENV["GRACENOTE_CLIENT_ID"] = "1252545-34543523452345"
12
+ end
13
+
14
+ after do
15
+ Configuration.instance.reset
8
16
  end
9
17
 
10
- it "has a client_id" do
11
- UnderFire::Configuration.client_id.must_equal "12345668"
18
+ describe "a completed configuration" do
19
+
20
+ it "has a client_id" do
21
+ config = Configuration.instance
22
+ config.client_id.must_equal "1252545-34543523452345"
23
+ end
24
+
25
+ it "has a user_id" do
26
+ config = Configuration.instance
27
+ config.user_id.must_equal "12354534"
28
+ end
12
29
  end
13
30
 
14
- it "has a user_id" do
15
- UnderFire::Configuration.user_id.must_equal "1432145345-13413554646D35134"
31
+ describe "unconfigured" do
32
+ before do
33
+ ENV["GRACENOTE_CLIENT_ID"] = ""
34
+ ENV["GRACENOTE_USER_ID"] = ""
35
+ end
36
+
37
+ describe "#configured?" do
38
+ it "returns false if there are no credentials" do
39
+ config = Configuration.instance
40
+ config.configured?.must_equal false
41
+ end
42
+ end
16
43
  end
17
44
  end
18
45
  end
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,4 @@
1
1
  require 'minitest/doc_reporter'
2
+ require 'webmock/minitest'
2
3
  require File.expand_path('../../lib/under_fire.rb', __FILE__)
3
4
 
data/todo.txt CHANGED
@@ -2,5 +2,3 @@
2
2
  -To implement:
3
3
  * ALBUM_FINGERPRINT
4
4
  * ALBUM_FETCH
5
- * REGISTRATION
6
- -Use symbols for 'SINGLE_BEST' and 'SINGLE_BEST_COVER'
data/under_fire.gemspec CHANGED
@@ -21,12 +21,12 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.add_development_dependency "bundler", "~> 1.3"
23
23
  spec.add_development_dependency "rake"
24
- spec.add_development_dependency "pry"
25
- spec.add_development_dependency "pry-doc"
24
+ spec.add_development_dependency "pry-plus"
26
25
  spec.add_development_dependency "minitest"
27
26
  spec.add_development_dependency "guard-minitest"
28
27
  spec.add_development_dependency "rr"
29
28
  spec.add_development_dependency "minitest-doc_reporter", "~> 0.6.0"
29
+ spec.add_development_dependency "webmock"
30
30
  spec.add_development_dependency "ox"
31
31
  if RbConfig::CONFIG['target_os'] =~ /mswin|mingw|cygwi/
32
32
  spec.add_development_dependency "wdm", ">= 0.1.0"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: under_fire
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Thompson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-11 00:00:00.000000000 Z
11
+ date: 2014-02-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -39,7 +39,7 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: pry
42
+ name: pry-plus
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - '>='
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: pry-doc
56
+ name: minitest
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - '>='
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: minitest
70
+ name: guard-minitest
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - '>='
@@ -81,7 +81,7 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: guard-minitest
84
+ name: rr
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - '>='
@@ -95,33 +95,33 @@ dependencies:
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
- name: rr
98
+ name: minitest-doc_reporter
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - '>='
101
+ - - ~>
102
102
  - !ruby/object:Gem::Version
103
- version: '0'
103
+ version: 0.6.0
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - '>='
108
+ - - ~>
109
109
  - !ruby/object:Gem::Version
110
- version: '0'
110
+ version: 0.6.0
111
111
  - !ruby/object:Gem::Dependency
112
- name: minitest-doc_reporter
112
+ name: webmock
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - ~>
115
+ - - '>='
116
116
  - !ruby/object:Gem::Version
117
- version: 0.6.0
117
+ version: '0'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - ~>
122
+ - - '>='
123
123
  - !ruby/object:Gem::Version
124
- version: 0.6.0
124
+ version: '0'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: ox
127
127
  requirement: !ruby/object:Gem::Requirement
@@ -214,8 +214,10 @@ executables:
214
214
  extensions: []
215
215
  extra_rdoc_files: []
216
216
  files:
217
+ - .ackrc
217
218
  - .gitignore
218
219
  - .ruby-version
220
+ - Changelog
219
221
  - Gemfile
220
222
  - Guardfile
221
223
  - LICENSE.txt
@@ -233,8 +235,9 @@ files:
233
235
  - lib/under_fire/client.rb
234
236
  - lib/under_fire/configuration.rb
235
237
  - lib/under_fire/registration.rb
236
- - lib/under_fire/toc_reader.rb
237
238
  - lib/under_fire/version.rb
239
+ - spec/fixtures/.ufrc
240
+ - spec/fixtures/album_response.xml
238
241
  - spec/lib/under_fire/album_fetch_spec.rb
239
242
  - spec/lib/under_fire/album_search_spec.rb
240
243
  - spec/lib/under_fire/album_toc_search_spec.rb
@@ -242,6 +245,7 @@ files:
242
245
  - spec/lib/under_fire/api_response.rb
243
246
  - spec/lib/under_fire/api_response_spec.rb
244
247
  - spec/lib/under_fire/base_query_spec.rb
248
+ - spec/lib/under_fire/cli_spec.rb
245
249
  - spec/lib/under_fire/configuration_spec.rb
246
250
  - spec/sample/response.xml
247
251
  - spec/sample/toc.txt
@@ -274,6 +278,8 @@ signing_key:
274
278
  specification_version: 4
275
279
  summary: An unofficial wrapper for the Gracenote web API
276
280
  test_files:
281
+ - spec/fixtures/.ufrc
282
+ - spec/fixtures/album_response.xml
277
283
  - spec/lib/under_fire/album_fetch_spec.rb
278
284
  - spec/lib/under_fire/album_search_spec.rb
279
285
  - spec/lib/under_fire/album_toc_search_spec.rb
@@ -281,6 +287,7 @@ test_files:
281
287
  - spec/lib/under_fire/api_response.rb
282
288
  - spec/lib/under_fire/api_response_spec.rb
283
289
  - spec/lib/under_fire/base_query_spec.rb
290
+ - spec/lib/under_fire/cli_spec.rb
284
291
  - spec/lib/under_fire/configuration_spec.rb
285
292
  - spec/sample/response.xml
286
293
  - spec/sample/toc.txt
@@ -1,19 +0,0 @@
1
- require 'discid'
2
-
3
- module UnderFire
4
- # Reads CD and returns table of contents (start frame of each track).
5
- #
6
- # @example
7
- # UnderFire.TOCReader.read
8
- class TOCReader
9
- # @return [Array<String>] array of start frame strings
10
- def self.read
11
- device = "/dev/cdrom"
12
- disc = DiscId.read(device)
13
- toc = []
14
- disc.tracks {|t| toc << t.offset.to_s}
15
- toc.join(" ")
16
- end
17
- end
18
- end
19
-