Class: Shazamio::Shazam

Inherits:
Object
  • Object
show all
Includes:
Request
Defined in:
lib/shazamio/shazam.rb

Overview

Ruby port of shazamio.api.Shazam. Synchronous (see HTTPClient for why), so no asyncio/aiohttp equivalent is needed -- just call methods directly.

shazam = Shazamio::Shazam.new
result = shazam.recognize("song.mp3")
puts result.dig("track", "title")

NOTE: this only exposes the endpoints that are currently reachable. A separate group of endpoints (artist info, artist albums, album info, and every "top tracks" chart) is broken on Shazam's side right now -- their own web app hits the same error -- and was removed from here rather than shipped broken. See the "Not included" section of README.md for details, including how to bring them back if/when Apple fixes it upstream.

Constant Summary

Constants included from Request

Request::TIME_ZONE

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Request

#headers

Constructor Details

#initialize(language: "en-US", endpoint_country: "GB", http_client: nil) ⇒ Shazam

Returns a new instance of Shazam.



32
33
34
35
36
# File 'lib/shazamio/shazam.rb', line 32

def initialize(language: "en-US", endpoint_country: "GB", http_client: nil)
  @language = language
  @endpoint_country = endpoint_country
  @http_client = http_client || HTTPClient.new
end

Instance Attribute Details

#endpoint_countryObject (readonly)

Returns the value of attribute endpoint_country.



30
31
32
# File 'lib/shazamio/shazam.rb', line 30

def endpoint_country
  @endpoint_country
end

#http_clientObject (readonly)

Returns the value of attribute http_client.



30
31
32
# File 'lib/shazamio/shazam.rb', line 30

def http_client
  @http_client
end

#languageObject (readonly)

Returns the value of attribute language.



30
31
32
# File 'lib/shazamio/shazam.rb', line 30

def language
  @language
end

Instance Method Details

#get_youtube_data(link, proxy: nil) ⇒ Object



135
136
137
# File 'lib/shazamio/shazam.rb', line 135

def get_youtube_data(link, proxy: nil)
  http_client.request("GET", link, headers: headers, proxy: proxy)
end

#listening_counter(track_id, proxy: nil) ⇒ Object



123
124
125
126
# File 'lib/shazamio/shazam.rb', line 123

def listening_counter(track_id, proxy: nil)
  url = format(ShazamUrl::LISTENING_COUNTER, track_id: track_id)
  http_client.request("GET", url, headers: headers, proxy: proxy)
end

#listening_counter_many(track_ids, proxy: nil) ⇒ Object



128
129
130
131
132
133
# File 'lib/shazamio/shazam.rb', line 128

def listening_counter_many(track_ids, proxy: nil)
  http_client.request(
    "GET", ShazamUrl::LISTENING_COUNTER_MANY,
    headers: headers, params: { "id" => track_ids }, proxy: proxy
  )
end

#recognize(data, proxy: nil) ⇒ Hash

Recognize a track from an audio file path, raw audio bytes (wrapped in e.g. StringIO), or an Array of signed 16-bit PCM samples already at 16kHz mono.

There is no Ruby equivalent of the Python project's compiled Rust recognizer (shazamio_core); this always uses the pure-Ruby signature algorithm (see Algorithm::SignatureGenerator), which is Python's "legacy" path (recognize_song). It works the same way, just slower.

Parameters:

  • data (String, Array<Integer>, #read)

    file path, audio bytes (via an IO-like object), or PCM samples

  • proxy (String, nil) (defaults to: nil)

Returns:

  • (Hash)

    Shazam's raw JSON response



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/shazamio/shazam.rb', line 51

def recognize(data, proxy: nil)
  samples =
    if data.is_a?(Array)
      data
    else
      AudioLoader.pcm_s16le_mono_16k(data)
    end

  generator = SignatureGenerator.new
  generator.feed_input(samples)
  generator.max_time_seconds = 12

  duration_seconds = samples.length / 16_000.0
  if duration_seconds > 12 * 3
    generator.samples_processed += 16_000 * ((duration_seconds / 2).to_i - 6)
  end

  signature = generator.get_next_signature
  return { "matches" => [] } if signature.nil?

  send_recognize_request(signature, proxy: proxy)
end


115
116
117
118
119
120
121
# File 'lib/shazamio/shazam.rb', line 115

def related_tracks(track_id, limit: 20, offset: 0, proxy: nil)
  url = format(
    ShazamUrl::RELATED_SONGS, language: language, endpoint_country: endpoint_country,
                               limit: limit, offset: offset, track_id: track_id
  )
  http_client.request("GET", url, headers: headers, proxy: proxy)
end

#search_artist(query, limit: 10, offset: 0, proxy: nil) ⇒ Object



99
100
101
102
103
104
105
# File 'lib/shazamio/shazam.rb', line 99

def search_artist(query, limit: 10, offset: 0, proxy: nil)
  url = format(
    ShazamUrl::SEARCH_ARTIST, language: language, endpoint_country: endpoint_country,
                               limit: limit, offset: offset, query: cgi_escape(query)
  )
  http_client.request("GET", url, headers: headers, proxy: proxy)
end

#search_track(query, limit: 10, offset: 0, proxy: nil) ⇒ Object



107
108
109
110
111
112
113
# File 'lib/shazamio/shazam.rb', line 107

def search_track(query, limit: 10, offset: 0, proxy: nil)
  url = format(
    ShazamUrl::SEARCH_MUSIC, language: language, endpoint_country: endpoint_country,
                              limit: limit, offset: offset, query: cgi_escape(query)
  )
  http_client.request("GET", url, headers: headers, proxy: proxy)
end

#send_recognize_request(signature, proxy: nil) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/shazamio/shazam.rb', line 74

def send_recognize_request(signature, proxy: nil)
  body = Converter.data_search(
    Request::TIME_ZONE,
    signature.encode_to_uri,
    (signature.number_samples / signature.sample_rate_hz.to_f * 1000).to_i,
    (Time.now.to_f * 1000).to_i
  )

  url = format(
    ShazamUrl::SEARCH_FROM_FILE,
    language: language,
    device: Device.random,
    endpoint_country: endpoint_country,
    uuid_1: SecureRandom.uuid.upcase,
    uuid_2: SecureRandom.uuid.upcase
  )

  http_client.request("POST", url, headers: headers, json: body, proxy: proxy)
end

#track_about(track_id, proxy: nil) ⇒ Object



94
95
96
97
# File 'lib/shazamio/shazam.rb', line 94

def track_about(track_id, proxy: nil)
  url = format(ShazamUrl::ABOUT_TRACK, language: language, endpoint_country: endpoint_country, track_id: track_id)
  http_client.request("GET", url, headers: headers, proxy: proxy)
end