class MainController(tk.Frame): """ Controller for our views """ def __init__(self, parent): """Creates the main window""" tk.Frame.__init__(self, parent) self._root_win = tk.Toplevel() self._main_window = MainWindow(self._root_win, self) self._vlc_instance = vlc.Instance() self._player = self._vlc_instance.media_player_new() self.list_songs_callback() self.queue_titles = [] def list_songs_callback(self): """ Lists song titles in listbox. """ response = requests.get("http://localhost:5000/songs/all") song_list = response.json() self.song_title_list = [] for song in song_list: self.song_title_list.append(song['title']) self._main_window.add_titles_to_listbox(self.song_title_list) def play_callback(self): """Play a song specified by the index. """ index = self._main_window.get_index() response = requests.get("http://localhost:5000/songs/all") song_list = response.json() song = song_list[index] media_file = song['pathname'] + song['filename'] if self._player.get_state() == vlc.State.Playing: self._player.stop() self.update_play_stats(song['filename']) media = self._vlc_instance.media_new_path(media_file) self._player.set_media(media) self._player.play() self._main_window.song_playing['text'] = song['title'] self._main_window.artist_name['text'] = song['artist'] self._main_window.runtime_value['text'] = song['runtime'] self._main_window.album_name['text'] = song['album'] self._main_window.genre_name['text'] = song['genre'] self._main_window.state_value['text'] = "Playing" def pause_callback(self): """ Pause the player """ if self._player.get_state() == vlc.State.Playing: self._player.pause() self._main_window.state_value['text'] = "Paused" def resume_callback(self): """ Resume playing """ if self._player.get_state() == vlc.State.Paused: self._player.pause() self._main_window.state_value['text'] = "Playing" def stop_callback(self): """ Stop the player """ self._player.stop() self._main_window.state_value['text'] = "Stopped" def quit_callback(self): """ Exit the application. """ self.master.quit() def open_mp3_file(self): """ Load the file name selected""" abs_path = filedialog.askopenfilename(initialdir='.\\Music\\') path = os.getcwd() + "\\Music\\" file = os.path.basename(abs_path) if file.endswith('.mp3'): mp3_file = eyed3.load(os.path.join(path, file)) runtime = mp3_file.info.time_secs mins = int(runtime // 60) secs = int(runtime % 60) song = Song(str(getattr(mp3_file.tag, 'title')), str(getattr(mp3_file.tag, 'artist')), '{}:{}'.format(mins, secs), '{}'.format(path), '{}'.format(file), str(getattr(mp3_file.tag, 'album')), str(getattr(mp3_file.tag, 'genre'))) self.add_callback(song) def add_callback(self, song): """ Add audio file. """ data = { 'title': song.title, 'artist': song.artist, 'runtime': song.runtime, 'pathname': song.pathname, 'filename': song.filename, 'album': song.album, 'genre': song.genre } response = requests.post("http://localhost:5000/songs", json=data) if response.status_code == 200: self.list_songs_callback() msg_str = song.title + " has been added to library" messagebox.showinfo(title="Song Added", message=msg_str) else: msg_str = response.content messagebox.showinfo(title="Error", message=msg_str) def update_rating(self, event): """Updates the rating for the selected song""" index = self._main_window.get_index() form_data = self._rate_song.get_form_data() try: form_data['rating'] = int(form_data['rating']) get_response = requests.get("http://localhost:5000/songs/all") song_list = get_response.json() song = song_list[index] response = requests.put("http://localhost:5000/songs/rating/" + song['filename'], json=form_data) if response.status_code == 200: message = song['title'] + " has been successfully rated" messagebox.showinfo(title="Song Rated", message=message) self._close_rate_song_popup() else: message = response.content messagebox.showinfo(title="Error", message=message) except ValueError: message = "Rating must be a number" messagebox.showinfo(title="Error", message=message) def update_play_stats(self, filename): """Updates the play count and last_played""" requests.put("http://localhost:5000/songs/play_count/" + filename) def delete_callback(self): """ Deletes selected song from the library. """ index = self._main_window.get_index() get_response = requests.get("http://localhost:5000/songs/all") song_list = get_response.json() song = song_list[index] filename = song['filename'] del_response = requests.delete("http://localhost:5000/songs/" + filename) if del_response.status_code == 200: self.list_songs_callback() msg_str = song['title'] + " has been deleted from library" messagebox.showinfo(title="Song Added", message=msg_str) if song['title'] in self.queue_titles: self.queue_titles.remove(song['title']) else: msg_str = del_response.content messagebox.showinfo(title="Song Deleted", message=msg_str) def rate_song_popup(self): """ Show Rating Popup Window """ self._rate_win = tk.Toplevel() self._rate_song = RatingWindow(self._rate_win, self, self._main_window.get_title()) def _close_rate_song_popup(self): """ Close Rating Popup """ self._rate_win.destroy() def queue_pop_up(self): """Loads the Queue Window""" self._queue_win = tk.Toplevel() self._view_queue = ViewQueueWindow(self._queue_win, self, self.queue_titles) def delete_from_queue(self): """Removes a song from queue""" index = self._view_queue.get_index() self.queue_titles.pop(index) self._view_queue.list_songs_in_queue() def _close_queue_popup(self): """ Close Rating Popup """ self._queue_win.destroy() def add_queue_popup(self): """Adds the selected song to the queue""" self._add_queue_win = tk.Toplevel() self._add_queue = AddQueueWindow(self._add_queue_win, self, self.song_title_list) def add_to_queue_callback(self): """Adds the selected song to the queue list box""" index = self._add_queue.get_index() get_response = requests.get("http://localhost:5000/songs/all") song_list = get_response.json() song = song_list[index] self._view_queue.listbox.insert(tk.END, song['title']) self.queue_titles.append(song['title']) def _close_add_queue_popup(self): """ Close Rating Popup """ self._add_queue_win.destroy()
class MainController(tk.Frame): """ Controller for our views """ def __init__(self, parent): """Creates the main window""" tk.Frame.__init__(self, parent) # creates an instance of YouTubeAPI self.youtube_api = YouTubeAPI() # creates an instance of the MainWindow class self._root_win = tk.Toplevel() self._main_window = MainWindow(self._root_win, self) # defines a list to add all of the downloaded video titles self._video_titles = [] # call this function to add all the names to the list at startup self.list_titles_callback() def download_callback(self): """Downloads a YouTube video with the specified URL Posts the video data to the API""" yt = self.download.yt_obj try: if self.download.format_label['text'] != "mp3": path = self.__validate_path() res = self.__validate_res() format = self.__validate_format() fps = self.__validate_fps() streams_list = self.__validate_video(yt, format, res, fps) video = streams_list[0] # Checks if the file already exists in the directory for clip in self.youtube_api.get_all_videos(): file, extension = clip['filename'].split(".") if yt.title == clip['title'] and yt.author == clip['author'] and \ path == clip['pathname'] and extension == format: raise ValueError("File already exists") file_location = video.download(path) data = { 'title': yt.title, 'author': yt.author, 'resolution': video.resolution, 'frame_rate': video.fps, 'pathname': path, 'filename': os.path.basename(file_location) } response = self.youtube_api.add_video(data) msg = "Your video has been downloaded" messagebox.showinfo(title="Downloaded", message=msg) self.download_win.destroy() self.list_titles_callback() else: streams_list, path = self.__validate_audio(yt) video = streams_list[0] for clip in self.youtube_api.get_all_videos(): if yt.title == clip['title'] and yt.author == clip['author'] \ and path == clip["pathname"]: raise ValueError("File already exists") file_location = video.download(path) file_name, extension = os.path.basename(file_location).split( ".") file = file_name + ".mp3" os.rename(file_location, path + file) data = { 'title': yt.title, 'author': yt.author, 'resolution': video.resolution, 'frame_rate': video.fps, 'pathname': path, 'filename': file } response = self.youtube_api.add_video(data) msg = "Your video has been downloaded" messagebox.showinfo(title="Downloaded", message=msg) self.download_win.destroy() self.list_titles_callback() except ValueError as e: messagebox.showinfo(title="Error", message=str(e)) def __validate_path(self) -> str: """Checks if a path is chosen""" path = self.download.file_label['text'] if path == "": raise ValueError("Pick a file location.") return path def __validate_res(self) -> str: """Checks if a resolution is chosen""" res = self.download.res_label['text'] if res == "": raise ValueError("Pick a resolution") return res def __validate_format(self) -> str: """Checks if a format is chosen""" format = self.download.format_label['text'] if format == "": raise ValueError("Pick a file format") return format def __validate_fps(self) -> str: """Checks if fps is chosen""" fps = self.download.fps_label['text'] if fps == "": raise ValueError("Pick fps") return fps def __validate_video(self, yt, format, res, fps) -> list: """Validates streams for videos""" try: streams_list = [] for stream in yt.streams: type, extension = stream.mime_type.split("/") if extension == format and stream.resolution == res and stream.fps == fps: streams_list.append(stream) if len(streams_list) < 1: raise ValueError return streams_list except Exception: msg = "This format is not available. Try picking another format." messagebox.showinfo(title="Error", message=msg) def __validate_audio(self, yt): """Validates streams for audio""" format = self.download.format_label['text'] path = self.download.file_label['text'] if path == "": raise ValueError("Pick a file location.") streams_list = [] for stream in yt.streams: type, old_extenstion = stream.mime_type.split("/") if type == "audio": new_extention = old_extenstion.replace(old_extenstion, "mp3") if new_extention == format: streams_list.append(stream) return streams_list, path def list_titles_callback(self): """ Lists video titles in listbox. Gets all the videos stored in the database and adds the title""" self._video_titles.clear() # removes all items in the list # calls API and returns a list of videos video_list = self.youtube_api.get_all_videos() for video in video_list: self._video_titles.append(video['title']) # inserts the titles to the tkinter listbox self._main_window.insert_to_listbox(self._video_titles) def play_video(self, event): """Plays the selected video""" index = self._main_window.get_index() if self._main_window.get_title() == "": msg_str = "You must select a video first." messagebox.showinfo(title="Error", message=msg_str) else: video_list = self.youtube_api.get_all_videos() video = video_list[index] file_location = video['pathname'] + video['filename'] os.startfile(file_location) def rename_window_popup(self, event): """Launches the Rename Window""" title = self._main_window.get_title() if title == "": msg_str = "You must select a video first to rename." messagebox.showinfo(title="Error", message=msg_str) else: self.rename_win = tk.Toplevel() self.rename = RenameWindow(self.rename_win, self, title) def details_window_popup(self, event): """Launches a window with the video details listed""" if self._main_window.get_title() == "": msg_str = "You must select a video first." messagebox.showinfo(title="Error", message=msg_str) else: index = self._main_window.get_index() video_list = self.youtube_api.get_all_videos() video = video_list[index] self.details_win = tk.Toplevel() self.details = DetailsWindow(self.details_win, video) def download_win_popup(self): """Launches the Download settings window""" try: yt_obj = YouTube(self._main_window.get_link()) self.download_win = tk.Toplevel() self.download = DownloadWindow(self.download_win, self, yt_obj) except Exception: msg_str = "Please paste a valid YouTube URL" messagebox.showinfo(title="Error", message=msg_str) def update_title(self, event): """Updates the title of the video - sends request to API""" index = self._main_window.get_index() form_data = self.rename.get_form_data() if form_data['title'] == "": message = "Field cannot be left empty" messagebox.showinfo(title="Error", message=message) else: video_list = self.youtube_api.get_all_videos() video = video_list[index] response = self.youtube_api.update_title(form_data, video['pathname'], video['filename']) if response == 200: message = "Video Title has been updated" messagebox.showinfo(title="Video Updated", message=message) self.rename_win.destroy() self.list_titles_callback() else: message = response messagebox.showinfo(title="Error", message=message) def delete_callback(self, event): """ Deletes selected video from the library. """ index = self._main_window.get_index( ) # returns index of title in listbox if self._main_window.get_title( ) == "": # checks if you selected a video before deleting msg_str = "You must select a video first." messagebox.showinfo(title="Error", message=msg_str) else: # gets a list of all the videos in the database video_list = self.youtube_api.get_all_videos() video = video_list[index] # gets the specific video you chose filename = video['filename'] # sends a delete request to the API del_response = self.youtube_api.delete_video( video['pathname'], filename) if del_response == 200: msg_str = video['title'] + " has been deleted from library" messagebox.showinfo(title="Video Deleted", message=msg_str) self.list_titles_callback() os.remove(video['pathname'] + filename) else: msg_str = del_response messagebox.showinfo(title="Error", message=msg_str)