Reworked configuration

This commit is contained in:
Uriziel 2012-12-29 15:27:30 +01:00
parent 5b65d67d10
commit fe2aae1d83
6 changed files with 234 additions and 242 deletions

View File

@ -47,27 +47,27 @@ class SyncClientFactory(ClientFactory):
self._timesTried = self.retry
class SyncplayClient(object):
def __init__(self, playerClass, ui, args):
def __init__(self, playerClass, ui, config):
self.protocolFactory = SyncClientFactory(self)
self.ui = UiManager(self, ui)
self.userlist = SyncplayUserlist(self.ui, self)
self._protocol = None
if(args.room == None or args.room == ''):
args.room = constants.DEFAULT_ROOM
self.defaultRoom = args.room
if(config['room'] == None or config['room'] == ''):
config['room'] = constants.DEFAULT_ROOM
self.defaultRoom = config['room']
self.playerPositionBeforeLastSeek = 0.0
self.setUsername(args.name)
self.setRoom(args.room)
if(args.password):
args.password = hashlib.md5(args.password).hexdigest()
self._serverPassword = args.password
if(not args.file):
self.setUsername(config['name'])
self.setRoom(config['room'])
if(config['password']):
config['password'] = hashlib.md5(config['password']).hexdigest()
self._serverPassword = config['password']
if(not config['file']):
self.__getUserlistOnLogon = True
else:
self.__getUserlistOnLogon = False
self._player = None
self._playerClass = playerClass
self._startupArgs = args
self._config = config
self._running = False
self._askPlayerTimer = None
@ -324,7 +324,7 @@ class SyncplayClient(object):
return
self._running = True
if self._playerClass:
self._playerClass.run(self, self._startupArgs.player_path, self._startupArgs.file, self._startupArgs._args)
self._playerClass.run(self, self._config['playerPath'], self._config['file'], self._config['playerArgs'])
self._playerClass = None
self.protocolFactory = SyncClientFactory(self)
reactor.connectTCP(host, port, self.protocolFactory)

View File

@ -1,61 +1,26 @@
from syncplay.client import SyncplayClient
import sys
from syncplay.ui.ConfigurationGetter import ConfigurationGetter, InvalidConfigValue
from syncplay.ui.ConfigurationGetter import ConfigurationGetter
from syncplay import ui
try:
from syncplay.players.mpc import MPCHCAPIPlayer
except ImportError:
MPCHCAPIPlayer = None
from syncplay.players.mplayer import MplayerPlayer
try:
from syncplay.ui.GuiConfiguration import GuiConfiguration
except ImportError:
GuiConfiguration = None
class SyncplayClientManager(object):
def __init__(self):
self._prepareArguments()
self.interface = ui.getUi(graphical=not self.args.no_gui)
self._checkAndSaveConfiguration()
def run(self):
config = ConfigurationGetter().getConfiguration()
interface = ui.getUi(graphical=not config["noGui"])
syncplayClient = None
if(self.argsGetter.playerType == "mpc"):
syncplayClient = SyncplayClient(MPCHCAPIPlayer, self.interface, self.args)
elif(self.argsGetter.playerType == "mplayer"):
syncplayClient = SyncplayClient(MplayerPlayer, self.interface, self.args)
if(config['playerType'] == "mpc"):
syncplayClient = SyncplayClient(MPCHCAPIPlayer, interface, config)
elif(config['playerType'] == "mplayer"):
syncplayClient = SyncplayClient(MplayerPlayer, interface, config)
if(syncplayClient):
self.interface.addClient(syncplayClient)
syncplayClient.start(self.args.host, self.args.port)
interface.addClient(syncplayClient)
syncplayClient.start(config['host'], config['port'])
else:
self.interface.showErrorMessage("Unable to start client")
interface.showErrorMessage("Unable to start client")
def _checkAndSaveConfiguration(self):
try:
self._promptForMissingArguments()
self.argsGetter.saveValuesIntoConfigFile()
except InvalidConfigValue:
self._checkAndSaveConfiguration()
except Exception, e:
print e.message
sys.exit()
def _prepareArguments(self):
self.argsGetter = ConfigurationGetter()
self.args = self.argsGetter.getConfiguration()
def _guiPromptForMissingArguments(self):
if(GuiConfiguration):
self.args = GuiConfiguration(self.args, self.args.force_gui_prompt).getProcessedConfiguration()
def _promptForMissingArguments(self):
if(self.args.no_gui):
if (self.args.host == None):
self.args.host = self.interface.promptFor(prompt="Hostname: ", message="You must supply hostname on the first run, it's easier through command line arguments.")
if (self.args.name == None):
self.args.name = self.interface.promptFor(prompt="Username: ", message="You must supply username on the first run, it's easier through command line arguments.")
if (self.args.player_path == None):
self.args.player_path = self.interface.promptFor(prompt="Player executable: ", message="You must supply path to your player on the first run, it's easier through command line arguments.")
else:
self._guiPromptForMissingArguments()

