-
Notifications
You must be signed in to change notification settings - Fork 1
/
main.py
265 lines (251 loc) · 10.2 KB
/
main.py
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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
import os
import random
from spotify import Spotify, simplify_string
from lyrics import swag_lyrics
import transcript
import time
from fuzzywuzzy import fuzz
import subprocess as sp
import speech
speechRecognizer = speech.Speech(2)
#|##########################################################################|#
#| SETUP |#
#|##########################################################################|#
# (1) in terminal, `pip3 install requests`
# (2) create/add a file in the "store" folder named "store.txt"
# (3) go to https://developer.spotify.com/dashboard/login
# (1) login
# (2) create an app
# (3) copy Client ID and paste into first line of "store.txt"
# (4) click "SHOW CLIENT SECRET"
# (5) copy Client Secret and paste into second line of "store.txt"
# (6) save the file ("store.txt")
# (4) in terminal, `python3 main.py`
# ENVIRONMENT VARIABLES
FRAME_DURATION = 40 # (seconds)
FRAME_SHIFT = 0 # (seconds) can be positive or negative
TIME_TOLERANCE_INCREMENT = 5 # (seconds)
MAXIMUM_TOLERANCE = 20 # (seconds)
def say(text: str) -> None:
sp.call(['say', text])
def setup():
if os.path.exists("store/store.txt"):
id, sec, token = receive_keys()
spotify = Spotify(id, sec, token)
else:
spotify = Spotify()
spotify.authenticate()
# Pause Spotify if it's playing right now
if spotify.status()["is_playing"]:
spotify.pause()
print("A song was already playing. The song has been paused")
return spotify
def run(spotify):
playlist_found = False
while not playlist_found:
playlist_found, playlist = ask_for_playlist(spotify)
say(f"Playing your {playlist['name']} playlist...")
print(f"Playing your {playlist['name']} playlist...")
# Valid playlist, now we get the tracks
tracks = spotify.get_tracks(playlist["tracks"])
random_track = random.choice(tracks)
# Once a random track is found, add it to the queue and skip to it
print(f"Adding {random_track['name']} to the queue...")
spotify.add_to_queue(random_track)
spotify.skip()
# lyrics = swag_lyrics.lyrics(random_track["name"], random_track["artists"][0])
# print(lyrics)
# Seek to a random time on the song
random_time = spotify.get_random_time(random_track)
ranom_time = 90000
success = spotify.seek(random_time, random_track)
while not success:
# random_time = spotify.get_random_time(random_track)
success = spotify.seek(random_time, random_track)
if not success:
print("Trying again...")
start_time = time.time()
# Given Song Title and Artist, input into transcript finder
transcript = get_transcript_frame(random_track["name"], random_track["duration"], random_time)
if transcript:
pass
# for each in transcript:
# print(each)
else:
say("Sorry, I wasn't able to get lyrics to match to that song")
print("Error: Unable to get lyrics")
time_diff = time.time() - start_time < 10
while time_diff:
time_diff = time.time() - start_time < 10
print("Pausing song....")
# PAUSE SPOTIFY SONG AFTER 10 SEC OF PLAYING
spotify.pause()
lyrics = ""
for i in transcript:
lyrics = lyrics + " " + i["text"]
say("Player 1 raised their hands first.")
# NOW GET USER INPUT
user_input = speechRecognizer.startSpeechRecognition(10)
print("Time's up!")
# print(lyrics)
# user_input = "You look so broken when you cry One more and then I'll say goodbye"
# user_input = lyrics[10:50]
print("User input received:")
print(user_input)
potential = []
for idx, char in enumerate(lyrics):
if char == ' ':
lyric_sub = lyrics[idx : idx + len(user_input)]
ratio = fuzz.ratio(user_input, lyric_sub)
if ratio > 50:
potential.append(lyric_sub)
if idx > len(lyrics) - len(user_input) - 5:
break
print(potential)
if potential:
for each in potential:
print(each)
say("Correct!")
print("Correct!")
else:
say("Sorry! That wasn't correct!")
print("Sorry! That wasn't correct!")
# playing = True
# while playing:
# playing = ask_for_command(spotify)
def ask_for_playlist(spotify):
say(f"Which playlist would you like? ")
request = speechRecognizer.startSpeechRecognition(4)
ret = spotify.get_playlist(request)
# Parse return
# CASE: Error: specified playlist is empty
# CASE: Error: specified playlist has no matches in your playlists
if ret == -1 or ret == -2:
if ret == -1:
print("Error: specified playlist is empty")
say("Sorry, that playlist was empty")
elif ret == -2:
print("Error: specified playlist has no matches in your playlists")
say("Sorry, that playlist doesn't match and playlist in your library")
# TODO More error handling (like asking again, or if they want a random track instead)
say("Do you want to ask again or play a random playlist instead? ")
ret = simplify_string(speechRecognizer.startSpeechRecognition(3))
# ret = input("Do you want to ask again or play a random playlist instead? ")
if ret == "ask again":
return False, None
elif ret in ["random", "play random", "play a random song", "whatever"]:
ret = spotify.get_playlist()
return True, ret
return False, None
# CASE: When ret is a list, it means that ret has a list of playlist dicts that may have been a match
# Ask the user which one they want, or none of them
elif isinstance(ret, list):
names = []
for each in ret:
names.append(simplify_string(each["name"]))
toggle_response = True
random = False
while ret not in names and not random:
if toggle_response:
say(f"I found {names} as matches. Which one did you mean? ")
ret = simplify_string(speechRecognizer.startSpeechRecognition(5))
# ret = simplify_string(input(f"I found {names} as matches. Which one did you mean? "))
toggle_response = not toggle_response
else:
say("Sorry, please try again, or you could tell me to play a random one ")
ret =simplify_string(speechRecognizer.startSpeechRecognition(4))
# ret = simplify_string(input("Sorry, please try again, or you could tell me to play a random one "))
if ret in ["random", "play random", "play a random song", "whatever"]:
random = True
if not random:
return True, spotify.get_playlist(ret)
return True, spotify.get_playlist()
# CASE: ret is a playlist dict
elif isinstance(ret, dict):
return True, ret
return False, None
def ask_for_command(spotify):
request = input("Let's begin! What would you like to do? ")
if request == "seek":
duration = input("Time(ms): ")
spotify.seek(duration) # Example: 20000 = 20 seconds
elif request == "pause":
spotify.pause()
elif request == "play":
spotify.play()
elif request == "skip":
spotify.skip()
elif request in ["exit", "stop", "cancel", "quit"]:
spotify.pause()
print("Thanks for playing!")
return False
return True
def receive_keys():
with open("store/store.txt", "r") as f:
l = [None] * 3
for idx, line in enumerate(f):
if line.strip() != "":
l[idx] = line.strip()
if idx >= 2:
break
return tuple(l)
def get_transcript_frame(track_name, track_duration, start_time):
video_id = transcript.get_video_id(track_name, track_duration)
lyric_arr = transcript.get_transcript(video_id)
return get_frame(lyric_arr, start_time)
def get_frame(lyric_arr, start_time):
""" Performs binary search to find subarry of lyrics according to time
"""
# Convert time from milliseconds to seconds
start_time = (start_time / 1000) + FRAME_SHIFT
first = 0
last = len(lyric_arr) - 1
time_tolerance = TIME_TOLERANCE_INCREMENT
found = False
mid = 0
while not found:
while (first <= last):
mid = (first + last) // 2
mid_start_time = lyric_arr[mid]["start"]
time_difference = abs(start_time - mid_start_time)
if time_difference <= time_tolerance:
found = lyric_arr[mid]
break
elif start_time < mid_start_time:
last = mid - 1
else:
first = mid + 1
# CASE no matching lyrics found with maximum second tolerance
if not found and time_tolerance > MAXIMUM_TOLERANCE:
print("Error: Middle index not found")
return False
# CASE current tolerance was not enough, increase the time tilerance
elif not found:
time_tolerance += TIME_TOLERANCE_INCREMENT
# Closest matching item in the transcript list has been found
# Create a subarray of items before and after
transcript_frame = [found]
scan_left = mid - 1
scan_right = mid + 1
total_duration = found["duration"]
while scan_left and scan_right:
if scan_left and scan_left >= 0 and abs(lyric_arr[scan_left]["duration"]) + total_duration <= FRAME_DURATION:
# Add item to beginning of the list
transcript_frame.insert(0, lyric_arr[scan_left])
total_duration += abs(lyric_arr[scan_left]["duration"])
scan_left -= 1
else:
scan_left = False
# Might need to change to len instead of len - 1
if scan_right and scan_right < len(lyric_arr) - 1 and abs(lyric_arr[scan_right]["duration"]) + total_duration <= FRAME_DURATION:
# Add item to end of the list
transcript_frame.append(lyric_arr[scan_right])
total_duration += abs(lyric_arr[scan_right]["duration"])
scan_right += 1
else:
scan_right = False
# The transcript frame has been made
return transcript_frame
if __name__ == '__main__':
spotify = setup()
run(spotify)