refactoring + encapsulation
This commit is contained in:
parent
18681538e2
commit
f8672bdd6d
@ -1,7 +1,4 @@
|
||||
#coding:utf8
|
||||
import thread
|
||||
import sys
|
||||
|
||||
from twisted.internet import reactor
|
||||
from syncplay import client
|
||||
from syncplay.players import mpc_using_api
|
||||
@ -9,17 +6,16 @@ from syncplay.players import mpc_using_api
|
||||
from syncplay import utils
|
||||
|
||||
|
||||
def prepare_args(args):
|
||||
if (args.mpc_path == None):
|
||||
sys.exit("You must supply mpc-path on first run")
|
||||
args.args.extend(['/open', '/new'])
|
||||
def prepareArguments():
|
||||
args = utils.MPCConfigurationGetter()
|
||||
args.prepareClientConfiguration()
|
||||
return args.getClientConfiguration()
|
||||
|
||||
if __name__ == '__main__':
|
||||
manager = None
|
||||
try:
|
||||
args = utils.get_configuration()
|
||||
prepare_args(args)
|
||||
manager = client.Manager(args.host, args.port, args.name, lambda m: mpc_using_api.run_mpc(m, args.mpc_path, args.file, args.args))
|
||||
args = prepareArguments()
|
||||
manager = client.Manager(args.host, args.port, args.name, lambda m: mpc_using_api.run_mpc(m, args.mpc_path, args.file, args._args))
|
||||
manager.start()
|
||||
finally:
|
||||
if(manager): manager.stop()
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
#coding:utf8
|
||||
import thread
|
||||
import sys
|
||||
|
||||
from twisted.internet import reactor
|
||||
from syncplay import client
|
||||
from syncplay.players import mplayer
|
||||
|
||||
from syncplay import utils
|
||||
|
||||
def prepareArguments():
|
||||
args = utils.ConfigurationGetter()
|
||||
args.prepareClientConfiguration()
|
||||
return args.getClientConfiguration()
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = utils.get_configuration()
|
||||
args = prepareArguments()
|
||||
args.args.extend(('-slave', '-msglevel', 'all=1:global=4'))
|
||||
if(args.file): args.args.extend((args.file,))
|
||||
manager = client.Manager(args.host, args.port, args.name, lambda m: mplayer.run_mplayer(m, 'mplayer', args.args))
|
||||
|
||||
@ -8,7 +8,7 @@ from twisted.internet import reactor
|
||||
from twisted.internet.protocol import ClientFactory
|
||||
from syncplay import utils
|
||||
from .network_utils import (
|
||||
arg_count,
|
||||
argumentCount,
|
||||
CommandProtocol,
|
||||
)
|
||||
from .utils import format_time
|
||||
@ -30,7 +30,7 @@ class SyncClientProtocol(CommandProtocol):
|
||||
self.manager.stop()
|
||||
CommandProtocol.handle_error(self, args)
|
||||
|
||||
@arg_count(1)
|
||||
@argumentCount(1)
|
||||
def handle_init_hello(self, args):
|
||||
message ='Connected as ' + args[0]
|
||||
print message
|
||||
@ -39,7 +39,7 @@ class SyncClientProtocol(CommandProtocol):
|
||||
self.send_list()
|
||||
self.manager.schedule_send_status()
|
||||
|
||||
@arg_count(2, 3)
|
||||
@argumentCount(2, 3)
|
||||
def handle_connected_present(self, args):
|
||||
if len(args) == 3:
|
||||
who, where, what = args
|
||||
@ -54,7 +54,7 @@ class SyncClientProtocol(CommandProtocol):
|
||||
print message
|
||||
if(self.manager.player): self.manager.player.display_message(message)
|
||||
|
||||
@arg_count(4, 5)
|
||||
@argumentCount(4, 5)
|
||||
def handle_connected_state(self, args):
|
||||
args = self.__parseState(args)
|
||||
if not args:
|
||||
@ -65,7 +65,7 @@ class SyncClientProtocol(CommandProtocol):
|
||||
|
||||
self.manager.update_global_state(counter, ctime, paused, position, name)
|
||||
|
||||
@arg_count(3)
|
||||
@argumentCount(3)
|
||||
def handle_connected_seek(self, args):
|
||||
ctime, position, who = args
|
||||
try:
|
||||
@ -79,30 +79,30 @@ class SyncClientProtocol(CommandProtocol):
|
||||
|
||||
self.manager.seek(ctime, position, who)
|
||||
|
||||
@arg_count(1)
|
||||
@argumentCount(1)
|
||||
def handle_connected_ping(self, args):
|
||||
self.send_message('pong', args[0], int(time.time()*100000))
|
||||
|
||||
@arg_count(3)
|
||||
@argumentCount(3)
|
||||
def handle_connected_playing(self, args):
|
||||
who, where, what = args
|
||||
message = '%s is playing \'%s\' in the room: \'%s\'' % (who, what, where)
|
||||
print message
|
||||
if(self.manager.player): self.manager.player.display_message(message)
|
||||
|
||||
@arg_count(1)
|
||||
@argumentCount(1)
|
||||
def handle_connected_joined(self, args):
|
||||
message = '%s joined' % args[0]
|
||||
print message
|
||||
if(self.manager.player): self.manager.player.display_message(message)
|
||||
|
||||
@arg_count(2)
|
||||
@argumentCount(2)
|
||||
def handle_connected_room(self, args):
|
||||
message = '%s entered the room: \'%s\'' % (args[0], args[1])
|
||||
print message
|
||||
if(self.manager.player): self.manager.player.display_message(message)
|
||||
|
||||
@arg_count(1)
|
||||
@argumentCount(1)
|
||||
def handle_connected_left(self, args):
|
||||
message = '%s left' % args[0]
|
||||
print message
|
||||
|
||||
@ -18,13 +18,12 @@ from zope.interface import implements
|
||||
|
||||
from .utils import ArgumentParser
|
||||
|
||||
|
||||
def arg_count(minimum, maximum=None):
|
||||
def argumentCount(minimum, maximum=None):
|
||||
def decorator(f):
|
||||
@wraps(f)
|
||||
def wrapper(self, args):
|
||||
if ((len(args) != minimum) if maximum is None else not (minimum <= len(args) <= maximum)):
|
||||
self.drop_with_error('Invalid arguments')
|
||||
self.dropWithError('Invalid arguments')
|
||||
return
|
||||
return f(self, args)
|
||||
return wrapper
|
||||
|
||||
@ -1,75 +1,59 @@
|
||||
#coding:utf8
|
||||
|
||||
import ConfigParser
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
RE_ARG = re.compile(r"('(?:[^\\']+|\\\\|\\')*'|[^\s']+)(?:\s+|\Z)")
|
||||
RE_NEED_QUOTING = re.compile(r"[\s'\\]")
|
||||
RE_QUOTABLE = re.compile(r"['\\]")
|
||||
RE_UNQUOTABLE = re.compile(r"\\(['\\])")
|
||||
|
||||
class InvalidArgumentException(Exception):
|
||||
pass
|
||||
|
||||
def quote_arg(arg):
|
||||
if isinstance(arg, unicode):
|
||||
arg = arg.encode('utf8')
|
||||
elif not isinstance(arg, str):
|
||||
arg = str(arg)
|
||||
|
||||
if not arg or RE_NEED_QUOTING.search(arg):
|
||||
return "'%s'" % RE_QUOTABLE.sub(r'\\\g<0>', arg)
|
||||
return arg
|
||||
|
||||
def unqote_arg(arg):
|
||||
if arg.startswith("'") and len(arg) > 1:
|
||||
arg = RE_UNQUOTABLE.sub(r'\1', arg[1:-1])
|
||||
return arg.decode('utf8', 'replace')
|
||||
|
||||
def _split_args(args):
|
||||
pos = 0
|
||||
while pos < len(args):
|
||||
match = RE_ARG.match(args, pos)
|
||||
if not match:
|
||||
raise InvalidArgumentException()
|
||||
pos = match.end()
|
||||
yield unqote_arg(match.group(1))
|
||||
|
||||
def split_args(args):
|
||||
try:
|
||||
return list(_split_args(args))
|
||||
except InvalidArgumentException:
|
||||
return None
|
||||
|
||||
def join_args(args):
|
||||
return ' '.join(quote_arg(arg) for arg in args)
|
||||
|
||||
def parse_state(args):
|
||||
if len(args) == 4:
|
||||
counter, ctime, state, position = args
|
||||
who_changed_state = None
|
||||
elif len(args) == 5:
|
||||
counter, ctime, state, position, who_changed_state = args
|
||||
else:
|
||||
return
|
||||
|
||||
if not state in ('paused', 'playing'):
|
||||
return
|
||||
|
||||
paused = state == 'paused'
|
||||
|
||||
try:
|
||||
counter = int(counter)
|
||||
ctime = int(ctime)
|
||||
position = int(position)
|
||||
except ValueError:
|
||||
return
|
||||
|
||||
ctime /= 1000.0
|
||||
position /= 1000.0
|
||||
|
||||
return counter, ctime, paused, position, who_changed_state
|
||||
|
||||
class ArgumentParser():
|
||||
RE_ARG = re.compile(r"('(?:[^\\']+|\\\\|\\')*'|[^\s']+)(?:\s+|\Z)")
|
||||
RE_NEED_QUOTING = re.compile(r"[\s'\\]")
|
||||
RE_QUOTABLE = re.compile(r"['\\]")
|
||||
RE_UNQUOTABLE = re.compile(r"\\(['\\])")
|
||||
|
||||
class InvalidArgumentException(Exception):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def quoteArgument(arg):
|
||||
if isinstance(arg, unicode):
|
||||
arg = arg.encode('utf8')
|
||||
elif not isinstance(arg, str):
|
||||
arg = str(arg)
|
||||
|
||||
if not arg or ArgumentParser.RE_NEED_QUOTING.search(arg):
|
||||
return "'%s'" % ArgumentParser.RE_QUOTABLE.sub(r'\\\g<0>', arg)
|
||||
return arg
|
||||
|
||||
@staticmethod
|
||||
def unqoteArgument(arg):
|
||||
if arg.startswith("'") and len(arg) > 1:
|
||||
arg = ArgumentParser.RE_UNQUOTABLE.sub(r'\1', arg[1:-1])
|
||||
return arg.decode('utf8', 'replace')
|
||||
|
||||
@staticmethod
|
||||
def __splitArguments(args):
|
||||
pos = 0
|
||||
while pos < len(args):
|
||||
match = ArgumentParser.RE_ARG.match(args, pos)
|
||||
if not match:
|
||||
raise ArgumentParser.InvalidArgumentException()
|
||||
pos = match.end()
|
||||
yield ArgumentParser.unqoteArgument(match.group(1))
|
||||
|
||||
@staticmethod
|
||||
def splitArguments(args):
|
||||
try:
|
||||
return list(ArgumentParser.__splitArguments(args))
|
||||
except ArgumentParser.InvalidArgumentException:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def joinArguments(args):
|
||||
return ' '.join(ArgumentParser.quoteArgument(arg) for arg in args)
|
||||
|
||||
|
||||
def find_exec_path(name):
|
||||
if os.access(name, os.X_OK):
|
||||
return name
|
||||
@ -86,22 +70,13 @@ def format_time(value):
|
||||
return '%02d:%02d:%02d.%02d' % (hours, minutes, seconds, mseconds)
|
||||
|
||||
|
||||
import sys
|
||||
import ConfigParser
|
||||
import argparse
|
||||
|
||||
def get_working_directory():
|
||||
frozen = getattr(sys, 'frozen', '')
|
||||
if not frozen:
|
||||
# not frozen: in regular python interpreter
|
||||
approot = os.path.dirname(os.path.dirname(__file__))
|
||||
|
||||
elif frozen in ('dll', 'console_exe', 'windows_exe'):
|
||||
# py2exe:
|
||||
approot = os.path.dirname(sys.executable)
|
||||
else:
|
||||
raise Exception('Working dir not found')
|
||||
return approot
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def stdin_thread(manager):
|
||||
try:
|
||||
@ -114,45 +89,111 @@ def stdin_thread(manager):
|
||||
except:
|
||||
pass
|
||||
|
||||
def get_configuration():
|
||||
parser = argparse.ArgumentParser(description='Syncplay',
|
||||
epilog='If no options supplied config values will be used')
|
||||
parser.add_argument('--host', metavar='hostname', type=str, help='server\'s address')
|
||||
parser.add_argument('--name', metavar='username', type=str, help='desired username')
|
||||
parser.add_argument('-m', '--mpc-path', metavar='path', type=str, help='path to mpc-hc.exe (only for sync_mpc_api client)')
|
||||
parser.add_argument('-d','--debug', action='store_true', help='debug mode')
|
||||
parser.add_argument('-n','--no-store', action='store_true', help='don\'t store values in syncplay.ini')
|
||||
parser.add_argument('file', metavar='file', type=str, nargs='?', help='file to play')
|
||||
parser.add_argument('args', metavar='options', type=str, nargs='*', help='player options, if you need to pass options starting with - prepend them with single \'--\' argument')
|
||||
args = parser.parse_args()
|
||||
|
||||
working_path = get_working_directory()
|
||||
config = ConfigParser.RawConfigParser()
|
||||
config.read(os.path.join(working_path, 'syncplay.ini'))
|
||||
section_name = 'sync' if not args.debug else 'debug'
|
||||
try:
|
||||
if(args.host == None): args.host = config.get(section_name, 'host')
|
||||
if(args.name == None): args.name = config.get(section_name, 'name')
|
||||
if(args.mpc_path == None): args.mpc_path = config.get(section_name, 'mpc_path')
|
||||
except ConfigParser.NoSectionError:
|
||||
pass
|
||||
except ConfigParser.NoOptionError:
|
||||
pass
|
||||
if(args.host == None or args.name == None):
|
||||
sys.exit("You must supply name and host on the first run")
|
||||
|
||||
if(not args.no_store):
|
||||
|
||||
|
||||
class ConfigurationGetter(object):
|
||||
def __init__(self):
|
||||
self._config = None
|
||||
self._args = None
|
||||
self._syncplayClient = None
|
||||
self._workingDir = None
|
||||
self._parser = None
|
||||
|
||||
with open(os.path.join(working_path, 'syncplay.ini'), 'wb') as configfile:
|
||||
if(not config.has_section(section_name)):
|
||||
config.add_section(section_name)
|
||||
config.set(section_name, 'host', args.host)
|
||||
config.set(section_name, 'name', args.name)
|
||||
config.set(section_name, 'mpc_path', args.mpc_path)
|
||||
config.write(configfile)
|
||||
if ':' in args.host:
|
||||
args.host, port = args.host.split(':', 1)
|
||||
args.port = int(port)
|
||||
else:
|
||||
args.port = 8999
|
||||
return args
|
||||
def _findWorkingDirectory(self):
|
||||
frozen = getattr(sys, 'frozen', '')
|
||||
if not frozen:
|
||||
self._workingDir = os.path.dirname(__file__)
|
||||
elif frozen in ('dll', 'console_exe', 'windows_exe'):
|
||||
self._workingDir = os.path.dirname(sys.executable)
|
||||
else:
|
||||
raise Exception('Working dir not found')
|
||||
|
||||
def _prepareArgParser(self):
|
||||
self._parser = argparse.ArgumentParser(description='Syncplay',
|
||||
epilog='If no options supplied _config values will be used')
|
||||
self._parser.add_argument('--no-gui', action='store_true', help='show no GUI')
|
||||
self._parser.add_argument('--host', metavar='hostname', type=str, help='server\'s address')
|
||||
self._parser.add_argument('--name', metavar='username', type=str, help='desired username')
|
||||
self._parser.add_argument('-d','--debug', action='store_true', help='debug mode')
|
||||
self._parser.add_argument('--no-store', action='store_true', help='don\'t store values in syncplay.ini')
|
||||
self._parser.add_argument('file', metavar='file', type=str, nargs='?', help='file to play')
|
||||
self._parser.add_argument('_args', metavar='options', type=str, nargs='*', help='player options, if you need to pass options starting with - prepend them with single \'--\' argument')
|
||||
|
||||
def _openConfigFile(self):
|
||||
if(not self._config):
|
||||
self._config = ConfigParser.RawConfigParser(allow_no_value=True)
|
||||
self._config.read(os.path.join(self._workingDir, 'syncplay.ini'))
|
||||
|
||||
def _getSectionName(self):
|
||||
return 'sync' if not self._args.debug else 'debug'
|
||||
|
||||
def _saveValuesIntoConfigFile(self):
|
||||
self._openConfigFile()
|
||||
section_name = self._getSectionName()
|
||||
if(not self._args.no_store):
|
||||
with open(os.path.join(self._workingDir, 'syncplay.ini'), 'wb') as configfile:
|
||||
if(not self._config.has_section(section_name)):
|
||||
self._config.add_section(section_name)
|
||||
self._setUpValuesToSave(section_name)
|
||||
self._config.write(configfile)
|
||||
|
||||
def _setUpValuesToSave(self, section_name):
|
||||
self._config.set(section_name, 'host', self._args.host)
|
||||
self._config.set(section_name, 'name', self._args.name)
|
||||
|
||||
def _readMissingValuesFromConfigFile(self):
|
||||
self._openConfigFile()
|
||||
section_name = self._getSectionName()
|
||||
try:
|
||||
self._valuesToReadFromConfig(section_name)
|
||||
except ConfigParser.NoSectionError:
|
||||
pass
|
||||
except ConfigParser.NoOptionError:
|
||||
pass
|
||||
|
||||
def _valuesToReadFromConfig(self, section_name):
|
||||
if (self._args.host == None):
|
||||
self._args.host = self._config.get(section_name, 'host')
|
||||
if (self._args.name == None):
|
||||
self._args.name = self._config.get(section_name, 'name')
|
||||
|
||||
def _splitPortAndHost(self):
|
||||
if ':' in self._args.host:
|
||||
self._args.host, port = self._args.host.split(':', 1)
|
||||
self._args.port = int(port)
|
||||
else:
|
||||
self._args.port = 8999
|
||||
|
||||
def prepareClientConfiguration(self):
|
||||
self._findWorkingDirectory()
|
||||
self._prepareArgParser()
|
||||
self._args = self._parser.parse_args()
|
||||
self._readMissingValuesFromConfigFile()
|
||||
self._splitPortAndHost()
|
||||
|
||||
def getClientConfiguration(self):
|
||||
return self._args
|
||||
|
||||
class MPCConfigurationGetter(ConfigurationGetter):
|
||||
def _prepareArgParser(self):
|
||||
ConfigurationGetter._prepareArgParser(self)
|
||||
self._parser.add_argument('--mpc-path', metavar='path', type=str, help='path to mpc-hc.exe (only for sync_mpc_api client)')
|
||||
|
||||
def _setUpValuesToSave(self, section_name):
|
||||
ConfigurationGetter._setUpValuesToSave(self, section_name)
|
||||
self._config.set(section_name, 'mpc_path', self._args.mpc_path)
|
||||
|
||||
def _valuesToReadFromConfig(self, section_name):
|
||||
ConfigurationGetter._valuesToReadFromConfig(self, section_name)
|
||||
if (self._args.mpc_path == None):
|
||||
self._args.mpc_path = self._config.get(section_name, 'mpc_path')
|
||||
|
||||
def __addSpecialMPCFlags(self):
|
||||
return self._args._args.extend(['/open', '/new'])
|
||||
|
||||
def prepareClientConfiguration(self):
|
||||
ConfigurationGetter.prepareClientConfiguration(self)
|
||||
self.__addSpecialMPCFlags()
|
||||
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user