Subida del proyecto

master
fosanz 7 months ago
commit 325ff8b550

8
.idea/.gitignore vendored

@ -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

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

@ -0,0 +1,25 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
<option name="ignoredPackages">
<value>
<list size="12">
<item index="0" class="java.lang.String" itemvalue="requests-oauthlib" />
<item index="1" class="java.lang.String" itemvalue="Werkzeug" />
<item index="2" class="java.lang.String" itemvalue="Flask-Assets" />
<item index="3" class="java.lang.String" itemvalue="SQLAlchemy" />
<item index="4" class="java.lang.String" itemvalue="libsass" />
<item index="5" class="java.lang.String" itemvalue="requests" />
<item index="6" class="java.lang.String" itemvalue="Flask-SQLAlchemy" />
<item index="7" class="java.lang.String" itemvalue="Jinja2" />
<item index="8" class="java.lang.String" itemvalue="Flask-Login" />
<item index="9" class="java.lang.String" itemvalue="Flask" />
<item index="10" class="java.lang.String" itemvalue="typing_extensions" />
<item index="11" class="java.lang.String" itemvalue="grpc" />
</list>
</value>
</option>
</inspection_tool>
</profile>
</component>

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.11 (SpotiMIDI)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11 (SpotiMIDI)" project-jdk-type="Python SDK" />
</project>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/SpotiMIDI.iml" filepath="$PROJECT_DIR$/.idea/SpotiMIDI.iml" />
</modules>
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

@ -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()

@ -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

@ -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()

@ -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()

@ -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

@ -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()

@ -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()

Binary file not shown.
Loading…
Cancel
Save

Powered by INFORMATICA.FP.EDU.ES.