# -*- coding:utf-8 -*- import configparser import os import pathlib import re import subprocess import sys import time from configparser import ExtendedInterpolation # import winreg from subprocess import Popen import psutil import pymysql import requests from PyQt5.QtCore import pyqtSignal, QThread from PyQt5.QtGui import QTextCursor from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox # 界面文件为 mainui.py from mainui import * configFile = 'config.ini' # 创建配置文件对象 config = configparser.ConfigParser(interpolation=ExtendedInterpolation(), inline_comment_prefixes=['#', ';'], allow_no_value=True) # 读取配置文件 config.read(configFile, encoding='utf-8') class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) self.apktool_path = config['TOOL_PATH']['apktool_path'] self.android_name = config['ANDROID']['android_name'] self.android_name_file = config['ANDROID']['android_name_file'] self.tmp_android_name = config['ANDROID']['tmp_android_name'] self.new_android_name = config['ANDROID']['new_android_name'] # 初始赋值 self.nowIpLabel.setText(config['GAME']['now_ip']) self.newIpInput.setText(config['GAME']['new_ip']) self.nowGameLabel.setText(config['GAME']['game_name']) self.newGameInput.setText(config['GAME']['game_name']) # 设置按钮状态 if not config.has_section('NGINX'): self.nginxButton.setDisabled(True) else: if isinstance(checkprocess("nginx.exe"), int): self.nginxButton.setText("关闭Nginx") else: self.nginxButton.setText("启动Nginx") if not config.has_section('MYSQL'): self.mysqlButton.setDisabled(True) else: if isinstance(checkprocess("mysqld.exe"), int): self.mysqlButton.setText("关闭MySql") else: self.mysqlButton.setText("启动MySql") if not config.has_section('WEB'): self.gmurlButton.setDisabled(True) self.yyurlButton.setDisabled(True) else: self.gmurlButton.setToolTip("

网址:" + config['WEB']['gm_url'] + "
帐号:" + config['WEB']['gm_user'] + "
密码:" + config['WEB']['gm_pass'] + "
校验码:" + config['WEB']['gm_code'] + "

") self.yyurlButton.setToolTip("

网址:" + config['WEB']['game_url'] + "
帐号:" + config['WEB']['game_user'] + "
密码:" + config['WEB']['game_pass'] + "
校验码:" + config['WEB']['game_code'] + "

