From e3d4a45ceadc96d365a2b57b5f8ca6a9641166eb Mon Sep 17 00:00:00 2001 From: Peter Stevenson <2E0PGS@gmail.com> Date: Sun, 28 Jan 2018 16:00:01 +0000 Subject: [PATCH 01/11] README.md updates. --- README.md | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index daa674d7..eb367ff7 100644 --- a/README.md +++ b/README.md @@ -8,16 +8,21 @@ Ben Dowling - [http://www.coderholic.com/pyradio](http://www.coderholic.com/pyra ## Requirements * python 2.6+/3.2+ -* mplayer or vlc installed and in your path +* mpv, mplayer or vlc installed and in your path. +* Pip -## Installation +## Installation via Pip -The first thing is to make sure MPlayer and VLC are installed and are in the +This is the simplist method for installing PyRadio. + +The first thing is to make sure MPV, MPlayer or VLC are installed and are in the PATH. To check this, go in your favorite terminal and make sure thiese programs -are launched when you type "mplayer" or "cvlc". +are launched when you type "mpv", "mplayer" or "cvlc". + +#### MacOSX: -MacOSX tip: MPlayer is one of the available packages provided by +MPlayer is one of the available packages provided by [Homebrew](https://github.com/Homebrew/homebrew). But it is not the case of VLC. Nevertheless, pyradio will also work with the binary of the application [VLC](http://www.videolan.org/vlc/download-macosx.html). You simply can add a @@ -26,10 +31,22 @@ PATH): ln -s /Applications/VLC.app/Contents/MacOS/VLC cvlc -The second step is to install the python package: +The second step is to use pip to install the python package: pip install pyradio +#### Linux: + + pip install pyradio + +## Building from source: + + python setup.py build + +The second step is to install the build: + + sudo python setup.py install + ## Shell From 3f4d5540ec73a61121df98dcd387cdabbacedc70 Mon Sep 17 00:00:00 2001 From: Peter Stevenson <2E0PGS@gmail.com> Date: Sun, 28 Jan 2018 16:03:09 +0000 Subject: [PATCH 02/11] More README.md improvements. --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index eb367ff7..3f88ba30 100644 --- a/README.md +++ b/README.md @@ -22,12 +22,11 @@ are launched when you type "mpv", "mplayer" or "cvlc". #### MacOSX: -MPlayer is one of the available packages provided by -[Homebrew](https://github.com/Homebrew/homebrew). But it is not the case of -VLC. Nevertheless, pyradio will also work with the binary of the application -[VLC](http://www.videolan.org/vlc/download-macosx.html). You simply can add a -symbolic link to the executable as follows (this link must of course be in your -PATH): +MPlayer is one of the available packages provided by [Homebrew](https://github.com/Homebrew/homebrew). + +But it is not the case of VLC. Nevertheless, pyradio will also work with the binary of the application [VLC](http://www.videolan.org/vlc/download-macosx.html). + +You simply can add a symbolic link to the executable as follows (this link must of course be in your PATH): ln -s /Applications/VLC.app/Contents/MacOS/VLC cvlc @@ -41,6 +40,8 @@ The second step is to use pip to install the python package: ## Building from source: +#### MaxOSX and Linux: + python setup.py build The second step is to install the build: From acb3119433fa89736365042969f8a422eccf4486 Mon Sep 17 00:00:00 2001 From: Peter Stevenson <2E0PGS@gmail.com> Date: Sun, 28 Jan 2018 16:16:18 +0000 Subject: [PATCH 03/11] Add MPV support. --- pyradio/player.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/pyradio/player.py b/pyradio/player.py index dd50b9ef..d29f756b 100644 --- a/pyradio/player.py +++ b/pyradio/player.py @@ -94,6 +94,39 @@ def volumeUp(self): def volumeDown(self): pass +class MpvPlayer(Player): + """Implementation of Player object for MPV""" + + PLAYER_CMD = "mpv" + + def _buildStartOpts(self, streamUrl, playList=False): + """ Builds the options to pass to subprocess.""" + if playList: + opts = [self.PLAYER_CMD, "-quiet", "-playlist", streamUrl] + else: + opts = [self.PLAYER_CMD, "-quiet", streamUrl] + return opts + + def mute(self): + """ mute mpv """ + self._sendCommand("m") + + def pause(self): + """ pause streaming (if possible) """ + self._sendCommand("p") + + def _stop(self): + """ exit pyradio (and kill mpv instance) """ + self._sendCommand("q") + + def volumeUp(self): + """ increase mpv's volume """ + self._sendCommand("*") + + def volumeDown(self): + """ decrease mpv's volume """ + self._sendCommand("/") + class MpPlayer(Player): """Implementation of Player object for MPlayer""" From b4c0666388119d32c3bb9058956290b506466781 Mon Sep 17 00:00:00 2001 From: Peter Stevenson <2E0PGS@gmail.com> Date: Sun, 28 Jan 2018 17:06:06 +0000 Subject: [PATCH 04/11] More changes for MPV support. Cleanup a few other bits of code. --- README.md | 42 +++++++++++++++++++----------------------- pyradio/main.py | 12 ++++++------ pyradio/player.py | 18 +++++++++--------- pyradio/radio.py | 4 ++-- 4 files changed, 36 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 3f88ba30..4fc3ca8c 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,12 @@ Command line internet radio player. Ben Dowling - [http://www.coderholic.com/pyradio](http://www.coderholic.com/pyradio) - ## Requirements * python 2.6+/3.2+ * mpv, mplayer or vlc installed and in your path. * Pip - ## Installation via Pip This is the simplist method for installing PyRadio. @@ -38,7 +36,7 @@ The second step is to use pip to install the python package: pip install pyradio -## Building from source: +## Building from source #### MaxOSX and Linux: @@ -48,35 +46,33 @@ The second step is to install the build: sudo python setup.py install - -## Shell +## Shell commands $ pyradio -h - usage: main.py [-h] [--stations STATIONS] [--random] [--add] [--list] + usage: main.py [--help] [--stations ] [--random] [--add] [--list] Console radio player optional arguments: - -h, --help show this help message and exit - --stations STATIONS, -s STATIONS - Path on stations csv file. - --random, -r Start and play random station. - --add, -a Add station to list. - --list, -l List of added stations. - --debug, -d Debug mode (pyradio.log created) + -h, --help Show this help message and exit. + -s, --stations Use specified station CSV file. + -r, --random Start and play a random station. + -a, --add Add station to list. + -l, --list List of added stations. + -d, --debug Debug mode (pyradio.log created). To be attached with any bug report. - ## Controls + ``` -Up/Down/j/k/PgUp/PgDown Change station selection -Enter Play selected station --/+ Change volume -m Mute -r Select and play a random station -g Jump to first station -G Jump to n-th station -Space Stop/start playing selected station -Esc/q Quit +Up/Down/j/k/PgUp/PgDown Change station selection. +Enter Play selected station. +-/+ Change volume. +m Mute. +r Select and play a random station. +g Jump to first station. +G Jump to n-th station. +Space Stop/start playing selected station. +Esc/q Quit. ``` diff --git a/pyradio/main.py b/pyradio/main.py index 03a51ac5..f6d2ab6e 100644 --- a/pyradio/main.py +++ b/pyradio/main.py @@ -38,16 +38,16 @@ def __configureLogger(): def shell(): parser = ArgumentParser(description="Console radio player") - parser.add_argument("--stations", "-s", default=DEFAULT_FILE, - help="Path on stations csv file.") + parser.add_argument("-s", "--stations", default=DEFAULT_FILE, + help="Use specified station CSV file.") parser.add_argument("--play", "-p", nargs='?', default=False, - help="Start and play. " + help="Start and play." "The value is num station or empty for random.") - parser.add_argument("--add", "-a", action='store_true', + parser.add_argument("-a", "--add", action='store_true', help="Add station to list.") - parser.add_argument("--list", "-l", action='store_true', + parser.add_argument("-l", "--list", action='store_true', help="List of added stations.") - parser.add_argument("--debug", "-d", action='store_true', + parser.add_argument("-d", "--debug", action='store_true', help="Start pyradio in debug mode.") args = parser.parse_args() diff --git a/pyradio/player.py b/pyradio/player.py index d29f756b..d751a376 100644 --- a/pyradio/player.py +++ b/pyradio/player.py @@ -7,7 +7,7 @@ class Player(object): - """ Media player class. Playing is handled by mplayer """ + """ Media player class. Playing is handled by player sub classes """ process = None def __init__(self, outputStream): @@ -55,7 +55,7 @@ def play(self, streamUrl): logger.debug("Player started") def _sendCommand(self, command): - """ send keystroke command to mplayer """ + """ send keystroke command to player """ if(self.process is not None): try: @@ -68,7 +68,7 @@ def _sendCommand(self, command): exc_info=True) def close(self): - """ exit pyradio (and kill mplayer instance) """ + """ exit pyradio (and kill player instance) """ # First close the subprocess self._stop() @@ -102,9 +102,9 @@ class MpvPlayer(Player): def _buildStartOpts(self, streamUrl, playList=False): """ Builds the options to pass to subprocess.""" if playList: - opts = [self.PLAYER_CMD, "-quiet", "-playlist", streamUrl] + opts = [self.PLAYER_CMD, "--no-video", "--playlist", streamUrl] else: - opts = [self.PLAYER_CMD, "-quiet", streamUrl] + opts = [self.PLAYER_CMD, "--no-video", streamUrl] return opts def mute(self): @@ -175,7 +175,7 @@ def _buildStartOpts(self, streamUrl, playList=False): return opts def mute(self): - """ mute mplayer """ + """ mute vlc """ if not self.muted: self._sendCommand("volume 0\n") @@ -189,15 +189,15 @@ def pause(self): self._sendCommand("stop\n") def _stop(self): - """ exit pyradio (and kill mplayer instance) """ + """ exit pyradio (and kill vlc instance) """ self._sendCommand("shutdown\n") def volumeUp(self): - """ increase mplayer's volume """ + """ increase vlc's volume """ self._sendCommand("volup\n") def volumeDown(self): - """ decrease mplayer's volume """ + """ decrease vlc's volume """ self._sendCommand("voldown\n") diff --git a/pyradio/radio.py b/pyradio/radio.py index d411a6b6..7ba05661 100644 --- a/pyradio/radio.py +++ b/pyradio/radio.py @@ -55,7 +55,7 @@ def setup(self, stdscr): curses.init_pair(9, curses.COLOR_BLACK, curses.COLOR_GREEN) self.log = Log() - # For the time being, supported players are mplayer and vlc. + # For the time being, supported players are mpv, mplayer and vlc. self.player = player.probePlayer()(self.log) self.stdscr.nodelay(0) @@ -180,7 +180,7 @@ def playSelection(self): self.player.play(stream_url) except OSError: self.log.write('Error starting player.' - 'Are you sure mplayer is installed?') + 'Are you sure a supported player is installed?') def keypress(self, char): # Number of stations to change with the page up/down keys From 30b0a4c40693ec4fb0210eb4b442e1c611f92fa1 Mon Sep 17 00:00:00 2001 From: Peter Stevenson <2E0PGS@gmail.com> Date: Sun, 28 Jan 2018 17:33:23 +0000 Subject: [PATCH 05/11] These are audio only anyway. Supress outputs. MPV support works now besides the stdin commands dont seem to work with MPV for some reason! --- pyradio/player.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyradio/player.py b/pyradio/player.py index d751a376..ba293b2c 100644 --- a/pyradio/player.py +++ b/pyradio/player.py @@ -102,9 +102,9 @@ class MpvPlayer(Player): def _buildStartOpts(self, streamUrl, playList=False): """ Builds the options to pass to subprocess.""" if playList: - opts = [self.PLAYER_CMD, "--no-video", "--playlist", streamUrl] + opts = [self.PLAYER_CMD, "--quiet", "--playlist", streamUrl] else: - opts = [self.PLAYER_CMD, "--no-video", streamUrl] + opts = [self.PLAYER_CMD, "--quiet", streamUrl] return opts def mute(self): From f08d166453aab856dd7f1ac97f19e62c3110c88d Mon Sep 17 00:00:00 2001 From: Peter Stevenson <2E0PGS@gmail.com> Date: Sun, 28 Jan 2018 20:11:15 +0000 Subject: [PATCH 06/11] Working IPC control of MPV via socat. Downsides are it requires an extra dep. Also it seems to spam the debug console a bit. But it's one method that works. --- pyradio/player.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/pyradio/player.py b/pyradio/player.py index ba293b2c..236697eb 100644 --- a/pyradio/player.py +++ b/pyradio/player.py @@ -99,33 +99,36 @@ class MpvPlayer(Player): PLAYER_CMD = "mpv" + os.system("rm /tmp/mpvsocket"); + def _buildStartOpts(self, streamUrl, playList=False): """ Builds the options to pass to subprocess.""" if playList: - opts = [self.PLAYER_CMD, "--quiet", "--playlist", streamUrl] + opts = [self.PLAYER_CMD, "--quiet", "--playlist", streamUrl, "--input-ipc-server=/tmp/mpvsocket"] else: - opts = [self.PLAYER_CMD, "--quiet", streamUrl] + opts = [self.PLAYER_CMD, "--quiet", streamUrl, "--input-ipc-server=/tmp/mpvsocket"] return opts def mute(self): """ mute mpv """ - self._sendCommand("m") + os.system("echo 'cycle mute' | socat - /tmp/mpvsocket"); def pause(self): """ pause streaming (if possible) """ - self._sendCommand("p") + os.system("echo 'cycle pause' | socat - /tmp/mpvsocket"); def _stop(self): """ exit pyradio (and kill mpv instance) """ - self._sendCommand("q") + os.system("echo 'quit' | socat - /tmp/mpvsocket"); + os.system("rm /tmp/mpvsocket"); def volumeUp(self): """ increase mpv's volume """ - self._sendCommand("*") + os.system("echo 'cycle volume' | socat - /tmp/mpvsocket"); def volumeDown(self): """ decrease mpv's volume """ - self._sendCommand("/") + os.system("echo 'cycle volume down' | socat - /tmp/mpvsocket"); class MpPlayer(Player): From 3f55a8d8074576f1f61411ba07364c172d2734d0 Mon Sep 17 00:00:00 2001 From: Peter Stevenson <2E0PGS@gmail.com> Date: Sat, 3 Feb 2018 16:02:12 +0000 Subject: [PATCH 07/11] Update README.md for mpv support. --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 4fc3ca8c..adaba72a 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,10 @@ Ben Dowling - [http://www.coderholic.com/pyradio](http://www.coderholic.com/pyra ## Requirements * python 2.6+/3.2+ +* python-pip * mpv, mplayer or vlc installed and in your path. -* Pip -## Installation via Pip +## Installation via pip This is the simplist method for installing PyRadio. @@ -18,7 +18,7 @@ The first thing is to make sure MPV, MPlayer or VLC are installed and are in the PATH. To check this, go in your favorite terminal and make sure thiese programs are launched when you type "mpv", "mplayer" or "cvlc". -#### MacOSX: +#### MacOSX MPlayer is one of the available packages provided by [Homebrew](https://github.com/Homebrew/homebrew). @@ -32,13 +32,13 @@ The second step is to use pip to install the python package: pip install pyradio -#### Linux: +#### Linux pip install pyradio ## Building from source -#### MaxOSX and Linux: +#### MaxOSX and Linux python setup.py build From c1ad9037ef6d4fa41723b4822f74500673d98253 Mon Sep 17 00:00:00 2001 From: Peter Stevenson <2E0PGS@gmail.com> Date: Sat, 3 Feb 2018 16:03:32 +0000 Subject: [PATCH 08/11] Update README.md of mpv support via socat feature. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index adaba72a..20395464 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Ben Dowling - [http://www.coderholic.com/pyradio](http://www.coderholic.com/pyra * python 2.6+/3.2+ * python-pip * mpv, mplayer or vlc installed and in your path. +* socat ## Installation via pip From e70f8153199a8014e6b7dbfe95a41cda185b28d9 Mon Sep 17 00:00:00 2001 From: Peter Stevenson <2E0PGS@gmail.com> Date: Sun, 13 May 2018 13:02:54 +0100 Subject: [PATCH 09/11] We need to check which version of MPV is installed for command line flag https://github.com/mpv-player/mpv/commit/cd50ebba363315e15276e3b0895c33e85813fc4a --- pyradio/player.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/pyradio/player.py b/pyradio/player.py index 236697eb..6b36a45f 100644 --- a/pyradio/player.py +++ b/pyradio/player.py @@ -103,10 +103,29 @@ class MpvPlayer(Player): def _buildStartOpts(self, streamUrl, playList=False): """ Builds the options to pass to subprocess.""" + + """ Test for newer MPV versions as it supports different IPC flags. """ + p = subprocess.Popen([self.PLAYER_CMD, "--input-ipc-server"], stdout=subprocess.PIPE, stdin=subprocess.PIPE, shell=False) + out = p.communicate() + if "error" not in out[0]: + if logger.isEnabledFor(logging.DEBUG): + logger.debug("--input-ipc-server is supported.") + newerMpv = 1; + else: + if logger.isEnabledFor(logging.DEBUG): + logger.debug("--input-ipc-server is not supported.") + newerMpv = 0; + if playList: - opts = [self.PLAYER_CMD, "--quiet", "--playlist", streamUrl, "--input-ipc-server=/tmp/mpvsocket"] + if newerMpv: + opts = [self.PLAYER_CMD, "--quiet", "--playlist", streamUrl, "--input-ipc-server=/tmp/mpvsocket"] + else: + opts = [self.PLAYER_CMD, "--quiet", "--playlist", streamUrl, "--input-unix-socket=/tmp/mpvsocket"] else: - opts = [self.PLAYER_CMD, "--quiet", streamUrl, "--input-ipc-server=/tmp/mpvsocket"] + if newerMpv: + opts = [self.PLAYER_CMD, "--quiet", streamUrl, "--input-ipc-server=/tmp/mpvsocket"] + else: + opts = [self.PLAYER_CMD, "--quiet", streamUrl, "--input-unix-socket=/tmp/mpvsocket"] return opts def mute(self): From ef550ecdd80abba47fbae1258c998a5d82909c48 Mon Sep 17 00:00:00 2001 From: Peter Stevenson <2E0PGS@gmail.com> Date: Sun, 13 May 2018 13:21:18 +0100 Subject: [PATCH 10/11] Use "not found" since error was used in other MPV warnings. --- pyradio/player.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyradio/player.py b/pyradio/player.py index 6b36a45f..1f57bbc3 100644 --- a/pyradio/player.py +++ b/pyradio/player.py @@ -107,7 +107,7 @@ def _buildStartOpts(self, streamUrl, playList=False): """ Test for newer MPV versions as it supports different IPC flags. """ p = subprocess.Popen([self.PLAYER_CMD, "--input-ipc-server"], stdout=subprocess.PIPE, stdin=subprocess.PIPE, shell=False) out = p.communicate() - if "error" not in out[0]: + if "not found" not in out[0]: if logger.isEnabledFor(logging.DEBUG): logger.debug("--input-ipc-server is supported.") newerMpv = 1; From 118a20c723d2e4b10c3383e2a255c3639d1af9cc Mon Sep 17 00:00:00 2001 From: Peter Stevenson <2E0PGS@gmail.com> Date: Sun, 13 May 2018 13:30:51 +0100 Subject: [PATCH 11/11] Final documentation changes before merge. --- README.md | 2 +- pyradio/radio.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 20395464..acccc63e 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Ben Dowling - [http://www.coderholic.com/pyradio](http://www.coderholic.com/pyra * python 2.6+/3.2+ * python-pip * mpv, mplayer or vlc installed and in your path. -* socat +* socat (if you wish to use MPV) ## Installation via pip diff --git a/pyradio/radio.py b/pyradio/radio.py index 7ba05661..3f9646e9 100644 --- a/pyradio/radio.py +++ b/pyradio/radio.py @@ -4,6 +4,8 @@ # http://www.coderholic.com/pyradio # Ben Dowling - 2009 - 2010 # Kirill Klenov - 2012 +# Peter Stevenson (2E0PGS) - 2018 + import curses import logging import os