new playlist format

This commit is contained in:
Azlux 2018-11-13 15:48:09 +01:00
parent b4ae33602e
commit 6aca72eaee
10 changed files with 357 additions and 185 deletions

View File

@ -27,6 +27,9 @@ allow_private_message = True
# Maximum track played when a playlist is added.
max_track_playlist = 20
# Maximum music duration (minutes)
max_track_duration = 60
[webinterface]
enabled = False
is_web_proxified = True
@ -42,7 +45,7 @@ play_playlist = playlist
help = help
stop = stop
list = list
next = skip
skip = skip
current_music = np
volume = v
kill = kill
@ -68,12 +71,17 @@ not_playing = No music right now
bad_file = Bad file requested
no_file = File not found
bad_url = Bad URL requested
unable_download = Error while downloading the music...
multiple_matches = Track not found! Possible candidates:
queue_contents = The next items in the queue are:
queue_empty = No more music in the playlist!
now_playing = Now playing %s<br />%s
not_in_my_channel = You're not in my channel, command refused !
pm_not_allowed = Private message aren't allowed.
too_long = This music is too long, skipping !
download_in_progress = Download of %s in progress
no_possible = it's not possible to do that
removing_item = Removing entry %s from queue
help = Command available:
<br />!file [path]
@ -82,7 +90,7 @@ help = Command available:
<br />!radio [url] - url of a stream
<br />!list - display list of available tracks
<br />!queue - display items in queue
<br />!next - jump to the next music of the playlist
<br />!skip - jump to the next music of the playlist (of remove the X items if you add a number)
<br />!stop - stop and clear the playlist
<br />!oust - stop + Go to default channel
<br />!v - get or change the volume (in %)

5
db.ini
View File

@ -1,4 +1,5 @@
[bot]
volume = 0.1
volume = 0.02
ban_music = []
ban_user = []
ban_user = []

0
media/__init__.py Normal file
View File

0
media/file.py Normal file
View File

0
media/playlist.py Normal file
View File

71
media/radio.py Normal file
View File

@ -0,0 +1,71 @@
import re
import urllib
import logging
import json
import http.client
import struct
def get_radio_server_description(url):
p = re.compile('(https?\:\/\/[^\/]*)', re.IGNORECASE)
res = re.search(p, url)
base_url = res.group(1)
url_icecast = base_url + '/status-json.xsl'
url_shoutcast = base_url + '/stats?json=1'
title_server = None
try:
request = urllib.request.Request(url_shoutcast)
response = urllib.request.urlopen(request)
data = json.loads(response.read().decode("utf-8"))
title_server = data['servertitle']
logging.info("TITLE FOUND SHOUTCAST: " + title_server)
except urllib.error.HTTPError:
pass
except http.client.BadStatusLine:
pass
except ValueError:
return False
if not title_server:
try:
request = urllib.request.Request(url_icecast)
response = urllib.request.urlopen(request)
data = json.loads(response.read().decode('utf-8', errors='ignore'), strict=False)
source = data['icestats']['source']
if type(source) is list:
source = source[0]
title_server = source['server_name'] + ' - ' + source['server_description']
logging.info("TITLE FOUND ICECAST: " + title_server)
if not title_server:
title_server = url
except urllib.error.URLError:
title_server = url
except urllib.error.HTTPError:
return False
except http.client.BadStatusLine:
pass
return title_server
def get_radio_title(url):
request = urllib.request.Request(url, headers={'Icy-MetaData': 1})
try:
response = urllib.request.urlopen(request)
icy_metaint_header = int(response.headers['icy-metaint'])
if icy_metaint_header is not None:
response.read(icy_metaint_header)
metadata_length = struct.unpack('B', response.read(1))[0] * 16 # length byte
metadata = response.read(metadata_length).rstrip(b'\0')
logging.info(metadata)
# extract title from the metadata
m = re.search(br"StreamTitle='([^']*)';", metadata)
if m:
title = m.group(1)
if title:
return title.decode()
except (urllib.error.URLError, urllib.error.HTTPError):
pass
return 'Unable to get the music title'

39
media/system.py Normal file
View File

