# All library imports
from tkinter import *
from tkinter import messagebox
from pypresence import Presence
import time
import datetime
import requests
import urllib
import os
import os.path
from os import path
import sys
import linecache
import SystemTray
import psutil
from plyer.utils import platform
from plyer import notification
# Window setting up
window = Tk() # Main window init
window.title("RichPresence") # Window title init
window.geometry("800x500") # Window size setting
# Global variables (used for inter-function variables not passed as argument)
global info
global log
info = 0
log = 0
# Confirm button
def confirm(ID_Entry):
"""First setting up, asks user info (Discord application ID) and saves it in Identity.txt file"""
global info
global log
Client_ID = ID_Entry.get()
log.write("["+getTime()+"] "+ "Making sure Identity info is valid\n")
log.flush()
info.write(Client_ID+'\n') # Save Client ID (Discord application number string)
log.write("["+getTime()+"] "+ "Finished writing first-time info to identity file\n")
log.flush()
messagebox.showinfo(title = "Success", message = "Correctly saved info! Restart program to use.") # Indicates success of saved data
try:
log.write("["+getTime()+"] "+ "Closing identity file access to remove danger of corruption\n")
log.flush()
info.close() # Close txt file
except:
PrintException()
leave() # Exit application, restart program
def Timer():
"""Timer function, asks user whatever time they want (hours, minutes, seconds), then calls createTimer"""
global log
try:
MainFrame.destroy() # Destroy previous window (deletes buttons, labels of main menu)
log.write("["+getTime()+"] "+ "Destroyed Main frame window\n")
log.flush()
Time = Label(window, text = "Choose your time!").grid(column = 0, row = 0) # Main label
Hours = Label(window, text = "Hours:").grid(column=0, row=2) # Hours label
HoursEntry = Entry(window, width = 10) # Hour entry (user input area)
HoursEntry.grid(column=1, row=2) # add to grid
Minutes = Label(window, text = "Minutes:").grid(column=2, row=2) # Minutes label
MinutesEntry = Entry(window, width = 10) # Minutes entry (user input area)
MinutesEntry.grid(column=3, row=2) # add to grid
Seconds = Label(window, text = "Seconds:").grid(column=4, row=2) # Seconds label
SecondsEntry = Entry(window, width = 10) # Seconds entry (user input area)
SecondsEntry.grid(column=5, row=2) # add to grid
label = Label(window, text= "Choose the top text:").grid(column=0, row = 3) # Text label
TextEntry = Entry(window, width = 20) # Entry box (user input area) for text you want to add
TextEntry.grid(column = 1, row = 3) # add to grid
Confirm = Button(window, text="Confirm", command = lambda: createTimer(HoursEntry, MinutesEntry, SecondsEntry, TextEntry)).grid(row = 4, sticky = W) # Confirm button
log.write("["+getTime()+"] "+ "Created Timer window\n")
log.flush()
except:
PrintException()
def createTimer(HoursEntry, MinutesEntry, SecondsEntry, Text):
"""Gets all timer values, and converts to correct value, then if all is correct, start the timer with info and display to Discord profile"""
global log
log.write("["+getTime()+"] "+ "Confirmed data entry\n")
log.flush()
try:
hour = int(HoursEntry.get()) # Gets Entry Hour Information
minutes = int(MinutesEntry.get()) # Gets Minutes Entry Information
seconds = int(SecondsEntry.get()) # Gets Seconds Entry Information
text = str(Text.get()) # Gets text Entry Information
log.write("["+getTime()+"] "+ "Timer values approved with profile: \nSelected hour: "+str(hour)+"\nSelected minutes: "+str(minutes)+"\nSelected seconds:"+str(seconds)+"\nSelected additional text: "+text+"\n")
log.flush()
except:
PrintException()
log.write("["+getTime()+"] "+ "Closing UI - leaving Python\n")
log.flush()
window.destroy()
print("Your code is running! Keep this window open to display your status!\nCheck the *System Tray* to hide / show this window")
minute_counter = 0 # Initialize variable
counter=0
for i in text:
counter += 1
log.write("["+getTime()+"] "+ "Opening Identity file\n")
log.flush()
info = open("Identity.txt", "r+")
client_id = info.readline()
RPC = Presence(client_id, pipe=0)
RPC.connect()
try:
log.write("["+getTime()+"] "+ "Attempting to create system notification\n")
log.flush()
notification.notify(
title='Tray Rich Presence',
message='Rich Presence is still running in tray!\nUse it to hide / show the CMD window!',
app_name='RichPresence',
app_icon='DiscordLogo.' + ('ico' if platform == 'win' else 'png')
)
except:
PrintException()
log.write("["+getTime()+"] "+ "Notification Success!\n")
log.flush()
if text == "" or text == " " or counter<=1: # If no text was selected
time_left = {'hours': hour, 'minutes': minutes, 'seconds': seconds} # Time left at start
log.write("["+getTime()+"] "+ "Total timer look: "+str(time_left)+"\n")
log.flush()
try:
# Main timer loop
log.write("["+getTime()+"] "+ "Created loop\n")
log.flush()
log.write("["+getTime()+"] "+ "Started loop - closing log\n")
log.flush()
while hour + minutes + seconds >= 0:
time_left['seconds'] -=15
minute_counter += 1
if minute_counter >= 4:
minute_counter = 0
time_left['seconds'] = 60
time_left['minutes'] -=1
if time_left['minutes'] <= 0:
time_left['minutes'] = 60
time_left['hours'] -= 1
RPC.update(details='Time left: ' + str(time_left['hours']) + ' hours, ' + str(time_left['minutes']) + ' minutes, ' + str(time_left['seconds']) + ' seconds.')
time.sleep(15)
except:
PrintException()
else: # If text was selected
time_left = {'hours': hour, 'minutes': minutes, 'seconds': seconds} # Time left at start
log.write("["+getTime()+"] "+ "Total timer look: "+str(time_left)+"\n")
log.flush()
try:
# Main timer loop
log.write("["+getTime()+"] "+ "Created loop\n")
log.flush()
log.write("["+getTime()+"] "+ "Started loop - closing log\n")
log.flush()
while hour + minutes + seconds >= 0:
time_left['seconds'] -=15
minute_counter += 1
if minute_counter >= 4:
minute_counter = 0
time_left['seconds'] = 60
time_left['minutes'] -=1
if time_left['minutes'] <= 0:
time_left['minutes'] = 60
time_left['hours'] -= 1
RPC.update(details=text,state='Time left: ' + str(time_left['hours']) + ' hours, ' + str(time_left['minutes']) + ' minutes, ' + str(time_left['seconds']) + ' seconds.')
time.sleep(15)
except:
PrintException()
def Local():
"""Display local time for user (uses computer local time settings), then updates user discord status"""
global log
log.write("["+getTime()+"] "+ "Closing UI - Keeping Python console\n")
log.flush()
MainFrame.destroy() # Destroy main menu window
window.destroy()
print("Your code is running! Keep this window open to have your status shown!\nCheck the *System Tray* to hide / show this window")
info = open("Identity.txt", "r+")
client_id = info.readline()
RPC = Presence(client_id, pipe=0)
RPC.connect()
try:
log.write("["+getTime()+"] "+ "Attempting to create system notification\n")
log.flush()
notification.notify(
title='Tray Rich Presence',
message='Rich Presence is still running in tray!\nUse it to hide / show the CMD window!',
app_name='RichPresence',
app_icon='DiscordLogo.' + ('ico' if platform == 'win' else 'png')
)
except:
PrintException()
log.write("["+getTime()+"] "+ "Notification success!\n")
log.flush()
try:
log.write("["+getTime()+"] "+ "Created loop\n")
log.flush()
log.write("["+getTime()+"] "+ "Started loop - closing log\n")
log.flush()
while True:
RPC.update(details='Current time: ' + str(datetime.datetime.now().replace(microsecond=0))) # Update loop for discord profile
time.sleep(1)
except:
PrintException()
def HWINFO():
"""Displays user's hardware information"""
global log
try:
MainFrame.destroy()
log.write("["+getTime()+"] "+ "Main menu window destroyed\n")
log.flush()
Hard = Label(window, text = "Welcome to the Hardware Information area!").grid(column = 0, row = 0) # Main presentation label
showCPU = BooleanVar() # Show user balance question (boolean value returned)
Checkbutton(window, text="Show CPU usage?", variable = showCPU).grid(row = 1, sticky = W) # Checkbutton grid (add to window)
showRAM = BooleanVar() # Show user XP question (boolean value returned)
Checkbutton(window, text = "Show RAM usage?", variable = showRAM).grid(row = 2, sticky = W) # Checkbutton grid (add to window)
showSmallImg = BooleanVar() # Show user balance question (boolean value returned)
ImgLbl = Label(window, text = "What is your image name (needs to be uploaded to Discord application)").grid(column = 0, row = 3) # Status Image Name
ImgEntry = Entry(window, width = 20) # Image name entry (user input area)
ImgEntry.grid(column = 1, row = 3) # Add to grid (add to window)
SmallImgLbl = Label(window, text = "What is your small image name (needs to be uploaded to Discord application)").grid(column = 0, row = 4) # Status Image Name
SmallImgEntry = Entry(window, width = 20) # Image name entry (user input area)
SmallImgEntry.grid(column = 1, row = 4) # Add to grid (add to window)
ImgTextLbl = Label(window, text = "What is the text you want for the image (appears on image hover)").grid(column = 0, row = 5) # Image text label
ImgTextEntry = Entry(window, width = 20) # Image text entry (user input area)
ImgTextEntry.grid(column = 1, row = 5) # Add to grid (add to window)
showRunningTime = BooleanVar() # Show elapsed time question (boolean value returned)
Checkbutton(window, text = "Show elapsed time?", variable = showRunningTime).grid(row = 6, sticky = W) # Checkbutton grid (add to window)
Confirm = Button(window, text="Confirm", command = lambda: ShowHWINFO(showCPU, showRAM, ImgEntry, SmallImgEntry, ImgTextEntry, showRunningTime)).grid(row = 7, sticky = W) # Confirm button add to grid (add to window)
log.write("["+getTime()+"] "+ "Hardware information window created!\n")
log.flush()
except:
PrintException()
def ShowHWINFO(showCPU, showRAM, ImgEntry, SmallImgEntry, ImgTextEntry, showRunningTime):
"""Area for hardware info loop."""
global log
try:
showCPU = showCPU.get() # Gets Balance Boolean info (True or False) to indicate if a user wants to show balance or not
showRAM = showRAM.get() # Gets XP Boolean info (True or False) to indicate if a user wants to show xp or not
ImgEntry = ImgEntry.get()
SmallImgEntry = SmallImgEntry.get()
ImgTextEntry = ImgTextEntry.get()
showRunningTime = showRunningTime.get()
log.write("["+getTime()+"] "+ "Hardware choice was approved as: \nShow CPU: "+str(showCPU)+"\nShow RAM: "+str(showRAM)+"\n")
log.flush()
# Check if there is an Image added
if ImgEntry == "" or ImgEntry == " " or ImgEntry == None:
ImgEntry = None
log.write("["+getTime()+"] "+ "Couldn't find custom image entry - No Image will be displayed\n")
log.flush()
elif len(ImgEntry) > 32:
messagebox.showwarning(title = 'Warning', message = "Your Image name is too long! Continuing would break the process.\nMake sure it is equal to or smaller than 32 characters!")
log.write("["+getTime()+"] "+ "Image name was too long (exceeded 32 characters). Process interupted.\n")
log.flush()
leave()
if SmallImgEntry == "" or SmallImgEntry == " " or SmallImgEntry == None:
SmallImgEntry = None
log.write("["+getTime()+"] "+ "Couldn't find custom small image entry - No small image will be displayed\n")
log.flush()
elif len(SmallImgEntry) > 32:
messagebox.showwarning(title = 'Warning', message = "Your Small Image name is too long! Continuing would break the process.\nMake sure it is equal to or smaller than 32 characters!")
log.write("["+getTime()+"] "+ "Small Image name was too long (exceeded 32 characters). Process interupted.\n")
log.flush()
leave()
# Check if there is Image Text added
if ImgTextEntry == "" or ImgTextEntry == " " or ImgTextEntry == None:
ImgTextEntry = None
log.write("["+getTime()+"] "+ "Couldn't find custom image text entry - No text on image will be displayed\n")
log.flush()
# Does the user want to display elapsed time
if showRunningTime == False:
showRunningTime = None
log.write("["+getTime()+"] "+ "Running time None - No elapsed time will be shown\n")
log.flush()
except:
PrintException()
log.write("["+getTime()+"] "+ "Closing UI - Keeping Python console\n")
log.flush()
window.destroy()
print("Your code is running! Keep this window open to keep your status shown!\nCheck the *System Tray* to hide / show this window")
try:
log.write("["+getTime()+"] "+ "Attempting to create system notification\n")
log.flush()
notification.notify(
title='Tray Rich Presence',
message='Rich Presence is still running in tray!\nUse it to hide / show the CMD window!',
app_name='RichPresence',
app_icon='DiscordLogo.' + ('ico' if platform == 'win' else 'png')
)
except:
PrintException()
log.write("["+getTime()+"] "+ "Notification success!\n")
log.flush()
info = open("Identity.txt", "r+")
client_id = info.readline()
constant = time.time()
RPC = Presence(client_id, pipe=0)
RPC.connect()
while True:
if showRunningTime == True:
if showCPU == True and showRAM == True: # If user wants both to show:
RPC.update(details='CPU usage: '+str(psutil.cpu_percent())+'%',state='And RAM usage: ' + str(psutil.virtual_memory().used/1000000000)[:-7] +' / '+str(psutil.virtual_memory().total/1000000000)[:-7]+'GB', large_image = ImgEntry, small_image = SmallImgEntry, start = constant, large_text = ImgTextEntry, ) # CPU and RAM
time.sleep(15)
elif showCPU == True and showRAM == False:
RPC.update(details='CPU usage: '+str(psutil.cpu_percent())+'%', large_image = ImgEntry, small_image = SmallImgEntry, start = constant, large_text = ImgTextEntry,) # Show CPU only
time.sleep(15)
elif showCPU == False and showRAM == True:
RPC.update(details='RAM usage: '+str(psutil.virtual_memory().used/1000000000)[:-7]+' / '+str(psutil.virtual_memory().total/1000000000)[:-7]+'GB', large_image = ImgEntry, small_image = SmallImgEntry, start = constant, large_text = ImgTextEntry,) # Show RAM only
time.sleep(15)
else:
messagebox.showerror(title = 'Error!', message = 'No info selected! Revert to choice menu') # If user hasn't selected any info to display, revert to menu
HWINFO() # Call main menu function
else:
if showCPU == True and showRAM == True: # If user wants both to show:
RPC.update(details='CPU usage: '+str(psutil.cpu_percent())+'%',state='And RAM usage: ' + str(psutil.virtual_memory().used/1000000000)[:-7] +' / '+str(psutil.virtual_memory().total/1000000000)[:-7]+'GB', large_image = ImgEntry, small_image = SmallImgEntry, large_text = ImgTextEntry, ) # CPU and RAM
time.sleep(15)
elif showCPU == True and showRAM == False:
RPC.update(details='CPU usage: '+str(psutil.cpu_percent())+'%', large_image = ImgEntry, small_image = SmallImgEntry, large_text = ImgTextEntry,) # Show CPU only
time.sleep(15)
elif showCPU == False and showRAM == True:
RPC.update(details='RAM usage: '+str(psutil.virtual_memory().used/1000000000)[:-7]+' / '+str(psutil.virtual_memory().total/1000000000)[:-7]+'GB', large_image = ImgEntry, small_image = SmallImgEntry, large_text = ImgTextEntry,) # Show RAM only
time.sleep(15)
else:
messagebox.showerror(title = 'Error!', message = 'No info selected! Revert to choice menu') # If user hasn't selected any info to display, revert to menu
HWINFO() # Call main menu function
def Custom():
"""Displays a custom user profile"""
global log
try:
MainFrame.destroy() # Delete main menu window
log.write("["+getTime()+"] "+ "Main menu window destroyed\n")
log.flush()
Cust = Label (window, text= "Welcome to your custom area!").grid(column = 0, row = 0) # Main presentation label
Details = Label(window, text = "What details do you want ?(details is the top part of the status)").grid(column = 0, row = 1) # Details label
DetailsEntry = Entry(window, width = 50) # Details Entry (user input area)
DetailsEntry.grid(column = 1, row = 1) # Add to grid (add to window)
State = Label(window, text = "What state do you want ?(state is the bottom of the status)").grid(column = 0, row = 2) # State label
StateEntry = Entry(window, width = 50) # State entry (user input area)
StateEntry.grid(column = 1, row = 2) # Add to grid (add to window)
useButtons = BooleanVar() # Boolean variable, fo the use or not of buttons.
Checkbutton(window, text = "Do you want any buttons?", variable = useButtons).grid(row = 3, sticky = W) # Checkbutton grid (add to window)
But1NameLbl = Label(window, text = "What do you want as button name ?(what is shown on the button)").grid(column = 0, row = 4) # First button name label
But1NameEntry = Entry(window, width = 20) # Button 1 entry (user input area)
But1NameEntry.grid(column=1, row = 4) # Add to grid (add to window)
But1LinkLbl = Label(window, text = "What do you want as button link ?(what will the button link to?)").grid(column = 0, row = 5) # First button link label
But1LinkEntry = Entry(window, width = 20) # First button entry (user input area)
But1LinkEntry.grid(column=1, row = 5) # Add to grid (add to window)
But2NameLbl = Label(window, text = "What do you want as button second button name ?(what is shown on the button)").grid(column = 0, row = 6) # Second button name label
But2NameEntry = Entry(window, width = 20) # Button 2 entry (user input area)
But2NameEntry.grid(column=1, row = 6) # Add to grid (add to window)
But2LinkLbl = Label(window, text = "What do you want as button second button link ?(what will the button link to?)").grid(column = 0, row = 7) # Second button link label
But2LinkEntry = Entry(window, width = 20) # Second button entry (user input area)
But2LinkEntry.grid(column=1, row = 7) # Add to grid (add to window)
ImgLbl = Label(window, text = "What is your image name (needs to be uploaded to Discord application)").grid(column = 0, row = 8) # Status Image Name
ImgEntry = Entry(window, width = 20) # Image name entry (user input area)
ImgEntry.grid(column = 1, row = 8) # Add to grid (add to window)
SmallImgLbl = Label(window, text = "What is your small image name (needs to be uploaded to Discord application)").grid(column = 0, row = 9) # Status Image Name
SmallImgEntry = Entry(window, width = 20) # Image name entry (user input area)
SmallImgEntry.grid(column = 1, row = 9) # Add to grid (add to window)
ImgTextLbl = Label(window, text = "What is the text you want for the image (appears on image hover)").grid(column = 0, row = 10) # Image text label
ImgTextEntry = Entry(window, width = 20) # Image text entry (user input area)
ImgTextEntry.grid(column = 1, row = 10) # Add to grid (add to window)
showRunningTime = BooleanVar() # Show elapsed time question (boolean value returned)
Checkbutton(window, text = "Show elapsed time?", variable = showRunningTime).grid(row = 11, sticky = W) # Checkbutton grid (add to window)
Confirm = Button(window, text="Confirm", command = lambda: createCustom(DetailsEntry, StateEntry, useButtons, But1NameEntry, But1LinkEntry, But2NameEntry, But2LinkEntry, ImgEntry, SmallImgEntry, ImgTextEntry, showRunningTime, False, 0)).grid(row = 12, sticky = W) # Confirm button
if path.exists('preset1.txt'): # If preset 1 file exists
Preset1 = Button(window, text=" Use Preset 1 ", command = lambda: catchCustom(1)).grid(row=14, sticky=W) # Option for user to use the preset 1
else:
# Preset 1 doesn't exist
Preset1 = Button(window, text="Save Preset 1", command = lambda: saveCustom(DetailsEntry, StateEntry, useButtons, But1NameEntry, But1LinkEntry, But2NameEntry, But2LinkEntry, ImgEntry, SmallImgEntry, ImgTextEntry, showRunningTime, 1)).grid(row=14, sticky=W) # Save to Preset 1 file
if path.exists('preset2.txt'): # If preset 2 file exists
Preset2 = Button(window, text=" Use Preset 2 ", command = lambda: catchCustom(2)).grid(row=15, sticky=W) # Option for user to use the preset 2
else:
# Preset 2 doesn't exist
Preset2 = Button(window, text="Save Preset 2", command = lambda: saveCustom(DetailsEntry, StateEntry, useButtons, But1NameEntry, But1LinkEntry, But2NameEntry, But2LinkEntry, ImgEntry, SmallImgEntry, ImgTextEntry, showRunningTime, 2)).grid(row=15, sticky=W) # Save to Preset 2 file option
if path.exists('preset3.txt'): # If preset 3 file exists
Preset3 = Button(window, text=" Use Preset 3 ", command = lambda: catchCustom(3)).grid(row=16, sticky=W) # Option for user to use the preset 3
else:
# Preset 3 doesn't exist
Preset3 = Button(window, text="Save Preset 3", command = lambda: saveCustom(DetailsEntry, StateEntry, useButtons, But1NameEntry, But1LinkEntry, But2NameEntry, But2LinkEntry, ImgEntry, SmallImgEntry, ImgTextEntry, showRunningTime, 3)).grid(row=16, sticky=W) # Save the Preset 3 file option
Warn = Label(window, text = "!Warning! Leave Blank if you don't want an item").grid(row = 13) # Leave blank if you don't want an item displayed
log.write("["+getTime()+"] "+ "Successfully created custom status window\n") # Write to log
log.flush()
except:
PrintException()
def saveCustom(DetailsEntry, StateEntry, useButtons, But1NameEntry, But1LinkEntry, But2NameEntry, But2LinkEntry, ImgEntry, SmallImgEntry, ImgTextEntry, showRunningTime, n):
"""Function used to write user-selected info to a file, so he can use it as a preset whenever he loads app"""
global log
log.write("["+getTime()+"] "+ "User save Preset "+str(n)+"\n") # Write to log
log.flush()
try:
preset = open("preset"+str(n)+".txt","w+") # Create new Preset file (n being the preset number, from 1 to 3)
DetailsEntry = DetailsEntry.get() # Get details
StateEntry = StateEntry.get() # Get State
useButtons = useButtons.get() # Get the usage of buttons
But1NameEntry = But1NameEntry.get() # Get Button 1 name
But1LinkEntry = But1LinkEntry.get() # Get button 1 link
But2NameEntry = But2NameEntry.get() # Get button 2 name
But2LinkEntry = But2LinkEntry.get() # Get button 2 link
ImgEntry = ImgEntry.get() # Get image name
SmallImgEntry = SmallImgEntry.get() # get small image name
ImgTextEntry = ImgTextEntry.get() # Get image text
showRunningTime = showRunningTime.get() # Get the running time option
log.write("["+getTime()+"] "+ "Got all info added by user in window\n") # Write to log
log.flush()
preset.write(str(DetailsEntry)+"\n") # Save details info to preset
preset.write(str(StateEntry)+"\n") # Save state info to preset
preset.write(str(useButtons)+"\n") # Save the usage of buttons info to preset
preset.write(str(But1NameEntry)+"\n") # Save button 1 name info to preset
preset.write(str(But1LinkEntry)+"\n") # Save button 1 link info to preset
preset.write(str(But2NameEntry)+"\n") # Save button 2 name info to preset
preset.write(str(But2LinkEntry)+"\n") # Save button 2 link info to preset
preset.write(str(ImgEntry)+"\n") # Save image name info to preset
preset.write(str(SmallImgEntry)+"\n") # Save small image info to preset
preset.write(str(ImgTextEntry)+"\n") # Save image text info to preset
preset.write(str(showRunningTime)) # Save usage of elapsed time info to preset
log.write("["+getTime()+"] "+ "Saved user info choice to preset "+str(n)+"\n") # Save to log
log.flush()
Custom()
except:
PrintException()
def catchCustom(n):
"""When a user chooses a preset, get the info from preset file"""
global log
log.write("["+getTime()+"] "+ "User chose Preset "+str(n)+"\n") # Write to log
log.flush()
try:
f = open("preset"+str(n)+".txt", "r+") # Open the preset choice (n ranging from 1 to 3)
DetailsEntry = f.readline()[:-1] # Read first line of preset file, Details
StateEntry = f.readline()[:-1] # Read second line of preset file, State
useButtons = f.readline()[:-1] # Read third line of preset file, want to use buttons?
But1NameEntry = f.readline()[:-1] # Read fourth line of preset file, Button 1 Name
But1LinkEntry = f.readline()[:-1] # Read fith line of preset file, Button 1 Link
But2NameEntry = f.readline()[:-1] # Read sixth line of preset file, Button 2 Name
But2LinkEntry = f.readline()[:-1] # Read seventh line of preset file, Button 2 Link
ImgEntry = f.readline()[:-1] # Read eighth line of preset file, Image name
SmallImgEntry = f.readline()[:-1] # Read ninth line of the preset file, small image text
ImgTextEntry = f.readline()[:-1] # Read tenth line of preset file, Image text
showRunningTime = f.readline() # Read the eleventh line of the preset file, usage of elapsed time
log.write("["+getTime()+"] "+ "Accessed preset "+str(n)+" information\n") # Write to log
log.flush()
createCustom(DetailsEntry, StateEntry, useButtons, But1NameEntry, But1LinkEntry, But2NameEntry, But2LinkEntry, ImgEntry, SmallImgEntry, ImgTextEntry, showRunningTime, True, n) # Call the activation of the main custom profile usage
except:
PrintException()
def createCustom(DetailsEntry, StateEntry, useButtons, But1NameEntry, But1LinkEntry, But2NameEntry, But2LinkEntry, ImgEntry, SmallImgEntry, ImgTextEntry, showRunningTime, state, n):
"""Creates the custom discord status loop, using user-provided info"""
global log
constant = time.time() # Time from launch of the command (acts as elapsed game time)
try:
log.write("["+getTime()+"] "+ "Attempting to create system notification\n")
log.flush()
notification.notify(
title='Tray Rich Presence',
message='Rich Presence is still running in tray!\nUse it to hide / show the CMD window!',
app_name='RichPresence',
app_icon='DiscordLogo.' + ('ico' if platform == 'win' else 'png')
)
except:
PrintException()
log.write("["+getTime()+"] "+ "Notification success!\n")
log.flush()
info = open("Identity.txt", "r+")
client_id = info.readline()
RPC = Presence(client_id, pipe=0)
RPC.connect()
# Get all of the info from entries
try:
if state == False: # If presets aren't used
DetailsEntry = str(DetailsEntry.get()) # Get details
StateEntry = str(StateEntry.get()) # Get State
useButtons = useButtons.get() # Get the usage of buttons
But1NameEntry = str(But1NameEntry.get()) # Get Button 1 name
But1LinkEntry = str(But1LinkEntry.get()) # Get button 1 link
But2NameEntry = str(But2NameEntry.get()) # Get button 2 name
But2LinkEntry = str(But2LinkEntry.get()) # Get button 2 link
ImgEntry = str(ImgEntry.get()) # Get image name
SmallImgEntry = str(SmallImgEntry.get()) # Get Small Image name
ImgTextEntry = str(ImgTextEntry.get()) # Get image text
showRunningTime = showRunningTime.get() # Get the running time option
log.write("["+getTime()+"] "+ "Custom values approved as: \nDetails: "+DetailsEntry+"\nState: "+StateEntry+"\nShow Buttons?: "+str(useButtons)+"\nButton 1 Name: "+But1NameEntry+"\nButton 1 Link: "+But1LinkEntry+"\nButton 2 Name: "+But2NameEntry+"\nButton 2 Link: "+But2LinkEntry+"\nImage Name: "+ImgEntry+"\nSmall Image Name: "+SmallImgEntry+"\nImage Text on hover: "+ImgTextEntry+"\nShow elapsed time?: "+str(showRunningTime)+"\n") # Write to log
log.flush()
else: # Presets are used
f = open("preset"+str(n)+".txt", "r+") # Open the preset choice (n ranging from 1 to 3)
DetailsEntry = str(f.readline()[:-1]) # Read first line of preset file, Details
StateEntry = str(f.readline()[:-1]) # Read second line of preset file, State
useButtons = f.readline()[:-1] # Read third line of preset file, want to use buttons?
But1NameEntry = str(f.readline()[:-1]) # Read fourth line of preset file, Button 1 Name
But1LinkEntry = str(f.readline()[:-1]) # Read fith line of preset file, Button 1 Link
But2NameEntry = str(f.readline()[:-1]) # Read sixth line of preset file, Button 2 Name
But2LinkEntry = str(f.readline()[:-1]) # Read seventh line of preset file, Button 2 Link
ImgEntry = str(f.readline()[:-1]) # Read eighth line of preset file, Image name
SmallImgEntry = str(f.readline()[:-1]) # Read ninth line of preset file, Small Image name
ImgTextEntry = str(f.readline()[:-1]) # Read tenth line of preset file, Image text
showRunningTime = f.readline() # Read the eleventh line of the preset file, usage of elapsed time
log.write("["+getTime()+"] "+ "Custom values approved as: \nDetails: "+DetailsEntry+"\nState: "+StateEntry+"\nShow Buttons?: "+str(useButtons)+"\nButton 1 Name: "+But1NameEntry+"\nButton 1 Link: "+But1LinkEntry+"\nButton 2 Name: "+But2NameEntry+"\nButton 2 Link: "+But2LinkEntry+"\nImage Name: "+ImgEntry+"\nSmall Image Name: "+SmallImgEntry+"\nImage Text on hover: "+ImgTextEntry+"\nShow elapsed time?: "+str(showRunningTime)+"\n") # Write to log
except:
PrintException()
window.destroy()
print("Your code is running! Keep this window open to have your status shown!\nCheck the *System Tray* to hide / show this window")
# Check if details were added
if DetailsEntry == "" or DetailsEntry == " " or DetailsEntry == None:
DetailsEntry = None
log.write("["+getTime()+"] "+ "Couldn't find custom details entry - No details will be displayed\n")
log.flush()
# Check if a State was added
if StateEntry == "" or StateEntry == " " or StateEntry == None:
StateEntry = None
log.write("["+getTime()+"] "+ "Couldn't find custom state entry - No state will be displayed\n")
log.flush()
# Check if there is an Image added
if ImgEntry == "" or ImgEntry == " " or ImgEntry == None:
ImgEntry = None
log.write("["+getTime()+"] "+ "Couldn't find custom image entry - No Image will be displayed\n")
log.flush()
elif len(ImgEntry) > 32:
messagebox.showwarning(title = 'Warning', message = "Your Image name is too long! Continuing would break the process.\nMake sure it is equal to or smaller than 32 characters!")
log.write("["+getTime()+"] "+ "Image name was too long (exceeded 32 characters). Process interupted.\n")
log.flush()
leave()
if SmallImgEntry == "" or SmallImgEntry == " " or SmallImgEntry == None:
SmallImgEntry = None
log.write("["+getTime()+"] "+ "Couldn't find custom small image entry - No small image will be displayed\n")
log.flush()
elif len(SmallImgEntry) > 32:
messagebox.showwarning(title = 'Warning', message = "Your Small Image name is too long! Continuing would break the process.\nMake sure it is equal to or smaller than 32 characters!")
log.write("["+getTime()+"] "+ "Small Image name was too long (exceeded 32 characters). Process interupted.\n")
log.flush()
leave()
# Check if there is Image Text added
if ImgTextEntry == "" or ImgTextEntry == " " or ImgTextEntry == None:
ImgTextEntry = None
log.write("["+getTime()+"] "+ "Couldn't find custom image text entry - No text on image will be displayed\n")
log.flush()
# Does the user want to display elapsed time
if showRunningTime == False:
showRunningTime = None
log.write("["+getTime()+"] "+ "Running time None - No elapsed time will be shown\n")
log.flush()
isButton1 = True # Variable used to determine usage of button 1
isButton2 = True # Variable used to determine usage of button 2
try:
if useButtons == True or useButtons == "True" or useButtons == "True " or useButtons == "True\n": # Does the user want to use buttons?
if But1NameEntry == "" or But1NameEntry == " " or But1LinkEntry == "" or But1LinkEntry == " ": # Is anything blank (determines user intentions for button use)
log.write("["+getTime()+"] "+ "Exception found: Button 1 name or Button 1 Link were empty, but user selected buttons, see next line for issue.\n")
log.flush()
isButton1 = False # Did not want to use first button
# Used for extended logging (where is the issue)
if But1LinkEntry == "" or But1LinkEntry == " ":
# Link 1 was empty, but a name was still given
log.write("["+getTime()+"] "+ "Button 1 Name given - No link found (Error)\n")
log.flush()
if But1NameEntry == "" or But1NameEntry == " ":
# Name 1 was empty, but a link was still given
log.write("["+getTime()+"] "+ "Button 1 Link given - No name found (Error)\n")
log.flush()
else:
# Make sure that the link is valid before being added to status
if But1LinkEntry[0:7] == 'http://' or But1LinkEntry[0:8] == 'https://': # Does it start with correct information
url = But1LinkEntry
request = requests.get(url)
if request.status_code == 200: # Test if the link is valid
log.write("["+getTime()+"] "+ "Button 1 Link is valid\n")
log.flush()
else: # Link is not valid, return error
messagebox.showerror(title = 'Error!', message = "Failed to validate link! Use format 'http://{website}.com' or 'https://{website}.com'")
log.write("["+getTime()+"] "+ "Provided Button 1 Link is invalid\n")
log.flush()
else: # http or https was not specified, add https:// to check if it works after
log.write("["+getTime()+"] "+ "Button 1 Link did not include http or https, trying automatic conversion to https\n")
log.flush()
try:
But1LinkEntry = 'https://'+But1LinkEntry
url = But1LinkEntry
request = requests.get(url)
if request.status_code == 200: # Test if the link is valid
log.write("["+getTime()+"] "+ "Link modified and validated!\n")
log.flush()
else: # Link is not valid, return error
messagebox.showerror(title = 'Error!', message = "Failed to validate link! Use format 'http://{website}.com' or 'https://{website}.com'")
log.write("["+getTime()+"] "+ "Error while parsing https: link still invalid - change link.\n")
log.flush()
except:
PrintException()
if But2NameEntry == "" or But2NameEntry == " " or But2LinkEntry == "" or But2LinkEntry == " ": # Is anything blank (determines user intentions)
log.write("["+getTime()+"] "+ "Exception found: Button 2 name or Button 2 Link were empty, but user selected buttons, see next line for issue.\n")
log.flush()
isButton2 = False # Did not want to use second button
# Extended logging for issues
if But2LinkEntry == "" or But2LinkEntry == " ": # Link was given, but no name was specified
log.write("["+getTime()+"] "+ "Button 2 Name given - No Link found (Error)\n")
log.flush()
if But2NameEntry == "" or But2NameEntry == " ": # Name was given, but no link was specified
log.write("["+getTime()+"] "+ "Button 2 Link given - No Name found (Error)\n")
log.flush()
else:
# Make sure link is valid before adding to status
if But2LinkEntry[0:7] == 'http://' or But2LinkEntry[0:8] == 'https://': # if it starts with http:// or https://
url = But2LinkEntry
request = requests.get(url)
if request.status_code == 200: # Check if a page with that is found and valid
log.write("["+getTime()+"] "+ "Button 2 Link is valid\n")
log.flush()
else:
# Print error if that link is invalid
log.write("["+getTime()+"] "+ "Provided Button 2 Link is invalid\n")
log.flush()
messagebox.showerror(title = 'Error!', message = "Failed to validate link! Use format 'http://{website}.com' or 'https://{website}.com'")
else:
# http or https was not specified, add https:// to check if it works better
log.write("["+getTime()+"] "+ "Button 2 Link did not include http or https, trying automatic conversion to https\n")
log.flush()
try:
But2LinkEntry = 'https://'+But2LinkEntry
url = But2LinkEntry
request = requests.get(url)
if request.status_code == 200: # Test if the link is valid
log.write("["+getTime()+"] "+ "Link modified and validated!\n")
log.flush()
else: # Link is not valid, return error
log.write("["+getTime()+"] "+ "Error while parsing https: link still invalid - change link.\n")
log.flush()
messagebox.showerror(title = 'Error!', message = "Failed to validate link! Use format 'http://{website}.com' or 'https://{website}.com'")
except:
PrintException()
# Both buttons want to be used
if isButton1 == True and isButton2 == True:
log.write("["+getTime()+"] "+ "Choice of Button 1 and Button 2 approved\n")
log.flush()
if showRunningTime == None:
log.write("["+getTime()+"] "+ "Choice no elapsed time approved\n")
log.flush()
log.write("["+getTime()+"] "+ "Created loop\n")
log.flush()
log.write("["+getTime()+"] "+ "Started loop - closing log\n")
log.flush()
# Both buttons want to be used, but not elapsed time
while True:
RPC.update(
details=DetailsEntry,
state=StateEntry,
large_image = ImgEntry,
small_image = SmallImgEntry,
large_text = ImgTextEntry,
buttons = [{"label": But1NameEntry, "url": But1LinkEntry}, {"label": But2NameEntry, "url": But2LinkEntry}])
time.sleep(20)
else:
log.write("["+getTime()+"] "+ "Choice elapsed time approved\n")
log.flush()
log.write("["+getTime()+"] "+ "Started loop - closing log\n")
log.flush()
# Both buttons want to be used, and show elapsed time
while True:
RPC.update(
details=DetailsEntry,
state=StateEntry,
large_image = ImgEntry,
small_image = SmallImgEntry,
start = constant,
large_text = ImgTextEntry,
buttons = [{"label": But1NameEntry, "url": But1LinkEntry}, {"label": But2NameEntry, "url": But2LinkEntry}])
time.sleep(20)
# User wants a button 1, but not a button 2
if isButton1 == True and isButton2 == False:
log.write("["+getTime()+"] "+ "Choice of Button 1 approved, Button 2 - disabled\n")
log.flush()
if showRunningTime == None:
log.write("["+getTime()+"] "+ "Choice no elapsed time approved\n")
log.flush()
log.write("["+getTime()+"] "+ "Started loop - closing log\n")
log.flush()
# Show button 1, but not elapsed time
while True:
RPC.update(
details=DetailsEntry,
state=StateEntry,
large_image = ImgEntry,
small_image = SmallImgEntry,
large_text = ImgTextEntry,
buttons = [{"label": But1NameEntry, "url": But1LinkEntry}])
time.sleep(20)
else:
log.write("["+getTime()+"] "+ "Choice elapsed time approved\n")
log.flush()
log.write("["+getTime()+"] "+ "Started loop - closing log\n")
log.flush()
# Show button 1, with elapsed time
while True:
RPC.update(
details=DetailsEntry,
state=StateEntry,
start=constant,
large_image = ImgEntry,
small_image = SmallImgEntry,
large_text = ImgTextEntry,
buttons = [{"label": But1NameEntry, "url": But1LinkEntry}])
time.sleep(20)
# User wants second button, but not first, which reverts to having button 1 enabled but not the second :)
if isButton1 == False and isButton2 == True:
log.write("["+getTime()+"] "+ "Choice Button 1 - disabled, choice Button 2 approved\n")
log.flush()
if showRunningTime == None:
log.write("["+getTime()+"] "+ "Choice no elapsed time approved\n")
log.flush()
log.write("["+getTime()+"] "+ "Started loop - closing log\n")
log.flush()
# Show button 2 (1), but not elapsed time
while True:
RPC.update(
details=DetailsEntry,
state=StateEntry,
large_image = ImgEntry,
small_image = SmallImgEntry,
large_text = ImgTextEntry,
buttons = [{"label": But2NameEntry, "url": But2LinkEntry}])
time.sleep(20)
else:
log.write("["+getTime()+"] "+ "Choice elapsed time approved\n")
log.flush()
log.write("["+getTime()+"] "+ "Started loop - closing log\n")
log.flush()
# Show button 2 (1), with elapsed time
while True:
RPC.update(
details=DetailsEntry,
state=StateEntry,
start=constant,
large_image = ImgEntry,
small_image = SmallImgEntry,
large_text = ImgTextEntry,
buttons = [{"label": But1NameEntry, "url": But1LinkEntry}])
time.sleep(20)
# If the user does not want to use any buttons
else:
log.write("["+getTime()+"] "+ "Choice Button 1 and Button 2 disabled\n")
log.flush()
if showRunningTime == None:
log.write("["+getTime()+"] "+ "Choice no elapsed time approved\n")
log.flush()
log.write("["+getTime()+"] "+ "Started loop - closing log\n")
log.flush()
# Does not show buttons, but also removes elapsed time
while True:
RPC.update(
details=DetailsEntry,
state=StateEntry,
large_image = ImgEntry,
small_image = SmallImgEntry,
large_text = ImgTextEntry)
time.sleep(20)
else:
log.write("["+getTime()+"] "+ "Choice elapsed time approved\n")
log.flush()
log.write("["+getTime()+"] "+ "Started loop - closing log\n")
log.flush()
# Does not show buttons, but includes elapsed time
while True:
RPC.update(
details=DetailsEntry,
state=StateEntry,
start = constant,
large_image = ImgEntry,
small_image = SmallImgEntry,
large_text = ImgTextEntry)
time.sleep(20)
except:
PrintException()
def leave():
"""Exits the program, used for the exit button"""
global log
log.write("["+getTime()+"] "+ "Call exit\n")
log.flush()
sys.exit() # Calls exit function
def close():
"""Function called to close process py.exe when Tray Icon is active"""
os.system("TASKKILL /F /IM py.exe")
for process in (process for process in psutil.process_iter() if process.name()=="py.exe"):
process.kill()
sys.exit()
def getTime():
"""Get local user time, used for the logs."""
global log
try:
return str(datetime.datetime.now()) # Get local time
except:
PrintException()
def checkUpdate():
"""Function used to check if an update is available for RichPresence, by trying to get a file name on the RichPresence website."""
global log
try:
localVer = "2.7.2" # Manually set by code author (Angaros) each new variation
headers = {
"User-Agent": 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36'
}
updateCheck = requests.get(url = 'https://rich-presence-website.vercel.app/'+localVer+'.txt', headers = headers) # Request the version file located on website.
if updateCheck.status_code != 200: # If the file isn't found, client version is not the latest version
messagebox.showwarning(title = 'Warning', message = "You are on version "+localVer+", which is not the latest. You can still use the app, but new functionalities will not be added.")
log.write("["+getTime()+"] "+ "Found user on version "+localVer+". Please consider upgrading (use website).\n") # Write to log
log.flush()
else: # If file is found from website, then user is on latest version
log.write("["+getTime()+"] "+ "Found user on version "+localVer+". You are on the latest version.\n") # Write to log
log.flush()
except:
PrintException()
def checkInternet():
"""Function that checks if user is connected to internet - RichPresence can't work if user is not connected."""
global log
try:
url = "http://www.google.com" # url we will connect to (google has a very high uptime, so if it fails it will usually be user fault.)
timeout = 5 # timeout settings to retry connection
request = requests.get(url, timeout=timeout) # Try to connect to url (google.com) using timeout
except:
messagebox.showerror(title = 'Error', message = "You are not connected to internet, Rich Presence will not work without an active internet connection.") # Tell user he need to be connected
log.write("["+getTime()+"] "+ "User not connected to internet - RichPresence will not work\n") # Write to log
log.flush()
PrintException() # Call error
def PrintException():
"""Function used to save the error whenever an exception is caught, and saves it in logs. Useful for debugging on client platform"""
global log
log = open("mainLog.txt","a") # Re-open log, in case it was previously closed. Won't do anything if already open
exc_type, exc_obj, tb = sys.exc_info()
f = tb.tb_frame
lineno = tb.tb_lineno # Get line number
filename = f.f_code.co_filename # Get file name
linecache.checkcache(filename) # Get line cache
line = linecache.getline(filename, lineno, f.f_globals) # Get globals running (variables are captured)
log.write("["+getTime()+"] "+ 'Error caught in: ({}, LINE {} "{}"): {}, type: {}'.format(filename, lineno, line.strip(), exc_obj, exc_type)) # Get info and write it to log.
log.flush()
leave() # Exceptions indicate fatal issues, leave function must be called.
def NewLog():
"""Checks if mainLog is too large, and have oldLog to contain that info. If more are made, constantly replace the oldLog, and create a blank mainLog. Allows to only have 2 log files, with a max size of 100 KB."""
global log
try:
filesize = os.path.getsize("mainLog.txt") # Get mainLog size
if filesize >= 100000: # If larger than 100 KB.
if os.path.isfile('oldLog.txt'): # oldLog exists
log.close() # close log, to start the conversion (operations can't be made on open file)
os.remove("oldLog.txt") # remove oldLog
os.rename("mainLog.txt", "oldLog.txt") # Move mainLog into oldLog
log = open("mainLog.txt","a") # Make a blank mainLog
else:
log.close() # close log, to start the conversion (operations can't be made on open file)
os.rename("mainLog.txt", "oldLog.txt") # change mainLog to oldLog
log = open("mainLog.txt","a") # create blank mainLog
except:
PrintException()
def start():
global log
try:
log.write("["+getTime()+"] "+ "Starting System Tray\n")
log.flush()
SystemTray.start()
except:
PrintException()
## Program Start
log = open("mainLog.txt","a") # Opens Log file, contains logs (updated in real time)
NewLog() # Check log file size
log.write("\n---------------------------------------New Session started----------------------------------------\n")
log.flush()
try:
info = open("Identity.txt","r+") # Open Identity file, contains user information
log.write("["+getTime()+"] "+ "Accessed Identity file\n")
log.flush()
except:
log.write("["+getTime()+"] "+ "Identity File not found or removed!\n")
log.flush()
PrintException()
filesize = os.path.getsize("Identity.txt") # Gets Identity file size
log.write("["+getTime()+"] "+ "Accessed log file\n")
log.flush()
# Internet connection test
try:
log.write("["+getTime()+"] "+ "Trying to connect to internet\n")
log.flush()
checkInternet()
log.write("["+getTime()+"] "+ "User connected to internet - may proceed\n")
log.flush()
except:
PrintException()
# Try to check for a latest update
try:
log.write("["+getTime()+"] "+ "Checking for latest update!\n")
log.flush()
checkUpdate()
except:
PrintException()
try:
start()
log.write("["+getTime()+"] "+ "Tray mode activated\n")
log.flush()
except:
PrintException()
try:
window.protocol('WM_DELETE_WINDOW', leave) # Remap the "X" button of the tkinter to the leave function
except:
PrintException()
log.write("["+getTime()+"] "+ "Remapped close button\n")
log.flush()
if filesize == 0: # Is Identity empty, if so, ask for User information
log.write("["+getTime()+"] "+ "Identity file is empty - launching first-time setup!\n")
log.flush()
try:
ID = Label(window, text = "What is the application ID?").grid(column = 0, row = 1) # Main label
ID_Entry = Entry(window, width=30) # Enter user application ID (user input area)
ID_Entry.grid(column = 1, row = 1) # add to grid (show on window)
Confirm = Button(window, text="Confirm", command = lambda: confirm(ID_Entry)).grid(column = 0, row = 4) # Create confirm button and add to window
log.write("["+getTime()+"] "+ "Initialized initial setup Menu\n")
log.flush()
except:
PrintException()
else:
# Create main menu pannel selection
MainFrame = Frame(window)
client_id = info.readline()
log.write("["+getTime()+"] "+ "Accessed identity info: \nDiscord Application ID: " + client_id + ".")
log.flush()
try:
Choice = Label(MainFrame, text = "What do you want?").pack(side=TOP) # Main Label
timer = Button(MainFrame, text = "Make a Timer!", command = Timer).pack(side=TOP) # Main Label
local = Button(MainFrame, text = "Show local time!", command = Local).pack(side=TOP) # Local time button
hardware = Button(MainFrame, text = "Show my hardware info!", command = HWINFO).pack(side=TOP) # Hardware Info button
custom = Button(MainFrame, text= "Show a custom status!", command = Custom).pack(side=TOP) # Custom info button
Warn = Label(MainFrame, text = "Warning! Setting any of the previous will crash the program. It will still work though.").pack(side=TOP) # Warning with usage
Exit = Button(MainFrame,text='Exit', command = leave).pack(side=TOP) # Exit button command
Credit = Label(MainFrame, text = "Made by Angaros#1263").pack(side=TOP) # Credits for me
MainFrame.pack(padx=10,pady=10)
log.write("["+getTime()+"] "+ "Initialized Main Menu\n")
log.flush()
except:
PrintException()
# Mainloop for the window frame
window.mainloop()