diff --git a/README.html b/README.html index f90892ee..5255b104 100644 --- a/README.html +++ b/README.html @@ -7,22 +7,29 @@ PyRadio README + a{ color: SaddleBrown;} +a:visited{color: SaddleBrown;} +
-

PyRadio

+

PyRadio

Command line internet radio player.

Ben Dowling - https://github.com/coderholic

Table of contents Top

diff --git a/build.html b/build.html index baee3db1..44d29fe6 100644 --- a/build.html +++ b/build.html @@ -7,22 +7,29 @@ PyRadio Build Instructions + a{ color: SaddleBrown;} +a:visited{color: SaddleBrown;} +
-

PyRadio Build Instructions

+

PyRadio Build Instructions

PyRadio: Command line internet radio player.

Ben Dowling - https://github.com/coderholic

Table of contents Top

diff --git a/devel/pre-commit b/devel/pre-commit index 90d3a5ad..fe803378 100755 --- a/devel/pre-commit +++ b/devel/pre-commit @@ -2,7 +2,7 @@ # convert TABs to SPACEs in Changelog sed -i 's/\t/ /g' Changelog # Create HTML file from md files -for afile in README.md build.md windows.md +for afile in README.md build.md windows.md windows-mplayer.md do #[ -z "$(git status | grep ${afile})" ] || { out=${afile/%.md/.html} @@ -12,6 +12,8 @@ do echo '% PyRadio Build Instructions' > tmp.md elif [ "$afile" = "windows.md" ];then echo '% PyRadio on Windows' > tmp.md + elif [ "$afile" = "windows-mplayer.md" ];then + echo '% MPlayer Installation on Windows' > tmp.md fi cat ${afile} >> tmp.md pandoc -s -t html tmp.md -o ${out} || { @@ -21,12 +23,17 @@ do } sed -i '/]*>/a \ html {margin: 2em;} \ - h2 {margin-top: 2.5em; border-bottom:1px solid #D6D6D6;} \ - h3 {margin-top: 2em;} \ + h2 {margin-top: 2.5em; border-bottom:1px solid SaddleBrown; color: SaddleBrown;} \ + h3 {margin-top: 2em; color: SaddleBrown;} \ + h4 {margin-top: 2em; color: SaddleBrown;} \ + STRONG {color: SaddleBrown;} \ dl {margin: 2em;} \ dd {margin: 1em;} \ dt {font-weight: bold;} \ - pre { background-color: #F6F6F6; padding: 1.5em; border: 1px solid #E6E6E6; overflow: auto;}' ${out} + TABLE {border: 1px solid SaddleBrown;} \ + TH {text-align: left; color: SaddleBrown;border: 1px solid SaddleBrown;} \ + TD {text-align: left; padding-right: 8px;border: 1px solid SaddleBrown;} \ + pre { background-color: rgba(139, 69, 19, 0.80); color: #fff; padding: 1.5em; border: 1px solid #A87207; border-radius: 15px; overflow: auto;}' ${out} sed -i -e 's///g' \ -e 's{{{g' \ -e 's{pyradio{[pyradio]{' \ @@ -37,10 +44,14 @@ do -e 's/\.md">/.html">/g' \ -e '/h1 class="title"/d' \ -e 's/Top&{' ${out} + -e 's{{ Top&{' \ + -e 's|<.style>$|a{ color: SaddleBrown;}\na:visited{color: SaddleBrown;}\n|' \ + -e 's/

