apple_music_client 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9d166b694f4a2075905d1060763fea4b8d6c2d922505364b5bc0ca9a81d4dbd9
4
+ data.tar.gz: c7baf1770de42a4d6655f34407e2eee3e6611e0a02efa016dbf55632aabf0c12
5
+ SHA512:
6
+ metadata.gz: b5c2f7ad3442bd16f0f9541f4e6fbea51ac6e2a2d3be8b7ed56ae67d928ebd85abcca1c2beae8d6761836775ea3c1ef1eba58ff7bd9c1fdd637ca588f6675a3c
7
+ data.tar.gz: 81e2be6832ee559eca83fa0a080a1b8fd2849ae93161888f4e0b852526a7a204a0a263f04ef783f3ae8959e1bf56f90de0b37527880e699ed8c80266139e74de
@@ -0,0 +1,2 @@
1
+ require_relative './storeClient'
2
+ require_relative './libraryClient'
data/lib/client.rb ADDED
@@ -0,0 +1,92 @@
1
+ require 'jwt'
2
+ require 'httparty'
3
+ require 'time'
4
+
5
+ module AppleMusic
6
+
7
+ # THANKS https://medium.com/@defv/connecting-to-the-apple-music-api-from-a-ruby-on-rails-application-eba9d12f5cf9
8
+ class TokenFactory
9
+
10
+ def self.generate(secret_key_path:, team_id:, key_id:)
11
+ ecdsa_key = OpenSSL::PKey::EC.new File.read(secret_key_path)
12
+ ecdsa_public = OpenSSL::PKey::EC.new ecdsa_key
13
+ ecdsa_public.private_key = nil
14
+ JWT.encode TokenFactory.authentication_payload(team_id), ecdsa_public, 'ES256', { kid: key_id }
15
+ end
16
+
17
+ private
18
+
19
+ def self.authentication_payload(team_id)
20
+ {
21
+ iss: team_id,
22
+ iat: Time.now.to_i - 100,
23
+ exp: Time.now.to_i + 12000
24
+ }
25
+ end
26
+
27
+ end
28
+
29
+ class Client
30
+
31
+ def initialize(token)
32
+ @token = token
33
+ end
34
+
35
+ def get(resource)
36
+ response = HTTParty.get(
37
+ "https://api.music.apple.com#{resource}",
38
+ {headers: headers})
39
+
40
+ if response.code == 200
41
+ JSON.parse(response.body)
42
+ else
43
+ puts "NON 200 CODE for resource #{resource}"
44
+ puts response
45
+ end
46
+ end
47
+
48
+ def post(resource)
49
+ HTTParty.post(
50
+ "https://api.music.apple.com#{resource}",
51
+ {headers: headers}
52
+ )
53
+ end
54
+
55
+ def headers
56
+ {
57
+ 'Authorization': "Bearer #{@token}"
58
+ }
59
+ end
60
+
61
+ end
62
+
63
+ class PaginatedResponse
64
+ include Enumerable
65
+
66
+ def initialize(client, response)
67
+ @client = client
68
+ @response = response
69
+ end
70
+
71
+ def each(&block)
72
+ return to_enum(:each) unless block_given?
73
+ return if @response.nil? or @response["data"].nil?
74
+
75
+ @response["data"].each(&block)
76
+ return if @response["next"].nil?
77
+ PaginatedResponse.new(@client, @client.get(@response["next"])).each(&block)
78
+ end
79
+
80
+ end
81
+
82
+
83
+ class DataType < Struct
84
+ def initialize(args)
85
+ args.merge(args['attributes'])
86
+ .filter { |k,_| members.include?(k.to_sym) }
87
+ .each { |k,v| public_send("#{k}=", v) }
88
+ freeze
89
+ end
90
+ end
91
+
92
+ end
@@ -0,0 +1,26 @@
1
+ require_relative './client'
2
+
3
+ module AppleMusic
4
+
5
+ class LibraryClient < Client
6
+
7
+ def initialize(token, user_token)
8
+ super(token)
9
+ @user_token = user_token
10
+ end
11
+
12
+ def get_user_artists
13
+ PaginatedResponse.new(self, get("/v1/me/library/artists"))
14
+ end
15
+
16
+ def add_to_library(album:)
17
+ post("/v1/me/library?ids[albums]=#{album}")
18
+ end
19
+
20
+ def headers
21
+ super.merge({ 'Music-User-Token': @user_token })
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -0,0 +1,54 @@
1
+ require 'erb'
2
+ require 'json'
3
+ require 'date'
4
+ require_relative './client'
5
+
6
+ module AppleMusic
7
+
8
+ class StoreClient < Client
9
+
10
+ def find_artist(artist_name:)
11
+ response = get_catalog("search?term=#{escape(artist_name)}&types=artists")
12
+ parse(response.dig("results", "artists", "data"))[0]
13
+ end
14
+
15
+ def get_artist(artist_id:)
16
+ response = get_catalog("artists/#{artist_id}")
17
+ parse(response["data"])[0]
18
+ end
19
+
20
+ def get_albums(artist:)
21
+ response = PaginatedResponse.new(self, get("/v1/catalog/us/artists/#{artist.id}/albums?limit=100"))
22
+ parse(response).sort_by { |album| album.releaseDate }.reverse
23
+ end
24
+
25
+ private
26
+
27
+ def escape(term)
28
+ ERB::Util.url_encode(term)
29
+ end
30
+
31
+ def get_catalog(resource)
32
+ get("/v1/catalog/us/#{resource}")
33
+ end
34
+
35
+ def parse(payload)
36
+ return [] if payload.nil?
37
+
38
+ payload.map do |value|
39
+ if value["type"] == "artists"
40
+ Artist.new(value)
41
+ elsif value["type"] == "albums"
42
+ Album.new(value)
43
+ else
44
+ puts "Unknown type:", value
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ Artist = DataType.new(:id, :name)
51
+ Album = DataType.new(:id, :name, :isSingle, :releaseDate)
52
+
53
+
54
+ end
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: apple_music_client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Kaeden Wile
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-05-08 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/apple_music_client.rb
20
+ - lib/client.rb
21
+ - lib/libraryClient.rb
22
+ - lib/storeClient.rb
23
+ homepage: https://rubygems.org/gems/apple_music_client
24
+ licenses:
25
+ - MIT
26
+ metadata: {}
27
+ post_install_message:
28
+ rdoc_options: []
29
+ require_paths:
30
+ - lib
31
+ required_ruby_version: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ required_rubygems_version: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubygems_version: 3.1.4
43
+ signing_key:
44
+ specification_version: 4
45
+ summary: Client for access to Apple Music APIs
46
+ test_files: []