Skip to content

Commit 72ef6c9

Browse files
committed
Add Show support
1 parent e44fd91 commit 72ef6c9

15 files changed

+953
-0
lines changed

lib/rspotify.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ module RSpotify
1313
autoload :Playlist, 'rspotify/playlist'
1414
autoload :Recommendations, 'rspotify/recommendations'
1515
autoload :RecommendationSeed, 'rspotify/recommendation_seed'
16+
autoload :Show, 'rspotify/show'
1617
autoload :Track, 'rspotify/track'
1718
autoload :TrackLink, 'rspotify/track_link'
1819
autoload :User, 'rspotify/user'

lib/rspotify/episode.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ def initialize(options = {})
7474
@resume_point = options['resume_point'] || {}
7575
@uri = options['uri']
7676

77+
@show = if options['show']
78+
Show.new options['show']
79+
end
80+
7781
super(options)
7882
end
7983
end

lib/rspotify/show.rb

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
module RSpotify
2+
3+
# @attr [Array<String>] available_markets A list of the countries in which the show can be played, identified by their ISO 3166-1 alpha-2 code.
4+
# @attr [Array<Hash>] copyrights The copyright statements of the show.
5+
# @attr [String] description A description of the show. HTML tags are stripped away from this field, use html_description field in case HTML tags are needed.
6+
# @attr [Boolean] explicit Whether or not the show has explicit content (true = yes it does; false = no it does not OR unknown).
7+
# @attr [String] html_description A description of the show. This field may contain HTML tags.
8+
# @attr [Array<Hash>] images The cover art for the show in various sizes, widest first.
9+
# @attr [Boolean] is_externally_hosted True if all of the show’s episodes are hosted outside of Spotify’s CDN. This field might be null in some cases.
10+
# @attr [Array<String>] languages A list of the languages used in the show, identified by their ISO 639 code.
11+
# @attr [String] media_type The media type of the show.
12+
# @attr [String] name The name of the show.
13+
# @attr [String] publisher The publisher of the show.
14+
class Show < Base
15+
16+
# Returns Show object(s) with id(s) provided
17+
#
18+
# @param id [String, Array] Maximum: 50 IDs
19+
# @param market [String] An {https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 ISO 3166-1 alpha-2 country code}.
20+
# @return [Show, Array<Show>]
21+
#
22+
# @example
23+
# show = RSpotify::Show.find('3Z6JdCS2d0eFEpXHKI6WqH')
24+
# show.class #=> RSpotify::Show
25+
# show.name #=> "Consider This from NPR"
26+
def self.find(ids, market: nil )
27+
super(ids, 'show', market: market)
28+
end
29+
30+
# Returns array of Show objects matching the query. It's also possible to find the total number of search results for the query
31+
#
32+
# @param query [String] The search query's keywords. See the q description in {https://developer.spotify.com/web-api/search-item here} for details.
33+
# @param limit [Integer] Maximum number of shows to return. Maximum: 50. Default: 20.
34+
# @param offset [Integer] The index of the first show to return. Use with limit to get the next set of shows. Default: 0.
35+
# @param market [String] An {https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 ISO 3166-1 alpha-2 country code}.
36+
# @return [Array<Show>]
37+
#
38+
# @example
39+
# shows = RSpotify::Show.search('NPR')
40+
# shows = RSpotify::Show.search('NPR', market: 'US', limit: 10)
41+
#
42+
# RSpotify::Show.search('NPR').total #=> 357
43+
def self.search(query, limit: 20, offset: 0, market: nil)
44+
super(query, 'show', limit: limit, offset: offset, market: market)
45+
end
46+
47+
def initialize(options = {})
48+
@available_markets = options['available_markets']
49+
@copyrights = options['copyrights']
50+
@description = options['description']
51+
@explicit = options['explicit']
52+
@html_description = options['html_description']
53+
@images = options['images']
54+
@is_externally_hosted = options['is_externally_hosted']
55+
@languages = options['languages']
56+
@media_type = options['media_type']
57+
@name = options['name']
58+
@publisher = options['publisher']
59+
60+
episodes = options['episodes']['items'] if options['episodes']
61+
62+
@episodes_cache = if episodes
63+
episodes.map { |e| Episode.new e }
64+
end
65+
66+
super(options)
67+
end
68+
69+
# Returns array of episodes from the show
70+
#
71+
# @param limit [Integer] Maximum number of episodes to return. Maximum: 50. Default: 20.
72+
# @param offset [Integer] The index of the first track to return. Use with limit to get the next set of objects. Default: 0.
73+
# @param market [String] An {https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 ISO 3166-1 alpha-2 country code}.
74+
# @return [Array<Episode>]
75+
#
76+
# @example
77+
# show = RSpotify::Show.find('3Z6JdCS2d0eFEpXHKI6WqH')
78+
# show.episodes.first.name #=> "Colin Powell's Complicated Legacy"
79+
def episodes(limit: 20, offset: 0, market: nil )
80+
last_episode = offset + limit - 1
81+
if @episodes_cache && last_episode < 20 && !RSpotify.raw_response
82+
return @episodes_cache[offset..last_episode]
83+
end
84+
85+
url = "#{@href}/episodes?limit=#{limit}&offset=#{offset}"
86+
url << "&market=#{market}" if market
87+
88+
response = RSpotify.get url
89+
90+
json = RSpotify.raw_response ? JSON.parse(response) : response
91+
episodes = json['items']
92+
93+
episodes.map! { |e| Episode.new e }
94+
@episodes_cache = episodes if limit == 20 && offset == 0
95+
return response if RSpotify.raw_response
96+
episodes
97+
end
98+
99+
end
100+
end

