discord-but-fast/discord-but-fast.py

1050 lines
29 KiB
Python

#!/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","<br>")
if "link" in text:
index = len(self.links)
self.links.append(text["link"])
processedText = '<a href="' +html.escape(str(index))+ '">' +processedText+ '</a>'
if "style" in text:
processedText = '<span style="' +html.escape(text["style"])+ '">' +processedText+ '</span>'
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()