Initial Commit

Initial commit of Code Base.
This commit is contained in:
Mario Steele 2025-06-12 14:31:14 -05:00
parent 293b1213e1
commit c11a4ebbc2
653 changed files with 36893 additions and 1 deletions

View file

@ -0,0 +1,37 @@
extends EditorInspectorPlugin
const EventsubConfigProperty = preload("res://addons/twitcher/editor/inspector/twitch_eventsub_config_property.gd")
func _can_handle(object: Object) -> bool:
return object is TwitchEventsubConfig
func _parse_property(object: Object, type: Variant.Type, name: String, \
hint_type: PropertyHint, hint_string: String, usage_flags: int, \
wide: bool) -> bool:
if name == &"condition":
add_property_editor("condition", EventsubConfigProperty.new(), true)
return true
if name == &"type":
add_property_editor("type", ToDocs.new(), true, "Documentation")
return false
class ToDocs extends EditorProperty:
const EXT_LINK = preload("res://addons/twitcher/assets/ext-link.svg")
var docs = Button.new()
func _init() -> void:
docs.text = "To dev.twitch.tv"
docs.icon = EXT_LINK
docs.pressed.connect(_on_to_docs)
add_child(docs)
add_focusable(docs)
func _on_to_docs() -> void:
var eventsub_config: TwitchEventsubConfig = get_edited_object()
OS.shell_open(eventsub_config.definition.documentation_link)

View file

@ -0,0 +1 @@
uid://c1afm3xjonwxr

View file

@ -0,0 +1,75 @@
extends EditorProperty
const USER_CONVERTER = preload("res://addons/twitcher/editor/inspector/user_converter.tscn")
const TwitchEditorSettings = preload("res://addons/twitcher/editor/twitch_editor_settings.gd")
var _container: Node = GridContainer.new()
func _init():
_container.columns = 2
add_child(_container)
set_bottom_editor(_container)
func _on_type_change(new_type: TwitchEventsubDefinition.Type) -> void:
var eventsub_config: TwitchEventsubConfig = get_edited_object();
if eventsub_config != null:
for meta in eventsub_config.get_meta_list():
if meta.ends_with("_user"):
eventsub_config.remove_meta(meta)
_create_conditions()
func _update_property() -> void:
_create_conditions()
func _create_conditions() -> void:
for node in _container.get_children():
node.queue_free()
var eventsub_config: TwitchEventsubConfig = get_edited_object();
if eventsub_config == null || eventsub_config.get_class() == &"EditorDebuggerRemoteObject": return
for condition_name: StringName in eventsub_config.definition.conditions:
var condition_value = eventsub_config.condition.get_or_add(condition_name, "")
var condition_title = Label.new()
condition_title.text = condition_name.capitalize()
_container.add_child(condition_title)
var editor_token = TwitchEditorSettings.editor_oauth_token
if condition_name.to_lower().ends_with("user_id") && editor_token.is_token_valid():
var user_converter = USER_CONVERTER.instantiate()
user_converter.changed.connect(_on_changed_user.bind(condition_name))
_container.add_child(user_converter)
if eventsub_config.has_meta(condition_name + "_user"):
var user = eventsub_config.get_meta(condition_name + "_user")
user_converter.update_user(user)
elif condition_value != "":
user_converter.user_id = condition_value
user_converter.reload()
else:
var input = LineEdit.new()
input.text_submitted.connect(_on_change_text.bind(condition_name, input))
input.focus_exited.connect(_on_change_text.bind("", condition_name, input))
input.text = condition_value
input.size_flags_horizontal = Control.SIZE_EXPAND_FILL
_container.add_child(input)
func _on_changed_user(user: TwitchUser, condition_name: StringName) -> void:
var eventsub_config: TwitchEventsubConfig = get_edited_object();
if user == null:
eventsub_config.condition[condition_name] = ""
eventsub_config.remove_meta(condition_name + "_user")
emit_changed(&"condition", eventsub_config.condition)
else:
eventsub_config.condition[condition_name] = user.id
eventsub_config.set_meta(condition_name + "_user", user)
emit_changed(&"condition", eventsub_config.condition)
func _on_change_text(new_text: String, condition_name: StringName, input: LineEdit) -> void:
print("BLUB")
var eventsub_config: TwitchEventsubConfig = get_edited_object();
eventsub_config.condition[condition_name] = input.text
#emit_changed(&"condition", eventsub_config.condition)

