-
Notifications
You must be signed in to change notification settings - Fork 2
/
RankChangeAnnouncer_StreamlabsSystem.py
230 lines (198 loc) · 8.96 KB
/
RankChangeAnnouncer_StreamlabsSystem.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
#---------------------------------------
# Import Libraries
#---------------------------------------
import os
import codecs
import json
import time
import threading
#---------------------------------------
# [Required] Script Information
#---------------------------------------
ScriptName = "Rank Change Announcer"
Website = "https://www.github.com/hyperneon"
Creator = "GameTangent"
Version = "1.4.2"
Description = "Announce in chat when a user changes ranks"
#---------------------------------------
# Set Variables
#---------------------------------------
SettingsFile = os.path.join(os.path.dirname(__file__), "RCASettings.json")
#---------------------------------------
# Classes
#---------------------------------------
class Settings(object):
""" Load in saved settings file if available else set default values. """
def __init__(self, settingsfile=None):
try:
with codecs.open(settingsfile, encoding="utf-8-sig", mode="r") as f:
self.__dict__ = json.load(f, encoding="utf-8")
except:
self.rank_up_message = "KAPOW Congrats to {0} for LEVELING UP to {1} KAPOW"
self.rank_down_message = "FailFish {0} is slacking and leveled down to {1} FailFish"
self.announcer_timer = 30
self.rank_system = "Points"
self.use_streamlabs_currency = False
self.announce_rank_ups = True
self.announce_rank_downs = False
self.announce_lurkers = False
def reload(self, jsondata):
""" Reload settings from Chatbot user interface by given json data. """
self.__dict__ = json.loads(jsondata, encoding="utf-8")
return
def save(self, settingsfile):
""" Save settings contained within to .json and .js settings files. """
try:
with codecs.open(settingsfile, encoding="utf-8-sig", mode="w+") as f:
json.dump(self.__dict__, f, encoding="utf-8")
with codecs.open(settingsfile.replace("json", "js"), encoding="utf-8-sig", mode="w+") as f:
f.write("var settings = {0};".format(json.dumps(self.__dict__, encoding='utf-8')))
except:
Parent.Log(ScriptName, "Failed to save settings to file.")
return
#---------------------------------------
# Functions
#---------------------------------------
def ProcessAndSendAlerts():
""" Processes the ranks in a thread """
# Globals
global LastRunTime
global LastRankList
new_ranks = GetRankList()
rank_changes = CalculateRankChanges(new_ranks, LastRankList)
# Iterate over each rank_change and send chat messages if enabled
for name, rank_details in rank_changes.items():
if rank_details['level_up']:
if ScriptSettings.announce_rank_ups:
Parent.SendTwitchMessage(ScriptSettings.rank_up_message.format(name, rank_details['rank']))
else:
if ScriptSettings.announce_rank_downs:
Parent.SendTwitchMessage(ScriptSettings.rank_down_message.format(name, rank_details['rank']))
# Save new rank list to LastRankList for next time
LastRankList = new_ranks
# Set new timestamp
LastRunTime = time.time()
return
def GetRankList():
"""
GetRankList is a function that retrieves the full list of viewers and then looks up their
ranks and points. It returns a dictionary with the following structure:
{user_name: {'rank': rank, 'points': points}}
If ScriptSettings.announce_lurkers is false it will only return active users
"""
# If announce_lurkers is true then get the full Viewer list
if ScriptSettings.announce_lurkers:
viewers = Parent.GetViewerList()
else:
viewers = Parent.GetActiveUsers()
ranks = BuildRankHash(viewers)
points = Parent.GetPointsAll(viewers)
rank_list = {}
for id in viewers:
try:
rank_list[Parent.GetDisplayName(id)] = {'rank': ranks[id], 'points': points[id]}
except:
Parent.Log(ScriptName, "Failed to get Rank or Points for UserID: " + id + " Please check if the user exists in the Users tab")
continue
return rank_list
def BuildRankHash(viewers):
"""
Since the introduction of the StreamLabs Chatbot, GetRanksAll no longer works if the bot is set
to use Streamlabs Extension Currency. As a workaround, we can build the PythonDictionary ourselves one by one
at the cost of performance. We only need to do this if use_streamlabs_currency == true.
"""
if ScriptSettings.use_streamlabs_currency:
# Build the rank dictionary
ranks = {}
for name in viewers:
ranks[name] = Parent.GetRank(name)
else:
# The original GetRanksAll method still works with legacy currency so just return it
ranks = Parent.GetRanksAll(viewers)
return ranks
def CalculateRankChanges(new_ranks, old_ranks):
"""
CalculateRankChanges is a function which compares 2 dictionaries of ranks and finds
those items which are present in both sets AND whose ranks have changed. It then
compares the point values in each set to determine if the rank has gone up or down.
It returns a dictionary with the following structure:
{user_name: {'rank': new_rank, 'level_up': True/False}}
"""
# Get only names in both sets as new names may have just joined chat and not actually changed rank
intersect = set(new_ranks) & set(old_ranks)
rank_changes = {}
for name in intersect:
new_rank = new_ranks[name]
old_rank = old_ranks[name]
# Add rank to list if new rank title is different from old title
if new_rank['rank'] != old_rank['rank']:
# Leveling up if new points are higher than old points
# If we're using an Hours based system then we'll always level up
if ScriptSettings.rank_system == "Hours" or new_rank['points'] >= old_rank['points']:
rank_changes[name] = {'rank': new_rank['rank'], 'level_up': True}
else:
rank_changes[name] = {'rank': new_rank['rank'], 'level_up': False}
return rank_changes
#---------------------------------------
# [Required] Intialize Data (Only called on Load)
#---------------------------------------
def Init():
"""
Init is a required function and is called the script is being loaded into memory
and becomes active. In here you can initialize any data your script will require,
for example read the settings file for saved settings.
"""
# Globals
global ScriptSettings
global LastRunTime
global LastRankList
# Load in saved settings
ScriptSettings = Settings(SettingsFile)
# Set LastRunTime to now
LastRunTime = time.time()
# Initialize With The Current Rank List
LastRankList = GetRankList()
# End of Init
return
#---------------------------------------
# Reload Settings on Save
#---------------------------------------
def ReloadSettings(jsondata):
"""
ReloadSettings is an optional function that gets called once the user clicks on
the Save Settings button of the corresponding script in the scripts tab if an
user interface has been created for said script. The entire Json object will be
passed to the function so you can load that back into your settings without
having to read the newly saved settings file.
"""
# Globals
global ScriptSettings
# Reload newly saved settings
ScriptSettings.reload(jsondata)
# End of ReloadSettings
return
#---------------------------------------
# [Required] Execute Data / Process Messages
#---------------------------------------
def Execute(data):
"""
Execute is a required function that gets called when there is new data to be
processed. Like a Twitch or Discord chat messages or even raw data send from
Twitch IRC. This function will _not_ be called when the user disabled the script
with the switch on the user interface.
"""
return
#---------------------------------------
# [Required] Tick Function
#---------------------------------------
def Tick():
"""
Tick is a required function and will be called every time the program progresses.
This can be used for example to create simple timer if you want to do let the
script do something on a timed basis.This function will _not_ be called when the
user disabled the script with the switch on the user interface.
"""
# Only run check if it's been more than the announcer_timer limit since the LastRunTime
if time.time() - LastRunTime >= ScriptSettings.announcer_timer:
threading.Thread(target=ProcessAndSendAlerts).start()
return