From 40add3070e85d4b2e31a4f6031f813fea618ba18 Mon Sep 17 00:00:00 2001 From: Michal Bielecki Date: Tue, 22 Jan 2013 23:49:45 +0100 Subject: [PATCH 1/6] Fix for backquote in filename Fixes the "moc.MocError: /bin/sh: 1: Syntax error: EOF in backquote substitution" error, when trying to play a track that contains a backquote in its filename --- moc/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moc/__init__.py b/moc/__init__.py index b30c1b5..994744f 100644 --- a/moc/__init__.py +++ b/moc/__init__.py @@ -36,7 +36,7 @@ def _quote_file_args(files): def _exec_command(command, parameters=''): cmd = subprocess.Popen( - ['mocp --%s %s' %(command, parameters)], + ["mocp --%s %s" %(command, parameters.replace('`', '\`'))], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, close_fds=True ) From 9c617d891731ba6dae7bc9b1f04bf06e2832d5b9 Mon Sep 17 00:00:00 2001 From: Michal Bielecki Date: Wed, 23 Jan 2013 18:13:21 +0100 Subject: [PATCH 2/6] Better support for backquotes and other nasty characters in file path --- moc/__init__.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/moc/__init__.py b/moc/__init__.py index 994744f..cb1a4bf 100644 --- a/moc/__init__.py +++ b/moc/__init__.py @@ -21,7 +21,7 @@ class MocNotRunning(MocError): """ Raised if a command failed because the moc server does not run """ # Helper functions -def _quote_file_args(files): +def _check_file_args(files): if isinstance(files, str): raise TypeError("Argument must be a list/iterable, not str") quoted = [] @@ -29,16 +29,16 @@ def _quote_file_args(files): if os.path.exists(file) or file.startswith(('http://', 'ftp://')): # MOC only supports HTTP and FTP, not even HTTPS. # (See `is_url` in `files.c`.) - quoted.append('"%s"' % file) + quoted.append('%s' % file) else: raise OSError("File %r does not exist" % file) - return ' '.join(quoted) + return quoted -def _exec_command(command, parameters=''): +def _exec_command(command, parameters=[]): cmd = subprocess.Popen( - ["mocp --%s %s" %(command, parameters.replace('`', '\`'))], + ["mocp", "--%s" % (command)] + parameters, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - shell=True, close_fds=True + close_fds=True ) stdout, stderr = cmd.communicate() if cmd.returncode: @@ -124,7 +124,7 @@ def quickplay(files): Raises an :exc:`OSError` if any of the `files` can not be found. """ - _exec_command('playit', _quote_file_args(files)) + _exec_command('playit', _check_file_args(files)) def _moc_output_to_dict(output): @@ -183,14 +183,14 @@ def increase_volume(level=5): """ Aliases: ``increase_volume()``, ``volume_up()``, ``louder()``, ``upper_volume()`` """ - _exec_command('volume', '+%d' % level) + _exec_command('volume', ['+%d' % level]) louder = upper_volume = volume_up = increase_volume def decrease_volume(level=5): """ Aliases: ``decrease_volume()``, ``volume_down()``, ``lower()``, ``lower_volume()`` """ - _exec_command('volume', '-%d' % level) + _exec_command('volume', ['-%d' % level]) lower = lower_volume = volume_down = decrease_volume def seek(n): @@ -198,10 +198,10 @@ def seek(n): Moves the current playback seed forward by `n` seconds (or backward if `n` is negative). """ - _exec_command('seek', n) + _exec_command('seek', [n]) def _controls(what): - makefunc = lambda action: lambda: _exec_command(action, what) and None or None + makefunc = lambda action: lambda: _exec_command(action, [what]) and None or None return (makefunc(action) for action in ('on', 'off', 'toggle')) enable_repeat, disable_repeat, toggle_repeat = _controls('repeat') @@ -260,7 +260,7 @@ def playlist_append(files_directories_playlists): Appends the files, directories and/or in `files_directories_playlists` to moc's playlist. """ - _exec_command('append', _quote_file_args(files_directories_playlists)) + _exec_command('append', _check_file_args(files_directories_playlists)) append_to_playlist = playlist_append def playlist_clear(): From d9d8ced572fb8b8490fb8a48ae3934c7f88b22f9 Mon Sep 17 00:00:00 2001 From: Michal Bielecki Date: Fri, 25 Jan 2013 21:12:23 +0100 Subject: [PATCH 3/6] _check_file_args() is not returning anything anymore - it's just used to check ig files/streams are valid --- moc/__init__.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/moc/__init__.py b/moc/__init__.py index cb1a4bf..c062647 100644 --- a/moc/__init__.py +++ b/moc/__init__.py @@ -22,21 +22,24 @@ class MocNotRunning(MocError): # Helper functions def _check_file_args(files): + """ + Checks if every element from dictonary passed in parameter is a valid + filepath, is a http or ftp url. + + Raises TypeError if parameter is a string or OSError if any of files + in dictonary does not exist. + """ if isinstance(files, str): raise TypeError("Argument must be a list/iterable, not str") - quoted = [] for file in files: - if os.path.exists(file) or file.startswith(('http://', 'ftp://')): + if not os.path.exists(file) and not file.startswith(('http://', 'ftp://')): # MOC only supports HTTP and FTP, not even HTTPS. # (See `is_url` in `files.c`.) - quoted.append('%s' % file) - else: raise OSError("File %r does not exist" % file) - return quoted def _exec_command(command, parameters=[]): cmd = subprocess.Popen( - ["mocp", "--%s" % (command)] + parameters, + ["mocp", "--%s" % command] + parameters, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True ) @@ -124,7 +127,8 @@ def quickplay(files): Raises an :exc:`OSError` if any of the `files` can not be found. """ - _exec_command('playit', _check_file_args(files)) + _check_file_args(files) + _exec_command('playit', files) def _moc_output_to_dict(output): @@ -260,7 +264,8 @@ def playlist_append(files_directories_playlists): Appends the files, directories and/or in `files_directories_playlists` to moc's playlist. """ - _exec_command('append', _check_file_args(files_directories_playlists)) + _check_file_args(files_directories_playlists) + _exec_command('append', files_directories_playlists) append_to_playlist = playlist_append def playlist_clear(): From 02431292cc704c965e3e4295fe9264e3573fb8e1 Mon Sep 17 00:00:00 2001 From: Michal Bielecki Date: Fri, 1 Feb 2013 23:40:03 +0100 Subject: [PATCH 4/6] Added a way for passing configuration file and possibly other command line parameters --- moc/__init__.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/moc/__init__.py b/moc/__init__.py index c062647..c1edbec 100644 --- a/moc/__init__.py +++ b/moc/__init__.py @@ -3,6 +3,10 @@ import os import subprocess +class Cli: + extra_arguments = [] + + STATE_NOT_RUNNING = -1 STATE_STOPPED = 0 STATE_PAUSED = 1 @@ -39,7 +43,7 @@ def _check_file_args(files): def _exec_command(command, parameters=[]): cmd = subprocess.Popen( - ["mocp", "--%s" % command] + parameters, + ["mocp", "--%s" % command] + parameters + Cli.extra_arguments, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True ) @@ -52,6 +56,11 @@ def _exec_command(command, parameters=[]): raise MocError(errmsg) return stdout +def set_config_file(config_file_path): + if not os.path.exists(config_file_path): + raise OSError("Configuration file '%r' does not exists" % config_file_path) + Cli.extra_arguments = Cli.extra_arguments + ["--config", config_file_path] + def start_server(): """ Starts the moc server. """ _exec_command('server') From 4ed1cceccc7b9cad4e9b1b751d352fdfa7a9ffc0 Mon Sep 17 00:00:00 2001 From: Michal Bielecki Date: Sat, 20 Apr 2013 22:20:46 +0200 Subject: [PATCH 5/6] Added set_volume and get_volume methods get_volume gets mixer volume level from moc server by use of socket. We are now parsing moc config file, in order to check where socket file is. --- docs/source/moc.rst | 2 ++ moc/__init__.py | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/docs/source/moc.rst b/docs/source/moc.rst index 1400ea0..6b3cd74 100644 --- a/docs/source/moc.rst +++ b/docs/source/moc.rst @@ -22,6 +22,8 @@ Controlling the playback .. autofunction:: increase_volume .. autofunction:: decrease_volume +.. autofunction:: get_volume +.. autofunction:: set_volume .. autofunction:: moc.next .. autofunction:: moc.previous diff --git a/moc/__init__.py b/moc/__init__.py index c1edbec..79b3724 100644 --- a/moc/__init__.py +++ b/moc/__init__.py @@ -1,11 +1,16 @@ #!/usr/bin/env python from __future__ import with_statement -import os +import os, os.path import subprocess +import socket +import struct +import ConfigParser + class Cli: extra_arguments = [] - + configfile = "~/.moc/config" + socketfile = "~/.moc/socket2" STATE_NOT_RUNNING = -1 STATE_STOPPED = 0 @@ -59,11 +64,24 @@ def _exec_command(command, parameters=[]): def set_config_file(config_file_path): if not os.path.exists(config_file_path): raise OSError("Configuration file '%r' does not exists" % config_file_path) + + Cli.configfile = config_file_path Cli.extra_arguments = Cli.extra_arguments + ["--config", config_file_path] + update_moc_dir() + +def update_moc_dir(): + """ + Reads configuration file and searches for mocdir + """ + config = ConfigParser.RawConfigParser() + config.read(os.path.expanduser(Cli.configfile)) + if config.get('MOCDir'): + Cli.socketfile = config.get('MOCDir') def start_server(): """ Starts the moc server. """ _exec_command('server') + update_moc_dir() def stop_server(): """ Shuts down the moc server. """ @@ -206,6 +224,19 @@ def decrease_volume(level=5): _exec_command('volume', ['-%d' % level]) lower = lower_volume = volume_down = decrease_volume +def get_volume(): + s = socket.socket( socket.AF_UNIX, socket.SOCK_STREAM ) + s.connect(os.path.expanduser(Cli.socketfile)) + s.send(struct.pack('i', 0x1a)) + unpacker = struct.Struct('i i') + data = s.recv(unpacker.size) + s.close() + + return unpacker.unpack(data)[1] + +def set_volume(level): + _exec_command('volume', ['%d' % level]) + def seek(n): """ Moves the current playback seed forward by `n` seconds From e9ebb2d548f4b9003834439d1b59cca0afe55f33 Mon Sep 17 00:00:00 2001 From: Michal Bielecki Date: Sat, 20 Apr 2013 23:29:45 +0200 Subject: [PATCH 6/6] Fix for custom mocdir --- moc/__init__.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/moc/__init__.py b/moc/__init__.py index 79b3724..903d447 100644 --- a/moc/__init__.py +++ b/moc/__init__.py @@ -5,7 +5,7 @@ import socket import struct import ConfigParser - +import StringIO class Cli: extra_arguments = [] @@ -73,10 +73,16 @@ def update_moc_dir(): """ Reads configuration file and searches for mocdir """ + + configF = StringIO.StringIO() + configF.write('[dummysection]') + configF.write(open(os.path.expanduser(Cli.configfile), 'r').read()) + configF.seek(0, os.SEEK_SET) + config = ConfigParser.RawConfigParser() - config.read(os.path.expanduser(Cli.configfile)) - if config.get('MOCDir'): - Cli.socketfile = config.get('MOCDir') + config.readfp(configF) + if config.get('dummysection', 'MOCDir'): + Cli.socketfile = config.get('dummysection','MOCDir') + '/socket2' def start_server(): """ Starts the moc server. """