{ Top&{' \ "$out" fi diff --git a/pyradio/__init__.py b/pyradio/__init__.py index b8750962..dec014e2 100644 --- a/pyradio/__init__.py +++ b/pyradio/__init__.py @@ -6,7 +6,7 @@ # New stable version: '' # Beta version: 'betax', x=1,2,3... # RC version: 'RCx', x=1,23... -app_state = 'beta4' +app_state = 'beta5' __version__ = version = '.'.join(map(str, version_info)) __project__ = __name__ diff --git a/pyradio/config b/pyradio/config index b79dceae..27890b6e 100644 --- a/pyradio/config +++ b/pyradio/config @@ -48,6 +48,15 @@ default_encoding = utf-8 # Default value: 10 connection_timeout = 10 +# Force http connections +# Most radio stations use plain old http protocol to broadcast, but +# some of them use https. If this is enabled, all connections will +# use http; results depend on the combination of station/player. +# +# Valid values: True, true, False, false +# Default value: False +force_http = False + # Default theme # Hardcooded themes: # dark (default) (8 colors) diff --git a/pyradio/config.py b/pyradio/config.py index 4ba5c1f3..bdba6cb2 100644 --- a/pyradio/config.py +++ b/pyradio/config.py @@ -1188,10 +1188,9 @@ def read_config(self): if sp[1] == '': return -2 if sp[0] == 'player': - if platform.startswith('win'): - self.opts['player'][1] = 'mplayer' - else: - self.opts['player'][1] = sp[1].lower().strip() + self.opts['player'][1] = sp[1].lower().strip() + if sys.platform.startswith('win'): + self.opts['player'][1] = self.opts['player'][1].replace('mpv,', '') elif sp[0] == 'connection_timeout': self.opts['connection_timeout'][1] = sp[1].strip() # check integer number and set to 10 if error diff --git a/pyradio/config_window.py b/pyradio/config_window.py index 6a4067a4..83359cd7 100644 --- a/pyradio/config_window.py +++ b/pyradio/config_window.py @@ -39,14 +39,10 @@ class PyRadioConfigWindow(object): _num_of_help_lines = 0 _help_text = [] _help_text.append(None) - if platform.startswith('win'): - _help_text.append(['When running on Windows, PyRadio can only use mplayer as its player.', '|', - 'Thus, this option is disabled.']) - else: - _help_text.append(['Specify the player to use with PyRadio, or the player detection order.', '|', - 'This is the eqivelant to the -u , --use-player command line option.', '|', - 'Example:', ' player = vlc', 'or', ' player = vlc,mpv, mplayer', '|', - 'Default value: mpv,mplayer,vlc']) + _help_text.append(['Specify the player to use with PyRadio, or the player detection order.', '|', + 'This is the eqivelant to the -u , --use-player command line option.', '|', + 'Example:', ' player = vlc', 'or', ' player = vlc,mpv, mplayer', '|', + 'Default value: mpv,mplayer,vlc']) _help_text.append(['This is the playlist to open at start up, if none is specified.', '|', 'This is the equivalent to the -s , --stations command line option.', '|', 'Default value: stations']) @@ -400,10 +396,7 @@ def keypress(self, char): vals = list(self._config_options.items()) sel = vals[self.selection][0] if sel == 'player': - if platform.startswith('win'): - return -1, [] - else: - return self.n_u.SELECT_PLAYER_MODE, [] + return self.n_u.SELECT_PLAYER_MODE, [] elif sel == 'default_encoding': return self.n_u.SELECT_ENCODING_MODE, [] elif sel == 'theme': @@ -438,7 +431,10 @@ class PyRadioSelectPlayer(object): _win = None - _players = ( 'mpv', 'mplayer', 'vlc' ) + if platform == 'win32': + _players = ( 'mplayer', 'vlc' ) + else: + _players = ( 'mpv', 'mplayer', 'vlc' ) _working_players = [ [], [] ] # REMINDER: column 1 is acive players - displayed right diff --git a/pyradio/del_vlc_log.py b/pyradio/del_vlc_log.py new file mode 100644 index 00000000..b691b2e9 --- /dev/null +++ b/pyradio/del_vlc_log.py @@ -0,0 +1,26 @@ +import os +from sys import platform + +def RemoveWinVlcLogFiles(*args): + """ Removes all VLC log files within pyradio config + directory on Windows. + + Files currently in use will not be deleted. + """ + if platform.startswith('win'): + adir = args[0] + #print('config = "{}"'.format(adir)) + files = [file for file in os.listdir(adir) if 'vlc_log.' in file] + if files: + for afile in files: + #print(afile) + try: + #print('removing "{}"'.format(afile)) + os.remove(os.path.join(adir, afile)) + except: + pass + +if __name__ == "__main__": + # example: + import threading + threading.Thread(target=RemoveWinVlcLogFiles('C:\\Users\\Spiros\\AppData\\Roaming\\pyradio')).start() diff --git a/pyradio/main.py b/pyradio/main.py index 55e62a85..382ccfec 100644 --- a/pyradio/main.py +++ b/pyradio/main.py @@ -12,7 +12,10 @@ PATTERN = '%(asctime)s - %(name)s - %(levelname)s - %(message)s' -IMPLEMENTED_PLAYERS =('mpv', 'mplayer', 'cvlc') +if platform.startswith('win'): + IMPLEMENTED_PLAYERS =('mplayer', 'cvlc') +else: + IMPLEMENTED_PLAYERS =('mpv', 'mplayer', 'cvlc') @contextmanager def pyradio_config_file(): @@ -182,7 +185,10 @@ def shell(): if args.debug: __configureLogger() - print('Debug mode activated; printing messages to file: "~/pyradio.log"') + if platform.startswith('win'): + print('Debug mode activated\n printing messages to file: "{}\pyradio.log"'.format(getenv('USERPROFILE'))) + else: + print('Debug mode activated; printing messages to file: "~/pyradio.log"') else: ''' Refer to https://docs.python.org/3.7/howto/logging.html section "What happens if no configuration is provided" diff --git a/pyradio/player.py b/pyradio/player.py index 225c88ed..87ff9e6d 100644 --- a/pyradio/player.py +++ b/pyradio/player.py @@ -2,6 +2,7 @@ import subprocess import threading import os +import random import logging from os.path import expanduser from sys import platform, version_info, platform @@ -96,6 +97,23 @@ def _access_check(fn, mode): return None +def find_vlc_on_windows(config_dir=None): + REAL_PLAYER_CMD ='' + for path in ('C:\\Program Files\\VideoLAN\\VLC\\vlc.exe', + 'C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe' + ): + if os.path.exists(path): + REAL_PLAYER_CMD = path + break + return REAL_PLAYER_CMD + + #result = [] + #for root, dirs, files in os.walk(path): + # for name in files: + # if fnmatch.fnmatch(name, pattern): + # result.append(os.path.join(root, name)) + #return result + class Player(object): """ Media player class. Playing is handled by player sub classes """ @@ -137,6 +155,9 @@ class Player(object): # used to stop mpv update thread on python3 stop_mpv_status_update_thread = False + # used to stop vlc update thread on windows + stop_win_vlc_status_update_thread = False + # bitrate, url, audio_format etc. _icy_data = {} @@ -145,8 +166,10 @@ class Player(object): GET_AUDIO_CODEC = b'{ "command": ["get_property", "audio-codec"], "request_id": 300 }\n' GET_AUDIO_CODEC_NAME = b'{ "command": ["get_property", "audio-codec-name"], "request_id": 400 }\n' - def __init__(self, outputStream, + def __init__(self, + outputStream, config_encoding, + config_dir, playback_timeout, force_http, playback_timeout_counter, @@ -154,13 +177,23 @@ def __init__(self, outputStream, info_display_handler): self.outputStream = outputStream self.config_encoding = config_encoding - self.playback_timeout = playback_timeout + self.config_dir = config_dir + try: + self.playback_timeout = int(playback_timeout) + except: + self.playback_timeout = 10 self.force_http = force_http self.playback_timeout_counter = playback_timeout_counter self.playback_timeout_handler = playback_timeout_handler self.info_display_handler = info_display_handler self.status_update_lock = outputStream.lock + #if self.WIN and self.PLAYER_CMD == 'cvlc': + if platform == 'win32': + """ delete old vlc files (vlc_log.*) """ + from .del_vlc_log import RemoveWinVlcLogFiles + threading.Thread(target=RemoveWinVlcLogFiles(config_dir)).start() + def __del__(self): self.close() @@ -424,6 +457,8 @@ def updateStatus(self, *args): #with lock: # self.oldUserInput['Title'] = 'Connecting to: "{}"'.format(self.name) # self.outputStream.write(msg=self.oldUserInput['Title']) + """ Force volume display even when icy title is not received """ + self.oldUserInput['Title'] = 'Playing: "{}"'.format(self.name) try: out = self.process.stdout while(True): @@ -632,6 +667,165 @@ def updateMPVStatus(self, *args): if (logger.isEnabledFor(logging.INFO)): logger.info("MPV updateStatus thread stopped.") + def updateWinVLCStatus(self, *args): + has_error = False + if (logger.isEnabledFor(logging.DEBUG)): + logger.debug("Win VLC updateStatus thread started.") + fn = args[0] + enc = args[1] + stop = args[2] + """ Force volume display even when icy title is not received """ + self.oldUserInput['Title'] = 'Playing: "{}"'.format(self.name) + logger.error('DE ==== {0}\n{1}\n{2}'.format(fn, enc, stop)) + #with lock: + # self.oldUserInput['Title'] = 'Connecting to: "{}"'.format(self.name) + # self.outputStream.write(msg=self.oldUserInput['Title']) + + go_on = False + while not go_on: + if stop(): + break + try: + fp = open(fn, mode='rt', encoding=enc, errors='ignore') + go_on = True + except: + pass + + try: + logger.error('DE >>>>====---- BREFORE OUT ----====<<<<') + #out = self.process.stdout + while(True): + if stop(): + break + subsystemOut = fp.readline() + subsystemOut = subsystemOut.strip() + subsystemOut = subsystemOut.replace("\r", "").replace("\n", "") + if subsystemOut == '': + continue + logger.error('DE >>> "{}"'.format(subsystemOut)) + if not self._is_accepted_input(subsystemOut): + continue + logger.error('DE --- accepted') + if self.oldUserInput['Input'] != subsystemOut: + if stop(): + break + if (logger.isEnabledFor(logging.DEBUG)): + if version_info < (3, 0): + disp = subsystemOut.encode('utf-8', 'replace').strip() + logger.debug("User input: {}".format(disp)) + else: + logger.debug("User input: {}".format(subsystemOut)) + self.oldUserInput['Input'] = subsystemOut + if self.volume_string in subsystemOut: + if stop(): + break + # disable volume for mpv + if self.REAL_PLAYER_CMD != "mpv": + #logger.error("***** volume") + if self.oldUserInput['Volume'] != subsystemOut: + self.oldUserInput['Volume'] = subsystemOut + self.volume = ''.join(c for c in subsystemOut if c.isdigit()) + + # IMPORTANT: do this here, so that cvlc actual_volume + # gets updated in _format_volume_string + string_to_show = self._format_volume_string(subsystemOut) + self._format_title_string(self.oldUserInput['Title']) + + if self.show_volume and self.oldUserInput['Title']: + self.outputStream.write(msg=string_to_show, counter='') + self.threadUpdateTitle() + elif self._is_in_playback_token(subsystemOut): + if stop(): + break + self.stop_timeout_counter_thread = True + try: + self.connection_timeout_thread.join() + except: + pass + if (not self.playback_is_on) and (logger.isEnabledFor(logging.INFO)): + logger.info('*** updateStatus(): Start of playback detected ***') + #if self.outputStream.last_written_string.startswith('Connecting to'): + if self.oldUserInput['Title'] == '': + new_input = 'Playing: "{}"'.format(self.name) + else: + new_input = self.oldUserInput['Title'] + self.outputStream.write(msg=new_input, counter='') + self.playback_is_on = True + if 'AO: [' in subsystemOut: + with self.status_update_lock: + if version_info > (3, 0): + self._icy_data['audio_format'] = subsystemOut.split('] ')[1].split(' (')[0] + else: + self._icy_data['audio_format'] = subsystemOut.split('] ')[1].split(' (')[0].encode('utf-8') + self.info_display_handler() + #logger.error('DE 3 {}'.format(self._icy_data)) + elif self._is_icy_entry(subsystemOut): + if stop(): + break + + #logger.error("***** icy_entry") + title = self._format_title_string(subsystemOut) + ok_to_display = False + if title[len(self.icy_title_prefix):].strip(): + self.oldUserInput['Title'] = title + # make sure title will not pop-up while Volume value is on + if self.delay_thread is None: + ok_to_display = True + if ok_to_display and self.playback_is_on: + string_to_show = self.title_prefix + title + self.outputStream.write(msg=string_to_show, counter='') + else: + ok_to_display = True + if (logger.isEnabledFor(logging.INFO)): + logger.info('Icy-Title is NOT valid') + if ok_to_display and self.playback_is_on: + title = 'Playing: "{}"'.format(self.name) + self.oldUserInput['Title'] = title + string_to_show = self.title_prefix + title + self.outputStream.write(msg=string_to_show, counter='') + #else: + # if self.oldUserInput['Title'] == '': + # self.oldUserInput['Title'] = 'Connecting to: "{}"'.format(self.name) + # self.outputStream.write(msg=self.oldUserInput['Title'], counter='') + + else: + if stop(): + break + for a_token in self.icy_audio_tokens.keys(): + if a_token in subsystemOut: + logger.error(' DE token = "{}"'.format(a_token)) + logger.error(' DE icy_audio_tokens[a_token] = "{}"'.format(self.icy_audio_tokens[a_token])) + a_str = subsystemOut.split(a_token) + logger.error(' DE str = "{}"'.format(a_str)) + with self.status_update_lock: + if self.icy_audio_tokens[a_token] == 'icy-br': + self._icy_data[self.icy_audio_tokens[a_token]] = a_str[1].replace('kbit/s', '') + else: + self._icy_data[self.icy_audio_tokens[a_token]] = a_str[1] + if self.icy_audio_tokens[a_token] == 'codec': + if '[' in self._icy_data['codec']: + self._icy_data['codec-name'] = self._icy_data['codec'].split('] ')[0].replace('[', '') + self._icy_data['codec'] = self._icy_data['codec'].split('] ')[1] + if version_info < (3, 0): + for an_item in self._icy_data.keys(): + try: + self._icy_data[an_item] = self._icy_data[an_item].encode(self._station_encoding, 'replace') + except UnicodeDecodeError as e: + self._icy_data[an_item] = '' + if 'codec-name' in self._icy_data.keys(): + self._icy_data['codec-name'] = self._icy_data['codec-name'].replace('"', '') + #logger.error('DE audio data\n\n{}\n\n'.format(self._icy_data)) + self.info_display_handler() + except: + has_error = True + if logger.isEnabledFor(logging.ERROR): + logger.error("Error in Win VLC updateStatus thread.", exc_info=True) + if (logger.isEnabledFor(logging.INFO)): + logger.info("Win VLC updateStatus thread stopped.") + try: + fp.close() + except: + pass + def _request_mpv_info_data(self, sock): with self.status_update_lock: ret = len(self._icy_data) @@ -862,26 +1056,33 @@ def play(self, name, streamUrl, encoding = ''): opts = self._buildStartOpts(streamUrl, isPlayList) self.stop_mpv_status_update_thread = False #logger.error('DE opts\n\n{}\n\n'.format(opts)) - if self.PLAYER_CMD == "mpv" and version_info > (3, 0): + if platform.startswith('win') and self.PLAYER_CMD == 'cvlc': + self.stop_win_vlc_status_update_thread = False + """Launches vlc windowless""" + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW self.process = subprocess.Popen(opts, shell=False, - stdout=subprocess.DEVNULL, - stdin=subprocess.DEVNULL, - stderr=subprocess.DEVNULL) - t = threading.Thread(target=self.updateMPVStatus, args=(lambda: self.stop_mpv_status_update_thread, )) + startupinfo=startupinfo) + t = threading.Thread(target=self.updateWinVLCStatus, args=( + self._vlc_stdout_log_file, + self.config_encoding, + lambda: self.stop_win_vlc_status_update_thread)) else: - self.process = subprocess.Popen(opts, shell=False, - stdout=subprocess.PIPE, - stdin=subprocess.PIPE, - stderr=subprocess.STDOUT) - t = threading.Thread(target=self.updateStatus, args=()) + if self.PLAYER_CMD == "mpv" and version_info > (3, 0): + self.process = subprocess.Popen(opts, shell=False, + stdout=subprocess.DEVNULL, + stdin=subprocess.DEVNULL, + stderr=subprocess.DEVNULL) + t = threading.Thread(target=self.updateMPVStatus, args=(lambda: self.stop_mpv_status_update_thread, )) + else: + self.process = subprocess.Popen(opts, shell=False, + stdout=subprocess.PIPE, + stdin=subprocess.PIPE, + stderr=subprocess.STDOUT) + t = threading.Thread(target=self.updateStatus, args=()) t.start() # start playback check timer thread self.stop_timeout_counter_thread = False - logger.error('=========================') - logger.error('function self.playback_timeout_counter = {}'.format(self.playback_timeout_counter)) - logger.error('int self.playback_timeout = {}'.format(self.playback_timeout)) - logger.error('str self.name = {}'.format(self.name)) - logger.error('=========================') try: self.connection_timeout_thread = threading.Thread( target=self.playback_timeout_counter, @@ -906,7 +1107,10 @@ def _sendCommand(self, command): if logger.isEnabledFor(logging.DEBUG): logger.debug("Command: {}".format(command).strip()) self.process.stdin.write(command.encode('utf-8', 'replace')) - self.process.stdin.flush() + try: + self.process.stdin.flush() + except: + pass except: msg = "Error when sending: {}" if logger.isEnabledFor(logging.ERROR): @@ -918,8 +1122,8 @@ def close(self): self._no_mute_on_stop_playback() # First close the subprocess + logger.error('DE self._stop()') self._stop() - # Here is fallback solution and cleanup self.stop_timeout_counter_thread = True try: @@ -934,11 +1138,10 @@ def close(self): if self.process is not None: if platform.startswith('win'): try: - #subprocess.check_output("Taskkill /PID %d /F" % self.process.pid) - #subprocess.Popen(["Taskkill", "/PID", "{}".format(self.process.pid), "/F"]) subprocess.Call(['Taskkill', '/PID', '{}'.format(self.process.pid), '/F']) + self.process = None except: - pass + logger.error('Taskkill failed to kill PID {}'.format(self.process.pid)) else: try: os.kill(self.process.pid, 15) @@ -956,6 +1159,8 @@ def toggleMute(self): if self.PLAYER_CMD == 'mpv': self.muted = self._mute() + elif self.PLAYER_CMD == 'cvlc': + self._mute() else: self.muted = not self.muted self._mute() @@ -1022,7 +1227,8 @@ class MpvPlayer(Player): """Implementation of Player object for MPV""" PLAYER_CMD = "mpv" - if pywhich(PLAYER_CMD): + REAL_PLAYER_CMD = "mpv" + if pywhich(REAL_PLAYER_CMD): executable_found = True else: executable_found = False @@ -1099,7 +1305,7 @@ 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, "--no-video", "--input-ipc-server"], stdout=subprocess.PIPE, stdin=subprocess.PIPE, shell=False) + p = subprocess.Popen([self.REAL_PLAYER_CMD, "--no-video", "--input-ipc-server"], stdout=subprocess.PIPE, stdin=subprocess.PIPE, shell=False) out = p.communicate() if "not found" not in str(out[0]): if logger.isEnabledFor(logging.DEBUG): @@ -1109,17 +1315,16 @@ def _buildStartOpts(self, streamUrl, playList=False): if logger.isEnabledFor(logging.DEBUG): logger.debug("--input-ipc-server is not supported.") newerMpv = 0; - if playList: if newerMpv: - opts = [self.PLAYER_CMD, "--no-video", "--quiet", "--playlist=" + self._url_to_use(streamUrl), "--input-ipc-server=" + self.mpvsocket] + opts = [self.REAL_PLAYER_CMD, "--no-video", "--quiet", "--playlist=" + self._url_to_use(streamUrl), "--input-ipc-server=" + self.mpvsocket] else: - opts = [self.PLAYER_CMD, "--no-video", "--quiet", "--playlist=" + self._url_to_use(streamUrl), "--input-unix-socket=" + self.mpvsocket] + opts = [self.REAL_PLAYER_CMD, "--no-video", "--quiet", "--playlist=" + self._url_to_use(streamUrl), "--input-unix-socket=" + self.mpvsocket] else: if newerMpv: - opts = [self.PLAYER_CMD, "--no-video", "--quiet", self._url_to_use(streamUrl), "--input-ipc-server=" + self.mpvsocket] + opts = [self.REAL_PLAYER_CMD, "--no-video", "--quiet", self._url_to_use(streamUrl), "--input-ipc-server=" + self.mpvsocket] else: - opts = [self.PLAYER_CMD, "--no-video", "--quiet", self._url_to_use(streamUrl), "--input-unix-socket=" + self.mpvsocket] + opts = [self.REAL_PLAYER_CMD, "--no-video", "--quiet", self._url_to_use(streamUrl), "--input-unix-socket=" + self.mpvsocket] if self.USE_PROFILE == -1: self.USE_PROFILE = self._configHasProfile() @@ -1348,7 +1553,8 @@ class MpPlayer(Player): """Implementation of Player object for MPlayer""" PLAYER_CMD = "mplayer" - if pywhich(PLAYER_CMD): + REAL_PLAYER_CMD = "mplayer" + if pywhich(REAL_PLAYER_CMD): executable_found = True else: executable_found = False @@ -1426,10 +1632,7 @@ def _configHasProfile(self): def _buildStartOpts(self, streamUrl, playList=False): """ Builds the options to pass to subprocess.""" - if playList: - opts = [self.PLAYER_CMD, "-vo", "null", "-quiet", "-playlist", self._url_to_use(streamUrl)] - else: - opts = [self.PLAYER_CMD, "-vo", "-quiet", self._url_to_use(streamUrl)] + opts = [self.REAL_PLAYER_CMD, "-vo", "null", "-quiet"] if self.USE_PROFILE == -1: self.USE_PROFILE = self._configHasProfile() @@ -1438,6 +1641,9 @@ def _buildStartOpts(self, streamUrl, playList=False): opts.append("pyradio") if (logger.isEnabledFor(logging.DEBUG)): logger.debug("using profile [pyradio]") + if playList: + opts.append("-playlist") + opts.append(self._url_to_use(streamUrl)) return opts def _mute(self): @@ -1482,12 +1688,27 @@ def _format_volume_string(self, volume_string): class VlcPlayer(Player): """Implementation of Player for VLC""" - + WIN = False + if platform.startswith('win'): + WIN = True + logger.error('DE WIN = {}'.format(WIN)) PLAYER_CMD = "cvlc" - if pywhich(PLAYER_CMD): - executable_found = True + if WIN: + # TODO: search and finde vlc.exe + # REAL_PLAYER_CMD = "C:\\Program Files\\VideoLAN\\VLC\\vlc.exe" + REAL_PLAYER_CMD = find_vlc_on_windows() + if REAL_PLAYER_CMD: + executable_found = True + else: + executable_found = False else: - executable_found = False + REAL_PLAYER_CMD = "cvlc" + if pywhich(REAL_PLAYER_CMD): + executable_found = True + else: + executable_found = False + + print('executable: {}'.format(REAL_PLAYER_CMD)) if executable_found: """ items of this tupple are considered icy-title @@ -1515,51 +1736,131 @@ class VlcPlayer(Player): """ When found in station transmission, playback is on """ _playback_token_tuple = ('main audio ', 'Content-Type: audio' ) + """ Windows only variables """ + _vlc_stdout_log_file = '' + _port = None + win_show_vlc_volume_function = None + def save_volume(self): pass def _buildStartOpts(self, streamUrl, playList=False): """ Builds the options to pass to subprocess.""" - opts = [self.PLAYER_CMD, "--no-video", "-Irc", "-vv", self._url_to_use(streamUrl)] + #opts = [self.REAL_PLAYER_CMD, "-Irc", "--quiet", streamUrl] + if self.WIN: + """ Get a random port (44000-44999) + Create a log file for vlc and make sure it is unique + and it is created beforehand + """ + random.seed() + ok_to_go_on = False + while True: + logger.error('DE getting port for {}'.format(self.config_dir)) + self._port = random.randint(44000, 44999) + self._vlc_stdout_log_file = os.path.join(self.config_dir, 'vlc_log.' + str(self._port)) + if os.path.exists(self._vlc_stdout_log_file): + """ another instance running? """ + logger.error('DE file exists: "{}"'.format(self._vlc_stdout_log_file)) + continue + try: + with open(self._vlc_stdout_log_file, 'w') as f: + ok_to_go_on = True + except: + logger.error('DE file not opened: "{}"'.format(self._vlc_stdout_log_file)) + continue + if ok_to_go_on: + break + + opts = [self.REAL_PLAYER_CMD, "-Irc", "--rc-host", + "127.0.0.1:" + str(self._port), + "--file-logging", "--logmode", "text", "--log-verbose", "4", + "--logfile", self._vlc_stdout_log_file, "-vv", + streamUrl.replace('https://', 'http://')] + + if logger.isEnabledFor(logging.INFO): + logger.info('vlc listening on 127.0.0.1:{}'.format(self._port)) + logger.info('vlc log file: "{}"'.format(self._vlc_stdout_log_file)) + + else: + opts = [self.REAL_PLAYER_CMD, "-Irc", "-vv", streamUrl.replace('https://', 'http://')] return opts def _mute(self): """ mute vlc """ - + logger.error('DE vlc_mute(): muted = {}'.format(self.muted)) if self.muted: - self._sendCommand("volume {}\n".format(self.actual_volume)) + if self.WIN: + self._win_set_volume(self._unmuted_volume) + else: + self._sendCommand("volume {}\n".format(self.actual_volume)) if logger.isEnabledFor(logging.DEBUG): logger.debug('VLC unmuted: {0} ({1}%)'.format(self.actual_volume, int(100 * self.actual_volume / self.max_volume))) + self.muted = False else: if self.actual_volume == -1: self._get_volume() - self._sendCommand("volume 0\n") + if self.WIN: + self._win_mute() + else: + self._sendCommand("volume 0\n") + self.muted = True if logger.isEnabledFor(logging.DEBUG): logger.debug('VLC muted: 0 (0%)') def pause(self): """ pause streaming (if possible) """ - self._sendCommand("stop\n") + if self.WIN: + self._win_pause() + else: + self._sendCommand("stop\n") def _stop(self): """ exit pyradio (and kill vlc instance) """ + logger.error('setting self.stop_win_vlc_status_update_thread = True') + self.stop_win_vlc_status_update_thread = True if self.ctrl_c_pressed: return - self._sendCommand("shutdown\n") + if self.WIN: + if self.process: + self._req('quit') + threading.Thread(target=self._remove_vlc_stdout_log_file, args=()).start() + else: + self._sendCommand("shutdown\n") self._icy_data = {} + def _remove_vlc_stdout_log_file(self): + file_to_remove = self._vlc_stdout_log_file + if file_to_remove: + while os.path.exists(file_to_remove): + try: + os.remove(file_to_remove) + if logger.isEnabledFor(logging.DEBUG): + logger.debug('vlc log file removed: "' + file_to_remove + "'") + except: + pass + #logger.error('Failed {}'.format(count)) + def _volume_up(self): """ increase vlc's volume """ - self._sendCommand("volup\n") + if self.WIN: + self._win_volup() + self._win_show_vlc_volume() + else: + self._sendCommand("volup\n") def _volume_down(self): """ decrease vlc's volume """ - self._sendCommand("voldown\n") + if self.WIN: + self._win_voldown() + self._win_show_vlc_volume() + else: + self._sendCommand("voldown\n") - def _format_volume_string(self, volume_string): + def _format_volume_string(self, volume_string=None): """ format vlc's volume """ - dec_sep = '.' if '.' in volume_string else ',' - self.actual_volume = int(volume_string.split(self.volume_string)[1].split(dec_sep)[0].split()[0]) + if not self.WIN: + dec_sep = '.' if '.' in volume_string else ',' + self.actual_volume = int(volume_string.split(self.volume_string)[1].split(dec_sep)[0].split()[0]) return '[Vol: {}%] '.format(int(100 * self.actual_volume / self.max_volume)) def _format_title_string(self, title_string): @@ -1574,11 +1875,18 @@ def _format_title_string(self, title_string): def _is_accepted_input(self, input_string): """ vlc input filtering """ ret = False - accept_filter = (self.volume_string, - "http stream debug: ", - "format: ", - ": using", - ) + if self.WIN: + accept_filter = (self.volume_string, + "debug: ", + "format: ", + "using: ", + ) + else: + accept_filter = (self.volume_string, + "http stream debug: ", + "format: ", + ": using", + ) reject_filter = () for n in accept_filter: if n in input_string: @@ -1594,7 +1902,10 @@ def _is_accepted_input(self, input_string): def _get_volume(self): """ get vlc's actual_volume""" self.show_volume = False - self._sendCommand("voldown 0\n") + if self.WIN: + self._win_get_volume() + else: + self._sendCommand("voldown 0\n") def _no_mute_on_stop_playback(self): """ make sure vlc does not stop muted """ @@ -1603,21 +1914,131 @@ def _no_mute_on_stop_playback(self): if self.isPlaying(): if self.actual_volume == -1: self._get_volume() - while self.actual_volume == -1: - pass + if self.actual_volume == -1: + self.actual_volume = 0 if self.actual_volume == 0: self.actual_volume = int(self.max_volume*0.25) - self._sendCommand('volume {}\n'.format(self.actual_volume)) + if self.WIN: + self._win_set_volume(self.actual_volume) + else: + self._sendCommand('volume {}\n'.format(self.actual_volume)) if logger.isEnabledFor(logging.DEBUG): logger.debug('Unmuting VLC on exit: {} (25%)'.format(self.actual_volume)) elif self.muted: if self.actual_volume > 0: - self._sendCommand('volume {}\n'.format(self.actual_volume)) + if self.WIN: + self._win_set_volume(self.actual_volume) + else: + self._sendCommand('volume {}\n'.format(self.actual_volume)) if logger.isEnabledFor(logging.DEBUG): logger.debug('VLC volume restored on exit: {0} ({1}%)'.format(self.actual_volume, int(100 * self.actual_volume / self.max_volume))) self.show_volume = True + """ WINDOWS PART """ + + def _req(self, msg, ret_function=None, full=True): + response = '' + try: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + # Connect to server and send data + sock.settimeout(0.7) + sock.connect(('127.0.0.1', self._port)) + response = "" + received = "" + sock.sendall(bytes(msg + '\n', "utf-8")) + if msg != 'quit': + try: + while (True): + received = (sock.recv(4096)).decode() + #print('received: "{}"'.format(received)) + response = response + received + if full: + if response.count("\r\n") > 1: + sock.close() + break + else: + if response.count("\r\n") > 0: + sock.close() + break + except: + response = response + received + pass + sock.close() + except: + pass + if ret_function: + ret_function(response) + return response + + def _thrededreq(self, msg, ret_function=None): + threading.Thread(target=self._req, args=(msg,ret_function)).start() + + def _win_show_vlc_volume(self): + #if self.win_show_vlc_volume_function: + self._win_get_volume() + pvol = int((self.actual_volume + 1) / self.max_volume * 100 * 2) + if pvol > 0: + avol = '[Vol: {}%] '.format(pvol) + if self.show_volume and self.oldUserInput['Title']: + self.outputStream.write(msg=avol + self.oldUserInput['Title'], counter='') + self.threadUpdateTitle() + + def _win_get_volume(self): + self._thrededreq("volume", self._get_volume_response) + + def _get_volume_response(self, msg): + parts = msg.split('\r\n') + for n in parts: + if 'volume' in n: + vol = n.split(': ')[-1].replace(' )', '') + for n in ('.', ','): + ind = vol.find(n) + if ind > -1: + vol = vol[:ind] + break + self.actual_volume = int(vol) + logger.error('DE _get_volume_response: vol = {}'.format(vol)) + break + if self.actual_volume == 0: + self.muted = True + else: + self.muted = False + #self.print_response(vol) + + def _win_volup(self): + self._thrededreq("volup 1") + + def _win_voldown(self): + self._thrededreq("voldown 1") + + def _win_set_volume(self, vol): + ivol = int(vol) + self._thrededreq("volume " + str(ivol)) + self.actual_volume = ivol + + def _win_mute(self): + self._win_get_volume() + self._unmuted_volume = self.actual_volume + self._thrededreq("volume 0") + self.actual_volume = 0 + self.muted = True + + def _win_pause(self): + self._thrededreq('pause') + + def _win_is_playing(self): + self._thrededreq('is_playing', self._win_get_playing_state) + + def _win_get_playing_state(self, msg): + parts = msg.split('\r\n') + rep = False + for n in parts: + if n == "1" or 'play state:' in n: + rep = True + break + #self.print_response(rep) + def probePlayer(requested_player=''): """ Probes the multimedia players which are available on the host system.""" @@ -1648,11 +2069,12 @@ def probePlayer(requested_player=''): ret_player = check_player(player) if ret_player is not None: break + logger.error('**** Player is {}'.format(ret_player)) return ret_player def check_player(a_player): try: - p = subprocess.Popen([a_player.PLAYER_CMD, "--help"], + p = subprocess.Popen([a_player.REAL_PLAYER_CMD, "--help"], stdout=subprocess.PIPE, stdin=subprocess.PIPE, shell=False) diff --git a/pyradio/radio.py b/pyradio/radio.py index 75918850..8d3f6541 100644 --- a/pyradio/radio.py +++ b/pyradio/radio.py @@ -389,8 +389,10 @@ def setup(self, stdscr): self.log = Log() # For the time being, supported players are mpv, mplayer and vlc. try: - self.player = player.probePlayer(requested_player=self.requested_player)(self.log, + self.player = player.probePlayer(requested_player=self.requested_player)( + self.log, self._cnf.default_encoding, + self._cnf.stations_dir, self._cnf.connection_timeout_int, self._cnf.force_http, self.playbackTimeoutCounter, @@ -894,7 +896,6 @@ def playSelection(self): def playbackTimeoutCounter(self, *args): timeout = args[0] - logger.info('DE \n\ntimeout = {}\n\n'.format(timeout)) station_name = args[1] stop = args[2] if stop(): @@ -949,6 +950,7 @@ def connectionFailed(self): def stopPlayer(self, show_message=True): """ stop player """ try: + logger.error('DE ---- self.player.close()') self.player.close() except: pass @@ -4371,8 +4373,8 @@ def keypress(self, char): self.refreshBody() return else: - """ go back to playlist history """ if self._cnf.is_register: + """ go back to playlist history """ self._open_playlist_from_history() return """ exit """ @@ -4541,6 +4543,7 @@ def keypress(self, char): self.log.counter = None self._update_status_bar_right() if self.number_of_items > 0: + logger.error('DE ====---- isPlaying = {} ----===='.format(self.player.isPlaying)) if self.player.isPlaying(): self.stopPlayer(show_message=True) else: diff --git a/windows-mplayer.html b/windows-mplayer.html new file mode 100644 index 00000000..0ac2a416 --- /dev/null +++ b/windows-mplayer.html @@ -0,0 +1,79 @@ + + + + + + + MPlayer Installation on Windows + + + +
+
+

MPlayer Installation on Windows

+

PyRadio: Command line internet radio player.

+

Ben Dowling - https://github.com/coderholic

+

Table of contents Top

+ +

[Back to Build Instructions] [Back to README]

+

MPlayer installation Top

+

Go to MPlayer’s home and open the download page. Then scroll down to the Binaries section and get to the MPlayer Windows builds page. Then scroll down again until you get to the Build selection table to select an installation bundle.

+

Note: I am stating here all the links, although all one has to do is get to the last one and download the MPlayer setup. This is done so that in case any of the links change in the future, the way to go will be known, having MPlayer’s home page as a starting point.

+

You will end up downloading a 7z archive, which contains a directory whose name is similar to MPlayer-corei7-r38135+gb272d5b9b6.

+

Note: MPlayer provides CPU type dependent builds. In case you select the wrong mplayer build, you will end up connecting to stations but having no sound. If this is the case, please do go back to the download page and get the right build for your system / CPU.

+

Extract this directory to whatever place you like and rename it to mplayer.

+

Here comes the tricky part…

+

Move the mplayer directory to either on of the following locations:

+
    +
  1. %USERPROFILE%

    +

    This is actually your “Home” directory.

    +

    Please make a note that you will add "%USERPROFILE%\mplayer to PATH.

  2. +
  3. %APPDATA%\pyradio

    +

    This is (or will be) “PyRadio’s configuration directory”.

    +

    In case the pyradio directory does not exit, you just go ahead and create it.

    +

    (Make a note that you will add "%APPDATA%\pyradio\mplayer to PATH)

  4. +
+

In either case, in order to do that, open an Explorer File Manager window, and enter at its location field %USERPROFILE% or %APPDATA%.

+

If you are unsure on how to do that, please refer to the following image (you can ENTER %USERPROFILE% or %APPDATA% or any other Windows System Variable this way).

+

Navigating to %APPDATA%

+

Adding MPlayer to the PATH Top

+

The final step is to add MPlayer to the PATH System Variable.

+

Now, you already know the path string that has to be added (you have made a note of it in the previous step).

+

There’s just one thing to say here: Windows provide a “User variable for User” and a “System variables” section in the “Environment Variables” window.

+

Add the path string to the “User variables for User” section.

+

In order to make the actual addition, please refer to the following image.

+

Adding MPlayer to the PATH

+

After applying the changes you should log off and back on or restart the system, because changes done to the PATH variable will take effect the next time you log into the system.

+

When you are back on, verify that you can run MPlayer; open a console (press the Win key, type cmd and press ENTER) and type “mplayer”.

+

If you get something similar to the following snippet, you are all good.

+
MPlayer Redxii-SVN-r38119-6.2.0 (x86_64) (C) 2000-2018 MPlayer Team
+Using FFmpeg N-92801-g7efe84aebd (2018-12-25 00:44:17 +0100)
+Compiled on 2018-12-25 13:55:17 EST (rev. 1)
+Usage:   mplayer [options] [url|path/]filename
+

If mplayer was not found, you just have to go through the PATH modification procedure again.

+ + diff --git a/windows-mplayer.md b/windows-mplayer.md new file mode 100644 index 00000000..c42d4424 --- /dev/null +++ b/windows-mplayer.md @@ -0,0 +1,79 @@ +# MPlayer Installation on Windows + +**PyRadio**: Command line internet radio player. + +Ben Dowling - [https://github.com/coderholic](https://github.com/coderholic) + + +## Table of contents + +* [MPlayer installation](#mplayer-installation) + * [Adding MPlayer to the PATH](#adding-mplayer-to-the-path) + +[[Back to Build Instructions]](windows.md) [[Back to README]](README.md) + +## MPlayer installation + +Go to [MPlayer's home](http://www.mplayerhq.hu/) and open the [download](http://www.mplayerhq.hu/design7/dload.html) page. Then scroll down to the **Binaries** section and get to the [MPlayer Windows builds](http://oss.netfarm.it/mplayer/) page. Then scroll down again until you get to the **Build selection table** to select an installation bundle. + +**Note:** I am stating here all the links, although all one has to do is get to the last one and download the **MPlayer setup**. This is done so that in case any of the links change in the future, the way to go will be known, having [MPlayer's home page](http://www.mplayerhq.hu/) as a starting point. + +You will end up downloading a [7z archive](https://www.7-zip.org/), which contains a directory whose name is similar to **MPlayer-corei7-r38135+gb272d5b9b6**. + +**Note:** *MPlayer* provides CPU type dependent builds. In case you select the wrong *mplayer* build, you will end up connecting to stations but having no sound. If this is the case, please do go back to the download page and get the right build for your system / CPU. + +Extract this directory to whatever place you like and **rename** it to **mplayer**. + +Here comes the tricky part... + +Move the **mplayer** directory to either on of the following locations: + +a. **%USERPROFILE%** + + This is actually your "*Home*" directory. + + Please make a note that you will add "**%USERPROFILE%\\mplayer** to PATH. + +b. **%APPDATA%\\pyradio** + + This is (or will be) "*PyRadio's configuration directory*". + + In case the **pyradio** directory does not exit, you just go ahead and create it. + + (Make a note that you will add "**%APPDATA%\\pyradio\\mplayer** to PATH) + +In either case, in order to do that, open an **Explorer File Manager** window, and enter at its location field **%USERPROFILE%** or **%APPDATA%**. + +If you are unsure on how to do that, please refer to the following image (you can ENTER **%USERPROFILE%** or **%APPDATA%** or any other Windows System Variable this way). + +[Navigating to %APPDATA%](https://members.hellug.gr/sng/pyradio/appdata.jpg) + + +### Adding MPlayer to the PATH + +The final step is to add MPlayer to the PATH System Variable. + +Now, you already know the **path string** that has to be added (you have made a note of it in the previous step). + +There's just one thing to say here: Windows provide a "*User variable for User*" and a "*System variables*" section in the "*Environment Variables*" window. + +Add the **path string** to the "*User variables for User*" section. + +In order to make the actual addition, please refer to the following image. + +[Adding MPlayer to the PATH](https://members.hellug.gr/sng/pyradio/path.jpg) + +After applying the changes you should **log off and back on** or **restart the system**, because changes done to the PATH variable will take effect the next time you log into the system. + +When you are back on, verify that you can run **MPlayer**; open a console (press the **Win** key, type **cmd** and press **ENTER**) and type "**mplayer**". + +If you get something similar to the following snippet, you are all good. + +``` +MPlayer Redxii-SVN-r38119-6.2.0 (x86_64) (C) 2000-2018 MPlayer Team +Using FFmpeg N-92801-g7efe84aebd (2018-12-25 00:44:17 +0100) +Compiled on 2018-12-25 13:55:17 EST (rev. 1) +Usage: mplayer [options] [url|path/]filename +``` + +If **mplayer** was not found, you just have to go through the PATH modification procedure again. diff --git a/windows.html b/windows.html index 33b89242..890411ad 100644 --- a/windows.html +++ b/windows.html @@ -7,22 +7,29 @@ PyRadio on Windows + a{ color: SaddleBrown;} +a:visited{color: SaddleBrown;} +
-

PyRadio on Windows

+

PyRadio on Windows

PyRadio: Command line internet radio player.

Ben Dowling - https://github.com/coderholic

Table of contents Top

@@ -36,9 +43,10 @@

Table of contents <
  • 1.1 Installing Python
  • 1.2 Verifying the installation
  • -
  • 2. MPlayer installation +
  • 2. Player installation
  • 3. Git installation (optional)
  • 4. PyRadio installation @@ -64,14 +72,16 @@

    Running PyRadio on Windows How it all works Top

    First of all, let me tell you that if you are still running Windows XP, you can just stop reading right now; it won’t happen…

    -

    Then, due to reasons that are of no importance right now, MPlayer is the only player that can be used. Furthermore, special care has to be taken in order to be able to save the volume of the player.

    +

    Then, due to reasons that are of no importance right now, mpv is not (yet?) supported. That leaves us with MPlayer and VLC.

    +

    Installing MPlayer takes a couple of extra steps, and you may find that some streams (e.g. m3u8) may not be playable. Furthermore, special care has to be taken in order to be able to save the volume of the player.

    +

    VLC is much easier to install, but song titles’ updating may not be 100% consistaent. If this is not a deal breaker for you, then just go on and use VLC as PyRadio’s player.

    Other than that, you will have a fully functional PyRadio installation.

    Having said that, let us proceed with the installation.

    Installation Top

    The installation consists of three (optionally four) steps:

    1. Python installation
    2. -
    3. MPlayer installation
    4. +
    5. Player installation
    6. Git installation (optional)
    7. PyRadio installation
    @@ -87,44 +97,43 @@

    1.2 Verifying the installation

    Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:54:40) [MSC v.1900 64 bit (AMD64)] on win
     Type "help", "copyright", "credits" or "license" for more information.
     >>>
    -

    If the command could not be found, you have to run the installation again, select “Modify” and set the “Add Python to environment varaibles” option. You can refer to the following image to see the relevant setting.

    +

    If the command could not be found, you have to run the installation again, select “Modify” and set the “Add Python to environment variables” option. You can refer to the following image to see the relevant setting.

    Python Installation Modification

    Note: If you don’t have the setup file of the original Python installation, you will have to download it from Python’s Windows Downloads. In case you want to upgrade to the latest version, you must uninstall the one currently installed, beforehand.

    -

    2. MPlayer installation Top

    -

    Go to MPlayer’s home and open the download page. Then scroll down to the Binaries section and get to the MPlayer Windows builds page. Then scroll down again until you get to the Build selection table to select an installation bundle.

    -

    Note: I am stating here all the links, although all one has to do is get to the last one and download the MPlayer setup. This is done so that in case any of the links change in the future, the way to go will be known, having MPlayer’s home page as a starting point.

    -

    You will end up downloading a 7z archive, which contains a directory whose name is similar to MPlayer-corei7-r38135+gb272d5b9b6.

    -

    Note: MPlayer provides CPU type dependent builds. In case you select the wrong mplayer build, you will end up connecting to stations but having no sound. If this is the case, please do go back to the download page and get the right build for your system / CPU.

    -

    Extract this directory to whatever place you like and rename it to mplayer.

    -

    Here comes the tricky part…

    -

    Move the mplayer directory to either on of the following locations:

    -
      -
    1. %USERPROFILE%

      -

      This is actually your “Home” directory.

      -

      Please make a note that you will add "%USERPROFILE%\mplayer to PATH.

    2. -
    3. %APPDATA%\pyradio

      -

      This is (or will be) “PyRadio’s configuration directory”.

      -

      In case the pyradio directory does not exit, you just go ahead and create it.

      -

      (Make a note that you will add "%APPDATA%\pyradio\mplayer to PATH)

    4. -
    -

    In either case, in order to do that, open an Explorer File Manager window, and enter at its location field %USERPROFILE% or %APPDATA%.

    -

    If you are unsure on how to do that, please refer to the following image (you can ENTER %USERPROFILE% or %APPDATA% or any other Windows System Variable this way).

    -

    Navigating to %APPDATA%

    -

    2.1 Adding MPlayer to the PATH

    -

    The final step is to add MPlayer to the PATH System Variable.

    -

    Now, you already know the path string that has to be added (you have made a note of it in the previous step).

    -

    There’s just one thing to say here: Windows provide a “User variable for User” and a “System variables” section in the “Environment Variables” window.

    -

    Add the path string to the “User variables for User” section.

    -

    In order to make the actual addition, please refer to the following image.

    -

    Adding MPlayer to the PATH

    -

    After applying the changes you should log off and back on or restart the system, because changes done to the PATH variable will take effect the next time you log into the system.

    -

    When you are back on, verify that you can run MPlayer; open a console (press the Win key, type cmd and press ENTER) and type “mplayer”.

    -

    If you get something similar to the following snippet, you are all good.

    -
    MPlayer Redxii-SVN-r38119-6.2.0 (x86_64) (C) 2000-2018 MPlayer Team
    -Using FFmpeg N-92801-g7efe84aebd (2018-12-25 00:44:17 +0100)
    -Compiled on 2018-12-25 13:55:17 EST (rev. 1)
    -Usage:   mplayer [options] [url|path/]filename
    -

    If mplayer was not found, you just have to go through the PATH modification procedure again.

    +

    2. Player installation Top

    +

    It’s time to decide which player you want to use, either MPlayer or VLC, or even both of them.

    +

    This is what you should know before making your decision:

    + +++++ + + + + + + + + + + + + + + + + + + + +
    MPlayerVLC
    ProsFully functionalEasy installation
    Plays almost all streams
    ConsExtra steps to install
    May not play all streams (e.g. m3u8)
    Titles update is not consistent
    +

    2.1 MPlayer installation

    +

    If MPlayer is your selection, please refer to the relevant instructions.

    +

    2.2 VLC installation

    +

    If VLC is your selection, just go and get it and install it as any other Windows program.

    +

    As long as you install it to its default location (e.g “C:\Program Files\VideoLAN\VLC” or “C:\Program Files (x86)\VideoLAN\VLC”) Pyradio will be able to detect and use it.

    3. Git installation (optional) Top

    This is an optional step, so if you do not want to install yet another program to your PC, you are free to skip it.

    Having said that, why would you install Git?

    diff --git a/windows.md b/windows.md index cbe35ac7..05636494 100644 --- a/windows.md +++ b/windows.md @@ -12,8 +12,9 @@ Ben Dowling - [https://github.com/coderholic](https://github.com/coderholic) * [1. Python installation](#python-installation) * [1.1 Installing Python](#installing-python) * [1.2 Verifying the installation](#verifying-the-installation) - * [2. MPlayer installation](#mplayer-installation) - * [2.1 Adding MPlayer to the PATH](#adding-mplayer-to-the-path) + * [2. Player installation](#player-installation) + * [2.1 MPlayer installation](#mplayer-installation) + * [2.2 VLC installation](#vlc-installation) * [3. Git installation (optional)](#git-installation-optional) * [4. PyRadio installation](#pyradio-installation) * [4.1 Using Git](#using-git) @@ -41,7 +42,11 @@ This page will guide you through the process of installing, updating and running First of all, let me tell you that if you are still running Windows XP, you can just stop reading right now; it won't happen... -Then, due to reasons that are of no importance right now, [MPlayer](http://www.mplayerhq.hu/design7/news.html) is the only player that can be used. Furthermore, special care has to be taken in order to be able to save the volume of the player. +Then, due to reasons that are of no importance right now, [mpv](https://mpv.io/) is not (yet?) supported. That leaves us with [MPlayer](http://www.mplayerhq.hu/design7/news.html) and [VLC](https://www.videolan.org/vlc/). + +Installing [MPlayer](http://www.mplayerhq.hu/) takes a couple of extra steps, and you may find that some streams (e.g. m3u8) may not be playable. Furthermore, special care has to be taken in order to be able to save the volume of the player. + +[VLC](https://www.videolan.org/vlc/) is much easier to install, but song titles' updating may not be 100% consistaent. If this is not a deal breaker for you, then just go on and use [VLC](https://www.videolan.org/vlc/) as **PyRadio**'s player. Other than that, you will have a fully functional **PyRadio** installation. @@ -52,7 +57,7 @@ Having said that, let us proceed with the installation. The installation consists of three (optionally four) steps: 1. **Python** installation -2. **MPlayer** installation +2. **Player** installation 3. **Git** installation (optional) 4. **PyRadio** installation @@ -81,78 +86,34 @@ Type "help", "copyright", "credits" or "license" for more information. >>> ``` -If the command could not be found, you have to run the installation again, select "*Modify*" and set the "*Add Python to environment varaibles*" option. You can refer to the following image to see the relevant setting. +If the command could not be found, you have to run the installation again, select "*Modify*" and set the "*Add Python to environment variables*" option. You can refer to the following image to see the relevant setting. [Python Installation Modification](https://members.hellug.gr/sng/pyradio/python2.jpg) - **Note:** If you don't have the setup file of the original **Python** installation, you will have to **download** it from [Python's Windows Downloads](https://www.python.org/downloads/windows/). In case you want to upgrade to the latest version, you **must uninstall** the one currently installed, beforehand. -### 2. MPlayer installation - -Go to [MPlayer's home](http://www.mplayerhq.hu/) and open the [download](http://www.mplayerhq.hu/design7/dload.html) page. Then scroll down to the **Binaries** section and get to the [MPlayer Windows builds](http://oss.netfarm.it/mplayer/) page. Then scroll down again until you get to the **Build selection table** to select an installation bundle. - -**Note:** I am stating here all the links, although all one has to do is get to the last one and download the **MPlayer setup**. This is done so that in case any of the links change in the future, the way to go will be known, having [MPlayer's home page](http://www.mplayerhq.hu/) as a starting point. - -You will end up downloading a [7z archive](https://www.7-zip.org/), which contains a directory whose name is similar to **MPlayer-corei7-r38135+gb272d5b9b6**. - -**Note:** *MPlayer* provides CPU type dependent builds. In case you select the wrong *mplayer* build, you will end up connecting to stations but having no sound. If this is the case, please do go back to the download page and get the right build for your system / CPU. - -Extract this directory to whatever place you like and **rename** it to **mplayer**. - -Here comes the tricky part... - -Move the **mplayer** directory to either on of the following locations: - -a. **%USERPROFILE%** - - This is actually your "*Home*" directory. - - Please make a note that you will add "**%USERPROFILE%\\mplayer** to PATH. +### 2. Player installation -b. **%APPDATA%\\pyradio** +It's time to decide which player you want to use, either [MPlayer](http://www.mplayerhq.hu/design7/news.html) or [VLC](https://www.videolan.org/vlc/), or even both of them. - This is (or will be) "*PyRadio's configuration directory*". +This is what you should know before making your decision: - In case the **pyradio** directory does not exit, you just go ahead and create it. +| | MPlayer | VLC | +|----------|----------------------------------------------------------------|-----------------------------------------------| +| **Pros** | Fully functional | Easy installation
    Plays almost all streams | +| **Cons** | Extra steps to install
    May not play all streams (e.g. m3u8) | Titles update is not consistent | - (Make a note that you will add "**%APPDATA%\\pyradio\\mplayer** to PATH) -In either case, in order to do that, open an **Explorer File Manager** window, and enter at its location field **%USERPROFILE%** or **%APPDATA%**. +#### 2.1 MPlayer installation -If you are unsure on how to do that, please refer to the following image (you can ENTER **%USERPROFILE%** or **%APPDATA%** or any other Windows System Variable this way). +If [MPlayer](http://www.mplayerhq.hu/) is your selection, please refer to the [relevant instructions](windows-mplayer.md). -[Navigating to %APPDATA%](https://members.hellug.gr/sng/pyradio/appdata.jpg) +#### 2.2 VLC installation +If [VLC](https://www.videolan.org/vlc/) is your selection, just go and get it and install it as any other Windows program. -#### 2.1 Adding MPlayer to the PATH - -The final step is to add MPlayer to the PATH System Variable. - -Now, you already know the **path string** that has to be added (you have made a note of it in the previous step). - -There's just one thing to say here: Windows provide a "*User variable for User*" and a "*System variables*" section in the "*Environment Variables*" window. - -Add the **path string** to the "*User variables for User*" section. - -In order to make the actual addition, please refer to the following image. - -[Adding MPlayer to the PATH](https://members.hellug.gr/sng/pyradio/path.jpg) - -After applying the changes you should **log off and back on** or **restart the system**, because changes done to the PATH variable will take effect the next time you log into the system. - -When you are back on, verify that you can run **MPlayer**; open a console (press the **Win** key, type **cmd** and press **ENTER**) and type "**mplayer**". - -If you get something similar to the following snippet, you are all good. - -``` -MPlayer Redxii-SVN-r38119-6.2.0 (x86_64) (C) 2000-2018 MPlayer Team -Using FFmpeg N-92801-g7efe84aebd (2018-12-25 00:44:17 +0100) -Compiled on 2018-12-25 13:55:17 EST (rev. 1) -Usage: mplayer [options] [url|path/]filename -``` - -If **mplayer** was not found, you just have to go through the PATH modification procedure again. +As long as you install it to its default location (e.g "*C:\\Program Files\\VideoLAN\\VLC*" or "*C:\\Program Files (x86)\\VideoLAN\\VLC*") **Pyradio** will be able to detect and use it. + ### 3. Git installation (optional) @@ -262,7 +223,7 @@ Finally, you can type **pyradio** and enjoy! ## Updating PyRadio -**PyRadio** will inform you when a new release is available. +**PyRadio** will inform you when a new release is available. To start the update procedure, close **PyRadio** if it's still running. @@ -305,9 +266,9 @@ Example: ** Removing executable ... done ** Removing Desktop shortcut ... done Looking for python installed files... - ** Removing "pyradio-0.8.8-py3.7.egg" ... done - ** Removing "pyradio-0.7.9-py3.7.egg" ... done - ** Removing "pyradio-0.6.3-py3.7.egg" ... done + ** Removing "pyradio-0.8.8-py3.7.egg" ... done + ** Removing "pyradio-0.7.9-py3.7.egg" ... done + ** Removing "pyradio-0.6.3-py3.7.egg" ... done PyRadio successfully uninstalled! *********************************************************