") if config.has_section('ANDROID'): self.fanbianyiButton.setToolTip("反编译的APK路径:
" + config['ANDROID']['android_name'] + "
反编译后的文件路径:
" + config['ANDROID']['android_name_file']) self.shengchengButton.setToolTip("生成的APK路径:
" + config['ANDROID']['tmp_android_name']) self.qianmingButton.setToolTip("签名后的APK路径:
" + config['ANDROID']['new_android_name'] + "
密钥路径:
" + config['TOOL_PATH']['apktool_path'] + "key.keystore") # 初始化JAVA配置 if not os.getenv('JAVA_HOME'): java_path = config['TOOL_PATH']['java_path'] os.environ['JAVA_HOME'] = java_path os.environ['path'] = os.getenv('path') + java_path + 'bin;' + java_path + 'jre\\bin;' os.environ['CLASSPATH'] = java_path + 'bin;' + java_path + 'lib\\dt.jar;' + java_path + 'lib\\tools.jar;' # print(os.getenv('JAVA_HOME')) # print(os.getenv('CLASSPATH')) # print(os.getenv('path')) def saveSet(self, event): print('保存设置,按钮被单击') message = QMessageBox.information(self, "提示信息", "确定要保存设置吗?", QMessageBox.Ok | QMessageBox.No, QMessageBox.No) if message == QMessageBox.No: return # 取值 now_ip = config['GAME']['now_ip'] new_ip = self.newIpInput.text() now_game = config['GAME']['game_name'] new_game = self.newGameInput.text() compile_ip = re.compile('^(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|[1-9])\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)$') # 验证IP地址格式 if (new_ip == "") or new_game == "" or not (compile_ip.match(new_ip)): QMessageBox.information(self, "提示信息", "IP地址、游戏名称为空或有误,请正确填写IPv4地址或游戏名称!") return # 处理SQL语句 if config.has_section('GAME_DATA_SQL'): sqls = [] for key, value in config.items('GAME_DATA_SQL'): print(key, value) sql = value.replace('~【game_ip】~', new_ip) sql = sql.replace('~【game_name】~', new_game) sqls.append(sql) print(key, sql) # 判断MYSQL是否启动 if sqls: if isinstance(checkprocess("mysqld.exe"), int): mysql_run(sqls) else: message = QMessageBox.information(self, "提示信息", "MYSQL尚未启动,数据库相关脚本无法执行,是否现在启动MYSQL?", QMessageBox.Ok | QMessageBox.No, QMessageBox.Ok) if message == QMessageBox.Ok: self.mysql(self.mysqlButton) # 触发MYSQL启动按钮 sum = 0 # 以0.5秒的频次检测MYSQL是否启动,超过20次则超时 while not isinstance(checkprocess("mysqld.exe"), int): if sum > 20: QMessageBox.information(self, "提示信息", "MYSQL启动失败,请重新尝试!") return time.sleep(0.5) sum = sum + 1 mysql_run(sqls) else: return # 配置文件处理 sum = 0 for key, value in config.items('GAME_FILE_PATH'): print(key, value) # 处理文件编码 if len(value.split(",")) < 2: code = config['GAME']['file_encoding'] else: code = value.split(",")[1] filename = value.split(",")[0] # 执行文件内容替换 try: with open(filename, 'rt+', encoding=code) as f: t = f.read() t = t.replace(now_ip, new_ip) t = t.replace(now_game, new_game) # 读写偏移位置移到最开始处 f.seek(0, 0) f.write(t) # 设置文件结尾 EOF f.truncate() sum = sum + 1 except: QMessageBox.information(self, "提示信息", "替换“" + filename + "”出错,可能文件不存在或编码不对,请检查需要替换的文件编码与配置文件编码是否相符!") return # 写入配置文件 config.set('GAME', 'game_name', new_game) config.set('GAME', 'now_ip', new_ip) config.set('GAME', 'new_ip', new_ip) saveconfig = open(configFile, 'wt', encoding=config['GAME']['file_encoding']) config.write(saveconfig) # 把要修改的节点的内容写到文件中 saveconfig.close() # 设置按钮文字变化 self.nowGameLabel.setText(new_game) self.nowIpLabel.setText(new_ip) # 成功提示 QMessageBox.information(self, "提示信息", "配置保存成功!重启游戏后生效!
游戏名称:" + new_game + "----游戏IP:" + new_ip + "
共配置了" + str(sum) + "个文件") print('修改完成:' + new_game + ':' + new_ip) def nginx(self, event): if self.nginxButton.text() == '启动Nginx': Popen('start .\\nginx.exe', shell=True, cwd=config['NGINX']['nginx_path'], # encoding='utf-8' ) Popen( config['PHP']['php_spawner_path'] + 'php-cgi-spawner.exe "' + config['PHP']['php_path'] + 'php-cgi.exe -c ' + config['PHP']['php_path'] + 'php.ini" ' + config['PHP']['php_cgi_port'] + ' 1+16', shell=True, # cwd=config['GAME']['dir'] + 'phpstudy_pro', # encoding='utf-8' ) self.nginxButton.setText("关闭Nginx") else: nginx_process = Popen('.\\nginx.exe -s stop', shell=True, cwd=config['NGINX']['nginx_path'], # encoding='utf-8' ) spawner_process = Popen('taskkill /f /t /im php-cgi-spawner.exe', shell=True, # encoding='utf-8' ) PHP_process = Popen('taskkill /f /t /im php-cgi.exe', shell=True, # encoding='utf-8' ) self.nginxButton.setText("启动Nginx") # print(process) # os.chdir("D:\\LYserver\\phpstudy_pro\\Extensions\\Nginx1.15.11") # nginxtype = os.system('start .\\nginx.exe') # 不弹出界面 # if nginxtype # os.system('start .\\nginx.exe') #弹出界面 print('启动Nginx,按钮被单击') def mysql(self, event): if self.mysqlButton.text() == '启动MySql': Popen('.\\mysqld.exe', shell=True, cwd=config['MYSQL']['mysql_path'] + 'bin', # encoding='utf-8' ) self.mysqlButton.setText("关闭MySql") else: Popen('taskkill /f /t /im mysqld.exe', shell=True, # encoding='utf-8' ) self.mysqlButton.setText("启动MySql") print('启动MySql,按钮被单击') def game(self, event): if self.gameButton.text() == '启动游戏': # 读取游戏启动路径 for key, value in config.items('GAME_PATH'): print(key, value) # 处理启动时间 if len(value.split(",")) < 2: sleeptime = 0 else: sleeptime = float(value.split(",")[1]) game_file = value.split(",")[0] try: Popen('start ' + game_file, shell=True, # cwd=values, # encoding='utf-8' ) time.sleep(float(sleeptime)) # 延迟启动时间 except: QMessageBox.information(self, "提示信息", "启动“" + game_file + "”出错,可能文件不存在或配置不对!") return self.gameButton.setText("关闭游戏") else: # 读取游戏启动路径 for key, value in config.items('GAME_PATH'): print(key, value) # 获取进程名称并结束进程 game_file = value.split(",")[0].split("\\") game_file = game_file[len(game_file) - 1] try: Popen( 'taskkill /f /t /im ' + game_file, shell=True, # encoding='utf-8' ) except: QMessageBox.information(self, "提示信息", "关闭游戏进程:“" + game_file + "”出错!") return # Popen( # 'taskkill /f /t /im LocalLogServer64_R.exe & taskkill /f /t /im LoggerServer64_R.exe & taskkill /f /t /im SessionServer64_R.exe & taskkill /f /t /im NameServer64_R.exe & taskkill /f /t /im LogicServerCQ64_R.exe & taskkill /f /t /im GateServer64_R.exe & taskkill /f /t /im DBCenterServer64_R.exe & taskkill /f /t /im DBServer64_R.exe & taskkill /f /t /im BackStageServer64_R.exe & taskkill /f /t /im AMServer64_R.exe', # shell=True, # # encoding='utf-8' # ) self.gameButton.setText("启动游戏") print('启动游戏,按钮被单击') def fanbianyi(self, event): obj = self.fanbianyiButton # obj.setText('运行中') title = obj.text() cmd = 'apktool d ' + self.android_name + ' -f -o ' + self.android_name_file cwd = self.apktool_path code = "gbk" path = self.android_name_file self.add_cmd_msg(cmd, cwd, title, obj, path, code) print('反编译APK,按钮被单击') def shengcheng(self, event): obj = self.shengchengButton # obj.setText('运行中') title = obj.text() cmd = 'apktool b ' + self.android_name_file + ' -o ' + self.tmp_android_name cwd = self.apktool_path code = "gbk" path = self.tmp_android_name self.add_cmd_msg(cmd, cwd, title, obj, path, code) print('生成APK,按钮被单击') def qianming(self, event): obj = self.qianmingButton # obj.setText('运行中') title = obj.text() cmd = 'jarsigner -verbose -keystore key.keystore -storepass 123456 -signedjar ' + self.new_android_name + ' ' + self.tmp_android_name + ' key.keystore' cwd = self.apktool_path code = "gbk" path = self.new_android_name self.add_cmd_msg(cmd, cwd, title, obj, path, code) print('APK签名,按钮被单击') def heidisql(self, event): cmd = 'start "" ' + config['TOOL_PATH']['heidisql_path'] Popen(cmd, shell=True, # cwd=config['MYSQL']['mysql_path'] + 'bin', # encoding='utf-8' ) print('heidisql,按钮被单击') def gmurl(self, event): cmd = 'start ' + config['WEB']['gm_url'] Popen(cmd, shell=True, # cwd=config['MYSQL']['mysql_path'] + 'bin', # encoding='utf-8' ) print('gmurl,按钮被单击') # TODO 增加自动登录GM后台功能 def yyurl(self, event): cmd = 'start ' + config['WEB']['game_url'] Popen(cmd, shell=True, # cwd=config['MYSQL']['mysql_path'] + 'bin', # encoding='utf-8' ) print('yyurl,按钮被单击') # TODO 增加自动登录后台功能 # VC运行库 def msvbcrt(self, event): cmd = 'start "" ' + config['TOOL_PATH']['msvbcrt_path'] Popen(cmd, shell=True, # cwd=config['MYSQL']['mysql_path'] + 'bin', # encoding='utf-8' ) print('VC运行库,按钮被单击') # 程序升级 def up(self, event): if self.upButton.text() == '检查新版' or self.upButton.text() == '无新版本': newVersion = getNewVersion() # 获取新版本号 # if os.path.isfile("upgrade.bat"): # 判断是否有upgrade.bat这个文件,有就删除 # os.remove("upgrade.bat") if version < newVersion: # 判断当前程序是否是最新版本 self.upButton.setText("新版本:" + str(newVersion)) else: self.upButton.setText("无新版本") print('当前版本:', version, '\t最新版本:', newVersion) else: cmd = 'start ' + 'https://shileiye.com/' Popen(cmd, shell=True, ) print('检查新版,按钮被单击') # TODO 增加自动下载更新功能 # 利用新线程进行脚本执行回显 def add_cmd_msg(self, cmd, cwd="", title="", obj="", path="", code="utf8"): obj.setEnabled(False) self.CMDtextEdit.clear() self.CMDtextEdit.append(title + "脚本开始执行!") self.work = Thread(cmd, cwd, title, obj, path, code) self.work.trigger.connect(self.show_msg) # 线程中的trigger与主类中的方法进行绑定 self.work.daemon = True # 主进程退出则该线程也退出 self.work.start() # 开启线程 # 更新UI方法 def show_msg(self, str): self.CMDtextEdit.moveCursor(QTextCursor.End) self.CMDtextEdit.append(str) # self.CMDtextEdit.insertPlainText(str) # self.CMDtextEdit.insertHtml(str) # 线程类 class Thread(QThread): trigger = pyqtSignal(str) # 注意pyqtSignal一定要实例到__init__前面 def __init__(self, cmd, cwd="", title="", obj="", path="", code="utf8"): super(Thread, self).__init__() # 定义的变量 self.cmd = cmd self.cwd = cwd self.title = title self.obj = obj self.path = path self.code = code self.state = True # 执行耗时操作 def run(self): process = subprocess.Popen(self.cmd, shell=True, cwd=self.cwd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) while process.poll() is None: line = process.stdout.readline() line = line.strip() if line: self.trigger.emit(line.decode(self.code, 'ignore')) print(line.decode(self.code, 'ignore')) self.trigger.emit(self.title + '脚本执行结束!') self.obj.setEnabled(True) # self.obj.setText(self.title) # print(self.obj) # self.fanbianyiButton.setEnabled(False) # self.fanbianyiButton.setText('运行中') if self.path != "": self.trigger.emit('文件路径:' + self.path) startfile(self.path) # MYSQL操作函数 def mysql_run(sqls, table=""): print(sqls) # 打开数据库连接 db = pymysql.connect(host=config['MYSQL']['mysql_host'], user=config['MYSQL']['mysql_user'], password=config['MYSQL']['mysql_pass'], database=table, port=int(config['MYSQL']['mysql_port']) ) # 使用cursor()方法获取操作游标 cursor = db.cursor() for sql in sqls: try: # 执行SQL语句 cursor.execute(sql) # 提交到数据库执行 db.commit() print('更新成功') except: print('出错了') # 发生错误时回滚 db.rollback() # 关闭数据库连接 db.close() print('MySql执行完毕') # 进程判断,返回进程ID def checkprocess(processname): pl = psutil.pids() for pid in pl: if psutil.Process(pid).name() == processname: return pid # 打开文件或文件夹,并且选中文件 def startfile(filename): try: os.startfile(f'explorer /select, "{pathlib.Path(filename)}') except: subprocess.Popen(f'explorer /select, "{pathlib.Path(filename)}') # 获取最新程序版本号 def getNewVersion(): url = r'http://127.0.0.1:82/Version.txt' try: value = requests.get(url, timeout=10).content.decode() except: value = 0 return float(value) if __name__ == '__main__': version = 1.0 app = QApplication(sys.argv) myWin = MainWindow() myWin.show() sys.exit(app.exec_())