View file

@ -0,0 +1 @@
uid://drv4gmn8akxf2

View file

@ -0,0 +1,83 @@
extends EditorInspectorPlugin
func _can_handle(object: Object) -> bool:
return object is TwitchEventsub || object is TwitchService
func _parse_property(object: Object, type: Variant.Type, name: String, hint_type: PropertyHint, hint_string: String, usage_flags: int, wide: bool) -> bool:
if name == &"scopes" && object.get_class() != &"EditorDebuggerRemoteObject":
if (object is TwitchService && object.eventsub != null) || object is TwitchEventsub:
add_property_editor(&"scope_validation", ScopeValidation.new(), true, "Scope Validation")
return false
class ScopeValidation extends EditorProperty:
const WARNING_LABEL_SETTINGS = preload("res://addons/twitcher/assets/warning_label_settings.tres")
const INFO_LABEL_SETTINGS = preload("res://addons/twitcher/assets/info_label_settings.tres")
var _warning_label: Label = Label.new();
var _apply_scopes: Button = Button.new();
var _needed_scopes: Dictionary = {}
var container: Control = VBoxContainer.new()
func _init():
_warning_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
_warning_label.text = "Press validate to check if scopes maybe are missing."
var validate_button = Button.new();
validate_button.text = "Validate";
validate_button.tooltip_text = "Checks the scopes of the subscriptions " \
+ " if they match the defined scopes in the scope " \
+ " property";
validate_button.pressed.connect(_on_validate_scopes);
_apply_scopes.text = "Apply Scopes";
_apply_scopes.tooltip_text = "Apply Scopes to the scope resource in " \
+ " this TwitchEventsub. It maybe not needed depending on the " \
+ " Subscription. Please check the documentation if there is a logical " \
+ " condition and apply the scopes accordingly.";
_apply_scopes.pressed.connect(_on_apply_scopes);
add_child(validate_button)
container.add_child(_warning_label)
add_child(container)
set_bottom_editor(container)
func _on_apply_scopes() -> void:
var scopes = get_edited_object().scopes;
var scopes_to_add: Array[StringName] = [];
for scope in _needed_scopes.values():
scopes_to_add.append(scope);
scopes.add_scopes(scopes_to_add);
_clear_warning();
func _on_validate_scopes() -> void:
var scopes = get_edited_object().scopes;
var subscriptions = get_edited_object().get_subscriptions();
_needed_scopes.clear()
for subscription: TwitchEventsubConfig in subscriptions:
if subscription == null: continue
for scope in subscription.definition.scopes:
_needed_scopes[scope] = scope
for scope in scopes.used_scopes:
_needed_scopes.erase(scope)
if !_needed_scopes.is_empty():
if _apply_scopes.get_parent() == null: container.add_child(_apply_scopes)
_warning_label.label_settings = WARNING_LABEL_SETTINGS
var needed_scopes = ", ".join(_needed_scopes.values())
_warning_label.text = "You may miss scopes please check documentation if you need to add: %s" % needed_scopes;
else:
_clear_warning()
func _clear_warning() -> void:
_warning_label.text = "Scopes seems to be OK for this EventSub."
_warning_label.label_settings = INFO_LABEL_SETTINGS
if _apply_scopes.get_parent() != null:
container.remove_child(_apply_scopes)

View file

@ -0,0 +1 @@
uid://cuo2g5oib1cf3

View file

