# This is WebJammies, it retrieves music from servers! # It's like radio, but better! # WebJammies is very easy to set up! # It uses simple HTTP(S) and INI files as a sort DB import requests import time import os import shutil # FIXME: Just for testing, take out later: import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) # FIXME: Just for testing! try: from discordrp import Presence richpresense = True except ImportError: print("You don't have `discordrp` installed! Disabling Discord Rich Presence.") richpresense = False try: import pygame except ImportError: print("Fatal! You need to install the `pygame` module to use WebJammies!") exit(1) class MusicPlayer: def __init__(self): self.discordrp: DiscordRP = None self.nextfile = "song0.mp3" self.nextmeta = None self.looping = False self.server = None self.mixer = pygame.mixer self.mixer.init() def play_audio_file(self, _file=None): if not _file and not self.nextfile: return if not _file: self.discordrp.set_drp(self.nextmeta, self.server) self.mixer.music.load(self.nextfile) self.mixer.music.play() print( f"Currently playing: {self.nextmeta}\n" "Press + to open the menu!" ) paused = False while True: try: if not self.mixer.music.get_busy() and not paused: self.mixer.music.unload() return while self.mixer.music.get_busy(): time.sleep(0.1) except KeyboardInterrupt: print( "\n" f"Currently listening to: {self.nextmeta}\n" "Here's some things you can do while listening:\n" "[1] Play / Pause\n" "[2] Skip\n" "[3] Previous song\n" "[4] Stop\n" "[5] Close this menu (return to listening)\n" "[6] Stop looping music" ) choice = int(input()) if choice == 1: if not paused: paused = True self.mixer.music.pause() print( f"Currently paused: {self.nextmeta}\n" "Press + to open the menu and start playing again!" ) else: paused = False self.mixer.music.unpause() print( f"Currently playing: {self.nextmeta}\n" "Press + to open the menu!" ) continue elif choice == 2: # figure smth out. pass elif choice == 3: # same thing. pass elif choice == 4: self.mixer.music.stop() self.mixer.music.unload() return elif choice == 5: print( f"Currently playing: {self.nextmeta}\n" "Press + to open the menu!" ) continue elif choice == 6: if self.looping is False: print("Can't stop looping music when we're not looping!") continue else: self.mixer.music.stop() self.mixer.music.unload() self.looping = False return else: self.discordrp.set_drp(_file, "localfile") self.mixer.music.load(_file) self.mixer.music.play() while self.mixer.music.get_busy(): print( "Currently listening to: localfile\n" "Here's some things you can do while listening:\n" "[1] Pause\n" "[2] Skip\n" "[3] Previous song\n" "[4] Stop" ) choice = input() class MusicGetter: def __init__(self): self.musicplayer = None self.server = None self.discordrp = None self.cursong_idx = 0 self.maxidx = None self.songs = [] self.metadata = {} print("Welcome to WebJammies!") print("Checking some things...") if richpresense is True: self.discordrp = DiscordRP() print("Discord Rich Presence enabled!") else: self.discordrp = DiscordRP() # We still init it to prevent any bad code thingys print("Discord Rich Presence not active.") print("Initializing MusicPlayer...") if os.path.exists("webjammies_temp"): shutil.rmtree("webjammies_temp") os.mkdir("webjammies_temp") os.chdir("webjammies_temp") self.musicplayer = MusicPlayer() self.musicplayer.discordrp = self.discordrp def get_server(self): server = input("Enter the server of choice: ") self.server = server content = requests.get(f"{server}/webjammies/index.ini", verify=False) text = content.text.splitlines() append_to_songs = False append_to_meta = False for line in text: if line.startswith("#"): continue elif line == "[FILES]": append_to_songs = True continue elif line == "[META]": append_to_songs = False append_to_meta = True i_since = 0 elif line == "[EOF]": break elif append_to_songs is True: self.songs.append(f"{line}") elif append_to_meta is True: self.metadata[f"{self.songs[i_since]}"] = line i_since += 1 else: print("This server is not a WebJammies server! Please enter the correct server.") exit(1) self.maxidx = len(self.songs) print("Loaded server configuration.") def download_song(self, song): content = requests.get(f"{self.server}/webjammies/{song}", verify=False) # for some reason windows will throw permission denied errors trying to # overwrite the file, so that's why i'll remove it first for windows if os.name == "nt": if os.path.exists("song0.mp3"): os.remove("song0.mp3") with open("song0.mp3", "wb") as f: f.write(content.content) self.musicplayer.nextmeta = self.metadata.get(song) def menu(self): self.discordrp.default_drp() if self.server is None: print( "\n" "Whatcha wanna do?\n" "[1] Connect to a server\n" "[2] Start playing audio\n" "[5] Loop music\n" "[6] Exit" ) else: print( "\n" f"Currently you're connected to: {self.server}\n" "Whatcha wanna do?\n" "[1] Connect to a different server\n" "[2] Start playing audio\n" "[3] Choose a song\n" "[4] Show whole playlist\n" "[5] Loop music\n" "[6] Exit" ) # TODO: add some error checking choice = int(input()) if choice == 1: self.get_server() print("MusicPlayer is loading the new configuration...") self.musicplayer.server = self.server self.download_song(self.songs[0]) self.cursong_idx += 1 return elif choice == 2: print("") if self.server is None: print("Cannot play music without a server!") return self.musicplayer.play_audio_file() # automatically retrieve the next file after playing. self.download_song(self.songs[self.cursong_idx]) # if we've reached the end of the list of songs, just wrap to 0 if self.cursong_idx >= self.maxidx: self.cursong_idx = 0 else: self.cursong_idx += 1 return elif choice == 3: print("") print("Enter some details about the song to listen to!") song = input() for key, value in self.metadata.items(): if song.lower() in value.lower(): print( "We might have a match!\n" f"Is the song you're looking for: {value}?" ) choice = input("You can enter 'y' for yes, 'n' for no.\n") if choice.lower() == "y": # I know this is stupid, but I really just wanna make sure it works :'( song_idx = self.songs.index(key) self.download_song(self.songs[song_idx]) self.musicplayer.play_audio_file() break elif choice.lower() == "n": print("Aww shucks! We'll keep looking!") continue else: print("Uuh, that wasn't what we were expecting!") return else: print("Bad news, we couldn't find anything! :(") return return elif choice == 4: print("") print(f"Alrighty! Here's the whole playlist from the server {self.server}") for value in self.metadata.values(): print(f"{value}") print("And that's all!") return elif choice == 5: print("") # TODO: make this better if self.server is None: print("Cannot play music without a server!") return self.musicplayer.looping = True while self.musicplayer.looping: self.musicplayer.play_audio_file() self.download_song(self.songs[self.cursong_idx]) if self.cursong_idx >= self.maxidx: self.cursong_idx = 0 self.download_song(self.songs[self.cursong_idx]) else: self.cursong_idx += 1 return elif choice == 6: exit(0) class DiscordRP: def __init__(self): self.client_id = "1346549750555476018" try: self.presence = Presence(self.client_id) except Exception: print("Error! Could not connect to Discord! Make sure Discord is active!") print("Disabling presence...") self.presence = None self.default_drp() def default_drp(self): if self.presence is None: return self.presence.set( { "name": "WebJammies", "type": 2, "details": "Not jamming at the moment", "state": "Looking for a server", "timestamps": {"start": int(time.time())} } ) def set_drp(self, song, server): if self.presence is None: return self.presence.set( { "name": "WebJammies", "type": 2, "details": f"Jamming to {song}!", "state": f"Found on server: {server}", "timestamps": {"start": int(time.time())} } ) if __name__ == "__main__": m = MusicGetter() while True: m.menu()