spotify_rec 1.0 → 1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '00749e0a49528b3d680597ee48924685869ab8963027609a951f0d8e1bd6bfd6'
4
- data.tar.gz: ead9a411308f5234a5b4d1919201e0721f1191304a3e486e5f75e644db23fe1b
3
+ metadata.gz: 6e297d8af48b8d8d7ab6c0636518af40d7051e794ab637c725d544ecfa68679e
4
+ data.tar.gz: 2297ec4f7c3cfe5372eb30b6b5df7cd5fcf269e56857f9a014f9d9b378a6a8c6
5
5
  SHA512:
6
- metadata.gz: 88011906853f7d6e5e6e4fe650c5d474f0caa8534ee8ee590e7bd5178b48bf773a4b56c9d12f9fee97db0ce8affb8d7860a783330290ef4024c68e91a0aa43c7
7
- data.tar.gz: cd0e528637accbbd6c8a15b6a6de7d58e8b21e04cabe9c73787c9fb8885db2056b27075a6fefd199be3a40924f050f53aec97be5e2bbe1d58d32684700d7dd39
6
+ metadata.gz: c84dcb222e6107e57ac132796adfc3e05c6562063cfbb2f94cba521c669d095b359f49f0c1653b6395a89bd9c24bc132861b6b09fe6a454d2680a56b6fda0b92
7
+ data.tar.gz: 88a353cd4e84c0c465e4406bc899acbabe80cde04aee16ac123d019c258cb9508690ac981956b138f7f6bca2a31850c23b709bf67c80323d936cdccf8bc130a9
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
4
  # gems
4
5
  require 'rspotify'
@@ -15,40 +16,46 @@ require_relative '../lib/login'
15
16
  require_relative '../lib/rec'
16
17
  require_relative '../lib/menu'
17
18
  require_relative '../lib/my_list'
19
+ require_relative '../lib/tutorial'
20
+ require_relative '../lib/error'
18
21
 
19
- #modules
22
+ # modules
20
23
  include Login
24
+ include Tutorial
21
25
 
22
- RSpotify.authenticate("712ff89a218a4e6dbe1f169e06f949b9", "e9e0517f405b4a01a1be8823126459b7")
23
- $prompt = TTY::Prompt.new
26
+ RSpotify.authenticate('712ff89a218a4e6dbe1f169e06f949b9', 'e9e0517f405b4a01a1be8823126459b7')
24
27
 
25
- VERSION = 1.0
28
+ VERSION = 1.5
26
29
 
27
30
  ARGV << '--run' if ARGV.empty?
28
31
 
29
32
  options = {}
30
33
  parser = OptionParser.new do |opts|
31
- opts.banner = "Welcome to Spotify Recommendations! Usage: spotifyrec [options]".colorize(:light_green)
32
-
33
- opts.on("-v", "--version", "Display the version") do
34
- puts "Spotify Recommendations version #{VERSION}".colorize(:light_green)
35
- end
36
-
37
- opts.on("-h", "--help", "Display the help message") do
38
- puts opts
39
- exit
40
- end
41
-
42
- opts.on("-qGENRE", "--quick=GENRE", "Generate a quick recommendation with the chosen genre") do |genre|
43
- recommendations = RSpotify::Recommendations.generate(limit: 5, seed_genres: [genre])
44
- cleaned_recs = recommendations.tracks.map { |t| "#{t.name} by #{t.artists[0].name}" }
45
- puts "》 RECOMMENDATIONS 《".colorize(:light_green)
46
- cleaned_recs.each { |track| puts track }
47
- end
48
-
49
- opts.on("-r", "--run", "Run the application") do
50
- Login::login
51
- end
34
+ opts.banner = 'Welcome to Spotify Recommendations! Usage: spotify_rec [options]'.colorize(:light_green)
35
+
36
+ opts.on('-v', '--version', 'Display the version') do
37
+ puts "Spotify Recommendations version #{VERSION}".colorize(:light_green)
38
+ end
39
+
40
+ opts.on('-h', '--help', 'Display the help message') do
41
+ puts opts
42
+ exit
43
+ end
44
+
45
+ opts.on('-t', '--tutorial', 'View a brief tutorial') do
46
+ Tutorial.start
47
+ end
48
+
49
+ opts.on('-qGENRE', '--quick=GENRE', 'Generate a quick recommendation with the chosen genre') do |genre|
50
+ recommendations = RSpotify::Recommendations.generate(limit: 5, seed_genres: [genre])
51
+ cleaned_recs = recommendations.tracks.map { |t| "#{t.name} by #{t.artists[0].name}" }
52
+ puts '》 RECOMMENDATIONS 《'.colorize(:light_green)
53
+ cleaned_recs.each { |track| puts track }
54
+ end
55
+
56
+ opts.on('-r', '--run', 'Run the application') do
57
+ Login.initial_login
58
+ end
52
59
  end