@ -0,0 +1,46 @@
@tool
extends EditorInspectorPlugin
func _can_handle(object: Object) -> bool:
return object is TwitchMediaLoader
func _parse_property(object: Object, type: Variant.Type, name: String, hint_type: PropertyHint, hint_string: String, usage_flags: int, wide: bool) -> bool:
if name == &"cache_emote":
var clear_emote_button = ClearCacheEditor.new(object.cache_emote)
add_property_editor("cache_cheermote", clear_emote_button, true, "Clear Emote Cache")
if name == &"cache_badge":
var clear_badge_button = ClearCacheEditor.new(object.cache_badge)
add_property_editor("cache_cheermote", clear_badge_button, true, "Clear Badge Cache")
if name == &"cache_cheermote":
var clear_cheermote_button = ClearCacheEditor.new(object.cache_cheermote)
add_property_editor("cache_cheermote", clear_cheermote_button, true, "Clear Cheermotes Cache")
return false
class ClearCacheEditor extends EditorProperty:
var _button: Button
func _init(path: String) -> void:
_button = Button.new()
_button.text = "Clear"
_button.pressed.connect(_clear.bind(path))
add_child(_button)
func _clear(path: String) -> void:
var dir: DirAccess = DirAccess.open(path)
for file: String in dir.get_files():
if file.ends_with(".res"):
var err: Error = dir.remove(file)
if err != OK:
push_error("Can't delete %s/%s cause of %s" % [dir, file, error_string(err)])
var tween = create_tween()
var _button_color = _button.modulate
tween.tween_property(_button, "modulate", Color.GREEN, .25)
tween.tween_property(_button, "modulate", _button_color, .25)
tween.play()

View file

@ -0,0 +1 @@
uid://be76dqjl123t8

View file

@ -0,0 +1,91 @@
extends RefCounted
## Helper class for easier editing of Project Settings
class_name TwitchProperty
var key: String;
var default_value: Variant;
func _init(k: String, default_val: Variant = "") -> void:
key = k;
default_value = default_val;
_add_property()
func _add_property():
if not ProjectSettings.has_setting(key):
ProjectSettings.set_setting(key, default_value);
ProjectSettings.set_initial_value(key, default_value);
func get_val() -> Variant:
return ProjectSettings.get_setting_with_override(key);
func set_val(val) -> void:
ProjectSettings.set(key, val);
func basic() -> TwitchProperty:
ProjectSettings.set_as_basic(key, true);
return self;
func as_str(description: String = "") -> TwitchProperty:
return _add_type_def(TYPE_STRING, PROPERTY_HINT_PLACEHOLDER_TEXT, description);
func as_select(values: Array[String], optional: bool = true) -> TwitchProperty:
var hint_string = ",".join(values);
var enum_hint = PROPERTY_HINT_ENUM;
if optional: enum_hint = PROPERTY_HINT_ENUM_SUGGESTION;
return _add_type_def(TYPE_STRING, enum_hint, hint_string);
func as_bit_field(values: Array[String]) -> TwitchProperty:
var hint_string = ",".join(values);
return _add_type_def(TYPE_INT, PROPERTY_HINT_FLAGS, hint_string);
func as_password(description: String = "") -> TwitchProperty:
return _add_type_def(TYPE_STRING, PROPERTY_HINT_PASSWORD, description);
func as_bool(description: String = "") -> TwitchProperty:
return _add_type_def(TYPE_BOOL, PROPERTY_HINT_PLACEHOLDER_TEXT, description)
func as_num() -> TwitchProperty:
return _add_type_def(TYPE_INT, PROPERTY_HINT_NONE, "")
func as_global() -> TwitchProperty:
return _add_type_def(TYPE_STRING, PROPERTY_HINT_GLOBAL_FILE, "");
func as_image() -> TwitchProperty:
return _add_type_def(TYPE_STRING, PROPERTY_HINT_FILE, "*.png,*.jpg,*.tres")
func as_dir() -> TwitchProperty:
return _add_type_def(TYPE_STRING, PROPERTY_HINT_DIR, "");
## Type should be the generic type of the array
func as_list(type: Variant = "") -> TwitchProperty:
return _add_type_def(TYPE_ARRAY, PROPERTY_HINT_ARRAY_TYPE, type);
## The hint string can be a set of filters with wildcards like "*.png,*.jpg"
func as_global_save(file_types: String = "") -> TwitchProperty:
return _add_type_def(TYPE_STRING, PROPERTY_HINT_GLOBAL_SAVE_FILE, file_types)
func _add_type_def(type: int, hint: int, hint_string: Variant) -> TwitchProperty:
ProjectSettings.add_property_info({
"name": key,
"type": type,
"hint": hint,
"hint_string": hint_string
})
return self

