spotify_rec 1.3 → 1.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/spotify_rec +2 -2
- data/lib/error.rb +10 -0
- data/lib/login.rb +13 -10
- data/lib/menu.rb +27 -2
- data/lib/my_list.rb +14 -5
- data/lib/playlist.rb +11 -6
- data/lib/rec.rb +7 -9
- data/lib/spec/rec_spec.rb +24 -0
- data/lib/spec/user_spec.rb +34 -0
- data/lib/user.rb +12 -8
- data/public/users.json +4 -38
- metadata +62 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 84cf7ac404f9c5262b1e66a4d6a6704f09fc07ed33e6f6736f7a4de480512855
|
4
|
+
data.tar.gz: e9d32f90865a8ad5008a7e25e7bb6d91d1a8bd48f717e1ed67d011a799707f19
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf853d941376b0143060368ecd6f413b0c651ec59de1086214f3a097fccf9064b3fc2c226691ab084ed9296ae07c50ecc98f371a03de00890bd13b9206f526df
|
7
|
+
data.tar.gz: e47f913e7ddaba1eb220426f9f8a7f4d6f4edbecb981fb28d3778da88af0df3190789897aa6939bc0db411112c663d519afc2fa9441ab120a2079d09592080f0
|
data/bin/spotify_rec
CHANGED
@@ -25,7 +25,7 @@ include Tutorial
|
|
25
25
|
|
26
26
|
RSpotify.authenticate('712ff89a218a4e6dbe1f169e06f949b9', 'e9e0517f405b4a01a1be8823126459b7')
|
27
27
|
|
28
|
-
VERSION = 1.
|
28
|
+
VERSION = 1.6
|
29
29
|
|
30
30
|
ARGV << '--run' if ARGV.empty?
|
31
31
|
|
@@ -54,7 +54,7 @@ parser = OptionParser.new do |opts|
|
|
54
54
|
end
|
55
55
|
|
56
56
|
opts.on('-r', '--run', 'Run the application') do
|
57
|
-
Login.
|
57
|
+
Login.initial_login
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
data/lib/error.rb
ADDED
data/lib/login.rb
CHANGED
@@ -7,22 +7,20 @@ module Login
|
|
7
7
|
@count = 0
|
8
8
|
|
9
9
|
# Login Logic Section
|
10
|
+
# Prompts the user to indicate whether they are a new or returning user
|
10
11
|
def initial_login
|
11
12
|
clear
|
12
13
|
ascii_art
|
13
14
|
puts '》 Welcome to the Spotify Recommendations App! 《'.colorize(:light_green)
|
14
15
|
puts
|
15
|
-
@prompt.select("Are you a new or returning user? \n", %w[New Returning])
|
16
|
-
|
17
|
-
|
18
|
-
def login
|
19
|
-
new_returning = initial_login.downcase
|
20
|
-
new_user if new_returning == 'new'
|
21
|
-
returning_user if new_returning == 'returning'
|
16
|
+
selection = @prompt.select("Are you a new or returning user? \n", %w[New Returning])
|
17
|
+
new_user if selection == 'New'
|
18
|
+
returning_user if selection == 'Returning'
|
22
19
|
end
|
23
20
|
|
24
21
|
# New user
|
25
|
-
|
22
|
+
# Prompts user to enter username for new account. Checks name for any special characters.
|
23
|
+
# Raises error if special character is included, and prompts the user again.
|
26
24
|
def new_user
|
27
25
|
system('clear')
|
28
26
|
File.open(userdata, 'w') { |f| f.write([].to_json) } unless File.exist?(userdata)
|
@@ -36,6 +34,7 @@ module Login
|
|
36
34
|
new_user
|
37
35
|
end
|
38
36
|
|
37
|
+
# Prompts for new password. Validates password so no special characters are included.
|
39
38
|
def new_user_password(username)
|
40
39
|
password = @prompt.mask('Password >')
|
41
40
|
raise RequirementError.new, 'Requirements not met' if password.match?(/[!@#$%^&*(),.?":{}|<>]/)
|
@@ -47,6 +46,7 @@ module Login
|
|
47
46
|
puts 'Password cannot contain special characters. Please try again!'.colorize(:light_red)
|
48
47
|
end
|
49
48
|
|
49
|
+
# Converts user details into a hash, ready to be stored in JSON file
|
50
50
|
def store_user
|
51
51
|
data = load_data
|
52
52
|
user_details = {
|
@@ -60,6 +60,7 @@ module Login
|
|
60
60
|
write_user(data)
|
61
61
|
end
|
62
62
|
|
63
|
+
# Writes the hash of user data to the JSON file
|
63
64
|
def write_user(data)
|
64
65
|
File.open(userdata, 'w') do |f|
|
65
66
|
f.puts JSON.pretty_generate(data)
|
@@ -70,7 +71,7 @@ module Login
|
|
70
71
|
end
|
71
72
|
|
72
73
|
# Returning user
|
73
|
-
|
74
|
+
# Prompts user to enter username and password
|
74
75
|
def returning_user
|
75
76
|
system('clear')
|
76
77
|
File.open(userdata, 'w') { |f| f.write([].to_json) } unless File.exist?(userdata)
|
@@ -80,11 +81,13 @@ module Login
|
|
80
81
|
authenticate(username, user_password)
|
81
82
|
end
|
82
83
|
|
84
|
+
# Loads data from JSON file
|
83
85
|
def authenticate(username, user_password)
|
84
86
|
data_arr = load_data
|
85
87
|
user_data(data_arr, username, user_password)
|
86
88
|
end
|
87
89
|
|
90
|
+
# Checks whether supplied username and password match any in the userfile
|
88
91
|
def user_data(data, username, user_password)
|
89
92
|
data.each do |hash|
|
90
93
|
next unless hash['username'].downcase == username.downcase
|
@@ -98,6 +101,7 @@ module Login
|
|
98
101
|
no_auth
|
99
102
|
end
|
100
103
|
|
104
|
+
# Method exits application if user is unsuccessful 3 times or more. Otherwise returns to login
|
101
105
|
def no_auth
|
102
106
|
puts 'Incorrect username or password!'.colorize(:red)
|
103
107
|
sleep(1)
|
@@ -109,7 +113,6 @@ module Login
|
|
109
113
|
end
|
110
114
|
|
111
115
|
# Helper Module Methods
|
112
|
-
|
113
116
|
def user
|
114
117
|
@user
|
115
118
|
end
|
data/lib/menu.rb
CHANGED
@@ -7,25 +7,45 @@ class Menu
|
|
7
7
|
@playlist = Playlist.new(@user)
|
8
8
|
end
|
9
9
|
|
10
|
+
# Prompts the user to select an item on the menu
|
10
11
|
def display_menu
|
11
12
|
system('clear')
|
12
13
|
arr = ['My List', 'Recommendations', 'Playlist', 'Account Details', 'Exit']
|
13
14
|
@prompt.select("》 MAIN MENU 《\n".colorize(:light_green), arr)
|
14
15
|
end
|
15
16
|
|
17
|
+
# Begins to case the user selection from the menu
|
16
18
|
def menu_router
|
17
19
|
selection = display_menu
|
18
20
|
case selection
|
19
21
|
when 'My List'
|
20
22
|
my_list
|
21
23
|
when 'Recommendations'
|
24
|
+
recommendations_menu
|
25
|
+
else
|
26
|
+
case_menu(selection)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Opens the recommendations menu
|
31
|
+
def recommendations_menu
|
32
|
+
if @user.mylist.length.positive?
|
22
33
|
recommendation = Rec.new(@user)
|
23
34
|
recommendation.amount_of_suggestions
|
24
35
|
else
|
25
|
-
|
36
|
+
no_items
|
26
37
|
end
|
27
38
|
end
|
28
39
|
|
40
|
+
# Sends user back to menu if they don't have any items in 'MyList' yet
|
41
|
+
def no_items
|
42
|
+
puts "Uh oh! You don't have any items in your list yet, so we can't generate any".colorize(:light_red)
|
43
|
+
puts 'recommendations. Please add some before doing this!'.colorize(:light_red)
|
44
|
+
@prompt.keypress('Press any key to return to the previous menu..')
|
45
|
+
menu_router
|
46
|
+
end
|
47
|
+
|
48
|
+
# Continues to case the menu selection and route the user
|
29
49
|
def case_menu(selection)
|
30
50
|
case selection
|
31
51
|
when 'Playlist'
|
@@ -33,10 +53,11 @@ class Menu
|
|
33
53
|
when 'Account Details'
|
34
54
|
account_details
|
35
55
|
when 'Exit'
|
36
|
-
|
56
|
+
p "Is this exiting?"
|
37
57
|
end
|
38
58
|
end
|
39
59
|
|
60
|
+
# Shows the MyList menu
|
40
61
|
def my_list
|
41
62
|
system('clear')
|
42
63
|
selection = @prompt.select("》 MY LIST 《\n".colorize(:light_green), %w[Display Add Remove Back])
|
@@ -44,6 +65,7 @@ class Menu
|
|
44
65
|
case_my_list(selection, mylist)
|
45
66
|
end
|
46
67
|
|
68
|
+
# Cases the selection from the MyList menu and routes to the required method
|
47
69
|
def case_my_list(selection, mylist)
|
48
70
|
case selection
|
49
71
|
when 'Display'
|
@@ -57,12 +79,14 @@ class Menu
|
|
57
79
|
end
|
58
80
|
end
|
59
81
|
|
82
|
+
# Prompts the user to select from the Account details menu
|
60
83
|
def account_details_select
|
61
84
|
system('clear')
|
62
85
|
arr = ['View Details', 'Change Username', 'Change Password', 'Delete Account', 'Back']
|
63
86
|
@prompt.select('》 ACCOUNT DETAILS 《\n'.colorize(:light_green), arr)
|
64
87
|
end
|
65
88
|
|
89
|
+
# Cases the account details menu and routes the user
|
66
90
|
def account_details
|
67
91
|
selection = account_details_select
|
68
92
|
case selection
|
@@ -76,6 +100,7 @@ class Menu
|
|
76
100
|
end
|
77
101
|
end
|
78
102
|
|
103
|
+
# Continues to case the account details menu and route the user
|
79
104
|
def case_account_details(selection)
|
80
105
|
case selection
|
81
106
|
when 'Change Password'
|
data/lib/my_list.rb
CHANGED
@@ -9,7 +9,7 @@ class MyList
|
|
9
9
|
end
|
10
10
|
|
11
11
|
# Display MyList
|
12
|
-
|
12
|
+
# Displays items in MyList. Raises error if no items in list
|
13
13
|
def list
|
14
14
|
raise MyListEmpty.new, 'List must not be empty' if @mylist.empty?
|
15
15
|
|
@@ -20,6 +20,7 @@ class MyList
|
|
20
20
|
empty_list
|
21
21
|
end
|
22
22
|
|
23
|
+
# Generates the list in table view and prints it to the screen
|
23
24
|
def list_table
|
24
25
|
rows = @mylist.map do |hash|
|
25
26
|
if hash['type'] == 'track' || hash['type'] == 'album'
|
@@ -32,6 +33,7 @@ class MyList
|
|
32
33
|
puts table
|
33
34
|
end
|
34
35
|
|
36
|
+
# Tells the user they have no items in their list, and returns to menu
|
35
37
|
def empty_list
|
36
38
|
puts 'Oh no! Your list is currently empty!'.colorize(:light_red)
|
37
39
|
puts 'Add up to 5 items to your list. An item can be a song, artist or genre.'.colorize(:light_red)
|
@@ -41,13 +43,14 @@ class MyList
|
|
41
43
|
end
|
42
44
|
|
43
45
|
# Add to MyList
|
44
|
-
|
46
|
+
# Prompts the user to specify what type of item to add
|
45
47
|
def add_to_list
|
46
48
|
list_too_long if @mylist.length >= 5
|
47
49
|
selection = @prompt.select('Which type would you like to add?'.colorize(:light_green), %w[Song Artist Genre Back])
|
48
50
|
case_add_to_list(selection)
|
49
51
|
end
|
50
52
|
|
53
|
+
# Returns user to menu if the MyList has too many items
|
51
54
|
def list_too_long
|
52
55
|
puts "Oh no! You've reached maximum capacity in your list! You won't be able to add".colorize(:light_red)
|
53
56
|
puts 'another item until you remove an existing one.'.colorize(:light_red)
|
@@ -56,6 +59,7 @@ class MyList
|
|
56
59
|
@menu.my_list
|
57
60
|
end
|
58
61
|
|
62
|
+
# Cases the add to list selection and routes the user
|
59
63
|
def case_add_to_list(selection)
|
60
64
|
case selection
|
61
65
|
when 'Song'
|
@@ -69,6 +73,7 @@ class MyList
|
|
69
73
|
end
|
70
74
|
end
|
71
75
|
|
76
|
+
# Prompts user for song name and searches spotify. Prompts user to select a result
|
72
77
|
def search_song
|
73
78
|
song_query = @prompt.ask('What is the name of the song?'.colorize(:light_green))
|
74
79
|
tracks = RSpotify::Track.search(song_query, limit: 5)
|
@@ -80,7 +85,8 @@ class MyList
|
|
80
85
|
add_to_list if selection[0] == 'Back'
|
81
86
|
store_song(selection)
|
82
87
|
end
|
83
|
-
|
88
|
+
|
89
|
+
# Stores the song in a hash ready to be written to the file
|
84
90
|
def store_song(details)
|
85
91
|
track = RSpotify::Track.search("#{details[0]} #{details[1]}", limit: 1).first
|
86
92
|
song_details = {
|
@@ -93,6 +99,7 @@ class MyList
|
|
93
99
|
update_file
|
94
100
|
end
|
95
101
|
|
102
|
+
# Prompts user for artist name, searches for the artist and prompts user to select a result
|
96
103
|
def search_artist
|
97
104
|
artist_query = @prompt.ask('What is the name of the artist?'.colorize(:light_green))
|
98
105
|
artists = RSpotify::Artist.search(artist_query, limit: 5)
|
@@ -103,6 +110,7 @@ class MyList
|
|
103
110
|
store_artist(selection)
|
104
111
|
end
|
105
112
|
|
113
|
+
# Stores the artist details in a hash, ready to be written to userfile
|
106
114
|
def store_artist(details)
|
107
115
|
artist = RSpotify::Artist.search(details.to_s, limit: 1).first
|
108
116
|
artist_details = {
|
@@ -114,6 +122,7 @@ class MyList
|
|
114
122
|
update_file
|
115
123
|
end
|
116
124
|
|
125
|
+
# Prompts user to select genre from the list. Stores details in hash to be written to file
|
117
126
|
def store_genre
|
118
127
|
genres = RSpotify::Recommendations.available_genre_seeds
|
119
128
|
genre = @prompt.select('Which genre would you like to add to your list?', genres, filter: true)
|
@@ -126,7 +135,7 @@ class MyList
|
|
126
135
|
end
|
127
136
|
|
128
137
|
# Remove From MyList
|
129
|
-
|
138
|
+
# Prompts user to select item to remove from MyList. Removes item from mylist array
|
130
139
|
def remove_from_list
|
131
140
|
empty_list if @mylist.length <= 0
|
132
141
|
item_names = @mylist.map { |item| item['name'] }
|
@@ -140,7 +149,7 @@ class MyList
|
|
140
149
|
end
|
141
150
|
|
142
151
|
# Update userfile
|
143
|
-
|
152
|
+
# Writes the user MyList to the userfile
|
144
153
|
def update_file
|
145
154
|
updated_data = Login.load_data.each { |user| user['mylist'] = @mylist if user['id'] == @user.uid.to_s }
|
146
155
|
File.open(userdata, 'w') do |f|
|
data/lib/playlist.rb
CHANGED
@@ -10,7 +10,7 @@ class Playlist
|
|
10
10
|
end
|
11
11
|
|
12
12
|
# Playlist Menu Section
|
13
|
-
|
13
|
+
# Prompts user to select an item from the menu
|
14
14
|
def menu
|
15
15
|
system('clear')
|
16
16
|
selection = @prompt.select('》 PLAYLIST 《', ['Display', 'Add', 'Remove', 'Export To File', 'Back'])
|
@@ -22,6 +22,7 @@ class Playlist
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
+
# Cases the user selection and routes the user
|
25
26
|
def case_menu(selection)
|
26
27
|
case selection
|
27
28
|
when 'Add'
|
@@ -33,6 +34,7 @@ class Playlist
|
|
33
34
|
end
|
34
35
|
end
|
35
36
|
|
37
|
+
# Continues to case the selection and route the user
|
36
38
|
def second_case_menu(selection)
|
37
39
|
case selection
|
38
40
|
when 'Export To File'
|
@@ -44,7 +46,7 @@ class Playlist
|
|
44
46
|
end
|
45
47
|
|
46
48
|
# View Playlist
|
47
|
-
|
49
|
+
# Generates table from user playlist and prints it to the screen
|
48
50
|
def list
|
49
51
|
puts '》 PLAYLIST 《'
|
50
52
|
empty if @playlist.empty?
|
@@ -55,6 +57,7 @@ class Playlist
|
|
55
57
|
menu
|
56
58
|
end
|
57
59
|
|
60
|
+
# Tells user if their playlist is empty and sends them back to the menu
|
58
61
|
def empty
|
59
62
|
puts 'Oh no! Your playlist is currently empty!'
|
60
63
|
puts 'You can add songs manually from the previous menu, or generate recommendations and add those!'
|
@@ -64,7 +67,7 @@ class Playlist
|
|
64
67
|
end
|
65
68
|
|
66
69
|
# Add to Playlist
|
67
|
-
|
70
|
+
# Prompts user to enter song name, searches for song and prompts user to select a result
|
68
71
|
def add
|
69
72
|
song_query = @prompt.ask('What is the name of the song?')
|
70
73
|
tracks = RSpotify::Track.search(song_query, limit: 5)
|
@@ -77,6 +80,7 @@ class Playlist
|
|
77
80
|
store(selection)
|
78
81
|
end
|
79
82
|
|
83
|
+
# Turns song details into a hash and adds to playlist array
|
80
84
|
def store(details)
|
81
85
|
track = RSpotify::Track.search("#{details[0]} #{details[1]}", limit: 1).first
|
82
86
|
song_details = {
|
@@ -89,7 +93,7 @@ class Playlist
|
|
89
93
|
end
|
90
94
|
|
91
95
|
# Remove from Playlist
|
92
|
-
|
96
|
+
# Prompts user to select item in playlist to remove and deleted from playlist array
|
93
97
|
def remove
|
94
98
|
empty if @playlist.length <= 0
|
95
99
|
item_names = @playlist.map { |item| "#{item['name']} by #{item['artist']}" }
|
@@ -103,7 +107,7 @@ class Playlist
|
|
103
107
|
end
|
104
108
|
|
105
109
|
# Update Playlist in file
|
106
|
-
|
110
|
+
# Loads userdata and updates playlist in file. Returns the user to the menu
|
107
111
|
def update_playlist
|
108
112
|
updated_data = Login.load_data.each { |user| user['playlist'] = @playlist if user['id'] == @user.uid.to_s }
|
109
113
|
File.open(Login.userdata, 'w') do |f|
|
@@ -115,7 +119,7 @@ class Playlist
|
|
115
119
|
end
|
116
120
|
|
117
121
|
# Export playlist to file
|
118
|
-
|
122
|
+
# Writes user playlist information to a markdown file
|
119
123
|
def export_to_file
|
120
124
|
path = File.join(File.dirname(File.dirname(File.absolute_path(__FILE__))))
|
121
125
|
File.open("#{path}/playlist.md", 'w') do |f|
|
@@ -128,6 +132,7 @@ class Playlist
|
|
128
132
|
copy_to_desktop(path)
|
129
133
|
end
|
130
134
|
|
135
|
+
# Copies markdown file to desktop for easy access
|
131
136
|
def copy_to_desktop(path)
|
132
137
|
system("cp #{path}/playlist.md ~/Desktop/playlist.md")
|
133
138
|
puts 'Exported playlist to your Desktop!'
|
data/lib/rec.rb
CHANGED
@@ -10,9 +10,9 @@ class Rec
|
|
10
10
|
@prompt = TTY::Prompt.new
|
11
11
|
end
|
12
12
|
|
13
|
+
# Prompts user to choose how many suggestions to generate
|
13
14
|
def amount_of_suggestions
|
14
15
|
system('clear')
|
15
|
-
too_many_items if @user_list.length > 5
|
16
16
|
puts '》 RECOMMENDATIONS 《'
|
17
17
|
amount = @prompt.ask('How many recommendations would you like to generate?'.colorize(:light_green)) do |q|
|
18
18
|
q.in '1-10'
|
@@ -21,14 +21,7 @@ class Rec
|
|
21
21
|
recommend(amount.to_i)
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
puts "Uh oh! You don't have any items in your list yet, so we can't generate any".colorize(:light_red)
|
26
|
-
puts 'recommendations. Please add some before doing this!'.colorize(:light_red)
|
27
|
-
@prompt.keypress('Press any key to return to the previous menu..')
|
28
|
-
menu = Menu.new(@user)
|
29
|
-
menu.display_menu
|
30
|
-
end
|
31
|
-
|
24
|
+
# Prompts user to select which recommendations to add to their playlist
|
32
25
|
def recommend(num)
|
33
26
|
system('clear')
|
34
27
|
recommendations = recommendations_generate(num)
|
@@ -39,6 +32,7 @@ class Rec
|
|
39
32
|
clean_recommendations(selections)
|
40
33
|
end
|
41
34
|
|
35
|
+
# Sorts list items into arrays to be used in generating recommendations
|
42
36
|
def sort_my_list
|
43
37
|
@tracks.clear
|
44
38
|
@artists.clear
|
@@ -50,11 +44,13 @@ class Rec
|
|
50
44
|
end
|
51
45
|
end
|
52
46
|
|
47
|
+
# Generates recommendations with RSpotify
|
53
48
|
def recommendations_generate(num)
|
54
49
|
sort_my_list
|
55
50
|
RSpotify::Recommendations.generate(limit: num, seed_artists: @artists, seed_genres: @genres, seed_tracks: @tracks)
|
56
51
|
end
|
57
52
|
|
53
|
+
# Searches again for song selections to get the track object rather than just the name and artist
|
58
54
|
def clean_recommendations(selections)
|
59
55
|
selections.each do |track|
|
60
56
|
details = track.split(' by ')
|
@@ -64,6 +60,7 @@ class Rec
|
|
64
60
|
update_file
|
65
61
|
end
|
66
62
|
|
63
|
+
# Pulls song details from track and stores in a hash. Pushes to user playlist array
|
67
64
|
def song_details(song)
|
68
65
|
song_details = {
|
69
66
|
'name' => song.name,
|
@@ -73,6 +70,7 @@ class Rec
|
|
73
70
|
@user.playlist << song_details
|
74
71
|
end
|
75
72
|
|
73
|
+
# Updates file with current user playlist
|
76
74
|
def update_file
|
77
75
|
updated_data = Login.load_data.each { |user| user['playlist'] = @user.playlist if user['id'] == @user.uid.to_s }
|
78
76
|
File.open(userdata, 'w') do |f|
|
@@ -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/user.rb
CHANGED
@@ -14,29 +14,31 @@ class User
|
|
14
14
|
@prompt = TTY::Prompt.new
|
15
15
|
end
|
16
16
|
|
17
|
+
# Prints user details
|
17
18
|
def details
|
18
19
|
puts "Username: #{@username.colorize(:light_green)}"
|
19
20
|
puts "Password: #{@password.colorize(:light_green)}"
|
20
21
|
puts "User ID: #{@uid.to_s.colorize(:light_green)}"
|
21
22
|
@prompt.keypress('Press any key to continue..')
|
22
|
-
menu = Menu.new(
|
23
|
+
menu = Menu.new(self)
|
23
24
|
menu.account_details
|
24
25
|
end
|
25
26
|
|
26
27
|
# Change Username section
|
27
|
-
|
28
|
+
# Changes user name and routes back to menu
|
28
29
|
def change_username(new_name)
|
29
30
|
update_username(new_name)
|
30
31
|
@username = new_name
|
31
|
-
puts "Success! Your new username is #{
|
32
|
+
puts "Success! Your new username is #{@username}".colorize(:light_green)
|
32
33
|
@prompt.keypress('Press any key to continue..')
|
33
|
-
menu = Menu.new(
|
34
|
+
menu = Menu.new(self)
|
34
35
|
menu.account_details
|
35
36
|
end
|
36
37
|
|
38
|
+
# Updates username in file
|
37
39
|
def update_username(new_name)
|
38
40
|
updated_data = Login.load_data.each do |user|
|
39
|
-
user['username'] = new_name if user['id'] ==
|
41
|
+
user['username'] = new_name if user['id'] == @uid.to_s
|
40
42
|
end
|
41
43
|
File.open(Login.userdata, 'w') do |f|
|
42
44
|
f.puts JSON.pretty_generate(updated_data)
|
@@ -44,16 +46,17 @@ class User
|
|
44
46
|
end
|
45
47
|
|
46
48
|
# Change password section
|
47
|
-
|
49
|
+
# Changes user name and routes back to menu
|
48
50
|
def change_password(new_password)
|
49
51
|
update_password(new_password)
|
50
52
|
@password = new_password
|
51
53
|
puts 'Success! Your password has been changed.'.colorize(:light_green)
|
52
54
|
@prompt.keypress('Press any key to continue..')
|
53
|
-
menu = Menu.new(
|
55
|
+
menu = Menu.new(self)
|
54
56
|
menu.account_details
|
55
57
|
end
|
56
58
|
|
59
|
+
# Updates user password in file
|
57
60
|
def update_password(new_password)
|
58
61
|
updated_data = Login.load_data.each do |user|
|
59
62
|
user['password'] = new_password if user['id'] == Login.user.uid.to_s
|
@@ -64,7 +67,7 @@ class User
|
|
64
67
|
end
|
65
68
|
|
66
69
|
# Delete account section
|
67
|
-
|
70
|
+
#Prompts user to confirm they would like to delete account.
|
68
71
|
def delete_account
|
69
72
|
puts 'Woah there! Deleting your account is serious business, and cannot be undone.'.colorize(:light_red)
|
70
73
|
selection = @prompt.yes?('Are you sure you want to delete your account?'.colorize(:light_red))
|
@@ -76,6 +79,7 @@ class User
|
|
76
79
|
end
|
77
80
|
end
|
78
81
|
|
82
|
+
# Deletes user data from the userfile
|
79
83
|
def delete_from_file
|
80
84
|
updated_data = []
|
81
85
|
Login.load_data.each { |user| updated_data << user unless user['id'] == Login.user.uid.to_s }
|
data/public/users.json
CHANGED
@@ -1,47 +1,13 @@
|
|
1
1
|
[
|
2
2
|
{
|
3
3
|
"id": "1",
|
4
|
-
"username": "
|
4
|
+
"username": "user",
|
5
5
|
"password": "password",
|
6
6
|
"playlist": [
|
7
|
-
|
8
|
-
"name": "44 More",
|
9
|
-
"id": "3e7Y6sfFlIdBMJhX7wpqVO",
|
10
|
-
"artist": "Logic"
|
11
|
-
},
|
12
|
-
{
|
13
|
-
"name": "Outnumbered",
|
14
|
-
"id": "6UjZ2Yx2g2a52XxiA8ONxZ",
|
15
|
-
"artist": "Dermot Kennedy"
|
16
|
-
}
|
7
|
+
|
17
8
|
],
|
18
9
|
"mylist": [
|
19
|
-
|
20
|
-
"name": "Dermot Kennedy",
|
21
|
-
"id": "5KNNVgR6LBIABRIomyCwKJ",
|
22
|
-
"type": "artist"
|
23
|
-
},
|
24
|
-
{
|
25
|
-
"name": "MIDDLE CHILD",
|
26
|
-
"artist": "J. Cole",
|
27
|
-
"id": "2JvzF1RMd7lE3KmFlsyZD8",
|
28
|
-
"type": "track"
|
29
|
-
},
|
30
|
-
{
|
31
|
-
"name": "Pop",
|
32
|
-
"type": "genre"
|
33
|
-
},
|
34
|
-
{
|
35
|
-
"name": "Fool's Gold - Acoustic",
|
36
|
-
"artist": "Passenger",
|
37
|
-
"id": "4JPB2Kjr3lkMJFz4sZnt6G",
|
38
|
-
"type": "track"
|
39
|
-
},
|
40
|
-
{
|
41
|
-
"name": "Drake",
|
42
|
-
"id": "3TVXtAsR1Inumwj472S9r4",
|
43
|
-
"type": "artist"
|
44
|
-
}
|
10
|
+
|
45
11
|
]
|
46
12
|
}
|
47
|
-
]
|
13
|
+
]
|
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.10'
|
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,11 +74,14 @@ 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
|
83
|
+
- lib/spec/rec_spec.rb
|
84
|
+
- lib/spec/user_spec.rb
|
26
85
|
- lib/tutorial.rb
|
27
86
|
- lib/user.rb
|
28
87
|
- public/users.json
|