commit 325ff8b550f1f3417772a9f6f393b4e95093c466 Author: fosanz Date: Fri Feb 16 14:33:05 2024 +0100 Subida del proyecto diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/SpotiMIDI.iml b/.idea/SpotiMIDI.iml new file mode 100644 index 0000000..2c80e12 --- /dev/null +++ b/.idea/SpotiMIDI.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..31542ff --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,25 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..7931c11 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..faae9ef --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/client/MediaPlayer.py b/client/MediaPlayer.py new file mode 100644 index 0000000..3eadc1b --- /dev/null +++ b/client/MediaPlayer.py @@ -0,0 +1,45 @@ +import threading +import time +import mido +from mido import MidiFile + +from StoppableThread import StoppableThread +from Requestor import Requestor + +class MediaPlayer: + + def __init__(self, host, port): + self.requestor = Requestor(host, port) + self.song_thread = None + self.output = mido.open_output() + + def request_song(self, song_name): + bytes_song = self.requestor.getSong(song_name) + + with open('received_song.mid', 'wb') as file: + file.write(bytes_song) + + if self.song_thread is not None and self.song_thread.is_alive(): + self.song_thread.stop() + + self.song_thread = StoppableThread(target=self.play_song, args=('received_song.mid',)) + self.song_thread.start() + + def play_song(self, song_path): + mid = MidiFile(song_path) + try: + for msg in mid.play(): + if threading.current_thread().stopped(): + break + + self.output.send(msg) + + except Exception as e: + print(e) + + finally: + self.output.reset() + + def stop_song(self): + if self.song_thread is not None and self.song_thread.is_alive(): + self.song_thread.stop() \ No newline at end of file diff --git a/client/Requestor.py b/client/Requestor.py new file mode 100644 index 0000000..ba38ca9 --- /dev/null +++ b/client/Requestor.py @@ -0,0 +1,32 @@ +import socket + + +class Requestor(object): + + def __init__(self, host: str, port: int): + self.host = host + self.port = port + + + def getSongList(self) -> list: + client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + client.connect((self.host, self.port)) + client.send('getSongList'.encode('utf-8')) + song_list = client.recv(1024).decode('utf-8') + client.close() + return song_list.split('\n') + + def getSong(self, song_id: int) -> bytes: + client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + client.connect((self.host, self.port)) + client.send(f'getSong:{song_id}'.encode('utf-8')) + + song_data = b"" + while True: + chunk = client.recv(1024) + if not chunk: + break + song_data += chunk + + client.close() + return song_data \ No newline at end of file diff --git a/client/StoppableThread.py b/client/StoppableThread.py new file mode 100644 index 0000000..31f4c7a --- /dev/null +++ b/client/StoppableThread.py @@ -0,0 +1,13 @@ +import threading + +class StoppableThread(threading.Thread): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._stop_event = threading.Event() + self._pause_event = threading.Event() + + def stop(self): + self._stop_event.set() + + def stopped(self): + return self._stop_event.is_set() \ No newline at end of file diff --git a/client/client.py b/client/client.py new file mode 100644 index 0000000..a7be31f --- /dev/null +++ b/client/client.py @@ -0,0 +1,40 @@ +import os +import tkinter as tk + +from MediaPlayer import MediaPlayer + +CLIENT_HOST = "localhost" +CLIENT_PORT = 9999 +media_player = MediaPlayer(CLIENT_HOST, CLIENT_PORT) + +def request_selected_song(): + selected_song = song_listbox.get(song_listbox.curselection()) + media_player.request_song(selected_song) + +def stop_song(): + media_player.stop_song() + +root = tk.Tk() +root.title("Song Requestor") + +song_listbox = tk.Listbox(root, height=10, width=50) +song_listbox.pack() + +song_list = media_player.requestor.getSongList() +for song in song_list: + if song: # Check if song is not an empty string + song_listbox.insert(tk.END, song) + +request_button = tk.Button(root, text="Play song", command=request_selected_song) +request_button.pack() + +play_pause_button = tk.Button(root, text="Stop song", command=stop_song) +play_pause_button.pack() + +def on_close(): + media_player.stop_song() + os.remove('received_song.mid') + root.destroy() + +root.protocol("WM_DELETE_WINDOW", on_close) +root.mainloop() \ No newline at end of file diff --git a/server/Library.py b/server/Library.py new file mode 100644 index 0000000..ddce1d1 --- /dev/null +++ b/server/Library.py @@ -0,0 +1,69 @@ +import os + +from mido import MetaMessage + +from Song import Song +import mido + +class Library(object): + + def __init__(self): + self.songs = [] + + def initialize(self, songs_dir: str): + print("Initializing library") + for root, dirs, files in os.walk(songs_dir): + for i, file in enumerate(files): + if file.endswith('.mid'): + name = file.split('-')[0] + author = file.split('-')[1].split('.')[0] + path = os.path.join(root, file) + song = Song(i, name, author, path, self.get_request_count_from_midi_file(path)) + print(f"Loaded song: {song.name} by {song.author} with {song.total_requests} requests") + self.songs.append(song) + + def get_request_count_from_midi_file(self, file_path): + mid = mido.MidiFile(file_path) + + for i, track in enumerate(mid.tracks): + for msg in track: + if msg.type == 'text' and 'Request count:' in msg.text: + return int(msg.text.split(': ')[1]) + + # If no 'text' MetaMessage with the request count is found, add one with a count of 0 + msg = MetaMessage('text', text='Request count: 0') + mid.tracks[0].append(msg) + mid.save(file_path) + return 0 + + def get_song_list(self) -> str: + sorted = self.songs.copy() + sorted.sort(key=lambda x: x.total_requests, reverse=True) + song_list = "" + for song in sorted: + song_list += f"{song.id}: {song.name} by {song.author}\n" + return song_list + + def get_song_by_id(self, id: int) -> Song: + for song in self.songs: + if song.id == id: + # Increment the request count + song.total_requests += 1 + + # Load the MIDI file + mid = mido.MidiFile(song.path) + + # Remove the old 'text' MetaMessage with the request count + for i, track in enumerate(mid.tracks): + for j, msg in enumerate(track): + if msg.type == 'text' and 'Request count:' in msg.text: + del track[j] + + # Add a new 'text' MetaMessage with the updated request count + mid.tracks[0].append(MetaMessage('text', text=f'Request count: {song.total_requests}')) + + # Save the MIDI file + mid.save(song.path) + + return song + return None \ No newline at end of file diff --git a/server/Song.py b/server/Song.py new file mode 100644 index 0000000..0e250fd --- /dev/null +++ b/server/Song.py @@ -0,0 +1,17 @@ +class Song(object): + + def __init__(self, id: int, name: str, author: str, path: str, total_requests: int): + self.id = id + self.name = name + self.author = author + self.path = path + self.total_requests = total_requests + + def get_total_requests(self) -> int: + return self.total_requests + + def get_name(self) -> str: + return self.name + + def get_data(self) -> bytes: + return open(self.path, 'rb').read() \ No newline at end of file diff --git a/server/server.py b/server/server.py new file mode 100644 index 0000000..cde4cdb --- /dev/null +++ b/server/server.py @@ -0,0 +1,39 @@ +import socket +import threading + +from Library import Library +from Song import Song +import os + +SONGS_DIR = os.path.join(os.path.dirname(__file__), 'songs') + +library = Library() +library.initialize(SONGS_DIR) + +def handle_client(client_socket): + request = client_socket.recv(1024).decode('utf-8') + print(f"Received: {request}") + + if request == 'getSongList': + client_socket.send(library.get_song_list().encode('utf-8')) + + elif request.startswith('getSong:'): + song_id = int(request.split(':')[1]) + song: Song = library.get_song_by_id(song_id) + print(f"Sending song: {song.name} by {song.author} to {client_socket.getpeername()}") + client_socket.send(song.get_data()) + client_socket.close() + +def start_server(): + server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + server.bind(("0.0.0.0", 9999)) + server.listen(5) + print("Listening on port 9999") + + while True: + client, addr = server.accept() + print(f"Accepted connection from: {addr[0]}:{addr[1]}") + client_handler = threading.Thread(target=handle_client, args=(client,)) + client_handler.start() + +start_server() \ No newline at end of file diff --git a/songs/Michael Jackson - Billie Jean.mid b/songs/Michael Jackson - Billie Jean.mid new file mode 100644 index 0000000..df0ca4f Binary files /dev/null and b/songs/Michael Jackson - Billie Jean.mid differ diff --git a/songs/Pirates of the Caribbean - He's a Pirate.mid b/songs/Pirates of the Caribbean - He's a Pirate.mid new file mode 100644 index 0000000..ac37c1e Binary files /dev/null and b/songs/Pirates of the Caribbean - He's a Pirate.mid differ diff --git a/songs/Rick Astley - Never Gonna Give You Up.mid b/songs/Rick Astley - Never Gonna Give You Up.mid new file mode 100644 index 0000000..f32b5ad Binary files /dev/null and b/songs/Rick Astley - Never Gonna Give You Up.mid differ diff --git a/songs/Super Mario 64 - Medley.mid b/songs/Super Mario 64 - Medley.mid new file mode 100644 index 0000000..069fb8b Binary files /dev/null and b/songs/Super Mario 64 - Medley.mid differ diff --git a/songs/Tetris - Tetris Main Theme.mid b/songs/Tetris - Tetris Main Theme.mid new file mode 100644 index 0000000..9d53526 Binary files /dev/null and b/songs/Tetris - Tetris Main Theme.mid differ diff --git a/songs/Wii Channels - Mii Channel.mid b/songs/Wii Channels - Mii Channel.mid new file mode 100644 index 0000000..118e4cf Binary files /dev/null and b/songs/Wii Channels - Mii Channel.mid differ