#!/usr/bin/env python3 import sys oldexcepthook = sys.excepthook def newexcepthook(type,value,traceback): oldexcepthook(type,value,traceback) input("Press ENTER to quit.") # - this causes issues with Qt's input hook sys.excepthook = newexcepthook import os p = os.path.join pUp = os.path.dirname s = False if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'): s = os.path.realpath(sys.executable) else: s = os.path.realpath(__file__) sp = pUp(s) os.chdir(sp) # script start import qtpy from qtpy.QtGui import * from qtpy.QtWidgets import * from qtpy.QtCore import * from qtpy.QtMultimedia import QSound import urllib.parse import html import threading import asyncio import logging import configparser import datetime import json import traceback distro = "Discord but fast" version = (0,2,0) versionString = ".".join(map(str,version)) pathLogins = p(sp,"logins") guiLock = threading.Condition() openGuis = [] guiTasks = [] ready = False online = True unreadChannels = [] oldUnreadChannels = [] def doNothing(): pass def listMove(list,ind,newInd): if newInd > ind: newInd = newInd - 1 list.insert(newInd,list.pop(ind)) def addGuiTask(gui,func,args,kwargs,condition = None): guiTasks.append((gui,func,args,kwargs,condition)) def getTitle(text = False): title = "" if text == False: title = distro + " " + versionString else: title = text + " - " + distro + " " + versionString return title def getChannelDisplayName(channel): channelName = "Unknown" if type(channel) == discord.DMChannel: channelName = channel.recipient.name + "#" +channel.recipient.discriminator elif type(channel) == discord.GroupChannel: if channel.name: channelName = "Group: " +channel.name else: channelName = "Group: [No name]" if channel.id in unreadChannels: channelName = "* " +channelName return channelName def playNotificationSound(): if notificationSound: notificationSound.play() class dbfApp: def __init__(self): self.app = QApplication(sys.argv) self.uiTimer = QTimer(self.app) self.uiTimer.setInterval(round(float(config["performance"]["uiTickTime"])*1000)) self.uiTimer.timeout.connect(self.update) self.uiTimer.start() def update(self): guiLock.acquire() index = 0 length = len(openGuis) while index < length: if openGuis[index].closed == True: del openGuis[index] length -= 1 continue index += 1 if len(unreadChannels) > 0: activeWindow = app.app.activeWindow() if activeWindow != None: index = 0 while index < length: gui = openGuis[index] if gui.window == activeWindow: activeWindow = gui break index += 1 if activeWindow.type == "channel": if activeWindow.channel.id in unreadChannels: if activeWindow.messageLog.scrollbar.value() == activeWindow.messageLog.scrollbar.maximum(): del unreadChannels[unreadChannels.index(activeWindow.channel.id)] index = 0 while index < length: gui = openGuis[index] if gui.type == "channel": if gui.channel.id in unreadChannels: if gui.read == False: index += 1; continue gui.title = getChannelDisplayName(gui.channel) gui.window.setWindowTitle(getTitle(gui.title)) gui.read = False else: if gui.read == True: index += 1; continue gui.title = getChannelDisplayName(gui.channel) gui.window.setWindowTitle(getTitle(gui.title)) gui.read = True index += 1 global oldUnreadChannels unreadChannelsLength = len(unreadChannels) if oldUnreadChannels != unreadChannels: for gui in openGuis: if gui.type == "channels": if unreadChannelsLength > 0: gui.title = "* Channels" gui.window.setWindowTitle(getTitle(gui.title)) else: gui.title = "Channels" gui.window.setWindowTitle(getTitle(gui.title)) gui.repopulateChannels("conversations") oldUnreadChannels = unreadChannels.copy() fh = open(p(loginPath,"unreadChannels.json"),"w") fh.write(json.dumps(unreadChannels)) fh.close() conditions = [] length = len(guiTasks) while length > 0: task = guiTasks.pop(0) gui = task[0] length -= 1 condition = task[4] if condition: conditions.append(condition) if gui == None: task[1](*task[2],**task[3]) continue if gui == "open": openGuis.append(task[1](*task[2],**task[3])) continue if gui.closed == True: continue task[1](*task[2],**task[3]) guiLock.notifyAll() guiLock.release() for condition in conditions: condition.acquire() condition.notifyAll() condition.release() class dbfMainWindow(QMainWindow): def __init__(self,*args,customEventFilter = None,**kwargs): super(dbfMainWindow,self).__init__(*args,**kwargs) if customEventFilter != None: self.customEventFilter = customEventFilter self.installEventFilter(self) def eventFilter(self,source,event): rtn = self.customEventFilter[1](self.customEventFilter[0],source,event) if rtn == None: rtn = False return rtn class dbfTextBrowser: def __init__(self,*args,**kwargs): self.widget = QTextBrowser(*args,**kwargs) self.widget.setOpenLinks(False) self.widget.anchorClicked.connect(self.anchorClicked) self.scrollbar = self.widget.verticalScrollBar() self.links = [] def getHtml(self,texts): htmlOut = "" for text in texts: processedText = "" raw = False #print(str(text)) if "raw" in text: raw = text["raw"] if raw: processedText = text["text"] else: processedText = html.escape(text["text"]).replace("\n","
") if "link" in text: index = len(self.links) self.links.append(text["link"]) processedText = '' +processedText+ '' if "style" in text: processedText = '' +processedText+ '' htmlOut += processedText return htmlOut def set(self,texts): oldValue = self.scrollbar.value() isMaxScroll = (oldValue == self.scrollbar.maximum()) self.links = [] self.widget.clear() self.widget.insertHtml(self.getHtml(texts)) if isMaxScroll: self.scrollbar.setValue(self.scrollbar.maximum()) else: self.scrollbar.setValue(oldValue) def append(self,texts): oldValue = self.scrollbar.value() isMaxScroll = (oldValue == self.scrollbar.maximum()) self.widget.insertHtml(self.getHtml(texts)) if isMaxScroll: self.scrollbar.setValue(self.scrollbar.maximum()) else: self.scrollbar.setValue(oldValue) def anchorClicked(self,url): urlFunc = self.links[int(urllib.parse.unquote(url.toString()))] urlFunc[0](*urlFunc[1],**urlFunc[2]) class guiLoginChooser: def __init__(self): self.closed = False self.type = "loginChooser" self.title = "Login" self.width = 300 self.height = 78 self.window = QWidget() global style self.window.setStyleSheet(style) self.window.setWindowTitle(getTitle(self.title)) self.window.resize(self.width,self.height) self.window.resizeEvent = self.resizeEvent self.window.closeEvent = self.closeEvent self.createElements() def createElements(self): self.label = QLabel("Choose an account:",self.window) self.label.setAlignment(Qt.AlignCenter) self.dropdown = QComboBox(self.window) self.buttonNew = QPushButton("New",self.window) self.buttonNew.clicked.connect(self.newLogin) self.buttonLogin = QPushButton("Login",self.window) self.buttonLogin.clicked.connect(self.login) for root,dirs,files in os.walk(pathLogins): for file in dirs: ffile = p(root,file) lfile = ffile.rsplit(os.sep,1)[1] self.dropdown.addItem(lfile) break self.resizeElements() self.window.show() def resizeElements(self): self.label.move(5,5) self.label.resize(self.width - 10,12) self.dropdown.move(40,20) self.dropdown.resize(self.width - 80,22) self.buttonLogin.move(self.width - 64 - 5,self.height - 24 - 5) self.buttonLogin.resize(64,24) self.buttonNew.move(5,self.height - 24 - 5) self.buttonNew.resize(64,24) def resizeEvent(self, event): self.width = self.window.width() self.height = self.window.height() self.resizeElements() QWidget.resizeEvent(self.window, event) def newLogin(self, event): openGuis.append(guiNewLogin()) self.window.close() def login(self, event): threading.Thread(target=init,args=(self.dropdown.currentText(),)).start() def closeEvent(self, event): self.closed = True class guiNewLogin: def __init__(self): self.closed = False self.type = "newLogin" self.title = "Create new login" self.width = 300 self.height = 84 self.window = QWidget() global style self.window.setStyleSheet(style) self.window.setWindowTitle(getTitle(self.title)) self.window.resize(self.width,self.height) self.window.resizeEvent = self.resizeEvent self.window.closeEvent = self.closeEvent self.createElements() def createElements(self): self.labelName = QLabel("Name:",self.window) self.labelName.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.textName = QLineEdit(self.window) self.labelToken = QLabel("Token:",self.window) self.labelToken.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.textToken = QLineEdit(self.window) self.buttonBack = QPushButton("< Back",self.window) self.buttonBack.clicked.connect(self.login) self.buttonAdd = QPushButton("Add",self.window) self.buttonAdd.clicked.connect(self.createLogin) self.resizeElements() self.window.show() def resizeElements(self): self.labelName.move(5,5) self.labelName.resize(62,22) self.textName.move(69,5) self.textName.resize(self.width - 69 - 15,22) self.labelToken.move(5,27) self.labelToken.resize(62,22) self.textToken.move(69,27) self.textToken.resize(self.width - 69 - 15,22) self.buttonBack.move(5,self.height - 24 - 5) self.buttonBack.resize(64,24) self.buttonAdd.move(self.width - 64 - 5,self.height - 24 - 5) self.buttonAdd.resize(64,24) def resizeEvent(self, event): self.width = self.window.width() self.height = self.window.height() self.resizeElements() QWidget.resizeEvent(self.window, event) def login(self, event): openGuis.append(guiLoginChooser()) self.window.close() def createLogin(self, event): global pathLogins os.makedirs(p(pathLogins,self.textName.text(),"messageTimes")) tf = open(p(pathLogins,self.textName.text(),"token"),"w") tf.write(self.textToken.text()) tf.close() self.login(None) def closeEvent(self, event): self.closed = True class guiLoginProgress: def __init__(self): self.closed = False self.type = "loginProgress" self.title = "Logging in..." self.width = 320 self.height = 240 self.window = QWidget() global style self.window.setStyleSheet(style) self.window.setWindowTitle(getTitle(self.title)) self.window.resize(self.width,self.height) self.window.resizeEvent = self.resizeEvent self.window.closeEvent = self.closeEvent self.createElements() def createElements(self): self.log = dbfTextBrowser(self.window) self.log.widget.setFont(fonts["monospace"]) self.logScroll = self.log.widget.verticalScrollBar() self.resizeElements() self.window.show() def resizeElements(self): self.log.widget.move(0,0) self.log.widget.resize(self.width,self.height) def resizeEvent(self, event): self.width = self.window.width() self.height = self.window.height() self.resizeElements() QWidget.resizeEvent(self.window, event) def closeEvent(self, event): self.closed = True QWidget.closeEvent(self.window, event) class guiChannels: def __init__(self): self.closed = False self.type = "channels" self.title = "Channels" global unreadChannels if len(unreadChannels) > 0: self.title = "* " +self.title self.width = 200 self.height = 350 self.window = dbfMainWindow(customEventFilter = (self,self.eventFilter)) global style self.window.setStyleSheet(style) self.window.setWindowTitle(getTitle(self.title)) self.window.resize(self.width,self.height) self.window.eventFilter = None self.window.resizeEvent = self.resizeEvent self.window.closeEvent = self.closeEvent self.createElements() def createElements(self): self.menuBar = self.window.menuBar() self.fileMenu = self.menuBar.addMenu("File") self.conversations = [] self.friends = [] self.picture = QLabel(self.window) self.picturePix = QPixmap("assets/images/windows.png").scaled(32,32,Qt.KeepAspectRatio) self.picture.setPixmap(self.picturePix) self.name = QLabel(self.window) self.name.setStyleSheet("font-weight: bold") self.name.setText(client.user.name + "#" +client.user.discriminator) self.status = QLabel(self.window) self.status.setText("A status") self.tabs = QTabWidget(self.window) self.conversationTab = QWidget(self.window) self.tabs.addTab(self.conversationTab,"Conversations") self.conversationList = QListWidget(self.conversationTab) self.conversationList.itemDoubleClicked.connect(self.openChannel) self.friendTab = QWidget(self.window) self.tabs.addTab(self.friendTab,"Friends") self.resizeElements() self.window.show() self.resizeElements() # Taking a hammer to solve the issue, here. Without calling resizeElements twice, the lists inside the tabs do not resize correctly when the window first opens. self.tabs.currentChanged.connect(self.changedTab) def resizeElements(self): mb = self.menuBar.height() self.picture.move(5,mb + 5) self.picture.resize(32,32) self.name.move(32+10, mb+5) self.name.resize(self.width-32-15, 16) self.status.move(32+10, mb+5+16) self.status.resize(self.width-32-15, 16) self.tabs.move(0, mb+32+10) self.tabs.resize(self.width, self.height-mb-32-10) self.conversationList.resize(self.conversationTab.width(),self.conversationTab.height()) def resizeEvent(self, event): self.width = self.window.width() self.height = self.window.height() self.resizeElements() QWidget.resizeEvent(self.window, event) def closeEvent(self, event): self.closed = True QWidget.closeEvent(self.window, event) def clearChannels(self,list): channels = None qlist = None if list == "conversations": channels = self.conversations qlist = self.conversationList channels.clear() qlist.clear() def repopulateChannels(self,list): channels = None qlist = None if list == "conversations": channels = self.conversations qlist = self.conversationList qlist.clear() for channel in channels: qlist.addItem(getChannelDisplayName(channel)) def moveChannel(self,list,channel,index): channels = None if list == "conversations": channels = self.conversations listMove(channels,channels.index(channel),index) self.repopulateChannels(list) def sortChannels(self,list): channels = None if list == "conversations": channels = self.conversations newChannels = [] while True: index = 0 length = len(channels) largestTime = None largestElement = None while index < length: channel = channels[index] time = getLastMessageTime(channel) if not time: index += 1; continue if not largestTime: largestTime = time largestElement = index index += 1 continue if time < largestTime: largestTime = time largestElement = index index += 1 if largestElement == None: break newChannels.append(channels.pop(largestElement)) newChannels.reverse() newChannels.extend(channels) channels.clear() channels.extend(newChannels) self.repopulateChannels(list) def addChannel(self,list,channel): channels = None qlist = None if list == "conversations": channels = self.conversations qlist = self.conversationList if channel in channels: return channels.append(channel) qlist.addItem(getChannelDisplayName(channel)) def openChannel(self): tab = self.tabs.currentWidget() channel = None if tab == self.conversationTab: channel = self.conversations[self.conversationList.currentRow()] guiLock.acquire() for gui in openGuis: if gui.type == "channel": if gui.channel == channel: gui.window.setWindowState(gui.window.windowState() & ~Qt.WindowMinimized | Qt.WindowActive) gui.window.activateWindow() guiLock.release() return openGuis.append(guiChannel(channel)) guiLock.release() def eventFilter(_,self,source,event): #print(source,event) if event.type() == QEvent.KeyPress: if event.key() in (Qt.Key_Return,Qt.Key_Enter): if self.window.focusWidget() in (self.conversationList,): self.openChannel() return True def changedTab(self,i): self.resizeElements() class guiChannel: def __init__(self,channel): self.closed = False self.ready = False self.type = "channel" self.title = getChannelDisplayName(channel) self.width = 320 self.height = 350 self.window = dbfMainWindow() global style self.window.setStyleSheet(style) self.window.setWindowTitle(getTitle(self.title)) self.window.resize(self.width,self.height) self.channel = channel self.read = (not channel.id in unreadChannels) self.messages = [] self.pendingMessages = [] self.window.resizeEvent = self.resizeEvent self.window.closeEvent = self.closeEvent self.createElements() class chatTextBox(QPlainTextEdit): def __init__(self,parent = None,exSelf = None): super().__init__(parent = parent) self.exSelf = exSelf self.installEventFilter(self) def eventFilter(self,source,event): if event.type() == QEvent.KeyPress: if event.key() in (Qt.Key_Return,Qt.Key_Enter): modifiers = QApplication.keyboardModifiers() if (modifiers & Qt.ShiftModifier): return False if self.exSelf.window.focusWidget() in (self.exSelf.textbox,): self.exSelf.sendMessage() return True return False def createElements(self): self.menuBar = self.window.menuBar() self.fileMenu = self.menuBar.addMenu("File") self.messageLog = dbfTextBrowser(self.window) self.messageLogScroll = self.messageLog.widget.verticalScrollBar() self.textbox = self.chatTextBox(self.window,self) self.buttonSend = QPushButton("Send",self.window) self.buttonSend.clicked.connect(self.sendMessage) self.resizeElements() self.window.show() def resizeElements(self): mb = self.menuBar.height() self.messageLog.widget.move(0,mb) self.messageLog.widget.resize(self.width,self.height-mb-48-24-10) self.textbox.move(0,mb+self.height-mb-48-24-10) self.textbox.resize(self.width,48) self.buttonSend.move(self.width-64-5,self.height-24-5) self.buttonSend.resize(64,24) def resizeEvent(self, event): self.width = self.window.width() self.height = self.window.height() self.resizeElements() QWidget.resizeEvent(self.window, event) def closeEvent(self, event): self.closed = True QWidget.closeEvent(self.window, event) def confirmEvent(self, event): pass def addMessage(self, message): global config while len(self.messages) >= int(config["performance"]["maxMessagesListed"]): del self.messages[0] self.messages.append(message) self.messageLog.set({}) for message in self.messages: texts = [ {"text":"\n" + message.author.name+ ": ","style":config["textStyle"]["userHighlight"]}, {"text":message.content} ] for attachment in message.attachments: texts.append( {"text":"\n> Attach: ","style":"color: orange"} ) texts.append( {"text":attachment.url} ) self.messageLog.append(texts) def sendMessage(self): self.pendingMessages.append(self.textbox.toPlainText()) self.textbox.setPlainText("") def setReady(self): self.ready = True def dtToString(dt): return json.dumps([dt.year,dt.month,dt.day,dt.hour,dt.minute,dt.second,dt.microsecond]) def dtFromString(js): ls = json.loads(js) return datetime.datetime(*ls) def getMessageTimePath(channel): return p(loginPath,"messageTimes",str(channel.id)) msgTimeLock = threading.Lock() def getLastMessageTime(channel): msgTimeLock.acquire() mtpath = getMessageTimePath(channel) if not os.path.isfile(mtpath): msgTimeLock.release(); return None fh = open(mtpath,"r") st = fh.read() fh.close() msgTimeLock.release() return dtFromString(st) def setLastMessageTime(channel,time): msgTimeLock.acquire() mtpath = getMessageTimePath(channel) fh = open(mtpath,"w") fh.write(dtToString(time)) fh.close() msgTimeLock.release() def discordClient(token): logging.basicConfig(level=logging.INFO) loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) global client client = discord.Client() global channelFilter channelFilter = (discord.DMChannel,discord.GroupChannel) global loginPath async def fetchLostMessages(channel): newTime = None while True: try: async for msg in channel.history(limit=1): newTime = msg.created_at break except Exception: print(traceback.format_exc()) print("! could not fetch lost messages for " +str(channel.id)+ ", retrying...") if not newTime: return False oldTime = getLastMessageTime(channel) if not oldTime: setLastMessageTime(channel,newTime) return False if newTime == oldTime: return False fetchMsgs = False guiLock.acquire() if not channel.id in unreadChannels: unreadChannels.append(channel.id) for gui in openGuis: if gui.type == "channel": if channel != gui.channel: continue fetchMsgs = True break guiLock.release() if fetchMsgs == True: newMsgs = None while True: try: newMsgs = [] async for message in channel.history(limit=100,before=newTime,after=oldTime): newMsgs.append(message) break except Exception: print(traceback.format_exc()) print("! could not fetch lost messages for " +str(channel.id)+ ", retrying...") guiLock.acquire() for message in newMsgs: for gui in openGuis: if gui.type == "channel": if channel != gui.channel: continue addGuiTask(gui,gui.addMessage,(message,),{}) guiLock.release() setLastMessageTime(channel,newTime) if not channel.id in unreadChannels: unreadChannels.append(channel.id) return True async def fetchAllLostMessages(): print("fetching all lost messages...") newMessages = False for channel in client.private_channels: if not type(channel) in channelFilter: continue r = await fetchLostMessages(channel) if newMessages == False and r == True: newMessages = True if newMessages == True: guiLock.acquire() addGuiTask(None,playNotificationSound,(),{}) guiLock.release() print("done fetching.") @client.event async def on_ready(): print("on_ready") global online global channelFilter global ready if ready == False: condition = threading.Condition() condition.acquire() guiLock.acquire() for gui in openGuis: if gui.type == "loginProgress": addGuiTask(gui,gui.window.close,(),{}) addGuiTask("open",guiChannels,(),{},condition) guiLock.release() condition.wait() condition.release() condition.acquire() guiLock.acquire() for gui in openGuis: if gui.type == "channels": for channel in client.private_channels: addGuiTask(gui,gui.addChannel,("conversations",channel,),{}) addGuiTask(gui,gui.sortChannels,("conversations",),{},condition) guiLock.release() condition.wait() condition.release() guiLoop.start() ready = True if config["messageTracking"]["trackMessages"] == "true" and config["messageTracking"]["recheckMessages"] == "true": await fetchAllLostMessages() if online == False: online = True @client.event async def on_resumed(): print("on_resumed") global online global channelFilter if config["messageTracking"]["trackMessages"] == "true" and config["messageTracking"]["recheckMessages"] == "true": await fetchAllLostMessages() if online == False: online = True @client.event async def on_message(message): messages = [message] if type(message.channel) in channelFilter and config["messageTracking"]["trackMessages"] == "true": oldTime = getLastMessageTime(message.channel) if oldTime: if config["messageTracking"]["paranoidMessages"] == "true": newMsgs = None while True: try: newMsgs = [] async for msg in message.channel.history(limit=100,before=message.created_at,after=oldTime): newMsgs.append(msg) break except Exception: print(traceback.format_exc()) print("! could not fetch lost messages for " +str(message.channel.id)+ ", retrying...") if len(newMsgs) > 0: print("paranoia found missed messages") for msg in newMsgs: messages.append(msg) setLastMessageTime(message.channel,message.created_at) guiLock.acquire() if type(message.channel) in channelFilter: addGuiTask(None,playNotificationSound,(),{}) if not message.channel.id in unreadChannels: unreadChannels.append(message.channel.id) for gui in openGuis: if gui.type == "channels": if message.channel in gui.conversations: addGuiTask(gui,gui.moveChannel,("conversations",message.channel,0),{}) if gui.type == "channel": if message.channel != gui.channel: continue for msg in messages: addGuiTask(gui,gui.addMessage,(msg,),{}) guiLock.release() @tasks.loop(seconds=float(config["performance"]["uiTickTime"])) async def guiLoop(): guis = [] guiLock.acquire() for gui in openGuis: guis.append(gui) if gui.type == "channel": while len(gui.pendingMessages) > 0: msg = gui.pendingMessages.pop(0) try: await gui.channel.send(msg) except Exception: print(traceback.format_exc()) print("! failed sending message: " +msg) guiLock.release() for gui in guis: if gui.type == "channel": if gui.ready == False: channel = gui.channel messages = [] try: messages = await channel.history(limit=int(config["performance"]["historyFetch"])).flatten() except Exception: print(traceback.format_exc()) print("! failed fetching messages for channel " +str(channel.id)) messages = reversed(messages) guiLock.acquire() message = None for message in messages: addGuiTask(gui,gui.addMessage,(message,),{}) if message != None and config["messageTracking"]["trackMessages"] == "true": setLastMessageTime(channel,message.created_at) condition = threading.Condition() condition.acquire() addGuiTask(gui,gui.setReady,(),{},condition) guiLock.release() condition.wait() condition.release() loop.create_task(client.start(token,bot = False)) loop.run_forever() def init(nlogin): condition = threading.Condition() condition.acquire() guiLock.acquire() addGuiTask("open",guiLoginProgress,(),{},condition) for gui in openGuis: if gui.type == "loginChooser": addGuiTask(gui,gui.window.close,(),{}) guiLock.release() condition.wait() condition.release() guiLock.acquire() for gui in openGuis: if gui.type == "loginProgress": addGuiTask(gui,gui.log.append,([[ {"text":"fetching token..."} ]]),{}) guiLock.release() global login login = nlogin global loginPath loginPath = p(pathLogins,login) token = "" with open(p(loginPath,"token")) as tokenFile: token = tokenFile.read() if os.path.isfile(p(loginPath,"unreadChannels.json")): global unreadChannels fh = open(p(loginPath,"unreadChannels.json")) unreadChannels = json.loads(fh.read()) fh.close() guiLock.acquire() for gui in openGuis: if gui.type == "loginProgress": addGuiTask(gui,gui.log.append,([[ {"text":"\nloading discord.py..."} ]]),{}) guiLock.release() global discord import discord global tasks from discord.ext import tasks guiLock.acquire() for gui in openGuis: if gui.type == "loginProgress": addGuiTask(gui,gui.log.append,([[ {"text":"\nlogging in..."} ]]),{}) guiLock.release() threading.Thread(target=discordClient,args=(token,)).start() def loadStyle(config): global fonts fonts = {} fonts["default"] = QFont() fonts["monospace"] = QFont("monospace") fonts["monospace"].setStyleHint(QFont.TypeWriter) if config["font"]["defaultType"] != "default": fonts["default"] = QFont(config["font"]["defaultType"]) if config["font"]["defaultSize"] != "default": fonts["default"].setPointSize(int(config["font"]["defaultSize"])) if config["font"]["monoType"] != "default": fonts["monospace"] = QFont(config["font"]["monoType"]) if config["font"]["monoSize"] != "default": fonts["monospace"].setPointSize(int(config["font"]["monoSize"])) app.app.setFont(fonts["default"]) global style style = "" if config["style"]["baseStyle"] != "default": app.app.setStyle(config["style"]["baseStyle"]) if config["style"]["backgroundColor"] != "default": style += "background:" +config["style"]["backgroundColor"]+ ";" if config["style"]["fontColor"] != "default": style += "color:" +config["style"]["fontColor"]+ ";" def main(): pyqtRemoveInputHook() global config config = configparser.ConfigParser() config.read(p(sp,"default.ini")) global app app = dbfApp() loadStyle(config) global notificationSound if config["sound"]["notification"].lower() != "none": notificationSound = QSound(config["sound"]["notification"]) else: notificationSound = None loginGui = guiLoginChooser() openGuis.append(loginGui) sys.exit(app.app.exec_()) if __name__ == "__main__": main()