View file

@ -0,0 +1 @@
uid://ci8bdo18wnodj

View file

@ -0,0 +1,13 @@
extends EditorInspectorPlugin
const TwitchScopeProperty = preload("res://addons/twitcher/editor/inspector/twitch_scope_property.gd")
func _can_handle(object: Object) -> bool:
return object is TwitchOAuthScopes
func _parse_property(object: Object, type: Variant.Type, name: String, hint_type: PropertyHint, hint_string: String, usage_flags: int, wide: bool) -> bool:
if name == "used_scopes":
add_property_editor("used_scopes", TwitchScopeProperty.new(), true);
return false;
return false

View file

@ -0,0 +1 @@
uid://c7832kf7htajv

View file

@ -0,0 +1,51 @@
extends EditorProperty
const TITLE_SETTING := preload("res://addons/twitcher/assets/title_label_settings.tres")
var _scope_checkboxes: Dictionary[StringName, CheckBox]
var grid: GridContainer = GridContainer.new();
signal scope_selected(scope: TwitchScope.Definition)
func _init() -> void:
grid.columns = 1;
var grouped_scopes = TwitchScope.get_grouped_scopes();
for category: String in grouped_scopes:
var title_category = Label.new();
title_category.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER;
title_category.text = category.capitalize();
title_category.label_settings = TITLE_SETTING;
grid.add_child(title_category);
grid.add_child(Control.new());
for scope: TwitchScope.Definition in grouped_scopes[category]:
var checkbox: CheckBox = CheckBox.new();
checkbox.text = scope.value;
checkbox.toggled.connect(_on_checkbox_pressed.bind(scope))
checkbox.tooltip_text = scope.description
_scope_checkboxes[scope.value] = checkbox
grid.add_child(checkbox);
add_focusable(checkbox);
add_child(grid);
func _on_scope_changed() -> void:
update_property()
func _update_property() -> void:
for scope: StringName in _scope_checkboxes.keys():
var checkbox: CheckBox = _scope_checkboxes[scope];
var scopes: OAuthScopes = get_edited_object()
checkbox.button_pressed = scopes.used_scopes.find(scope) != -1;
func _on_checkbox_pressed(toggled_on: bool, scope: TwitchScope.Definition) -> void:
var scopes: OAuthScopes = get_edited_object()
if toggled_on:
if scopes.used_scopes.find(scope.value) == -1:
scopes.used_scopes.append(scope.value)
else:
scopes.used_scopes.erase(scope.value)
emit_changed("used_scopes", scopes.used_scopes, &"", true)
scope_selected.emit(scope)

View file

@ -0,0 +1 @@
uid://xldq5o0osdgq

View file

@ -0,0 +1,14 @@
@tool
extends "res://addons/twitcher/lib/oOuch/oauth_token_info.gd"
const TWITCH_TOKEN_REVOKE_POPUP = preload("res://addons/twitcher/editor/inspector/twitch_token_revoke_popup.tscn")
const TwitchTokenRevokePopup = preload("res://addons/twitcher/editor/inspector/twitch_token_revoke_popup.gd")
func _on_revoke_pressed() -> void:
var popup: TwitchTokenRevokePopup = TWITCH_TOKEN_REVOKE_POPUP.instantiate()
popup.token = token
add_child(popup)
popup.popup_centered()
var success = await popup.revoked
if success: _reset_token()

View file

@ -0,0 +1 @@
uid://c8no6da8ae0xt

View file

