diff --git a/.gitmodules b/.gitmodules index 853108d..0ff38ab 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,4 @@ + [submodule "pymumble"] path = pymumble - url = https://github.com/azlux/pymumble + url = git://github.com/azlux/pymumble.git diff --git a/README.fr.md b/README.fr.md deleted file mode 100644 index 294675f..0000000 --- a/README.fr.md +++ /dev/null @@ -1,24 +0,0 @@ -# botamusique -[English Version](README.md) - -====== - -##FR: - -Botamusique est un bot pour mumble qui a pour vocation de permettre aux utillisateurs d'écouter de la musique ensemble via sa sortie son. -Les fonctionnalités prévues sont celles qu'on attend d'un lecteur de musique classique (Musique suivante, précédente, aléatoire, lecture d'un repertoire) -Pour ceci il va chercher les musiques téléchargées par les utillisateurs dans un dossier. - -#### Commandes -- [ ] list -- [ ] play -- [ ] playfolder -- [ ] list -- [ ] random -- [ ] volume -- [ ] skip -- [ ] stop -- [ ] joinme - -#### Futur proche -A terme une interface web sera ajoutée pour faciliter son utillisation. \ No newline at end of file diff --git a/README.md b/README.md index 5237f9d..f0f49a5 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,13 @@ Note that the ToDo list at the end of the Readme is **outdated** and **not appli Botamusique is a mumble bot which goal is to allow users to listen music together with its audio output. Predicted functionnalities will be the one you could expect from any classic music player. -1. Where to start +Bot the can play : +- Radio url +- Youtube/Soundcloud URL (everything supported by youtube-dl) +- Local folder (disabled, I need to work on the web interface) + +#### Web interface +* Disable * I need to work on it. Since I use this bot for radio, youtube/soundcloud and folder music, the web interace isn't ready. You need to create a folder for all your music. Organize your music by subfolder. The main folder need to be declare into the config (with a '/' at the end) @@ -30,46 +36,23 @@ The main folder need to be declare into the config (with a '/' at the end) commands (don't forget the sudo mode): ``` -apt-get install python3-pip -pip3 install opuslib -pip3 install protobuf -pip3 install flask -apt-get install ffmpeg +apt install python3-pip +apt install ffmpeg +apt install youtube-dl git clone --recurse-submodules https://github.com/azlux/botamusique.git cd ./botamusique +pip3 install -r requirements.txt chmod +x ./mumbleBot.py ``` #### Starting the bot -./mumbleBot.py -s HOST -u BOTNAME -P PASSWORD -p PORT -c CHANNEL +`./mumbleBot.py -s HOST -u BOTNAME -P PASSWORD -p PORT -c CHANNEL` -The bot listen to the 8181 port so you should redirect to this one in you NAT configuration to let others peoples access the web interface. +The bot listen to the 8181 port so you should redirect to this one in you NAT configuration to let others peoples access the web interface. (DISABLED) 2.TODO list ### TODOLIST -#### Features -- [ ] Next song -- [ ] Previous song -- [x] Randomizer -- [ ] Looking for songs previously downloaded in a folder by users. - -#### Commands with the interface -- [x] list -- [x] play -- [x] playfolder -- [x] random - -#### Commands by message to the bot -- [x] volume -- [ ] skip -- [x] stop -- [x] joinme -- [x] away - -#### Web Interface -- [x] Primary functions -- [ ] CSS - +Check the issue #3 diff --git a/configuration.ini b/configuration.ini index 215138a..b2d5dfe 100644 --- a/configuration.ini +++ b/configuration.ini @@ -1,16 +1,13 @@ [bot] comment = Coucou, Je suis née du savoir du Azlux, accès au https://azlux.fr/bot volume = 0.1 -admin = BafTac -music_folder = /home/fabian/music/mumblebot/ +admin = Azlux;AzMobile +music_folder = /home/dmichel/botamusique/music/ tmp_folder = /tmp/ +web_interface = False +is_web_proxified = True ignored_folders = tmp ignored_files = Thumbs.db -is_proxified = True - -[debug] -ffmpeg = False -mumbleConnection = False [command] play_file = file @@ -28,6 +25,12 @@ stop_and_getout = oust joinme = joinme queue = queue +[radio] +ponyville = http://192.99.131.205:8000/stream.mp3 +luna = http://radio.ponyvillelive.com:8002/stream +radiobrony = http://62.210.138.34:8000/live +celestiaradio = http://celestia.aiverse.org:8000/mp3_256 +jazz = http://jazz-wr04.ice.infomaniak.ch/jazz-wr04-128.mp3 [strings] current_volume = volume : %d%% @@ -40,7 +43,7 @@ no_file = Not file here bad_url = Bad URL asked multiple_matches = Track not found! Possible candidates: queue_contents = The next items in the queue are: -queue_empty = The queue is empty! +queue_empty = No more music in the playlist! help = Command available:
!play_file @@ -53,3 +56,7 @@ help = Command available:
!oust - stop + Go to default channel
!v - get or change the volume (in %)
!joinme + +[debug] +ffmpeg = False +mumbleConnection = False diff --git a/interface.py b/interface.py index 98e82a2..f575a50 100644 --- a/interface.py +++ b/interface.py @@ -71,7 +71,8 @@ def index(): if 'add_file' in request.form and ".." not in request.form['add_file']: item = ('file', request.form['add_file'], datetime.now().timestamp()) var.playlist.append(item) - if ('add_folder' in request.form and ".." not in request.form['add_folder']) or ('add_folder_recursively' in request.form and ".." not in request.form['add_folder_recursively']) : + + elif ('add_folder' in request.form and ".." not in request.form['add_folder']) or ('add_folder_recursively' in request.form and ".." not in request.form['add_folder_recursively']) : try: folder = request.form['add_folder'] except: @@ -88,6 +89,13 @@ def index(): files = list(map(lambda file: ('file', os.path.join(folder, file), datetime.now().timestamp()), files)) print('Adding to playlist: ', files) var.playlist.extend(files) + + elif 'add_url' in request.form : + var.playlist.append(['url', request.form['add_url']]) + + elif 'add_radio' in request.form: + var.playlist.append(['radio', request.form['add_radio']]) + elif 'delete_music' in request.form: for item in var.playlist: if str(item[2]) == request.form['delete_music']: @@ -97,6 +105,7 @@ def index(): action = request.form['action'] if action == "randomize": random.shuffle(var.playlist) + if var.current_music: source = var.current_music[0] # format for current_music below: diff --git a/media.py b/media.py index 64af452..8fbae1d 100644 --- a/media.py +++ b/media.py @@ -18,7 +18,7 @@ def get_radio_server_description(url): response = urllib.request.urlopen(request) data = json.loads(response.read().decode("utf-8")) title_server = data['servertitle'] - logging.debug("TITLE FOUND SHOUTCAST: " + title_server) + logging.info("TITLE FOUND SHOUTCAST: " + title_server) except urllib.error.HTTPError: pass except http.client.BadStatusLine: @@ -30,9 +30,9 @@ def get_radio_server_description(url): try: request = urllib.request.Request(url_icecast) response = urllib.request.urlopen(request) - data = json.loads(response.read().decode('utf-8',errors='ignore'),strict=False) + data = json.loads(response.read().decode('utf-8', errors='ignore'), strict=False) title_server = data['icestats']['source'][0]['server_name'] + ' - ' + data['icestats']['source'][0]['server_description'] - logging.debug("TITLE FOUND ICECAST: " + title_server) + logging.info("TITLE FOUND ICECAST: " + title_server) if not title_server: title_server = url except urllib.error.URLError: @@ -55,7 +55,7 @@ def get_radio_title(url): metadata_length = struct.unpack('B', response.read(1))[0] * 16 # length byte metadata = response.read(metadata_length).rstrip(b'\0') - logging.debug(metadata) + logging.info(metadata) # extract title from the metadata m = re.search(br"StreamTitle='([^']*)';", metadata) if m: @@ -65,3 +65,14 @@ def get_radio_title(url): except (urllib.error.URLError, urllib.error.HTTPError): pass return 'Impossible to get the music title' + + +def get_url(string): + if string.startswith('http'): + return string + p = re.compile('href="(.+)"', re.IGNORECASE) + res = re.search(p, string) + if res: + return res.group(1) + else: + return False diff --git a/mumbleBot.py b/mumbleBot.py index 0d3aa9d..fb2b889 100644 --- a/mumbleBot.py +++ b/mumbleBot.py @@ -18,6 +18,7 @@ import variables as var import hashlib import youtube_dl import media +import logging import util class MumbleBot: @@ -28,6 +29,12 @@ class MumbleBot: self.channel = args.channel var.current_music = None + FORMAT = '%(asctime)s: %(message)s' + if args.quiet: + logging.basicConfig(format=FORMAT, level=logging.ERROR, datefmt='%Y-%m-%d %H:%M:%S') + else: + logging.basicConfig(format=FORMAT, level=logging.DEBUG, datefmt='%Y-%m-%d %H:%M:%S') + ###### ## Format of the Playlist : ## [("","")] @@ -47,12 +54,12 @@ class MumbleBot: var.user = args.user var.music_folder = var.config.get('bot', 'music_folder') - var.is_proxified = var.config.getboolean("bot", "is_proxified") + var.is_proxified = var.config.getboolean("bot", "is_web_proxified") self.exit = False self.nb_exit = 0 self.thread = None - if args.wi_addr: + if var.config.getboolean("bot", "web_interface"): interface.init_proxy() tt = threading.Thread(target=start_web_interface, args=(args.wi_addr, args.wi_port)) tt.daemon = True @@ -74,11 +81,11 @@ class MumbleBot: self.loop() def ctrl_caught(self, signal, frame): - print("\ndeconnection asked") + logging.info("\ndeconnection asked") self.exit = True self.stop() if self.nb_exit > 1: - print("Forced Quit") + logging.info("Forced Quit") sys.exit(0) self.nb_exit += 1 @@ -94,7 +101,7 @@ class MumbleBot: else: return - print(command + ' - ' + parameter + ' by ' + self.mumble.users[text.actor]['name']) + logging.info(command + ' - ' + parameter + ' by ' + self.mumble.users[text.actor]['name']) if command == var.config.get('command', 'play_file') and parameter: music_folder = var.config.get('bot', 'music_folder') @@ -122,6 +129,8 @@ class MumbleBot: var.playlist.append(["url", parameter]) elif command == var.config.get('command', 'play_radio') and parameter: + if var.config.has_option('radio', parameter): + parameter = var.config.get('radio', parameter) var.playlist.append(["radio", parameter]) elif command == var.config.get('command', 'help'): @@ -180,9 +189,14 @@ class MumbleBot: self.mumble.users[text.actor].send_message(reply) elif command == var.config.get('command', 'next'): - var.current_music = [var.playlist[0][0], var.playlist[0][1], None, None] - var.playlist.pop(0) - self.launch_next() + if var.playlist: + var.current_music = [var.playlist[0][0], var.playlist[0][1], None, None] + var.playlist.pop(0) + self.launch_next() + else: + self.mumble.users[text.actor].send_message(var.config.get('strings', 'queue_empty')) + self.stop() + elif command == var.config.get('command', 'list'): folder_path = var.config.get('bot', 'music_folder') @@ -226,9 +240,9 @@ class MumbleBot: path = "" title = "" if var.current_music[0] == "url": - regex = re.compile(" 0: time.sleep(0.01) @@ -326,10 +342,11 @@ def start_web_interface(addr, port): if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Bot for playing radio stream on Mumble') + parser = argparse.ArgumentParser(description='Bot for playing music on Mumble') # General arguments parser.add_argument("--config", dest='config', type=str, default='configuration.ini', help='Load configuration from this file. Default: configuration.ini') + parser.add_argument("-q", "--quiet", dest="quiet", action="store_true", help="Only Error logs") # Mumble arguments parser.add_argument("-s", "--server", dest="host", type=str, required=True, help="The server's hostame of a mumble server") diff --git a/pymumble b/pymumble index d9f70dd..d2ad1fd 160000 --- a/pymumble +++ b/pymumble @@ -1 +1 @@ -Subproject commit d9f70dd61d69c80e322aa1185d541e6e04376148 +Subproject commit d2ad1fde0c9e427622fb9c69ca7e20783a19d101 diff --git a/requirements.txt b/requirements.txt index 03203d3..0b1e08d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ -opuslib==1.1.0 -protobuf==3.1.0 +opuslib==2.0.0 +protobuf==3.4.0 flask youtube-dl python-magic diff --git a/templates/index.html b/templates/index.html index 27a574d..5205f9d 100644 --- a/templates/index.html +++ b/templates/index.html @@ -66,7 +66,20 @@ -
+
+ Add Youtube/Soundcloud URL : +
+ + +
+
+
+ Add Radio URL : +
+ + +
+
Currently Playing :