From 2d788c77f565c59818e94de1cc4d41f49b423d6f Mon Sep 17 00:00:00 2001 From: azlux Date: Thu, 16 Apr 2020 22:13:11 +0200 Subject: [PATCH 1/6] New version --- mumbleBot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mumbleBot.py b/mumbleBot.py index b71d914..3d66db6 100644 --- a/mumbleBot.py +++ b/mumbleBot.py @@ -30,7 +30,7 @@ from media.cache import MusicCache class MumbleBot: - version = '6.1.1' + version = '6.1.2' def __init__(self, args): self.log = logging.getLogger("bot") From f95e07c9af11ce813f6beefe76422c07a4cf0dfe Mon Sep 17 00:00:00 2001 From: Daniel Gunzinger Date: Thu, 16 Apr 2020 19:09:24 +0200 Subject: [PATCH 2/6] implement trivial volume control slider and reporting of current volume to webinterface --- interface.py | 16 ++++++++++++++-- templates/index.html | 13 +++++++++---- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/interface.py b/interface.py index fd8c794..9e8c5bb 100644 --- a/interface.py +++ b/interface.py @@ -234,13 +234,15 @@ def status(): 'current_index': var.playlist.current_index, 'empty': False, 'play': not var.bot.is_pause, - 'mode': var.playlist.mode}) + 'mode': var.playlist.mode, + 'volume': var.db.getfloat('bot', 'volume')}) else: return jsonify({'ver': var.playlist.version, 'current_index': var.playlist.current_index, 'empty': True, 'play': not var.bot.is_pause, - 'mode': var.playlist.mode}) + 'mode': var.playlist.mode, + 'volume': var.db.getfloat('bot', 'volume')}) @web.route("/post", methods=['POST']) @@ -401,6 +403,16 @@ def post(): var.bot.volume_set = 0 var.db.set('bot', 'volume', str(var.bot.volume_set)) log.info("web: volume up to %d" % (var.bot.volume_set * 100)) + elif action == "volume_set_value": + if 'new_volume' in request.form: + # new_volume is slider value ranging from 0-100 + var.bot.volume_set = (request.form['new_volume'] * 0.01) + if var.bot.volume_set > 1: + var.bot.volume_set = 1 + elif var.bot.volume_set < 0: + var.bot.volume_set = 0 + var.db.set('bot', 'volume', str(var.bot.volume_set)) + log.info("web: volume set to %d" % (var.bot.volume_set * 100)) return status() diff --git a/templates/index.html b/templates/index.html index 17cc72d..164a488 100644 --- a/templates/index.html +++ b/templates/index.html @@ -72,6 +72,11 @@ onclick="request('post', {action : 'volume_up'})"> + + + @@ -497,7 +502,7 @@ if (data.ver !== playlist_ver) { checkForPlaylistUpdate(); } - updateControls(data.empty, data.play, data.mode); + updateControls(data.empty, data.play, data.mode, data.volume); } } }); @@ -659,7 +664,7 @@ displayActiveItem(data.current_index); } } - updateControls(data.empty, data.play, data.mode); + updateControls(data.empty, data.play, data.mode, data.volume); } } }); @@ -682,7 +687,7 @@ ); } - function updateControls(empty, play, mode){ + function updateControls(empty, play, mode, volume){ if(empty){ $("#play-btn").prop("disabled", true); $("#pause-btn").prop("disabled", true); @@ -719,7 +724,7 @@ $("#random-btn").removeClass("btn-primary").addClass("btn-secondary").prop("disabled", false); $("#autoplay-btn").removeClass("btn-secondary").addClass("btn-primary").prop("disabled", true); } - + $("#volume-slider").value = volume; } function themeInit(){ From 08c76aab9d10514b1579108aef489ca00aa49cbd Mon Sep 17 00:00:00 2001 From: Daniel Gunzinger Date: Thu, 16 Apr 2020 19:36:14 +0200 Subject: [PATCH 3/6] fix typeerror when setting volume; fix processing of volume updates in client-side webinterface --- interface.py | 2 +- templates/index.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface.py b/interface.py index 9e8c5bb..e28e444 100644 --- a/interface.py +++ b/interface.py @@ -406,7 +406,7 @@ def post(): elif action == "volume_set_value": if 'new_volume' in request.form: # new_volume is slider value ranging from 0-100 - var.bot.volume_set = (request.form['new_volume'] * 0.01) + var.bot.volume_set = (int(request.form['new_volume']) * 0.01) if var.bot.volume_set > 1: var.bot.volume_set = 1 elif var.bot.volume_set < 0: diff --git a/templates/index.html b/templates/index.html index 164a488..ae91b9c 100644 --- a/templates/index.html +++ b/templates/index.html @@ -724,7 +724,7 @@ $("#random-btn").removeClass("btn-primary").addClass("btn-secondary").prop("disabled", false); $("#autoplay-btn").removeClass("btn-secondary").addClass("btn-primary").prop("disabled", true); } - $("#volume-slider").value = volume; + document.getElementById("volume-slider").value = Math.round(volume*100); } function themeInit(){ From b8ebcce945c02da07562ee7beaedf4c3170b06a9 Mon Sep 17 00:00:00 2001 From: Daniel Gunzinger Date: Thu, 16 Apr 2020 23:31:08 +0200 Subject: [PATCH 4/6] use bootstrap styling for the slider, center it vertically; move slider between the two volume buttons --- static/css/custom.css | 5 ++++- templates/index.html | 10 ++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/static/css/custom.css b/static/css/custom.css index fd152eb..21e0d12 100644 --- a/static/css/custom.css +++ b/static/css/custom.css @@ -108,4 +108,7 @@ font-style: italic !important; font-weight: 300; } - +#volume-slider { + margin-top: 8px; + margin-right: 6px; +} diff --git a/templates/index.html b/templates/index.html index ae91b9c..7a6c415 100644 --- a/templates/index.html +++ b/templates/index.html @@ -68,15 +68,17 @@ onclick="request('post', {action : 'volume_down'})"> + + + + - -
From e0e0819605058ce07dc29293d09bf98188cdba51 Mon Sep 17 00:00:00 2001 From: Terry Geng Date: Sat, 18 Apr 2020 09:57:07 +0800 Subject: [PATCH 5/6] fix: use native python function to create non-blocking pipe. Thanks @azlux for this solution. Close #116. Also created an option 'redirect_ffmpeg_log' to enable/disable reading the log of ffmpeg. --- configuration.default.ini | 1 + mumbleBot.py | 33 +++++++++++++++++++++------------ util.py | 36 ++++++++++++++++++++++++------------ 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/configuration.default.ini b/configuration.default.ini index eb6f42a..ff15036 100644 --- a/configuration.default.ini +++ b/configuration.default.ini @@ -105,6 +105,7 @@ password = [debug] # Set ffmpeg to True if you want to display DEBUG level log of ffmpeg. ffmpeg = False +redirect_ffmpeg_log = True mumbleConnection = False # This is a list of default radio stations. diff --git a/mumbleBot.py b/mumbleBot.py index 3d66db6..cf89acd 100644 --- a/mumbleBot.py +++ b/mumbleBot.py @@ -162,6 +162,8 @@ class MumbleBot: self._display_rms = False self._max_rms = 0 + self.redirect_ffmpeg_log = var.config.getboolean('debug', 'redirect_ffmpeg_log', fallback=True) + # Set the CTRL+C shortcut def ctrl_caught(self, signal, frame): @@ -375,9 +377,12 @@ class MumbleBot: # The ffmpeg process is a thread # prepare pipe for catching stderr of ffmpeg - pipe_rd, pipe_wd = os.pipe() - util.pipe_no_wait(pipe_rd) # Let the pipe work in non-blocking mode - self.thread_stderr = os.fdopen(pipe_rd) + if self.redirect_ffmpeg_log: + pipe_rd, pipe_wd = util.pipe_no_wait() # Let the pipe work in non-blocking mode + self.thread_stderr = os.fdopen(pipe_rd) + else: + pipe_rd, pipe_wd = None, None + self.thread = sp.Popen(command, stdout=sp.PIPE, stderr=pipe_wd, bufsize=480) self.is_pause = False self.read_pcm_size = 0 @@ -449,12 +454,13 @@ class MumbleBot: raw_music = self.thread.stdout.read(480) self.read_pcm_size += 480 - try: - self.last_ffmpeg_err = self.thread_stderr.readline() - if self.last_ffmpeg_err: - self.log.debug("ffmpeg: " + self.last_ffmpeg_err.strip("\n")) - except: - pass + if self.redirect_ffmpeg_log: + try: + self.last_ffmpeg_err = self.thread_stderr.readline() + if self.last_ffmpeg_err: + self.log.debug("ffmpeg: " + self.last_ffmpeg_err.strip("\n")) + except: + pass if raw_music: # Adjust the volume and send it to mumble @@ -623,9 +629,12 @@ class MumbleBot: self.log.info("bot: execute ffmpeg command: " + " ".join(command)) # The ffmpeg process is a thread # prepare pipe for catching stderr of ffmpeg - pipe_rd, pipe_wd = os.pipe() - util.pipe_no_wait(pipe_rd) # Let the pipe work in non-blocking mode - self.thread_stderr = os.fdopen(pipe_rd) + if self.redirect_ffmpeg_log: + pipe_rd, pipe_wd = util.pipe_no_wait() # Let the pipe work in non-blocking mode + self.thread_stderr = os.fdopen(pipe_rd) + else: + pipe_rd, pipe_wd = None, None + self.thread = sp.Popen(command, stdout=sp.PIPE, stderr=pipe_wd, bufsize=480) self.last_volume_cycle_time = time.time() self.pause_at_id = "" diff --git a/util.py b/util.py index 20456b7..654f8eb 100644 --- a/util.py +++ b/util.py @@ -163,19 +163,29 @@ def url_unban(url): return res -def pipe_no_wait(pipefd): - """ Used to fetch the STDERR of ffmpeg. pipefd is the file descriptor returned from os.pipe()""" +def pipe_no_wait(): + """ Generate a non-block pipe used to fetch the STDERR of ffmpeg. + """ + if platform == "linux" or platform == "linux2" or platform == "darwin": import fcntl import os - try: - fl = fcntl.fcntl(pipefd, fcntl.F_GETFL) - fcntl.fcntl(pipefd, fcntl.F_SETFL, fl | os.O_NONBLOCK) - except: - print(sys.exc_info()[1]) - return False + + pipe_rd = 0 + pipe_wd = 0 + + if hasattr(os, "pipe2"): + pipe_rd, pipe_wd = os.pipe2(os.O_NONBLOCK) else: - return True + pipe_rd, pipe_wd = os.pipe() + + try: + fl = fcntl.fcntl(pipe_rd, fcntl.F_GETFL) + fcntl.fcntl(pipe_rd, fcntl.F_SETFL, fl | os.O_NONBLOCK) + except: + print(sys.exc_info()[1]) + return None, None + return pipe_rd, pipe_wd elif platform == "win32": # https://stackoverflow.com/questions/34504970/non-blocking-read-on-os-pipe-on-windows @@ -185,6 +195,8 @@ def pipe_no_wait(pipefd): from ctypes import windll, byref, wintypes, WinError, POINTER from ctypes.wintypes import HANDLE, DWORD, BOOL + pipe_rd, pipe_wd = os.pipe() + LPDWORD = POINTER(DWORD) PIPE_NOWAIT = wintypes.DWORD(0x00000001) ERROR_NO_DATA = 232 @@ -193,13 +205,13 @@ def pipe_no_wait(pipefd): SetNamedPipeHandleState.argtypes = [HANDLE, LPDWORD, LPDWORD, LPDWORD] SetNamedPipeHandleState.restype = BOOL - h = msvcrt.get_osfhandle(pipefd) + h = msvcrt.get_osfhandle(pipe_rd) res = windll.kernel32.SetNamedPipeHandleState(h, byref(PIPE_NOWAIT), None, None) if res == 0: print(WinError()) - return False - return True + return None, None + return pipe_rd, pipe_wd class Dir(object): From 563ce8f37b4ccf8ee0f996e54ef45eb1cadb5689 Mon Sep 17 00:00:00 2001 From: Azlux Date: Sat, 18 Apr 2020 14:55:12 +0200 Subject: [PATCH 6/6] fix indent --- util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util.py b/util.py index 654f8eb..1116944 100644 --- a/util.py +++ b/util.py @@ -185,7 +185,7 @@ def pipe_no_wait(): except: print(sys.exc_info()[1]) return None, None - return pipe_rd, pipe_wd + return pipe_rd, pipe_wd elif platform == "win32": # https://stackoverflow.com/questions/34504970/non-blocking-read-on-os-pipe-on-windows