Merge branch 'uif' into fix-HTTP-500-on-playlist-delete

This commit is contained in:
Fabian Würfl 2018-06-02 15:54:32 +02:00 committed by GitHub
commit 9215d993c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 112 additions and 95 deletions

3
.gitmodules vendored
View File

@ -1,3 +1,4 @@
[submodule "pymumble"]
path = pymumble
url = https://github.com/azlux/pymumble
url = git://github.com/azlux/pymumble.git

View File

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

View File

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

View File

@ -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:
<br />!play_file <path>
@ -53,3 +56,7 @@ help = Command available:
<br />!oust - stop + Go to default channel
<br />!v - get or change the volume (in %)
<br />!joinme
[debug]
ffmpeg = False
mumbleConnection = False

View File

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

View File

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

View File

@ -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 :
## [("<type>","<path>")]
@ -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("<a href=\"(.*?)\"")
m = regex.match(var.current_music[1])
url = m.group(1)
url = media.get_url(var.current_music[1])
if not url:
return
path, title = self.download_music(url)
var.current_music[1] = url
@ -237,9 +251,9 @@ class MumbleBot:
title = var.current_music[1]
elif var.current_music[0] == "radio":
regex = re.compile("<a href=\"(.*?)\"")
m = regex.match(var.current_music[1])
url = m.group(1)
url = media.get_url(var.current_music[1])
if not url:
return
var.current_music[1] = url
path = url
title = media.get_radio_server_description(url)
@ -249,7 +263,7 @@ class MumbleBot:
else:
ffmpeg_debug = "warning"
command = ["ffmpeg", '-v', ffmpeg_debug, '-nostdin', '-i', path, '-ac', '1', '-f', 's16le', '-ar', '48000', '-']
command = ["/usr/bin/ffmpeg", '-v', ffmpeg_debug, '-nostdin', '-i', path, '-ac', '1', '-f', 's16le', '-ar', '48000', '-']
self.thread = sp.Popen(command, stdout=sp.PIPE, bufsize=480)
var.current_music[2] = title
var.current_music[3] = path
@ -271,9 +285,8 @@ class MumbleBot:
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
for i in range(2):
try:
info_dict = ydl.extract_info(url, download=False)
info_dict = ydl.extract_info(url)
video_title = info_dict['title']
ydl.download([url])
except youtube_dl.utils.DownloadError:
pass
else:
@ -295,10 +308,13 @@ class MumbleBot:
else:
time.sleep(0.1)
if (self.thread is None or not raw_music) and len(var.playlist) != 0:
var.current_music = [var.playlist[0][0], var.playlist[0][1], None, None]
var.playlist.pop(0)
self.launch_next()
if self.thread is None or not raw_music:
if len(var.playlist) != 0:
var.current_music = [var.playlist[0][0], var.playlist[0][1], None, None]
var.playlist.pop(0)
self.launch_next()
elif len(var.playlist) == 0 and var.current_music:
var.current_music = None
while self.mumble.sound_output.get_buffer_size() > 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")

@ -1 +1 @@
Subproject commit d9f70dd61d69c80e322aa1185d541e6e04376148
Subproject commit d2ad1fde0c9e427622fb9c69ca7e20783a19d101

View File

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

View File

@ -66,7 +66,20 @@
</form>
</div>
<br />
<div id="url">
Add Youtube/Soundcloud URL :
<form method="post">
<input type=text name="add_url">
<input type="submit" value="Add URL">
</form>
</div>
<div id="radio">
Add Radio URL :
<form method="post">
<input type=text name="add_radio">
<input type="submit" value="Add Radio">
</form>
</div>
<div id="playlist">
Currently Playing :