@ -0,0 +1,39 @@
import logging
import os
def get_size_folder(path):
folder_size = 0
for (path, dirs, files) in os.walk(path):
for file in files:
filename = os.path.join(path, file)
folder_size += os.path.getsize(filename)
return int(folder_size / (1024 * 1024))
def clear_tmp_folder(path, size):
if size == -1:
return
elif size == 0:
for (path, dirs, files) in os.walk(path):
for file in files:
filename = os.path.join(path, file)
os.remove(filename)
else:
if get_size_folder(path=path) > size:
all_files = ""
for (path, dirs, files) in os.walk(path):
all_files = [os.path.join(path, file) for file in files]
all_files.sort(key=lambda x: os.path.getmtime(x))
size_tp = 0
print(all_files)
for idx, file in enumerate(all_files):
size_tp += os.path.getsize(file)
if int(size_tp / (1024 * 1024)) > size:
logging.info("Cleaning tmp folder")
to_remove = all_files[:idx]
print(to_remove)
for f in to_remove:
logging.debug("Removing " + f)
os.remove(os.path.join(path, f))
return

17
media/url.py Normal file
View File

@ -0,0 +1,17 @@
import youtube_dl
import variables as var
def get_url_info():
with youtube_dl.YoutubeDL() as ydl:
for i in range(2):
try:
print(var.playlist)
info = ydl.extract_info(var.playlist[-1]['url'], download=False)
var.playlist[-1]['duration'] = info['duration'] / 60
var.playlist[-1]['title'] = info['title']
except youtube_dl.utils.DownloadError:
pass
else:
return True
return False

View File