@ -0,0 +1,7 @@
[gd_scene load_steps=3 format=3 uid="uid://c7qvkjw425jaf"]
[ext_resource type="PackedScene" uid="uid://6d2jst8ga4le" path="res://addons/twitcher/lib/oOuch/oauth_token_info.tscn" id="1_0mxfe"]
[ext_resource type="Script" uid="uid://c8no6da8ae0xt" path="res://addons/twitcher/editor/inspector/twitch_token_info.gd" id="2_kejyg"]
[node name="TokenInfo" instance=ExtResource("1_0mxfe")]
script = ExtResource("2_kejyg")

View file

@ -0,0 +1,50 @@
@tool
extends Window
const TwitchEditorSettings = preload("res://addons/twitcher/editor/twitch_editor_settings.gd")
@export var token: OAuthToken
@onready var inspector: HBoxContainer = %Inspector
@onready var cancel: Button = %Cancel
@onready var revoke_locally: Button = %RevokeLocally
@onready var revoke_twitch: Button = %RevokeTwitch
@onready var twitch_token_handler: TwitchTokenHandler = %TwitchTokenHandler
signal revoked(success: bool)
var picker: EditorResourcePicker
func _ready() -> void:
picker = EditorResourcePicker.new()
picker.base_type = "OAuthSetting"
picker.edited_resource = TwitchEditorSettings.game_oauth_setting
picker.size_flags_horizontal = Control.SIZE_EXPAND_FILL
inspector.add_child(picker)
cancel.pressed.connect(_on_cancel)
revoke_locally.pressed.connect(_on_revoke_locally)
revoke_twitch.pressed.connect(_on_revoke_twitch)
twitch_token_handler.token = token
close_requested.connect(_on_cancel)
func _on_cancel() -> void:
revoked.emit(false)
queue_free()
func _on_revoke_locally() -> void:
revoked.emit(true)
token.remove_tokens()
queue_free()
func _on_revoke_twitch() -> void:
revoked.emit(true)
if is_instance_valid(picker.edited_resource):
twitch_token_handler.oauth_setting = picker.edited_resource
await twitch_token_handler.revoke_token()
queue_free()

View file

@ -0,0 +1 @@
uid://bp1fga8addrlc

View file