spec/lib/rspotify/show_spec.rb

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
describe RSpotify::Show do
2+
describe 'Show::find receiving id as a string' do
3+
4+
before(:each) do
5+
@show = VCR.use_cassette('show:find:5CfCWKI5pZ28U0uOzXkDHe') do
6+
RSpotify::Show.find('5CfCWKI5pZ28U0uOzXkDHe')
7+
end
8+
end
9+
10+
it 'should find show with correct attributes' do
11+
expect(@show.available_markets) .to be_an Array
12+
expect(@show.copyrights) .to eq []
13+
expect(@show.external_urls['spotify']) .to eq 'https://open.spotify.com/show/5CfCWKI5pZ28U0uOzXkDHe'
14+
expect(@show.description) .to eq 'Candid conversations with entrepreneurs, artists, athletes, visionaries of all kinds—about their successes, and their failures, and what they learned from both. Hosted by Alex Blumberg, from Gimlet Media.'
15+
expect(@show.explicit) .to eq true
16+
expect(@show.html_description) .to eq '<p>Candid conversations with entrepreneurs, artists, athletes, visionaries of all kinds—about their successes, and their failures, and what they learned from both. Hosted by Alex Blumberg, from Gimlet Media.</p>'
17+
expect(@show.href) .to eq 'https://api.spotify.com/v1/shows/5CfCWKI5pZ28U0uOzXkDHe'
18+
expect(@show.id) .to eq '5CfCWKI5pZ28U0uOzXkDHe'
19+
expect(@show.images) .to include ({'height' => 640, 'width' => 640, 'url' => 'https://i.scdn.co/image/ab6765630000ba8a9d827f6e7e311b5947cce059'})
20+
expect(@show.is_externally_hosted) .to eq false
21+
expect(@show.languages) .to eq ["en"]
22+
expect(@show.media_type) .to eq "audio"
23+
expect(@show.name) .to eq "Without Fail"
24+
expect(@show.publisher) .to eq "Gimlet"
25+
expect(@show.type) .to eq 'show'
26+
expect(@show.uri) .to eq 'spotify:show:5CfCWKI5pZ28U0uOzXkDHe'
27+
end
28+
29+
it 'should find show with correct episodes' do
30+
episodes = @show.episodes
31+
expect(episodes) .to be_an Array
32+
expect(episodes.size) .to eq 20
33+
expect(episodes.first) .to be_an RSpotify::Episode
34+
expect(episodes.map(&:name)) .to include("Introducing Michelle Obama and Her Mentees")
35+
end
36+
end
37+
38+
describe 'Show::find receiving array of ids' do
39+
it 'should find the right shows' do
40+
ids = ['5CfCWKI5pZ28U0uOzXkDHe']
41+
shows = VCR.use_cassette('show:find_many:5CfCWKI5pZ28U0uOzXkDHe') do
42+
RSpotify::Show.find(ids)
43+
end
44+
expect(shows) .to be_an Array
45+
expect(shows.size) .to eq 1
46+
expect(shows.first) .to be_an RSpotify::Show
47+
expect(shows.map(&:name)) .to include("Without Fail")
48+
49+
ids << '5as3aKmN2k11yfDDDSrvaZ'
50+
shows = VCR.use_cassette('show:find_many:5CfCWKI5pZ28U0uOzXkDHe:5as3aKmN2k11yfDDDSrvaZ') do
51+
RSpotify::Show.find(ids)
52+
end
53+
expect(shows) .to be_an Array
54+
expect(shows.size) .to eq 2
55+
expect(shows.first) .to be_an RSpotify::Show
56+
expect(shows.map(&:name)) .to include("Giant Bombcast")
57+
end
58+
59+
it 'should find shows available in the given market' do
60+
ids = ['5CfCWKI5pZ28U0uOzXkDHe', '5as3aKmN2k11yfDDDSrvaZ']
61+
shows = VCR.use_cassette('show:find_many:5CfCWKI5pZ28U0uOzXkDHe:5as3aKmN2k11yfDDDSrvaZ:market:CA') do
62+
RSpotify::Show.find(ids, market: 'CA')
63+
end
64+
65+
expect(shows) .to be_an Array
66+
expect(shows.map(&:id)) .to include '5CfCWKI5pZ28U0uOzXkDHe'
67+
end
68+
end
69+
70+
describe 'Show::search' do
71+
it 'should search for the right shows' do
72+
shows = VCR.use_cassette('show:search:without fail') do
73+
RSpotify::Show.search('Without Fail')
74+
end
75+
expect(shows) .to be_an Array
76+
expect(shows.size) .to eq 20
77+
expect(shows.total) .to eq 233
78+
expect(shows.first) .to be_an RSpotify::Show
79+
expect(shows.map(&:name)) .to include('Without Fail', 'Teach Without a Burden')
80+
end
81+
82+
it 'should accept additional options' do
83+
shows = VCR.use_cassette('show:search:without fail:limit:10') do
84+
RSpotify::Show.search('Without Fail', limit: 10)
85+
end
86+
expect(shows.size) .to eq 10
87+
expect(shows.map(&:name)) .to include('Without Fail', 'Teach Without a Burden')
88+
89+
shows = VCR.use_cassette('show:search:without fail:offset:10') do
90+
RSpotify::Show.search('Without Fail', offset: 10)
91+
end
92+
expect(shows.size) .to eq 20
93+
expect(shows.map(&:name)) .to include('Weight Loss Mindset', 'Two In The Think Tank')
94+
95+
shows = VCR.use_cassette('show:search:without fail:offset:10:limit:10') do
96+
RSpotify::Show.search('Without Fail', limit: 10, offset: 10)
97+
end
98+
expect(shows.size) .to eq 10
99+
expect(shows.map(&:name)) .to include('Two In The Think Tank')
100+
101+
shows = VCR.use_cassette('show:search:without fail:market:ES') do
102+
RSpotify::Show.search('Without Fail', market: 'ES')
103+
end
104+
ES_shows = shows.select { |a| a.available_markets.include?('ES') }
105+
expect(ES_shows.length).to eq(shows.length)
106+
end
107+
end
108+
109+
describe '#episodes' do
110+
it 'should fetch more episodes' do
111+
show = VCR.use_cassette('show:find:5CfCWKI5pZ28U0uOzXkDHe') do
112+
RSpotify::Show.find('5CfCWKI5pZ28U0uOzXkDHe')
113+
end
114+
115+
episodes = VCR.use_cassette('show:find:5CfCWKI5pZ28U0uOzXkDHe:episodes') do
116+
show.episodes(offset: 20, limit: 20)
117+
end
118+
119+
expect(episodes) .to be_an Array
120+
expect(episodes.size) .to eq 20
121+
expect(episodes.first.name) .to eq 'Being an A$$hole: The Final Frontier for Women on the Screen'
122+
expect(episodes.first.id) .to eq '0DD6d3lmUjkIHzC13Z6fbs'
123+
end
124+
125+
it "should find episodes available in the given market" do
126+
show = VCR.use_cassette('show:find:5CfCWKI5pZ28U0uOzXkDHe') do
127+
RSpotify::Show.find('5CfCWKI5pZ28U0uOzXkDHe')
128+
end
129+
130+
episodes = VCR.use_cassette('show:find:5CfCWKI5pZ28U0uOzXkDHe:episodes:market:ES') do
131+
show.episodes(offset: 20, limit: 20, market: 'ES')
132+
end
133+
134+
expect(episodes.first.name) .to eq 'Being an A$$hole: The Final Frontier for Women on the Screen'
135+
expect(episodes.first.id) .to eq '0DD6d3lmUjkIHzC13Z6fbs'
136+
end
137+
end
138+
end

spec/vcr_cassettes/show_find_5CfCWKI5pZ28U0uOzXkDHe.yml

Lines changed: 66 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)