spotify_rec 1.1 → 1.6
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 +4 -4
- data/bin/spotify_rec +33 -26
- data/lib/error.rb +10 -0
- data/lib/login.rb +154 -117
- data/lib/menu.rb +116 -67
- data/lib/my_list.rb +162 -137
- data/lib/playlist.rb +103 -67
- data/lib/rec.rb +54 -44
- data/lib/spec/rec_spec.rb +24 -0
- data/lib/spec/user_spec.rb +34 -0
- data/lib/tutorial.rb +56 -0
- data/lib/user.rb +93 -69
- data/public/users.json +1 -13
- metadata +64 -5
- data/lib/run.rb +0 -47
data/lib/rec.rb
CHANGED
@@ -1,74 +1,84 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
class Rec
|
3
4
|
def initialize(user)
|
4
5
|
@user_list = user.mylist
|
5
6
|
@user = user
|
6
7
|
@tracks = []
|
7
8
|
@artists = []
|
8
9
|
@genres = []
|
10
|
+
@prompt = TTY::Prompt.new
|
9
11
|
end
|
10
12
|
|
13
|
+
# Prompts user to choose how many suggestions to generate
|
14
|
+
def amount_of_suggestions
|
15
|
+
system('clear')
|
16
|
+
puts '》 RECOMMENDATIONS 《'
|
17
|
+
amount = @prompt.ask('How many recommendations would you like to generate?'.colorize(:light_green)) do |q|
|
18
|
+
q.in '1-10'
|
19
|
+
q.messages[:range?] = 'Number must be between 1 and 10'
|
20
|
+
end
|
21
|
+
recommend(amount.to_i)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Prompts user to select which recommendations to add to their playlist
|
25
|
+
def recommend(num)
|
26
|
+
system('clear')
|
27
|
+
recommendations = recommendations_generate(num)
|
28
|
+
cleaned_recs = recommendations.tracks.map { |t| "#{t.name} by #{t.artists[0].name}" }
|
29
|
+
puts '》 RECOMMENDATIONS 《'.colorize(:light_green)
|
30
|
+
puts 'Select the recommendations you want to add to your playlist!'
|
31
|
+
selections = @prompt.multi_select('Hit enter with none selected to skip.', cleaned_recs)
|
32
|
+
clean_recommendations(selections)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Sorts list items into arrays to be used in generating recommendations
|
11
36
|
def sort_my_list
|
12
37
|
@tracks.clear
|
13
38
|
@artists.clear
|
14
39
|
@genres.clear
|
15
40
|
@user_list.each do |item|
|
16
|
-
@tracks << item[
|
17
|
-
@artists << item[
|
18
|
-
@genres << item[
|
41
|
+
@tracks << item['id'] if item['type'] == 'track'
|
42
|
+
@artists << item['id'] if item['type'] == 'artist'
|
43
|
+
@genres << item['name'].downcase if item['type'] == 'genre'
|
19
44
|
end
|
20
45
|
end
|
21
46
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
end
|
27
|
-
puts "Sweet! Your list has been updated!".colorize(:light_green)
|
28
|
-
$prompt.keypress("Press any key to return to the previous menu..")
|
29
|
-
menu = Menu.new(@user)
|
30
|
-
menu.menu_router
|
47
|
+
# Generates recommendations with RSpotify
|
48
|
+
def recommendations_generate(num)
|
49
|
+
sort_my_list
|
50
|
+
RSpotify::Recommendations.generate(limit: num, seed_artists: @artists, seed_genres: @genres, seed_tracks: @tracks)
|
31
51
|
end
|
32
52
|
|
53
|
+
# Searches again for song selections to get the track object rather than just the name and artist
|
33
54
|
def clean_recommendations(selections)
|
34
55
|
selections.each do |track|
|
35
|
-
details = track.split(
|
56
|
+
details = track.split(' by ')
|
36
57
|
song = RSpotify::Track.search("#{details[0]} #{details[1]}", limit: 1).first
|
37
|
-
song_details
|
38
|
-
"name" => song.name,
|
39
|
-
"id" => song.id,
|
40
|
-
"artist" => song.artists[0].name }
|
41
|
-
@user.playlist << song_details
|
58
|
+
song_details(song)
|
42
59
|
end
|
43
60
|
update_file
|
44
61
|
end
|
45
62
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
clean_recommendations(selections)
|
63
|
+
# Pulls song details from track and stores in a hash. Pushes to user playlist array
|
64
|
+
def song_details(song)
|
65
|
+
song_details = {
|
66
|
+
'name' => song.name,
|
67
|
+
'id' => song.id,
|
68
|
+
'artist' => song.artists[0].name
|
69
|
+
}
|
70
|
+
@user.playlist << song_details
|
55
71
|
end
|
56
72
|
|
57
|
-
|
58
|
-
|
59
|
-
if @
|
60
|
-
|
61
|
-
|
62
|
-
menu = Menu.new(@user)
|
63
|
-
menu.display_menu
|
64
|
-
end
|
65
|
-
puts "》 RECOMMENDATIONS 《"
|
66
|
-
amount = $prompt.ask("How many recommendations would you like to generate?".colorize(:light_green)) do |q|
|
67
|
-
q.in '1-10'
|
68
|
-
q.messages[:range?] = "Number must be between 1 and 10"
|
73
|
+
# Updates file with current user playlist
|
74
|
+
def update_file
|
75
|
+
updated_data = Login.load_data.each { |user| user['playlist'] = @user.playlist if user['id'] == @user.uid.to_s }
|
76
|
+
File.open(userdata, 'w') do |f|
|
77
|
+
f.puts JSON.pretty_generate(updated_data)
|
69
78
|
end
|
70
|
-
|
79
|
+
puts 'Sweet! Your list has been updated!'.colorize(:light_green)
|
80
|
+
@prompt.keypress('Press any key to return to the previous menu..')
|
81
|
+
menu = Menu.new(@user)
|
82
|
+
menu.menu_router
|
71
83
|
end
|
72
|
-
|
73
|
-
|
74
|
-
end
|
84
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rspotify'
|
2
|
+
require_relative '../user'
|
3
|
+
|
4
|
+
RSpotify.authenticate('712ff89a218a4e6dbe1f169e06f949b9', 'e9e0517f405b4a01a1be8823126459b7')
|
5
|
+
|
6
|
+
describe 'Recommendations' do
|
7
|
+
it 'should generate a list of recommendations' do
|
8
|
+
genre = 'pop'
|
9
|
+
recommendations = RSpotify::Recommendations.generate(limit: 5, seed_genres: [genre])
|
10
|
+
expect(recommendations.tracks.length).to eq(5)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should take the first recommendation and add it to the user playlist' do
|
14
|
+
name = 'user'
|
15
|
+
password = 'password123'
|
16
|
+
uid = '12345'
|
17
|
+
user = User.new(name, password, uid)
|
18
|
+
genre = 'pop'
|
19
|
+
recommendations = RSpotify::Recommendations.generate(limit: 5, seed_genres: [genre])
|
20
|
+
track = recommendations.tracks.first
|
21
|
+
user.playlist << track
|
22
|
+
expect(user.playlist.length).to eq(1)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../user'
|
4
|
+
require 'json'
|
5
|
+
require 'tty-prompt'
|
6
|
+
|
7
|
+
describe 'User' do
|
8
|
+
it 'should create a user with a name, password and user id' do
|
9
|
+
name = 'user'
|
10
|
+
password = 'password123'
|
11
|
+
uid = '12345'
|
12
|
+
user = User.new(name, password, uid)
|
13
|
+
expect(user.username).to eq('user')
|
14
|
+
expect(user.password).to eq('password123')
|
15
|
+
expect(user.uid).to eq('12345')
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should create a user and add a track to the users MyList' do
|
19
|
+
name = 'user'
|
20
|
+
password = 'password123'
|
21
|
+
uid = '12345'
|
22
|
+
user = User.new(name, password, uid)
|
23
|
+
song = {
|
24
|
+
'name': 'Gyalchester',
|
25
|
+
'artist': 'Drake',
|
26
|
+
'id': '6UjfByV1lDLW0SOVQA4NAi',
|
27
|
+
'type': 'track'
|
28
|
+
}
|
29
|
+
user.mylist << song
|
30
|
+
expect(user.mylist.first[:name]).to eq('Gyalchester')
|
31
|
+
expect(user.mylist.first[:artist]).to eq('Drake')
|
32
|
+
expect(user.mylist.first[:id]).to eq('6UjfByV1lDLW0SOVQA4NAi')
|
33
|
+
end
|
34
|
+
end
|
data/lib/tutorial.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Contains methods to display tutorial screens
|
4
|
+
module Tutorial
|
5
|
+
@prompt = TTY::Prompt.new
|
6
|
+
|
7
|
+
def start
|
8
|
+
system('clear')
|
9
|
+
puts '》 WELCOME TO SPOTIFY REC 《'.colorize(:light_green)
|
10
|
+
puts 'This tutorial will walk you through the basics to using the app.'
|
11
|
+
puts "There are 3 main areas that you'll need to understand:"
|
12
|
+
puts '- My List'
|
13
|
+
puts '- Recommendations'
|
14
|
+
puts '- Playlist'
|
15
|
+
puts
|
16
|
+
@prompt.keypress('Press any key to continue..')
|
17
|
+
my_list
|
18
|
+
end
|
19
|
+
|
20
|
+
def my_list
|
21
|
+
system('clear')
|
22
|
+
puts '》 MY LIST 《'.colorize(:light_green)
|
23
|
+
puts 'My List is the base that your recommendations are generated from. It can consist of'
|
24
|
+
puts "up to 5 of any 'items'. An item is either a track, artist or genre. You can add and remove"
|
25
|
+
puts 'items from my list, so make sure to change them up regularly to get a range of recommendations!'
|
26
|
+
puts "Searching for an item will return the top 5 results for your keywords, so if yours doesn't show"
|
27
|
+
puts 'up, try searching again with a more specific query!'
|
28
|
+
puts
|
29
|
+
@prompt.keypress('Press any key to continue..')
|
30
|
+
recommendations
|
31
|
+
end
|
32
|
+
|
33
|
+
def recommendations
|
34
|
+
system('clear')
|
35
|
+
puts '》 RECOMMENDATIONS 《'.colorize(:light_green)
|
36
|
+
puts 'As mentioned on the previous screen, recommendations are tracks, and are generated based on the'
|
37
|
+
puts "items in your list. You can select the amount you'd like to generate, and select any number of"
|
38
|
+
puts 'the recommendations to store in your playlist. Recommendations are capped at 10 per generate,'
|
39
|
+
puts 'but you can repeat the generate step as many times as you would like.'
|
40
|
+
puts
|
41
|
+
@prompt.keypress('Press any key to continue..')
|
42
|
+
playlist
|
43
|
+
end
|
44
|
+
|
45
|
+
def playlist
|
46
|
+
system('clear')
|
47
|
+
puts '》 PLAYLIST 《'.colorize(:light_green)
|
48
|
+
puts "Your playlist stores all of the recommendations you've chosen, but you can also manually add and"
|
49
|
+
puts "remove songs as well. This can all be done from the playlist menu. At any point you'd like to look"
|
50
|
+
puts 'at your playlist outside of Spotify Rec, you can export the contents to a file on your desktop.'
|
51
|
+
puts 'This file includes a link to each song on Spotify, so you can easily go and start listening!'
|
52
|
+
puts
|
53
|
+
@prompt.keypress('Press any key to return to finish..')
|
54
|
+
exit
|
55
|
+
end
|
56
|
+
end
|
data/lib/user.rb
CHANGED
@@ -1,69 +1,93 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
@
|
10
|
-
@
|
11
|
-
@
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
puts
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# An instance of User should be made for everyone who logs in or signs up
|
4
|
+
class User
|
5
|
+
attr_reader :username, :password, :uid
|
6
|
+
attr_accessor :playlist, :mylist
|
7
|
+
|
8
|
+
def initialize(username, password, uid, playlist = [], mylist = [])
|
9
|
+
@username = username
|
10
|
+
@password = password
|
11
|
+
@playlist = playlist
|
12
|
+
@uid = uid
|
13
|
+
@mylist = mylist
|
14
|
+
@prompt = TTY::Prompt.new
|
15
|
+
end
|
16
|
+
|
17
|
+
# Prints user details
|
18
|
+
def details
|
19
|
+
puts "Username: #{@username.colorize(:light_green)}"
|
20
|
+
puts "Password: #{@password.colorize(:light_green)}"
|
21
|
+
puts "User ID: #{@uid.to_s.colorize(:light_green)}"
|
22
|
+
@prompt.keypress('Press any key to continue..')
|
23
|
+
menu = Menu.new(self)
|
24
|
+
menu.account_details
|
25
|
+
end
|
26
|
+
|
27
|
+
# Change Username section
|
28
|
+
# Changes user name and routes back to menu
|
29
|
+
def change_username(new_name)
|
30
|
+
update_username(new_name)
|
31
|
+
@username = new_name
|
32
|
+
puts "Success! Your new username is #{@username}".colorize(:light_green)
|
33
|
+
@prompt.keypress('Press any key to continue..')
|
34
|
+
menu = Menu.new(self)
|
35
|
+
menu.account_details
|
36
|
+
end
|
37
|
+
|
38
|
+
# Updates username in file
|
39
|
+
def update_username(new_name)
|
40
|
+
updated_data = Login.load_data.each do |user|
|
41
|
+
user['username'] = new_name if user['id'] == @uid.to_s
|
42
|
+
end
|
43
|
+
File.open(Login.userdata, 'w') do |f|
|
44
|
+
f.puts JSON.pretty_generate(updated_data)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Change password section
|
49
|
+
# Changes user name and routes back to menu
|
50
|
+
def change_password(new_password)
|
51
|
+
update_password(new_password)
|
52
|
+
@password = new_password
|
53
|
+
puts 'Success! Your password has been changed.'.colorize(:light_green)
|
54
|
+
@prompt.keypress('Press any key to continue..')
|
55
|
+
menu = Menu.new(self)
|
56
|
+
menu.account_details
|
57
|
+
end
|
58
|
+
|
59
|
+
# Updates user password in file
|
60
|
+
def update_password(new_password)
|
61
|
+
updated_data = Login.load_data.each do |user|
|
62
|
+
user['password'] = new_password if user['id'] == Login.user.uid.to_s
|
63
|
+
end
|
64
|
+
File.open(Login.userdata, 'w') do |f|
|
65
|
+
f.puts JSON.pretty_generate(updated_data)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Delete account section
|
70
|
+
#Prompts user to confirm they would like to delete account.
|
71
|
+
def delete_account
|
72
|
+
puts 'Woah there! Deleting your account is serious business, and cannot be undone.'.colorize(:light_red)
|
73
|
+
selection = @prompt.yes?('Are you sure you want to delete your account?'.colorize(:light_red))
|
74
|
+
if selection
|
75
|
+
delete_from_file
|
76
|
+
else
|
77
|
+
menu = Menu.new(Login.user)
|
78
|
+
menu.account_details
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Deletes user data from the userfile
|
83
|
+
def delete_from_file
|
84
|
+
updated_data = []
|
85
|
+
Login.load_data.each { |user| updated_data << user unless user['id'] == Login.user.uid.to_s }
|
86
|
+
File.open(Login.userdata, 'w') do |f|
|
87
|
+
f.puts JSON.pretty_generate(updated_data)
|
88
|
+
end
|
89
|
+
puts 'Your account has been deleted. The program will now exit.'.colorize(:light_red)
|
90
|
+
@prompt.keypress('Press any key to continue..')
|
91
|
+
exit
|
92
|
+
end
|
93
|
+
end
|
data/public/users.json
CHANGED
metadata
CHANGED
@@ -1,15 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spotify_rec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '1.
|
4
|
+
version: '1.6'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Ahale
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
12
|
-
dependencies:
|
11
|
+
date: 2020-10-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: tty-prompt
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: terminal-table
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspotify
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: colorize
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
13
69
|
description:
|
14
70
|
email:
|
15
71
|
executables:
|
@@ -18,12 +74,15 @@ extensions: []
|
|
18
74
|
extra_rdoc_files: []
|
19
75
|
files:
|
20
76
|
- bin/spotify_rec
|
77
|
+
- lib/error.rb
|
21
78
|
- lib/login.rb
|
22
79
|
- lib/menu.rb
|
23
80
|
- lib/my_list.rb
|
24
81
|
- lib/playlist.rb
|
25
82
|
- lib/rec.rb
|
26
|
-
- lib/
|
83
|
+
- lib/spec/rec_spec.rb
|
84
|
+
- lib/spec/user_spec.rb
|
85
|
+
- lib/tutorial.rb
|
27
86
|
- lib/user.rb
|
28
87
|
- public/users.json
|
29
88
|
homepage:
|
@@ -38,7 +97,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
38
97
|
requirements:
|
39
98
|
- - ">="
|
40
99
|
- !ruby/object:Gem::Version
|
41
|
-
version: '
|
100
|
+
version: '2.4'
|
42
101
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
102
|
requirements:
|
44
103
|
- - ">="
|