From 63eb02eb27d24769792ae1f75444c81a0c1dc328 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Sun, 8 Mar 2026 16:18:39 -0500 Subject: [PATCH 1/6] Updated TwitcherExtended Fixed get_users(), check if user_ids[0] is an array, and if so, set user_ids to user_ids[0]. Remove debugging prints in get_live_streamers_data() Added get_team_info() to get Twitch Team information by name. --- lib/twitcher_extended/twitcher_extended.gd | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/twitcher_extended/twitcher_extended.gd b/lib/twitcher_extended/twitcher_extended.gd index 30d20c45..43c826eb 100644 --- a/lib/twitcher_extended/twitcher_extended.gd +++ b/lib/twitcher_extended/twitcher_extended.gd @@ -308,6 +308,8 @@ func reply_message(message: String, msg_id: String, as_streamer: bool = false) - func get_users_by_id(...user_ids: Array) -> Array[TwitchUser]: var tusers: Array[TwitchUser] = [] var qusers: Array[String] = [] + if user_ids[0] is Array: + user_ids = user_ids[0] for user_id in user_ids: if _cache_users.has(user_id): tusers.append(_cache_users[user_id]) @@ -521,15 +523,19 @@ func get_live_streamers_data(user_ids: Array = []) -> Dictionary[String, TwitchS user_ids = user_ids.slice(99) opt.user_id = new_batch var streams_iterator := await api.get_streams(opt) - print("Fetching live...") for stream_promise in streams_iterator: var stream_data: TwitchStream = await stream_promise if stream_data: - print("%s(%s) is live" % [stream_data.user_name, stream_data.user_id]) streams_data[stream_data.user_id] = stream_data - else: - print("WTF!!!! Iter is null?") - print("Fetching is done.") _is_processing_streams = false return streams_data + +func get_team_info(team_name: String) -> TwitchTeam: + var opt := TwitchGetTeams.Opt.new() + opt.name = team_name + var team_resp := await api.get_teams(opt) + if team_resp and team_resp.data.size() > 0: + return team_resp.data[0] + else: + return null #endregion From 58e4207cd5838e82ddef57b63b8f921c28672714 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Sun, 8 Mar 2026 16:19:22 -0500 Subject: [PATCH 2/6] Updated Globals Added function t oget members of the Indie Game Devs Team. --- lib/globals.gd | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/lib/globals.gd b/lib/globals.gd index e316c0c0..f9c17470 100644 --- a/lib/globals.gd +++ b/lib/globals.gd @@ -67,6 +67,7 @@ func _setup_live_stream_timer() -> void: _run_live_streamer_update() _tmr_live_stream.start() + get_indie_game_devs_members() func _run_live_streamer_update() -> void: live_streamers_updating.emit() @@ -141,3 +142,41 @@ func get_exception_points() -> PackedVector2Array: func get_polygon_points() -> PackedVector2Array: return _hull_points + +func get_indie_game_devs_members() -> void: + var team = await twitcher.get_team_info("indiegamedevs") + var new_users: Array[TwitchUser] + if team: + var chatters: Array[Chatter] = [] + chatters.assign(context.chatters.all()) + var new_members: Array[TwitchTeam.Users] = [] + print("Got team: ", team.team_name) + print("Member Count: ", team.users.size()) + for team_member: TwitchTeam.Users in team.users: + if not chatters.any(func(x: Chatter): return x.twitch_id == team_member.user_id): + new_members.append(team_member) + + if new_members.size() > 0: + var iter = 0 + const MAX_ITER = 100 + while not new_members.is_empty(): + iter += 1 + if iter > MAX_ITER: + return + + var new_batch: Array[String] = [] + new_batch.assign(new_members.slice(0,99).map(func(x): return x.user_id)) + new_members.assign(new_members.slice(99)) + var res = await twitcher.get_users_by_id(new_batch) + new_users.append_array(res) + print("Found: %d new members not in database" % new_users.size()) + for user: TwitchUser in new_users: + var chatter = Chatter.new() + chatter.twitch_id = user.id + chatter.is_streamer = true + chatter.is_indie_game_dev = true + chatter.user = user + chatter.first_added = Time.get_unix_time_from_system() + chatter.first_seen = -1 + chatter.last_seen = -1 + context.chatters.append(chatter) From 6a384d3052722158cda23c257e9cf9ea23101196 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Sun, 8 Mar 2026 16:20:12 -0500 Subject: [PATCH 3/6] Updated TwitchUserInfo Added signal for when we start expanding, and added it to the tween callback. --- UI/Controls/twitch_user_info.gd | 2 ++ 1 file changed, 2 insertions(+) diff --git a/UI/Controls/twitch_user_info.gd b/UI/Controls/twitch_user_info.gd index f8540b58..184b08f8 100644 --- a/UI/Controls/twitch_user_info.gd +++ b/UI/Controls/twitch_user_info.gd @@ -6,6 +6,7 @@ const CHEVRONS = [ ] @export var expanded: bool = false +signal extra_expanding(is_expanding: bool) signal extra_expanded(is_expanded: bool) var is_extra_panel_expanded: bool @@ -90,6 +91,7 @@ func toggle_extra_panel(val: bool) -> void: tw_expand.kill() %ExtraInfo.show() tw_expand = create_tween() + tw_expand.tween_callback(extra_expanding.emit.bind(is_extra_panel_expanded)) tw_expand.set_ease(Tween.EASE_OUT) tw_expand.set_trans(Tween.TRANS_CUBIC) tw_expand.tween_property(%ExtraInfo, ^"custom_minimum_size:x", min_size_x, 0.3) From 11e4590d8e2c3ffaa0678c4c756bc1144bf6075f Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Sun, 8 Mar 2026 16:21:01 -0500 Subject: [PATCH 4/6] Updated InternalTwtchUserInfo When TwitchUserInfo starts expanding, or collapsing the extra info, ensure that User Promo is being hidden/shown accordingly. --- UI/Controls/internal_twitch_user_info.gd | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/UI/Controls/internal_twitch_user_info.gd b/UI/Controls/internal_twitch_user_info.gd index 990e0124..34755355 100644 --- a/UI/Controls/internal_twitch_user_info.gd +++ b/UI/Controls/internal_twitch_user_info.gd @@ -10,3 +10,7 @@ var chatter: Chatter: tui.populate_from_chatter(chatter) if not up: return up.chatter = value + +func _ready() -> void: + tui.extra_expanding.connect(func(x): if x: up.visible = false) + tui.extra_expanded.connect(func(x): if not x: up.visible = true) From 991597ff21b2bddd88f689f28c1ead8d653fdc52 Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Sun, 8 Mar 2026 16:24:55 -0500 Subject: [PATCH 5/6] Updated UserEntry Removed ScrollContainer code, as it doesn't work with Filtering (Online / Name filtering). Added VisibleOnScreenNotifier2D to the control, to handle on screen visibility notification. Connected screen_entered to check_update_profile_picture. Added check if not is_on_screen(), to not try and update the profile picture. --- UI/Controls/user_entry.gd | 13 +++---------- UI/Controls/user_entry.tscn | 3 +++ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/UI/Controls/user_entry.gd b/UI/Controls/user_entry.gd index 9619de88..02e7ca76 100644 --- a/UI/Controls/user_entry.gd +++ b/UI/Controls/user_entry.gd @@ -5,26 +5,19 @@ var chatter: Chatter var tw_hidden: Tween var is_expanded: bool = false - -var scroll: ScrollContainer -var is_visible_in_scroll: bool: - get: - if not scroll: return false - return scroll.get_global_rect().intersects(get_global_rect()) var is_profile_picture_loaded: bool = false signal user_selected(chatter: Chatter) # Called when the node enters the scene tree for the first time. func _ready() -> void: - scroll = get_parent().get_parent() - scroll.get_v_scroll_bar().scrolling.connect(check_update_profile_picture) - visibility_changed.connect(check_update_profile_picture) update() toggle_buttons(false) Globals.live_streamers_updated.connect(func(): %LiveStatus.visible = chatter.twitch_id in Globals.live_streamers.keys()) await get_tree().process_frame check_update_profile_picture() + %ScreenNotifer.rect = get_rect() + %ScreenNotifer.screen_entered.connect(check_update_profile_picture) %User.pressed.connect(user_selected.emit.bind(chatter)) %Shoutout.pressed.connect(func(): Globals.twitcher.shoutout(chatter.user)) %Promote.pressed.connect(func(): Globals.twitcher.send_message(chatter.promo_msg)) @@ -60,7 +53,7 @@ func check_update_profile_picture() -> void: if is_profile_picture_loaded: return if not chatter: return await get_tree().process_frame - if not is_visible_in_scroll: return + if not %ScreenNotifer.is_on_screen(): return is_profile_picture_loaded = true await update_profile_picture() if not %AvatarImg.texture: is_profile_picture_loaded = false diff --git a/UI/Controls/user_entry.tscn b/UI/Controls/user_entry.tscn index 7805b1f1..0d111c26 100644 --- a/UI/Controls/user_entry.tscn +++ b/UI/Controls/user_entry.tscn @@ -134,3 +134,6 @@ theme_override_styles/normal = SubResource("StyleBoxFlat_ddi2y") icon = ExtResource("7_k1oax") icon_alignment = 1 expand_icon = true + +[node name="ScreenNotifer" type="VisibleOnScreenNotifier2D" parent="." unique_id=1597669003] +unique_name_in_owner = true From b9e0233f25454c447b8f9ef78cf33d68fad7d16b Mon Sep 17 00:00:00 2001 From: Mario Steele Date: Sun, 8 Mar 2026 16:26:06 -0500 Subject: [PATCH 6/6] Updated UserList Refactor filter_live_users() into filter_list(). New Filter function, first filters for live users, then checks to see if _filter_name is an empty string, and the item is visible, before checking to see if display name matches te filter name variable. --- UI/Controls/user_list.gd | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/UI/Controls/user_list.gd b/UI/Controls/user_list.gd index 88b4dc7d..ead631b9 100644 --- a/UI/Controls/user_list.gd +++ b/UI/Controls/user_list.gd @@ -9,14 +9,20 @@ var filtering_live: bool = false: set(value): filtering_live = value if value: - filter_live_users() + filter_list() else: reset_filter() +var _filter_name: String = "" + # Called when the node enters the scene tree for the first time. func _ready() -> void: + %Filter.text_changed.connect(_update_filter_name) %FilterLive.pressed.connect(func(): filtering_live = !filtering_live) +func _update_filter_name(txt: String) -> void: + _filter_name = txt.to_lower() + filter_list() func clear_list() -> void: for node in %UserList.get_children(): @@ -51,7 +57,10 @@ func reset_filter() -> void: for entry: UserEntry in %UserList.get_children(): entry.visible = true -func filter_live_users() -> void: +func filter_list() -> void: reset_filter() for entry: UserEntry in %UserList.get_children(): - entry.visible = entry.chatter.twitch_id in Globals.live_streamers.keys() + if filtering_live: + entry.visible = entry.chatter.twitch_id in Globals.live_streamers.keys() + if _filter_name != "" and entry.visible: + entry.visible = entry.chatter.user.display_name.to_lower().contains(_filter_name)