View File

@ -5,6 +5,7 @@ MPC_OSD_POSITION = 2 #Right corner, 1 for left
MPLAYER_OSD_LEVEL = 1
UI_TIME_FORMAT = "[%X] "
DEFAULT_ROOM = 'default'
DEFAULT_CONFIG_NAME = ".syncplay"
#Changing these might be ok
SEEK_BOUNDARY = 1

View File

@ -1,8 +1,12 @@
import ConfigParser
from ConfigParser import SafeConfigParser
import argparse
import os
import sys
from syncplay import constants
try:
from syncplay.ui.GuiConfiguration import GuiConfiguration
except ImportError:
GuiConfiguration = None
class InvalidConfigValue(Exception):
def __init__(self, message):
@ -10,14 +14,115 @@ class InvalidConfigValue(Exception):
class ConfigurationGetter(object):
def __init__(self):
self._config = None
self._args = None
self._syncplayClient = None
self._configFile = None
self._parser = None
self._configName = ".syncplay"
self.playerType = None
self._config = {
"host": None,
"port": constants.DEFAULT_PORT,
"name": None,
"debug": False,
"forceGuiPrompt": False,
"noGui": False,
"noStore": False,
"room": constants.DEFAULT_ROOM,
"password": None,
"playerPath": None,
"file": None,
"playerArgs": [],
"playerType": None,
}
self._required = [
"host",
"port",
"name",
"playerPath",
"playerType",
]
self._iniStructure = {
"server_data": ["host", "port", "password"],
"client_settings": ["name", "room", "playerPath"]
}
self._argparser = argparse.ArgumentParser(description='Solution to synchronize playback of multiple MPlayer and MPC-HC instances over the network.',
epilog='If no options supplied values from configuration file will be used')
self._argparser.add_argument('--no-gui', action='store_true', help='show no GUI')
self._argparser.add_argument('-a', '--host', metavar='hostname', type=str, help='server\'s address')
self._argparser.add_argument('-n', '--name', metavar='username', type=str, help='desired username')
self._argparser.add_argument('-d', '--debug', action='store_true', help='debug mode')
self._argparser.add_argument('-g', '--force-gui-prompt', action='store_true', help='make configuration prompt appear')
self._argparser.add_argument('--no-store', action='store_true', help='don\'t store values in syncplay.ini')
self._argparser.add_argument('-r', '--room', metavar='room', type=str, nargs='?', help='default room')
self._argparser.add_argument('-p', '--password', metavar='password', type=str, nargs='?', help='server password')
self._argparser.add_argument('--player-path', metavar='path', type=str, help='path to your player executable')
self._argparser.add_argument('file', metavar='file', type=str, nargs='?', help='file to play')
self._argparser.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 _validateArguments(self):
for key in self._required:
if(key == "playerPath"):
if(self._isPlayerMPCAndValid(self._config["playerPath"])):
self._config["playerType"] = "mpc"
self.__addSpecialMPCFlags()
elif(self._isMplayerPathAndValid(self._config["playerPath"])):
self._config["playerType"] = "mplayer"
else:
raise InvalidConfigValue("Player path is not set properly")
elif(key == "host"):
self._config["host"], self._config["port"] = self._splitPortAndHost(self._config["host"])
hostNotValid = (self._config["host"] == "" or self._config["host"] is None)
portNotValid = (self._config["port"] == "" or self._config["port"] is None)
if(hostNotValid or portNotValid):
raise InvalidConfigValue("Hostname can't be empty")
elif(self._config[key] == "" or self._config[key] is None):
raise InvalidConfigValue("{} can't be empty".format(key))
def _overrideConfigWithArgs(self, args):
for key, val in vars(args).items():
if(val):
if(key == "force_gui_prompt"):
key = "forceGuiPrompt"
if(key == "no_store"):
key = "noStore"
if(key == "player_path"):
key = "playerPath"
if(key == "_args"):
key = "playerArgs"
if(key == "no_gui"):
key = "noGui"
self._config[key] = val
def _isPlayerMPCAndValid(self, path):
if(os.path.isfile(path)):
if(path[-10:] == 'mpc-hc.exe' or path[-12:] == 'mpc-hc64.exe'):
return True
if(os.path.isfile(path + "\\mpc-hc.exe")):
path += "\\mpc-hc.exe"
return True
if(os.path.isfile(path + "\\mpc-hc64.exe")):
path += "\\mpc-hc64.exe"
return True
return False
def __addSpecialMPCFlags(self):
self._config['playerArgs'].extend(['/open', '/new'])
def _isMplayerPathAndValid(self, playerPath):
if("mplayer" in playerPath):
if os.access(playerPath, os.X_OK):
return True
for path in os.environ['PATH'].split(':'):
path = os.path.join(os.path.realpath(path), playerPath)
if os.access(path, os.X_OK):
self._config['playerPath'] = path
return True
return False
def _splitPortAndHost(self, host):
port = constants.DEFAULT_PORT if not self._config["port"] else self._config["port"]
if(host):
if ':' in host:
host, port = host.split(':', 1)
return host, int(port)
def _findWorkingDir(self):
frozen = getattr(sys, 'frozen', '')
if not frozen:
@ -30,154 +135,79 @@ class ConfigurationGetter(object):
def _checkForPortableFile(self):
path = self._findWorkingDir()
if(os.path.isfile(os.path.join(path, self._configName))):
return os.path.join(path, self._configName)
if(os.path.isfile(os.path.join(path, constants.DEFAULT_CONFIG_NAME))):
return os.path.join(path, constants.DEFAULT_CONFIG_NAME)
def _getConfigurationFilePath(self):
self._configFile = self._checkForPortableFile()
if(not self._configFile):
configFile = self._checkForPortableFile()
if(not configFile):
if(os.name <> 'nt'):
self._configFile = os.path.join(os.getenv('HOME', '.'), self._configName)
configFile = os.path.join(os.getenv('HOME', '.'), constants.DEFAULT_CONFIG_NAME)
else:
self._configFile = os.path.join(os.getenv('APPDATA', '.'), self._configName)
configFile = os.path.join(os.getenv('APPDATA', '.'), constants.DEFAULT_CONFIG_NAME)
return configFile
def _prepareArgParser(self):
self._parser = argparse.ArgumentParser(description='Solution to synchronize playback of multiple MPlayer and MPC-HC instances over the network.',
epilog='If no options supplied values from .syncplay file will be used')
self._parser.add_argument('--no-gui', action='store_true', help='show no GUI')
self._parser.add_argument('-a', '--host', metavar='hostname', type=str, help='server\'s address')
self._parser.add_argument('-n', '--name', metavar='username', type=str, help='desired username')
self._parser.add_argument('-d', '--debug', action='store_true', help='debug mode')
self._parser.add_argument('-g', '--force-gui-prompt', action='store_true', help='make configuration prompt appear')
self._parser.add_argument('--no-store', action='store_true', help='don\'t store values in syncplay.ini')
self._parser.add_argument('-r', '--room', metavar='room', type=str, nargs='?', help='default room')
self._parser.add_argument('-p', '--password', metavar='password', type=str, nargs='?', help='server password')
self._parser.add_argument('--player-path', metavar='path', type=str, help='path to your player executable')
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(self._configFile)
def _getSectionName(self):
return 'sync' if not self._args.debug else 'debug'
def saveValuesIntoConfigFile(self):
self._splitPortAndHost()
self._openConfigFile()
section_name = self._getSectionName()
self._validateArguments()
if(not self._args.no_store):
with open(self._configFile, 'wb') as configfile:
if(not self._config.has_section(section_name)):
self._config.add_section(section_name)
self._config.set(section_name, 'host', self._args.host+":"+str(self._args.port))
self._config.set(section_name, 'name', self._args.name)
self._config.set(section_name, 'room', self._args.room)
self._config.set(section_name, 'password', self._args.password)
self._config.set(section_name, 'player_path', self._args.player_path)
self._config.write(configfile)
def _validateArguments(self):
if(not (self._args.host <> "" and self._args.host is not None)):
self._args.host = None
raise InvalidConfigValue("Hostname can't be empty")
if(not (self._args.name <> "" and self._args.name is not None)):
self._args.name = None
raise InvalidConfigValue("Username can't be empty")
if(self._isPlayerMPCAndValid()):
self._addSpecialMPCFlags()
self.playerType = "mpc"
elif(self._isMplayerPathValid()):
self.playerType = "mplayer"
else:
self._args.player_path = None
raise InvalidConfigValue('Path to player is not valid')
def _parseConfigFile(self, iniPath):
parser = SafeConfigParser()
parser.read(iniPath)
for section, options in self._iniStructure.items():
if(parser.has_section(section)):
for option in options:
if(parser.has_option(section, option)):
self._config[option] = parser.get(section, option)
def _readConfigValue(self, section_name, name):
def _checkConfig(self):
try:
return self._config.get(section_name, name)
except ConfigParser.NoOptionError:
return None
def _readMissingValuesFromConfigFile(self):
self._openConfigFile()
section_name = self._getSectionName()
try:
self._valuesToReadFromConfig(section_name)
except ConfigParser.NoSectionError:
pass
self._validateArguments()
except InvalidConfigValue:
try:
for key, value in self._promptForMissingArguments().items():
self._config[key] = value
self._checkConfig()
except:
sys.exit()
def _isPlayerMPCAndValid(self):
if(os.path.isfile(self._args.player_path)):
if(self._args.player_path[-10:] == 'mpc-hc.exe' or self._args.player_path[-12:] == 'mpc-hc64.exe'):
return True
if(os.path.isfile(self._args.player_path + "\\mpc-hc.exe")):
self._args.player_path += "\\mpc-hc.exe"
return True
if(os.path.isfile(self._args.player_path + "\\mpc-hc64.exe")):
self._args.player_path += "\\mpc-hc64.exe"
return True
return False
def _promptForMissingArguments(self):
if(self._config['noGui']):
print "Some necessary arguments are missing, refer to --help"
sys.exit()
elif(GuiConfiguration):
return GuiConfiguration(self._config).getProcessedConfiguration()
def _addSpecialMPCFlags(self):
self._args._args.extend(['/open', '/new'])
def _isMplayerPathValid(self):
if("mplayer" in self._args.player_path):
if os.access(self._args.player_path, os.X_OK):
return True
for path in os.environ['PATH'].split(':'):
path = os.path.join(os.path.realpath(path), self._args.player_path)
if os.access(path, os.X_OK):
self._args.player_path = path
return True
return False
def _valuesToReadFromConfig(self, section_name):
if (self._args.host == None):
self._args.host = self._readConfigValue(section_name, 'host')
if (self._args.name == None):
self._args.name = self._readConfigValue(section_name, 'name')
if (self._args.room == None):
self._args.room = self._readConfigValue(section_name, 'room')
if (self._args.password == None):
self._args.password = self._readConfigValue(section_name, 'password')
if (self._args.player_path == None):
self._args.player_path = self._readConfigValue(section_name, 'player_path')
def _splitPortAndHost(self):
if(self._args.host):
if ':' in self._args.host:
self._args.host, port = self._args.host.split(':', 1)
self._args.port = int(port)
elif("port" not in self._args):
self._args.port = constants.DEFAULT_PORT
def setConfiguration(self, args):
self._args = args
def _saveConfig(self, iniPath):
parser = SafeConfigParser()
for section, options in self._iniStructure.items():
if(not parser.has_section(section)):
parser.add_section(section)
for option in options:
parser.set(section, option, str(self._config[option]))
parser.write(file(iniPath, "w"))
def getConfiguration(self):
self._getConfigurationFilePath()
self._prepareArgParser()
self._args = self._parser.parse_args()
self._readMissingValuesFromConfigFile()
self._splitPortAndHost()
return self._args
iniPath = self._getConfigurationFilePath()
self._parseConfigFile(iniPath)
args = self._argparser.parse_args()
self._overrideConfigWithArgs(args)
if(self._config['forceGuiPrompt']):
try:
self._promptForMissingArguments()
except:
sys.exit()
self._checkConfig()
self._saveConfig(iniPath)
return self._config
class ServerConfigurationGetter(ConfigurationGetter):
class ServerConfigurationGetter(object):
def getConfiguration(self):
self._prepareArgParser()
self._args = self._parser.parse_args()
self._args = self._argparser.parse_args()
if(self._args.port == None):
self._args.port = constants.DEFAULT_PORT
return self._args
def _prepareArgParser(self):
self._parser = argparse.ArgumentParser(description='Solution to synchronize playback of multiple MPlayer and MPC-HC instances over the network. Server instance',
self._argparser = argparse.ArgumentParser(description='Solution to synchronize playback of multiple MPlayer and MPC-HC instances over the network. Server instance',
epilog='If no options supplied _config values will be used')
self._parser.add_argument('--port', metavar='port', type=str, nargs='?', help='server TCP port')
self._parser.add_argument('--password', metavar='password', type=str, nargs='?', help='server password')
self._parser.add_argument('--isolate-rooms', action='store_true', help='should rooms be isolated?')
self._argparser.add_argument('--port', metavar='port', type=str, nargs='?', help='server TCP port')
self._argparser.add_argument('--password', metavar='password', type=str, nargs='?', help='server password')
self._argparser.add_argument('--isolate-rooms', action='store_true', help='should rooms be isolated?')

View File

@ -7,68 +7,64 @@ gtk.set_interactive(False)
import cairo, gio, pango, atk, pangocairo, gobject #@UnusedImport
class GuiConfiguration:
def __init__(self, args, force=False):
self.args = args
def __init__(self, config):
self.config = config
self.closedAndNotSaved = False
if(args.player_path == None or args.host == None or args.name == None or force):
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_title("Syncplay Configuration")
self.window.connect("delete_event", lambda w, e: self._windowClosed())
vbox = gtk.VBox(False, 0)
self.window.add(vbox)
vbox.show()
self._addLabeledEntries(args, vbox)
self.hostEntry.select_region(0, len(self.hostEntry.get_text()))
button = gtk.Button(stock=gtk.STOCK_SAVE)
button.connect("clicked", lambda w: self._saveDataAndLeave())
vbox.pack_start(button, True, True, 0)
button.set_flags(gtk.CAN_DEFAULT)
button.grab_default()
button.show()
self.window.show()
gtk.main()
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_title("Syncplay Configuration")
self.window.connect("delete_event", lambda w, e: self._windowClosed())
vbox = gtk.VBox(False, 0)
self.window.add(vbox)
vbox.show()
self._addLabeledEntries(config, vbox)
self.hostEntry.select_region(0, len(self.hostEntry.get_text()))
button = gtk.Button(stock=gtk.STOCK_SAVE)
button.connect("clicked", lambda w: self._saveDataAndLeave())
vbox.pack_start(button, True, True, 0)
button.set_flags(gtk.CAN_DEFAULT)
button.grab_default()
button.show()
self.window.show()
gtk.main()
def _windowClosed(self):
self.window.destroy()
gtk.main_quit()
self.closedAndNotSaved = True
def _addLabeledEntries(self, args, vbox):
if(args.host == None):
def _addLabeledEntries(self, config, vbox):
if(config['host'] == None):
host = ""
elif(":" in args.host):
host = args.host
elif("port" in args):
host = args.host+":"+str(args.port)
elif(":" in config['host']):
host = config['host']
else:
host = args.host
self.hostEntry = self._addLabeledEntryToVbox('Host: ', host, vbox, lambda __, _: self._saveDataAndLeave())
self.userEntry = self._addLabeledEntryToVbox('Username: ', args.name, vbox, lambda __, _: self._saveDataAndLeave())
self.roomEntry = self._addLabeledEntryToVbox('Default room (optional): ', args.room, vbox, lambda __, _: self._saveDataAndLeave())
self.passEntry = self._addLabeledEntryToVbox('Server password (optional): ', args.password, vbox, lambda __, _: self._saveDataAndLeave())
self._tryToFillUpMpcPath()
self.mpcEntry = self._addLabeledEntryToVbox('Path to player executable: ', self.args.player_path, vbox, lambda __, _: self._saveDataAndLeave())
host = config['host']+":"+str(config['port'])
def _tryToFillUpMpcPath(self):
if(self.args.player_path == None):
self.hostEntry = self._addLabeledEntryToVbox('Host: ', host, vbox, lambda __, _: self._saveDataAndLeave())
self.userEntry = self._addLabeledEntryToVbox('Username: ', config['name'], vbox, lambda __, _: self._saveDataAndLeave())
self.roomEntry = self._addLabeledEntryToVbox('Default room (optional): ', config['room'], vbox, lambda __, _: self._saveDataAndLeave())
self.passEntry = self._addLabeledEntryToVbox('Server password (optional): ', config['password'], vbox, lambda __, _: self._saveDataAndLeave())
self.mpcEntry = self._addLabeledEntryToVbox('Path to player executable: ', self._tryToFillUpMpcPath(config['playerPath']), vbox, lambda __, _: self._saveDataAndLeave())
def _tryToFillUpMpcPath(self, playerPath):
if(playerPath == None):
for path in constants.MPC_PATHS:
if(os.path.isfile(path)):
self.args.player_path = path
return
return path
return playerPath
def getProcessedConfiguration(self):
if(self.closedAndNotSaved):
raise self.WindowClosed
return self.args
return self.config
def _saveDataAndLeave(self):
self.args.host = self.hostEntry.get_text()
self.args.name = self.userEntry.get_text()
self.args.room = self.roomEntry.get_text()
self.args.password = self.passEntry.get_text()
self.args.player_path = self.mpcEntry.get_text()
self.config['host'] = self.hostEntry.get_text()
self.config['name'] = self.userEntry.get_text()
self.config['room'] = self.roomEntry.get_text()
self.config['password'] = self.passEntry.get_text()
self.config['playerPath'] = self.mpcEntry.get_text()
self.window.destroy()
gtk.main_quit()

View File

@ -2,4 +2,4 @@
from syncplay.clientManager import SyncplayClientManager
if(__name__ == '__main__'):
SyncplayClientManager()
SyncplayClientManager().run()