jarvisbot_songfinder 1.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.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +2 -0
  5. data/Gemfile +6 -0
  6. data/Gemfile.lock +122 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +91 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +24 -0
  11. data/bin/setup +8 -0
  12. data/fixtures/vcr_cassettes/query_text.yml +211 -0
  13. data/fixtures/vcr_cassettes/query_track_delegation.yml +211 -0
  14. data/fixtures/vcr_cassettes/query_youtube_url.yml +140 -0
  15. data/fixtures/vcr_cassettes/search_query_auxiliary_provider.yml +517 -0
  16. data/fixtures/vcr_cassettes/search_query_not_found.yml +111 -0
  17. data/fixtures/vcr_cassettes/search_query_preferred_and_auxiliary.yml +211 -0
  18. data/fixtures/vcr_cassettes/search_query_preferred_provider.yml +211 -0
  19. data/fixtures/vcr_cassettes/spotify_invalid_region_restricted.yml +55 -0
  20. data/fixtures/vcr_cassettes/spotify_invalid_search.yml +55 -0
  21. data/fixtures/vcr_cassettes/spotify_invalid_too_long.yml +55 -0
  22. data/fixtures/vcr_cassettes/spotify_valid.yml +55 -0
  23. data/fixtures/vcr_cassettes/spotify_valid_clean_or_unknown.yml +55 -0
  24. data/fixtures/vcr_cassettes/spotify_valid_explicit.yml +55 -0
  25. data/fixtures/vcr_cassettes/spotify_valid_search.yml +107 -0
  26. data/fixtures/vcr_cassettes/spotify_vcr_test.yml +55 -0
  27. data/fixtures/vcr_cassettes/url_query_known_provider.yml +187 -0
  28. data/fixtures/vcr_cassettes/youtube_invalid.yml +58 -0
  29. data/fixtures/vcr_cassettes/youtube_invalid_region_restricted.yml +147 -0
  30. data/fixtures/vcr_cassettes/youtube_invalid_regionrestricted.yml +147 -0
  31. data/fixtures/vcr_cassettes/youtube_invalid_search.yml +59 -0
  32. data/fixtures/vcr_cassettes/youtube_invalid_too_long.yml +140 -0
  33. data/fixtures/vcr_cassettes/youtube_invalid_wrong_category.yml +254 -0
  34. data/fixtures/vcr_cassettes/youtube_invalid_wrongcategory.yml +254 -0
  35. data/fixtures/vcr_cassettes/youtube_valid.yml +427 -0
  36. data/fixtures/vcr_cassettes/youtube_valid_search.yml +287 -0
  37. data/jarvisbot_songfinder.gemspec +52 -0
  38. data/lib/jarvisbot_songfinder.rb +21 -0
  39. data/lib/jarvisbot_songfinder/configuration.rb +28 -0
  40. data/lib/jarvisbot_songfinder/helpers/query.rb +34 -0
  41. data/lib/jarvisbot_songfinder/helpers/reply_message.rb +101 -0
  42. data/lib/jarvisbot_songfinder/helpers/search_query.rb +21 -0
  43. data/lib/jarvisbot_songfinder/helpers/url_query.rb +22 -0
  44. data/lib/jarvisbot_songfinder/providers/bandrequest.rb +36 -0
  45. data/lib/jarvisbot_songfinder/providers/provider.rb +64 -0
  46. data/lib/jarvisbot_songfinder/providers/spotify_api.rb +93 -0
  47. data/lib/jarvisbot_songfinder/providers/unknown_provider.rb +13 -0
  48. data/lib/jarvisbot_songfinder/providers/unknown_search_provider.rb +13 -0
  49. data/lib/jarvisbot_songfinder/providers/youtube_api.rb +137 -0
  50. data/lib/jarvisbot_songfinder/version.rb +3 -0
  51. metadata +237 -0