53
60
 
54
- parser.parse!
61
+ parser.parse!
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ class RequirementError < StandardError
4
+ end
5
+
6
+ class MyListEmpty < StandardError
7
+ end
8
+
9
+ class UserFileError < StandardError
10
+ end
@@ -1,117 +1,154 @@
1
- require_relative 'menu'
2
-
3
- module Login
4
-
5
- def user
6
- return @user
7
- end
8
-
9
- def userdata
10
- path = File.join(File.dirname(File.dirname(File.absolute_path(__FILE__))))
11
- userfile = "#{path}/public/users.json"
12
- return userfile
13
- end
14
-
15
- def clear
16
- system("clear")
17
- end
18
-
19
- def initial_login
20
- clear
21
- puts " ;;;;;;;;;;;;;;;;;;;
22
- ;;;;;;;;;;;;;;;;;;;
23
- ; ;
24
- ; ;
25
- ; ;
26
- ; ;
27
- ; ;
28
- ; ;
29
- ,;;;;; ,;;;;;
30
- ;;;;;; ;;;;;;
31
- `;;;;' `;;;;'
32
- ".colorize(:light_green)
33
- puts "》 Welcome to the Spotify Recommendations App! 《".colorize(:light_green)
34
- puts
35
- return $prompt.select("Are you a new or returning user? \n", %w(New Returning))
36
- end
37
-
38
- def load_data
39
- file = File.read(userdata)
40
- return JSON.parse(file)
41
- end
42
-
43
- def gen_uid
44
- return load_data.length + 1
45
- end
46
-
47
- def store_user
48
- data = load_data
49
- user_details = {
50
- "id" => "#{@user.uid}",
51
- "username" => @user.username,
52
- "password" => @user.password,
53
- "playlist" => @user.playlist,
54
- "mylist" => @user.mylist
55
- }
56
- data << user_details
57
- File.open(userdata,"w") do |f|
58
- f.puts JSON.pretty_generate(data)
59
- end
60
- puts "You're now registered! Logging you in..".colorize(:light_green)
61
- sleep(1)
62
- @menu = Menu.new(@user)
63
- @menu.menu_router
64
- end
65
-
66
- def new_user
67
- system("clear")
68
- puts "Welcome! Please register for an account to continue.".colorize(:light_green)
69
- username = $prompt.ask("Username >") { |u| u.validate(/\A[0-9a-zA-Z'-]*\z/, "Username must only contain letters and numbers")}
70
- password = $prompt.mask("Password >")
71
- @user = User.new(username, password, gen_uid)
72
- @user_playlist = Playlist.new(@user)
73
- store_user
74
- end
75
-
76
- def returning_user
77
- system("clear")
78
- puts "Welcome back! Please login to continue.".colorize(:light_green)
79
- username = $prompt.ask("Username >")
80
- password= $prompt.mask("Password >")
81
- authenticate(username, password)
82
- end
83
-
84
- def authenticate(username, password)
85
- data = load_data
86
- auth = false
87
- data.each do |hash|
88
- if hash["username"].downcase == username.downcase
89
- if hash["password"] == password
90
- auth = true
91
- @user = User.new(username, password, hash["id"], hash["playlist"], hash["mylist"])
92
- @user_playlist = Playlist.new(@user)
93
- puts "Success! Logging you in..".colorize(:light_green)
94
- sleep(1)
95
- @menu = Menu.new(@user)
96
- @menu.menu_router
97
- end
98
- end
99
- end
100
- unless auth
101
- puts "Incorrect username or password!".colorize(:red)
102
- sleep(1)
103
- returning_user
104
- end
105
- end
106
-
107
- def login
108
- new_returning = initial_login.downcase
109
- if new_returning == "new"
110
- new_user
111
- end
112
- if new_returning == "returning"
113
- returning_user
114
- end
115
- end
116
-
117
- end
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'menu'
4
+
5
+ module Login
6
+ @prompt = TTY::Prompt.new
7
+ @count = 0
8
+
9
+ # Login Logic Section
10
+ # Prompts the user to indicate whether they are a new or returning user
11
+ def initial_login
12
+ clear
13
+ ascii_art
14
+ puts '》 Welcome to the Spotify Recommendations App! 《'.colorize(:light_green)
15
+ puts
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'
19
+ end
20
+
21
+ # New user
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.
24
+ def new_user
25
+ system('clear')
26
+ File.open(userdata, 'w') { |f| f.write([].to_json) } unless File.exist?(userdata)
27
+ puts 'Welcome! Please register for an account to continue.'.colorize(:light_green)
28
+ username = @prompt.ask('Username >')
29
+ raise RequirementError.new, 'Requirements not met' if username.match?(/[!@#$%^&*(),.?":{}|<>]/)
30
+
31
+ new_user_password(username)
32
+ rescue RequirementError
33
+ puts 'Username cannot contain special characters. Please try again!'.colorize(:light_red)
34
+ new_user
35
+ end
36
+
37
+ # Prompts for new password. Validates password so no special characters are included.
38
+ def new_user_password(username)
39
+ password = @prompt.mask('Password >')
40
+ raise RequirementError.new, 'Requirements not met' if password.match?(/[!@#$%^&*(),.?":{}|<>]/)
41
+
42
+ @user = User.new(username, password, gen_uid)
43
+ @user_playlist = Playlist.new(@user)
44
+ store_user
45
+ rescue RequirementError
46
+ puts 'Password cannot contain special characters. Please try again!'.colorize(:light_red)
47
+ end
48
+
49
+ # Converts user details into a hash, ready to be stored in JSON file
50
+ def store_user
51
+ data = load_data
52
+ user_details = {
53
+ 'id' => @user.uid.to_s,
54
+ 'username' => @user.username,
55
+ 'password' => @user.password,
56
+ 'playlist' => @user.playlist,
57
+ 'mylist' => @user.mylist
58
+ }
59
+ data << user_details
60
+ write_user(data)
61
+ end
62
+
63
+ # Writes the hash of user data to the JSON file
64
+ def write_user(data)
65
+ File.open(userdata, 'w') do |f|
66
+ f.puts JSON.pretty_generate(data)
67
+ end
68
+ puts "You're now registered! Logging you in..".colorize(:light_green)
69
+ sleep(1)
70
+ go_to_menu
71
+ end
72
+
73
+ # Returning user
74
+ # Prompts user to enter username and password
75
+ def returning_user
76
+ system('clear')
77
+ File.open(userdata, 'w') { |f| f.write([].to_json) } unless File.exist?(userdata)
78
+ puts 'Welcome back! Please login to continue.'.colorize(:light_green)
79
+ username = @prompt.ask('Username >')
80
+ user_password = @prompt.mask('Password >')
81
+ authenticate(username, user_password)
82
+ end
83
+
84
+ # Loads data from JSON file
85
+ def authenticate(username, user_password)
86
+ data_arr = load_data
87
+ user_data(data_arr, username, user_password)
88
+ end
89
+
90
+ # Checks whether supplied username and password match any in the userfile
91
+ def user_data(data, username, user_password)
92
+ data.each do |hash|
93
+ next unless hash['username'].downcase == username.downcase
94
+
95
+ next unless hash['password'] == user_password
96
+
97
+ @user = User.new(username, user_password, hash['id'], hash['playlist'], hash['mylist'])
98
+ go_to_menu
99
+ end
100
+ @count += 1
101
+ no_auth
102
+ end
103
+
104
+ # Method exits application if user is unsuccessful 3 times or more. Otherwise returns to login
105
+ def no_auth
106
+ puts 'Incorrect username or password!'.colorize(:red)
107
+ sleep(1)
108
+ if @count >= 3
109
+ puts 'You have tried too many times! The application will now close..'.colorize(:light_red)
110
+ exit
111
+ end
112
+ returning_user
113
+ end
114
+
115
+ # Helper Module Methods
116
+ def user
117
+ @user
118
+ end
119
+
120
+ def gen_uid
121
+ load_data.length + 1
122
+ end
123
+
124
+ def userdata
125
+ path = File.join(File.dirname(File.dirname(File.absolute_path(__FILE__))))
126
+ "#{path}/public/users.json"
127
+ end
128
+
129
+ def load_data
130
+ file = File.read(userdata)
131
+ JSON.parse(file)
132
+ end
133
+
134
+ def clear
135
+ system('clear')
136
+ end
137
+
138
+ def go_to_menu
139
+ menu = Menu.new(@user)
140
+ menu.menu_router
141
+ end
142
+
143
+ def ascii_art
144
+ puts " ;;;;;;;;;;;;;;;;;;;
145
+ ; ;
146
+ ; ;
147
+ ; ;
148
+ ; ;
149
+ ; ;
150
+ ,;;;;; ,;;;;;
151
+ ;;;;;; ;;;;;;
152
+ `;;;;' `;;;;'\n".colorize(:light_green)
153
+ end
154
+ end
@@ -1,67 +1,116 @@
1
- class Menu
2
-
3
- def initialize(user)
4
- @user = user
5
- @prompt = prompt = TTY::Prompt.new
6
- @playlist = Playlist.new(@user)
7
- end
8
-
9
- def display_menu
10
- system("clear")
11
- return @prompt.select("》 MAIN MENU 《\n".colorize(:light_green), (["My List", "Recommendations", "Playlist", "Account Details", "Exit"]))
12
- end
13
-
14
- def my_list
15
- system("clear")
16
- selection = @prompt.select("》 MY LIST 《\n".colorize(:light_green), (["Display", "Add", "Remove", "Back"]))
17
- mylist = MyList.new(@user)
18
- case selection
19
- when "Display"
20
- mylist.list
21
- when "Add"
22
- mylist.add_to_list
23
- when "Remove"
24
- mylist.remove_from_list
25
- when "Back"
26
- menu_router
27
- end
28
- end
29
-
30
- def account_details
31
- system("clear")
32
- selection = @prompt.select("》 ACCOUNT MENU 《 \n".colorize(:light_green), (["View Details", "Change Username", "Change Password", "Delete Account", "Back"]))
33
- case selection
34
- when "View Details"
35
- @user.details
36
- when "Change Username"
37
- username = @prompt.ask("Please enter your new username >") { |u| u.validate(/\A[0-9a-zA-Z'-]*\z/, "Username must only contain letters and numbers")}
38
- @user.change_username(username)
39
- when "Change Password"
40
- password = @prompt.ask("Please enter your new password >")
41
- @user.change_password(password)
42
- when "Delete Account"
43
- @user.delete_account
44
- when "Back"
45
- menu_router
46
- end
47
- end
48
-
49
- def menu_router
50
- selection = display_menu
51
- case selection
52
- when "My List"
53
- system("clear")
54
- my_list
55
- when "Recommendations"
56
- recommendation = Rec.new(@user)
57
- recommendation.amount_of_suggestions
58
- when "Playlist"
59
- @playlist.menu
60
- when "Account Details"
61
- account_details
62
- when "Exit"
63
- exit
64
- end
65
- end
66
-
67
- end
1
+ # frozen_string_literal: true
2
+
3
+ class Menu
4
+ def initialize(user)
5
+ @user = user
6
+ @prompt = TTY::Prompt.new
7
+ @playlist = Playlist.new(@user)
8
+ @list_length = @user.mylist.length
9
+ end
10
+
11
+ # Prompts the user to select an item on the menu
12
+ def display_menu
13
+ system('clear')
14
+ arr = ['My List', 'Recommendations', 'Playlist', 'Account Details', 'Exit']
15
+ @prompt.select("》 MAIN MENU 《\n".colorize(:light_green), arr)
16
+ end
17
+
18
+ # Begins to case the user selection from the menu
19
+ def menu_router
20
+ selection = display_menu
21
+ case selection
22
+ when 'My List'
23
+ my_list
24
+ when 'Recommendations'
25
+ recommendations_menu
26
+ else
27
+ case_menu(selection)
28
+ end
29
+ end
30
+
31
+ # Opens the recommendations menu
32
+ def recommendations_menu
33
+ if @list_length.positive?
34
+ recommendation = Rec.new(@user)
35
+ recommendation.amount_of_suggestions
36
+ else
37
+ no_items
38
+ end
39
+ end
40
+
41
+ # Sends user back to menu if they don't have any items in 'MyList' yet
42
+ def no_items
43
+ puts "Uh oh! You don't have any items in your list yet, so we can't generate any".colorize(:light_red)
44
+ puts 'recommendations. Please add some before doing this!'.colorize(:light_red)
45
+ @prompt.keypress('Press any key to return to the previous menu..')
46
+ display_menu
47
+ end
48
+
49
+ # Continues to case the menu selection and route the user
50
+ def case_menu(selection)
51
+ case selection
52
+ when 'Playlist'
53
+ @playlist.menu
54
+ when 'Account Details'
55
+ account_details
56
+ when 'Exit'
57
+ exit
58
+ end
59
+ end
60
+
61
+ # Shows the MyList menu
62
+ def my_list
63
+ system('clear')
64
+ selection = @prompt.select("》 MY LIST 《\n".colorize(:light_green), %w[Display Add Remove Back])
65
+ mylist = MyList.new(@user)
66
+ case_my_list(selection, mylist)
67
+ end
68
+
69
+ # Cases the selection from the MyList menu and routes to the required method
70
+ def case_my_list(selection, mylist)
71
+ case selection
72
+ when 'Display'
73
+ mylist.list
74
+ when 'Add'
75
+ mylist.add_to_list
76
+ when 'Remove'
77
+ mylist.remove_from_list
78
+ when 'Back'
79
+ menu_router
80
+ end
81
+ end
82
+
83
+ # Prompts the user to select from the Account details menu
84
+ def account_details_select
85
+ system('clear')
86
+ arr = ['View Details', 'Change Username', 'Change Password', 'Delete Account', 'Back']
87
+ @prompt.select('》 ACCOUNT DETAILS 《\n'.colorize(:light_green), arr)
88
+ end
89
+
90
+ # Cases the account details menu and routes the user
91
+ def account_details
92
+ selection = account_details_select
93
+ case selection
94
+ when 'View Details'
95
+ @user.details
96
+ when 'Change Username'
97
+ username = @prompt.ask('Please enter your new username >')
98
+ @user.change_username(username)
99
+ else
100
+ case_account_details(selection)
101
+ end
102
+ end
103
+
104
+ # Continues to case the account details menu and route the user
105
+ def case_account_details(selection)
106
+ case selection
107
+ when 'Change Password'
108
+ password = @prompt.ask('Please enter your new password >')
109
+ @user.change_password(password)
110
+ when 'Delete Account'
111
+ @user.delete_account
112
+ when 'Back'
113
+ menu_router
114
+ end
115
+ end
116
+ end