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