apple_music 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.env.example +4 -0
- data/.gitignore +4 -0
- data/.rubocop.yml +11 -10
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +50 -35
- data/README.md +223 -1
- data/apple_music.gemspec +2 -1
- data/bin/console +3 -9
- data/bin/setup +1 -0
- data/lib/apple_music.rb +36 -0
- data/lib/apple_music/activity.rb +52 -0
- data/lib/apple_music/activity/attributes.rb +19 -0
- data/lib/apple_music/activity/relationships.rb +16 -0
- data/lib/apple_music/album.rb +62 -0
- data/lib/apple_music/album/attributes.rb +50 -0
- data/lib/apple_music/album/relationships.rb +18 -0
- data/lib/apple_music/apple_curator.rb +10 -0
- data/lib/apple_music/apple_curator/attributes.rb +19 -0
- data/lib/apple_music/apple_curator/relationships.rb +16 -0
- data/lib/apple_music/artist.rb +67 -0
- data/lib/apple_music/artist/attributes.rb +19 -0
- data/lib/apple_music/artist/relationships.rb +20 -0
- data/lib/apple_music/artwork.rb +30 -0
- data/lib/apple_music/chart.rb +33 -0
- data/lib/apple_music/chart_response.rb +21 -0
- data/lib/apple_music/config.rb +45 -0
- data/lib/apple_music/connection.rb +45 -0
- data/lib/apple_music/curator.rb +52 -0
- data/lib/apple_music/curator/attributes.rb +19 -0
- data/lib/apple_music/curator/relationships.rb +16 -0
- data/lib/apple_music/editorial_notes.rb +13 -0
- data/lib/apple_music/error.rb +27 -0
- data/lib/apple_music/genre.rb +38 -0
- data/lib/apple_music/genre/attributes.rb +16 -0
- data/lib/apple_music/music_video.rb +76 -0
- data/lib/apple_music/music_video/attributes.rb +42 -0
- data/lib/apple_music/music_video/relationships.rb +18 -0
- data/lib/apple_music/play_parameters.rb +13 -0
- data/lib/apple_music/playlist.rb +57 -0
- data/lib/apple_music/playlist/attributes.rb +45 -0
- data/lib/apple_music/playlist/relationships.rb +17 -0
- data/lib/apple_music/preview.rb +13 -0
- data/lib/apple_music/relationship.rb +23 -0
- data/lib/apple_music/resource.rb +57 -0
- data/lib/apple_music/response.rb +29 -0
- data/lib/apple_music/search.rb +39 -0
- data/lib/apple_music/search_result.rb +20 -0
- data/lib/apple_music/song.rb +81 -0
- data/lib/apple_music/song/attributes.rb +39 -0
- data/lib/apple_music/song/relationships.rb +19 -0
- data/lib/apple_music/station.rb +38 -0
- data/lib/apple_music/station/attributes.rb +27 -0
- data/lib/apple_music/storefront.rb +32 -0
- data/lib/apple_music/storefront/attributes.rb +18 -0
- data/lib/apple_music/version.rb +1 -1
- metadata +66 -5
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppleMusic
|
4
|
+
# https://developer.apple.com/documentation/applemusicapi/chart
|
5
|
+
class Chart
|
6
|
+
attr_reader :chart, :data, :href, :name, :next
|
7
|
+
|
8
|
+
def initialize(props = {})
|
9
|
+
@chart = props['chart'] # required
|
10
|
+
@data = Array(props['data']).map { |attrs| Resource.build(attrs) } # required
|
11
|
+
@href = props['href'] # required
|
12
|
+
@name = props['name'] # required
|
13
|
+
@next = props['next']
|
14
|
+
end
|
15
|
+
|
16
|
+
class << self
|
17
|
+
# e.g. AppleMusic::Chart.list(types: ['songs', 'albums', 'playlists'], genre: 20, limit: 30)
|
18
|
+
# https://developer.apple.com/documentation/applemusicapi/get_catalog_charts
|
19
|
+
def list(**options)
|
20
|
+
raise ParameterMissing, 'required parameter :types is missing' unless options[:types]
|
21
|
+
|
22
|
+
types = options[:types].is_a?(Array) ? options[:types].join(',') : options[:types]
|
23
|
+
storefront = Storefront.lookup(options.delete(:storefront))
|
24
|
+
response = AppleMusic.get("catalog/#{storefront}/charts", options.merge(types: types))
|
25
|
+
ChartResponse.new(response.body['results'] || {})
|
26
|
+
end
|
27
|
+
|
28
|
+
def search(**_options)
|
29
|
+
warn 'WARN: :charts is not searchable resource'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppleMusic
|
4
|
+
# https://developer.apple.com/documentation/applemusicapi/chartresponse
|
5
|
+
class ChartResponse
|
6
|
+
attr_reader :albums, :music_videos, :songs, :playlists
|
7
|
+
|
8
|
+
def initialize(props = {})
|
9
|
+
@albums = build_chart(props['albums'])&.data || []
|
10
|
+
@music_videos = build_chart(props['music-videos'])&.data || []
|
11
|
+
@songs = build_chart(props['songs'])&.data || []
|
12
|
+
@playlists = build_chart(props['playlists'])&.data || []
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def build_chart(resources)
|
18
|
+
Array(resources).map { |props| Chart.new(props) }.first
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'faraday'
|
4
|
+
require 'jwt'
|
5
|
+
require 'openssl'
|
6
|
+
|
7
|
+
module AppleMusic
|
8
|
+
class Config
|
9
|
+
ALGORITHM = 'ES256'
|
10
|
+
TOKEN_EXPIRATION_TIME = 60 * 60 * 24 # 1.day
|
11
|
+
DEFAULT_STOREFRONT = 'us'
|
12
|
+
|
13
|
+
attr_accessor :secret_key, :secret_key_path, :team_id, :music_id,
|
14
|
+
:token_expiration_time, :adapter, :storefront
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@secret_key_path = ENV['APPLE_MUSIC_SECRET_KEY_PATH']
|
18
|
+
@secret_key = ENV['APPLE_MUSIC_SECRET_KEY']
|
19
|
+
@team_id = ENV['APPLE_MUSIC_TEAM_ID']
|
20
|
+
@music_id = ENV['APPLE_MUSIC_MUSIC_ID']
|
21
|
+
@token_expiration_time = TOKEN_EXPIRATION_TIME
|
22
|
+
@adapter = Faraday.default_adapter
|
23
|
+
@storefront = ENV.fetch('APPLE_MUSIC_STOREFRONT') { DEFAULT_STOREFRONT }
|
24
|
+
end
|
25
|
+
|
26
|
+
def authentication_token
|
27
|
+
private_key = OpenSSL::PKey::EC.new(apple_music_secret_key)
|
28
|
+
JWT.encode(authentication_payload, private_key, ALGORITHM, kid: music_id)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def apple_music_secret_key
|
34
|
+
@secret_key ||= File.read(secret_key_path)
|
35
|
+
end
|
36
|
+
|
37
|
+
def authentication_payload(now = Time.now)
|
38
|
+
{
|
39
|
+
iss: team_id,
|
40
|
+
iat: now.to_i,
|
41
|
+
exp: now.to_i + token_expiration_time
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'faraday'
|
4
|
+
require 'faraday_middleware'
|
5
|
+
|
6
|
+
require 'apple_music/config'
|
7
|
+
|
8
|
+
module AppleMusic
|
9
|
+
class ApiError < StandardError; end
|
10
|
+
class ParameterMissing < StandardError; end
|
11
|
+
|
12
|
+
API_URI = 'https://api.music.apple.com/v1/'
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def config
|
16
|
+
@config ||= Config.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def configure(&block)
|
20
|
+
block.call(config)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def client
|
26
|
+
@client ||= Faraday.new(API_URI) do |conn|
|
27
|
+
conn.response :json, content_type: /\bjson\z/
|
28
|
+
conn.headers['Authorization'] = "Bearer #{config.authentication_token}"
|
29
|
+
conn.adapter config.adapter
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def method_missing(name, *args, &block)
|
34
|
+
if client.respond_to?(name)
|
35
|
+
client.send(name, *args, &block)
|
36
|
+
else
|
37
|
+
super
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def respond_to_missing?(name, include_private = false)
|
42
|
+
client.respond_to?(name, include_private)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppleMusic
|
4
|
+
# https://developer.apple.com/documentation/applemusicapi/curator
|
5
|
+
class Curator < Resource
|
6
|
+
class << self
|
7
|
+
# e.g. AppleMusic::Curator.find(1107687517)
|
8
|
+
# https://developer.apple.com/documentation/applemusicapi/get_a_catalog_curator
|
9
|
+
def find(id, **options)
|
10
|
+
storefront = Storefront.lookup(options.delete(:storefront))
|
11
|
+
response = AppleMusic.get("catalog/#{storefront}/curators/#{id}", options)
|
12
|
+
Response.new(response.body).data.first
|
13
|
+
end
|
14
|
+
|
15
|
+
# e.g. AppleMusic::Curator.list(ids: [976439448, 1107687517])
|
16
|
+
def list(**options)
|
17
|
+
raise ParameterMissing, 'required parameter :ids is missing' unless options[:ids]
|
18
|
+
|
19
|
+
get_collection_by_ids(options.delete(:ids), options)
|
20
|
+
end
|
21
|
+
|
22
|
+
# e.g. AppleMusic::Curator.get_collection_by_ids([976439448, 1107687517])
|
23
|
+
# https://developer.apple.com/documentation/applemusicapi/get_multiple_catalog_curators
|
24
|
+
def get_collection_by_ids(ids, **options)
|
25
|
+
ids = ids.is_a?(Array) ? ids.join(',') : ids
|
26
|
+
storefront = Storefront.lookup(options.delete(:storefront))
|
27
|
+
response = AppleMusic.get("catalog/#{storefront}/curators", options.merge(ids: ids))
|
28
|
+
Response.new(response.body).data
|
29
|
+
end
|
30
|
+
|
31
|
+
# e.g. AppleMusic::Curator.get_relationship(976439448, :playlists)
|
32
|
+
# https://developer.apple.com/documentation/applemusicapi/get_a_catalog_curator_s_relationship_directly_by_name
|
33
|
+
def get_relationship(id, relationship_type, **options)
|
34
|
+
storefront = Storefront.lookup(options.delete(:storefront))
|
35
|
+
response = AppleMusic.get("catalog/#{storefront}/curators/#{id}/#{relationship_type}", options)
|
36
|
+
Response.new(response.body).data
|
37
|
+
end
|
38
|
+
|
39
|
+
# e.g. AppleMusic::Curator.related_playlists(976439448)
|
40
|
+
def related_playlists(id, **options)
|
41
|
+
get_relationship(id, :playlists, options)
|
42
|
+
end
|
43
|
+
|
44
|
+
def search(term, **options)
|
45
|
+
AppleMusic.search(**options.merge(term: term, types: :curators)).curators
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
require 'apple_music/curator/attributes'
|
52
|
+
require 'apple_music/curator/relationships'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppleMusic
|
4
|
+
class Curator < Resource
|
5
|
+
# https://developer.apple.com/documentation/applemusicapi/curator/attributes
|
6
|
+
class Attributes
|
7
|
+
attr_reader :artwork, :editorial_notes, :name, :url
|
8
|
+
|
9
|
+
def initialize(props = {})
|
10
|
+
@artwork = Artwork.new(props['artwork']) # required
|
11
|
+
@editorial_notes = EditorialNotes.new(props['editorialNotes']) if props['editorialNotes']
|
12
|
+
@name = props['name'] # required
|
13
|
+
@url = props['url'] # required
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
self.attributes_model = self::Attributes
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppleMusic
|
4
|
+
class Curator < Resource
|
5
|
+
# https://developer.apple.com/documentation/applemusicapi/curator/relationships
|
6
|
+
class Curator::Relationships
|
7
|
+
attr_reader :playlists
|
8
|
+
|
9
|
+
def initialize(props = {})
|
10
|
+
@playlists = Relationship.new(props['playlists']).data
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
self.relationships_model = self::Relationships
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppleMusic
|
4
|
+
# https://developer.apple.com/documentation/applemusicapi/editorialnotes
|
5
|
+
class EditorialNotes
|
6
|
+
attr_reader :short, :standard
|
7
|
+
|
8
|
+
def initialize(props = {})
|
9
|
+
@short = props['short'] # required
|
10
|
+
@standard = props['standard'] # required
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppleMusic
|
4
|
+
# https://developer.apple.com/documentation/applemusicapi/error
|
5
|
+
class Error
|
6
|
+
attr_reader :code, :detail, :id, :source, :status, :title
|
7
|
+
|
8
|
+
def initialize(props = {})
|
9
|
+
@code = props['code'] # required
|
10
|
+
@detail = props['detail']
|
11
|
+
@id = props['id'] # required
|
12
|
+
@source = Source.new(props['source']) if props['source']
|
13
|
+
@status = props['status'] # required
|
14
|
+
@title = props['title'] # required
|
15
|
+
end
|
16
|
+
|
17
|
+
# https://developer.apple.com/documentation/applemusicapi/error/source
|
18
|
+
class Source
|
19
|
+
attr_reader :parameter, :pointer
|
20
|
+
|
21
|
+
def initialize(options = {})
|
22
|
+
@parameter = options['parameter']
|
23
|
+
@pointer = options['pointer']
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppleMusic
|
4
|
+
# https://developer.apple.com/documentation/applemusicapi/genre
|
5
|
+
class Genre < Resource
|
6
|
+
class << self
|
7
|
+
# e.g. AppleMusic::Genre.find(14)
|
8
|
+
# https://developer.apple.com/documentation/applemusicapi/get_a_catalog_genre
|
9
|
+
# https://developer.apple.com/documentation/applemusicapi/get_a_catalog_song
|
10
|
+
def find(id, **options)
|
11
|
+
storefront = Storefront.lookup(options.delete(:storefront))
|
12
|
+
response = AppleMusic.get("catalog/#{storefront}/genres/#{id}", options)
|
13
|
+
Response.new(response.body).data.first
|
14
|
+
end
|
15
|
+
|
16
|
+
# e.g. AppleMusic::Genre.list
|
17
|
+
# e.g. AppleMusic::Genre.list(ids: [20, 34])
|
18
|
+
# https://developer.apple.com/documentation/applemusicapi/get_catalog_top_charts_genres
|
19
|
+
# https://developer.apple.com/documentation/applemusicapi/get_multiple_catalog_genres
|
20
|
+
def list(**options)
|
21
|
+
if options[:ids]
|
22
|
+
ids = options[:ids].is_a?(Array) ? options[:ids].join(',') : options[:ids]
|
23
|
+
options[:ids] = ids
|
24
|
+
end
|
25
|
+
|
26
|
+
storefront = Storefront.lookup(options.delete(:storefront))
|
27
|
+
response = AppleMusic.get("catalog/#{storefront}/genres", options)
|
28
|
+
Response.new(response.body).data
|
29
|
+
end
|
30
|
+
|
31
|
+
def search(**_options)
|
32
|
+
warn 'WARN: :genres is not searchable resource'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
require 'apple_music/genre/attributes'
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppleMusic
|
4
|
+
class Genre < Resource
|
5
|
+
# https://developer.apple.com/documentation/applemusicapi/genre/attributes
|
6
|
+
class Attributes
|
7
|
+
attr_reader :name
|
8
|
+
|
9
|
+
def initialize(props = {})
|
10
|
+
@name = props['name'] # required
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
self.attributes_model = self::Attributes
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppleMusic
|
4
|
+
# https://developer.apple.com/documentation/applemusicapi/musicvideo
|
5
|
+
class MusicVideo < Resource
|
6
|
+
class << self
|
7
|
+
# e.g. AppleMusic::MusicVideo.find(401135199)
|
8
|
+
# https://developer.apple.com/documentation/applemusicapi/get_a_catalog_music_video
|
9
|
+
def find(id, **options)
|
10
|
+
storefront = Storefront.lookup(options.delete(:storefront))
|
11
|
+
response = AppleMusic.get("catalog/#{storefront}/music-videos/#{id}", options)
|
12
|
+
Response.new(response.body).data.first
|
13
|
+
end
|
14
|
+
|
15
|
+
# e.g. AppleMusic::MusicVideo.list(ids: [401135199, 401147268])
|
16
|
+
# e.g. AppleMusic::MusicVideo.list(isrc: 'GBDCE0900012')
|
17
|
+
def list(**options)
|
18
|
+
if options[:ids]
|
19
|
+
get_collection_by_ids(options.delete(:ids), options)
|
20
|
+
elsif options[:isrc]
|
21
|
+
get_collection_by_isrc(options.delete(:isrc), options)
|
22
|
+
else
|
23
|
+
raise ParameterMissing, 'required parameter :ids or :isrc is missing'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# e.g. AppleMusic::MusicVideo.get_collection_by_ids([401135199, 401147268])
|
28
|
+
# https://developer.apple.com/documentation/applemusicapi/get_multiple_catalog_music_videos_by_id
|
29
|
+
def get_collection_by_ids(ids, **options)
|
30
|
+
ids = ids.is_a?(Array) ? ids.join(',') : ids
|
31
|
+
storefront = Storefront.lookup(options.delete(:storefront))
|
32
|
+
response = AppleMusic.get("catalog/#{storefront}/music-videos", options.merge(ids: ids))
|
33
|
+
Response.new(response.body).data
|
34
|
+
end
|
35
|
+
|
36
|
+
# e.g. AppleMusic::MusicVideo.get_collection_by_isrc('GBDCE0900012')
|
37
|
+
# https://developer.apple.com/documentation/applemusicapi/get_multiple_catalog_music_videos_by_isrc
|
38
|
+
def get_collection_by_isrc(isrc, **options)
|
39
|
+
isrc = isrc.is_a?(Array) ? isrc.join(',') : isrc
|
40
|
+
storefront = Storefront.lookup(options.delete(:storefront))
|
41
|
+
response = AppleMusic.get("catalog/#{storefront}/music-videos", options.merge('filter[isrc]': isrc))
|
42
|
+
Response.new(response.body).data
|
43
|
+
end
|
44
|
+
|
45
|
+
# e.g. AppleMusic::MusicVideo.get_relationship(401135199, :albums)
|
46
|
+
# https://developer.apple.com/documentation/applemusicapi/get_a_catalog_music_video_s_relationship_directly_by_name
|
47
|
+
def get_relationship(id, relationship_type, **options)
|
48
|
+
storefront = Storefront.lookup(options.delete(:storefront))
|
49
|
+
response = AppleMusic.get("catalog/#{storefront}/music-videos/#{id}/#{relationship_type}", options)
|
50
|
+
Response.new(response.body).data
|
51
|
+
end
|
52
|
+
|
53
|
+
# e.g. AppleMusic::MusicVideo.related_albums(401135199)
|
54
|
+
def related_albums(id, **options)
|
55
|
+
get_relationship(id, :albums, options)
|
56
|
+
end
|
57
|
+
|
58
|
+
# e.g. AppleMusic::MusicVideo.related_artists(401135199)
|
59
|
+
def related_artists(id, **options)
|
60
|
+
get_relationship(id, :artists, options)
|
61
|
+
end
|
62
|
+
|
63
|
+
# e.g. AppleMusic::MusicVideo.related_genres(401135199)
|
64
|
+
def related_genres(id, **options)
|
65
|
+
get_relationship(id, :genres, options)
|
66
|
+
end
|
67
|
+
|
68
|
+
def search(term, **options)
|
69
|
+
AppleMusic.search(**options.merge(term: term, types: 'music-videos')).music_videos
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
require 'apple_music/music_video/attributes'
|
76
|
+
require 'apple_music/music_video/relationships'
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppleMusic
|
4
|
+
class MusicVideo < Resource
|
5
|
+
# https://developer.apple.com/documentation/applemusicapi/musicvideo/attributes
|
6
|
+
class Attributes
|
7
|
+
attr_reader :album_name, :artist_name, :artwork, :content_rating, :duration_in_millis,
|
8
|
+
:editorial_notes, :genre_names, :isrc, :name, :play_params, :previews,
|
9
|
+
:release_date, :track_number, :url, :video_sub_type, :has_hdr, :has_4k
|
10
|
+
|
11
|
+
def initialize(props = {})
|
12
|
+
@album_name = props['albumName']
|
13
|
+
@artist_name = props['artistName'] # required
|
14
|
+
@artwork = Artwork.new(props['artwork']) # required
|
15
|
+
@content_rating = props['contentRating']
|
16
|
+
@duration_in_millis = props['durationInMillis']
|
17
|
+
@editorial_notes = EditorialNotes.new(props['editorialNotes']) if props['editorialNotes']
|
18
|
+
@genre_names = props['genreNames'] # required
|
19
|
+
@isrc = props['isrc'] # required
|
20
|
+
@name = props['name'] # required
|
21
|
+
@play_params = PlayParameters.new(props['playParams']) if props['playParams']
|
22
|
+
@previews = Array(props['previews']).map { |attrs| Preview.new(attrs) } # required
|
23
|
+
@release_date = Date.parse(props['releaseDate']) # required
|
24
|
+
@track_number = props['trackNumber']
|
25
|
+
@url = props['url'] # required
|
26
|
+
@video_sub_type = props['videoSubType']
|
27
|
+
@has_hdr = props['hasHDR'] # required
|
28
|
+
@has_4k = props['has4K'] # required
|
29
|
+
end
|
30
|
+
|
31
|
+
def has_hdr?
|
32
|
+
has_hdr
|
33
|
+
end
|
34
|
+
|
35
|
+
def has_4k?
|
36
|
+
has_4k
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
self.attributes_model = self::Attributes
|
41
|
+
end
|
42
|
+
end
|