under_fire 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bb1de4137e3e56a58f163f7410cd950f0c9353be
4
+ data.tar.gz: 86cc6bc36b6ae0b03d190627e7efdbbdfa37cd27
5
+ SHA512:
6
+ metadata.gz: cf75d52b9dc93330343d74dd287bf48d39a86a2af86045ecd7bfc6417d1bc68f7819b754735ba9b177114583c4cc121c80b39d96dfff5880e2e7307e1c6bf13a
7
+ data.tar.gz: e1ec64051f8a67670dbf316495e8db128338d098943e73edb5cc7bef784812e58142450e799c27d613e0887496cf147f14a1be1d78932e42a72f91d8be13f39e
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.swp
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in under_fire.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,23 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :minitest do
5
+ # with Minitest::Spec
6
+ watch(%r{^spec/lib/under_fire/(.*)_spec\.rb})
7
+ watch(%r{^lib/under_fire/(.+)\.rb}) { |m| "spec/lib/under_fire/#{m[1]}_spec.rb" }
8
+ watch(%r{^spec/spec_helper\.rb}) { 'spec' }
9
+
10
+ # Rails 4
11
+ # watch(%r{^app/(.+)\.rb}) { |m| "test/#{m[1]}_test.rb" }
12
+ # watch(%r{^app/controllers/application_controller\.rb}) { 'test/controllers' }
13
+ # watch(%r{^app/controllers/(.+)_controller\.rb}) { |m| "test/integration/#{m[1]}_test.rb" }
14
+ # watch(%r{^app/views/(.+)_mailer/.+}) { |m| "test/mailers/#{m[1]}_mailer_test.rb" }
15
+ # watch(%r{^lib/(.+)\.rb}) { |m| "test/lib/#{m[1]}_test.rb" }
16
+ # watch(%r{^test/.+_test\.rb})
17
+ # watch(%r{^test/test_helper\.rb}) { 'test' }
18
+
19
+ # Rails < 4
20
+ # watch(%r{^app/controllers/(.*)\.rb}) { |m| "test/functional/#{m[1]}_test.rb" }
21
+ # watch(%r{^app/helpers/(.*)\.rb}) { |m| "test/helpers/#{m[1]}_test.rb" }
22
+ # watch(%r{^app/models/(.*)\.rb}) { |m| "test/unit/#{m[1]}_test.rb" }
23
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jason Thompson
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # UnderFire
2
+
3
+ Wraps Gracenote's API in Ruby goodness. Still under development.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'lib/under_fire'
6
+ t.test_files = FileList['spec/lib/under_fire/*_spec.rb']
7
+ t.verbose = true
8
+ end
9
+
10
+ task :default => :test
data/bin/under-fire ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'under_fire'
3
+
4
+ UnderFire::CLI.start(ARGV)
@@ -0,0 +1,50 @@
1
+ require 'under_fire/base_query'
2
+ require 'builder'
3
+
4
+ module UnderFire
5
+ # Builds XML for Gracenote's ALBUM_FETCH query.
6
+ #
7
+ # @see https://developer.gracenote.com/sites/default/files/web/html/index.html#Music%20Web%20API/ALBUM_FETCH.html#_Toc344907262
8
+ #
9
+ # @example
10
+ # search = UnderFire::Album_Fetch.new(:gn_id => '86372321-2C7F28ADC369EB90E53A7F6CA3A70D56')
11
+ # search.query => Response = The Beatles, Help!
12
+ class AlbumFetch < BaseQuery
13
+ # @return [String] XML string for query.
14
+ attr_reader :query
15
+
16
+ # @return [Hash] Search parameters with :mode removed.
17
+ attr_reader :parameters
18
+
19
+ # @return [String] Gracenote ID for album
20
+ attr_accessor :gn_id
21
+
22
+ # Requires album :gn_id or track :gn_id
23
+ #
24
+ # @param [Hash] args the arguments for Album_Fetch
25
+ # @option args [String] :gn_id Gracenote ID of album or track
26
+ # @option args [String] :mode Either 'SINGLE_BEST' or 'SINGLE_BEST_COVER'
27
+ # (Only needed if track :gn_id used)
28
+ def initialize(args)
29
+ super args
30
+ @parameters = args.reject {|k,v| k == :mode}
31
+ parameters.each do |k,v| send("#{k}=", v) end
32
+ @query = build_query
33
+ end
34
+
35
+ # Builds ALBUM_FETCH-specific part of ALBUM_FETCH query and adds it to the base query
36
+ # common to all query types. Called by constructor.
37
+ #
38
+ # @return [String] XML string for ALBUM_FETCH query.
39
+ def build_query
40
+ build_base_query do |builder|
41
+ builder.query(cmd: "ALBUM_FETCH"){
42
+ builder.mode "SINGLE_BEST_COVER"
43
+ parameters.each do |k,v|
44
+ builder.gn_id gn_id
45
+ end
46
+ }
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,64 @@
1
+ require 'under_fire/base_query'
2
+ require 'builder'
3
+
4
+ module UnderFire
5
+ # Builds XML for Gracenote's ALBUM_SEARCH query.
6
+ #
7
+ # @see https://developer.gracenote.com/sites/default/files/web/html/index.html#Music%20Web%20API/ALBUM_SEARCH.html#_Toc344907249
8
+ #
9
+ # @example
10
+ # search = UnderFire::AlbumSearch.new(:artist => 'Radiohead')
11
+ # search.query #=> XML for Gracenote ALBUM_SEARCH query for albums by Radiohead.
12
+ #
13
+ # search = UnderFire::AlbumSearch.new(:track_title = > 'Paranoid Android',
14
+ # :artist => 'Radiohead',
15
+ # :mode => 'SINGLE_BEST_COVER')
16
+ # search.query #=> XML for ALBUM_SEARCH
17
+ #
18
+ #
19
+ class AlbumSearch < BaseQuery
20
+ # @return [String] XML string for query.
21
+ attr_reader :query
22
+
23
+ # @return [Hash] search parameters without :mode
24
+ attr_reader :parameters
25
+
26
+ # @return [String]
27
+ attr_accessor :artist
28
+
29
+ # @return [String]
30
+ attr_accessor :track_title
31
+
32
+ # @return [String]
33
+ attr_accessor :album_title
34
+
35
+ # At least one of :artist, :track_title, :album_title is required (:mode is optional).
36
+ #
37
+ # @param [Hash] args the arguments for an Album_Search.
38
+ # @option args [String] :artist Name of the artist.
39
+ # @option args [String] :track_title Name of the song/track.
40
+ # @option args [String] :album_title Name of the album.
41
+ # @option args [String] :mode Either 'SINGLE_BEST' or 'SINGLE_BEST_COVER'
42
+ def initialize(args={})
43
+ super args[:mode]
44
+ @parameters = args.reject {|k,v| k == :mode}
45
+ parameters.each do |k,v| send("#{k}=", v) end
46
+ @query = build_query
47
+ end
48
+
49
+ # Builds ALBUM_SEARCH-specific part of ALBUM_SEARCH query and adds it to the base query
50
+ # common to all query types. Called by constructor.
51
+ #
52
+ # @return [String] XML string for ALBUM_SEARCH query.
53
+ def build_query
54
+ build_base_query do |builder|
55
+ builder.query(cmd: "ALBUM_SEARCH"){
56
+ builder.mode "SINGLE_BEST_COVER"
57
+ parameters.each do |k,v|
58
+ builder.text(v, type: k.to_s.upcase)
59
+ end
60
+ }
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,45 @@
1
+ require 'under_fire/base_query'
2
+ require 'builder'
3
+
4
+ module UnderFire
5
+ # Builds XML for Gracenote's ALBUM_TOC query
6
+ #
7
+ # @see 'https://developer.gracenote.com/sites/default/files/web/html/index.html#Music%20Web%20API/ALBUM_TOC.html#_Toc344907258'
8
+ #
9
+ # @example
10
+ # search = UnderFire::AlbumTOCSearch.new(:toc => '182 10762 22515 32372 43735 53335 63867 78305 89792 98702 110612 122590 132127 141685')
11
+ # search.query #=> XML query string for ALBUM_TOC query.
12
+ class AlbumTOCSearch < BaseQuery
13
+ # @return [String] CD Table of contents.
14
+ attr_reader :toc
15
+
16
+ # @return [String] XML string for ALBUM_TOC query.
17
+ attr_reader :query
18
+
19
+ # :toc is required (:mode is optional).
20
+ #
21
+ # @param [Hash] args arguments to create an ALBUM_TOC query.
22
+ # @option [String] :toc CD table of contents (space-separated list of track start frames)
23
+ # @option [String] :mode Either 'SINGLE_BEST' or 'SINGLE_BEST_COVER'
24
+ def initialize(args)
25
+ super args[:mode]
26
+ @toc = args[:toc]
27
+ @query = build_query
28
+ end
29
+
30
+ # Builds TOC-specific part of ALBUM_TOC query and adds it to the base query
31
+ # common to all query types. Called by constructor.
32
+ #
33
+ # @return [String] XML string for ALBUM_TOC query.
34
+ def build_query
35
+ build_base_query do |builder|
36
+ builder.query(cmd: "ALBUM_TOC"){
37
+ builder.mode mode
38
+ builder.toc {
39
+ builder.offsets toc
40
+ }
41
+ }
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,50 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'uri'
4
+ require 'open-uri'
5
+
6
+ module UnderFire
7
+ # HTTP requests required for Gracenote API.
8
+ #
9
+ # @todo Error handling
10
+ #
11
+ # @example
12
+ # response = UnderFire::ApiRequest.post(query_xml, api_url)
13
+ #
14
+ # response = UnderFire::ApiRequest.get_file(image_url, filename)
15
+ class APIRequest
16
+ # @param [String] query XML query string
17
+ # @param [String] api_url url for your application
18
+ # @return [Net::HTTPResponse]
19
+ def self.post(query, api_url)
20
+ uri = URI(api_url)
21
+ http = Net::HTTP.new(uri.host, uri.port)
22
+ http.use_ssl = true
23
+ http.ssl_version = 'SSLv3'
24
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
25
+ req = Net::HTTP::Post.new(uri.request_uri)
26
+ req.body = query
27
+ req['Content-Type'] = 'application/xml'
28
+ res = http.request(req)
29
+ res
30
+ end
31
+
32
+ # @param [String] url URL that points to file.
33
+ # @param [String] filename Filename and path for saving downloaded file.
34
+ def self.get_file(url, filename)
35
+ uri = URI url
36
+
37
+ Net::HTTP.start(uri.host, uri.port) do |http|
38
+ request = Net::HTTP::Get.new uri
39
+
40
+ http.request request do |response|
41
+ open filename, 'w' do |io|
42
+ response.read_body do |chunk|
43
+ io.write chunk
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,57 @@
1
+ require 'nori'
2
+
3
+ module UnderFire
4
+ # Wraps query response, providing to_h and to_s methods for easy processing.
5
+ class APIResponse
6
+ # @return [Hash] Response as Hash.
7
+ attr_reader :response
8
+
9
+ # @param [String] response XML string.
10
+ def initialize(response)
11
+ @response = parse_response(response)
12
+ end
13
+
14
+ # @return [Hash] Hash representation of response.
15
+ def to_h
16
+ response[:responses]
17
+ end
18
+
19
+ # @return [String] String represenation suitable for command line.
20
+ def to_s
21
+ recursive_to_s(to_h)
22
+ end
23
+
24
+ # @return [Boolean] Did the query return something?
25
+ def success?
26
+ response[:responses][:response][:@status] == 'OK'
27
+ end
28
+
29
+ private
30
+
31
+ # Recursively walks nested hash structure to return string representation.
32
+ # @return [String] Flat string representation of nest Hash.
33
+ def recursive_to_s(hash)
34
+ output = ""
35
+ hash.each do |k,v|
36
+ if v.is_a? Hash
37
+ output << "\n"
38
+ output << "#{k}:\n#{recursive_to_s(v)}\n"
39
+ elsif v.is_a? Array
40
+ output << "\n"
41
+ v.each {|i| output << "#{recursive_to_s(i)}\n" }
42
+ else
43
+ output << "#{k}: #{v}\n"
44
+ end
45
+ end
46
+ output
47
+ end
48
+
49
+ # Builds hash from XML response.
50
+ # @param [String] response XML response string.
51
+ # @return [Hash] Hash representation of response.
52
+ def parse_response(response)
53
+ parser = Nori.new(:convert_tags_to => lambda {|tag| tag.snakecase.to_sym })
54
+ parser.parse(response)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,30 @@
1
+ require 'under_fire/configuration'
2
+ require 'builder'
3
+
4
+ module UnderFire
5
+ # Builds an XML query with information common to all queries (to be subclassed by individual queries).
6
+ class BaseQuery
7
+ # @return [String]
8
+ attr_reader :mode
9
+
10
+ # @param [String] mode Either 'SINGLE_BEST' or 'SINGLE_BEST_COVER' (defaults to 'SINGLE_BEST_COVER').
11
+ def initialize(mode="SINGLE_BEST_COVER")
12
+ @mode = mode || "SINGLE_BEST_COVER"
13
+ end
14
+
15
+ # @yield [Builder] builder object used by subclass's build_query method.
16
+ def build_base_query(&block)
17
+ builder = Builder::XmlMarkup.new
18
+ builder.queries {
19
+ builder.auth {
20
+ builder.client Configuration.client_id
21
+ builder.user Configuration.user_id
22
+ }
23
+ builder.lang "eng"
24
+ builder.country "canada"
25
+ builder.app_info %Q{app="under-fire #{VERSION}", os="#{RUBY_PLATFORM}"}
26
+ yield builder
27
+ }
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,66 @@
1
+ require 'thor'
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'
7
+
8
+ module UnderFire
9
+ # Command Line interface
10
+ class CLI < Thor
11
+ include UnderFire
12
+
13
+ def initialize(*)
14
+ super
15
+ end
16
+
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."
19
+ 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
23
+ end
24
+
25
+ desc "album", "Queries Gracenote with album <title>, <song> title, or <artist> name"
26
+ method_option :album_title,
27
+ :aliases => '-t',
28
+ :desc => "Specify album title",
29
+ :required => false
30
+ method_option :track_title,
31
+ :aliases => ['-s', :song_title],
32
+ :desc => "Specify song title",
33
+ :required => false
34
+ method_option :artist,
35
+ :aliases => '-a',
36
+ :desc => "Specify artist name",
37
+ :required => false
38
+ 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
+ end
43
+
44
+ desc "id", "Fetches album info using given Gracenote ID."
45
+ method_option :gn_id, :aliases => ['-i', '--id'], :required => true,
46
+ :desc => "Gracenote album or song GN_ID"
47
+ 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
52
+
53
+ desc "cover", "Gets cover from Gracenote."
54
+ method_option :url, :aliases => '-u', :required => true,
55
+ :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."
58
+ def cover
59
+ say "Fetching cover"
60
+ url = options[:url]
61
+ file_name = options[:file_name].empty? ? "cover.jpg" : options[:file_name]
62
+ APIRequest.get_file(url, file_name)
63
+ say "saved #{file_name} in #{File.dirname __FILE__}"
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,72 @@
1
+ require 'under_fire/album_search'
2
+ require 'under_fire/album_toc_search'
3
+ require 'under_fire/album_fetch'
4
+ require 'under_fire/api_request'
5
+ require 'under_fire/api_response'
6
+ require 'under_fire/configuration'
7
+ require 'under_fire/toc_reader'
8
+
9
+ require 'pry'
10
+
11
+ module UnderFire
12
+ # Public interface to UnderFire's functionality.
13
+ #
14
+ # @example
15
+ # client = UnderFire::Client.new
16
+ # client.album_search(:artist => 'Miles Davis') #=> lots of results
17
+ #
18
+ # client = UnderFire::Client.new
19
+ # client.find_by_toc
20
+ class Client
21
+ include UnderFire
22
+
23
+ # @return [String] API URL for application.
24
+ attr_reader :api_url
25
+
26
+ def initialize
27
+ @api_url = Configuration.api_url
28
+ end
29
+
30
+ # Searches for album using TOC of CD in drive.
31
+ # @return [APIResponse]
32
+ # @see UnderFire::AlbumTOCSearch
33
+ def find_by_toc
34
+ search = AlbumTOCSearch.new(get_toc)
35
+ response = APIRequest.post(search.query, api_url)
36
+ APIResponse.new(response.body)
37
+ end
38
+
39
+ # Finds album using one or more of :artist, :track_title and :album_title
40
+ # @return [APIResponse]
41
+ # @see UnderFire::AlbumSearch Description of arguments.
42
+ def find_album(args)
43
+ search = AlbumSearch.new(args)
44
+ response = APIRequest.post(search.query, api_url)
45
+ APIResponse.new(response.body)
46
+ end
47
+
48
+ # Fetches album with given album :gn_id or track :gn_id
49
+ # @return [APIResponse]
50
+ # @see UnderFire::AlbumFetch Description of arguments.
51
+ def fetch_album(args)
52
+ search = AlbumFetch.new(args)
53
+ response = APIRequest.post(search.query, api_url)
54
+ APIResponse.new(response.body)
55
+ end
56
+
57
+ # Fetches cover art using results of query.
58
+ # @param [APIResponse] response
59
+ def fetch_cover(response)
60
+ res = response.to_h
61
+ response_url = res['RESPONSE']['ALBUM']['URL']
62
+ title = res['RESPONSE']['ALBUM']['TITLE']
63
+ APIRequest.get_file(response_url, "#{title}-cover.jpeg")
64
+ end
65
+
66
+ private
67
+
68
+ def get_toc
69
+ TOCReader.read
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,39 @@
1
+ module UnderFire
2
+ # Configuration information. Currently stored as environment variables.
3
+ module Configuration
4
+ # Gracenote client id stored in environment variable.
5
+ # @return [String]
6
+ def client_id
7
+ ENV['GRACENOTE_CLIENT_ID']
8
+ end
9
+
10
+ # Part of client id before the hyphen (used by api_url).
11
+ # @return [String]
12
+ def client_id_string
13
+ ci_string, _ = ENV['GRACENOTE_CLIENT_ID'].split('-')
14
+ ci_string
15
+ end
16
+
17
+ # Part of client id after hyphen
18
+ # @return [String]
19
+ def client_tag
20
+ _, ct = ENV['GRACENOTE_CLIENT_ID'].split('-')
21
+ ct
22
+ end
23
+
24
+ # Gracenote user id stored as environment variable.
25
+ # @return [String]
26
+ def user_id
27
+ ENV['GRACENOTE_USER_ID']
28
+ end
29
+
30
+ # Gracenote API url for use in queries.
31
+ # @return [String]
32
+ def api_url
33
+ "https://c#{client_id_string}.web.cddbp.net/webapi/xml/1.0/"
34
+ end
35
+
36
+ module_function :client_id, :client_tag, :api_url, :user_id,
37
+ :client_id_string
38
+ end
39
+ end
@@ -0,0 +1,29 @@
1
+ require 'under_fire/configuration'
2
+ require 'builder'
3
+
4
+ module UnderFire
5
+ # Register an application using client_id (only needs to be done once per application).
6
+ #
7
+ # @see https://developer.gracenote.com/sites/default/files/web/html/index.html#Music%20Web%20API/Registration%20and%20Authentication.html#_Toc344907213
8
+ class Registration
9
+ # @return [String] XML string for query
10
+ attr_reader :query
11
+
12
+ def initialize
13
+ @query = build_query
14
+ end
15
+
16
+ # Builds XML for REGISTRATION query.
17
+ #
18
+ # @return [String] XML string for REGISTRATION
19
+ def build_query
20
+ builder = Builder::XmlMarkup.new
21
+ xml = builder.queries {
22
+ builder.query(cmd: 'REGISTER'){
23
+ builder.client UnderFire::Configuration.client_id
24
+ }
25
+ }
26
+ xml
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,19 @@
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
+
@@ -0,0 +1,10 @@
1
+ module UnderFire
2
+ # Because I always forget:
3
+ #
4
+ # Given a version number MAJOR.MINOR.PATCH, increment the:
5
+ # MAJOR version when you make incompatible API changes,
6
+ # MINOR version when you add functionality in a backwards-compatible manner, and
7
+ # PATCH version when you make backwards-compatible bug fixes.
8
+ # Refer to: http://semver.org/
9
+ VERSION = "0.6.1"
10
+ end
data/lib/under_fire.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'under_fire/version'
2
+ require 'under_fire/configuration'
3
+ require 'under_fire/album_search'
4
+ require 'under_fire/album_fetch'
5
+ require 'under_fire/registration'
6
+ require 'under_fire/api_request'
7
+ require 'under_fire/api_response'
8
+ require 'under_fire/album_toc_search'
9
+ require 'under_fire/cli'
10
+
11
+ # A wrapper library for the Gracenote web API that also provides a command line executable (under-fire).
12
+ module UnderFire
13
+ end