Created
August 14, 2014 03:32
-
-
Save meoow/4fd695a7cfaf1b429b3a to your computer and use it in GitHub Desktop.
Simple GUI for xunlei-lixian
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python2.7 | |
| from PyQt4.QtCore import SIGNAL, pyqtSignal, QObject, QString | |
| from PyQt4.QtGui import (QApplication, QDialog, | |
| QTextBrowser, QPushButton, QVBoxLayout, | |
| QLineEdit, QGridLayout, QTextCursor, | |
| QLabel, QHBoxLayout, QFileDialog, | |
| QCheckBox , QSizePolicy , QSpacerItem, | |
| QGroupBox, QComboBox, QSpinBox) | |
| import sys,os,re | |
| import subprocess as subp | |
| import platform as pf | |
| import getopt | |
| import argparse | |
| from lixian_config import Config, LIXIAN_DEFAULT_CONFIG | |
| #from lixian_cli import execute_command as lx_exec | |
| #sys.stderr = codecs.lookup('utf-8')[-1](sys.stderr) | |
| class EmitStream(QObject): | |
| textWritten = pyqtSignal(str) | |
| def write(self, text): | |
| self.textWritten.emit(text.decode('gbk')) | |
| class Form(QDialog): | |
| def __init__(self,parent=None): | |
| super(Form, self).__init__(parent) | |
| # self.stdout = EmitStream(textWritten=self.textOutput) | |
| # sys.stderr = EmitStream(textWritten=self.textOutputErr) | |
| self.pyInterpreDict = {'Linux':'python2.7','Windows':'python.exe'} | |
| self.lx_exec = '{0} lixian_cli.py'.format(self.pyInterpreDict.get(pf.system(),'python2')) | |
| self.matchCompletedTask = re.compile(r' completed$') | |
| self.toolList = [u'aria2',u'wget',u'asyn'] | |
| self.lxConfig = Config(LIXIAN_DEFAULT_CONFIG) | |
| savedDir = self.lxConfig.get('output-dir') | |
| if savedDir is None: | |
| savedDir = os.environ['HOME'] | |
| continue_ = self.lxConfig.get('continue') | |
| delete_ = self.lxConfig.get('delete') | |
| tool_ = self.lxConfig.get('tool') | |
| aria2opts = self.lxConfig.get("aria2-opts") | |
| #addTaskBtnGrp = QButtonGroup() | |
| addTaskButton = QPushButton(u"Add &Task") | |
| addTaskButton.setFixedWidth(86) | |
| addBtTaskButton = QPushButton(u'BT File') | |
| #addTaskBtnGrp.addButton(addTaskButton,1) | |
| #addTaskBtnGrp.addButton(addBtTaskButton,2) | |
| downloadButton = QPushButton(u'&Go') | |
| downloadButton.setFixedWidth(86) | |
| addConfigButton = QPushButton(u'Add &Config') | |
| addConfigButton.setFixedWidth(86) | |
| listButton = QPushButton(u'&List') | |
| listButton.setFixedWidth(86) | |
| deleteButton = QPushButton(u'&Delete') | |
| deleteButton.setFixedWidth(86) | |
| clearButton = QPushButton(u'&Clear') | |
| clearButton.setFixedWidth(86) | |
| outputDirBrButton = QPushButton(u'&Browse') | |
| outputDirBrButton.setFixedWidth(86) | |
| self.taskLine = QLineEdit() | |
| self.downloadLine = QLineEdit() | |
| self.configLine = QLineEdit() | |
| self.deleteLine = QLineEdit() | |
| self.outputDirLine = QLineEdit() | |
| configToggleSpacerItem=QSpacerItem(1,1,QSizePolicy.Expanding) | |
| self.continueCheckBox = QCheckBox(u'Continue') | |
| self.deleteCheckBox = QCheckBox(u'Delete') | |
| toolLabel = QLabel(u'Tool:') | |
| self.toolComboBox = QComboBox() | |
| self.toolComboBox.addItems(self.toolList) | |
| # self.toolLineEdit.setMaximumWidth(50) | |
| serversLabel = QLabel(u'Servers:') | |
| connectionsLabel = QLabel(u'Connections:') | |
| self.toolxSpinBox = QSpinBox() | |
| self.toolxSpinBox.setRange(1,16) | |
| self.toolsSpinBox = QSpinBox() | |
| self.toolsSpinBox.setRange(1,16) | |
| taskLabel = QLabel(u'URL: ') | |
| downLabel = QLabel(u'Download: ') | |
| outputDirLabel = QLabel(u'Output Dir: ') | |
| blankLabel = QLabel() | |
| configLineLayout = QHBoxLayout() | |
| deleteLineLayout = QHBoxLayout() | |
| configLineLayout.addWidget(self.configLine) | |
| configLineLayout.addWidget(addConfigButton) | |
| deleteLineLayout.addWidget(self.deleteLine) | |
| deleteLineLayout.addWidget(deleteButton) | |
| self.taskLine.setMinimumWidth(300) | |
| operationAeraLayout = QGridLayout() | |
| operationAeraLayout.addWidget(taskLabel,0,0) | |
| operationAeraLayout.addWidget(self.taskLine,0,1) | |
| operationAeraLayout.addWidget(addTaskButton,0,2) | |
| operationAeraLayout.addWidget(downLabel,1,0) | |
| operationAeraLayout.addWidget(self.downloadLine,1,1) | |
| operationAeraLayout.addWidget(downloadButton,1,2) | |
| operationAeraLayout.addWidget(outputDirLabel,2,0) | |
| operationAeraLayout.addWidget(self.outputDirLine,2,1) | |
| operationAeraLayout.addWidget(outputDirBrButton,2,2) | |
| configToggleGrpBox = QGroupBox('Configuration') | |
| configToggleLayout = QHBoxLayout(configToggleGrpBox) | |
| configToggleLayout.addWidget(self.continueCheckBox) | |
| configToggleLayout.addWidget(self.deleteCheckBox) | |
| configToggleLayout.addWidget(toolLabel) | |
| configToggleLayout.addWidget(self.toolComboBox) | |
| configToggleLayout.addWidget(connectionsLabel) | |
| configToggleLayout.addWidget(self.toolsSpinBox) | |
| configToggleLayout.addWidget(serversLabel) | |
| configToggleLayout.addWidget(self.toolxSpinBox) | |
| configToggleLayout.addItem(configToggleSpacerItem) | |
| configToggleLayout.addStretch() | |
| cfgDltLstClrLayout = QGridLayout() | |
| cfgDltLstClrLayout.addLayout(configLineLayout,0,0) | |
| cfgDltLstClrLayout.addWidget(listButton,0,1) | |
| cfgDltLstClrLayout.addWidget(blankLabel,0,2) | |
| cfgDltLstClrLayout.addLayout(deleteLineLayout,1,0) | |
| cfgDltLstClrLayout.addWidget(clearButton,1,1) | |
| cfgDltLstClrLayout.addWidget(blankLabel,1,2) | |
| self.fuckTextBrsr = QTextBrowser() | |
| layout = QVBoxLayout() | |
| layout.addLayout(operationAeraLayout) | |
| layout.addWidget(configToggleGrpBox) | |
| layout.addLayout(cfgDltLstClrLayout) | |
| layout.addWidget(self.fuckTextBrsr) | |
| self.setLayout(layout) | |
| self.setWindowTitle('Offline Thunder Downloader for TriMeow Church') | |
| self.osQuoteDict = {'Linux':"'","Windows":'"'} | |
| self.codecDict = {'Linux':'utf-8', 'Windows':'gbk'} | |
| self.outputDirLine.setText(savedDir) | |
| if continue_: | |
| self.continueCheckBox.setChecked(1) | |
| if delete_: | |
| self.deleteCheckBox.setChecked(1) | |
| connectionsNum, serversNum, dummy = self.parseAria2Opts(aria2opts) | |
| self.toolxSpinBox.setValue(connectionsNum) | |
| self.toolsSpinBox.setValue(serversNum) | |
| self.toolComboBox.setCurrentIndex(self.toolList.index(tool_ or 'aria2')) | |
| self.saveConfig() | |
| self.connect(addTaskButton,SIGNAL('clicked()'),self.addURLTask) | |
| self.connect(downloadButton,SIGNAL('clicked()'),self.download) | |
| self.connect(addConfigButton,SIGNAL('clicked()'),self.addConfig) | |
| self.connect(listButton, SIGNAL('clicked()'),self.listFile) | |
| self.connect(deleteButton, SIGNAL('clicked()'),self.deleteTask) | |
| self.connect(clearButton, SIGNAL('clicked()'),self.clearOutput) | |
| self.connect(outputDirBrButton, SIGNAL('clicked()'),self.browseDir) | |
| self.connect(self.continueCheckBox, SIGNAL('stateChanged(int)'), self.toggleContinue) | |
| self.connect(self.deleteCheckBox, SIGNAL('stateChanged(int)'), self.toggleDelete) | |
| self.connect(self.toolxSpinBox, SIGNAL('valueChanged(int)'), self.changeSoX) | |
| self.connect(self.toolsSpinBox, SIGNAL('valueChanged(int)'),self.changeSoX) | |
| self.connect(self.toolComboBox, SIGNAL('currentIndexChanged(int)'),self.changeTool) | |
| def changeSoX(self,verbose=True): | |
| dumm1, dumm2, args = self.parseAria2Opts(self.lxConfig.get('aria2-opts')) | |
| self.lxConfig.put('aria2-opts',' '.join( args+['-x',str(self.toolxSpinBox.value()),'-s',str(self.toolsSpinBox.value())])) | |
| return | |
| def changeTool(self): | |
| self.lxConfig.put('tool',self.toolList[self.toolComboBox.currentIndex()]) | |
| def toggleContinue(self,verbose=True): | |
| if self.continueCheckBox.isChecked(): | |
| self.lxConfig.put('continue') | |
| else: | |
| self.lxConfig.delete('continue') | |
| return | |
| def toggleDelete(self,verbose=True): | |
| if self.deleteCheckBox.isChecked(): | |
| self.lxConfig.put('delete') | |
| else: | |
| self.lxConfig.delete('delete') | |
| return | |
| def addConfig(self): | |
| infos, exitStatus = self.commandString2Pipe('{0} config {1}'.format(self.lx_exec, unicode(self.configLine.text()))) | |
| self.htmlOutput('<font color=darkblue>{0}</font>'.format(infos)) | |
| if exitStatus is None: | |
| self.configLine.clear() | |
| def download(self): | |
| result = subp.call('{0} download {1}'.format(self.lx_exec, unicode(self.downloadLine.text())),shell=True) | |
| if not result.real: | |
| self.downloadLine.clear() | |
| return | |
| def addURLTask(self): | |
| infos, exitStatus = self.commandString2Pipe('''{0} add {2}{1}{2}'''.format(self.lx_exec, unicode(self.taskLine.text()),self.osQuoteDict.get(pf.system(),"'"))) | |
| self.textOutput(infos) | |
| if exitStatus is None: | |
| self.taskLine.clear() | |
| return | |
| def addBTTask(self): | |
| fileName = unicode(QFileDialog.getOpenFileName(self,"choose bt file")) | |
| if fileName: | |
| self.taskLine.setText(fileName) | |
| infos, exitStatus = self.commandString2Pipe('''{0} add --bt {2}{1}{2}'''.format(self.lx_exec, fileName, self.osQuoteDict.get(pf.system(),"'"))) | |
| self.textOutput(infos) | |
| if exitStatus is None: | |
| self.taskLine.clear() | |
| return | |
| def listFile(self): | |
| self.fuckTextBrsr.clear() | |
| infos, exitStatus = self.commandString2Pipe('{0} list'.format(self.lx_exec)) | |
| infoLines = infos.split('\n') | |
| for index, line in enumerate(infoLines): | |
| if not self.matchCompletedTask.search(line): | |
| infoLines[index] = u'<i>{0}</i>'.format(line) | |
| self.htmlOutput('<br>'.join(infoLines)) | |
| return | |
| def browseDir(self): | |
| dirName = unicode(QFileDialog.getExistingDirectory(self)) | |
| if dirName: | |
| self.outputDirLine.setText(dirName) | |
| infos, exitStatus = self.commandString2Pipe('{0} config output-dir={2}{1}{2}'.format(self.lx_exec, unicode(self.outputDirLine.text()), self.osQuoteDict.get(pf.system(),"'") )) | |
| self.htmlOutput('<font color=darkblue>{0}</font><br>'.format(infos)) | |
| def deleteTask(self): | |
| infos, exitStatus = self.commandString2Pipe('{0} delete {1}'.format(self.lx_exec,unicode(self.deleteLine.text()))) | |
| self.textOutput(infos) | |
| if exitStatus is None: | |
| self.deleteLine.clear() | |
| def commandString2Pipe(self,text): | |
| cmdPipe = os.popen(text) | |
| return (''.join(x.decode(self.codecDict.get(pf.system(),'utf-8')) for x in cmdPipe.readlines()), cmdPipe.close()) | |
| def textOutput(self,text): | |
| self.fuckTextBrsr.moveCursor(QTextCursor.End) | |
| self.fuckTextBrsr.insertPlainText(u'{0}\n'.format(text)) | |
| self.fuckTextBrsr.moveCursor(QTextCursor.End) | |
| def htmlOutput(self,text): | |
| self.fuckTextBrsr.moveCursor(QTextCursor.End) | |
| self.fuckTextBrsr.insertHtml(u'{0}\n'.format(text)) | |
| self.fuckTextBrsr.moveCursor(QTextCursor.End) | |
| def textOutputErr(self, text): | |
| self.fuckTextBrsr.moveCursor(QTextCursor.End) | |
| self.fuckTextBrsr.insertHtml('<font color=red>{0}</font><br>'.format(text)) | |
| self.fuckTextBrsr.moveCursor(QTextCursor.End) | |
| def clearOutput(self): | |
| self.fuckTextBrsr.clear() | |
| # def parseAria2Opts(self,args): | |
| # try: | |
| # opts, args = getopt.getopt(re.split(r'\s+|=',args),'x:s:',['max-connection-per-server','split']) | |
| # except getopt.GetoptError: | |
| # pass | |
| # for o,a in opts: | |
| # if o in ('-x','--max-connection-per-server'): | |
| # x=int(a) | |
| # elif o in ('-s','--split'): | |
| # s=int(a) | |
| # return x,s | |
| def parseAria2Opts(self,args): | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument('-x','--max-connection-per-server',dest='x', | |
| type=int,default=10) | |
| parser.add_argument('-s','--split',dest='s',type=int,default=10) | |
| opts, args = parser.parse_known_args(re.split(r'\s+|=',args or "")) | |
| return opts.x, opts.s, args | |
| def saveConfig(self): | |
| continue_ = self.continueCheckBox.isChecked() | |
| delete_ = self.deleteCheckBox.isChecked() | |
| tool = self.toolList[self.toolComboBox.currentIndex()] | |
| if continue_: | |
| self.lxConfig.put('continue') | |
| else: | |
| self.lxConfig.delete('continue') | |
| if delete_: | |
| self.lxConfig.put('delete') | |
| else: | |
| self.lxConfig.delete('delete') | |
| self.lxConfig.put('tool',tool) | |
| self.lxConfig.put('output-dir',self.outputDirLine.text()) | |
| self.changeSoX() | |
| return | |
| if __name__ == '__main__': | |
| import sys,os | |
| if sys.version_info[0] != 2: | |
| raise SystemExit('Must use Python 2 series') | |
| if os.isatty(sys.stdout.fileno()): | |
| app = QApplication(sys.argv) | |
| form = Form() | |
| form.show() | |
| form.exec_() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment