Passed
Push — master ( e2662a...8b3758 )
by manny
01:50
created

racetime_obs.fill_race_list()   B

Complexity

Conditions 7

Size

Total Lines 17
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 17
rs 8
c 0
b 0
f 0
cc 7
nop 3
1
from threading import Thread
2
import obspython as obs
3
import racetime_client
4
from rtgg_obs import RacetimeObs
5
from helpers.obs_context_manager import source_ar, source_list_ar, data_ar
6
7
rtgg_obs = RacetimeObs()
8
9
def script_description():
10
    return "<center><p>Select a text source to use as your timer and enter your full " + \
11
        "username on racetime.gg  (including discriminator). This only needs " + \
12
        "to be done once.\n\nThen select the race room each race you join and " + \
13
        "stop worrying about whether you started your timer or not.<hr/></p>"
14
15
16
def script_load(settings):
17
    rtgg_obs.timer.use_podium_colors = obs.obs_data_get_bool(settings, "use_podium")
18
19
    race_update_t = Thread(target=rtgg_obs.race_update_thread)
20
    race_update_t.daemon = True
21
    race_update_t.start()
22
23
24
def script_save(settings):
25
    obs.obs_data_set_bool(settings, "use_podium", rtgg_obs.timer.use_podium_colors)
26
27
def script_update(settings):
28
    script_update_setup_settings(settings)
29
    script_update_timer_settings(settings)
30
    script_update_coop_settings(settings)
31
    script_update_qualifier_settings(settings)
32
33
def script_update_qualifier_settings(settings):
34
    rtgg_obs.qualifier.enabled = obs.obs_data_get_bool(settings, "use_qualifier")
35
    rtgg_obs.qualifier.qualifier_cutoff = obs.obs_data_get_int(settings, "qualifier_cutoff")
36
    rtgg_obs.logger.debug(f"qualifier_cutoff is {rtgg_obs.qualifier.qualifier_cutoff}")
37
    rtgg_obs.qualifier.qualifier_par_source = obs.obs_data_get_string(
38
        settings, "qualifier_par_source")
39
    rtgg_obs.qualifier.qualifier_score_source = obs.obs_data_get_string(
40
        settings, "qualifier_score_source")
41
42
def script_update_coop_settings(settings):
43
    rtgg_obs.coop.enabled = obs.obs_data_get_bool(settings, "use_coop")
44
    rtgg_obs.coop.partner = obs.obs_data_get_string(settings, "coop_partner")
45
    rtgg_obs.coop.opponent1 = obs.obs_data_get_string(settings, "coop_opponent1")
46
    rtgg_obs.coop.opponent2 = obs.obs_data_get_string(settings, "coop_opponent2")
47
    rtgg_obs.coop.source_name = obs.obs_data_get_string(settings, "coop_source")
48
    rtgg_obs.coop.label_source_name = obs.obs_data_get_string(settings, "coop_label")
49
50
def script_update_timer_settings(settings):
51
    obs.timer_remove(update_sources)
52
53
    rtgg_obs.timer.use_podium_colors = obs.obs_data_get_bool(settings, "use_podium")
54
    rtgg_obs.timer.pre_color = obs.obs_data_get_int(settings, "pre_color")
55
    rtgg_obs.timer.first_color = obs.obs_data_get_int(settings, "first_color")
56
    rtgg_obs.timer.second_color = obs.obs_data_get_int(settings, "second_color")
57
    rtgg_obs.timer.third_color = obs.obs_data_get_int(settings, "third_color")
58
    rtgg_obs.timer.racing_color = obs.obs_data_get_int(settings, "racing_color")
59
    rtgg_obs.timer.finished_color = obs.obs_data_get_int(settings, "finished_color")
60
61
    if rtgg_obs.timer.source_name != "" and rtgg_obs.selected_race != "":
62
        obs.timer_add(update_sources, 100)
63
        rtgg_obs.timer.enabled = True
64
    else:
65
        rtgg_obs.timer.enabled = False
66
    rtgg_obs.logger.debug(f"timer.enabled is {rtgg_obs.timer.enabled}")
67
    rtgg_obs.logger.debug(f"timer.source_name is {rtgg_obs.timer.source_name}")
68
    rtgg_obs.logger.debug(f"selected_race is {rtgg_obs.selected_race}")
69
70
def script_update_setup_settings(settings):
71
    rtgg_obs.update_logger(obs.obs_data_get_bool(settings, "enable_log"),
72
        obs.obs_data_get_bool(settings, "log_to_file"),
73
        obs.obs_data_get_string(settings, "log_file"), 
74
        obs.obs_data_get_string(settings, "log_level"))
75
76
    rtgg_obs.full_name = obs.obs_data_get_string(settings, "username")
77
78
    rtgg_obs.timer.source_name = obs.obs_data_get_string(settings, "source")
79
80
    rtgg_obs.selected_race = obs.obs_data_get_string(settings, "race")
81
    rtgg_obs.category = obs.obs_data_get_string(settings, "category_filter")
82
83
84
def script_defaults(settings):
85
    obs.obs_data_set_default_string(settings, "race_info", "Race info")
86
    obs.obs_data_set_default_string(settings, "race", "")
87
88
def script_properties():
89
    props = obs.obs_properties_create()
90
    script_setup(props)
91
    script_timer_settings(props)
92
    script_coop_settings(props)
93
    script_qualifier_settings(props)
94
95
    return props
96
97
def script_qualifier_settings(props):
98
    p = obs.obs_properties_add_bool(
99
        props, "use_qualifier", "Display race results as tournament qualifier?")
100
    obs.obs_property_set_modified_callback(p, qualifier_toggled)
101
    qualifier_group = obs.obs_properties_create()
102
    obs.obs_properties_add_group(
103
        props, "qualifier_group", "Qualifier Mode", obs.OBS_GROUP_NORMAL, qualifier_group)
104
    obs.obs_property_set_visible(
105
        obs.obs_properties_get(props, "qualifier_group"), rtgg_obs.qualifier.enabled)
106
    p = obs.obs_properties_add_int_slider(
107
        qualifier_group, "qualifier_cutoff", "Use Top X as par time, where X=", 3, 10, 1)
108
    p = obs.obs_properties_add_list(qualifier_group, "qualifier_par_source",
109
                                    "Qualifier Par Time Source", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)
110
    rtgg_obs.fill_source_list(p)
111
    p = obs.obs_properties_add_list(qualifier_group, "qualifier_score_source",
112
                                    "Qualifier Score Source", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)
113
    rtgg_obs.fill_source_list(p)
114
115
def script_coop_settings(props):
116
    p = obs.obs_properties_add_bool(
117
        props, "use_coop", "Display coop information?")
118
    obs.obs_property_set_modified_callback(p, coop_toggled)
119
    coop_group = obs.obs_properties_create()
120
    obs.obs_properties_add_group(
121
        props, "coop_group", "Co-op Mode", obs.OBS_GROUP_NORMAL, coop_group)
122
    obs.obs_property_set_visible(
123
        obs.obs_properties_get(props, "coop_group"), rtgg_obs.coop.enabled)
124
    p = obs.obs_properties_add_list(
125
        coop_group, "coop_partner", "Co-op Partner", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING)
126
    p = obs.obs_properties_add_list(
127
        coop_group, "coop_opponent1", "Co-op Opponent 1", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING)
128
    p = obs.obs_properties_add_list(
129
        coop_group, "coop_opponent2", "Co-op Opponent 2", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING)
130
    rtgg_obs.fill_coop_entrant_lists(props)
131
    p = obs.obs_properties_add_list(coop_group, "coop_source", "Coop Text Source",
132
                                    obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)
133
    obs.obs_property_set_long_description(
134
        p, "This text source will display the time that the last racer needs to finish for their team to win")
135
    rtgg_obs.fill_source_list(p)
136
    p = obs.obs_properties_add_list(coop_group, "coop_label", "Coop Label Text Source",
137
                                    obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)
138
    obs.obs_property_set_long_description(
139
        p, "This text source will be use to display a label such as \'<PartnerName> needs to finish before\' based on who the last racer is")
140
    rtgg_obs.fill_source_list(p)
141
142
def script_timer_settings(props):
143
    p = obs.obs_properties_add_bool(props, "use_podium", "Use custom color for podium finishes?")
144
    obs.obs_property_set_modified_callback(p, podium_toggled)
145
    podium_group = obs.obs_properties_create()
146
    obs.obs_properties_add_group(
147
        props, "podium_group", "Podium Colors", obs.OBS_GROUP_NORMAL, podium_group)
148
    obs.obs_property_set_visible(obs.obs_properties_get(
149
        props, "podium_group"), rtgg_obs.timer.use_podium_colors)
150
    obs.obs_properties_add_color(podium_group, "pre_color", "Pre-race:")
151
    obs.obs_properties_add_color(podium_group, "racing_color", "Still racing:")
152
    obs.obs_properties_add_color(podium_group, "first_color", "1st place:")
153
    obs.obs_properties_add_color(podium_group, "second_color", "2nd place:")
154
    obs.obs_properties_add_color(podium_group, "third_color", "3rd place:")
155
    obs.obs_properties_add_color(
156
        podium_group, "finished_color", "After podium:")
157
158
def script_setup(props):
159
    setup_group = obs.obs_properties_create()
160
    obs.obs_properties_add_group(
161
        props, "initial_setup", "Initial setup - Check to make changes", obs.OBS_GROUP_CHECKABLE, setup_group)
162
    p = obs.obs_properties_add_list(
163
        setup_group, "source", "Text Source", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)
164
    rtgg_obs.fill_source_list(p)
165
    obs.obs_properties_add_text(
166
        setup_group, "username", "Username", obs.OBS_TEXT_DEFAULT)
167
    logging = obs.obs_properties_add_bool(
168
        setup_group, "enable_log", "Enable logging")
169
    log_levels = obs.obs_properties_add_list(
170
        setup_group, "log_level", "Log lever", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING)
171
    obs.obs_property_list_add_string(log_levels, "Error", "Error")
172
    obs.obs_property_list_add_string(log_levels, "Debug", "Debug")
173
    obs.obs_property_list_add_string(log_levels, "Info", "Info")
174
    obs.obs_property_set_long_description(
175
        logging, "Generally, only log errors unless you are developing or are trying to find a specific problem.")
176
    obs.obs_properties_add_bool(setup_group, "log_to_file", "Log to file?")
177
    category_list = obs.obs_properties_add_list(
178
        props, "category_filter", "Filter by Category", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING)
179
    race_list = obs.obs_properties_add_list(
180
        props, "race", "Race", obs.OBS_COMBO_TYPE_LIST, obs.OBS_COMBO_FORMAT_STRING)
181
    obs.obs_property_set_modified_callback(race_list, new_race_selected)
182
    obs.obs_property_set_modified_callback(
183
        category_list, new_category_selected)
184
185
    p = obs.obs_properties_add_text(
186
        props, "race_info", "Race Desc", obs.OBS_TEXT_MULTILINE)
187
    obs.obs_property_set_enabled(p, False)
188
189
    refresh = obs.obs_properties_add_button(
190
        props, "button", "Refresh", lambda *props: None)
191
    obs.obs_property_set_modified_callback(refresh, refresh_pressed)
192
193
def refresh_pressed(props, prop, *args, **kwargs):
194
    rtgg_obs.fill_source_list(obs.obs_properties_get(props, "source"))
195
    rtgg_obs.fill_source_list(obs.obs_properties_get(props, "coop_label"))
196
    rtgg_obs.fill_source_list(obs.obs_properties_get(props, "coop_text"))
197
    rtgg_obs.fill_source_list(obs.obs_properties_get(props, "qualifier_par_source"))
198
    rtgg_obs.fill_source_list(obs.obs_properties_get(props, "qualifier_score_source"))
199
    rtgg_obs.fill_race_list(obs.obs_properties_get(props, "race"),
200
                obs.obs_properties_get(props, "category_filter"))
201
    if rtgg_obs.race is not None:
202
        rtgg_obs.coop.update_coop_text(rtgg_obs.race, rtgg_obs.full_name)
203
        rtgg_obs.qualifier.update_qualifier_text(rtgg_obs.race, rtgg_obs.full_name)
204
    return True
205
206
207
def new_race_selected(props, prop, settings):
208
    rtgg_obs.selected_race = obs.obs_data_get_string(settings, "race")
209
    r = racetime_client.get_race(rtgg_obs.selected_race)
210
    if r is not None:
211
        rtgg_obs.race = r
212
        rtgg_obs.coop.update_coop_text(rtgg_obs.race, rtgg_obs.full_name)
213
        rtgg_obs.qualifier.update_qualifier_text(rtgg_obs.race, rtgg_obs.full_name)
214
        rtgg_obs.logger.info(f"new race selected: {rtgg_obs.race}")
215
        obs.obs_data_set_default_string(settings, "race_info", r.info)
216
        rtgg_obs.fill_coop_entrant_lists(props)
217
    else:
218
        obs.obs_data_set_default_string(
219
            settings, "race_info", "Race not found")
220
221
    rtgg_obs.race_changed = True
222
    return True
223
224
225
def new_category_selected(props, prop, settings):
226
    rtgg_obs.category = obs.obs_data_get_string(settings, "category_filter")
227
    rtgg_obs.logger.info(f"new category selected: {rtgg_obs.category}")
228
    rtgg_obs.fill_race_list(obs.obs_properties_get(props, "race"), prop)
229
    return True
230
231
232
def podium_toggled(props, prop, settings):
233
    vis = obs.obs_data_get_bool(settings, "use_podium")
234
    obs.obs_property_set_visible(
235
        obs.obs_properties_get(props, "podium_group"), vis)
236
    return True
237
238
239
def coop_toggled(props, prop, settings):
240
    vis = obs.obs_data_get_bool(settings, "use_coop")
241
    obs.obs_property_set_visible(
242
        obs.obs_properties_get(props, "coop_group"), vis)
243
    return True
244
245
246
def qualifier_toggled(props, prop, settings):
247
    vis = obs.obs_data_get_bool(settings, "use_qualifier")
248
    obs.obs_property_set_visible(
249
        obs.obs_properties_get(props, "qualifier_group"), vis)
250
    return True
251
252
def update_sources():
253
    if rtgg_obs.race is not None:
254
        if rtgg_obs.timer.enabled:
255
            color, time = rtgg_obs.timer.get_timer_text(rtgg_obs.race, rtgg_obs.full_name)
256
            set_source_text(rtgg_obs.timer.source_name, time, color)
257
        if rtgg_obs.coop.enabled:
258
            set_source_text(rtgg_obs.coop.source_name, rtgg_obs.coop.text, None)
259
            set_source_text(rtgg_obs.coop.label_source_name, rtgg_obs.coop.label_text, None)
260
        if rtgg_obs.qualifier.enabled:
261
            set_source_text(rtgg_obs.qualifier.qualifier_par_source, rtgg_obs.qualifier.qualifier_par_text, None)
262
            set_source_text(rtgg_obs.qualifier.qualifier_score_source, rtgg_obs.qualifier.entrant_score, None)
263
        pass
264
265
def fill_source_list(p):
266
    obs.obs_property_list_clear(p)
267
    obs.obs_property_list_add_string(p, "", "")
268
    with source_list_ar() as sources:
269
        if sources is not None:
270
            for source in sources:
271
                source_id = obs.obs_source_get_unversioned_id(source)
272
                if source_id == "text_gdiplus" or source_id == "text_ft2_source":
273
                    name = obs.obs_source_get_name(source)
274
                    obs.obs_property_list_add_string(p, name, name)
275
276
def fill_race_list(self, race_list, category_list):
277
    obs.obs_property_list_clear(race_list)
278
    obs.obs_property_list_clear(category_list)
279
    obs.obs_property_list_add_string(category_list, "All", "All")
280
281
    obs.obs_property_list_add_string(race_list, "", "")
282
    races = racetime_client.get_races()
283
    if races is not None:
284
        categories = []
285
        for race in races:
286
            if self.category == "" or self.category == "All" or race.category.name == self.category:
287
                obs.obs_property_list_add_string(
288
                    race_list, race.name, race.name)
289
            if not race.category.name in categories:
290
                categories.append(race.category.name)
291
                obs.obs_property_list_add_string(
292
                    category_list, race.category.name, race.category.name)
293
294
295
def fill_coop_entrant_lists(self, props):
296
    self.fill_entrant_list(obs.obs_properties_get(props, "coop_partner"))
297
    self.fill_entrant_list(obs.obs_properties_get(props, "coop_opponent1"))
298
    self.fill_entrant_list(obs.obs_properties_get(props, "coop_opponent2"))
299
300
301
def fill_entrant_list(self, entrant_list):
302
    obs.obs_property_list_clear(entrant_list)
303
    obs.obs_property_list_add_string(entrant_list, "", "")
304
    if self.race is not None:
305
        for entrant in self.race.entrants:
306
            obs.obs_property_list_add_string(
307
                entrant_list, entrant.user.full_name, entrant.user.full_name)
308
309
# copied and modified from scripted-text.py by UpgradeQ
310
311
def set_source_text(source_name: str, text: str, color: int):
312
    with source_ar(source_name) as source, data_ar() as settings:
313
        obs.obs_data_set_string(settings, "text", text)
314
        source_id = obs.obs_source_get_unversioned_id(source)
315
        if color is not None:
316
            if source_id == "text_gdiplus":
317
                obs.obs_data_set_int(settings, "color", color)  # colored text
318
319
            else:  # freetype2,if taken from user input it should be reversed for getting correct color
320
                number = "".join(hex(color)[2:])
321
                color = int("0xff" f"{number}", base=16)
322
                obs.obs_data_set_int(settings, "color1", color)
323
        
324
        obs.obs_source_update(source, settings)