@@ -0,0 +1,21 @@
1
+ module JarvisbotSongfinder
2
+ class SearchQuery
3
+ def initialize(query)
4
+ @query = query
5
+ @provider = select_provider
6
+ end
7
+
8
+ def track
9
+ @provider
10
+ end
11
+
12
+ private
13
+
14
+ def select_provider
15
+ provider = Provider.available_providers.find do |p|
16
+ p.from_search @query
17
+ end
18
+ provider.nil? ? UnknownSearchProvider.new : provider.from_search(@query)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,22 @@
1
+ module JarvisbotSongfinder
2
+ class UrlQuery
3
+ def initialize(url)
4
+ @url = url
5
+ @provider = select_provider
6
+ end
7
+
8
+ def track
9
+ @provider
10
+ end
11
+
12
+ private
13
+
14
+ def select_provider
15
+ # TODO: redo with .find instead of .select
16
+ provider = Provider.available_providers.find do |p|
17
+ p::URL_REGEX.match @url
18
+ end
19
+ provider.nil? ? UnknownProvider.new : provider.new(@url)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,36 @@
1
+ module JarvisbotSongfinder
2
+ class Bandrequest < Provider
3
+ def initialize(band)
4
+ super()
5
+ @band = band
6
+ end
7
+
8
+ def length
9
+ 0
10
+ end
11
+
12
+ def title
13
+ ""
14
+ end
15
+
16
+ def artist
17
+ @band
18
+ end
19
+
20
+ def provider
21
+ "bandrequest"
22
+ end
23
+
24
+ def url
25
+ "https://www.last.fm/search?q=#{@band}"
26
+ end
27
+
28
+ def explicit?
29
+ false
30
+ end
31
+
32
+ def valid?
33
+ true
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,64 @@
1
+ module JarvisbotSongfinder
2
+ class Provider
3
+ @available_providers ||= []
4
+ class << self
5
+ attr_accessor :available_providers
6
+ end
7
+
8
+ attr_reader :errors
9
+ def initialize
10
+ @errors = []
11
+ end
12
+
13
+ def length
14
+ raise NotImplementedError
15
+ end
16
+
17
+ def title
18
+ raise NotImplementedError
19
+ end
20
+
21
+ def artist
22
+ raise NotImplementedError
23
+ end
24
+
25
+ def provider
26
+ raise NotImplementedError
27
+ end
28
+
29
+ def valid?
30
+ return false if @errors.any?
31
+ available_in_region? && not_too_long? && in_music_category?
32
+ end
33
+
34
+ def url
35
+ raise NotImplementedError
36
+ end
37
+
38
+ def explicit?
39
+ raise NotImplementedError
40
+ end
41
+
42
+ private
43
+
44
+ def add_error(error)
45
+ @errors << error unless @errors.include? error
46
+ end
47
+
48
+ def available_in_region?
49
+ raise NotImplementedError
50
+ end
51
+
52
+ def not_too_long?
53
+ length < 600
54
+ end
55
+
56
+ def in_music_category?
57
+ raise NotImplementedError
58
+ end
59
+
60
+ def get_track
61
+ raise NotImplementedError
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,93 @@
1
+ module JarvisbotSongfinder
2
+ class SpotifyAPI < Provider
3
+ Provider.available_providers << self
4
+ ID_REGEX = /\Ahttps?:\/\/(?:embed\.|open\.)(?:spotify\.com\/)(?:track\/|\?uri=spotify:track:)((\w|-){22})/
5
+ URL_REGEX = /spotify\.com/
6
+
7
+ def initialize(url)
8
+ super()
9
+ @track_id = get_track_id(url)
10
+ check_id_validity
11
+ valid? unless @errors.any?
12
+ end
13
+
14
+ def self.from_search(query)
15
+ results = RSpotify::Track.search(query)
16
+ if results.any?
17
+ link = "https://open.spotify.com/track/#{results.first.id}"
18
+ return self.new(link)
19
+ else
20
+ return nil
21
+ end
22
+ end
23
+
24
+ def length
25
+ @track.duration_ms / 1000
26
+ end
27
+
28
+ def title
29
+ @track.name
30
+ end
31
+
32
+ def artist
33
+ @track.artists.first.name
34
+ end
35
+
36
+ def url
37
+ "https://open.spotify.com/track/#{@track.id}"
38
+ end
39
+
40
+ def provider
41
+ "spotify"
42
+ end
43
+
44
+ def explicit?
45
+ @track.explicit
46
+ end
47
+
48
+ private
49
+
50
+ # :nocov:
51
+ def get_track_id(url)
52
+ if !ID_REGEX.match(url)
53
+ add_error ReplyMessage::Request.invalid_video_id
54
+ return nil
55
+ else
56
+ ID_REGEX.match(url)[1]
57
+ end
58
+ end
59
+
60
+ def check_id_validity
61
+ begin
62
+ @track = RSpotify::Track.find(@track_id)
63
+ rescue RestClient::BadRequest => e
64
+ add_error ReplyMessage::Request.invalid_video_id
65
+ end
66
+ end
67
+ # :nocov:
68
+
69
+ def in_music_category?
70
+ true
71
+ end
72
+
73
+ def not_too_long?
74
+ if length < 600
75
+ return true
76
+ else
77
+ add_error ReplyMessage::Request.too_long
78
+ return false
79
+ end
80
+ end
81
+
82
+ def available_in_region?
83
+ return true if @track.available_markets.empty?
84
+
85
+ if @track.available_markets.include? JarvisbotSongfinder.configuration.region
86
+ return true
87
+ else
88
+ add_error ReplyMessage::Request.region_restricted
89
+ return false
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,13 @@
1
+ module JarvisbotSongfinder
2
+ class UnknownProvider
3
+ attr_reader :errors
4
+
5
+ def initialize
6
+ @errors = [ReplyMessage::Request.unknown_provider]
7
+ end
8
+
9
+ def valid?
10
+ false
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module JarvisbotSongfinder
2
+ class UnknownSearchProvider
3
+ attr_reader :errors
4
+
5
+ def initialize
6
+ @errors = [ReplyMessage::Search.not_found]
7
+ end
8
+
9
+ def valid?
10
+ false
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,137 @@
1
+ module JarvisbotSongfinder
2
+ class YoutubeAPI < Provider
3
+ Provider.available_providers << self
4
+ ID_REGEX = /\A((?:https?:)?\/\/)?((?:www|m)\.)?((?:youtube\.com|youtu\.be))(\/(?:[\w\-]+\?v=|embed\/|v\/)?)([\w\-]+)(\S+)?/
5
+ URL_REGEX = /youtube\.com|youtu\.be/
6
+
7
+ def initialize(url)
8
+ super()
9
+ @track_id = get_track_id(url)
10
+ @track = Yt::Video.new(id: @track_id) # unless @track_id.nil?
11
+ check_id_validity
12
+ valid? unless @errors.any?
13
+ end
14
+
15
+ def self.from_search(query)
16
+ videos = Yt::Collections::Videos.new
17
+ params = {q: query, order: "relevance", video_category_id: 10}
18
+ if track_id = videos.where(params)&.first&.id
19
+ link = "https://www.youtube.com/watch?v=#{track_id}"
20
+ return self.new(link)
21
+ else
22
+ return nil
23
+ end
24
+ end
25
+
26
+ def title
27
+ @track.title
28
+ end
29
+
30
+ def length
31
+ @track.duration
32
+ end
33
+
34
+ def artist
35
+ @track.channel_title
36
+ end
37
+
38
+ def url
39
+ "https://www.youtube.com/watch?v=#{@track_id}"
40
+ end
41
+
42
+ def provider
43
+ "youtube"
44
+ end
45
+
46
+ def explicit?
47
+ # no way to know
48
+ false
49
+ end
50
+
51
+ private
52
+
53
+ # :nocov:
54
+ def get_track_id(url)
55
+ if !ID_REGEX.match(url)
56
+ add_error ReplyMessage::Request.invalid_video_id
57
+ return nil
58
+ else
59
+ ID_REGEX.match(url)[5]
60
+ end
61
+ end
62
+
63
+ def check_id_validity
64
+ begin
65
+ @track.empty?
66
+ rescue Yt::Errors::NoItems => e
67
+ add_error ReplyMessage::Request.invalid_video_id
68
+ end
69
+ end
70
+
71
+ def not_too_long?
72
+ if @track.duration < 600
73
+ return true
74
+ else
75
+ add_error ReplyMessage::Request.too_long
76
+ return false
77
+ end
78
+ end
79
+
80
+ def in_music_category?
81
+ if @track.category_id == "10"
82
+ return true
83
+ else
84
+ add_error ReplyMessage::Request.invalid_category
85
+ return false
86
+ end
87
+ end
88
+
89
+ def available_in_region?
90
+ # TODO: refactor this into proper methods, this can be a guard clause
91
+ if listed?
92
+ if allowed_list_exists?
93
+ if in_allowed_list?
94
+ return true
95
+ else
96
+ add_error ReplyMessage::Request.region_restricted
97
+ return false
98
+ end
99
+ else
100
+ if in_blocked_list?
101
+ add_error ReplyMessage::Request.region_restricted
102
+ return false
103
+ else
104
+ return true
105
+ end
106
+ end
107
+ else
108
+ return true
109
+ end
110
+ end
111
+
112
+ def listed?
113
+ !!@track.content_detail.data&.dig('regionRestriction')
114
+ end
115
+
116
+ def allowed_list_exists?
117
+ !!@track.content_detail.data&.dig('regionRestriction', 'allowed')
118
+ end
119
+
120
+ def in_allowed_list?
121
+ if allowed_list = @track.content_detail.data&.dig('regionRestriction', 'allowed')
122
+ allowed_list.include?(JarvisbotSongfinder.configuration.region)
123
+ else
124
+ return false
125
+ end
126
+ end
127
+
128
+ def in_blocked_list?
129
+ if blocked_list = @track.content_detail.data&.dig('regionRestriction', 'blocked')
130
+ blocked_list.include?(JarvisbotSongfinder.configuration.region)
131
+ else
132
+ return false
133
+ end
134
+ end
135
+ end
136
+ # :nocov:
137
+ end
@@ -0,0 +1,3 @@
1
+ module JarvisbotSongfinder
2
+ VERSION = "1.0.0"
3
+ end
metadata ADDED
@@ -0,0 +1,237 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jarvisbot_songfinder
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Nick
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-02-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.17'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.17'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.16'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.16'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: vcr
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: webmock
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: httparty
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.16'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.16'
125
+ - !ruby/object:Gem::Dependency
126
+ name: yt
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.29.1
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.29.1
139
+ - !ruby/object:Gem::Dependency
140
+ name: rspotify
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 2.4.0
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: 2.4.0
153
+ description: Gem jarvissongbot uses to take user input and transform it into queryable
154
+ music track found on enabled providers (youtube, spotify), validating it afterwards
155
+ email:
156
+ - doublejarvis@gmail.com
157
+ executables: []
158
+ extensions: []
159
+ extra_rdoc_files: []
160
+ files:
161
+ - ".gitignore"
162
+ - ".rspec"
163
+ - ".rubocop.yml"
164
+ - Gemfile
165
+ - Gemfile.lock
166
+ - LICENSE.txt
167
+ - README.md
168
+ - Rakefile
169
+ - bin/console
170
+ - bin/setup
171
+ - fixtures/vcr_cassettes/query_text.yml
172
+ - fixtures/vcr_cassettes/query_track_delegation.yml
173
+ - fixtures/vcr_cassettes/query_youtube_url.yml
174
+ - fixtures/vcr_cassettes/search_query_auxiliary_provider.yml
175
+ - fixtures/vcr_cassettes/search_query_not_found.yml
176
+ - fixtures/vcr_cassettes/search_query_preferred_and_auxiliary.yml
177
+ - fixtures/vcr_cassettes/search_query_preferred_provider.yml
178
+ - fixtures/vcr_cassettes/spotify_invalid_region_restricted.yml
179
+ - fixtures/vcr_cassettes/spotify_invalid_search.yml
180
+ - fixtures/vcr_cassettes/spotify_invalid_too_long.yml
181
+ - fixtures/vcr_cassettes/spotify_valid.yml
182
+ - fixtures/vcr_cassettes/spotify_valid_clean_or_unknown.yml
183
+ - fixtures/vcr_cassettes/spotify_valid_explicit.yml
184
+ - fixtures/vcr_cassettes/spotify_valid_search.yml
185
+ - fixtures/vcr_cassettes/spotify_vcr_test.yml
186
+ - fixtures/vcr_cassettes/url_query_known_provider.yml
187
+ - fixtures/vcr_cassettes/youtube_invalid.yml
188
+ - fixtures/vcr_cassettes/youtube_invalid_region_restricted.yml
189
+ - fixtures/vcr_cassettes/youtube_invalid_regionrestricted.yml
190
+ - fixtures/vcr_cassettes/youtube_invalid_search.yml
191
+ - fixtures/vcr_cassettes/youtube_invalid_too_long.yml
192
+ - fixtures/vcr_cassettes/youtube_invalid_wrong_category.yml
193
+ - fixtures/vcr_cassettes/youtube_invalid_wrongcategory.yml
194
+ - fixtures/vcr_cassettes/youtube_valid.yml
195
+ - fixtures/vcr_cassettes/youtube_valid_search.yml
196
+ - jarvisbot_songfinder.gemspec
197
+ - lib/jarvisbot_songfinder.rb
198
+ - lib/jarvisbot_songfinder/configuration.rb
199
+ - lib/jarvisbot_songfinder/helpers/query.rb
200
+ - lib/jarvisbot_songfinder/helpers/reply_message.rb
201
+ - lib/jarvisbot_songfinder/helpers/search_query.rb
202
+ - lib/jarvisbot_songfinder/helpers/url_query.rb
203
+ - lib/jarvisbot_songfinder/providers/bandrequest.rb
204
+ - lib/jarvisbot_songfinder/providers/provider.rb
205
+ - lib/jarvisbot_songfinder/providers/spotify_api.rb
206
+ - lib/jarvisbot_songfinder/providers/unknown_provider.rb
207
+ - lib/jarvisbot_songfinder/providers/unknown_search_provider.rb
208
+ - lib/jarvisbot_songfinder/providers/youtube_api.rb
209
+ - lib/jarvisbot_songfinder/version.rb
210
+ homepage: https://gitlab.com/DoubleJarvis/jarvisbot_songfinder
211
+ licenses:
212
+ - MIT
213
+ metadata:
214
+ homepage_uri: https://gitlab.com/DoubleJarvis/jarvisbot_songfinder
215
+ source_code_uri: https://gitlab.com/DoubleJarvis/jarvisbot_songfinder
216
+ changelog_uri: https://gitlab.com/DoubleJarvis/jarvisbot_songfinder/changelog.md
217
+ post_install_message:
218
+ rdoc_options: []
219
+ require_paths:
220
+ - lib
221
+ required_ruby_version: !ruby/object:Gem::Requirement
222
+ requirements:
223
+ - - ">="
224
+ - !ruby/object:Gem::Version
225
+ version: 2.5.0
226
+ required_rubygems_version: !ruby/object:Gem::Requirement
227
+ requirements:
228
+ - - ">="
229
+ - !ruby/object:Gem::Version
230
+ version: '0'
231
+ requirements: []
232
+ rubyforge_project:
233
+ rubygems_version: 2.7.3
234
+ signing_key:
235
+ specification_version: 4
236
+ summary: Take user input and return music track
237
+ test_files: []