@ -14,13 +14,18 @@ import interface
import variables as var
import hashlib
import youtube_dl
import media
import logging
import util
import base64
from PIL import Image
from io import BytesIO
from mutagen.easyid3 import EasyID3
import re
import media.url
import media.file
import media.playlist
import media.radio
import media.system
class MumbleBot:
@ -28,7 +33,6 @@ class MumbleBot:
signal.signal(signal.SIGINT, self.ctrl_caught)
self.volume = var.config.getfloat('bot', 'volume')
self.channel = args.channel
var.current_music = {}
FORMAT = '%(asctime)s: %(message)s'
if args.quiet:
@ -36,25 +40,6 @@ class MumbleBot:
else:
logging.basicConfig(format=FORMAT, level=logging.DEBUG, datefmt='%Y-%m-%d %H:%M:%S')
######
## Format of the Playlist :
## [("<type>","<path/url>")]
## types : file, radio, url, is_playlist, number_music_to_play
######
######
## Format of the current_music variable
# var.current_music = { "type" : str,
# "path" : str, # path of the file to play
# "url" : str # url to download
# "title" : str,
# "user" : str,
# "is_playlist": boolean,
# "number_track_to_play": int, # FOR PLAYLIST ONLY
# "start_index" : int, # FOR PLAYLIST ONLY
# "current_index" : int} # FOR PLAYLIST ONLY
# len(var.current_music) = 6
var.playlist = []
var.user = args.user
@ -63,7 +48,7 @@ class MumbleBot:
self.exit = False
self.nb_exit = 0
self.thread = None
self.playing = False
self.is_playing = False
if var.config.getboolean("webinterface", "enabled"):
wi_addr = var.config.get("webinterface", "listening_addr")
@ -107,7 +92,7 @@ class MumbleBot:
self.loop()
def ctrl_caught(self, signal, frame):
logging.info("\nSIGINT caught, quitting")
logging.info("\nSIGINT caught, quitting, {} more to kill".format(2 - self.nb_exit))
self.exit = True
self.stop()
if self.nb_exit > 1:
@ -150,25 +135,46 @@ class MumbleBot:
if path.startswith(music_folder):
if os.path.isfile(path):
filename = path.replace(music_folder, '')
var.playlist.append(["file", filename, user])
music = {'type': 'file',
'path': filename,
'user': user}
var.playlist.append(music)
else:
# try to do a partial match
matches = [file for file in util.get_recursive_filelist_sorted(music_folder) if parameter.lower() in file.lower()]
if len(matches) == 0:
self.mumble.users[text.actor].send_message(var.config.get('strings', 'no_file'))
self.send_msg(var.config.get('strings', 'no_file'), text)
elif len(matches) == 1:
var.playlist.append(["file", matches[0], user])
music = {'type': 'file',
'path': matches[0],
'user': user}
var.playlist.append(music)
else:
msg = var.config.get('strings', 'multiple_matches') + '<br />'
msg += '<br />'.join(matches)
self.mumble.users[text.actor].send_message(msg)
self.send_msg(msg, text)
else:
self.mumble.users[text.actor].send_message(var.config.get('strings', 'bad_file'))
self.send_msg(var.config.get('strings', 'bad_file'), text)
self.async_download_next()
elif command == var.config.get('command', 'play_url') and parameter:
var.playlist.append(["url", parameter, user])
self.async_download_next()
music = {'type': 'url',
'url': self.get_url_from_input(parameter),
'user': user,
'ready': 'validation'}
var.playlist.append(music)
if media.url.get_url_info():
if var.playlist[-1]['duration'] > var.config.getint('bot', 'max_track_duration'):
var.playlist.pop()
self.send_msg(var.config.get('strings', 'too_long'), text)
else:
var.playlist[-1]['ready'] = "no"
self.async_download_next()
else:
var.playlist.pop()
self.send_msg(var.config.get('strings', 'unable_download'), text)
elif command == var.config.get('command', 'play_playlist') and parameter:
offset = 1
@ -176,17 +182,26 @@ class MumbleBot:
offset = int(parameter.split(" ")[-1])
except ValueError:
pass
var.playlist.append(["playlist", parameter, user, var.config.getint('bot', 'max_track_playlist'), offset])
music = {'type': 'playlist',
'url': self.get_url_from_input(parameter),
'user': user,
'max_track_allowed': var.config.getint('bot', 'max_track_playlist'),
'current_index': 1,
'start_index': offset}
var.playlist.append(music)
self.async_download_next()
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, user])
music = {'type': 'radio',
'url': self.get_url_from_input(parameter),
'user': user}
var.playlist.append(music)
self.async_download_next()
elif command == var.config.get('command', 'help'):
self.send_msg_channel(var.config.get('strings', 'help'))
self.send_msg(var.config.get('strings', 'help'), text)
elif command == var.config.get('command', 'stop'):
self.stop()
@ -208,9 +223,9 @@ class MumbleBot:
else:
msg += "Update done : " + tp.split('Successfully installed')[1]
if 'up-to-date' not in sp.check_output(['/usr/bin/env', 'git', 'pull']).decode():
msg += "<br /> Botamusique is up-to-date"
msg += "<br /> I'm up-to-date"
else:
msg += "<br /> Botamusique have available update"
msg += "<br /> I have available updates, need to do it manually"
self.mumble.users[text.actor].send_message(msg)
else:
self.mumble.users[text.actor].send_message(var.config.get('strings', 'not_admin'))
@ -223,56 +238,62 @@ class MumbleBot:
elif command == var.config.get('command', 'volume'):
if parameter is not None and parameter.isdigit() and 0 <= int(parameter) <= 100:
self.volume = float(float(parameter) / 100)
self.send_msg_channel(var.config.get('strings', 'change_volume') % (
int(self.volume * 100), self.mumble.users[text.actor]['name']))
self.send_msg(var.config.get('strings', 'change_volume') % (
int(self.volume * 100), self.mumble.users[text.actor]['name']), text)
var.db.set('bot', 'volume', str(self.volume))
else:
self.send_msg_channel(var.config.get('strings', 'current_volume') % int(self.volume * 100))
self.send_msg(var.config.get('strings', 'current_volume') % int(self.volume * 100), text)
elif command == var.config.get('command', 'current_music'):
if var.current_music:
source = var.current_music["type"]
if len(var.playlist) > 0:
source = var.playlist[0]["type"]
if source == "radio":
reply = "[radio] {title} on {url} by {user}".format(
title=media.get_radio_title(var.current_music["path"]),
url=var.current_music["title"],
user=var.current_music["user"]
title=media.radio.get_radio_title(var.playlist[0]["url"]),
url=var.playlist[0]["title"],
user=var.playlist[0]["user"]
)
elif source == "url":
reply = "[url] {title} (<a href=\"{url}\">{url}</a>) by {user}".format(
title=var.current_music["title"],
url=var.current_music["path"],
user=var.current_music["user"]
title=var.playlist[0]["title"],
url=var.playlist[0]["url"],
user=var.playlist[0]["user"]
)
elif source == "file":
reply = "[file] {title} by {user}".format(
title=var.current_music["title"],
user=var.current_music["user"])
title=var.playlist[0]["title"],
user=var.playlist[0]["user"])
elif source == "playlist":
reply = "[playlist] {title} (from the playlist <a href=\"{url}\">{playlist}</a> by {user}".format(
title=var.current_music["title"],
url=var.current_music["path"],
playlist=var.current_music["playlist_title"],
user=var.current_music["user"]
title=var.playlist[0]["title"],
url=var.playlist[0]["url"],
playlist=var.playlist[0]["playlist_title"],
user=var.playlist[0]["user"]
)
else:
reply = "(?)[{}] {} {} by {}".format(
var.current_music["type"],
var.current_music["path"],
var.current_music["title"],
var.current_music["user"]
var.playlist[0]["type"],
var.playlist[0]["url"] if 'url' in var.playlist[0] else var.playlist[0]["path"],
var.playlist[0]["title"],
var.playlist[0]["user"]
)
else:
reply = var.config.get('strings', 'not_playing')
self.mumble.users[text.actor].send_message(reply)
self.send_msg(reply, text)
elif command == var.config.get('command', 'next'):
if self.get_next():
self.launch_next()
elif command == var.config.get('command', 'skip'):
if parameter is not None and parameter.isdigit() and int(parameter) > 0:
if int(parameter) < len(var.playlist):
removed = var.playlist.pop(int(parameter))
self.send_msg(var.config.get('strings', 'removing_item') % (removed['title'] if 'title' in removed else removed['url']), text)
else:
self.send_msg(var.config.get('strings', 'no_possible'), text)
elif self.next():
self.launch_music()
self.async_download_next()
else:
self.mumble.users[text.actor].send_message(var.config.get('strings', 'queue_empty'))
self.send_msg(var.config.get('strings', 'queue_empty'), text)
self.stop()
elif command == var.config.get('command', 'list'):
@ -280,36 +301,28 @@ class MumbleBot:
files = util.get_recursive_filelist_sorted(folder_path)
if files:
self.mumble.users[text.actor].send_message('<br>'.join(files))
self.send_msg('<br>'.join(files), text)
else:
self.mumble.users[text.actor].send_message(var.config.get('strings', 'no_file'))
self.send_msg(var.config.get('strings', 'no_file'), text)
elif command == var.config.get('command', 'queue'):
if len(var.playlist) == 0:
if len(var.playlist) <= 1:
msg = var.config.get('strings', 'queue_empty')
else:
msg = var.config.get('strings', 'queue_contents') + '<br />'
for (music_type, path, user) in var.playlist:
msg += '({}) {}<br />'.format(music_type, path)
i = 1
for value in var.playlist[1:]:
msg += '[{}] ({}) {}<br />'.format(i, value['type'], value['title'] if 'title' in value else value['url'])
i += 1
self.send_msg_channel(msg)
self.send_msg(msg, text)
elif command == var.config.get('command', 'repeat'):
var.playlist.append([var.current_music["type"], var.current_music["path"], var.current_music["user"]])
var.playlist.append([var.playlist[0]["type"], var.playlist[0]["path"], var.playlist[0]["user"]])
else:
self.mumble.users[text.actor].send_message(var.config.get('strings', 'bad_command'))
def launch_play_file(self, path):
self.stop()
if var.config.getboolean('debug', 'ffmpeg'):
ffmpeg_debug = "debug"
else:
ffmpeg_debug = "warning"
command = ["ffmpeg", '-v', ffmpeg_debug, '-nostdin', '-i', path, '-ac', '1', '-f', 's16le', '-ar', '48000', '-']
self.thread = sp.Popen(command, stdout=sp.PIPE, bufsize=480)
self.playing = True
@staticmethod
def is_admin(user):
list_admin = var.config.get('bot', 'admin').split(';')
@ -319,60 +332,38 @@ class MumbleBot:
return False
@staticmethod
def get_next():
def next():
# Return True is next is possible
if var.current_music and var.current_music['type'] == "playlist":
var.current_music['current_index'] += 1
if var.current_music['current_index'] <= (var.current_music['start_index'] + var.current_music['number_track_to_play']):
if len(var.playlist) > 0 and var.playlist[0]['type'] == "playlist":
var.playlist[0]['current_index'] = var.playlist[0]['current_index'] + 1
if var.playlist[0]['current_index'] <= (var.playlist[0]['start_index'] + var.playlist[0]['max_track_allowed']):
return True
if not var.playlist:
if len(var.playlist) > 1:
var.playlist.pop(0)
return True
elif len(var.playlist) == 1:
var.playlist.pop(0)
return False
else:
return False
if var.playlist[0][0] == "playlist":
var.current_music = {'type': var.playlist[0][0],
'url': var.playlist[0][1],
'title': None,
'user': var.playlist[0][2],
'is_playlist': True,
'number_track_to_play': var.playlist[0][3],
'start_index': var.playlist[0][4],
'current_index': var.playlist[0][4]
}
else:
var.current_music = {'type': var.playlist[0][0],
'url': var.playlist[0][1],
'title': None,
'user': var.playlist[0][2]}
var.playlist.pop(0)
return True
def launch_next(self):
path = ""
title = ""
def launch_music(self):
uri = ""
var.next_downloaded = False
logging.debug(var.current_music)
if var.current_music["type"] == "url" or var.current_music["type"] == "playlist":
url = media.get_url(var.current_music["url"])
logging.debug(var.playlist)
if var.playlist[0]["type"] == "url" or var.playlist[0]["type"] == "playlist":
media.system.clear_tmp_folder(var.config.get('bot', 'tmp_folder'), var.config.getint('bot', 'tmp_folder_max_size'))
if not url:
return
media.clear_tmp_folder(var.config.get('bot', 'tmp_folder'), var.config.getint('bot', 'tmp_folder_max_size'))
if var.current_music["type"] == "playlist":
path, title = self.download_music(url, var.current_music["current_index"])
var.current_music["playlist_title"] = title
else:
path, title = self.download_music(url)
var.current_music["path"] = path
if os.path.isfile(path):
audio = EasyID3(path)
self.download_music(index=0)
uri = var.playlist[0]['path']
if os.path.isfile(uri):
audio = EasyID3(uri)
title = ""
if audio["title"]:
title = audio["title"][0]
path_thumbnail = var.config.get('bot', 'tmp_folder') + hashlib.md5(path.encode()).hexdigest() + '.jpg'
path_thumbnail = var.config.get('bot', 'tmp_folder') + hashlib.md5(uri.encode()).hexdigest() + '.jpg'
thumbnail_html = ""
if os.path.isfile(path_thumbnail):
im = Image.open(path_thumbnail)
@ -384,54 +375,59 @@ class MumbleBot:
logging.debug(thumbnail_html)
if var.config.getboolean('bot', 'announce_current_music'):
self.send_msg_channel(var.config.get('strings', 'now_playing') % (title, thumbnail_html))
self.send_msg(var.config.get('strings', 'now_playing') % (title, thumbnail_html))
else:
if var.current_music["type"] == "playlist":
var.current_music['current_index'] = var.current_music['number_track_to_play']
if self.get_next():
self.launch_next()
self.async_download_next()
pass
elif var.current_music["type"] == "file":
path = var.config.get('bot', 'music_folder') + var.current_music["path"]
title = var.current_music["path"]
elif var.playlist[0]["type"] == "file":
uri = var.config.get('bot', 'music_folder') + var.playlist[0]["path"]
elif var.current_music["type"] == "radio":
url = media.get_url(var.current_music["url"])
if not url:
return
var.current_music["path"] = url
path = url
title = media.get_radio_server_description(url)
var.current_music["title"] = title
elif var.playlist[0]["type"] == "radio":
uri = var.playlist[0]["url"]
title = media.radio.get_radio_server_description(uri)
var.playlist[0]["title"] = title
if var.config.getboolean('debug', 'ffmpeg'):
ffmpeg_debug = "debug"
else:
ffmpeg_debug = "warning"
command = ["ffmpeg", '-v', ffmpeg_debug, '-nostdin', '-i', path, '-ac', '1', '-f', 's16le', '-ar', '48000', '-']
self.thread = sp.Popen(command, stdout=sp.PIPE, bufsize=480)
print(var.playlist)
command = ["ffmpeg", '-v', ffmpeg_debug, '-nostdin', '-i', uri, '-ac', '1', '-f', 's16le', '-ar', '48000', '-']
if var.playlist[0]["type"] == "readio":
command = ["ffmpeg", '-v', ffmpeg_debug,'-reconnect', '1', '-reconnect_at_eof', '1', '-reconnect_streamed', '1', '-reconnect_delay_max', '4294', '-nostdin', '-i', uri, '-ac', '1', '-f', 's16le', '-ar', '48000', '-']
self.thread = sp.Popen(command, stdout=sp.PIPE, bufsize=480)
self.is_playing = True
@staticmethod
def download_music(url, index=None):
def download_music(self, index, next_with_playlist=False):
url = var.playlist[index]['url']
url_hash = hashlib.md5(url.encode()).hexdigest()
if index:
url_hash = url_hash + "-" + str(index)
if var.playlist[index]['type'] == 'playlist':
url_hash = url_hash + "-" + str(var.playlist[index]['current_index'])
path = var.config.get('bot', 'tmp_folder') + url_hash + ".%(ext)s"
mp3 = path.replace(".%(ext)s", ".mp3")
if os.path.isfile(mp3):
audio = EasyID3(mp3)
video_title = audio["title"][0]
else:
if index:
var.playlist[index]['path'] = mp3
# if os.path.isfile(mp3):
# audio = EasyID3(mp3)
# var.playlist[index]['title'] = audio["title"][0]
if var.playlist[index]['ready'] == "no":
var.playlist[index]['ready'] = "downloading"
self.send_msg(var.config.get('strings', "download_in_progress") % var.playlist[index]['title'])
if var.playlist[index]['type'] == 'playlist':
item = str(var.playlist[index]['current_index'])
if next_with_playlist:
item = str(var.playlist[index]['current_index'] + 1)
ydl_opts = {
'format': 'bestaudio/best',
'outtmpl': path,
'writethumbnail': True,
'updatetime': False,
'playlist_items': str(index),
'playlist_items': item,
'postprocessors': [{
'key': 'FFmpegExtractAudio',
'preferredcodec': 'mp3',
@ -451,42 +447,42 @@ class MumbleBot:
'preferredquality': '192'},
{'key': 'FFmpegMetadata'}]
}
video_title = ""
print(ydl_opts)
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
for i in range(2):
try:
info_dict = ydl.extract_info(url)
video_title = info_dict['title']
ydl.extract_info(url)
var.playlist[index]['ready'] = "yes"
except youtube_dl.utils.DownloadError:
pass
else:
break
return mp3, video_title
return True
def async_download_next(self):
if not var.next_downloaded:
if len(var.playlist) > 0 and var.playlist[0]['type'] == 'playlist':
th = threading.Thread(target=self.download_music, kwargs={'index': 0, 'next_with_playlist': True})
elif len(var.playlist) > 1 and var.playlist[1]['type'] == 'url':
th = threading.Thread(target=self.download_music, kwargs={'index': 1})
else:
return
var.next_downloaded = True
logging.info("Start download in thread")
th = threading.Thread(target=self.download_next, args=())
th.daemon = True
th.start()
def download_next(self):
if not var.current_music:
return
@staticmethod
def get_url_from_input(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:
if var.current_music["type"] == "playlist":
if var.current_music['current_index'] + 1 <= (var.current_music['start_index'] + var.current_music['number_track_to_play']):
self.download_music(media.get_url(var.current_music['url']), var.current_music["current_index"] + 1)
if var.playlist:
url = media.get_url(var.playlist[0][1])
if not url:
return
if var.playlist[0][0] == "playlist":
self.download_music(url, var.current_music["current_index"])
elif var.playlist[0][0] == "playlist":
self.download_music(url)
return False
def loop(self):
raw_music = ""
@ -504,11 +500,12 @@ class MumbleBot:
time.sleep(0.1)
if self.thread is None or not raw_music:
if self.get_next():
self.launch_next()
if self.is_playing:
self.is_playing = False
self.next()
if len(var.playlist) > 0 and ('ready' not in var.playlist[0] or var.playlist[0]['ready'] != 'validation'):
self.launch_music()
self.async_download_next()
else:
var.current_music = None
while self.mumble.sound_output.get_buffer_size() > 0:
time.sleep(0.01)
@ -519,18 +516,20 @@ class MumbleBot:
def stop(self):
if self.thread:
var.current_music = None
self.thread.kill()
self.thread = None
var.playlist = []
self.is_playing = False
def set_comment(self):
self.mumble.users.myself.comment(var.config.get('bot', 'comment'))
def send_msg_channel(self, msg, channel=None):
if not channel:
channel = self.mumble.channels[self.mumble.users.myself['channel_id']]
channel.send_text_message(msg)
def send_msg(self, msg, text=None):
if not text.session:
own_channel = self.mumble.channels[self.mumble.users.myself['channel_id']]
own_channel.send_text_message(msg)
else:
self.mumble.users[text.actor].send_message(msg)
def start_web_interface(addr, port):

37
playlist.txt Normal file
View File

@ -0,0 +1,37 @@
type : url
url
title
path
duration
thundnail
user
ready (validation, no, downloading, yes)
type : playlist
url
path
playlist_title
nb_track_allowed
nb_track_playlist
max_track_allowed
start_index
current_index
current url
current_title
current_duration
current_thundnail
user
ready (validation, No, in progress, Yes)
type : radio
url
name
current_title
user
type : file
path
title
duration
user