@ -0,0 +1,74 @@
[gd_scene load_steps=6 format=3 uid="uid://b4n67bt8ni6ge"]
[ext_resource type="Script" uid="uid://bp1fga8addrlc" path="res://addons/twitcher/editor/inspector/twitch_token_revoke_popup.gd" id="1_4n8su"]
[ext_resource type="Script" uid="uid://blnbogtrshw4r" path="res://addons/twitcher/auth/twitch_token_handler.gd" id="2_iycl8"]
[ext_resource type="Resource" uid="uid://c4scwuk8q0r40" path="res://addons/twitcher/lib/oOuch/default_key_provider.tres" id="3_4n8su"]
[ext_resource type="Script" uid="uid://b52xp7c23ucfk" path="res://addons/twitcher/lib/oOuch/oauth_token.gd" id="4_iycl8"]
[sub_resource type="Resource" id="Resource_twsgi"]
script = ExtResource("4_iycl8")
_crypto_key_provider = ExtResource("3_4n8su")
_identifier = "Auth-2409"
_cache_path = "user://auth.conf"
[node name="TokenRevokePopup" type="Window"]
title = "Revoke Token"
position = Vector2i(0, 36)
size = Vector2i(400, 200)
script = ExtResource("1_4n8su")
[node name="MarginContainer" type="MarginContainer" parent="."]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_constants/margin_left = 10
theme_override_constants/margin_top = 10
theme_override_constants/margin_right = 10
theme_override_constants/margin_bottom = 10
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
layout_mode = 2
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer"]
custom_minimum_size = Vector2(0, 50)
layout_mode = 2
text = "You can decide to revoke the token locally or actually invalidate it on Twitch side too. To revoke it on Twitch the client id must be known: "
autowrap_mode = 3
[node name="Inspector" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer/Inspector"]
layout_mode = 2
text = "OAuth Setting:"
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
layout_mode = 2
size_flags_vertical = 10
[node name="Cancel" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "Cancel"
[node name="RevokeTwitch" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "Revoke on Twitch"
[node name="RevokeLocally" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "Revoke Locally"
[node name="TwitchTokenHandler" type="Node" parent="."]
unique_name_in_owner = true
script = ExtResource("2_iycl8")
token = SubResource("Resource_twsgi")
metadata/_custom_type_script = "uid://blnbogtrshw4r"

View file

@ -0,0 +1,44 @@
@tool
extends EditorInspectorPlugin
const TwitchEditorSettings = preload("res://addons/twitcher/editor/twitch_editor_settings.gd")
const UserProperty = preload("res://addons/twitcher/editor/inspector/user_property.gd")
const TEST_CREDENTIALS = preload("res://addons/twitcher/editor/setup/test_credentials.tscn")
const TestCredentials = preload("res://addons/twitcher/editor/setup/test_credentials.gd")
func _can_handle(object: Object) -> bool:
return true
func _parse_property(object: Object, type: Variant.Type, name: String, hint_type: PropertyHint, hint_string: String, usage_flags: int, wide: bool) -> bool:
if hint_string == "TwitchUser":
if TwitchEditorSettings.is_valid():
add_property_editor(name, UserProperty.new())
return true
else:
var info_label: Label = Label.new()
info_label.text = "Authorize editor to have a custom inspector for the '%s'." % name.capitalize()
info_label.label_settings = LabelSettings.new()
info_label.label_settings.font_size = 13
info_label.label_settings.font_color = Color.AQUA
info_label.autowrap_mode = TextServer.AUTOWRAP_WORD
info_label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
var authorize_editor: TestCredentials = TEST_CREDENTIALS.instantiate()
authorize_editor.text = "Authorize Editor"
authorize_editor.authorized.connect(_on_authorized.bind(object), CONNECT_DEFERRED)
var hbox: HBoxContainer = HBoxContainer.new()
hbox.add_child(info_label)
hbox.add_child(authorize_editor)
hbox.size_flags_horizontal = Control.SIZE_EXPAND_FILL
add_custom_control(hbox)
return false
func _on_authorized(object: Object) -> void:
EditorInterface.get_inspector().edit(null)
EditorInterface.get_inspector().edit(object)

View file

@ -0,0 +1 @@
uid://cpq13q33gcqov

View file

@ -0,0 +1,134 @@
@tool
extends HBoxContainer
class_name UserConverter
const TwitchEditorSettings = preload("res://addons/twitcher/editor/twitch_editor_settings.gd")
const TwitchTweens = preload("res://addons/twitcher/editor/twitch_tweens.gd")
@onready var _login: LineEdit = %Login
@onready var _id: LineEdit = %Id
@onready var _swap_view: Button = %SwapView
@onready var search: Button = %Search
@export var user: TwitchUser
@export var token: OAuthToken
@export var setting: OAuthSetting
static var _current_user: TwitchUser
var user_login: String:
set(val):
user_login = val
_login.text = val
_login.caret_column = val.length()
get(): return _login.text
var user_id: String:
set(val):
user_id = val
_id.text = val
_id.caret_column = val.length()
get(): return _id.text
signal changed(user: TwitchUser)
func _ready() -> void:
if token == null: token = TwitchEditorSettings.editor_oauth_token
if setting == null: setting = TwitchEditorSettings.editor_oauth_setting
_login.text_changed.connect(_on_login_changed)
_login.text_submitted.connect(_on_text_submitted)
_id.text_changed.connect(_on_id_changed)
_id.text_submitted.connect(_on_text_submitted)
_swap_view.pressed.connect(_on_swap_view)
_load_current_user()
search.pressed.connect(_on_changed)
## Experimental tries to load user from api key
func _load_current_user() -> void:
if _current_user == null:
var users: TwitchGetUsers.Opt = TwitchGetUsers.Opt.new()
_current_user = await _get_user(users)
if _current_user != null:
user_login = _current_user.login
user_id = _current_user.id
changed.emit(_current_user)
func _on_swap_view() -> void:
if _login.visible:
_login.visible = false
_id.visible = true
_swap_view.text = "ID"
else:
_login.visible = true
_id.visible = false
_swap_view.text = "Name"
func _on_id_changed(new_text: String) -> void:
_login.text = ""
TwitchTweens.loading(self, Color.AQUA)
func _on_login_changed(new_text: String) -> void:
_id.text = ""
TwitchTweens.loading(self, Color.AQUA)
func reload() -> void:
TwitchTweens.loading(self)
var new_user_login: String = _login.text
var new_user_id: String = _id.text
if new_user_id == "" && new_user_login == "":
changed.emit(null)
return
var users: TwitchGetUsers.Opt = TwitchGetUsers.Opt.new()
if new_user_login != "" && (user == null || user.login != new_user_login):
users.login = [ new_user_login ]
elif new_user_id != "" && (user == null || user.id != new_user_id):
users.id = [ new_user_id ]
if users.id != null || users.login != null:
user = await _get_user(users)
if user == null:
await TwitchTweens.flash(self, Color.RED)
else:
await TwitchTweens.flash(self, Color.GREEN)
user_login = user.login
user_id = user.id
changed.emit(user)
func update_user(user: TwitchUser) -> void:
user_login = user.login
user_id = user.id
func _on_text_submitted(new_text: String) -> void:
reload()
func _on_changed() -> void:
reload()
func _get_user(get_user_opt: TwitchGetUsers.Opt) -> TwitchUser:
var api: TwitchAPI = TwitchAPI.new()
api.token = token
api.oauth_setting = setting
add_child(api)
var response: TwitchGetUsers.Response = await api.get_users(get_user_opt)
var data: Array[TwitchUser] = response.data
if data.is_empty():
printerr("User %s%s was not found." % [ get_user_opt.login, get_user_opt.id ])
return null
remove_child(api)
return data[0]

View file

@ -0,0 +1 @@
uid://b6qdiwr7rawx1

View file

@ -0,0 +1,33 @@
[gd_scene load_steps=3 format=3 uid="uid://cus81w3pidhjo"]
[ext_resource type="Script" uid="uid://b6qdiwr7rawx1" path="res://addons/twitcher/editor/inspector/user_converter.gd" id="1_ior8m"]
[ext_resource type="Texture2D" uid="uid://1e6nrtqsuc6" path="res://addons/twitcher/assets/icon_search.tres" id="2_t7vdb"]
[node name="UserConverter" type="HBoxContainer"]
offset_right = 40.0
offset_bottom = 40.0
size_flags_horizontal = 3
script = ExtResource("1_ior8m")
[node name="Login" type="LineEdit" parent="."]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
placeholder_text = "User Login"
[node name="Id" type="LineEdit" parent="."]
unique_name_in_owner = true
visible = false
layout_mode = 2
size_flags_horizontal = 3
placeholder_text = "User ID"
[node name="SwapView" type="Button" parent="."]
unique_name_in_owner = true
layout_mode = 2
text = "Name"
[node name="Search" type="Button" parent="."]
unique_name_in_owner = true
layout_mode = 2
icon = ExtResource("2_t7vdb")

View file

@ -0,0 +1,29 @@
@tool
extends EditorProperty
const USER_CONVERTER = preload("res://addons/twitcher/editor/inspector/user_converter.tscn")
const UserConverter = preload("res://addons/twitcher/editor/inspector/user_converter.gd")
const TwitchEditorSettings = preload("res://addons/twitcher/editor/twitch_editor_settings.gd")
var _converter: UserConverter
func _init():
_converter = USER_CONVERTER.instantiate()
_converter.changed.connect(_on_changed)
add_child(_converter)
func _update_property() -> void:
var user: TwitchUser = get_edited_object()[get_edited_property()]
if user == null:
_converter.user_id = ""
_converter.user_login = ""
else:
_converter.user_id = user.id
_converter.user_login = user.login
func _on_changed(user: TwitchUser) -> void:
emit_changed(get_edited_property(), user, &"", true)
_update_property()

View file

@ -0,0 +1 @@
uid://c4ba54q6ecn7y