diff --git a/.gitignore b/.gitignore index 4a28b98..6e384e8 100644 --- a/.gitignore +++ b/.gitignore @@ -414,4 +414,4 @@ FodyWeavers.xsd # JetBrains Rider *.sln.iml - +.idea/ diff --git a/Library/Singletons/GifManager.cs b/Library/Singletons/GifManager.cs new file mode 100644 index 0000000..ca5d889 --- /dev/null +++ b/Library/Singletons/GifManager.cs @@ -0,0 +1,22 @@ +using Godot; + +namespace PokePurple.Library.Singletons; + +public class GifManager +{ + private static GifManager? _instance; + public static GifManager Instance => _instance ?? (_instance = new GifManager()); + + private Node _gifManager; + + public GifManager() + { + _gifManager = ((SceneTree)Engine.GetMainLoop()).GetRoot().GetNode("GifManager"); + } + + public AnimatedTexture AnimatedTextureFromBuffer(byte[] data, int max_frames = 0) => _gifManager.Call("animated_texture_from_buffer", data, max_frames).As(); + public AnimatedTexture AnimatedTextureFromFile(string file, int max_frames = 0) => _gifManager.Call("animated_texture_from_file", file, max_frames).As(); + + public SpriteFrames SpriteFramesFromBuffer(byte[] data, int max_frames = 0) => _gifManager.Call("sprite_frames_from_buffer", data, max_frames).As(); + public SpriteFrames SpriteFramesFromFile(string file, int max_frames = 0) => _gifManager.Call("sprite_frames_from_file", file, max_frames).As(); +} \ No newline at end of file diff --git a/Library/Singletons/GifManager.cs.uid b/Library/Singletons/GifManager.cs.uid new file mode 100644 index 0000000..c31f287 --- /dev/null +++ b/Library/Singletons/GifManager.cs.uid @@ -0,0 +1 @@ +uid://dphxqo51pj8i7 diff --git a/Library/Singletons/Globals.cs b/Library/Singletons/Globals.cs new file mode 100644 index 0000000..ae84f7d --- /dev/null +++ b/Library/Singletons/Globals.cs @@ -0,0 +1,12 @@ +using Godot; +using System; +using Godot.Sharp.Extras; + +public partial class Globals : Node +{ + [NodePath] private Node _twitchService; + public override void _Ready() + { + this.OnReady(); + } +} diff --git a/Library/Singletons/Globals.cs.uid b/Library/Singletons/Globals.cs.uid new file mode 100644 index 0000000..76cf275 --- /dev/null +++ b/Library/Singletons/Globals.cs.uid @@ -0,0 +1 @@ +uid://6nrfqrw53c1s diff --git a/Library/Singletons/globals.tscn b/Library/Singletons/globals.tscn new file mode 100644 index 0000000..a8cf05c --- /dev/null +++ b/Library/Singletons/globals.tscn @@ -0,0 +1,47 @@ +[gd_scene load_steps=12 format=3 uid="uid://b8whblp2hgrp"] + +[ext_resource type="Script" uid="uid://6nrfqrw53c1s" path="res://Library/Singletons/Globals.cs" id="1_gsl6h"] +[ext_resource type="Script" uid="uid://i8st3lv0lidh" path="res://addons/twitcher/twitch_service.gd" id="1_ocehi"] +[ext_resource type="Script" uid="uid://dcrliedgr6eol" path="res://addons/twitcher/lib/oOuch/crypto_key_provider.gd" id="2_gsl6h"] +[ext_resource type="Script" uid="uid://00xbijwpi8xa" path="res://addons/twitcher/lib/oOuch/oauth_setting.gd" id="3_amvha"] +[ext_resource type="Script" uid="uid://b3n3et8mebjcc" path="res://addons/twitcher/auth/twitch_oauth_scopes.gd" id="4_fcooh"] +[ext_resource type="Resource" uid="uid://c4scwuk8q0r40" path="res://addons/twitcher/lib/oOuch/default_key_provider.tres" id="5_65rqk"] +[ext_resource type="Script" uid="uid://b52xp7c23ucfk" path="res://addons/twitcher/lib/oOuch/oauth_token.gd" id="6_lppa0"] + +[sub_resource type="Resource" id="Resource_54bgt"] +script = ExtResource("2_gsl6h") +encrpytion_secret_location = "user://encryption_key.cfg" + +[sub_resource type="Resource" id="Resource_km1mv"] +script = ExtResource("3_amvha") +redirect_url = "http://localhost:7170" +well_known_url = "" +token_url = "https://id.twitch.tv/oauth2/token" +authorization_url = "https://id.twitch.tv/oauth2/authorize" +device_authorization_url = "https://id.twitch.tv/oauth2/device" +cache_file = "user://auth.conf" +client_id = "xqh437vs83im368db89iwflm130ufb" +authorization_flow = 0 +_encryption_key_provider = SubResource("Resource_54bgt") +client_secret = "D8bwpU1vz2zu6P9l0D3ktvctJMCuFspuG//RPTsyP8w=" + +[sub_resource type="Resource" id="Resource_to4h6"] +script = ExtResource("4_fcooh") +used_scopes = Array[StringName]([&"moderation:read", &"user:bot", &"user:read:chat", &"user:write:chat", &"chat:edit", &"chat:read"]) +metadata/_custom_type_script = "uid://b3n3et8mebjcc" + +[sub_resource type="Resource" id="Resource_3e7ys"] +script = ExtResource("6_lppa0") +_crypto_key_provider = ExtResource("5_65rqk") +_identifier = "EditorToken" +_cache_path = "user://auth.conf" + +[node name="Globals" type="Node"] +script = ExtResource("1_gsl6h") + +[node name="TwitchService" type="Node" parent="."] +script = ExtResource("1_ocehi") +oauth_setting = SubResource("Resource_km1mv") +scopes = SubResource("Resource_to4h6") +token = SubResource("Resource_3e7ys") +metadata/_custom_type_script = "uid://i8st3lv0lidh" diff --git a/PokePurple.csproj b/PokePurple.csproj new file mode 100644 index 0000000..c648366 --- /dev/null +++ b/PokePurple.csproj @@ -0,0 +1,11 @@ + + + net8.0 + true + enable + + + + + + \ No newline at end of file diff --git a/PokePurple.sln b/PokePurple.sln new file mode 100644 index 0000000..9a70651 --- /dev/null +++ b/PokePurple.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PokePurple", "PokePurple.csproj", "{5C940B04-31D7-4268-9B7E-63D5C488E573}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + ExportDebug|Any CPU = ExportDebug|Any CPU + ExportRelease|Any CPU = ExportRelease|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5C940B04-31D7-4268-9B7E-63D5C488E573}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5C940B04-31D7-4268-9B7E-63D5C488E573}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5C940B04-31D7-4268-9B7E-63D5C488E573}.ExportDebug|Any CPU.ActiveCfg = ExportDebug|Any CPU + {5C940B04-31D7-4268-9B7E-63D5C488E573}.ExportDebug|Any CPU.Build.0 = ExportDebug|Any CPU + {5C940B04-31D7-4268-9B7E-63D5C488E573}.ExportRelease|Any CPU.ActiveCfg = ExportRelease|Any CPU + {5C940B04-31D7-4268-9B7E-63D5C488E573}.ExportRelease|Any CPU.Build.0 = ExportRelease|Any CPU + EndGlobalSection +EndGlobal diff --git a/addons/godotgif/LICENSE.txt b/addons/godotgif/LICENSE.txt new file mode 100644 index 0000000..f8a2334 --- /dev/null +++ b/addons/godotgif/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 B0TLANNER Games + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/addons/godotgif/README.md b/addons/godotgif/README.md new file mode 100644 index 0000000..019419b --- /dev/null +++ b/addons/godotgif/README.md @@ -0,0 +1,139 @@ +# Godot GIF +
+ +

+ Logo +

+ +

+ GitHub Build + MIT License +

+ + +## Description +GDExtension for Godot 4+ to load GIF files as [AnimatedTexture](https://docs.godotengine.org/en/stable/classes/class_animatedtexture.html) and/or [SpriteFrames](https://docs.godotengine.org/en/stable/classes/class_spriteframes.html). + +NOTE: ~~**AnimatedTexture**~~ has been marked as deprecated according to development docs and could be removed in a future version of Godot. + + +## Usage + +### Editor + +Gif files can be imported at edit time as one of the supported types via Import options. + +
+ Editor Imports Options + +![Editor Imports Options](./docs-images/EditorImportSettings.gif) +
+ +See the [Editor Imports](./demo/editor_imports_example.tscn) example scene. +
+ Editor Imports Example + +![Editor Imports](./docs-images/EditorImports.gif) +
+ +
+ +### Runtime + +Gif files can be loaded at runtime as one of the supported types via the `GifManager` singleton. + +`GifManager` exposes the following methods for loading gifs either from file or from bytes directly: +![GifManager Methods](./docs-images/methods.png) + +e.g. to load from file +```py +get_node("AnimFromRuntimeFile").texture = GifManager.animated_texture_from_file("res://examples/file/optic.gif") + +get_node("AnimatedSprite2RuntimeFile").sprite_frames = GifManager.sprite_frames_from_file("res://examples/file/optic.gif") +``` + +See the [Runtime Imports](./demo/main.tscn) example scene. +
+ Runtime Imports Example + +![Runtime Imports](./docs-images/RuntimeImports.gif) +
+ + +## Installation + +Download the `gdextension` artifact from the [latest successful build](https://github.com/BOTLANNER/godot-gif/actions/workflows/build_releases.yml). (It should be right at the bottom of the **Summary**) +![image](https://github.com/BOTLANNER/godot-gif/assets/16349308/f28867c6-f669-45f2-9309-dbb17cec2031) + +Extract the contents to your Godot project directory. + +You should have an `addons` directory at the root with the following structure: +```bash +└───addons + └───godotgif + │ godotgif.gdextension + │ LICENSE.txt + │ README.md + │ + └───bin + │ godotgif.windows.template_debug.x86_32.dll + │ godotgif.windows.template_debug.x86_64.dll + │ godotgif.windows.template_release.x86_32.dll + │ godotgif.windows.template_release.x86_64.dll + │ libgodotgif.android.template_debug.arm64.so + │ libgodotgif.android.template_release.arm64.so + │ libgodotgif.linux.template_debug.x86_32.so + │ libgodotgif.linux.template_debug.x86_64.so + │ libgodotgif.linux.template_release.x86_32.so + │ libgodotgif.linux.template_release.x86_64.so + │ + ├───godotgif.macos.template_debug.framework + │ libgodotgif.macos.template_debug + │ + └───godotgif.macos.template_release.framework + libgodotgif.macos.template_release +``` + +Open your project. Any exisitng gifs should auto-import. New gifs in the project directory will automatically import as `SpriteFrames`. To convert them into `AnimatedTexture`, update the [import settings](#editor). + +The `GifManager` class should also now be available for access within GDScript. + +## Contributing + +### Setup + +Ensure **SCons** is setup. Refer to [Introduction to the buildsystem](https://docs.godotengine.org/en/stable/contributing/development/compiling/introduction_to_the_buildsystem.html) + +* If using a different version of Godot, be sure to dump the bindings e.g. + ```sh + godot --dump-extension-api extension_api.json + ``` +* Compile with + ```sh + scons platform= custom_api_file=extension_api.json + ``` + +### Debugging + +This repository is configured for use with [VSCode](https://code.visualstudio.com/) + +[Launch configurations](./.vscode/launch.json) have been setup for both debugging in editor and in runtime provided certain **VSCode** extensions are present and environment variables are defined. + +The following environment variables are required: + +1. `GODOT_PATH` - The directory in which Godot is installed +1. `GODOT_EXECUTABLE` - The executable name of the Godot installation + +### More Details +Refer to [GDExtension C++ example](https://docs.godotengine.org/en/stable/tutorials/scripting/gdextension/gdextension_cpp_example.html) + + +## License + +Unless otherwise specified, the extension is released under the +[MIT license](LICENSE.txt). + +See the full list of third-party libraries with their licenses used by this +extension at [src/thirdparty/README.md](src/thirdparty/README.md). + +This implementation heavily borrowed inspiration from the [gif module](https://github.com/goostengine/goost/tree/gd3/modules/gif) for [Goost](https://github.com/goostengine/goost) that is currently only based on Godot 3 diff --git a/addons/godotgif/bin/godotgif.macos.template_debug.framework/libgodotgif.macos.template_debug b/addons/godotgif/bin/godotgif.macos.template_debug.framework/libgodotgif.macos.template_debug new file mode 100644 index 0000000..128f00d Binary files /dev/null and b/addons/godotgif/bin/godotgif.macos.template_debug.framework/libgodotgif.macos.template_debug differ diff --git a/addons/godotgif/bin/godotgif.macos.template_release.framework/libgodotgif.macos.template_release b/addons/godotgif/bin/godotgif.macos.template_release.framework/libgodotgif.macos.template_release new file mode 100644 index 0000000..854edb7 Binary files /dev/null and b/addons/godotgif/bin/godotgif.macos.template_release.framework/libgodotgif.macos.template_release differ diff --git a/addons/godotgif/bin/godotgif.windows.template_debug.x86_32.dll b/addons/godotgif/bin/godotgif.windows.template_debug.x86_32.dll new file mode 100644 index 0000000..9b1dc08 Binary files /dev/null and b/addons/godotgif/bin/godotgif.windows.template_debug.x86_32.dll differ diff --git a/addons/godotgif/bin/godotgif.windows.template_debug.x86_64.dll b/addons/godotgif/bin/godotgif.windows.template_debug.x86_64.dll new file mode 100644 index 0000000..dfaf311 Binary files /dev/null and b/addons/godotgif/bin/godotgif.windows.template_debug.x86_64.dll differ diff --git a/addons/godotgif/bin/godotgif.windows.template_release.x86_32.dll b/addons/godotgif/bin/godotgif.windows.template_release.x86_32.dll new file mode 100644 index 0000000..fa8bd6e Binary files /dev/null and b/addons/godotgif/bin/godotgif.windows.template_release.x86_32.dll differ diff --git a/addons/godotgif/bin/godotgif.windows.template_release.x86_64.dll b/addons/godotgif/bin/godotgif.windows.template_release.x86_64.dll new file mode 100644 index 0000000..f3938f7 Binary files /dev/null and b/addons/godotgif/bin/godotgif.windows.template_release.x86_64.dll differ diff --git a/addons/godotgif/bin/libgodotgif.android.template_debug.arm64.so b/addons/godotgif/bin/libgodotgif.android.template_debug.arm64.so new file mode 100644 index 0000000..655e467 Binary files /dev/null and b/addons/godotgif/bin/libgodotgif.android.template_debug.arm64.so differ diff --git a/addons/godotgif/bin/libgodotgif.android.template_release.arm64.so b/addons/godotgif/bin/libgodotgif.android.template_release.arm64.so new file mode 100644 index 0000000..54e8972 Binary files /dev/null and b/addons/godotgif/bin/libgodotgif.android.template_release.arm64.so differ diff --git a/addons/godotgif/bin/libgodotgif.linux.template_debug.x86_32.so b/addons/godotgif/bin/libgodotgif.linux.template_debug.x86_32.so new file mode 100644 index 0000000..5f8e4f3 Binary files /dev/null and b/addons/godotgif/bin/libgodotgif.linux.template_debug.x86_32.so differ diff --git a/addons/godotgif/bin/libgodotgif.linux.template_debug.x86_64.so b/addons/godotgif/bin/libgodotgif.linux.template_debug.x86_64.so new file mode 100644 index 0000000..15fcff2 Binary files /dev/null and b/addons/godotgif/bin/libgodotgif.linux.template_debug.x86_64.so differ diff --git a/addons/godotgif/bin/libgodotgif.linux.template_release.x86_32.so b/addons/godotgif/bin/libgodotgif.linux.template_release.x86_32.so new file mode 100644 index 0000000..c20509a Binary files /dev/null and b/addons/godotgif/bin/libgodotgif.linux.template_release.x86_32.so differ diff --git a/addons/godotgif/bin/libgodotgif.linux.template_release.x86_64.so b/addons/godotgif/bin/libgodotgif.linux.template_release.x86_64.so new file mode 100644 index 0000000..bcfdf22 Binary files /dev/null and b/addons/godotgif/bin/libgodotgif.linux.template_release.x86_64.so differ diff --git a/addons/godotgif/godotgif.gdextension b/addons/godotgif/godotgif.gdextension new file mode 100644 index 0000000..352d121 --- /dev/null +++ b/addons/godotgif/godotgif.gdextension @@ -0,0 +1,23 @@ +[configuration] + +entry_symbol = "godot_gif_library_init" +compatibility_minimum = "4.4" + +[libraries] + +macos.debug = "bin/godotgif.macos.template_debug.framework/libgodotgif.macos.template_debug" +macos.release = "bin/godotgif.macos.template_release.framework/libgodotgif.macos.template_release" +windows.debug.x86_32 = "bin/godotgif.windows.template_debug.x86_32.dll" +windows.release.x86_32 = "bin/godotgif.windows.template_release.x86_32.dll" +windows.debug.x86_64 = "bin/godotgif.windows.template_debug.x86_64.dll" +windows.release.x86_64 = "bin/godotgif.windows.template_release.x86_64.dll" +linux.debug.x86_64 = "bin/libgodotgif.linux.template_debug.x86_64.so" +linux.release.x86_64 = "bin/libgodotgif.linux.template_release.x86_64.so" +linux.debug.arm64 = "bin/libgodotgif.linux.template_debug.arm64.so" +linux.release.arm64 = "bin/libgodotgif.linux.template_release.arm64.so" +linux.debug.rv64 = "bin/libgodotgif.linux.template_debug.rv64.so" +linux.release.rv64 = "bin/libgodotgif.linux.template_release.rv64.so" +android.debug.x86_64 = "bin/libgodotgif.android.template_debug.x86_64.so" +android.release.x86_64 = "bin/libgodotgif.android.template_release.x86_64.so" +android.debug.arm64 = "bin/libgodotgif.android.template_debug.arm64.so" +android.release.arm64 = "bin/libgodotgif.android.template_release.arm64.so" diff --git a/addons/godotgif/godotgif.gdextension.uid b/addons/godotgif/godotgif.gdextension.uid new file mode 100644 index 0000000..e6d4615 --- /dev/null +++ b/addons/godotgif/godotgif.gdextension.uid @@ -0,0 +1 @@ +uid://xpotkvhtirqd diff --git a/addons/twitcher/COPYRIGHT.txt b/addons/twitcher/COPYRIGHT.txt new file mode 100644 index 0000000..c6df935 --- /dev/null +++ b/addons/twitcher/COPYRIGHT.txt @@ -0,0 +1 @@ +Copyright Kemomi 2024 - 2025. All rights reserved. diff --git a/addons/twitcher/LICENSE b/addons/twitcher/LICENSE new file mode 100644 index 0000000..c349651 --- /dev/null +++ b/addons/twitcher/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Kani + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/addons/twitcher/assets/api-icon.svg b/addons/twitcher/assets/api-icon.svg new file mode 100644 index 0000000..50790a1 --- /dev/null +++ b/addons/twitcher/assets/api-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/twitcher/assets/api-icon.svg.import b/addons/twitcher/assets/api-icon.svg.import new file mode 100644 index 0000000..1fe6898 --- /dev/null +++ b/addons/twitcher/assets/api-icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://sp45xp1nleuk" +path="res://.godot/imported/api-icon.svg-16588d9bd32b7709dca1da03b9d3c51f.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/twitcher/assets/api-icon.svg" +dest_files=["res://.godot/imported/api-icon.svg-16588d9bd32b7709dca1da03b9d3c51f.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/twitcher/assets/auth-icon.svg b/addons/twitcher/assets/auth-icon.svg new file mode 100644 index 0000000..ccbf475 --- /dev/null +++ b/addons/twitcher/assets/auth-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/twitcher/assets/auth-icon.svg.import b/addons/twitcher/assets/auth-icon.svg.import new file mode 100644 index 0000000..e2d1456 --- /dev/null +++ b/addons/twitcher/assets/auth-icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://1kwo4knd8h05" +path="res://.godot/imported/auth-icon.svg-8c3337a2de3e7408dd8b0185710eb409.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/twitcher/assets/auth-icon.svg" +dest_files=["res://.godot/imported/auth-icon.svg-8c3337a2de3e7408dd8b0185710eb409.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/twitcher/assets/chat-icon.svg b/addons/twitcher/assets/chat-icon.svg new file mode 100644 index 0000000..fc93f64 --- /dev/null +++ b/addons/twitcher/assets/chat-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/twitcher/assets/chat-icon.svg.import b/addons/twitcher/assets/chat-icon.svg.import new file mode 100644 index 0000000..1cf4566 --- /dev/null +++ b/addons/twitcher/assets/chat-icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://txhld57vfpmo" +path="res://.godot/imported/chat-icon.svg-e1164fbfcc337348789c82b706287c92.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/twitcher/assets/chat-icon.svg" +dest_files=["res://.godot/imported/chat-icon.svg-e1164fbfcc337348789c82b706287c92.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/twitcher/assets/command-icon.svg b/addons/twitcher/assets/command-icon.svg new file mode 100644 index 0000000..11f8ff2 --- /dev/null +++ b/addons/twitcher/assets/command-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/twitcher/assets/command-icon.svg.import b/addons/twitcher/assets/command-icon.svg.import new file mode 100644 index 0000000..b52bf96 --- /dev/null +++ b/addons/twitcher/assets/command-icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dr6bv6l3g4as3" +path="res://.godot/imported/command-icon.svg-29aa6e8d352722ad63fdf993d5c2472a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/twitcher/assets/command-icon.svg" +dest_files=["res://.godot/imported/command-icon.svg-29aa6e8d352722ad63fdf993d5c2472a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/twitcher/assets/error-page.txt b/addons/twitcher/assets/error-page.txt new file mode 100644 index 0000000..8fae5f6 --- /dev/null +++ b/addons/twitcher/assets/error-page.txt @@ -0,0 +1,82 @@ + + + + + + + Twitcher - Login Failed + + + + + +
+
Login Failed
+
Login attempt was unsuccessful. Page should automatically close when it doesn't happen close it manually.
+ Close Page +
+ + diff --git a/addons/twitcher/assets/event-icon.svg b/addons/twitcher/assets/event-icon.svg new file mode 100644 index 0000000..0e22f0b --- /dev/null +++ b/addons/twitcher/assets/event-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/twitcher/assets/event-icon.svg.import b/addons/twitcher/assets/event-icon.svg.import new file mode 100644 index 0000000..c324c07 --- /dev/null +++ b/addons/twitcher/assets/event-icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://co7dy71iroidu" +path="res://.godot/imported/event-icon.svg-ae206972b8adb971cf3c156d8f980130.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/twitcher/assets/event-icon.svg" +dest_files=["res://.godot/imported/event-icon.svg-ae206972b8adb971cf3c156d8f980130.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/twitcher/assets/eventsub-icon.svg b/addons/twitcher/assets/eventsub-icon.svg new file mode 100644 index 0000000..6108d9a --- /dev/null +++ b/addons/twitcher/assets/eventsub-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/twitcher/assets/eventsub-icon.svg.import b/addons/twitcher/assets/eventsub-icon.svg.import new file mode 100644 index 0000000..dc462b5 --- /dev/null +++ b/addons/twitcher/assets/eventsub-icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://dykujenp3l608" +path="res://.godot/imported/eventsub-icon.svg-ce0c1dc80296ea912c84ec427215a2e3.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/twitcher/assets/eventsub-icon.svg" +dest_files=["res://.godot/imported/eventsub-icon.svg-ce0c1dc80296ea912c84ec427215a2e3.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/twitcher/assets/ext-link.svg b/addons/twitcher/assets/ext-link.svg new file mode 100644 index 0000000..b2a7aa8 --- /dev/null +++ b/addons/twitcher/assets/ext-link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/twitcher/assets/ext-link.svg.import b/addons/twitcher/assets/ext-link.svg.import new file mode 100644 index 0000000..909c1ac --- /dev/null +++ b/addons/twitcher/assets/ext-link.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bwgk2bv7wbbo7" +path="res://.godot/imported/ext-link.svg-e60b226c6ba08585f6582dc226fddebb.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/twitcher/assets/ext-link.svg" +dest_files=["res://.godot/imported/ext-link.svg-e60b226c6ba08585f6582dc226fddebb.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/twitcher/assets/fallback_texture.tres b/addons/twitcher/assets/fallback_texture.tres new file mode 100644 index 0000000..12d7f21 --- /dev/null +++ b/addons/twitcher/assets/fallback_texture.tres @@ -0,0 +1,9 @@ +[gd_resource type="GradientTexture1D" load_steps=2 format=3 uid="uid://g1dbcjksbotw"] + +[sub_resource type="Gradient" id="Gradient_dsf6b"] +offsets = PackedFloat32Array(0) +colors = PackedColorArray(0.921569, 0.227451, 0.988235, 1) + +[resource] +gradient = SubResource("Gradient_dsf6b") +width = 1 diff --git a/addons/twitcher/assets/favicon.ico b/addons/twitcher/assets/favicon.ico new file mode 100644 index 0000000..e3f21d1 Binary files /dev/null and b/addons/twitcher/assets/favicon.ico differ diff --git a/addons/twitcher/assets/icon_search.tres b/addons/twitcher/assets/icon_search.tres new file mode 100644 index 0000000..b296b16 --- /dev/null +++ b/addons/twitcher/assets/icon_search.tres @@ -0,0 +1,13 @@ +[gd_resource type="ImageTexture" load_steps=2 format=3 uid="uid://1e6nrtqsuc6"] + +[sub_resource type="Image" id="Image_mutbh"] +data = { +"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 225, 225, 68, 224, 224, 224, 184, 224, 224, 224, 240, 224, 224, 224, 232, 224, 224, 224, 186, 227, 227, 227, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 129, 224, 224, 224, 254, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 122, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 225, 225, 68, 224, 224, 224, 254, 224, 224, 224, 254, 224, 224, 224, 123, 224, 224, 224, 32, 224, 224, 224, 33, 225, 225, 225, 125, 224, 224, 224, 254, 224, 224, 224, 254, 226, 226, 226, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 184, 224, 224, 224, 255, 224, 224, 224, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 225, 225, 225, 125, 224, 224, 224, 255, 225, 225, 225, 174, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 240, 224, 224, 224, 255, 231, 231, 231, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 226, 226, 226, 35, 224, 224, 224, 255, 224, 224, 224, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 232, 224, 224, 224, 255, 224, 224, 224, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 228, 228, 228, 37, 224, 224, 224, 255, 224, 224, 224, 228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 186, 224, 224, 224, 255, 224, 224, 224, 123, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 130, 224, 224, 224, 255, 224, 224, 224, 173, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 227, 227, 227, 62, 224, 224, 224, 255, 224, 224, 224, 254, 225, 225, 225, 126, 225, 225, 225, 34, 227, 227, 227, 36, 224, 224, 224, 131, 224, 224, 224, 255, 224, 224, 224, 255, 226, 226, 226, 77, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 122, 224, 224, 224, 254, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 210, 231, 231, 231, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 226, 226, 226, 69, 225, 225, 225, 174, 224, 224, 224, 233, 224, 224, 224, 228, 224, 224, 224, 173, 226, 226, 226, 77, 224, 224, 224, 210, 224, 224, 224, 255, 224, 224, 224, 210, 231, 231, 231, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 231, 231, 21, 224, 224, 224, 210, 224, 224, 224, 255, 224, 224, 224, 210, 231, 231, 231, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 231, 231, 21, 224, 224, 224, 210, 224, 224, 224, 255, 224, 224, 224, 210, 231, 231, 231, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 231, 231, 21, 224, 224, 224, 210, 224, 224, 224, 227, 225, 225, 225, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 231, 231, 231, 21, 225, 225, 225, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[resource] +image = SubResource("Image_mutbh") diff --git a/addons/twitcher/assets/info_label_settings.tres b/addons/twitcher/assets/info_label_settings.tres new file mode 100644 index 0000000..4f8545f --- /dev/null +++ b/addons/twitcher/assets/info_label_settings.tres @@ -0,0 +1,4 @@ +[gd_resource type="LabelSettings" format=3 uid="uid://d12dapnv7b00n"] + +[resource] +font_color = Color(0.400671, 0.976237, 1, 1) diff --git a/addons/twitcher/assets/media-loader-icon.svg b/addons/twitcher/assets/media-loader-icon.svg new file mode 100644 index 0000000..83610fa --- /dev/null +++ b/addons/twitcher/assets/media-loader-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/twitcher/assets/media-loader-icon.svg.import b/addons/twitcher/assets/media-loader-icon.svg.import new file mode 100644 index 0000000..b8c4ede --- /dev/null +++ b/addons/twitcher/assets/media-loader-icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://drsj3w203jihf" +path="res://.godot/imported/media-loader-icon.svg-7569e70d457bf77b040db83e53346e05.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/twitcher/assets/media-loader-icon.svg" +dest_files=["res://.godot/imported/media-loader-icon.svg-7569e70d457bf77b040db83e53346e05.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/twitcher/assets/no_profile.png b/addons/twitcher/assets/no_profile.png new file mode 100644 index 0000000..3fe0e63 Binary files /dev/null and b/addons/twitcher/assets/no_profile.png differ diff --git a/addons/twitcher/assets/no_profile.png.import b/addons/twitcher/assets/no_profile.png.import new file mode 100644 index 0000000..182559e --- /dev/null +++ b/addons/twitcher/assets/no_profile.png.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://6nflfslr4a52" +path.s3tc="res://.godot/imported/no_profile.png-c0302c23dfe26865f13493d5d6d52fb6.s3tc.ctex" +metadata={ +"imported_formats": ["s3tc_bptc"], +"vram_texture": true +} + +[deps] + +source_file="res://addons/twitcher/assets/no_profile.png" +dest_files=["res://.godot/imported/no_profile.png-c0302c23dfe26865f13493d5d6d52fb6.s3tc.ctex"] + +[params] + +compress/mode=2 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=true +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=0 diff --git a/addons/twitcher/assets/service-icon.svg b/addons/twitcher/assets/service-icon.svg new file mode 100644 index 0000000..1a33980 --- /dev/null +++ b/addons/twitcher/assets/service-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/twitcher/assets/service-icon.svg.import b/addons/twitcher/assets/service-icon.svg.import new file mode 100644 index 0000000..cb25626 --- /dev/null +++ b/addons/twitcher/assets/service-icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://cvvl6migokgdw" +path="res://.godot/imported/service-icon.svg-e43d86792dba5abf158c9a90e8467717.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/twitcher/assets/service-icon.svg" +dest_files=["res://.godot/imported/service-icon.svg-e43d86792dba5abf158c9a90e8467717.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/twitcher/assets/success-page.txt b/addons/twitcher/assets/success-page.txt new file mode 100644 index 0000000..b12bf54 --- /dev/null +++ b/addons/twitcher/assets/success-page.txt @@ -0,0 +1,79 @@ + + + + + + + Twitcher - Login + + + + + +
+
Login Success
+
Page should automatically close when it doesn't happen close it manually.
+ Close Page +
+ + diff --git a/addons/twitcher/assets/title_label_settings.tres b/addons/twitcher/assets/title_label_settings.tres new file mode 100644 index 0000000..743d85b --- /dev/null +++ b/addons/twitcher/assets/title_label_settings.tres @@ -0,0 +1,9 @@ +[gd_resource type="LabelSettings" load_steps=2 format=3 uid="uid://bnsxy6gcm8q11"] + +[sub_resource type="SystemFont" id="SystemFont_rtf3j"] +font_weight = 800 +force_autohinter = true + +[resource] +font = SubResource("SystemFont_rtf3j") +font_size = 18 diff --git a/addons/twitcher/assets/transparent.tres b/addons/twitcher/assets/transparent.tres new file mode 100644 index 0000000..0b734ab --- /dev/null +++ b/addons/twitcher/assets/transparent.tres @@ -0,0 +1,9 @@ +[gd_resource type="GradientTexture1D" load_steps=2 format=3 uid="uid://bdhuy21ldt2vv"] + +[sub_resource type="Gradient" id="Gradient_y3p12"] +offsets = PackedFloat32Array(1) +colors = PackedColorArray(1, 1, 1, 0) + +[resource] +gradient = SubResource("Gradient_y3p12") +width = 1 diff --git a/addons/twitcher/assets/twitcher-icon.svg b/addons/twitcher/assets/twitcher-icon.svg new file mode 100644 index 0000000..29e1ed8 --- /dev/null +++ b/addons/twitcher/assets/twitcher-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/addons/twitcher/assets/twitcher-icon.svg.import b/addons/twitcher/assets/twitcher-icon.svg.import new file mode 100644 index 0000000..f74a27b --- /dev/null +++ b/addons/twitcher/assets/twitcher-icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ctljyyw6gikq0" +path="res://.godot/imported/twitcher-icon.svg-eae8d458f370f3edcefb2f6360cb1ecc.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/twitcher/assets/twitcher-icon.svg" +dest_files=["res://.godot/imported/twitcher-icon.svg-eae8d458f370f3edcefb2f6360cb1ecc.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/twitcher/assets/warning_label_settings.tres b/addons/twitcher/assets/warning_label_settings.tres new file mode 100644 index 0000000..5fa8bda --- /dev/null +++ b/addons/twitcher/assets/warning_label_settings.tres @@ -0,0 +1,4 @@ +[gd_resource type="LabelSettings" format=3 uid="uid://cng881nsuud80"] + +[resource] +font_color = Color(1, 0.870588, 0.4, 1) diff --git a/addons/twitcher/auth/preset_game_scopes.tres b/addons/twitcher/auth/preset_game_scopes.tres new file mode 100644 index 0000000..ec4e463 --- /dev/null +++ b/addons/twitcher/auth/preset_game_scopes.tres @@ -0,0 +1,8 @@ +[gd_resource type="Resource" script_class="TwitchOAuthScopes" load_steps=2 format=3 uid="uid://3dm6ts8hwlys"] + +[ext_resource type="Script" uid="uid://b3n3et8mebjcc" path="res://addons/twitcher/auth/twitch_oauth_scopes.gd" id="1_bpjq8"] + +[resource] +script = ExtResource("1_bpjq8") +used_scopes = Array[StringName]([&"user:read:chat", &"user:write:chat", &"user:bot"]) +metadata/_custom_type_script = "uid://b3n3et8mebjcc" diff --git a/addons/twitcher/auth/preset_overlay_scopes.tres b/addons/twitcher/auth/preset_overlay_scopes.tres new file mode 100644 index 0000000..384affe --- /dev/null +++ b/addons/twitcher/auth/preset_overlay_scopes.tres @@ -0,0 +1,8 @@ +[gd_resource type="Resource" script_class="TwitchOAuthScopes" load_steps=2 format=3 uid="uid://fcmfkstye4bq"] + +[ext_resource type="Script" uid="uid://b3n3et8mebjcc" path="res://addons/twitcher/auth/twitch_oauth_scopes.gd" id="1_2b4sa"] + +[resource] +script = ExtResource("1_2b4sa") +used_scopes = Array[StringName]([&"user:read:chat", &"user:write:chat", &"user:bot"]) +metadata/_custom_type_script = "uid://b3n3et8mebjcc" diff --git a/addons/twitcher/auth/twitch_auth.gd b/addons/twitcher/auth/twitch_auth.gd new file mode 100644 index 0000000..37ec4e6 --- /dev/null +++ b/addons/twitcher/auth/twitch_auth.gd @@ -0,0 +1,135 @@ +@icon("res://addons/twitcher/assets/auth-icon.svg") +@tool +extends Twitcher + +## Delegate class for the oOuch Library. +class_name TwitchAuth + +const HttpUtil = preload("res://addons/twitcher/lib/http/http_util.gd") + +static var _log: TwitchLogger = TwitchLogger.new("TwitchAuth") + +## The requested devicecode to show to the user for authorization +signal device_code_requested(device_code: OAuth.OAuthDeviceCodeResponse); + +## Where and how to authorize. +@export var oauth_setting: OAuthSetting: + set(val): + oauth_setting = val + if auth != null: auth.oauth_setting = oauth_setting + if token_handler != null: token_handler.oauth_setting = oauth_setting + update_configuration_warnings() +## Shows the what to authorize page of twitch again. (for example you need to relogin with a different account aka bot account) +@export var force_verify: bool +## Where should the tokens be saved into +@export var token: OAuthToken: + set(val): + token = val + if token_handler != null: token_handler.token = token + update_configuration_warnings() +## Scopes for the token that should be requested +@export var scopes: OAuthScopes: + set(val): + scopes = val + if auth != null: auth.scopes = scopes + update_configuration_warnings() + +## Takes care to authorize the user +@onready var auth: OAuth +## Takes care to fetch and refresh oauth tokens +@onready var token_handler: TwitchTokenHandler + + +var is_authenticated: bool: + get(): return auth.is_authenticated() + + +func _init() -> void: + child_entered_tree.connect(_on_enter_child) + # There could be better locations but this ensures that its there when an + # auth is needed. + var http_logger = TwitchLogger.new("Http") + HttpUtil.set_logger(http_logger.e, http_logger.i, http_logger.d) + + +func _on_enter_child(node: Node) -> void: + if node is OAuth: auth = node + if node is TwitchTokenHandler: token_handler = node + + +func _ready() -> void: + OAuth.set_logger(_log.e, _log.i, _log.d); + if oauth_setting == null: oauth_setting = create_default_oauth_setting() + _ensure_children() + + +func _ensure_children() -> void: + if token_handler == null: + token_handler = TwitchTokenHandler.new() + token_handler.name = "TokenHandler" + + if auth == null: + auth = OAuth.new() + auth.name = "OAuth" + + _sync_childs() + + if not auth.is_inside_tree(): + add_child(auth) + auth.owner = owner + if not token_handler.is_inside_tree(): + add_child(token_handler) + token_handler.owner = owner + + +func _sync_childs() -> void: + token_handler.oauth_setting = oauth_setting + token_handler.token = token + auth.token_handler = token_handler + auth.oauth_setting = oauth_setting + auth.scopes = scopes + auth.force_verify = &"true" if force_verify else &"false" + + +func authorize() -> bool: + _sync_childs() + if await auth.login(): + token_handler.process_mode = Node.PROCESS_MODE_INHERIT + return true + return false + + +func refresh_token() -> void: + auth.refresh_token() + + +static func create_default_oauth_setting() -> OAuthSetting: + var oauth_setting = OAuthSetting.new() + oauth_setting.authorization_flow = OAuth.AuthorizationFlow.AUTHORIZATION_CODE_FLOW + oauth_setting.device_authorization_url = "https://id.twitch.tv/oauth2/device" + oauth_setting.token_url = "https://id.twitch.tv/oauth2/token" + oauth_setting.authorization_url = "https://id.twitch.tv/oauth2/authorize" + oauth_setting.cache_file = "user://auth.conf" + oauth_setting.redirect_url = "http://localhost:7170" + return oauth_setting + + +## Checks if the correctly setup +func is_configured() -> bool: + return _get_configuration_warnings().is_empty() + + +func _get_configuration_warnings() -> PackedStringArray: + var result: PackedStringArray = [] + if oauth_setting == null: + result.append("OAuthSetting missing") + else: + var oauth_setting_problems : PackedStringArray = oauth_setting.get_valididation_problems() + if not oauth_setting_problems.is_empty(): + result.append("OAuthSetting is invalid") + result.append_array(oauth_setting_problems) + if scopes == null: + result.append("OAuthScopes is missing") + if token == null: + result.append("OAuthToken is missing") + return result diff --git a/addons/twitcher/auth/twitch_auth.gd.uid b/addons/twitcher/auth/twitch_auth.gd.uid new file mode 100644 index 0000000..129e006 --- /dev/null +++ b/addons/twitcher/auth/twitch_auth.gd.uid @@ -0,0 +1 @@ +uid://iv0mgv0lu8b0 diff --git a/addons/twitcher/auth/twitch_oauth_scopes.gd b/addons/twitcher/auth/twitch_oauth_scopes.gd new file mode 100644 index 0000000..3394461 --- /dev/null +++ b/addons/twitcher/auth/twitch_oauth_scopes.gd @@ -0,0 +1,6 @@ +@tool +@icon("res://addons/twitcher/lib/oOuch/scope-icon.svg") +extends OAuthScopes + +## Technically the same like OAuthScopes just with a custom inspector for Twitch scopes +class_name TwitchOAuthScopes diff --git a/addons/twitcher/auth/twitch_oauth_scopes.gd.uid b/addons/twitcher/auth/twitch_oauth_scopes.gd.uid new file mode 100644 index 0000000..b9efd15 --- /dev/null +++ b/addons/twitcher/auth/twitch_oauth_scopes.gd.uid @@ -0,0 +1 @@ +uid://b3n3et8mebjcc diff --git a/addons/twitcher/auth/twitch_scope.gd b/addons/twitcher/auth/twitch_scope.gd new file mode 100644 index 0000000..77b4c34 --- /dev/null +++ b/addons/twitcher/auth/twitch_scope.gd @@ -0,0 +1,195 @@ +@tool +extends Resource + +class_name TwitchScope + +class Definition extends Object: + var value: StringName + var description: String + var categroy: String + + + func _init(val: StringName, desc: String, cat: String = "") -> void: + value = val + description = desc + categroy = cat + + + func get_category() -> String: + if categroy: return categroy + return value.substr(0, value.find(":")) + + +static var ANALYTICS_READ_EXTENSIONS = Definition.new(&"analytics:read:extensions", "View analytics data for the Twitch Extensions owned by the authenticated account.") +static var ANALYTICS_READ_GAMES = Definition.new(&"analytics:read:games", "View analytics data for the games owned by the authenticated account.") +static var BITS_READ = Definition.new(&"bits:read", "View Bits information for a channel.") +static var CHANNEL_BOT = Definition.new(&"channel:bot", "Joins your channel’s chatroom as a bot user, and perform chat-related actions as that user.") +static var CHANNEL_MANAGE_ADS = Definition.new(&"channel:manage:ads", "Manage ads schedule on a channel.") +static var CHANNEL_READ_ADS = Definition.new(&"channel:read:ads", "Read the ads schedule and details on your channel.") +static var CHANNEL_MANAGE_BROADCAST = Definition.new(&"channel:manage:broadcast", "Manage a channel’s broadcast configuration, including updating channel configuration and managing stream markers and stream tags.") +static var CHANNEL_READ_CHARITY = Definition.new(&"channel:read:charity", "Read charity campaign details and user donations on your channel.") +static var CHANNEL_EDIT_COMMERCIAL = Definition.new(&"channel:edit:commercial", "Run commercials on a channel.") +static var CHANNEL_READ_EDITORS = Definition.new(&"channel:read:editors", "View a list of users with the editor role for a channel.") +static var CHANNEL_MANAGE_EXTENSIONS = Definition.new(&"channel:manage:extensions", "Manage a channel’s Extension configuration, including activating Extensions.") +static var CHANNEL_READ_GOALS = Definition.new(&"channel:read:goals", "View Creator Goals for a channel.") +static var CHANNEL_READ_GUEST_STAR = Definition.new(&"channel:read:guest_star", "Read Guest Star details for your channel.") +static var CHANNEL_MANAGE_GUEST_STAR = Definition.new(&"channel:manage:guest_star", "Manage Guest Star for your channel.") +static var CHANNEL_READ_HYPE_TRAIN = Definition.new(&"channel:read:hype_train", "View Hype Train information for a channel.") +static var CHANNEL_MANAGE_MODERATORS = Definition.new(&"channel:manage:moderators", "Add or remove the moderator role from users in your channel.") +static var CHANNEL_READ_POLLS = Definition.new(&"channel:read:polls", "View a channel’s polls.") +static var CHANNEL_MANAGE_POLLS = Definition.new(&"channel:manage:polls", "Manage a channel’s polls.") +static var CHANNEL_READ_PREDICTIONS = Definition.new(&"channel:read:predictions", "View a channel’s Channel Points Predictions.") +static var CHANNEL_MANAGE_PREDICTIONS = Definition.new(&"channel:manage:predictions", "Manage of channel’s Channel Points Predictions") +static var CHANNEL_MANAGE_RAIDS = Definition.new(&"channel:manage:raids", "Manage a channel raiding another channel.") +static var CHANNEL_READ_REDEMPTIONS = Definition.new(&"channel:read:redemptions", "View Channel Points custom rewards and their redemptions on a channel.") +static var CHANNEL_MANAGE_REDEMPTIONS = Definition.new(&"channel:manage:redemptions", "Manage Channel Points custom rewards and their redemptions on a channel.") +static var CHANNEL_MANAGE_SCHEDULE = Definition.new(&"channel:manage:schedule", "Manage a channel’s stream schedule.") +static var CHANNEL_READ_STREAM_KEY = Definition.new(&"channel:read:stream_key", "View an authorized user’s stream key.") +static var CHANNEL_READ_SUBSCRIPTIONS = Definition.new(&"channel:read:subscriptions", "View a list of all subscribers to a channel and check if a user is subscribed to a channel.") +static var CHANNEL_MANAGE_VIDEOS = Definition.new(&"channel:manage:videos", "Manage a channel’s videos, including deleting videos.") +static var CHANNEL_READ_VIPS = Definition.new(&"channel:read:vips", "Read the list of VIPs in your channel.") +static var CHANNEL_MANAGE_VIPS = Definition.new(&"channel:manage:vips", "Add or remove the VIP role from users in your channel.") +static var CLIPS_EDIT = Definition.new(&"clips:edit", "Manage Clips for a channel.") +static var MODERATION_READ = Definition.new(&"moderation:read", "View a channel’s moderation data including Moderators, Bans, Timeouts, and Automod settings.") +static var MODERATOR_MANAGE_ANNOUNCEMENTS = Definition.new(&"moderator:manage:announcements", "Send announcements in channels where you have the moderator role.") +static var MODERATOR_MANAGE_AUTOMOD = Definition.new(&"moderator:manage:automod", "Manage messages held for review by AutoMod in channels where you are a moderator.") +static var MODERATOR_READ_AUTOMOD_SETTINGS = Definition.new(&"moderator:read:automod_settings", "View a broadcaster’s AutoMod settings.") +static var MODERATOR_MANAGE_AUTOMOD_SETTINGS = Definition.new(&"moderator:manage:automod_settings", "Manage a broadcaster’s AutoMod settings.") +static var MODERATOR_READ_BANNED_USERS = Definition.new(&"moderator:read:banned_users", "Read the list of bans or unbans in channels where you have the moderator role.") +static var MODERATOR_MANAGE_BANNED_USERS = Definition.new(&"moderator:manage:banned_users", "Ban and unban users.") +static var MODERATOR_READ_BLOCKED_TERMS = Definition.new(&"moderator:read:blocked_terms", "View a broadcaster’s list of blocked terms.") +static var MODERATOR_READ_CHAT_MESSAGES = Definition.new(&"moderator:read:chat_messages", "Read deleted chat messages in channels where you have the moderator role.") +static var MODERATOR_MANAGE_BLOCKED_TERMS = Definition.new(&"moderator:manage:blocked_terms", "Manage a broadcaster’s list of blocked terms.") +static var MODERATOR_MANAGE_CHAT_MESSAGES = Definition.new(&"moderator:manage:chat_messages", "Delete chat messages in channels where you have the moderator role") +static var MODERATOR_READ_CHAT_SETTINGS = Definition.new(&"moderator:read:chat_settings", "View a broadcaster’s chat room settings.") +static var MODERATOR_MANAGE_CHAT_SETTINGS = Definition.new(&"moderator:manage:chat_settings", "Manage a broadcaster’s chat room settings.") +static var MODERATOR_READ_CHATTERS = Definition.new(&"moderator:read:chatters", "View the chatters in a broadcaster’s chat room.") +static var MODERATOR_READ_FOLLOWERS = Definition.new(&"moderator:read:followers", "Read the followers of a broadcaster.") +static var MODERATOR_READ_GUEST_STAR = Definition.new(&"moderator:read:guest_star", "Read Guest Star details for channels where you are a Guest Star moderator.") +static var MODERATOR_MANAGE_GUEST_STAR = Definition.new(&"moderator:manage:guest_star", "Manage Guest Star for channels where you are a Guest Star moderator.") +static var MODERATOR_READ_MODERATORS = Definition.new(&"moderator:read:moderators", "Read the list of moderators in channels where you have the moderator role.") +static var MODERATOR_READ_SHIELD_MODE = Definition.new(&"moderator:read:shield_mode", "View a broadcaster’s Shield Mode status.") +static var MODERATOR_MANAGE_SHIELD_MODE = Definition.new(&"moderator:manage:shield_mode", "Manage a broadcaster’s Shield Mode status.") +static var MODERATOR_READ_SHOUTOUTS = Definition.new(&"moderator:read:shoutouts", "View a broadcaster’s shoutouts.") +static var MODERATOR_MANAGE_SHOUTOUTS = Definition.new(&"moderator:manage:shoutouts", "Manage a broadcaster’s shoutouts.") +static var MODERATOR_READ_SUSPICIOUS_USERS = Definition.new(&"moderator:read:suspicious_users", "Read chat messages from suspicious users and see users flagged as suspicious in channels where you have the moderator role.") +static var MODERATOR_READ_UNBAN_REQUESTS = Definition.new(&"moderator:read:unban_requests", "View a broadcaster’s unban requests.") +static var MODERATOR_MANAGE_UNBAN_REQUESTS = Definition.new(&"moderator:manage:unban_requests", "Manage a broadcaster’s unban requests.") +static var MODERATOR_READ_VIPS = Definition.new(&"moderator:read:vips", "Read the list of VIPs in channels where you have the moderator role.") +static var MODERATOR_READ_WARNINGS = Definition.new(&"moderator:read:warnings", "Read warnings in channels where you have the moderator role.") +static var MODERATOR_MANAGE_WARNINGS = Definition.new(&"moderator:manage:warnings", "Warn users in channels where you have the moderator role.") +static var USER_BOT = Definition.new(&"user:bot", "Join a specified chat channel as your user and appear as a bot, and perform chat-related actions as your user.") +static var USER_EDIT = Definition.new(&"user:edit", "Manage a user object.") +static var USER_EDIT_BROADCAST = Definition.new(&"user:edit:broadcast", "View and edit a user’s broadcasting configuration, including Extension configurations.") +static var USER_READ_BLOCKED_USERS = Definition.new(&"user:read:blocked_users", "View the block list of a user.") +static var USER_MANAGE_BLOCKED_USERS = Definition.new(&"user:manage:blocked_users", "Manage the block list of a user.") +static var USER_READ_BROADCAST = Definition.new(&"user:read:broadcast", "View a user’s broadcasting configuration, including Extension configurations.") +static var USER_READ_CHAT = Definition.new(&"user:read:chat", "Receive chatroom messages and informational notifications relating to a channel’s chatroom.") +static var USER_MANAGE_CHAT_COLOR = Definition.new(&"user:manage:chat_color", "Update the color used for the user’s name in chat.") +static var USER_READ_EMAIL = Definition.new(&"user:read:email", "View a user’s email address.") +static var USER_READ_EMOTES = Definition.new(&"user:read:emotes", "View emotes available to a user") +static var USER_READ_FOLLOWS = Definition.new(&"user:read:follows", "View the list of channels a user follows.") +static var USER_READ_MODERATED_CHANNELS = Definition.new(&"user:read:moderated_channels", "Read the list of channels you have moderator privileges in.") +static var USER_READ_SUBSCRIPTIONS = Definition.new(&"user:read:subscriptions", "View if an authorized user is subscribed to specific channels.") +static var USER_READ_WHISPERS = Definition.new(&"user:read:whispers", "Receive whispers sent to your user.") +static var USER_MANAGE_WHISPERS = Definition.new(&"user:manage:whispers", "Receive whispers sent to your user, and send whispers on your user’s behalf.") +static var USER_WRITE_CHAT = Definition.new(&"user:write:chat", "Send chat messages to a chatroom.") +static var CHAT_READ = Definition.new(&"chat:edit", "Send chat messages to a chatroom using an IRC connection.", "IRC") +static var CHAT_EDIT = Definition.new(&"chat:read", "View chat messages sent in a chatroom using an IRC connection.", "IRC") + +## Key: Scope Name as String | Value: Definition +static var SCOPE_MAP: Dictionary = { + "analytics:read:extensions" = ANALYTICS_READ_EXTENSIONS, + "analytics:read:games" = ANALYTICS_READ_GAMES, + "bits:read" = BITS_READ, + "channel:bot" = CHANNEL_BOT, + "channel:manage:ads" = CHANNEL_MANAGE_ADS, + "channel:read:ads" = CHANNEL_READ_ADS, + "channel:manage:broadcast" = CHANNEL_MANAGE_BROADCAST, + "channel:read:charity" = CHANNEL_READ_CHARITY, + "channel:edit:commercial" = CHANNEL_EDIT_COMMERCIAL, + "channel:read:editors" = CHANNEL_READ_EDITORS, + "channel:manage:extensions" = CHANNEL_MANAGE_EXTENSIONS, + "channel:read:goals" = CHANNEL_READ_GOALS, + "channel:read:guest_star" = CHANNEL_READ_GUEST_STAR, + "channel:manage:guest_star" = CHANNEL_MANAGE_GUEST_STAR, + "channel:read:hype_train" = CHANNEL_READ_HYPE_TRAIN, + "channel:manage:moderators" = CHANNEL_MANAGE_MODERATORS, + "channel:read:polls" = CHANNEL_READ_POLLS, + "channel:manage:polls" = CHANNEL_MANAGE_POLLS, + "channel:read:predictions" = CHANNEL_READ_PREDICTIONS, + "channel:manage:predictions" = CHANNEL_MANAGE_PREDICTIONS, + "channel:manage:raids" = CHANNEL_MANAGE_RAIDS, + "channel:read:redemptions" = CHANNEL_READ_REDEMPTIONS, + "channel:manage:redemptions" = CHANNEL_MANAGE_REDEMPTIONS, + "channel:manage:schedule" = CHANNEL_MANAGE_SCHEDULE, + "channel:read:stream_key" = CHANNEL_READ_STREAM_KEY, + "channel:read:subscriptions" = CHANNEL_READ_SUBSCRIPTIONS, + "channel:manage:videos" = CHANNEL_MANAGE_VIDEOS, + "channel:read:vips" = CHANNEL_READ_VIPS, + "channel:manage:vips" = CHANNEL_MANAGE_VIPS, + "clips:edit" = CLIPS_EDIT, + "moderation:read" = MODERATION_READ, + "moderator:manage:announcements" = MODERATOR_MANAGE_ANNOUNCEMENTS, + "moderator:manage:automod" = MODERATOR_MANAGE_AUTOMOD, + "moderator:read:automod_settings" = MODERATOR_READ_AUTOMOD_SETTINGS, + "moderator:manage:automod_settings" = MODERATOR_MANAGE_AUTOMOD_SETTINGS, + "moderator:read:banned_users" = MODERATOR_READ_BANNED_USERS, + "moderator:manage:banned_users" = MODERATOR_MANAGE_BANNED_USERS, + "moderator:read:blocked_terms" = MODERATOR_READ_BLOCKED_TERMS, + "moderator:read:chat_messages" = MODERATOR_READ_CHAT_MESSAGES, + "moderator:manage:blocked_terms" = MODERATOR_MANAGE_BLOCKED_TERMS, + "moderator:manage:chat_messages" = MODERATOR_MANAGE_CHAT_MESSAGES, + "moderator:read:chat_settings" = MODERATOR_READ_CHAT_SETTINGS, + "moderator:manage:chat_settings" = MODERATOR_MANAGE_CHAT_SETTINGS, + "moderator:read:chatters" = MODERATOR_READ_CHATTERS, + "moderator:read:followers" = MODERATOR_READ_FOLLOWERS, + "moderator:read:guest_star" = MODERATOR_READ_GUEST_STAR, + "moderator:manage:guest_star" = MODERATOR_MANAGE_GUEST_STAR, + "moderator:read:moderators" = MODERATOR_READ_MODERATORS, + "moderator:read:shield_mode" = MODERATOR_READ_SHIELD_MODE, + "moderator:manage:shield_mode" = MODERATOR_MANAGE_SHIELD_MODE, + "moderator:read:shoutouts" = MODERATOR_READ_SHOUTOUTS, + "moderator:manage:shoutouts" = MODERATOR_MANAGE_SHOUTOUTS, + "moderator:read:suspicious_users" = MODERATOR_READ_SUSPICIOUS_USERS, + "moderator:read:unban_requests" = MODERATOR_READ_UNBAN_REQUESTS, + "moderator:manage:unban_requests" = MODERATOR_MANAGE_UNBAN_REQUESTS, + "moderator:read:vips" = MODERATOR_READ_VIPS, + "moderator:read:warnings" = MODERATOR_READ_WARNINGS, + "moderator:manage:warnings" = MODERATOR_MANAGE_WARNINGS, + "user:bot" = USER_BOT, + "user:edit" = USER_EDIT, + "user:edit:broadcast" = USER_EDIT_BROADCAST, + "user:read:blocked_users" = USER_READ_BLOCKED_USERS, + "user:manage:blocked_users" = USER_MANAGE_BLOCKED_USERS, + "user:read:broadcast" = USER_READ_BROADCAST, + "user:read:chat" = USER_READ_CHAT, + "user:manage:chat_color" = USER_MANAGE_CHAT_COLOR, + "user:read:email" = USER_READ_EMAIL, + "user:read:emotes" = USER_READ_EMOTES, + "user:read:follows" = USER_READ_FOLLOWS, + "user:read:moderated_channels" = USER_READ_MODERATED_CHANNELS, + "user:read:subscriptions" = USER_READ_SUBSCRIPTIONS, + "user:read:whispers" = USER_READ_WHISPERS, + "user:manage:whispers" = USER_MANAGE_WHISPERS, + "user:write:chat" = USER_WRITE_CHAT, + "chat:read" = CHAT_READ, + "chat:edit" = CHAT_EDIT, +} + + +## Key: Category as String, value as Array[Definition] +static func get_grouped_scopes() -> Dictionary: + var result = {} + for scope: Definition in get_all_scopes(): + var category_name = scope.get_category() + var category = result.get_or_add(category_name, []) + category.append(scope) + return result + + +static func get_all_scopes() -> Array[Definition]: + var scopes: Array[Definition] = [] + for scope in SCOPE_MAP.values(): + scopes.append(scope) + return scopes diff --git a/addons/twitcher/auth/twitch_scope.gd.uid b/addons/twitcher/auth/twitch_scope.gd.uid new file mode 100644 index 0000000..4adcea2 --- /dev/null +++ b/addons/twitcher/auth/twitch_scope.gd.uid @@ -0,0 +1 @@ +uid://bjgpdxggorn0l diff --git a/addons/twitcher/auth/twitch_token_handler.gd b/addons/twitcher/auth/twitch_token_handler.gd new file mode 100644 index 0000000..ea97ef2 --- /dev/null +++ b/addons/twitcher/auth/twitch_token_handler.gd @@ -0,0 +1,50 @@ +@icon("res://addons/twitcher/assets/auth-icon.svg") +@tool +extends OAuthTokenHandler + +class_name TwitchTokenHandler + +## Time between checking the validation of the tokens +var _last_validation_check: int = 0 + + +func _ready() -> void: + super._ready() + # We don't need to check right after the start + _last_validation_check = Time.get_ticks_msec() + 60 * 60 * 1000; + + +func _check_token_refresh() -> void: + super._check_token_refresh() + + if _last_validation_check < Time.get_ticks_msec(): + _validate_token() + + +## Calles the validation endpoint of Twtich to make sure +func _validate_token() -> void: + _last_validation_check = Time.get_ticks_msec() + 60 * 60 * 1000; + var validation_request = _http_client.request("https://id.twitch.tv/oauth2/validate", HTTPClient.METHOD_GET, { + "Authorization": "OAuth %s" % await token.get_access_token() + }, "") + var response = await _http_client.wait_for_request(validation_request) + if response.response_code != 200: + refresh_tokens() + return + + var response_string: String = response.response_data.get_string_from_utf8(); + var response_data = JSON.parse_string(response_string); + if response_data["expires_in"] <= 0: + refresh_tokens() + return + + +func revoke_token() -> void: + var request = _http_client.request("https://id.twitch.tv/oauth2/revoke", HTTPClient.METHOD_POST, + { "Content-Type": "application/x-www-form-urlencoded" }, + "client_id=%s&token=%s" % [oauth_setting.client_id, await token.get_access_token()]) + var response: BufferedHTTPClient.ResponseData = await _http_client.wait_for_request(request) + if response.error: + var response_message = response.response_data.get_string_from_utf8() + logError("Couldn't revoke Token cause of: %s" % response_message) + token.remove_tokens() diff --git a/addons/twitcher/auth/twitch_token_handler.gd.uid b/addons/twitcher/auth/twitch_token_handler.gd.uid new file mode 100644 index 0000000..583ef51 --- /dev/null +++ b/addons/twitcher/auth/twitch_token_handler.gd.uid @@ -0,0 +1 @@ +uid://blnbogtrshw4r diff --git a/addons/twitcher/chat/twitch_announcement_color.gd b/addons/twitcher/chat/twitch_announcement_color.gd new file mode 100644 index 0000000..ed4f49c --- /dev/null +++ b/addons/twitcher/chat/twitch_announcement_color.gd @@ -0,0 +1,14 @@ +extends RefCounted + +class_name TwitchAnnouncementColor + +static var BLUE: TwitchAnnouncementColor = TwitchAnnouncementColor.new("blue") +static var GREEN: TwitchAnnouncementColor = TwitchAnnouncementColor.new("green") +static var ORANGE: TwitchAnnouncementColor = TwitchAnnouncementColor.new("orange") +static var PURPLE: TwitchAnnouncementColor = TwitchAnnouncementColor.new("purple") +static var PRIMARY: TwitchAnnouncementColor = TwitchAnnouncementColor.new("primary") + +var value; + +func _init(color: String) -> void: + value = color; diff --git a/addons/twitcher/chat/twitch_announcement_color.gd.uid b/addons/twitcher/chat/twitch_announcement_color.gd.uid new file mode 100644 index 0000000..0d83a8b --- /dev/null +++ b/addons/twitcher/chat/twitch_announcement_color.gd.uid @@ -0,0 +1 @@ +uid://doop8abj8sed6 diff --git a/addons/twitcher/chat/twitch_chat.gd b/addons/twitcher/chat/twitch_chat.gd new file mode 100644 index 0000000..3ec42e0 --- /dev/null +++ b/addons/twitcher/chat/twitch_chat.gd @@ -0,0 +1,116 @@ +@icon("../assets/chat-icon.svg") +@tool +extends Twitcher + +## Grants access to read and write to a chat +class_name TwitchChat + +static var _log: TwitchLogger = TwitchLogger.new("TwitchChat") + +static var instance: TwitchChat + +@export var broadcaster_user: TwitchUser: + set(val): + broadcaster_user = val + update_configuration_warnings() +## Can be null. Then the owner of the access token will be used to send message aka the current user. +@export var sender_user: TwitchUser +@export var media_loader: TwitchMediaLoader +@export var eventsub: TwitchEventsub: + set(val): + eventsub = val + update_configuration_warnings() +@export var api: TwitchAPI: + set(val): + api = val + update_configuration_warnings() + +## Should it subscribe on ready +@export var subscribe_on_ready: bool = true + + +## Triggered when a chat message got received +signal message_received(message: TwitchChatMessage) + + +func _ready() -> void: + _log.d("is ready") + if media_loader == null: media_loader = TwitchMediaLoader.instance + if api == null: api = TwitchAPI.instance + if eventsub == null: eventsub = TwitchEventsub.instance + eventsub.event.connect(_on_event_received) + if not Engine.is_editor_hint() && subscribe_on_ready: + subscribe() + + +func _enter_tree() -> void: + if instance == null: instance = self + + +func _exit_tree() -> void: + if instance == self: instance = null + + +## Subscribe to eventsub and preload data if not happend yet +func subscribe() -> void: + if broadcaster_user == null: + printerr("BroadcasterUser is not set. Can't subscribe to chat.") + return + + if is_instance_valid(media_loader): + media_loader.preload_badges(broadcaster_user.id) + media_loader.preload_emotes(broadcaster_user.id) + + for subscription: TwitchEventsubConfig in eventsub.get_subscriptions(): + if subscription.type == TwitchEventsubDefinition.Type.CHANNEL_CHAT_MESSAGE and \ + subscription.condition.broadcaster_user_id == broadcaster_user.id: + # it is already subscribed + return + + if sender_user == null: + var current_user: TwitchGetUsers.Response = await api.get_users(null) + sender_user = current_user.data[0] + + var config: TwitchEventsubConfig = TwitchEventsubConfig.new() + config.type = TwitchEventsubDefinition.Type.CHANNEL_CHAT_MESSAGE + config.condition = { + "broadcaster_user_id": broadcaster_user.id, + "user_id": sender_user.id + } + eventsub.subscribe(config) + _log.i("Listen to Chat of %s (%s)" % [broadcaster_user.display_name, broadcaster_user.id]) + + +func _on_event_received(type: StringName, data: Dictionary) -> void: + if type != TwitchEventsubDefinition.CHANNEL_CHAT_MESSAGE.value: return + var message: TwitchChatMessage = TwitchChatMessage.from_json(data) + if message.broadcaster_user_id == broadcaster_user.id: + message_received.emit(message) + + +func send_message(message: String, reply_parent_message_id: String = "") -> Array[TwitchSendChatMessage.ResponseData]: + var message_body: TwitchSendChatMessage.Body = TwitchSendChatMessage.Body.new() + message_body.broadcaster_id = broadcaster_user.id + message_body.sender_id = sender_user.id + message_body.message = message + if reply_parent_message_id: + message_body.reply_parent_message_id = reply_parent_message_id + + var response: TwitchSendChatMessage.Response = await api.send_chat_message(message_body) + if _log.enabled: + for message_data: TwitchSendChatMessage.ResponseData in response.data: + if not message_data.is_sent: + _log.w(message_data.drop_reason) + + return response.data + + +func _get_configuration_warnings() -> PackedStringArray: + var result: PackedStringArray = [] + if eventsub == null: + result.append("TwitchEventsub not assigned") + if api == null: + result.append("TwitchAPI not assigned") + if broadcaster_user == null: + result.append("Target broadcaster not specified") + return result diff --git a/addons/twitcher/chat/twitch_chat.gd.uid b/addons/twitcher/chat/twitch_chat.gd.uid new file mode 100644 index 0000000..c37b139 --- /dev/null +++ b/addons/twitcher/chat/twitch_chat.gd.uid @@ -0,0 +1 @@ +uid://dcq1bvfrqimqq diff --git a/addons/twitcher/chat/twitch_chat_message.gd b/addons/twitcher/chat/twitch_chat_message.gd new file mode 100644 index 0000000..c370ea7 --- /dev/null +++ b/addons/twitcher/chat/twitch_chat_message.gd @@ -0,0 +1,367 @@ +extends RefCounted + +class_name TwitchChatMessage + +enum FragmentType { + text = 0, + cheermote = 1, + emote = 2, + mention = 3 +} + +const FRAGMENT_TYPES = ["text", "cheermote", "emote", "mention"] + +enum EmoteFormat { + animated = 0, + _static = 1 +} + +const EMOTE_FORMATES = ["animated", "static"] + +enum MessageType { + ## Normal chat message + text = 0, + ## The default reward where the message is highlighted + channel_points_highlighted = 1, + ## Channel points were used to send this message in sub-only mode. + channel_points_sub_only = 2, + ## when a new user is typing for the first time + user_intro = 3, + ## When the power up message effect was used on this message + power_ups_message_effect = 4, + ## When a gigantified emote was posted + power_ups_gigantified_emote = 5 +} + +const MESSAGE_TYPES = ["text", "channel_points_highlighted", "channel_points_sub_only", "user_intro", "power_ups_message_effect", "power_ups_gigantified_emote"] + +class Message extends RefCounted: + ## The chat message in plain text. + var text: String + ## Ordered list of chat message fragments. + var fragments: Array[Fragment] = [] + + + static func from_json(d: Dictionary) -> Message: + var result = Message.new() + if d.has("text") and d["text"] != null: + result.text = d["text"] + if d.has("fragments") and d["fragments"] != null: + for value in d["fragments"]: + result.fragments.append(Fragment.from_json(value)) + return result + + +class Fragment extends RefCounted: + ## The type of message fragment. See "TwitchChatMessage.FRAGMENT_TYPE_*" + var type: MessageType + ## Message text in fragment. + var text: String + ## Optional. Metadata pertaining to the cheermote. + var cheermote: Cheermote + ## Optional. Metadata pertaining to the emote. + var emote: Emote + ## Optional. Metadata pertaining to the mention. + var mention: Mention + + + static func from_json(d: Dictionary) -> Fragment: + var result = Fragment.new() + if d.has("type") and d["type"] != null: + result.type = FragmentType[d["type"]] + if d.has("text") and d["text"] != null: + result.text = d["text"] + if d.has("cheermote") and d["cheermote"] != null: + result.cheermote = Cheermote.from_json(d["cheermote"]) + if d.has("emote") and d["emote"] != null: + result.emote = Emote.from_json(d["emote"]) + if d.has("mention") and d["mention"] != null: + result.mention = Mention.from_json(d["mention"]) + return result + + +class Mention extends RefCounted: + ## The user ID of the mentioned user. + var user_id: String + ## The user name of the mentioned user. + var user_name: String + ## The user login of the mentioned user. + var user_login: String + + + static func from_json(d: Dictionary) -> Mention: + var result = Mention.new() + if d.has("user_id") and d["user_id"] != null: + result.user_id = d["user_id"] + if d.has("user_name") and d["user_name"] != null: + result.user_name = d["user_name"] + if d.has("user_login") and d["user_login"] != null: + result.user_login = d["user_login"] + return result + + +class Cheermote extends RefCounted: + ## The name portion of the Cheermote string that you use in chat to cheer Bits. The full Cheermote string is the concatenation of {prefix} + {number of Bits}. For example, if the prefix is “Cheer” and you want to cheer 100 Bits, the full Cheermote string is Cheer100. When the Cheermote string is entered in chat, Twitch converts it to the image associated with the Bits tier that was cheered. + var prefix: String + ## The amount of bits cheered. + var bits: int + ## The tier level of the cheermote. + var tier: int + + + func get_sprite_frames(_media_loader: TwitchMediaLoader, cheermote_definition: TwitchCheermoteDefinition) -> SpriteFrames: + var cheer_results = await _media_loader.get_cheer_tier(prefix, "%s" % tier, cheermote_definition.theme, cheermote_definition.type, cheermote_definition.scale) + return cheer_results.spriteframes + + + static func from_json(d: Dictionary) -> Cheermote: + var result = Cheermote.new() + if d.has("prefix") and d["prefix"] != null: + result.prefix = d["prefix"] + if d.has("bits") and d["bits"] != null: + result.bits = d["bits"] + if d.has("tier") and d["tier"] != null: + result.tier = d["tier"] + return result + + +class Emote extends RefCounted: + ## An ID that uniquely identifies this emote. + var id: String + ## An ID that identifies the emote set that the emote belongs to. + var emote_set_id: String + ## The ID of the broadcaster who owns the emote. + var owner_id: String + ## The formats that the emote is available in. For example, if the emote is available only as a static PNG, the array contains only static. But if the emote is available as a static PNG and an animated GIF, the array contains static and animated. See: "TwitchChatMessage.EMOTE_TYPE_*" + var format: Array[EmoteFormat] = [] + + + ## Resolves the spriteframes from this emote. Check `format` for possible formats. + ## Format: Defaults to animated when not available it uses static + ## Scale: 1, 2, 3 + func get_sprite_frames(_media_loader: TwitchMediaLoader, format: String = "", scale: int = 1, dark: bool = true) -> SpriteFrames: + var definition: TwitchEmoteDefinition = TwitchEmoteDefinition.new(id) + if dark: definition.theme_dark() + else: definition.theme_light() + match scale: + 1: definition.scale_1() + 2: definition.scale_2() + 3: definition.scale_3() + _: definition.scale_1() + var emotes = await _media_loader.get_emotes_by_definition([definition]) + return emotes[definition] + + + static func from_json(d: Dictionary) -> Emote: + var result = Emote.new() + if d.has("id") and d["id"] != null: + result.id = d["id"] + if d.has("emote_set_id") and d["emote_set_id"] != null: + result.emote_set_id = d["emote_set_id"] + if d.has("owner_id") and d["owner_id"] != null: + result.owner_id = d["owner_id"] + if d.has("format") and d["format"] != null: + for format in d["format"]: + if format == "static": + result.format.append(EmoteFormat._static) + elif format == "animated": + result.format.append(EmoteFormat.animated) + return result + + + + +class Badge extends RefCounted: + ## An ID that identifies this set of chat badges. For example, Bits or Subscriber. + var set_id: String + ## An ID that identifies this version of the badge. The ID can be any value. For example, for Bits, the ID is the Bits tier level, but for World of Warcraft, it could be Alliance or Horde. + var id: String + ## Contains metadata related to the chat badges in the badges tag. Currently, this tag contains metadata only for subscriber badges, to indicate the number of months the user has been a subscriber. + var info: String + + static func from_json(d: Dictionary) -> Badge: + var result = Badge.new() + if d.has("set_id") and d["set_id"] != null: + result.set_id = d["set_id"] + if d.has("id") and d["id"] != null: + result.id = d["id"] + if d.has("info") and d["info"] != null: + result.info = d["info"] + return result + + + +class Cheer extends RefCounted: + ## The amount of Bits the user cheered. + var bits: int + + + static func from_json(d: Dictionary) -> Cheer: + var result = Cheer.new() + if d.has("bits") and d["bits"] != null: + result.bits = d["bits"] + return result + +class Reply extends RefCounted: + ## An ID that uniquely identifies the parent message that this message is replying to. + var parent_message_id: String + ## The message body of the parent message. + var parent_message_body: String + ## User ID of the sender of the parent message. + var parent_user_id: String + ## User name of the sender of the parent message. + var parent_user_name: String + ## User login of the sender of the parent message. + var parent_user_login: String + ## An ID that identifies the parent message of the reply thread. + var thread_message_id: String + ## User ID of the sender of the thread’s parent message. + var thread_user_id: String + ## User name of the sender of the thread’s parent message. + var thread_user_name: String + ## User login of the sender of the thread’s parent message. + var thread_user_login: String + + static func from_json(d: Dictionary) -> Reply: + var result = Reply.new() + if d.has("parent_message_id") and d["parent_message_id"] != null: + result.parent_message_id = d["parent_message_id"] + if d.has("parent_message_body") and d["parent_message_body"] != null: + result.parent_message_body = d["parent_message_body"] + if d.has("parent_user_id") and d["parent_user_id"] != null: + result.parent_user_id = d["parent_user_id"] + if d.has("parent_user_name") and d["parent_user_name"] != null: + result.parent_user_name = d["parent_user_name"] + if d.has("parent_user_login") and d["parent_user_login"] != null: + result.parent_user_login = d["parent_user_login"] + if d.has("thread_message_id") and d["thread_message_id"] != null: + result.thread_message_id = d["thread_message_id"] + if d.has("thread_user_id") and d["thread_user_id"] != null: + result.thread_user_id = d["thread_user_id"] + if d.has("thread_user_name") and d["thread_user_name"] != null: + result.thread_user_name = d["thread_user_name"] + if d.has("thread_user_login") and d["thread_user_login"] != null: + result.thread_user_login = d["thread_user_login"] + return result + + +## The broadcaster user ID. +var broadcaster_user_id: String +## The broadcaster display name. +var broadcaster_user_name: String +## The broadcaster login. +var broadcaster_user_login: String +## The user ID of the user that sent the message. +var chatter_user_id: String +## The user name of the user that sent the message. +var chatter_user_name: String +## The user login of the user that sent the message. +var chatter_user_login: String +## A UUID that identifies the message. +var message_id: String +## The structured chat message. +var message: Message +## The type of message. +var message_type: MessageType +## List of chat badges. +var badges: Array[Badge] = [] +## Optional. Metadata if this message is a cheer. +var cheer: Cheer +## The color of the user’s name in the chat room. This is a hexadecimal RGB color code in the form, #;. This tag may be empty if it is never set. +var color: String +## Optional. Metadata if this message is a reply. +var reply: Reply +## Optional. The ID of a channel points custom reward that was redeemed. +var channel_points_custom_reward_id: String +## Optional. The broadcaster user ID of the channel the message was sent from. Is null when the message happens in the same channel as the broadcaster. Is not null when in a shared chat session, and the action happens in the channel of a participant other than the broadcaster. +var source_broadcaster_user_id: String +## Optional. The user name of the broadcaster of the channel the message was sent from. Is null when the message happens in the same channel as the broadcaster. Is not null when in a shared chat session, and the action happens in the channel of a participant other than the broadcaster. +var source_broadcaster_user_name: String +## Optional. The login of the broadcaster of the channel the message was sent from. Is null when the message happens in the same channel as the broadcaster. Is not null when in a shared chat session, and the action happens in the channel of a participant other than the broadcaster. +var source_broadcaster_user_login: String +## Optional. The UUID that identifies the source message from the channel the message was sent from. Is null when the message happens in the same channel as the broadcaster. Is not null when in a shared chat session, and the action happens in the channel of a participant other than the broadcaster. +var source_message_id: String +## Optional. The list of chat badges for the chatter in the channel the message was sent from. Is null when the message happens in the same channel as the broadcaster. Is not null when in a shared chat session, and the action happens in the channel of a participant other than the broadcaster. +var source_badges: Array[Badge] = [] + + +## Loads a chat message from Json decoded dictionary. TwitchService is optional in case images and badges should be load from the message. +static func from_json(d: Dictionary) -> TwitchChatMessage: + var result = TwitchChatMessage.new() + if d.has("broadcaster_user_id") and d["broadcaster_user_id"] != null: + result.broadcaster_user_id = d["broadcaster_user_id"] + if d.has("broadcaster_user_name") and d["broadcaster_user_name"] != null: + result.broadcaster_user_name = d["broadcaster_user_name"] + if d.has("broadcaster_user_login") and d["broadcaster_user_login"] != null: + result.broadcaster_user_login = d["broadcaster_user_login"] + if d.has("chatter_user_id") and d["chatter_user_id"] != null: + result.chatter_user_id = d["chatter_user_id"] + if d.has("chatter_user_name") and d["chatter_user_name"] != null: + result.chatter_user_name = d["chatter_user_name"] + if d.has("chatter_user_login") and d["chatter_user_login"] != null: + result.chatter_user_login = d["chatter_user_login"] + if d.has("message_id") and d["message_id"] != null: + result.message_id = d["message_id"] + if d.has("message") and d["message"] != null: + result.message = Message.from_json(d["message"]) + if d.has("message_type") and d["message_type"] != null: + result.message_type = MessageType[d["message_type"]] + if d.has("badges") and d["badges"] != null: + for value in d["badges"]: + result.badges.append(Badge.from_json(value)) + if d.has("cheer") and d["cheer"] != null: + result.cheer = Cheer.from_json(d["cheer"]) + if d.has("color") and d["color"] != null: + result.color = d["color"] + if d.has("reply") and d["reply"] != null: + result.reply = Reply.from_json(d["reply"]) + if d.has("channel_points_custom_reward_id") and d["channel_points_custom_reward_id"] != null: + result.channel_points_custom_reward_id = d["channel_points_custom_reward_id"] + if d.has("source_broadcaster_user_id") and d["source_broadcaster_user_id"] != null: + result.source_broadcaster_user_id = d["source_broadcaster_user_id"] + if d.has("source_broadcaster_user_name") and d["source_broadcaster_user_name"] != null: + result.source_broadcaster_user_name = d["source_broadcaster_user_name"] + if d.has("source_broadcaster_user_login") and d["source_broadcaster_user_login"] != null: + result.source_broadcaster_user_login = d["source_broadcaster_user_login"] + if d.has("source_message_id") and d["source_message_id"] != null: + result.source_message_id = d["source_message_id"] + if d.has("source_badges") and d["source_badges"] != null: + for value in d["source_badges"]: + result.source_badges.append(Badge.from_json(value)) + return result + + +## Key: TwitchBadgeDefinition | Value: SpriteFrames +func get_badges(_media_loader: TwitchMediaLoader, scale: int = 1) -> Dictionary[TwitchBadgeDefinition, SpriteFrames]: + var definitions : Array[TwitchBadgeDefinition] = [] + for badge in badges: + var badge_definition : TwitchBadgeDefinition = TwitchBadgeDefinition.new(badge.set_id, badge.id, scale, broadcaster_user_id) + definitions.append(badge_definition) + var emotes : Dictionary[TwitchBadgeDefinition, SpriteFrames] = await _media_loader.get_badges(definitions) + return emotes + + +## Key: TwitchBadgeDefinition | Value: SpriteFrames +func get_source_badges(_media_loader: TwitchMediaLoader, scale: int = 1) -> Dictionary[TwitchBadgeDefinition, SpriteFrames]: + var definitions : Array[TwitchBadgeDefinition] = [] + for badge in source_badges: + var badge_definition : TwitchBadgeDefinition = TwitchBadgeDefinition.new(badge.set_id, badge.id, scale, broadcaster_user_id) + definitions.append(badge_definition) + var emotes : Dictionary[TwitchBadgeDefinition, SpriteFrames] = await _media_loader.get_badges(definitions) + return emotes + +## Returns a the color of the user or the default when its not set never null +func get_color(default_color: String = "#AAAAAA") -> String: + return default_color if color == null || color == "" else color + + +## Preload all emojis in parallel to reduce loadtime +func load_emotes_from_fragment(_media_loader: TwitchMediaLoader) -> Dictionary[TwitchEmoteDefinition, SpriteFrames]: + var emotes_to_load : Array[TwitchEmoteDefinition] = [] + + for fragment : TwitchChatMessage.Fragment in message.fragments: + match fragment.type: + TwitchChatMessage.FragmentType.emote: + var definition : TwitchEmoteDefinition = TwitchEmoteDefinition.new(fragment.emote.id) + emotes_to_load.append(definition) + return await _media_loader.get_emotes_by_definition(emotes_to_load) diff --git a/addons/twitcher/chat/twitch_chat_message.gd.uid b/addons/twitcher/chat/twitch_chat_message.gd.uid new file mode 100644 index 0000000..e3f700a --- /dev/null +++ b/addons/twitcher/chat/twitch_chat_message.gd.uid @@ -0,0 +1 @@ +uid://bxu8no18dq2e3 diff --git a/addons/twitcher/chat/twitch_command.gd b/addons/twitcher/chat/twitch_command.gd new file mode 100644 index 0000000..8ed3a8f --- /dev/null +++ b/addons/twitcher/chat/twitch_command.gd @@ -0,0 +1,173 @@ +@icon("res://addons/twitcher/assets/command-icon.svg") +extends Twitcher + +# Untested yet +## A single command like !lurk +class_name TwitchCommand + +static var ALL_COMMANDS: Array[TwitchCommand] = [] + +## Called when the command got received in the right format +signal command_received(from_username: String, info: TwitchCommandInfo, args: PackedStringArray) + +## Called when the command got received in the wrong format +signal received_invalid_command(from_username: String, info: TwitchCommandInfo, args: PackedStringArray) + +## Required permission to execute the command +enum PermissionFlag { + EVERYONE = 0, + VIP = 1, + SUB = 2, + MOD = 4, + STREAMER = 8, + MOD_STREAMER = 12, # Mods and the streamer + NON_REGULAR = 15 # Everyone but regular viewers +} + +## Where the command should be accepted +enum WhereFlag { + CHAT = 1, + WHISPER = 2, + ANYWHERE = 3 +} + +@export var command_prefixes : Array[String] = ["!"] +## Name Command +@export var command: String +## Optional names of commands +@export var aliases: Array[String] +## Description for the user +@export_multiline var description: String + +## Minimal amount of argument 0 means no argument needed +@export var args_min: int = 0 +## Max amount of arguments -1 means infinite +@export var args_max: int = -1 +## Wich role of user is allowed to use it +@export var permission_level: PermissionFlag = PermissionFlag.EVERYONE +## Where is it allowed to use chat or whisper or both +@export var where: WhereFlag = WhereFlag.CHAT +## All allowed users empty array means everyone +@export var allowed_users: Array[String] = [] +## All chatrooms where the command listens to +@export var listen_to_chatrooms: Array[String] = [] + +## The eventsub to listen for chatmessages +@export var eventsub: TwitchEventsub + +static func create( + eventsub: TwitchEventsub, + cmd_name: String, + callable: Callable, + min_args: int = 0, + max_args: int = 0, + permission_level: int = PermissionFlag.EVERYONE, + where: int = WhereFlag.CHAT, + allowed_users: Array[String] = [], + listen_to_chatrooms: Array[String] = []) -> TwitchCommand: + var command := TwitchCommand.new() + command.eventsub = eventsub + command.command = cmd_name + command.command_received.connect(callable) + command.args_min = min_args + command.args_max = max_args + command.permission_level = permission_level + command.where = where + command.allowed_users = allowed_users + command.listen_to_chatrooms = listen_to_chatrooms + return command + + +func _enter_tree() -> void: + if eventsub == null: eventsub = TwitchEventsub.instance + eventsub.event.connect(_on_event) + ALL_COMMANDS.append(self) + + +func _exit_tree() -> void: + eventsub.event.disconnect(_on_event) + ALL_COMMANDS.erase(self) + + +func _on_event(type: StringName, data: Dictionary) -> void: + if type == TwitchEventsubDefinition.CHANNEL_CHAT_MESSAGE.value: + if where & WhereFlag.CHAT != WhereFlag.CHAT: return + var message : String = data.message.text + var username : String = data.chatter_user_login + var channel_name : String = data.broadcaster_user_login + if not _should_handle(message, username, channel_name): return + var chat_message = TwitchChatMessage.from_json(data) + _handle_command(username, message, channel_name, chat_message) + + if type == TwitchEventsubDefinition.USER_WHISPER_MESSAGE.value: + if where & WhereFlag.WHISPER != WhereFlag.WHISPER: return + var message : String = data.whisper.text + var from_user : String = data.from_user_login + if not _should_handle(message, from_user, from_user): return + _handle_command(from_user, message, data.to_user_login, data) + + +func add_alias(alias: String) -> void: + aliases.append(alias) + + +func _should_handle(message: String, username: String, channel_name: String) -> bool: + if not listen_to_chatrooms.is_empty() && not listen_to_chatrooms.has(channel_name): return false + if not allowed_users.is_empty() && not allowed_users.has(username): return false + if not command_prefixes.has(message.left(1)): return false + + # remove the command symbol in front + message = message.right(-1) + var split : PackedStringArray = message.split(" ", true, 1) + var current_command := split[0] + if current_command != command && not aliases.has(current_command): return false + return true + + +func _handle_command(from_username: String, raw_message: String, to_user: String, data: Variant) -> void: + # remove the command symbol in front + raw_message = raw_message.right(-1) + var cmd_msg = raw_message.split(" ", true, 1) + var message = "" + var arg_array : PackedStringArray = [] + var command = cmd_msg[0] + var info = TwitchCommandInfo.new(self, to_user, from_username, arg_array, data) + if cmd_msg.size() > 1: + message = cmd_msg[1] + arg_array.append_array(message.split(" ", false)) + var to_less_arguments = arg_array.size() < args_min + var to_much_arguments = arg_array.size() > args_max + if to_much_arguments && args_max != -1 || to_less_arguments: + received_invalid_command.emit(from_username, info, arg_array) + return + var premission_required = permission_level != 0 + if premission_required: + var user_perm_flags = _get_perm_flag_from_tags(data) + if user_perm_flags & permission_level == 0: + received_invalid_command.emit(from_username, info, arg_array) + return + if arg_array.size() == 0: + if args_min > 0: + received_invalid_command.emit(from_username, info, arg_array) + return + + var empty_args: Array[String] = [] + if args_max > 0: + command_received.emit(from_username, info, empty_args) + else: + command_received.emit(from_username, info, empty_args) + else: + command_received.emit(from_username, info, arg_array) + + +func _get_perm_flag_from_tags(data : Variant) -> int: + var flag: int = 0 + if data is TwitchChatMessage: + var message: TwitchChatMessage = data as TwitchChatMessage + for badge in message.badges: + match badge.set_id: + "broadcaster": flag += PermissionFlag.STREAMER + "vip": flag += PermissionFlag.VIP + "moderator": flag += PermissionFlag.MOD + "subscriber": flag += PermissionFlag.SUB + return flag diff --git a/addons/twitcher/chat/twitch_command.gd.uid b/addons/twitcher/chat/twitch_command.gd.uid new file mode 100644 index 0000000..6646c49 --- /dev/null +++ b/addons/twitcher/chat/twitch_command.gd.uid @@ -0,0 +1 @@ +uid://bmluckfvgm1c2 diff --git a/addons/twitcher/chat/twitch_command_help.gd b/addons/twitcher/chat/twitch_command_help.gd new file mode 100644 index 0000000..9069da6 --- /dev/null +++ b/addons/twitcher/chat/twitch_command_help.gd @@ -0,0 +1,83 @@ +@icon("res://addons/twitcher/assets/command-icon.svg") +extends TwitchCommand + +class_name TwitchCommandHelp + +## Used to determine the Sender User if empty and to send the message back +@export var twitch_api: TwitchAPI +## Sender User that will send the answers on the command. Can be empty then the current user will be used +@export var sender_user: TwitchUser + +var _current_user: TwitchUser + + +func _ready() -> void: + if command == "": command = "help" + + command_received.connect(_on_command_receive) + if twitch_api == null: twitch_api = TwitchAPI.instance + if twitch_api == null: + push_error("Command is missing TwitchAPI to answer!") + return + + var response: TwitchGetUsers.Response = await twitch_api.get_users(TwitchGetUsers.Opt.new()) + _current_user = response.data[0] + if sender_user == null: sender_user = _current_user + + +func _on_command_receive(from_username: String, info: TwitchCommandInfo, args: PackedStringArray) -> void: + if info.original_message is TwitchChatMessage: + var help_message: String = _generate_help_message(args, false) + var chat_message: TwitchChatMessage = info.original_message as TwitchChatMessage + var message_body: TwitchSendChatMessage.Body = TwitchSendChatMessage.Body.new() + message_body.broadcaster_id = chat_message.broadcaster_user_id + message_body.sender_id = sender_user.id + message_body.message = help_message + message_body.reply_parent_message_id = chat_message.message_id + twitch_api.send_chat_message(message_body) + else: + var help_message: String = _generate_help_message(args, true) + var message: Dictionary = info.original_message + if message["to_user_id"] != _current_user.id: + push_error("Can't answer the whisper message receiver is not the user that will be used as sender!") + return + var message_body: TwitchSendWhisper.Body = TwitchSendWhisper.Body.new() + message_body.message = help_message + twitch_api.send_whisper(message_body, message["to_user_id"], message["from_user_id"]) + + +func _generate_help_message(args: Array[String], whisper_only: bool) -> String: + var message: String = "" + var show_details: bool = not args.is_empty() + + for command in TwitchCommand.ALL_COMMANDS: + if command == self: continue + var should_be_added: bool = command.where == TwitchCommand.WhereFlag.ANYWHERE \ + || command.where == TwitchCommand.WhereFlag.WHISPER && whisper_only \ + || command.where == TwitchCommand.WhereFlag.CHAT && not whisper_only + + if not args.is_empty(): + should_be_added = should_be_added && _is_command_in_args(command, args) + + if should_be_added: + if show_details: + message += "[%s%s - %s] " % [command.command_prefixes[0], command.command, command.description] + else: + message += "%s%s, " % [command.command_prefixes[0], command.command] + + if message == "": + return "No commands registered" + elif not show_details: + message = message.trim_suffix(", ") + message = "List of all Commands: %s | You can use '!help COMMAND' for details!" % message + return message + + +func _is_command_in_args(command: TwitchCommand, args: Array[String]) -> bool: + for arg in args: + if command.command == arg: + return true + if command.aliases.has(arg): + return true + return false + diff --git a/addons/twitcher/chat/twitch_command_help.gd.uid b/addons/twitcher/chat/twitch_command_help.gd.uid new file mode 100644 index 0000000..8075588 --- /dev/null +++ b/addons/twitcher/chat/twitch_command_help.gd.uid @@ -0,0 +1 @@ +uid://ch0rxi1ogjx3q diff --git a/addons/twitcher/chat/twitch_command_info.gd b/addons/twitcher/chat/twitch_command_info.gd new file mode 100644 index 0000000..60e025a --- /dev/null +++ b/addons/twitcher/chat/twitch_command_info.gd @@ -0,0 +1,25 @@ +extends RefCounted + +## Meta information about the command sender +class_name TwitchCommandInfo + + +var command : TwitchCommand +var channel_name : String +var username : String +var arguments : Array[String] +## Depending on the type it's either a TwitchChatMessage or a Dictionary of the whisper message data +var original_message : Variant + + +func _init( + _command: TwitchCommand, + _channel_name: String, + _username: String, + _arguments: Array[String], + _original_message: Variant): + command = _command + channel_name = _channel_name + username = _username + arguments = _arguments + original_message = _original_message diff --git a/addons/twitcher/chat/twitch_command_info.gd.uid b/addons/twitcher/chat/twitch_command_info.gd.uid new file mode 100644 index 0000000..7aa497f --- /dev/null +++ b/addons/twitcher/chat/twitch_command_info.gd.uid @@ -0,0 +1 @@ +uid://c5k8j4ag3n0su diff --git a/addons/twitcher/default_oauth_token.tres b/addons/twitcher/default_oauth_token.tres new file mode 100644 index 0000000..379cbdd --- /dev/null +++ b/addons/twitcher/default_oauth_token.tres @@ -0,0 +1,10 @@ +[gd_resource type="Resource" script_class="OAuthToken" load_steps=3 format=3 uid="uid://m7epy882axmp"] + +[ext_resource type="Resource" uid="uid://c4scwuk8q0r40" path="res://addons/twitcher/lib/oOuch/default_key_provider.tres" id="1_byqke"] +[ext_resource type="Script" uid="uid://b52xp7c23ucfk" path="res://addons/twitcher/lib/oOuch/oauth_token.gd" id="2_phbii"] + +[resource] +script = ExtResource("2_phbii") +_crypto_key_provider = ExtResource("1_byqke") +_identifier = "EditorToken" +_cache_path = "user://auth.conf" diff --git a/addons/twitcher/editor/api_generator/twitch_api_generator.gd b/addons/twitcher/editor/api_generator/twitch_api_generator.gd new file mode 100644 index 0000000..ebc8be8 --- /dev/null +++ b/addons/twitcher/editor/api_generator/twitch_api_generator.gd @@ -0,0 +1,606 @@ +@icon("res://addons/twitcher/assets/api-icon.svg") +@tool +extends Twitcher + +class_name TwitchAPIGenerator + +const suffixes: Array[String] = ["Response", "Body", "Opt"] + +const api_output_path = "res://addons/twitcher/generated/" +const twitch_api_header : String = """@tool +extends Twitcher + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## Interaction with the Twitch REST API. +class_name TwitchAPI + +static var _log: TwitchLogger = TwitchLogger.new("TwitchAPI") + +static var instance: TwitchAPI + +## Maximal tries to reauthrorize before giving up the request. +const MAX_AUTH_ERRORS = 3 + +## Called when the API returns unauthenticated mostly cause the accesstoken is expired +signal unauthenticated + +## Called when the API returns 403 means there are permissions / scopes missing +signal unauthorized + +## To authorize against the Twitch API +@export var token: OAuthToken: + set(val): + token = val + update_configuration_warnings() +## OAuth settings needed for client information +@export var oauth_setting: OAuthSetting: + set(val): + oauth_setting = val + update_configuration_warnings() +## URI to the Twitch API +@export var api_host: String = "https://api.twitch.tv/helix" + +## Client to make HTTP requests +var client: BufferedHTTPClient + + +func _ready() -> void: + client = BufferedHTTPClient.new() + client.name = "ApiClient" + add_child(client) + + +func _enter_tree() -> void: + if instance == null: instance = self + + +func _exit_tree() -> void: + if instance == self: instance = null + + +func _get_configuration_warnings() -> PackedStringArray: + var result: PackedStringArray = [] + if token == null: + result.append("Please set a token to use") + if oauth_setting == null: + result.append("Please set the correct oauth settings") + return result + + +func request(path: String, method: int, body: Variant = "", content_type: String = "", error_count: int = 0) -> BufferedHTTPClient.ResponseData: + var header : Dictionary = { + "Authorization": "Bearer %s" % [await token.get_access_token()], + "Client-ID": oauth_setting.client_id + } + if content_type != "": + header["Content-Type"] = content_type + + var request_body: String = "" + if body == null || (body is String && body == ""): + request_body = "" + elif body is Object && body.has_method("to_json"): + request_body = body.to_json() + else: + request_body = JSON.stringify(body) + + var req: BufferedHTTPClient.RequestData = client.request(api_host + path, method, header, request_body) + var res: BufferedHTTPClient.ResponseData = await client.wait_for_request(req) + + # Try to fix Godot TLS Bug + if res.result == 5: + return await retry(req, res, path, method, body, content_type, error_count + 1) + + match res.response_code: + 400: + var error_message: String = res.response_data.get_string_from_utf8() + _log.e("'%s' failed cause of: \\n%s" % [path, error_message]) + 401: # Token expired / or missing permissions + _log.e("'%s' is unauthorized. It is probably your scopes." % path) + unauthorized.emit() + 403: + _log.i("'%s' is unauthenticated. Refresh token." % path) + unauthenticated.emit() + await token.authorized + return await retry(req, res, path, method, body, content_type, error_count + 1) + return res + + +func retry(request: BufferedHTTPClient.RequestData, + response: BufferedHTTPClient.ResponseData, + path: String, + method: int, + body: Variant = "", + content_type: String = "", + error_count: int = 0) -> BufferedHTTPClient.ResponseData: + if error_count + 1 < MAX_AUTH_ERRORS: + return await request(path, method, body, content_type, error_count + 1) + else: + # Give up the request after trying multiple times and + # return an empty response with correct error code + var empty_response: BufferedHTTPClient.ResponseData = client.empty_response(request) + empty_response.response_code = response.response_code + return empty_response + + +## Converts unix timestamp to RFC 3339 (example: 2021-10-27T00:00:00Z) when passed a string uses as is +static func get_rfc_3339_date_format(time: Variant) -> String: + if typeof(time) == TYPE_INT: + var date_time = Time.get_datetime_dict_from_unix_time(time) + return "%s-%02d-%02dT%02d:%02d:%02dZ" % [date_time['year'], date_time['month'], date_time['day'], date_time['hour'], date_time['minute'], date_time['second']] + return str(time) + +""" + +@export var parser: TwitchAPIParser + +var grouped_files: Dictionary[String, Variant] = {} + + +func prepare_component(component: TwitchGenComponent) -> void: + if component._is_root: + var base_name = get_base_name(component._classname) + + # No suffix class lives by its own + if base_name == component._classname: + if grouped_files.has(base_name): + push_error("That file shouldn't exist: %s" % base_name) + component._classname = "Twitch" + component._classname + grouped_files[base_name] = component + else: + var file: GroupedComponent = grouped_files.get(base_name, GroupedComponent.new()) + file.base_name = "Twitch" + base_name + file.components.append(component) + grouped_files[base_name] = file + component._classname = component._classname.trim_prefix(base_name) + component.set_meta("fqdn", file.base_name + "." + component._classname) + var sub_components_to_update: Array[TwitchGenComponent] = component._sub_components.values().duplicate() + for sub_component in sub_components_to_update: + sub_component._classname = component._classname + sub_component._classname + sub_components_to_update.append_array(sub_component._sub_components.values()) + pass + + + +func generate_api() -> void: + for component: Variant in parser.components: + prepare_component(component) + + # Generate TwitchAPI + var twitch_api_code = twitch_api_header + for method: TwitchGenMethod in parser.methods: + twitch_api_code += method_code(method) + write_output_file(api_output_path + "twitch_api.gd", twitch_api_code) + + # Generate Components + for component: Variant in grouped_files.values(): + var code = "" + if component is GroupedComponent: + code = group_code(component) + else: + code = component_code(component, 0) + write_output_file(api_output_path + component.get_filename(), code) + + print("API regenerated you can find it under: %s" % api_output_path) + + +class GroupedComponent extends RefCounted: + var base_name: String + var prefix: String + var components: Array[TwitchGenComponent] = [] + + + func _update_base_name(val: String) -> void: + base_name = val + + + func get_filename() -> String: + return base_name.to_snake_case() + ".gd" + + +func group_code(group: GroupedComponent) -> String: + var code = """@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name {name} + """.format({"name": group.base_name}) + for component in group.components: + component._is_root = false + code += "\n\n" + code += component_code(component, 1) + return code + +#region Field Code Generation + +func field_declaration(field: TwitchGenField) -> String: + var type = get_type(field._type, field._is_array) + return """ +## {description} +@export var {name}: {type}: + set(val): + {name} = val + track_data(&"{name}", val)\n""".format({ + "name": field._name, + "description": ident(field._description, 0, "## "), + "type": type + }) + + +#endregion + +#region Parameter Code Generation + +#func get_code() -> String: + #if _name == "broadcaster_id": + #var default_value = "default_broadcaster_login" if _type == "String" else "[default_broadcaster_login]" + #return "%s: %s = %s" % [_name, get_type(), default_value] + #return "%s: %s" % [_name, get_type()] + +#endregion + +#region Method Code Generation + +func parameter_doc(method: TwitchGenMethod) -> String: + if method._required_parameters.is_empty(): + return "## [no required query parameters to describe]" + var doc : String = "" + for parameter: TwitchGenParameter in method._required_parameters: + doc += "## {name} - {documentation} \n".format({ + 'name': parameter._name, + 'documentation': ident(parameter._description, 0, "## ") + }) + return doc.rstrip("\n") + + +func parameter_array(method: TwitchGenMethod, with_type: bool = false, fully_qualified: bool = false) -> Array[String]: + var parameters : Array[String] = [] + if method._contains_body: parameters.append(get_parameter("body", method._body_type, false, with_type, fully_qualified)) + if method._contains_optional: parameters.append(get_parameter("opt", method.get_optional_type(), false, with_type, fully_qualified)) + + method._parameters.sort_custom(TwitchGenParameter.sort) + for parameter: TwitchGenParameter in method._required_parameters: + parameters.append(get_parameter(parameter._name, parameter._type, parameter._is_array, with_type, fully_qualified)) + return parameters + + +func method_parameter(method: TwitchGenMethod, with_type: bool = false, fully_qualified: bool = false) -> String: + return ", ".join(parameter_array(method, with_type, fully_qualified)) + + +func path_code(method: TwitchGenMethod) -> String: + var body_code : String = "var path = \"%s?\"\n" % method._path + + if method._contains_optional: + body_code += "var optionals: Dictionary[StringName, Variant] = {}\n" + body_code += "if opt != null: optionals = opt.to_dict()\n" + + for parameter: TwitchGenParameter in method._parameters: + if parameter._required: + body_code += parameter_path_code(parameter) + "\n" + else: + body_code += "if optionals.has(\"%s\"):\n" % parameter._name + body_code += "\t%s\n" % ident(parameter_path_code(parameter, "optionals."), 1) + return body_code + + +func parameter_path_code(parameter: TwitchGenParameter, prefix: String = "") -> String: + var body: String + if parameter._is_time: + body = "path += \"{key}=\" + get_rfc_3339_date_format({value}) + \"&\"" + + elif parameter._is_array: + body = """ +for param in {value}: + path += "{key}=" + str(param) + "&" """.trim_prefix("\n\t") + else: + body = "path += \"{key}=\" + str({value}) + \"&\"" + + return body.format({ + 'value': prefix + parameter._name, + 'key': parameter._name + }) + + ## Exceptional method cause twitch api is not uniform +func paging_code_stream_schedule() -> String: + return """ +if parsed_result.data.pagination != null: + opt.after = parsed_result.data.pagination.cursor + parsed_result.data._next_page = get_channel_stream_schedule.bind(opt, broadcaster_id)\n""" + + +func paging_code(method: TwitchGenMethod) -> String: + if method._name == "get_channel_stream_schedule": + return paging_code_stream_schedule() + + var code: String = "" + code += "if parsed_result.pagination != null:\n" + var after_parameter: TwitchGenParameter = method.get_parameter_by_name("after") + var result_component: TwitchGenComponent = get_component(method._result_type) + var pagination_parameter: TwitchGenField = result_component.get_field_by_name("pagination") + if pagination_parameter == null: + print("Check %s paging without paging?" % method._name) + pass + elif pagination_parameter._type == "String": + code += "\tvar cursor: String = parsed_result.pagination\n" + else: + code += "\tvar cursor: String = parsed_result.pagination.cursor\n" + if after_parameter._required: + code += "\t{parameter} = cursor\n" + else: + code += "\topt.{parameter} = cursor\n" + code += "\tparsed_result._next_page = {name}.bind({parameters})\n" + + return code.format({ + "parameter": after_parameter._name, + "name": method._name, + "parameters": method_parameter(method) + }) + + +func response_code(method: TwitchGenMethod) -> String: + var code: String = "" + var result_type = get_type(method._result_type, false, true) + if result_type != "BufferedHTTPClient.ResponseData": + code = """ +var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) +var parsed_result: {result_type} = {result_type}.from_json(result) +parsed_result.response = response +""".format({ 'result_type': result_type }) + if method._has_paging: code += paging_code(method) + code += "return parsed_result" + else: + code = "return response" + return code + + +func method_code(method: TwitchGenMethod) -> String: + return """ + +## {summary} +## +{parameter_doc} +## +## {doc_url} +func {name}({parameters}) -> {result_type}: + {path_code} + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_{method}, {body_variable}, "{content_type}") + {response_code} +""".format({ + "summary": method._summary, + "parameter_doc": parameter_doc(method), + "doc_url": method._doc_url, + "name": method._name, + "parameters": method_parameter(method, true, true), + "result_type": get_type(method._result_type, false, true), + "path_code": ident(path_code(method), 1), + "content_type": get_type(method._content_type, false, true), + "method": method._http_verb.to_upper(), + "body_variable": "body" if method._contains_body else "\"\"", + "response_code": ident(response_code(method), 1), + }) + + +#endregion + +#region Component Code Generation + + +func component_code(component: TwitchGenComponent, level: int = 0) -> String: + var code: String = "" + if component._is_root: + code += """@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## {description} +## {ref} +class_name {classname} + """ + else: + code = """ +## {description} +## {ref} +class {classname} extends TwitchData: +""" + var class_code : String = "" + for field: TwitchGenField in component._fields: + class_code += field_declaration(field) + + if component._is_response: + class_code += "var response: BufferedHTTPClient.ResponseData" + class_code += "\n\n" + class_code += create_code(component) + "\n\n" + class_code += from_json_code(component) + + if component._has_paging: + class_code += "\n\n" + iter_code(component) + + var sub_component_code: String + for sub_component in component._sub_components.values(): + sub_component_code += "\n\n" + component_code(sub_component, 1) + + return code.format({ + "description": ident(component._description, 0, "## "), + "classname": component._classname, + "ref": component._ref + }) + ident(class_code, level) + sub_component_code + + +func create_code(component: TwitchGenComponent) -> String: + var parameters: Array[String] = [] + for field in component._fields: + if field._is_required: + parameters.append("_" + get_parameter(field._name, field._type, field._is_array)) + + var variable_name = component._classname.to_snake_case() + var code : String = """ +## Constructor with all required fields. +static func create({parameters}) -> {classname}: + var {variablename}: {classname} = {classname}.new()\n""".format({ + "parameters": ", ".join(parameters), + "classname": component._classname, + "variablename": variable_name + }) + + for field in component._fields: + if field._is_required: + code += "\t{classname}.{name} = _{name}\n".format({ + "name": field._name, + "classname": variable_name + }) + + code += "\treturn %s" % variable_name + return code + + +func from_json_code(component: TwitchGenComponent) -> String: + var code : String = """ +static func from_json(d: Dictionary) -> {classname}: + var result: {classname} = {classname}.new() +""".format({"classname": component._classname}) + for field: TwitchGenField in component._fields: + code += "\tif d.get(\"{name}\", null) != null:\n" + if field._is_typed_array: + code += """ + for value in d["{name}"]: + result.{name}.append({type}.from_json(value))\n""".lstrip("\n") + elif field._is_array: + code += """ + for value in d["{name}"]: + result.{name}.append(value)\n""".lstrip("\n") + elif field._is_sub_class: + code += "\t\tresult.{name} = {type}.from_json(d[\"{name}\"])\n" + else: + code += "\t\tresult.{name} = d[\"{name}\"]\n" + code = code.format({ + "name": field._name, + "type": get_type(field._type, false) + }) + code += "\treturn result\n" + + return code + + +func iter_code(component: TwitchGenComponent) -> String: + var data_variable_name: String = "data" + var path_to_data: String = "" + if component._ref == "#/components/schemas/GetChannelStreamScheduleResponse/Data": + data_variable_name = "segments" + path_to_data = "data." + + var code: String + if component._ref == "#/components/schemas/GetExtensionLiveChannelsResponse": + code += """ +func _has_pagination() -> bool: + if pagination == null || pagination == "": return false + return true +""" + else: + code += """ +func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true +""" + + code += """ +var _next_page: Callable +var _cur_iter: int = 0 + + +func next_page() -> {response_type}: + var response: {response_type} = await _next_page.call() + _cur_iter = 0 + _next_page = response.{path_to_data}_next_page +{copy_code} + return response + + +func _iter_init(iter: Array) -> bool: + if {data_variable_name}.is_empty(): return false + iter[0] = {data_variable_name}[0] + return {data_variable_name}.size() > 0 + + +func _iter_next(iter: Array) -> bool: + if {data_variable_name}.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = {data_variable_name}[_cur_iter] + if {data_variable_name}.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + +func _iter_get(iter: Variant) -> Variant: + if {data_variable_name}.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter""" + var copy_code: String + for field in component._fields: + copy_code += "\t{_name} = response.{path_to_data}{_name}\n".format(field) + + return code.format({ + "data_variable_name": data_variable_name, + "copy_code": copy_code, + "path_to_data": path_to_data, + "response_type": component.get_root_classname() + }) +#endregion + +#region Utils + + +func get_type(type: String, is_array: bool = false, full_qualified: bool = false) -> String: + var result_type : String = "" + if type.begins_with("#"): + var component: TwitchGenComponent = parser.get_component_by_ref(type) + result_type = component._classname + if full_qualified and component.has_meta("fqdn"): + result_type = component.get_meta("fqdn") + else: + result_type = type + return result_type if not is_array else "Array[%s]" % result_type + + +func get_component(type: String) -> TwitchGenComponent: + if type.begins_with("#"): + return parser.get_component_by_ref(type) + else: + return null + +func ident(code: String, level: int, padding: String = "") -> String: + return code.replace("\n", "\n" + "\t".repeat(level) + padding) + + +# Writes the processed content to the output file. +func write_output_file(file_output: String, content: String) -> void: + var file = FileAccess.open(file_output, FileAccess.WRITE); + if file == null: + var error_message = error_string(FileAccess.get_open_error()); + push_error("Failed to open output file: %s\n%s" % [file_output, error_message]) + return + file.store_string(content) + file.flush() + file.close() + + +func get_base_name(file: String) -> String: + var new_file: String = file + for suffix: String in suffixes: + new_file = new_file.trim_suffix(suffix) + return new_file + + +func get_parameter(title: String, type: String, is_array = false, with_type: bool = true, fully_qualified: bool = false) -> String: + if with_type: + return "{name}: {type}".format({ + "name": title, + "type": get_type(type, is_array, fully_qualified) + }) + else: + return title + +#endregion \ No newline at end of file diff --git a/addons/twitcher/editor/api_generator/twitch_api_generator.gd.uid b/addons/twitcher/editor/api_generator/twitch_api_generator.gd.uid new file mode 100644 index 0000000..3f6eeda --- /dev/null +++ b/addons/twitcher/editor/api_generator/twitch_api_generator.gd.uid @@ -0,0 +1 @@ +uid://cetl2un34bjb1 diff --git a/addons/twitcher/editor/api_generator/twitch_api_parser.gd b/addons/twitcher/editor/api_generator/twitch_api_parser.gd new file mode 100644 index 0000000..56917cf --- /dev/null +++ b/addons/twitcher/editor/api_generator/twitch_api_parser.gd @@ -0,0 +1,247 @@ +@icon("res://addons/twitcher/assets/api-icon.svg") +@tool +extends Twitcher + +class_name TwitchAPIParser + +const SWAGGER_API = "https://raw.githubusercontent.com/DmitryScaletta/twitch-api-swagger/refs/heads/main/openapi.json" + +var definition: Dictionary = {} +var component_map: Dictionary[String, TwitchGenComponent] = {} +var components: Array[TwitchGenComponent] = [] +var methods: Array[TwitchGenMethod] = [] + +var client: BufferedHTTPClient = BufferedHTTPClient.new() + +signal component_added(component: TwitchGenComponent) +signal method_added(method: TwitchGenMethod) + + +class ComponentRepo extends RefCounted: + var _component: TwitchGenComponent + var _component_map: Dictionary[String, TwitchGenComponent] + + + func get_comp(component_name: String) -> TwitchGenComponent: + var component = _component.get_component(component_name) + if component != null: return component + return _component_map.get(component_name) + + + func _init(component: TwitchGenComponent, component_map: Dictionary[String, TwitchGenComponent]) -> void: + _component = component + _component_map = component_map + + +func _ready() -> void: + client.name = "APIGeneratorClient" + + +func parse_api() -> void: + print("start generating API") + if definition == {}: + print("load Twitch definition") + definition = await _load_swagger_definition() + + _parsing_components() + _parsing_paths() + + +func _load_swagger_definition() -> Dictionary: + add_child(client) + client.max_error_count = 3 + var request = client.request(SWAGGER_API, HTTPClient.METHOD_GET, {}, "") + var response_data = await client.wait_for_request(request) + + if response_data.error: + printerr("Cant generate API") + return {} + var response_str = response_data.response_data.get_string_from_utf8() + var response = JSON.parse_string(response_str) + remove_child(client) + return response + + +func _parsing_components() -> void: + var schemas = definition["components"]["schemas"] + for schema_name in schemas: + var schema: Dictionary = schemas[schema_name] + if schema["type"] != "object": + printerr("Not an object") + continue + + var ref = "#/components/schemas/" + schema_name + var component = TwitchGenComponent.new(schema_name, ref) + component._is_root = true + component._is_response = true + _parse_properties(component, schema) + _add_component(ref, component) + + +func _parse_properties(component: TwitchGenComponent, schema: Dictionary) -> void: + var properties = schema["properties"] + for property_name: String in properties: + var property: Dictionary = properties[property_name] + var field: TwitchGenField = TwitchGenField.new() + field._name = property_name + field._description = property.get("description", "") + field._type = _get_param_type(property) + + var classname: String = property_name.capitalize().replace(" ", "") + + + if property.has("properties"): + var sub_component = _add_sub_component(classname, field._description, component, property) + field._type = sub_component._ref + + ## Arrays that has custom types + elif property.get("type", "") == "array": + field._is_array = true + field._is_sub_class = false + var items = property.get("items", {}) + if items.has("$ref"): + field._type = items.get("$ref") + elif items.has("properties"): + var sub_component = _add_sub_component(classname, field._description, component, items) + field._type = sub_component._ref + + component.add_field(field) + + var requires: Array = schema.get("required", []) + for required_field: String in requires: + var field: TwitchGenField = component.get_field_by_name(required_field) + field._is_required = true + + +func _add_sub_component(classname: String, description: String, parent_component: TwitchGenComponent, properties: Dictionary) -> TwitchGenComponent: + var ref: String = parent_component._ref + "/" + classname + var sub_component = TwitchGenComponent.new(classname, ref) + sub_component._description = description + _parse_properties(sub_component, properties) + parent_component.add_component(sub_component) + _add_component(ref, sub_component) + return sub_component + + +func _parsing_paths() -> void: + var paths = definition.get("paths", {}) + for path in paths: + var method_specs = paths[path] + for http_verb: String in method_specs: + var method_spec = method_specs[http_verb] as Dictionary + var method = _parse_method(http_verb, method_spec) + method._path = path + if method._contains_optional: + var component : TwitchGenComponent = method.get_optional_component() + _add_component(component._ref, component) + methods.append(method) + method_added.emit(method) + + +func _parse_method(http_verb: String, method_spec: Dictionary) -> TwitchGenMethod: + var method: TwitchGenMethod = TwitchGenMethod.new() + method._http_verb = http_verb + method._name = method_spec.get("operationId", "method_" + http_verb).replace("-", "_") + method._summary = method_spec.get("summary", "No summary provided.") + method._description = method_spec.get("description", "No description provided.") + method._doc_url = method_spec.get("externalDocs", {}).get("url", "No link provided") + _parse_parameters(method, method_spec) + + # Body Type + if method_spec.has("requestBody"): + method._body_type = "Dictionary" + var ref = method_spec.get("requestBody").get("content", {}).get("application/json", {}).get("schema", {}).get("$ref", "") + if ref != "": + method._body_type = ref + + # Result Type + method._result_type = "BufferedHTTPClient.ResponseData" + var responses = method_spec.get("responses", {}) + if responses.has("200") || responses.has("202"): + var content: Dictionary = {} + if responses.has("200"): + content = responses["200"].get("content", {}) + elif content == {}: + content = responses["202"].get("content", {}) + + # Assuming the successful response is a JSON object + method._result_type = "Dictionary" + + # Special case for /schedule/icalendar + if content.has("text/calendar"): + method._result_type = "BufferedHTTPClient.ResponseData" + + + # Try to resolve the component references + var ref = content.get("application/json", {}).get("schema", {}).get("$ref", "") + if ref != "": + method._result_type = ref + + # Content Type + if method_spec.has("requestBody"): + var requestBody = method_spec.get("requestBody") + var content = requestBody.get("content") + method._content_type = content.keys()[0] + elif http_verb == "POST": + method._content_type = "application/x-www-form-urlencoded" + return method + + +func _parse_parameters(method: TwitchGenMethod, method_spec: Dictionary) -> void: + var parameter_specs = method_spec.get("parameters", []) + for parameter_spec in parameter_specs: + var parameter: TwitchGenParameter = TwitchGenParameter.new() + var schema = parameter_spec["schema"] + parameter._name = parameter_spec.get("name", "") + parameter._description = parameter_spec.get("description", "") + parameter._type = _get_param_type(schema) + parameter._required = parameter_spec.get("required", false) + parameter._is_time = schema.get("format", "") == "date-time" + parameter._is_array = schema.get("type", "") == "array" + method.add_parameter(parameter) + + +func _add_component(ref: String, component: TwitchGenComponent) -> void: + components.append(component) + component_map[ref] = component + + +func get_component_by_ref(ref: String) -> TwitchGenComponent: + return component_map[ref] + + +func _get_param_type(schema: Dictionary) -> String: + if schema.has("$ref"): + return schema["$ref"] + + if not schema.has("type"): + return "Variant" # Maybe ugly + + var type = schema["type"] + var format = schema.get("format", "") + match type: + "object": + if schema.has("additinalProperties"): + return _get_param_type(schema["additinalProperties"]) + return "Dictionary" + "string": + # Why did I do this in the first place? + # Lets disable and see if problems appear + #if format == "date-time": + # return "Variant" + return "String" + "integer": + return "int" + "number": + return "float" if format == "float" else "int" + "boolean": + return "bool" + "array": + var ref: String = schema["items"].get("$ref", "") + if schema["items"].get("type", "") == "string": + return "String" + elif ref != "": + return ref + else: + return "Variant" + _: return "Variant" diff --git a/addons/twitcher/editor/api_generator/twitch_api_parser.gd.uid b/addons/twitcher/editor/api_generator/twitch_api_parser.gd.uid new file mode 100644 index 0000000..6eecd60 --- /dev/null +++ b/addons/twitcher/editor/api_generator/twitch_api_parser.gd.uid @@ -0,0 +1 @@ +uid://o7q04krfh33l diff --git a/addons/twitcher/editor/api_generator/twitch_gen.gd b/addons/twitcher/editor/api_generator/twitch_gen.gd new file mode 100644 index 0000000..874bc07 --- /dev/null +++ b/addons/twitcher/editor/api_generator/twitch_gen.gd @@ -0,0 +1,3 @@ +extends RefCounted + +class_name TwitchGen diff --git a/addons/twitcher/editor/api_generator/twitch_gen.gd.uid b/addons/twitcher/editor/api_generator/twitch_gen.gd.uid new file mode 100644 index 0000000..fd8412f --- /dev/null +++ b/addons/twitcher/editor/api_generator/twitch_gen.gd.uid @@ -0,0 +1 @@ +uid://cvtstbwwwf7gf diff --git a/addons/twitcher/editor/api_generator/twitch_gen_component.gd b/addons/twitcher/editor/api_generator/twitch_gen_component.gd new file mode 100644 index 0000000..e36b25a --- /dev/null +++ b/addons/twitcher/editor/api_generator/twitch_gen_component.gd @@ -0,0 +1,60 @@ +@tool +extends TwitchGen + +class_name TwitchGenComponent + +var _classname: String +var _ref: String +var _description: String +var _fields: Array[TwitchGenField] = [] +var _field_map: Dictionary[String, TwitchGenField] = {} +var _parent_component: TwitchGenComponent +var _sub_components: Dictionary[String, TwitchGenComponent] = {} +var _is_root: bool +var _is_response: bool +var _has_paging: bool +var _filename: String: + get(): return _classname.to_snake_case() + ".gd" + + +func _init(classname: String, ref: String) -> void: + _classname = _sanatize_classname(classname) + _ref = ref + + +func add_field(field: TwitchGenField) -> void: + _fields.append(field) + _field_map[field._name] = field + if field._name == "pagination": + _has_paging = true + + +func get_field_by_name(field_name: String) -> TwitchGenField: + return _field_map.get(field_name, null) + + +func get_root_classname() -> String: + var parent: TwitchGenComponent = self + while parent._parent_component != null: + parent = parent._parent_component + return parent._classname + + +func get_filename() -> String: + return get_root_classname().to_snake_case() + ".gd" + + +func _sanatize_classname(val: String) -> String: + match val: + "Image": return "TwitchImage" + "Panel": return "TwitchPanel" + _: return val + + +func get_component(component_name: String) -> TwitchGenComponent: + return _sub_components.get(component_name) + + +func add_component(sub_component: TwitchGenComponent) -> void: + _sub_components[sub_component._classname] = sub_component + sub_component._parent_component = self diff --git a/addons/twitcher/editor/api_generator/twitch_gen_component.gd.uid b/addons/twitcher/editor/api_generator/twitch_gen_component.gd.uid new file mode 100644 index 0000000..3fac53c --- /dev/null +++ b/addons/twitcher/editor/api_generator/twitch_gen_component.gd.uid @@ -0,0 +1 @@ +uid://cttaojg743q5y diff --git a/addons/twitcher/editor/api_generator/twitch_gen_field.gd b/addons/twitcher/editor/api_generator/twitch_gen_field.gd new file mode 100644 index 0000000..6dd313e --- /dev/null +++ b/addons/twitcher/editor/api_generator/twitch_gen_field.gd @@ -0,0 +1,31 @@ +@tool +extends TwitchGen + +class_name TwitchGenField + +var _name: String: + set = _update_name +var _description: String +var _type: String +var _is_required: bool +var _is_sub_class: bool: + get(): return _type.begins_with("#") +var _is_array: bool +var _is_typed_array: bool: + get(): return _is_array && _type.begins_with("#") + + +## Couple of names from the Twitch API are messed up like keywords for godot or numbers +func _update_name(val: String) -> void: + match val: + "animated": _name = "animated_format" + "static": _name = "static_format" + "1": _name = "_1" + "2": _name = "_2" + "3": _name = "_3" + "4": _name = "_4" + "1.5": _name = "_1_5" + "100x100": _name = "_100x100" + "24x24": _name = "_24x24" + "300x200": _name = "_300x200" + _: _name = val diff --git a/addons/twitcher/editor/api_generator/twitch_gen_field.gd.uid b/addons/twitcher/editor/api_generator/twitch_gen_field.gd.uid new file mode 100644 index 0000000..7424fef --- /dev/null +++ b/addons/twitcher/editor/api_generator/twitch_gen_field.gd.uid @@ -0,0 +1 @@ +uid://dgx1w74garjdh diff --git a/addons/twitcher/editor/api_generator/twitch_gen_method.gd b/addons/twitcher/editor/api_generator/twitch_gen_method.gd new file mode 100644 index 0000000..a64f5d5 --- /dev/null +++ b/addons/twitcher/editor/api_generator/twitch_gen_method.gd @@ -0,0 +1,59 @@ +@tool +extends TwitchGen + +class_name TwitchGenMethod +var _http_verb: String +var _name: String +var _summary: String +var _description: String +var _path: String +var _doc_url: String +var _parameters: Array[TwitchGenParameter] = [] +var _parameter_map: Dictionary[String, TwitchGenParameter] = {} +var _required_parameters: Array[TwitchGenParameter]: + get(): return _parameters.filter(func(p): return p._required) +var _optional_parameters: Array[TwitchGenParameter]: + get(): return _parameters.filter(func(p): return not p._required) +var _body_type: String +var _result_type: String +var _content_type: String +var _has_paging: bool +var _contains_optional: bool +var _contains_body: bool: + get(): return _body_type != null and _body_type != "" + + +func add_parameter(parameter: TwitchGenParameter) -> void: + _parameters.append(parameter) + _contains_optional = _contains_optional || not parameter._required + _parameter_map[parameter._name] = parameter + if parameter._name == "after": + _has_paging = true + + +func get_parameter_by_name(name: String) -> TwitchGenParameter: + return _parameter_map.get(name) + + +func get_optional_classname() -> String: + return _name.capitalize().replace(" ", "") + "Opt" + + +func get_optional_type() -> String: + return "#/components/schemas/" + get_optional_classname() + + +func get_optional_component() -> TwitchGenComponent: + var component = TwitchGenComponent.new(get_optional_classname(), get_optional_type()) + component._description = "All optional parameters for TwitchAPI.%s" % _name + component._is_root = true + for parameter: TwitchGenParameter in _optional_parameters: + var field = TwitchGenField.new() + field._name = parameter._name + field._type = parameter._type + field._description = parameter._description + field._is_required = false + field._is_array = parameter._is_array + component.add_field(field) + + return component diff --git a/addons/twitcher/editor/api_generator/twitch_gen_method.gd.uid b/addons/twitcher/editor/api_generator/twitch_gen_method.gd.uid new file mode 100644 index 0000000..ab432ec --- /dev/null +++ b/addons/twitcher/editor/api_generator/twitch_gen_method.gd.uid @@ -0,0 +1 @@ +uid://dkwhf6s838d20 diff --git a/addons/twitcher/editor/api_generator/twitch_gen_parameter.gd b/addons/twitcher/editor/api_generator/twitch_gen_parameter.gd new file mode 100644 index 0000000..656596f --- /dev/null +++ b/addons/twitcher/editor/api_generator/twitch_gen_parameter.gd @@ -0,0 +1,22 @@ +@tool +extends TwitchGen + +class_name TwitchGenParameter +var _name: String +var _description: String +var _required: bool +var _type: String +var _is_time: bool +var _is_array: bool + +static func sort(p1: TwitchGenParameter, p2: TwitchGenParameter) -> bool: + if p1._name == "broadcaster_id": + return false + if p2._name == "broadcaster_id": + return true + if p1._required && not p2._required: + return true + if not p1._required && p2._required: + return false + return p1._name < p2._name + diff --git a/addons/twitcher/editor/api_generator/twitch_gen_parameter.gd.uid b/addons/twitcher/editor/api_generator/twitch_gen_parameter.gd.uid new file mode 100644 index 0000000..4d35c02 --- /dev/null +++ b/addons/twitcher/editor/api_generator/twitch_gen_parameter.gd.uid @@ -0,0 +1 @@ +uid://1ptmbsygcfyt diff --git a/addons/twitcher/editor/inspector/twitch_eventsub_config_inspector.gd b/addons/twitcher/editor/inspector/twitch_eventsub_config_inspector.gd new file mode 100644 index 0000000..57b02df --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_eventsub_config_inspector.gd @@ -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) diff --git a/addons/twitcher/editor/inspector/twitch_eventsub_config_inspector.gd.uid b/addons/twitcher/editor/inspector/twitch_eventsub_config_inspector.gd.uid new file mode 100644 index 0000000..965aa5f --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_eventsub_config_inspector.gd.uid @@ -0,0 +1 @@ +uid://c1afm3xjonwxr diff --git a/addons/twitcher/editor/inspector/twitch_eventsub_config_property.gd b/addons/twitcher/editor/inspector/twitch_eventsub_config_property.gd new file mode 100644 index 0000000..21a2c05 --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_eventsub_config_property.gd @@ -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) diff --git a/addons/twitcher/editor/inspector/twitch_eventsub_config_property.gd.uid b/addons/twitcher/editor/inspector/twitch_eventsub_config_property.gd.uid new file mode 100644 index 0000000..909afb6 --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_eventsub_config_property.gd.uid @@ -0,0 +1 @@ +uid://drv4gmn8akxf2 diff --git a/addons/twitcher/editor/inspector/twitch_eventsub_inspector.gd b/addons/twitcher/editor/inspector/twitch_eventsub_inspector.gd new file mode 100644 index 0000000..37552ed --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_eventsub_inspector.gd @@ -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) diff --git a/addons/twitcher/editor/inspector/twitch_eventsub_inspector.gd.uid b/addons/twitcher/editor/inspector/twitch_eventsub_inspector.gd.uid new file mode 100644 index 0000000..d486e88 --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_eventsub_inspector.gd.uid @@ -0,0 +1 @@ +uid://cuo2g5oib1cf3 diff --git a/addons/twitcher/editor/inspector/twitch_media_loader_inspector.gd b/addons/twitcher/editor/inspector/twitch_media_loader_inspector.gd new file mode 100644 index 0000000..307dd33 --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_media_loader_inspector.gd @@ -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() diff --git a/addons/twitcher/editor/inspector/twitch_media_loader_inspector.gd.uid b/addons/twitcher/editor/inspector/twitch_media_loader_inspector.gd.uid new file mode 100644 index 0000000..559bf4a --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_media_loader_inspector.gd.uid @@ -0,0 +1 @@ +uid://be76dqjl123t8 diff --git a/addons/twitcher/editor/inspector/twitch_property.gd b/addons/twitcher/editor/inspector/twitch_property.gd new file mode 100644 index 0000000..f5c0981 --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_property.gd @@ -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 diff --git a/addons/twitcher/editor/inspector/twitch_property.gd.uid b/addons/twitcher/editor/inspector/twitch_property.gd.uid new file mode 100644 index 0000000..e93dad6 --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_property.gd.uid @@ -0,0 +1 @@ +uid://ci8bdo18wnodj diff --git a/addons/twitcher/editor/inspector/twitch_scope_inspector.gd b/addons/twitcher/editor/inspector/twitch_scope_inspector.gd new file mode 100644 index 0000000..767f3a2 --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_scope_inspector.gd @@ -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 diff --git a/addons/twitcher/editor/inspector/twitch_scope_inspector.gd.uid b/addons/twitcher/editor/inspector/twitch_scope_inspector.gd.uid new file mode 100644 index 0000000..7c1b855 --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_scope_inspector.gd.uid @@ -0,0 +1 @@ +uid://c7832kf7htajv diff --git a/addons/twitcher/editor/inspector/twitch_scope_property.gd b/addons/twitcher/editor/inspector/twitch_scope_property.gd new file mode 100644 index 0000000..af61398 --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_scope_property.gd @@ -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) diff --git a/addons/twitcher/editor/inspector/twitch_scope_property.gd.uid b/addons/twitcher/editor/inspector/twitch_scope_property.gd.uid new file mode 100644 index 0000000..bf04d15 --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_scope_property.gd.uid @@ -0,0 +1 @@ +uid://xldq5o0osdgq diff --git a/addons/twitcher/editor/inspector/twitch_token_info.gd b/addons/twitcher/editor/inspector/twitch_token_info.gd new file mode 100644 index 0000000..74c94fa --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_token_info.gd @@ -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() diff --git a/addons/twitcher/editor/inspector/twitch_token_info.gd.uid b/addons/twitcher/editor/inspector/twitch_token_info.gd.uid new file mode 100644 index 0000000..dbd6306 --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_token_info.gd.uid @@ -0,0 +1 @@ +uid://c8no6da8ae0xt diff --git a/addons/twitcher/editor/inspector/twitch_token_info.tscn b/addons/twitcher/editor/inspector/twitch_token_info.tscn new file mode 100644 index 0000000..6788985 --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_token_info.tscn @@ -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") diff --git a/addons/twitcher/editor/inspector/twitch_token_revoke_popup.gd b/addons/twitcher/editor/inspector/twitch_token_revoke_popup.gd new file mode 100644 index 0000000..3267519 --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_token_revoke_popup.gd @@ -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() diff --git a/addons/twitcher/editor/inspector/twitch_token_revoke_popup.gd.uid b/addons/twitcher/editor/inspector/twitch_token_revoke_popup.gd.uid new file mode 100644 index 0000000..3090b83 --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_token_revoke_popup.gd.uid @@ -0,0 +1 @@ +uid://bp1fga8addrlc diff --git a/addons/twitcher/editor/inspector/twitch_token_revoke_popup.tscn b/addons/twitcher/editor/inspector/twitch_token_revoke_popup.tscn new file mode 100644 index 0000000..3fdd662 --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_token_revoke_popup.tscn @@ -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" diff --git a/addons/twitcher/editor/inspector/twitch_user_inspector.gd b/addons/twitcher/editor/inspector/twitch_user_inspector.gd new file mode 100644 index 0000000..52fcb97 --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_user_inspector.gd @@ -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) diff --git a/addons/twitcher/editor/inspector/twitch_user_inspector.gd.uid b/addons/twitcher/editor/inspector/twitch_user_inspector.gd.uid new file mode 100644 index 0000000..67aaa9e --- /dev/null +++ b/addons/twitcher/editor/inspector/twitch_user_inspector.gd.uid @@ -0,0 +1 @@ +uid://cpq13q33gcqov diff --git a/addons/twitcher/editor/inspector/user_converter.gd b/addons/twitcher/editor/inspector/user_converter.gd new file mode 100644 index 0000000..281982e --- /dev/null +++ b/addons/twitcher/editor/inspector/user_converter.gd @@ -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] \ No newline at end of file diff --git a/addons/twitcher/editor/inspector/user_converter.gd.uid b/addons/twitcher/editor/inspector/user_converter.gd.uid new file mode 100644 index 0000000..59d03c7 --- /dev/null +++ b/addons/twitcher/editor/inspector/user_converter.gd.uid @@ -0,0 +1 @@ +uid://b6qdiwr7rawx1 diff --git a/addons/twitcher/editor/inspector/user_converter.tscn b/addons/twitcher/editor/inspector/user_converter.tscn new file mode 100644 index 0000000..18fae17 --- /dev/null +++ b/addons/twitcher/editor/inspector/user_converter.tscn @@ -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") \ No newline at end of file diff --git a/addons/twitcher/editor/inspector/user_property.gd b/addons/twitcher/editor/inspector/user_property.gd new file mode 100644 index 0000000..6cffdca --- /dev/null +++ b/addons/twitcher/editor/inspector/user_property.gd @@ -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() diff --git a/addons/twitcher/editor/inspector/user_property.gd.uid b/addons/twitcher/editor/inspector/user_property.gd.uid new file mode 100644 index 0000000..f8a4b02 --- /dev/null +++ b/addons/twitcher/editor/inspector/user_property.gd.uid @@ -0,0 +1 @@ +uid://c4ba54q6ecn7y diff --git a/addons/twitcher/editor/project_setting_property.gd b/addons/twitcher/editor/project_setting_property.gd new file mode 100644 index 0000000..697418e --- /dev/null +++ b/addons/twitcher/editor/project_setting_property.gd @@ -0,0 +1,98 @@ +@tool +extends RefCounted + +class_name ProjectSettingProperty + +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() -> ProjectSettingProperty: + ProjectSettings.set_as_basic(key, true) + return self + + +func as_str(description: String = "") -> ProjectSettingProperty: + return _add_type_def(TYPE_STRING, PROPERTY_HINT_PLACEHOLDER_TEXT, description) + + +func as_select(values: Array[String], optional: bool = true) -> ProjectSettingProperty: + 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) + + +# Won't work in godot 4.4 the resource is not loaded when you select the project and it will just drop it out of the list. +#func as_resoruce(resource_name: StringName) -> ProjectSettingProperty: +# return _add_type_def(TYPE_OBJECT, PROPERTY_HINT_RESOURCE_TYPE, resource_name) + + +func as_bit_field(values: Array[String]) -> ProjectSettingProperty: + var hint_string = ",".join(values) + return _add_type_def(TYPE_INT, PROPERTY_HINT_FLAGS, hint_string) + + +func as_password(description: String = "") -> ProjectSettingProperty: + return _add_type_def(TYPE_STRING, PROPERTY_HINT_PASSWORD, description) + + +func as_bool(description: String = "") -> ProjectSettingProperty: + return _add_type_def(TYPE_BOOL, PROPERTY_HINT_PLACEHOLDER_TEXT, description) + + +func as_num() -> ProjectSettingProperty: + return _add_type_def(TYPE_INT, PROPERTY_HINT_NONE, "") + + +func as_global() -> ProjectSettingProperty: + return _add_type_def(TYPE_STRING, PROPERTY_HINT_GLOBAL_FILE, "") + + +## file_type is comma separated values "*.png,*.jpg,*.tres" +func as_file(file_type: String) -> ProjectSettingProperty: + return _add_type_def(TYPE_STRING, PROPERTY_HINT_FILE, file_type) + + +func as_dir() -> ProjectSettingProperty: + return _add_type_def(TYPE_STRING, PROPERTY_HINT_DIR, "") + + +## Type should be the generic type of the array +func as_list(type: Variant = "") -> ProjectSettingProperty: + 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 = "") -> ProjectSettingProperty: + return _add_type_def(TYPE_STRING, PROPERTY_HINT_GLOBAL_SAVE_FILE, file_types) + + +func _add_type_def(type: int, hint: int, hint_string: Variant) -> ProjectSettingProperty: + ProjectSettings.add_property_info({ + "name": key, + "type": type, + "hint": hint, + "hint_string": hint_string + }) + return self diff --git a/addons/twitcher/editor/project_setting_property.gd.uid b/addons/twitcher/editor/project_setting_property.gd.uid new file mode 100644 index 0000000..1d589e9 --- /dev/null +++ b/addons/twitcher/editor/project_setting_property.gd.uid @@ -0,0 +1 @@ +uid://cbmgm86618sxe diff --git a/addons/twitcher/editor/setup/file_select.gd b/addons/twitcher/editor/setup/file_select.gd new file mode 100644 index 0000000..58ec04f --- /dev/null +++ b/addons/twitcher/editor/setup/file_select.gd @@ -0,0 +1,55 @@ +@tool +extends Control + +class_name FileSelect + +@export var default_path: String +@export var path: String: set = update_filepath +@export var filters: PackedStringArray: set = update_filters + +@onready var line_edit: LineEdit = %LineEdit +@onready var button: Button = %Button +@onready var file_dialog: FileDialog = %FileDialog + +signal file_selected(path: String) + + +func _ready() -> void: + var icon = EditorInterface.get_editor_theme().get_icon(&"FileBrowse", &"EditorIcons") + button.icon = icon + button.pressed.connect(_on_open_file_dialog) + file_dialog.file_selected.connect(_on_file_selected) + line_edit.text_changed.connect(_on_path_changed) + update_filepath(path) + update_filters(filters) + + +func update_filepath(new_path: String) -> void: + if new_path == null || new_path == "": + new_path = default_path + path = new_path + if is_inside_tree(): + line_edit.text = new_path + file_dialog.current_path = new_path + + +func update_filters(new_filters: PackedStringArray) -> void: + filters = new_filters + if is_inside_tree(): + file_dialog.filters = new_filters + + +func _on_open_file_dialog() -> void: + file_dialog.show() + + +func _on_path_changed(new_path: String) -> void: + file_dialog.current_path = new_path + path = new_path + file_selected.emit(new_path) + + +func _on_file_selected(new_path: String) -> void: + line_edit.text = new_path + path = new_path + file_selected.emit(new_path) diff --git a/addons/twitcher/editor/setup/file_select.gd.uid b/addons/twitcher/editor/setup/file_select.gd.uid new file mode 100644 index 0000000..a79bd69 --- /dev/null +++ b/addons/twitcher/editor/setup/file_select.gd.uid @@ -0,0 +1 @@ +uid://cgfc1nq4f4nae diff --git a/addons/twitcher/editor/setup/file_select.tscn b/addons/twitcher/editor/setup/file_select.tscn new file mode 100644 index 0000000..67d1c63 --- /dev/null +++ b/addons/twitcher/editor/setup/file_select.tscn @@ -0,0 +1,40 @@ +[gd_scene load_steps=4 format=3 uid="uid://b7smp156mdns6"] + +[ext_resource type="Script" uid="uid://cgfc1nq4f4nae" path="res://addons/twitcher/editor/setup/file_select.gd" id="1_lnnjv"] + +[sub_resource type="Image" id="Image_lnnjv"] +data = { +"data": PackedByteArray(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 225, 225, 225, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 224, 224, 224, 255, 225, 225, 225, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 238, 225, 225, 225, 150, 225, 225, 225, 150, 224, 224, 224, 221, 224, 224, 224, 148, 224, 224, 224, 168, 224, 224, 224, 228, 224, 224, 224, 156, 224, 224, 224, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 238, 230, 230, 230, 30, 255, 255, 255, 1, 255, 255, 255, 1, 0, 0, 0, 0, 255, 255, 255, 1, 255, 255, 255, 1, 0, 0, 0, 0, 255, 255, 255, 1, 255, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 225, 225, 225, 150, 0, 0, 0, 0, 224, 224, 224, 194, 224, 224, 224, 193, 0, 0, 0, 0, 224, 224, 224, 194, 224, 224, 224, 193, 0, 0, 0, 0, 224, 224, 224, 194, 224, 224, 224, 193, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 153, 0, 0, 0, 0, 225, 225, 225, 191, 224, 224, 224, 189, 0, 0, 0, 0, 225, 225, 225, 191, 224, 224, 224, 189, 0, 0, 0, 0, 225, 225, 225, 191, 224, 224, 224, 189, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), +"format": "RGBA8", +"height": 16, +"mipmaps": false, +"width": 16 +} + +[sub_resource type="ImageTexture" id="ImageTexture_7udr7"] +image = SubResource("Image_lnnjv") + +[node name="FileSelect" type="HBoxContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +script = ExtResource("1_lnnjv") + +[node name="LineEdit" type="LineEdit" parent="."] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "Location where the OAuth Settings get saved to." + +[node name="Button" type="Button" parent="."] +unique_name_in_owner = true +layout_mode = 2 +icon = SubResource("ImageTexture_7udr7") + +[node name="FileDialog" type="FileDialog" parent="."] +unique_name_in_owner = true +auto_translate_mode = 1 +initial_position = 1 diff --git a/addons/twitcher/editor/setup/focus_child_show.gd b/addons/twitcher/editor/setup/focus_child_show.gd new file mode 100644 index 0000000..87842c8 --- /dev/null +++ b/addons/twitcher/editor/setup/focus_child_show.gd @@ -0,0 +1,24 @@ +extends Node + +@export var show_elements: Array[Control] = [] + + +func _ready() -> void: + for element: Control in show_elements: + element.hide() + + for child in get_children(): + if child.has_signal(&"focus_entered"): + child.connect(&"focus_entered", _on_focus_entered) + if child.has_signal(&"focus_exited"): + child.connect(&"focus_exited", _on_focus_exited) + + +func _on_focus_entered() -> void: + for element: Node in show_elements: + element.show() + + +func _on_focus_exited() -> void: + for element: Node in show_elements: + element.hide() diff --git a/addons/twitcher/editor/setup/focus_child_show.gd.uid b/addons/twitcher/editor/setup/focus_child_show.gd.uid new file mode 100644 index 0000000..24674af --- /dev/null +++ b/addons/twitcher/editor/setup/focus_child_show.gd.uid @@ -0,0 +1 @@ +uid://ddugotjvuahex diff --git a/addons/twitcher/editor/setup/page_authorization.gd b/addons/twitcher/editor/setup/page_authorization.gd new file mode 100644 index 0000000..9f84d2c --- /dev/null +++ b/addons/twitcher/editor/setup/page_authorization.gd @@ -0,0 +1,101 @@ +@tool +extends Node + +const TwitchEditorSettings = preload("res://addons/twitcher/editor/twitch_editor_settings.gd") +const TwitchTweens = preload("res://addons/twitcher/editor/twitch_tweens.gd") +const TWITCH_SERVICE = preload("res://addons/twitcher/twitch_service.tscn") + +@onready var authorization_explaination: RichTextLabel = %AuthExplain + +@onready var client_id: LineEdit = %ClientId +@onready var client_secret: LineEdit = %ClientSecret +@onready var redirect_url: LineEdit = %RedirectURL + +@onready var oauth_setting_file_select: FileSelect = %OauthSettingFileSelect +@onready var token_file_select: FileSelect = %TokenFileSelect + +@onready var to_documentation: Button = %ToDocumentation + +@onready var o_auth_save: Button = %OAuthSave +@onready var test_response: Label = %TestResponse + +var has_changes: bool: + set(val): + has_changes = val + changed.emit.call_deferred() + o_auth_save.text = o_auth_save.text.trim_suffix(" (unsaved changes)") + if has_changes: o_auth_save.text += " (unsaved changes)" + +signal changed + + +func _ready() -> void: + authorization_explaination.meta_clicked.connect(_on_link_clicked) + + redirect_url.text_changed.connect(_on_text_changed) + client_id.text_changed.connect(_on_text_changed) + client_secret.text_changed.connect(_on_text_changed) + to_documentation.pressed.connect(_on_to_documentation_pressed) + oauth_setting_file_select.file_selected.connect(_on_file_changed) + token_file_select.file_selected.connect(_on_file_changed) + + o_auth_save.pressed.connect(_on_save) + + _load_oauth_setting() + + +func _load_oauth_setting() -> void: + var setting: OAuthSetting = TwitchEditorSettings.editor_oauth_setting + client_id.text = setting.client_id + client_secret.text = setting.get_client_secret() + redirect_url.text = setting.redirect_url + + +func _on_link_clicked(link: Variant) -> void: + OS.shell_open(link) + + +func _on_text_changed(val: String) -> void: + reset_response_message() + var setting: OAuthSetting = TwitchEditorSettings.editor_oauth_setting + setting.client_id = client_id.text + setting.set_client_secret(client_secret.text) + setting.redirect_url = redirect_url.text + has_changes = true + + +func reset_response_message() -> void: + test_response.text = "" + + +func _on_file_changed() -> void: + has_changes = true + + +func is_auth_existing() -> bool: + return is_instance_valid(TwitchEditorSettings.editor_oauth_setting) + + +func _on_save() -> void: + TwitchEditorSettings.save_editor_oauth_setting() + TwitchEditorSettings.save_editor_oauth_token() + + var setting_path = oauth_setting_file_select.path + var setting = TwitchEditorSettings.editor_oauth_setting.duplicate(true) + setting.take_over_path(setting_path) + ResourceSaver.save(setting, setting_path) + TwitchEditorSettings.game_oauth_setting = setting + + var token_path = token_file_select.path + var token = TwitchEditorSettings.editor_oauth_token.duplicate() + token.take_over_path(token_path) + ResourceSaver.save(token, token_path) + TwitchEditorSettings.game_oauth_token = token + + TwitchTweens.flash(o_auth_save, Color.GREEN) + ProjectSettings.save() + has_changes = false + + +func _on_to_documentation_pressed() -> void: + OS.shell_open("https://dev.twitch.tv/docs/authentication/") diff --git a/addons/twitcher/editor/setup/page_authorization.gd.uid b/addons/twitcher/editor/setup/page_authorization.gd.uid new file mode 100644 index 0000000..92d254d --- /dev/null +++ b/addons/twitcher/editor/setup/page_authorization.gd.uid @@ -0,0 +1 @@ +uid://dxql15j5ornlc diff --git a/addons/twitcher/editor/setup/page_authorization.tscn b/addons/twitcher/editor/setup/page_authorization.tscn new file mode 100644 index 0000000..a95127f --- /dev/null +++ b/addons/twitcher/editor/setup/page_authorization.tscn @@ -0,0 +1,182 @@ +[gd_scene load_steps=6 format=3 uid="uid://dm6jvnuikxtei"] + +[ext_resource type="Script" uid="uid://dxql15j5ornlc" path="res://addons/twitcher/editor/setup/page_authorization.gd" id="1_78hk7"] +[ext_resource type="LabelSettings" uid="uid://bnsxy6gcm8q11" path="res://addons/twitcher/assets/title_label_settings.tres" id="2_owlil"] +[ext_resource type="PackedScene" uid="uid://b7smp156mdns6" path="res://addons/twitcher/editor/setup/file_select.tscn" id="3_dbhpx"] +[ext_resource type="Script" uid="uid://ddugotjvuahex" path="res://addons/twitcher/editor/setup/focus_child_show.gd" id="3_o4tdm"] +[ext_resource type="PackedScene" uid="uid://bfksyo3klyvdn" path="res://addons/twitcher/editor/setup/test_credentials.tscn" id="5_dbhpx"] + +[node name="Authorization" type="MarginContainer"] +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 +script = ExtResource("1_78hk7") +metadata/_tab_index = 1 + +[node name="Layout" type="VBoxContainer" parent="."] +layout_mode = 2 +size_flags_vertical = 3 + +[node name="Title" type="Label" parent="Layout"] +layout_mode = 2 +text = "Step 2: Authorization" +label_settings = ExtResource("2_owlil") +horizontal_alignment = 1 + +[node name="ToDocumentation" type="Button" parent="Layout/Title"] +unique_name_in_owner = true +layout_mode = 1 +anchors_preset = 6 +anchor_left = 1.0 +anchor_top = 0.5 +anchor_right = 1.0 +anchor_bottom = 0.5 +offset_left = -52.0 +offset_top = -15.5 +offset_bottom = 15.5 +grow_horizontal = 0 +grow_vertical = 2 +text = "DOCS" +metadata/_edit_use_anchors_ = true + +[node name="PanelContainer" type="PanelContainer" parent="Layout"] +layout_mode = 2 + +[node name="MarginContainer" type="MarginContainer" parent="Layout/PanelContainer"] +layout_mode = 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="Layout/PanelContainer/MarginContainer"] +layout_mode = 2 + +[node name="AuthorizationTitle" type="Label" parent="Layout/PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "General" +label_settings = ExtResource("2_owlil") +horizontal_alignment = 1 + +[node name="AuthExplain" type="RichTextLabel" parent="Layout/PanelContainer/MarginContainer/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +theme_override_font_sizes/normal_font_size = 12 +bbcode_enabled = true +text = "The credentials that are used by the editor and game to connect to Twitch. You can request your credentials [url=https://dev.twitch.tv/console/apps/create]Twitch Dev Console[/url] for more informations see [url=https://twitcher.kani.dev/#authorization]Documentation[/url]" +fit_content = true +vertical_alignment = 1 + +[node name="AuthorizationOptions" type="GridContainer" parent="Layout/PanelContainer/MarginContainer/VBoxContainer" node_paths=PackedStringArray("show_elements")] +layout_mode = 2 +size_flags_vertical = 3 +size_flags_stretch_ratio = 3.0 +columns = 2 +script = ExtResource("3_o4tdm") +show_elements = [NodePath("../AuthExplain")] + +[node name="ClientIdLabel" type="Label" parent="Layout/PanelContainer/MarginContainer/VBoxContainer/AuthorizationOptions"] +layout_mode = 2 +text = "Client ID:" + +[node name="ClientId" type="LineEdit" parent="Layout/PanelContainer/MarginContainer/VBoxContainer/AuthorizationOptions"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +text = "1ae0idgxbvn6vi97ls7d89cyd919oq" + +[node name="ClientSecretLabel" type="Label" parent="Layout/PanelContainer/MarginContainer/VBoxContainer/AuthorizationOptions"] +layout_mode = 2 +text = "Client Secret:" + +[node name="ClientSecret" type="LineEdit" parent="Layout/PanelContainer/MarginContainer/VBoxContainer/AuthorizationOptions"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +text = "k22x037lmmrmkmwvy79xr19qfy993g" +secret = true + +[node name="RedirectURLLabel" type="Label" parent="Layout/PanelContainer/MarginContainer/VBoxContainer/AuthorizationOptions"] +layout_mode = 2 +text = "Redirect URL:" + +[node name="RedirectURL" type="LineEdit" parent="Layout/PanelContainer/MarginContainer/VBoxContainer/AuthorizationOptions"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +tooltip_text = "Location that Twitch is calling after the login process. Take care that this one is the same that you used during creation of the application within the twitch dev console." +text = "http://localhost:7170" + +[node name="HSeparator2" type="HSeparator" parent="Layout/PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 10 + +[node name="GameSettingTitle" type="Label" parent="Layout/PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +text = "Game" +label_settings = ExtResource("2_owlil") +horizontal_alignment = 1 + +[node name="GameExplain" type="RichTextLabel" parent="Layout/PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +theme_override_font_sizes/normal_font_size = 12 +bbcode_enabled = true +text = "These settings are needed for the game to connect with Twitch." +fit_content = true +vertical_alignment = 1 + +[node name="GameSetting" type="GridContainer" parent="Layout/PanelContainer/MarginContainer/VBoxContainer" node_paths=PackedStringArray("show_elements")] +layout_mode = 2 +columns = 2 +script = ExtResource("3_o4tdm") +show_elements = [NodePath("../GameExplain")] + +[node name="OauthSettingLabel" type="Label" parent="Layout/PanelContainer/MarginContainer/VBoxContainer/GameSetting"] +layout_mode = 2 +text = "Auth File Path:" + +[node name="OauthSettingFileSelect" parent="Layout/PanelContainer/MarginContainer/VBoxContainer/GameSetting" instance=ExtResource("3_dbhpx")] +unique_name_in_owner = true +layout_mode = 2 +default_path = "res://addons/twitcher/twitch_oauth_setting.tres" +path = "res://addons/twitcher/twitch_oauth_setting.tres" +filters = PackedStringArray("*.tres", "*.res") + +[node name="TokenLabel" type="Label" parent="Layout/PanelContainer/MarginContainer/VBoxContainer/GameSetting"] +layout_mode = 2 +text = "Token File Path:" + +[node name="TokenFileSelect" parent="Layout/PanelContainer/MarginContainer/VBoxContainer/GameSetting" instance=ExtResource("3_dbhpx")] +unique_name_in_owner = true +layout_mode = 2 +default_path = "res://addons/twitcher/default_oauth_token.tres" +path = "res://addons/twitcher/default_oauth_token.tres" +filters = PackedStringArray("*.tres", "*.res") + +[node name="HSeparator" type="HSeparator" parent="Layout/PanelContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 10 + +[node name="HBoxContainer" type="HBoxContainer" parent="Layout"] +layout_mode = 2 + +[node name="TestCredentials" parent="Layout/HBoxContainer" node_paths=PackedStringArray("test_response") instance=ExtResource("5_dbhpx")] +layout_mode = 2 +size_flags_horizontal = 3 +test_response = NodePath("../../TestResponse") + +[node name="OAuthSave" type="Button" parent="Layout/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +text = "Save" + +[node name="TestResponse" type="Label" parent="Layout"] +unique_name_in_owner = true +layout_mode = 2 diff --git a/addons/twitcher/editor/setup/page_use_case.gd b/addons/twitcher/editor/setup/page_use_case.gd new file mode 100644 index 0000000..71003ea --- /dev/null +++ b/addons/twitcher/editor/setup/page_use_case.gd @@ -0,0 +1,139 @@ +@tool +extends MarginContainer + +enum UseCase { + Overlay, Game, Other +} + +const PRESET_GAME_SCOPES = preload("res://addons/twitcher/auth/preset_game_scopes.tres") +const PRESET_OVERLAY_SCOPES = preload("res://addons/twitcher/auth/preset_overlay_scopes.tres") +const TwitchScopeProperty = preload("res://addons/twitcher/editor/inspector/twitch_scope_property.gd") +const TwitchEditorSettings = preload("res://addons/twitcher/editor/twitch_editor_settings.gd") +const TwitchTweens = preload("res://addons/twitcher/editor/twitch_tweens.gd") + +@export var choose_button_group: ButtonGroup + +@onready var overlay: CheckBox = %Overlay +@onready var game: CheckBox = %Game +@onready var something_else: CheckBox = %SomethingElse +@onready var scope_list: RichTextLabel = %ScopeList +@onready var to_documentation: Button = %ToDocumentation +@onready var scope_file_select: FileSelect = %ScopeFileSelect +@onready var scopes_container: HBoxContainer = %Scopes +@onready var advanced_edit: CheckButton = %AdvancedEdit +@onready var other_scope_options: PanelContainer = %OtherScopeOptions +@onready var extended_scope_info: PanelContainer = %ExtendedScopeInfo +@onready var save: Button = %Save + +var other_scope_property: TwitchScopeProperty = TwitchScopeProperty.new() +var scopes: TwitchOAuthScopes: set = update_scopes +var has_changes: bool: + set(val): + has_changes = val + changed.emit() + save.text = save.text.trim_suffix(" (unsaved changes)") + if has_changes: save.text += " (unsaved changes)" + +signal changed +signal use_case_changed(use_case: UseCase) + + +func _ready() -> void: + to_documentation.pressed.connect(_on_to_documentation_pressed) + choose_button_group.pressed.connect(_on_choose) + scope_file_select.file_selected.connect(_on_scope_file_selected) + save.pressed.connect(_on_save_pressed) + other_scope_property.scope_selected.connect(_on_scope_info) + advanced_edit.toggled.connect(_on_toggle_advanced_edit) + + scopes_container.hide() + extended_scope_info.hide() + extended_scope_info.add_child(other_scope_property) + + # Reset radio buttons cause it's a tool script and the radio button stay and won't throw another signal otherwise + game.set_pressed_no_signal(false) + overlay.set_pressed_no_signal(false) + something_else.set_pressed_no_signal(false) + + scope_file_select.path = TwitchEditorSettings.get_scope_path() + match TwitchEditorSettings.project_preset: + TwitchEditorSettings.PRESET_GAME: + game.button_pressed = true + TwitchEditorSettings.PRESET_OVERLAY: + overlay.button_pressed = true + TwitchEditorSettings.PRESET_OTHER: + something_else.button_pressed = true + + # Needs to be resetted cause the radio reset will change the has_changges to true + has_changes = false + +func _on_scope_file_selected(path: String) -> void: + has_changes = true + if FileAccess.file_exists(path): + var resource = load(path) + if resource is OAuthScopes: scopes = resource + else: OS.alert("The selected scope is not a scope file, it will be overwritten!") + + +func _on_toggle_advanced_edit(toggled_on: bool) -> void: + extended_scope_info.visible = toggled_on + + +func _on_choose(button: BaseButton) -> void: + match button: + overlay: + use_case_changed.emit(UseCase.Overlay) + scopes = PRESET_OVERLAY_SCOPES.duplicate(true) + advanced_edit.button_pressed = false + TwitchEditorSettings.project_preset = TwitchEditorSettings.PRESET_OVERLAY + game: + use_case_changed.emit(UseCase.Game) + scopes = PRESET_GAME_SCOPES.duplicate(true) + advanced_edit.button_pressed = false + TwitchEditorSettings.project_preset = TwitchEditorSettings.PRESET_GAME + something_else: + use_case_changed.emit(UseCase.Other) + scopes = TwitchOAuthScopes.new() + advanced_edit.button_pressed = true + TwitchEditorSettings.project_preset = TwitchEditorSettings.PRESET_OTHER + + _show_selected_scopes() + has_changes = true + +func _on_scope_info(scope: TwitchScope.Definition) -> void: + _show_selected_scopes() + + +func _on_save_pressed() -> void: + var s_path = scope_file_select.path + scopes.take_over_path(s_path) + ResourceSaver.save(scopes, s_path) + TwitchEditorSettings.set_scope_path(s_path) + TwitchTweens.flash(save, Color.GREEN) + has_changes = false + + +func _show_selected_scopes() -> void: + scopes_container.show() + + if scopes.used_scopes.is_empty(): + scope_list.text = "[i]No scopes selected yet[/i]" + return + + var scope_description: String = "" + for scope_name: StringName in scopes.used_scopes: + var scope: TwitchScope.Definition = TwitchScope.SCOPE_MAP[scope_name] + scope_description += "[b]%s[/b] - %s\n\n" % [scope.value, scope.description] + + scope_list.text = scope_description + + +func _on_to_documentation_pressed() -> void: + OS.shell_open("https://dev.twitch.tv/docs/authentication/scopes/") + + +func update_scopes(val: TwitchOAuthScopes) -> void: + scopes = val + other_scope_property.set_object_and_property(scopes, "") + other_scope_property.update_property() + _show_selected_scopes() diff --git a/addons/twitcher/editor/setup/page_use_case.gd.uid b/addons/twitcher/editor/setup/page_use_case.gd.uid new file mode 100644 index 0000000..1203340 --- /dev/null +++ b/addons/twitcher/editor/setup/page_use_case.gd.uid @@ -0,0 +1 @@ +uid://cjni881olloyf diff --git a/addons/twitcher/editor/setup/page_use_case.tscn b/addons/twitcher/editor/setup/page_use_case.tscn new file mode 100644 index 0000000..a46dc96 --- /dev/null +++ b/addons/twitcher/editor/setup/page_use_case.tscn @@ -0,0 +1,162 @@ +[gd_scene load_steps=5 format=3 uid="uid://c7pja1druikbn"] + +[ext_resource type="Script" uid="uid://cjni881olloyf" path="res://addons/twitcher/editor/setup/page_use_case.gd" id="1_2qemh"] +[ext_resource type="LabelSettings" uid="uid://bnsxy6gcm8q11" path="res://addons/twitcher/assets/title_label_settings.tres" id="1_r6qea"] +[ext_resource type="ButtonGroup" uid="uid://bkocyfdqvh4t" path="res://addons/twitcher/editor/setup/use_case_button_group.tres" id="1_vqr26"] +[ext_resource type="PackedScene" uid="uid://b7smp156mdns6" path="res://addons/twitcher/editor/setup/file_select.tscn" id="4_c6y6e"] + +[node name="UseCase" type="MarginContainer"] +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 +script = ExtResource("1_2qemh") +choose_button_group = ExtResource("1_vqr26") +metadata/_tab_index = 0 + +[node name="ScrollContainer" type="ScrollContainer" parent="."] +layout_mode = 2 + +[node name="SelectionContainer" type="VBoxContainer" parent="ScrollContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="Title" type="Label" parent="ScrollContainer/SelectionContainer"] +layout_mode = 2 +text = "Step 1: Use Case" +label_settings = ExtResource("1_r6qea") +horizontal_alignment = 1 + +[node name="ToDocumentation" type="Button" parent="ScrollContainer/SelectionContainer/Title"] +unique_name_in_owner = true +layout_mode = 1 +anchors_preset = 6 +anchor_left = 1.0 +anchor_top = 0.5 +anchor_right = 1.0 +anchor_bottom = 0.5 +offset_left = -52.0 +offset_top = -15.5 +offset_bottom = 15.5 +grow_horizontal = 0 +grow_vertical = 2 +text = "DOCS" +metadata/_edit_use_anchors_ = true + +[node name="Explaination" type="RichTextLabel" parent="ScrollContainer/SelectionContainer"] +layout_mode = 2 +theme_override_font_sizes/normal_font_size = 12 +bbcode_enabled = true +text = "To help you with scopes and authentication please select your use case." +fit_content = true +vertical_alignment = 1 + +[node name="ChooseLabel" type="Label" parent="ScrollContainer/SelectionContainer"] +layout_mode = 2 +text = "What do you want to make:" + +[node name="Overlay" type="CheckBox" parent="ScrollContainer/SelectionContainer"] +unique_name_in_owner = true +layout_mode = 2 +button_pressed = true +button_group = ExtResource("1_vqr26") +text = "Overlay" + +[node name="Game" type="CheckBox" parent="ScrollContainer/SelectionContainer"] +unique_name_in_owner = true +layout_mode = 2 +button_group = ExtResource("1_vqr26") +text = "Game" + +[node name="SomethingElse" type="CheckBox" parent="ScrollContainer/SelectionContainer"] +unique_name_in_owner = true +layout_mode = 2 +button_group = ExtResource("1_vqr26") +text = "I know what I do / Something else" + +[node name="HSeparator" type="HSeparator" parent="ScrollContainer/SelectionContainer"] +layout_mode = 2 +theme_override_constants/separation = 20 + +[node name="Scopes" type="HBoxContainer" parent="ScrollContainer/SelectionContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 + +[node name="ExtendedScopeInfo" type="PanelContainer" parent="ScrollContainer/SelectionContainer/Scopes"] +unique_name_in_owner = true +visible = false +layout_mode = 2 + +[node name="OtherScopeOptions" type="PanelContainer" parent="ScrollContainer/SelectionContainer/Scopes"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="VBoxContainer" type="VBoxContainer" parent="ScrollContainer/SelectionContainer/Scopes/OtherScopeOptions"] +layout_mode = 2 + +[node name="ScopeListLabel" type="Label" parent="ScrollContainer/SelectionContainer/Scopes/OtherScopeOptions/VBoxContainer"] +layout_mode = 2 +text = "Scopes:" +label_settings = ExtResource("1_r6qea") + +[node name="AdvancedEdit" type="CheckButton" parent="ScrollContainer/SelectionContainer/Scopes/OtherScopeOptions/VBoxContainer/ScopeListLabel"] +unique_name_in_owner = true +layout_mode = 1 +anchors_preset = 6 +anchor_left = 1.0 +anchor_top = 0.5 +anchor_right = 1.0 +anchor_bottom = 0.5 +offset_left = -168.0 +offset_top = -15.5 +offset_bottom = 15.5 +grow_horizontal = 0 +grow_vertical = 2 +text = "Edit (Advanced)" + +[node name="ScopeList" type="RichTextLabel" parent="ScrollContainer/SelectionContainer/Scopes/OtherScopeOptions/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +bbcode_enabled = true +text = "[b]user:read:chat[/b] - Receive chatroom messages and informational notifications relating to a channel’s chatroom. + +[b]user:write:chat[/b] - Send chat messages to a chatroom. + +[b]moderator:read:followers[/b] - Read the followers of a broadcaster. + +[b]bits:read[/b] - View Bits information for a channel. + +[b]channel:read:redemptions[/b] - View Channel Points custom rewards and their redemptions on a channel. + +[b]channel:manage:redemptions[/b] - Manage Channel Points custom rewards and their redemptions on a channel. + +" +fit_content = true + +[node name="HSeparator" type="HSeparator" parent="ScrollContainer/SelectionContainer/Scopes/OtherScopeOptions/VBoxContainer"] +layout_mode = 2 +theme_override_constants/separation = 10 + +[node name="ScopeFileLabel" type="Label" parent="ScrollContainer/SelectionContainer/Scopes/OtherScopeOptions/VBoxContainer"] +layout_mode = 2 +text = "Save selected scopes:" + +[node name="ScopeFileSelect" parent="ScrollContainer/SelectionContainer/Scopes/OtherScopeOptions/VBoxContainer" instance=ExtResource("4_c6y6e")] +unique_name_in_owner = true +layout_mode = 2 +default_path = "res://twitch_scopes.tres" +path = "res://twitch_scopes.tres" +filters = PackedStringArray("*.tres", "*.res") + +[node name="Save" type="Button" parent="ScrollContainer/SelectionContainer/Scopes/OtherScopeOptions/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Save Scopes" diff --git a/addons/twitcher/editor/setup/page_utilities.gd b/addons/twitcher/editor/setup/page_utilities.gd new file mode 100644 index 0000000..88c78ab --- /dev/null +++ b/addons/twitcher/editor/setup/page_utilities.gd @@ -0,0 +1,74 @@ +@tool +extends MarginContainer + +const script_path: String = "res://addons/twitcher/twitch_service.tscn" +const autoload_name: String = "Twitch" +const setting_key: String = "autoload/%s" % autoload_name +const setting_value: String = "*" + script_path + +@onready var autoload_install: Button = %AutoloadInstall +@onready var autoload_info: Label = %AutoloadInfo +@onready var autoload_description: RichTextLabel = %AutoloadDescription + + +func _ready() -> void: + autoload_description.text = autoload_description.text.format({ + "autoload_name": autoload_name + }) + autoload_install.pressed.connect(_on_install_autoload_pressed) + _update_install_autoload() + + +func _update_install_autoload() -> void: + if ProjectSettings.has_setting(setting_key): + autoload_install.text = "Uninstall Autoload" + else: + autoload_install.text = "Install Autoload" + + +func _on_install_autoload_pressed() -> void: + if ProjectSettings.has_setting(setting_key): + _uninstall_autoload() + else: + _install_autload() + _update_install_autoload() + + +func _uninstall_autoload() -> void: + ProjectSettings.clear(setting_key) + + var err = ProjectSettings.save() + + if err == OK: + autoload_info.text = "Autoload '%s' uninstalled successfully!\nYou might need to reload the current project for changes to fully apply everywhere in the editor immediately." % autoload_name + print("Successfully removed autoload: %s" % autoload_name) + else: + autoload_info.text = "Failed to save project settings.\nError code: %s" % error_string(err) + printerr("Failed to save project settings! Error: ", error_string(err)) + + +func _install_autload() -> void: + if not FileAccess.file_exists(script_path): + OS.alert("The TwitchService file does not exist at:\n" + script_path, "Error") + return + + var setting_key: String = "autoload/%s" % autoload_name + var setting_value: String = "*" + script_path + if ProjectSettings.has_setting(setting_key): + var existing_value = ProjectSettings.get_setting(setting_key) + if existing_value == setting_value: + autoload_info.text = "Autoload '%s' with the same path is already installed." % autoload_name + return + else: + autoload_info.text = "Autoload '%s' already exists but points to a different path (%s)." % [autoload_name, existing_value] + return + + ProjectSettings.set_setting(setting_key, setting_value) + var err = ProjectSettings.save() + + if err == OK: + autoload_info.text = "Autoload '%s' installed successfully!\nYou might need to reload the current project for changes to fully apply everywhere in the editor immediately." % autoload_name + print("Successfully added autoload: %s -> %s" % [autoload_name, script_path]) + else: + autoload_info.text = "Failed to save project settings.\nError code: %s" % error_string(err) + printerr("Failed to save project settings! Error: ", error_string(err)) diff --git a/addons/twitcher/editor/setup/page_utilities.gd.uid b/addons/twitcher/editor/setup/page_utilities.gd.uid new file mode 100644 index 0000000..6e64095 --- /dev/null +++ b/addons/twitcher/editor/setup/page_utilities.gd.uid @@ -0,0 +1 @@ +uid://dw37fk6mah3jk diff --git a/addons/twitcher/editor/setup/page_utilities.tscn b/addons/twitcher/editor/setup/page_utilities.tscn new file mode 100644 index 0000000..249108a --- /dev/null +++ b/addons/twitcher/editor/setup/page_utilities.tscn @@ -0,0 +1,96 @@ +[gd_scene load_steps=4 format=3 uid="uid://d4l63q706mkhw"] + +[ext_resource type="Script" uid="uid://dw37fk6mah3jk" path="res://addons/twitcher/editor/setup/page_utilities.gd" id="1_sexj5"] +[ext_resource type="LabelSettings" uid="uid://bnsxy6gcm8q11" path="res://addons/twitcher/assets/title_label_settings.tres" id="1_yi5sa"] +[ext_resource type="LabelSettings" uid="uid://cng881nsuud80" path="res://addons/twitcher/assets/warning_label_settings.tres" id="3_fj7h2"] + +[node name="Utilities" type="MarginContainer"] +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 +script = ExtResource("1_sexj5") +metadata/_tab_index = 2 + +[node name="ScrollContainer" type="ScrollContainer" parent="."] +layout_mode = 2 + +[node name="Container" type="VBoxContainer" parent="ScrollContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="Header" type="Label" parent="ScrollContainer/Container"] +layout_mode = 2 +text = "Utilities" +label_settings = ExtResource("1_yi5sa") +horizontal_alignment = 1 + +[node name="HSeparator" type="HSeparator" parent="ScrollContainer/Container"] +layout_mode = 2 +theme_override_constants/separation = 20 + +[node name="AutoloadDescription" type="RichTextLabel" parent="ScrollContainer/Container"] +unique_name_in_owner = true +layout_mode = 2 +bbcode_enabled = true +text = "For basic use cases an autoload is the easiest way to setup Twitcher. Adds an autoload named [b]{autoload_name}[/b] + +[i]Advantage:[/i] ++ easy access everywhere +[i]Disadvantage:[/i] +- It will be always initialized, even when you want to test a small scene standalone Tiwtcher will do authorization, subscribing to eventsub etc. + +[b]Alternative:[/b] +The first nodes in the scene tree of every major nodes like TwitchAPI, TwitchEventsub, TwitchChat, TwitchMediaLoader and TwitchService are available as Singleton via their instance variable. + +Example +[code]TwitchAPI.instance.get_users(...)[/code]" +fit_content = true + +[node name="AutoloadInstall" type="Button" parent="ScrollContainer/Container"] +unique_name_in_owner = true +layout_mode = 2 +text = "Uninstall Autoload" + +[node name="AutoloadInfo" type="Label" parent="ScrollContainer/Container"] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 100) +layout_mode = 2 +label_settings = ExtResource("3_fj7h2") +autowrap_mode = 3 + +[node name="HSeparator2" type="HSeparator" parent="ScrollContainer/Container"] +layout_mode = 2 +theme_override_constants/separation = 20 + +[node name="AutoloadDescription2" type="RichTextLabel" parent="ScrollContainer/Container"] +visible = false +layout_mode = 2 +bbcode_enabled = true +text = "For a game with Twitch integration you probably want to read the chat from the streamer to act on the commands. For that the streamer need to authorize your application. For the authorization flow use the [url=https://dev.twitch.tv/docs/authentication/getting-tokens-oauth/#device-code-grant-flow]Device Code Flow[/url] so that you don't share the client secret in the code. + + +[b]Hints:[/b] +- Take care that you take the least amount of scopes for the game otherwise you could scare the streamer away. +[i]Advantage:[/i] ++ easy access everywhere +[i]Disadvantage:[/i] +- It will be always initialized, even when you want to test a small scene standalone Tiwtcher will do authorization, subscribing to eventsub etc. + +[b]Alternative:[/b] +The first nodes in the scene tree of every major nodes like TwitchAPI, TwitchEventsub, TwitchChat, TwitchMediaLoader and TwitchService are available as Singleton via their instance variable. + +Example +[code]TwitchAPI.instance.get_users(...)[/code]" +fit_content = true + +[node name="Button" type="Button" parent="ScrollContainer/Container"] +visible = false +layout_mode = 2 +text = "Add Game Example" diff --git a/addons/twitcher/editor/setup/setup.gd b/addons/twitcher/editor/setup/setup.gd new file mode 100644 index 0000000..4fe28a6 --- /dev/null +++ b/addons/twitcher/editor/setup/setup.gd @@ -0,0 +1,58 @@ +@tool +extends Window + +const PageUseCase = preload("res://addons/twitcher/editor/setup/page_use_case.gd") +const TwitchEditorSettings = preload("res://addons/twitcher/editor/twitch_editor_settings.gd") +const PageAuthorization = preload("res://addons/twitcher/editor/setup/page_authorization.gd") + +#Setup +#- Check for Authorization Stuff +#-- Client Credentials +#-- Editor Token +#-- Scopes +#- Auth Button +#- Create Base Node Structure + +@onready var authorization: PageAuthorization = %Authorization +@onready var use_case: PageUseCase = %UseCase as PageUseCase +@onready var close: Button = %Close +@onready var startup_check: CheckButton = %StartupCheck + + +func _ready(): + close_requested.connect(_on_close) + close.pressed.connect(_on_close) + startup_check.toggled.connect(_on_toggle_startup_check) + startup_check.button_pressed = TwitchEditorSettings.show_setup_on_startup + use_case.changed.connect(_on_changed) + authorization.changed.connect(_on_changed) + pass + + +func _on_changed() -> void: + close.text = close.text.trim_suffix(" (unsaved changes)") + if use_case.has_changes || authorization.has_changes: + close.text = close.text + " (unsaved changes)" + + +func _on_toggle_startup_check(toggle_on: bool) -> void: + TwitchEditorSettings.show_setup_on_startup = toggle_on + ProjectSettings.save() + + +func _input(event: InputEvent) -> void: + if event is InputEventKey: + var key_event: InputEventKey = event as InputEventKey + if key_event.keycode == KEY_ESCAPE: + _on_close() + + +func _on_close() -> void: + if use_case.has_changes || authorization.has_changes: + var popup = ConfirmationDialog.new() + popup.dialog_text = "You have unsaved changes! Are you sure to close the setup?" + popup.confirmed.connect(queue_free) + add_child(popup) + popup.popup_centered() + else: + queue_free() diff --git a/addons/twitcher/editor/setup/setup.gd.uid b/addons/twitcher/editor/setup/setup.gd.uid new file mode 100644 index 0000000..2ad7486 --- /dev/null +++ b/addons/twitcher/editor/setup/setup.gd.uid @@ -0,0 +1 @@ +uid://bbguje3a0cl8t diff --git a/addons/twitcher/editor/setup/setup.tscn b/addons/twitcher/editor/setup/setup.tscn new file mode 100644 index 0000000..d5f40d6 --- /dev/null +++ b/addons/twitcher/editor/setup/setup.tscn @@ -0,0 +1,51 @@ +[gd_scene load_steps=6 format=3 uid="uid://wu1fprbhr62"] + +[ext_resource type="Script" uid="uid://bbguje3a0cl8t" path="res://addons/twitcher/editor/setup/setup.gd" id="1_o5snq"] +[ext_resource type="PackedScene" uid="uid://c7pja1druikbn" path="res://addons/twitcher/editor/setup/page_use_case.tscn" id="2_6678v"] +[ext_resource type="PackedScene" uid="uid://dm6jvnuikxtei" path="res://addons/twitcher/editor/setup/page_authorization.tscn" id="3_qcivh"] +[ext_resource type="PackedScene" uid="uid://d4l63q706mkhw" path="res://addons/twitcher/editor/setup/page_utilities.tscn" id="4_qcivh"] + +[sub_resource type="ButtonGroup" id="ButtonGroup_6678v"] + +[node name="SetupWindow" type="Window"] +title = "Setup Twitcher" +initial_position = 2 +size = Vector2i(800, 800) +script = ExtResource("1_o5snq") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 + +[node name="Setup" type="TabContainer" parent="VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 +current_tab = 0 + +[node name="UseCase" parent="VBoxContainer/Setup" instance=ExtResource("2_6678v")] +unique_name_in_owner = true +layout_mode = 2 +choose_button_group = SubResource("ButtonGroup_6678v") + +[node name="Authorization" parent="VBoxContainer/Setup" instance=ExtResource("3_qcivh")] +unique_name_in_owner = true +visible = false +layout_mode = 2 + +[node name="Utilities" parent="VBoxContainer/Setup" instance=ExtResource("4_qcivh")] +visible = false +layout_mode = 2 + +[node name="StartupCheck" type="CheckButton" parent="VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +button_pressed = true +text = "Show on startup (you can open it via 'Project/Tools/Twitcher Setup')" + +[node name="Close" type="Button" parent="VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Close" diff --git a/addons/twitcher/editor/setup/test_credentials.gd b/addons/twitcher/editor/setup/test_credentials.gd new file mode 100644 index 0000000..5de57e4 --- /dev/null +++ b/addons/twitcher/editor/setup/test_credentials.gd @@ -0,0 +1,58 @@ +@tool +extends Button + +const TwitchTweens = preload("res://addons/twitcher/editor/twitch_tweens.gd") +const TwitchEditorSettings = preload("res://addons/twitcher/editor/twitch_editor_settings.gd") + +@export var oauth_setting: OAuthSetting: set = update_oauth_setting +@export var oauth_token: OAuthToken: set = update_oauth_token +@export var test_response: Label + +@onready var twitch_auth: TwitchAuth = %TwitchAuth + +signal authorized + +func _ready() -> void: + pressed.connect(_pressed) + oauth_setting = TwitchEditorSettings.editor_oauth_setting + oauth_token = TwitchEditorSettings.editor_oauth_token + + +func _notification(what: int) -> void: + if what == NOTIFICATION_PREDELETE: + oauth_token.authorized.disconnect(_on_authorized) + + +func _pressed() -> void: + TwitchTweens.loading(self) + await twitch_auth.authorize() + + if twitch_auth.token.is_token_valid(): + if test_response: + test_response.text = "Credentials are valid!" + test_response.add_theme_color_override(&"font_color", Color.GREEN) + TwitchTweens.flash(self, Color.GREEN) + authorized.emit() + else: + if test_response: + test_response.text = "Credentials are invalid!" + test_response.add_theme_color_override(&"font_color", Color.RED) + TwitchTweens.flash(self, Color.RED) + + +func update_oauth_token(new_oauth_token: OAuthToken) -> void: + oauth_token = new_oauth_token + oauth_token.authorized.connect(_on_authorized) + if is_inside_tree(): + twitch_auth.token = new_oauth_token + + +func update_oauth_setting(new_oauth_setting: OAuthSetting) -> void: + oauth_setting = new_oauth_setting + disabled = not oauth_setting.is_valid() + if is_inside_tree(): + twitch_auth.oauth_setting = oauth_setting + + +func _on_authorized() -> void: + if is_inside_tree(): authorized.emit() diff --git a/addons/twitcher/editor/setup/test_credentials.gd.uid b/addons/twitcher/editor/setup/test_credentials.gd.uid new file mode 100644 index 0000000..7107e86 --- /dev/null +++ b/addons/twitcher/editor/setup/test_credentials.gd.uid @@ -0,0 +1 @@ +uid://13afcys4swos diff --git a/addons/twitcher/editor/setup/test_credentials.tscn b/addons/twitcher/editor/setup/test_credentials.tscn new file mode 100644 index 0000000..e8cf13e --- /dev/null +++ b/addons/twitcher/editor/setup/test_credentials.tscn @@ -0,0 +1,37 @@ +[gd_scene load_steps=9 format=3 uid="uid://bfksyo3klyvdn"] + +[ext_resource type="Script" uid="uid://13afcys4swos" path="res://addons/twitcher/editor/setup/test_credentials.gd" id="1_j2v3o"] +[ext_resource type="Script" uid="uid://iv0mgv0lu8b0" path="res://addons/twitcher/auth/twitch_auth.gd" id="1_kojf4"] +[ext_resource type="Script" uid="uid://b3n3et8mebjcc" path="res://addons/twitcher/auth/twitch_oauth_scopes.gd" id="3_2rqpn"] +[ext_resource type="Resource" path="user://editor_oauth_setting.tres" id="3_kojf4"] +[ext_resource type="Resource" path="user://editor_oauth_token.tres" id="4_j2v3o"] +[ext_resource type="Script" uid="uid://bf0wi70haua35" path="res://addons/twitcher/lib/oOuch/oauth.gd" id="6_hkawa"] +[ext_resource type="Script" uid="uid://blnbogtrshw4r" path="res://addons/twitcher/auth/twitch_token_handler.gd" id="7_v5ghs"] + +[sub_resource type="Resource" id="Resource_1cpcx"] +script = ExtResource("3_2rqpn") +used_scopes = Array[StringName]([]) +metadata/_custom_type_script = "uid://b3n3et8mebjcc" + +[node name="TestCredentials" type="Button"] +text = "Test Credentials" +script = ExtResource("1_j2v3o") + +[node name="TwitchAuth" type="Node" parent="."] +unique_name_in_owner = true +script = ExtResource("1_kojf4") +oauth_setting = ExtResource("3_kojf4") +token = ExtResource("4_j2v3o") +scopes = SubResource("Resource_1cpcx") +metadata/_custom_type_script = "uid://iv0mgv0lu8b0" + +[node name="OAuth" type="Node" parent="TwitchAuth" node_paths=PackedStringArray("token_handler")] +script = ExtResource("6_hkawa") +oauth_setting = ExtResource("3_kojf4") +scopes = SubResource("Resource_1cpcx") +token_handler = NodePath("../TokenHandler") + +[node name="TokenHandler" type="Node" parent="TwitchAuth"] +script = ExtResource("7_v5ghs") +oauth_setting = ExtResource("3_kojf4") +token = ExtResource("4_j2v3o") diff --git a/addons/twitcher/editor/setup/use_case_button_group.tres b/addons/twitcher/editor/setup/use_case_button_group.tres new file mode 100644 index 0000000..aecc11f --- /dev/null +++ b/addons/twitcher/editor/setup/use_case_button_group.tres @@ -0,0 +1,3 @@ +[gd_resource type="ButtonGroup" format=3 uid="uid://bkocyfdqvh4t"] + +[resource] diff --git a/addons/twitcher/editor/twitch_editor_settings.gd b/addons/twitcher/editor/twitch_editor_settings.gd new file mode 100644 index 0000000..b45a0da --- /dev/null +++ b/addons/twitcher/editor/twitch_editor_settings.gd @@ -0,0 +1,145 @@ +@tool +extends RefCounted + +## Utilitiy Node for Inspector to calling API functionallity at any point + +const EDITOR_OAUTH_TOKEN: String = "user://editor_oauth_token.tres" +const EDITOR_OAUTH_SETTING: String = "user://editor_oauth_setting.tres" +const GAME_OAUTH_TOKEN: String = "res://twitch_oauth_token.tres" +const GAME_OAUTH_SETTING: String = "res://twitch_oauth_setting.tres" +const TWITCH_DEFAULT_SCOPE: String = "res://addons/twitcher/auth/preset_overlay_scopes.tres" + +const PRESET_GAME: StringName = &"Game" +const PRESET_OVERLAY: StringName = &"Overlay" +const PRESET_OTHER: StringName = &"Other" + +static var _editor_oauth_token_property: ProjectSettingProperty +static var editor_oauth_token: OAuthToken: + set(val): + editor_oauth_token = val + _editor_oauth_token_property.set_val(val.resource_path) + +static var _editor_oauth_setting_property: ProjectSettingProperty +static var editor_oauth_setting: OAuthSetting: + set(val): + editor_oauth_setting = val + _editor_oauth_setting_property.set_val(val.resource_path) + +static var _game_oauth_token_property: ProjectSettingProperty +static var game_oauth_token: OAuthToken: + set(val): + game_oauth_token = val + _game_oauth_token_property.set_val(val.resource_path) + +static var _game_oauth_setting_property: ProjectSettingProperty +static var game_oauth_setting: OAuthSetting: + set(val): + game_oauth_setting = val + _game_oauth_setting_property.set_val(val.resource_path) + +static var _scope_property: ProjectSettingProperty +static var scopes: TwitchOAuthScopes: + set(val): + scopes = val + _scope_property.set_val(val.resource_path) + +static var _show_setup_on_startup: ProjectSettingProperty +static var show_setup_on_startup: bool: + set(val): _show_setup_on_startup.set_val(val) + get: return _show_setup_on_startup.get_val() + +static var _project_preset: ProjectSettingProperty +static var project_preset: StringName: + set(val): _project_preset.set_val(val) + get: return _project_preset.get_val() + +static var _initialized: bool + + +static func setup() -> void: + if not _initialized: + _initialized = true + _setup_project_settings() + _reload_setting() + + +static func _setup_project_settings() -> void: + _editor_oauth_token_property = ProjectSettingProperty.new("twitcher/editor/editor_oauth_token", EDITOR_OAUTH_TOKEN) + _editor_oauth_token_property.as_file("*.res,*.tres") + + _editor_oauth_setting_property = ProjectSettingProperty.new("twitcher/editor/editor_oauth_setting", EDITOR_OAUTH_SETTING) + _editor_oauth_setting_property.as_file("*.res,*.tres") + + _game_oauth_token_property = ProjectSettingProperty.new("twitcher/editor/game_oauth_token", GAME_OAUTH_TOKEN) + _game_oauth_token_property.as_file("*.res,*.tres") + + _game_oauth_setting_property = ProjectSettingProperty.new("twitcher/editor/game_oauth_setting", GAME_OAUTH_SETTING) + _game_oauth_setting_property.as_file("*.res,*.tres") + + _scope_property = ProjectSettingProperty.new("twitcher/editor/default_scopes", TWITCH_DEFAULT_SCOPE) + _scope_property.as_file("*.res,*.tres") + + _show_setup_on_startup = ProjectSettingProperty.new("twitcher/editor/show_setup_on_startup", true) + + _project_preset = ProjectSettingProperty.new("twitcher/editor/project_preset") + _project_preset.as_select([PRESET_GAME, PRESET_OVERLAY, PRESET_OTHER], false) + + +static func _reload_setting() -> void: + editor_oauth_setting = load(_editor_oauth_setting_property.get_val()) + editor_oauth_token = load(_editor_oauth_token_property.get_val()) + game_oauth_setting = load(_game_oauth_setting_property.get_val()) + game_oauth_token = load(_game_oauth_token_property.get_val()) + + var editor_oauth_token_path: String = _editor_oauth_token_property.get_val() + if editor_oauth_token_path: + if not FileAccess.file_exists(editor_oauth_token_path): + _create_editor_oauth_token() + + var editor_oauth_setting_path: String = _editor_oauth_setting_property.get_val() + if editor_oauth_setting_path: + if not FileAccess.file_exists(editor_oauth_setting_path): + _create_editor_oauth_setting() + + var scope_path: String = get_scope_path() + if scope_path and FileAccess.file_exists(scope_path): + scopes = load(scope_path) + + +static func save_editor_oauth_setting() -> void: + ResourceSaver.save(editor_oauth_setting) + + +static func save_editor_oauth_token() -> void: + ResourceSaver.save(editor_oauth_token) + + +static func get_scope_path() -> String: + return _scope_property.get_val() + + +static func set_scope_path(path: String) -> void: + _scope_property.set_val(path) + + +static func is_valid() -> bool: + var token_valid = is_instance_valid(editor_oauth_token) && editor_oauth_token.is_token_valid() + var setting_valid = is_instance_valid(editor_oauth_setting) && editor_oauth_setting.is_valid() + return token_valid && setting_valid + + +static func _create_editor_oauth_token() -> void: + var path: String = _editor_oauth_token_property.get_val() + var token = OAuthToken.new() + token._identifier = "EditorToken" + token.take_over_path(path) + editor_oauth_token = token + save_editor_oauth_token() + + +static func _create_editor_oauth_setting() -> void: + var path: String = _editor_oauth_setting_property.get_val() + var setting = TwitchAuth.create_default_oauth_setting() + setting.take_over_path(path) + editor_oauth_setting = setting + save_editor_oauth_setting() diff --git a/addons/twitcher/editor/twitch_editor_settings.gd.uid b/addons/twitcher/editor/twitch_editor_settings.gd.uid new file mode 100644 index 0000000..3767d52 --- /dev/null +++ b/addons/twitcher/editor/twitch_editor_settings.gd.uid @@ -0,0 +1 @@ +uid://kqcukq2xqnuf diff --git a/addons/twitcher/editor/twitch_tweens.gd b/addons/twitcher/editor/twitch_tweens.gd new file mode 100644 index 0000000..633320c --- /dev/null +++ b/addons/twitcher/editor/twitch_tweens.gd @@ -0,0 +1,17 @@ +static func flash(object: Control, color: Color, duration: float = .25) -> void: + var tween = object.create_tween() + tween.tween_property(object, ^"modulate", color, duration)\ + .set_ease(Tween.EASE_OUT)\ + .set_trans(Tween.TRANS_CIRC) + tween.tween_property(object, ^"modulate", Color.WHITE, duration)\ + .set_ease(Tween.EASE_OUT)\ + .set_trans(Tween.TRANS_CIRC) + await tween.finished + + +static func loading(object: Control, color: Color = Color.YELLOW) -> void: + var tween: Tween = object.create_tween() + tween.tween_property(object, ^"modulate", color, 0.2) \ + .set_trans(Tween.TRANS_LINEAR) \ + .set_ease(Tween.EASE_IN_OUT) + await tween.finished diff --git a/addons/twitcher/editor/twitch_tweens.gd.uid b/addons/twitcher/editor/twitch_tweens.gd.uid new file mode 100644 index 0000000..bf15a56 --- /dev/null +++ b/addons/twitcher/editor/twitch_tweens.gd.uid @@ -0,0 +1 @@ +uid://duhsr84u352ef diff --git a/addons/twitcher/eventsub/twitch_event_listener.gd b/addons/twitcher/eventsub/twitch_event_listener.gd new file mode 100644 index 0000000..d7d8f13 --- /dev/null +++ b/addons/twitcher/eventsub/twitch_event_listener.gd @@ -0,0 +1,72 @@ +@tool +@icon("../assets/event-icon.svg") +extends Twitcher + +## Listens to an event and publishes it as signal. +## Usage for easy access of events on test and normal eventsub makes it more obvious what a scene +## is listening before diving in the code. + +## [b]Expects that the signal was already configured in the eventsub or manually subscribed[/b] +class_name TwitchEventListener +static var _log : TwitchLogger = TwitchLogger.new("TwitchEventListener") + +@export var eventsub: TwitchEventsub: + set = _update_eventsub + +@export var subscription: TwitchEventsubDefinition.Type: + set(val): + subscription = val + subscription_definition = TwitchEventsubDefinition.ALL[subscription] + update_configuration_warnings() + +var subscription_definition: TwitchEventsubDefinition + + +## Called when the event got received +signal received(data: Dictionary) + + +func _ready() -> void: + _update_eventsub(eventsub) + + +func _enter_tree() -> void: + start_listening() + + +func _exit_tree() -> void: + stop_listening() + + +func start_listening() -> void: + _log.d("start listening %s" % subscription_definition.get_readable_name()) + if eventsub != null && not eventsub.event.is_connected(_on_received): + eventsub.event.connect(_on_received) + + +func stop_listening() -> void: + _log.d("stop listening %s" % subscription_definition.get_readable_name()) + if eventsub != null && eventsub.event.is_connected(_on_received): + eventsub.event.disconnect(_on_received) + + +func _update_eventsub(val: TwitchEventsub): + stop_listening() + eventsub = val + update_configuration_warnings() + if val == null: return + start_listening() + + +func _on_received(type: String, data: Dictionary): + if type == subscription_definition.value: + received.emit(data) + + +func _get_configuration_warnings() -> PackedStringArray: + var result: PackedStringArray = [] + if eventsub == null: + result.append("'EventSub' is missing") + if subscription == null: + result.append("'Subscription' is missing") + return result diff --git a/addons/twitcher/eventsub/twitch_event_listener.gd.uid b/addons/twitcher/eventsub/twitch_event_listener.gd.uid new file mode 100644 index 0000000..d21a97d --- /dev/null +++ b/addons/twitcher/eventsub/twitch_event_listener.gd.uid @@ -0,0 +1 @@ +uid://bol5ltrjr6ux8 diff --git a/addons/twitcher/eventsub/twitch_eventsub.gd b/addons/twitcher/eventsub/twitch_eventsub.gd new file mode 100644 index 0000000..0d1cc63 --- /dev/null +++ b/addons/twitcher/eventsub/twitch_eventsub.gd @@ -0,0 +1,379 @@ +@icon("res://addons/twitcher/assets/eventsub-icon.svg") +@tool +extends Twitcher + +## Handles the evensub part of twitch. Returns the event data when receives it. +class_name TwitchEventsub + +static var _log: TwitchLogger = TwitchLogger.new("TwitchEventsub") + +static var instance: TwitchEventsub + +## An object that identifies the message. +class Metadata extends RefCounted: + ## An ID that uniquely identifies the message. Twitch sends messages at least once, but if Twitch is unsure of whether you received a notification, it’ll resend the message. This means you may receive a notification twice. If Twitch resends the message, the message ID is the same. + var message_id: String + ## The type of message, which is set to session_keepalive. + var message_type: String + ## The UTC date and time that the message was sent. + var message_timestamp: String + + func _init(d: Dictionary): + message_id = d['message_id'] + message_type = d['message_type'] + message_timestamp = d['message_timestamp'] + + +## An object that contains information about the connection. +class Session extends RefCounted: + ## An ID that uniquely identifies this WebSocket connection. Use this ID to set the session_id field in all subscription requests. + var id: String + ## The connection’s status, which is set to connected. + var status: String + ## The maximum number of seconds that you should expect silence before receiving a keepalive message. For a welcome message, this is the number of seconds that you have to subscribe to an event after receiving the welcome message. If you don’t subscribe to an event within this window, the socket is disconnected. + var keepalive_timeout_seconds: int + ## The URL to reconnect to if you get a Reconnect message. Is set to null. + var reconnect_url: String + ## The UTC date and time that the connection was created. + var connected_at: String + + func _init(d: Dictionary): + id = d["id"] + status = d["status"] + var timeout = d["keepalive_timeout_seconds"] + keepalive_timeout_seconds = timeout if timeout != null else 30 + if d["reconnect_url"] != null: + reconnect_url = d["reconnect_url"] + connected_at = d["connected_at"] + +## A specific event received from eventsub +class Event extends RefCounted: + var type: TwitchEventsubDefinition: + get(): return TwitchEventsubDefinition.BY_NAME[message.payload.subscription.type] + var data: Dictionary: + get(): return message.payload.event + var message: TwitchNotificationMessage + + func _init(notification_message: TwitchNotificationMessage) -> void: + message = notification_message + + +## Will be send as soon as the websocket connection is up and running you can use it to subscribe to events +signal session_id_received(id: String) + +## Will be called when an event is sent from Twitch. +signal event(type: StringName, data: Dictionary) + +## Will be called when an event is sent from Twitch. Same like event signal but better named and easier to use in inline awaits. +signal event_received(event: Event) + +## Will be called when an event got revoked from your subscription by Twitch. +signal events_revoked(type: StringName, status: String) + +## Called when any eventsub message is received for low level access +signal message_received(message: Variant) + + +@export var api: TwitchAPI +@export var _subscriptions: Array[TwitchEventsubConfig] = [] +@export var scopes: OAuthScopes +@export var eventsub_live_server_url: String = "wss://eventsub.wss.twitch.tv/ws" +@export var eventsub_test_server_url: String = "ws://127.0.0.1:8080/ws" +@export var use_test_server: bool +@export var ignore_message_eventsub_in_seconds: int = 600 + +var _client: WebsocketClient = WebsocketClient.new() +var _test_client : WebsocketClient = WebsocketClient.new() +## Swap over client in case Twitch sends us the message for a new server. +## See: https://dev.twitch.tv/docs/eventsub/handling-websocket-events/#reconnect-message +var _swap_over_client : WebsocketClient + +var session: Session +## Holds the messages that was processed already. +## Key: MessageID Value: Timestamp +var eventsub_messages: Dictionary = {} +var last_keepalive: int +var is_open: bool: + get(): return _client.is_open +var _should_connect: bool + +## When the Websocket server is shutting down and the client is doing a +## gracefull handover +var _swap_over_process: bool + +## queues the actions that should be executed when the connection is established +var _action_stack: Array[SubscriptionAction] +var _executing_action_stack: bool +## Increased on every reconnect without subscriptions +var _empty_connections: int + +## Determines the action that the subscription should do +class SubscriptionAction extends RefCounted: + var subscribe: bool + var subscription: TwitchEventsubConfig + + func _to_string() -> String: + return "%s %s" % [("Subscribe to" if subscribe else "Unsubscribe from"), subscription.definition.get_readable_name()] + + +func _init() -> void: + _client.connection_url = eventsub_live_server_url + _client.message_received.connect(_data_received) + _client.connection_established.connect(_on_connection_established) + _client.connection_closed.connect(_on_connection_closed) + _test_client.connection_url = eventsub_test_server_url + _test_client.message_received.connect(_data_received) + + +func _ready() -> void: + _client.name = "Websocket Client" + add_child(_client) + if use_test_server: + _test_client.name = "Websocket Client Test" + add_child(_test_client) + if api == null: api = TwitchAPI.instance + + +func _enter_tree() -> void: + if instance == null: instance = self + + +func _exit_tree() -> void: + if instance == self: instance = null + + +## Propergated call from twitch service +func do_setup() -> void: + await open_connection() + _log.i("Eventsub setup") + + +func wait_setup() -> void: + await wait_for_session_established() + + +## Waits until the eventsub is fully established +func wait_for_session_established() -> void: + if session == null: await session_id_received + + +func _on_connection_established() -> void: + if not _swap_over_process: + _action_stack.clear() + if _subscriptions.is_empty(): _empty_connections += 1 + if _empty_connections >= 3: + _empty_connections = 0 + _log.e("Stopped eventsub cause of no subscription.") + close_connection() + return + + # Resubscribe + _log.i("Connection established -> resubscribe to: [%s]" % [_subscriptions]) + for sub in _subscriptions: _add_action(sub, true) + _execute_action_stack() + + +func _on_connection_closed() -> void: + session = null + + +func open_connection() -> void: + if _client.is_closed: + _client.open_connection() + if _test_client.is_closed && use_test_server: + _test_client.open_connection() + + +func close_connection() -> void: + if not _client.is_closed: + _client.close() + if not _test_client.is_closed: + _test_client.close() + + +## Add a new subscription +func subscribe(eventsub_config: TwitchEventsubConfig) -> void: + _log.i("Subscribe to %s" % eventsub_config.definition.get_readable_name()) + _subscriptions.append(eventsub_config) + _add_action(eventsub_config, true) + _empty_connections = 0 + + +func has_subscription(eventsub_definition: TwitchEventsubDefinition, condition: Dictionary) -> bool: + for subscription: TwitchEventsubConfig in _subscriptions: + if subscription.definition == eventsub_definition && subscription.condition == condition: + return true + return false + + +## Remove a subscription +func unsubscribe(eventsub_config: TwitchEventsubConfig) -> void: + _subscriptions.erase(eventsub_config) + _add_action(eventsub_config, false) + + +## Process the queue of actions until its empty +func _execute_action_stack() -> void: + if _executing_action_stack: return + await wait_for_session_established() + _log.d("Execute actions [%s]" % [_action_stack]) + _executing_action_stack = true + while not _action_stack.is_empty(): + var action = _action_stack.pop_back() + var sub: TwitchEventsubConfig = action.subscription + if action.subscribe: + _subscribe(sub) + else: + _unsubscribe(sub) + _executing_action_stack = false + + +## Adds a subscribe or unsubscribe action to the queue +func _add_action(sub: TwitchEventsubConfig, subscribe: bool) -> void: + var sub_action = SubscriptionAction.new() + sub_action.subscription = sub + sub_action.subscribe = subscribe + _action_stack.append(sub_action) + _log.d("Add subscribe action: %s" % sub.definition.get_readable_name()) + _execute_action_stack() + + +## Refer to https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/ +## for details on which API versions are available and which conditions are required. +func _subscribe(subscription: TwitchEventsubConfig) -> String: + var event_name = subscription.definition.value + var version = subscription.definition.version + var conditions = subscription.condition + + var data : TwitchCreateEventSubSubscription.Body = TwitchCreateEventSubSubscription.Body.new() + var transport : TwitchCreateEventSubSubscription.BodyTransport = TwitchCreateEventSubSubscription.BodyTransport.new() + data.type = event_name + data.version = version + data.condition = conditions + data.transport = transport + transport.method = "websocket" + transport.session_id = session.id + + _log.d("Do subscribe: %s" % event_name) + + var eventsub_response = await api.create_eventsub_subscription(data) + + if eventsub_response.response.response_code == 401: + _log.e("Subscription failed for '%s': Missing authentication for eventsub. The token got not authenticated yet. Please login!" % data.type) + _client.close(3000, "Missing Authentication") + return "" + elif eventsub_response.response.response_code == 403: + _log.e("Subscription failed for '%s': The token is missing proper scopes. [url='%s']Please check documentation[/url]!" % [data.type, subscription.definition.documentation_link]) + _log.d(eventsub_response.response.response_data.get_string_from_utf8()) + _client.close(3003, "Missing Authorization") + return "" + if eventsub_response.response.response_code < 200 || eventsub_response.response.response_code >= 300: + _log.e("Subscription failed for '%s'. Unknown error %s: %s" % [data.type, eventsub_response.response.response_code, eventsub_response.response.response_data.get_string_from_utf8()]) + return "" + elif (eventsub_response.response.response_data.is_empty()): + return "" + _log.i("Now listening to '%s' events." % data.type) + + var result = JSON.parse_string(eventsub_response.response.response_data.get_string_from_utf8()) + return result.data[0].id + + +## Unsubscribes from an eventsub in case of an error returns false +func _unsubscribe(subscription: TwitchEventsubConfig) -> bool: + var response = await api.delete_eventsub_subscription(subscription.id) + return response.error || response.response_code != 200 + + +func _data_received(data : PackedByteArray) -> void: + var message_str : String = data.get_string_from_utf8() + var message_json : Dictionary = JSON.parse_string(message_str) + if not message_json.has("metadata"): + _log.e("Twitch send something undocumented: %s" % message_str) + return + var metadata : Metadata = Metadata.new(message_json["metadata"]) + var id = metadata.message_id + var timestamp_str = metadata.message_timestamp + var timestamp = Time.get_unix_time_from_datetime_string(timestamp_str) + + if(_message_got_processed(id) || _message_is_to_old(timestamp)): + return + + eventsub_messages[id] = timestamp + last_keepalive = Time.get_ticks_msec() + + match metadata.message_type: + "session_welcome": + var welcome_message = TwitchWelcomeMessage.new(message_json) + session = welcome_message.payload.session + session_id_received.emit(session.id) + _log.i("Session established %s" % session.id) + message_received.emit(welcome_message) + "session_keepalive": + # Notification from server that the connection is still alive + var keep_alive_message = TwitchKeepaliveMessage.new(message_json) + message_received.emit(keep_alive_message) + pass + "session_reconnect": + var reconnect_message = TwitchReconnectMessage.new(message_json) + message_received.emit(reconnect_message) + _handle_reconnect(reconnect_message) + "revocation": + var revocation_message = TwitchRevocationMessage.new(message_json) + message_received.emit(revocation_message) + events_revoked.emit(revocation_message.payload.subscription.type, + revocation_message.payload.subscription.status) + "notification": + var notification_message = TwitchNotificationMessage.new(message_json) + message_received.emit(notification_message) + event.emit(notification_message.payload.subscription.type, + notification_message.payload.event) + event_received.emit(Event.new(notification_message)) + _cleanup() + + +func _handle_reconnect(reconnect_message: TwitchReconnectMessage): + _log.i("Session is forced to reconnect") + _swap_over_process = true + var reconnect_url = reconnect_message.payload.session.reconnect_url + _swap_over_client = WebsocketClient.new() + _swap_over_client.message_received.connect(_data_received) + _swap_over_client.connection_established.connect(_on_connection_established) + _swap_over_client.connection_url = reconnect_url + add_child(_swap_over_client) + _swap_over_client.open_connection() + await session_id_received + _client.close(1000, "Closed cause of reconnect.") + remove_child(_client) + _client = _swap_over_client + _swap_over_client = null + _swap_over_process = false + _log.i("Session reconnected on %s" % reconnect_url) + + +## Cleanup old messages that won't be processed anymore cause of time to prevent a +## memory problem on long runinng applications. +func _cleanup() -> void: + for message_id in eventsub_messages.keys(): + var timestamp = eventsub_messages[message_id] + if _message_is_to_old(timestamp): + eventsub_messages.erase(message_id) + + +func _message_got_processed(message_id: String) -> bool: + return eventsub_messages.has(message_id) + + +func _message_is_to_old(timestamp: int) -> bool: + return timestamp < Time.get_unix_time_from_system() - ignore_message_eventsub_in_seconds + + +func get_client() -> WebsocketClient: + return _client + + +func get_test_client() -> WebsocketClient: + return _test_client + +## Returns a copy of the current subscribed events. Don't modify the result they won't get applied anyway. +func get_subscriptions() -> Array[TwitchEventsubConfig]: + return _subscriptions.duplicate() diff --git a/addons/twitcher/eventsub/twitch_eventsub.gd.uid b/addons/twitcher/eventsub/twitch_eventsub.gd.uid new file mode 100644 index 0000000..90a3a5d --- /dev/null +++ b/addons/twitcher/eventsub/twitch_eventsub.gd.uid @@ -0,0 +1 @@ +uid://blmhj3j00yk45 diff --git a/addons/twitcher/eventsub/twitch_eventsub_config.gd b/addons/twitcher/eventsub/twitch_eventsub_config.gd new file mode 100644 index 0000000..10baca2 --- /dev/null +++ b/addons/twitcher/eventsub/twitch_eventsub_config.gd @@ -0,0 +1,47 @@ +@tool +extends Resource + +## Defines howto subscribe to a eventsub subscription. +class_name TwitchEventsubConfig +static var _log: TwitchLogger = TwitchLogger.new("TwitchEventsubConfig") + +## What do you want to subscribe +@export var type: TwitchEventsubDefinition.Type: + set = _update_type + +## How do you want to subscribe defined by `definition conditions`. +@export var condition: Dictionary = {} + +var definition: TwitchEventsubDefinition: + get(): return TwitchEventsubDefinition.ALL[type] + +## Send from the server to identify the subscription for unsubscribing +var id: String + +## Called when type changed +signal type_changed(new_type: TwitchEventsubDefinition.Type) + + +static func create(definition: TwitchEventsubDefinition, conditions: Dictionary) -> TwitchEventsubConfig: + var config = TwitchEventsubConfig.new() + config.type = definition.type + config.condition = conditions + for condition_name: StringName in definition.conditions: + if not conditions.has(condition_name): + _log.w("You miss probably following condition %s" % condition_name) + return config + + +func _update_type(val: TwitchEventsubDefinition.Type) -> void: + if type != val: + type = val + var definition: TwitchEventsubDefinition = TwitchEventsubDefinition.ALL[type] + var new_condition: Dictionary = {} + for condition_key: StringName in definition.conditions: + new_condition[condition_key] = condition.get(condition_key, "") + condition = new_condition + type_changed.emit(val) + + +func _to_string() -> String: + return "%s" % definition.get_readable_name() diff --git a/addons/twitcher/eventsub/twitch_eventsub_config.gd.uid b/addons/twitcher/eventsub/twitch_eventsub_config.gd.uid new file mode 100644 index 0000000..e669124 --- /dev/null +++ b/addons/twitcher/eventsub/twitch_eventsub_config.gd.uid @@ -0,0 +1 @@ +uid://cjug64e3433g0 diff --git a/addons/twitcher/eventsub/twitch_eventsub_definition.gd b/addons/twitcher/eventsub/twitch_eventsub_definition.gd new file mode 100644 index 0000000..f8a7926 --- /dev/null +++ b/addons/twitcher/eventsub/twitch_eventsub_definition.gd @@ -0,0 +1,357 @@ +@tool +extends Object + +class_name TwitchEventsubDefinition + +## All supported subscriptions should be used in comination with get_all method as index. +enum Type { + AUTOMOD_MESSAGE_HOLD, + AUTOMOD_MESSAGE_UPDATE, + AUTOMOD_SETTINGS_UPDATE, + AUTOMOD_TERMS_UPDATE, + CHANNEL_UPDATE, + CHANNEL_FOLLOW, + CHANNEL_AD_BREAK_BEGIN, + CHANNEL_CHAT_CLEAR, + CHANNEL_CHAT_CLEAR_USER_MESSAGES, + CHANNEL_CHAT_MESSAGE, + CHANNEL_CHAT_MESSAGE_DELETE, + CHANNEL_CHAT_NOTIFICATION, + CHANNEL_CHAT_SETTINGS_UPDATE, + CHANNEL_CHAT_USER_MESSAGE_HOLD, + CHANNEL_CHAT_USER_MESSAGE_UPDATE, + CHANNEL_SUBSCRIBE, + CHANNEL_SUBSCRIPTION_END, + CHANNEL_SUBSCRIPTION_GIFT, + CHANNEL_SUBSCRIPTION_MESSAGE, + CHANNEL_CHEER, + CHANNEL_RAID, + CHANNEL_BAN, + CHANNEL_UNBAN, + CHANNEL_UNBAN_REQUEST_CREATE, + CHANNEL_UNBAN_REQUEST_RESOLVE, + CHANNEL_MODERATE, + CHANNEL_MODERATE_V2, + CHANNEL_MODERATOR_ADD, + CHANNEL_MODERATOR_REMOVE, + CHANNEL_GUEST_STAR_SESSION_BEGIN, + CHANNEL_GUEST_STAR_SESSION_END, + CHANNEL_GUEST_STAR_GUEST_UPDATE, + CHANNEL_GUEST_STAR_SETTINGS_UPDATE, + CHANNEL_CHANNEL_POINTS_AUTOMATIC_REWARD_REDEMPTION_ADD, + CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_ADD, + CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_UPDATE, + CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REMOVE, + CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REDEMPTION_ADD, + CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REDEMPTION_UPDATE, + CHANNEL_POLL_BEGIN, + CHANNEL_POLL_PROGRESS, + CHANNEL_POLL_END, + CHANNEL_PREDICTION_BEGIN, + CHANNEL_PREDICTION_PROGRESS, + CHANNEL_PREDICTION_LOCK, + CHANNEL_PREDICTION_END, + CHANNEL_SUSPICIOUS_USER_UPDATE, + CHANNEL_SUSPICIOUS_USER_MESSAGE, + CHANNEL_VIP_ADD, + CHANNEL_VIP_REMOVE, + CHANNEL_WARNING_ACKNOWLEDGE, + CHANNEL_WARNING_SEND, + CHANNEL_HYPE_TRAIN_BEGIN, + CHANNEL_HYPE_TRAIN_PROGRESS, + CHANNEL_HYPE_TRAIN_END, + CHANNEL_CHARITY_CAMPAIGN_DONATE, + CHANNEL_CHARITY_CAMPAIGN_START, + CHANNEL_CHARITY_CAMPAIGN_PROGRESS, + CHANNEL_CHARITY_CAMPAIGN_STOP, + CHANNEL_SHARED_CHAT_BEGIN, + CHANNEL_SHARED_CHAT_UPDATE, + CHANNEL_SHARED_CHAT_END, + CHANNEL_SHIELD_MODE_BEGIN, + CHANNEL_SHIELD_MODE_END, + CHANNEL_SHOUTOUT_CREATE, + CHANNEL_SHOUTOUT_RECEIVE, + CONDUIT_SHARD_DISABLED, + DROP_ENTITLEMENT_GRANT, + EXTENSION_BITS_TRANSACTION_CREATE, + CHANNEL_GOAL_BEGIN, + CHANNEL_GOAL_PROGRESS, + CHANNEL_GOAL_END, + STREAM_ONLINE, + STREAM_OFFLINE, + USER_AUTHORIZATION_GRANT, + USER_AUTHORIZATION_REVOKE, + USER_UPDATE, + USER_WHISPER_MESSAGE, +} + +## The type of itself +var type: Type +## Name within Twitch +var value: StringName +## Version defined in Twitch +var version: StringName +## Keys of the conditions it need for setup +var conditions: Array[StringName] +## Possible scopes it needs (on some of them its more then needed) +var scopes: Array[StringName] +## Link to the twitch documentation +var documentation_link: String + + +func _init(typ: Type, val: StringName, ver: StringName, cond: Array[StringName], scps: Array[StringName], doc_link: String): + type = typ + value = val + version = ver + conditions = cond + scopes = scps + documentation_link = doc_link + +## Get a human readable name of it +func get_readable_name() -> String: + return "%s (v%s)" % [value, version] + + +static var AUTOMOD_MESSAGE_HOLD := TwitchEventsubDefinition.new(Type.AUTOMOD_MESSAGE_HOLD, &"automod.message.hold", &"1", [&"broadcaster_user_id",&"moderator_user_id"], [&"moderator:manage:automod"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#automodmessagehold") +static var AUTOMOD_MESSAGE_UPDATE := TwitchEventsubDefinition.new(Type.AUTOMOD_MESSAGE_UPDATE, &"automod.message.update", &"1", [&"broadcaster_user_id",&"moderator_user_id"], [&"moderator:manage:automod"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#automodmessageupdate") +static var AUTOMOD_SETTINGS_UPDATE := TwitchEventsubDefinition.new(Type.AUTOMOD_SETTINGS_UPDATE, &"automod.settings.update", &"1", [&"broadcaster_user_id",&"moderator_user_id"], [&"moderator:read:automod_settings"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#automodsettingsupdate") +static var AUTOMOD_TERMS_UPDATE := TwitchEventsubDefinition.new(Type.AUTOMOD_TERMS_UPDATE, &"automod.terms.update", &"1", [&"broadcaster_user_id",&"moderator_user_id"], [&"moderator:manage:automod"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#automodtermsupdate") +static var CHANNEL_UPDATE := TwitchEventsubDefinition.new(Type.CHANNEL_UPDATE, &"channel.update", &"2", [&"broadcaster_user_id"], [], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelupdate") +static var CHANNEL_FOLLOW := TwitchEventsubDefinition.new(Type.CHANNEL_FOLLOW, &"channel.follow", &"2", [&"broadcaster_user_id",&"moderator_user_id"], [&"moderator:read:followers"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelfollow") +static var CHANNEL_AD_BREAK_BEGIN := TwitchEventsubDefinition.new(Type.CHANNEL_AD_BREAK_BEGIN, &"channel.ad_break.begin", &"1", [&"broadcaster_user_id"], [&"channel:read:ads"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelad_breakbegin") +static var CHANNEL_CHAT_CLEAR := TwitchEventsubDefinition.new(Type.CHANNEL_CHAT_CLEAR, &"channel.chat.clear", &"1", [&"broadcaster_user_id",&"user_id"], [&"channel:bot",&"user:bot",&"user:read:chat"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelchatclear") +static var CHANNEL_CHAT_CLEAR_USER_MESSAGES := TwitchEventsubDefinition.new(Type.CHANNEL_CHAT_CLEAR_USER_MESSAGES, &"channel.chat.clear_user_messages", &"1", [&"broadcaster_user_id",&"user_id"], [&"channel:bot",&"user:bot",&"user:read:chat"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelchatclear_user_messages") +static var CHANNEL_CHAT_MESSAGE := TwitchEventsubDefinition.new(Type.CHANNEL_CHAT_MESSAGE, &"channel.chat.message", &"1", [&"broadcaster_user_id",&"user_id"], [&"channel:bot",&"user:bot",&"user:read:chat"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelchatmessage") +static var CHANNEL_CHAT_MESSAGE_DELETE := TwitchEventsubDefinition.new(Type.CHANNEL_CHAT_MESSAGE_DELETE, &"channel.chat.message_delete", &"1", [&"broadcaster_user_id",&"user_id"], [&"channel:bot",&"user:bot",&"user:read:chat"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelchatmessage_delete") +static var CHANNEL_CHAT_NOTIFICATION := TwitchEventsubDefinition.new(Type.CHANNEL_CHAT_NOTIFICATION, &"channel.chat.notification", &"1", [&"broadcaster_user_id",&"user_id"], [&"channel:bot",&"user:bot",&"user:read:chat"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelchatnotification") +static var CHANNEL_CHAT_SETTINGS_UPDATE := TwitchEventsubDefinition.new(Type.CHANNEL_CHAT_SETTINGS_UPDATE, &"channel.chat_settings.update", &"1", [&"broadcaster_user_id",&"user_id"], [&"channel:bot",&"user:bot",&"user:read:chat"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelchat_settingsupdate") +static var CHANNEL_CHAT_USER_MESSAGE_HOLD := TwitchEventsubDefinition.new(Type.CHANNEL_CHAT_USER_MESSAGE_HOLD, &"channel.chat.user_message_hold", &"1", [&"broadcaster_user_id",&"user_id"], [&"user:bot",&"user:read:chat"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelchatuser_message_hold") +static var CHANNEL_CHAT_USER_MESSAGE_UPDATE := TwitchEventsubDefinition.new(Type.CHANNEL_CHAT_USER_MESSAGE_UPDATE, &"channel.chat.user_message_update", &"1", [&"broadcaster_user_id",&"user_id"], [&"user:bot",&"user:read:chat"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelchatuser_message_update") +static var CHANNEL_SUBSCRIBE := TwitchEventsubDefinition.new(Type.CHANNEL_SUBSCRIBE, &"channel.subscribe", &"1", [&"broadcaster_user_id"], [&"channel:read:subscriptions"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelsubscribe") +static var CHANNEL_SUBSCRIPTION_END := TwitchEventsubDefinition.new(Type.CHANNEL_SUBSCRIPTION_END, &"channel.subscription.end", &"1", [&"broadcaster_user_id"], [&"channel:read:subscriptions"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelsubscriptionend") +static var CHANNEL_SUBSCRIPTION_GIFT := TwitchEventsubDefinition.new(Type.CHANNEL_SUBSCRIPTION_GIFT, &"channel.subscription.gift", &"1", [&"broadcaster_user_id"], [&"channel:read:subscriptions"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelsubscriptiongift") +static var CHANNEL_SUBSCRIPTION_MESSAGE := TwitchEventsubDefinition.new(Type.CHANNEL_SUBSCRIPTION_MESSAGE, &"channel.subscription.message", &"1", [&"broadcaster_user_id"], [&"channel:read:subscriptions"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelsubscriptionmessage") +static var CHANNEL_CHEER := TwitchEventsubDefinition.new(Type.CHANNEL_CHEER, &"channel.cheer", &"1", [&"broadcaster_user_id"], [&"bits:read"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelcheer") +static var CHANNEL_RAID := TwitchEventsubDefinition.new(Type.CHANNEL_RAID, &"channel.raid", &"1", [&"to_broadcaster_user_id"], [], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelraid") +static var CHANNEL_BAN := TwitchEventsubDefinition.new(Type.CHANNEL_BAN, &"channel.ban", &"1", [&"broadcaster_user_id"], [&"channel:moderate"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelban") +static var CHANNEL_UNBAN := TwitchEventsubDefinition.new(Type.CHANNEL_UNBAN, &"channel.unban", &"1", [&"broadcaster_user_id"], [&"channel:moderate"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelunban") +static var CHANNEL_UNBAN_REQUEST_CREATE := TwitchEventsubDefinition.new(Type.CHANNEL_UNBAN_REQUEST_CREATE, &"channel.unban_request.create", &"1", [&"broadcaster_user_id",&"moderator_user_id"], [&"moderator:read:unban_requests",&"moderator:manage:unban_requests"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelunban_requestcreate") +static var CHANNEL_UNBAN_REQUEST_RESOLVE := TwitchEventsubDefinition.new(Type.CHANNEL_UNBAN_REQUEST_RESOLVE, &"channel.unban_request.resolve", &"1", [&"broadcaster_user_id",&"moderator_user_id"], [&"moderator:read:unban_requests",&"moderator:manage:unban_requests"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelunban_requestresolve") +static var CHANNEL_MODERATE := TwitchEventsubDefinition.new(Type.CHANNEL_MODERATE, &"channel.moderate", &"1", [&"broadcaster_user_id",&"moderator_user_id"], [&"moderator:manage:banned_users",&"moderator:manage:blocked_terms",&"moderator:read:banned_users",&"moderator:manage:chat_messages",&"moderator:manage:unban_requests",&"moderator:manage:chat_settings",&"moderator:read:unban_requests",&"moderator:read:chat_settings",&"moderator:read:vips",&"moderator:read:chat_messages",&"moderator:read:blocked_terms",&"moderator:read:moderators"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelmoderate") +static var CHANNEL_MODERATE_V2 := TwitchEventsubDefinition.new(Type.CHANNEL_MODERATE_V2, &"channel.moderate", &"2", [&"broadcaster_user_id",&"moderator_user_id"], [&"moderator:manage:banned_users",&"moderator:manage:blocked_terms",&"moderator:read:banned_users",&"moderator:manage:chat_messages",&"moderator:manage:unban_requests",&"moderator:manage:warnings",&"moderator:manage:chat_settings",&"moderator:read:unban_requests",&"moderator:read:chat_settings",&"moderator:read:vips",&"moderator:read:warnings",&"moderator:read:chat_messages",&"moderator:read:blocked_terms",&"moderator:read:moderators"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelmoderate-v2") +static var CHANNEL_MODERATOR_ADD := TwitchEventsubDefinition.new(Type.CHANNEL_MODERATOR_ADD, &"channel.moderator.add", &"1", [&"broadcaster_user_id"], [&"moderation:read"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelmoderatoradd") +static var CHANNEL_MODERATOR_REMOVE := TwitchEventsubDefinition.new(Type.CHANNEL_MODERATOR_REMOVE, &"channel.moderator.remove", &"1", [&"broadcaster_user_id"], [&"moderation:read"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelmoderatorremove") +static var CHANNEL_GUEST_STAR_SESSION_BEGIN := TwitchEventsubDefinition.new(Type.CHANNEL_GUEST_STAR_SESSION_BEGIN, &"channel.guest_star_session.begin", &"beta", [&"broadcaster_user_id",&"moderator_user_id"], [&"channel:read:guest_star",&"moderator:manage:guest_star",&"moderator:read:guest_star",&"channel:manage:guest_star"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelguest_star_sessionbegin") +static var CHANNEL_GUEST_STAR_SESSION_END := TwitchEventsubDefinition.new(Type.CHANNEL_GUEST_STAR_SESSION_END, &"channel.guest_star_session.end", &"beta", [&"broadcaster_user_id",&"moderator_user_id"], [&"channel:read:guest_star",&"moderator:manage:guest_star",&"moderator:read:guest_star",&"channel:manage:guest_star"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelguest_star_sessionend") +static var CHANNEL_GUEST_STAR_GUEST_UPDATE := TwitchEventsubDefinition.new(Type.CHANNEL_GUEST_STAR_GUEST_UPDATE, &"channel.guest_star_guest.update", &"beta", [&"broadcaster_user_id",&"moderator_user_id"], [&"channel:read:guest_star",&"moderator:manage:guest_star",&"moderator:read:guest_star",&"channel:manage:guest_star"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelguest_star_guestupdate") +static var CHANNEL_GUEST_STAR_SETTINGS_UPDATE := TwitchEventsubDefinition.new(Type.CHANNEL_GUEST_STAR_SETTINGS_UPDATE, &"channel.guest_star_settings.update", &"beta", [&"broadcaster_user_id",&"moderator_user_id"], [&"channel:read:guest_star",&"moderator:manage:guest_star",&"moderator:read:guest_star",&"channel:manage:guest_star"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelguest_star_settingsupdate") +static var CHANNEL_CHANNEL_POINTS_AUTOMATIC_REWARD_REDEMPTION_ADD := TwitchEventsubDefinition.new(Type.CHANNEL_CHANNEL_POINTS_AUTOMATIC_REWARD_REDEMPTION_ADD, &"channel.channel_points_automatic_reward_redemption.add", &"1", [&"broadcaster_user_id"], [&"channel:read:redemptions",&"channel:manage:redemptions"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelchannel_points_automatic_reward_redemptionadd") +static var CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_ADD := TwitchEventsubDefinition.new(Type.CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_ADD, &"channel.channel_points_custom_reward.add", &"1", [&"broadcaster_user_id"], [&"channel:read:redemptions",&"channel:manage:redemptions"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelchannel_points_custom_rewardadd") +static var CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_UPDATE := TwitchEventsubDefinition.new(Type.CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_UPDATE, &"channel.channel_points_custom_reward.update", &"1", [&"broadcaster_user_id",&"reward_id"], [&"channel:read:redemptions",&"channel:manage:redemptions"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelchannel_points_custom_rewardupdate") +static var CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REMOVE := TwitchEventsubDefinition.new(Type.CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REMOVE, &"channel.channel_points_custom_reward.remove", &"1", [&"broadcaster_user_id",&"reward_id"], [&"channel:read:redemptions",&"channel:manage:redemptions"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelchannel_points_custom_rewardremove") +static var CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REDEMPTION_ADD := TwitchEventsubDefinition.new(Type.CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REDEMPTION_ADD, &"channel.channel_points_custom_reward_redemption.add", &"1", [&"broadcaster_user_id",&"reward_id"], [&"channel:read:redemptions",&"channel:manage:redemptions"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelchannel_points_custom_reward_redemptionadd") +static var CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REDEMPTION_UPDATE := TwitchEventsubDefinition.new(Type.CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REDEMPTION_UPDATE, &"channel.channel_points_custom_reward_redemption.update", &"1", [&"broadcaster_user_id",&"reward_id"], [&"channel:read:redemptions",&"channel:manage:redemptions"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelchannel_points_custom_reward_redemptionupdate") +static var CHANNEL_POLL_BEGIN := TwitchEventsubDefinition.new(Type.CHANNEL_POLL_BEGIN, &"channel.poll.begin", &"1", [&"broadcaster_user_id"], [&"channel:manage:polls",&"channel:read:polls"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelpollbegin") +static var CHANNEL_POLL_PROGRESS := TwitchEventsubDefinition.new(Type.CHANNEL_POLL_PROGRESS, &"channel.poll.progress", &"1", [&"broadcaster_user_id"], [&"channel:manage:polls",&"channel:read:polls"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelpollprogress") +static var CHANNEL_POLL_END := TwitchEventsubDefinition.new(Type.CHANNEL_POLL_END, &"channel.poll.end", &"1", [&"broadcaster_user_id"], [&"channel:manage:polls",&"channel:read:polls"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelpollend") +static var CHANNEL_PREDICTION_BEGIN := TwitchEventsubDefinition.new(Type.CHANNEL_PREDICTION_BEGIN, &"channel.prediction.begin", &"1", [&"broadcaster_user_id"], [&"channel:manage:predictions",&"channel:read:predictions"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelpredictionbegin") +static var CHANNEL_PREDICTION_PROGRESS := TwitchEventsubDefinition.new(Type.CHANNEL_PREDICTION_PROGRESS, &"channel.prediction.progress", &"1", [&"broadcaster_user_id"], [&"channel:manage:predictions",&"channel:read:predictions"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelpredictionprogress") +static var CHANNEL_PREDICTION_LOCK := TwitchEventsubDefinition.new(Type.CHANNEL_PREDICTION_LOCK, &"channel.prediction.lock", &"1", [&"broadcaster_user_id"], [&"channel:manage:predictions",&"channel:read:predictions"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelpredictionlock") +static var CHANNEL_PREDICTION_END := TwitchEventsubDefinition.new(Type.CHANNEL_PREDICTION_END, &"channel.prediction.end", &"1", [&"broadcaster_user_id"], [&"channel:manage:predictions",&"channel:read:predictions"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelpredictionend") +static var CHANNEL_SUSPICIOUS_USER_UPDATE := TwitchEventsubDefinition.new(Type.CHANNEL_SUSPICIOUS_USER_UPDATE, &"channel.suspicious_user.update", &"1", [&"broadcaster_user_id",&"moderator_user_id"], [&"moderator:read:suspicious_users"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelsuspicious_userupdate") +static var CHANNEL_SUSPICIOUS_USER_MESSAGE := TwitchEventsubDefinition.new(Type.CHANNEL_SUSPICIOUS_USER_MESSAGE, &"channel.suspicious_user.message", &"1", [&"moderator_user_id",&"broadcaster_user_id"], [&"moderator:read:suspicious_users"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelsuspicious_usermessage") +static var CHANNEL_VIP_ADD := TwitchEventsubDefinition.new(Type.CHANNEL_VIP_ADD, &"channel.vip.add", &"1", [&"broadcaster_user_id"], [&"channel:manage:vips",&"channel:read:vips"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelvipadd") +static var CHANNEL_VIP_REMOVE := TwitchEventsubDefinition.new(Type.CHANNEL_VIP_REMOVE, &"channel.vip.remove", &"1", [&"broadcaster_user_id"], [&"channel:manage:vips",&"channel:read:vips"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelvipremove") +static var CHANNEL_WARNING_ACKNOWLEDGE := TwitchEventsubDefinition.new(Type.CHANNEL_WARNING_ACKNOWLEDGE, &"channel.warning.acknowledge", &"1", [&"broadcaster_user_id",&"moderator_user_id"], [&"moderator:manage:warnings",&"moderator:read:warnings"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelwarningacknowledge") +static var CHANNEL_WARNING_SEND := TwitchEventsubDefinition.new(Type.CHANNEL_WARNING_SEND, &"channel.warning.send", &"1", [&"broadcaster_user_id",&"moderator_user_id"], [&"moderator:manage:warnings",&"moderator:read:warnings"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelwarningsend") +static var CHANNEL_HYPE_TRAIN_BEGIN := TwitchEventsubDefinition.new(Type.CHANNEL_HYPE_TRAIN_BEGIN, &"channel.hype_train.begin", &"1", [&"broadcaster_user_id"], [&"channel:read:hype_train"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelhype_trainbegin") +static var CHANNEL_HYPE_TRAIN_PROGRESS := TwitchEventsubDefinition.new(Type.CHANNEL_HYPE_TRAIN_PROGRESS, &"channel.hype_train.progress", &"1", [&"broadcaster_user_id"], [&"channel:read:hype_train"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelhype_trainprogress") +static var CHANNEL_HYPE_TRAIN_END := TwitchEventsubDefinition.new(Type.CHANNEL_HYPE_TRAIN_END, &"channel.hype_train.end", &"1", [&"broadcaster_user_id"], [&"channel:read:hype_train"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelhype_trainend") +static var CHANNEL_CHARITY_CAMPAIGN_DONATE := TwitchEventsubDefinition.new(Type.CHANNEL_CHARITY_CAMPAIGN_DONATE, &"channel.charity_campaign.donate", &"1", [&"broadcaster_user_id"], [&"channel:read:charity"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelcharity_campaigndonate") +static var CHANNEL_CHARITY_CAMPAIGN_START := TwitchEventsubDefinition.new(Type.CHANNEL_CHARITY_CAMPAIGN_START, &"channel.charity_campaign.start", &"1", [&"broadcaster_user_id"], [&"channel:read:charity"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelcharity_campaignstart") +static var CHANNEL_CHARITY_CAMPAIGN_PROGRESS := TwitchEventsubDefinition.new(Type.CHANNEL_CHARITY_CAMPAIGN_PROGRESS, &"channel.charity_campaign.progress", &"1", [&"broadcaster_user_id"], [&"channel:read:charity"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelcharity_campaignprogress") +static var CHANNEL_CHARITY_CAMPAIGN_STOP := TwitchEventsubDefinition.new(Type.CHANNEL_CHARITY_CAMPAIGN_STOP, &"channel.charity_campaign.stop", &"1", [&"broadcaster_user_id"], [&"channel:read:charity"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelcharity_campaignstop") +static var CHANNEL_SHARED_CHAT_BEGIN := TwitchEventsubDefinition.new(Type.CHANNEL_SHARED_CHAT_BEGIN, &"channel.shared_chat.begin", &"beta", [&"broadcaster_user_id"], [], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelshared_chatbegin") +static var CHANNEL_SHARED_CHAT_UPDATE := TwitchEventsubDefinition.new(Type.CHANNEL_SHARED_CHAT_UPDATE, &"channel.shared_chat.update", &"beta", [&"broadcaster_user_id"], [], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelshared_chatupdate") +static var CHANNEL_SHARED_CHAT_END := TwitchEventsubDefinition.new(Type.CHANNEL_SHARED_CHAT_END, &"channel.shared_chat.end", &"beta", [&"broadcaster_user_id"], [], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelshared_chatend") +static var CHANNEL_SHIELD_MODE_BEGIN := TwitchEventsubDefinition.new(Type.CHANNEL_SHIELD_MODE_BEGIN, &"channel.shield_mode.begin", &"1", [&"broadcaster_user_id",&"moderator_user_id"], [&"moderator:read:shield_mode",&"moderator:manage:shield_mode"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelshield_modebegin") +static var CHANNEL_SHIELD_MODE_END := TwitchEventsubDefinition.new(Type.CHANNEL_SHIELD_MODE_END, &"channel.shield_mode.end", &"1", [&"broadcaster_user_id",&"moderator_user_id"], [&"moderator:read:shield_mode",&"moderator:manage:shield_mode"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelshield_modeend") +static var CHANNEL_SHOUTOUT_CREATE := TwitchEventsubDefinition.new(Type.CHANNEL_SHOUTOUT_CREATE, &"channel.shoutout.create", &"1", [&"broadcaster_user_id",&"moderator_user_id"], [&"moderator:read:shoutouts",&"moderator:manage:shoutouts"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelshoutoutcreate") +static var CHANNEL_SHOUTOUT_RECEIVE := TwitchEventsubDefinition.new(Type.CHANNEL_SHOUTOUT_RECEIVE, &"channel.shoutout.receive", &"1", [&"broadcaster_user_id",&"moderator_user_id"], [&"moderator:read:shoutouts",&"moderator:manage:shoutouts"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelshoutoutreceive") +static var CONDUIT_SHARD_DISABLED := TwitchEventsubDefinition.new(Type.CONDUIT_SHARD_DISABLED, &"conduit.shard.disabled", &"1", [&"client_id"], [], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#conduitsharddisabled") +static var DROP_ENTITLEMENT_GRANT := TwitchEventsubDefinition.new(Type.DROP_ENTITLEMENT_GRANT, &"drop.entitlement.grant", &"1", [&"organization_id",&"category_id",&"campaign_id"], [], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#dropentitlementgrant") +static var EXTENSION_BITS_TRANSACTION_CREATE := TwitchEventsubDefinition.new(Type.EXTENSION_BITS_TRANSACTION_CREATE, &"extension.bits_transaction.create", &"1", [&"extension_client_id"], [], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#extensionbits_transactioncreate") +static var CHANNEL_GOAL_BEGIN := TwitchEventsubDefinition.new(Type.CHANNEL_GOAL_BEGIN, &"channel.goal.begin", &"1", [&"broadcaster_user_id"], [&"channel:read:goals"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelgoalbegin") +static var CHANNEL_GOAL_PROGRESS := TwitchEventsubDefinition.new(Type.CHANNEL_GOAL_PROGRESS, &"channel.goal.progress", &"1", [&"broadcaster_user_id"], [&"channel:read:goals"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelgoalprogress") +static var CHANNEL_GOAL_END := TwitchEventsubDefinition.new(Type.CHANNEL_GOAL_END, &"channel.goal.end", &"1", [&"broadcaster_user_id"], [&"channel:read:goals"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#channelgoalend") +static var STREAM_ONLINE := TwitchEventsubDefinition.new(Type.STREAM_ONLINE, &"stream.online", &"1", [&"broadcaster_user_id"], [], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#streamonline") +static var STREAM_OFFLINE := TwitchEventsubDefinition.new(Type.STREAM_OFFLINE, &"stream.offline", &"1", [&"broadcaster_user_id"], [], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#streamoffline") +static var USER_AUTHORIZATION_GRANT := TwitchEventsubDefinition.new(Type.USER_AUTHORIZATION_GRANT, &"user.authorization.grant", &"1", [&"client_id"], [], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#userauthorizationgrant") +static var USER_AUTHORIZATION_REVOKE := TwitchEventsubDefinition.new(Type.USER_AUTHORIZATION_REVOKE, &"user.authorization.revoke", &"1", [&"client_id"], [], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#userauthorizationrevoke") +static var USER_UPDATE := TwitchEventsubDefinition.new(Type.USER_UPDATE, &"user.update", &"1", [&"user_id"], [&"user:read:email"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#userupdate") +static var USER_WHISPER_MESSAGE := TwitchEventsubDefinition.new(Type.USER_WHISPER_MESSAGE, &"user.whisper.message", &"1", [&"user_id"], [&"user:manage:whispers",&"user:read:whispers"], "https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/#userwhispermessage") + + +## Returns all supported subscriptions +static var ALL: Dictionary[TwitchEventsubDefinition.Type, TwitchEventsubDefinition] = { + Type.AUTOMOD_MESSAGE_HOLD: AUTOMOD_MESSAGE_HOLD, + Type.AUTOMOD_MESSAGE_UPDATE: AUTOMOD_MESSAGE_UPDATE, + Type.AUTOMOD_SETTINGS_UPDATE: AUTOMOD_SETTINGS_UPDATE, + Type.AUTOMOD_TERMS_UPDATE: AUTOMOD_TERMS_UPDATE, + Type.CHANNEL_UPDATE: CHANNEL_UPDATE, + Type.CHANNEL_FOLLOW: CHANNEL_FOLLOW, + Type.CHANNEL_AD_BREAK_BEGIN: CHANNEL_AD_BREAK_BEGIN, + Type.CHANNEL_CHAT_CLEAR: CHANNEL_CHAT_CLEAR, + Type.CHANNEL_CHAT_CLEAR_USER_MESSAGES: CHANNEL_CHAT_CLEAR_USER_MESSAGES, + Type.CHANNEL_CHAT_MESSAGE: CHANNEL_CHAT_MESSAGE, + Type.CHANNEL_CHAT_MESSAGE_DELETE: CHANNEL_CHAT_MESSAGE_DELETE, + Type.CHANNEL_CHAT_NOTIFICATION: CHANNEL_CHAT_NOTIFICATION, + Type.CHANNEL_CHAT_SETTINGS_UPDATE: CHANNEL_CHAT_SETTINGS_UPDATE, + Type.CHANNEL_CHAT_USER_MESSAGE_HOLD: CHANNEL_CHAT_USER_MESSAGE_HOLD, + Type.CHANNEL_CHAT_USER_MESSAGE_UPDATE: CHANNEL_CHAT_USER_MESSAGE_UPDATE, + Type.CHANNEL_SUBSCRIBE: CHANNEL_SUBSCRIBE, + Type.CHANNEL_SUBSCRIPTION_END: CHANNEL_SUBSCRIPTION_END, + Type.CHANNEL_SUBSCRIPTION_GIFT: CHANNEL_SUBSCRIPTION_GIFT, + Type.CHANNEL_SUBSCRIPTION_MESSAGE: CHANNEL_SUBSCRIPTION_MESSAGE, + Type.CHANNEL_CHEER: CHANNEL_CHEER, + Type.CHANNEL_RAID: CHANNEL_RAID, + Type.CHANNEL_BAN: CHANNEL_BAN, + Type.CHANNEL_UNBAN: CHANNEL_UNBAN, + Type.CHANNEL_UNBAN_REQUEST_CREATE: CHANNEL_UNBAN_REQUEST_CREATE, + Type.CHANNEL_UNBAN_REQUEST_RESOLVE: CHANNEL_UNBAN_REQUEST_RESOLVE, + Type.CHANNEL_MODERATE: CHANNEL_MODERATE, + Type.CHANNEL_MODERATE_V2: CHANNEL_MODERATE_V2, + Type.CHANNEL_MODERATOR_ADD: CHANNEL_MODERATOR_ADD, + Type.CHANNEL_MODERATOR_REMOVE: CHANNEL_MODERATOR_REMOVE, + Type.CHANNEL_GUEST_STAR_SESSION_BEGIN: CHANNEL_GUEST_STAR_SESSION_BEGIN, + Type.CHANNEL_GUEST_STAR_SESSION_END: CHANNEL_GUEST_STAR_SESSION_END, + Type.CHANNEL_GUEST_STAR_GUEST_UPDATE: CHANNEL_GUEST_STAR_GUEST_UPDATE, + Type.CHANNEL_GUEST_STAR_SETTINGS_UPDATE: CHANNEL_GUEST_STAR_SETTINGS_UPDATE, + Type.CHANNEL_CHANNEL_POINTS_AUTOMATIC_REWARD_REDEMPTION_ADD: CHANNEL_CHANNEL_POINTS_AUTOMATIC_REWARD_REDEMPTION_ADD, + Type.CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_ADD: CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_ADD, + Type.CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_UPDATE: CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_UPDATE, + Type.CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REMOVE: CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REMOVE, + Type.CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REDEMPTION_ADD: CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REDEMPTION_ADD, + Type.CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REDEMPTION_UPDATE: CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REDEMPTION_UPDATE, + Type.CHANNEL_POLL_BEGIN: CHANNEL_POLL_BEGIN, + Type.CHANNEL_POLL_PROGRESS: CHANNEL_POLL_PROGRESS, + Type.CHANNEL_POLL_END: CHANNEL_POLL_END, + Type.CHANNEL_PREDICTION_BEGIN: CHANNEL_PREDICTION_BEGIN, + Type.CHANNEL_PREDICTION_PROGRESS: CHANNEL_PREDICTION_PROGRESS, + Type.CHANNEL_PREDICTION_LOCK: CHANNEL_PREDICTION_LOCK, + Type.CHANNEL_PREDICTION_END: CHANNEL_PREDICTION_END, + Type.CHANNEL_SUSPICIOUS_USER_UPDATE: CHANNEL_SUSPICIOUS_USER_UPDATE, + Type.CHANNEL_SUSPICIOUS_USER_MESSAGE: CHANNEL_SUSPICIOUS_USER_MESSAGE, + Type.CHANNEL_VIP_ADD: CHANNEL_VIP_ADD, + Type.CHANNEL_VIP_REMOVE: CHANNEL_VIP_REMOVE, + Type.CHANNEL_WARNING_ACKNOWLEDGE: CHANNEL_WARNING_ACKNOWLEDGE, + Type.CHANNEL_WARNING_SEND: CHANNEL_WARNING_SEND, + Type.CHANNEL_HYPE_TRAIN_BEGIN: CHANNEL_HYPE_TRAIN_BEGIN, + Type.CHANNEL_HYPE_TRAIN_PROGRESS: CHANNEL_HYPE_TRAIN_PROGRESS, + Type.CHANNEL_HYPE_TRAIN_END: CHANNEL_HYPE_TRAIN_END, + Type.CHANNEL_CHARITY_CAMPAIGN_DONATE: CHANNEL_CHARITY_CAMPAIGN_DONATE, + Type.CHANNEL_CHARITY_CAMPAIGN_START: CHANNEL_CHARITY_CAMPAIGN_START, + Type.CHANNEL_CHARITY_CAMPAIGN_PROGRESS: CHANNEL_CHARITY_CAMPAIGN_PROGRESS, + Type.CHANNEL_CHARITY_CAMPAIGN_STOP: CHANNEL_CHARITY_CAMPAIGN_STOP, + Type.CHANNEL_SHARED_CHAT_BEGIN: CHANNEL_SHARED_CHAT_BEGIN, + Type.CHANNEL_SHARED_CHAT_UPDATE: CHANNEL_SHARED_CHAT_UPDATE, + Type.CHANNEL_SHARED_CHAT_END: CHANNEL_SHARED_CHAT_END, + Type.CHANNEL_SHIELD_MODE_BEGIN: CHANNEL_SHIELD_MODE_BEGIN, + Type.CHANNEL_SHIELD_MODE_END: CHANNEL_SHIELD_MODE_END, + Type.CHANNEL_SHOUTOUT_CREATE: CHANNEL_SHOUTOUT_CREATE, + Type.CHANNEL_SHOUTOUT_RECEIVE: CHANNEL_SHOUTOUT_RECEIVE, + Type.CONDUIT_SHARD_DISABLED: CONDUIT_SHARD_DISABLED, + Type.DROP_ENTITLEMENT_GRANT: DROP_ENTITLEMENT_GRANT, + Type.EXTENSION_BITS_TRANSACTION_CREATE: EXTENSION_BITS_TRANSACTION_CREATE, + Type.CHANNEL_GOAL_BEGIN: CHANNEL_GOAL_BEGIN, + Type.CHANNEL_GOAL_PROGRESS: CHANNEL_GOAL_PROGRESS, + Type.CHANNEL_GOAL_END: CHANNEL_GOAL_END, + Type.STREAM_ONLINE: STREAM_ONLINE, + Type.STREAM_OFFLINE: STREAM_OFFLINE, + Type.USER_AUTHORIZATION_GRANT: USER_AUTHORIZATION_GRANT, + Type.USER_AUTHORIZATION_REVOKE: USER_AUTHORIZATION_REVOKE, + Type.USER_UPDATE: USER_UPDATE, + Type.USER_WHISPER_MESSAGE: USER_WHISPER_MESSAGE, +} + +## Returns all supported subscriptions by name +static var BY_NAME: Dictionary[StringName, TwitchEventsubDefinition] = { + AUTOMOD_MESSAGE_HOLD.value: AUTOMOD_MESSAGE_HOLD, + AUTOMOD_MESSAGE_UPDATE.value: AUTOMOD_MESSAGE_UPDATE, + AUTOMOD_SETTINGS_UPDATE.value: AUTOMOD_SETTINGS_UPDATE, + AUTOMOD_TERMS_UPDATE.value: AUTOMOD_TERMS_UPDATE, + CHANNEL_UPDATE.value: CHANNEL_UPDATE, + CHANNEL_FOLLOW.value: CHANNEL_FOLLOW, + CHANNEL_AD_BREAK_BEGIN.value: CHANNEL_AD_BREAK_BEGIN, + CHANNEL_CHAT_CLEAR.value: CHANNEL_CHAT_CLEAR, + CHANNEL_CHAT_CLEAR_USER_MESSAGES.value: CHANNEL_CHAT_CLEAR_USER_MESSAGES, + CHANNEL_CHAT_MESSAGE.value: CHANNEL_CHAT_MESSAGE, + CHANNEL_CHAT_MESSAGE_DELETE.value: CHANNEL_CHAT_MESSAGE_DELETE, + CHANNEL_CHAT_NOTIFICATION.value: CHANNEL_CHAT_NOTIFICATION, + CHANNEL_CHAT_SETTINGS_UPDATE.value: CHANNEL_CHAT_SETTINGS_UPDATE, + CHANNEL_CHAT_USER_MESSAGE_HOLD.value: CHANNEL_CHAT_USER_MESSAGE_HOLD, + CHANNEL_CHAT_USER_MESSAGE_UPDATE.value: CHANNEL_CHAT_USER_MESSAGE_UPDATE, + CHANNEL_SUBSCRIBE.value: CHANNEL_SUBSCRIBE, + CHANNEL_SUBSCRIPTION_END.value: CHANNEL_SUBSCRIPTION_END, + CHANNEL_SUBSCRIPTION_GIFT.value: CHANNEL_SUBSCRIPTION_GIFT, + CHANNEL_SUBSCRIPTION_MESSAGE.value: CHANNEL_SUBSCRIPTION_MESSAGE, + CHANNEL_CHEER.value: CHANNEL_CHEER, + CHANNEL_RAID.value: CHANNEL_RAID, + CHANNEL_BAN.value: CHANNEL_BAN, + CHANNEL_UNBAN.value: CHANNEL_UNBAN, + CHANNEL_UNBAN_REQUEST_CREATE.value: CHANNEL_UNBAN_REQUEST_CREATE, + CHANNEL_UNBAN_REQUEST_RESOLVE.value: CHANNEL_UNBAN_REQUEST_RESOLVE, + CHANNEL_MODERATE.value: CHANNEL_MODERATE, + CHANNEL_MODERATE_V2.value: CHANNEL_MODERATE_V2, + CHANNEL_MODERATOR_ADD.value: CHANNEL_MODERATOR_ADD, + CHANNEL_MODERATOR_REMOVE.value: CHANNEL_MODERATOR_REMOVE, + CHANNEL_GUEST_STAR_SESSION_BEGIN.value: CHANNEL_GUEST_STAR_SESSION_BEGIN, + CHANNEL_GUEST_STAR_SESSION_END.value: CHANNEL_GUEST_STAR_SESSION_END, + CHANNEL_GUEST_STAR_GUEST_UPDATE.value: CHANNEL_GUEST_STAR_GUEST_UPDATE, + CHANNEL_GUEST_STAR_SETTINGS_UPDATE.value: CHANNEL_GUEST_STAR_SETTINGS_UPDATE, + CHANNEL_CHANNEL_POINTS_AUTOMATIC_REWARD_REDEMPTION_ADD.value: CHANNEL_CHANNEL_POINTS_AUTOMATIC_REWARD_REDEMPTION_ADD, + CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_ADD.value: CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_ADD, + CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_UPDATE.value: CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_UPDATE, + CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REMOVE.value: CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REMOVE, + CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REDEMPTION_ADD.value: CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REDEMPTION_ADD, + CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REDEMPTION_UPDATE.value: CHANNEL_CHANNEL_POINTS_CUSTOM_REWARD_REDEMPTION_UPDATE, + CHANNEL_POLL_BEGIN.value: CHANNEL_POLL_BEGIN, + CHANNEL_POLL_PROGRESS.value: CHANNEL_POLL_PROGRESS, + CHANNEL_POLL_END.value: CHANNEL_POLL_END, + CHANNEL_PREDICTION_BEGIN.value: CHANNEL_PREDICTION_BEGIN, + CHANNEL_PREDICTION_PROGRESS.value: CHANNEL_PREDICTION_PROGRESS, + CHANNEL_PREDICTION_LOCK.value: CHANNEL_PREDICTION_LOCK, + CHANNEL_PREDICTION_END.value: CHANNEL_PREDICTION_END, + CHANNEL_SUSPICIOUS_USER_UPDATE.value: CHANNEL_SUSPICIOUS_USER_UPDATE, + CHANNEL_SUSPICIOUS_USER_MESSAGE.value: CHANNEL_SUSPICIOUS_USER_MESSAGE, + CHANNEL_VIP_ADD.value: CHANNEL_VIP_ADD, + CHANNEL_VIP_REMOVE.value: CHANNEL_VIP_REMOVE, + CHANNEL_WARNING_ACKNOWLEDGE.value: CHANNEL_WARNING_ACKNOWLEDGE, + CHANNEL_WARNING_SEND.value: CHANNEL_WARNING_SEND, + CHANNEL_HYPE_TRAIN_BEGIN.value: CHANNEL_HYPE_TRAIN_BEGIN, + CHANNEL_HYPE_TRAIN_PROGRESS.value: CHANNEL_HYPE_TRAIN_PROGRESS, + CHANNEL_HYPE_TRAIN_END.value: CHANNEL_HYPE_TRAIN_END, + CHANNEL_CHARITY_CAMPAIGN_DONATE.value: CHANNEL_CHARITY_CAMPAIGN_DONATE, + CHANNEL_CHARITY_CAMPAIGN_START.value: CHANNEL_CHARITY_CAMPAIGN_START, + CHANNEL_CHARITY_CAMPAIGN_PROGRESS.value: CHANNEL_CHARITY_CAMPAIGN_PROGRESS, + CHANNEL_CHARITY_CAMPAIGN_STOP.value: CHANNEL_CHARITY_CAMPAIGN_STOP, + CHANNEL_SHARED_CHAT_BEGIN.value: CHANNEL_SHARED_CHAT_BEGIN, + CHANNEL_SHARED_CHAT_UPDATE.value: CHANNEL_SHARED_CHAT_UPDATE, + CHANNEL_SHARED_CHAT_END.value: CHANNEL_SHARED_CHAT_END, + CHANNEL_SHIELD_MODE_BEGIN.value: CHANNEL_SHIELD_MODE_BEGIN, + CHANNEL_SHIELD_MODE_END.value: CHANNEL_SHIELD_MODE_END, + CHANNEL_SHOUTOUT_CREATE.value: CHANNEL_SHOUTOUT_CREATE, + CHANNEL_SHOUTOUT_RECEIVE.value: CHANNEL_SHOUTOUT_RECEIVE, + CONDUIT_SHARD_DISABLED.value: CONDUIT_SHARD_DISABLED, + DROP_ENTITLEMENT_GRANT.value: DROP_ENTITLEMENT_GRANT, + EXTENSION_BITS_TRANSACTION_CREATE.value: EXTENSION_BITS_TRANSACTION_CREATE, + CHANNEL_GOAL_BEGIN.value: CHANNEL_GOAL_BEGIN, + CHANNEL_GOAL_PROGRESS.value: CHANNEL_GOAL_PROGRESS, + CHANNEL_GOAL_END.value: CHANNEL_GOAL_END, + STREAM_ONLINE.value: STREAM_ONLINE, + STREAM_OFFLINE.value: STREAM_OFFLINE, + USER_AUTHORIZATION_GRANT.value: USER_AUTHORIZATION_GRANT, + USER_AUTHORIZATION_REVOKE.value: USER_AUTHORIZATION_REVOKE, + USER_UPDATE.value: USER_UPDATE, + USER_WHISPER_MESSAGE.value: USER_WHISPER_MESSAGE, +} diff --git a/addons/twitcher/eventsub/twitch_eventsub_definition.gd.uid b/addons/twitcher/eventsub/twitch_eventsub_definition.gd.uid new file mode 100644 index 0000000..926b47f --- /dev/null +++ b/addons/twitcher/eventsub/twitch_eventsub_definition.gd.uid @@ -0,0 +1 @@ +uid://cxmnkr64wc2hx diff --git a/addons/twitcher/eventsub/twitch_keepalive_message.gd b/addons/twitcher/eventsub/twitch_keepalive_message.gd new file mode 100644 index 0000000..cf48d52 --- /dev/null +++ b/addons/twitcher/eventsub/twitch_keepalive_message.gd @@ -0,0 +1,13 @@ +extends RefCounted + +## Defines the message that the EventSub WebSocket server sends your client to indicate that the WebSocket connection is healthy. +## See: https://dev.twitch.tv/docs/eventsub/websocket-reference/#keepalive-message +class_name TwitchKeepaliveMessage + +var metadata: TwitchEventsub.Metadata; +## Is always empty +var payload: Dictionary = {}; + +func _init(d: Dictionary) -> void: + metadata = TwitchEventsub.Metadata.new(d.get("metadata", {})); + payload = d["payload"]; diff --git a/addons/twitcher/eventsub/twitch_keepalive_message.gd.uid b/addons/twitcher/eventsub/twitch_keepalive_message.gd.uid new file mode 100644 index 0000000..55111c7 --- /dev/null +++ b/addons/twitcher/eventsub/twitch_keepalive_message.gd.uid @@ -0,0 +1 @@ +uid://dygbx208p487l diff --git a/addons/twitcher/eventsub/twitch_notification_message.gd b/addons/twitcher/eventsub/twitch_notification_message.gd new file mode 100644 index 0000000..48b194a --- /dev/null +++ b/addons/twitcher/eventsub/twitch_notification_message.gd @@ -0,0 +1,79 @@ +extends RefCounted + +class_name TwitchNotificationMessage + +## An object that identifies the message. +class Metadata extends TwitchEventsub.Metadata: + ## The type of event sent in the message. + var subscription_type: String; + ## The version number of the subscription type’s definition. This is the same value specified in the subscription request. + var subscription_version: String; + + func _init(d: Dictionary) -> void: + super._init(d); + subscription_type = d["subscription_type"]; + subscription_version = d["subscription_version"]; + +## An object that contains the message. +class Payload extends RefCounted: + ## An object that contains information about your subscription. + var subscription: Subscription; + ## The event’s data. For information about the event’s data, see the subscription type’s description in Subscription Types. https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types + var event: Dictionary; + + func _init(d: Dictionary) -> void: + var sub = d.get("subscription"); + if sub != null: + subscription = Subscription.new(sub) + + event = d["event"] + +## An object that contains information about your subscription. +class Subscription extends RefCounted: + ## An ID that uniquely identifies this subscription. + var id: String; + ## The subscription’s status, which is set to enabled. + var status: String; + ## The type of event sent in the message. See the event field. + var type: String; + ## The version number of the subscription type’s definition. + var version: String; + ## The event’s cost. See Subscription limits. (https://dev.twitch.tv/docs/eventsub/manage-subscriptions#subscription-limits) + var cost: int; + ## The conditions under which the event fires. For example, if you requested notifications when a broadcaster gets a new follower, this object contains the broadcaster’s ID. For information about the condition’s data, see the subscription type’s description in Subscription types. (https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types) + var condition: Dictionary; + ## An object that contains information about the transport used for notifications. + var transport: Transport; + ## The UTC date and time that the subscription was created. + var created_at: String; + + func _init(d: Dictionary) -> void: + id = d["id"]; + status = d["status"]; + type = d["type"]; + version = d["version"]; + cost = d["cost"]; + condition = d["condition"]; + transport = Transport.new(d.get("transport", {})); + created_at = d["created_at"]; + +## An object that contains information about the transport used for notifications. +class Transport extends RefCounted: + ## The transport method, which is set to websocket. + var method: String; + ## An ID that uniquely identifies the WebSocket connection. + var session_id: String; + + func _init(d: Dictionary) -> void: + method = d["method"]; + session_id = d["session_id"]; + +## An object that identifies the message. +var metadata: Metadata; + +## An object that contains the message. +var payload: Payload; + +func _init(d: Dictionary) -> void: + metadata = Metadata.new(d["metadata"]) + payload = Payload.new(d["payload"]) diff --git a/addons/twitcher/eventsub/twitch_notification_message.gd.uid b/addons/twitcher/eventsub/twitch_notification_message.gd.uid new file mode 100644 index 0000000..51ba5ba --- /dev/null +++ b/addons/twitcher/eventsub/twitch_notification_message.gd.uid @@ -0,0 +1 @@ +uid://2xnomqtfyxcd diff --git a/addons/twitcher/eventsub/twitch_reconnect_message.gd b/addons/twitcher/eventsub/twitch_reconnect_message.gd new file mode 100644 index 0000000..0ce208a --- /dev/null +++ b/addons/twitcher/eventsub/twitch_reconnect_message.gd @@ -0,0 +1,20 @@ +extends RefCounted + +class_name TwitchReconnectMessage + +## An object that contains the message. +class Payload extends RefCounted: + var session: TwitchEventsub.Session; + + func _init(d: Dictionary) -> void: + session = TwitchEventsub.Session.new(d.get("session", {})); + +## An object that identifies the message. +var metadata: TwitchEventsub.Metadata; + +## An object that contains the message. +var payload: Payload; + +func _init(d: Dictionary) -> void: + metadata = TwitchEventsub.Metadata.new(d.get("metadata", {})); + payload = Payload.new(d.get("payload", {})); diff --git a/addons/twitcher/eventsub/twitch_reconnect_message.gd.uid b/addons/twitcher/eventsub/twitch_reconnect_message.gd.uid new file mode 100644 index 0000000..1c4fd30 --- /dev/null +++ b/addons/twitcher/eventsub/twitch_reconnect_message.gd.uid @@ -0,0 +1 @@ +uid://ciqfgatm1v2wy diff --git a/addons/twitcher/eventsub/twitch_revocation_message.gd b/addons/twitcher/eventsub/twitch_revocation_message.gd new file mode 100644 index 0000000..e9f87c6 --- /dev/null +++ b/addons/twitcher/eventsub/twitch_revocation_message.gd @@ -0,0 +1,76 @@ +extends RefCounted + +class_name TwitchRevocationMessage + +## An object that identifies the message. +class Metadata extends TwitchEventsub.Metadata: + ## The type of event sent in the message. + var subscription_type: String; + ## The version number of the subscription type’s definition. This is the same value specified in the subscription request. + var subscription_version: String; + + func _init(d: Dictionary) -> void: + super._init(d); + subscription_type = d["subscription_type"]; + subscription_version = d["subscription_version"]; + +## An object that contains the message. +class Payload extends RefCounted: + ## An object that contains information about your subscription. + var subscription: Subscription; + + func _init(d: Dictionary) -> void: + subscription = Subscription.new(d.get("subscription", {})) + +## An object that contains information about your subscription. +class Subscription extends RefCounted: + ## An ID that uniquely identifies this subscription. + var id: String; + ## he subscription's status. The following are the possible values:[br] + ## authorization_revoked — The user in the condition object revoked the authorization that let you get events on their behalf.[br] + ## user_removed — The user in the condition object is no longer a Twitch user.[br] + ## version_removed — The subscribed to subscription type and version is no longer supported. + var status: String; + ## The type of event sent in the message. + var type: String; + ## The version number of the subscription type's definition. + var version: String; + ## The event's cost. See Subscription limits (https://dev.twitch.tv/docs/eventsub/manage-subscriptions/#subscription-limits) + var cost: String; + ## The conditions under which the event fires. For example, if you requested notifications when a broadcaster gets a new follower, this object contains the broadcaster’s ID. For information about the condition's data, see the subscription type's description in Subscription Types. (https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types) + var condition: Dictionary; + ## An object that contains information about the transport used for notifications. + var transport: Transport; + ## The UTC date and time that the subscription was created. + var created_at: String; + + func _init(d: Dictionary) -> void: + id = d["id"]; + status = d["status"]; + type = d["type"]; + version = d["version"]; + cost = d["cost"]; + condition = d["condition"]; + transport = Transport.new(d.get("transport", {})); + created_at = d["created_at"]; + +## An object that contains information about the transport used for notifications. +class Transport extends RefCounted: + ## The transport method, which is set to websocket. + var method: String; + ## An ID that uniquely identifies the WebSocket connection. + var session_id: String; + + func _init(d: Dictionary) -> void: + method = d["method"]; + session_id = d["session_id"]; + +## An object that identifies the message. +var metadata: Metadata; + +## An object that contains the message. +var payload: Payload; + +func _init(d: Dictionary) -> void: + metadata = Metadata.new(d.get("metadata", {})) + payload = Payload.new(d.get("payload", {})) diff --git a/addons/twitcher/eventsub/twitch_revocation_message.gd.uid b/addons/twitcher/eventsub/twitch_revocation_message.gd.uid new file mode 100644 index 0000000..029fcd1 --- /dev/null +++ b/addons/twitcher/eventsub/twitch_revocation_message.gd.uid @@ -0,0 +1 @@ +uid://c1evlw325jeeg diff --git a/addons/twitcher/eventsub/twitch_welcome_message.gd b/addons/twitcher/eventsub/twitch_welcome_message.gd new file mode 100644 index 0000000..5d18ce1 --- /dev/null +++ b/addons/twitcher/eventsub/twitch_welcome_message.gd @@ -0,0 +1,18 @@ +extends RefCounted + +## Defines the first message that the EventSub WebSocket server sends after your client connects to the server. +## See: https://dev.twitch.tv/docs/eventsub/websocket-reference/#welcome-message +class_name TwitchWelcomeMessage + +class TwitchWelcomeMessagePayload extends RefCounted: + var session: TwitchEventsub.Session; + + func _init(d: Dictionary) -> void: + session = TwitchEventsub.Session.new(d.get("session", {})); + +var metadata: TwitchEventsub.Metadata; +var payload: TwitchWelcomeMessagePayload; + +func _init(d: Dictionary) -> void: + metadata = TwitchEventsub.Metadata.new(d.get("metadata", {})); + payload = TwitchWelcomeMessagePayload.new(d.get("payload", {})); diff --git a/addons/twitcher/eventsub/twitch_welcome_message.gd.uid b/addons/twitcher/eventsub/twitch_welcome_message.gd.uid new file mode 100644 index 0000000..7f4b5c4 --- /dev/null +++ b/addons/twitcher/eventsub/twitch_welcome_message.gd.uid @@ -0,0 +1 @@ +uid://qh68xfq2isug diff --git a/addons/twitcher/generated/README.md b/addons/twitcher/generated/README.md new file mode 100644 index 0000000..506e51f --- /dev/null +++ b/addons/twitcher/generated/README.md @@ -0,0 +1,5 @@ +# This folder is autogenerated via `res://addons/twitcher/editor/twitch_api_generator.gd` + +All changes can be overriden very easily. +I case you want to add / change functionallity extend the classes or even better +use [composition over inheritance](https://en.wikipedia.org/wiki/Composition_over_inheritance) diff --git a/addons/twitcher/generated/twitch_add_blocked_term.gd b/addons/twitcher/generated/twitch_add_blocked_term.gd new file mode 100644 index 0000000..5435e75 --- /dev/null +++ b/addons/twitcher/generated/twitch_add_blocked_term.gd @@ -0,0 +1,66 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchAddBlockedTerm + + + +## +## #/components/schemas/AddBlockedTermBody +class Body extends TwitchData: + + ## The word or phrase to block from being used in the broadcaster’s chat room. The term must contain a minimum of 2 characters and may contain up to a maximum of 500 characters. + ## + ## Terms may include a wildcard character (\*). The wildcard character must appear at the beginning or end of a word or set of characters. For example, \*foo or foo\*. + ## + ## If the blocked term already exists, the response contains the existing blocked term. + @export var text: String: + set(val): + text = val + track_data(&"text", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_text: String) -> Body: + var body: Body = Body.new() + body.text = _text + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("text", null) != null: + result.text = d["text"] + return result + + + +## +## #/components/schemas/AddBlockedTermResponse +class Response extends TwitchData: + + ## A list that contains the single blocked term that the broadcaster added. + @export var data: Array[TwitchBlockedTerm]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchBlockedTerm]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchBlockedTerm.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_add_blocked_term.gd.uid b/addons/twitcher/generated/twitch_add_blocked_term.gd.uid new file mode 100644 index 0000000..48ffe6b --- /dev/null +++ b/addons/twitcher/generated/twitch_add_blocked_term.gd.uid @@ -0,0 +1 @@ +uid://crmqbuhp7k7ms diff --git a/addons/twitcher/generated/twitch_api.gd b/addons/twitcher/generated/twitch_api.gd new file mode 100644 index 0000000..eaa3025 --- /dev/null +++ b/addons/twitcher/generated/twitch_api.gd @@ -0,0 +1,3115 @@ +@tool +extends Twitcher + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## Interaction with the Twitch REST API. +class_name TwitchAPI + +static var _log: TwitchLogger = TwitchLogger.new("TwitchAPI") + +static var instance: TwitchAPI + +## Maximal tries to reauthrorize before giving up the request. +const MAX_AUTH_ERRORS = 3 + +## Called when the API returns unauthenticated mostly cause the accesstoken is expired +signal unauthenticated + +## Called when the API returns 403 means there are permissions / scopes missing +signal unauthorized + +## To authorize against the Twitch API +@export var token: OAuthToken: + set(val): + token = val + update_configuration_warnings() +## OAuth settings needed for client information +@export var oauth_setting: OAuthSetting: + set(val): + oauth_setting = val + update_configuration_warnings() +## URI to the Twitch API +@export var api_host: String = "https://api.twitch.tv/helix" + +## Client to make HTTP requests +var client: BufferedHTTPClient + + +func _ready() -> void: + client = BufferedHTTPClient.new() + client.name = "ApiClient" + add_child(client) + + +func _enter_tree() -> void: + if instance == null: instance = self + + +func _exit_tree() -> void: + if instance == self: instance = null + + +func _get_configuration_warnings() -> PackedStringArray: + var result: PackedStringArray = [] + if token == null: + result.append("Please set a token to use") + if oauth_setting == null: + result.append("Please set the correct oauth settings") + return result + + +func request(path: String, method: int, body: Variant = "", content_type: String = "", error_count: int = 0) -> BufferedHTTPClient.ResponseData: + var header : Dictionary = { + "Authorization": "Bearer %s" % [await token.get_access_token()], + "Client-ID": oauth_setting.client_id + } + if content_type != "": + header["Content-Type"] = content_type + + var request_body: String = "" + if body == null || (body is String && body == ""): + request_body = "" + elif body is Object && body.has_method("to_json"): + request_body = body.to_json() + else: + request_body = JSON.stringify(body) + + var req: BufferedHTTPClient.RequestData = client.request(api_host + path, method, header, request_body) + var res: BufferedHTTPClient.ResponseData = await client.wait_for_request(req) + + # Try to fix Godot TLS Bug + if res.result == 5: + return await retry(req, res, path, method, body, content_type, error_count + 1) + + match res.response_code: + 400: + var error_message: String = res.response_data.get_string_from_utf8() + _log.e("'%s' failed cause of: \n%s" % [path, error_message]) + 401: # Token expired / or missing permissions + _log.e("'%s' is unauthorized. It is probably your scopes." % path) + unauthorized.emit() + 403: + _log.i("'%s' is unauthenticated. Refresh token." % path) + unauthenticated.emit() + await token.authorized + return await retry(req, res, path, method, body, content_type, error_count + 1) + return res + + +func retry(request: BufferedHTTPClient.RequestData, + response: BufferedHTTPClient.ResponseData, + path: String, + method: int, + body: Variant = "", + content_type: String = "", + error_count: int = 0) -> BufferedHTTPClient.ResponseData: + if error_count + 1 < MAX_AUTH_ERRORS: + return await request(path, method, body, content_type, error_count + 1) + else: + # Give up the request after trying multiple times and + # return an empty response with correct error code + var empty_response: BufferedHTTPClient.ResponseData = client.empty_response(request) + empty_response.response_code = response.response_code + return empty_response + + +## Converts unix timestamp to RFC 3339 (example: 2021-10-27T00:00:00Z) when passed a string uses as is +static func get_rfc_3339_date_format(time: Variant) -> String: + if typeof(time) == TYPE_INT: + var date_time = Time.get_datetime_dict_from_unix_time(time) + return "%s-%02d-%02dT%02d:%02d:%02dZ" % [date_time['year'], date_time['month'], date_time['day'], date_time['hour'], date_time['minute'], date_time['second']] + return str(time) + + + +## Starts a commercial on the specified channel. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#start-commercial +func start_commercial(body: TwitchStartCommercial.Body) -> TwitchStartCommercial.Response: + var path = "/channels/commercial?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchStartCommercial.Response = TwitchStartCommercial.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Returns ad schedule related information. +## +## broadcaster_id - Provided `broadcaster_id` must match the `user_id` in the auth token. +## +## https://dev.twitch.tv/docs/api/reference#get-ad-schedule +func get_ad_schedule(broadcaster_id: String) -> TwitchGetAdSchedule.Response: + var path = "/channels/ads?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetAdSchedule.Response = TwitchGetAdSchedule.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Pushes back the timestamp of the upcoming automatic mid-roll ad by 5 minutes. +## +## broadcaster_id - Provided `broadcaster_id` must match the `user_id` in the auth token. +## +## https://dev.twitch.tv/docs/api/reference#snooze-next-ad +func snooze_next_ad(broadcaster_id: String) -> TwitchSnoozeNextAd.Response: + var path = "/channels/ads/schedule/snooze?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchSnoozeNextAd.Response = TwitchSnoozeNextAd.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets an analytics report for one or more extensions. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-extension-analytics +func get_extension_analytics(opt: TwitchGetExtensionAnalytics.Opt) -> TwitchGetExtensionAnalytics.Response: + var path = "/analytics/extensions?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("ended_at"): + path += "ended_at=" + get_rfc_3339_date_format(optionals.ended_at) + "&" + if optionals.has("extension_id"): + path += "extension_id=" + str(optionals.extension_id) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("started_at"): + path += "started_at=" + get_rfc_3339_date_format(optionals.started_at) + "&" + if optionals.has("type"): + path += "type=" + str(optionals.type) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetExtensionAnalytics.Response = TwitchGetExtensionAnalytics.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_extension_analytics.bind(opt) + return parsed_result + + +## Gets an analytics report for one or more games. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-game-analytics +func get_game_analytics(opt: TwitchGetGameAnalytics.Opt) -> TwitchGetGameAnalytics.Response: + var path = "/analytics/games?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("ended_at"): + path += "ended_at=" + get_rfc_3339_date_format(optionals.ended_at) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("game_id"): + path += "game_id=" + str(optionals.game_id) + "&" + if optionals.has("started_at"): + path += "started_at=" + get_rfc_3339_date_format(optionals.started_at) + "&" + if optionals.has("type"): + path += "type=" + str(optionals.type) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetGameAnalytics.Response = TwitchGetGameAnalytics.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_game_analytics.bind(opt) + return parsed_result + + +## Gets the Bits leaderboard for the authenticated broadcaster. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-bits-leaderboard +func get_bits_leaderboard(opt: TwitchGetBitsLeaderboard.Opt) -> TwitchGetBitsLeaderboard.Response: + var path = "/bits/leaderboard?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("count"): + path += "count=" + str(optionals.count) + "&" + if optionals.has("period"): + path += "period=" + str(optionals.period) + "&" + if optionals.has("started_at"): + path += "started_at=" + get_rfc_3339_date_format(optionals.started_at) + "&" + if optionals.has("user_id"): + path += "user_id=" + str(optionals.user_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetBitsLeaderboard.Response = TwitchGetBitsLeaderboard.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets a list of Cheermotes that users can use to cheer Bits. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-cheermotes +func get_cheermotes(opt: TwitchGetCheermotes.Opt) -> TwitchGetCheermotes.Response: + var path = "/bits/cheermotes?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("broadcaster_id"): + path += "broadcaster_id=" + str(optionals.broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetCheermotes.Response = TwitchGetCheermotes.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets an extension’s list of transactions. +## +## extension_id - The ID of the extension whose list of transactions you want to get. +## +## https://dev.twitch.tv/docs/api/reference#get-extension-transactions +func get_extension_transactions(opt: TwitchGetExtensionTransactions.Opt, extension_id: String) -> TwitchGetExtensionTransactions.Response: + var path = "/extensions/transactions?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "extension_id=" + str(extension_id) + "&" + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("id"): + + for param in optionals.id: + path += "id=" + str(param) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetExtensionTransactions.Response = TwitchGetExtensionTransactions.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_extension_transactions.bind(opt, extension_id) + return parsed_result + + +## Gets information about one or more channels. +## +## broadcaster_id - The ID of the broadcaster whose channel you want to get. To specify more than one ID, include this parameter for each broadcaster you want to get. For example, `broadcaster_id=1234&broadcaster_id=5678`. You may specify a maximum of 100 IDs. The API ignores duplicate IDs and IDs that are not found. +## +## https://dev.twitch.tv/docs/api/reference#get-channel-information +func get_channel_information(broadcaster_id: Array[String]) -> TwitchGetChannelInformation.Response: + var path = "/channels?" + + for param in broadcaster_id: + path += "broadcaster_id=" + str(param) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetChannelInformation.Response = TwitchGetChannelInformation.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Updates a channel’s properties. +## +## broadcaster_id - The ID of the broadcaster whose channel you want to update. This ID must match the user ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#modify-channel-information +func modify_channel_information(body: TwitchModifyChannelInformation.Body, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/channels?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PATCH, body, "application/json") + return response + + +## Gets the broadcaster’s list editors. +## +## broadcaster_id - The ID of the broadcaster that owns the channel. This ID must match the user ID in the access token. +## +## https://dev.twitch.tv/docs/api/reference#get-channel-editors +func get_channel_editors(broadcaster_id: String) -> TwitchGetChannelEditors.Response: + var path = "/channels/editors?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetChannelEditors.Response = TwitchGetChannelEditors.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets a list of broadcasters that the specified user follows. You can also use this endpoint to see whether a user follows a specific broadcaster. +## +## user_id - A user’s ID. Returns the list of broadcasters that this user follows. This ID must match the user ID in the user OAuth token. +## +## https://dev.twitch.tv/docs/api/reference#get-followed-channels +func get_followed_channels(opt: TwitchGetFollowedChannels.Opt, user_id: String) -> TwitchGetFollowedChannels.Response: + var path = "/channels/followed?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "user_id=" + str(user_id) + "&" + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("broadcaster_id"): + path += "broadcaster_id=" + str(optionals.broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetFollowedChannels.Response = TwitchGetFollowedChannels.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_followed_channels.bind(opt, user_id) + return parsed_result + + +## Gets a list of users that follow the specified broadcaster. You can also use this endpoint to see whether a specific user follows the broadcaster. +## +## broadcaster_id - The broadcaster’s ID. Returns the list of users that follow this broadcaster. +## +## https://dev.twitch.tv/docs/api/reference#get-channel-followers +func get_channel_followers(opt: TwitchGetChannelFollowers.Opt, broadcaster_id: String) -> TwitchGetChannelFollowers.Response: + var path = "/channels/followers?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("user_id"): + path += "user_id=" + str(optionals.user_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetChannelFollowers.Response = TwitchGetChannelFollowers.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_channel_followers.bind(opt, broadcaster_id) + return parsed_result + + +## Creates a Custom Reward in the broadcaster’s channel. +## +## broadcaster_id - The ID of the broadcaster to add the custom reward to. This ID must match the user ID found in the OAuth token. +## +## https://dev.twitch.tv/docs/api/reference#create-custom-rewards +func create_custom_rewards(body: TwitchCreateCustomRewards.Body, broadcaster_id: String) -> TwitchCreateCustomRewards.Response: + var path = "/channel_points/custom_rewards?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchCreateCustomRewards.Response = TwitchCreateCustomRewards.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Deletes a custom reward that the broadcaster created. +## +## broadcaster_id - The ID of the broadcaster that created the custom reward. This ID must match the user ID found in the OAuth token. +## id - The ID of the custom reward to delete. +## +## https://dev.twitch.tv/docs/api/reference#delete-custom-reward +func delete_custom_reward(id: String, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/channel_points/custom_rewards?" + path += "id=" + str(id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_DELETE, "", "") + return response + + +## Gets a list of custom rewards that the specified broadcaster created. +## +## broadcaster_id - The ID of the broadcaster whose custom rewards you want to get. This ID must match the user ID found in the OAuth token. +## +## https://dev.twitch.tv/docs/api/reference#get-custom-reward +func get_custom_reward(opt: TwitchGetCustomReward.Opt, broadcaster_id: String) -> TwitchGetCustomReward.Response: + var path = "/channel_points/custom_rewards?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("id"): + + for param in optionals.id: + path += "id=" + str(param) + "&" + if optionals.has("only_manageable_rewards"): + path += "only_manageable_rewards=" + str(optionals.only_manageable_rewards) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetCustomReward.Response = TwitchGetCustomReward.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Updates a custom reward. +## +## broadcaster_id - The ID of the broadcaster that’s updating the reward. This ID must match the user ID found in the OAuth token. +## id - The ID of the reward to update. +## +## https://dev.twitch.tv/docs/api/reference#update-custom-reward +func update_custom_reward(body: TwitchUpdateCustomReward.Body, id: String, broadcaster_id: String) -> TwitchUpdateCustomReward.Response: + var path = "/channel_points/custom_rewards?" + path += "id=" + str(id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PATCH, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchUpdateCustomReward.Response = TwitchUpdateCustomReward.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets a list of redemptions for a custom reward. +## +## broadcaster_id - The ID of the broadcaster that owns the custom reward. This ID must match the user ID found in the user OAuth token. +## reward_id - The ID that identifies the custom reward whose redemptions you want to get. +## +## https://dev.twitch.tv/docs/api/reference#get-custom-reward-redemption +func get_custom_reward_redemption(opt: TwitchGetCustomRewardRedemption.Opt, reward_id: String, broadcaster_id: String) -> TwitchGetCustomRewardRedemption.Response: + var path = "/channel_points/custom_rewards/redemptions?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "reward_id=" + str(reward_id) + "&" + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("id"): + + for param in optionals.id: + path += "id=" + str(param) + "&" + if optionals.has("sort"): + path += "sort=" + str(optionals.sort) + "&" + if optionals.has("status"): + path += "status=" + str(optionals.status) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetCustomRewardRedemption.Response = TwitchGetCustomRewardRedemption.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_custom_reward_redemption.bind(opt, reward_id, broadcaster_id) + return parsed_result + + +## Updates a redemption’s status. +## +## id - A list of IDs that identify the redemptions to update. To specify more than one ID, include this parameter for each redemption you want to update. For example, `id=1234&id=5678`. You may specify a maximum of 50 IDs. +## broadcaster_id - The ID of the broadcaster that’s updating the redemption. This ID must match the user ID in the user access token. +## reward_id - The ID that identifies the reward that’s been redeemed. +## +## https://dev.twitch.tv/docs/api/reference#update-redemption-status +func update_redemption_status(body: TwitchUpdateRedemptionStatus.Body, id: Array[String], reward_id: String, broadcaster_id: String) -> TwitchUpdateRedemptionStatus.Response: + var path = "/channel_points/custom_rewards/redemptions?" + + for param in id: + path += "id=" + str(param) + "&" + path += "reward_id=" + str(reward_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PATCH, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchUpdateRedemptionStatus.Response = TwitchUpdateRedemptionStatus.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets information about the broadcaster’s active charity campaign. +## +## broadcaster_id - The ID of the broadcaster that’s currently running a charity campaign. This ID must match the user ID in the access token. +## +## https://dev.twitch.tv/docs/api/reference#get-charity-campaign +func get_charity_campaign(broadcaster_id: String) -> TwitchGetCharityCampaign.Response: + var path = "/charity/campaigns?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetCharityCampaign.Response = TwitchGetCharityCampaign.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets the list of donations that users have made to the broadcaster’s active charity campaign. +## +## broadcaster_id - The ID of the broadcaster that’s currently running a charity campaign. This ID must match the user ID in the access token. +## +## https://dev.twitch.tv/docs/api/reference#get-charity-campaign-donations +func get_charity_campaign_donations(opt: TwitchGetCharityCampaignDonations.Opt, broadcaster_id: String) -> TwitchGetCharityCampaignDonations.Response: + var path = "/charity/donations?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetCharityCampaignDonations.Response = TwitchGetCharityCampaignDonations.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_charity_campaign_donations.bind(opt, broadcaster_id) + return parsed_result + + +## Gets the list of users that are connected to the broadcaster’s chat session. +## +## broadcaster_id - The ID of the broadcaster whose list of chatters you want to get. +## moderator_id - The ID of the broadcaster or one of the broadcaster’s moderators. This ID must match the user ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#get-chatters +func get_chatters(opt: TwitchGetChatters.Opt, moderator_id: String, broadcaster_id: String) -> TwitchGetChatters.Response: + var path = "/chat/chatters?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "moderator_id=" + str(moderator_id) + "&" + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetChatters.Response = TwitchGetChatters.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_chatters.bind(opt, moderator_id, broadcaster_id) + return parsed_result + + +## Gets the broadcaster’s list of custom emotes. +## +## broadcaster_id - An ID that identifies the broadcaster whose emotes you want to get. +## +## https://dev.twitch.tv/docs/api/reference#get-channel-emotes +func get_channel_emotes(broadcaster_id: String) -> TwitchGetChannelEmotes.Response: + var path = "/chat/emotes?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetChannelEmotes.Response = TwitchGetChannelEmotes.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets all global emotes. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-global-emotes +func get_global_emotes() -> TwitchGetGlobalEmotes.Response: + var path = "/chat/emotes/global?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetGlobalEmotes.Response = TwitchGetGlobalEmotes.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets emotes for one or more specified emote sets. +## +## emote_set_id - An ID that identifies the emote set to get. Include this parameter for each emote set you want to get. For example, `emote_set_id=1234&emote_set_id=5678`. You may specify a maximum of 25 IDs. The response contains only the IDs that were found and ignores duplicate IDs. +## +## To get emote set IDs, use the [Get Channel Emotes](https://dev.twitch.tv/docs/api/reference#get-channel-emotes) API. +## +## https://dev.twitch.tv/docs/api/reference#get-emote-sets +func get_emote_sets(emote_set_id: Array[String]) -> TwitchGetEmoteSets.Response: + var path = "/chat/emotes/set?" + + for param in emote_set_id: + path += "emote_set_id=" + str(param) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetEmoteSets.Response = TwitchGetEmoteSets.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets the broadcaster’s list of custom chat badges. +## +## broadcaster_id - The ID of the broadcaster whose chat badges you want to get. +## +## https://dev.twitch.tv/docs/api/reference#get-channel-chat-badges +func get_channel_chat_badges(broadcaster_id: String) -> TwitchGetChannelChatBadges.Response: + var path = "/chat/badges?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetChannelChatBadges.Response = TwitchGetChannelChatBadges.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets Twitch’s list of chat badges. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-global-chat-badges +func get_global_chat_badges() -> TwitchGetGlobalChatBadges.Response: + var path = "/chat/badges/global?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetGlobalChatBadges.Response = TwitchGetGlobalChatBadges.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets the broadcaster’s chat settings. +## +## broadcaster_id - The ID of the broadcaster whose chat settings you want to get. +## +## https://dev.twitch.tv/docs/api/reference#get-chat-settings +func get_chat_settings(opt: TwitchGetChatSettings.Opt, broadcaster_id: String) -> TwitchGetChatSettings.Response: + var path = "/chat/settings?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("moderator_id"): + path += "moderator_id=" + str(optionals.moderator_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetChatSettings.Response = TwitchGetChatSettings.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Updates the broadcaster’s chat settings. +## +## broadcaster_id - The ID of the broadcaster whose chat settings you want to update. +## moderator_id - The ID of a user that has permission to moderate the broadcaster’s chat room, or the broadcaster’s ID if they’re making the update. This ID must match the user ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#update-chat-settings +func update_chat_settings(body: TwitchUpdateChatSettings.Body, moderator_id: String, broadcaster_id: String) -> TwitchUpdateChatSettings.Response: + var path = "/chat/settings?" + path += "moderator_id=" + str(moderator_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PATCH, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchUpdateChatSettings.Response = TwitchUpdateChatSettings.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## NEW Retrieves the active shared chat session for a channel. +## +## broadcaster_id - The User ID of the channel broadcaster. +## +## https://dev.twitch.tv/docs/api/reference#get-shared-chat-session +func get_shared_chat_session(broadcaster_id: String) -> TwitchGetSharedChatSession.Response: + var path = "/shared_chat/session?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetSharedChatSession.Response = TwitchGetSharedChatSession.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## NEW Retrieves emotes available to the user across all channels. +## +## user_id - The ID of the user. This ID must match the user ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#get-user-emotes +func get_user_emotes(opt: TwitchGetUserEmotes.Opt, user_id: String) -> TwitchGetUserEmotes.Response: + var path = "/chat/emotes/user?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "user_id=" + str(user_id) + "&" + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("broadcaster_id"): + path += "broadcaster_id=" + str(optionals.broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetUserEmotes.Response = TwitchGetUserEmotes.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_user_emotes.bind(opt, user_id) + return parsed_result + + +## Sends an announcement to the broadcaster’s chat room. +## +## broadcaster_id - The ID of the broadcaster that owns the chat room to send the announcement to. +## moderator_id - The ID of a user who has permission to moderate the broadcaster’s chat room, or the broadcaster’s ID if they’re sending the announcement. This ID must match the user ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#send-chat-announcement +func send_chat_announcement(body: TwitchSendChatAnnouncement.Body, moderator_id: String, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/chat/announcements?" + path += "moderator_id=" + str(moderator_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, body, "application/json") + return response + + +## Sends a Shoutout to the specified broadcaster. +## +## from_broadcaster_id - The ID of the broadcaster that’s sending the Shoutout. +## to_broadcaster_id - The ID of the broadcaster that’s receiving the Shoutout. +## moderator_id - The ID of the broadcaster or a user that is one of the broadcaster’s moderators. This ID must match the user ID in the access token. +## +## https://dev.twitch.tv/docs/api/reference#send-a-shoutout +func send_a_shoutout(from_broadcaster_id: String, moderator_id: String, to_broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/chat/shoutouts?" + path += "from_broadcaster_id=" + str(from_broadcaster_id) + "&" + path += "moderator_id=" + str(moderator_id) + "&" + path += "to_broadcaster_id=" + str(to_broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, "", "") + return response + + +## NEW Sends a message to the broadcaster’s chat room. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#send-chat-message +func send_chat_message(body: TwitchSendChatMessage.Body) -> TwitchSendChatMessage.Response: + var path = "/chat/messages?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchSendChatMessage.Response = TwitchSendChatMessage.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets the color used for the user’s name in chat. +## +## user_id - The ID of the user whose username color you want to get. To specify more than one user, include the _user\_id_ parameter for each user to get. For example, `&user_id=1234&user_id=5678`. The maximum number of IDs that you may specify is 100. +## +## The API ignores duplicate IDs and IDs that weren’t found. +## +## https://dev.twitch.tv/docs/api/reference#get-user-chat-color +func get_user_chat_color(user_id: Array[String]) -> TwitchGetUserChatColor.Response: + var path = "/chat/color?" + + for param in user_id: + path += "user_id=" + str(param) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetUserChatColor.Response = TwitchGetUserChatColor.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Updates the color used for the user’s name in chat. +## +## user_id - The ID of the user whose chat color you want to update. This ID must match the user ID in the access token. +## color - The color to use for the user's name in chat. All users may specify one of the following named color values. +## +## * blue +## * blue\_violet +## * cadet\_blue +## * chocolate +## * coral +## * dodger\_blue +## * firebrick +## * golden\_rod +## * green +## * hot\_pink +## * orange\_red +## * red +## * sea\_green +## * spring\_green +## * yellow\_green +## +## Turbo and Prime users may specify a named color or a Hex color code like #9146FF. If you use a Hex color code, remember to URL encode it. +## +## https://dev.twitch.tv/docs/api/reference#update-user-chat-color +func update_user_chat_color(color: String, user_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/chat/color?" + path += "color=" + str(color) + "&" + path += "user_id=" + str(user_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PUT, "", "") + return response + + +## Creates a clip from the broadcaster’s stream. +## +## broadcaster_id - The ID of the broadcaster whose stream you want to create a clip from. +## +## https://dev.twitch.tv/docs/api/reference#create-clip +func create_clip(opt: TwitchCreateClip.Opt, broadcaster_id: String) -> TwitchCreateClip.Response: + var path = "/clips?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("has_delay"): + path += "has_delay=" + str(optionals.has_delay) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchCreateClip.Response = TwitchCreateClip.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets one or more video clips. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-clips +func get_clips(opt: TwitchGetClips.Opt) -> TwitchGetClips.Response: + var path = "/clips?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("before"): + path += "before=" + str(optionals.before) + "&" + if optionals.has("ended_at"): + path += "ended_at=" + get_rfc_3339_date_format(optionals.ended_at) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("game_id"): + path += "game_id=" + str(optionals.game_id) + "&" + if optionals.has("id"): + + for param in optionals.id: + path += "id=" + str(param) + "&" + if optionals.has("is_featured"): + path += "is_featured=" + str(optionals.is_featured) + "&" + if optionals.has("started_at"): + path += "started_at=" + get_rfc_3339_date_format(optionals.started_at) + "&" + if optionals.has("broadcaster_id"): + path += "broadcaster_id=" + str(optionals.broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetClips.Response = TwitchGetClips.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_clips.bind(opt) + return parsed_result + + +## NEW Gets the conduits for a client ID. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-conduits +func get_conduits() -> TwitchGetConduits.Response: + var path = "/eventsub/conduits?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetConduits.Response = TwitchGetConduits.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## NEW Creates a new conduit. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#create-conduits +func create_conduits(body: TwitchCreateConduits.Body) -> TwitchCreateConduits.Response: + var path = "/eventsub/conduits?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchCreateConduits.Response = TwitchCreateConduits.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## NEW Updates a conduit’s shard count. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#update-conduits +func update_conduits(body: TwitchUpdateConduits.Body) -> TwitchUpdateConduits.Response: + var path = "/eventsub/conduits?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PATCH, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchUpdateConduits.Response = TwitchUpdateConduits.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## NEW Deletes a specified conduit. +## +## id - Conduit ID. +## +## https://dev.twitch.tv/docs/api/reference#delete-conduit +func delete_conduit(id: String) -> BufferedHTTPClient.ResponseData: + var path = "/eventsub/conduits?" + path += "id=" + str(id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_DELETE, "", "") + return response + + +## NEW Gets a lists of all shards for a conduit. +## +## conduit_id - Conduit ID. +## +## https://dev.twitch.tv/docs/api/reference#get-conduit-shards +func get_conduit_shards(opt: TwitchGetConduitShards.Opt, conduit_id: String) -> TwitchGetConduitShards.Response: + var path = "/eventsub/conduits/shards?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "conduit_id=" + str(conduit_id) + "&" + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("status"): + path += "status=" + str(optionals.status) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetConduitShards.Response = TwitchGetConduitShards.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_conduit_shards.bind(opt, conduit_id) + return parsed_result + + +## NEW Updates shard(s) for a conduit. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#update-conduit-shards +func update_conduit_shards(body: TwitchUpdateConduitShards.Body) -> TwitchUpdateConduitShards.Response: + var path = "/eventsub/conduits/shards?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PATCH, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchUpdateConduitShards.Response = TwitchUpdateConduitShards.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets information about Twitch content classification labels. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-content-classification-labels +func get_content_classification_labels(opt: TwitchGetContentClassificationLabels.Opt) -> TwitchGetContentClassificationLabels.Response: + var path = "/content_classification_labels?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("locale"): + path += "locale=" + str(optionals.locale) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetContentClassificationLabels.Response = TwitchGetContentClassificationLabels.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets an organization’s list of entitlements that have been granted to a game, a user, or both. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-drops-entitlements +func get_drops_entitlements(opt: TwitchGetDropsEntitlements.Opt) -> TwitchGetDropsEntitlements.Response: + var path = "/entitlements/drops?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("fulfillment_status"): + path += "fulfillment_status=" + str(optionals.fulfillment_status) + "&" + if optionals.has("game_id"): + path += "game_id=" + str(optionals.game_id) + "&" + if optionals.has("id"): + + for param in optionals.id: + path += "id=" + str(param) + "&" + if optionals.has("user_id"): + path += "user_id=" + str(optionals.user_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetDropsEntitlements.Response = TwitchGetDropsEntitlements.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_drops_entitlements.bind(opt) + return parsed_result + + +## Updates the Drop entitlement’s fulfillment status. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#update-drops-entitlements +func update_drops_entitlements(body: TwitchUpdateDropsEntitlements.Body) -> TwitchUpdateDropsEntitlements.Response: + var path = "/entitlements/drops?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PATCH, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchUpdateDropsEntitlements.Response = TwitchUpdateDropsEntitlements.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets the specified configuration segment from the specified extension. +## +## extension_id - The ID of the extension that contains the configuration segment you want to get. +## segment - The type of configuration segment to get. Possible case-sensitive values are: +## +## * broadcaster +## * developer +## * global +## +## You may specify one or more segments. To specify multiple segments, include the `segment` parameter for each segment to get. For example, `segment=broadcaster&segment=developer`. Ignores duplicate segments. +## +## https://dev.twitch.tv/docs/api/reference#get-extension-configuration-segment +func get_extension_configuration_segment(opt: TwitchGetExtensionConfigurationSegment.Opt, extension_id: String, segment: String) -> TwitchGetExtensionConfigurationSegment.Response: + var path = "/extensions/configurations?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "extension_id=" + str(extension_id) + "&" + path += "segment=" + str(segment) + "&" + if optionals.has("broadcaster_id"): + path += "broadcaster_id=" + str(optionals.broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetExtensionConfigurationSegment.Response = TwitchGetExtensionConfigurationSegment.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Updates a configuration segment. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#set-extension-configuration-segment +func set_extension_configuration_segment(body: TwitchSetExtensionConfigurationSegment.Body) -> BufferedHTTPClient.ResponseData: + var path = "/extensions/configurations?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PUT, body, "application/json") + return response + + +## Updates the extension’s required_configuration string. +## +## broadcaster_id - The ID of the broadcaster that installed the extension on their channel. +## +## https://dev.twitch.tv/docs/api/reference#set-extension-required-configuration +func set_extension_required_configuration(body: TwitchSetExtensionRequiredConfiguration.Body, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/extensions/required_configuration?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PUT, body, "application/json") + return response + + +## Sends a message to one or more viewers. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#send-extension-pubsub-message +func send_extension_pubsub_message(body: TwitchSendExtensionPubSubMessage.Body) -> BufferedHTTPClient.ResponseData: + var path = "/extensions/pubsub?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, body, "application/json") + return response + + +## Gets a list of broadcasters that are streaming live and have installed or activated the extension. +## +## extension_id - The ID of the extension to get. Returns the list of broadcasters that are live and that have installed or activated this extension. +## +## https://dev.twitch.tv/docs/api/reference#get-extension-live-channels +func get_extension_live_channels(opt: TwitchGetExtensionLiveChannels.Opt, extension_id: String) -> TwitchGetExtensionLiveChannels.Response: + var path = "/extensions/live?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "extension_id=" + str(extension_id) + "&" + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetExtensionLiveChannels.Response = TwitchGetExtensionLiveChannels.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination + opt.after = cursor + parsed_result._next_page = get_extension_live_channels.bind(opt, extension_id) + return parsed_result + + +## Gets an extension’s list of shared secrets. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-extension-secrets +func get_extension_secrets() -> TwitchGetExtensionSecrets.Response: + var path = "/extensions/jwt/secrets?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetExtensionSecrets.Response = TwitchGetExtensionSecrets.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Creates a shared secret used to sign and verify JWT tokens. +## +## extension_id - The ID of the extension to apply the shared secret to. +## +## https://dev.twitch.tv/docs/api/reference#create-extension-secret +func create_extension_secret(opt: TwitchCreateExtensionSecret.Opt, extension_id: String) -> TwitchCreateExtensionSecret.Response: + var path = "/extensions/jwt/secrets?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "extension_id=" + str(extension_id) + "&" + if optionals.has("delay"): + path += "delay=" + str(optionals.delay) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchCreateExtensionSecret.Response = TwitchCreateExtensionSecret.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Sends a message to the specified broadcaster’s chat room. +## +## broadcaster_id - The ID of the broadcaster that has activated the extension. +## +## https://dev.twitch.tv/docs/api/reference#send-extension-chat-message +func send_extension_chat_message(body: TwitchSendExtensionChatMessage.Body, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/extensions/chat?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, body, "application/json") + return response + + +## Gets information about an extension. +## +## extension_id - The ID of the extension to get. +## +## https://dev.twitch.tv/docs/api/reference#get-extensions +func get_extensions(opt: TwitchGetExtensions.Opt, extension_id: String) -> TwitchGetExtensions.Response: + var path = "/extensions?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "extension_id=" + str(extension_id) + "&" + if optionals.has("extension_version"): + path += "extension_version=" + str(optionals.extension_version) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetExtensions.Response = TwitchGetExtensions.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets information about a released extension. +## +## extension_id - The ID of the extension to get. +## +## https://dev.twitch.tv/docs/api/reference#get-released-extensions +func get_released_extensions(opt: TwitchGetReleasedExtensions.Opt, extension_id: String) -> TwitchGetReleasedExtensions.Response: + var path = "/extensions/released?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "extension_id=" + str(extension_id) + "&" + if optionals.has("extension_version"): + path += "extension_version=" + str(optionals.extension_version) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetReleasedExtensions.Response = TwitchGetReleasedExtensions.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets the list of Bits products that belongs to the extension. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-extension-bits-products +func get_extension_bits_products(opt: TwitchGetExtensionBitsProducts.Opt) -> TwitchGetExtensionBitsProducts.Response: + var path = "/bits/extensions?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("should_include_all"): + path += "should_include_all=" + str(optionals.should_include_all) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetExtensionBitsProducts.Response = TwitchGetExtensionBitsProducts.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Adds or updates a Bits product that the extension created. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#update-extension-bits-product +func update_extension_bits_product(body: TwitchUpdateExtensionBitsProduct.Body) -> TwitchUpdateExtensionBitsProduct.Response: + var path = "/bits/extensions?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PUT, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchUpdateExtensionBitsProduct.Response = TwitchUpdateExtensionBitsProduct.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Creates an EventSub subscription. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#create-eventsub-subscription +func create_eventsub_subscription(body: TwitchCreateEventSubSubscription.Body) -> TwitchCreateEventSubSubscription.Response: + var path = "/eventsub/subscriptions?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchCreateEventSubSubscription.Response = TwitchCreateEventSubSubscription.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Deletes an EventSub subscription. +## +## id - The ID of the subscription to delete. +## +## https://dev.twitch.tv/docs/api/reference#delete-eventsub-subscription +func delete_eventsub_subscription(id: String) -> BufferedHTTPClient.ResponseData: + var path = "/eventsub/subscriptions?" + path += "id=" + str(id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_DELETE, "", "") + return response + + +## Gets a list of EventSub subscriptions that the client in the access token created. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-eventsub-subscriptions +func get_eventsub_subscriptions(opt: TwitchGetEventsubSubscriptions.Opt) -> TwitchGetEventSubSubscriptions.Response: + var path = "/eventsub/subscriptions?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("status"): + path += "status=" + str(optionals.status) + "&" + if optionals.has("type"): + path += "type=" + str(optionals.type) + "&" + if optionals.has("user_id"): + path += "user_id=" + str(optionals.user_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetEventSubSubscriptions.Response = TwitchGetEventSubSubscriptions.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_eventsub_subscriptions.bind(opt) + return parsed_result + + +## Gets information about all broadcasts on Twitch. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-top-games +func get_top_games(opt: TwitchGetTopGames.Opt) -> TwitchGetTopGames.Response: + var path = "/games/top?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("before"): + path += "before=" + str(optionals.before) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetTopGames.Response = TwitchGetTopGames.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_top_games.bind(opt) + return parsed_result + + +## Gets information about specified games. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-games +func get_games(opt: TwitchGetGames.Opt) -> TwitchGetGames.Response: + var path = "/games?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("id"): + + for param in optionals.id: + path += "id=" + str(param) + "&" + if optionals.has("igdb_id"): + + for param in optionals.igdb_id: + path += "igdb_id=" + str(param) + "&" + if optionals.has("name"): + + for param in optionals.name: + path += "name=" + str(param) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetGames.Response = TwitchGetGames.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets the broadcaster’s list of active goals. +## +## broadcaster_id - The ID of the broadcaster that created the goals. This ID must match the user ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#get-creator-goals +func get_creator_goals(broadcaster_id: String) -> TwitchGetCreatorGoals.Response: + var path = "/goals?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetCreatorGoals.Response = TwitchGetCreatorGoals.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## BETA Gets the channel settings for configuration of the Guest Star feature for a particular host. +## +## broadcaster_id - The ID of the broadcaster you want to get guest star settings for. +## moderator_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s chat room. This ID must match the user ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#get-channel-guest-star-settings +func get_channel_guest_star_settings(moderator_id: String, broadcaster_id: String) -> TwitchGetChannelGuestStarSettings.Response: + var path = "/guest_star/channel_settings?" + path += "moderator_id=" + str(moderator_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetChannelGuestStarSettings.Response = TwitchGetChannelGuestStarSettings.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## BETA Mutates the channel settings for configuration of the Guest Star feature for a particular host. +## +## broadcaster_id - The ID of the broadcaster you want to update Guest Star settings for. +## +## https://dev.twitch.tv/docs/api/reference#update-channel-guest-star-settings +func update_channel_guest_star_settings(body: TwitchUpdateChannelGuestStarSettings.Body, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/guest_star/channel_settings?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PUT, body, "application/json") + return response + + +## BETA Gets information about an ongoing Guest Star session for a particular channel. +## +## broadcaster_id - ID for the user hosting the Guest Star session. +## moderator_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s chat room. This ID must match the user ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#get-guest-star-session +func get_guest_star_session(moderator_id: String, broadcaster_id: String) -> TwitchGetGuestStarSession.Response: + var path = "/guest_star/session?" + path += "moderator_id=" + str(moderator_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetGuestStarSession.Response = TwitchGetGuestStarSession.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## BETA Programmatically creates a Guest Star session on behalf of the broadcaster. +## +## broadcaster_id - The ID of the broadcaster you want to create a Guest Star session for. Provided `broadcaster_id` must match the `user_id` in the auth token. +## +## https://dev.twitch.tv/docs/api/reference#create-guest-star-session +func create_guest_star_session(broadcaster_id: String) -> TwitchCreateGuestStarSession.Response: + var path = "/guest_star/session?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchCreateGuestStarSession.Response = TwitchCreateGuestStarSession.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## BETA Programmatically ends a Guest Star session on behalf of the broadcaster. +## +## broadcaster_id - The ID of the broadcaster you want to end a Guest Star session for. Provided `broadcaster_id` must match the `user_id` in the auth token. +## session_id - ID for the session to end on behalf of the broadcaster. +## +## https://dev.twitch.tv/docs/api/reference#end-guest-star-session +func end_guest_star_session(session_id: String, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/guest_star/session?" + path += "session_id=" + str(session_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_DELETE, "", "") + return response + + +## BETA Provides the caller with a list of pending invites to a Guest Star session. +## +## broadcaster_id - The ID of the broadcaster running the Guest Star session. +## moderator_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s chat room. This ID must match the `user_id` in the user access token. +## session_id - The session ID to query for invite status. +## +## https://dev.twitch.tv/docs/api/reference#get-guest-star-invites +func get_guest_star_invites(moderator_id: String, session_id: String, broadcaster_id: String) -> TwitchGetGuestStarInvites.Response: + var path = "/guest_star/invites?" + path += "moderator_id=" + str(moderator_id) + "&" + path += "session_id=" + str(session_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetGuestStarInvites.Response = TwitchGetGuestStarInvites.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## BETA Sends an invite to a specified guest on behalf of the broadcaster for a Guest Star session in progress. +## +## broadcaster_id - The ID of the broadcaster running the Guest Star session. +## moderator_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s chat room. This ID must match the `user_id` in the user access token. +## session_id - The session ID for the invite to be sent on behalf of the broadcaster. +## guest_id - Twitch User ID for the guest to invite to the Guest Star session. +## +## https://dev.twitch.tv/docs/api/reference#send-guest-star-invite +func send_guest_star_invite(guest_id: String, moderator_id: String, session_id: String, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/guest_star/invites?" + path += "guest_id=" + str(guest_id) + "&" + path += "moderator_id=" + str(moderator_id) + "&" + path += "session_id=" + str(session_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, "", "") + return response + + +## BETA Revokes a previously sent invite for a Guest Star session. +## +## broadcaster_id - The ID of the broadcaster running the Guest Star session. +## moderator_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s chat room. This ID must match the `user_id` in the user access token. +## session_id - The ID of the session for the invite to be revoked on behalf of the broadcaster. +## guest_id - Twitch User ID for the guest to revoke the Guest Star session invite from. +## +## https://dev.twitch.tv/docs/api/reference#delete-guest-star-invite +func delete_guest_star_invite(guest_id: String, moderator_id: String, session_id: String, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/guest_star/invites?" + path += "guest_id=" + str(guest_id) + "&" + path += "moderator_id=" + str(moderator_id) + "&" + path += "session_id=" + str(session_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_DELETE, "", "") + return response + + +## BETA Allows a previously invited user to be assigned a slot within the active Guest Star session. +## +## broadcaster_id - The ID of the broadcaster running the Guest Star session. +## moderator_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s chat room. This ID must match the `user_id` in the user access token. +## session_id - The ID of the Guest Star session in which to assign the slot. +## guest_id - The Twitch User ID corresponding to the guest to assign a slot in the session. This user must already have an invite to this session, and have indicated that they are ready to join. +## slot_id - The slot assignment to give to the user. Must be a numeric identifier between “1” and “N” where N is the max number of slots for the session. Max number of slots allowed for the session is reported by [Get Channel Guest Star Settings](https://dev.twitch.tv/docs/api/reference#get-channel-guest-star-settings). +## +## https://dev.twitch.tv/docs/api/reference#assign-guest-star-slot +func assign_guest_star_slot(guest_id: String, moderator_id: String, session_id: String, slot_id: String, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/guest_star/slot?" + path += "guest_id=" + str(guest_id) + "&" + path += "moderator_id=" + str(moderator_id) + "&" + path += "session_id=" + str(session_id) + "&" + path += "slot_id=" + str(slot_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, "", "") + return response + + +## BETA Allows a user to update the assigned slot for a particular user within the active Guest Star session. +## +## broadcaster_id - The ID of the broadcaster running the Guest Star session. +## moderator_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s chat room. This ID must match the `user_id` in the user access token. +## session_id - The ID of the Guest Star session in which to update slot settings. +## source_slot_id - The slot assignment previously assigned to a user. +## +## https://dev.twitch.tv/docs/api/reference#update-guest-star-slot +func update_guest_star_slot(opt: TwitchUpdateGuestStarSlot.Opt, moderator_id: String, session_id: String, source_slot_id: String, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/guest_star/slot?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "moderator_id=" + str(moderator_id) + "&" + path += "session_id=" + str(session_id) + "&" + path += "source_slot_id=" + str(source_slot_id) + "&" + if optionals.has("destination_slot_id"): + path += "destination_slot_id=" + str(optionals.destination_slot_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PATCH, "", "") + return response + + +## BETA Allows a caller to remove a slot assignment from a user participating in an active Guest Star session. +## +## broadcaster_id - The ID of the broadcaster running the Guest Star session. +## moderator_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s chat room. This ID must match the user ID in the user access token. +## session_id - The ID of the Guest Star session in which to remove the slot assignment. +## guest_id - The Twitch User ID corresponding to the guest to remove from the session. +## slot_id - The slot ID representing the slot assignment to remove from the session. +## +## https://dev.twitch.tv/docs/api/reference#delete-guest-star-slot +func delete_guest_star_slot(opt: TwitchDeleteGuestStarSlot.Opt, guest_id: String, moderator_id: String, session_id: String, slot_id: String, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/guest_star/slot?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "guest_id=" + str(guest_id) + "&" + path += "moderator_id=" + str(moderator_id) + "&" + path += "session_id=" + str(session_id) + "&" + path += "slot_id=" + str(slot_id) + "&" + if optionals.has("should_reinvite_guest"): + path += "should_reinvite_guest=" + str(optionals.should_reinvite_guest) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_DELETE, "", "") + return response + + +## BETA Allows a user to update slot settings for a particular guest within a Guest Star session. +## +## broadcaster_id - The ID of the broadcaster running the Guest Star session. +## moderator_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s chat room. This ID must match the user ID in the user access token. +## session_id - The ID of the Guest Star session in which to update a slot’s settings. +## slot_id - The slot assignment that has previously been assigned to a user. +## +## https://dev.twitch.tv/docs/api/reference#update-guest-star-slot-settings +func update_guest_star_slot_settings(opt: TwitchUpdateGuestStarSlotSettings.Opt, moderator_id: String, session_id: String, slot_id: String, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/guest_star/slot_settings?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "moderator_id=" + str(moderator_id) + "&" + path += "session_id=" + str(session_id) + "&" + path += "slot_id=" + str(slot_id) + "&" + if optionals.has("is_audio_enabled"): + path += "is_audio_enabled=" + str(optionals.is_audio_enabled) + "&" + if optionals.has("is_live"): + path += "is_live=" + str(optionals.is_live) + "&" + if optionals.has("is_video_enabled"): + path += "is_video_enabled=" + str(optionals.is_video_enabled) + "&" + if optionals.has("volume"): + path += "volume=" + str(optionals.volume) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PATCH, "", "") + return response + + +## Gets information about the broadcaster’s current or most recent Hype Train event. +## +## broadcaster_id - The ID of the broadcaster that’s running the Hype Train. This ID must match the User ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#get-hype-train-events +func get_hype_train_events(opt: TwitchGetHypeTrainEvents.Opt, broadcaster_id: String) -> TwitchGetHypeTrainEvents.Response: + var path = "/hypetrain/events?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetHypeTrainEvents.Response = TwitchGetHypeTrainEvents.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_hype_train_events.bind(opt, broadcaster_id) + return parsed_result + + +## Checks whether AutoMod would flag the specified message for review. +## +## broadcaster_id - The ID of the broadcaster whose AutoMod settings and list of blocked terms are used to check the message. This ID must match the user ID in the access token. +## +## https://dev.twitch.tv/docs/api/reference#check-automod-status +func check_automod_status(body: TwitchCheckAutoModStatus.Body, broadcaster_id: String) -> TwitchCheckAutoModStatus.Response: + var path = "/moderation/enforcements/status?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchCheckAutoModStatus.Response = TwitchCheckAutoModStatus.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Allow or deny the message that AutoMod flagged for review. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#manage-held-automod-messages +func manage_held_automod_messages(body: TwitchManageHeldAutoModMessages.Body) -> BufferedHTTPClient.ResponseData: + var path = "/moderation/automod/message?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, body, "application/json") + return response + + +## Gets the broadcaster’s AutoMod settings. +## +## broadcaster_id - The ID of the broadcaster whose AutoMod settings you want to get. +## moderator_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s chat room. This ID must match the user ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#get-automod-settings +func get_automod_settings(moderator_id: String, broadcaster_id: String) -> TwitchGetAutoModSettings.Response: + var path = "/moderation/automod/settings?" + path += "moderator_id=" + str(moderator_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetAutoModSettings.Response = TwitchGetAutoModSettings.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Updates the broadcaster’s AutoMod settings. +## +## broadcaster_id - The ID of the broadcaster whose AutoMod settings you want to update. +## moderator_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s chat room. This ID must match the user ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#update-automod-settings +func update_automod_settings(body: TwitchUpdateAutoModSettings.Body, moderator_id: String, broadcaster_id: String) -> TwitchUpdateAutoModSettings.Response: + var path = "/moderation/automod/settings?" + path += "moderator_id=" + str(moderator_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PUT, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchUpdateAutoModSettings.Response = TwitchUpdateAutoModSettings.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets all users that the broadcaster banned or put in a timeout. +## +## broadcaster_id - The ID of the broadcaster whose list of banned users you want to get. This ID must match the user ID in the access token. +## +## https://dev.twitch.tv/docs/api/reference#get-banned-users +func get_banned_users(opt: TwitchGetBannedUsers.Opt, broadcaster_id: String) -> TwitchGetBannedUsers.Response: + var path = "/moderation/banned?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("before"): + path += "before=" + str(optionals.before) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("user_id"): + + for param in optionals.user_id: + path += "user_id=" + str(param) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetBannedUsers.Response = TwitchGetBannedUsers.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_banned_users.bind(opt, broadcaster_id) + return parsed_result + + +## Bans a user from participating in a broadcaster’s chat room or puts them in a timeout. +## +## broadcaster_id - The ID of the broadcaster whose chat room the user is being banned from. +## moderator_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s chat room. This ID must match the user ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#ban-user +func ban_user(body: TwitchBanUser.Body, moderator_id: String, broadcaster_id: String) -> TwitchBanUser.Response: + var path = "/moderation/bans?" + path += "moderator_id=" + str(moderator_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchBanUser.Response = TwitchBanUser.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Removes the ban or timeout that was placed on the specified user. +## +## broadcaster_id - The ID of the broadcaster whose chat room the user is banned from chatting in. +## moderator_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s chat room. This ID must match the user ID in the user access token. +## user_id - The ID of the user to remove the ban or timeout from. +## +## https://dev.twitch.tv/docs/api/reference#unban-user +func unban_user(moderator_id: String, user_id: String, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/moderation/bans?" + path += "moderator_id=" + str(moderator_id) + "&" + path += "user_id=" + str(user_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_DELETE, "", "") + return response + + +## NEW Gets a list of unban requests for a broadcaster’s channel. +## +## broadcaster_id - The ID of the broadcaster whose channel is receiving unban requests. +## moderator_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s unban requests. This ID must match the user ID in the user access token. +## status - Filter by a status. +## +## * pending +## * approved +## * denied +## * acknowledged +## * canceled +## +## https://dev.twitch.tv/docs/api/reference#get-unban-requests +func get_unban_requests(opt: TwitchGetUnbanRequests.Opt, moderator_id: String, status: String, broadcaster_id: String) -> TwitchGetUnbanRequests.Response: + var path = "/moderation/unban_requests?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "moderator_id=" + str(moderator_id) + "&" + path += "status=" + str(status) + "&" + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("user_id"): + path += "user_id=" + str(optionals.user_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetUnbanRequests.Response = TwitchGetUnbanRequests.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_unban_requests.bind(opt, moderator_id, status, broadcaster_id) + return parsed_result + + +## NEW Resolves an unban request by approving or denying it. +## +## broadcaster_id - The ID of the broadcaster whose channel is approving or denying the unban request. +## moderator_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s unban requests. This ID must match the user ID in the user access token. +## unban_request_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s unban requests. This ID must match the user ID in the user access token. +## status - Resolution status. +## +## * approved +## * denied +## +## https://dev.twitch.tv/docs/api/reference#resolve-unban-requests +func resolve_unban_requests(opt: TwitchResolveUnbanRequests.Opt, moderator_id: String, status: String, unban_request_id: String, broadcaster_id: String) -> TwitchResolveUnbanRequests.Response: + var path = "/moderation/unban_requests?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "moderator_id=" + str(moderator_id) + "&" + path += "status=" + str(status) + "&" + path += "unban_request_id=" + str(unban_request_id) + "&" + if optionals.has("resolution_text"): + path += "resolution_text=" + str(optionals.resolution_text) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PATCH, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchResolveUnbanRequests.Response = TwitchResolveUnbanRequests.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets the broadcaster’s list of non-private, blocked words or phrases. +## +## broadcaster_id - The ID of the broadcaster whose blocked terms you’re getting. +## moderator_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s chat room. This ID must match the user ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#get-blocked-terms +func get_blocked_terms(opt: TwitchGetBlockedTerms.Opt, moderator_id: String, broadcaster_id: String) -> TwitchGetBlockedTerms.Response: + var path = "/moderation/blocked_terms?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "moderator_id=" + str(moderator_id) + "&" + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetBlockedTerms.Response = TwitchGetBlockedTerms.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_blocked_terms.bind(opt, moderator_id, broadcaster_id) + return parsed_result + + +## Adds a word or phrase to the broadcaster’s list of blocked terms. +## +## broadcaster_id - The ID of the broadcaster that owns the list of blocked terms. +## moderator_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s chat room. This ID must match the user ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#add-blocked-term +func add_blocked_term(body: TwitchAddBlockedTerm.Body, moderator_id: String, broadcaster_id: String) -> TwitchAddBlockedTerm.Response: + var path = "/moderation/blocked_terms?" + path += "moderator_id=" + str(moderator_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchAddBlockedTerm.Response = TwitchAddBlockedTerm.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Removes the word or phrase from the broadcaster’s list of blocked terms. +## +## broadcaster_id - The ID of the broadcaster that owns the list of blocked terms. +## moderator_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s chat room. This ID must match the user ID in the user access token. +## id - The ID of the blocked term to remove from the broadcaster’s list of blocked terms. +## +## https://dev.twitch.tv/docs/api/reference#remove-blocked-term +func remove_blocked_term(id: String, moderator_id: String, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/moderation/blocked_terms?" + path += "id=" + str(id) + "&" + path += "moderator_id=" + str(moderator_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_DELETE, "", "") + return response + + +## Removes a single chat message or all chat messages from the broadcaster’s chat room. +## +## broadcaster_id - The ID of the broadcaster that owns the chat room to remove messages from. +## moderator_id - The ID of the broadcaster or a user that has permission to moderate the broadcaster’s chat room. This ID must match the user ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#delete-chat-messages +func delete_chat_messages(opt: TwitchDeleteChatMessages.Opt, moderator_id: String, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/moderation/chat?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "moderator_id=" + str(moderator_id) + "&" + if optionals.has("message_id"): + path += "message_id=" + str(optionals.message_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_DELETE, "", "") + return response + + +## Gets a list of channels that the specified user has moderator privileges in. +## +## user_id - A user’s ID. Returns the list of channels that this user has moderator privileges in. This ID must match the user ID in the user OAuth token +## +## https://dev.twitch.tv/docs/api/reference#get-moderated-channels +func get_moderated_channels(opt: TwitchGetModeratedChannels.Opt, user_id: String) -> TwitchGetModeratedChannels.Response: + var path = "/moderation/channels?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "user_id=" + str(user_id) + "&" + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetModeratedChannels.Response = TwitchGetModeratedChannels.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_moderated_channels.bind(opt, user_id) + return parsed_result + + +## Gets all users allowed to moderate the broadcaster’s chat room. +## +## broadcaster_id - The ID of the broadcaster whose list of moderators you want to get. This ID must match the user ID in the access token. +## +## https://dev.twitch.tv/docs/api/reference#get-moderators +func get_moderators(opt: TwitchGetModerators.Opt, broadcaster_id: String) -> TwitchGetModerators.Response: + var path = "/moderation/moderators?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("user_id"): + + for param in optionals.user_id: + path += "user_id=" + str(param) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetModerators.Response = TwitchGetModerators.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_moderators.bind(opt, broadcaster_id) + return parsed_result + + +## Adds a moderator to the broadcaster’s chat room. +## +## broadcaster_id - The ID of the broadcaster that owns the chat room. This ID must match the user ID in the access token. +## user_id - The ID of the user to add as a moderator in the broadcaster’s chat room. +## +## https://dev.twitch.tv/docs/api/reference#add-channel-moderator +func add_channel_moderator(user_id: String, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/moderation/moderators?" + path += "user_id=" + str(user_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, "", "") + return response + + +## Removes a moderator from the broadcaster’s chat room. +## +## broadcaster_id - The ID of the broadcaster that owns the chat room. This ID must match the user ID in the access token. +## user_id - The ID of the user to remove as a moderator from the broadcaster’s chat room. +## +## https://dev.twitch.tv/docs/api/reference#remove-channel-moderator +func remove_channel_moderator(user_id: String, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/moderation/moderators?" + path += "user_id=" + str(user_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_DELETE, "", "") + return response + + +## Gets a list of the broadcaster’s VIPs. +## +## broadcaster_id - The ID of the broadcaster whose list of VIPs you want to get. This ID must match the user ID in the access token. +## +## https://dev.twitch.tv/docs/api/reference#get-vips +func get_vips(opt: TwitchGetVips.Opt, broadcaster_id: String) -> TwitchGetVIPs.Response: + var path = "/channels/vips?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("user_id"): + + for param in optionals.user_id: + path += "user_id=" + str(param) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetVIPs.Response = TwitchGetVIPs.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_vips.bind(opt, broadcaster_id) + return parsed_result + + +## Adds the specified user as a VIP in the broadcaster’s channel. +## +## user_id - The ID of the user to give VIP status to. +## broadcaster_id - The ID of the broadcaster that’s adding the user as a VIP. This ID must match the user ID in the access token. +## +## https://dev.twitch.tv/docs/api/reference#add-channel-vip +func add_channel_vip(user_id: String, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/channels/vips?" + path += "user_id=" + str(user_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, "", "") + return response + + +## Removes the specified user as a VIP in the broadcaster’s channel. +## +## user_id - The ID of the user to remove VIP status from. +## broadcaster_id - The ID of the broadcaster who owns the channel where the user has VIP status. +## +## https://dev.twitch.tv/docs/api/reference#remove-channel-vip +func remove_channel_vip(user_id: String, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/channels/vips?" + path += "user_id=" + str(user_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_DELETE, "", "") + return response + + +## Activates or deactivates the broadcaster’s Shield Mode. +## +## broadcaster_id - The ID of the broadcaster whose Shield Mode you want to activate or deactivate. +## moderator_id - The ID of the broadcaster or a user that is one of the broadcaster’s moderators. This ID must match the user ID in the access token. +## +## https://dev.twitch.tv/docs/api/reference#update-shield-mode-status +func update_shield_mode_status(body: TwitchUpdateShieldModeStatus.Body, moderator_id: String, broadcaster_id: String) -> TwitchUpdateShieldModeStatus.Response: + var path = "/moderation/shield_mode?" + path += "moderator_id=" + str(moderator_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PUT, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchUpdateShieldModeStatus.Response = TwitchUpdateShieldModeStatus.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets the broadcaster’s Shield Mode activation status. +## +## broadcaster_id - The ID of the broadcaster whose Shield Mode activation status you want to get. +## moderator_id - The ID of the broadcaster or a user that is one of the broadcaster’s moderators. This ID must match the user ID in the access token. +## +## https://dev.twitch.tv/docs/api/reference#get-shield-mode-status +func get_shield_mode_status(moderator_id: String, broadcaster_id: String) -> TwitchGetShieldModeStatus.Response: + var path = "/moderation/shield_mode?" + path += "moderator_id=" + str(moderator_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetShieldModeStatus.Response = TwitchGetShieldModeStatus.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## NEW Warns a user in the specified broadcaster’s chat room, preventing them from chat interaction until the warning is acknowledged. +## +## broadcaster_id - The ID of the channel in which the warning will take effect. +## moderator_id - The ID of the twitch user who requested the warning. +## +## https://dev.twitch.tv/docs/api/reference#warn-chat-user +func warn_chat_user(body: TwitchWarnChatUser.Body, moderator_id: String, broadcaster_id: String) -> TwitchWarnChatUser.Response: + var path = "/moderation/warnings?" + path += "moderator_id=" + str(moderator_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchWarnChatUser.Response = TwitchWarnChatUser.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets a list of polls that the broadcaster created. +## +## broadcaster_id - The ID of the broadcaster that created the polls. This ID must match the user ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#get-polls +func get_polls(opt: TwitchGetPolls.Opt, broadcaster_id: String) -> TwitchGetPolls.Response: + var path = "/polls?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("id"): + + for param in optionals.id: + path += "id=" + str(param) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetPolls.Response = TwitchGetPolls.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_polls.bind(opt, broadcaster_id) + return parsed_result + + +## Creates a poll that viewers in the broadcaster’s channel can vote on. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#create-poll +func create_poll(body: TwitchCreatePoll.Body) -> TwitchCreatePoll.Response: + var path = "/polls?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchCreatePoll.Response = TwitchCreatePoll.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## End an active poll. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#end-poll +func end_poll(body: TwitchEndPoll.Body) -> TwitchEndPoll.Response: + var path = "/polls?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PATCH, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchEndPoll.Response = TwitchEndPoll.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets a list of Channel Points Predictions that the broadcaster created. +## +## broadcaster_id - The ID of the broadcaster whose predictions you want to get. This ID must match the user ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#get-predictions +func get_predictions(opt: TwitchGetPredictions.Opt, broadcaster_id: String) -> TwitchGetPredictions.Response: + var path = "/predictions?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("id"): + + for param in optionals.id: + path += "id=" + str(param) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetPredictions.Response = TwitchGetPredictions.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_predictions.bind(opt, broadcaster_id) + return parsed_result + + +## Create a Channel Points Prediction. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#create-prediction +func create_prediction(body: TwitchCreatePrediction.Body) -> TwitchCreatePrediction.Response: + var path = "/predictions?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchCreatePrediction.Response = TwitchCreatePrediction.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Locks, resolves, or cancels a Channel Points Prediction. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#end-prediction +func end_prediction(body: TwitchEndPrediction.Body) -> TwitchEndPrediction.Response: + var path = "/predictions?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PATCH, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchEndPrediction.Response = TwitchEndPrediction.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Raid another channel by sending the broadcaster’s viewers to the targeted channel. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#start-a-raid +func start_a_raid(opt: TwitchStartARaid.Opt) -> TwitchStartRaid.Response: + var path = "/raids?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("from_broadcaster_id"): + path += "from_broadcaster_id=" + str(optionals.from_broadcaster_id) + "&" + if optionals.has("to_broadcaster_id"): + path += "to_broadcaster_id=" + str(optionals.to_broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchStartRaid.Response = TwitchStartRaid.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Cancel a pending raid. +## +## broadcaster_id - The ID of the broadcaster that initiated the raid. This ID must match the user ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#cancel-a-raid +func cancel_a_raid(broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/raids?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_DELETE, "", "") + return response + + +## Gets the broadcaster’s streaming schedule. +## +## broadcaster_id - The ID of the broadcaster that owns the streaming schedule you want to get. +## +## https://dev.twitch.tv/docs/api/reference#get-channel-stream-schedule +func get_channel_stream_schedule(opt: TwitchGetChannelStreamSchedule.Opt, broadcaster_id: String) -> TwitchGetChannelStreamSchedule.Response: + var path = "/schedule?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("id"): + + for param in optionals.id: + path += "id=" + str(param) + "&" + if optionals.has("start_time"): + path += "start_time=" + get_rfc_3339_date_format(optionals.start_time) + "&" + if optionals.has("utc_offset"): + path += "utc_offset=" + str(optionals.utc_offset) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetChannelStreamSchedule.Response = TwitchGetChannelStreamSchedule.Response.from_json(result) + parsed_result.response = response + + if parsed_result.data.pagination != null: + opt.after = parsed_result.data.pagination.cursor + parsed_result.data._next_page = get_channel_stream_schedule.bind(opt, broadcaster_id) + return parsed_result + + +## Gets the broadcaster’s streaming schedule as an iCalendar. +## +## broadcaster_id - The ID of the broadcaster that owns the streaming schedule you want to get. +## +## https://dev.twitch.tv/docs/api/reference#get-channel-icalendar +func get_channel_icalendar(broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/schedule/icalendar?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + return response + + +## Updates the broadcaster’s schedule settings, such as scheduling a vacation. +## +## broadcaster_id - The ID of the broadcaster whose schedule settings you want to update. The ID must match the user ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#update-channel-stream-schedule +func update_channel_stream_schedule(opt: TwitchUpdateChannelStreamSchedule.Opt, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/schedule/settings?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("is_vacation_enabled"): + path += "is_vacation_enabled=" + str(optionals.is_vacation_enabled) + "&" + if optionals.has("timezone"): + path += "timezone=" + str(optionals.timezone) + "&" + if optionals.has("vacation_end_time"): + path += "vacation_end_time=" + get_rfc_3339_date_format(optionals.vacation_end_time) + "&" + if optionals.has("vacation_start_time"): + path += "vacation_start_time=" + get_rfc_3339_date_format(optionals.vacation_start_time) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PATCH, "", "") + return response + + +## Adds a single or recurring broadcast to the broadcaster’s streaming schedule. +## +## broadcaster_id - The ID of the broadcaster that owns the schedule to add the broadcast segment to. This ID must match the user ID in the user access token. +## +## https://dev.twitch.tv/docs/api/reference#create-channel-stream-schedule-segment +func create_channel_stream_schedule_segment(body: TwitchCreateChannelStreamScheduleSegment.Body, broadcaster_id: String) -> TwitchCreateChannelStreamScheduleSegment.Response: + var path = "/schedule/segment?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchCreateChannelStreamScheduleSegment.Response = TwitchCreateChannelStreamScheduleSegment.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Updates a scheduled broadcast segment. +## +## broadcaster_id - The ID of the broadcaster who owns the broadcast segment to update. This ID must match the user ID in the user access token. +## id - The ID of the broadcast segment to update. +## +## https://dev.twitch.tv/docs/api/reference#update-channel-stream-schedule-segment +func update_channel_stream_schedule_segment(body: TwitchUpdateChannelStreamScheduleSegment.Body, id: String, broadcaster_id: String) -> TwitchUpdateChannelStreamScheduleSegment.Response: + var path = "/schedule/segment?" + path += "id=" + str(id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PATCH, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchUpdateChannelStreamScheduleSegment.Response = TwitchUpdateChannelStreamScheduleSegment.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Deletes a broadcast from the broadcaster’s streaming schedule. +## +## broadcaster_id - The ID of the broadcaster that owns the streaming schedule. This ID must match the user ID in the user access token. +## id - The ID of the broadcast segment to remove. +## +## https://dev.twitch.tv/docs/api/reference#delete-channel-stream-schedule-segment +func delete_channel_stream_schedule_segment(id: String, broadcaster_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/schedule/segment?" + path += "id=" + str(id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_DELETE, "", "") + return response + + +## Gets the games or categories that match the specified query. +## +## query - The URI-encoded search string. For example, encode _#archery_ as `%23archery` and search strings like _angel of death_ as `angel%20of%20death`. +## +## https://dev.twitch.tv/docs/api/reference#search-categories +func search_categories(opt: TwitchSearchCategories.Opt, query: String) -> TwitchSearchCategories.Response: + var path = "/search/categories?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "query=" + str(query) + "&" + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchSearchCategories.Response = TwitchSearchCategories.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = search_categories.bind(opt, query) + return parsed_result + + +## Gets the channels that match the specified query and have streamed content within the past 6 months. +## +## query - The URI-encoded search string. For example, encode search strings like _angel of death_ as `angel%20of%20death`. +## +## https://dev.twitch.tv/docs/api/reference#search-channels +func search_channels(opt: TwitchSearchChannels.Opt, query: String) -> TwitchSearchChannels.Response: + var path = "/search/channels?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "query=" + str(query) + "&" + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("live_only"): + path += "live_only=" + str(optionals.live_only) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchSearchChannels.Response = TwitchSearchChannels.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = search_channels.bind(opt, query) + return parsed_result + + +## Gets the channel’s stream key. +## +## broadcaster_id - The ID of the broadcaster that owns the channel. The ID must match the user ID in the access token. +## +## https://dev.twitch.tv/docs/api/reference#get-stream-key +func get_stream_key(broadcaster_id: String) -> TwitchGetStreamKey.Response: + var path = "/streams/key?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetStreamKey.Response = TwitchGetStreamKey.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets a list of all streams. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-streams +func get_streams(opt: TwitchGetStreams.Opt) -> TwitchGetStreams.Response: + var path = "/streams?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("before"): + path += "before=" + str(optionals.before) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("game_id"): + + for param in optionals.game_id: + path += "game_id=" + str(param) + "&" + if optionals.has("language"): + + for param in optionals.language: + path += "language=" + str(param) + "&" + if optionals.has("type"): + path += "type=" + str(optionals.type) + "&" + if optionals.has("user_id"): + + for param in optionals.user_id: + path += "user_id=" + str(param) + "&" + if optionals.has("user_login"): + + for param in optionals.user_login: + path += "user_login=" + str(param) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetStreams.Response = TwitchGetStreams.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_streams.bind(opt) + return parsed_result + + +## Gets the list of broadcasters that the user follows and that are streaming live. +## +## user_id - The ID of the user whose list of followed streams you want to get. This ID must match the user ID in the access token. +## +## https://dev.twitch.tv/docs/api/reference#get-followed-streams +func get_followed_streams(opt: TwitchGetFollowedStreams.Opt, user_id: String) -> TwitchGetFollowedStreams.Response: + var path = "/streams/followed?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "user_id=" + str(user_id) + "&" + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetFollowedStreams.Response = TwitchGetFollowedStreams.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_followed_streams.bind(opt, user_id) + return parsed_result + + +## Adds a marker to a live stream. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#create-stream-marker +func create_stream_marker(body: TwitchCreateStreamMarker.Body) -> TwitchCreateStreamMarker.Response: + var path = "/streams/markers?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchCreateStreamMarker.Response = TwitchCreateStreamMarker.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets a list of markers from the user’s most recent stream or from the specified VOD/video. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-stream-markers +func get_stream_markers(opt: TwitchGetStreamMarkers.Opt) -> TwitchGetStreamMarkers.Response: + var path = "/streams/markers?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("before"): + path += "before=" + str(optionals.before) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("user_id"): + path += "user_id=" + str(optionals.user_id) + "&" + if optionals.has("video_id"): + path += "video_id=" + str(optionals.video_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetStreamMarkers.Response = TwitchGetStreamMarkers.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_stream_markers.bind(opt) + return parsed_result + + +## Gets a list of users that subscribe to the specified broadcaster. +## +## broadcaster_id - The broadcaster’s ID. This ID must match the user ID in the access token. +## +## https://dev.twitch.tv/docs/api/reference#get-broadcaster-subscriptions +func get_broadcaster_subscriptions(opt: TwitchGetBroadcasterSubscriptions.Opt, broadcaster_id: String) -> TwitchGetBroadcasterSubscriptions.Response: + var path = "/subscriptions?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("before"): + path += "before=" + str(optionals.before) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("user_id"): + + for param in optionals.user_id: + path += "user_id=" + str(param) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetBroadcasterSubscriptions.Response = TwitchGetBroadcasterSubscriptions.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_broadcaster_subscriptions.bind(opt, broadcaster_id) + return parsed_result + + +## Checks whether the user subscribes to the broadcaster’s channel. +## +## broadcaster_id - The ID of a partner or affiliate broadcaster. +## user_id - The ID of the user that you’re checking to see whether they subscribe to the broadcaster in _broadcaster\_id_. This ID must match the user ID in the access Token. +## +## https://dev.twitch.tv/docs/api/reference#check-user-subscription +func check_user_subscription(user_id: String, broadcaster_id: String) -> TwitchCheckUserSubscription.Response: + var path = "/subscriptions/user?" + path += "user_id=" + str(user_id) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchCheckUserSubscription.Response = TwitchCheckUserSubscription.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets the list of all stream tags that Twitch defines. You can also filter the list by one or more tag IDs. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-all-stream-tags +func get_all_stream_tags(opt: TwitchGetAllStreamTags.Opt) -> TwitchGetAllStreamTags.Response: + var path = "/tags/streams?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("tag_id"): + + for param in optionals.tag_id: + path += "tag_id=" + str(param) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetAllStreamTags.Response = TwitchGetAllStreamTags.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_all_stream_tags.bind(opt) + return parsed_result + + +## Gets the list of stream tags that the broadcaster or Twitch added to their channel. +## +## broadcaster_id - The ID of the broadcaster whose stream tags you want to get. +## +## https://dev.twitch.tv/docs/api/reference#get-stream-tags +func get_stream_tags(broadcaster_id: String) -> TwitchGetStreamTags.Response: + var path = "/streams/tags?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetStreamTags.Response = TwitchGetStreamTags.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets the list of Twitch teams that the broadcaster is a member of. +## +## broadcaster_id - The ID of the broadcaster whose teams you want to get. +## +## https://dev.twitch.tv/docs/api/reference#get-channel-teams +func get_channel_teams(broadcaster_id: String) -> TwitchGetChannelTeams.Response: + var path = "/teams/channel?" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetChannelTeams.Response = TwitchGetChannelTeams.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets information about the specified Twitch team. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-teams +func get_teams(opt: TwitchGetTeams.Opt) -> TwitchGetTeams.Response: + var path = "/teams?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("id"): + path += "id=" + str(optionals.id) + "&" + if optionals.has("name"): + path += "name=" + str(optionals.name) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetTeams.Response = TwitchGetTeams.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets information about one or more users. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-users +func get_users(opt: TwitchGetUsers.Opt) -> TwitchGetUsers.Response: + var path = "/users?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("id"): + + for param in optionals.id: + path += "id=" + str(param) + "&" + if optionals.has("login"): + + for param in optionals.login: + path += "login=" + str(param) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetUsers.Response = TwitchGetUsers.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Updates the user’s information. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#update-user +func update_user(opt: TwitchUpdateUser.Opt) -> TwitchUpdateUser.Response: + var path = "/users?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("description"): + path += "description=" + str(optionals.description) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PUT, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchUpdateUser.Response = TwitchUpdateUser.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets the list of users that the broadcaster has blocked. +## +## broadcaster_id - The ID of the broadcaster whose list of blocked users you want to get. +## +## https://dev.twitch.tv/docs/api/reference#get-user-block-list +func get_user_block_list(opt: TwitchGetUserBlockList.Opt, broadcaster_id: String) -> TwitchGetUserBlockList.Response: + var path = "/users/blocks?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + path += "broadcaster_id=" + str(broadcaster_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetUserBlockList.Response = TwitchGetUserBlockList.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_user_block_list.bind(opt, broadcaster_id) + return parsed_result + + +## Blocks the specified user from interacting with or having contact with the broadcaster. +## +## target_user_id - The ID of the user to block. The API ignores the request if the broadcaster has already blocked the user. +## +## https://dev.twitch.tv/docs/api/reference#block-user +func block_user(opt: TwitchBlockUser.Opt, target_user_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/users/blocks?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + path += "target_user_id=" + str(target_user_id) + "&" + if optionals.has("reason"): + path += "reason=" + str(optionals.reason) + "&" + if optionals.has("source_context"): + path += "source_context=" + str(optionals.source_context) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PUT, "", "") + return response + + +## Removes the user from the broadcaster’s list of blocked users. +## +## target_user_id - The ID of the user to remove from the broadcaster’s list of blocked users. The API ignores the request if the broadcaster hasn’t blocked the user. +## +## https://dev.twitch.tv/docs/api/reference#unblock-user +func unblock_user(target_user_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/users/blocks?" + path += "target_user_id=" + str(target_user_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_DELETE, "", "") + return response + + +## Gets a list of all extensions (both active and inactive) that the broadcaster has installed. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-user-extensions +func get_user_extensions() -> TwitchGetUserExtensions.Response: + var path = "/users/extensions/list?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetUserExtensions.Response = TwitchGetUserExtensions.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets the active extensions that the broadcaster has installed for each configuration. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-user-active-extensions +func get_user_active_extensions(opt: TwitchGetUserActiveExtensions.Opt) -> TwitchGetUserActiveExtensions.Response: + var path = "/users/extensions?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("user_id"): + path += "user_id=" + str(optionals.user_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetUserActiveExtensions.Response = TwitchGetUserActiveExtensions.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Updates an installed extension’s information. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#update-user-extensions +func update_user_extensions(body: TwitchUpdateUserExtensions.Body) -> TwitchUpdateUserExtensions.Response: + var path = "/users/extensions?" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_PUT, body, "application/json") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchUpdateUserExtensions.Response = TwitchUpdateUserExtensions.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Gets information about one or more published videos. +## +## [no required query parameters to describe] +## +## https://dev.twitch.tv/docs/api/reference#get-videos +func get_videos(opt: TwitchGetVideos.Opt) -> TwitchGetVideos.Response: + var path = "/videos?" + var optionals: Dictionary[StringName, Variant] = {} + if opt != null: optionals = opt.to_dict() + if optionals.has("after"): + path += "after=" + str(optionals.after) + "&" + if optionals.has("before"): + path += "before=" + str(optionals.before) + "&" + if optionals.has("first"): + path += "first=" + str(optionals.first) + "&" + if optionals.has("game_id"): + path += "game_id=" + str(optionals.game_id) + "&" + if optionals.has("id"): + + for param in optionals.id: + path += "id=" + str(param) + "&" + if optionals.has("language"): + path += "language=" + str(optionals.language) + "&" + if optionals.has("period"): + path += "period=" + str(optionals.period) + "&" + if optionals.has("sort"): + path += "sort=" + str(optionals.sort) + "&" + if optionals.has("type"): + path += "type=" + str(optionals.type) + "&" + if optionals.has("user_id"): + path += "user_id=" + str(optionals.user_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_GET, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchGetVideos.Response = TwitchGetVideos.Response.from_json(result) + parsed_result.response = response + if parsed_result.pagination != null: + var cursor: String = parsed_result.pagination.cursor + opt.after = cursor + parsed_result._next_page = get_videos.bind(opt) + return parsed_result + + +## Deletes one or more videos. +## +## id - The list of videos to delete. To specify more than one video, include the _id_ parameter for each video to delete. For example, `id=1234&id=5678`. You can delete a maximum of 5 videos per request. Ignores invalid video IDs. +## +## If the user doesn’t have permission to delete one of the videos in the list, none of the videos are deleted. +## +## https://dev.twitch.tv/docs/api/reference#delete-videos +func delete_videos(id: Array[String]) -> TwitchDeleteVideos.Response: + var path = "/videos?" + + for param in id: + path += "id=" + str(param) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_DELETE, "", "") + + var result: Variant = JSON.parse_string(response.response_data.get_string_from_utf8()) + var parsed_result: TwitchDeleteVideos.Response = TwitchDeleteVideos.Response.from_json(result) + parsed_result.response = response + return parsed_result + + +## Sends a whisper message to the specified user. +## +## from_user_id - The ID of the user sending the whisper. This user must have a verified phone number. This ID must match the user ID in the user access token. +## to_user_id - The ID of the user to receive the whisper. +## +## https://dev.twitch.tv/docs/api/reference#send-whisper +func send_whisper(body: TwitchSendWhisper.Body, from_user_id: String, to_user_id: String) -> BufferedHTTPClient.ResponseData: + var path = "/whispers?" + path += "from_user_id=" + str(from_user_id) + "&" + path += "to_user_id=" + str(to_user_id) + "&" + + var response: BufferedHTTPClient.ResponseData = await request(path, HTTPClient.METHOD_POST, body, "application/json") + return response \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_api.gd.uid b/addons/twitcher/generated/twitch_api.gd.uid new file mode 100644 index 0000000..92d40dc --- /dev/null +++ b/addons/twitcher/generated/twitch_api.gd.uid @@ -0,0 +1 @@ +uid://cw30cwveway65 diff --git a/addons/twitcher/generated/twitch_auto_mod_settings.gd b/addons/twitcher/generated/twitch_auto_mod_settings.gd new file mode 100644 index 0000000..0b03b97 --- /dev/null +++ b/addons/twitcher/generated/twitch_auto_mod_settings.gd @@ -0,0 +1,119 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/AutoModSettings +class_name TwitchAutoModSettings + +## The broadcaster’s ID. +@export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + +## The moderator’s ID. +@export var moderator_id: String: + set(val): + moderator_id = val + track_data(&"moderator_id", val) + +## The default AutoMod level for the broadcaster. This field is **null** if the broadcaster has set one or more of the individual settings. +@export var overall_level: int: + set(val): + overall_level = val + track_data(&"overall_level", val) + +## The Automod level for discrimination against disability. +@export var disability: int: + set(val): + disability = val + track_data(&"disability", val) + +## The Automod level for hostility involving aggression. +@export var aggression: int: + set(val): + aggression = val + track_data(&"aggression", val) + +## The AutoMod level for discrimination based on sexuality, sex, or gender. +@export var sexuality_sex_or_gender: int: + set(val): + sexuality_sex_or_gender = val + track_data(&"sexuality_sex_or_gender", val) + +## The Automod level for discrimination against women. +@export var misogyny: int: + set(val): + misogyny = val + track_data(&"misogyny", val) + +## The Automod level for hostility involving name calling or insults. +@export var bullying: int: + set(val): + bullying = val + track_data(&"bullying", val) + +## The Automod level for profanity. +@export var swearing: int: + set(val): + swearing = val + track_data(&"swearing", val) + +## The Automod level for racial discrimination. +@export var race_ethnicity_or_religion: int: + set(val): + race_ethnicity_or_religion = val + track_data(&"race_ethnicity_or_religion", val) + +## The Automod level for sexual content. +@export var sex_based_terms: int: + set(val): + sex_based_terms = val + track_data(&"sex_based_terms", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_broadcaster_id: String, _moderator_id: String, _overall_level: int, _disability: int, _aggression: int, _sexuality_sex_or_gender: int, _misogyny: int, _bullying: int, _swearing: int, _race_ethnicity_or_religion: int, _sex_based_terms: int) -> TwitchAutoModSettings: + var twitch_auto_mod_settings: TwitchAutoModSettings = TwitchAutoModSettings.new() + twitch_auto_mod_settings.broadcaster_id = _broadcaster_id + twitch_auto_mod_settings.moderator_id = _moderator_id + twitch_auto_mod_settings.overall_level = _overall_level + twitch_auto_mod_settings.disability = _disability + twitch_auto_mod_settings.aggression = _aggression + twitch_auto_mod_settings.sexuality_sex_or_gender = _sexuality_sex_or_gender + twitch_auto_mod_settings.misogyny = _misogyny + twitch_auto_mod_settings.bullying = _bullying + twitch_auto_mod_settings.swearing = _swearing + twitch_auto_mod_settings.race_ethnicity_or_religion = _race_ethnicity_or_religion + twitch_auto_mod_settings.sex_based_terms = _sex_based_terms + return twitch_auto_mod_settings + + +static func from_json(d: Dictionary) -> TwitchAutoModSettings: + var result: TwitchAutoModSettings = TwitchAutoModSettings.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("moderator_id", null) != null: + result.moderator_id = d["moderator_id"] + if d.get("overall_level", null) != null: + result.overall_level = d["overall_level"] + if d.get("disability", null) != null: + result.disability = d["disability"] + if d.get("aggression", null) != null: + result.aggression = d["aggression"] + if d.get("sexuality_sex_or_gender", null) != null: + result.sexuality_sex_or_gender = d["sexuality_sex_or_gender"] + if d.get("misogyny", null) != null: + result.misogyny = d["misogyny"] + if d.get("bullying", null) != null: + result.bullying = d["bullying"] + if d.get("swearing", null) != null: + result.swearing = d["swearing"] + if d.get("race_ethnicity_or_religion", null) != null: + result.race_ethnicity_or_religion = d["race_ethnicity_or_religion"] + if d.get("sex_based_terms", null) != null: + result.sex_based_terms = d["sex_based_terms"] + return result diff --git a/addons/twitcher/generated/twitch_auto_mod_settings.gd.uid b/addons/twitcher/generated/twitch_auto_mod_settings.gd.uid new file mode 100644 index 0000000..5414b73 --- /dev/null +++ b/addons/twitcher/generated/twitch_auto_mod_settings.gd.uid @@ -0,0 +1 @@ +uid://da1xnqcvu7tc0 diff --git a/addons/twitcher/generated/twitch_auto_mod_status.gd b/addons/twitcher/generated/twitch_auto_mod_status.gd new file mode 100644 index 0000000..27a2bda --- /dev/null +++ b/addons/twitcher/generated/twitch_auto_mod_status.gd @@ -0,0 +1,38 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/AutoModStatus +class_name TwitchAutoModStatus + +## The caller-defined ID passed in the request. +@export var msg_id: String: + set(val): + msg_id = val + track_data(&"msg_id", val) + +## A Boolean value that indicates whether Twitch would approve the message for chat or hold it for moderator review or block it from chat. Is **true** if Twitch would approve the message; otherwise, **false** if Twitch would hold the message for moderator review or block it from chat. +@export var is_permitted: bool: + set(val): + is_permitted = val + track_data(&"is_permitted", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_msg_id: String, _is_permitted: bool) -> TwitchAutoModStatus: + var twitch_auto_mod_status: TwitchAutoModStatus = TwitchAutoModStatus.new() + twitch_auto_mod_status.msg_id = _msg_id + twitch_auto_mod_status.is_permitted = _is_permitted + return twitch_auto_mod_status + + +static func from_json(d: Dictionary) -> TwitchAutoModStatus: + var result: TwitchAutoModStatus = TwitchAutoModStatus.new() + if d.get("msg_id", null) != null: + result.msg_id = d["msg_id"] + if d.get("is_permitted", null) != null: + result.is_permitted = d["is_permitted"] + return result diff --git a/addons/twitcher/generated/twitch_auto_mod_status.gd.uid b/addons/twitcher/generated/twitch_auto_mod_status.gd.uid new file mode 100644 index 0000000..a3021eb --- /dev/null +++ b/addons/twitcher/generated/twitch_auto_mod_status.gd.uid @@ -0,0 +1 @@ +uid://ysgxjcmt1nul diff --git a/addons/twitcher/generated/twitch_ban_user.gd b/addons/twitcher/generated/twitch_ban_user.gd new file mode 100644 index 0000000..3c7197c --- /dev/null +++ b/addons/twitcher/generated/twitch_ban_user.gd @@ -0,0 +1,172 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchBanUser + + + +## +## #/components/schemas/BanUserBody +class Body extends TwitchData: + + ## Identifies the user and type of ban. + @export var data: BodyData: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: BodyData) -> Body: + var body: Body = Body.new() + body.data = _data + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("data", null) != null: + result.data = BodyData.from_json(d["data"]) + return result + + + +## Identifies the user and type of ban. +## #/components/schemas/BanUserBody/Data +class BodyData extends TwitchData: + + ## The ID of the user to ban or put in a timeout. + @export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + + ## To ban a user indefinitely, don’t include this field. + ## + ## To put a user in a timeout, include this field and specify the timeout period, in seconds. The minimum timeout is 1 second and the maximum is 1,209,600 seconds (2 weeks). + ## + ## To end a user’s timeout early, set this field to 1, or use the [Unban user](https://dev.twitch.tv/docs/api/reference#unban-user) endpoint. + @export var duration: int: + set(val): + duration = val + track_data(&"duration", val) + + ## The reason the you’re banning the user or putting them in a timeout. The text is user defined and is limited to a maximum of 500 characters. + @export var reason: String: + set(val): + reason = val + track_data(&"reason", val) + + + + ## Constructor with all required fields. + static func create(_user_id: String) -> BodyData: + var body_data: BodyData = BodyData.new() + body_data.user_id = _user_id + return body_data + + + static func from_json(d: Dictionary) -> BodyData: + var result: BodyData = BodyData.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("duration", null) != null: + result.duration = d["duration"] + if d.get("reason", null) != null: + result.reason = d["reason"] + return result + + + +## +## #/components/schemas/BanUserResponse +class Response extends TwitchData: + + ## A list that contains the user you successfully banned or put in a timeout. + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + return result + + + +## A list that contains the user you successfully banned or put in a timeout. +## #/components/schemas/BanUserResponse/Data +class ResponseData extends TwitchData: + + ## The broadcaster whose chat room the user was banned from chatting in. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## The moderator that banned or put the user in the timeout. + @export var moderator_id: String: + set(val): + moderator_id = val + track_data(&"moderator_id", val) + + ## The user that was banned or put in a timeout. + @export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + + ## The UTC date and time (in RFC3339 format) that the ban or timeout was placed. + @export var created_at: String: + set(val): + created_at = val + track_data(&"created_at", val) + + ## The UTC date and time (in RFC3339 format) that the timeout will end. Is **null** if the user was banned instead of being put in a timeout. + @export var end_time: String: + set(val): + end_time = val + track_data(&"end_time", val) + + + + ## Constructor with all required fields. + static func create(_broadcaster_id: String, _moderator_id: String, _user_id: String, _created_at: String, _end_time: String) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.broadcaster_id = _broadcaster_id + response_data.moderator_id = _moderator_id + response_data.user_id = _user_id + response_data.created_at = _created_at + response_data.end_time = _end_time + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("moderator_id", null) != null: + result.moderator_id = d["moderator_id"] + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("created_at", null) != null: + result.created_at = d["created_at"] + if d.get("end_time", null) != null: + result.end_time = d["end_time"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_ban_user.gd.uid b/addons/twitcher/generated/twitch_ban_user.gd.uid new file mode 100644 index 0000000..8858008 --- /dev/null +++ b/addons/twitcher/generated/twitch_ban_user.gd.uid @@ -0,0 +1 @@ +uid://by54cigjuq85x diff --git a/addons/twitcher/generated/twitch_banned_user.gd b/addons/twitcher/generated/twitch_banned_user.gd new file mode 100644 index 0000000..62fc01f --- /dev/null +++ b/addons/twitcher/generated/twitch_banned_user.gd @@ -0,0 +1,101 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/BannedUser +class_name TwitchBannedUser + +## The ID of the banned user. +@export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + +## The banned user’s login name. +@export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) + +## The banned user’s display name. +@export var user_name: String: + set(val): + user_name = val + track_data(&"user_name", val) + +## The UTC date and time (in RFC3339 format) of when the timeout expires, or an empty string if the user is permanently banned. +@export var expires_at: String: + set(val): + expires_at = val + track_data(&"expires_at", val) + +## The UTC date and time (in RFC3339 format) of when the user was banned. +@export var created_at: String: + set(val): + created_at = val + track_data(&"created_at", val) + +## The reason the user was banned or put in a timeout if the moderator provided one. +@export var reason: String: + set(val): + reason = val + track_data(&"reason", val) + +## The ID of the moderator that banned the user or put them in a timeout. +@export var moderator_id: String: + set(val): + moderator_id = val + track_data(&"moderator_id", val) + +## The moderator’s login name. +@export var moderator_login: String: + set(val): + moderator_login = val + track_data(&"moderator_login", val) + +## The moderator’s display name. +@export var moderator_name: String: + set(val): + moderator_name = val + track_data(&"moderator_name", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_user_id: String, _user_login: String, _user_name: String, _expires_at: String, _created_at: String, _reason: String, _moderator_id: String, _moderator_login: String, _moderator_name: String) -> TwitchBannedUser: + var twitch_banned_user: TwitchBannedUser = TwitchBannedUser.new() + twitch_banned_user.user_id = _user_id + twitch_banned_user.user_login = _user_login + twitch_banned_user.user_name = _user_name + twitch_banned_user.expires_at = _expires_at + twitch_banned_user.created_at = _created_at + twitch_banned_user.reason = _reason + twitch_banned_user.moderator_id = _moderator_id + twitch_banned_user.moderator_login = _moderator_login + twitch_banned_user.moderator_name = _moderator_name + return twitch_banned_user + + +static func from_json(d: Dictionary) -> TwitchBannedUser: + var result: TwitchBannedUser = TwitchBannedUser.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + if d.get("user_name", null) != null: + result.user_name = d["user_name"] + if d.get("expires_at", null) != null: + result.expires_at = d["expires_at"] + if d.get("created_at", null) != null: + result.created_at = d["created_at"] + if d.get("reason", null) != null: + result.reason = d["reason"] + if d.get("moderator_id", null) != null: + result.moderator_id = d["moderator_id"] + if d.get("moderator_login", null) != null: + result.moderator_login = d["moderator_login"] + if d.get("moderator_name", null) != null: + result.moderator_name = d["moderator_name"] + return result diff --git a/addons/twitcher/generated/twitch_banned_user.gd.uid b/addons/twitcher/generated/twitch_banned_user.gd.uid new file mode 100644 index 0000000..35a30ff --- /dev/null +++ b/addons/twitcher/generated/twitch_banned_user.gd.uid @@ -0,0 +1 @@ +uid://btn5nmya3pbly diff --git a/addons/twitcher/generated/twitch_bits_leaderboard.gd b/addons/twitcher/generated/twitch_bits_leaderboard.gd new file mode 100644 index 0000000..5529b5f --- /dev/null +++ b/addons/twitcher/generated/twitch_bits_leaderboard.gd @@ -0,0 +1,65 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/BitsLeaderboard +class_name TwitchBitsLeaderboard + +## An ID that identifies a user on the leaderboard. +@export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + +## The user’s login name. +@export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) + +## The user’s display name. +@export var user_name: String: + set(val): + user_name = val + track_data(&"user_name", val) + +## The user’s position on the leaderboard. +@export var rank: int: + set(val): + rank = val + track_data(&"rank", val) + +## The number of Bits the user has cheered. +@export var score: int: + set(val): + score = val + track_data(&"score", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_user_id: String, _user_login: String, _user_name: String, _rank: int, _score: int) -> TwitchBitsLeaderboard: + var twitch_bits_leaderboard: TwitchBitsLeaderboard = TwitchBitsLeaderboard.new() + twitch_bits_leaderboard.user_id = _user_id + twitch_bits_leaderboard.user_login = _user_login + twitch_bits_leaderboard.user_name = _user_name + twitch_bits_leaderboard.rank = _rank + twitch_bits_leaderboard.score = _score + return twitch_bits_leaderboard + + +static func from_json(d: Dictionary) -> TwitchBitsLeaderboard: + var result: TwitchBitsLeaderboard = TwitchBitsLeaderboard.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + if d.get("user_name", null) != null: + result.user_name = d["user_name"] + if d.get("rank", null) != null: + result.rank = d["rank"] + if d.get("score", null) != null: + result.score = d["score"] + return result diff --git a/addons/twitcher/generated/twitch_bits_leaderboard.gd.uid b/addons/twitcher/generated/twitch_bits_leaderboard.gd.uid new file mode 100644 index 0000000..b2189a9 --- /dev/null +++ b/addons/twitcher/generated/twitch_bits_leaderboard.gd.uid @@ -0,0 +1 @@ +uid://ds3gv8nlj3sym diff --git a/addons/twitcher/generated/twitch_block_user.gd b/addons/twitcher/generated/twitch_block_user.gd new file mode 100644 index 0000000..a6d4dab --- /dev/null +++ b/addons/twitcher/generated/twitch_block_user.gd @@ -0,0 +1,50 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchBlockUser + + + +## All optional parameters for TwitchAPI.block_user +## #/components/schemas/BlockUserOpt +class Opt extends TwitchData: + + ## The location where the harassment took place that is causing the brodcaster to block the user. Possible values are: + ## + ## * chat + ## * whisper + ## + ## . + @export var source_context: String: + set(val): + source_context = val + track_data(&"source_context", val) + + ## The reason that the broadcaster is blocking the user. Possible values are: + ## + ## * harassment + ## * spam + ## * other + @export var reason: String: + set(val): + reason = val + track_data(&"reason", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("source_context", null) != null: + result.source_context = d["source_context"] + if d.get("reason", null) != null: + result.reason = d["reason"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_block_user.gd.uid b/addons/twitcher/generated/twitch_block_user.gd.uid new file mode 100644 index 0000000..c821377 --- /dev/null +++ b/addons/twitcher/generated/twitch_block_user.gd.uid @@ -0,0 +1 @@ +uid://cfvd224a7lj8w diff --git a/addons/twitcher/generated/twitch_blocked_term.gd b/addons/twitcher/generated/twitch_blocked_term.gd new file mode 100644 index 0000000..c7225d4 --- /dev/null +++ b/addons/twitcher/generated/twitch_blocked_term.gd @@ -0,0 +1,87 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/BlockedTerm +class_name TwitchBlockedTerm + +## The broadcaster that owns the list of blocked terms. +@export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + +## The moderator that blocked the word or phrase from being used in the broadcaster’s chat room. +@export var moderator_id: String: + set(val): + moderator_id = val + track_data(&"moderator_id", val) + +## An ID that identifies this blocked term. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The blocked word or phrase. +@export var text: String: + set(val): + text = val + track_data(&"text", val) + +## The UTC date and time (in RFC3339 format) that the term was blocked. +@export var created_at: String: + set(val): + created_at = val + track_data(&"created_at", val) + +## The UTC date and time (in RFC3339 format) that the term was updated. +## +## When the term is added, this timestamp is the same as `created_at`. The timestamp changes as AutoMod continues to deny the term. +@export var updated_at: String: + set(val): + updated_at = val + track_data(&"updated_at", val) + +## The UTC date and time (in RFC3339 format) that the blocked term is set to expire. After the block expires, users may use the term in the broadcaster’s chat room. +## +## This field is **null** if the term was added manually or was permanently blocked by AutoMod. +@export var expires_at: String: + set(val): + expires_at = val + track_data(&"expires_at", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_broadcaster_id: String, _moderator_id: String, _id: String, _text: String, _created_at: String, _updated_at: String, _expires_at: String) -> TwitchBlockedTerm: + var twitch_blocked_term: TwitchBlockedTerm = TwitchBlockedTerm.new() + twitch_blocked_term.broadcaster_id = _broadcaster_id + twitch_blocked_term.moderator_id = _moderator_id + twitch_blocked_term.id = _id + twitch_blocked_term.text = _text + twitch_blocked_term.created_at = _created_at + twitch_blocked_term.updated_at = _updated_at + twitch_blocked_term.expires_at = _expires_at + return twitch_blocked_term + + +static func from_json(d: Dictionary) -> TwitchBlockedTerm: + var result: TwitchBlockedTerm = TwitchBlockedTerm.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("moderator_id", null) != null: + result.moderator_id = d["moderator_id"] + if d.get("id", null) != null: + result.id = d["id"] + if d.get("text", null) != null: + result.text = d["text"] + if d.get("created_at", null) != null: + result.created_at = d["created_at"] + if d.get("updated_at", null) != null: + result.updated_at = d["updated_at"] + if d.get("expires_at", null) != null: + result.expires_at = d["expires_at"] + return result diff --git a/addons/twitcher/generated/twitch_blocked_term.gd.uid b/addons/twitcher/generated/twitch_blocked_term.gd.uid new file mode 100644 index 0000000..42c326a --- /dev/null +++ b/addons/twitcher/generated/twitch_blocked_term.gd.uid @@ -0,0 +1 @@ +uid://dut1o64kt25wi diff --git a/addons/twitcher/generated/twitch_broadcaster_subscription.gd b/addons/twitcher/generated/twitch_broadcaster_subscription.gd new file mode 100644 index 0000000..adb39ab --- /dev/null +++ b/addons/twitcher/generated/twitch_broadcaster_subscription.gd @@ -0,0 +1,132 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/BroadcasterSubscription +class_name TwitchBroadcasterSubscription + +## An ID that identifies the broadcaster. +@export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + +## The broadcaster’s login name. +@export var broadcaster_login: String: + set(val): + broadcaster_login = val + track_data(&"broadcaster_login", val) + +## The broadcaster’s display name. +@export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + +## The ID of the user that gifted the subscription to the user. Is an empty string if `is_gift` is **false**. +@export var gifter_id: String: + set(val): + gifter_id = val + track_data(&"gifter_id", val) + +## The gifter’s login name. Is an empty string if `is_gift` is **false**. +@export var gifter_login: String: + set(val): + gifter_login = val + track_data(&"gifter_login", val) + +## The gifter’s display name. Is an empty string if `is_gift` is **false**. +@export var gifter_name: String: + set(val): + gifter_name = val + track_data(&"gifter_name", val) + +## A Boolean value that determines whether the subscription is a gift subscription. Is **true** if the subscription was gifted. +@export var is_gift: bool: + set(val): + is_gift = val + track_data(&"is_gift", val) + +## The name of the subscription. +@export var plan_name: String: + set(val): + plan_name = val + track_data(&"plan_name", val) + +## The type of subscription. Possible values are: +## +## * 1000 — Tier 1 +## * 2000 — Tier 2 +## * 3000 — Tier 3 +@export var tier: String: + set(val): + tier = val + track_data(&"tier", val) + +## An ID that identifies the subscribing user. +@export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + +## The user’s display name. +@export var user_name: String: + set(val): + user_name = val + track_data(&"user_name", val) + +## The user’s login name. +@export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_broadcaster_id: String, _broadcaster_login: String, _broadcaster_name: String, _gifter_id: String, _gifter_login: String, _gifter_name: String, _is_gift: bool, _plan_name: String, _tier: String, _user_id: String, _user_name: String, _user_login: String) -> TwitchBroadcasterSubscription: + var twitch_broadcaster_subscription: TwitchBroadcasterSubscription = TwitchBroadcasterSubscription.new() + twitch_broadcaster_subscription.broadcaster_id = _broadcaster_id + twitch_broadcaster_subscription.broadcaster_login = _broadcaster_login + twitch_broadcaster_subscription.broadcaster_name = _broadcaster_name + twitch_broadcaster_subscription.gifter_id = _gifter_id + twitch_broadcaster_subscription.gifter_login = _gifter_login + twitch_broadcaster_subscription.gifter_name = _gifter_name + twitch_broadcaster_subscription.is_gift = _is_gift + twitch_broadcaster_subscription.plan_name = _plan_name + twitch_broadcaster_subscription.tier = _tier + twitch_broadcaster_subscription.user_id = _user_id + twitch_broadcaster_subscription.user_name = _user_name + twitch_broadcaster_subscription.user_login = _user_login + return twitch_broadcaster_subscription + + +static func from_json(d: Dictionary) -> TwitchBroadcasterSubscription: + var result: TwitchBroadcasterSubscription = TwitchBroadcasterSubscription.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_login", null) != null: + result.broadcaster_login = d["broadcaster_login"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + if d.get("gifter_id", null) != null: + result.gifter_id = d["gifter_id"] + if d.get("gifter_login", null) != null: + result.gifter_login = d["gifter_login"] + if d.get("gifter_name", null) != null: + result.gifter_name = d["gifter_name"] + if d.get("is_gift", null) != null: + result.is_gift = d["is_gift"] + if d.get("plan_name", null) != null: + result.plan_name = d["plan_name"] + if d.get("tier", null) != null: + result.tier = d["tier"] + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_name", null) != null: + result.user_name = d["user_name"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + return result diff --git a/addons/twitcher/generated/twitch_broadcaster_subscription.gd.uid b/addons/twitcher/generated/twitch_broadcaster_subscription.gd.uid new file mode 100644 index 0000000..64ddf9c --- /dev/null +++ b/addons/twitcher/generated/twitch_broadcaster_subscription.gd.uid @@ -0,0 +1 @@ +uid://dwjgwneb8uxui diff --git a/addons/twitcher/generated/twitch_category.gd b/addons/twitcher/generated/twitch_category.gd new file mode 100644 index 0000000..8ea2679 --- /dev/null +++ b/addons/twitcher/generated/twitch_category.gd @@ -0,0 +1,47 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/Category +class_name TwitchCategory + +## A URL to an image of the game’s box art or streaming category. +@export var box_art_url: String: + set(val): + box_art_url = val + track_data(&"box_art_url", val) + +## The name of the game or category. +@export var name: String: + set(val): + name = val + track_data(&"name", val) + +## An ID that uniquely identifies the game or category. +@export var id: String: + set(val): + id = val + track_data(&"id", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_box_art_url: String, _name: String, _id: String) -> TwitchCategory: + var twitch_category: TwitchCategory = TwitchCategory.new() + twitch_category.box_art_url = _box_art_url + twitch_category.name = _name + twitch_category.id = _id + return twitch_category + + +static func from_json(d: Dictionary) -> TwitchCategory: + var result: TwitchCategory = TwitchCategory.new() + if d.get("box_art_url", null) != null: + result.box_art_url = d["box_art_url"] + if d.get("name", null) != null: + result.name = d["name"] + if d.get("id", null) != null: + result.id = d["id"] + return result diff --git a/addons/twitcher/generated/twitch_category.gd.uid b/addons/twitcher/generated/twitch_category.gd.uid new file mode 100644 index 0000000..34dff39 --- /dev/null +++ b/addons/twitcher/generated/twitch_category.gd.uid @@ -0,0 +1 @@ +uid://be2yia4ctewtx diff --git a/addons/twitcher/generated/twitch_channel.gd b/addons/twitcher/generated/twitch_channel.gd new file mode 100644 index 0000000..5528989 --- /dev/null +++ b/addons/twitcher/generated/twitch_channel.gd @@ -0,0 +1,132 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/Channel +class_name TwitchChannel + +## The ISO 639-1 two-letter language code of the language used by the broadcaster. For example, _en_ for English. If the broadcaster uses a language not in the list of [supported stream languages](https://help.twitch.tv/s/article/languages-on-twitch#streamlang), the value is _other_. +@export var broadcaster_language: String: + set(val): + broadcaster_language = val + track_data(&"broadcaster_language", val) + +## The broadcaster’s login name. +@export var broadcaster_login: String: + set(val): + broadcaster_login = val + track_data(&"broadcaster_login", val) + +## The broadcaster’s display name. +@export var display_name: String: + set(val): + display_name = val + track_data(&"display_name", val) + +## The ID of the game that the broadcaster is playing or last played. +@export var game_id: String: + set(val): + game_id = val + track_data(&"game_id", val) + +## The name of the game that the broadcaster is playing or last played. +@export var game_name: String: + set(val): + game_name = val + track_data(&"game_name", val) + +## An ID that uniquely identifies the channel (this is the broadcaster’s ID). +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## A Boolean value that determines whether the broadcaster is streaming live. Is **true** if the broadcaster is streaming live; otherwise, **false**. +@export var is_live: bool: + set(val): + is_live = val + track_data(&"is_live", val) + +## **IMPORTANT** As of February 28, 2023, this field is deprecated and returns only an empty array. If you use this field, please update your code to use the `tags` field. +## +## The list of tags that apply to the stream. The list contains IDs only when the channel is steaming live. For a list of possible tags, see [List of All Tags](https://www.twitch.tv/directory/all/tags). The list doesn’t include Category Tags. +@export var tag_ids: Array[String]: + set(val): + tag_ids = val + track_data(&"tag_ids", val) + +## The tags applied to the channel. +@export var tags: Array[String]: + set(val): + tags = val + track_data(&"tags", val) + +## A URL to a thumbnail of the broadcaster’s profile image. +@export var thumbnail_url: String: + set(val): + thumbnail_url = val + track_data(&"thumbnail_url", val) + +## The stream’s title. Is an empty string if the broadcaster didn’t set it. +@export var title: String: + set(val): + title = val + track_data(&"title", val) + +## The UTC date and time (in RFC3339 format) of when the broadcaster started streaming. The string is empty if the broadcaster is not streaming live. +@export var started_at: String: + set(val): + started_at = val + track_data(&"started_at", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_broadcaster_language: String, _broadcaster_login: String, _display_name: String, _game_id: String, _game_name: String, _id: String, _is_live: bool, _tag_ids: Array[String], _tags: Array[String], _thumbnail_url: String, _title: String, _started_at: String) -> TwitchChannel: + var twitch_channel: TwitchChannel = TwitchChannel.new() + twitch_channel.broadcaster_language = _broadcaster_language + twitch_channel.broadcaster_login = _broadcaster_login + twitch_channel.display_name = _display_name + twitch_channel.game_id = _game_id + twitch_channel.game_name = _game_name + twitch_channel.id = _id + twitch_channel.is_live = _is_live + twitch_channel.tag_ids = _tag_ids + twitch_channel.tags = _tags + twitch_channel.thumbnail_url = _thumbnail_url + twitch_channel.title = _title + twitch_channel.started_at = _started_at + return twitch_channel + + +static func from_json(d: Dictionary) -> TwitchChannel: + var result: TwitchChannel = TwitchChannel.new() + if d.get("broadcaster_language", null) != null: + result.broadcaster_language = d["broadcaster_language"] + if d.get("broadcaster_login", null) != null: + result.broadcaster_login = d["broadcaster_login"] + if d.get("display_name", null) != null: + result.display_name = d["display_name"] + if d.get("game_id", null) != null: + result.game_id = d["game_id"] + if d.get("game_name", null) != null: + result.game_name = d["game_name"] + if d.get("id", null) != null: + result.id = d["id"] + if d.get("is_live", null) != null: + result.is_live = d["is_live"] + if d.get("tag_ids", null) != null: + for value in d["tag_ids"]: + result.tag_ids.append(value) + if d.get("tags", null) != null: + for value in d["tags"]: + result.tags.append(value) + if d.get("thumbnail_url", null) != null: + result.thumbnail_url = d["thumbnail_url"] + if d.get("title", null) != null: + result.title = d["title"] + if d.get("started_at", null) != null: + result.started_at = d["started_at"] + return result diff --git a/addons/twitcher/generated/twitch_channel.gd.uid b/addons/twitcher/generated/twitch_channel.gd.uid new file mode 100644 index 0000000..f823672 --- /dev/null +++ b/addons/twitcher/generated/twitch_channel.gd.uid @@ -0,0 +1 @@ +uid://b77eemd6nsdjf diff --git a/addons/twitcher/generated/twitch_channel_editor.gd b/addons/twitcher/generated/twitch_channel_editor.gd new file mode 100644 index 0000000..f38590e --- /dev/null +++ b/addons/twitcher/generated/twitch_channel_editor.gd @@ -0,0 +1,47 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/ChannelEditor +class_name TwitchChannelEditor + +## An ID that uniquely identifies a user with editor permissions. +@export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + +## The user’s display name. +@export var user_name: String: + set(val): + user_name = val + track_data(&"user_name", val) + +## The date and time, in RFC3339 format, when the user became one of the broadcaster’s editors. +@export var created_at: String: + set(val): + created_at = val + track_data(&"created_at", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_user_id: String, _user_name: String, _created_at: String) -> TwitchChannelEditor: + var twitch_channel_editor: TwitchChannelEditor = TwitchChannelEditor.new() + twitch_channel_editor.user_id = _user_id + twitch_channel_editor.user_name = _user_name + twitch_channel_editor.created_at = _created_at + return twitch_channel_editor + + +static func from_json(d: Dictionary) -> TwitchChannelEditor: + var result: TwitchChannelEditor = TwitchChannelEditor.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_name", null) != null: + result.user_name = d["user_name"] + if d.get("created_at", null) != null: + result.created_at = d["created_at"] + return result diff --git a/addons/twitcher/generated/twitch_channel_editor.gd.uid b/addons/twitcher/generated/twitch_channel_editor.gd.uid new file mode 100644 index 0000000..84a8e75 --- /dev/null +++ b/addons/twitcher/generated/twitch_channel_editor.gd.uid @@ -0,0 +1 @@ +uid://ceah5b3esf15j diff --git a/addons/twitcher/generated/twitch_channel_emote.gd b/addons/twitcher/generated/twitch_channel_emote.gd new file mode 100644 index 0000000..f3640bb --- /dev/null +++ b/addons/twitcher/generated/twitch_channel_emote.gd @@ -0,0 +1,168 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/ChannelEmote +class_name TwitchChannelEmote + +## An ID that identifies this emote. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The name of the emote. This is the name that viewers type in the chat window to get the emote to appear. +@export var name: String: + set(val): + name = val + track_data(&"name", val) + +## The image URLs for the emote. These image URLs always provide a static, non-animated emote image with a light background. +## +## **NOTE:** You should use the templated URL in the `template` field to fetch the image instead of using these URLs. +@export var images: Images: + set(val): + images = val + track_data(&"images", val) + +## The subscriber tier at which the emote is unlocked. This field contains the tier information only if `emote_type` is set to `subscriptions`, otherwise, it's an empty string. +@export var tier: String: + set(val): + tier = val + track_data(&"tier", val) + +## The type of emote. The possible values are: +## +## * bitstier — A custom Bits tier emote. +## * follower — A custom follower emote. +## * subscriptions — A custom subscriber emote. +@export var emote_type: String: + set(val): + emote_type = val + track_data(&"emote_type", val) + +## An ID that identifies the emote set that the emote belongs to. +@export var emote_set_id: String: + set(val): + emote_set_id = val + track_data(&"emote_set_id", val) + +## The formats that the emote is available in. For example, if the emote is available only as a static PNG, the array contains only `static`. But if the emote is available as a static PNG and an animated GIF, the array contains `static` and `animated`. The possible formats are: +## +## * animated — An animated GIF is available for this emote. +## * static — A static PNG file is available for this emote. +@export var format: Array[String]: + set(val): + format = val + track_data(&"format", val) + +## The sizes that the emote is available in. For example, if the emote is available in small and medium sizes, the array contains 1.0 and 2.0\. Possible sizes are: +## +## * 1.0 — A small version (28px x 28px) is available. +## * 2.0 — A medium version (56px x 56px) is available. +## * 3.0 — A large version (112px x 112px) is available. +@export var scale: Array[String]: + set(val): + scale = val + track_data(&"scale", val) + +## The background themes that the emote is available in. Possible themes are: +## +## * dark +## * light +@export var theme_mode: Array[String]: + set(val): + theme_mode = val + track_data(&"theme_mode", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _name: String, _images: Images, _tier: String, _emote_type: String, _emote_set_id: String, _format: Array[String], _scale: Array[String], _theme_mode: Array[String]) -> TwitchChannelEmote: + var twitch_channel_emote: TwitchChannelEmote = TwitchChannelEmote.new() + twitch_channel_emote.id = _id + twitch_channel_emote.name = _name + twitch_channel_emote.images = _images + twitch_channel_emote.tier = _tier + twitch_channel_emote.emote_type = _emote_type + twitch_channel_emote.emote_set_id = _emote_set_id + twitch_channel_emote.format = _format + twitch_channel_emote.scale = _scale + twitch_channel_emote.theme_mode = _theme_mode + return twitch_channel_emote + + +static func from_json(d: Dictionary) -> TwitchChannelEmote: + var result: TwitchChannelEmote = TwitchChannelEmote.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("name", null) != null: + result.name = d["name"] + if d.get("images", null) != null: + result.images = Images.from_json(d["images"]) + if d.get("tier", null) != null: + result.tier = d["tier"] + if d.get("emote_type", null) != null: + result.emote_type = d["emote_type"] + if d.get("emote_set_id", null) != null: + result.emote_set_id = d["emote_set_id"] + if d.get("format", null) != null: + for value in d["format"]: + result.format.append(value) + if d.get("scale", null) != null: + for value in d["scale"]: + result.scale.append(value) + if d.get("theme_mode", null) != null: + for value in d["theme_mode"]: + result.theme_mode.append(value) + return result + + + +## The image URLs for the emote. These image URLs always provide a static, non-animated emote image with a light background. +## +## **NOTE:** You should use the templated URL in the `template` field to fetch the image instead of using these URLs. +## #/components/schemas/ChannelEmote/Images +class Images extends TwitchData: + + ## A URL to the small version (28px x 28px) of the emote. + @export var url_1x: String: + set(val): + url_1x = val + track_data(&"url_1x", val) + + ## A URL to the medium version (56px x 56px) of the emote. + @export var url_2x: String: + set(val): + url_2x = val + track_data(&"url_2x", val) + + ## A URL to the large version (112px x 112px) of the emote. + @export var url_4x: String: + set(val): + url_4x = val + track_data(&"url_4x", val) + + + + ## Constructor with all required fields. + static func create(_url_1x: String, _url_2x: String, _url_4x: String) -> Images: + var images: Images = Images.new() + images.url_1x = _url_1x + images.url_2x = _url_2x + images.url_4x = _url_4x + return images + + + static func from_json(d: Dictionary) -> Images: + var result: Images = Images.new() + if d.get("url_1x", null) != null: + result.url_1x = d["url_1x"] + if d.get("url_2x", null) != null: + result.url_2x = d["url_2x"] + if d.get("url_4x", null) != null: + result.url_4x = d["url_4x"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_channel_emote.gd.uid b/addons/twitcher/generated/twitch_channel_emote.gd.uid new file mode 100644 index 0000000..6359f00 --- /dev/null +++ b/addons/twitcher/generated/twitch_channel_emote.gd.uid @@ -0,0 +1 @@ +uid://dsi08lylfjtyy diff --git a/addons/twitcher/generated/twitch_channel_information.gd b/addons/twitcher/generated/twitch_channel_information.gd new file mode 100644 index 0000000..f35443d --- /dev/null +++ b/addons/twitcher/generated/twitch_channel_information.gd @@ -0,0 +1,121 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/ChannelInformation +class_name TwitchChannelInformation + +## An ID that uniquely identifies the broadcaster. +@export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + +## The broadcaster’s login name. +@export var broadcaster_login: String: + set(val): + broadcaster_login = val + track_data(&"broadcaster_login", val) + +## The broadcaster’s display name. +@export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + +## The broadcaster’s preferred language. The value is an ISO 639-1 two-letter language code (for example, _en_ for English). The value is set to “other” if the language is not a Twitch supported language. +@export var broadcaster_language: String: + set(val): + broadcaster_language = val + track_data(&"broadcaster_language", val) + +## The name of the game that the broadcaster is playing or last played. The value is an empty string if the broadcaster has never played a game. +@export var game_name: String: + set(val): + game_name = val + track_data(&"game_name", val) + +## An ID that uniquely identifies the game that the broadcaster is playing or last played. The value is an empty string if the broadcaster has never played a game. +@export var game_id: String: + set(val): + game_id = val + track_data(&"game_id", val) + +## The title of the stream that the broadcaster is currently streaming or last streamed. The value is an empty string if the broadcaster has never streamed. +@export var title: String: + set(val): + title = val + track_data(&"title", val) + +## The value of the broadcaster’s stream delay setting, in seconds. This field’s value defaults to zero unless 1) the request specifies a user access token, 2) the ID in the _broadcaster\_id_ query parameter matches the user ID in the access token, and 3) the broadcaster has partner status and they set a non-zero stream delay value. +@export var delay: int: + set(val): + delay = val + track_data(&"delay", val) + +## The tags applied to the channel. +@export var tags: Array[String]: + set(val): + tags = val + track_data(&"tags", val) + +## The CCLs applied to the channel. +@export var content_classification_labels: Array[String]: + set(val): + content_classification_labels = val + track_data(&"content_classification_labels", val) + +## Boolean flag indicating if the channel has branded content. +@export var is_branded_content: bool: + set(val): + is_branded_content = val + track_data(&"is_branded_content", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_broadcaster_id: String, _broadcaster_login: String, _broadcaster_name: String, _broadcaster_language: String, _game_name: String, _game_id: String, _title: String, _delay: int, _tags: Array[String], _content_classification_labels: Array[String], _is_branded_content: bool) -> TwitchChannelInformation: + var twitch_channel_information: TwitchChannelInformation = TwitchChannelInformation.new() + twitch_channel_information.broadcaster_id = _broadcaster_id + twitch_channel_information.broadcaster_login = _broadcaster_login + twitch_channel_information.broadcaster_name = _broadcaster_name + twitch_channel_information.broadcaster_language = _broadcaster_language + twitch_channel_information.game_name = _game_name + twitch_channel_information.game_id = _game_id + twitch_channel_information.title = _title + twitch_channel_information.delay = _delay + twitch_channel_information.tags = _tags + twitch_channel_information.content_classification_labels = _content_classification_labels + twitch_channel_information.is_branded_content = _is_branded_content + return twitch_channel_information + + +static func from_json(d: Dictionary) -> TwitchChannelInformation: + var result: TwitchChannelInformation = TwitchChannelInformation.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_login", null) != null: + result.broadcaster_login = d["broadcaster_login"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + if d.get("broadcaster_language", null) != null: + result.broadcaster_language = d["broadcaster_language"] + if d.get("game_name", null) != null: + result.game_name = d["game_name"] + if d.get("game_id", null) != null: + result.game_id = d["game_id"] + if d.get("title", null) != null: + result.title = d["title"] + if d.get("delay", null) != null: + result.delay = d["delay"] + if d.get("tags", null) != null: + for value in d["tags"]: + result.tags.append(value) + if d.get("content_classification_labels", null) != null: + for value in d["content_classification_labels"]: + result.content_classification_labels.append(value) + if d.get("is_branded_content", null) != null: + result.is_branded_content = d["is_branded_content"] + return result diff --git a/addons/twitcher/generated/twitch_channel_information.gd.uid b/addons/twitcher/generated/twitch_channel_information.gd.uid new file mode 100644 index 0000000..b27ce9b --- /dev/null +++ b/addons/twitcher/generated/twitch_channel_information.gd.uid @@ -0,0 +1 @@ +uid://cpne5mqp80ogl diff --git a/addons/twitcher/generated/twitch_channel_stream_schedule_segment.gd b/addons/twitcher/generated/twitch_channel_stream_schedule_segment.gd new file mode 100644 index 0000000..71ac019 --- /dev/null +++ b/addons/twitcher/generated/twitch_channel_stream_schedule_segment.gd @@ -0,0 +1,120 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/ChannelStreamScheduleSegment +class_name TwitchChannelStreamScheduleSegment + +## An ID that identifies this broadcast segment. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The UTC date and time (in RFC3339 format) of when the broadcast starts. +@export var start_time: String: + set(val): + start_time = val + track_data(&"start_time", val) + +## The UTC date and time (in RFC3339 format) of when the broadcast ends. +@export var end_time: String: + set(val): + end_time = val + track_data(&"end_time", val) + +## The broadcast segment’s title. +@export var title: String: + set(val): + title = val + track_data(&"title", val) + +## Indicates whether the broadcaster canceled this segment of a recurring broadcast. If the broadcaster canceled this segment, this field is set to the same value that’s in the `end_time` field; otherwise, it’s set to **null**. +@export var canceled_until: String: + set(val): + canceled_until = val + track_data(&"canceled_until", val) + +## The type of content that the broadcaster plans to stream or **null** if not specified. +@export var category: Category: + set(val): + category = val + track_data(&"category", val) + +## A Boolean value that determines whether the broadcast is part of a recurring series that streams at the same time each week or is a one-time broadcast. Is **true** if the broadcast is part of a recurring series. +@export var is_recurring: bool: + set(val): + is_recurring = val + track_data(&"is_recurring", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _start_time: String, _end_time: String, _title: String, _canceled_until: String, _category: Category, _is_recurring: bool) -> TwitchChannelStreamScheduleSegment: + var twitch_channel_stream_schedule_segment: TwitchChannelStreamScheduleSegment = TwitchChannelStreamScheduleSegment.new() + twitch_channel_stream_schedule_segment.id = _id + twitch_channel_stream_schedule_segment.start_time = _start_time + twitch_channel_stream_schedule_segment.end_time = _end_time + twitch_channel_stream_schedule_segment.title = _title + twitch_channel_stream_schedule_segment.canceled_until = _canceled_until + twitch_channel_stream_schedule_segment.category = _category + twitch_channel_stream_schedule_segment.is_recurring = _is_recurring + return twitch_channel_stream_schedule_segment + + +static func from_json(d: Dictionary) -> TwitchChannelStreamScheduleSegment: + var result: TwitchChannelStreamScheduleSegment = TwitchChannelStreamScheduleSegment.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("start_time", null) != null: + result.start_time = d["start_time"] + if d.get("end_time", null) != null: + result.end_time = d["end_time"] + if d.get("title", null) != null: + result.title = d["title"] + if d.get("canceled_until", null) != null: + result.canceled_until = d["canceled_until"] + if d.get("category", null) != null: + result.category = Category.from_json(d["category"]) + if d.get("is_recurring", null) != null: + result.is_recurring = d["is_recurring"] + return result + + + +## The type of content that the broadcaster plans to stream or **null** if not specified. +## #/components/schemas/ChannelStreamScheduleSegment/Category +class Category extends TwitchData: + + ## An ID that identifies the category that best represents the content that the broadcaster plans to stream. For example, the game’s ID if the broadcaster will play a game or the Just Chatting ID if the broadcaster will host a talk show. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## The name of the category. For example, the game’s title if the broadcaster will play a game or Just Chatting if the broadcaster will host a talk show. + @export var name: String: + set(val): + name = val + track_data(&"name", val) + + + + ## Constructor with all required fields. + static func create(_id: String, _name: String) -> Category: + var category: Category = Category.new() + category.id = _id + category.name = _name + return category + + + static func from_json(d: Dictionary) -> Category: + var result: Category = Category.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("name", null) != null: + result.name = d["name"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_channel_stream_schedule_segment.gd.uid b/addons/twitcher/generated/twitch_channel_stream_schedule_segment.gd.uid new file mode 100644 index 0000000..371c7b3 --- /dev/null +++ b/addons/twitcher/generated/twitch_channel_stream_schedule_segment.gd.uid @@ -0,0 +1 @@ +uid://cnuxysxl4ho1 diff --git a/addons/twitcher/generated/twitch_channel_team.gd b/addons/twitcher/generated/twitch_channel_team.gd new file mode 100644 index 0000000..0a4d138 --- /dev/null +++ b/addons/twitcher/generated/twitch_channel_team.gd @@ -0,0 +1,128 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/ChannelTeam +class_name TwitchChannelTeam + +## An ID that identifies the broadcaster. +@export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + +## The broadcaster’s login name. +@export var broadcaster_login: String: + set(val): + broadcaster_login = val + track_data(&"broadcaster_login", val) + +## The broadcaster’s display name. +@export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + +## A URL to the team’s background image. +@export var background_image_url: String: + set(val): + background_image_url = val + track_data(&"background_image_url", val) + +## A URL to the team’s banner. +@export var banner: String: + set(val): + banner = val + track_data(&"banner", val) + +## The UTC date and time (in RFC3339 format) of when the team was created. +@export var created_at: String: + set(val): + created_at = val + track_data(&"created_at", val) + +## The UTC date and time (in RFC3339 format) of the last time the team was updated. +@export var updated_at: String: + set(val): + updated_at = val + track_data(&"updated_at", val) + +## The team’s description. The description may contain formatting such as Markdown, HTML, newline (\\n) characters, etc. +@export var info: String: + set(val): + info = val + track_data(&"info", val) + +## A URL to a thumbnail image of the team’s logo. +@export var thumbnail_url: String: + set(val): + thumbnail_url = val + track_data(&"thumbnail_url", val) + +## The team’s name. +@export var team_name: String: + set(val): + team_name = val + track_data(&"team_name", val) + +## The team’s display name. +@export var team_display_name: String: + set(val): + team_display_name = val + track_data(&"team_display_name", val) + +## An ID that identifies the team. +@export var id: String: + set(val): + id = val + track_data(&"id", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_broadcaster_id: String, _broadcaster_login: String, _broadcaster_name: String, _background_image_url: String, _banner: String, _created_at: String, _updated_at: String, _info: String, _thumbnail_url: String, _team_name: String, _team_display_name: String, _id: String) -> TwitchChannelTeam: + var twitch_channel_team: TwitchChannelTeam = TwitchChannelTeam.new() + twitch_channel_team.broadcaster_id = _broadcaster_id + twitch_channel_team.broadcaster_login = _broadcaster_login + twitch_channel_team.broadcaster_name = _broadcaster_name + twitch_channel_team.background_image_url = _background_image_url + twitch_channel_team.banner = _banner + twitch_channel_team.created_at = _created_at + twitch_channel_team.updated_at = _updated_at + twitch_channel_team.info = _info + twitch_channel_team.thumbnail_url = _thumbnail_url + twitch_channel_team.team_name = _team_name + twitch_channel_team.team_display_name = _team_display_name + twitch_channel_team.id = _id + return twitch_channel_team + + +static func from_json(d: Dictionary) -> TwitchChannelTeam: + var result: TwitchChannelTeam = TwitchChannelTeam.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_login", null) != null: + result.broadcaster_login = d["broadcaster_login"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + if d.get("background_image_url", null) != null: + result.background_image_url = d["background_image_url"] + if d.get("banner", null) != null: + result.banner = d["banner"] + if d.get("created_at", null) != null: + result.created_at = d["created_at"] + if d.get("updated_at", null) != null: + result.updated_at = d["updated_at"] + if d.get("info", null) != null: + result.info = d["info"] + if d.get("thumbnail_url", null) != null: + result.thumbnail_url = d["thumbnail_url"] + if d.get("team_name", null) != null: + result.team_name = d["team_name"] + if d.get("team_display_name", null) != null: + result.team_display_name = d["team_display_name"] + if d.get("id", null) != null: + result.id = d["id"] + return result diff --git a/addons/twitcher/generated/twitch_channel_team.gd.uid b/addons/twitcher/generated/twitch_channel_team.gd.uid new file mode 100644 index 0000000..efd5c7b --- /dev/null +++ b/addons/twitcher/generated/twitch_channel_team.gd.uid @@ -0,0 +1 @@ +uid://bcbfc8frdl2f1 diff --git a/addons/twitcher/generated/twitch_charity_campaign.gd b/addons/twitcher/generated/twitch_charity_campaign.gd new file mode 100644 index 0000000..8df1570 --- /dev/null +++ b/addons/twitcher/generated/twitch_charity_campaign.gd @@ -0,0 +1,205 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/CharityCampaign +class_name TwitchCharityCampaign + +## An ID that identifies the charity campaign. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## An ID that identifies the broadcaster that’s running the campaign. +@export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + +## The broadcaster’s login name. +@export var broadcaster_login: String: + set(val): + broadcaster_login = val + track_data(&"broadcaster_login", val) + +## The broadcaster’s display name. +@export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + +## The charity’s name. +@export var charity_name: String: + set(val): + charity_name = val + track_data(&"charity_name", val) + +## A description of the charity. +@export var charity_description: String: + set(val): + charity_description = val + track_data(&"charity_description", val) + +## A URL to an image of the charity’s logo. The image’s type is PNG and its size is 100px X 100px. +@export var charity_logo: String: + set(val): + charity_logo = val + track_data(&"charity_logo", val) + +## A URL to the charity’s website. +@export var charity_website: String: + set(val): + charity_website = val + track_data(&"charity_website", val) + +## The current amount of donations that the campaign has received. +@export var current_amount: CurrentAmount: + set(val): + current_amount = val + track_data(&"current_amount", val) + +## The campaign’s fundraising goal. This field is **null** if the broadcaster has not defined a fundraising goal. +@export var target_amount: TargetAmount: + set(val): + target_amount = val + track_data(&"target_amount", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _broadcaster_id: String, _broadcaster_login: String, _broadcaster_name: String, _charity_name: String, _charity_description: String, _charity_logo: String, _charity_website: String, _current_amount: CurrentAmount, _target_amount: TargetAmount) -> TwitchCharityCampaign: + var twitch_charity_campaign: TwitchCharityCampaign = TwitchCharityCampaign.new() + twitch_charity_campaign.id = _id + twitch_charity_campaign.broadcaster_id = _broadcaster_id + twitch_charity_campaign.broadcaster_login = _broadcaster_login + twitch_charity_campaign.broadcaster_name = _broadcaster_name + twitch_charity_campaign.charity_name = _charity_name + twitch_charity_campaign.charity_description = _charity_description + twitch_charity_campaign.charity_logo = _charity_logo + twitch_charity_campaign.charity_website = _charity_website + twitch_charity_campaign.current_amount = _current_amount + twitch_charity_campaign.target_amount = _target_amount + return twitch_charity_campaign + + +static func from_json(d: Dictionary) -> TwitchCharityCampaign: + var result: TwitchCharityCampaign = TwitchCharityCampaign.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_login", null) != null: + result.broadcaster_login = d["broadcaster_login"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + if d.get("charity_name", null) != null: + result.charity_name = d["charity_name"] + if d.get("charity_description", null) != null: + result.charity_description = d["charity_description"] + if d.get("charity_logo", null) != null: + result.charity_logo = d["charity_logo"] + if d.get("charity_website", null) != null: + result.charity_website = d["charity_website"] + if d.get("current_amount", null) != null: + result.current_amount = CurrentAmount.from_json(d["current_amount"]) + if d.get("target_amount", null) != null: + result.target_amount = TargetAmount.from_json(d["target_amount"]) + return result + + + +## The current amount of donations that the campaign has received. +## #/components/schemas/CharityCampaign/CurrentAmount +class CurrentAmount extends TwitchData: + + ## The monetary amount. The amount is specified in the currency’s minor unit. For example, the minor units for USD is cents, so if the amount is $5.50 USD, `value` is set to 550. + @export var value: int: + set(val): + value = val + track_data(&"value", val) + + ## The number of decimal places used by the currency. For example, USD uses two decimal places. Use this number to translate `value` from minor units to major units by using the formula: + ## + ## `value / 10^decimal_places` + @export var decimal_places: int: + set(val): + decimal_places = val + track_data(&"decimal_places", val) + + ## The ISO-4217 three-letter currency code that identifies the type of currency in `value`. + @export var currency: String: + set(val): + currency = val + track_data(&"currency", val) + + + + ## Constructor with all required fields. + static func create(_value: int, _decimal_places: int, _currency: String) -> CurrentAmount: + var current_amount: CurrentAmount = CurrentAmount.new() + current_amount.value = _value + current_amount.decimal_places = _decimal_places + current_amount.currency = _currency + return current_amount + + + static func from_json(d: Dictionary) -> CurrentAmount: + var result: CurrentAmount = CurrentAmount.new() + if d.get("value", null) != null: + result.value = d["value"] + if d.get("decimal_places", null) != null: + result.decimal_places = d["decimal_places"] + if d.get("currency", null) != null: + result.currency = d["currency"] + return result + + + +## The campaign’s fundraising goal. This field is **null** if the broadcaster has not defined a fundraising goal. +## #/components/schemas/CharityCampaign/TargetAmount +class TargetAmount extends TwitchData: + + ## The monetary amount. The amount is specified in the currency’s minor unit. For example, the minor units for USD is cents, so if the amount is $5.50 USD, `value` is set to 550. + @export var value: int: + set(val): + value = val + track_data(&"value", val) + + ## The number of decimal places used by the currency. For example, USD uses two decimal places. Use this number to translate `value` from minor units to major units by using the formula: + ## + ## `value / 10^decimal_places` + @export var decimal_places: int: + set(val): + decimal_places = val + track_data(&"decimal_places", val) + + ## The ISO-4217 three-letter currency code that identifies the type of currency in `value`. + @export var currency: String: + set(val): + currency = val + track_data(&"currency", val) + + + + ## Constructor with all required fields. + static func create(_value: int, _decimal_places: int, _currency: String) -> TargetAmount: + var target_amount: TargetAmount = TargetAmount.new() + target_amount.value = _value + target_amount.decimal_places = _decimal_places + target_amount.currency = _currency + return target_amount + + + static func from_json(d: Dictionary) -> TargetAmount: + var result: TargetAmount = TargetAmount.new() + if d.get("value", null) != null: + result.value = d["value"] + if d.get("decimal_places", null) != null: + result.decimal_places = d["decimal_places"] + if d.get("currency", null) != null: + result.currency = d["currency"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_charity_campaign.gd.uid b/addons/twitcher/generated/twitch_charity_campaign.gd.uid new file mode 100644 index 0000000..b908bd3 --- /dev/null +++ b/addons/twitcher/generated/twitch_charity_campaign.gd.uid @@ -0,0 +1 @@ +uid://bfccgp4ggf3cs diff --git a/addons/twitcher/generated/twitch_charity_campaign_donation.gd b/addons/twitcher/generated/twitch_charity_campaign_donation.gd new file mode 100644 index 0000000..557dea5 --- /dev/null +++ b/addons/twitcher/generated/twitch_charity_campaign_donation.gd @@ -0,0 +1,122 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/CharityCampaignDonation +class_name TwitchCharityCampaignDonation + +## An ID that identifies the donation. The ID is unique across campaigns. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## An ID that identifies the charity campaign that the donation applies to. +@export var campaign_id: String: + set(val): + campaign_id = val + track_data(&"campaign_id", val) + +## An ID that identifies a user that donated money to the campaign. +@export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + +## The user’s login name. +@export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) + +## The user’s display name. +@export var user_name: String: + set(val): + user_name = val + track_data(&"user_name", val) + +## An object that contains the amount of money that the user donated. +@export var amount: Amount: + set(val): + amount = val + track_data(&"amount", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _campaign_id: String, _user_id: String, _user_login: String, _user_name: String, _amount: Amount) -> TwitchCharityCampaignDonation: + var twitch_charity_campaign_donation: TwitchCharityCampaignDonation = TwitchCharityCampaignDonation.new() + twitch_charity_campaign_donation.id = _id + twitch_charity_campaign_donation.campaign_id = _campaign_id + twitch_charity_campaign_donation.user_id = _user_id + twitch_charity_campaign_donation.user_login = _user_login + twitch_charity_campaign_donation.user_name = _user_name + twitch_charity_campaign_donation.amount = _amount + return twitch_charity_campaign_donation + + +static func from_json(d: Dictionary) -> TwitchCharityCampaignDonation: + var result: TwitchCharityCampaignDonation = TwitchCharityCampaignDonation.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("campaign_id", null) != null: + result.campaign_id = d["campaign_id"] + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + if d.get("user_name", null) != null: + result.user_name = d["user_name"] + if d.get("amount", null) != null: + result.amount = Amount.from_json(d["amount"]) + return result + + + +## An object that contains the amount of money that the user donated. +## #/components/schemas/CharityCampaignDonation/Amount +class Amount extends TwitchData: + + ## The monetary amount. The amount is specified in the currency’s minor unit. For example, the minor units for USD is cents, so if the amount is $5.50 USD, `value` is set to 550. + @export var value: int: + set(val): + value = val + track_data(&"value", val) + + ## The number of decimal places used by the currency. For example, USD uses two decimal places. Use this number to translate `value` from minor units to major units by using the formula: + ## + ## `value / 10^decimal_places` + @export var decimal_places: int: + set(val): + decimal_places = val + track_data(&"decimal_places", val) + + ## The ISO-4217 three-letter currency code that identifies the type of currency in `value`. + @export var currency: String: + set(val): + currency = val + track_data(&"currency", val) + + + + ## Constructor with all required fields. + static func create(_value: int, _decimal_places: int, _currency: String) -> Amount: + var amount: Amount = Amount.new() + amount.value = _value + amount.decimal_places = _decimal_places + amount.currency = _currency + return amount + + + static func from_json(d: Dictionary) -> Amount: + var result: Amount = Amount.new() + if d.get("value", null) != null: + result.value = d["value"] + if d.get("decimal_places", null) != null: + result.decimal_places = d["decimal_places"] + if d.get("currency", null) != null: + result.currency = d["currency"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_charity_campaign_donation.gd.uid b/addons/twitcher/generated/twitch_charity_campaign_donation.gd.uid new file mode 100644 index 0000000..f854a97 --- /dev/null +++ b/addons/twitcher/generated/twitch_charity_campaign_donation.gd.uid @@ -0,0 +1 @@ +uid://bk4mrla21bejo diff --git a/addons/twitcher/generated/twitch_chat_badge.gd b/addons/twitcher/generated/twitch_chat_badge.gd new file mode 100644 index 0000000..1c59676 --- /dev/null +++ b/addons/twitcher/generated/twitch_chat_badge.gd @@ -0,0 +1,130 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/ChatBadge +class_name TwitchChatBadge + +## An ID that identifies this set of chat badges. For example, Bits or Subscriber. +@export var set_id: String: + set(val): + set_id = val + track_data(&"set_id", val) + +## The list of chat badges in this set. +@export var versions: Array[Versions]: + set(val): + versions = val + track_data(&"versions", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_set_id: String, _versions: Array[Versions]) -> TwitchChatBadge: + var twitch_chat_badge: TwitchChatBadge = TwitchChatBadge.new() + twitch_chat_badge.set_id = _set_id + twitch_chat_badge.versions = _versions + return twitch_chat_badge + + +static func from_json(d: Dictionary) -> TwitchChatBadge: + var result: TwitchChatBadge = TwitchChatBadge.new() + if d.get("set_id", null) != null: + result.set_id = d["set_id"] + if d.get("versions", null) != null: + for value in d["versions"]: + result.versions.append(Versions.from_json(value)) + return result + + + +## The list of chat badges in this set. +## #/components/schemas/ChatBadge/Versions +class Versions extends TwitchData: + + ## An ID that identifies this version of the badge. The ID can be any value. For example, for Bits, the ID is the Bits tier level, but for World of Warcraft, it could be Alliance or Horde. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## A URL to the small version (18px x 18px) of the badge. + @export var image_url_1x: String: + set(val): + image_url_1x = val + track_data(&"image_url_1x", val) + + ## A URL to the medium version (36px x 36px) of the badge. + @export var image_url_2x: String: + set(val): + image_url_2x = val + track_data(&"image_url_2x", val) + + ## A URL to the large version (72px x 72px) of the badge. + @export var image_url_4x: String: + set(val): + image_url_4x = val + track_data(&"image_url_4x", val) + + ## The title of the badge. + @export var title: String: + set(val): + title = val + track_data(&"title", val) + + ## The description of the badge. + @export var description: String: + set(val): + description = val + track_data(&"description", val) + + ## The action to take when clicking on the badge. Set to `null` if no action is specified. + @export var click_action: String: + set(val): + click_action = val + track_data(&"click_action", val) + + ## The URL to navigate to when clicking on the badge. Set to `null` if no URL is specified. + @export var click_url: String: + set(val): + click_url = val + track_data(&"click_url", val) + + + + ## Constructor with all required fields. + static func create(_id: String, _image_url_1x: String, _image_url_2x: String, _image_url_4x: String, _title: String, _description: String, _click_action: String, _click_url: String) -> Versions: + var versions: Versions = Versions.new() + versions.id = _id + versions.image_url_1x = _image_url_1x + versions.image_url_2x = _image_url_2x + versions.image_url_4x = _image_url_4x + versions.title = _title + versions.description = _description + versions.click_action = _click_action + versions.click_url = _click_url + return versions + + + static func from_json(d: Dictionary) -> Versions: + var result: Versions = Versions.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("image_url_1x", null) != null: + result.image_url_1x = d["image_url_1x"] + if d.get("image_url_2x", null) != null: + result.image_url_2x = d["image_url_2x"] + if d.get("image_url_4x", null) != null: + result.image_url_4x = d["image_url_4x"] + if d.get("title", null) != null: + result.title = d["title"] + if d.get("description", null) != null: + result.description = d["description"] + if d.get("click_action", null) != null: + result.click_action = d["click_action"] + if d.get("click_url", null) != null: + result.click_url = d["click_url"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_chat_badge.gd.uid b/addons/twitcher/generated/twitch_chat_badge.gd.uid new file mode 100644 index 0000000..546acae --- /dev/null +++ b/addons/twitcher/generated/twitch_chat_badge.gd.uid @@ -0,0 +1 @@ +uid://b0gnrrvi7p5av diff --git a/addons/twitcher/generated/twitch_chat_settings.gd b/addons/twitcher/generated/twitch_chat_settings.gd new file mode 100644 index 0000000..a64ed38 --- /dev/null +++ b/addons/twitcher/generated/twitch_chat_settings.gd @@ -0,0 +1,134 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/ChatSettings +class_name TwitchChatSettings + +## The ID of the broadcaster specified in the request. +@export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + +## A Boolean value that determines whether chat messages must contain only emotes. Is **true** if chat messages may contain only emotes; otherwise, **false**. +@export var emote_mode: bool: + set(val): + emote_mode = val + track_data(&"emote_mode", val) + +## A Boolean value that determines whether the broadcaster restricts the chat room to followers only. +## +## Is **true** if the broadcaster restricts the chat room to followers only; otherwise, **false**. +## +## See the `follower_mode_duration` field for how long users must follow the broadcaster before being able to participate in the chat room. +@export var follower_mode: bool: + set(val): + follower_mode = val + track_data(&"follower_mode", val) + +## The length of time, in minutes, that users must follow the broadcaster before being able to participate in the chat room. Is **null** if `follower_mode` is **false**. +@export var follower_mode_duration: int: + set(val): + follower_mode_duration = val + track_data(&"follower_mode_duration", val) + +## The moderator’s ID. The response includes this field only if the request specifies a user access token that includes the **moderator:read:chat\_settings** scope. +@export var moderator_id: String: + set(val): + moderator_id = val + track_data(&"moderator_id", val) + +## A Boolean value that determines whether the broadcaster adds a short delay before chat messages appear in the chat room. This gives chat moderators and bots a chance to remove them before viewers can see the message. See the `non_moderator_chat_delay_duration` field for the length of the delay. Is **true** if the broadcaster applies a delay; otherwise, **false**. +## +## The response includes this field only if the request specifies a user access token that includes the **moderator:read:chat\_settings** scope and the user in the _moderator\_id_ query parameter is one of the broadcaster’s moderators. +@export var non_moderator_chat_delay: bool: + set(val): + non_moderator_chat_delay = val + track_data(&"non_moderator_chat_delay", val) + +## The amount of time, in seconds, that messages are delayed before appearing in chat. Is **null** if `non_moderator_chat_delay` is **false**. +## +## The response includes this field only if the request specifies a user access token that includes the **moderator:read:chat\_settings** scope and the user in the _moderator\_id_ query parameter is one of the broadcaster’s moderators. +@export var non_moderator_chat_delay_duration: int: + set(val): + non_moderator_chat_delay_duration = val + track_data(&"non_moderator_chat_delay_duration", val) + +## A Boolean value that determines whether the broadcaster limits how often users in the chat room are allowed to send messages. +## +## Is **true** if the broadcaster applies a delay; otherwise, **false**. +## +## See the `slow_mode_wait_time` field for the delay. +@export var slow_mode: bool: + set(val): + slow_mode = val + track_data(&"slow_mode", val) + +## The amount of time, in seconds, that users must wait between sending messages. +## +## Is **null** if slow\_mode is **false**. +@export var slow_mode_wait_time: int: + set(val): + slow_mode_wait_time = val + track_data(&"slow_mode_wait_time", val) + +## A Boolean value that determines whether only users that subscribe to the broadcaster’s channel may talk in the chat room. +## +## Is **true** if the broadcaster restricts the chat room to subscribers only; otherwise, **false**. +@export var subscriber_mode: bool: + set(val): + subscriber_mode = val + track_data(&"subscriber_mode", val) + +## A Boolean value that determines whether the broadcaster requires users to post only unique messages in the chat room. +## +## Is **true** if the broadcaster requires unique messages only; otherwise, **false**. +@export var unique_chat_mode: bool: + set(val): + unique_chat_mode = val + track_data(&"unique_chat_mode", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_broadcaster_id: String, _emote_mode: bool, _follower_mode: bool, _follower_mode_duration: int, _slow_mode: bool, _slow_mode_wait_time: int, _subscriber_mode: bool, _unique_chat_mode: bool) -> TwitchChatSettings: + var twitch_chat_settings: TwitchChatSettings = TwitchChatSettings.new() + twitch_chat_settings.broadcaster_id = _broadcaster_id + twitch_chat_settings.emote_mode = _emote_mode + twitch_chat_settings.follower_mode = _follower_mode + twitch_chat_settings.follower_mode_duration = _follower_mode_duration + twitch_chat_settings.slow_mode = _slow_mode + twitch_chat_settings.slow_mode_wait_time = _slow_mode_wait_time + twitch_chat_settings.subscriber_mode = _subscriber_mode + twitch_chat_settings.unique_chat_mode = _unique_chat_mode + return twitch_chat_settings + + +static func from_json(d: Dictionary) -> TwitchChatSettings: + var result: TwitchChatSettings = TwitchChatSettings.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("emote_mode", null) != null: + result.emote_mode = d["emote_mode"] + if d.get("follower_mode", null) != null: + result.follower_mode = d["follower_mode"] + if d.get("follower_mode_duration", null) != null: + result.follower_mode_duration = d["follower_mode_duration"] + if d.get("moderator_id", null) != null: + result.moderator_id = d["moderator_id"] + if d.get("non_moderator_chat_delay", null) != null: + result.non_moderator_chat_delay = d["non_moderator_chat_delay"] + if d.get("non_moderator_chat_delay_duration", null) != null: + result.non_moderator_chat_delay_duration = d["non_moderator_chat_delay_duration"] + if d.get("slow_mode", null) != null: + result.slow_mode = d["slow_mode"] + if d.get("slow_mode_wait_time", null) != null: + result.slow_mode_wait_time = d["slow_mode_wait_time"] + if d.get("subscriber_mode", null) != null: + result.subscriber_mode = d["subscriber_mode"] + if d.get("unique_chat_mode", null) != null: + result.unique_chat_mode = d["unique_chat_mode"] + return result diff --git a/addons/twitcher/generated/twitch_chat_settings.gd.uid b/addons/twitcher/generated/twitch_chat_settings.gd.uid new file mode 100644 index 0000000..ac350c0 --- /dev/null +++ b/addons/twitcher/generated/twitch_chat_settings.gd.uid @@ -0,0 +1 @@ +uid://d10yuxg35qlpa diff --git a/addons/twitcher/generated/twitch_chat_settings_updated.gd b/addons/twitcher/generated/twitch_chat_settings_updated.gd new file mode 100644 index 0000000..a676f72 --- /dev/null +++ b/addons/twitcher/generated/twitch_chat_settings_updated.gd @@ -0,0 +1,132 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/ChatSettingsUpdated +class_name TwitchChatSettingsUpdated + +## The ID of the broadcaster specified in the request. +@export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + +## A Boolean value that determines whether chat messages must contain only emotes. Is **true** if chat messages may contain only emotes; otherwise, **false**. +@export var emote_mode: bool: + set(val): + emote_mode = val + track_data(&"emote_mode", val) + +## A Boolean value that determines whether the broadcaster restricts the chat room to followers only. +## +## Is **true** if the broadcaster restricts the chat room to followers only; otherwise, **false**. +## +## See the `follower_mode_duration` field for how long users must follow the broadcaster before being able to participate in the chat room. +@export var follower_mode: bool: + set(val): + follower_mode = val + track_data(&"follower_mode", val) + +## The length of time, in minutes, that users must follow the broadcaster before being able to participate in the chat room. Is **null** if `follower_mode` is **false**. +@export var follower_mode_duration: int: + set(val): + follower_mode_duration = val + track_data(&"follower_mode_duration", val) + +## The moderator’s ID. The response includes this field only if the request specifies a user access token that includes the **moderator:read:chat\_settings** scope. +@export var moderator_id: String: + set(val): + moderator_id = val + track_data(&"moderator_id", val) + +## A Boolean value that determines whether the broadcaster adds a short delay before chat messages appear in the chat room. This gives chat moderators and bots a chance to remove them before viewers can see the message. See the `non_moderator_chat_delay_duration` field for the length of the delay. Is **true** if the broadcaster applies a delay; otherwise, **false**. +@export var non_moderator_chat_delay: bool: + set(val): + non_moderator_chat_delay = val + track_data(&"non_moderator_chat_delay", val) + +## The amount of time, in seconds, that messages are delayed before appearing in chat. Is **null** if `non_moderator_chat_delay` is **false**. +@export var non_moderator_chat_delay_duration: int: + set(val): + non_moderator_chat_delay_duration = val + track_data(&"non_moderator_chat_delay_duration", val) + +## A Boolean value that determines whether the broadcaster limits how often users in the chat room are allowed to send messages. +## +## Is **true** if the broadcaster applies a delay; otherwise, **false**. +## +## See the `slow_mode_wait_time` field for the delay. +@export var slow_mode: bool: + set(val): + slow_mode = val + track_data(&"slow_mode", val) + +## The amount of time, in seconds, that users must wait between sending messages. +## +## Is **null** if slow\_mode is **false**. +@export var slow_mode_wait_time: int: + set(val): + slow_mode_wait_time = val + track_data(&"slow_mode_wait_time", val) + +## A Boolean value that determines whether only users that subscribe to the broadcaster’s channel may talk in the chat room. +## +## Is **true** if the broadcaster restricts the chat room to subscribers only; otherwise, **false**. +@export var subscriber_mode: bool: + set(val): + subscriber_mode = val + track_data(&"subscriber_mode", val) + +## A Boolean value that determines whether the broadcaster requires users to post only unique messages in the chat room. +## +## Is **true** if the broadcaster requires unique messages only; otherwise, **false**. +@export var unique_chat_mode: bool: + set(val): + unique_chat_mode = val + track_data(&"unique_chat_mode", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_broadcaster_id: String, _emote_mode: bool, _follower_mode: bool, _follower_mode_duration: int, _non_moderator_chat_delay: bool, _non_moderator_chat_delay_duration: int, _slow_mode: bool, _slow_mode_wait_time: int, _subscriber_mode: bool, _unique_chat_mode: bool) -> TwitchChatSettingsUpdated: + var twitch_chat_settings_updated: TwitchChatSettingsUpdated = TwitchChatSettingsUpdated.new() + twitch_chat_settings_updated.broadcaster_id = _broadcaster_id + twitch_chat_settings_updated.emote_mode = _emote_mode + twitch_chat_settings_updated.follower_mode = _follower_mode + twitch_chat_settings_updated.follower_mode_duration = _follower_mode_duration + twitch_chat_settings_updated.non_moderator_chat_delay = _non_moderator_chat_delay + twitch_chat_settings_updated.non_moderator_chat_delay_duration = _non_moderator_chat_delay_duration + twitch_chat_settings_updated.slow_mode = _slow_mode + twitch_chat_settings_updated.slow_mode_wait_time = _slow_mode_wait_time + twitch_chat_settings_updated.subscriber_mode = _subscriber_mode + twitch_chat_settings_updated.unique_chat_mode = _unique_chat_mode + return twitch_chat_settings_updated + + +static func from_json(d: Dictionary) -> TwitchChatSettingsUpdated: + var result: TwitchChatSettingsUpdated = TwitchChatSettingsUpdated.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("emote_mode", null) != null: + result.emote_mode = d["emote_mode"] + if d.get("follower_mode", null) != null: + result.follower_mode = d["follower_mode"] + if d.get("follower_mode_duration", null) != null: + result.follower_mode_duration = d["follower_mode_duration"] + if d.get("moderator_id", null) != null: + result.moderator_id = d["moderator_id"] + if d.get("non_moderator_chat_delay", null) != null: + result.non_moderator_chat_delay = d["non_moderator_chat_delay"] + if d.get("non_moderator_chat_delay_duration", null) != null: + result.non_moderator_chat_delay_duration = d["non_moderator_chat_delay_duration"] + if d.get("slow_mode", null) != null: + result.slow_mode = d["slow_mode"] + if d.get("slow_mode_wait_time", null) != null: + result.slow_mode_wait_time = d["slow_mode_wait_time"] + if d.get("subscriber_mode", null) != null: + result.subscriber_mode = d["subscriber_mode"] + if d.get("unique_chat_mode", null) != null: + result.unique_chat_mode = d["unique_chat_mode"] + return result diff --git a/addons/twitcher/generated/twitch_chat_settings_updated.gd.uid b/addons/twitcher/generated/twitch_chat_settings_updated.gd.uid new file mode 100644 index 0000000..f4f912d --- /dev/null +++ b/addons/twitcher/generated/twitch_chat_settings_updated.gd.uid @@ -0,0 +1 @@ +uid://rp8u05k22h77 diff --git a/addons/twitcher/generated/twitch_chatter.gd b/addons/twitcher/generated/twitch_chatter.gd new file mode 100644 index 0000000..eb256d7 --- /dev/null +++ b/addons/twitcher/generated/twitch_chatter.gd @@ -0,0 +1,47 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/Chatter +class_name TwitchChatter + +## The ID of a user that’s connected to the broadcaster’s chat room. +@export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + +## The user’s login name. +@export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) + +## The user’s display name. +@export var user_name: String: + set(val): + user_name = val + track_data(&"user_name", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_user_id: String, _user_login: String, _user_name: String) -> TwitchChatter: + var twitch_chatter: TwitchChatter = TwitchChatter.new() + twitch_chatter.user_id = _user_id + twitch_chatter.user_login = _user_login + twitch_chatter.user_name = _user_name + return twitch_chatter + + +static func from_json(d: Dictionary) -> TwitchChatter: + var result: TwitchChatter = TwitchChatter.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + if d.get("user_name", null) != null: + result.user_name = d["user_name"] + return result diff --git a/addons/twitcher/generated/twitch_chatter.gd.uid b/addons/twitcher/generated/twitch_chatter.gd.uid new file mode 100644 index 0000000..e65350e --- /dev/null +++ b/addons/twitcher/generated/twitch_chatter.gd.uid @@ -0,0 +1 @@ +uid://d0och515dnpht diff --git a/addons/twitcher/generated/twitch_check_auto_mod_status.gd b/addons/twitcher/generated/twitch_check_auto_mod_status.gd new file mode 100644 index 0000000..cb5909b --- /dev/null +++ b/addons/twitcher/generated/twitch_check_auto_mod_status.gd @@ -0,0 +1,99 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchCheckAutoModStatus + + + +## +## #/components/schemas/CheckAutoModStatusBody +class Body extends TwitchData: + + ## The list of messages to check. The list must contain at least one message and may contain up to a maximum of 100 messages. + @export var data: Array[BodyData]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[BodyData]) -> Body: + var body: Body = Body.new() + body.data = _data + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(BodyData.from_json(value)) + return result + + + +## The list of messages to check. The list must contain at least one message and may contain up to a maximum of 100 messages. +## #/components/schemas/CheckAutoModStatusBody/Data +class BodyData extends TwitchData: + + ## A caller-defined ID used to correlate this message with the same message in the response. + @export var msg_id: String: + set(val): + msg_id = val + track_data(&"msg_id", val) + + ## The message to check. + @export var msg_text: String: + set(val): + msg_text = val + track_data(&"msg_text", val) + + + + ## Constructor with all required fields. + static func create(_msg_id: String, _msg_text: String) -> BodyData: + var body_data: BodyData = BodyData.new() + body_data.msg_id = _msg_id + body_data.msg_text = _msg_text + return body_data + + + static func from_json(d: Dictionary) -> BodyData: + var result: BodyData = BodyData.new() + if d.get("msg_id", null) != null: + result.msg_id = d["msg_id"] + if d.get("msg_text", null) != null: + result.msg_text = d["msg_text"] + return result + + + +## +## #/components/schemas/CheckAutoModStatusResponse +class Response extends TwitchData: + + ## The list of messages and whether Twitch would approve them for chat. + @export var data: Array[TwitchAutoModStatus]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchAutoModStatus]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchAutoModStatus.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_check_auto_mod_status.gd.uid b/addons/twitcher/generated/twitch_check_auto_mod_status.gd.uid new file mode 100644 index 0000000..f64e68b --- /dev/null +++ b/addons/twitcher/generated/twitch_check_auto_mod_status.gd.uid @@ -0,0 +1 @@ +uid://cvx1r2bhj5cfk diff --git a/addons/twitcher/generated/twitch_check_user_subscription.gd b/addons/twitcher/generated/twitch_check_user_subscription.gd new file mode 100644 index 0000000..b906ecd --- /dev/null +++ b/addons/twitcher/generated/twitch_check_user_subscription.gd @@ -0,0 +1,35 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchCheckUserSubscription + + + +## +## #/components/schemas/CheckUserSubscriptionResponse +class Response extends TwitchData: + + ## A list that contains a single object with information about the user’s subscription. + @export var data: Array[TwitchUserSubscription]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchUserSubscription]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchUserSubscription.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_check_user_subscription.gd.uid b/addons/twitcher/generated/twitch_check_user_subscription.gd.uid new file mode 100644 index 0000000..ac086b1 --- /dev/null +++ b/addons/twitcher/generated/twitch_check_user_subscription.gd.uid @@ -0,0 +1 @@ +uid://bl18pfscbkvum diff --git a/addons/twitcher/generated/twitch_cheermote.gd b/addons/twitcher/generated/twitch_cheermote.gd new file mode 100644 index 0000000..8b887d4 --- /dev/null +++ b/addons/twitcher/generated/twitch_cheermote.gd @@ -0,0 +1,162 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/Cheermote +class_name TwitchCheermote + +## The name portion of the Cheermote string that you use in chat to cheer Bits. The full Cheermote string is the concatenation of {prefix} + {number of Bits}. For example, if the prefix is “Cheer” and you want to cheer 100 Bits, the full Cheermote string is Cheer100\. When the Cheermote string is entered in chat, Twitch converts it to the image associated with the Bits tier that was cheered. +@export var prefix: String: + set(val): + prefix = val + track_data(&"prefix", val) + +## A list of tier levels that the Cheermote supports. Each tier identifies the range of Bits that you can cheer at that tier level and an image that graphically identifies the tier level. +@export var tiers: Array[Tiers]: + set(val): + tiers = val + track_data(&"tiers", val) + +## The type of Cheermote. Possible values are: +## +## * global\_first\_party — A Twitch-defined Cheermote that is shown in the Bits card. +## * global\_third\_party — A Twitch-defined Cheermote that is not shown in the Bits card. +## * channel\_custom — A broadcaster-defined Cheermote. +## * display\_only — Do not use; for internal use only. +## * sponsored — A sponsor-defined Cheermote. When used, the sponsor adds additional Bits to the amount that the user cheered. For example, if the user cheered Terminator100, the broadcaster might receive 110 Bits, which includes the sponsor's 10 Bits contribution. +@export var type: String: + set(val): + type = val + track_data(&"type", val) + +## The order that the Cheermotes are shown in the Bits card. The numbers may not be consecutive. For example, the numbers may jump from 1 to 7 to 13\. The order numbers are unique within a Cheermote type (for example, global\_first\_party) but may not be unique amongst all Cheermotes in the response. +@export var order: int: + set(val): + order = val + track_data(&"order", val) + +## The date and time, in RFC3339 format, when this Cheermote was last updated. +@export var last_updated: String: + set(val): + last_updated = val + track_data(&"last_updated", val) + +## A Boolean value that indicates whether this Cheermote provides a charitable contribution match during charity campaigns. +@export var is_charitable: bool: + set(val): + is_charitable = val + track_data(&"is_charitable", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_prefix: String, _tiers: Array[Tiers], _type: String, _order: int, _last_updated: String, _is_charitable: bool) -> TwitchCheermote: + var twitch_cheermote: TwitchCheermote = TwitchCheermote.new() + twitch_cheermote.prefix = _prefix + twitch_cheermote.tiers = _tiers + twitch_cheermote.type = _type + twitch_cheermote.order = _order + twitch_cheermote.last_updated = _last_updated + twitch_cheermote.is_charitable = _is_charitable + return twitch_cheermote + + +static func from_json(d: Dictionary) -> TwitchCheermote: + var result: TwitchCheermote = TwitchCheermote.new() + if d.get("prefix", null) != null: + result.prefix = d["prefix"] + if d.get("tiers", null) != null: + for value in d["tiers"]: + result.tiers.append(Tiers.from_json(value)) + if d.get("type", null) != null: + result.type = d["type"] + if d.get("order", null) != null: + result.order = d["order"] + if d.get("last_updated", null) != null: + result.last_updated = d["last_updated"] + if d.get("is_charitable", null) != null: + result.is_charitable = d["is_charitable"] + return result + + + +## A list of tier levels that the Cheermote supports. Each tier identifies the range of Bits that you can cheer at that tier level and an image that graphically identifies the tier level. +## #/components/schemas/Cheermote/Tiers +class Tiers extends TwitchData: + + ## The minimum number of Bits that you must cheer at this tier level. The maximum number of Bits that you can cheer at this level is determined by the required minimum Bits of the next tier level minus 1\. For example, if `min_bits` is 1 and `min_bits` for the next tier is 100, the Bits range for this tier level is 1 through 99\. The minimum Bits value of the last tier is the maximum number of Bits you can cheer using this Cheermote. For example, 10000. + @export var min_bits: int: + set(val): + min_bits = val + track_data(&"min_bits", val) + + ## The tier level. Possible tiers are: + ## + ## * 1 + ## * 100 + ## * 500 + ## * 1000 + ## * 5000 + ## * 10000 + ## * 100000 + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## The hex code of the color associated with this tier level (for example, #979797). + @export var color: String: + set(val): + color = val + track_data(&"color", val) + + ## + @export var images: TwitchCheermoteImages: + set(val): + images = val + track_data(&"images", val) + + ## A Boolean value that determines whether users can cheer at this tier level. + @export var can_cheer: bool: + set(val): + can_cheer = val + track_data(&"can_cheer", val) + + ## A Boolean value that determines whether this tier level is shown in the Bits card. Is **true** if this tier level is shown in the Bits card. + @export var show_in_bits_card: bool: + set(val): + show_in_bits_card = val + track_data(&"show_in_bits_card", val) + + + + ## Constructor with all required fields. + static func create(_min_bits: int, _id: String, _color: String, _images: TwitchCheermoteImages, _can_cheer: bool, _show_in_bits_card: bool) -> Tiers: + var tiers: Tiers = Tiers.new() + tiers.min_bits = _min_bits + tiers.id = _id + tiers.color = _color + tiers.images = _images + tiers.can_cheer = _can_cheer + tiers.show_in_bits_card = _show_in_bits_card + return tiers + + + static func from_json(d: Dictionary) -> Tiers: + var result: Tiers = Tiers.new() + if d.get("min_bits", null) != null: + result.min_bits = d["min_bits"] + if d.get("id", null) != null: + result.id = d["id"] + if d.get("color", null) != null: + result.color = d["color"] + if d.get("images", null) != null: + result.images = TwitchCheermoteImages.from_json(d["images"]) + if d.get("can_cheer", null) != null: + result.can_cheer = d["can_cheer"] + if d.get("show_in_bits_card", null) != null: + result.show_in_bits_card = d["show_in_bits_card"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_cheermote.gd.uid b/addons/twitcher/generated/twitch_cheermote.gd.uid new file mode 100644 index 0000000..f8c6dfb --- /dev/null +++ b/addons/twitcher/generated/twitch_cheermote.gd.uid @@ -0,0 +1 @@ +uid://b85p7sst7537c diff --git a/addons/twitcher/generated/twitch_cheermote_image_format.gd b/addons/twitcher/generated/twitch_cheermote_image_format.gd new file mode 100644 index 0000000..dde2cd9 --- /dev/null +++ b/addons/twitcher/generated/twitch_cheermote_image_format.gd @@ -0,0 +1,60 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/CheermoteImageFormat +class_name TwitchCheermoteImageFormat + +## +@export var _1: String: + set(val): + _1 = val + track_data(&"_1", val) + +## +@export var _2: String: + set(val): + _2 = val + track_data(&"_2", val) + +## +@export var _3: String: + set(val): + _3 = val + track_data(&"_3", val) + +## +@export var _4: String: + set(val): + _4 = val + track_data(&"_4", val) + +## +@export var _1_5: String: + set(val): + _1_5 = val + track_data(&"_1_5", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create() -> TwitchCheermoteImageFormat: + var twitch_cheermote_image_format: TwitchCheermoteImageFormat = TwitchCheermoteImageFormat.new() + return twitch_cheermote_image_format + + +static func from_json(d: Dictionary) -> TwitchCheermoteImageFormat: + var result: TwitchCheermoteImageFormat = TwitchCheermoteImageFormat.new() + if d.get("_1", null) != null: + result._1 = d["_1"] + if d.get("_2", null) != null: + result._2 = d["_2"] + if d.get("_3", null) != null: + result._3 = d["_3"] + if d.get("_4", null) != null: + result._4 = d["_4"] + if d.get("_1_5", null) != null: + result._1_5 = d["_1_5"] + return result diff --git a/addons/twitcher/generated/twitch_cheermote_image_format.gd.uid b/addons/twitcher/generated/twitch_cheermote_image_format.gd.uid new file mode 100644 index 0000000..c0a2d2a --- /dev/null +++ b/addons/twitcher/generated/twitch_cheermote_image_format.gd.uid @@ -0,0 +1 @@ +uid://csud7awisckb0 diff --git a/addons/twitcher/generated/twitch_cheermote_image_theme.gd b/addons/twitcher/generated/twitch_cheermote_image_theme.gd new file mode 100644 index 0000000..6e451e3 --- /dev/null +++ b/addons/twitcher/generated/twitch_cheermote_image_theme.gd @@ -0,0 +1,36 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/CheermoteImageTheme +class_name TwitchCheermoteImageTheme + +## +@export var animated_format: TwitchCheermoteImageFormat: + set(val): + animated_format = val + track_data(&"animated_format", val) + +## +@export var static_format: TwitchCheermoteImageFormat: + set(val): + static_format = val + track_data(&"static_format", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create() -> TwitchCheermoteImageTheme: + var twitch_cheermote_image_theme: TwitchCheermoteImageTheme = TwitchCheermoteImageTheme.new() + return twitch_cheermote_image_theme + + +static func from_json(d: Dictionary) -> TwitchCheermoteImageTheme: + var result: TwitchCheermoteImageTheme = TwitchCheermoteImageTheme.new() + if d.get("animated_format", null) != null: + result.animated_format = TwitchCheermoteImageFormat.from_json(d["animated_format"]) + if d.get("static_format", null) != null: + result.static_format = TwitchCheermoteImageFormat.from_json(d["static_format"]) + return result diff --git a/addons/twitcher/generated/twitch_cheermote_image_theme.gd.uid b/addons/twitcher/generated/twitch_cheermote_image_theme.gd.uid new file mode 100644 index 0000000..8804aa9 --- /dev/null +++ b/addons/twitcher/generated/twitch_cheermote_image_theme.gd.uid @@ -0,0 +1 @@ +uid://c0ndet8biyyie diff --git a/addons/twitcher/generated/twitch_cheermote_images.gd b/addons/twitcher/generated/twitch_cheermote_images.gd new file mode 100644 index 0000000..f55a69d --- /dev/null +++ b/addons/twitcher/generated/twitch_cheermote_images.gd @@ -0,0 +1,36 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/CheermoteImages +class_name TwitchCheermoteImages + +## +@export var light: TwitchCheermoteImageTheme: + set(val): + light = val + track_data(&"light", val) + +## +@export var dark: TwitchCheermoteImageTheme: + set(val): + dark = val + track_data(&"dark", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create() -> TwitchCheermoteImages: + var twitch_cheermote_images: TwitchCheermoteImages = TwitchCheermoteImages.new() + return twitch_cheermote_images + + +static func from_json(d: Dictionary) -> TwitchCheermoteImages: + var result: TwitchCheermoteImages = TwitchCheermoteImages.new() + if d.get("light", null) != null: + result.light = TwitchCheermoteImageTheme.from_json(d["light"]) + if d.get("dark", null) != null: + result.dark = TwitchCheermoteImageTheme.from_json(d["dark"]) + return result diff --git a/addons/twitcher/generated/twitch_cheermote_images.gd.uid b/addons/twitcher/generated/twitch_cheermote_images.gd.uid new file mode 100644 index 0000000..560cd8c --- /dev/null +++ b/addons/twitcher/generated/twitch_cheermote_images.gd.uid @@ -0,0 +1 @@ +uid://cv2utje686064 diff --git a/addons/twitcher/generated/twitch_clip.gd b/addons/twitcher/generated/twitch_clip.gd new file mode 100644 index 0000000..0a86785 --- /dev/null +++ b/addons/twitcher/generated/twitch_clip.gd @@ -0,0 +1,175 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/Clip +class_name TwitchClip + +## An ID that uniquely identifies the clip. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## A URL to the clip. +@export var url: String: + set(val): + url = val + track_data(&"url", val) + +## A URL that you can use in an iframe to embed the clip (see [Embedding Video and Clips](https://dev.twitch.tv/docs/embed/video-and-clips/)). +@export var embed_url: String: + set(val): + embed_url = val + track_data(&"embed_url", val) + +## An ID that identifies the broadcaster that the video was clipped from. +@export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + +## The broadcaster’s display name. +@export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + +## An ID that identifies the user that created the clip. +@export var creator_id: String: + set(val): + creator_id = val + track_data(&"creator_id", val) + +## The user’s display name. +@export var creator_name: String: + set(val): + creator_name = val + track_data(&"creator_name", val) + +## An ID that identifies the video that the clip came from. This field contains an empty string if the video is not available. +@export var video_id: String: + set(val): + video_id = val + track_data(&"video_id", val) + +## The ID of the game that was being played when the clip was created. +@export var game_id: String: + set(val): + game_id = val + track_data(&"game_id", val) + +## The ISO 639-1 two-letter language code that the broadcaster broadcasts in. For example, _en_ for English. The value is _other_ if the broadcaster uses a language that Twitch doesn’t support. +@export var language: String: + set(val): + language = val + track_data(&"language", val) + +## The title of the clip. +@export var title: String: + set(val): + title = val + track_data(&"title", val) + +## The number of times the clip has been viewed. +@export var view_count: int: + set(val): + view_count = val + track_data(&"view_count", val) + +## The date and time of when the clip was created. The date and time is in RFC3339 format. +@export var created_at: String: + set(val): + created_at = val + track_data(&"created_at", val) + +## A URL to a thumbnail image of the clip. +@export var thumbnail_url: String: + set(val): + thumbnail_url = val + track_data(&"thumbnail_url", val) + +## The length of the clip, in seconds. Precision is 0.1. +@export var duration: float: + set(val): + duration = val + track_data(&"duration", val) + +## The zero-based offset, in seconds, to where the clip starts in the video (VOD). Is **null** if the video is not available or hasn’t been created yet from the live stream (see `video_id`). +## +## Note that there’s a delay between when a clip is created during a broadcast and when the offset is set. During the delay period, `vod_offset` is **null**. The delay is indeterminant but is typically minutes long. +@export var vod_offset: int: + set(val): + vod_offset = val + track_data(&"vod_offset", val) + +## A Boolean value that indicates if the clip is featured or not. +@export var is_featured: bool: + set(val): + is_featured = val + track_data(&"is_featured", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _url: String, _embed_url: String, _broadcaster_id: String, _broadcaster_name: String, _creator_id: String, _creator_name: String, _video_id: String, _game_id: String, _language: String, _title: String, _view_count: int, _created_at: String, _thumbnail_url: String, _duration: float, _vod_offset: int, _is_featured: bool) -> TwitchClip: + var twitch_clip: TwitchClip = TwitchClip.new() + twitch_clip.id = _id + twitch_clip.url = _url + twitch_clip.embed_url = _embed_url + twitch_clip.broadcaster_id = _broadcaster_id + twitch_clip.broadcaster_name = _broadcaster_name + twitch_clip.creator_id = _creator_id + twitch_clip.creator_name = _creator_name + twitch_clip.video_id = _video_id + twitch_clip.game_id = _game_id + twitch_clip.language = _language + twitch_clip.title = _title + twitch_clip.view_count = _view_count + twitch_clip.created_at = _created_at + twitch_clip.thumbnail_url = _thumbnail_url + twitch_clip.duration = _duration + twitch_clip.vod_offset = _vod_offset + twitch_clip.is_featured = _is_featured + return twitch_clip + + +static func from_json(d: Dictionary) -> TwitchClip: + var result: TwitchClip = TwitchClip.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("url", null) != null: + result.url = d["url"] + if d.get("embed_url", null) != null: + result.embed_url = d["embed_url"] + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + if d.get("creator_id", null) != null: + result.creator_id = d["creator_id"] + if d.get("creator_name", null) != null: + result.creator_name = d["creator_name"] + if d.get("video_id", null) != null: + result.video_id = d["video_id"] + if d.get("game_id", null) != null: + result.game_id = d["game_id"] + if d.get("language", null) != null: + result.language = d["language"] + if d.get("title", null) != null: + result.title = d["title"] + if d.get("view_count", null) != null: + result.view_count = d["view_count"] + if d.get("created_at", null) != null: + result.created_at = d["created_at"] + if d.get("thumbnail_url", null) != null: + result.thumbnail_url = d["thumbnail_url"] + if d.get("duration", null) != null: + result.duration = d["duration"] + if d.get("vod_offset", null) != null: + result.vod_offset = d["vod_offset"] + if d.get("is_featured", null) != null: + result.is_featured = d["is_featured"] + return result diff --git a/addons/twitcher/generated/twitch_clip.gd.uid b/addons/twitcher/generated/twitch_clip.gd.uid new file mode 100644 index 0000000..06bd4b4 --- /dev/null +++ b/addons/twitcher/generated/twitch_clip.gd.uid @@ -0,0 +1 @@ +uid://xnhce7fula3h diff --git a/addons/twitcher/generated/twitch_content_classification_label.gd b/addons/twitcher/generated/twitch_content_classification_label.gd new file mode 100644 index 0000000..8901744 --- /dev/null +++ b/addons/twitcher/generated/twitch_content_classification_label.gd @@ -0,0 +1,47 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/ContentClassificationLabel +class_name TwitchContentClassificationLabel + +## Unique identifier for the CCL. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## Localized description of the CCL. +@export var description: String: + set(val): + description = val + track_data(&"description", val) + +## Localized name of the CCL. +@export var name: String: + set(val): + name = val + track_data(&"name", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _description: String, _name: String) -> TwitchContentClassificationLabel: + var twitch_content_classification_label: TwitchContentClassificationLabel = TwitchContentClassificationLabel.new() + twitch_content_classification_label.id = _id + twitch_content_classification_label.description = _description + twitch_content_classification_label.name = _name + return twitch_content_classification_label + + +static func from_json(d: Dictionary) -> TwitchContentClassificationLabel: + var result: TwitchContentClassificationLabel = TwitchContentClassificationLabel.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("description", null) != null: + result.description = d["description"] + if d.get("name", null) != null: + result.name = d["name"] + return result diff --git a/addons/twitcher/generated/twitch_content_classification_label.gd.uid b/addons/twitcher/generated/twitch_content_classification_label.gd.uid new file mode 100644 index 0000000..aba4662 --- /dev/null +++ b/addons/twitcher/generated/twitch_content_classification_label.gd.uid @@ -0,0 +1 @@ +uid://bdpfg15y6hg6t diff --git a/addons/twitcher/generated/twitch_create_channel_stream_schedule_segment.gd b/addons/twitcher/generated/twitch_create_channel_stream_schedule_segment.gd new file mode 100644 index 0000000..ea5d250 --- /dev/null +++ b/addons/twitcher/generated/twitch_create_channel_stream_schedule_segment.gd @@ -0,0 +1,203 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchCreateChannelStreamScheduleSegment + + + +## +## #/components/schemas/CreateChannelStreamScheduleSegmentBody +class Body extends TwitchData: + + ## The date and time that the broadcast segment starts. Specify the date and time in RFC3339 format (for example, 2021-07-01T18:00:00Z). + @export var start_time: String: + set(val): + start_time = val + track_data(&"start_time", val) + + ## The time zone where the broadcast takes place. Specify the time zone using [IANA time zone database](https://www.iana.org/time-zones) format (for example, America/New\_York). + @export var timezone: String: + set(val): + timezone = val + track_data(&"timezone", val) + + ## The length of time, in minutes, that the broadcast is scheduled to run. The duration must be in the range 30 through 1380 (23 hours). + @export var duration: String: + set(val): + duration = val + track_data(&"duration", val) + + ## A Boolean value that determines whether the broadcast recurs weekly. Is **true** if the broadcast recurs weekly. Only partners and affiliates may add non-recurring broadcasts. + @export var is_recurring: bool: + set(val): + is_recurring = val + track_data(&"is_recurring", val) + + ## The ID of the category that best represents the broadcast’s content. To get the category ID, use the [Search Categories](https://dev.twitch.tv/docs/api/reference#search-categories) endpoint. + @export var category_id: String: + set(val): + category_id = val + track_data(&"category_id", val) + + ## The broadcast’s title. The title may contain a maximum of 140 characters. + @export var title: String: + set(val): + title = val + track_data(&"title", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_start_time: String, _timezone: String, _duration: String) -> Body: + var body: Body = Body.new() + body.start_time = _start_time + body.timezone = _timezone + body.duration = _duration + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("start_time", null) != null: + result.start_time = d["start_time"] + if d.get("timezone", null) != null: + result.timezone = d["timezone"] + if d.get("duration", null) != null: + result.duration = d["duration"] + if d.get("is_recurring", null) != null: + result.is_recurring = d["is_recurring"] + if d.get("category_id", null) != null: + result.category_id = d["category_id"] + if d.get("title", null) != null: + result.title = d["title"] + return result + + + +## +## #/components/schemas/CreateChannelStreamScheduleSegmentResponse +class Response extends TwitchData: + + ## The broadcaster’s streaming scheduled. + @export var data: ResponseData: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: ResponseData) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + result.data = ResponseData.from_json(d["data"]) + return result + + + +## The broadcaster’s streaming scheduled. +## #/components/schemas/CreateChannelStreamScheduleSegmentResponse/Data +class ResponseData extends TwitchData: + + ## A list that contains the single broadcast segment that you added. + @export var segments: Array[TwitchChannelStreamScheduleSegment]: + set(val): + segments = val + track_data(&"segments", val) + + ## The ID of the broadcaster that owns the broadcast schedule. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## The broadcaster’s display name. + @export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + + ## The broadcaster’s login name. + @export var broadcaster_login: String: + set(val): + broadcaster_login = val + track_data(&"broadcaster_login", val) + + ## The dates when the broadcaster is on vacation and not streaming. Is set to **null** if vacation mode is not enabled. + @export var vacation: ResponseVacation: + set(val): + vacation = val + track_data(&"vacation", val) + + + + ## Constructor with all required fields. + static func create(_segments: Array[TwitchChannelStreamScheduleSegment], _broadcaster_id: String, _broadcaster_name: String, _broadcaster_login: String, _vacation: ResponseVacation) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.segments = _segments + response_data.broadcaster_id = _broadcaster_id + response_data.broadcaster_name = _broadcaster_name + response_data.broadcaster_login = _broadcaster_login + response_data.vacation = _vacation + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("segments", null) != null: + for value in d["segments"]: + result.segments.append(TwitchChannelStreamScheduleSegment.from_json(value)) + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + if d.get("broadcaster_login", null) != null: + result.broadcaster_login = d["broadcaster_login"] + if d.get("vacation", null) != null: + result.vacation = ResponseVacation.from_json(d["vacation"]) + return result + + + +## The dates when the broadcaster is on vacation and not streaming. Is set to **null** if vacation mode is not enabled. +## #/components/schemas/CreateChannelStreamScheduleSegmentResponse/Data/Vacation +class ResponseVacation extends TwitchData: + + ## The UTC date and time (in RFC3339 format) of when the broadcaster’s vacation starts. + @export var start_time: String: + set(val): + start_time = val + track_data(&"start_time", val) + + ## The UTC date and time (in RFC3339 format) of when the broadcaster’s vacation ends. + @export var end_time: String: + set(val): + end_time = val + track_data(&"end_time", val) + + + + ## Constructor with all required fields. + static func create(_start_time: String, _end_time: String) -> ResponseVacation: + var response_vacation: ResponseVacation = ResponseVacation.new() + response_vacation.start_time = _start_time + response_vacation.end_time = _end_time + return response_vacation + + + static func from_json(d: Dictionary) -> ResponseVacation: + var result: ResponseVacation = ResponseVacation.new() + if d.get("start_time", null) != null: + result.start_time = d["start_time"] + if d.get("end_time", null) != null: + result.end_time = d["end_time"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_create_channel_stream_schedule_segment.gd.uid b/addons/twitcher/generated/twitch_create_channel_stream_schedule_segment.gd.uid new file mode 100644 index 0000000..c089ac1 --- /dev/null +++ b/addons/twitcher/generated/twitch_create_channel_stream_schedule_segment.gd.uid @@ -0,0 +1 @@ +uid://dirdmoagnwksy diff --git a/addons/twitcher/generated/twitch_create_clip.gd b/addons/twitcher/generated/twitch_create_clip.gd new file mode 100644 index 0000000..6228599 --- /dev/null +++ b/addons/twitcher/generated/twitch_create_clip.gd @@ -0,0 +1,99 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchCreateClip + + + +## +## #/components/schemas/CreateClipResponse +class Response extends TwitchData: + + ## + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + return result + + + +## +## #/components/schemas/CreateClipResponse/Data +class ResponseData extends TwitchData: + + ## A URL that you can use to edit the clip’s title, identify the part of the clip to publish, and publish the clip. [Learn More](https://help.twitch.tv/s/article/how-to-use-clips) + ## + ## The URL is valid for up to 24 hours or until the clip is published, whichever comes first. + @export var edit_url: String: + set(val): + edit_url = val + track_data(&"edit_url", val) + + ## An ID that uniquely identifies the clip. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + + + ## Constructor with all required fields. + static func create(_edit_url: String, _id: String) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.edit_url = _edit_url + response_data.id = _id + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("edit_url", null) != null: + result.edit_url = d["edit_url"] + if d.get("id", null) != null: + result.id = d["id"] + return result + + + +## All optional parameters for TwitchAPI.create_clip +## #/components/schemas/CreateClipOpt +class Opt extends TwitchData: + + ## A Boolean value that determines whether the API captures the clip at the moment the viewer requests it or after a delay. If **false** (default), Twitch captures the clip at the moment the viewer requests it (this is the same clip experience as the Twitch UX). If **true**, Twitch adds a delay before capturing the clip (this basically shifts the capture window to the right slightly). + @export var has_delay: bool: + set(val): + has_delay = val + track_data(&"has_delay", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("has_delay", null) != null: + result.has_delay = d["has_delay"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_create_clip.gd.uid b/addons/twitcher/generated/twitch_create_clip.gd.uid new file mode 100644 index 0000000..e0857c6 --- /dev/null +++ b/addons/twitcher/generated/twitch_create_clip.gd.uid @@ -0,0 +1 @@ +uid://dl4qg2h6hfagg diff --git a/addons/twitcher/generated/twitch_create_conduits.gd b/addons/twitcher/generated/twitch_create_conduits.gd new file mode 100644 index 0000000..efc8739 --- /dev/null +++ b/addons/twitcher/generated/twitch_create_conduits.gd @@ -0,0 +1,98 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchCreateConduits + + + +## +## #/components/schemas/CreateConduitsBody +class Body extends TwitchData: + + ## The number of shards to create for this conduit. + @export var shard_count: int: + set(val): + shard_count = val + track_data(&"shard_count", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_shard_count: int) -> Body: + var body: Body = Body.new() + body.shard_count = _shard_count + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("shard_count", null) != null: + result.shard_count = d["shard_count"] + return result + + + +## +## #/components/schemas/CreateConduitsResponse +class Response extends TwitchData: + + ## List of information about the client’s conduits. + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + return result + + + +## List of information about the client’s conduits. +## #/components/schemas/CreateConduitsResponse/Data +class ResponseData extends TwitchData: + + ## Conduit ID. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## Number of shards created for this conduit. + @export var shard_count: int: + set(val): + shard_count = val + track_data(&"shard_count", val) + + + + ## Constructor with all required fields. + static func create(_id: String, _shard_count: int) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.id = _id + response_data.shard_count = _shard_count + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("shard_count", null) != null: + result.shard_count = d["shard_count"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_create_conduits.gd.uid b/addons/twitcher/generated/twitch_create_conduits.gd.uid new file mode 100644 index 0000000..40c2554 --- /dev/null +++ b/addons/twitcher/generated/twitch_create_conduits.gd.uid @@ -0,0 +1 @@ +uid://bons7t6r3bd0i diff --git a/addons/twitcher/generated/twitch_create_custom_rewards.gd b/addons/twitcher/generated/twitch_create_custom_rewards.gd new file mode 100644 index 0000000..73529f3 --- /dev/null +++ b/addons/twitcher/generated/twitch_create_custom_rewards.gd @@ -0,0 +1,159 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchCreateCustomRewards + + + +## +## #/components/schemas/CreateCustomRewardsBody +class Body extends TwitchData: + + ## The custom reward’s title. The title may contain a maximum of 45 characters and it must be unique amongst all of the broadcaster’s custom rewards. + @export var title: String: + set(val): + title = val + track_data(&"title", val) + + ## The cost of the reward, in Channel Points. The minimum is 1 point. + @export var cost: int: + set(val): + cost = val + track_data(&"cost", val) + + ## The prompt shown to the viewer when they redeem the reward. Specify a prompt if `is_user_input_required` is **true**. The prompt is limited to a maximum of 200 characters. + @export var prompt: String: + set(val): + prompt = val + track_data(&"prompt", val) + + ## A Boolean value that determines whether the reward is enabled. Viewers see only enabled rewards. The default is **true**. + @export var is_enabled: bool: + set(val): + is_enabled = val + track_data(&"is_enabled", val) + + ## The background color to use for the reward. Specify the color using Hex format (for example, #9147FF). + @export var background_color: String: + set(val): + background_color = val + track_data(&"background_color", val) + + ## A Boolean value that determines whether the user needs to enter information when redeeming the reward. See the `prompt` field. The default is **false**. + @export var is_user_input_required: bool: + set(val): + is_user_input_required = val + track_data(&"is_user_input_required", val) + + ## A Boolean value that determines whether to limit the maximum number of redemptions allowed per live stream (see the `max_per_stream` field). The default is **false**. + @export var is_max_per_stream_enabled: bool: + set(val): + is_max_per_stream_enabled = val + track_data(&"is_max_per_stream_enabled", val) + + ## The maximum number of redemptions allowed per live stream. Applied only if `is_max_per_stream_enabled` is **true**. The minimum value is 1. + @export var max_per_stream: int: + set(val): + max_per_stream = val + track_data(&"max_per_stream", val) + + ## A Boolean value that determines whether to limit the maximum number of redemptions allowed per user per stream (see the `max_per_user_per_stream` field). The default is **false**. + @export var is_max_per_user_per_stream_enabled: bool: + set(val): + is_max_per_user_per_stream_enabled = val + track_data(&"is_max_per_user_per_stream_enabled", val) + + ## The maximum number of redemptions allowed per user per stream. Applied only if `is_max_per_user_per_stream_enabled` is **true**. The minimum value is 1. + @export var max_per_user_per_stream: int: + set(val): + max_per_user_per_stream = val + track_data(&"max_per_user_per_stream", val) + + ## A Boolean value that determines whether to apply a cooldown period between redemptions (see the `global_cooldown_seconds` field for the duration of the cooldown period). The default is **false**. + @export var is_global_cooldown_enabled: bool: + set(val): + is_global_cooldown_enabled = val + track_data(&"is_global_cooldown_enabled", val) + + ## The cooldown period, in seconds. Applied only if the `is_global_cooldown_enabled` field is **true**. The minimum value is 1; however, the minimum value is 60 for it to be shown in the Twitch UX. + @export var global_cooldown_seconds: int: + set(val): + global_cooldown_seconds = val + track_data(&"global_cooldown_seconds", val) + + ## A Boolean value that determines whether redemptions should be set to FULFILLED status immediately when a reward is redeemed. If **false**, status is set to UNFULFILLED and follows the normal request queue process. The default is **false**. + @export var should_redemptions_skip_request_queue: bool: + set(val): + should_redemptions_skip_request_queue = val + track_data(&"should_redemptions_skip_request_queue", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_title: String, _cost: int) -> Body: + var body: Body = Body.new() + body.title = _title + body.cost = _cost + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("title", null) != null: + result.title = d["title"] + if d.get("cost", null) != null: + result.cost = d["cost"] + if d.get("prompt", null) != null: + result.prompt = d["prompt"] + if d.get("is_enabled", null) != null: + result.is_enabled = d["is_enabled"] + if d.get("background_color", null) != null: + result.background_color = d["background_color"] + if d.get("is_user_input_required", null) != null: + result.is_user_input_required = d["is_user_input_required"] + if d.get("is_max_per_stream_enabled", null) != null: + result.is_max_per_stream_enabled = d["is_max_per_stream_enabled"] + if d.get("max_per_stream", null) != null: + result.max_per_stream = d["max_per_stream"] + if d.get("is_max_per_user_per_stream_enabled", null) != null: + result.is_max_per_user_per_stream_enabled = d["is_max_per_user_per_stream_enabled"] + if d.get("max_per_user_per_stream", null) != null: + result.max_per_user_per_stream = d["max_per_user_per_stream"] + if d.get("is_global_cooldown_enabled", null) != null: + result.is_global_cooldown_enabled = d["is_global_cooldown_enabled"] + if d.get("global_cooldown_seconds", null) != null: + result.global_cooldown_seconds = d["global_cooldown_seconds"] + if d.get("should_redemptions_skip_request_queue", null) != null: + result.should_redemptions_skip_request_queue = d["should_redemptions_skip_request_queue"] + return result + + + +## +## #/components/schemas/CreateCustomRewardsResponse +class Response extends TwitchData: + + ## A list that contains the single custom reward you created. + @export var data: Array[TwitchCustomReward]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchCustomReward]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchCustomReward.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_create_custom_rewards.gd.uid b/addons/twitcher/generated/twitch_create_custom_rewards.gd.uid new file mode 100644 index 0000000..9263e0e --- /dev/null +++ b/addons/twitcher/generated/twitch_create_custom_rewards.gd.uid @@ -0,0 +1 @@ +uid://cv6f7hpvjsm24 diff --git a/addons/twitcher/generated/twitch_create_event_sub_subscription.gd b/addons/twitcher/generated/twitch_create_event_sub_subscription.gd new file mode 100644 index 0000000..1f908d6 --- /dev/null +++ b/addons/twitcher/generated/twitch_create_event_sub_subscription.gd @@ -0,0 +1,181 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchCreateEventSubSubscription + + + +## +## #/components/schemas/CreateEventSubSubscriptionBody +class Body extends TwitchData: + + ## The type of subscription to create. For a list of subscriptions that you can create, see [Subscription Types](https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types#subscription-types). Set this field to the value in the **Name** column of the Subscription Types table. + @export var type: String: + set(val): + type = val + track_data(&"type", val) + + ## The version number that identifies the definition of the subscription type that you want the response to use. + @export var version: String: + set(val): + version = val + track_data(&"version", val) + + ## A JSON object that contains the parameter values that are specific to the specified subscription type. For the object’s required and optional fields, see the subscription type’s documentation. + @export var condition: Dictionary: + set(val): + condition = val + track_data(&"condition", val) + + ## The transport details that you want Twitch to use when sending you notifications. + @export var transport: BodyTransport: + set(val): + transport = val + track_data(&"transport", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_type: String, _version: String, _condition: Dictionary, _transport: BodyTransport) -> Body: + var body: Body = Body.new() + body.type = _type + body.version = _version + body.condition = _condition + body.transport = _transport + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("type", null) != null: + result.type = d["type"] + if d.get("version", null) != null: + result.version = d["version"] + if d.get("condition", null) != null: + result.condition = d["condition"] + if d.get("transport", null) != null: + result.transport = BodyTransport.from_json(d["transport"]) + return result + + + +## The transport details that you want Twitch to use when sending you notifications. +## #/components/schemas/CreateEventSubSubscriptionBody/Transport +class BodyTransport extends TwitchData: + + ## The transport method. Possible values are: + ## + ## * webhook + ## * websocket + ## * conduit + @export var method: String: + set(val): + method = val + track_data(&"method", val) + + ## The callback URL where the notifications are sent. The URL must use the HTTPS protocol and port 443\. See [Processing an event](https://dev.twitch.tv/docs/eventsub/handling-webhook-events#processing-an-event). Specify this field only if `method` is set to **webhook**. + ## + ## **NOTE**: Redirects are not followed. + @export var callback: String: + set(val): + callback = val + track_data(&"callback", val) + + ## The secret used to verify the signature. The secret must be an ASCII string that’s a minimum of 10 characters long and a maximum of 100 characters long. For information about how the secret is used, see [Verifying the event message](https://dev.twitch.tv/docs/eventsub/handling-webhook-events#verifying-the-event-message). Specify this field only if `method` is set to **webhook**. + @export var secret: String: + set(val): + secret = val + track_data(&"secret", val) + + ## An ID that identifies the WebSocket to send notifications to. When you connect to EventSub using WebSockets, the server returns the ID in the Welcome message. Specify this field only if `method` is set to **websocket**. + @export var session_id: String: + set(val): + session_id = val + track_data(&"session_id", val) + + ## An ID that identifies the conduit to send notifications to. When you create a conduit, the server returns the conduit ID. Specify this field only if `method` is set to **conduit**. + @export var conduit_id: String: + set(val): + conduit_id = val + track_data(&"conduit_id", val) + + + + ## Constructor with all required fields. + static func create(_method: String) -> BodyTransport: + var body_transport: BodyTransport = BodyTransport.new() + body_transport.method = _method + return body_transport + + + static func from_json(d: Dictionary) -> BodyTransport: + var result: BodyTransport = BodyTransport.new() + if d.get("method", null) != null: + result.method = d["method"] + if d.get("callback", null) != null: + result.callback = d["callback"] + if d.get("secret", null) != null: + result.secret = d["secret"] + if d.get("session_id", null) != null: + result.session_id = d["session_id"] + if d.get("conduit_id", null) != null: + result.conduit_id = d["conduit_id"] + return result + + + +## +## #/components/schemas/CreateEventSubSubscriptionResponse +class Response extends TwitchData: + + ## A list that contains the single subscription that you created. + @export var data: Array[TwitchEventSubSubscription]: + set(val): + data = val + track_data(&"data", val) + + ## The total number of subscriptions you’ve created. + @export var total: int: + set(val): + total = val + track_data(&"total", val) + + ## The sum of all of your subscription costs. [Learn More](https://dev.twitch.tv/docs/eventsub/manage-subscriptions/#subscription-limits) + @export var total_cost: int: + set(val): + total_cost = val + track_data(&"total_cost", val) + + ## The maximum total cost that you’re allowed to incur for all subscriptions you create. + @export var max_total_cost: int: + set(val): + max_total_cost = val + track_data(&"max_total_cost", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchEventSubSubscription], _total: int, _total_cost: int, _max_total_cost: int) -> Response: + var response: Response = Response.new() + response.data = _data + response.total = _total + response.total_cost = _total_cost + response.max_total_cost = _max_total_cost + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchEventSubSubscription.from_json(value)) + if d.get("total", null) != null: + result.total = d["total"] + if d.get("total_cost", null) != null: + result.total_cost = d["total_cost"] + if d.get("max_total_cost", null) != null: + result.max_total_cost = d["max_total_cost"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_create_event_sub_subscription.gd.uid b/addons/twitcher/generated/twitch_create_event_sub_subscription.gd.uid new file mode 100644 index 0000000..5a5162c --- /dev/null +++ b/addons/twitcher/generated/twitch_create_event_sub_subscription.gd.uid @@ -0,0 +1 @@ +uid://o5jsuop8s3fq diff --git a/addons/twitcher/generated/twitch_create_extension_secret.gd b/addons/twitcher/generated/twitch_create_extension_secret.gd new file mode 100644 index 0000000..ab8e4a9 --- /dev/null +++ b/addons/twitcher/generated/twitch_create_extension_secret.gd @@ -0,0 +1,61 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchCreateExtensionSecret + + + +## +## #/components/schemas/CreateExtensionSecretResponse +class Response extends TwitchData: + + ## A list that contains the newly added secrets. + @export var data: Array[TwitchExtensionSecret]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchExtensionSecret]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchExtensionSecret.from_json(value)) + return result + + + +## All optional parameters for TwitchAPI.create_extension_secret +## #/components/schemas/CreateExtensionSecretOpt +class Opt extends TwitchData: + + ## The amount of time, in seconds, to delay activating the secret. The delay should provide enough time for instances of the extension to gracefully switch over to the new secret. The minimum delay is 300 seconds (5 minutes). The default is 300 seconds. + @export var delay: int: + set(val): + delay = val + track_data(&"delay", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("delay", null) != null: + result.delay = d["delay"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_create_extension_secret.gd.uid b/addons/twitcher/generated/twitch_create_extension_secret.gd.uid new file mode 100644 index 0000000..ed807fb --- /dev/null +++ b/addons/twitcher/generated/twitch_create_extension_secret.gd.uid @@ -0,0 +1 @@ +uid://cve0b0q7ilalj diff --git a/addons/twitcher/generated/twitch_create_guest_star_session.gd b/addons/twitcher/generated/twitch_create_guest_star_session.gd new file mode 100644 index 0000000..f747ea9 --- /dev/null +++ b/addons/twitcher/generated/twitch_create_guest_star_session.gd @@ -0,0 +1,35 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchCreateGuestStarSession + + + +## +## #/components/schemas/CreateGuestStarSessionResponse +class Response extends TwitchData: + + ## Summary of the session details. + @export var data: Array[TwitchGuestStarSession]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchGuestStarSession]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchGuestStarSession.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_create_guest_star_session.gd.uid b/addons/twitcher/generated/twitch_create_guest_star_session.gd.uid new file mode 100644 index 0000000..78bdacf --- /dev/null +++ b/addons/twitcher/generated/twitch_create_guest_star_session.gd.uid @@ -0,0 +1 @@ +uid://xisxuptqxomh diff --git a/addons/twitcher/generated/twitch_create_poll.gd b/addons/twitcher/generated/twitch_create_poll.gd new file mode 100644 index 0000000..eea9e71 --- /dev/null +++ b/addons/twitcher/generated/twitch_create_poll.gd @@ -0,0 +1,133 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchCreatePoll + + + +## +## #/components/schemas/CreatePollBody +class Body extends TwitchData: + + ## The ID of the broadcaster that’s running the poll. This ID must match the user ID in the user access token. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## The question that viewers will vote on. For example, _What game should I play next?_ The question may contain a maximum of 60 characters. + @export var title: String: + set(val): + title = val + track_data(&"title", val) + + ## A list of choices that viewers may choose from. The list must contain a minimum of 2 choices and up to a maximum of 5 choices. + @export var choices: Array[BodyChoices]: + set(val): + choices = val + track_data(&"choices", val) + + ## The length of time (in seconds) that the poll will run for. The minimum is 15 seconds and the maximum is 1800 seconds (30 minutes). + @export var duration: int: + set(val): + duration = val + track_data(&"duration", val) + + ## A Boolean value that indicates whether viewers may cast additional votes using Channel Points. If **true**, the viewer may cast more than one vote but each additional vote costs the number of Channel Points specified in `channel_points_per_vote`. The default is **false** (viewers may cast only one vote). For information about Channel Points, see [Channel Points Guide](https://help.twitch.tv/s/article/channel-points-guide). + @export var channel_points_voting_enabled: bool: + set(val): + channel_points_voting_enabled = val + track_data(&"channel_points_voting_enabled", val) + + ## The number of points that the viewer must spend to cast one additional vote. The minimum is 1 and the maximum is 1000000\. Set only if `ChannelPointsVotingEnabled` is **true**. + @export var channel_points_per_vote: int: + set(val): + channel_points_per_vote = val + track_data(&"channel_points_per_vote", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_broadcaster_id: String, _title: String, _choices: Array[BodyChoices], _duration: int) -> Body: + var body: Body = Body.new() + body.broadcaster_id = _broadcaster_id + body.title = _title + body.choices = _choices + body.duration = _duration + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("title", null) != null: + result.title = d["title"] + if d.get("choices", null) != null: + for value in d["choices"]: + result.choices.append(BodyChoices.from_json(value)) + if d.get("duration", null) != null: + result.duration = d["duration"] + if d.get("channel_points_voting_enabled", null) != null: + result.channel_points_voting_enabled = d["channel_points_voting_enabled"] + if d.get("channel_points_per_vote", null) != null: + result.channel_points_per_vote = d["channel_points_per_vote"] + return result + + + +## A list of choices that viewers may choose from. The list must contain a minimum of 2 choices and up to a maximum of 5 choices. +## #/components/schemas/CreatePollBody/Choices +class BodyChoices extends TwitchData: + + ## One of the choices the viewer may select. The choice may contain a maximum of 25 characters. + @export var title: String: + set(val): + title = val + track_data(&"title", val) + + + + ## Constructor with all required fields. + static func create(_title: String) -> BodyChoices: + var body_choices: BodyChoices = BodyChoices.new() + body_choices.title = _title + return body_choices + + + static func from_json(d: Dictionary) -> BodyChoices: + var result: BodyChoices = BodyChoices.new() + if d.get("title", null) != null: + result.title = d["title"] + return result + + + +## +## #/components/schemas/CreatePollResponse +class Response extends TwitchData: + + ## A list that contains the single poll that you created. + @export var data: Array[TwitchPoll]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchPoll]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchPoll.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_create_poll.gd.uid b/addons/twitcher/generated/twitch_create_poll.gd.uid new file mode 100644 index 0000000..7d206cc --- /dev/null +++ b/addons/twitcher/generated/twitch_create_poll.gd.uid @@ -0,0 +1 @@ +uid://cshwdnu6h67gu diff --git a/addons/twitcher/generated/twitch_create_prediction.gd b/addons/twitcher/generated/twitch_create_prediction.gd new file mode 100644 index 0000000..f4ff195 --- /dev/null +++ b/addons/twitcher/generated/twitch_create_prediction.gd @@ -0,0 +1,117 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchCreatePrediction + + + +## +## #/components/schemas/CreatePredictionBody +class Body extends TwitchData: + + ## The ID of the broadcaster that’s running the prediction. This ID must match the user ID in the user access token. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## The question that the broadcaster is asking. For example, _Will I finish this entire pizza?_ The title is limited to a maximum of 45 characters. + @export var title: String: + set(val): + title = val + track_data(&"title", val) + + ## The list of possible outcomes that the viewers may choose from. The list must contain a minimum of 2 choices and up to a maximum of 10 choices. + @export var outcomes: Array[BodyOutcomes]: + set(val): + outcomes = val + track_data(&"outcomes", val) + + ## The length of time (in seconds) that the prediction will run for. The minimum is 30 seconds and the maximum is 1800 seconds (30 minutes). + @export var prediction_window: int: + set(val): + prediction_window = val + track_data(&"prediction_window", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_broadcaster_id: String, _title: String, _outcomes: Array[BodyOutcomes], _prediction_window: int) -> Body: + var body: Body = Body.new() + body.broadcaster_id = _broadcaster_id + body.title = _title + body.outcomes = _outcomes + body.prediction_window = _prediction_window + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("title", null) != null: + result.title = d["title"] + if d.get("outcomes", null) != null: + for value in d["outcomes"]: + result.outcomes.append(BodyOutcomes.from_json(value)) + if d.get("prediction_window", null) != null: + result.prediction_window = d["prediction_window"] + return result + + + +## The list of possible outcomes that the viewers may choose from. The list must contain a minimum of 2 choices and up to a maximum of 10 choices. +## #/components/schemas/CreatePredictionBody/Outcomes +class BodyOutcomes extends TwitchData: + + ## The text of one of the outcomes that the viewer may select. The title is limited to a maximum of 25 characters. + @export var title: String: + set(val): + title = val + track_data(&"title", val) + + + + ## Constructor with all required fields. + static func create(_title: String) -> BodyOutcomes: + var body_outcomes: BodyOutcomes = BodyOutcomes.new() + body_outcomes.title = _title + return body_outcomes + + + static func from_json(d: Dictionary) -> BodyOutcomes: + var result: BodyOutcomes = BodyOutcomes.new() + if d.get("title", null) != null: + result.title = d["title"] + return result + + + +## +## #/components/schemas/CreatePredictionResponse +class Response extends TwitchData: + + ## A list that contains the single prediction that you created. + @export var data: Array[TwitchPrediction]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchPrediction]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchPrediction.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_create_prediction.gd.uid b/addons/twitcher/generated/twitch_create_prediction.gd.uid new file mode 100644 index 0000000..440bc00 --- /dev/null +++ b/addons/twitcher/generated/twitch_create_prediction.gd.uid @@ -0,0 +1 @@ +uid://oas7j3xjgwex diff --git a/addons/twitcher/generated/twitch_create_stream_marker.gd b/addons/twitcher/generated/twitch_create_stream_marker.gd new file mode 100644 index 0000000..5265dec --- /dev/null +++ b/addons/twitcher/generated/twitch_create_stream_marker.gd @@ -0,0 +1,70 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchCreateStreamMarker + + + +## +## #/components/schemas/CreateStreamMarkerBody +class Body extends TwitchData: + + ## The ID of the broadcaster that’s streaming content. This ID must match the user ID in the access token or the user in the access token must be one of the broadcaster’s editors. + @export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + + ## A short description of the marker to help the user remember why they marked the location. The maximum length of the description is 140 characters. + @export var description: String: + set(val): + description = val + track_data(&"description", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_user_id: String) -> Body: + var body: Body = Body.new() + body.user_id = _user_id + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("description", null) != null: + result.description = d["description"] + return result + + + +## +## #/components/schemas/CreateStreamMarkerResponse +class Response extends TwitchData: + + ## A list that contains the single marker that you added. + @export var data: Array[TwitchStreamMarkerCreated]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchStreamMarkerCreated]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchStreamMarkerCreated.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_create_stream_marker.gd.uid b/addons/twitcher/generated/twitch_create_stream_marker.gd.uid new file mode 100644 index 0000000..d78c9df --- /dev/null +++ b/addons/twitcher/generated/twitch_create_stream_marker.gd.uid @@ -0,0 +1 @@ +uid://6xerpyoforp2 diff --git a/addons/twitcher/generated/twitch_creator_goal.gd b/addons/twitcher/generated/twitch_creator_goal.gd new file mode 100644 index 0000000..2fe169b --- /dev/null +++ b/addons/twitcher/generated/twitch_creator_goal.gd @@ -0,0 +1,115 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/CreatorGoal +class_name TwitchCreatorGoal + +## An ID that identifies this goal. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## An ID that identifies the broadcaster that created the goal. +@export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + +## The broadcaster’s display name. +@export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + +## The broadcaster’s login name. +@export var broadcaster_login: String: + set(val): + broadcaster_login = val + track_data(&"broadcaster_login", val) + +## The type of goal. Possible values are: +## +## * follower — The goal is to increase followers. +## * subscription — The goal is to increase subscriptions. This type shows the net increase or decrease in tier points associated with the subscriptions. +## * subscription\_count — The goal is to increase subscriptions. This type shows the net increase or decrease in the number of subscriptions. +## * new\_subscription — The goal is to increase subscriptions. This type shows only the net increase in tier points associated with the subscriptions (it does not account for users that unsubscribed since the goal started). +## * new\_subscription\_count — The goal is to increase subscriptions. This type shows only the net increase in the number of subscriptions (it does not account for users that unsubscribed since the goal started). +@export var type: String: + set(val): + type = val + track_data(&"type", val) + +## A description of the goal. Is an empty string if not specified. +@export var description: String: + set(val): + description = val + track_data(&"description", val) + +## The goal’s current value. +## +## The goal’s `type` determines how this value is increased or decreased. +## +## * If `type` is follower, this field is set to the broadcaster's current number of followers. This number increases with new followers and decreases when users unfollow the broadcaster. +## * If `type` is subscription, this field is increased and decreased by the points value associated with the subscription tier. For example, if a tier-two subscription is worth 2 points, this field is increased or decreased by 2, not 1. +## * If `type` is subscription\_count, this field is increased by 1 for each new subscription and decreased by 1 for each user that unsubscribes. +## * If `type` is new\_subscription, this field is increased by the points value associated with the subscription tier. For example, if a tier-two subscription is worth 2 points, this field is increased by 2, not 1. +## * If `type` is new\_subscription\_count, this field is increased by 1 for each new subscription. +@export var current_amount: int: + set(val): + current_amount = val + track_data(&"current_amount", val) + +## The goal’s target value. For example, if the broadcaster has 200 followers before creating the goal, and their goal is to double that number, this field is set to 400. +@export var target_amount: int: + set(val): + target_amount = val + track_data(&"target_amount", val) + +## The UTC date and time (in RFC3339 format) that the broadcaster created the goal. +@export var created_at: String: + set(val): + created_at = val + track_data(&"created_at", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _broadcaster_id: String, _broadcaster_name: String, _broadcaster_login: String, _type: String, _description: String, _current_amount: int, _target_amount: int, _created_at: String) -> TwitchCreatorGoal: + var twitch_creator_goal: TwitchCreatorGoal = TwitchCreatorGoal.new() + twitch_creator_goal.id = _id + twitch_creator_goal.broadcaster_id = _broadcaster_id + twitch_creator_goal.broadcaster_name = _broadcaster_name + twitch_creator_goal.broadcaster_login = _broadcaster_login + twitch_creator_goal.type = _type + twitch_creator_goal.description = _description + twitch_creator_goal.current_amount = _current_amount + twitch_creator_goal.target_amount = _target_amount + twitch_creator_goal.created_at = _created_at + return twitch_creator_goal + + +static func from_json(d: Dictionary) -> TwitchCreatorGoal: + var result: TwitchCreatorGoal = TwitchCreatorGoal.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + if d.get("broadcaster_login", null) != null: + result.broadcaster_login = d["broadcaster_login"] + if d.get("type", null) != null: + result.type = d["type"] + if d.get("description", null) != null: + result.description = d["description"] + if d.get("current_amount", null) != null: + result.current_amount = d["current_amount"] + if d.get("target_amount", null) != null: + result.target_amount = d["target_amount"] + if d.get("created_at", null) != null: + result.created_at = d["created_at"] + return result diff --git a/addons/twitcher/generated/twitch_creator_goal.gd.uid b/addons/twitcher/generated/twitch_creator_goal.gd.uid new file mode 100644 index 0000000..2dc03bf --- /dev/null +++ b/addons/twitcher/generated/twitch_creator_goal.gd.uid @@ -0,0 +1 @@ +uid://d6ek35kfjk3e diff --git a/addons/twitcher/generated/twitch_custom_reward.gd b/addons/twitcher/generated/twitch_custom_reward.gd new file mode 100644 index 0000000..8792f40 --- /dev/null +++ b/addons/twitcher/generated/twitch_custom_reward.gd @@ -0,0 +1,399 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/CustomReward +class_name TwitchCustomReward + +## The ID that uniquely identifies the broadcaster. +@export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + +## The broadcaster’s login name. +@export var broadcaster_login: String: + set(val): + broadcaster_login = val + track_data(&"broadcaster_login", val) + +## The broadcaster’s display name. +@export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + +## The ID that uniquely identifies this custom reward. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The title of the reward. +@export var title: String: + set(val): + title = val + track_data(&"title", val) + +## The prompt shown to the viewer when they redeem the reward if user input is required. See the `is_user_input_required` field. +@export var prompt: String: + set(val): + prompt = val + track_data(&"prompt", val) + +## The cost of the reward in Channel Points. +@export var cost: int: + set(val): + cost = val + track_data(&"cost", val) + +## A set of custom images for the reward. This field is **null** if the broadcaster didn’t upload images. +@export var image: TwitchImage: + set(val): + image = val + track_data(&"image", val) + +## A set of default images for the reward. +@export var default_image: DefaultImage: + set(val): + default_image = val + track_data(&"default_image", val) + +## The background color to use for the reward. The color is in Hex format (for example, #00E5CB). +@export var background_color: String: + set(val): + background_color = val + track_data(&"background_color", val) + +## A Boolean value that determines whether the reward is enabled. Is **true** if enabled; otherwise, **false**. Disabled rewards aren’t shown to the user. +@export var is_enabled: bool: + set(val): + is_enabled = val + track_data(&"is_enabled", val) + +## A Boolean value that determines whether the user must enter information when they redeem the reward. Is **true** if the user is prompted. +@export var is_user_input_required: bool: + set(val): + is_user_input_required = val + track_data(&"is_user_input_required", val) + +## The settings used to determine whether to apply a maximum to the number of redemptions allowed per live stream. +@export var max_per_stream_setting: MaxPerStreamSetting: + set(val): + max_per_stream_setting = val + track_data(&"max_per_stream_setting", val) + +## The settings used to determine whether to apply a maximum to the number of redemptions allowed per user per live stream. +@export var max_per_user_per_stream_setting: MaxPerUserPerStreamSetting: + set(val): + max_per_user_per_stream_setting = val + track_data(&"max_per_user_per_stream_setting", val) + +## The settings used to determine whether to apply a cooldown period between redemptions and the length of the cooldown. +@export var global_cooldown_setting: GlobalCooldownSetting: + set(val): + global_cooldown_setting = val + track_data(&"global_cooldown_setting", val) + +## A Boolean value that determines whether the reward is currently paused. Is **true** if the reward is paused. Viewers can’t redeem paused rewards. +@export var is_paused: bool: + set(val): + is_paused = val + track_data(&"is_paused", val) + +## A Boolean value that determines whether the reward is currently in stock. Is **true** if the reward is in stock. Viewers can’t redeem out of stock rewards. +@export var is_in_stock: bool: + set(val): + is_in_stock = val + track_data(&"is_in_stock", val) + +## A Boolean value that determines whether redemptions should be set to FULFILLED status immediately when a reward is redeemed. If **false**, status is set to UNFULFILLED and follows the normal request queue process. +@export var should_redemptions_skip_request_queue: bool: + set(val): + should_redemptions_skip_request_queue = val + track_data(&"should_redemptions_skip_request_queue", val) + +## The number of redemptions redeemed during the current live stream. The number counts against the `max_per_stream_setting` limit. This field is **null** if the broadcaster’s stream isn’t live or _max\_per\_stream\_setting_ isn’t enabled. +@export var redemptions_redeemed_current_stream: int: + set(val): + redemptions_redeemed_current_stream = val + track_data(&"redemptions_redeemed_current_stream", val) + +## The timestamp of when the cooldown period expires. Is **null** if the reward isn’t in a cooldown state. See the `global_cooldown_setting` field. +@export var cooldown_expires_at: String: + set(val): + cooldown_expires_at = val + track_data(&"cooldown_expires_at", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_broadcaster_id: String, _broadcaster_login: String, _broadcaster_name: String, _id: String, _title: String, _prompt: String, _cost: int, _image: TwitchImage, _default_image: DefaultImage, _background_color: String, _is_enabled: bool, _is_user_input_required: bool, _max_per_stream_setting: MaxPerStreamSetting, _max_per_user_per_stream_setting: MaxPerUserPerStreamSetting, _global_cooldown_setting: GlobalCooldownSetting, _is_paused: bool, _is_in_stock: bool, _should_redemptions_skip_request_queue: bool, _redemptions_redeemed_current_stream: int, _cooldown_expires_at: String) -> TwitchCustomReward: + var twitch_custom_reward: TwitchCustomReward = TwitchCustomReward.new() + twitch_custom_reward.broadcaster_id = _broadcaster_id + twitch_custom_reward.broadcaster_login = _broadcaster_login + twitch_custom_reward.broadcaster_name = _broadcaster_name + twitch_custom_reward.id = _id + twitch_custom_reward.title = _title + twitch_custom_reward.prompt = _prompt + twitch_custom_reward.cost = _cost + twitch_custom_reward.image = _image + twitch_custom_reward.default_image = _default_image + twitch_custom_reward.background_color = _background_color + twitch_custom_reward.is_enabled = _is_enabled + twitch_custom_reward.is_user_input_required = _is_user_input_required + twitch_custom_reward.max_per_stream_setting = _max_per_stream_setting + twitch_custom_reward.max_per_user_per_stream_setting = _max_per_user_per_stream_setting + twitch_custom_reward.global_cooldown_setting = _global_cooldown_setting + twitch_custom_reward.is_paused = _is_paused + twitch_custom_reward.is_in_stock = _is_in_stock + twitch_custom_reward.should_redemptions_skip_request_queue = _should_redemptions_skip_request_queue + twitch_custom_reward.redemptions_redeemed_current_stream = _redemptions_redeemed_current_stream + twitch_custom_reward.cooldown_expires_at = _cooldown_expires_at + return twitch_custom_reward + + +static func from_json(d: Dictionary) -> TwitchCustomReward: + var result: TwitchCustomReward = TwitchCustomReward.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_login", null) != null: + result.broadcaster_login = d["broadcaster_login"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + if d.get("id", null) != null: + result.id = d["id"] + if d.get("title", null) != null: + result.title = d["title"] + if d.get("prompt", null) != null: + result.prompt = d["prompt"] + if d.get("cost", null) != null: + result.cost = d["cost"] + if d.get("image", null) != null: + result.image = TwitchImage.from_json(d["image"]) + if d.get("default_image", null) != null: + result.default_image = DefaultImage.from_json(d["default_image"]) + if d.get("background_color", null) != null: + result.background_color = d["background_color"] + if d.get("is_enabled", null) != null: + result.is_enabled = d["is_enabled"] + if d.get("is_user_input_required", null) != null: + result.is_user_input_required = d["is_user_input_required"] + if d.get("max_per_stream_setting", null) != null: + result.max_per_stream_setting = MaxPerStreamSetting.from_json(d["max_per_stream_setting"]) + if d.get("max_per_user_per_stream_setting", null) != null: + result.max_per_user_per_stream_setting = MaxPerUserPerStreamSetting.from_json(d["max_per_user_per_stream_setting"]) + if d.get("global_cooldown_setting", null) != null: + result.global_cooldown_setting = GlobalCooldownSetting.from_json(d["global_cooldown_setting"]) + if d.get("is_paused", null) != null: + result.is_paused = d["is_paused"] + if d.get("is_in_stock", null) != null: + result.is_in_stock = d["is_in_stock"] + if d.get("should_redemptions_skip_request_queue", null) != null: + result.should_redemptions_skip_request_queue = d["should_redemptions_skip_request_queue"] + if d.get("redemptions_redeemed_current_stream", null) != null: + result.redemptions_redeemed_current_stream = d["redemptions_redeemed_current_stream"] + if d.get("cooldown_expires_at", null) != null: + result.cooldown_expires_at = d["cooldown_expires_at"] + return result + + + +## A set of custom images for the reward. This field is **null** if the broadcaster didn’t upload images. +## #/components/schemas/CustomReward/Image +class TwitchImage extends TwitchData: + + ## The URL to a small version of the image. + @export var url_1x: String: + set(val): + url_1x = val + track_data(&"url_1x", val) + + ## The URL to a medium version of the image. + @export var url_2x: String: + set(val): + url_2x = val + track_data(&"url_2x", val) + + ## The URL to a large version of the image. + @export var url_4x: String: + set(val): + url_4x = val + track_data(&"url_4x", val) + + + + ## Constructor with all required fields. + static func create(_url_1x: String, _url_2x: String, _url_4x: String) -> TwitchImage: + var twitch_image: TwitchImage = TwitchImage.new() + twitch_image.url_1x = _url_1x + twitch_image.url_2x = _url_2x + twitch_image.url_4x = _url_4x + return twitch_image + + + static func from_json(d: Dictionary) -> TwitchImage: + var result: TwitchImage = TwitchImage.new() + if d.get("url_1x", null) != null: + result.url_1x = d["url_1x"] + if d.get("url_2x", null) != null: + result.url_2x = d["url_2x"] + if d.get("url_4x", null) != null: + result.url_4x = d["url_4x"] + return result + + + +## A set of default images for the reward. +## #/components/schemas/CustomReward/DefaultImage +class DefaultImage extends TwitchData: + + ## The URL to a small version of the image. + @export var url_1x: String: + set(val): + url_1x = val + track_data(&"url_1x", val) + + ## The URL to a medium version of the image. + @export var url_2x: String: + set(val): + url_2x = val + track_data(&"url_2x", val) + + ## The URL to a large version of the image. + @export var url_4x: String: + set(val): + url_4x = val + track_data(&"url_4x", val) + + + + ## Constructor with all required fields. + static func create(_url_1x: String, _url_2x: String, _url_4x: String) -> DefaultImage: + var default_image: DefaultImage = DefaultImage.new() + default_image.url_1x = _url_1x + default_image.url_2x = _url_2x + default_image.url_4x = _url_4x + return default_image + + + static func from_json(d: Dictionary) -> DefaultImage: + var result: DefaultImage = DefaultImage.new() + if d.get("url_1x", null) != null: + result.url_1x = d["url_1x"] + if d.get("url_2x", null) != null: + result.url_2x = d["url_2x"] + if d.get("url_4x", null) != null: + result.url_4x = d["url_4x"] + return result + + + +## The settings used to determine whether to apply a maximum to the number of redemptions allowed per live stream. +## #/components/schemas/CustomReward/MaxPerStreamSetting +class MaxPerStreamSetting extends TwitchData: + + ## A Boolean value that determines whether the reward applies a limit on the number of redemptions allowed per live stream. Is **true** if the reward applies a limit. + @export var is_enabled: bool: + set(val): + is_enabled = val + track_data(&"is_enabled", val) + + ## The maximum number of redemptions allowed per live stream. + @export var max_per_stream: int: + set(val): + max_per_stream = val + track_data(&"max_per_stream", val) + + + + ## Constructor with all required fields. + static func create(_is_enabled: bool, _max_per_stream: int) -> MaxPerStreamSetting: + var max_per_stream_setting: MaxPerStreamSetting = MaxPerStreamSetting.new() + max_per_stream_setting.is_enabled = _is_enabled + max_per_stream_setting.max_per_stream = _max_per_stream + return max_per_stream_setting + + + static func from_json(d: Dictionary) -> MaxPerStreamSetting: + var result: MaxPerStreamSetting = MaxPerStreamSetting.new() + if d.get("is_enabled", null) != null: + result.is_enabled = d["is_enabled"] + if d.get("max_per_stream", null) != null: + result.max_per_stream = d["max_per_stream"] + return result + + + +## The settings used to determine whether to apply a maximum to the number of redemptions allowed per user per live stream. +## #/components/schemas/CustomReward/MaxPerUserPerStreamSetting +class MaxPerUserPerStreamSetting extends TwitchData: + + ## A Boolean value that determines whether the reward applies a limit on the number of redemptions allowed per user per live stream. Is **true** if the reward applies a limit. + @export var is_enabled: bool: + set(val): + is_enabled = val + track_data(&"is_enabled", val) + + ## The maximum number of redemptions allowed per user per live stream. + @export var max_per_user_per_stream: int: + set(val): + max_per_user_per_stream = val + track_data(&"max_per_user_per_stream", val) + + + + ## Constructor with all required fields. + static func create(_is_enabled: bool, _max_per_user_per_stream: int) -> MaxPerUserPerStreamSetting: + var max_per_user_per_stream_setting: MaxPerUserPerStreamSetting = MaxPerUserPerStreamSetting.new() + max_per_user_per_stream_setting.is_enabled = _is_enabled + max_per_user_per_stream_setting.max_per_user_per_stream = _max_per_user_per_stream + return max_per_user_per_stream_setting + + + static func from_json(d: Dictionary) -> MaxPerUserPerStreamSetting: + var result: MaxPerUserPerStreamSetting = MaxPerUserPerStreamSetting.new() + if d.get("is_enabled", null) != null: + result.is_enabled = d["is_enabled"] + if d.get("max_per_user_per_stream", null) != null: + result.max_per_user_per_stream = d["max_per_user_per_stream"] + return result + + + +## The settings used to determine whether to apply a cooldown period between redemptions and the length of the cooldown. +## #/components/schemas/CustomReward/GlobalCooldownSetting +class GlobalCooldownSetting extends TwitchData: + + ## A Boolean value that determines whether to apply a cooldown period. Is **true** if a cooldown period is enabled. + @export var is_enabled: bool: + set(val): + is_enabled = val + track_data(&"is_enabled", val) + + ## The cooldown period, in seconds. + @export var global_cooldown_seconds: int: + set(val): + global_cooldown_seconds = val + track_data(&"global_cooldown_seconds", val) + + + + ## Constructor with all required fields. + static func create(_is_enabled: bool, _global_cooldown_seconds: int) -> GlobalCooldownSetting: + var global_cooldown_setting: GlobalCooldownSetting = GlobalCooldownSetting.new() + global_cooldown_setting.is_enabled = _is_enabled + global_cooldown_setting.global_cooldown_seconds = _global_cooldown_seconds + return global_cooldown_setting + + + static func from_json(d: Dictionary) -> GlobalCooldownSetting: + var result: GlobalCooldownSetting = GlobalCooldownSetting.new() + if d.get("is_enabled", null) != null: + result.is_enabled = d["is_enabled"] + if d.get("global_cooldown_seconds", null) != null: + result.global_cooldown_seconds = d["global_cooldown_seconds"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_custom_reward.gd.uid b/addons/twitcher/generated/twitch_custom_reward.gd.uid new file mode 100644 index 0000000..c0c3f5a --- /dev/null +++ b/addons/twitcher/generated/twitch_custom_reward.gd.uid @@ -0,0 +1 @@ +uid://d34uaswkjcjbo diff --git a/addons/twitcher/generated/twitch_custom_reward_redemption.gd b/addons/twitcher/generated/twitch_custom_reward_redemption.gd new file mode 100644 index 0000000..8e00aac --- /dev/null +++ b/addons/twitcher/generated/twitch_custom_reward_redemption.gd @@ -0,0 +1,178 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/CustomRewardRedemption +class_name TwitchCustomRewardRedemption + +## The ID that uniquely identifies the broadcaster. +@export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + +## The broadcaster’s login name. +@export var broadcaster_login: String: + set(val): + broadcaster_login = val + track_data(&"broadcaster_login", val) + +## The broadcaster’s display name. +@export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + +## The ID that uniquely identifies this redemption.. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The ID of the user that redeemed the reward. +@export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + +## The user’s display name. +@export var user_name: String: + set(val): + user_name = val + track_data(&"user_name", val) + +## The user’s login name. +@export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) + +## An object that describes the reward that the user redeemed. +@export var reward: Reward: + set(val): + reward = val + track_data(&"reward", val) + +## The text that the user entered at the prompt when they redeemed the reward; otherwise, an empty string if user input was not required. +@export var user_input: String: + set(val): + user_input = val + track_data(&"user_input", val) + +## The state of the redemption. Possible values are: +## +## * CANCELED +## * FULFILLED +## * UNFULFILLED +@export var status: String: + set(val): + status = val + track_data(&"status", val) + +## The date and time of when the reward was redeemed, in RFC3339 format. +@export var redeemed_at: String: + set(val): + redeemed_at = val + track_data(&"redeemed_at", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_broadcaster_id: String, _broadcaster_login: String, _broadcaster_name: String, _id: String, _user_id: String, _user_name: String, _user_login: String, _reward: Reward, _user_input: String, _status: String, _redeemed_at: String) -> TwitchCustomRewardRedemption: + var twitch_custom_reward_redemption: TwitchCustomRewardRedemption = TwitchCustomRewardRedemption.new() + twitch_custom_reward_redemption.broadcaster_id = _broadcaster_id + twitch_custom_reward_redemption.broadcaster_login = _broadcaster_login + twitch_custom_reward_redemption.broadcaster_name = _broadcaster_name + twitch_custom_reward_redemption.id = _id + twitch_custom_reward_redemption.user_id = _user_id + twitch_custom_reward_redemption.user_name = _user_name + twitch_custom_reward_redemption.user_login = _user_login + twitch_custom_reward_redemption.reward = _reward + twitch_custom_reward_redemption.user_input = _user_input + twitch_custom_reward_redemption.status = _status + twitch_custom_reward_redemption.redeemed_at = _redeemed_at + return twitch_custom_reward_redemption + + +static func from_json(d: Dictionary) -> TwitchCustomRewardRedemption: + var result: TwitchCustomRewardRedemption = TwitchCustomRewardRedemption.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_login", null) != null: + result.broadcaster_login = d["broadcaster_login"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + if d.get("id", null) != null: + result.id = d["id"] + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_name", null) != null: + result.user_name = d["user_name"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + if d.get("reward", null) != null: + result.reward = Reward.from_json(d["reward"]) + if d.get("user_input", null) != null: + result.user_input = d["user_input"] + if d.get("status", null) != null: + result.status = d["status"] + if d.get("redeemed_at", null) != null: + result.redeemed_at = d["redeemed_at"] + return result + + + +## An object that describes the reward that the user redeemed. +## #/components/schemas/CustomRewardRedemption/Reward +class Reward extends TwitchData: + + ## The ID that uniquely identifies the reward. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## The reward’s title. + @export var title: String: + set(val): + title = val + track_data(&"title", val) + + ## The prompt displayed to the viewer if user input is required. + @export var prompt: String: + set(val): + prompt = val + track_data(&"prompt", val) + + ## The reward’s cost, in Channel Points. + @export var cost: int: + set(val): + cost = val + track_data(&"cost", val) + + + + ## Constructor with all required fields. + static func create(_id: String, _title: String, _prompt: String, _cost: int) -> Reward: + var reward: Reward = Reward.new() + reward.id = _id + reward.title = _title + reward.prompt = _prompt + reward.cost = _cost + return reward + + + static func from_json(d: Dictionary) -> Reward: + var result: Reward = Reward.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("title", null) != null: + result.title = d["title"] + if d.get("prompt", null) != null: + result.prompt = d["prompt"] + if d.get("cost", null) != null: + result.cost = d["cost"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_custom_reward_redemption.gd.uid b/addons/twitcher/generated/twitch_custom_reward_redemption.gd.uid new file mode 100644 index 0000000..6e3a701 --- /dev/null +++ b/addons/twitcher/generated/twitch_custom_reward_redemption.gd.uid @@ -0,0 +1 @@ +uid://0s4apewkcan0 diff --git a/addons/twitcher/generated/twitch_delete_chat_messages.gd b/addons/twitcher/generated/twitch_delete_chat_messages.gd new file mode 100644 index 0000000..5e88ae8 --- /dev/null +++ b/addons/twitcher/generated/twitch_delete_chat_messages.gd @@ -0,0 +1,39 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchDeleteChatMessages + + + +## All optional parameters for TwitchAPI.delete_chat_messages +## #/components/schemas/DeleteChatMessagesOpt +class Opt extends TwitchData: + + ## The ID of the message to remove. The `id` tag in the [PRIVMSG](https://dev.twitch.tv/docs/irc/tags#privmsg-tags) tag contains the message’s ID. Restrictions: + ## + ## * The message must have been created within the last 6 hours. + ## * The message must not belong to the broadcaster. + ## * The message must not belong to another moderator. + ## + ## If not specified, the request removes all messages in the broadcaster’s chat room. + @export var message_id: String: + set(val): + message_id = val + track_data(&"message_id", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("message_id", null) != null: + result.message_id = d["message_id"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_delete_chat_messages.gd.uid b/addons/twitcher/generated/twitch_delete_chat_messages.gd.uid new file mode 100644 index 0000000..fc52941 --- /dev/null +++ b/addons/twitcher/generated/twitch_delete_chat_messages.gd.uid @@ -0,0 +1 @@ +uid://bifgk3c6tnogu diff --git a/addons/twitcher/generated/twitch_delete_guest_star_slot.gd b/addons/twitcher/generated/twitch_delete_guest_star_slot.gd new file mode 100644 index 0000000..92debee --- /dev/null +++ b/addons/twitcher/generated/twitch_delete_guest_star_slot.gd @@ -0,0 +1,33 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchDeleteGuestStarSlot + + + +## All optional parameters for TwitchAPI.delete_guest_star_slot +## #/components/schemas/DeleteGuestStarSlotOpt +class Opt extends TwitchData: + + ## Flag signaling that the guest should be reinvited to the session, sending them back to the invite queue. + @export var should_reinvite_guest: String: + set(val): + should_reinvite_guest = val + track_data(&"should_reinvite_guest", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("should_reinvite_guest", null) != null: + result.should_reinvite_guest = d["should_reinvite_guest"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_delete_guest_star_slot.gd.uid b/addons/twitcher/generated/twitch_delete_guest_star_slot.gd.uid new file mode 100644 index 0000000..8a0d354 --- /dev/null +++ b/addons/twitcher/generated/twitch_delete_guest_star_slot.gd.uid @@ -0,0 +1 @@ +uid://cumi77bjenewb diff --git a/addons/twitcher/generated/twitch_delete_videos.gd b/addons/twitcher/generated/twitch_delete_videos.gd new file mode 100644 index 0000000..b2de60e --- /dev/null +++ b/addons/twitcher/generated/twitch_delete_videos.gd @@ -0,0 +1,35 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchDeleteVideos + + + +## +## #/components/schemas/DeleteVideosResponse +class Response extends TwitchData: + + ## The list of IDs of the videos that were deleted. + @export var data: Array[String]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[String]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(value) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_delete_videos.gd.uid b/addons/twitcher/generated/twitch_delete_videos.gd.uid new file mode 100644 index 0000000..aef777a --- /dev/null +++ b/addons/twitcher/generated/twitch_delete_videos.gd.uid @@ -0,0 +1 @@ +uid://e4uvq6ctah05 diff --git a/addons/twitcher/generated/twitch_drops_entitlement.gd b/addons/twitcher/generated/twitch_drops_entitlement.gd new file mode 100644 index 0000000..e8965a9 --- /dev/null +++ b/addons/twitcher/generated/twitch_drops_entitlement.gd @@ -0,0 +1,86 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/DropsEntitlement +class_name TwitchDropsEntitlement + +## An ID that identifies the entitlement. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## An ID that identifies the benefit (reward). +@export var benefit_id: String: + set(val): + benefit_id = val + track_data(&"benefit_id", val) + +## The UTC date and time (in RFC3339 format) of when the entitlement was granted. +@export var timestamp: String: + set(val): + timestamp = val + track_data(&"timestamp", val) + +## An ID that identifies the user who was granted the entitlement. +@export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + +## An ID that identifies the game the user was playing when the reward was entitled. +@export var game_id: String: + set(val): + game_id = val + track_data(&"game_id", val) + +## The entitlement’s fulfillment status. Possible values are: +## +## * CLAIMED +## * FULFILLED +@export var fulfillment_status: String: + set(val): + fulfillment_status = val + track_data(&"fulfillment_status", val) + +## The UTC date and time (in RFC3339 format) of when the entitlement was last updated. +@export var last_updated: String: + set(val): + last_updated = val + track_data(&"last_updated", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _benefit_id: String, _timestamp: String, _user_id: String, _game_id: String, _fulfillment_status: String, _last_updated: String) -> TwitchDropsEntitlement: + var twitch_drops_entitlement: TwitchDropsEntitlement = TwitchDropsEntitlement.new() + twitch_drops_entitlement.id = _id + twitch_drops_entitlement.benefit_id = _benefit_id + twitch_drops_entitlement.timestamp = _timestamp + twitch_drops_entitlement.user_id = _user_id + twitch_drops_entitlement.game_id = _game_id + twitch_drops_entitlement.fulfillment_status = _fulfillment_status + twitch_drops_entitlement.last_updated = _last_updated + return twitch_drops_entitlement + + +static func from_json(d: Dictionary) -> TwitchDropsEntitlement: + var result: TwitchDropsEntitlement = TwitchDropsEntitlement.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("benefit_id", null) != null: + result.benefit_id = d["benefit_id"] + if d.get("timestamp", null) != null: + result.timestamp = d["timestamp"] + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("game_id", null) != null: + result.game_id = d["game_id"] + if d.get("fulfillment_status", null) != null: + result.fulfillment_status = d["fulfillment_status"] + if d.get("last_updated", null) != null: + result.last_updated = d["last_updated"] + return result diff --git a/addons/twitcher/generated/twitch_drops_entitlement.gd.uid b/addons/twitcher/generated/twitch_drops_entitlement.gd.uid new file mode 100644 index 0000000..a9d36bd --- /dev/null +++ b/addons/twitcher/generated/twitch_drops_entitlement.gd.uid @@ -0,0 +1 @@ +uid://dd4h7ue40wrt0 diff --git a/addons/twitcher/generated/twitch_drops_entitlement_updated.gd b/addons/twitcher/generated/twitch_drops_entitlement_updated.gd new file mode 100644 index 0000000..d1e8342 --- /dev/null +++ b/addons/twitcher/generated/twitch_drops_entitlement_updated.gd @@ -0,0 +1,45 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/DropsEntitlementUpdated +class_name TwitchDropsEntitlementUpdated + +## A string that indicates whether the status of the entitlements in the `ids` field were successfully updated. Possible values are: +## +## * INVALID\_ID — The entitlement IDs in the `ids` field are not valid. +## * NOT\_FOUND — The entitlement IDs in the `ids` field were not found. +## * SUCCESS — The status of the entitlements in the `ids` field were successfully updated. +## * UNAUTHORIZED — The user or organization identified by the user access token is not authorized to update the entitlements. +## * UPDATE\_FAILED — The update failed. These are considered transient errors and the request should be retried later. +@export var status: String: + set(val): + status = val + track_data(&"status", val) + +## The list of entitlements that the status in the `status` field applies to. +@export var ids: Array[String]: + set(val): + ids = val + track_data(&"ids", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_status: String, _ids: Array[String]) -> TwitchDropsEntitlementUpdated: + var twitch_drops_entitlement_updated: TwitchDropsEntitlementUpdated = TwitchDropsEntitlementUpdated.new() + twitch_drops_entitlement_updated.status = _status + twitch_drops_entitlement_updated.ids = _ids + return twitch_drops_entitlement_updated + + +static func from_json(d: Dictionary) -> TwitchDropsEntitlementUpdated: + var result: TwitchDropsEntitlementUpdated = TwitchDropsEntitlementUpdated.new() + if d.get("status", null) != null: + result.status = d["status"] + if d.get("ids", null) != null: + for value in d["ids"]: + result.ids.append(value) + return result diff --git a/addons/twitcher/generated/twitch_drops_entitlement_updated.gd.uid b/addons/twitcher/generated/twitch_drops_entitlement_updated.gd.uid new file mode 100644 index 0000000..fffd80d --- /dev/null +++ b/addons/twitcher/generated/twitch_drops_entitlement_updated.gd.uid @@ -0,0 +1 @@ +uid://b8bl0d0wy1n0f diff --git a/addons/twitcher/generated/twitch_emote.gd b/addons/twitcher/generated/twitch_emote.gd new file mode 100644 index 0000000..e55e3d0 --- /dev/null +++ b/addons/twitcher/generated/twitch_emote.gd @@ -0,0 +1,168 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/Emote +class_name TwitchEmote + +## An ID that uniquely identifies this emote. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The name of the emote. This is the name that viewers type in the chat window to get the emote to appear. +@export var name: String: + set(val): + name = val + track_data(&"name", val) + +## The image URLs for the emote. These image URLs always provide a static, non-animated emote image with a light background. +## +## **NOTE:** You should use the templated URL in the `template` field to fetch the image instead of using these URLs. +@export var images: Images: + set(val): + images = val + track_data(&"images", val) + +## The type of emote. The possible values are: +## +## * bitstier — A Bits tier emote. +## * follower — A follower emote. +## * subscriptions — A subscriber emote. +@export var emote_type: String: + set(val): + emote_type = val + track_data(&"emote_type", val) + +## An ID that identifies the emote set that the emote belongs to. +@export var emote_set_id: String: + set(val): + emote_set_id = val + track_data(&"emote_set_id", val) + +## The ID of the broadcaster who owns the emote. +@export var owner_id: String: + set(val): + owner_id = val + track_data(&"owner_id", val) + +## The formats that the emote is available in. For example, if the emote is available only as a static PNG, the array contains only `static`. But if the emote is available as a static PNG and an animated GIF, the array contains `static` and `animated`. The possible formats are: +## +## * animated — An animated GIF is available for this emote. +## * static — A static PNG file is available for this emote. +@export var format: Array[String]: + set(val): + format = val + track_data(&"format", val) + +## The sizes that the emote is available in. For example, if the emote is available in small and medium sizes, the array contains 1.0 and 2.0\. Possible sizes are: +## +## * 1.0 — A small version (28px x 28px) is available. +## * 2.0 — A medium version (56px x 56px) is available. +## * 3.0 — A large version (112px x 112px) is available. +@export var scale: Array[String]: + set(val): + scale = val + track_data(&"scale", val) + +## The background themes that the emote is available in. Possible themes are: +## +## * dark +## * light +@export var theme_mode: Array[String]: + set(val): + theme_mode = val + track_data(&"theme_mode", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _name: String, _images: Images, _emote_type: String, _emote_set_id: String, _owner_id: String, _format: Array[String], _scale: Array[String], _theme_mode: Array[String]) -> TwitchEmote: + var twitch_emote: TwitchEmote = TwitchEmote.new() + twitch_emote.id = _id + twitch_emote.name = _name + twitch_emote.images = _images + twitch_emote.emote_type = _emote_type + twitch_emote.emote_set_id = _emote_set_id + twitch_emote.owner_id = _owner_id + twitch_emote.format = _format + twitch_emote.scale = _scale + twitch_emote.theme_mode = _theme_mode + return twitch_emote + + +static func from_json(d: Dictionary) -> TwitchEmote: + var result: TwitchEmote = TwitchEmote.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("name", null) != null: + result.name = d["name"] + if d.get("images", null) != null: + result.images = Images.from_json(d["images"]) + if d.get("emote_type", null) != null: + result.emote_type = d["emote_type"] + if d.get("emote_set_id", null) != null: + result.emote_set_id = d["emote_set_id"] + if d.get("owner_id", null) != null: + result.owner_id = d["owner_id"] + if d.get("format", null) != null: + for value in d["format"]: + result.format.append(value) + if d.get("scale", null) != null: + for value in d["scale"]: + result.scale.append(value) + if d.get("theme_mode", null) != null: + for value in d["theme_mode"]: + result.theme_mode.append(value) + return result + + + +## The image URLs for the emote. These image URLs always provide a static, non-animated emote image with a light background. +## +## **NOTE:** You should use the templated URL in the `template` field to fetch the image instead of using these URLs. +## #/components/schemas/Emote/Images +class Images extends TwitchData: + + ## A URL to the small version (28px x 28px) of the emote. + @export var url_1x: String: + set(val): + url_1x = val + track_data(&"url_1x", val) + + ## A URL to the medium version (56px x 56px) of the emote. + @export var url_2x: String: + set(val): + url_2x = val + track_data(&"url_2x", val) + + ## A URL to the large version (112px x 112px) of the emote. + @export var url_4x: String: + set(val): + url_4x = val + track_data(&"url_4x", val) + + + + ## Constructor with all required fields. + static func create(_url_1x: String, _url_2x: String, _url_4x: String) -> Images: + var images: Images = Images.new() + images.url_1x = _url_1x + images.url_2x = _url_2x + images.url_4x = _url_4x + return images + + + static func from_json(d: Dictionary) -> Images: + var result: Images = Images.new() + if d.get("url_1x", null) != null: + result.url_1x = d["url_1x"] + if d.get("url_2x", null) != null: + result.url_2x = d["url_2x"] + if d.get("url_4x", null) != null: + result.url_4x = d["url_4x"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_emote.gd.uid b/addons/twitcher/generated/twitch_emote.gd.uid new file mode 100644 index 0000000..6eb7256 --- /dev/null +++ b/addons/twitcher/generated/twitch_emote.gd.uid @@ -0,0 +1 @@ +uid://cr8cnwu0wlel6 diff --git a/addons/twitcher/generated/twitch_end_guest_star_session.gd b/addons/twitcher/generated/twitch_end_guest_star_session.gd new file mode 100644 index 0000000..7ac5b97 --- /dev/null +++ b/addons/twitcher/generated/twitch_end_guest_star_session.gd @@ -0,0 +1,35 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchEndGuestStarSession + + + +## +## #/components/schemas/EndGuestStarSessionResponse +class Response extends TwitchData: + + ## Summary of the session details when the session was ended. + @export var data: Array[TwitchGuestStarSession]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchGuestStarSession]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchGuestStarSession.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_end_guest_star_session.gd.uid b/addons/twitcher/generated/twitch_end_guest_star_session.gd.uid new file mode 100644 index 0000000..07146ce --- /dev/null +++ b/addons/twitcher/generated/twitch_end_guest_star_session.gd.uid @@ -0,0 +1 @@ +uid://dnv76mguitjfe diff --git a/addons/twitcher/generated/twitch_end_poll.gd b/addons/twitcher/generated/twitch_end_poll.gd new file mode 100644 index 0000000..6bd2485 --- /dev/null +++ b/addons/twitcher/generated/twitch_end_poll.gd @@ -0,0 +1,83 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchEndPoll + + + +## +## #/components/schemas/EndPollBody +class Body extends TwitchData: + + ## The ID of the broadcaster that’s running the poll. This ID must match the user ID in the user access token. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## The ID of the poll to update. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## The status to set the poll to. Possible case-sensitive values are: + ## + ## * TERMINATED — Ends the poll before the poll is scheduled to end. The poll remains publicly visible. + ## * ARCHIVED — Ends the poll before the poll is scheduled to end, and then archives it so it's no longer publicly visible. + @export var status: String: + set(val): + status = val + track_data(&"status", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_broadcaster_id: String, _id: String, _status: String) -> Body: + var body: Body = Body.new() + body.broadcaster_id = _broadcaster_id + body.id = _id + body.status = _status + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("id", null) != null: + result.id = d["id"] + if d.get("status", null) != null: + result.status = d["status"] + return result + + + +## +## #/components/schemas/EndPollResponse +class Response extends TwitchData: + + ## A list that contains the poll that you ended. + @export var data: Array[TwitchPoll]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchPoll]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchPoll.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_end_poll.gd.uid b/addons/twitcher/generated/twitch_end_poll.gd.uid new file mode 100644 index 0000000..4cb6156 --- /dev/null +++ b/addons/twitcher/generated/twitch_end_poll.gd.uid @@ -0,0 +1 @@ +uid://c85hwqlquv0me diff --git a/addons/twitcher/generated/twitch_end_prediction.gd b/addons/twitcher/generated/twitch_end_prediction.gd new file mode 100644 index 0000000..01949fc --- /dev/null +++ b/addons/twitcher/generated/twitch_end_prediction.gd @@ -0,0 +1,96 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchEndPrediction + + + +## +## #/components/schemas/EndPredictionBody +class Body extends TwitchData: + + ## The ID of the broadcaster that’s running the prediction. This ID must match the user ID in the user access token. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## The ID of the prediction to update. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## The status to set the prediction to. Possible case-sensitive values are: + ## + ## * RESOLVED — The winning outcome is determined and the Channel Points are distributed to the viewers who predicted the correct outcome. + ## * CANCELED — The broadcaster is canceling the prediction and sending refunds to the participants. + ## * LOCKED — The broadcaster is locking the prediction, which means viewers may no longer make predictions. + ## + ## The broadcaster can update an active prediction to LOCKED, RESOLVED, or CANCELED; and update a locked prediction to RESOLVED or CANCELED. + ## + ## The broadcaster has up to 24 hours after the prediction window closes to resolve the prediction. If not, Twitch sets the status to CANCELED and returns the points. + @export var status: String: + set(val): + status = val + track_data(&"status", val) + + ## The ID of the winning outcome. You must set this parameter if you set `status` to RESOLVED. + @export var winning_outcome_id: String: + set(val): + winning_outcome_id = val + track_data(&"winning_outcome_id", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_broadcaster_id: String, _id: String, _status: String) -> Body: + var body: Body = Body.new() + body.broadcaster_id = _broadcaster_id + body.id = _id + body.status = _status + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("id", null) != null: + result.id = d["id"] + if d.get("status", null) != null: + result.status = d["status"] + if d.get("winning_outcome_id", null) != null: + result.winning_outcome_id = d["winning_outcome_id"] + return result + + + +## +## #/components/schemas/EndPredictionResponse +class Response extends TwitchData: + + ## A list that contains the single prediction that you updated. + @export var data: Array[TwitchPrediction]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchPrediction]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchPrediction.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_end_prediction.gd.uid b/addons/twitcher/generated/twitch_end_prediction.gd.uid new file mode 100644 index 0000000..6472dca --- /dev/null +++ b/addons/twitcher/generated/twitch_end_prediction.gd.uid @@ -0,0 +1 @@ +uid://dlqtp0nl2h2ow diff --git a/addons/twitcher/generated/twitch_event_sub_subscription.gd b/addons/twitcher/generated/twitch_event_sub_subscription.gd new file mode 100644 index 0000000..8803d15 --- /dev/null +++ b/addons/twitcher/generated/twitch_event_sub_subscription.gd @@ -0,0 +1,172 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/EventSubSubscription +class_name TwitchEventSubSubscription + +## An ID that identifies the subscription. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The subscription's status. The subscriber receives events only for **enabled** subscriptions. Possible values are: +## +## * enabled — The subscription is enabled. +## * webhook\_callback\_verification\_pending — The subscription is pending verification of the specified callback URL. +## * webhook\_callback\_verification\_failed — The specified callback URL failed verification. +## * notification\_failures\_exceeded — The notification delivery failure rate was too high. +## * authorization\_revoked — The authorization was revoked for one or more users specified in the **Condition** object. +## * moderator\_removed — The moderator that authorized the subscription is no longer one of the broadcaster's moderators. +## * user\_removed — One of the users specified in the **Condition** object was removed. +## * version\_removed — The subscription to subscription type and version is no longer supported. +## * beta\_maintenance — The subscription to the beta subscription type was removed due to maintenance. +## * websocket\_disconnected — The client closed the connection. +## * websocket\_failed\_ping\_pong — The client failed to respond to a ping message. +## * websocket\_received\_inbound\_traffic — The client sent a non-pong message. Clients may only send pong messages (and only in response to a ping message). +## * websocket\_connection\_unused — The client failed to subscribe to events within the required time. +## * websocket\_internal\_error — The Twitch WebSocket server experienced an unexpected error. +## * websocket\_network\_timeout — The Twitch WebSocket server timed out writing the message to the client. +## * websocket\_network\_error — The Twitch WebSocket server experienced a network error writing the message to the client. +@export var status: String: + set(val): + status = val + track_data(&"status", val) + +## The subscription's type. See [Subscription Types](https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types#subscription-types). +@export var type: String: + set(val): + type = val + track_data(&"type", val) + +## The version number that identifies this definition of the subscription's data. +@export var version: String: + set(val): + version = val + track_data(&"version", val) + +## The subscription's parameter values. This is a string-encoded JSON object whose contents are determined by the subscription type. +@export var condition: Dictionary: + set(val): + condition = val + track_data(&"condition", val) + +## The date and time (in RFC3339 format) of when the subscription was created. +@export var created_at: String: + set(val): + created_at = val + track_data(&"created_at", val) + +## The transport details used to send the notifications. +@export var transport: Transport: + set(val): + transport = val + track_data(&"transport", val) + +## The amount that the subscription counts against your limit. [Learn More](https://dev.twitch.tv/docs/eventsub/manage-subscriptions/#subscription-limits) +@export var cost: int: + set(val): + cost = val + track_data(&"cost", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _status: String, _type: String, _version: String, _condition: Dictionary, _created_at: String, _transport: Transport, _cost: int) -> TwitchEventSubSubscription: + var twitch_event_sub_subscription: TwitchEventSubSubscription = TwitchEventSubSubscription.new() + twitch_event_sub_subscription.id = _id + twitch_event_sub_subscription.status = _status + twitch_event_sub_subscription.type = _type + twitch_event_sub_subscription.version = _version + twitch_event_sub_subscription.condition = _condition + twitch_event_sub_subscription.created_at = _created_at + twitch_event_sub_subscription.transport = _transport + twitch_event_sub_subscription.cost = _cost + return twitch_event_sub_subscription + + +static func from_json(d: Dictionary) -> TwitchEventSubSubscription: + var result: TwitchEventSubSubscription = TwitchEventSubSubscription.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("status", null) != null: + result.status = d["status"] + if d.get("type", null) != null: + result.type = d["type"] + if d.get("version", null) != null: + result.version = d["version"] + if d.get("condition", null) != null: + result.condition = d["condition"] + if d.get("created_at", null) != null: + result.created_at = d["created_at"] + if d.get("transport", null) != null: + result.transport = Transport.from_json(d["transport"]) + if d.get("cost", null) != null: + result.cost = d["cost"] + return result + + + +## The transport details used to send the notifications. +## #/components/schemas/EventSubSubscription/Transport +class Transport extends TwitchData: + + ## The transport method. Possible values are: + ## + ## * webhook + ## * websocket + @export var method: String: + set(val): + method = val + track_data(&"method", val) + + ## The callback URL where the notifications are sent. Included only if `method` is set to **webhook**. + @export var callback: String: + set(val): + callback = val + track_data(&"callback", val) + + ## An ID that identifies the WebSocket that notifications are sent to. Included only if `method` is set to **websocket**. + @export var session_id: String: + set(val): + session_id = val + track_data(&"session_id", val) + + ## The UTC date and time that the WebSocket connection was established. Included only if `method` is set to **websocket**. + @export var connected_at: String: + set(val): + connected_at = val + track_data(&"connected_at", val) + + ## The UTC date and time that the WebSocket connection was lost. Included only if `method` is set to **websocket**. + @export var disconnected_at: String: + set(val): + disconnected_at = val + track_data(&"disconnected_at", val) + + + + ## Constructor with all required fields. + static func create(_method: String) -> Transport: + var transport: Transport = Transport.new() + transport.method = _method + return transport + + + static func from_json(d: Dictionary) -> Transport: + var result: Transport = Transport.new() + if d.get("method", null) != null: + result.method = d["method"] + if d.get("callback", null) != null: + result.callback = d["callback"] + if d.get("session_id", null) != null: + result.session_id = d["session_id"] + if d.get("connected_at", null) != null: + result.connected_at = d["connected_at"] + if d.get("disconnected_at", null) != null: + result.disconnected_at = d["disconnected_at"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_event_sub_subscription.gd.uid b/addons/twitcher/generated/twitch_event_sub_subscription.gd.uid new file mode 100644 index 0000000..16c476d --- /dev/null +++ b/addons/twitcher/generated/twitch_event_sub_subscription.gd.uid @@ -0,0 +1 @@ +uid://e8nf7nbqecah diff --git a/addons/twitcher/generated/twitch_extension.gd b/addons/twitcher/generated/twitch_extension.gd new file mode 100644 index 0000000..7c0aea7 --- /dev/null +++ b/addons/twitcher/generated/twitch_extension.gd @@ -0,0 +1,538 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/Extension +class_name TwitchExtension + +## The name of the user or organization that owns the extension. +@export var author_name: String: + set(val): + author_name = val + track_data(&"author_name", val) + +## A Boolean value that determines whether the extension has features that use Bits. Is **true** if the extension has features that use Bits. +@export var bits_enabled: bool: + set(val): + bits_enabled = val + track_data(&"bits_enabled", val) + +## A Boolean value that determines whether a user can install the extension on their channel. Is **true** if a user can install the extension. +## +## Typically, this is set to **false** if the extension is currently in testing mode and requires users to be allowlisted (the allowlist is configured on Twitch’s [developer site](https://dev.twitch.tv/console/extensions) under the **Extensions** \-> **Extension** \-> **Version** \-> **Access**). +@export var can_install: bool: + set(val): + can_install = val + track_data(&"can_install", val) + +## The location of where the extension’s configuration is stored. Possible values are: +## +## * hosted — The Extensions Configuration Service hosts the configuration. +## * custom — The Extension Backend Service (EBS) hosts the configuration. +## * none — The extension doesn't require configuration. +@export var configuration_location: String: + set(val): + configuration_location = val + track_data(&"configuration_location", val) + +## A longer description of the extension. It appears on the details page. +@export var description: String: + set(val): + description = val + track_data(&"description", val) + +## A URL to the extension’s Terms of Service. +@export var eula_tos_url: String: + set(val): + eula_tos_url = val + track_data(&"eula_tos_url", val) + +## A Boolean value that determines whether the extension can communicate with the installed channel’s chat. Is **true** if the extension can communicate with the channel’s chat room. +@export var has_chat_support: bool: + set(val): + has_chat_support = val + track_data(&"has_chat_support", val) + +## A URL to the default icon that’s displayed in the Extensions directory. +@export var icon_url: String: + set(val): + icon_url = val + track_data(&"icon_url", val) + +## +@export var icon_urls: TwitchExtensionIconUrls: + set(val): + icon_urls = val + track_data(&"icon_urls", val) + +## The extension’s ID. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The extension’s name. +@export var name: String: + set(val): + name = val + track_data(&"name", val) + +## A URL to the extension’s privacy policy. +@export var privacy_policy_url: String: + set(val): + privacy_policy_url = val + track_data(&"privacy_policy_url", val) + +## A Boolean value that determines whether the extension wants to explicitly ask viewers to link their Twitch identity. +@export var request_identity_link: bool: + set(val): + request_identity_link = val + track_data(&"request_identity_link", val) + +## A list of URLs to screenshots that are shown in the Extensions marketplace. +@export var screenshot_urls: Array[String]: + set(val): + screenshot_urls = val + track_data(&"screenshot_urls", val) + +## The extension’s state. Possible values are: +## +## * Approved +## * AssetsUploaded +## * Deleted +## * Deprecated +## * InReview +## * InTest +## * PendingAction +## * Rejected +## * Released +@export var state: String: + set(val): + state = val + track_data(&"state", val) + +## Indicates whether the extension can view the user’s subscription level on the channel that the extension is installed on. Possible values are: +## +## * none — The extension can't view the user’s subscription level. +## * optional — The extension can view the user’s subscription level. +@export var subscriptions_support_level: String: + set(val): + subscriptions_support_level = val + track_data(&"subscriptions_support_level", val) + +## A short description of the extension that streamers see when hovering over the discovery splash screen in the Extensions manager. +@export var summary: String: + set(val): + summary = val + track_data(&"summary", val) + +## The email address that users use to get support for the extension. +@export var support_email: String: + set(val): + support_email = val + track_data(&"support_email", val) + +## The extension’s version number. +@export var version: String: + set(val): + version = val + track_data(&"version", val) + +## A brief description displayed on the channel to explain how the extension works. +@export var viewer_summary: String: + set(val): + viewer_summary = val + track_data(&"viewer_summary", val) + +## Describes all views-related information such as how the extension is displayed on mobile devices. +@export var views: Views: + set(val): + views = val + track_data(&"views", val) + +## Allowlisted configuration URLs for displaying the extension (the allowlist is configured on Twitch’s [developer site](https://dev.twitch.tv/console/extensions) under the **Extensions** \-> **Extension** \-> **Version** \-> **Capabilities**). +@export var allowlisted_config_urls: Array[String]: + set(val): + allowlisted_config_urls = val + track_data(&"allowlisted_config_urls", val) + +## Allowlisted panel URLs for displaying the extension (the allowlist is configured on Twitch’s [developer site](https://dev.twitch.tv/console/extensions) under the **Extensions** \-> **Extension** \-> **Version** \-> **Capabilities**). +@export var allowlisted_panel_urls: Array[String]: + set(val): + allowlisted_panel_urls = val + track_data(&"allowlisted_panel_urls", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_author_name: String, _bits_enabled: bool, _can_install: bool, _configuration_location: String, _description: String, _eula_tos_url: String, _has_chat_support: bool, _icon_url: String, _icon_urls: TwitchExtensionIconUrls, _id: String, _name: String, _privacy_policy_url: String, _request_identity_link: bool, _screenshot_urls: Array[String], _state: String, _subscriptions_support_level: String, _summary: String, _support_email: String, _version: String, _viewer_summary: String, _views: Views, _allowlisted_config_urls: Array[String], _allowlisted_panel_urls: Array[String]) -> TwitchExtension: + var twitch_extension: TwitchExtension = TwitchExtension.new() + twitch_extension.author_name = _author_name + twitch_extension.bits_enabled = _bits_enabled + twitch_extension.can_install = _can_install + twitch_extension.configuration_location = _configuration_location + twitch_extension.description = _description + twitch_extension.eula_tos_url = _eula_tos_url + twitch_extension.has_chat_support = _has_chat_support + twitch_extension.icon_url = _icon_url + twitch_extension.icon_urls = _icon_urls + twitch_extension.id = _id + twitch_extension.name = _name + twitch_extension.privacy_policy_url = _privacy_policy_url + twitch_extension.request_identity_link = _request_identity_link + twitch_extension.screenshot_urls = _screenshot_urls + twitch_extension.state = _state + twitch_extension.subscriptions_support_level = _subscriptions_support_level + twitch_extension.summary = _summary + twitch_extension.support_email = _support_email + twitch_extension.version = _version + twitch_extension.viewer_summary = _viewer_summary + twitch_extension.views = _views + twitch_extension.allowlisted_config_urls = _allowlisted_config_urls + twitch_extension.allowlisted_panel_urls = _allowlisted_panel_urls + return twitch_extension + + +static func from_json(d: Dictionary) -> TwitchExtension: + var result: TwitchExtension = TwitchExtension.new() + if d.get("author_name", null) != null: + result.author_name = d["author_name"] + if d.get("bits_enabled", null) != null: + result.bits_enabled = d["bits_enabled"] + if d.get("can_install", null) != null: + result.can_install = d["can_install"] + if d.get("configuration_location", null) != null: + result.configuration_location = d["configuration_location"] + if d.get("description", null) != null: + result.description = d["description"] + if d.get("eula_tos_url", null) != null: + result.eula_tos_url = d["eula_tos_url"] + if d.get("has_chat_support", null) != null: + result.has_chat_support = d["has_chat_support"] + if d.get("icon_url", null) != null: + result.icon_url = d["icon_url"] + if d.get("icon_urls", null) != null: + result.icon_urls = TwitchExtensionIconUrls.from_json(d["icon_urls"]) + if d.get("id", null) != null: + result.id = d["id"] + if d.get("name", null) != null: + result.name = d["name"] + if d.get("privacy_policy_url", null) != null: + result.privacy_policy_url = d["privacy_policy_url"] + if d.get("request_identity_link", null) != null: + result.request_identity_link = d["request_identity_link"] + if d.get("screenshot_urls", null) != null: + for value in d["screenshot_urls"]: + result.screenshot_urls.append(value) + if d.get("state", null) != null: + result.state = d["state"] + if d.get("subscriptions_support_level", null) != null: + result.subscriptions_support_level = d["subscriptions_support_level"] + if d.get("summary", null) != null: + result.summary = d["summary"] + if d.get("support_email", null) != null: + result.support_email = d["support_email"] + if d.get("version", null) != null: + result.version = d["version"] + if d.get("viewer_summary", null) != null: + result.viewer_summary = d["viewer_summary"] + if d.get("views", null) != null: + result.views = Views.from_json(d["views"]) + if d.get("allowlisted_config_urls", null) != null: + for value in d["allowlisted_config_urls"]: + result.allowlisted_config_urls.append(value) + if d.get("allowlisted_panel_urls", null) != null: + for value in d["allowlisted_panel_urls"]: + result.allowlisted_panel_urls.append(value) + return result + + + +## Describes all views-related information such as how the extension is displayed on mobile devices. +## #/components/schemas/Extension/Views +class Views extends TwitchData: + + ## Describes how the extension is displayed on mobile devices. + @export var mobile: Mobile: + set(val): + mobile = val + track_data(&"mobile", val) + + ## Describes how the extension is rendered if the extension may be activated as a panel extension. + @export var panel: TwitchPanel: + set(val): + panel = val + track_data(&"panel", val) + + ## Describes how the extension is rendered if the extension may be activated as a video-overlay extension. + @export var video_overlay: VideoOverlay: + set(val): + video_overlay = val + track_data(&"video_overlay", val) + + ## Describes how the extension is rendered if the extension may be activated as a video-component extension. + @export var component: Component: + set(val): + component = val + track_data(&"component", val) + + ## Describes the view that is shown to broadcasters while they are configuring your extension within the Extension Manager. + @export var config: Config: + set(val): + config = val + track_data(&"config", val) + + + + ## Constructor with all required fields. + static func create(_mobile: Mobile, _panel: TwitchPanel, _video_overlay: VideoOverlay, _component: Component, _config: Config) -> Views: + var views: Views = Views.new() + views.mobile = _mobile + views.panel = _panel + views.video_overlay = _video_overlay + views.component = _component + views.config = _config + return views + + + static func from_json(d: Dictionary) -> Views: + var result: Views = Views.new() + if d.get("mobile", null) != null: + result.mobile = Mobile.from_json(d["mobile"]) + if d.get("panel", null) != null: + result.panel = TwitchPanel.from_json(d["panel"]) + if d.get("video_overlay", null) != null: + result.video_overlay = VideoOverlay.from_json(d["video_overlay"]) + if d.get("component", null) != null: + result.component = Component.from_json(d["component"]) + if d.get("config", null) != null: + result.config = Config.from_json(d["config"]) + return result + + + +## Describes how the extension is displayed on mobile devices. +## #/components/schemas/Extension/Views/Mobile +class Mobile extends TwitchData: + + ## The HTML file that is shown to viewers on mobile devices. This page is presented to viewers as a panel behind the chat area of the mobile app. + @export var viewer_url: String: + set(val): + viewer_url = val + track_data(&"viewer_url", val) + + + + ## Constructor with all required fields. + static func create(_viewer_url: String) -> Mobile: + var mobile: Mobile = Mobile.new() + mobile.viewer_url = _viewer_url + return mobile + + + static func from_json(d: Dictionary) -> Mobile: + var result: Mobile = Mobile.new() + if d.get("viewer_url", null) != null: + result.viewer_url = d["viewer_url"] + return result + + + +## Describes how the extension is rendered if the extension may be activated as a panel extension. +## #/components/schemas/Extension/Views/Panel +class TwitchPanel extends TwitchData: + + ## The HTML file that is shown to viewers on the channel page when the extension is activated in a Panel slot. + @export var viewer_url: String: + set(val): + viewer_url = val + track_data(&"viewer_url", val) + + ## The height, in pixels, of the panel component that the extension is rendered in. + @export var height: int: + set(val): + height = val + track_data(&"height", val) + + ## A Boolean value that determines whether the extension can link to non-Twitch domains. + @export var can_link_external_content: bool: + set(val): + can_link_external_content = val + track_data(&"can_link_external_content", val) + + + + ## Constructor with all required fields. + static func create(_viewer_url: String, _height: int, _can_link_external_content: bool) -> TwitchPanel: + var twitch_panel: TwitchPanel = TwitchPanel.new() + twitch_panel.viewer_url = _viewer_url + twitch_panel.height = _height + twitch_panel.can_link_external_content = _can_link_external_content + return twitch_panel + + + static func from_json(d: Dictionary) -> TwitchPanel: + var result: TwitchPanel = TwitchPanel.new() + if d.get("viewer_url", null) != null: + result.viewer_url = d["viewer_url"] + if d.get("height", null) != null: + result.height = d["height"] + if d.get("can_link_external_content", null) != null: + result.can_link_external_content = d["can_link_external_content"] + return result + + + +## Describes how the extension is rendered if the extension may be activated as a video-overlay extension. +## #/components/schemas/Extension/Views/VideoOverlay +class VideoOverlay extends TwitchData: + + ## The HTML file that is shown to viewers on the channel page when the extension is activated on the Video - Overlay slot. + @export var viewer_url: String: + set(val): + viewer_url = val + track_data(&"viewer_url", val) + + ## A Boolean value that determines whether the extension can link to non-Twitch domains. + @export var can_link_external_content: bool: + set(val): + can_link_external_content = val + track_data(&"can_link_external_content", val) + + + + ## Constructor with all required fields. + static func create(_viewer_url: String, _can_link_external_content: bool) -> VideoOverlay: + var video_overlay: VideoOverlay = VideoOverlay.new() + video_overlay.viewer_url = _viewer_url + video_overlay.can_link_external_content = _can_link_external_content + return video_overlay + + + static func from_json(d: Dictionary) -> VideoOverlay: + var result: VideoOverlay = VideoOverlay.new() + if d.get("viewer_url", null) != null: + result.viewer_url = d["viewer_url"] + if d.get("can_link_external_content", null) != null: + result.can_link_external_content = d["can_link_external_content"] + return result + + + +## Describes how the extension is rendered if the extension may be activated as a video-component extension. +## #/components/schemas/Extension/Views/Component +class Component extends TwitchData: + + ## The HTML file that is shown to viewers on the channel page when the extension is activated in a Video - Component slot. + @export var viewer_url: String: + set(val): + viewer_url = val + track_data(&"viewer_url", val) + + ## The width value of the ratio (width : height) which determines the extension’s width, and how the extension’s iframe will resize in different video player environments. + @export var aspect_ratio_x: int: + set(val): + aspect_ratio_x = val + track_data(&"aspect_ratio_x", val) + + ## The height value of the ratio (width : height) which determines the extension’s height, and how the extension’s iframe will resize in different video player environments. + @export var aspect_ratio_y: int: + set(val): + aspect_ratio_y = val + track_data(&"aspect_ratio_y", val) + + ## A Boolean value that determines whether to apply CSS zoom. If **true**, a CSS zoom is applied such that the size of the extension is variable but the inner dimensions are fixed based on Scale Pixels. This allows your extension to render as if it is of fixed width and height. If **false**, the inner dimensions of the extension iframe are variable, meaning your extension must implement responsiveness. + @export var autoscale: bool: + set(val): + autoscale = val + track_data(&"autoscale", val) + + ## The base width, in pixels, of the extension to use when scaling (see `autoscale`). This value is ignored if `autoscale` is **false**. + @export var scale_pixels: int: + set(val): + scale_pixels = val + track_data(&"scale_pixels", val) + + ## The height as a percent of the maximum height of a video component extension. Values are between 1% - 100%. + @export var target_height: int: + set(val): + target_height = val + track_data(&"target_height", val) + + ## A Boolean value that determines whether the extension can link to non-Twitch domains. + @export var can_link_external_content: bool: + set(val): + can_link_external_content = val + track_data(&"can_link_external_content", val) + + + + ## Constructor with all required fields. + static func create(_viewer_url: String, _aspect_ratio_x: int, _aspect_ratio_y: int, _autoscale: bool, _scale_pixels: int, _target_height: int, _can_link_external_content: bool) -> Component: + var component: Component = Component.new() + component.viewer_url = _viewer_url + component.aspect_ratio_x = _aspect_ratio_x + component.aspect_ratio_y = _aspect_ratio_y + component.autoscale = _autoscale + component.scale_pixels = _scale_pixels + component.target_height = _target_height + component.can_link_external_content = _can_link_external_content + return component + + + static func from_json(d: Dictionary) -> Component: + var result: Component = Component.new() + if d.get("viewer_url", null) != null: + result.viewer_url = d["viewer_url"] + if d.get("aspect_ratio_x", null) != null: + result.aspect_ratio_x = d["aspect_ratio_x"] + if d.get("aspect_ratio_y", null) != null: + result.aspect_ratio_y = d["aspect_ratio_y"] + if d.get("autoscale", null) != null: + result.autoscale = d["autoscale"] + if d.get("scale_pixels", null) != null: + result.scale_pixels = d["scale_pixels"] + if d.get("target_height", null) != null: + result.target_height = d["target_height"] + if d.get("can_link_external_content", null) != null: + result.can_link_external_content = d["can_link_external_content"] + return result + + + +## Describes the view that is shown to broadcasters while they are configuring your extension within the Extension Manager. +## #/components/schemas/Extension/Views/Config +class Config extends TwitchData: + + ## The HTML file shown to broadcasters while they are configuring your extension within the Extension Manager. + @export var viewer_url: String: + set(val): + viewer_url = val + track_data(&"viewer_url", val) + + ## A Boolean value that determines whether the extension can link to non-Twitch domains. + @export var can_link_external_content: bool: + set(val): + can_link_external_content = val + track_data(&"can_link_external_content", val) + + + + ## Constructor with all required fields. + static func create(_viewer_url: String, _can_link_external_content: bool) -> Config: + var config: Config = Config.new() + config.viewer_url = _viewer_url + config.can_link_external_content = _can_link_external_content + return config + + + static func from_json(d: Dictionary) -> Config: + var result: Config = Config.new() + if d.get("viewer_url", null) != null: + result.viewer_url = d["viewer_url"] + if d.get("can_link_external_content", null) != null: + result.can_link_external_content = d["can_link_external_content"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_extension.gd.uid b/addons/twitcher/generated/twitch_extension.gd.uid new file mode 100644 index 0000000..b2abf73 --- /dev/null +++ b/addons/twitcher/generated/twitch_extension.gd.uid @@ -0,0 +1 @@ +uid://djhrkne5pduls diff --git a/addons/twitcher/generated/twitch_extension_analytics.gd b/addons/twitcher/generated/twitch_extension_analytics.gd new file mode 100644 index 0000000..c41992d --- /dev/null +++ b/addons/twitcher/generated/twitch_extension_analytics.gd @@ -0,0 +1,93 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/ExtensionAnalytics +class_name TwitchExtensionAnalytics + +## An ID that identifies the extension that the report was generated for. +@export var extension_id: String: + set(val): + extension_id = val + track_data(&"extension_id", val) + +## The URL that you use to download the report. The URL is valid for 5 minutes. +@export var URL: String: + set(val): + URL = val + track_data(&"URL", val) + +## The type of report. +@export var type: String: + set(val): + type = val + track_data(&"type", val) + +## The reporting window’s start and end dates, in RFC3339 format. +@export var date_range: DateRange: + set(val): + date_range = val + track_data(&"date_range", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_extension_id: String, _URL: String, _type: String, _date_range: DateRange) -> TwitchExtensionAnalytics: + var twitch_extension_analytics: TwitchExtensionAnalytics = TwitchExtensionAnalytics.new() + twitch_extension_analytics.extension_id = _extension_id + twitch_extension_analytics.URL = _URL + twitch_extension_analytics.type = _type + twitch_extension_analytics.date_range = _date_range + return twitch_extension_analytics + + +static func from_json(d: Dictionary) -> TwitchExtensionAnalytics: + var result: TwitchExtensionAnalytics = TwitchExtensionAnalytics.new() + if d.get("extension_id", null) != null: + result.extension_id = d["extension_id"] + if d.get("URL", null) != null: + result.URL = d["URL"] + if d.get("type", null) != null: + result.type = d["type"] + if d.get("date_range", null) != null: + result.date_range = DateRange.from_json(d["date_range"]) + return result + + + +## The reporting window’s start and end dates, in RFC3339 format. +## #/components/schemas/ExtensionAnalytics/DateRange +class DateRange extends TwitchData: + + ## The reporting window’s start date. + @export var started_at: String: + set(val): + started_at = val + track_data(&"started_at", val) + + ## The reporting window’s end date. + @export var ended_at: String: + set(val): + ended_at = val + track_data(&"ended_at", val) + + + + ## Constructor with all required fields. + static func create(_started_at: String, _ended_at: String) -> DateRange: + var date_range: DateRange = DateRange.new() + date_range.started_at = _started_at + date_range.ended_at = _ended_at + return date_range + + + static func from_json(d: Dictionary) -> DateRange: + var result: DateRange = DateRange.new() + if d.get("started_at", null) != null: + result.started_at = d["started_at"] + if d.get("ended_at", null) != null: + result.ended_at = d["ended_at"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_extension_analytics.gd.uid b/addons/twitcher/generated/twitch_extension_analytics.gd.uid new file mode 100644 index 0000000..44838a7 --- /dev/null +++ b/addons/twitcher/generated/twitch_extension_analytics.gd.uid @@ -0,0 +1 @@ +uid://dqmnnsrlinxyu diff --git a/addons/twitcher/generated/twitch_extension_bits_product.gd b/addons/twitcher/generated/twitch_extension_bits_product.gd new file mode 100644 index 0000000..c653052 --- /dev/null +++ b/addons/twitcher/generated/twitch_extension_bits_product.gd @@ -0,0 +1,113 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/ExtensionBitsProduct +class_name TwitchExtensionBitsProduct + +## The product's SKU. The SKU is unique across an extension's products. +@export var sku: String: + set(val): + sku = val + track_data(&"sku", val) + +## An object that contains the product's cost information. +@export var cost: Cost: + set(val): + cost = val + track_data(&"cost", val) + +## A Boolean value that indicates whether the product is in development. If **true**, the product is not available for public use. +@export var in_development: bool: + set(val): + in_development = val + track_data(&"in_development", val) + +## The product's name as displayed in the extension. +@export var display_name: String: + set(val): + display_name = val + track_data(&"display_name", val) + +## The date and time, in RFC3339 format, when the product expires. +@export var expiration: String: + set(val): + expiration = val + track_data(&"expiration", val) + +## A Boolean value that determines whether Bits product purchase events are broadcast to all instances of an extension on a channel. The events are broadcast via the `onTransactionComplete` helper callback. Is **true** if the event is broadcast to all instances. +@export var is_broadcast: bool: + set(val): + is_broadcast = val + track_data(&"is_broadcast", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_sku: String, _cost: Cost, _in_development: bool, _display_name: String, _expiration: String, _is_broadcast: bool) -> TwitchExtensionBitsProduct: + var twitch_extension_bits_product: TwitchExtensionBitsProduct = TwitchExtensionBitsProduct.new() + twitch_extension_bits_product.sku = _sku + twitch_extension_bits_product.cost = _cost + twitch_extension_bits_product.in_development = _in_development + twitch_extension_bits_product.display_name = _display_name + twitch_extension_bits_product.expiration = _expiration + twitch_extension_bits_product.is_broadcast = _is_broadcast + return twitch_extension_bits_product + + +static func from_json(d: Dictionary) -> TwitchExtensionBitsProduct: + var result: TwitchExtensionBitsProduct = TwitchExtensionBitsProduct.new() + if d.get("sku", null) != null: + result.sku = d["sku"] + if d.get("cost", null) != null: + result.cost = Cost.from_json(d["cost"]) + if d.get("in_development", null) != null: + result.in_development = d["in_development"] + if d.get("display_name", null) != null: + result.display_name = d["display_name"] + if d.get("expiration", null) != null: + result.expiration = d["expiration"] + if d.get("is_broadcast", null) != null: + result.is_broadcast = d["is_broadcast"] + return result + + + +## An object that contains the product's cost information. +## #/components/schemas/ExtensionBitsProduct/Cost +class Cost extends TwitchData: + + ## The product's price. + @export var amount: int: + set(val): + amount = val + track_data(&"amount", val) + + ## The type of currency. Possible values are: + ## + ## * bits + @export var type: String: + set(val): + type = val + track_data(&"type", val) + + + + ## Constructor with all required fields. + static func create(_amount: int, _type: String) -> Cost: + var cost: Cost = Cost.new() + cost.amount = _amount + cost.type = _type + return cost + + + static func from_json(d: Dictionary) -> Cost: + var result: Cost = Cost.new() + if d.get("amount", null) != null: + result.amount = d["amount"] + if d.get("type", null) != null: + result.type = d["type"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_extension_bits_product.gd.uid b/addons/twitcher/generated/twitch_extension_bits_product.gd.uid new file mode 100644 index 0000000..bb1d76f --- /dev/null +++ b/addons/twitcher/generated/twitch_extension_bits_product.gd.uid @@ -0,0 +1 @@ +uid://bagxroa6i57mf diff --git a/addons/twitcher/generated/twitch_extension_configuration_segment.gd b/addons/twitcher/generated/twitch_extension_configuration_segment.gd new file mode 100644 index 0000000..54828e7 --- /dev/null +++ b/addons/twitcher/generated/twitch_extension_configuration_segment.gd @@ -0,0 +1,59 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/ExtensionConfigurationSegment +class_name TwitchExtensionConfigurationSegment + +## The type of segment. Possible values are: +## +## * broadcaster +## * developer +## * global +@export var segment: String: + set(val): + segment = val + track_data(&"segment", val) + +## The ID of the broadcaster that installed the extension. The object includes this field only if the `segment` query parameter is set to developer or broadcaster. +@export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + +## The contents of the segment. This string may be a plain-text string or a string-encoded JSON object. +@export var content: String: + set(val): + content = val + track_data(&"content", val) + +## The version number that identifies this definition of the segment’s data. +@export var version: String: + set(val): + version = val + track_data(&"version", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_segment: String, _content: String, _version: String) -> TwitchExtensionConfigurationSegment: + var twitch_extension_configuration_segment: TwitchExtensionConfigurationSegment = TwitchExtensionConfigurationSegment.new() + twitch_extension_configuration_segment.segment = _segment + twitch_extension_configuration_segment.content = _content + twitch_extension_configuration_segment.version = _version + return twitch_extension_configuration_segment + + +static func from_json(d: Dictionary) -> TwitchExtensionConfigurationSegment: + var result: TwitchExtensionConfigurationSegment = TwitchExtensionConfigurationSegment.new() + if d.get("segment", null) != null: + result.segment = d["segment"] + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("content", null) != null: + result.content = d["content"] + if d.get("version", null) != null: + result.version = d["version"] + return result diff --git a/addons/twitcher/generated/twitch_extension_configuration_segment.gd.uid b/addons/twitcher/generated/twitch_extension_configuration_segment.gd.uid new file mode 100644 index 0000000..5e503ce --- /dev/null +++ b/addons/twitcher/generated/twitch_extension_configuration_segment.gd.uid @@ -0,0 +1 @@ +uid://kd31s5uklh71 diff --git a/addons/twitcher/generated/twitch_extension_icon_urls.gd b/addons/twitcher/generated/twitch_extension_icon_urls.gd new file mode 100644 index 0000000..330743f --- /dev/null +++ b/addons/twitcher/generated/twitch_extension_icon_urls.gd @@ -0,0 +1,44 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/ExtensionIconUrls +class_name TwitchExtensionIconUrls + +## +@export var _100x100: String: + set(val): + _100x100 = val + track_data(&"_100x100", val) + +## +@export var _24x24: String: + set(val): + _24x24 = val + track_data(&"_24x24", val) + +## +@export var _300x200: String: + set(val): + _300x200 = val + track_data(&"_300x200", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create() -> TwitchExtensionIconUrls: + var twitch_extension_icon_urls: TwitchExtensionIconUrls = TwitchExtensionIconUrls.new() + return twitch_extension_icon_urls + + +static func from_json(d: Dictionary) -> TwitchExtensionIconUrls: + var result: TwitchExtensionIconUrls = TwitchExtensionIconUrls.new() + if d.get("_100x100", null) != null: + result._100x100 = d["_100x100"] + if d.get("_24x24", null) != null: + result._24x24 = d["_24x24"] + if d.get("_300x200", null) != null: + result._300x200 = d["_300x200"] + return result diff --git a/addons/twitcher/generated/twitch_extension_icon_urls.gd.uid b/addons/twitcher/generated/twitch_extension_icon_urls.gd.uid new file mode 100644 index 0000000..1cda716 --- /dev/null +++ b/addons/twitcher/generated/twitch_extension_icon_urls.gd.uid @@ -0,0 +1 @@ +uid://cmoojllshgvh0 diff --git a/addons/twitcher/generated/twitch_extension_live_channel.gd b/addons/twitcher/generated/twitch_extension_live_channel.gd new file mode 100644 index 0000000..8ab57f2 --- /dev/null +++ b/addons/twitcher/generated/twitch_extension_live_channel.gd @@ -0,0 +1,65 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/ExtensionLiveChannel +class_name TwitchExtensionLiveChannel + +## The ID of the broadcaster that is streaming live and has installed or activated the extension. +@export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + +## The broadcaster’s display name. +@export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + +## The name of the category or game being streamed. +@export var game_name: String: + set(val): + game_name = val + track_data(&"game_name", val) + +## The ID of the category or game being streamed. +@export var game_id: String: + set(val): + game_id = val + track_data(&"game_id", val) + +## The title of the broadcaster’s stream. May be an empty string if not specified. +@export var title: String: + set(val): + title = val + track_data(&"title", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_broadcaster_id: String, _broadcaster_name: String, _game_name: String, _game_id: String, _title: String) -> TwitchExtensionLiveChannel: + var twitch_extension_live_channel: TwitchExtensionLiveChannel = TwitchExtensionLiveChannel.new() + twitch_extension_live_channel.broadcaster_id = _broadcaster_id + twitch_extension_live_channel.broadcaster_name = _broadcaster_name + twitch_extension_live_channel.game_name = _game_name + twitch_extension_live_channel.game_id = _game_id + twitch_extension_live_channel.title = _title + return twitch_extension_live_channel + + +static func from_json(d: Dictionary) -> TwitchExtensionLiveChannel: + var result: TwitchExtensionLiveChannel = TwitchExtensionLiveChannel.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + if d.get("game_name", null) != null: + result.game_name = d["game_name"] + if d.get("game_id", null) != null: + result.game_id = d["game_id"] + if d.get("title", null) != null: + result.title = d["title"] + return result diff --git a/addons/twitcher/generated/twitch_extension_live_channel.gd.uid b/addons/twitcher/generated/twitch_extension_live_channel.gd.uid new file mode 100644 index 0000000..96d1157 --- /dev/null +++ b/addons/twitcher/generated/twitch_extension_live_channel.gd.uid @@ -0,0 +1 @@ +uid://cvmneq8w38gjn diff --git a/addons/twitcher/generated/twitch_extension_secret.gd b/addons/twitcher/generated/twitch_extension_secret.gd new file mode 100644 index 0000000..ad860f7 --- /dev/null +++ b/addons/twitcher/generated/twitch_extension_secret.gd @@ -0,0 +1,85 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/ExtensionSecret +class_name TwitchExtensionSecret + +## The version number that identifies this definition of the secret’s data. +@export var format_version: int: + set(val): + format_version = val + track_data(&"format_version", val) + +## The list of secrets. +@export var secrets: Array[Secrets]: + set(val): + secrets = val + track_data(&"secrets", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_format_version: int, _secrets: Array[Secrets]) -> TwitchExtensionSecret: + var twitch_extension_secret: TwitchExtensionSecret = TwitchExtensionSecret.new() + twitch_extension_secret.format_version = _format_version + twitch_extension_secret.secrets = _secrets + return twitch_extension_secret + + +static func from_json(d: Dictionary) -> TwitchExtensionSecret: + var result: TwitchExtensionSecret = TwitchExtensionSecret.new() + if d.get("format_version", null) != null: + result.format_version = d["format_version"] + if d.get("secrets", null) != null: + for value in d["secrets"]: + result.secrets.append(Secrets.from_json(value)) + return result + + + +## The list of secrets. +## #/components/schemas/ExtensionSecret/Secrets +class Secrets extends TwitchData: + + ## The raw secret that you use with JWT encoding. + @export var content: String: + set(val): + content = val + track_data(&"content", val) + + ## The UTC date and time (in RFC3339 format) that you may begin using this secret to sign a JWT. + @export var active_at: String: + set(val): + active_at = val + track_data(&"active_at", val) + + ## The UTC date and time (in RFC3339 format) that you must stop using this secret to decode a JWT. + @export var expires_at: String: + set(val): + expires_at = val + track_data(&"expires_at", val) + + + + ## Constructor with all required fields. + static func create(_content: String, _active_at: String, _expires_at: String) -> Secrets: + var secrets: Secrets = Secrets.new() + secrets.content = _content + secrets.active_at = _active_at + secrets.expires_at = _expires_at + return secrets + + + static func from_json(d: Dictionary) -> Secrets: + var result: Secrets = Secrets.new() + if d.get("content", null) != null: + result.content = d["content"] + if d.get("active_at", null) != null: + result.active_at = d["active_at"] + if d.get("expires_at", null) != null: + result.expires_at = d["expires_at"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_extension_secret.gd.uid b/addons/twitcher/generated/twitch_extension_secret.gd.uid new file mode 100644 index 0000000..68aa3b8 --- /dev/null +++ b/addons/twitcher/generated/twitch_extension_secret.gd.uid @@ -0,0 +1 @@ +uid://eqe680mdiuyy diff --git a/addons/twitcher/generated/twitch_extension_transaction.gd b/addons/twitcher/generated/twitch_extension_transaction.gd new file mode 100644 index 0000000..5db64ae --- /dev/null +++ b/addons/twitcher/generated/twitch_extension_transaction.gd @@ -0,0 +1,232 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/ExtensionTransaction +class_name TwitchExtensionTransaction + +## An ID that identifies the transaction. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The UTC date and time (in RFC3339 format) of the transaction. +@export var timestamp: String: + set(val): + timestamp = val + track_data(&"timestamp", val) + +## The ID of the broadcaster that owns the channel where the transaction occurred. +@export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + +## The broadcaster’s login name. +@export var broadcaster_login: String: + set(val): + broadcaster_login = val + track_data(&"broadcaster_login", val) + +## The broadcaster’s display name. +@export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + +## The ID of the user that purchased the digital product. +@export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + +## The user’s login name. +@export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) + +## The user’s display name. +@export var user_name: String: + set(val): + user_name = val + track_data(&"user_name", val) + +## The type of transaction. Possible values are: +## +## * BITS\_IN\_EXTENSION +@export var product_type: String: + set(val): + product_type = val + track_data(&"product_type", val) + +## Contains details about the digital product. +@export var product_data: ProductData: + set(val): + product_data = val + track_data(&"product_data", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _timestamp: String, _broadcaster_id: String, _broadcaster_login: String, _broadcaster_name: String, _user_id: String, _user_login: String, _user_name: String, _product_type: String, _product_data: ProductData) -> TwitchExtensionTransaction: + var twitch_extension_transaction: TwitchExtensionTransaction = TwitchExtensionTransaction.new() + twitch_extension_transaction.id = _id + twitch_extension_transaction.timestamp = _timestamp + twitch_extension_transaction.broadcaster_id = _broadcaster_id + twitch_extension_transaction.broadcaster_login = _broadcaster_login + twitch_extension_transaction.broadcaster_name = _broadcaster_name + twitch_extension_transaction.user_id = _user_id + twitch_extension_transaction.user_login = _user_login + twitch_extension_transaction.user_name = _user_name + twitch_extension_transaction.product_type = _product_type + twitch_extension_transaction.product_data = _product_data + return twitch_extension_transaction + + +static func from_json(d: Dictionary) -> TwitchExtensionTransaction: + var result: TwitchExtensionTransaction = TwitchExtensionTransaction.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("timestamp", null) != null: + result.timestamp = d["timestamp"] + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_login", null) != null: + result.broadcaster_login = d["broadcaster_login"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + if d.get("user_name", null) != null: + result.user_name = d["user_name"] + if d.get("product_type", null) != null: + result.product_type = d["product_type"] + if d.get("product_data", null) != null: + result.product_data = ProductData.from_json(d["product_data"]) + return result + + + +## Contains details about the digital product. +## #/components/schemas/ExtensionTransaction/ProductData +class ProductData extends TwitchData: + + ## An ID that identifies the digital product. + @export var sku: String: + set(val): + sku = val + track_data(&"sku", val) + + ## Set to `twitch.ext.` \+ ``. + @export var domain: String: + set(val): + domain = val + track_data(&"domain", val) + + ## Contains details about the digital product’s cost. + @export var cost: Cost: + set(val): + cost = val + track_data(&"cost", val) + + ## A Boolean value that determines whether the product is in development. Is **true** if the digital product is in development and cannot be exchanged. + @export var inDevelopment: bool: + set(val): + inDevelopment = val + track_data(&"inDevelopment", val) + + ## The name of the digital product. + @export var displayName: String: + set(val): + displayName = val + track_data(&"displayName", val) + + ## This field is always empty since you may purchase only unexpired products. + @export var expiration: String: + set(val): + expiration = val + track_data(&"expiration", val) + + ## A Boolean value that determines whether the data was broadcast to all instances of the extension. Is **true** if the data was broadcast to all instances. + @export var broadcast: bool: + set(val): + broadcast = val + track_data(&"broadcast", val) + + + + ## Constructor with all required fields. + static func create(_sku: String, _domain: String, _cost: Cost, _inDevelopment: bool, _displayName: String, _expiration: String, _broadcast: bool) -> ProductData: + var product_data: ProductData = ProductData.new() + product_data.sku = _sku + product_data.domain = _domain + product_data.cost = _cost + product_data.inDevelopment = _inDevelopment + product_data.displayName = _displayName + product_data.expiration = _expiration + product_data.broadcast = _broadcast + return product_data + + + static func from_json(d: Dictionary) -> ProductData: + var result: ProductData = ProductData.new() + if d.get("sku", null) != null: + result.sku = d["sku"] + if d.get("domain", null) != null: + result.domain = d["domain"] + if d.get("cost", null) != null: + result.cost = Cost.from_json(d["cost"]) + if d.get("inDevelopment", null) != null: + result.inDevelopment = d["inDevelopment"] + if d.get("displayName", null) != null: + result.displayName = d["displayName"] + if d.get("expiration", null) != null: + result.expiration = d["expiration"] + if d.get("broadcast", null) != null: + result.broadcast = d["broadcast"] + return result + + + +## Contains details about the digital product’s cost. +## #/components/schemas/ExtensionTransaction/ProductData/Cost +class Cost extends TwitchData: + + ## The amount exchanged for the digital product. + @export var amount: int: + set(val): + amount = val + track_data(&"amount", val) + + ## The type of currency exchanged. Possible values are: + ## + ## * bits + @export var type: String: + set(val): + type = val + track_data(&"type", val) + + + + ## Constructor with all required fields. + static func create(_amount: int, _type: String) -> Cost: + var cost: Cost = Cost.new() + cost.amount = _amount + cost.type = _type + return cost + + + static func from_json(d: Dictionary) -> Cost: + var result: Cost = Cost.new() + if d.get("amount", null) != null: + result.amount = d["amount"] + if d.get("type", null) != null: + result.type = d["type"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_extension_transaction.gd.uid b/addons/twitcher/generated/twitch_extension_transaction.gd.uid new file mode 100644 index 0000000..500f316 --- /dev/null +++ b/addons/twitcher/generated/twitch_extension_transaction.gd.uid @@ -0,0 +1 @@ +uid://bq87rulgk036l diff --git a/addons/twitcher/generated/twitch_game.gd b/addons/twitcher/generated/twitch_game.gd new file mode 100644 index 0000000..2d09dd8 --- /dev/null +++ b/addons/twitcher/generated/twitch_game.gd @@ -0,0 +1,56 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/Game +class_name TwitchGame + +## An ID that identifies the category or game. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The category’s or game’s name. +@export var name: String: + set(val): + name = val + track_data(&"name", val) + +## A URL to the category’s or game’s box art. You must replace the `{width}x{height}` placeholder with the size of image you want. +@export var box_art_url: String: + set(val): + box_art_url = val + track_data(&"box_art_url", val) + +## The ID that [IGDB](https://www.igdb.com/) uses to identify this game. If the IGDB ID is not available to Twitch, this field is set to an empty string. +@export var igdb_id: String: + set(val): + igdb_id = val + track_data(&"igdb_id", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _name: String, _box_art_url: String, _igdb_id: String) -> TwitchGame: + var twitch_game: TwitchGame = TwitchGame.new() + twitch_game.id = _id + twitch_game.name = _name + twitch_game.box_art_url = _box_art_url + twitch_game.igdb_id = _igdb_id + return twitch_game + + +static func from_json(d: Dictionary) -> TwitchGame: + var result: TwitchGame = TwitchGame.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("name", null) != null: + result.name = d["name"] + if d.get("box_art_url", null) != null: + result.box_art_url = d["box_art_url"] + if d.get("igdb_id", null) != null: + result.igdb_id = d["igdb_id"] + return result diff --git a/addons/twitcher/generated/twitch_game.gd.uid b/addons/twitcher/generated/twitch_game.gd.uid new file mode 100644 index 0000000..4af3a39 --- /dev/null +++ b/addons/twitcher/generated/twitch_game.gd.uid @@ -0,0 +1 @@ +uid://dd12ryhhkmvss diff --git a/addons/twitcher/generated/twitch_game_analytics.gd b/addons/twitcher/generated/twitch_game_analytics.gd new file mode 100644 index 0000000..95cbee8 --- /dev/null +++ b/addons/twitcher/generated/twitch_game_analytics.gd @@ -0,0 +1,93 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/GameAnalytics +class_name TwitchGameAnalytics + +## An ID that identifies the game that the report was generated for. +@export var game_id: String: + set(val): + game_id = val + track_data(&"game_id", val) + +## The URL that you use to download the report. The URL is valid for 5 minutes. +@export var URL: String: + set(val): + URL = val + track_data(&"URL", val) + +## The type of report. +@export var type: String: + set(val): + type = val + track_data(&"type", val) + +## The reporting window’s start and end dates, in RFC3339 format. +@export var date_range: DateRange: + set(val): + date_range = val + track_data(&"date_range", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_game_id: String, _URL: String, _type: String, _date_range: DateRange) -> TwitchGameAnalytics: + var twitch_game_analytics: TwitchGameAnalytics = TwitchGameAnalytics.new() + twitch_game_analytics.game_id = _game_id + twitch_game_analytics.URL = _URL + twitch_game_analytics.type = _type + twitch_game_analytics.date_range = _date_range + return twitch_game_analytics + + +static func from_json(d: Dictionary) -> TwitchGameAnalytics: + var result: TwitchGameAnalytics = TwitchGameAnalytics.new() + if d.get("game_id", null) != null: + result.game_id = d["game_id"] + if d.get("URL", null) != null: + result.URL = d["URL"] + if d.get("type", null) != null: + result.type = d["type"] + if d.get("date_range", null) != null: + result.date_range = DateRange.from_json(d["date_range"]) + return result + + + +## The reporting window’s start and end dates, in RFC3339 format. +## #/components/schemas/GameAnalytics/DateRange +class DateRange extends TwitchData: + + ## The reporting window’s start date. + @export var started_at: String: + set(val): + started_at = val + track_data(&"started_at", val) + + ## The reporting window’s end date. + @export var ended_at: String: + set(val): + ended_at = val + track_data(&"ended_at", val) + + + + ## Constructor with all required fields. + static func create(_started_at: String, _ended_at: String) -> DateRange: + var date_range: DateRange = DateRange.new() + date_range.started_at = _started_at + date_range.ended_at = _ended_at + return date_range + + + static func from_json(d: Dictionary) -> DateRange: + var result: DateRange = DateRange.new() + if d.get("started_at", null) != null: + result.started_at = d["started_at"] + if d.get("ended_at", null) != null: + result.ended_at = d["ended_at"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_game_analytics.gd.uid b/addons/twitcher/generated/twitch_game_analytics.gd.uid new file mode 100644 index 0000000..5a4b5c8 --- /dev/null +++ b/addons/twitcher/generated/twitch_game_analytics.gd.uid @@ -0,0 +1 @@ +uid://bug7muidumlkf diff --git a/addons/twitcher/generated/twitch_get_ad_schedule.gd b/addons/twitcher/generated/twitch_get_ad_schedule.gd new file mode 100644 index 0000000..b3c154c --- /dev/null +++ b/addons/twitcher/generated/twitch_get_ad_schedule.gd @@ -0,0 +1,107 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetAdSchedule + + + +## +## #/components/schemas/GetAdScheduleResponse +class Response extends TwitchData: + + ## A list that contains information related to the channel’s ad schedule. + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + return result + + + +## A list that contains information related to the channel’s ad schedule. +## #/components/schemas/GetAdScheduleResponse/Data +class ResponseData extends TwitchData: + + ## The number of snoozes available for the broadcaster. + @export var snooze_count: int: + set(val): + snooze_count = val + track_data(&"snooze_count", val) + + ## The UTC timestamp when the broadcaster will gain an additional snooze, in RFC3339 format. + @export var snooze_refresh_at: String: + set(val): + snooze_refresh_at = val + track_data(&"snooze_refresh_at", val) + + ## The UTC timestamp of the broadcaster’s next scheduled ad, in RFC3339 format. Empty if the channel has no ad scheduled or is not live. + @export var next_ad_at: String: + set(val): + next_ad_at = val + track_data(&"next_ad_at", val) + + ## The length in seconds of the scheduled upcoming ad break. + @export var duration: int: + set(val): + duration = val + track_data(&"duration", val) + + ## The UTC timestamp of the broadcaster’s last ad-break, in RFC3339 format. Empty if the channel has not run an ad or is not live. + @export var last_ad_at: String: + set(val): + last_ad_at = val + track_data(&"last_ad_at", val) + + ## The amount of pre-roll free time remaining for the channel in seconds. Returns 0 if they are currently not pre-roll free. + @export var preroll_free_time: int: + set(val): + preroll_free_time = val + track_data(&"preroll_free_time", val) + + + + ## Constructor with all required fields. + static func create(_snooze_count: int, _snooze_refresh_at: String, _next_ad_at: String, _duration: int, _last_ad_at: String, _preroll_free_time: int) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.snooze_count = _snooze_count + response_data.snooze_refresh_at = _snooze_refresh_at + response_data.next_ad_at = _next_ad_at + response_data.duration = _duration + response_data.last_ad_at = _last_ad_at + response_data.preroll_free_time = _preroll_free_time + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("snooze_count", null) != null: + result.snooze_count = d["snooze_count"] + if d.get("snooze_refresh_at", null) != null: + result.snooze_refresh_at = d["snooze_refresh_at"] + if d.get("next_ad_at", null) != null: + result.next_ad_at = d["next_ad_at"] + if d.get("duration", null) != null: + result.duration = d["duration"] + if d.get("last_ad_at", null) != null: + result.last_ad_at = d["last_ad_at"] + if d.get("preroll_free_time", null) != null: + result.preroll_free_time = d["preroll_free_time"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_ad_schedule.gd.uid b/addons/twitcher/generated/twitch_get_ad_schedule.gd.uid new file mode 100644 index 0000000..cdaf242 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_ad_schedule.gd.uid @@ -0,0 +1 @@ +uid://o7ledpu2xxqf diff --git a/addons/twitcher/generated/twitch_get_all_stream_tags.gd b/addons/twitcher/generated/twitch_get_all_stream_tags.gd new file mode 100644 index 0000000..9d469d5 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_all_stream_tags.gd @@ -0,0 +1,152 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetAllStreamTags + + + +## +## #/components/schemas/GetAllStreamTagsResponse +class Response extends TwitchData: + + ## The list of stream tags that the broadcaster can apply to their channel. + @export var data: Array[TwitchStreamTag]: + set(val): + data = val + track_data(&"data", val) + + ## The information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchStreamTag]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchStreamTag.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## The information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetAllStreamTagsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Set the request’s _after_ query parameter to this value to page forwards through the results. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_all_stream_tags +## #/components/schemas/GetAllStreamTagsOpt +class Opt extends TwitchData: + + ## The ID of the tag to get. Used to filter the list of tags. To specify more than one tag, include the _tag\_id_ parameter for each tag to get. For example, `tag_id=1234&tag_id=5678`. The maximum number of IDs you may specify is 100\. Ignores invalid IDs but not duplicate IDs. + @export var tag_id: Array[String]: + set(val): + tag_id = val + track_data(&"tag_id", val) + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100\. The default is 20. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("tag_id", null) != null: + for value in d["tag_id"]: + result.tag_id.append(value) + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_all_stream_tags.gd.uid b/addons/twitcher/generated/twitch_get_all_stream_tags.gd.uid new file mode 100644 index 0000000..ffb3745 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_all_stream_tags.gd.uid @@ -0,0 +1 @@ +uid://bsl361olbslsl diff --git a/addons/twitcher/generated/twitch_get_auto_mod_settings.gd b/addons/twitcher/generated/twitch_get_auto_mod_settings.gd new file mode 100644 index 0000000..4ff7ebd --- /dev/null +++ b/addons/twitcher/generated/twitch_get_auto_mod_settings.gd @@ -0,0 +1,35 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetAutoModSettings + + + +## +## #/components/schemas/GetAutoModSettingsResponse +class Response extends TwitchData: + + ## The list of AutoMod settings. The list contains a single object that contains all the AutoMod settings. + @export var data: Array[TwitchAutoModSettings]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchAutoModSettings]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchAutoModSettings.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_auto_mod_settings.gd.uid b/addons/twitcher/generated/twitch_get_auto_mod_settings.gd.uid new file mode 100644 index 0000000..5dc09df --- /dev/null +++ b/addons/twitcher/generated/twitch_get_auto_mod_settings.gd.uid @@ -0,0 +1 @@ +uid://cn0jo18gvevx4 diff --git a/addons/twitcher/generated/twitch_get_banned_users.gd b/addons/twitcher/generated/twitch_get_banned_users.gd new file mode 100644 index 0000000..2af0920 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_banned_users.gd @@ -0,0 +1,162 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetBannedUsers + + + +## +## #/components/schemas/GetBannedUsersResponse +class Response extends TwitchData: + + ## The list of users that were banned or put in a timeout. + @export var data: Array[TwitchBannedUser]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchBannedUser]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchBannedUser.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetBannedUsersResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s _after_ query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_banned_users +## #/components/schemas/GetBannedUsersOpt +class Opt extends TwitchData: + + ## A list of user IDs used to filter the results. To specify more than one ID, include this parameter for each user you want to get. For example, `user_id=1234&user_id=5678`. You may specify a maximum of 100 IDs. + ## + ## The returned list includes only those users that were banned or put in a timeout. The list is returned in the same order that you specified the IDs. + @export var user_id: Array[String]: + set(val): + user_id = val + track_data(&"user_id", val) + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100 items per page. The default is 20. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + ## The cursor used to get the previous page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var before: String: + set(val): + before = val + track_data(&"before", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("user_id", null) != null: + for value in d["user_id"]: + result.user_id.append(value) + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + if d.get("before", null) != null: + result.before = d["before"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_banned_users.gd.uid b/addons/twitcher/generated/twitch_get_banned_users.gd.uid new file mode 100644 index 0000000..247f532 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_banned_users.gd.uid @@ -0,0 +1 @@ +uid://b8drtddq3tkto diff --git a/addons/twitcher/generated/twitch_get_bits_leaderboard.gd b/addons/twitcher/generated/twitch_get_bits_leaderboard.gd new file mode 100644 index 0000000..fba7b7b --- /dev/null +++ b/addons/twitcher/generated/twitch_get_bits_leaderboard.gd @@ -0,0 +1,149 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetBitsLeaderboard + + + +## +## #/components/schemas/GetBitsLeaderboardResponse +class Response extends TwitchData: + + ## A list of leaderboard leaders. The leaders are returned in rank order by how much they’ve cheered. The array is empty if nobody has cheered bits. + @export var data: Array[TwitchBitsLeaderboard]: + set(val): + data = val + track_data(&"data", val) + + ## The reporting window’s start and end dates, in RFC3339 format. The dates are calculated by using the _started\_at_ and _period_ query parameters. If you don’t specify the _started\_at_ query parameter, the fields contain empty strings. + @export var date_range: ResponseDateRange: + set(val): + date_range = val + track_data(&"date_range", val) + + ## The number of ranked users in `data`. This is the value in the _count_ query parameter or the total number of entries on the leaderboard, whichever is less. + @export var total: int: + set(val): + total = val + track_data(&"total", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchBitsLeaderboard], _date_range: ResponseDateRange, _total: int) -> Response: + var response: Response = Response.new() + response.data = _data + response.date_range = _date_range + response.total = _total + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchBitsLeaderboard.from_json(value)) + if d.get("date_range", null) != null: + result.date_range = ResponseDateRange.from_json(d["date_range"]) + if d.get("total", null) != null: + result.total = d["total"] + return result + + + +## The reporting window’s start and end dates, in RFC3339 format. The dates are calculated by using the _started\_at_ and _period_ query parameters. If you don’t specify the _started\_at_ query parameter, the fields contain empty strings. +## #/components/schemas/GetBitsLeaderboardResponse/DateRange +class ResponseDateRange extends TwitchData: + + ## The reporting window’s start date. + @export var started_at: String: + set(val): + started_at = val + track_data(&"started_at", val) + + ## The reporting window’s end date. + @export var ended_at: String: + set(val): + ended_at = val + track_data(&"ended_at", val) + + + + ## Constructor with all required fields. + static func create(_started_at: String, _ended_at: String) -> ResponseDateRange: + var response_date_range: ResponseDateRange = ResponseDateRange.new() + response_date_range.started_at = _started_at + response_date_range.ended_at = _ended_at + return response_date_range + + + static func from_json(d: Dictionary) -> ResponseDateRange: + var result: ResponseDateRange = ResponseDateRange.new() + if d.get("started_at", null) != null: + result.started_at = d["started_at"] + if d.get("ended_at", null) != null: + result.ended_at = d["ended_at"] + return result + + + +## All optional parameters for TwitchAPI.get_bits_leaderboard +## #/components/schemas/GetBitsLeaderboardOpt +class Opt extends TwitchData: + + ## The number of results to return. The minimum count is 1 and the maximum is 100\. The default is 10. + @export var count: int: + set(val): + count = val + track_data(&"count", val) + + ## The time period over which data is aggregated (uses the PST time zone). Possible values are: + ## + ## * day — A day spans from 00:00:00 on the day specified in _started\_at_ and runs through 00:00:00 of the next day. + ## * week — A week spans from 00:00:00 on the Monday of the week specified in _started\_at_ and runs through 00:00:00 of the next Monday. + ## * month — A month spans from 00:00:00 on the first day of the month specified in _started\_at_ and runs through 00:00:00 of the first day of the next month. + ## * year — A year spans from 00:00:00 on the first day of the year specified in _started\_at_ and runs through 00:00:00 of the first day of the next year. + ## * all — Default. The lifetime of the broadcaster's channel. + @export var period: String: + set(val): + period = val + track_data(&"period", val) + + ## The start date, in RFC3339 format, used for determining the aggregation period. Specify this parameter only if you specify the _period_ query parameter. The start date is ignored if _period_ is all. + ## + ## Note that the date is converted to PST before being used, so if you set the start time to `2022-01-01T00:00:00.0Z` and _period_ to month, the actual reporting period is December 2021, not January 2022\. If you want the reporting period to be January 2022, you must set the start time to `2022-01-01T08:00:00.0Z` or `2022-01-01T00:00:00.0-08:00`. + ## + ## If your start date uses the ‘+’ offset operator (for example, `2022-01-01T00:00:00.0+05:00`), you must URL encode the start date. + @export var started_at: String: + set(val): + started_at = val + track_data(&"started_at", val) + + ## An ID that identifies a user that cheered bits in the channel. If _count_ is greater than 1, the response may include users ranked above and below the specified user. To get the leaderboard’s top leaders, don’t specify a user ID. + @export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("count", null) != null: + result.count = d["count"] + if d.get("period", null) != null: + result.period = d["period"] + if d.get("started_at", null) != null: + result.started_at = d["started_at"] + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_bits_leaderboard.gd.uid b/addons/twitcher/generated/twitch_get_bits_leaderboard.gd.uid new file mode 100644 index 0000000..a100b35 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_bits_leaderboard.gd.uid @@ -0,0 +1 @@ +uid://csg85msecj0tg diff --git a/addons/twitcher/generated/twitch_get_blocked_terms.gd b/addons/twitcher/generated/twitch_get_blocked_terms.gd new file mode 100644 index 0000000..1bbb9fe --- /dev/null +++ b/addons/twitcher/generated/twitch_get_blocked_terms.gd @@ -0,0 +1,143 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetBlockedTerms + + + +## +## #/components/schemas/GetBlockedTermsResponse +class Response extends TwitchData: + + ## The list of blocked terms. The list is in descending order of when they were created (see the `created_at` timestamp). + @export var data: Array[TwitchBlockedTerm]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchBlockedTerm]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchBlockedTerm.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetBlockedTermsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s _after_ query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_blocked_terms +## #/components/schemas/GetBlockedTermsOpt +class Opt extends TwitchData: + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100 items per page. The default is 20. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_blocked_terms.gd.uid b/addons/twitcher/generated/twitch_get_blocked_terms.gd.uid new file mode 100644 index 0000000..f17617e --- /dev/null +++ b/addons/twitcher/generated/twitch_get_blocked_terms.gd.uid @@ -0,0 +1 @@ +uid://bia4e0g578tfj diff --git a/addons/twitcher/generated/twitch_get_broadcaster_subscriptions.gd b/addons/twitcher/generated/twitch_get_broadcaster_subscriptions.gd new file mode 100644 index 0000000..f0a9043 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_broadcaster_subscriptions.gd @@ -0,0 +1,180 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetBroadcasterSubscriptions + + + +## +## #/components/schemas/GetBroadcasterSubscriptionsResponse +class Response extends TwitchData: + + ## The list of users that subscribe to the broadcaster. The list is empty if the broadcaster has no subscribers. + @export var data: Array[TwitchBroadcasterSubscription]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + + ## The current number of subscriber points earned by this broadcaster. Points are based on the subscription tier of each user that subscribes to this broadcaster. For example, a Tier 1 subscription is worth 1 point, Tier 2 is worth 2 points, and Tier 3 is worth 6 points. The number of points determines the number of emote slots that are unlocked for the broadcaster (see [Subscriber Emote Slots](https://help.twitch.tv/s/article/subscriber-emote-guide#emoteslots)). + @export var points: int: + set(val): + points = val + track_data(&"points", val) + + ## The total number of users that subscribe to this broadcaster. + @export var total: int: + set(val): + total = val + track_data(&"total", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchBroadcasterSubscription], _points: int, _total: int) -> Response: + var response: Response = Response.new() + response.data = _data + response.points = _points + response.total = _total + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchBroadcasterSubscription.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + if d.get("points", null) != null: + result.points = d["points"] + if d.get("total", null) != null: + result.total = d["total"] + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + points = response.points + total = response.total + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetBroadcasterSubscriptionsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next or previous page of results. Use the cursor to set the request’s _after_ or _before_ query parameter depending on whether you’re paging forwards or backwards. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_broadcaster_subscriptions +## #/components/schemas/GetBroadcasterSubscriptionsOpt +class Opt extends TwitchData: + + ## Filters the list to include only the specified subscribers. To specify more than one subscriber, include this parameter for each subscriber. For example, `&user_id=1234&user_id=5678`. You may specify a maximum of 100 subscribers. + @export var user_id: Array[String]: + set(val): + user_id = val + track_data(&"user_id", val) + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100 items per page. The default is 20. + @export var first: String: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. Do not specify if you set the _user\_id_ query parameter. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + ## The cursor used to get the previous page of results. Do not specify if you set the _user\_id_ query parameter. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var before: String: + set(val): + before = val + track_data(&"before", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("user_id", null) != null: + for value in d["user_id"]: + result.user_id.append(value) + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + if d.get("before", null) != null: + result.before = d["before"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_broadcaster_subscriptions.gd.uid b/addons/twitcher/generated/twitch_get_broadcaster_subscriptions.gd.uid new file mode 100644 index 0000000..e93f1ea --- /dev/null +++ b/addons/twitcher/generated/twitch_get_broadcaster_subscriptions.gd.uid @@ -0,0 +1 @@ +uid://cxdka5b8313py diff --git a/addons/twitcher/generated/twitch_get_channel_chat_badges.gd b/addons/twitcher/generated/twitch_get_channel_chat_badges.gd new file mode 100644 index 0000000..ccaeb6c --- /dev/null +++ b/addons/twitcher/generated/twitch_get_channel_chat_badges.gd @@ -0,0 +1,35 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetChannelChatBadges + + + +## +## #/components/schemas/GetChannelChatBadgesResponse +class Response extends TwitchData: + + ## The list of chat badges. The list is sorted in ascending order by `set_id`, and within a set, the list is sorted in ascending order by `id`. + @export var data: Array[TwitchChatBadge]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchChatBadge]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchChatBadge.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_channel_chat_badges.gd.uid b/addons/twitcher/generated/twitch_get_channel_chat_badges.gd.uid new file mode 100644 index 0000000..69913b3 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_channel_chat_badges.gd.uid @@ -0,0 +1 @@ +uid://ccfuby1siu65r diff --git a/addons/twitcher/generated/twitch_get_channel_editors.gd b/addons/twitcher/generated/twitch_get_channel_editors.gd new file mode 100644 index 0000000..fcb1713 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_channel_editors.gd @@ -0,0 +1,35 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetChannelEditors + + + +## +## #/components/schemas/GetChannelEditorsResponse +class Response extends TwitchData: + + ## A list of users that are editors for the specified broadcaster. The list is empty if the broadcaster doesn’t have editors. + @export var data: Array[TwitchChannelEditor]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchChannelEditor]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchChannelEditor.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_channel_editors.gd.uid b/addons/twitcher/generated/twitch_get_channel_editors.gd.uid new file mode 100644 index 0000000..685ff29 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_channel_editors.gd.uid @@ -0,0 +1 @@ +uid://bee0orkp8th2t diff --git a/addons/twitcher/generated/twitch_get_channel_emotes.gd b/addons/twitcher/generated/twitch_get_channel_emotes.gd new file mode 100644 index 0000000..a20a585 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_channel_emotes.gd @@ -0,0 +1,44 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetChannelEmotes + + + +## +## #/components/schemas/GetChannelEmotesResponse +class Response extends TwitchData: + + ## The list of emotes that the specified broadcaster created. If the broadcaster hasn't created custom emotes, the list is empty. + @export var data: Array[TwitchChannelEmote]: + set(val): + data = val + track_data(&"data", val) + + ## A templated URL. Use the values from the `id`, `format`, `scale`, and `theme_mode` fields to replace the like-named placeholder strings in the templated URL to create a CDN (content delivery network) URL that you use to fetch the emote. For information about what the template looks like and how to use it to fetch emotes, see [Emote CDN URL format](https://dev.twitch.tv/docs/irc/emotes#cdn-template). You should use this template instead of using the URLs in the `images` object. + @export var template: String: + set(val): + template = val + track_data(&"template", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchChannelEmote], _template: String) -> Response: + var response: Response = Response.new() + response.data = _data + response.template = _template + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchChannelEmote.from_json(value)) + if d.get("template", null) != null: + result.template = d["template"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_channel_emotes.gd.uid b/addons/twitcher/generated/twitch_get_channel_emotes.gd.uid new file mode 100644 index 0000000..af9cc83 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_channel_emotes.gd.uid @@ -0,0 +1 @@ +uid://bfkf6a371k7ys diff --git a/addons/twitcher/generated/twitch_get_channel_followers.gd b/addons/twitcher/generated/twitch_get_channel_followers.gd new file mode 100644 index 0000000..0f402c4 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_channel_followers.gd @@ -0,0 +1,217 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetChannelFollowers + + + +## +## #/components/schemas/GetChannelFollowersResponse +class Response extends TwitchData: + + ## The list of users that follow the specified broadcaster. The list is in descending order by `followed_at` (with the most recent follower first). The list is empty if nobody follows the broadcaster, the specified `user_id` isn’t in the follower list, the user access token is missing the **moderator:read:followers** scope, or the user isn’t the broadcaster or moderator for the channel. + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read more](https://dev.twitch.tv/docs/api/guide#pagination). + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + + ## The total number of users that follow this broadcaster. As someone pages through the list, the number of users may change as users follow or unfollow the broadcaster. + @export var total: int: + set(val): + total = val + track_data(&"total", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData], _total: int) -> Response: + var response: Response = Response.new() + response.data = _data + response.total = _total + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + if d.get("total", null) != null: + result.total = d["total"] + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + total = response.total + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## The list of users that follow the specified broadcaster. The list is in descending order by `followed_at` (with the most recent follower first). The list is empty if nobody follows the broadcaster, the specified `user_id` isn’t in the follower list, the user access token is missing the **moderator:read:followers** scope, or the user isn’t the broadcaster or moderator for the channel. +## #/components/schemas/GetChannelFollowersResponse/Data +class ResponseData extends TwitchData: + + ## The UTC timestamp when the user started following the broadcaster. + @export var followed_at: String: + set(val): + followed_at = val + track_data(&"followed_at", val) + + ## An ID that uniquely identifies the user that’s following the broadcaster. + @export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + + ## The user’s login name. + @export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) + + ## The user’s display name. + @export var user_name: String: + set(val): + user_name = val + track_data(&"user_name", val) + + + + ## Constructor with all required fields. + static func create(_followed_at: String, _user_id: String, _user_login: String, _user_name: String) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.followed_at = _followed_at + response_data.user_id = _user_id + response_data.user_login = _user_login + response_data.user_name = _user_name + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("followed_at", null) != null: + result.followed_at = d["followed_at"] + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + if d.get("user_name", null) != null: + result.user_name = d["user_name"] + return result + + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read more](https://dev.twitch.tv/docs/api/guide#pagination). +## #/components/schemas/GetChannelFollowersResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s _after_ query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_channel_followers +## #/components/schemas/GetChannelFollowersOpt +class Opt extends TwitchData: + + ## A user’s ID. Use this parameter to see whether the user follows this broadcaster. If specified, the response contains this user if they follow the broadcaster. If not specified, the response contains all users that follow the broadcaster. + ## + ## Using this parameter requires both a user access token with the **moderator:read:followers** scope and the user ID in the access token match the broadcaster\_id or be the user ID for a moderator of the specified broadcaster. + @export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100\. The default is 20. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read more](https://dev.twitch.tv/docs/api/guide#pagination). + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_channel_followers.gd.uid b/addons/twitcher/generated/twitch_get_channel_followers.gd.uid new file mode 100644 index 0000000..d69792a --- /dev/null +++ b/addons/twitcher/generated/twitch_get_channel_followers.gd.uid @@ -0,0 +1 @@ +uid://bjqv8p6qqupvi diff --git a/addons/twitcher/generated/twitch_get_channel_guest_star_settings.gd b/addons/twitcher/generated/twitch_get_channel_guest_star_settings.gd new file mode 100644 index 0000000..88c3e21 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_channel_guest_star_settings.gd @@ -0,0 +1,73 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetChannelGuestStarSettings + + + +## +## #/components/schemas/GetChannelGuestStarSettingsResponse +class Response extends TwitchData: + + ## Flag determining if Guest Star moderators have access to control whether a guest is live once assigned to a slot. + @export var is_moderator_send_live_enabled: bool: + set(val): + is_moderator_send_live_enabled = val + track_data(&"is_moderator_send_live_enabled", val) + + ## Number of slots the Guest Star call interface will allow the host to add to a call. Required to be between 1 and 6. + @export var slot_count: int: + set(val): + slot_count = val + track_data(&"slot_count", val) + + ## Flag determining if Browser Sources subscribed to sessions on this channel should output audio + @export var is_browser_source_audio_enabled: bool: + set(val): + is_browser_source_audio_enabled = val + track_data(&"is_browser_source_audio_enabled", val) + + ## This setting determines how the guests within a session should be laid out within the browser source. Can be one of the following values: + ## + ## * `TILED_LAYOUT`: All live guests are tiled within the browser source with the same size. + ## * `SCREENSHARE_LAYOUT`: All live guests are tiled within the browser source with the same size. If there is an active screen share, it is sized larger than the other guests. + @export var group_layout: String: + set(val): + group_layout = val + track_data(&"group_layout", val) + + ## View only token to generate browser source URLs + @export var browser_source_token: String: + set(val): + browser_source_token = val + track_data(&"browser_source_token", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_is_moderator_send_live_enabled: bool, _slot_count: int, _is_browser_source_audio_enabled: bool, _group_layout: String, _browser_source_token: String) -> Response: + var response: Response = Response.new() + response.is_moderator_send_live_enabled = _is_moderator_send_live_enabled + response.slot_count = _slot_count + response.is_browser_source_audio_enabled = _is_browser_source_audio_enabled + response.group_layout = _group_layout + response.browser_source_token = _browser_source_token + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("is_moderator_send_live_enabled", null) != null: + result.is_moderator_send_live_enabled = d["is_moderator_send_live_enabled"] + if d.get("slot_count", null) != null: + result.slot_count = d["slot_count"] + if d.get("is_browser_source_audio_enabled", null) != null: + result.is_browser_source_audio_enabled = d["is_browser_source_audio_enabled"] + if d.get("group_layout", null) != null: + result.group_layout = d["group_layout"] + if d.get("browser_source_token", null) != null: + result.browser_source_token = d["browser_source_token"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_channel_guest_star_settings.gd.uid b/addons/twitcher/generated/twitch_get_channel_guest_star_settings.gd.uid new file mode 100644 index 0000000..4abade3 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_channel_guest_star_settings.gd.uid @@ -0,0 +1 @@ +uid://bysr415krbhvs diff --git a/addons/twitcher/generated/twitch_get_channel_information.gd b/addons/twitcher/generated/twitch_get_channel_information.gd new file mode 100644 index 0000000..9551596 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_channel_information.gd @@ -0,0 +1,35 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetChannelInformation + + + +## +## #/components/schemas/GetChannelInformationResponse +class Response extends TwitchData: + + ## A list that contains information about the specified channels. The list is empty if the specified channels weren’t found. + @export var data: Array[TwitchChannelInformation]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchChannelInformation]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchChannelInformation.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_channel_information.gd.uid b/addons/twitcher/generated/twitch_get_channel_information.gd.uid new file mode 100644 index 0000000..194834d --- /dev/null +++ b/addons/twitcher/generated/twitch_get_channel_information.gd.uid @@ -0,0 +1 @@ +uid://cxvsllsqxwp5e diff --git a/addons/twitcher/generated/twitch_get_channel_stream_schedule.gd b/addons/twitcher/generated/twitch_get_channel_stream_schedule.gd new file mode 100644 index 0000000..119d0fa --- /dev/null +++ b/addons/twitcher/generated/twitch_get_channel_stream_schedule.gd @@ -0,0 +1,271 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetChannelStreamSchedule + + + +## +## #/components/schemas/GetChannelStreamScheduleResponse +class Response extends TwitchData: + + ## The broadcaster’s streaming schedule. + @export var data: ResponseData: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: ResponseData) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + result.data = ResponseData.from_json(d["data"]) + return result + + + +## The broadcaster’s streaming schedule. +## #/components/schemas/GetChannelStreamScheduleResponse/Data +class ResponseData extends TwitchData: + + ## The list of broadcasts in the broadcaster’s streaming schedule. + @export var segments: Array[TwitchChannelStreamScheduleSegment]: + set(val): + segments = val + track_data(&"segments", val) + + ## The ID of the broadcaster that owns the broadcast schedule. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## The broadcaster’s display name. + @export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + + ## The broadcaster’s login name. + @export var broadcaster_login: String: + set(val): + broadcaster_login = val + track_data(&"broadcaster_login", val) + + ## The dates when the broadcaster is on vacation and not streaming. Is set to **null** if vacation mode is not enabled. + @export var vacation: ResponseVacation: + set(val): + vacation = val + track_data(&"vacation", val) + + ## The information used to page through a list of results. The object is empty if there are no more pages left to page through. [Read more](https://dev.twitch.tv/docs/api/guide#pagination). + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + + + + ## Constructor with all required fields. + static func create(_segments: Array[TwitchChannelStreamScheduleSegment], _broadcaster_id: String, _broadcaster_name: String, _broadcaster_login: String, _vacation: ResponseVacation) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.segments = _segments + response_data.broadcaster_id = _broadcaster_id + response_data.broadcaster_name = _broadcaster_name + response_data.broadcaster_login = _broadcaster_login + response_data.vacation = _vacation + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("segments", null) != null: + for value in d["segments"]: + result.segments.append(TwitchChannelStreamScheduleSegment.from_json(value)) + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + if d.get("broadcaster_login", null) != null: + result.broadcaster_login = d["broadcaster_login"] + if d.get("vacation", null) != null: + result.vacation = ResponseVacation.from_json(d["vacation"]) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response.data._next_page + segments = response.data.segments + broadcaster_id = response.data.broadcaster_id + broadcaster_name = response.data.broadcaster_name + broadcaster_login = response.data.broadcaster_login + vacation = response.data.vacation + pagination = response.data.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if segments.is_empty(): return false + iter[0] = segments[0] + return segments.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if segments.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = segments[_cur_iter] + if segments.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if segments.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## The dates when the broadcaster is on vacation and not streaming. Is set to **null** if vacation mode is not enabled. +## #/components/schemas/GetChannelStreamScheduleResponse/Data/Vacation +class ResponseVacation extends TwitchData: + + ## The UTC date and time (in RFC3339 format) of when the broadcaster’s vacation starts. + @export var start_time: String: + set(val): + start_time = val + track_data(&"start_time", val) + + ## The UTC date and time (in RFC3339 format) of when the broadcaster’s vacation ends. + @export var end_time: String: + set(val): + end_time = val + track_data(&"end_time", val) + + + + ## Constructor with all required fields. + static func create(_start_time: String, _end_time: String) -> ResponseVacation: + var response_vacation: ResponseVacation = ResponseVacation.new() + response_vacation.start_time = _start_time + response_vacation.end_time = _end_time + return response_vacation + + + static func from_json(d: Dictionary) -> ResponseVacation: + var result: ResponseVacation = ResponseVacation.new() + if d.get("start_time", null) != null: + result.start_time = d["start_time"] + if d.get("end_time", null) != null: + result.end_time = d["end_time"] + return result + + + +## The information used to page through a list of results. The object is empty if there are no more pages left to page through. [Read more](https://dev.twitch.tv/docs/api/guide#pagination). +## #/components/schemas/GetChannelStreamScheduleResponse/Data/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Set the request’s _after_ query parameter to this value. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_channel_stream_schedule +## #/components/schemas/GetChannelStreamScheduleOpt +class Opt extends TwitchData: + + ## The ID of the scheduled segment to return. To specify more than one segment, include the ID of each segment you want to get. For example, `id=1234&id=5678`. You may specify a maximum of 100 IDs. + @export var id: Array[String]: + set(val): + id = val + track_data(&"id", val) + + ## The UTC date and time that identifies when in the broadcaster’s schedule to start returning segments. If not specified, the request returns segments starting after the current UTC date and time. Specify the date and time in RFC3339 format (for example, `2022-09-01T00:00:00Z`). + @export var start_time: String: + set(val): + start_time = val + track_data(&"start_time", val) + + ## Not supported. + @export var utc_offset: String: + set(val): + utc_offset = val + track_data(&"utc_offset", val) + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 25 items per page. The default is 20. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("id", null) != null: + for value in d["id"]: + result.id.append(value) + if d.get("start_time", null) != null: + result.start_time = d["start_time"] + if d.get("utc_offset", null) != null: + result.utc_offset = d["utc_offset"] + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_channel_stream_schedule.gd.uid b/addons/twitcher/generated/twitch_get_channel_stream_schedule.gd.uid new file mode 100644 index 0000000..431a4c1 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_channel_stream_schedule.gd.uid @@ -0,0 +1 @@ +uid://de3xoglwtwjlr diff --git a/addons/twitcher/generated/twitch_get_channel_teams.gd b/addons/twitcher/generated/twitch_get_channel_teams.gd new file mode 100644 index 0000000..3a1c016 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_channel_teams.gd @@ -0,0 +1,35 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetChannelTeams + + + +## +## #/components/schemas/GetChannelTeamsResponse +class Response extends TwitchData: + + ## The list of teams that the broadcaster is a member of. Returns an empty array if the broadcaster is not a member of a team. + @export var data: Array[TwitchChannelTeam]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchChannelTeam]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchChannelTeam.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_channel_teams.gd.uid b/addons/twitcher/generated/twitch_get_channel_teams.gd.uid new file mode 100644 index 0000000..4f8bf58 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_channel_teams.gd.uid @@ -0,0 +1 @@ +uid://b17l78dhk563g diff --git a/addons/twitcher/generated/twitch_get_charity_campaign.gd b/addons/twitcher/generated/twitch_get_charity_campaign.gd new file mode 100644 index 0000000..0e50032 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_charity_campaign.gd @@ -0,0 +1,35 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetCharityCampaign + + + +## +## #/components/schemas/GetCharityCampaignResponse +class Response extends TwitchData: + + ## A list that contains the charity campaign that the broadcaster is currently running. The list is empty if the broadcaster is not running a charity campaign; the campaign information is not available after the campaign ends. + @export var data: Array[TwitchCharityCampaign]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchCharityCampaign]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchCharityCampaign.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_charity_campaign.gd.uid b/addons/twitcher/generated/twitch_get_charity_campaign.gd.uid new file mode 100644 index 0000000..5f83f66 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_charity_campaign.gd.uid @@ -0,0 +1 @@ +uid://drkf2tjmuenau diff --git a/addons/twitcher/generated/twitch_get_charity_campaign_donations.gd b/addons/twitcher/generated/twitch_get_charity_campaign_donations.gd new file mode 100644 index 0000000..23b34c3 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_charity_campaign_donations.gd @@ -0,0 +1,143 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetCharityCampaignDonations + + + +## +## #/components/schemas/GetCharityCampaignDonationsResponse +class Response extends TwitchData: + + ## A list that contains the donations that users have made to the broadcaster’s charity campaign. The list is empty if the broadcaster is not currently running a charity campaign; the donation information is not available after the campaign ends. + @export var data: Array[TwitchCharityCampaignDonation]: + set(val): + data = val + track_data(&"data", val) + + ## An object that contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchCharityCampaignDonation]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchCharityCampaignDonation.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## An object that contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetCharityCampaignDonationsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s _after_ query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_charity_campaign_donations +## #/components/schemas/GetCharityCampaignDonationsOpt +class Opt extends TwitchData: + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100\. The default is 20. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_charity_campaign_donations.gd.uid b/addons/twitcher/generated/twitch_get_charity_campaign_donations.gd.uid new file mode 100644 index 0000000..e2baa37 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_charity_campaign_donations.gd.uid @@ -0,0 +1 @@ +uid://drtw3qt21v18r diff --git a/addons/twitcher/generated/twitch_get_chat_settings.gd b/addons/twitcher/generated/twitch_get_chat_settings.gd new file mode 100644 index 0000000..12520b6 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_chat_settings.gd @@ -0,0 +1,65 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetChatSettings + + + +## +## #/components/schemas/GetChatSettingsResponse +class Response extends TwitchData: + + ## The list of chat settings. The list contains a single object with all the settings. + @export var data: Array[TwitchChatSettings]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchChatSettings]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchChatSettings.from_json(value)) + return result + + + +## All optional parameters for TwitchAPI.get_chat_settings +## #/components/schemas/GetChatSettingsOpt +class Opt extends TwitchData: + + ## The ID of the broadcaster or one of the broadcaster’s moderators. + ## + ## This field is required only if you want to include the `non_moderator_chat_delay` and `non_moderator_chat_delay_duration` settings in the response. + ## + ## If you specify this field, this ID must match the user ID in the user access token. + @export var moderator_id: String: + set(val): + moderator_id = val + track_data(&"moderator_id", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("moderator_id", null) != null: + result.moderator_id = d["moderator_id"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_chat_settings.gd.uid b/addons/twitcher/generated/twitch_get_chat_settings.gd.uid new file mode 100644 index 0000000..40c8799 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_chat_settings.gd.uid @@ -0,0 +1 @@ +uid://1tlajx7p4nrs diff --git a/addons/twitcher/generated/twitch_get_chatters.gd b/addons/twitcher/generated/twitch_get_chatters.gd new file mode 100644 index 0000000..3143527 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_chatters.gd @@ -0,0 +1,153 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetChatters + + + +## +## #/components/schemas/GetChattersResponse +class Response extends TwitchData: + + ## The list of users that are connected to the broadcaster’s chat room. The list is empty if no users are connected to the chat room. + @export var data: Array[TwitchChatter]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + + ## The total number of users that are connected to the broadcaster’s chat room. As you page through the list, the number of users may change as users join and leave the chat room. + @export var total: int: + set(val): + total = val + track_data(&"total", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchChatter], _total: int) -> Response: + var response: Response = Response.new() + response.data = _data + response.total = _total + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchChatter.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + if d.get("total", null) != null: + result.total = d["total"] + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + total = response.total + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetChattersResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s _after_ query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_chatters +## #/components/schemas/GetChattersOpt +class Opt extends TwitchData: + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 1,000\. The default is 100. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_chatters.gd.uid b/addons/twitcher/generated/twitch_get_chatters.gd.uid new file mode 100644 index 0000000..049d137 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_chatters.gd.uid @@ -0,0 +1 @@ +uid://cpdam4aowa666 diff --git a/addons/twitcher/generated/twitch_get_cheermotes.gd b/addons/twitcher/generated/twitch_get_cheermotes.gd new file mode 100644 index 0000000..80ede2b --- /dev/null +++ b/addons/twitcher/generated/twitch_get_cheermotes.gd @@ -0,0 +1,63 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetCheermotes + + + +## +## #/components/schemas/GetCheermotesResponse +class Response extends TwitchData: + + ## The list of Cheermotes. The list is in ascending order by the `order` field’s value. + @export var data: Array[TwitchCheermote]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchCheermote]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchCheermote.from_json(value)) + return result + + + +## All optional parameters for TwitchAPI.get_cheermotes +## #/components/schemas/GetCheermotesOpt +class Opt extends TwitchData: + + ## The ID of the broadcaster whose custom Cheermotes you want to get. Specify the broadcaster’s ID if you want to include the broadcaster’s Cheermotes in the response (not all broadcasters upload Cheermotes). If not specified, the response contains only global Cheermotes. + ## + ## If the broadcaster uploaded Cheermotes, the `type` field in the response is set to **channel\_custom**. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_cheermotes.gd.uid b/addons/twitcher/generated/twitch_get_cheermotes.gd.uid new file mode 100644 index 0000000..f884db2 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_cheermotes.gd.uid @@ -0,0 +1 @@ +uid://ntigonlydvam diff --git a/addons/twitcher/generated/twitch_get_clips.gd b/addons/twitcher/generated/twitch_get_clips.gd new file mode 100644 index 0000000..6ee9703 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_clips.gd @@ -0,0 +1,200 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetClips + + + +## +## #/components/schemas/GetClipsResponse +class Response extends TwitchData: + + ## The list of video clips. For clips returned by _game\_id_ or _broadcaster\_id_, the list is in descending order by view count. For lists returned by _id_, the list is in the same order as the input IDs. + @export var data: Array[TwitchClip]: + set(val): + data = val + track_data(&"data", val) + + ## The information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchClip]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchClip.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## The information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetClipsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Set the request’s _after_ or _before_ query parameter to this value depending on whether you’re paging forwards or backwards. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_clips +## #/components/schemas/GetClipsOpt +class Opt extends TwitchData: + + ## An ID that identifies the broadcaster whose video clips you want to get. Use this parameter to get clips that were captured from the broadcaster’s streams. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## An ID that identifies the game whose clips you want to get. Use this parameter to get clips that were captured from streams that were playing this game. + @export var game_id: String: + set(val): + game_id = val + track_data(&"game_id", val) + + ## An ID that identifies the clip to get. To specify more than one ID, include this parameter for each clip you want to get. For example, `id=foo&id=bar`. You may specify a maximum of 100 IDs. The API ignores duplicate IDs and IDs that aren’t found. + @export var id: Array[String]: + set(val): + id = val + track_data(&"id", val) + + ## The start date used to filter clips. The API returns only clips within the start and end date window. Specify the date and time in RFC3339 format. + @export var started_at: String: + set(val): + started_at = val + track_data(&"started_at", val) + + ## The end date used to filter clips. If not specified, the time window is the start date plus one week. Specify the date and time in RFC3339 format. + @export var ended_at: String: + set(val): + ended_at = val + track_data(&"ended_at", val) + + ## The maximum number of clips to return per page in the response. The minimum page size is 1 clip per page and the maximum is 100\. The default is 20. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the previous page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var before: String: + set(val): + before = val + track_data(&"before", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + ## A Boolean value that determines whether the response includes featured clips. If **true**, returns only clips that are featured. If **false**, returns only clips that aren’t featured. All clips are returned if this parameter is not present. + @export var is_featured: bool: + set(val): + is_featured = val + track_data(&"is_featured", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("game_id", null) != null: + result.game_id = d["game_id"] + if d.get("id", null) != null: + for value in d["id"]: + result.id.append(value) + if d.get("started_at", null) != null: + result.started_at = d["started_at"] + if d.get("ended_at", null) != null: + result.ended_at = d["ended_at"] + if d.get("first", null) != null: + result.first = d["first"] + if d.get("before", null) != null: + result.before = d["before"] + if d.get("after", null) != null: + result.after = d["after"] + if d.get("is_featured", null) != null: + result.is_featured = d["is_featured"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_clips.gd.uid b/addons/twitcher/generated/twitch_get_clips.gd.uid new file mode 100644 index 0000000..95949a2 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_clips.gd.uid @@ -0,0 +1 @@ +uid://3ouaj7trgxli diff --git a/addons/twitcher/generated/twitch_get_conduit_shards.gd b/addons/twitcher/generated/twitch_get_conduit_shards.gd new file mode 100644 index 0000000..37a9a5f --- /dev/null +++ b/addons/twitcher/generated/twitch_get_conduit_shards.gd @@ -0,0 +1,262 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetConduitShards + + + +## +## #/components/schemas/GetConduitShardsResponse +class Response extends TwitchData: + + ## List of information about a conduit's shards. + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + + ## Contains information used to page through a list of results. The object is empty if there are no more pages left to page through. + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## List of information about a conduit's shards. +## #/components/schemas/GetConduitShardsResponse/Data +class ResponseData extends TwitchData: + + ## Shard ID. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## The shard status. The subscriber receives events only for enabled shards. Possible values are: + ## + ## * enabled — The shard is enabled. + ## * webhook\_callback\_verification\_pending — The shard is pending verification of the specified callback URL. + ## * webhook\_callback\_verification\_failed — The specified callback URL failed verification. + ## * notification\_failures\_exceeded — The notification delivery failure rate was too high. + ## * websocket\_disconnected — The client closed the connection. + ## * websocket\_failed\_ping\_pong — The client failed to respond to a ping message. + ## * websocket\_received\_inbound\_traffic — The client sent a non-pong message. Clients may only send pong messages (and only in response to a ping message). + ## * websocket\_internal\_error — The Twitch WebSocket server experienced an unexpected error. + ## * websocket\_network\_timeout — The Twitch WebSocket server timed out writing the message to the client. + ## * websocket\_network\_error — The Twitch WebSocket server experienced a network error writing the message to the client. + ## * websocket\_failed\_to\_reconnect - The client failed to reconnect to the Twitch WebSocket server within the required time after a Reconnect Message. + @export var status: String: + set(val): + status = val + track_data(&"status", val) + + ## The transport details used to send the notifications. + @export var transport: ResponseTransport: + set(val): + transport = val + track_data(&"transport", val) + + + + ## Constructor with all required fields. + static func create(_id: String, _status: String, _transport: ResponseTransport) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.id = _id + response_data.status = _status + response_data.transport = _transport + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("status", null) != null: + result.status = d["status"] + if d.get("transport", null) != null: + result.transport = ResponseTransport.from_json(d["transport"]) + return result + + + +## The transport details used to send the notifications. +## #/components/schemas/GetConduitShardsResponse/Data/Transport +class ResponseTransport extends TwitchData: + + ## The transport method. Possible values are: + ## + ## * webhook + ## * websocket + @export var method: String: + set(val): + method = val + track_data(&"method", val) + + ## The callback URL where the notifications are sent. Included only if method is set to webhook. + @export var callback: String: + set(val): + callback = val + track_data(&"callback", val) + + ## An ID that identifies the WebSocket that notifications are sent to. Included only if method is set to websocket. + @export var session_id: String: + set(val): + session_id = val + track_data(&"session_id", val) + + ## The UTC date and time that the WebSocket connection was established. Included only if method is set to websocket. + @export var connected_at: String: + set(val): + connected_at = val + track_data(&"connected_at", val) + + ## The UTC date and time that the WebSocket connection was lost. Included only if method is set to websocket. + @export var disconnected_at: String: + set(val): + disconnected_at = val + track_data(&"disconnected_at", val) + + + + ## Constructor with all required fields. + static func create(_method: String) -> ResponseTransport: + var response_transport: ResponseTransport = ResponseTransport.new() + response_transport.method = _method + return response_transport + + + static func from_json(d: Dictionary) -> ResponseTransport: + var result: ResponseTransport = ResponseTransport.new() + if d.get("method", null) != null: + result.method = d["method"] + if d.get("callback", null) != null: + result.callback = d["callback"] + if d.get("session_id", null) != null: + result.session_id = d["session_id"] + if d.get("connected_at", null) != null: + result.connected_at = d["connected_at"] + if d.get("disconnected_at", null) != null: + result.disconnected_at = d["disconnected_at"] + return result + + + +## Contains information used to page through a list of results. The object is empty if there are no more pages left to page through. +## #/components/schemas/GetConduitShardsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s after query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_conduit_shards +## #/components/schemas/GetConduitShardsOpt +class Opt extends TwitchData: + + ## Status to filter by. + @export var status: String: + set(val): + status = val + track_data(&"status", val) + + ## The cursor used to get the next page of results. The pagination object in the response contains the cursor’s value. + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("status", null) != null: + result.status = d["status"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_conduit_shards.gd.uid b/addons/twitcher/generated/twitch_get_conduit_shards.gd.uid new file mode 100644 index 0000000..efe6010 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_conduit_shards.gd.uid @@ -0,0 +1 @@ +uid://dsdt7dyevwgt0 diff --git a/addons/twitcher/generated/twitch_get_conduits.gd b/addons/twitcher/generated/twitch_get_conduits.gd new file mode 100644 index 0000000..16c4b18 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_conduits.gd @@ -0,0 +1,71 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetConduits + + + +## +## #/components/schemas/GetConduitsResponse +class Response extends TwitchData: + + ## List of information about the client’s conduits. + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + return result + + + +## List of information about the client’s conduits. +## #/components/schemas/GetConduitsResponse/Data +class ResponseData extends TwitchData: + + ## Conduit ID. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## Number of shards associated with this conduit. + @export var shard_count: int: + set(val): + shard_count = val + track_data(&"shard_count", val) + + + + ## Constructor with all required fields. + static func create(_id: String, _shard_count: int) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.id = _id + response_data.shard_count = _shard_count + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("shard_count", null) != null: + result.shard_count = d["shard_count"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_conduits.gd.uid b/addons/twitcher/generated/twitch_get_conduits.gd.uid new file mode 100644 index 0000000..888d4fd --- /dev/null +++ b/addons/twitcher/generated/twitch_get_conduits.gd.uid @@ -0,0 +1 @@ +uid://yp50wtnjicn5 diff --git a/addons/twitcher/generated/twitch_get_content_classification_labels.gd b/addons/twitcher/generated/twitch_get_content_classification_labels.gd new file mode 100644 index 0000000..6fe96c9 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_content_classification_labels.gd @@ -0,0 +1,62 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetContentClassificationLabels + + + +## +## #/components/schemas/GetContentClassificationLabelsResponse +class Response extends TwitchData: + + ## A list that contains information about the available content classification labels. + @export var data: Array[TwitchContentClassificationLabel]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchContentClassificationLabel]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchContentClassificationLabel.from_json(value)) + return result + + + +## All optional parameters for TwitchAPI.get_content_classification_labels +## #/components/schemas/GetContentClassificationLabelsOpt +class Opt extends TwitchData: + + ## Locale for the Content Classification Labels. You may specify a maximum of 1 locale. Default: `“en-US”` + ## Supported locales: `"bg-BG", "cs-CZ", "da-DK", "da-DK", "de-DE", "el-GR", "en-GB", "en-US", "es-ES", "es-MX", "fi-FI", "fr-FR", "hu-HU", "it-IT", "ja-JP", "ko-KR", "nl-NL", "no-NO", "pl-PL", "pt-BT", "pt-PT", "ro-RO", "ru-RU", "sk-SK", "sv-SE", "th-TH", "tr-TR", "vi-VN", "zh-CN", "zh-TW"` + @export var locale: String: + set(val): + locale = val + track_data(&"locale", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("locale", null) != null: + result.locale = d["locale"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_content_classification_labels.gd.uid b/addons/twitcher/generated/twitch_get_content_classification_labels.gd.uid new file mode 100644 index 0000000..d3fea5c --- /dev/null +++ b/addons/twitcher/generated/twitch_get_content_classification_labels.gd.uid @@ -0,0 +1 @@ +uid://4dbbek007cw5 diff --git a/addons/twitcher/generated/twitch_get_creator_goals.gd b/addons/twitcher/generated/twitch_get_creator_goals.gd new file mode 100644 index 0000000..ed320b4 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_creator_goals.gd @@ -0,0 +1,35 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetCreatorGoals + + + +## +## #/components/schemas/GetCreatorGoalsResponse +class Response extends TwitchData: + + ## The list of goals. The list is empty if the broadcaster hasn’t created goals. + @export var data: Array[TwitchCreatorGoal]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchCreatorGoal]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchCreatorGoal.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_creator_goals.gd.uid b/addons/twitcher/generated/twitch_get_creator_goals.gd.uid new file mode 100644 index 0000000..5b8acda --- /dev/null +++ b/addons/twitcher/generated/twitch_get_creator_goals.gd.uid @@ -0,0 +1 @@ +uid://cdthsrrek3ohf diff --git a/addons/twitcher/generated/twitch_get_custom_reward.gd b/addons/twitcher/generated/twitch_get_custom_reward.gd new file mode 100644 index 0000000..67fffd9 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_custom_reward.gd @@ -0,0 +1,72 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetCustomReward + + + +## +## #/components/schemas/GetCustomRewardResponse +class Response extends TwitchData: + + ## A list of custom rewards. The list is in ascending order by `id`. If the broadcaster hasn’t created custom rewards, the list is empty. + @export var data: Array[TwitchCustomReward]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchCustomReward]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchCustomReward.from_json(value)) + return result + + + +## All optional parameters for TwitchAPI.get_custom_reward +## #/components/schemas/GetCustomRewardOpt +class Opt extends TwitchData: + + ## A list of IDs to filter the rewards by. To specify more than one ID, include this parameter for each reward you want to get. For example, `id=1234&id=5678`. You may specify a maximum of 50 IDs. + ## + ## Duplicate IDs are ignored. The response contains only the IDs that were found. If none of the IDs were found, the response is 404 Not Found. + @export var id: Array[String]: + set(val): + id = val + track_data(&"id", val) + + ## A Boolean value that determines whether the response contains only the custom rewards that the app may manage (the app is identified by the ID in the Client-Id header). Set to **true** to get only the custom rewards that the app may manage. The default is **false**. + @export var only_manageable_rewards: bool: + set(val): + only_manageable_rewards = val + track_data(&"only_manageable_rewards", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("id", null) != null: + for value in d["id"]: + result.id.append(value) + if d.get("only_manageable_rewards", null) != null: + result.only_manageable_rewards = d["only_manageable_rewards"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_custom_reward.gd.uid b/addons/twitcher/generated/twitch_get_custom_reward.gd.uid new file mode 100644 index 0000000..36cc046 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_custom_reward.gd.uid @@ -0,0 +1 @@ +uid://vevdxmqy34h2 diff --git a/addons/twitcher/generated/twitch_get_custom_reward_redemption.gd b/addons/twitcher/generated/twitch_get_custom_reward_redemption.gd new file mode 100644 index 0000000..c7766a0 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_custom_reward_redemption.gd @@ -0,0 +1,183 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetCustomRewardRedemption + + + +## +## #/components/schemas/GetCustomRewardRedemptionResponse +class Response extends TwitchData: + + ## The list of redemptions for the specified reward. The list is empty if there are no redemptions that match the redemption criteria. + @export var data: Array[TwitchCustomRewardRedemption]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through.[Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchCustomRewardRedemption]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchCustomRewardRedemption.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through.[Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetCustomRewardRedemptionResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s _after_ query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_custom_reward_redemption +## #/components/schemas/GetCustomRewardRedemptionOpt +class Opt extends TwitchData: + + ## The status of the redemptions to return. The possible case-sensitive values are: + ## + ## * CANCELED + ## * FULFILLED + ## * UNFULFILLED + ## + ## **NOTE**: This field is required only if you don’t specify the _id_ query parameter. + ## + ## **NOTE**: Canceled and fulfilled redemptions are returned for only a few days after they’re canceled or fulfilled. + @export var status: String: + set(val): + status = val + track_data(&"status", val) + + ## A list of IDs to filter the redemptions by. To specify more than one ID, include this parameter for each redemption you want to get. For example, `id=1234&id=5678`. You may specify a maximum of 50 IDs. + ## + ## Duplicate IDs are ignored. The response contains only the IDs that were found. If none of the IDs were found, the response is 404 Not Found. + @export var id: Array[String]: + set(val): + id = val + track_data(&"id", val) + + ## The order to sort redemptions by. The possible case-sensitive values are: + ## + ## * OLDEST + ## * NEWEST + ## + ## The default is OLDEST. + @export var sort: String: + set(val): + sort = val + track_data(&"sort", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read more](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + ## The maximum number of redemptions to return per page in the response. The minimum page size is 1 redemption per page and the maximum is 50\. The default is 20. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("status", null) != null: + result.status = d["status"] + if d.get("id", null) != null: + for value in d["id"]: + result.id.append(value) + if d.get("sort", null) != null: + result.sort = d["sort"] + if d.get("after", null) != null: + result.after = d["after"] + if d.get("first", null) != null: + result.first = d["first"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_custom_reward_redemption.gd.uid b/addons/twitcher/generated/twitch_get_custom_reward_redemption.gd.uid new file mode 100644 index 0000000..359c0f7 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_custom_reward_redemption.gd.uid @@ -0,0 +1 @@ +uid://miy23m4ho6ea diff --git a/addons/twitcher/generated/twitch_get_drops_entitlements.gd b/addons/twitcher/generated/twitch_get_drops_entitlements.gd new file mode 100644 index 0000000..2eadfcc --- /dev/null +++ b/addons/twitcher/generated/twitch_get_drops_entitlements.gd @@ -0,0 +1,179 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetDropsEntitlements + + + +## +## #/components/schemas/GetDropsEntitlementsResponse +class Response extends TwitchData: + + ## The list of entitlements. + @export var data: Array[TwitchDropsEntitlement]: + set(val): + data = val + track_data(&"data", val) + + ## The information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchDropsEntitlement]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchDropsEntitlement.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## The information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetDropsEntitlementsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Set the request’s _after_ query parameter to this value to page forward through the results. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_drops_entitlements +## #/components/schemas/GetDropsEntitlementsOpt +class Opt extends TwitchData: + + ## An ID that identifies the entitlement to get. Include this parameter for each entitlement you want to get. For example, `id=1234&id=5678`. You may specify a maximum of 100 IDs. + @export var id: Array[String]: + set(val): + id = val + track_data(&"id", val) + + ## An ID that identifies a user that was granted entitlements. + @export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + + ## An ID that identifies a game that offered entitlements. + @export var game_id: String: + set(val): + game_id = val + track_data(&"game_id", val) + + ## The entitlement’s fulfillment status. Used to filter the list to only those with the specified status. Possible values are: + ## + ## * CLAIMED + ## * FULFILLED + @export var fulfillment_status: String: + set(val): + fulfillment_status = val + track_data(&"fulfillment_status", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + ## The maximum number of entitlements to return per page in the response. The minimum page size is 1 entitlement per page and the maximum is 1000\. The default is 20. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("id", null) != null: + for value in d["id"]: + result.id.append(value) + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("game_id", null) != null: + result.game_id = d["game_id"] + if d.get("fulfillment_status", null) != null: + result.fulfillment_status = d["fulfillment_status"] + if d.get("after", null) != null: + result.after = d["after"] + if d.get("first", null) != null: + result.first = d["first"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_drops_entitlements.gd.uid b/addons/twitcher/generated/twitch_get_drops_entitlements.gd.uid new file mode 100644 index 0000000..bfd0e9a --- /dev/null +++ b/addons/twitcher/generated/twitch_get_drops_entitlements.gd.uid @@ -0,0 +1 @@ +uid://dns35jr4ihknl diff --git a/addons/twitcher/generated/twitch_get_emote_sets.gd b/addons/twitcher/generated/twitch_get_emote_sets.gd new file mode 100644 index 0000000..d9b8eb5 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_emote_sets.gd @@ -0,0 +1,44 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetEmoteSets + + + +## +## #/components/schemas/GetEmoteSetsResponse +class Response extends TwitchData: + + ## The list of emotes found in the specified emote sets. The list is empty if none of the IDs were found. The list is in the same order as the set IDs specified in the request. Each set contains one or more emoticons. + @export var data: Array[TwitchEmote]: + set(val): + data = val + track_data(&"data", val) + + ## A templated URL. Use the values from the `id`, `format`, `scale`, and `theme_mode` fields to replace the like-named placeholder strings in the templated URL to create a CDN (content delivery network) URL that you use to fetch the emote. For information about what the template looks like and how to use it to fetch emotes, see [Emote CDN URL format](https://dev.twitch.tv/docs/irc/emotes#cdn-template). You should use this template instead of using the URLs in the `images` object. + @export var template: String: + set(val): + template = val + track_data(&"template", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchEmote], _template: String) -> Response: + var response: Response = Response.new() + response.data = _data + response.template = _template + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchEmote.from_json(value)) + if d.get("template", null) != null: + result.template = d["template"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_emote_sets.gd.uid b/addons/twitcher/generated/twitch_get_emote_sets.gd.uid new file mode 100644 index 0000000..180e1ed --- /dev/null +++ b/addons/twitcher/generated/twitch_get_emote_sets.gd.uid @@ -0,0 +1 @@ +uid://yg1njcnm6m7a diff --git a/addons/twitcher/generated/twitch_get_event_sub_subscriptions.gd b/addons/twitcher/generated/twitch_get_event_sub_subscriptions.gd new file mode 100644 index 0000000..6153008 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_event_sub_subscriptions.gd @@ -0,0 +1,139 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetEventSubSubscriptions + + + +## +## #/components/schemas/GetEventSubSubscriptionsResponse +class Response extends TwitchData: + + ## The list of subscriptions. The list is ordered by the oldest subscription first. The list is empty if the client hasn't created subscriptions or there are no subscriptions that match the specified filter criteria. + @export var data: Array[TwitchEventSubSubscription]: + set(val): + data = val + track_data(&"data", val) + + ## The total number of subscriptions that you've created. + @export var total: int: + set(val): + total = val + track_data(&"total", val) + + ## The sum of all of your subscription costs. [Learn More](https://dev.twitch.tv/docs/eventsub/manage-subscriptions/#subscription-limits) + @export var total_cost: int: + set(val): + total_cost = val + track_data(&"total_cost", val) + + ## The maximum total cost that you're allowed to incur for all subscriptions that you create. + @export var max_total_cost: int: + set(val): + max_total_cost = val + track_data(&"max_total_cost", val) + + ## An object that contains the cursor used to get the next page of subscriptions. The object is empty if there are no more pages to get. The number of subscriptions returned per page is undertermined. + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchEventSubSubscription], _total: int, _total_cost: int, _max_total_cost: int) -> Response: + var response: Response = Response.new() + response.data = _data + response.total = _total + response.total_cost = _total_cost + response.max_total_cost = _max_total_cost + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchEventSubSubscription.from_json(value)) + if d.get("total", null) != null: + result.total = d["total"] + if d.get("total_cost", null) != null: + result.total_cost = d["total_cost"] + if d.get("max_total_cost", null) != null: + result.max_total_cost = d["max_total_cost"] + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + total = response.total + total_cost = response.total_cost + max_total_cost = response.max_total_cost + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## An object that contains the cursor used to get the next page of subscriptions. The object is empty if there are no more pages to get. The number of subscriptions returned per page is undertermined. +## #/components/schemas/GetEventSubSubscriptionsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor value that you set the _after_ query parameter to. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_event_sub_subscriptions.gd.uid b/addons/twitcher/generated/twitch_get_event_sub_subscriptions.gd.uid new file mode 100644 index 0000000..e3d0d5f --- /dev/null +++ b/addons/twitcher/generated/twitch_get_event_sub_subscriptions.gd.uid @@ -0,0 +1 @@ +uid://bqgn1u2ftu8nl diff --git a/addons/twitcher/generated/twitch_get_eventsub_subscriptions.gd b/addons/twitcher/generated/twitch_get_eventsub_subscriptions.gd new file mode 100644 index 0000000..f8efdea --- /dev/null +++ b/addons/twitcher/generated/twitch_get_eventsub_subscriptions.gd @@ -0,0 +1,76 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetEventsubSubscriptions + + + +## All optional parameters for TwitchAPI.get_eventsub_subscriptions +## #/components/schemas/GetEventsubSubscriptionsOpt +class Opt extends TwitchData: + + ## Filter subscriptions by its status. Possible values are: + ## + ## * enabled — The subscription is enabled. + ## * webhook\_callback\_verification\_pending — The subscription is pending verification of the specified callback URL. + ## * webhook\_callback\_verification\_failed — The specified callback URL failed verification. + ## * notification\_failures\_exceeded — The notification delivery failure rate was too high. + ## * authorization\_revoked — The authorization was revoked for one or more users specified in the **Condition** object. + ## * moderator\_removed — The moderator that authorized the subscription is no longer one of the broadcaster's moderators. + ## * user\_removed — One of the users specified in the **Condition** object was removed. + ## * chat\_user\_banned - The user specified in the **Condition** object was banned from the broadcaster's chat. + ## * version\_removed — The subscription to subscription type and version is no longer supported. + ## * beta\_maintenance — The subscription to the beta subscription type was removed due to maintenance. + ## * websocket\_disconnected — The client closed the connection. + ## * websocket\_failed\_ping\_pong — The client failed to respond to a ping message. + ## * websocket\_received\_inbound\_traffic — The client sent a non-pong message. Clients may only send pong messages (and only in response to a ping message). + ## * websocket\_connection\_unused — The client failed to subscribe to events within the required time. + ## * websocket\_internal\_error — The Twitch WebSocket server experienced an unexpected error. + ## * websocket\_network\_timeout — The Twitch WebSocket server timed out writing the message to the client. + ## * websocket\_network\_error — The Twitch WebSocket server experienced a network error writing the message to the client. + ## * websocket\_failed\_to\_reconnect - The client failed to reconnect to the Twitch WebSocket server within the required time after a Reconnect Message. + @export var status: String: + set(val): + status = val + track_data(&"status", val) + + ## Filter subscriptions by subscription type. For a list of subscription types, see [Subscription Types](https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types#subscription-types). + @export var type: String: + set(val): + type = val + track_data(&"type", val) + + ## Filter subscriptions by user ID. The response contains subscriptions where this ID matches a user ID that you specified in the **Condition** object when you [created the subscription](https://dev.twitch.tv/docs/api/reference#create-eventsub-subscription). + @export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + + ## The cursor used to get the next page of results. The `pagination` object in the response contains the cursor's value. + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("status", null) != null: + result.status = d["status"] + if d.get("type", null) != null: + result.type = d["type"] + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_eventsub_subscriptions.gd.uid b/addons/twitcher/generated/twitch_get_eventsub_subscriptions.gd.uid new file mode 100644 index 0000000..1fb134a --- /dev/null +++ b/addons/twitcher/generated/twitch_get_eventsub_subscriptions.gd.uid @@ -0,0 +1 @@ +uid://b2n2k0rn7ldkg diff --git a/addons/twitcher/generated/twitch_get_extension_analytics.gd b/addons/twitcher/generated/twitch_get_extension_analytics.gd new file mode 100644 index 0000000..69154fe --- /dev/null +++ b/addons/twitcher/generated/twitch_get_extension_analytics.gd @@ -0,0 +1,187 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetExtensionAnalytics + + + +## +## #/components/schemas/GetExtensionAnalyticsResponse +class Response extends TwitchData: + + ## A list of reports. The reports are returned in no particular order; however, the data within each report is in ascending order by date (newest first). The report contains one row of data per day of the reporting window; the report contains rows for only those days that the extension was used. The array is empty if there are no reports. + @export var data: Array[TwitchExtensionAnalytics]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchExtensionAnalytics]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchExtensionAnalytics.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetExtensionAnalyticsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s _after_ query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_extension_analytics +## #/components/schemas/GetExtensionAnalyticsOpt +class Opt extends TwitchData: + + ## The extension's client ID. If specified, the response contains a report for the specified extension. If not specified, the response includes a report for each extension that the authenticated user owns. + @export var extension_id: String: + set(val): + extension_id = val + track_data(&"extension_id", val) + + ## The type of analytics report to get. Possible values are: + ## + ## * overview\_v2 + @export var type: String: + set(val): + type = val + track_data(&"type", val) + + ## The reporting window's start date, in RFC3339 format. Set the time portion to zeroes (for example, 2021-10-22T00:00:00Z). + ## + ## The start date must be on or after January 31, 2018\. If you specify an earlier date, the API ignores it and uses January 31, 2018\. If you specify a start date, you must specify an end date. If you don't specify a start and end date, the report includes all available data since January 31, 2018. + ## + ## The report contains one row of data for each day in the reporting window. + @export var started_at: String: + set(val): + started_at = val + track_data(&"started_at", val) + + ## The reporting window's end date, in RFC3339 format. Set the time portion to zeroes (for example, 2021-10-27T00:00:00Z). The report is inclusive of the end date. + ## + ## Specify an end date only if you provide a start date. Because it can take up to two days for the data to be available, you must specify an end date that's earlier than today minus one to two days. If not, the API ignores your end date and uses an end date that is today minus one to two days. + @export var ended_at: String: + set(val): + ended_at = val + track_data(&"ended_at", val) + + ## The maximum number of report URLs to return per page in the response. The minimum page size is 1 URL per page and the maximum is 100 URLs per page. The default is 20. + ## + ## **NOTE**: While you may specify a maximum value of 100, the response will contain at most 20 URLs per page. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + ## + ## This parameter is ignored if the _extension\_id_ parameter is set. + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("extension_id", null) != null: + result.extension_id = d["extension_id"] + if d.get("type", null) != null: + result.type = d["type"] + if d.get("started_at", null) != null: + result.started_at = d["started_at"] + if d.get("ended_at", null) != null: + result.ended_at = d["ended_at"] + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_extension_analytics.gd.uid b/addons/twitcher/generated/twitch_get_extension_analytics.gd.uid new file mode 100644 index 0000000..c16edce --- /dev/null +++ b/addons/twitcher/generated/twitch_get_extension_analytics.gd.uid @@ -0,0 +1 @@ +uid://cnls1i1hbmgvl diff --git a/addons/twitcher/generated/twitch_get_extension_bits_products.gd b/addons/twitcher/generated/twitch_get_extension_bits_products.gd new file mode 100644 index 0000000..c132f11 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_extension_bits_products.gd @@ -0,0 +1,61 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetExtensionBitsProducts + + + +## +## #/components/schemas/GetExtensionBitsProductsResponse +class Response extends TwitchData: + + ## A list of Bits products that the extension created. The list is in ascending SKU order. The list is empty if the extension hasn’t created any products or they’re all expired or disabled. + @export var data: Array[TwitchExtensionBitsProduct]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchExtensionBitsProduct]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchExtensionBitsProduct.from_json(value)) + return result + + + +## All optional parameters for TwitchAPI.get_extension_bits_products +## #/components/schemas/GetExtensionBitsProductsOpt +class Opt extends TwitchData: + + ## A Boolean value that determines whether to include disabled or expired Bits products in the response. The default is **false**. + @export var should_include_all: bool: + set(val): + should_include_all = val + track_data(&"should_include_all", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("should_include_all", null) != null: + result.should_include_all = d["should_include_all"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_extension_bits_products.gd.uid b/addons/twitcher/generated/twitch_get_extension_bits_products.gd.uid new file mode 100644 index 0000000..1b26a74 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_extension_bits_products.gd.uid @@ -0,0 +1 @@ +uid://7vblsvayv6ak diff --git a/addons/twitcher/generated/twitch_get_extension_configuration_segment.gd b/addons/twitcher/generated/twitch_get_extension_configuration_segment.gd new file mode 100644 index 0000000..d82b85b --- /dev/null +++ b/addons/twitcher/generated/twitch_get_extension_configuration_segment.gd @@ -0,0 +1,61 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetExtensionConfigurationSegment + + + +## +## #/components/schemas/GetExtensionConfigurationSegmentResponse +class Response extends TwitchData: + + ## The list of requested configuration segments. The list is returned in the same order that you specified the list of segments in the request. + @export var data: Array[TwitchExtensionConfigurationSegment]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchExtensionConfigurationSegment]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchExtensionConfigurationSegment.from_json(value)) + return result + + + +## All optional parameters for TwitchAPI.get_extension_configuration_segment +## #/components/schemas/GetExtensionConfigurationSegmentOpt +class Opt extends TwitchData: + + ## The ID of the broadcaster that installed the extension. This parameter is required if you set the _segment_ parameter to broadcaster or developer. Do not specify this parameter if you set _segment_ to global. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_extension_configuration_segment.gd.uid b/addons/twitcher/generated/twitch_get_extension_configuration_segment.gd.uid new file mode 100644 index 0000000..fc5e4cc --- /dev/null +++ b/addons/twitcher/generated/twitch_get_extension_configuration_segment.gd.uid @@ -0,0 +1 @@ +uid://c04yrkdk5tnas diff --git a/addons/twitcher/generated/twitch_get_extension_live_channels.gd b/addons/twitcher/generated/twitch_get_extension_live_channels.gd new file mode 100644 index 0000000..2d2c91d --- /dev/null +++ b/addons/twitcher/generated/twitch_get_extension_live_channels.gd @@ -0,0 +1,116 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetExtensionLiveChannels + + + +## +## #/components/schemas/GetExtensionLiveChannelsResponse +class Response extends TwitchData: + + ## The list of broadcasters that are streaming live and that have installed or activated the extension. + @export var data: Array[TwitchExtensionLiveChannel]: + set(val): + data = val + track_data(&"data", val) + + ## This field contains the cursor used to page through the results. The field is empty if there are no more pages left to page through. Note that this field is a string compared to other endpoints that use a **Pagination** object. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: String: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchExtensionLiveChannel]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchExtensionLiveChannel.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = d["pagination"] + return result + + + + func _has_pagination() -> bool: + if pagination == null || pagination == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## All optional parameters for TwitchAPI.get_extension_live_channels +## #/components/schemas/GetExtensionLiveChannelsOpt +class Opt extends TwitchData: + + ## The specific maximum number of items per page in the response. The actual number returned may be less than this limit. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The `pagination` field in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_extension_live_channels.gd.uid b/addons/twitcher/generated/twitch_get_extension_live_channels.gd.uid new file mode 100644 index 0000000..1f0f593 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_extension_live_channels.gd.uid @@ -0,0 +1 @@ +uid://b6q2p6ypyf5ie diff --git a/addons/twitcher/generated/twitch_get_extension_secrets.gd b/addons/twitcher/generated/twitch_get_extension_secrets.gd new file mode 100644 index 0000000..64fcefb --- /dev/null +++ b/addons/twitcher/generated/twitch_get_extension_secrets.gd @@ -0,0 +1,35 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetExtensionSecrets + + + +## +## #/components/schemas/GetExtensionSecretsResponse +class Response extends TwitchData: + + ## The list of shared secrets that the extension created. + @export var data: Array[TwitchExtensionSecret]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchExtensionSecret]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchExtensionSecret.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_extension_secrets.gd.uid b/addons/twitcher/generated/twitch_get_extension_secrets.gd.uid new file mode 100644 index 0000000..7143d21 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_extension_secrets.gd.uid @@ -0,0 +1 @@ +uid://by4byfrvnnwlj diff --git a/addons/twitcher/generated/twitch_get_extension_transactions.gd b/addons/twitcher/generated/twitch_get_extension_transactions.gd new file mode 100644 index 0000000..9199279 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_extension_transactions.gd @@ -0,0 +1,152 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetExtensionTransactions + + + +## +## #/components/schemas/GetExtensionTransactionsResponse +class Response extends TwitchData: + + ## The list of transactions. + @export var data: Array[TwitchExtensionTransaction]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchExtensionTransaction]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchExtensionTransaction.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetExtensionTransactionsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s _after_ query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_extension_transactions +## #/components/schemas/GetExtensionTransactionsOpt +class Opt extends TwitchData: + + ## A transaction ID used to filter the list of transactions. Specify this parameter for each transaction you want to get. For example, `id=1234&id=5678`. You may specify a maximum of 100 IDs. + @export var id: Array[String]: + set(val): + id = val + track_data(&"id", val) + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100 items per page. The default is 20. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("id", null) != null: + for value in d["id"]: + result.id.append(value) + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_extension_transactions.gd.uid b/addons/twitcher/generated/twitch_get_extension_transactions.gd.uid new file mode 100644 index 0000000..06d5174 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_extension_transactions.gd.uid @@ -0,0 +1 @@ +uid://dk1rvby8ko4b5 diff --git a/addons/twitcher/generated/twitch_get_extensions.gd b/addons/twitcher/generated/twitch_get_extensions.gd new file mode 100644 index 0000000..e81125a --- /dev/null +++ b/addons/twitcher/generated/twitch_get_extensions.gd @@ -0,0 +1,61 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetExtensions + + + +## +## #/components/schemas/GetExtensionsResponse +class Response extends TwitchData: + + ## A list that contains the specified extension. + @export var data: Array[TwitchExtension]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchExtension]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchExtension.from_json(value)) + return result + + + +## All optional parameters for TwitchAPI.get_extensions +## #/components/schemas/GetExtensionsOpt +class Opt extends TwitchData: + + ## The version of the extension to get. If not specified, it returns the latest, released version. If you don’t have a released version, you must specify a version; otherwise, the list is empty. + @export var extension_version: String: + set(val): + extension_version = val + track_data(&"extension_version", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("extension_version", null) != null: + result.extension_version = d["extension_version"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_extensions.gd.uid b/addons/twitcher/generated/twitch_get_extensions.gd.uid new file mode 100644 index 0000000..e7b594c --- /dev/null +++ b/addons/twitcher/generated/twitch_get_extensions.gd.uid @@ -0,0 +1 @@ +uid://ve5t7kmi7hbr diff --git a/addons/twitcher/generated/twitch_get_followed_channels.gd b/addons/twitcher/generated/twitch_get_followed_channels.gd new file mode 100644 index 0000000..f856816 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_followed_channels.gd @@ -0,0 +1,215 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetFollowedChannels + + + +## +## #/components/schemas/GetFollowedChannelsResponse +class Response extends TwitchData: + + ## The list of broadcasters that the user follows. The list is in descending order by `followed_at` (with the most recently followed broadcaster first). The list is empty if the user doesn’t follow anyone. + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read more](https://dev.twitch.tv/docs/api/guide#pagination). + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + + ## The total number of broadcasters that the user follows. As someone pages through the list, the number may change as the user follows or unfollows broadcasters. + @export var total: int: + set(val): + total = val + track_data(&"total", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData], _total: int) -> Response: + var response: Response = Response.new() + response.data = _data + response.total = _total + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + if d.get("total", null) != null: + result.total = d["total"] + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + total = response.total + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## The list of broadcasters that the user follows. The list is in descending order by `followed_at` (with the most recently followed broadcaster first). The list is empty if the user doesn’t follow anyone. +## #/components/schemas/GetFollowedChannelsResponse/Data +class ResponseData extends TwitchData: + + ## An ID that uniquely identifies the broadcaster that this user is following. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## The broadcaster’s login name. + @export var broadcaster_login: String: + set(val): + broadcaster_login = val + track_data(&"broadcaster_login", val) + + ## The broadcaster’s display name. + @export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + + ## The UTC timestamp when the user started following the broadcaster. + @export var followed_at: String: + set(val): + followed_at = val + track_data(&"followed_at", val) + + + + ## Constructor with all required fields. + static func create(_broadcaster_id: String, _broadcaster_login: String, _broadcaster_name: String, _followed_at: String) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.broadcaster_id = _broadcaster_id + response_data.broadcaster_login = _broadcaster_login + response_data.broadcaster_name = _broadcaster_name + response_data.followed_at = _followed_at + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_login", null) != null: + result.broadcaster_login = d["broadcaster_login"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + if d.get("followed_at", null) != null: + result.followed_at = d["followed_at"] + return result + + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read more](https://dev.twitch.tv/docs/api/guide#pagination). +## #/components/schemas/GetFollowedChannelsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s _after_ query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_followed_channels +## #/components/schemas/GetFollowedChannelsOpt +class Opt extends TwitchData: + + ## A broadcaster’s ID. Use this parameter to see whether the user follows this broadcaster. If specified, the response contains this broadcaster if the user follows them. If not specified, the response contains all broadcasters that the user follows. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100\. The default is 20. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read more](https://dev.twitch.tv/docs/api/guide#pagination). + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_followed_channels.gd.uid b/addons/twitcher/generated/twitch_get_followed_channels.gd.uid new file mode 100644 index 0000000..17a53fd --- /dev/null +++ b/addons/twitcher/generated/twitch_get_followed_channels.gd.uid @@ -0,0 +1 @@ +uid://d0jkb77gcevai diff --git a/addons/twitcher/generated/twitch_get_followed_streams.gd b/addons/twitcher/generated/twitch_get_followed_streams.gd new file mode 100644 index 0000000..dc195be --- /dev/null +++ b/addons/twitcher/generated/twitch_get_followed_streams.gd @@ -0,0 +1,143 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetFollowedStreams + + + +## +## #/components/schemas/GetFollowedStreamsResponse +class Response extends TwitchData: + + ## The list of live streams of broadcasters that the specified user follows. The list is in descending order by the number of viewers watching the stream. Because viewers come and go during a stream, it’s possible to find duplicate or missing streams in the list as you page through the results. The list is empty if none of the followed broadcasters are streaming live. + @export var data: Array[TwitchStream]: + set(val): + data = val + track_data(&"data", val) + + ## The information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchStream]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchStream.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## The information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetFollowedStreamsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Set the request’s _after_ query parameter to this value. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_followed_streams +## #/components/schemas/GetFollowedStreamsOpt +class Opt extends TwitchData: + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100 items per page. The default is 100. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_followed_streams.gd.uid b/addons/twitcher/generated/twitch_get_followed_streams.gd.uid new file mode 100644 index 0000000..8373578 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_followed_streams.gd.uid @@ -0,0 +1 @@ +uid://dcebcynwot4r5 diff --git a/addons/twitcher/generated/twitch_get_game_analytics.gd b/addons/twitcher/generated/twitch_get_game_analytics.gd new file mode 100644 index 0000000..e5517c4 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_game_analytics.gd @@ -0,0 +1,187 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetGameAnalytics + + + +## +## #/components/schemas/GetGameAnalyticsResponse +class Response extends TwitchData: + + ## A list of reports. The reports are returned in no particular order; however, the data within each report is in ascending order by date (newest first). The report contains one row of data per day of the reporting window; the report contains rows for only those days that the game was used. A report is available only if the game was broadcast for at least 5 hours over the reporting period. The array is empty if there are no reports. + @export var data: Array[TwitchGameAnalytics]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchGameAnalytics]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchGameAnalytics.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetGameAnalyticsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s _after_ query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_game_analytics +## #/components/schemas/GetGameAnalyticsOpt +class Opt extends TwitchData: + + ## The game’s client ID. If specified, the response contains a report for the specified game. If not specified, the response includes a report for each of the authenticated user’s games. + @export var game_id: String: + set(val): + game_id = val + track_data(&"game_id", val) + + ## The type of analytics report to get. Possible values are: + ## + ## * overview\_v2 + @export var type: String: + set(val): + type = val + track_data(&"type", val) + + ## The reporting window’s start date, in RFC3339 format. Set the time portion to zeroes (for example, 2021-10-22T00:00:00Z). If you specify a start date, you must specify an end date. + ## + ## The start date must be within one year of today’s date. If you specify an earlier date, the API ignores it and uses a date that’s one year prior to today’s date. If you don’t specify a start and end date, the report includes all available data for the last 365 days from today. + ## + ## The report contains one row of data for each day in the reporting window. + @export var started_at: String: + set(val): + started_at = val + track_data(&"started_at", val) + + ## The reporting window’s end date, in RFC3339 format. Set the time portion to zeroes (for example, 2021-10-22T00:00:00Z). The report is inclusive of the end date. + ## + ## Specify an end date only if you provide a start date. Because it can take up to two days for the data to be available, you must specify an end date that’s earlier than today minus one to two days. If not, the API ignores your end date and uses an end date that is today minus one to two days. + @export var ended_at: String: + set(val): + ended_at = val + track_data(&"ended_at", val) + + ## The maximum number of report URLs to return per page in the response. The minimum page size is 1 URL per page and the maximum is 100 URLs per page. The default is 20. + ## + ## **NOTE**: While you may specify a maximum value of 100, the response will contain at most 20 URLs per page. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + ## + ## This parameter is ignored if _game\_id_ parameter is set. + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("game_id", null) != null: + result.game_id = d["game_id"] + if d.get("type", null) != null: + result.type = d["type"] + if d.get("started_at", null) != null: + result.started_at = d["started_at"] + if d.get("ended_at", null) != null: + result.ended_at = d["ended_at"] + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_game_analytics.gd.uid b/addons/twitcher/generated/twitch_get_game_analytics.gd.uid new file mode 100644 index 0000000..062161f --- /dev/null +++ b/addons/twitcher/generated/twitch_get_game_analytics.gd.uid @@ -0,0 +1 @@ +uid://do4py5hysupck diff --git a/addons/twitcher/generated/twitch_get_games.gd b/addons/twitcher/generated/twitch_get_games.gd new file mode 100644 index 0000000..3cbd13f --- /dev/null +++ b/addons/twitcher/generated/twitch_get_games.gd @@ -0,0 +1,80 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetGames + + + +## +## #/components/schemas/GetGamesResponse +class Response extends TwitchData: + + ## The list of categories and games. The list is empty if the specified categories and games weren’t found. + @export var data: Array[TwitchGame]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchGame]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchGame.from_json(value)) + return result + + + +## All optional parameters for TwitchAPI.get_games +## #/components/schemas/GetGamesOpt +class Opt extends TwitchData: + + ## The ID of the category or game to get. Include this parameter for each category or game you want to get. For example, `&id=1234&id=5678`. You may specify a maximum of 100 IDs. The endpoint ignores duplicate and invalid IDs or IDs that weren’t found. + @export var id: Array[String]: + set(val): + id = val + track_data(&"id", val) + + ## The name of the category or game to get. The name must exactly match the category’s or game’s title. Include this parameter for each category or game you want to get. For example, `&name=foo&name=bar`. You may specify a maximum of 100 names. The endpoint ignores duplicate names and names that weren’t found. + @export var name: Array[String]: + set(val): + name = val + track_data(&"name", val) + + ## The [IGDB](https://www.igdb.com/) ID of the game to get. Include this parameter for each game you want to get. For example, `&igdb_id=1234&igdb_id=5678`. You may specify a maximum of 100 IDs. The endpoint ignores duplicate and invalid IDs or IDs that weren’t found. + @export var igdb_id: Array[String]: + set(val): + igdb_id = val + track_data(&"igdb_id", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("id", null) != null: + for value in d["id"]: + result.id.append(value) + if d.get("name", null) != null: + for value in d["name"]: + result.name.append(value) + if d.get("igdb_id", null) != null: + for value in d["igdb_id"]: + result.igdb_id.append(value) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_games.gd.uid b/addons/twitcher/generated/twitch_get_games.gd.uid new file mode 100644 index 0000000..9d7310f --- /dev/null +++ b/addons/twitcher/generated/twitch_get_games.gd.uid @@ -0,0 +1 @@ +uid://cjog83t263bu diff --git a/addons/twitcher/generated/twitch_get_global_chat_badges.gd b/addons/twitcher/generated/twitch_get_global_chat_badges.gd new file mode 100644 index 0000000..de9c9b9 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_global_chat_badges.gd @@ -0,0 +1,35 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetGlobalChatBadges + + + +## +## #/components/schemas/GetGlobalChatBadgesResponse +class Response extends TwitchData: + + ## The list of chat badges. The list is sorted in ascending order by `set_id`, and within a set, the list is sorted in ascending order by `id`. + @export var data: Array[TwitchChatBadge]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchChatBadge]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchChatBadge.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_global_chat_badges.gd.uid b/addons/twitcher/generated/twitch_get_global_chat_badges.gd.uid new file mode 100644 index 0000000..fdf5ed3 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_global_chat_badges.gd.uid @@ -0,0 +1 @@ +uid://crdb6dfnmxmy5 diff --git a/addons/twitcher/generated/twitch_get_global_emotes.gd b/addons/twitcher/generated/twitch_get_global_emotes.gd new file mode 100644 index 0000000..967b8c1 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_global_emotes.gd @@ -0,0 +1,44 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetGlobalEmotes + + + +## +## #/components/schemas/GetGlobalEmotesResponse +class Response extends TwitchData: + + ## The list of global emotes. + @export var data: Array[TwitchGlobalEmote]: + set(val): + data = val + track_data(&"data", val) + + ## A templated URL. Use the values from the `id`, `format`, `scale`, and `theme_mode` fields to replace the like-named placeholder strings in the templated URL to create a CDN (content delivery network) URL that you use to fetch the emote. For information about what the template looks like and how to use it to fetch emotes, see [Emote CDN URL format](https://dev.twitch.tv/docs/irc/emotes#cdn-template). You should use this template instead of using the URLs in the `images` object. + @export var template: String: + set(val): + template = val + track_data(&"template", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchGlobalEmote], _template: String) -> Response: + var response: Response = Response.new() + response.data = _data + response.template = _template + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchGlobalEmote.from_json(value)) + if d.get("template", null) != null: + result.template = d["template"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_global_emotes.gd.uid b/addons/twitcher/generated/twitch_get_global_emotes.gd.uid new file mode 100644 index 0000000..70543e8 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_global_emotes.gd.uid @@ -0,0 +1 @@ +uid://d2o3tmbyvdtc6 diff --git a/addons/twitcher/generated/twitch_get_guest_star_invites.gd b/addons/twitcher/generated/twitch_get_guest_star_invites.gd new file mode 100644 index 0000000..47dc180 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_guest_star_invites.gd @@ -0,0 +1,35 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetGuestStarInvites + + + +## +## #/components/schemas/GetGuestStarInvitesResponse +class Response extends TwitchData: + + ## A list of invite objects describing the invited user as well as their ready status. + @export var data: Array[TwitchGuestStarInvite]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchGuestStarInvite]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchGuestStarInvite.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_guest_star_invites.gd.uid b/addons/twitcher/generated/twitch_get_guest_star_invites.gd.uid new file mode 100644 index 0000000..f6d00b4 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_guest_star_invites.gd.uid @@ -0,0 +1 @@ +uid://cm54sr3e5jfh5 diff --git a/addons/twitcher/generated/twitch_get_guest_star_session.gd b/addons/twitcher/generated/twitch_get_guest_star_session.gd new file mode 100644 index 0000000..6cd6445 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_guest_star_session.gd @@ -0,0 +1,35 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetGuestStarSession + + + +## +## #/components/schemas/GetGuestStarSessionResponse +class Response extends TwitchData: + + ## Summary of the session details + @export var data: Array[TwitchGuestStarSession]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchGuestStarSession]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchGuestStarSession.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_guest_star_session.gd.uid b/addons/twitcher/generated/twitch_get_guest_star_session.gd.uid new file mode 100644 index 0000000..65b3314 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_guest_star_session.gd.uid @@ -0,0 +1 @@ +uid://bbd4c101q84dg diff --git a/addons/twitcher/generated/twitch_get_hype_train_events.gd b/addons/twitcher/generated/twitch_get_hype_train_events.gd new file mode 100644 index 0000000..9f54fc9 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_hype_train_events.gd @@ -0,0 +1,143 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetHypeTrainEvents + + + +## +## #/components/schemas/GetHypeTrainEventsResponse +class Response extends TwitchData: + + ## The list of Hype Train events. The list is empty if the broadcaster hasn’t run a Hype Train within the last 5 days. + @export var data: Array[TwitchHypeTrainEvent]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchHypeTrainEvent]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchHypeTrainEvent.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetHypeTrainEventsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s _after_ query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_hype_train_events +## #/components/schemas/GetHypeTrainEventsOpt +class Opt extends TwitchData: + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100 items per page. The default is 1. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_hype_train_events.gd.uid b/addons/twitcher/generated/twitch_get_hype_train_events.gd.uid new file mode 100644 index 0000000..c2e27ca --- /dev/null +++ b/addons/twitcher/generated/twitch_get_hype_train_events.gd.uid @@ -0,0 +1 @@ +uid://cgm5e2hbk2elm diff --git a/addons/twitcher/generated/twitch_get_moderated_channels.gd b/addons/twitcher/generated/twitch_get_moderated_channels.gd new file mode 100644 index 0000000..b4e07e5 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_moderated_channels.gd @@ -0,0 +1,190 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetModeratedChannels + + + +## +## #/components/schemas/GetModeratedChannelsResponse +class Response extends TwitchData: + + ## The list of channels that the user has moderator privileges in. + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## The list of channels that the user has moderator privileges in. +## #/components/schemas/GetModeratedChannelsResponse/Data +class ResponseData extends TwitchData: + + ## An ID that uniquely identifies the channel this user can moderate. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## The channel’s login name. + @export var broadcaster_login: String: + set(val): + broadcaster_login = val + track_data(&"broadcaster_login", val) + + ## The channels’ display name. + @export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + + + + ## Constructor with all required fields. + static func create(_broadcaster_id: String, _broadcaster_login: String, _broadcaster_name: String) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.broadcaster_id = _broadcaster_id + response_data.broadcaster_login = _broadcaster_login + response_data.broadcaster_name = _broadcaster_name + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_login", null) != null: + result.broadcaster_login = d["broadcaster_login"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + return result + + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. +## #/components/schemas/GetModeratedChannelsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s after query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_moderated_channels +## #/components/schemas/GetModeratedChannelsOpt +class Opt extends TwitchData: + + ## The cursor used to get the next page of results. The Pagination object in the response contains the cursor’s value. + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + ## The maximum number of items to return per page in the response. + ## + ## Minimum page size is 1 item per page and the maximum is 100\. The default is 20. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("after", null) != null: + result.after = d["after"] + if d.get("first", null) != null: + result.first = d["first"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_moderated_channels.gd.uid b/addons/twitcher/generated/twitch_get_moderated_channels.gd.uid new file mode 100644 index 0000000..6d50557 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_moderated_channels.gd.uid @@ -0,0 +1 @@ +uid://ducqwy81pu67u diff --git a/addons/twitcher/generated/twitch_get_moderators.gd b/addons/twitcher/generated/twitch_get_moderators.gd new file mode 100644 index 0000000..3712ebd --- /dev/null +++ b/addons/twitcher/generated/twitch_get_moderators.gd @@ -0,0 +1,154 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetModerators + + + +## +## #/components/schemas/GetModeratorsResponse +class Response extends TwitchData: + + ## The list of moderators. + @export var data: Array[TwitchUserModerator]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchUserModerator]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchUserModerator.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetModeratorsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s _after_ query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_moderators +## #/components/schemas/GetModeratorsOpt +class Opt extends TwitchData: + + ## A list of user IDs used to filter the results. To specify more than one ID, include this parameter for each moderator you want to get. For example, `user_id=1234&user_id=5678`. You may specify a maximum of 100 IDs. + ## + ## The returned list includes only the users from the list who are moderators in the broadcaster’s channel. The list is returned in the same order as you specified the IDs. + @export var user_id: Array[String]: + set(val): + user_id = val + track_data(&"user_id", val) + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100 items per page. The default is 20. + @export var first: String: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("user_id", null) != null: + for value in d["user_id"]: + result.user_id.append(value) + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_moderators.gd.uid b/addons/twitcher/generated/twitch_get_moderators.gd.uid new file mode 100644 index 0000000..7af2a12 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_moderators.gd.uid @@ -0,0 +1 @@ +uid://cihnhjydprxy5 diff --git a/addons/twitcher/generated/twitch_get_polls.gd b/addons/twitcher/generated/twitch_get_polls.gd new file mode 100644 index 0000000..7733745 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_polls.gd @@ -0,0 +1,154 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetPolls + + + +## +## #/components/schemas/GetPollsResponse +class Response extends TwitchData: + + ## A list of polls. The polls are returned in descending order of start time unless you specify IDs in the request, in which case they're returned in the same order as you passed them in the request. The list is empty if the broadcaster hasn't created polls. + @export var data: Array[TwitchPoll]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchPoll]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchPoll.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetPollsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request's _after_ query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_polls +## #/components/schemas/GetPollsOpt +class Opt extends TwitchData: + + ## A list of IDs that identify the polls to return. To specify more than one ID, include this parameter for each poll you want to get. For example, `id=1234&id=5678`. You may specify a maximum of 20 IDs. + ## + ## Specify this parameter only if you want to filter the list that the request returns. The endpoint ignores duplicate IDs and those not owned by this broadcaster. + @export var id: Array[String]: + set(val): + id = val + track_data(&"id", val) + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 20 items per page. The default is 20. + @export var first: String: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("id", null) != null: + for value in d["id"]: + result.id.append(value) + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_polls.gd.uid b/addons/twitcher/generated/twitch_get_polls.gd.uid new file mode 100644 index 0000000..ed707fe --- /dev/null +++ b/addons/twitcher/generated/twitch_get_polls.gd.uid @@ -0,0 +1 @@ +uid://c7lc5fg1ep2b0 diff --git a/addons/twitcher/generated/twitch_get_predictions.gd b/addons/twitcher/generated/twitch_get_predictions.gd new file mode 100644 index 0000000..cea58ed --- /dev/null +++ b/addons/twitcher/generated/twitch_get_predictions.gd @@ -0,0 +1,152 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetPredictions + + + +## +## #/components/schemas/GetPredictionsResponse +class Response extends TwitchData: + + ## The broadcaster’s list of Channel Points Predictions. The list is sorted in descending ordered by when the prediction began (the most recent prediction is first). The list is empty if the broadcaster hasn’t created predictions. + @export var data: Array[TwitchPrediction]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchPrediction]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchPrediction.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetPredictionsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s _after_ query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_predictions +## #/components/schemas/GetPredictionsOpt +class Opt extends TwitchData: + + ## The ID of the prediction to get. To specify more than one ID, include this parameter for each prediction you want to get. For example, `id=1234&id=5678`. You may specify a maximum of 25 IDs. The endpoint ignores duplicate IDs and those not owned by the broadcaster. + @export var id: Array[String]: + set(val): + id = val + track_data(&"id", val) + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 25 items per page. The default is 20. + @export var first: String: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("id", null) != null: + for value in d["id"]: + result.id.append(value) + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_predictions.gd.uid b/addons/twitcher/generated/twitch_get_predictions.gd.uid new file mode 100644 index 0000000..7bcaff6 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_predictions.gd.uid @@ -0,0 +1 @@ +uid://cenvkii2xgne diff --git a/addons/twitcher/generated/twitch_get_released_extensions.gd b/addons/twitcher/generated/twitch_get_released_extensions.gd new file mode 100644 index 0000000..e685475 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_released_extensions.gd @@ -0,0 +1,61 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetReleasedExtensions + + + +## +## #/components/schemas/GetReleasedExtensionsResponse +class Response extends TwitchData: + + ## A list that contains the specified extension. + @export var data: Array[TwitchExtension]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchExtension]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchExtension.from_json(value)) + return result + + + +## All optional parameters for TwitchAPI.get_released_extensions +## #/components/schemas/GetReleasedExtensionsOpt +class Opt extends TwitchData: + + ## The version of the extension to get. If not specified, it returns the latest version. + @export var extension_version: String: + set(val): + extension_version = val + track_data(&"extension_version", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("extension_version", null) != null: + result.extension_version = d["extension_version"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_released_extensions.gd.uid b/addons/twitcher/generated/twitch_get_released_extensions.gd.uid new file mode 100644 index 0000000..e7011b0 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_released_extensions.gd.uid @@ -0,0 +1 @@ +uid://cptbi53x52e8i diff --git a/addons/twitcher/generated/twitch_get_shared_chat_session.gd b/addons/twitcher/generated/twitch_get_shared_chat_session.gd new file mode 100644 index 0000000..0d9b224 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_shared_chat_session.gd @@ -0,0 +1,126 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetSharedChatSession + + + +## +## #/components/schemas/GetSharedChatSessionResponse +class Response extends TwitchData: + + ## + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + return result + + + +## +## #/components/schemas/GetSharedChatSessionResponse/Data +class ResponseData extends TwitchData: + + ## The unique identifier for the shared chat session. + @export var session_id: String: + set(val): + session_id = val + track_data(&"session_id", val) + + ## The User ID of the host channel. + @export var host_broadcaster_id: String: + set(val): + host_broadcaster_id = val + track_data(&"host_broadcaster_id", val) + + ## The list of participants in the session. + @export var participants: Array[ResponseParticipants]: + set(val): + participants = val + track_data(&"participants", val) + + ## The UTC date and time (in RFC3339 format) for when the session was created. + @export var created_at: String: + set(val): + created_at = val + track_data(&"created_at", val) + + ## The UTC date and time (in RFC3339 format) for when the session was last updated. + @export var updated_at: String: + set(val): + updated_at = val + track_data(&"updated_at", val) + + + + ## Constructor with all required fields. + static func create(_session_id: String, _host_broadcaster_id: String, _participants: Array[ResponseParticipants], _created_at: String, _updated_at: String) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.session_id = _session_id + response_data.host_broadcaster_id = _host_broadcaster_id + response_data.participants = _participants + response_data.created_at = _created_at + response_data.updated_at = _updated_at + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("session_id", null) != null: + result.session_id = d["session_id"] + if d.get("host_broadcaster_id", null) != null: + result.host_broadcaster_id = d["host_broadcaster_id"] + if d.get("participants", null) != null: + for value in d["participants"]: + result.participants.append(ResponseParticipants.from_json(value)) + if d.get("created_at", null) != null: + result.created_at = d["created_at"] + if d.get("updated_at", null) != null: + result.updated_at = d["updated_at"] + return result + + + +## The list of participants in the session. +## #/components/schemas/GetSharedChatSessionResponse/Data/Participants +class ResponseParticipants extends TwitchData: + + ## The User ID of the participant channel. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + + + ## Constructor with all required fields. + static func create(_broadcaster_id: String) -> ResponseParticipants: + var response_participants: ResponseParticipants = ResponseParticipants.new() + response_participants.broadcaster_id = _broadcaster_id + return response_participants + + + static func from_json(d: Dictionary) -> ResponseParticipants: + var result: ResponseParticipants = ResponseParticipants.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_shared_chat_session.gd.uid b/addons/twitcher/generated/twitch_get_shared_chat_session.gd.uid new file mode 100644 index 0000000..4ab324d --- /dev/null +++ b/addons/twitcher/generated/twitch_get_shared_chat_session.gd.uid @@ -0,0 +1 @@ +uid://8b63h8eiw85h diff --git a/addons/twitcher/generated/twitch_get_shield_mode_status.gd b/addons/twitcher/generated/twitch_get_shield_mode_status.gd new file mode 100644 index 0000000..6148c9d --- /dev/null +++ b/addons/twitcher/generated/twitch_get_shield_mode_status.gd @@ -0,0 +1,98 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetShieldModeStatus + + + +## +## #/components/schemas/GetShieldModeStatusResponse +class Response extends TwitchData: + + ## A list that contains a single object with the broadcaster’s Shield Mode status. + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + return result + + + +## A list that contains a single object with the broadcaster’s Shield Mode status. +## #/components/schemas/GetShieldModeStatusResponse/Data +class ResponseData extends TwitchData: + + ## A Boolean value that determines whether Shield Mode is active. Is **true** if the broadcaster activated Shield Mode; otherwise, **false**. + @export var is_active: bool: + set(val): + is_active = val + track_data(&"is_active", val) + + ## An ID that identifies the moderator that last activated Shield Mode. Is an empty string if Shield Mode hasn’t been previously activated. + @export var moderator_id: String: + set(val): + moderator_id = val + track_data(&"moderator_id", val) + + ## The moderator’s login name. Is an empty string if Shield Mode hasn’t been previously activated. + @export var moderator_login: String: + set(val): + moderator_login = val + track_data(&"moderator_login", val) + + ## The moderator’s display name. Is an empty string if Shield Mode hasn’t been previously activated. + @export var moderator_name: String: + set(val): + moderator_name = val + track_data(&"moderator_name", val) + + ## The UTC timestamp (in RFC3339 format) of when Shield Mode was last activated. Is an empty string if Shield Mode hasn’t been previously activated. + @export var last_activated_at: String: + set(val): + last_activated_at = val + track_data(&"last_activated_at", val) + + + + ## Constructor with all required fields. + static func create(_is_active: bool, _moderator_id: String, _moderator_login: String, _moderator_name: String, _last_activated_at: String) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.is_active = _is_active + response_data.moderator_id = _moderator_id + response_data.moderator_login = _moderator_login + response_data.moderator_name = _moderator_name + response_data.last_activated_at = _last_activated_at + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("is_active", null) != null: + result.is_active = d["is_active"] + if d.get("moderator_id", null) != null: + result.moderator_id = d["moderator_id"] + if d.get("moderator_login", null) != null: + result.moderator_login = d["moderator_login"] + if d.get("moderator_name", null) != null: + result.moderator_name = d["moderator_name"] + if d.get("last_activated_at", null) != null: + result.last_activated_at = d["last_activated_at"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_shield_mode_status.gd.uid b/addons/twitcher/generated/twitch_get_shield_mode_status.gd.uid new file mode 100644 index 0000000..12cddac --- /dev/null +++ b/addons/twitcher/generated/twitch_get_shield_mode_status.gd.uid @@ -0,0 +1 @@ +uid://chhd8mjs2nctc diff --git a/addons/twitcher/generated/twitch_get_stream_key.gd b/addons/twitcher/generated/twitch_get_stream_key.gd new file mode 100644 index 0000000..76c8a0b --- /dev/null +++ b/addons/twitcher/generated/twitch_get_stream_key.gd @@ -0,0 +1,62 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetStreamKey + + + +## +## #/components/schemas/GetStreamKeyResponse +class Response extends TwitchData: + + ## A list that contains the channel’s stream key. + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + return result + + + +## A list that contains the channel’s stream key. +## #/components/schemas/GetStreamKeyResponse/Data +class ResponseData extends TwitchData: + + ## The channel’s stream key. + @export var stream_key: String: + set(val): + stream_key = val + track_data(&"stream_key", val) + + + + ## Constructor with all required fields. + static func create(_stream_key: String) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.stream_key = _stream_key + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("stream_key", null) != null: + result.stream_key = d["stream_key"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_stream_key.gd.uid b/addons/twitcher/generated/twitch_get_stream_key.gd.uid new file mode 100644 index 0000000..530aeb8 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_stream_key.gd.uid @@ -0,0 +1 @@ +uid://dd8dg0c0g51pm diff --git a/addons/twitcher/generated/twitch_get_stream_markers.gd b/addons/twitcher/generated/twitch_get_stream_markers.gd new file mode 100644 index 0000000..c0bc34e --- /dev/null +++ b/addons/twitcher/generated/twitch_get_stream_markers.gd @@ -0,0 +1,171 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetStreamMarkers + + + +## +## #/components/schemas/GetStreamMarkersResponse +class Response extends TwitchData: + + ## The list of markers grouped by the user that created the marks. + @export var data: Array[TwitchStreamMarkers]: + set(val): + data = val + track_data(&"data", val) + + ## The information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchStreamMarkers]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchStreamMarkers.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## The information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetStreamMarkersResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Set the request’s _after_ or _before_ query parameter to this value depending on whether you’re paging forwards or backwards. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_stream_markers +## #/components/schemas/GetStreamMarkersOpt +class Opt extends TwitchData: + + ## A user ID. The request returns the markers from this user’s most recent video. This ID must match the user ID in the access token or the user in the access token must be one of the broadcaster’s editors. + ## + ## This parameter and the _video\_id_ query parameter are mutually exclusive. + @export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + + ## A video on demand (VOD)/video ID. The request returns the markers from this VOD/video. The user in the access token must own the video or the user must be one of the broadcaster’s editors. + ## + ## This parameter and the _user\_id_ query parameter are mutually exclusive. + @export var video_id: String: + set(val): + video_id = val + track_data(&"video_id", val) + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100 items per page. The default is 20. + @export var first: String: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the previous page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var before: String: + set(val): + before = val + track_data(&"before", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("video_id", null) != null: + result.video_id = d["video_id"] + if d.get("first", null) != null: + result.first = d["first"] + if d.get("before", null) != null: + result.before = d["before"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_stream_markers.gd.uid b/addons/twitcher/generated/twitch_get_stream_markers.gd.uid new file mode 100644 index 0000000..bd1a6ef --- /dev/null +++ b/addons/twitcher/generated/twitch_get_stream_markers.gd.uid @@ -0,0 +1 @@ +uid://c3gr8dg7sft5y diff --git a/addons/twitcher/generated/twitch_get_stream_tags.gd b/addons/twitcher/generated/twitch_get_stream_tags.gd new file mode 100644 index 0000000..1450412 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_stream_tags.gd @@ -0,0 +1,35 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetStreamTags + + + +## +## #/components/schemas/GetStreamTagsResponse +class Response extends TwitchData: + + ## The list of stream tags. The list is empty if the broadcaster or Twitch hasn’t added tags to the broadcaster’s channel. + @export var data: Array[TwitchStreamTag]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchStreamTag]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchStreamTag.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_stream_tags.gd.uid b/addons/twitcher/generated/twitch_get_stream_tags.gd.uid new file mode 100644 index 0000000..c548aec --- /dev/null +++ b/addons/twitcher/generated/twitch_get_stream_tags.gd.uid @@ -0,0 +1 @@ +uid://xmkr128c2xai diff --git a/addons/twitcher/generated/twitch_get_streams.gd b/addons/twitcher/generated/twitch_get_streams.gd new file mode 100644 index 0000000..f8583cc --- /dev/null +++ b/addons/twitcher/generated/twitch_get_streams.gd @@ -0,0 +1,202 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetStreams + + + +## +## #/components/schemas/GetStreamsResponse +class Response extends TwitchData: + + ## The list of streams. + @export var data: Array[TwitchStream]: + set(val): + data = val + track_data(&"data", val) + + ## The information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchStream]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchStream.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## The information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetStreamsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Set the request’s _after_ or _before_ query parameter to this value depending on whether you’re paging forwards or backwards. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_streams +## #/components/schemas/GetStreamsOpt +class Opt extends TwitchData: + + ## A user ID used to filter the list of streams. Returns only the streams of those users that are broadcasting. You may specify a maximum of 100 IDs. To specify multiple IDs, include the _user\_id_ parameter for each user. For example, `&user_id=1234&user_id=5678`. + @export var user_id: Array[String]: + set(val): + user_id = val + track_data(&"user_id", val) + + ## A user login name used to filter the list of streams. Returns only the streams of those users that are broadcasting. You may specify a maximum of 100 login names. To specify multiple names, include the _user\_login_ parameter for each user. For example, `&user_login=foo&user_login=bar`. + @export var user_login: Array[String]: + set(val): + user_login = val + track_data(&"user_login", val) + + ## A game (category) ID used to filter the list of streams. Returns only the streams that are broadcasting the game (category). You may specify a maximum of 100 IDs. To specify multiple IDs, include the _game\_id_ parameter for each game. For example, `&game_id=9876&game_id=5432`. + @export var game_id: Array[String]: + set(val): + game_id = val + track_data(&"game_id", val) + + ## The type of stream to filter the list of streams by. Possible values are: + ## + ## * all + ## * live + ## + ## The default is _all_. + @export var type: String: + set(val): + type = val + track_data(&"type", val) + + ## A language code used to filter the list of streams. Returns only streams that broadcast in the specified language. Specify the language using an ISO 639-1 two-letter language code or _other_ if the broadcast uses a language not in the list of [supported stream languages](https://help.twitch.tv/s/article/languages-on-twitch#streamlang). + ## + ## You may specify a maximum of 100 language codes. To specify multiple languages, include the _language_ parameter for each language. For example, `&language=de&language=fr`. + @export var language: Array[String]: + set(val): + language = val + track_data(&"language", val) + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100 items per page. The default is 20. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the previous page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var before: String: + set(val): + before = val + track_data(&"before", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("user_id", null) != null: + for value in d["user_id"]: + result.user_id.append(value) + if d.get("user_login", null) != null: + for value in d["user_login"]: + result.user_login.append(value) + if d.get("game_id", null) != null: + for value in d["game_id"]: + result.game_id.append(value) + if d.get("type", null) != null: + result.type = d["type"] + if d.get("language", null) != null: + for value in d["language"]: + result.language.append(value) + if d.get("first", null) != null: + result.first = d["first"] + if d.get("before", null) != null: + result.before = d["before"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_streams.gd.uid b/addons/twitcher/generated/twitch_get_streams.gd.uid new file mode 100644 index 0000000..821ddad --- /dev/null +++ b/addons/twitcher/generated/twitch_get_streams.gd.uid @@ -0,0 +1 @@ +uid://cuiyg43dqei5d diff --git a/addons/twitcher/generated/twitch_get_teams.gd b/addons/twitcher/generated/twitch_get_teams.gd new file mode 100644 index 0000000..711f827 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_teams.gd @@ -0,0 +1,69 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetTeams + + + +## +## #/components/schemas/GetTeamsResponse +class Response extends TwitchData: + + ## A list that contains the single team that you requested. + @export var data: Array[TwitchTeam]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchTeam]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchTeam.from_json(value)) + return result + + + +## All optional parameters for TwitchAPI.get_teams +## #/components/schemas/GetTeamsOpt +class Opt extends TwitchData: + + ## The name of the team to get. This parameter and the _id_ parameter are mutually exclusive; you must specify the team’s name or ID but not both. + @export var name: String: + set(val): + name = val + track_data(&"name", val) + + ## The ID of the team to get. This parameter and the _name_ parameter are mutually exclusive; you must specify the team’s name or ID but not both. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("name", null) != null: + result.name = d["name"] + if d.get("id", null) != null: + result.id = d["id"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_teams.gd.uid b/addons/twitcher/generated/twitch_get_teams.gd.uid new file mode 100644 index 0000000..1487733 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_teams.gd.uid @@ -0,0 +1 @@ +uid://ciyghm6xdkyib diff --git a/addons/twitcher/generated/twitch_get_top_games.gd b/addons/twitcher/generated/twitch_get_top_games.gd new file mode 100644 index 0000000..5132e17 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_top_games.gd @@ -0,0 +1,151 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetTopGames + + + +## +## #/components/schemas/GetTopGamesResponse +class Response extends TwitchData: + + ## The list of broadcasts. The broadcasts are sorted by the number of viewers, with the most popular first. + @export var data: Array[TwitchGame]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchGame]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchGame.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetTopGamesResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s _after_ or _before_ query parameter to get the next or previous page of results. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_top_games +## #/components/schemas/GetTopGamesOpt +class Opt extends TwitchData: + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100 items per page. The default is 20. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + ## The cursor used to get the previous page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var before: String: + set(val): + before = val + track_data(&"before", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + if d.get("before", null) != null: + result.before = d["before"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_top_games.gd.uid b/addons/twitcher/generated/twitch_get_top_games.gd.uid new file mode 100644 index 0000000..ede1bb6 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_top_games.gd.uid @@ -0,0 +1 @@ +uid://dcj4fadol01cx diff --git a/addons/twitcher/generated/twitch_get_unban_requests.gd b/addons/twitcher/generated/twitch_get_unban_requests.gd new file mode 100644 index 0000000..ba3d4ef --- /dev/null +++ b/addons/twitcher/generated/twitch_get_unban_requests.gd @@ -0,0 +1,310 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetUnbanRequests + + + +## +## #/components/schemas/GetUnbanRequestsResponse +class Response extends TwitchData: + + ## A list that contains information about the channel's unban requests. + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + + ## Contains information used to page through a list of results. The object is empty if there are no more pages left to page through. + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## A list that contains information about the channel's unban requests. +## #/components/schemas/GetUnbanRequestsResponse/Data +class ResponseData extends TwitchData: + + ## Unban request ID. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## User ID of broadcaster whose channel is receiving the unban request. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## The broadcaster's display name. + @export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + + ## The broadcaster's login name. + @export var broadcaster_login: String: + set(val): + broadcaster_login = val + track_data(&"broadcaster_login", val) + + ## User ID of moderator who approved/denied the request. + @export var moderator_id: String: + set(val): + moderator_id = val + track_data(&"moderator_id", val) + + ## The moderator's login name. + @export var moderator_login: String: + set(val): + moderator_login = val + track_data(&"moderator_login", val) + + ## The moderator's display name. + @export var moderator_name: String: + set(val): + moderator_name = val + track_data(&"moderator_name", val) + + ## User ID of the requestor who is asking for an unban. + @export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + + ## The user's login name. + @export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) + + ## The user's display name. + @export var user_name: String: + set(val): + user_name = val + track_data(&"user_name", val) + + ## Text of the request from the requesting user. + @export var text: String: + set(val): + text = val + track_data(&"text", val) + + ## Status of the request. One of: + ## + ## * pending + ## * approved + ## * denied + ## * acknowledged + ## * canceled + @export var status: String: + set(val): + status = val + track_data(&"status", val) + + ## Timestamp of when the unban request was created. + @export var created_at: String: + set(val): + created_at = val + track_data(&"created_at", val) + + ## Timestamp of when moderator/broadcaster approved or denied the request. + @export var resolved_at: String: + set(val): + resolved_at = val + track_data(&"resolved_at", val) + + ## Text input by the resolver (moderator) of the unban. request + @export var resolution_text: String: + set(val): + resolution_text = val + track_data(&"resolution_text", val) + + + + ## Constructor with all required fields. + static func create(_id: String, _broadcaster_id: String, _broadcaster_name: String, _broadcaster_login: String, _moderator_id: String, _moderator_login: String, _moderator_name: String, _user_id: String, _user_login: String, _user_name: String, _text: String, _status: String, _created_at: String, _resolved_at: String, _resolution_text: String) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.id = _id + response_data.broadcaster_id = _broadcaster_id + response_data.broadcaster_name = _broadcaster_name + response_data.broadcaster_login = _broadcaster_login + response_data.moderator_id = _moderator_id + response_data.moderator_login = _moderator_login + response_data.moderator_name = _moderator_name + response_data.user_id = _user_id + response_data.user_login = _user_login + response_data.user_name = _user_name + response_data.text = _text + response_data.status = _status + response_data.created_at = _created_at + response_data.resolved_at = _resolved_at + response_data.resolution_text = _resolution_text + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + if d.get("broadcaster_login", null) != null: + result.broadcaster_login = d["broadcaster_login"] + if d.get("moderator_id", null) != null: + result.moderator_id = d["moderator_id"] + if d.get("moderator_login", null) != null: + result.moderator_login = d["moderator_login"] + if d.get("moderator_name", null) != null: + result.moderator_name = d["moderator_name"] + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + if d.get("user_name", null) != null: + result.user_name = d["user_name"] + if d.get("text", null) != null: + result.text = d["text"] + if d.get("status", null) != null: + result.status = d["status"] + if d.get("created_at", null) != null: + result.created_at = d["created_at"] + if d.get("resolved_at", null) != null: + result.resolved_at = d["resolved_at"] + if d.get("resolution_text", null) != null: + result.resolution_text = d["resolution_text"] + return result + + + +## Contains information used to page through a list of results. The object is empty if there are no more pages left to page through. +## #/components/schemas/GetUnbanRequestsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s after query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_unban_requests +## #/components/schemas/GetUnbanRequestsOpt +class Opt extends TwitchData: + + ## The ID used to filter what unban requests are returned. + @export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + + ## Cursor used to get next page of results. Pagination object in response contains cursor value. + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + ## The maximum number of items to return per page in response + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("after", null) != null: + result.after = d["after"] + if d.get("first", null) != null: + result.first = d["first"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_unban_requests.gd.uid b/addons/twitcher/generated/twitch_get_unban_requests.gd.uid new file mode 100644 index 0000000..a539c83 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_unban_requests.gd.uid @@ -0,0 +1 @@ +uid://bdjw8c31hmamj diff --git a/addons/twitcher/generated/twitch_get_user_active_extensions.gd b/addons/twitcher/generated/twitch_get_user_active_extensions.gd new file mode 100644 index 0000000..d8d5463 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_user_active_extensions.gd @@ -0,0 +1,103 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetUserActiveExtensions + + + +## +## #/components/schemas/GetUserActiveExtensionsResponse +class Response extends TwitchData: + + ## The active extensions that the broadcaster has installed. + @export var data: ResponseData: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create() -> Response: + var response: Response = Response.new() + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + result.data = ResponseData.from_json(d["data"]) + return result + + + +## The active extensions that the broadcaster has installed. +## #/components/schemas/GetUserActiveExtensionsResponse/Data +class ResponseData extends TwitchData: + + ## A dictionary that contains the data for a panel extension. The dictionary’s key is a sequential number beginning with 1\. The following fields contain the panel’s data for each key. + @export var panel: Dictionary: + set(val): + panel = val + track_data(&"panel", val) + + ## A dictionary that contains the data for a video-overlay extension. The dictionary’s key is a sequential number beginning with 1\. The following fields contain the overlay’s data for each key. + @export var overlay: Dictionary: + set(val): + overlay = val + track_data(&"overlay", val) + + ## A dictionary that contains the data for a video-component extension. The dictionary’s key is a sequential number beginning with 1\. The following fields contain the component’s data for each key. + @export var component: Dictionary: + set(val): + component = val + track_data(&"component", val) + + + + ## Constructor with all required fields. + static func create() -> ResponseData: + var response_data: ResponseData = ResponseData.new() + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("panel", null) != null: + result.panel = d["panel"] + if d.get("overlay", null) != null: + result.overlay = d["overlay"] + if d.get("component", null) != null: + result.component = d["component"] + return result + + + +## All optional parameters for TwitchAPI.get_user_active_extensions +## #/components/schemas/GetUserActiveExtensionsOpt +class Opt extends TwitchData: + + ## The ID of the broadcaster whose active extensions you want to get. + ## + ## This parameter is required if you specify an app access token and is optional if you specify a user access token. If you specify a user access token and don’t specify this parameter, the API uses the user ID from the access token. + @export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_user_active_extensions.gd.uid b/addons/twitcher/generated/twitch_get_user_active_extensions.gd.uid new file mode 100644 index 0000000..f6edf9a --- /dev/null +++ b/addons/twitcher/generated/twitch_get_user_active_extensions.gd.uid @@ -0,0 +1 @@ +uid://behw75yoiwgeu diff --git a/addons/twitcher/generated/twitch_get_user_block_list.gd b/addons/twitcher/generated/twitch_get_user_block_list.gd new file mode 100644 index 0000000..462862d --- /dev/null +++ b/addons/twitcher/generated/twitch_get_user_block_list.gd @@ -0,0 +1,143 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetUserBlockList + + + +## +## #/components/schemas/GetUserBlockListResponse +class Response extends TwitchData: + + ## The list of blocked users. The list is in descending order by when the user was blocked. + @export var data: Array[TwitchUserBlockList]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through.[Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchUserBlockList]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchUserBlockList.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through.[Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetUserBlockListResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s _after_ query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_user_block_list +## #/components/schemas/GetUserBlockListOpt +class Opt extends TwitchData: + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100\. The default is 20. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_user_block_list.gd.uid b/addons/twitcher/generated/twitch_get_user_block_list.gd.uid new file mode 100644 index 0000000..0e7b038 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_user_block_list.gd.uid @@ -0,0 +1 @@ +uid://c5phlcg37egid diff --git a/addons/twitcher/generated/twitch_get_user_chat_color.gd b/addons/twitcher/generated/twitch_get_user_chat_color.gd new file mode 100644 index 0000000..d3ce09c --- /dev/null +++ b/addons/twitcher/generated/twitch_get_user_chat_color.gd @@ -0,0 +1,35 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetUserChatColor + + + +## +## #/components/schemas/GetUserChatColorResponse +class Response extends TwitchData: + + ## The list of users and the color code they use for their name. + @export var data: Array[TwitchUserChatColor]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchUserChatColor]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchUserChatColor.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_user_chat_color.gd.uid b/addons/twitcher/generated/twitch_get_user_chat_color.gd.uid new file mode 100644 index 0000000..f1293d1 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_user_chat_color.gd.uid @@ -0,0 +1 @@ +uid://bd8nvrh2prny2 diff --git a/addons/twitcher/generated/twitch_get_user_emotes.gd b/addons/twitcher/generated/twitch_get_user_emotes.gd new file mode 100644 index 0000000..f62b04e --- /dev/null +++ b/addons/twitcher/generated/twitch_get_user_emotes.gd @@ -0,0 +1,279 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetUserEmotes + + + +## +## #/components/schemas/GetUserEmotesResponse +class Response extends TwitchData: + + ## + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + + ## A templated URL. Uses the values from the _id_, _format_, _scale_, and _theme\_mode_ fields to replace the like-named placeholder strings in the templated URL to create a CDN (content delivery network) URL that you use to fetch the emote. + ## + ## For information about what the template looks like and how to use it to fetch emotes, see [Emote CDN URL](https://dev.twitch.tv/docs/irc/emotes#cdn-template) format. + @export var template: String: + set(val): + template = val + track_data(&"template", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. + ## + ## For more information about pagination support, see [Twitch API Guide - Pagination](https://dev.twitch.tv/docs/api/guide#pagination). + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData], _template: String) -> Response: + var response: Response = Response.new() + response.data = _data + response.template = _template + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + if d.get("template", null) != null: + result.template = d["template"] + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + template = response.template + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## +## #/components/schemas/GetUserEmotesResponse/Data +class ResponseData extends TwitchData: + + ## An ID that uniquely identifies this emote. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## The User ID of broadcaster whose channel is receiving the unban request. + @export var name: String: + set(val): + name = val + track_data(&"name", val) + + ## The type of emote. The possible values are: + ## + ## * **none** — No emote type was assigned to this emote. + ## * **bitstier** — A Bits tier emote. + ## * **follower** — A follower emote. + ## * **subscriptions** — A subscriber emote. + ## * **channelpoints** — An emote granted by using channel points. + ## * **rewards** — An emote granted to the user through a special event. + ## * **hypetrain** — An emote granted for participation in a Hype Train. + ## * **prime** — An emote granted for linking an Amazon Prime account. + ## * **turbo** — An emote granted for having Twitch Turbo. + ## * **smilies** — Emoticons supported by Twitch. + ## * **globals** — An emote accessible by everyone. + ## * **owl2019** — Emotes related to Overwatch League 2019. + ## * **twofactor** — Emotes granted by enabling two-factor authentication on an account. + ## * **limitedtime** — Emotes that were granted for only a limited time. + @export var emote_type: String: + set(val): + emote_type = val + track_data(&"emote_type", val) + + ## An ID that identifies the emote set that the emote belongs to. + @export var emote_set_id: String: + set(val): + emote_set_id = val + track_data(&"emote_set_id", val) + + ## The ID of the broadcaster who owns the emote. + @export var owner_id: String: + set(val): + owner_id = val + track_data(&"owner_id", val) + + ## The formats that the emote is available in. For example, if the emote is available only as a static PNG, the array contains only static. But if the emote is available as a static PNG and an animated GIF, the array contains static and animated. + ## + ## * **animated** — An animated GIF is available for this emote. + ## * **static** — A static PNG file is available for this emote. + @export var format: Array[String]: + set(val): + format = val + track_data(&"format", val) + + ## The sizes that the emote is available in. For example, if the emote is available in small and medium sizes, the array contains 1.0 and 2.0\. + ## + ## * **1.0** — A small version (28px x 28px) is available. + ## * **2.0** — A medium version (56px x 56px) is available. + ## * **3.0** — A large version (112px x 112px) is available. + @export var scale: Array[String]: + set(val): + scale = val + track_data(&"scale", val) + + ## The background themes that the emote is available in. + ## + ## * **dark** + ## * **light** + @export var theme_mode: Array[String]: + set(val): + theme_mode = val + track_data(&"theme_mode", val) + + + + ## Constructor with all required fields. + static func create(_id: String, _name: String, _emote_type: String, _emote_set_id: String, _owner_id: String, _format: Array[String], _scale: Array[String], _theme_mode: Array[String]) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.id = _id + response_data.name = _name + response_data.emote_type = _emote_type + response_data.emote_set_id = _emote_set_id + response_data.owner_id = _owner_id + response_data.format = _format + response_data.scale = _scale + response_data.theme_mode = _theme_mode + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("name", null) != null: + result.name = d["name"] + if d.get("emote_type", null) != null: + result.emote_type = d["emote_type"] + if d.get("emote_set_id", null) != null: + result.emote_set_id = d["emote_set_id"] + if d.get("owner_id", null) != null: + result.owner_id = d["owner_id"] + if d.get("format", null) != null: + for value in d["format"]: + result.format.append(value) + if d.get("scale", null) != null: + for value in d["scale"]: + result.scale.append(value) + if d.get("theme_mode", null) != null: + for value in d["theme_mode"]: + result.theme_mode.append(value) + return result + + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. +## +## For more information about pagination support, see [Twitch API Guide - Pagination](https://dev.twitch.tv/docs/api/guide#pagination). +## #/components/schemas/GetUserEmotesResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s after query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_user_emotes +## #/components/schemas/GetUserEmotesOpt +class Opt extends TwitchData: + + ## The cursor used to get the next page of results. The Pagination object in the response contains the cursor’s value. + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + ## The User ID of a broadcaster you wish to get follower emotes of. Using this query parameter will guarantee inclusion of the broadcaster’s follower emotes in the response body. + ## + ## **Note:** If the user specified in `user_id` is subscribed to the broadcaster specified, their follower emotes will appear in the response body regardless if this query parameter is used. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("after", null) != null: + result.after = d["after"] + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_user_emotes.gd.uid b/addons/twitcher/generated/twitch_get_user_emotes.gd.uid new file mode 100644 index 0000000..f6bc583 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_user_emotes.gd.uid @@ -0,0 +1 @@ +uid://cisyrufmqhm05 diff --git a/addons/twitcher/generated/twitch_get_user_extensions.gd b/addons/twitcher/generated/twitch_get_user_extensions.gd new file mode 100644 index 0000000..7c83b3a --- /dev/null +++ b/addons/twitcher/generated/twitch_get_user_extensions.gd @@ -0,0 +1,35 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetUserExtensions + + + +## +## #/components/schemas/GetUserExtensionsResponse +class Response extends TwitchData: + + ## The list of extensions that the user has installed. + @export var data: Array[TwitchUserExtension]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchUserExtension]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchUserExtension.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_user_extensions.gd.uid b/addons/twitcher/generated/twitch_get_user_extensions.gd.uid new file mode 100644 index 0000000..767bca2 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_user_extensions.gd.uid @@ -0,0 +1 @@ +uid://dvienfsw61wj2 diff --git a/addons/twitcher/generated/twitch_get_users.gd b/addons/twitcher/generated/twitch_get_users.gd new file mode 100644 index 0000000..028c3a3 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_users.gd @@ -0,0 +1,71 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetUsers + + + +## +## #/components/schemas/GetUsersResponse +class Response extends TwitchData: + + ## The list of users. + @export var data: Array[TwitchUser]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchUser]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchUser.from_json(value)) + return result + + + +## All optional parameters for TwitchAPI.get_users +## #/components/schemas/GetUsersOpt +class Opt extends TwitchData: + + ## The ID of the user to get. To specify more than one user, include the _id_ parameter for each user to get. For example, `id=1234&id=5678`. The maximum number of IDs you may specify is 100. + @export var id: Array[String]: + set(val): + id = val + track_data(&"id", val) + + ## The login name of the user to get. To specify more than one user, include the _login_ parameter for each user to get. For example, `login=foo&login=bar`. The maximum number of login names you may specify is 100. + @export var login: Array[String]: + set(val): + login = val + track_data(&"login", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("id", null) != null: + for value in d["id"]: + result.id.append(value) + if d.get("login", null) != null: + for value in d["login"]: + result.login.append(value) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_users.gd.uid b/addons/twitcher/generated/twitch_get_users.gd.uid new file mode 100644 index 0000000..a4b9f7d --- /dev/null +++ b/addons/twitcher/generated/twitch_get_users.gd.uid @@ -0,0 +1 @@ +uid://chbom8p4hqbvq diff --git a/addons/twitcher/generated/twitch_get_vi_ps.gd b/addons/twitcher/generated/twitch_get_vi_ps.gd new file mode 100644 index 0000000..263412d --- /dev/null +++ b/addons/twitcher/generated/twitch_get_vi_ps.gd @@ -0,0 +1,109 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetVIPs + + + +## +## #/components/schemas/GetVIPsResponse +class Response extends TwitchData: + + ## The list of VIPs. The list is empty if the broadcaster doesn’t have VIP users. + @export var data: Array[TwitchUserVip]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchUserVip]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchUserVip.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetVIPsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s _after_ query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_vi_ps.gd.uid b/addons/twitcher/generated/twitch_get_vi_ps.gd.uid new file mode 100644 index 0000000..c87446d --- /dev/null +++ b/addons/twitcher/generated/twitch_get_vi_ps.gd.uid @@ -0,0 +1 @@ +uid://b8cnn7h1vimui diff --git a/addons/twitcher/generated/twitch_get_videos.gd b/addons/twitcher/generated/twitch_get_videos.gd new file mode 100644 index 0000000..0d0686c --- /dev/null +++ b/addons/twitcher/generated/twitch_get_videos.gd @@ -0,0 +1,248 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetVideos + + + +## +## #/components/schemas/GetVideosResponse +class Response extends TwitchData: + + ## The list of published videos that match the filter criteria. + @export var data: Array[TwitchVideo]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchVideo]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchVideo.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/GetVideosResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request's _after_ or _before_ query parameter depending on whether you're paging forwards or backwards through the results. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.get_videos +## #/components/schemas/GetVideosOpt +class Opt extends TwitchData: + + ## A list of IDs that identify the videos you want to get. To get more than one video, include this parameter for each video you want to get. For example, `id=1234&id=5678`. You may specify a maximum of 100 IDs. The endpoint ignores duplicate IDs and IDs that weren't found (if there's at least one valid ID). + ## + ## The _id_, _user\_id_, and _game\_id_ parameters are mutually exclusive. + @export var id: Array[String]: + set(val): + id = val + track_data(&"id", val) + + ## The ID of the user whose list of videos you want to get. + ## + ## The _id_, _user\_id_, and _game\_id_ parameters are mutually exclusive. + @export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + + ## A category or game ID. The response contains a maximum of 500 videos that show this content. To get category/game IDs, use the [Search Categories](https://dev.twitch.tv/docs/api/reference#search-categories) endpoint. + ## + ## The _id_, _user\_id_, and _game\_id_ parameters are mutually exclusive. + @export var game_id: String: + set(val): + game_id = val + track_data(&"game_id", val) + + ## A filter used to filter the list of videos by the language that the video owner broadcasts in. For example, to get videos that were broadcast in German, set this parameter to the ISO 639-1 two-letter code for German (i.e., DE). For a list of supported languages, see [Supported Stream Language](https://help.twitch.tv/s/article/languages-on-twitch#streamlang). If the language is not supported, use “other.” + ## + ## Specify this parameter only if you specify the _game\_id_ query parameter. + @export var language: String: + set(val): + language = val + track_data(&"language", val) + + ## A filter used to filter the list of videos by when they were published. For example, videos published in the last week. Possible values are: + ## + ## * all + ## * day + ## * month + ## * week + ## + ## The default is "all," which returns videos published in all periods. + ## + ## Specify this parameter only if you specify the _game\_id_ or _user\_id_ query parameter. + @export var period: String: + set(val): + period = val + track_data(&"period", val) + + ## The order to sort the returned videos in. Possible values are: + ## + ## * time — Sort the results in descending order by when they were created (i.e., latest video first). + ## * trending — Sort the results in descending order by biggest gains in viewership (i.e., highest trending video first). + ## * views — Sort the results in descending order by most views (i.e., highest number of views first). + ## + ## The default is "time." + ## + ## Specify this parameter only if you specify the _game\_id_ or _user\_id_ query parameter. + @export var sort: String: + set(val): + sort = val + track_data(&"sort", val) + + ## A filter used to filter the list of videos by the video's type. Possible case-sensitive values are: + ## + ## * all + ## * archive — On-demand videos (VODs) of past streams. + ## * highlight — Highlight reels of past streams. + ## * upload — External videos that the broadcaster uploaded using the Video Producer. + ## + ## The default is "all," which returns all video types. + ## + ## Specify this parameter only if you specify the _game\_id_ or _user\_id_ query parameter. + @export var type: String: + set(val): + type = val + track_data(&"type", val) + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100\. The default is 20. + ## + ## Specify this parameter only if you specify the _game\_id_ or _user\_id_ query parameter. + @export var first: String: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + ## + ## Specify this parameter only if you specify the _user\_id_ query parameter. + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + ## The cursor used to get the previous page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + ## + ## Specify this parameter only if you specify the _user\_id_ query parameter. + @export var before: String: + set(val): + before = val + track_data(&"before", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("id", null) != null: + for value in d["id"]: + result.id.append(value) + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("game_id", null) != null: + result.game_id = d["game_id"] + if d.get("language", null) != null: + result.language = d["language"] + if d.get("period", null) != null: + result.period = d["period"] + if d.get("sort", null) != null: + result.sort = d["sort"] + if d.get("type", null) != null: + result.type = d["type"] + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + if d.get("before", null) != null: + result.before = d["before"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_videos.gd.uid b/addons/twitcher/generated/twitch_get_videos.gd.uid new file mode 100644 index 0000000..3ead0ea --- /dev/null +++ b/addons/twitcher/generated/twitch_get_videos.gd.uid @@ -0,0 +1 @@ +uid://cvomjx2io3x8g diff --git a/addons/twitcher/generated/twitch_get_vips.gd b/addons/twitcher/generated/twitch_get_vips.gd new file mode 100644 index 0000000..da17b80 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_vips.gd @@ -0,0 +1,50 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchGetVips + + + +## All optional parameters for TwitchAPI.get_vips +## #/components/schemas/GetVipsOpt +class Opt extends TwitchData: + + ## Filters the list for specific VIPs. To specify more than one user, include the _user\_id_ parameter for each user to get. For example, `&user_id=1234&user_id=5678`. The maximum number of IDs that you may specify is 100\. Ignores the ID of those users in the list that aren’t VIPs. + @export var user_id: Array[String]: + set(val): + user_id = val + track_data(&"user_id", val) + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100\. The default is 20. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("user_id", null) != null: + for value in d["user_id"]: + result.user_id.append(value) + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_get_vips.gd.uid b/addons/twitcher/generated/twitch_get_vips.gd.uid new file mode 100644 index 0000000..d66cc40 --- /dev/null +++ b/addons/twitcher/generated/twitch_get_vips.gd.uid @@ -0,0 +1 @@ +uid://nc2aban0weuf diff --git a/addons/twitcher/generated/twitch_global_emote.gd b/addons/twitcher/generated/twitch_global_emote.gd new file mode 100644 index 0000000..ec29296 --- /dev/null +++ b/addons/twitcher/generated/twitch_global_emote.gd @@ -0,0 +1,137 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/GlobalEmote +class_name TwitchGlobalEmote + +## An ID that identifies this emote. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The name of the emote. This is the name that viewers type in the chat window to get the emote to appear. +@export var name: String: + set(val): + name = val + track_data(&"name", val) + +## The image URLs for the emote. These image URLs always provide a static, non-animated emote image with a light background. +## +## **NOTE:** You should use the templated URL in the `template` field to fetch the image instead of using these URLs. +@export var images: Images: + set(val): + images = val + track_data(&"images", val) + +## The formats that the emote is available in. For example, if the emote is available only as a static PNG, the array contains only `static`. But if the emote is available as a static PNG and an animated GIF, the array contains `static` and `animated`. The possible formats are: +## +## * animated — An animated GIF is available for this emote. +## * static — A static PNG file is available for this emote. +@export var format: Array[String]: + set(val): + format = val + track_data(&"format", val) + +## The sizes that the emote is available in. For example, if the emote is available in small and medium sizes, the array contains 1.0 and 2.0\. Possible sizes are: +## +## * 1.0 — A small version (28px x 28px) is available. +## * 2.0 — A medium version (56px x 56px) is available. +## * 3.0 — A large version (112px x 112px) is available. +@export var scale: Array[String]: + set(val): + scale = val + track_data(&"scale", val) + +## The background themes that the emote is available in. Possible themes are: +## +## * dark +## * light +@export var theme_mode: Array[String]: + set(val): + theme_mode = val + track_data(&"theme_mode", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _name: String, _images: Images, _format: Array[String], _scale: Array[String], _theme_mode: Array[String]) -> TwitchGlobalEmote: + var twitch_global_emote: TwitchGlobalEmote = TwitchGlobalEmote.new() + twitch_global_emote.id = _id + twitch_global_emote.name = _name + twitch_global_emote.images = _images + twitch_global_emote.format = _format + twitch_global_emote.scale = _scale + twitch_global_emote.theme_mode = _theme_mode + return twitch_global_emote + + +static func from_json(d: Dictionary) -> TwitchGlobalEmote: + var result: TwitchGlobalEmote = TwitchGlobalEmote.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("name", null) != null: + result.name = d["name"] + if d.get("images", null) != null: + result.images = Images.from_json(d["images"]) + if d.get("format", null) != null: + for value in d["format"]: + result.format.append(value) + if d.get("scale", null) != null: + for value in d["scale"]: + result.scale.append(value) + if d.get("theme_mode", null) != null: + for value in d["theme_mode"]: + result.theme_mode.append(value) + return result + + + +## The image URLs for the emote. These image URLs always provide a static, non-animated emote image with a light background. +## +## **NOTE:** You should use the templated URL in the `template` field to fetch the image instead of using these URLs. +## #/components/schemas/GlobalEmote/Images +class Images extends TwitchData: + + ## A URL to the small version (28px x 28px) of the emote. + @export var url_1x: String: + set(val): + url_1x = val + track_data(&"url_1x", val) + + ## A URL to the medium version (56px x 56px) of the emote. + @export var url_2x: String: + set(val): + url_2x = val + track_data(&"url_2x", val) + + ## A URL to the large version (112px x 112px) of the emote. + @export var url_4x: String: + set(val): + url_4x = val + track_data(&"url_4x", val) + + + + ## Constructor with all required fields. + static func create(_url_1x: String, _url_2x: String, _url_4x: String) -> Images: + var images: Images = Images.new() + images.url_1x = _url_1x + images.url_2x = _url_2x + images.url_4x = _url_4x + return images + + + static func from_json(d: Dictionary) -> Images: + var result: Images = Images.new() + if d.get("url_1x", null) != null: + result.url_1x = d["url_1x"] + if d.get("url_2x", null) != null: + result.url_2x = d["url_2x"] + if d.get("url_4x", null) != null: + result.url_4x = d["url_4x"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_global_emote.gd.uid b/addons/twitcher/generated/twitch_global_emote.gd.uid new file mode 100644 index 0000000..0d3fe7e --- /dev/null +++ b/addons/twitcher/generated/twitch_global_emote.gd.uid @@ -0,0 +1 @@ +uid://y5jlmdqski4v diff --git a/addons/twitcher/generated/twitch_guest.gd b/addons/twitcher/generated/twitch_guest.gd new file mode 100644 index 0000000..101a36f --- /dev/null +++ b/addons/twitcher/generated/twitch_guest.gd @@ -0,0 +1,197 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/Guest +class_name TwitchGuest + +## ID representing this guest’s slot assignment. +## +## * Host is always in slot "0" +## * Guests are assigned the following consecutive IDs (e.g, "1", "2", "3", etc) +## * Screen Share is represented as a special guest with the ID "SCREENSHARE" +## * The identifier here matches the ID referenced in browser source links used in broadcasting software. +@export var slot_id: String: + set(val): + slot_id = val + track_data(&"slot_id", val) + +## Flag determining whether or not the guest is visible in the browser source in the host’s streaming software. +@export var is_live: bool: + set(val): + is_live = val + track_data(&"is_live", val) + +## User ID of the guest assigned to this slot. +@export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + +## Display name of the guest assigned to this slot. +@export var user_display_name: String: + set(val): + user_display_name = val + track_data(&"user_display_name", val) + +## Login of the guest assigned to this slot. +@export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) + +## Value from 0 to 100 representing the host’s volume setting for this guest. +@export var volume: int: + set(val): + volume = val + track_data(&"volume", val) + +## Timestamp when this guest was assigned a slot in the session. +@export var assigned_at: String: + set(val): + assigned_at = val + track_data(&"assigned_at", val) + +## Information about the guest’s audio settings +@export var audio_settings: AudioSettings: + set(val): + audio_settings = val + track_data(&"audio_settings", val) + +## Information about the guest’s video settings +@export var video_settings: VideoSettings: + set(val): + video_settings = val + track_data(&"video_settings", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_slot_id: String, _is_live: bool, _user_id: String, _user_display_name: String, _user_login: String, _volume: int, _assigned_at: String, _audio_settings: AudioSettings, _video_settings: VideoSettings) -> TwitchGuest: + var twitch_guest: TwitchGuest = TwitchGuest.new() + twitch_guest.slot_id = _slot_id + twitch_guest.is_live = _is_live + twitch_guest.user_id = _user_id + twitch_guest.user_display_name = _user_display_name + twitch_guest.user_login = _user_login + twitch_guest.volume = _volume + twitch_guest.assigned_at = _assigned_at + twitch_guest.audio_settings = _audio_settings + twitch_guest.video_settings = _video_settings + return twitch_guest + + +static func from_json(d: Dictionary) -> TwitchGuest: + var result: TwitchGuest = TwitchGuest.new() + if d.get("slot_id", null) != null: + result.slot_id = d["slot_id"] + if d.get("is_live", null) != null: + result.is_live = d["is_live"] + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_display_name", null) != null: + result.user_display_name = d["user_display_name"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + if d.get("volume", null) != null: + result.volume = d["volume"] + if d.get("assigned_at", null) != null: + result.assigned_at = d["assigned_at"] + if d.get("audio_settings", null) != null: + result.audio_settings = AudioSettings.from_json(d["audio_settings"]) + if d.get("video_settings", null) != null: + result.video_settings = VideoSettings.from_json(d["video_settings"]) + return result + + + +## Information about the guest’s audio settings +## #/components/schemas/Guest/AudioSettings +class AudioSettings extends TwitchData: + + ## Flag determining whether the host is allowing the guest’s audio to be seen or heard within the session. + @export var is_host_enabled: bool: + set(val): + is_host_enabled = val + track_data(&"is_host_enabled", val) + + ## Flag determining whether the guest is allowing their audio to be transmitted to the session. + @export var is_guest_enabled: bool: + set(val): + is_guest_enabled = val + track_data(&"is_guest_enabled", val) + + ## Flag determining whether the guest has an appropriate audio device available to be transmitted to the session. + @export var is_available: bool: + set(val): + is_available = val + track_data(&"is_available", val) + + + + ## Constructor with all required fields. + static func create(_is_host_enabled: bool, _is_guest_enabled: bool, _is_available: bool) -> AudioSettings: + var audio_settings: AudioSettings = AudioSettings.new() + audio_settings.is_host_enabled = _is_host_enabled + audio_settings.is_guest_enabled = _is_guest_enabled + audio_settings.is_available = _is_available + return audio_settings + + + static func from_json(d: Dictionary) -> AudioSettings: + var result: AudioSettings = AudioSettings.new() + if d.get("is_host_enabled", null) != null: + result.is_host_enabled = d["is_host_enabled"] + if d.get("is_guest_enabled", null) != null: + result.is_guest_enabled = d["is_guest_enabled"] + if d.get("is_available", null) != null: + result.is_available = d["is_available"] + return result + + + +## Information about the guest’s video settings +## #/components/schemas/Guest/VideoSettings +class VideoSettings extends TwitchData: + + ## Flag determining whether the host is allowing the guest’s video to be seen or heard within the session. + @export var is_host_enabled: bool: + set(val): + is_host_enabled = val + track_data(&"is_host_enabled", val) + + ## Flag determining whether the guest is allowing their video to be transmitted to the session. + @export var is_guest_enabled: bool: + set(val): + is_guest_enabled = val + track_data(&"is_guest_enabled", val) + + ## Flag determining whether the guest has an appropriate video device available to be transmitted to the session. + @export var is_available: bool: + set(val): + is_available = val + track_data(&"is_available", val) + + + + ## Constructor with all required fields. + static func create(_is_host_enabled: bool, _is_guest_enabled: bool, _is_available: bool) -> VideoSettings: + var video_settings: VideoSettings = VideoSettings.new() + video_settings.is_host_enabled = _is_host_enabled + video_settings.is_guest_enabled = _is_guest_enabled + video_settings.is_available = _is_available + return video_settings + + + static func from_json(d: Dictionary) -> VideoSettings: + var result: VideoSettings = VideoSettings.new() + if d.get("is_host_enabled", null) != null: + result.is_host_enabled = d["is_host_enabled"] + if d.get("is_guest_enabled", null) != null: + result.is_guest_enabled = d["is_guest_enabled"] + if d.get("is_available", null) != null: + result.is_available = d["is_available"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_guest.gd.uid b/addons/twitcher/generated/twitch_guest.gd.uid new file mode 100644 index 0000000..5665737 --- /dev/null +++ b/addons/twitcher/generated/twitch_guest.gd.uid @@ -0,0 +1 @@ +uid://r51io6o4te3i diff --git a/addons/twitcher/generated/twitch_guest_star_invite.gd b/addons/twitcher/generated/twitch_guest_star_invite.gd new file mode 100644 index 0000000..82c722f --- /dev/null +++ b/addons/twitcher/generated/twitch_guest_star_invite.gd @@ -0,0 +1,87 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/GuestStarInvite +class_name TwitchGuestStarInvite + +## Twitch User ID corresponding to the invited guest +@export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + +## Timestamp when this user was invited to the session. +@export var invited_at: String: + set(val): + invited_at = val + track_data(&"invited_at", val) + +## Status representing the invited user’s join state. Can be one of the following: +## +## * `INVITED`: The user has been invited to the session but has not acknowledged it. +## * `ACCEPTED`: The invited user has acknowledged the invite and joined the waiting room, but may still be setting up their media devices or otherwise preparing to join the call. +## * `READY`: The invited user has signaled they are ready to join the call from the waiting room. +@export var status: String: + set(val): + status = val + track_data(&"status", val) + +## Flag signaling that the invited user has chosen to disable their local video device. The user has hidden themselves, but they may choose to reveal their video feed upon joining the session. +@export var is_video_enabled: bool: + set(val): + is_video_enabled = val + track_data(&"is_video_enabled", val) + +## Flag signaling that the invited user has chosen to disable their local audio device. The user has muted themselves, but they may choose to unmute their audio feed upon joining the session. +@export var is_audio_enabled: bool: + set(val): + is_audio_enabled = val + track_data(&"is_audio_enabled", val) + +## Flag signaling that the invited user has a video device available for sharing. +@export var is_video_available: bool: + set(val): + is_video_available = val + track_data(&"is_video_available", val) + +## Flag signaling that the invited user has an audio device available for sharing. +@export var is_audio_available: bool: + set(val): + is_audio_available = val + track_data(&"is_audio_available", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_user_id: String, _invited_at: String, _status: String, _is_video_enabled: bool, _is_audio_enabled: bool, _is_video_available: bool, _is_audio_available: bool) -> TwitchGuestStarInvite: + var twitch_guest_star_invite: TwitchGuestStarInvite = TwitchGuestStarInvite.new() + twitch_guest_star_invite.user_id = _user_id + twitch_guest_star_invite.invited_at = _invited_at + twitch_guest_star_invite.status = _status + twitch_guest_star_invite.is_video_enabled = _is_video_enabled + twitch_guest_star_invite.is_audio_enabled = _is_audio_enabled + twitch_guest_star_invite.is_video_available = _is_video_available + twitch_guest_star_invite.is_audio_available = _is_audio_available + return twitch_guest_star_invite + + +static func from_json(d: Dictionary) -> TwitchGuestStarInvite: + var result: TwitchGuestStarInvite = TwitchGuestStarInvite.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("invited_at", null) != null: + result.invited_at = d["invited_at"] + if d.get("status", null) != null: + result.status = d["status"] + if d.get("is_video_enabled", null) != null: + result.is_video_enabled = d["is_video_enabled"] + if d.get("is_audio_enabled", null) != null: + result.is_audio_enabled = d["is_audio_enabled"] + if d.get("is_video_available", null) != null: + result.is_video_available = d["is_video_available"] + if d.get("is_audio_available", null) != null: + result.is_audio_available = d["is_audio_available"] + return result diff --git a/addons/twitcher/generated/twitch_guest_star_invite.gd.uid b/addons/twitcher/generated/twitch_guest_star_invite.gd.uid new file mode 100644 index 0000000..da6ffdd --- /dev/null +++ b/addons/twitcher/generated/twitch_guest_star_invite.gd.uid @@ -0,0 +1 @@ +uid://ba0i6iveocqcg diff --git a/addons/twitcher/generated/twitch_guest_star_session.gd b/addons/twitcher/generated/twitch_guest_star_session.gd new file mode 100644 index 0000000..c43f665 --- /dev/null +++ b/addons/twitcher/generated/twitch_guest_star_session.gd @@ -0,0 +1,39 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/GuestStarSession +class_name TwitchGuestStarSession + +## ID uniquely representing the Guest Star session. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## List of guests currently interacting with the Guest Star session. +@export var guests: Array[TwitchGuest]: + set(val): + guests = val + track_data(&"guests", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _guests: Array[TwitchGuest]) -> TwitchGuestStarSession: + var twitch_guest_star_session: TwitchGuestStarSession = TwitchGuestStarSession.new() + twitch_guest_star_session.id = _id + twitch_guest_star_session.guests = _guests + return twitch_guest_star_session + + +static func from_json(d: Dictionary) -> TwitchGuestStarSession: + var result: TwitchGuestStarSession = TwitchGuestStarSession.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("guests", null) != null: + for value in d["guests"]: + result.guests.append(TwitchGuest.from_json(value)) + return result diff --git a/addons/twitcher/generated/twitch_guest_star_session.gd.uid b/addons/twitcher/generated/twitch_guest_star_session.gd.uid new file mode 100644 index 0000000..9d16d6c --- /dev/null +++ b/addons/twitcher/generated/twitch_guest_star_session.gd.uid @@ -0,0 +1 @@ +uid://dd3j3aobm1p2t diff --git a/addons/twitcher/generated/twitch_hype_train_event.gd b/addons/twitcher/generated/twitch_hype_train_event.gd new file mode 100644 index 0000000..13c6ac1 --- /dev/null +++ b/addons/twitcher/generated/twitch_hype_train_event.gd @@ -0,0 +1,273 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/HypeTrainEvent +class_name TwitchHypeTrainEvent + +## An ID that identifies this event. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The type of event. The string is in the form, hypetrain.{event\_name}. The request returns only progress event types (i.e., hypetrain.progression). +@export var event_type: String: + set(val): + event_type = val + track_data(&"event_type", val) + +## The UTC date and time (in RFC3339 format) that the event occurred. +@export var event_timestamp: String: + set(val): + event_timestamp = val + track_data(&"event_timestamp", val) + +## The version number of the definition of the event’s data. For example, the value is 1 if the data in `event_data` uses the first definition of the event’s data. +@export var version: String: + set(val): + version = val + track_data(&"version", val) + +## The event’s data. +@export var event_data: EventData: + set(val): + event_data = val + track_data(&"event_data", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _event_type: String, _event_timestamp: String, _version: String, _event_data: EventData) -> TwitchHypeTrainEvent: + var twitch_hype_train_event: TwitchHypeTrainEvent = TwitchHypeTrainEvent.new() + twitch_hype_train_event.id = _id + twitch_hype_train_event.event_type = _event_type + twitch_hype_train_event.event_timestamp = _event_timestamp + twitch_hype_train_event.version = _version + twitch_hype_train_event.event_data = _event_data + return twitch_hype_train_event + + +static func from_json(d: Dictionary) -> TwitchHypeTrainEvent: + var result: TwitchHypeTrainEvent = TwitchHypeTrainEvent.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("event_type", null) != null: + result.event_type = d["event_type"] + if d.get("event_timestamp", null) != null: + result.event_timestamp = d["event_timestamp"] + if d.get("version", null) != null: + result.version = d["version"] + if d.get("event_data", null) != null: + result.event_data = EventData.from_json(d["event_data"]) + return result + + + +## The event’s data. +## #/components/schemas/HypeTrainEvent/EventData +class EventData extends TwitchData: + + ## The ID of the broadcaster that’s running the Hype Train. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## The UTC date and time (in RFC3339 format) that another Hype Train can start. + @export var cooldown_end_time: String: + set(val): + cooldown_end_time = val + track_data(&"cooldown_end_time", val) + + ## The UTC date and time (in RFC3339 format) that the Hype Train ends. + @export var expires_at: String: + set(val): + expires_at = val + track_data(&"expires_at", val) + + ## The value needed to reach the next level. + @export var goal: int: + set(val): + goal = val + track_data(&"goal", val) + + ## An ID that identifies this Hype Train. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## The most recent contribution towards the Hype Train’s goal. + @export var last_contribution: LastContribution: + set(val): + last_contribution = val + track_data(&"last_contribution", val) + + ## The highest level that the Hype Train reached (the levels are 1 through 5). + @export var level: int: + set(val): + level = val + track_data(&"level", val) + + ## The UTC date and time (in RFC3339 format) that this Hype Train started. + @export var started_at: String: + set(val): + started_at = val + track_data(&"started_at", val) + + ## The top contributors for each contribution type. For example, the top contributor using BITS (by aggregate) and the top contributor using SUBS (by count). + @export var top_contributions: Array[TopContributions]: + set(val): + top_contributions = val + track_data(&"top_contributions", val) + + ## The current total amount raised. + @export var total: int: + set(val): + total = val + track_data(&"total", val) + + + + ## Constructor with all required fields. + static func create(_broadcaster_id: String, _cooldown_end_time: String, _expires_at: String, _goal: int, _id: String, _last_contribution: LastContribution, _level: int, _started_at: String, _top_contributions: Array[TopContributions], _total: int) -> EventData: + var event_data: EventData = EventData.new() + event_data.broadcaster_id = _broadcaster_id + event_data.cooldown_end_time = _cooldown_end_time + event_data.expires_at = _expires_at + event_data.goal = _goal + event_data.id = _id + event_data.last_contribution = _last_contribution + event_data.level = _level + event_data.started_at = _started_at + event_data.top_contributions = _top_contributions + event_data.total = _total + return event_data + + + static func from_json(d: Dictionary) -> EventData: + var result: EventData = EventData.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("cooldown_end_time", null) != null: + result.cooldown_end_time = d["cooldown_end_time"] + if d.get("expires_at", null) != null: + result.expires_at = d["expires_at"] + if d.get("goal", null) != null: + result.goal = d["goal"] + if d.get("id", null) != null: + result.id = d["id"] + if d.get("last_contribution", null) != null: + result.last_contribution = LastContribution.from_json(d["last_contribution"]) + if d.get("level", null) != null: + result.level = d["level"] + if d.get("started_at", null) != null: + result.started_at = d["started_at"] + if d.get("top_contributions", null) != null: + for value in d["top_contributions"]: + result.top_contributions.append(TopContributions.from_json(value)) + if d.get("total", null) != null: + result.total = d["total"] + return result + + + +## The most recent contribution towards the Hype Train’s goal. +## #/components/schemas/HypeTrainEvent/EventData/LastContribution +class LastContribution extends TwitchData: + + ## The total amount contributed. If `type` is BITS, `total` represents the amount of Bits used. If `type` is SUBS, `total` is 500, 1000, or 2500 to represent tier 1, 2, or 3 subscriptions, respectively. + @export var total: int: + set(val): + total = val + track_data(&"total", val) + + ## The contribution method used. Possible values are: + ## + ## * BITS — Cheering with Bits. + ## * SUBS — Subscription activity like subscribing or gifting subscriptions. + ## * OTHER — Covers other contribution methods not listed. + @export var type: String: + set(val): + type = val + track_data(&"type", val) + + ## The ID of the user that made the contribution. + @export var user: String: + set(val): + user = val + track_data(&"user", val) + + + + ## Constructor with all required fields. + static func create(_total: int, _type: String, _user: String) -> LastContribution: + var last_contribution: LastContribution = LastContribution.new() + last_contribution.total = _total + last_contribution.type = _type + last_contribution.user = _user + return last_contribution + + + static func from_json(d: Dictionary) -> LastContribution: + var result: LastContribution = LastContribution.new() + if d.get("total", null) != null: + result.total = d["total"] + if d.get("type", null) != null: + result.type = d["type"] + if d.get("user", null) != null: + result.user = d["user"] + return result + + + +## The top contributors for each contribution type. For example, the top contributor using BITS (by aggregate) and the top contributor using SUBS (by count). +## #/components/schemas/HypeTrainEvent/EventData/TopContributions +class TopContributions extends TwitchData: + + ## The total amount contributed. If `type` is BITS, `total` represents the amount of Bits used. If `type` is SUBS, `total` is 500, 1000, or 2500 to represent tier 1, 2, or 3 subscriptions, respectively. + @export var total: int: + set(val): + total = val + track_data(&"total", val) + + ## The contribution method used. Possible values are: + ## + ## * BITS — Cheering with Bits. + ## * SUBS — Subscription activity like subscribing or gifting subscriptions. + ## * OTHER — Covers other contribution methods not listed. + @export var type: String: + set(val): + type = val + track_data(&"type", val) + + ## The ID of the user that made the contribution. + @export var user: String: + set(val): + user = val + track_data(&"user", val) + + + + ## Constructor with all required fields. + static func create(_total: int, _type: String, _user: String) -> TopContributions: + var top_contributions: TopContributions = TopContributions.new() + top_contributions.total = _total + top_contributions.type = _type + top_contributions.user = _user + return top_contributions + + + static func from_json(d: Dictionary) -> TopContributions: + var result: TopContributions = TopContributions.new() + if d.get("total", null) != null: + result.total = d["total"] + if d.get("type", null) != null: + result.type = d["type"] + if d.get("user", null) != null: + result.user = d["user"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_hype_train_event.gd.uid b/addons/twitcher/generated/twitch_hype_train_event.gd.uid new file mode 100644 index 0000000..cf6b30a --- /dev/null +++ b/addons/twitcher/generated/twitch_hype_train_event.gd.uid @@ -0,0 +1 @@ +uid://dd8nh686wvbie diff --git a/addons/twitcher/generated/twitch_manage_held_auto_mod_messages.gd b/addons/twitcher/generated/twitch_manage_held_auto_mod_messages.gd new file mode 100644 index 0000000..2c87dac --- /dev/null +++ b/addons/twitcher/generated/twitch_manage_held_auto_mod_messages.gd @@ -0,0 +1,55 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchManageHeldAutoModMessages + + + +## +## #/components/schemas/ManageHeldAutoModMessagesBody +class Body extends TwitchData: + + ## The moderator who is approving or denying the held message. This ID must match the user ID in the access token. + @export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + + ## The ID of the message to allow or deny. + @export var msg_id: String: + set(val): + msg_id = val + track_data(&"msg_id", val) + + ## The action to take for the message. Possible values are: + ## + ## * ALLOW + ## * DENY + @export var action: String: + set(val): + action = val + track_data(&"action", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_user_id: String, _msg_id: String, _action: String) -> Body: + var body: Body = Body.new() + body.user_id = _user_id + body.msg_id = _msg_id + body.action = _action + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("msg_id", null) != null: + result.msg_id = d["msg_id"] + if d.get("action", null) != null: + result.action = d["action"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_manage_held_auto_mod_messages.gd.uid b/addons/twitcher/generated/twitch_manage_held_auto_mod_messages.gd.uid new file mode 100644 index 0000000..f70f464 --- /dev/null +++ b/addons/twitcher/generated/twitch_manage_held_auto_mod_messages.gd.uid @@ -0,0 +1 @@ +uid://blw16lh307ick diff --git a/addons/twitcher/generated/twitch_modify_channel_information.gd b/addons/twitcher/generated/twitch_modify_channel_information.gd new file mode 100644 index 0000000..4d8c6fd --- /dev/null +++ b/addons/twitcher/generated/twitch_modify_channel_information.gd @@ -0,0 +1,128 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchModifyChannelInformation + + + +## +## #/components/schemas/ModifyChannelInformationBody +class Body extends TwitchData: + + ## The ID of the game that the user plays. The game is not updated if the ID isn’t a game ID that Twitch recognizes. To unset this field, use “0” or “” (an empty string). + @export var game_id: String: + set(val): + game_id = val + track_data(&"game_id", val) + + ## The user’s preferred language. Set the value to an ISO 639-1 two-letter language code (for example, _en_ for English). Set to “other” if the user’s preferred language is not a Twitch supported language. The language isn’t updated if the language code isn’t a Twitch supported language. + @export var broadcaster_language: String: + set(val): + broadcaster_language = val + track_data(&"broadcaster_language", val) + + ## The title of the user’s stream. You may not set this field to an empty string. + @export var title: String: + set(val): + title = val + track_data(&"title", val) + + ## The number of seconds you want your broadcast buffered before streaming it live. The delay helps ensure fairness during competitive play. Only users with Partner status may set this field. The maximum delay is 900 seconds (15 minutes). + @export var delay: int: + set(val): + delay = val + track_data(&"delay", val) + + ## A list of channel-defined tags to apply to the channel. To remove all tags from the channel, set tags to an empty array. Tags help identify the content that the channel streams. [Learn More](https://help.twitch.tv/s/article/guide-to-tags) + ## + ## A channel may specify a maximum of 10 tags. Each tag is limited to a maximum of 25 characters and may not be an empty string or contain spaces or special characters. Tags are case insensitive. For readability, consider using camelCasing or PascalCasing. + @export var tags: Array[String]: + set(val): + tags = val + track_data(&"tags", val) + + ## List of labels that should be set as the Channel’s CCLs. + @export var content_classification_labels: Array[BodyContentClassificationLabels]: + set(val): + content_classification_labels = val + track_data(&"content_classification_labels", val) + + ## Boolean flag indicating if the channel has branded content. + @export var is_branded_content: bool: + set(val): + is_branded_content = val + track_data(&"is_branded_content", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create() -> Body: + var body: Body = Body.new() + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("game_id", null) != null: + result.game_id = d["game_id"] + if d.get("broadcaster_language", null) != null: + result.broadcaster_language = d["broadcaster_language"] + if d.get("title", null) != null: + result.title = d["title"] + if d.get("delay", null) != null: + result.delay = d["delay"] + if d.get("tags", null) != null: + for value in d["tags"]: + result.tags.append(value) + if d.get("content_classification_labels", null) != null: + for value in d["content_classification_labels"]: + result.content_classification_labels.append(BodyContentClassificationLabels.from_json(value)) + if d.get("is_branded_content", null) != null: + result.is_branded_content = d["is_branded_content"] + return result + + + +## List of labels that should be set as the Channel’s CCLs. +## #/components/schemas/ModifyChannelInformationBody/ContentClassificationLabels +class BodyContentClassificationLabels extends TwitchData: + + ## ID of the [Content Classification Labels](https://help.twitch.tv/s/article/content-classification-labels) that must be added/removed from the channel. Can be one of the following values: + ## + ## * DebatedSocialIssuesAndPolitics + ## * DrugsIntoxication + ## * SexualThemes + ## * ViolentGraphic + ## * Gambling + ## * ProfanityVulgarity + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## Boolean flag indicating whether the label should be enabled (true) or disabled for the channel. + @export var is_enabled: bool: + set(val): + is_enabled = val + track_data(&"is_enabled", val) + + + + ## Constructor with all required fields. + static func create(_id: String, _is_enabled: bool) -> BodyContentClassificationLabels: + var body_content_classification_labels: BodyContentClassificationLabels = BodyContentClassificationLabels.new() + body_content_classification_labels.id = _id + body_content_classification_labels.is_enabled = _is_enabled + return body_content_classification_labels + + + static func from_json(d: Dictionary) -> BodyContentClassificationLabels: + var result: BodyContentClassificationLabels = BodyContentClassificationLabels.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("is_enabled", null) != null: + result.is_enabled = d["is_enabled"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_modify_channel_information.gd.uid b/addons/twitcher/generated/twitch_modify_channel_information.gd.uid new file mode 100644 index 0000000..7f459d3 --- /dev/null +++ b/addons/twitcher/generated/twitch_modify_channel_information.gd.uid @@ -0,0 +1 @@ +uid://b2fyqvrox2xvl diff --git a/addons/twitcher/generated/twitch_poll.gd b/addons/twitcher/generated/twitch_poll.gd new file mode 100644 index 0000000..0737c1c --- /dev/null +++ b/addons/twitcher/generated/twitch_poll.gd @@ -0,0 +1,218 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/Poll +class_name TwitchPoll + +## An ID that identifies the poll. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## An ID that identifies the broadcaster that created the poll. +@export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + +## The broadcaster’s display name. +@export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + +## The broadcaster’s login name. +@export var broadcaster_login: String: + set(val): + broadcaster_login = val + track_data(&"broadcaster_login", val) + +## The question that viewers are voting on. For example, _What game should I play next?_ The title may contain a maximum of 60 characters. +@export var title: String: + set(val): + title = val + track_data(&"title", val) + +## A list of choices that viewers can choose from. The list will contain a minimum of two choices and up to a maximum of five choices. +@export var choices: Array[Choices]: + set(val): + choices = val + track_data(&"choices", val) + +## Not used; will be set to **false**. +@export var bits_voting_enabled: bool: + set(val): + bits_voting_enabled = val + track_data(&"bits_voting_enabled", val) + +## Not used; will be set to 0. +@export var bits_per_vote: int: + set(val): + bits_per_vote = val + track_data(&"bits_per_vote", val) + +## A Boolean value that indicates whether viewers may cast additional votes using Channel Points. For information about Channel Points, see [Channel Points Guide](https://help.twitch.tv/s/article/channel-points-guide). +@export var channel_points_voting_enabled: bool: + set(val): + channel_points_voting_enabled = val + track_data(&"channel_points_voting_enabled", val) + +## The number of points the viewer must spend to cast one additional vote. +@export var channel_points_per_vote: int: + set(val): + channel_points_per_vote = val + track_data(&"channel_points_per_vote", val) + +## The poll’s status. Valid values are: +## +## * ACTIVE — The poll is running. +## * COMPLETED — The poll ended on schedule (see the `duration` field). +## * TERMINATED — The poll was terminated before its scheduled end. +## * ARCHIVED — The poll has been archived and is no longer visible on the channel. +## * MODERATED — The poll was deleted. +## * INVALID — Something went wrong while determining the state. +@export var status: String: + set(val): + status = val + track_data(&"status", val) + +## The length of time (in seconds) that the poll will run for. +@export var duration: int: + set(val): + duration = val + track_data(&"duration", val) + +## The UTC date and time (in RFC3339 format) of when the poll began. +@export var started_at: String: + set(val): + started_at = val + track_data(&"started_at", val) + +## The UTC date and time (in RFC3339 format) of when the poll ended. If `status` is ACTIVE, this field is set to **null**. +@export var ended_at: String: + set(val): + ended_at = val + track_data(&"ended_at", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _broadcaster_id: String, _broadcaster_name: String, _broadcaster_login: String, _title: String, _choices: Array[Choices], _bits_voting_enabled: bool, _bits_per_vote: int, _channel_points_voting_enabled: bool, _channel_points_per_vote: int, _status: String, _duration: int, _started_at: String, _ended_at: String) -> TwitchPoll: + var twitch_poll: TwitchPoll = TwitchPoll.new() + twitch_poll.id = _id + twitch_poll.broadcaster_id = _broadcaster_id + twitch_poll.broadcaster_name = _broadcaster_name + twitch_poll.broadcaster_login = _broadcaster_login + twitch_poll.title = _title + twitch_poll.choices = _choices + twitch_poll.bits_voting_enabled = _bits_voting_enabled + twitch_poll.bits_per_vote = _bits_per_vote + twitch_poll.channel_points_voting_enabled = _channel_points_voting_enabled + twitch_poll.channel_points_per_vote = _channel_points_per_vote + twitch_poll.status = _status + twitch_poll.duration = _duration + twitch_poll.started_at = _started_at + twitch_poll.ended_at = _ended_at + return twitch_poll + + +static func from_json(d: Dictionary) -> TwitchPoll: + var result: TwitchPoll = TwitchPoll.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + if d.get("broadcaster_login", null) != null: + result.broadcaster_login = d["broadcaster_login"] + if d.get("title", null) != null: + result.title = d["title"] + if d.get("choices", null) != null: + for value in d["choices"]: + result.choices.append(Choices.from_json(value)) + if d.get("bits_voting_enabled", null) != null: + result.bits_voting_enabled = d["bits_voting_enabled"] + if d.get("bits_per_vote", null) != null: + result.bits_per_vote = d["bits_per_vote"] + if d.get("channel_points_voting_enabled", null) != null: + result.channel_points_voting_enabled = d["channel_points_voting_enabled"] + if d.get("channel_points_per_vote", null) != null: + result.channel_points_per_vote = d["channel_points_per_vote"] + if d.get("status", null) != null: + result.status = d["status"] + if d.get("duration", null) != null: + result.duration = d["duration"] + if d.get("started_at", null) != null: + result.started_at = d["started_at"] + if d.get("ended_at", null) != null: + result.ended_at = d["ended_at"] + return result + + + +## A list of choices that viewers can choose from. The list will contain a minimum of two choices and up to a maximum of five choices. +## #/components/schemas/Poll/Choices +class Choices extends TwitchData: + + ## An ID that identifies this choice. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## The choice’s title. The title may contain a maximum of 25 characters. + @export var title: String: + set(val): + title = val + track_data(&"title", val) + + ## The total number of votes cast for this choice. + @export var votes: int: + set(val): + votes = val + track_data(&"votes", val) + + ## The number of votes cast using Channel Points. + @export var channel_points_votes: int: + set(val): + channel_points_votes = val + track_data(&"channel_points_votes", val) + + ## Not used; will be set to 0. + @export var bits_votes: int: + set(val): + bits_votes = val + track_data(&"bits_votes", val) + + + + ## Constructor with all required fields. + static func create(_id: String, _title: String, _votes: int, _channel_points_votes: int, _bits_votes: int) -> Choices: + var choices: Choices = Choices.new() + choices.id = _id + choices.title = _title + choices.votes = _votes + choices.channel_points_votes = _channel_points_votes + choices.bits_votes = _bits_votes + return choices + + + static func from_json(d: Dictionary) -> Choices: + var result: Choices = Choices.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("title", null) != null: + result.title = d["title"] + if d.get("votes", null) != null: + result.votes = d["votes"] + if d.get("channel_points_votes", null) != null: + result.channel_points_votes = d["channel_points_votes"] + if d.get("bits_votes", null) != null: + result.bits_votes = d["bits_votes"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_poll.gd.uid b/addons/twitcher/generated/twitch_poll.gd.uid new file mode 100644 index 0000000..b34e2f2 --- /dev/null +++ b/addons/twitcher/generated/twitch_poll.gd.uid @@ -0,0 +1 @@ +uid://c4571q6e06upy diff --git a/addons/twitcher/generated/twitch_prediction.gd b/addons/twitcher/generated/twitch_prediction.gd new file mode 100644 index 0000000..dafa91d --- /dev/null +++ b/addons/twitcher/generated/twitch_prediction.gd @@ -0,0 +1,134 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/Prediction +class_name TwitchPrediction + +## An ID that identifies this prediction. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## An ID that identifies the broadcaster that created the prediction. +@export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + +## The broadcaster’s display name. +@export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + +## The broadcaster’s login name. +@export var broadcaster_login: String: + set(val): + broadcaster_login = val + track_data(&"broadcaster_login", val) + +## The question that the prediction asks. For example, _Will I finish this entire pizza?_ +@export var title: String: + set(val): + title = val + track_data(&"title", val) + +## The ID of the winning outcome. Is **null** unless `status` is RESOLVED. +@export var winning_outcome_id: String: + set(val): + winning_outcome_id = val + track_data(&"winning_outcome_id", val) + +## The list of possible outcomes for the prediction. +@export var outcomes: Array[TwitchPredictionOutcome]: + set(val): + outcomes = val + track_data(&"outcomes", val) + +## The length of time (in seconds) that the prediction will run for. +@export var prediction_window: int: + set(val): + prediction_window = val + track_data(&"prediction_window", val) + +## The prediction’s status. Valid values are: +## +## * ACTIVE — The Prediction is running and viewers can make predictions. +## * CANCELED — The broadcaster canceled the Prediction and refunded the Channel Points to the participants. +## * LOCKED — The broadcaster locked the Prediction, which means viewers can no longer make predictions. +## * RESOLVED — The winning outcome was determined and the Channel Points were distributed to the viewers who predicted the correct outcome. +@export var status: String: + set(val): + status = val + track_data(&"status", val) + +## The UTC date and time of when the Prediction began. +@export var created_at: String: + set(val): + created_at = val + track_data(&"created_at", val) + +## The UTC date and time of when the Prediction ended. If `status` is ACTIVE, this is set to **null**. +@export var ended_at: String: + set(val): + ended_at = val + track_data(&"ended_at", val) + +## The UTC date and time of when the Prediction was locked. If `status` is not LOCKED, this is set to **null**. +@export var locked_at: String: + set(val): + locked_at = val + track_data(&"locked_at", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _broadcaster_id: String, _broadcaster_name: String, _broadcaster_login: String, _title: String, _winning_outcome_id: String, _outcomes: Array[TwitchPredictionOutcome], _prediction_window: int, _status: String, _created_at: String, _ended_at: String, _locked_at: String) -> TwitchPrediction: + var twitch_prediction: TwitchPrediction = TwitchPrediction.new() + twitch_prediction.id = _id + twitch_prediction.broadcaster_id = _broadcaster_id + twitch_prediction.broadcaster_name = _broadcaster_name + twitch_prediction.broadcaster_login = _broadcaster_login + twitch_prediction.title = _title + twitch_prediction.winning_outcome_id = _winning_outcome_id + twitch_prediction.outcomes = _outcomes + twitch_prediction.prediction_window = _prediction_window + twitch_prediction.status = _status + twitch_prediction.created_at = _created_at + twitch_prediction.ended_at = _ended_at + twitch_prediction.locked_at = _locked_at + return twitch_prediction + + +static func from_json(d: Dictionary) -> TwitchPrediction: + var result: TwitchPrediction = TwitchPrediction.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + if d.get("broadcaster_login", null) != null: + result.broadcaster_login = d["broadcaster_login"] + if d.get("title", null) != null: + result.title = d["title"] + if d.get("winning_outcome_id", null) != null: + result.winning_outcome_id = d["winning_outcome_id"] + if d.get("outcomes", null) != null: + for value in d["outcomes"]: + result.outcomes.append(TwitchPredictionOutcome.from_json(value)) + if d.get("prediction_window", null) != null: + result.prediction_window = d["prediction_window"] + if d.get("status", null) != null: + result.status = d["status"] + if d.get("created_at", null) != null: + result.created_at = d["created_at"] + if d.get("ended_at", null) != null: + result.ended_at = d["ended_at"] + if d.get("locked_at", null) != null: + result.locked_at = d["locked_at"] + return result diff --git a/addons/twitcher/generated/twitch_prediction.gd.uid b/addons/twitcher/generated/twitch_prediction.gd.uid new file mode 100644 index 0000000..36affd5 --- /dev/null +++ b/addons/twitcher/generated/twitch_prediction.gd.uid @@ -0,0 +1 @@ +uid://s4i670p4bu33 diff --git a/addons/twitcher/generated/twitch_prediction_outcome.gd b/addons/twitcher/generated/twitch_prediction_outcome.gd new file mode 100644 index 0000000..f7c929e --- /dev/null +++ b/addons/twitcher/generated/twitch_prediction_outcome.gd @@ -0,0 +1,144 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/PredictionOutcome +class_name TwitchPredictionOutcome + +## An ID that identifies this outcome. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The outcome’s text. +@export var title: String: + set(val): + title = val + track_data(&"title", val) + +## The number of unique viewers that chose this outcome. +@export var users: int: + set(val): + users = val + track_data(&"users", val) + +## The number of Channel Points spent by viewers on this outcome. +@export var channel_points: int: + set(val): + channel_points = val + track_data(&"channel_points", val) + +## A list of viewers who were the top predictors; otherwise, **null** if none. +@export var top_predictors: Array[TopPredictors]: + set(val): + top_predictors = val + track_data(&"top_predictors", val) + +## The color that visually identifies this outcome in the UX. Possible values are: +## +## * BLUE +## * PINK +## +## If the number of outcomes is two, the color is BLUE for the first outcome and PINK for the second outcome. If there are more than two outcomes, the color is BLUE for all outcomes. +@export var color: String: + set(val): + color = val + track_data(&"color", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _title: String, _users: int, _channel_points: int, _top_predictors: Array[TopPredictors], _color: String) -> TwitchPredictionOutcome: + var twitch_prediction_outcome: TwitchPredictionOutcome = TwitchPredictionOutcome.new() + twitch_prediction_outcome.id = _id + twitch_prediction_outcome.title = _title + twitch_prediction_outcome.users = _users + twitch_prediction_outcome.channel_points = _channel_points + twitch_prediction_outcome.top_predictors = _top_predictors + twitch_prediction_outcome.color = _color + return twitch_prediction_outcome + + +static func from_json(d: Dictionary) -> TwitchPredictionOutcome: + var result: TwitchPredictionOutcome = TwitchPredictionOutcome.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("title", null) != null: + result.title = d["title"] + if d.get("users", null) != null: + result.users = d["users"] + if d.get("channel_points", null) != null: + result.channel_points = d["channel_points"] + if d.get("top_predictors", null) != null: + for value in d["top_predictors"]: + result.top_predictors.append(TopPredictors.from_json(value)) + if d.get("color", null) != null: + result.color = d["color"] + return result + + + +## A list of viewers who were the top predictors; otherwise, **null** if none. +## #/components/schemas/PredictionOutcome/TopPredictors +class TopPredictors extends TwitchData: + + ## An ID that identifies the viewer. + @export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + + ## The viewer’s display name. + @export var user_name: String: + set(val): + user_name = val + track_data(&"user_name", val) + + ## The viewer’s login name. + @export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) + + ## The number of Channel Points the viewer spent. + @export var channel_points_used: int: + set(val): + channel_points_used = val + track_data(&"channel_points_used", val) + + ## The number of Channel Points distributed to the viewer. + @export var channel_points_won: int: + set(val): + channel_points_won = val + track_data(&"channel_points_won", val) + + + + ## Constructor with all required fields. + static func create(_user_id: String, _user_name: String, _user_login: String, _channel_points_used: int, _channel_points_won: int) -> TopPredictors: + var top_predictors: TopPredictors = TopPredictors.new() + top_predictors.user_id = _user_id + top_predictors.user_name = _user_name + top_predictors.user_login = _user_login + top_predictors.channel_points_used = _channel_points_used + top_predictors.channel_points_won = _channel_points_won + return top_predictors + + + static func from_json(d: Dictionary) -> TopPredictors: + var result: TopPredictors = TopPredictors.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_name", null) != null: + result.user_name = d["user_name"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + if d.get("channel_points_used", null) != null: + result.channel_points_used = d["channel_points_used"] + if d.get("channel_points_won", null) != null: + result.channel_points_won = d["channel_points_won"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_prediction_outcome.gd.uid b/addons/twitcher/generated/twitch_prediction_outcome.gd.uid new file mode 100644 index 0000000..00d7df1 --- /dev/null +++ b/addons/twitcher/generated/twitch_prediction_outcome.gd.uid @@ -0,0 +1 @@ +uid://t5p7p3s20fyc diff --git a/addons/twitcher/generated/twitch_resolve_unban_requests.gd b/addons/twitcher/generated/twitch_resolve_unban_requests.gd new file mode 100644 index 0000000..370bf66 --- /dev/null +++ b/addons/twitcher/generated/twitch_resolve_unban_requests.gd @@ -0,0 +1,217 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchResolveUnbanRequests + + + +## +## #/components/schemas/ResolveUnbanRequestsResponse +class Response extends TwitchData: + + ## + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + return result + + + +## +## #/components/schemas/ResolveUnbanRequestsResponse/Data +class ResponseData extends TwitchData: + + ## Unban request ID. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## User ID of broadcaster whose channel is receiving the unban request. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## The broadcaster’s login name. + @export var broadcaster_login: String: + set(val): + broadcaster_login = val + track_data(&"broadcaster_login", val) + + ## The broadcaster’s display name. + @export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + + ## User ID of moderator who approved/denied the request. + @export var moderator_id: String: + set(val): + moderator_id = val + track_data(&"moderator_id", val) + + ## The moderator’s login name. + @export var moderator_login: String: + set(val): + moderator_login = val + track_data(&"moderator_login", val) + + ## The moderator’s display name. + @export var moderator_name: String: + set(val): + moderator_name = val + track_data(&"moderator_name", val) + + ## User ID of the requestor who is asking for an unban. + @export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + + ## The user’s login name. + @export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) + + ## The user’s display name. + @export var user_name: String: + set(val): + user_name = val + track_data(&"user_name", val) + + ## Text of the request from the requesting user. + @export var text: String: + set(val): + text = val + track_data(&"text", val) + + ## Status of the request. One of: + ## + ## * approved + ## * denied + @export var status: String: + set(val): + status = val + track_data(&"status", val) + + ## Timestamp of when the unban request was created. + @export var created_at: String: + set(val): + created_at = val + track_data(&"created_at", val) + + ## Timestamp of when moderator/broadcaster approved or denied the request. + @export var resolved_at: String: + set(val): + resolved_at = val + track_data(&"resolved_at", val) + + ## Text input by the resolver (moderator) of the unban request. + @export var resolution_text: String: + set(val): + resolution_text = val + track_data(&"resolution_text", val) + + + + ## Constructor with all required fields. + static func create(_id: String, _broadcaster_id: String, _broadcaster_login: String, _broadcaster_name: String, _moderator_id: String, _moderator_login: String, _moderator_name: String, _user_id: String, _user_login: String, _user_name: String, _text: String, _status: String, _created_at: String, _resolved_at: String, _resolution_text: String) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.id = _id + response_data.broadcaster_id = _broadcaster_id + response_data.broadcaster_login = _broadcaster_login + response_data.broadcaster_name = _broadcaster_name + response_data.moderator_id = _moderator_id + response_data.moderator_login = _moderator_login + response_data.moderator_name = _moderator_name + response_data.user_id = _user_id + response_data.user_login = _user_login + response_data.user_name = _user_name + response_data.text = _text + response_data.status = _status + response_data.created_at = _created_at + response_data.resolved_at = _resolved_at + response_data.resolution_text = _resolution_text + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_login", null) != null: + result.broadcaster_login = d["broadcaster_login"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + if d.get("moderator_id", null) != null: + result.moderator_id = d["moderator_id"] + if d.get("moderator_login", null) != null: + result.moderator_login = d["moderator_login"] + if d.get("moderator_name", null) != null: + result.moderator_name = d["moderator_name"] + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + if d.get("user_name", null) != null: + result.user_name = d["user_name"] + if d.get("text", null) != null: + result.text = d["text"] + if d.get("status", null) != null: + result.status = d["status"] + if d.get("created_at", null) != null: + result.created_at = d["created_at"] + if d.get("resolved_at", null) != null: + result.resolved_at = d["resolved_at"] + if d.get("resolution_text", null) != null: + result.resolution_text = d["resolution_text"] + return result + + + +## All optional parameters for TwitchAPI.resolve_unban_requests +## #/components/schemas/ResolveUnbanRequestsOpt +class Opt extends TwitchData: + + ## Message supplied by the unban request resolver. The message is limited to a maximum of 500 characters. + @export var resolution_text: String: + set(val): + resolution_text = val + track_data(&"resolution_text", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("resolution_text", null) != null: + result.resolution_text = d["resolution_text"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_resolve_unban_requests.gd.uid b/addons/twitcher/generated/twitch_resolve_unban_requests.gd.uid new file mode 100644 index 0000000..cabb72f --- /dev/null +++ b/addons/twitcher/generated/twitch_resolve_unban_requests.gd.uid @@ -0,0 +1 @@ +uid://xdmooyrs5ejn diff --git a/addons/twitcher/generated/twitch_search_categories.gd b/addons/twitcher/generated/twitch_search_categories.gd new file mode 100644 index 0000000..cb179e3 --- /dev/null +++ b/addons/twitcher/generated/twitch_search_categories.gd @@ -0,0 +1,143 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchSearchCategories + + + +## +## #/components/schemas/SearchCategoriesResponse +class Response extends TwitchData: + + ## The list of games or categories that match the query. The list is empty if there are no matches. + @export var data: Array[TwitchCategory]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through.[Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchCategory]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchCategory.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through.[Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/SearchCategoriesResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s _after_ query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.search_categories +## #/components/schemas/SearchCategoriesOpt +class Opt extends TwitchData: + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100 items per page. The default is 20. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_search_categories.gd.uid b/addons/twitcher/generated/twitch_search_categories.gd.uid new file mode 100644 index 0000000..c636069 --- /dev/null +++ b/addons/twitcher/generated/twitch_search_categories.gd.uid @@ -0,0 +1 @@ +uid://c5ou5278ciklb diff --git a/addons/twitcher/generated/twitch_search_channels.gd b/addons/twitcher/generated/twitch_search_channels.gd new file mode 100644 index 0000000..1923a3a --- /dev/null +++ b/addons/twitcher/generated/twitch_search_channels.gd @@ -0,0 +1,151 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchSearchChannels + + + +## +## #/components/schemas/SearchChannelsResponse +class Response extends TwitchData: + + ## The list of channels that match the query. The list is empty if there are no matches. + @export var data: Array[TwitchChannel]: + set(val): + data = val + track_data(&"data", val) + + ## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through.[Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var pagination: ResponsePagination: + set(val): + pagination = val + track_data(&"pagination", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchChannel]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchChannel.from_json(value)) + if d.get("pagination", null) != null: + result.pagination = ResponsePagination.from_json(d["pagination"]) + return result + + + + func _has_pagination() -> bool: + if pagination == null: return false + if pagination.cursor == null || pagination.cursor == "": return false + return true + + var _next_page: Callable + var _cur_iter: int = 0 + + + func next_page() -> Response: + var response: Response = await _next_page.call() + _cur_iter = 0 + _next_page = response._next_page + data = response.data + pagination = response.pagination + + return response + + + func _iter_init(iter: Array) -> bool: + if data.is_empty(): return false + iter[0] = data[0] + return data.size() > 0 + + + func _iter_next(iter: Array) -> bool: + if data.size() - 1 > _cur_iter: + _cur_iter += 1 + iter[0] = data[_cur_iter] + if data.size() - 1 == _cur_iter && not _has_pagination(): + return false + return true + + + func _iter_get(iter: Variant) -> Variant: + if data.size() - 1 == _cur_iter && _has_pagination(): + await next_page() + return iter + + +## Contains the information used to page through the list of results. The object is empty if there are no more pages left to page through.[Read More](https://dev.twitch.tv/docs/api/guide#pagination) +## #/components/schemas/SearchChannelsResponse/Pagination +class ResponsePagination extends TwitchData: + + ## The cursor used to get the next page of results. Use the cursor to set the request’s _after_ query parameter. + @export var cursor: String: + set(val): + cursor = val + track_data(&"cursor", val) + + + + ## Constructor with all required fields. + static func create() -> ResponsePagination: + var response_pagination: ResponsePagination = ResponsePagination.new() + return response_pagination + + + static func from_json(d: Dictionary) -> ResponsePagination: + var result: ResponsePagination = ResponsePagination.new() + if d.get("cursor", null) != null: + result.cursor = d["cursor"] + return result + + + +## All optional parameters for TwitchAPI.search_channels +## #/components/schemas/SearchChannelsOpt +class Opt extends TwitchData: + + ## A Boolean value that determines whether the response includes only channels that are currently streaming live. Set to **true** to get only channels that are streaming live; otherwise, **false** to get live and offline channels. The default is **false**. + @export var live_only: bool: + set(val): + live_only = val + track_data(&"live_only", val) + + ## The maximum number of items to return per page in the response. The minimum page size is 1 item per page and the maximum is 100 items per page. The default is 20. + @export var first: int: + set(val): + first = val + track_data(&"first", val) + + ## The cursor used to get the next page of results. The **Pagination** object in the response contains the cursor’s value. [Read More](https://dev.twitch.tv/docs/api/guide#pagination) + @export var after: String: + set(val): + after = val + track_data(&"after", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("live_only", null) != null: + result.live_only = d["live_only"] + if d.get("first", null) != null: + result.first = d["first"] + if d.get("after", null) != null: + result.after = d["after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_search_channels.gd.uid b/addons/twitcher/generated/twitch_search_channels.gd.uid new file mode 100644 index 0000000..b45529e --- /dev/null +++ b/addons/twitcher/generated/twitch_search_channels.gd.uid @@ -0,0 +1 @@ +uid://cm6j0tlaigxx5 diff --git a/addons/twitcher/generated/twitch_send_chat_announcement.gd b/addons/twitcher/generated/twitch_send_chat_announcement.gd new file mode 100644 index 0000000..1e14e3c --- /dev/null +++ b/addons/twitcher/generated/twitch_send_chat_announcement.gd @@ -0,0 +1,50 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchSendChatAnnouncement + + + +## +## #/components/schemas/SendChatAnnouncementBody +class Body extends TwitchData: + + ## The announcement to make in the broadcaster’s chat room. Announcements are limited to a maximum of 500 characters; announcements longer than 500 characters are truncated. + @export var message: String: + set(val): + message = val + track_data(&"message", val) + + ## The color used to highlight the announcement. Possible case-sensitive values are: + ## + ## * blue + ## * green + ## * orange + ## * purple + ## * primary (default) + ## + ## If `color` is set to _primary_ or is not set, the channel’s accent color is used to highlight the announcement (see **Profile Accent Color** under [profile settings](https://www.twitch.tv/settings/profile), **Channel and Videos**, and **Brand**). + @export var color: String: + set(val): + color = val + track_data(&"color", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_message: String) -> Body: + var body: Body = Body.new() + body.message = _message + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("message", null) != null: + result.message = d["message"] + if d.get("color", null) != null: + result.color = d["color"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_send_chat_announcement.gd.uid b/addons/twitcher/generated/twitch_send_chat_announcement.gd.uid new file mode 100644 index 0000000..c4308c2 --- /dev/null +++ b/addons/twitcher/generated/twitch_send_chat_announcement.gd.uid @@ -0,0 +1 @@ +uid://bfen51gxc77ou diff --git a/addons/twitcher/generated/twitch_send_chat_message.gd b/addons/twitcher/generated/twitch_send_chat_message.gd new file mode 100644 index 0000000..118ba76 --- /dev/null +++ b/addons/twitcher/generated/twitch_send_chat_message.gd @@ -0,0 +1,168 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchSendChatMessage + + + +## +## #/components/schemas/SendChatMessageBody +class Body extends TwitchData: + + ## The ID of the broadcaster whose chat room the message will be sent to. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## The ID of the user sending the message. This ID must match the user ID in the user access token. + @export var sender_id: String: + set(val): + sender_id = val + track_data(&"sender_id", val) + + ## The message to send. The message is limited to a maximum of 500 characters. Chat messages can also include emoticons. To include emoticons, use the name of the emote. The names are case sensitive. Don’t include colons around the name (e.g., :bleedPurple:). If Twitch recognizes the name, Twitch converts the name to the emote before writing the chat message to the chat room + @export var message: String: + set(val): + message = val + track_data(&"message", val) + + ## The ID of the chat message being replied to. + @export var reply_parent_message_id: String: + set(val): + reply_parent_message_id = val + track_data(&"reply_parent_message_id", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_broadcaster_id: String, _sender_id: String, _message: String) -> Body: + var body: Body = Body.new() + body.broadcaster_id = _broadcaster_id + body.sender_id = _sender_id + body.message = _message + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("sender_id", null) != null: + result.sender_id = d["sender_id"] + if d.get("message", null) != null: + result.message = d["message"] + if d.get("reply_parent_message_id", null) != null: + result.reply_parent_message_id = d["reply_parent_message_id"] + return result + + + +## +## #/components/schemas/SendChatMessageResponse +class Response extends TwitchData: + + ## + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + return result + + + +## +## #/components/schemas/SendChatMessageResponse/Data +class ResponseData extends TwitchData: + + ## The message id for the message that was sent. + @export var message_id: String: + set(val): + message_id = val + track_data(&"message_id", val) + + ## If the message passed all checks and was sent. + @export var is_sent: bool: + set(val): + is_sent = val + track_data(&"is_sent", val) + + ## The reason the message was dropped, if any. + @export var drop_reason: ResponseDropReason: + set(val): + drop_reason = val + track_data(&"drop_reason", val) + + + + ## Constructor with all required fields. + static func create(_message_id: String, _is_sent: bool) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.message_id = _message_id + response_data.is_sent = _is_sent + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("message_id", null) != null: + result.message_id = d["message_id"] + if d.get("is_sent", null) != null: + result.is_sent = d["is_sent"] + if d.get("drop_reason", null) != null: + result.drop_reason = ResponseDropReason.from_json(d["drop_reason"]) + return result + + + +## The reason the message was dropped, if any. +## #/components/schemas/SendChatMessageResponse/Data/DropReason +class ResponseDropReason extends TwitchData: + + ## Code for why the message was dropped. + @export var code: String: + set(val): + code = val + track_data(&"code", val) + + ## Message for why the message was dropped. + @export var message: String: + set(val): + message = val + track_data(&"message", val) + + + + ## Constructor with all required fields. + static func create(_code: String, _message: String) -> ResponseDropReason: + var response_drop_reason: ResponseDropReason = ResponseDropReason.new() + response_drop_reason.code = _code + response_drop_reason.message = _message + return response_drop_reason + + + static func from_json(d: Dictionary) -> ResponseDropReason: + var result: ResponseDropReason = ResponseDropReason.new() + if d.get("code", null) != null: + result.code = d["code"] + if d.get("message", null) != null: + result.message = d["message"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_send_chat_message.gd.uid b/addons/twitcher/generated/twitch_send_chat_message.gd.uid new file mode 100644 index 0000000..b18e7bd --- /dev/null +++ b/addons/twitcher/generated/twitch_send_chat_message.gd.uid @@ -0,0 +1 @@ +uid://bwk0378nocfl2 diff --git a/addons/twitcher/generated/twitch_send_extension_chat_message.gd b/addons/twitcher/generated/twitch_send_extension_chat_message.gd new file mode 100644 index 0000000..325c664 --- /dev/null +++ b/addons/twitcher/generated/twitch_send_extension_chat_message.gd @@ -0,0 +1,52 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchSendExtensionChatMessage + + + +## +## #/components/schemas/SendExtensionChatMessageBody +class Body extends TwitchData: + + ## The message. The message may contain a maximum of 280 characters. + @export var text: String: + set(val): + text = val + track_data(&"text", val) + + ## The ID of the extension that’s sending the chat message. + @export var extension_id: String: + set(val): + extension_id = val + track_data(&"extension_id", val) + + ## The extension’s version number. + @export var extension_version: String: + set(val): + extension_version = val + track_data(&"extension_version", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_text: String, _extension_id: String, _extension_version: String) -> Body: + var body: Body = Body.new() + body.text = _text + body.extension_id = _extension_id + body.extension_version = _extension_version + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("text", null) != null: + result.text = d["text"] + if d.get("extension_id", null) != null: + result.extension_id = d["extension_id"] + if d.get("extension_version", null) != null: + result.extension_version = d["extension_version"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_send_extension_chat_message.gd.uid b/addons/twitcher/generated/twitch_send_extension_chat_message.gd.uid new file mode 100644 index 0000000..3569ce1 --- /dev/null +++ b/addons/twitcher/generated/twitch_send_extension_chat_message.gd.uid @@ -0,0 +1 @@ +uid://bgldr1v6lh3mx diff --git a/addons/twitcher/generated/twitch_send_extension_pub_sub_message.gd b/addons/twitcher/generated/twitch_send_extension_pub_sub_message.gd new file mode 100644 index 0000000..9aa90e2 --- /dev/null +++ b/addons/twitcher/generated/twitch_send_extension_pub_sub_message.gd @@ -0,0 +1,67 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchSendExtensionPubSubMessage + + + +## +## #/components/schemas/SendExtensionPubSubMessageBody +class Body extends TwitchData: + + ## The target of the message. Possible values are: + ## + ## * broadcast + ## * global + ## * whisper- + ## + ## If `is_global_broadcast` is **true**, you must set this field to global. The broadcast and global values are mutually exclusive; specify only one of them. + @export var target: Array[String]: + set(val): + target = val + track_data(&"target", val) + + ## The ID of the broadcaster to send the message to. Don’t include this field if `is_global_broadcast` is set to **true**. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## A Boolean value that determines whether the message should be sent to all channels where your extension is active. Set to **true** if the message should be sent to all channels. The default is **false**. + @export var is_global_broadcast: bool: + set(val): + is_global_broadcast = val + track_data(&"is_global_broadcast", val) + + ## The message to send. The message can be a plain-text string or a string-encoded JSON object. The message is limited to a maximum of 5 KB. + @export var message: String: + set(val): + message = val + track_data(&"message", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_target: Array[String], _broadcaster_id: String, _message: String) -> Body: + var body: Body = Body.new() + body.target = _target + body.broadcaster_id = _broadcaster_id + body.message = _message + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("target", null) != null: + for value in d["target"]: + result.target.append(value) + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("is_global_broadcast", null) != null: + result.is_global_broadcast = d["is_global_broadcast"] + if d.get("message", null) != null: + result.message = d["message"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_send_extension_pub_sub_message.gd.uid b/addons/twitcher/generated/twitch_send_extension_pub_sub_message.gd.uid new file mode 100644 index 0000000..da14ea3 --- /dev/null +++ b/addons/twitcher/generated/twitch_send_extension_pub_sub_message.gd.uid @@ -0,0 +1 @@ +uid://ospk2kwra5he diff --git a/addons/twitcher/generated/twitch_send_whisper.gd b/addons/twitcher/generated/twitch_send_whisper.gd new file mode 100644 index 0000000..4628164 --- /dev/null +++ b/addons/twitcher/generated/twitch_send_whisper.gd @@ -0,0 +1,41 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchSendWhisper + + + +## +## #/components/schemas/SendWhisperBody +class Body extends TwitchData: + + ## The whisper message to send. The message must not be empty. + ## + ## The maximum message lengths are: + ## + ## * 500 characters if the user you're sending the message to hasn't whispered you before. + ## * 10,000 characters if the user you're sending the message to has whispered you before. + ## + ## Messages that exceed the maximum length are truncated. + @export var message: String: + set(val): + message = val + track_data(&"message", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_message: String) -> Body: + var body: Body = Body.new() + body.message = _message + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("message", null) != null: + result.message = d["message"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_send_whisper.gd.uid b/addons/twitcher/generated/twitch_send_whisper.gd.uid new file mode 100644 index 0000000..338baa3 --- /dev/null +++ b/addons/twitcher/generated/twitch_send_whisper.gd.uid @@ -0,0 +1 @@ +uid://c73ksa7b5f0fl diff --git a/addons/twitcher/generated/twitch_set_extension_configuration_segment.gd b/addons/twitcher/generated/twitch_set_extension_configuration_segment.gd new file mode 100644 index 0000000..f85a050 --- /dev/null +++ b/addons/twitcher/generated/twitch_set_extension_configuration_segment.gd @@ -0,0 +1,71 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchSetExtensionConfigurationSegment + + + +## +## #/components/schemas/SetExtensionConfigurationSegmentBody +class Body extends TwitchData: + + ## The ID of the extension to update. + @export var extension_id: String: + set(val): + extension_id = val + track_data(&"extension_id", val) + + ## The configuration segment to update. Possible case-sensitive values are: + ## + ## * broadcaster + ## * developer + ## * global + @export var segment: String: + set(val): + segment = val + track_data(&"segment", val) + + ## The ID of the broadcaster that installed the extension. Include this field only if the `segment` is set to developer or broadcaster. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## The contents of the segment. This string may be a plain-text string or a string-encoded JSON object. + @export var content: String: + set(val): + content = val + track_data(&"content", val) + + ## The version number that identifies this definition of the segment’s data. If not specified, the latest definition is updated. + @export var version: String: + set(val): + version = val + track_data(&"version", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_extension_id: String, _segment: String) -> Body: + var body: Body = Body.new() + body.extension_id = _extension_id + body.segment = _segment + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("extension_id", null) != null: + result.extension_id = d["extension_id"] + if d.get("segment", null) != null: + result.segment = d["segment"] + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("content", null) != null: + result.content = d["content"] + if d.get("version", null) != null: + result.version = d["version"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_set_extension_configuration_segment.gd.uid b/addons/twitcher/generated/twitch_set_extension_configuration_segment.gd.uid new file mode 100644 index 0000000..694c16b --- /dev/null +++ b/addons/twitcher/generated/twitch_set_extension_configuration_segment.gd.uid @@ -0,0 +1 @@ +uid://bb8hyabfsyyag diff --git a/addons/twitcher/generated/twitch_set_extension_required_configuration.gd b/addons/twitcher/generated/twitch_set_extension_required_configuration.gd new file mode 100644 index 0000000..ffbfb35 --- /dev/null +++ b/addons/twitcher/generated/twitch_set_extension_required_configuration.gd @@ -0,0 +1,52 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchSetExtensionRequiredConfiguration + + + +## +## #/components/schemas/SetExtensionRequiredConfigurationBody +class Body extends TwitchData: + + ## The ID of the extension to update. + @export var extension_id: String: + set(val): + extension_id = val + track_data(&"extension_id", val) + + ## The version of the extension to update. + @export var extension_version: String: + set(val): + extension_version = val + track_data(&"extension_version", val) + + ## The required\_configuration string to use with the extension. + @export var required_configuration: String: + set(val): + required_configuration = val + track_data(&"required_configuration", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_extension_id: String, _extension_version: String, _required_configuration: String) -> Body: + var body: Body = Body.new() + body.extension_id = _extension_id + body.extension_version = _extension_version + body.required_configuration = _required_configuration + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("extension_id", null) != null: + result.extension_id = d["extension_id"] + if d.get("extension_version", null) != null: + result.extension_version = d["extension_version"] + if d.get("required_configuration", null) != null: + result.required_configuration = d["required_configuration"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_set_extension_required_configuration.gd.uid b/addons/twitcher/generated/twitch_set_extension_required_configuration.gd.uid new file mode 100644 index 0000000..d533d65 --- /dev/null +++ b/addons/twitcher/generated/twitch_set_extension_required_configuration.gd.uid @@ -0,0 +1 @@ +uid://b1x0l12h5kmu5 diff --git a/addons/twitcher/generated/twitch_snooze_next_ad.gd b/addons/twitcher/generated/twitch_snooze_next_ad.gd new file mode 100644 index 0000000..58d7c73 --- /dev/null +++ b/addons/twitcher/generated/twitch_snooze_next_ad.gd @@ -0,0 +1,80 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchSnoozeNextAd + + + +## +## #/components/schemas/SnoozeNextAdResponse +class Response extends TwitchData: + + ## A list that contains information about the channel’s snoozes and next upcoming ad after successfully snoozing. + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + return result + + + +## A list that contains information about the channel’s snoozes and next upcoming ad after successfully snoozing. +## #/components/schemas/SnoozeNextAdResponse/Data +class ResponseData extends TwitchData: + + ## The number of snoozes available for the broadcaster. + @export var snooze_count: int: + set(val): + snooze_count = val + track_data(&"snooze_count", val) + + ## The UTC timestamp when the broadcaster will gain an additional snooze, in RFC3339 format. + @export var snooze_refresh_at: String: + set(val): + snooze_refresh_at = val + track_data(&"snooze_refresh_at", val) + + ## The UTC timestamp of the broadcaster’s next scheduled ad, in RFC3339 format. + @export var next_ad_at: String: + set(val): + next_ad_at = val + track_data(&"next_ad_at", val) + + + + ## Constructor with all required fields. + static func create(_snooze_count: int, _snooze_refresh_at: String, _next_ad_at: String) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.snooze_count = _snooze_count + response_data.snooze_refresh_at = _snooze_refresh_at + response_data.next_ad_at = _next_ad_at + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("snooze_count", null) != null: + result.snooze_count = d["snooze_count"] + if d.get("snooze_refresh_at", null) != null: + result.snooze_refresh_at = d["snooze_refresh_at"] + if d.get("next_ad_at", null) != null: + result.next_ad_at = d["next_ad_at"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_snooze_next_ad.gd.uid b/addons/twitcher/generated/twitch_snooze_next_ad.gd.uid new file mode 100644 index 0000000..c648208 --- /dev/null +++ b/addons/twitcher/generated/twitch_snooze_next_ad.gd.uid @@ -0,0 +1 @@ +uid://dhw1xxk2dc24f diff --git a/addons/twitcher/generated/twitch_start_a_raid.gd b/addons/twitcher/generated/twitch_start_a_raid.gd new file mode 100644 index 0000000..40046d6 --- /dev/null +++ b/addons/twitcher/generated/twitch_start_a_raid.gd @@ -0,0 +1,41 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchStartARaid + + + +## All optional parameters for TwitchAPI.start_a_raid +## #/components/schemas/StartARaidOpt +class Opt extends TwitchData: + + ## The ID of the broadcaster that’s sending the raiding party. This ID must match the user ID in the user access token. + @export var from_broadcaster_id: String: + set(val): + from_broadcaster_id = val + track_data(&"from_broadcaster_id", val) + + ## The ID of the broadcaster to raid. + @export var to_broadcaster_id: String: + set(val): + to_broadcaster_id = val + track_data(&"to_broadcaster_id", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("from_broadcaster_id", null) != null: + result.from_broadcaster_id = d["from_broadcaster_id"] + if d.get("to_broadcaster_id", null) != null: + result.to_broadcaster_id = d["to_broadcaster_id"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_start_a_raid.gd.uid b/addons/twitcher/generated/twitch_start_a_raid.gd.uid new file mode 100644 index 0000000..73e36a7 --- /dev/null +++ b/addons/twitcher/generated/twitch_start_a_raid.gd.uid @@ -0,0 +1 @@ +uid://b2ypwr1s02sns diff --git a/addons/twitcher/generated/twitch_start_commercial.gd b/addons/twitcher/generated/twitch_start_commercial.gd new file mode 100644 index 0000000..404fd45 --- /dev/null +++ b/addons/twitcher/generated/twitch_start_commercial.gd @@ -0,0 +1,116 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchStartCommercial + + + +## +## #/components/schemas/StartCommercialBody +class Body extends TwitchData: + + ## The ID of the partner or affiliate broadcaster that wants to run the commercial. This ID must match the user ID found in the OAuth token. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## The length of the commercial to run, in seconds. Twitch tries to serve a commercial that’s the requested length, but it may be shorter or longer. The maximum length you should request is 180 seconds. + @export var length: int: + set(val): + length = val + track_data(&"length", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_broadcaster_id: String, _length: int) -> Body: + var body: Body = Body.new() + body.broadcaster_id = _broadcaster_id + body.length = _length + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("length", null) != null: + result.length = d["length"] + return result + + + +## +## #/components/schemas/StartCommercialResponse +class Response extends TwitchData: + + ## An array that contains a single object with the status of your start commercial request. + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + return result + + + +## An array that contains a single object with the status of your start commercial request. +## #/components/schemas/StartCommercialResponse/Data +class ResponseData extends TwitchData: + + ## The length of the commercial you requested. If you request a commercial that’s longer than 180 seconds, the API uses 180 seconds. + @export var length: int: + set(val): + length = val + track_data(&"length", val) + + ## A message that indicates whether Twitch was able to serve an ad. + @export var message: String: + set(val): + message = val + track_data(&"message", val) + + ## The number of seconds you must wait before running another commercial. + @export var retry_after: int: + set(val): + retry_after = val + track_data(&"retry_after", val) + + + + ## Constructor with all required fields. + static func create(_length: int, _message: String, _retry_after: int) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.length = _length + response_data.message = _message + response_data.retry_after = _retry_after + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("length", null) != null: + result.length = d["length"] + if d.get("message", null) != null: + result.message = d["message"] + if d.get("retry_after", null) != null: + result.retry_after = d["retry_after"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_start_commercial.gd.uid b/addons/twitcher/generated/twitch_start_commercial.gd.uid new file mode 100644 index 0000000..9409be2 --- /dev/null +++ b/addons/twitcher/generated/twitch_start_commercial.gd.uid @@ -0,0 +1 @@ +uid://b07j06b3w1uyw diff --git a/addons/twitcher/generated/twitch_start_raid.gd b/addons/twitcher/generated/twitch_start_raid.gd new file mode 100644 index 0000000..90b5a97 --- /dev/null +++ b/addons/twitcher/generated/twitch_start_raid.gd @@ -0,0 +1,71 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchStartRaid + + + +## +## #/components/schemas/StartRaidResponse +class Response extends TwitchData: + + ## A list that contains a single object with information about the pending raid. + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + return result + + + +## A list that contains a single object with information about the pending raid. +## #/components/schemas/StartRaidResponse/Data +class ResponseData extends TwitchData: + + ## The UTC date and time, in RFC3339 format, of when the raid was requested. + @export var created_at: String: + set(val): + created_at = val + track_data(&"created_at", val) + + ## A Boolean value that indicates whether the channel being raided contains mature content. + @export var is_mature: bool: + set(val): + is_mature = val + track_data(&"is_mature", val) + + + + ## Constructor with all required fields. + static func create(_created_at: String, _is_mature: bool) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.created_at = _created_at + response_data.is_mature = _is_mature + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("created_at", null) != null: + result.created_at = d["created_at"] + if d.get("is_mature", null) != null: + result.is_mature = d["is_mature"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_start_raid.gd.uid b/addons/twitcher/generated/twitch_start_raid.gd.uid new file mode 100644 index 0000000..876d085 --- /dev/null +++ b/addons/twitcher/generated/twitch_start_raid.gd.uid @@ -0,0 +1 @@ +uid://crnrjqojt0t31 diff --git a/addons/twitcher/generated/twitch_stream.gd b/addons/twitcher/generated/twitch_stream.gd new file mode 100644 index 0000000..16d4e3b --- /dev/null +++ b/addons/twitcher/generated/twitch_stream.gd @@ -0,0 +1,163 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/Stream +class_name TwitchStream + +## An ID that identifies the stream. You can use this ID later to look up the video on demand (VOD). +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The ID of the user that’s broadcasting the stream. +@export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + +## The user’s login name. +@export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) + +## The user’s display name. +@export var user_name: String: + set(val): + user_name = val + track_data(&"user_name", val) + +## The ID of the category or game being played. +@export var game_id: String: + set(val): + game_id = val + track_data(&"game_id", val) + +## The ID of the category or game being played. +@export var game_name: String: + set(val): + game_name = val + track_data(&"game_name", val) + +## The type of stream. Possible values are: +## +## * live +## +## If an error occurs, this field is set to an empty string. +@export var type: String: + set(val): + type = val + track_data(&"type", val) + +## The stream’s title. Is an empty string if not set. +@export var title: String: + set(val): + title = val + track_data(&"title", val) + +## The number of users watching the stream. +@export var viewer_count: int: + set(val): + viewer_count = val + track_data(&"viewer_count", val) + +## The UTC date and time (in RFC3339 format) of when the broadcast began. +@export var started_at: String: + set(val): + started_at = val + track_data(&"started_at", val) + +## The language that the stream uses. This is an ISO 639-1 two-letter language code or _other_ if the stream uses a language not in the list of [supported stream languages](https://help.twitch.tv/s/article/languages-on-twitch#streamlang). +@export var language: String: + set(val): + language = val + track_data(&"language", val) + +## A URL to an image of a frame from the last 5 minutes of the stream. Replace the width and height placeholders in the URL (`{width}x{height}`) with the size of the image you want, in pixels. +@export var thumbnail_url: String: + set(val): + thumbnail_url = val + track_data(&"thumbnail_url", val) + +## **IMPORTANT** As of February 28, 2023, this field is deprecated and returns only an empty array. If you use this field, please update your code to use the `tags` field. +## +## The list of tags that apply to the stream. The list contains IDs only when the channel is steaming live. For a list of possible tags, see [List of All Tags](https://www.twitch.tv/directory/all/tags). The list doesn’t include Category Tags. +@export var tag_ids: Array[String]: + set(val): + tag_ids = val + track_data(&"tag_ids", val) + +## The tags applied to the stream. +@export var tags: Array[String]: + set(val): + tags = val + track_data(&"tags", val) + +## A Boolean value that indicates whether the stream is meant for mature audiences. +@export var is_mature: bool: + set(val): + is_mature = val + track_data(&"is_mature", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _user_id: String, _user_login: String, _user_name: String, _game_id: String, _game_name: String, _type: String, _title: String, _viewer_count: int, _started_at: String, _language: String, _thumbnail_url: String, _tag_ids: Array[String], _tags: Array[String], _is_mature: bool) -> TwitchStream: + var twitch_stream: TwitchStream = TwitchStream.new() + twitch_stream.id = _id + twitch_stream.user_id = _user_id + twitch_stream.user_login = _user_login + twitch_stream.user_name = _user_name + twitch_stream.game_id = _game_id + twitch_stream.game_name = _game_name + twitch_stream.type = _type + twitch_stream.title = _title + twitch_stream.viewer_count = _viewer_count + twitch_stream.started_at = _started_at + twitch_stream.language = _language + twitch_stream.thumbnail_url = _thumbnail_url + twitch_stream.tag_ids = _tag_ids + twitch_stream.tags = _tags + twitch_stream.is_mature = _is_mature + return twitch_stream + + +static func from_json(d: Dictionary) -> TwitchStream: + var result: TwitchStream = TwitchStream.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + if d.get("user_name", null) != null: + result.user_name = d["user_name"] + if d.get("game_id", null) != null: + result.game_id = d["game_id"] + if d.get("game_name", null) != null: + result.game_name = d["game_name"] + if d.get("type", null) != null: + result.type = d["type"] + if d.get("title", null) != null: + result.title = d["title"] + if d.get("viewer_count", null) != null: + result.viewer_count = d["viewer_count"] + if d.get("started_at", null) != null: + result.started_at = d["started_at"] + if d.get("language", null) != null: + result.language = d["language"] + if d.get("thumbnail_url", null) != null: + result.thumbnail_url = d["thumbnail_url"] + if d.get("tag_ids", null) != null: + for value in d["tag_ids"]: + result.tag_ids.append(value) + if d.get("tags", null) != null: + for value in d["tags"]: + result.tags.append(value) + if d.get("is_mature", null) != null: + result.is_mature = d["is_mature"] + return result diff --git a/addons/twitcher/generated/twitch_stream.gd.uid b/addons/twitcher/generated/twitch_stream.gd.uid new file mode 100644 index 0000000..7c11349 --- /dev/null +++ b/addons/twitcher/generated/twitch_stream.gd.uid @@ -0,0 +1 @@ +uid://ti42wkq54dsq diff --git a/addons/twitcher/generated/twitch_stream_marker_created.gd b/addons/twitcher/generated/twitch_stream_marker_created.gd new file mode 100644 index 0000000..f5dae61 --- /dev/null +++ b/addons/twitcher/generated/twitch_stream_marker_created.gd @@ -0,0 +1,56 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/StreamMarkerCreated +class_name TwitchStreamMarkerCreated + +## An ID that identifies this marker. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The UTC date and time (in RFC3339 format) of when the user created the marker. +@export var created_at: String: + set(val): + created_at = val + track_data(&"created_at", val) + +## The relative offset (in seconds) of the marker from the beginning of the stream. +@export var position_seconds: int: + set(val): + position_seconds = val + track_data(&"position_seconds", val) + +## A description that the user gave the marker to help them remember why they marked the location. +@export var description: String: + set(val): + description = val + track_data(&"description", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _created_at: String, _position_seconds: int, _description: String) -> TwitchStreamMarkerCreated: + var twitch_stream_marker_created: TwitchStreamMarkerCreated = TwitchStreamMarkerCreated.new() + twitch_stream_marker_created.id = _id + twitch_stream_marker_created.created_at = _created_at + twitch_stream_marker_created.position_seconds = _position_seconds + twitch_stream_marker_created.description = _description + return twitch_stream_marker_created + + +static func from_json(d: Dictionary) -> TwitchStreamMarkerCreated: + var result: TwitchStreamMarkerCreated = TwitchStreamMarkerCreated.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("created_at", null) != null: + result.created_at = d["created_at"] + if d.get("position_seconds", null) != null: + result.position_seconds = d["position_seconds"] + if d.get("description", null) != null: + result.description = d["description"] + return result diff --git a/addons/twitcher/generated/twitch_stream_marker_created.gd.uid b/addons/twitcher/generated/twitch_stream_marker_created.gd.uid new file mode 100644 index 0000000..1cec6c4 --- /dev/null +++ b/addons/twitcher/generated/twitch_stream_marker_created.gd.uid @@ -0,0 +1 @@ +uid://c6psfioqifwww diff --git a/addons/twitcher/generated/twitch_stream_markers.gd b/addons/twitcher/generated/twitch_stream_markers.gd new file mode 100644 index 0000000..bf5109c --- /dev/null +++ b/addons/twitcher/generated/twitch_stream_markers.gd @@ -0,0 +1,140 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/StreamMarkers +class_name TwitchStreamMarkers + +## The ID of the user that created the marker. +@export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + +## The user’s display name. +@export var user_name: String: + set(val): + user_name = val + track_data(&"user_name", val) + +## The user’s login name. +@export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) + +## A list of videos that contain markers. The list contains a single video. +@export var videos: Array[Variant]: + set(val): + videos = val + track_data(&"videos", val) + +## An ID that identifies this video. +@export var video_id: String: + set(val): + video_id = val + track_data(&"video_id", val) + +## The list of markers in this video. The list in ascending order by when the marker was created. +@export var markers: Array[Markers]: + set(val): + markers = val + track_data(&"markers", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_user_id: String, _user_name: String, _user_login: String, _videos: Array[Variant], _video_id: String, _markers: Array[Markers]) -> TwitchStreamMarkers: + var twitch_stream_markers: TwitchStreamMarkers = TwitchStreamMarkers.new() + twitch_stream_markers.user_id = _user_id + twitch_stream_markers.user_name = _user_name + twitch_stream_markers.user_login = _user_login + twitch_stream_markers.videos = _videos + twitch_stream_markers.video_id = _video_id + twitch_stream_markers.markers = _markers + return twitch_stream_markers + + +static func from_json(d: Dictionary) -> TwitchStreamMarkers: + var result: TwitchStreamMarkers = TwitchStreamMarkers.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_name", null) != null: + result.user_name = d["user_name"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + if d.get("videos", null) != null: + for value in d["videos"]: + result.videos.append(value) + if d.get("video_id", null) != null: + result.video_id = d["video_id"] + if d.get("markers", null) != null: + for value in d["markers"]: + result.markers.append(Markers.from_json(value)) + return result + + + +## The list of markers in this video. The list in ascending order by when the marker was created. +## #/components/schemas/StreamMarkers/Markers +class Markers extends TwitchData: + + ## An ID that identifies this marker. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## The UTC date and time (in RFC3339 format) of when the user created the marker. + @export var created_at: String: + set(val): + created_at = val + track_data(&"created_at", val) + + ## The description that the user gave the marker to help them remember why they marked the location. Is an empty string if the user didn’t provide one. + @export var description: String: + set(val): + description = val + track_data(&"description", val) + + ## The relative offset (in seconds) of the marker from the beginning of the stream. + @export var position_seconds: int: + set(val): + position_seconds = val + track_data(&"position_seconds", val) + + ## A URL that opens the video in Twitch Highlighter. + @export var url: String: + set(val): + url = val + track_data(&"url", val) + + + + ## Constructor with all required fields. + static func create(_id: String, _created_at: String, _description: String, _position_seconds: int, _url: String) -> Markers: + var markers: Markers = Markers.new() + markers.id = _id + markers.created_at = _created_at + markers.description = _description + markers.position_seconds = _position_seconds + markers.url = _url + return markers + + + static func from_json(d: Dictionary) -> Markers: + var result: Markers = Markers.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("created_at", null) != null: + result.created_at = d["created_at"] + if d.get("description", null) != null: + result.description = d["description"] + if d.get("position_seconds", null) != null: + result.position_seconds = d["position_seconds"] + if d.get("url", null) != null: + result.url = d["url"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_stream_markers.gd.uid b/addons/twitcher/generated/twitch_stream_markers.gd.uid new file mode 100644 index 0000000..b69b035 --- /dev/null +++ b/addons/twitcher/generated/twitch_stream_markers.gd.uid @@ -0,0 +1 @@ +uid://cymemfsps1hl5 diff --git a/addons/twitcher/generated/twitch_stream_tag.gd b/addons/twitcher/generated/twitch_stream_tag.gd new file mode 100644 index 0000000..c0bcc38 --- /dev/null +++ b/addons/twitcher/generated/twitch_stream_tag.gd @@ -0,0 +1,56 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/StreamTag +class_name TwitchStreamTag + +## An ID that identifies this tag. +@export var tag_id: String: + set(val): + tag_id = val + track_data(&"tag_id", val) + +## A Boolean value that determines whether the tag is an automatic tag. An automatic tag is one that Twitch adds to the stream. Broadcasters may not add automatic tags to their channel. The value is **true** if the tag is an automatic tag; otherwise, **false**. +@export var is_auto: bool: + set(val): + is_auto = val + track_data(&"is_auto", val) + +## A dictionary that contains the localized names of the tag. The key is in the form, -. For example, en-us. The value is the localized name. +@export var localization_names: Dictionary: + set(val): + localization_names = val + track_data(&"localization_names", val) + +## A dictionary that contains the localized descriptions of the tag. The key is in the form, -. For example, en-us. The value is the localized description. +@export var localization_descriptions: Dictionary: + set(val): + localization_descriptions = val + track_data(&"localization_descriptions", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_tag_id: String, _is_auto: bool, _localization_names: Dictionary, _localization_descriptions: Dictionary) -> TwitchStreamTag: + var twitch_stream_tag: TwitchStreamTag = TwitchStreamTag.new() + twitch_stream_tag.tag_id = _tag_id + twitch_stream_tag.is_auto = _is_auto + twitch_stream_tag.localization_names = _localization_names + twitch_stream_tag.localization_descriptions = _localization_descriptions + return twitch_stream_tag + + +static func from_json(d: Dictionary) -> TwitchStreamTag: + var result: TwitchStreamTag = TwitchStreamTag.new() + if d.get("tag_id", null) != null: + result.tag_id = d["tag_id"] + if d.get("is_auto", null) != null: + result.is_auto = d["is_auto"] + if d.get("localization_names", null) != null: + result.localization_names = d["localization_names"] + if d.get("localization_descriptions", null) != null: + result.localization_descriptions = d["localization_descriptions"] + return result diff --git a/addons/twitcher/generated/twitch_stream_tag.gd.uid b/addons/twitcher/generated/twitch_stream_tag.gd.uid new file mode 100644 index 0000000..825f494 --- /dev/null +++ b/addons/twitcher/generated/twitch_stream_tag.gd.uid @@ -0,0 +1 @@ +uid://d0apvlp414ivb diff --git a/addons/twitcher/generated/twitch_team.gd b/addons/twitcher/generated/twitch_team.gd new file mode 100644 index 0000000..e29a3d9 --- /dev/null +++ b/addons/twitcher/generated/twitch_team.gd @@ -0,0 +1,157 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/Team +class_name TwitchTeam + +## The list of team members. +@export var users: Array[Users]: + set(val): + users = val + track_data(&"users", val) + +## A URL to the team’s background image. +@export var background_image_url: String: + set(val): + background_image_url = val + track_data(&"background_image_url", val) + +## A URL to the team’s banner. +@export var banner: String: + set(val): + banner = val + track_data(&"banner", val) + +## The UTC date and time (in RFC3339 format) of when the team was created. +@export var created_at: String: + set(val): + created_at = val + track_data(&"created_at", val) + +## The UTC date and time (in RFC3339 format) of the last time the team was updated. +@export var updated_at: String: + set(val): + updated_at = val + track_data(&"updated_at", val) + +## The team’s description. The description may contain formatting such as Markdown, HTML, newline (\\n) characters, etc. +@export var info: String: + set(val): + info = val + track_data(&"info", val) + +## A URL to a thumbnail image of the team’s logo. +@export var thumbnail_url: String: + set(val): + thumbnail_url = val + track_data(&"thumbnail_url", val) + +## The team’s name. +@export var team_name: String: + set(val): + team_name = val + track_data(&"team_name", val) + +## The team’s display name. +@export var team_display_name: String: + set(val): + team_display_name = val + track_data(&"team_display_name", val) + +## An ID that identifies the team. +@export var id: String: + set(val): + id = val + track_data(&"id", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_users: Array[Users], _background_image_url: String, _banner: String, _created_at: String, _updated_at: String, _info: String, _thumbnail_url: String, _team_name: String, _team_display_name: String, _id: String) -> TwitchTeam: + var twitch_team: TwitchTeam = TwitchTeam.new() + twitch_team.users = _users + twitch_team.background_image_url = _background_image_url + twitch_team.banner = _banner + twitch_team.created_at = _created_at + twitch_team.updated_at = _updated_at + twitch_team.info = _info + twitch_team.thumbnail_url = _thumbnail_url + twitch_team.team_name = _team_name + twitch_team.team_display_name = _team_display_name + twitch_team.id = _id + return twitch_team + + +static func from_json(d: Dictionary) -> TwitchTeam: + var result: TwitchTeam = TwitchTeam.new() + if d.get("users", null) != null: + for value in d["users"]: + result.users.append(Users.from_json(value)) + if d.get("background_image_url", null) != null: + result.background_image_url = d["background_image_url"] + if d.get("banner", null) != null: + result.banner = d["banner"] + if d.get("created_at", null) != null: + result.created_at = d["created_at"] + if d.get("updated_at", null) != null: + result.updated_at = d["updated_at"] + if d.get("info", null) != null: + result.info = d["info"] + if d.get("thumbnail_url", null) != null: + result.thumbnail_url = d["thumbnail_url"] + if d.get("team_name", null) != null: + result.team_name = d["team_name"] + if d.get("team_display_name", null) != null: + result.team_display_name = d["team_display_name"] + if d.get("id", null) != null: + result.id = d["id"] + return result + + + +## The list of team members. +## #/components/schemas/Team/Users +class Users extends TwitchData: + + ## An ID that identifies the team member. + @export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + + ## The team member’s login name. + @export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) + + ## The team member’s display name. + @export var user_name: String: + set(val): + user_name = val + track_data(&"user_name", val) + + + + ## Constructor with all required fields. + static func create(_user_id: String, _user_login: String, _user_name: String) -> Users: + var users: Users = Users.new() + users.user_id = _user_id + users.user_login = _user_login + users.user_name = _user_name + return users + + + static func from_json(d: Dictionary) -> Users: + var result: Users = Users.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + if d.get("user_name", null) != null: + result.user_name = d["user_name"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_team.gd.uid b/addons/twitcher/generated/twitch_team.gd.uid new file mode 100644 index 0000000..dbef957 --- /dev/null +++ b/addons/twitcher/generated/twitch_team.gd.uid @@ -0,0 +1 @@ +uid://bfc8teem0sjwd diff --git a/addons/twitcher/generated/twitch_update_auto_mod_settings.gd b/addons/twitcher/generated/twitch_update_auto_mod_settings.gd new file mode 100644 index 0000000..4b3314e --- /dev/null +++ b/addons/twitcher/generated/twitch_update_auto_mod_settings.gd @@ -0,0 +1,125 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchUpdateAutoModSettings + + + +## +## #/components/schemas/UpdateAutoModSettingsBody +class Body extends TwitchData: + + ## The Automod level for hostility involving aggression. + @export var aggression: int: + set(val): + aggression = val + track_data(&"aggression", val) + + ## The Automod level for hostility involving name calling or insults. + @export var bullying: int: + set(val): + bullying = val + track_data(&"bullying", val) + + ## The Automod level for discrimination against disability. + @export var disability: int: + set(val): + disability = val + track_data(&"disability", val) + + ## The Automod level for discrimination against women. + @export var misogyny: int: + set(val): + misogyny = val + track_data(&"misogyny", val) + + ## The default AutoMod level for the broadcaster. + @export var overall_level: int: + set(val): + overall_level = val + track_data(&"overall_level", val) + + ## The Automod level for racial discrimination. + @export var race_ethnicity_or_religion: int: + set(val): + race_ethnicity_or_religion = val + track_data(&"race_ethnicity_or_religion", val) + + ## The Automod level for sexual content. + @export var sex_based_terms: int: + set(val): + sex_based_terms = val + track_data(&"sex_based_terms", val) + + ## The AutoMod level for discrimination based on sexuality, sex, or gender. + @export var sexuality_sex_or_gender: int: + set(val): + sexuality_sex_or_gender = val + track_data(&"sexuality_sex_or_gender", val) + + ## The Automod level for profanity. + @export var swearing: int: + set(val): + swearing = val + track_data(&"swearing", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create() -> Body: + var body: Body = Body.new() + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("aggression", null) != null: + result.aggression = d["aggression"] + if d.get("bullying", null) != null: + result.bullying = d["bullying"] + if d.get("disability", null) != null: + result.disability = d["disability"] + if d.get("misogyny", null) != null: + result.misogyny = d["misogyny"] + if d.get("overall_level", null) != null: + result.overall_level = d["overall_level"] + if d.get("race_ethnicity_or_religion", null) != null: + result.race_ethnicity_or_religion = d["race_ethnicity_or_religion"] + if d.get("sex_based_terms", null) != null: + result.sex_based_terms = d["sex_based_terms"] + if d.get("sexuality_sex_or_gender", null) != null: + result.sexuality_sex_or_gender = d["sexuality_sex_or_gender"] + if d.get("swearing", null) != null: + result.swearing = d["swearing"] + return result + + + +## +## #/components/schemas/UpdateAutoModSettingsResponse +class Response extends TwitchData: + + ## The list of AutoMod settings. The list contains a single object that contains all the AutoMod settings. + @export var data: Array[TwitchAutoModSettings]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchAutoModSettings]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchAutoModSettings.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_update_auto_mod_settings.gd.uid b/addons/twitcher/generated/twitch_update_auto_mod_settings.gd.uid new file mode 100644 index 0000000..d029b9d --- /dev/null +++ b/addons/twitcher/generated/twitch_update_auto_mod_settings.gd.uid @@ -0,0 +1 @@ +uid://bia0nlvntfcg4 diff --git a/addons/twitcher/generated/twitch_update_channel_guest_star_settings.gd b/addons/twitcher/generated/twitch_update_channel_guest_star_settings.gd new file mode 100644 index 0000000..bec0a8a --- /dev/null +++ b/addons/twitcher/generated/twitch_update_channel_guest_star_settings.gd @@ -0,0 +1,70 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchUpdateChannelGuestStarSettings + + + +## +## #/components/schemas/UpdateChannelGuestStarSettingsBody +class Body extends TwitchData: + + ## Flag determining if Guest Star moderators have access to control whether a guest is live once assigned to a slot. + @export var is_moderator_send_live_enabled: bool: + set(val): + is_moderator_send_live_enabled = val + track_data(&"is_moderator_send_live_enabled", val) + + ## Number of slots the Guest Star call interface will allow the host to add to a call. Required to be between 1 and 6. + @export var slot_count: int: + set(val): + slot_count = val + track_data(&"slot_count", val) + + ## Flag determining if Browser Sources subscribed to sessions on this channel should output audio + @export var is_browser_source_audio_enabled: bool: + set(val): + is_browser_source_audio_enabled = val + track_data(&"is_browser_source_audio_enabled", val) + + ## This setting determines how the guests within a session should be laid out within the browser source. Can be one of the following values: + ## + ## * `TILED_LAYOUT`: All live guests are tiled within the browser source with the same size. + ## * `SCREENSHARE_LAYOUT`: All live guests are tiled within the browser source with the same size. If there is an active screen share, it is sized larger than the other guests. + ## * `HORIZONTAL_LAYOUT`: All live guests are arranged in a horizontal bar within the browser source + ## * `VERTICAL_LAYOUT`: All live guests are arranged in a vertical bar within the browser source + @export var group_layout: String: + set(val): + group_layout = val + track_data(&"group_layout", val) + + ## Flag determining if Guest Star should regenerate the auth token associated with the channel’s browser sources. Providing a true value for this will immediately invalidate all browser sources previously configured in your streaming software. + @export var regenerate_browser_sources: bool: + set(val): + regenerate_browser_sources = val + track_data(&"regenerate_browser_sources", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create() -> Body: + var body: Body = Body.new() + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("is_moderator_send_live_enabled", null) != null: + result.is_moderator_send_live_enabled = d["is_moderator_send_live_enabled"] + if d.get("slot_count", null) != null: + result.slot_count = d["slot_count"] + if d.get("is_browser_source_audio_enabled", null) != null: + result.is_browser_source_audio_enabled = d["is_browser_source_audio_enabled"] + if d.get("group_layout", null) != null: + result.group_layout = d["group_layout"] + if d.get("regenerate_browser_sources", null) != null: + result.regenerate_browser_sources = d["regenerate_browser_sources"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_update_channel_guest_star_settings.gd.uid b/addons/twitcher/generated/twitch_update_channel_guest_star_settings.gd.uid new file mode 100644 index 0000000..b085f2a --- /dev/null +++ b/addons/twitcher/generated/twitch_update_channel_guest_star_settings.gd.uid @@ -0,0 +1 @@ +uid://cymuyecuhv371 diff --git a/addons/twitcher/generated/twitch_update_channel_stream_schedule.gd b/addons/twitcher/generated/twitch_update_channel_stream_schedule.gd new file mode 100644 index 0000000..3b5c9d8 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_channel_stream_schedule.gd @@ -0,0 +1,57 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchUpdateChannelStreamSchedule + + + +## All optional parameters for TwitchAPI.update_channel_stream_schedule +## #/components/schemas/UpdateChannelStreamScheduleOpt +class Opt extends TwitchData: + + ## A Boolean value that indicates whether the broadcaster has scheduled a vacation. Set to **true** to enable Vacation Mode and add vacation dates, or **false** to cancel a previously scheduled vacation. + @export var is_vacation_enabled: bool: + set(val): + is_vacation_enabled = val + track_data(&"is_vacation_enabled", val) + + ## The UTC date and time of when the broadcaster’s vacation starts. Specify the date and time in RFC3339 format (for example, 2021-05-16T00:00:00Z). Required if _is\_vacation\_enabled_ is **true**. + @export var vacation_start_time: String: + set(val): + vacation_start_time = val + track_data(&"vacation_start_time", val) + + ## The UTC date and time of when the broadcaster’s vacation ends. Specify the date and time in RFC3339 format (for example, 2021-05-30T23:59:59Z). Required if _is\_vacation\_enabled_ is **true**. + @export var vacation_end_time: String: + set(val): + vacation_end_time = val + track_data(&"vacation_end_time", val) + + ## The time zone that the broadcaster broadcasts from. Specify the time zone using [IANA time zone database](https://www.iana.org/time-zones) format (for example, America/New\_York). Required if _is\_vacation\_enabled_ is **true**. + @export var timezone: String: + set(val): + timezone = val + track_data(&"timezone", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("is_vacation_enabled", null) != null: + result.is_vacation_enabled = d["is_vacation_enabled"] + if d.get("vacation_start_time", null) != null: + result.vacation_start_time = d["vacation_start_time"] + if d.get("vacation_end_time", null) != null: + result.vacation_end_time = d["vacation_end_time"] + if d.get("timezone", null) != null: + result.timezone = d["timezone"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_update_channel_stream_schedule.gd.uid b/addons/twitcher/generated/twitch_update_channel_stream_schedule.gd.uid new file mode 100644 index 0000000..bc119f0 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_channel_stream_schedule.gd.uid @@ -0,0 +1 @@ +uid://bw0okld3eve8l diff --git a/addons/twitcher/generated/twitch_update_channel_stream_schedule_segment.gd b/addons/twitcher/generated/twitch_update_channel_stream_schedule_segment.gd new file mode 100644 index 0000000..579c0b2 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_channel_stream_schedule_segment.gd @@ -0,0 +1,204 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchUpdateChannelStreamScheduleSegment + + + +## +## #/components/schemas/UpdateChannelStreamScheduleSegmentBody +class Body extends TwitchData: + + ## The date and time that the broadcast segment starts. Specify the date and time in RFC3339 format (for example, 2022-08-02T06:00:00Z). + ## + ## **NOTE**: Only partners and affiliates may update a broadcast’s start time and only for non-recurring segments. + @export var start_time: String: + set(val): + start_time = val + track_data(&"start_time", val) + + ## The length of time, in minutes, that the broadcast is scheduled to run. The duration must be in the range 30 through 1380 (23 hours). + @export var duration: String: + set(val): + duration = val + track_data(&"duration", val) + + ## The ID of the category that best represents the broadcast’s content. To get the category ID, use the [Search Categories](https://dev.twitch.tv/docs/api/reference#search-categories) endpoint. + @export var category_id: String: + set(val): + category_id = val + track_data(&"category_id", val) + + ## The broadcast’s title. The title may contain a maximum of 140 characters. + @export var title: String: + set(val): + title = val + track_data(&"title", val) + + ## A Boolean value that indicates whether the broadcast is canceled. Set to **true** to cancel the segment. + ## + ## **NOTE**: For recurring segments, the API cancels the first segment after the current UTC date and time and not the specified segment (unless the specified segment is the next segment after the current UTC date and time). + @export var is_canceled: bool: + set(val): + is_canceled = val + track_data(&"is_canceled", val) + + ## The time zone where the broadcast takes place. Specify the time zone using [IANA time zone database](https://www.iana.org/time-zones) format (for example, America/New\_York). + @export var timezone: String: + set(val): + timezone = val + track_data(&"timezone", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create() -> Body: + var body: Body = Body.new() + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("start_time", null) != null: + result.start_time = d["start_time"] + if d.get("duration", null) != null: + result.duration = d["duration"] + if d.get("category_id", null) != null: + result.category_id = d["category_id"] + if d.get("title", null) != null: + result.title = d["title"] + if d.get("is_canceled", null) != null: + result.is_canceled = d["is_canceled"] + if d.get("timezone", null) != null: + result.timezone = d["timezone"] + return result + + + +## +## #/components/schemas/UpdateChannelStreamScheduleSegmentResponse +class Response extends TwitchData: + + ## The broadcaster’s streaming scheduled. + @export var data: ResponseData: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: ResponseData) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + result.data = ResponseData.from_json(d["data"]) + return result + + + +## The broadcaster’s streaming scheduled. +## #/components/schemas/UpdateChannelStreamScheduleSegmentResponse/Data +class ResponseData extends TwitchData: + + ## A list that contains the single broadcast segment that you updated. + @export var segments: Array[TwitchChannelStreamScheduleSegment]: + set(val): + segments = val + track_data(&"segments", val) + + ## The ID of the broadcaster that owns the broadcast schedule. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## The broadcaster’s display name. + @export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + + ## The broadcaster’s login name. + @export var broadcaster_login: String: + set(val): + broadcaster_login = val + track_data(&"broadcaster_login", val) + + ## The dates when the broadcaster is on vacation and not streaming. Is set to **null** if vacation mode is not enabled. + @export var vacation: ResponseVacation: + set(val): + vacation = val + track_data(&"vacation", val) + + + + ## Constructor with all required fields. + static func create(_segments: Array[TwitchChannelStreamScheduleSegment], _broadcaster_id: String, _broadcaster_name: String, _broadcaster_login: String, _vacation: ResponseVacation) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.segments = _segments + response_data.broadcaster_id = _broadcaster_id + response_data.broadcaster_name = _broadcaster_name + response_data.broadcaster_login = _broadcaster_login + response_data.vacation = _vacation + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("segments", null) != null: + for value in d["segments"]: + result.segments.append(TwitchChannelStreamScheduleSegment.from_json(value)) + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + if d.get("broadcaster_login", null) != null: + result.broadcaster_login = d["broadcaster_login"] + if d.get("vacation", null) != null: + result.vacation = ResponseVacation.from_json(d["vacation"]) + return result + + + +## The dates when the broadcaster is on vacation and not streaming. Is set to **null** if vacation mode is not enabled. +## #/components/schemas/UpdateChannelStreamScheduleSegmentResponse/Data/Vacation +class ResponseVacation extends TwitchData: + + ## The UTC date and time (in RFC3339 format) of when the broadcaster’s vacation starts. + @export var start_time: String: + set(val): + start_time = val + track_data(&"start_time", val) + + ## The UTC date and time (in RFC3339 format) of when the broadcaster’s vacation ends. + @export var end_time: String: + set(val): + end_time = val + track_data(&"end_time", val) + + + + ## Constructor with all required fields. + static func create(_start_time: String, _end_time: String) -> ResponseVacation: + var response_vacation: ResponseVacation = ResponseVacation.new() + response_vacation.start_time = _start_time + response_vacation.end_time = _end_time + return response_vacation + + + static func from_json(d: Dictionary) -> ResponseVacation: + var result: ResponseVacation = ResponseVacation.new() + if d.get("start_time", null) != null: + result.start_time = d["start_time"] + if d.get("end_time", null) != null: + result.end_time = d["end_time"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_update_channel_stream_schedule_segment.gd.uid b/addons/twitcher/generated/twitch_update_channel_stream_schedule_segment.gd.uid new file mode 100644 index 0000000..9293d21 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_channel_stream_schedule_segment.gd.uid @@ -0,0 +1 @@ +uid://c2ner7gducdjx diff --git a/addons/twitcher/generated/twitch_update_chat_settings.gd b/addons/twitcher/generated/twitch_update_chat_settings.gd new file mode 100644 index 0000000..0606d9e --- /dev/null +++ b/addons/twitcher/generated/twitch_update_chat_settings.gd @@ -0,0 +1,147 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchUpdateChatSettings + + + +## +## #/components/schemas/UpdateChatSettingsBody +class Body extends TwitchData: + + ## A Boolean value that determines whether chat messages must contain only emotes. + ## + ## Set to **true** if only emotes are allowed; otherwise, **false**. The default is **false**. + @export var emote_mode: bool: + set(val): + emote_mode = val + track_data(&"emote_mode", val) + + ## A Boolean value that determines whether the broadcaster restricts the chat room to followers only. + ## + ## Set to **true** if the broadcaster restricts the chat room to followers only; otherwise, **false**. The default is **true**. + ## + ## To specify how long users must follow the broadcaster before being able to participate in the chat room, see the `follower_mode_duration` field. + @export var follower_mode: bool: + set(val): + follower_mode = val + track_data(&"follower_mode", val) + + ## The length of time, in minutes, that users must follow the broadcaster before being able to participate in the chat room. Set only if `follower_mode` is **true**. Possible values are: 0 (no restriction) through 129600 (3 months). The default is 0. + @export var follower_mode_duration: int: + set(val): + follower_mode_duration = val + track_data(&"follower_mode_duration", val) + + ## A Boolean value that determines whether the broadcaster adds a short delay before chat messages appear in the chat room. This gives chat moderators and bots a chance to remove them before viewers can see the message. + ## + ## Set to **true** if the broadcaster applies a delay; otherwise, **false**. The default is **false**. + ## + ## To specify the length of the delay, see the `non_moderator_chat_delay_duration` field. + @export var non_moderator_chat_delay: bool: + set(val): + non_moderator_chat_delay = val + track_data(&"non_moderator_chat_delay", val) + + ## The amount of time, in seconds, that messages are delayed before appearing in chat. Set only if `non_moderator_chat_delay` is **true**. Possible values are: + ## + ## * 2 — 2 second delay (recommended) + ## * 4 — 4 second delay + ## * 6 — 6 second delay + @export var non_moderator_chat_delay_duration: int: + set(val): + non_moderator_chat_delay_duration = val + track_data(&"non_moderator_chat_delay_duration", val) + + ## A Boolean value that determines whether the broadcaster limits how often users in the chat room are allowed to send messages. Set to **true** if the broadcaster applies a wait period between messages; otherwise, **false**. The default is **false**. + ## + ## To specify the delay, see the `slow_mode_wait_time` field. + @export var slow_mode: bool: + set(val): + slow_mode = val + track_data(&"slow_mode", val) + + ## The amount of time, in seconds, that users must wait between sending messages. Set only if `slow_mode` is **true**. + ## + ## Possible values are: 3 (3 second delay) through 120 (2 minute delay). The default is 30 seconds. + @export var slow_mode_wait_time: int: + set(val): + slow_mode_wait_time = val + track_data(&"slow_mode_wait_time", val) + + ## A Boolean value that determines whether only users that subscribe to the broadcaster’s channel may talk in the chat room. + ## + ## Set to **true** if the broadcaster restricts the chat room to subscribers only; otherwise, **false**. The default is **false**. + @export var subscriber_mode: bool: + set(val): + subscriber_mode = val + track_data(&"subscriber_mode", val) + + ## A Boolean value that determines whether the broadcaster requires users to post only unique messages in the chat room. + ## + ## Set to **true** if the broadcaster allows only unique messages; otherwise, **false**. The default is **false**. + @export var unique_chat_mode: bool: + set(val): + unique_chat_mode = val + track_data(&"unique_chat_mode", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create() -> Body: + var body: Body = Body.new() + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("emote_mode", null) != null: + result.emote_mode = d["emote_mode"] + if d.get("follower_mode", null) != null: + result.follower_mode = d["follower_mode"] + if d.get("follower_mode_duration", null) != null: + result.follower_mode_duration = d["follower_mode_duration"] + if d.get("non_moderator_chat_delay", null) != null: + result.non_moderator_chat_delay = d["non_moderator_chat_delay"] + if d.get("non_moderator_chat_delay_duration", null) != null: + result.non_moderator_chat_delay_duration = d["non_moderator_chat_delay_duration"] + if d.get("slow_mode", null) != null: + result.slow_mode = d["slow_mode"] + if d.get("slow_mode_wait_time", null) != null: + result.slow_mode_wait_time = d["slow_mode_wait_time"] + if d.get("subscriber_mode", null) != null: + result.subscriber_mode = d["subscriber_mode"] + if d.get("unique_chat_mode", null) != null: + result.unique_chat_mode = d["unique_chat_mode"] + return result + + + +## +## #/components/schemas/UpdateChatSettingsResponse +class Response extends TwitchData: + + ## The list of chat settings. The list contains a single object with all the settings. + @export var data: Array[TwitchChatSettingsUpdated]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchChatSettingsUpdated]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchChatSettingsUpdated.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_update_chat_settings.gd.uid b/addons/twitcher/generated/twitch_update_chat_settings.gd.uid new file mode 100644 index 0000000..94f595c --- /dev/null +++ b/addons/twitcher/generated/twitch_update_chat_settings.gd.uid @@ -0,0 +1 @@ +uid://tpyjcv8fnl1q diff --git a/addons/twitcher/generated/twitch_update_conduit_shards.gd b/addons/twitcher/generated/twitch_update_conduit_shards.gd new file mode 100644 index 0000000..4504c99 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_conduit_shards.gd @@ -0,0 +1,343 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchUpdateConduitShards + + + +## +## #/components/schemas/UpdateConduitShardsBody +class Body extends TwitchData: + + ## Conduit ID. + @export var conduit_id: String: + set(val): + conduit_id = val + track_data(&"conduit_id", val) + + ## List of shards to update. + @export var shards: Array[BodyShards]: + set(val): + shards = val + track_data(&"shards", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_conduit_id: String, _shards: Array[BodyShards]) -> Body: + var body: Body = Body.new() + body.conduit_id = _conduit_id + body.shards = _shards + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("conduit_id", null) != null: + result.conduit_id = d["conduit_id"] + if d.get("shards", null) != null: + for value in d["shards"]: + result.shards.append(BodyShards.from_json(value)) + return result + + + +## List of shards to update. +## #/components/schemas/UpdateConduitShardsBody/Shards +class BodyShards extends TwitchData: + + ## Shard ID. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## The transport details that you want Twitch to use when sending you notifications. + @export var transport: BodyTransport: + set(val): + transport = val + track_data(&"transport", val) + + + + ## Constructor with all required fields. + static func create(_id: String, _transport: BodyTransport) -> BodyShards: + var body_shards: BodyShards = BodyShards.new() + body_shards.id = _id + body_shards.transport = _transport + return body_shards + + + static func from_json(d: Dictionary) -> BodyShards: + var result: BodyShards = BodyShards.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("transport", null) != null: + result.transport = BodyTransport.from_json(d["transport"]) + return result + + + +## The transport details that you want Twitch to use when sending you notifications. +## #/components/schemas/UpdateConduitShardsBody/Shards/Transport +class BodyTransport extends TwitchData: + + ## The transport method. Possible values are: + ## + ## * webhook + ## * websocket + @export var method: String: + set(val): + method = val + track_data(&"method", val) + + ## The callback URL where the notifications are sent. The URL must use the HTTPS protocol and port 443\. See Processing an event.Specify this field only if method is set to webhook.NOTE: Redirects are not followed. + @export var callback: String: + set(val): + callback = val + track_data(&"callback", val) + + ## The secret used to verify the signature. The secret must be an ASCII string that’s a minimum of 10 characters long and a maximum of 100 characters long. For information about how the secret is used, see Verifying the event message.Specify this field only if method is set to webhook. + @export var secret: String: + set(val): + secret = val + track_data(&"secret", val) + + ## An ID that identifies the WebSocket to send notifications to. When you connect to EventSub using WebSockets, the server returns the ID in the Welcome message.Specify this field only if method is set to websocket. + @export var session_id: String: + set(val): + session_id = val + track_data(&"session_id", val) + + + + ## Constructor with all required fields. + static func create() -> BodyTransport: + var body_transport: BodyTransport = BodyTransport.new() + return body_transport + + + static func from_json(d: Dictionary) -> BodyTransport: + var result: BodyTransport = BodyTransport.new() + if d.get("method", null) != null: + result.method = d["method"] + if d.get("callback", null) != null: + result.callback = d["callback"] + if d.get("secret", null) != null: + result.secret = d["secret"] + if d.get("session_id", null) != null: + result.session_id = d["session_id"] + return result + + + +## +## #/components/schemas/UpdateConduitShardsResponse +class Response extends TwitchData: + + ## List of successful shard updates. + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + + ## List of unsuccessful updates. + @export var errors: Array[ResponseErrors]: + set(val): + errors = val + track_data(&"errors", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData], _errors: Array[ResponseErrors]) -> Response: + var response: Response = Response.new() + response.data = _data + response.errors = _errors + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + if d.get("errors", null) != null: + for value in d["errors"]: + result.errors.append(ResponseErrors.from_json(value)) + return result + + + +## List of successful shard updates. +## #/components/schemas/UpdateConduitShardsResponse/Data +class ResponseData extends TwitchData: + + ## Shard ID. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## The shard status. The subscriber receives events only for enabled shards. Possible values are: + ## + ## * enabled — The shard is enabled. + ## * webhook\_callback\_verification\_pending — The shard is pending verification of the specified callback URL. + ## * webhook\_callback\_verification\_failed — The specified callback URL failed verification. + ## * notification\_failures\_exceeded — The notification delivery failure rate was too high. + ## * websocket\_disconnected — The client closed the connection. + ## * websocket\_failed\_ping\_pong — The client failed to respond to a ping message. + ## * websocket\_received\_inbound\_traffic — The client sent a non-pong message. Clients may only send pong messages (and only in response to a ping message). + ## * websocket\_internal\_error — The Twitch WebSocket server experienced an unexpected error. + ## * websocket\_network\_timeout — The Twitch WebSocket server timed out writing the message to the client. + ## * websocket\_network\_error — The Twitch WebSocket server experienced a network error writing the message to the client. + ## * websocket\_failed\_to\_reconnect - The client failed to reconnect to the Twitch WebSocket server within the required time after a Reconnect Message. + @export var status: String: + set(val): + status = val + track_data(&"status", val) + + ## The transport details used to send the notifications. + @export var transport: ResponseTransport: + set(val): + transport = val + track_data(&"transport", val) + + + + ## Constructor with all required fields. + static func create(_id: String, _status: String, _transport: ResponseTransport) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.id = _id + response_data.status = _status + response_data.transport = _transport + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("status", null) != null: + result.status = d["status"] + if d.get("transport", null) != null: + result.transport = ResponseTransport.from_json(d["transport"]) + return result + + + +## The transport details used to send the notifications. +## #/components/schemas/UpdateConduitShardsResponse/Data/Transport +class ResponseTransport extends TwitchData: + + ## The transport method. Possible values are: + ## + ## * webhook + ## * websocket + @export var method: String: + set(val): + method = val + track_data(&"method", val) + + ## The callback URL where the notifications are sent. Included only if method is set to webhook. + @export var callback: String: + set(val): + callback = val + track_data(&"callback", val) + + ## An ID that identifies the WebSocket that notifications are sent to. Included only if method is set to websocket. + @export var session_id: String: + set(val): + session_id = val + track_data(&"session_id", val) + + ## The UTC date and time that the WebSocket connection was established. Included only if method is set to websocket. + @export var connected_at: String: + set(val): + connected_at = val + track_data(&"connected_at", val) + + ## The UTC date and time that the WebSocket connection was lost. Included only if method is set to websocket. + @export var disconnected_at: String: + set(val): + disconnected_at = val + track_data(&"disconnected_at", val) + + + + ## Constructor with all required fields. + static func create(_method: String) -> ResponseTransport: + var response_transport: ResponseTransport = ResponseTransport.new() + response_transport.method = _method + return response_transport + + + static func from_json(d: Dictionary) -> ResponseTransport: + var result: ResponseTransport = ResponseTransport.new() + if d.get("method", null) != null: + result.method = d["method"] + if d.get("callback", null) != null: + result.callback = d["callback"] + if d.get("session_id", null) != null: + result.session_id = d["session_id"] + if d.get("connected_at", null) != null: + result.connected_at = d["connected_at"] + if d.get("disconnected_at", null) != null: + result.disconnected_at = d["disconnected_at"] + return result + + + +## List of unsuccessful updates. +## #/components/schemas/UpdateConduitShardsResponse/Errors +class ResponseErrors extends TwitchData: + + ## Shard ID. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## The error that occurred while updating the shard. Possible errors: + ## + ## * The length of the string in the secret field is not valid. + ## * The URL in the transport's callback field is not valid. The URL must use the HTTPS protocol and the 443 port number. + ## * The value specified in the method field is not valid. + ## * The callback field is required if you specify the webhook transport method. + ## * The session\_id field is required if you specify the WebSocket transport method. + ## * The websocket session is not connected. + ## * The shard id is outside of the conduit’s range. + @export var message: String: + set(val): + message = val + track_data(&"message", val) + + ## Error codes used to represent a specific error condition while attempting to update shards. + @export var code: String: + set(val): + code = val + track_data(&"code", val) + + + + ## Constructor with all required fields. + static func create(_id: String, _message: String, _code: String) -> ResponseErrors: + var response_errors: ResponseErrors = ResponseErrors.new() + response_errors.id = _id + response_errors.message = _message + response_errors.code = _code + return response_errors + + + static func from_json(d: Dictionary) -> ResponseErrors: + var result: ResponseErrors = ResponseErrors.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("message", null) != null: + result.message = d["message"] + if d.get("code", null) != null: + result.code = d["code"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_update_conduit_shards.gd.uid b/addons/twitcher/generated/twitch_update_conduit_shards.gd.uid new file mode 100644 index 0000000..d7740eb --- /dev/null +++ b/addons/twitcher/generated/twitch_update_conduit_shards.gd.uid @@ -0,0 +1 @@ +uid://dacxpre5dg6l3 diff --git a/addons/twitcher/generated/twitch_update_conduits.gd b/addons/twitcher/generated/twitch_update_conduits.gd new file mode 100644 index 0000000..f01a761 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_conduits.gd @@ -0,0 +1,107 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchUpdateConduits + + + +## +## #/components/schemas/UpdateConduitsBody +class Body extends TwitchData: + + ## Conduit ID. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## The new number of shards for this conduit. + @export var shard_count: int: + set(val): + shard_count = val + track_data(&"shard_count", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_id: String, _shard_count: int) -> Body: + var body: Body = Body.new() + body.id = _id + body.shard_count = _shard_count + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("shard_count", null) != null: + result.shard_count = d["shard_count"] + return result + + + +## +## #/components/schemas/UpdateConduitsResponse +class Response extends TwitchData: + + ## List of information about the client’s conduits. + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + return result + + + +## List of information about the client’s conduits. +## #/components/schemas/UpdateConduitsResponse/Data +class ResponseData extends TwitchData: + + ## Conduit ID. + @export var id: String: + set(val): + id = val + track_data(&"id", val) + + ## Number of shards associated with this conduit after the update. + @export var shard_count: int: + set(val): + shard_count = val + track_data(&"shard_count", val) + + + + ## Constructor with all required fields. + static func create(_id: String, _shard_count: int) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.id = _id + response_data.shard_count = _shard_count + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("shard_count", null) != null: + result.shard_count = d["shard_count"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_update_conduits.gd.uid b/addons/twitcher/generated/twitch_update_conduits.gd.uid new file mode 100644 index 0000000..2c97ed3 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_conduits.gd.uid @@ -0,0 +1 @@ +uid://d1vib5ftfiafj diff --git a/addons/twitcher/generated/twitch_update_custom_reward.gd b/addons/twitcher/generated/twitch_update_custom_reward.gd new file mode 100644 index 0000000..12e2124 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_custom_reward.gd @@ -0,0 +1,165 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchUpdateCustomReward + + + +## +## #/components/schemas/UpdateCustomRewardBody +class Body extends TwitchData: + + ## The reward’s title. The title may contain a maximum of 45 characters and it must be unique amongst all of the broadcaster’s custom rewards. + @export var title: String: + set(val): + title = val + track_data(&"title", val) + + ## The prompt shown to the viewer when they redeem the reward. Specify a prompt if `is_user_input_required` is **true**. The prompt is limited to a maximum of 200 characters. + @export var prompt: String: + set(val): + prompt = val + track_data(&"prompt", val) + + ## The cost of the reward, in channel points. The minimum is 1 point. + @export var cost: int: + set(val): + cost = val + track_data(&"cost", val) + + ## The background color to use for the reward. Specify the color using Hex format (for example, \\#00E5CB). + @export var background_color: String: + set(val): + background_color = val + track_data(&"background_color", val) + + ## A Boolean value that indicates whether the reward is enabled. Set to **true** to enable the reward. Viewers see only enabled rewards. + @export var is_enabled: bool: + set(val): + is_enabled = val + track_data(&"is_enabled", val) + + ## A Boolean value that determines whether users must enter information to redeem the reward. Set to **true** if user input is required. See the `prompt` field. + @export var is_user_input_required: bool: + set(val): + is_user_input_required = val + track_data(&"is_user_input_required", val) + + ## A Boolean value that determines whether to limit the maximum number of redemptions allowed per live stream (see the `max_per_stream` field). Set to **true** to limit redemptions. + @export var is_max_per_stream_enabled: bool: + set(val): + is_max_per_stream_enabled = val + track_data(&"is_max_per_stream_enabled", val) + + ## The maximum number of redemptions allowed per live stream. Applied only if `is_max_per_stream_enabled` is **true**. The minimum value is 1. + @export var max_per_stream: int: + set(val): + max_per_stream = val + track_data(&"max_per_stream", val) + + ## A Boolean value that determines whether to limit the maximum number of redemptions allowed per user per stream (see `max_per_user_per_stream`). The minimum value is 1\. Set to **true** to limit redemptions. + @export var is_max_per_user_per_stream_enabled: bool: + set(val): + is_max_per_user_per_stream_enabled = val + track_data(&"is_max_per_user_per_stream_enabled", val) + + ## The maximum number of redemptions allowed per user per stream. Applied only if `is_max_per_user_per_stream_enabled` is **true**. + @export var max_per_user_per_stream: int: + set(val): + max_per_user_per_stream = val + track_data(&"max_per_user_per_stream", val) + + ## A Boolean value that determines whether to apply a cooldown period between redemptions. Set to **true** to apply a cooldown period. For the duration of the cooldown period, see `global_cooldown_seconds`. + @export var is_global_cooldown_enabled: bool: + set(val): + is_global_cooldown_enabled = val + track_data(&"is_global_cooldown_enabled", val) + + ## The cooldown period, in seconds. Applied only if `is_global_cooldown_enabled` is **true**. The minimum value is 1; however, for it to be shown in the Twitch UX, the minimum value is 60. + @export var global_cooldown_seconds: int: + set(val): + global_cooldown_seconds = val + track_data(&"global_cooldown_seconds", val) + + ## A Boolean value that determines whether to pause the reward. Set to **true** to pause the reward. Viewers can’t redeem paused rewards.. + @export var is_paused: bool: + set(val): + is_paused = val + track_data(&"is_paused", val) + + ## A Boolean value that determines whether redemptions should be set to FULFILLED status immediately when a reward is redeemed. If **false**, status is set to UNFULFILLED and follows the normal request queue process. + @export var should_redemptions_skip_request_queue: bool: + set(val): + should_redemptions_skip_request_queue = val + track_data(&"should_redemptions_skip_request_queue", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create() -> Body: + var body: Body = Body.new() + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("title", null) != null: + result.title = d["title"] + if d.get("prompt", null) != null: + result.prompt = d["prompt"] + if d.get("cost", null) != null: + result.cost = d["cost"] + if d.get("background_color", null) != null: + result.background_color = d["background_color"] + if d.get("is_enabled", null) != null: + result.is_enabled = d["is_enabled"] + if d.get("is_user_input_required", null) != null: + result.is_user_input_required = d["is_user_input_required"] + if d.get("is_max_per_stream_enabled", null) != null: + result.is_max_per_stream_enabled = d["is_max_per_stream_enabled"] + if d.get("max_per_stream", null) != null: + result.max_per_stream = d["max_per_stream"] + if d.get("is_max_per_user_per_stream_enabled", null) != null: + result.is_max_per_user_per_stream_enabled = d["is_max_per_user_per_stream_enabled"] + if d.get("max_per_user_per_stream", null) != null: + result.max_per_user_per_stream = d["max_per_user_per_stream"] + if d.get("is_global_cooldown_enabled", null) != null: + result.is_global_cooldown_enabled = d["is_global_cooldown_enabled"] + if d.get("global_cooldown_seconds", null) != null: + result.global_cooldown_seconds = d["global_cooldown_seconds"] + if d.get("is_paused", null) != null: + result.is_paused = d["is_paused"] + if d.get("should_redemptions_skip_request_queue", null) != null: + result.should_redemptions_skip_request_queue = d["should_redemptions_skip_request_queue"] + return result + + + +## +## #/components/schemas/UpdateCustomRewardResponse +class Response extends TwitchData: + + ## The list contains the single reward that you updated. + @export var data: Array[TwitchCustomReward]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchCustomReward]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchCustomReward.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_update_custom_reward.gd.uid b/addons/twitcher/generated/twitch_update_custom_reward.gd.uid new file mode 100644 index 0000000..684b8e7 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_custom_reward.gd.uid @@ -0,0 +1 @@ +uid://che5jvmhkt8nn diff --git a/addons/twitcher/generated/twitch_update_drops_entitlements.gd b/addons/twitcher/generated/twitch_update_drops_entitlements.gd new file mode 100644 index 0000000..d230595 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_drops_entitlements.gd @@ -0,0 +1,73 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchUpdateDropsEntitlements + + + +## +## #/components/schemas/UpdateDropsEntitlementsBody +class Body extends TwitchData: + + ## A list of IDs that identify the entitlements to update. You may specify a maximum of 100 IDs. + @export var entitlement_ids: Array[String]: + set(val): + entitlement_ids = val + track_data(&"entitlement_ids", val) + + ## The fulfillment status to set the entitlements to. Possible values are: + ## + ## * CLAIMED — The user claimed the benefit. + ## * FULFILLED — The developer granted the benefit that the user claimed. + @export var fulfillment_status: String: + set(val): + fulfillment_status = val + track_data(&"fulfillment_status", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create() -> Body: + var body: Body = Body.new() + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("entitlement_ids", null) != null: + for value in d["entitlement_ids"]: + result.entitlement_ids.append(value) + if d.get("fulfillment_status", null) != null: + result.fulfillment_status = d["fulfillment_status"] + return result + + + +## +## #/components/schemas/UpdateDropsEntitlementsResponse +class Response extends TwitchData: + + ## A list that indicates which entitlements were successfully updated and those that weren’t. + @export var data: Array[TwitchDropsEntitlementUpdated]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchDropsEntitlementUpdated]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchDropsEntitlementUpdated.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_update_drops_entitlements.gd.uid b/addons/twitcher/generated/twitch_update_drops_entitlements.gd.uid new file mode 100644 index 0000000..15bc71a --- /dev/null +++ b/addons/twitcher/generated/twitch_update_drops_entitlements.gd.uid @@ -0,0 +1 @@ +uid://rwtv6ypknpaf diff --git a/addons/twitcher/generated/twitch_update_extension_bits_product.gd b/addons/twitcher/generated/twitch_update_extension_bits_product.gd new file mode 100644 index 0000000..7b4d99c --- /dev/null +++ b/addons/twitcher/generated/twitch_update_extension_bits_product.gd @@ -0,0 +1,142 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchUpdateExtensionBitsProduct + + + +## +## #/components/schemas/UpdateExtensionBitsProductBody +class Body extends TwitchData: + + ## The product's SKU. The SKU must be unique within an extension. The product's SKU cannot be changed. The SKU may contain only alphanumeric characters, dashes (-), underscores (\_), and periods (.) and is limited to a maximum of 255 characters. No spaces. + @export var sku: String: + set(val): + sku = val + track_data(&"sku", val) + + ## An object that contains the product's cost information. + @export var cost: BodyCost: + set(val): + cost = val + track_data(&"cost", val) + + ## The product's name as displayed in the extension. The maximum length is 255 characters. + @export var display_name: String: + set(val): + display_name = val + track_data(&"display_name", val) + + ## A Boolean value that indicates whether the product is in development. Set to **true** if the product is in development and not available for public use. The default is **false**. + @export var in_development: bool: + set(val): + in_development = val + track_data(&"in_development", val) + + ## The date and time, in RFC3339 format, when the product expires. If not set, the product does not expire. To disable the product, set the expiration date to a date in the past. + @export var expiration: String: + set(val): + expiration = val + track_data(&"expiration", val) + + ## A Boolean value that determines whether Bits product purchase events are broadcast to all instances of the extension on a channel. The events are broadcast via the `onTransactionComplete` helper callback. The default is **false**. + @export var is_broadcast: bool: + set(val): + is_broadcast = val + track_data(&"is_broadcast", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_sku: String, _cost: BodyCost, _display_name: String) -> Body: + var body: Body = Body.new() + body.sku = _sku + body.cost = _cost + body.display_name = _display_name + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("sku", null) != null: + result.sku = d["sku"] + if d.get("cost", null) != null: + result.cost = BodyCost.from_json(d["cost"]) + if d.get("display_name", null) != null: + result.display_name = d["display_name"] + if d.get("in_development", null) != null: + result.in_development = d["in_development"] + if d.get("expiration", null) != null: + result.expiration = d["expiration"] + if d.get("is_broadcast", null) != null: + result.is_broadcast = d["is_broadcast"] + return result + + + +## An object that contains the product's cost information. +## #/components/schemas/UpdateExtensionBitsProductBody/Cost +class BodyCost extends TwitchData: + + ## The product's price. + @export var amount: int: + set(val): + amount = val + track_data(&"amount", val) + + ## The type of currency. Possible values are: + ## + ## * bits — The minimum price is 1 and the maximum is 10000. + @export var type: String: + set(val): + type = val + track_data(&"type", val) + + + + ## Constructor with all required fields. + static func create(_amount: int, _type: String) -> BodyCost: + var body_cost: BodyCost = BodyCost.new() + body_cost.amount = _amount + body_cost.type = _type + return body_cost + + + static func from_json(d: Dictionary) -> BodyCost: + var result: BodyCost = BodyCost.new() + if d.get("amount", null) != null: + result.amount = d["amount"] + if d.get("type", null) != null: + result.type = d["type"] + return result + + + +## +## #/components/schemas/UpdateExtensionBitsProductResponse +class Response extends TwitchData: + + ## A list of Bits products that the extension created. The list is in ascending SKU order. The list is empty if the extension hasn't created any products or they're all expired or disabled. + @export var data: Array[TwitchExtensionBitsProduct]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchExtensionBitsProduct]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchExtensionBitsProduct.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_update_extension_bits_product.gd.uid b/addons/twitcher/generated/twitch_update_extension_bits_product.gd.uid new file mode 100644 index 0000000..6be0476 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_extension_bits_product.gd.uid @@ -0,0 +1 @@ +uid://c1fry1o2hvild diff --git a/addons/twitcher/generated/twitch_update_guest_star_slot.gd b/addons/twitcher/generated/twitch_update_guest_star_slot.gd new file mode 100644 index 0000000..b50e639 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_guest_star_slot.gd @@ -0,0 +1,33 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchUpdateGuestStarSlot + + + +## All optional parameters for TwitchAPI.update_guest_star_slot +## #/components/schemas/UpdateGuestStarSlotOpt +class Opt extends TwitchData: + + ## The slot to move this user assignment to. If the destination slot is occupied, the user assigned will be swapped into `source_slot_id`. + @export var destination_slot_id: String: + set(val): + destination_slot_id = val + track_data(&"destination_slot_id", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("destination_slot_id", null) != null: + result.destination_slot_id = d["destination_slot_id"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_update_guest_star_slot.gd.uid b/addons/twitcher/generated/twitch_update_guest_star_slot.gd.uid new file mode 100644 index 0000000..3c5b212 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_guest_star_slot.gd.uid @@ -0,0 +1 @@ +uid://chj72jmp18ygf diff --git a/addons/twitcher/generated/twitch_update_guest_star_slot_settings.gd b/addons/twitcher/generated/twitch_update_guest_star_slot_settings.gd new file mode 100644 index 0000000..3dd139e --- /dev/null +++ b/addons/twitcher/generated/twitch_update_guest_star_slot_settings.gd @@ -0,0 +1,57 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchUpdateGuestStarSlotSettings + + + +## All optional parameters for TwitchAPI.update_guest_star_slot_settings +## #/components/schemas/UpdateGuestStarSlotSettingsOpt +class Opt extends TwitchData: + + ## Flag indicating whether the slot is allowed to share their audio with the rest of the session. If false, the slot will be muted in any views containing the slot. + @export var is_audio_enabled: bool: + set(val): + is_audio_enabled = val + track_data(&"is_audio_enabled", val) + + ## Flag indicating whether the slot is allowed to share their video with the rest of the session. If false, the slot will have no video shared in any views containing the slot. + @export var is_video_enabled: bool: + set(val): + is_video_enabled = val + track_data(&"is_video_enabled", val) + + ## Flag indicating whether the user assigned to this slot is visible/can be heard from any public subscriptions. Generally, this determines whether or not the slot is enabled in any broadcasting software integrations. + @export var is_live: bool: + set(val): + is_live = val + track_data(&"is_live", val) + + ## Value from 0-100 that controls the audio volume for shared views containing the slot. + @export var volume: int: + set(val): + volume = val + track_data(&"volume", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("is_audio_enabled", null) != null: + result.is_audio_enabled = d["is_audio_enabled"] + if d.get("is_video_enabled", null) != null: + result.is_video_enabled = d["is_video_enabled"] + if d.get("is_live", null) != null: + result.is_live = d["is_live"] + if d.get("volume", null) != null: + result.volume = d["volume"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_update_guest_star_slot_settings.gd.uid b/addons/twitcher/generated/twitch_update_guest_star_slot_settings.gd.uid new file mode 100644 index 0000000..9f9c9cf --- /dev/null +++ b/addons/twitcher/generated/twitch_update_guest_star_slot_settings.gd.uid @@ -0,0 +1 @@ +uid://cvgocdv48imwq diff --git a/addons/twitcher/generated/twitch_update_redemption_status.gd b/addons/twitcher/generated/twitch_update_redemption_status.gd new file mode 100644 index 0000000..b16b099 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_redemption_status.gd @@ -0,0 +1,67 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchUpdateRedemptionStatus + + + +## +## #/components/schemas/UpdateRedemptionStatusBody +class Body extends TwitchData: + + ## The status to set the redemption to. Possible values are: + ## + ## * CANCELED + ## * FULFILLED + ## + ## Setting the status to CANCELED refunds the user’s channel points. + @export var status: String: + set(val): + status = val + track_data(&"status", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_status: String) -> Body: + var body: Body = Body.new() + body.status = _status + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("status", null) != null: + result.status = d["status"] + return result + + + +## +## #/components/schemas/UpdateRedemptionStatusResponse +class Response extends TwitchData: + + ## The list contains the single redemption that you updated. + @export var data: Array[TwitchCustomRewardRedemption]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchCustomRewardRedemption]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchCustomRewardRedemption.from_json(value)) + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_update_redemption_status.gd.uid b/addons/twitcher/generated/twitch_update_redemption_status.gd.uid new file mode 100644 index 0000000..fe9b157 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_redemption_status.gd.uid @@ -0,0 +1 @@ +uid://x8dfpnom73ce diff --git a/addons/twitcher/generated/twitch_update_shield_mode_status.gd b/addons/twitcher/generated/twitch_update_shield_mode_status.gd new file mode 100644 index 0000000..e941a72 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_shield_mode_status.gd @@ -0,0 +1,125 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchUpdateShieldModeStatus + + + +## +## #/components/schemas/UpdateShieldModeStatusBody +class Body extends TwitchData: + + ## A Boolean value that determines whether to activate Shield Mode. Set to **true** to activate Shield Mode; otherwise, **false** to deactivate Shield Mode. + @export var is_active: bool: + set(val): + is_active = val + track_data(&"is_active", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_is_active: bool) -> Body: + var body: Body = Body.new() + body.is_active = _is_active + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("is_active", null) != null: + result.is_active = d["is_active"] + return result + + + +## +## #/components/schemas/UpdateShieldModeStatusResponse +class Response extends TwitchData: + + ## A list that contains a single object with the broadcaster’s updated Shield Mode status. + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + return result + + + +## A list that contains a single object with the broadcaster’s updated Shield Mode status. +## #/components/schemas/UpdateShieldModeStatusResponse/Data +class ResponseData extends TwitchData: + + ## A Boolean value that determines whether Shield Mode is active. Is **true** if Shield Mode is active; otherwise, **false**. + @export var is_active: bool: + set(val): + is_active = val + track_data(&"is_active", val) + + ## An ID that identifies the moderator that last activated Shield Mode. + @export var moderator_id: String: + set(val): + moderator_id = val + track_data(&"moderator_id", val) + + ## The moderator’s login name. + @export var moderator_login: String: + set(val): + moderator_login = val + track_data(&"moderator_login", val) + + ## The moderator’s display name. + @export var moderator_name: String: + set(val): + moderator_name = val + track_data(&"moderator_name", val) + + ## The UTC timestamp (in RFC3339 format) of when Shield Mode was last activated. + @export var last_activated_at: String: + set(val): + last_activated_at = val + track_data(&"last_activated_at", val) + + + + ## Constructor with all required fields. + static func create(_is_active: bool, _moderator_id: String, _moderator_login: String, _moderator_name: String, _last_activated_at: String) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.is_active = _is_active + response_data.moderator_id = _moderator_id + response_data.moderator_login = _moderator_login + response_data.moderator_name = _moderator_name + response_data.last_activated_at = _last_activated_at + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("is_active", null) != null: + result.is_active = d["is_active"] + if d.get("moderator_id", null) != null: + result.moderator_id = d["moderator_id"] + if d.get("moderator_login", null) != null: + result.moderator_login = d["moderator_login"] + if d.get("moderator_name", null) != null: + result.moderator_name = d["moderator_name"] + if d.get("last_activated_at", null) != null: + result.last_activated_at = d["last_activated_at"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_update_shield_mode_status.gd.uid b/addons/twitcher/generated/twitch_update_shield_mode_status.gd.uid new file mode 100644 index 0000000..7804ee4 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_shield_mode_status.gd.uid @@ -0,0 +1 @@ +uid://b77rn5bibl3pg diff --git a/addons/twitcher/generated/twitch_update_user.gd b/addons/twitcher/generated/twitch_update_user.gd new file mode 100644 index 0000000..42137f9 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_user.gd @@ -0,0 +1,63 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchUpdateUser + + + +## +## #/components/schemas/UpdateUserResponse +class Response extends TwitchData: + + ## A list contains the single user that you updated. + @export var data: Array[TwitchUser]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[TwitchUser]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(TwitchUser.from_json(value)) + return result + + + +## All optional parameters for TwitchAPI.update_user +## #/components/schemas/UpdateUserOpt +class Opt extends TwitchData: + + ## The string to update the channel’s description to. The description is limited to a maximum of 300 characters. + ## + ## To remove the description, specify this parameter but don’t set it’s value (for example, `?description=`). + @export var description: String: + set(val): + description = val + track_data(&"description", val) + + + + ## Constructor with all required fields. + static func create() -> Opt: + var opt: Opt = Opt.new() + return opt + + + static func from_json(d: Dictionary) -> Opt: + var result: Opt = Opt.new() + if d.get("description", null) != null: + result.description = d["description"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_update_user.gd.uid b/addons/twitcher/generated/twitch_update_user.gd.uid new file mode 100644 index 0000000..d4868f4 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_user.gd.uid @@ -0,0 +1 @@ +uid://d2rgoccbwdvs2 diff --git a/addons/twitcher/generated/twitch_update_user_extensions.gd b/addons/twitcher/generated/twitch_update_user_extensions.gd new file mode 100644 index 0000000..6504b29 --- /dev/null +++ b/addons/twitcher/generated/twitch_update_user_extensions.gd @@ -0,0 +1,156 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchUpdateUserExtensions + + + +## +## #/components/schemas/UpdateUserExtensionsBody +class Body extends TwitchData: + + ## The extensions to update. The `data` field is a dictionary of extension types. The dictionary’s possible keys are: panel, overlay, or component. The key’s value is a dictionary of extensions. + ## + ## For the extension’s dictionary, the key is a sequential number beginning with 1\. For panel and overlay extensions, the key’s value is an object that contains the following fields: `active` (true/false), `id` (the extension’s ID), and `version` (the extension’s version). + ## + ## For component extensions, the key’s value includes the above fields plus the `x` and `y` fields, which identify the coordinate where the extension is placed. + @export var data: BodyData: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: BodyData) -> Body: + var body: Body = Body.new() + body.data = _data + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("data", null) != null: + result.data = BodyData.from_json(d["data"]) + return result + + + +## The extensions to update. The `data` field is a dictionary of extension types. The dictionary’s possible keys are: panel, overlay, or component. The key’s value is a dictionary of extensions. +## +## For the extension’s dictionary, the key is a sequential number beginning with 1\. For panel and overlay extensions, the key’s value is an object that contains the following fields: `active` (true/false), `id` (the extension’s ID), and `version` (the extension’s version). +## +## For component extensions, the key’s value includes the above fields plus the `x` and `y` fields, which identify the coordinate where the extension is placed. +## #/components/schemas/UpdateUserExtensionsBody/Data +class BodyData extends TwitchData: + + ## + @export var panel: Dictionary: + set(val): + panel = val + track_data(&"panel", val) + + ## + @export var overlay: Dictionary: + set(val): + overlay = val + track_data(&"overlay", val) + + ## + @export var component: Dictionary: + set(val): + component = val + track_data(&"component", val) + + + + ## Constructor with all required fields. + static func create() -> BodyData: + var body_data: BodyData = BodyData.new() + return body_data + + + static func from_json(d: Dictionary) -> BodyData: + var result: BodyData = BodyData.new() + if d.get("panel", null) != null: + result.panel = d["panel"] + if d.get("overlay", null) != null: + result.overlay = d["overlay"] + if d.get("component", null) != null: + result.component = d["component"] + return result + + + +## +## #/components/schemas/UpdateUserExtensionsResponse +class Response extends TwitchData: + + ## The extensions that the broadcaster updated. + @export var data: ResponseData: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: ResponseData) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + result.data = ResponseData.from_json(d["data"]) + return result + + + +## The extensions that the broadcaster updated. +## #/components/schemas/UpdateUserExtensionsResponse/Data +class ResponseData extends TwitchData: + + ## A dictionary that contains the data for a panel extension. The dictionary’s key is a sequential number beginning with 1\. The following fields contain the panel’s data for each key. + @export var panel: Dictionary: + set(val): + panel = val + track_data(&"panel", val) + + ## A dictionary that contains the data for a video-overlay extension. The dictionary’s key is a sequential number beginning with 1\. The following fields contain the overlay’s data for each key. + @export var overlay: Dictionary: + set(val): + overlay = val + track_data(&"overlay", val) + + ## A dictionary that contains the data for a video-component extension. The dictionary’s key is a sequential number beginning with 1\. The following fields contain the component’s data for each key. + @export var component: Dictionary: + set(val): + component = val + track_data(&"component", val) + + + + ## Constructor with all required fields. + static func create(_panel: Dictionary, _overlay: Dictionary, _component: Dictionary) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.panel = _panel + response_data.overlay = _overlay + response_data.component = _component + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("panel", null) != null: + result.panel = d["panel"] + if d.get("overlay", null) != null: + result.overlay = d["overlay"] + if d.get("component", null) != null: + result.component = d["component"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_update_user_extensions.gd.uid b/addons/twitcher/generated/twitch_update_user_extensions.gd.uid new file mode 100644 index 0000000..3c6258d --- /dev/null +++ b/addons/twitcher/generated/twitch_update_user_extensions.gd.uid @@ -0,0 +1 @@ +uid://bgfvvk40bo5yt diff --git a/addons/twitcher/generated/twitch_user.gd b/addons/twitcher/generated/twitch_user.gd new file mode 100644 index 0000000..24706fd --- /dev/null +++ b/addons/twitcher/generated/twitch_user.gd @@ -0,0 +1,131 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/User +class_name TwitchUser + +## An ID that identifies the user. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The user's login name. +@export var login: String: + set(val): + login = val + track_data(&"login", val) + +## The user's display name. +@export var display_name: String: + set(val): + display_name = val + track_data(&"display_name", val) + +## The type of user. Possible values are: +## +## * admin — Twitch administrator +## * global\_mod +## * staff — Twitch staff +## * "" — Normal user +@export var type: String: + set(val): + type = val + track_data(&"type", val) + +## The type of broadcaster. Possible values are: +## +## * affiliate — An [affiliate broadcaster](https://help.twitch.tv/s/article/joining-the-affiliate-program) +## * partner — A [partner broadcaster](https://help.twitch.tv/s/article/partner-program-overview) +## * "" — A normal broadcaster +@export var broadcaster_type: String: + set(val): + broadcaster_type = val + track_data(&"broadcaster_type", val) + +## The user's description of their channel. +@export var description: String: + set(val): + description = val + track_data(&"description", val) + +## A URL to the user's profile image. +@export var profile_image_url: String: + set(val): + profile_image_url = val + track_data(&"profile_image_url", val) + +## A URL to the user's offline image. +@export var offline_image_url: String: + set(val): + offline_image_url = val + track_data(&"offline_image_url", val) + +## The number of times the user's channel has been viewed. +## +## **NOTE**: This field has been deprecated (see [Get Users API endpoint – "view\_count" deprecation](https://discuss.dev.twitch.tv/t/get-users-api-endpoint-view-count-deprecation/37777)). Any data in this field is not valid and should not be used. +@export var view_count: int: + set(val): + view_count = val + track_data(&"view_count", val) + +## The user's verified email address. The object includes this field only if the user access token includes the **user:read:email** scope. +## +## If the request contains more than one user, only the user associated with the access token that provided consent will include an email address — the email address for all other users will be empty. +@export var email: String: + set(val): + email = val + track_data(&"email", val) + +## The UTC date and time that the user's account was created. The timestamp is in RFC3339 format. +@export var created_at: String: + set(val): + created_at = val + track_data(&"created_at", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _login: String, _display_name: String, _type: String, _broadcaster_type: String, _description: String, _profile_image_url: String, _offline_image_url: String, _view_count: int, _created_at: String) -> TwitchUser: + var twitch_user: TwitchUser = TwitchUser.new() + twitch_user.id = _id + twitch_user.login = _login + twitch_user.display_name = _display_name + twitch_user.type = _type + twitch_user.broadcaster_type = _broadcaster_type + twitch_user.description = _description + twitch_user.profile_image_url = _profile_image_url + twitch_user.offline_image_url = _offline_image_url + twitch_user.view_count = _view_count + twitch_user.created_at = _created_at + return twitch_user + + +static func from_json(d: Dictionary) -> TwitchUser: + var result: TwitchUser = TwitchUser.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("login", null) != null: + result.login = d["login"] + if d.get("display_name", null) != null: + result.display_name = d["display_name"] + if d.get("type", null) != null: + result.type = d["type"] + if d.get("broadcaster_type", null) != null: + result.broadcaster_type = d["broadcaster_type"] + if d.get("description", null) != null: + result.description = d["description"] + if d.get("profile_image_url", null) != null: + result.profile_image_url = d["profile_image_url"] + if d.get("offline_image_url", null) != null: + result.offline_image_url = d["offline_image_url"] + if d.get("view_count", null) != null: + result.view_count = d["view_count"] + if d.get("email", null) != null: + result.email = d["email"] + if d.get("created_at", null) != null: + result.created_at = d["created_at"] + return result diff --git a/addons/twitcher/generated/twitch_user.gd.uid b/addons/twitcher/generated/twitch_user.gd.uid new file mode 100644 index 0000000..3791ea2 --- /dev/null +++ b/addons/twitcher/generated/twitch_user.gd.uid @@ -0,0 +1 @@ +uid://cnmohrdxqihr0 diff --git a/addons/twitcher/generated/twitch_user_block_list.gd b/addons/twitcher/generated/twitch_user_block_list.gd new file mode 100644 index 0000000..52c819d --- /dev/null +++ b/addons/twitcher/generated/twitch_user_block_list.gd @@ -0,0 +1,47 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/UserBlockList +class_name TwitchUserBlockList + +## An ID that identifies the blocked user. +@export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + +## The blocked user’s login name. +@export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) + +## The blocked user’s display name. +@export var display_name: String: + set(val): + display_name = val + track_data(&"display_name", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_user_id: String, _user_login: String, _display_name: String) -> TwitchUserBlockList: + var twitch_user_block_list: TwitchUserBlockList = TwitchUserBlockList.new() + twitch_user_block_list.user_id = _user_id + twitch_user_block_list.user_login = _user_login + twitch_user_block_list.display_name = _display_name + return twitch_user_block_list + + +static func from_json(d: Dictionary) -> TwitchUserBlockList: + var result: TwitchUserBlockList = TwitchUserBlockList.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + if d.get("display_name", null) != null: + result.display_name = d["display_name"] + return result diff --git a/addons/twitcher/generated/twitch_user_block_list.gd.uid b/addons/twitcher/generated/twitch_user_block_list.gd.uid new file mode 100644 index 0000000..1d8db9e --- /dev/null +++ b/addons/twitcher/generated/twitch_user_block_list.gd.uid @@ -0,0 +1 @@ +uid://clxcu2w6xi4uo diff --git a/addons/twitcher/generated/twitch_user_chat_color.gd b/addons/twitcher/generated/twitch_user_chat_color.gd new file mode 100644 index 0000000..d2d0b6c --- /dev/null +++ b/addons/twitcher/generated/twitch_user_chat_color.gd @@ -0,0 +1,56 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/UserChatColor +class_name TwitchUserChatColor + +## An ID that uniquely identifies the user. +@export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + +## The user’s login name. +@export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) + +## The user’s display name. +@export var user_name: String: + set(val): + user_name = val + track_data(&"user_name", val) + +## The Hex color code that the user uses in chat for their name. If the user hasn’t specified a color in their settings, the string is empty. +@export var color: String: + set(val): + color = val + track_data(&"color", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_user_id: String, _user_login: String, _user_name: String, _color: String) -> TwitchUserChatColor: + var twitch_user_chat_color: TwitchUserChatColor = TwitchUserChatColor.new() + twitch_user_chat_color.user_id = _user_id + twitch_user_chat_color.user_login = _user_login + twitch_user_chat_color.user_name = _user_name + twitch_user_chat_color.color = _color + return twitch_user_chat_color + + +static func from_json(d: Dictionary) -> TwitchUserChatColor: + var result: TwitchUserChatColor = TwitchUserChatColor.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + if d.get("user_name", null) != null: + result.user_name = d["user_name"] + if d.get("color", null) != null: + result.color = d["color"] + return result diff --git a/addons/twitcher/generated/twitch_user_chat_color.gd.uid b/addons/twitcher/generated/twitch_user_chat_color.gd.uid new file mode 100644 index 0000000..8834628 --- /dev/null +++ b/addons/twitcher/generated/twitch_user_chat_color.gd.uid @@ -0,0 +1 @@ +uid://ct4qim6dtv5d0 diff --git a/addons/twitcher/generated/twitch_user_extension.gd b/addons/twitcher/generated/twitch_user_extension.gd new file mode 100644 index 0000000..e3e7362 --- /dev/null +++ b/addons/twitcher/generated/twitch_user_extension.gd @@ -0,0 +1,71 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/UserExtension +class_name TwitchUserExtension + +## An ID that identifies the extension. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The extension's version. +@export var version: String: + set(val): + version = val + track_data(&"version", val) + +## The extension's name. +@export var name: String: + set(val): + name = val + track_data(&"name", val) + +## A Boolean value that determines whether the extension is configured and can be activated. Is **true** if the extension is configured and can be activated. +@export var can_activate: bool: + set(val): + can_activate = val + track_data(&"can_activate", val) + +## The extension types that you can activate for this extension. Possible values are: +## +## * component +## * mobile +## * overlay +## * panel +@export var type: Array[String]: + set(val): + type = val + track_data(&"type", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _version: String, _name: String, _can_activate: bool, _type: Array[String]) -> TwitchUserExtension: + var twitch_user_extension: TwitchUserExtension = TwitchUserExtension.new() + twitch_user_extension.id = _id + twitch_user_extension.version = _version + twitch_user_extension.name = _name + twitch_user_extension.can_activate = _can_activate + twitch_user_extension.type = _type + return twitch_user_extension + + +static func from_json(d: Dictionary) -> TwitchUserExtension: + var result: TwitchUserExtension = TwitchUserExtension.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("version", null) != null: + result.version = d["version"] + if d.get("name", null) != null: + result.name = d["name"] + if d.get("can_activate", null) != null: + result.can_activate = d["can_activate"] + if d.get("type", null) != null: + for value in d["type"]: + result.type.append(value) + return result diff --git a/addons/twitcher/generated/twitch_user_extension.gd.uid b/addons/twitcher/generated/twitch_user_extension.gd.uid new file mode 100644 index 0000000..93e065f --- /dev/null +++ b/addons/twitcher/generated/twitch_user_extension.gd.uid @@ -0,0 +1 @@ +uid://ct2bdq3yyj1lx diff --git a/addons/twitcher/generated/twitch_user_extension_component.gd b/addons/twitcher/generated/twitch_user_extension_component.gd new file mode 100644 index 0000000..3b48eea --- /dev/null +++ b/addons/twitcher/generated/twitch_user_extension_component.gd @@ -0,0 +1,69 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/UserExtensionComponent +class_name TwitchUserExtensionComponent + +## A Boolean value that determines the extension’s activation state. If **false**, the user has not configured a component extension. +@export var active: bool: + set(val): + active = val + track_data(&"active", val) + +## An ID that identifies the extension. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The extension’s version. +@export var version: String: + set(val): + version = val + track_data(&"version", val) + +## The extension’s name. +@export var name: String: + set(val): + name = val + track_data(&"name", val) + +## The x-coordinate where the extension is placed. +@export var x: int: + set(val): + x = val + track_data(&"x", val) + +## The y-coordinate where the extension is placed. +@export var y: int: + set(val): + y = val + track_data(&"y", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_active: bool) -> TwitchUserExtensionComponent: + var twitch_user_extension_component: TwitchUserExtensionComponent = TwitchUserExtensionComponent.new() + twitch_user_extension_component.active = _active + return twitch_user_extension_component + + +static func from_json(d: Dictionary) -> TwitchUserExtensionComponent: + var result: TwitchUserExtensionComponent = TwitchUserExtensionComponent.new() + if d.get("active", null) != null: + result.active = d["active"] + if d.get("id", null) != null: + result.id = d["id"] + if d.get("version", null) != null: + result.version = d["version"] + if d.get("name", null) != null: + result.name = d["name"] + if d.get("x", null) != null: + result.x = d["x"] + if d.get("y", null) != null: + result.y = d["y"] + return result diff --git a/addons/twitcher/generated/twitch_user_extension_component.gd.uid b/addons/twitcher/generated/twitch_user_extension_component.gd.uid new file mode 100644 index 0000000..35d5bd3 --- /dev/null +++ b/addons/twitcher/generated/twitch_user_extension_component.gd.uid @@ -0,0 +1 @@ +uid://cddfggl11jud5 diff --git a/addons/twitcher/generated/twitch_user_extension_component_update.gd b/addons/twitcher/generated/twitch_user_extension_component_update.gd new file mode 100644 index 0000000..8b40d41 --- /dev/null +++ b/addons/twitcher/generated/twitch_user_extension_component_update.gd @@ -0,0 +1,61 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/UserExtensionComponentUpdate +class_name TwitchUserExtensionComponentUpdate + +## A Boolean value that determines the extension’s activation state. If **false**, the user has not configured a component extension. +@export var active: bool: + set(val): + active = val + track_data(&"active", val) + +## An ID that identifies the extension. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The extension’s version. +@export var version: String: + set(val): + version = val + track_data(&"version", val) + +## The x-coordinate where the extension is placed. +@export var x: int: + set(val): + x = val + track_data(&"x", val) + +## The y-coordinate where the extension is placed. +@export var y: int: + set(val): + y = val + track_data(&"y", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_active: bool) -> TwitchUserExtensionComponentUpdate: + var twitch_user_extension_component_update: TwitchUserExtensionComponentUpdate = TwitchUserExtensionComponentUpdate.new() + twitch_user_extension_component_update.active = _active + return twitch_user_extension_component_update + + +static func from_json(d: Dictionary) -> TwitchUserExtensionComponentUpdate: + var result: TwitchUserExtensionComponentUpdate = TwitchUserExtensionComponentUpdate.new() + if d.get("active", null) != null: + result.active = d["active"] + if d.get("id", null) != null: + result.id = d["id"] + if d.get("version", null) != null: + result.version = d["version"] + if d.get("x", null) != null: + result.x = d["x"] + if d.get("y", null) != null: + result.y = d["y"] + return result diff --git a/addons/twitcher/generated/twitch_user_extension_component_update.gd.uid b/addons/twitcher/generated/twitch_user_extension_component_update.gd.uid new file mode 100644 index 0000000..de1c758 --- /dev/null +++ b/addons/twitcher/generated/twitch_user_extension_component_update.gd.uid @@ -0,0 +1 @@ +uid://yxljiyhoaroy diff --git a/addons/twitcher/generated/twitch_user_extension_overlay.gd b/addons/twitcher/generated/twitch_user_extension_overlay.gd new file mode 100644 index 0000000..ad2d440 --- /dev/null +++ b/addons/twitcher/generated/twitch_user_extension_overlay.gd @@ -0,0 +1,53 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/UserExtensionOverlay +class_name TwitchUserExtensionOverlay + +## A Boolean value that determines the extension’s activation state. If **false**, the user has not configured an overlay extension. +@export var active: bool: + set(val): + active = val + track_data(&"active", val) + +## An ID that identifies the extension. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The extension’s version. +@export var version: String: + set(val): + version = val + track_data(&"version", val) + +## The extension’s name. +@export var name: String: + set(val): + name = val + track_data(&"name", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_active: bool) -> TwitchUserExtensionOverlay: + var twitch_user_extension_overlay: TwitchUserExtensionOverlay = TwitchUserExtensionOverlay.new() + twitch_user_extension_overlay.active = _active + return twitch_user_extension_overlay + + +static func from_json(d: Dictionary) -> TwitchUserExtensionOverlay: + var result: TwitchUserExtensionOverlay = TwitchUserExtensionOverlay.new() + if d.get("active", null) != null: + result.active = d["active"] + if d.get("id", null) != null: + result.id = d["id"] + if d.get("version", null) != null: + result.version = d["version"] + if d.get("name", null) != null: + result.name = d["name"] + return result diff --git a/addons/twitcher/generated/twitch_user_extension_overlay.gd.uid b/addons/twitcher/generated/twitch_user_extension_overlay.gd.uid new file mode 100644 index 0000000..b3fa869 --- /dev/null +++ b/addons/twitcher/generated/twitch_user_extension_overlay.gd.uid @@ -0,0 +1 @@ +uid://bhn0il1dfql11 diff --git a/addons/twitcher/generated/twitch_user_extension_overlay_update.gd b/addons/twitcher/generated/twitch_user_extension_overlay_update.gd new file mode 100644 index 0000000..9ebc8e4 --- /dev/null +++ b/addons/twitcher/generated/twitch_user_extension_overlay_update.gd @@ -0,0 +1,45 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/UserExtensionOverlayUpdate +class_name TwitchUserExtensionOverlayUpdate + +## A Boolean value that determines the extension’s activation state. If **false**, the user has not configured an overlay extension. +@export var active: bool: + set(val): + active = val + track_data(&"active", val) + +## An ID that identifies the extension. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The extension’s version. +@export var version: String: + set(val): + version = val + track_data(&"version", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_active: bool) -> TwitchUserExtensionOverlayUpdate: + var twitch_user_extension_overlay_update: TwitchUserExtensionOverlayUpdate = TwitchUserExtensionOverlayUpdate.new() + twitch_user_extension_overlay_update.active = _active + return twitch_user_extension_overlay_update + + +static func from_json(d: Dictionary) -> TwitchUserExtensionOverlayUpdate: + var result: TwitchUserExtensionOverlayUpdate = TwitchUserExtensionOverlayUpdate.new() + if d.get("active", null) != null: + result.active = d["active"] + if d.get("id", null) != null: + result.id = d["id"] + if d.get("version", null) != null: + result.version = d["version"] + return result diff --git a/addons/twitcher/generated/twitch_user_extension_overlay_update.gd.uid b/addons/twitcher/generated/twitch_user_extension_overlay_update.gd.uid new file mode 100644 index 0000000..d176419 --- /dev/null +++ b/addons/twitcher/generated/twitch_user_extension_overlay_update.gd.uid @@ -0,0 +1 @@ +uid://ctorwljjiqhuv diff --git a/addons/twitcher/generated/twitch_user_extension_panel.gd b/addons/twitcher/generated/twitch_user_extension_panel.gd new file mode 100644 index 0000000..efc93e6 --- /dev/null +++ b/addons/twitcher/generated/twitch_user_extension_panel.gd @@ -0,0 +1,53 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/UserExtensionPanel +class_name TwitchUserExtensionPanel + +## A Boolean value that determines the extension’s activation state. If **false**, the user has not configured a panel extension. +@export var active: bool: + set(val): + active = val + track_data(&"active", val) + +## An ID that identifies the extension. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The extension’s version. +@export var version: String: + set(val): + version = val + track_data(&"version", val) + +## The extension’s name. +@export var name: String: + set(val): + name = val + track_data(&"name", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_active: bool) -> TwitchUserExtensionPanel: + var twitch_user_extension_panel: TwitchUserExtensionPanel = TwitchUserExtensionPanel.new() + twitch_user_extension_panel.active = _active + return twitch_user_extension_panel + + +static func from_json(d: Dictionary) -> TwitchUserExtensionPanel: + var result: TwitchUserExtensionPanel = TwitchUserExtensionPanel.new() + if d.get("active", null) != null: + result.active = d["active"] + if d.get("id", null) != null: + result.id = d["id"] + if d.get("version", null) != null: + result.version = d["version"] + if d.get("name", null) != null: + result.name = d["name"] + return result diff --git a/addons/twitcher/generated/twitch_user_extension_panel.gd.uid b/addons/twitcher/generated/twitch_user_extension_panel.gd.uid new file mode 100644 index 0000000..7141577 --- /dev/null +++ b/addons/twitcher/generated/twitch_user_extension_panel.gd.uid @@ -0,0 +1 @@ +uid://dh7nkkluvupgv diff --git a/addons/twitcher/generated/twitch_user_extension_panel_update.gd b/addons/twitcher/generated/twitch_user_extension_panel_update.gd new file mode 100644 index 0000000..e66834c --- /dev/null +++ b/addons/twitcher/generated/twitch_user_extension_panel_update.gd @@ -0,0 +1,45 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/UserExtensionPanelUpdate +class_name TwitchUserExtensionPanelUpdate + +## A Boolean value that determines the extension’s activation state. If **false**, the user has not configured a panel extension. +@export var active: bool: + set(val): + active = val + track_data(&"active", val) + +## An ID that identifies the extension. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The extension’s version. +@export var version: String: + set(val): + version = val + track_data(&"version", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_active: bool) -> TwitchUserExtensionPanelUpdate: + var twitch_user_extension_panel_update: TwitchUserExtensionPanelUpdate = TwitchUserExtensionPanelUpdate.new() + twitch_user_extension_panel_update.active = _active + return twitch_user_extension_panel_update + + +static func from_json(d: Dictionary) -> TwitchUserExtensionPanelUpdate: + var result: TwitchUserExtensionPanelUpdate = TwitchUserExtensionPanelUpdate.new() + if d.get("active", null) != null: + result.active = d["active"] + if d.get("id", null) != null: + result.id = d["id"] + if d.get("version", null) != null: + result.version = d["version"] + return result diff --git a/addons/twitcher/generated/twitch_user_extension_panel_update.gd.uid b/addons/twitcher/generated/twitch_user_extension_panel_update.gd.uid new file mode 100644 index 0000000..85c0920 --- /dev/null +++ b/addons/twitcher/generated/twitch_user_extension_panel_update.gd.uid @@ -0,0 +1 @@ +uid://0nwbos23q70c diff --git a/addons/twitcher/generated/twitch_user_moderator.gd b/addons/twitcher/generated/twitch_user_moderator.gd new file mode 100644 index 0000000..f1e8f99 --- /dev/null +++ b/addons/twitcher/generated/twitch_user_moderator.gd @@ -0,0 +1,47 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/UserModerator +class_name TwitchUserModerator + +## The ID of the user that has permission to moderate the broadcaster’s channel. +@export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + +## The user’s login name. +@export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) + +## The user’s display name. +@export var user_name: String: + set(val): + user_name = val + track_data(&"user_name", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_user_id: String, _user_login: String, _user_name: String) -> TwitchUserModerator: + var twitch_user_moderator: TwitchUserModerator = TwitchUserModerator.new() + twitch_user_moderator.user_id = _user_id + twitch_user_moderator.user_login = _user_login + twitch_user_moderator.user_name = _user_name + return twitch_user_moderator + + +static func from_json(d: Dictionary) -> TwitchUserModerator: + var result: TwitchUserModerator = TwitchUserModerator.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + if d.get("user_name", null) != null: + result.user_name = d["user_name"] + return result diff --git a/addons/twitcher/generated/twitch_user_moderator.gd.uid b/addons/twitcher/generated/twitch_user_moderator.gd.uid new file mode 100644 index 0000000..099e79e --- /dev/null +++ b/addons/twitcher/generated/twitch_user_moderator.gd.uid @@ -0,0 +1 @@ +uid://d3hk3jq527llk diff --git a/addons/twitcher/generated/twitch_user_subscription.gd b/addons/twitcher/generated/twitch_user_subscription.gd new file mode 100644 index 0000000..9e82231 --- /dev/null +++ b/addons/twitcher/generated/twitch_user_subscription.gd @@ -0,0 +1,93 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/UserSubscription +class_name TwitchUserSubscription + +## An ID that identifies the broadcaster. +@export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + +## The broadcaster’s login name. +@export var broadcaster_login: String: + set(val): + broadcaster_login = val + track_data(&"broadcaster_login", val) + +## The broadcaster’s display name. +@export var broadcaster_name: String: + set(val): + broadcaster_name = val + track_data(&"broadcaster_name", val) + +## The ID of the user that gifted the subscription. The object includes this field only if `is_gift` is **true**. +@export var gifter_id: String: + set(val): + gifter_id = val + track_data(&"gifter_id", val) + +## The gifter’s login name. The object includes this field only if `is_gift` is **true**. +@export var gifter_login: String: + set(val): + gifter_login = val + track_data(&"gifter_login", val) + +## The gifter’s display name. The object includes this field only if `is_gift` is **true**. +@export var gifter_name: String: + set(val): + gifter_name = val + track_data(&"gifter_name", val) + +## A Boolean value that determines whether the subscription is a gift subscription. Is **true** if the subscription was gifted. +@export var is_gift: bool: + set(val): + is_gift = val + track_data(&"is_gift", val) + +## The type of subscription. Possible values are: +## +## * 1000 — Tier 1 +## * 2000 — Tier 2 +## * 3000 — Tier 3 +@export var tier: String: + set(val): + tier = val + track_data(&"tier", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_broadcaster_id: String, _broadcaster_login: String, _broadcaster_name: String, _is_gift: bool, _tier: String) -> TwitchUserSubscription: + var twitch_user_subscription: TwitchUserSubscription = TwitchUserSubscription.new() + twitch_user_subscription.broadcaster_id = _broadcaster_id + twitch_user_subscription.broadcaster_login = _broadcaster_login + twitch_user_subscription.broadcaster_name = _broadcaster_name + twitch_user_subscription.is_gift = _is_gift + twitch_user_subscription.tier = _tier + return twitch_user_subscription + + +static func from_json(d: Dictionary) -> TwitchUserSubscription: + var result: TwitchUserSubscription = TwitchUserSubscription.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("broadcaster_login", null) != null: + result.broadcaster_login = d["broadcaster_login"] + if d.get("broadcaster_name", null) != null: + result.broadcaster_name = d["broadcaster_name"] + if d.get("gifter_id", null) != null: + result.gifter_id = d["gifter_id"] + if d.get("gifter_login", null) != null: + result.gifter_login = d["gifter_login"] + if d.get("gifter_name", null) != null: + result.gifter_name = d["gifter_name"] + if d.get("is_gift", null) != null: + result.is_gift = d["is_gift"] + if d.get("tier", null) != null: + result.tier = d["tier"] + return result diff --git a/addons/twitcher/generated/twitch_user_subscription.gd.uid b/addons/twitcher/generated/twitch_user_subscription.gd.uid new file mode 100644 index 0000000..2044a40 --- /dev/null +++ b/addons/twitcher/generated/twitch_user_subscription.gd.uid @@ -0,0 +1 @@ +uid://ddpepdw7sx838 diff --git a/addons/twitcher/generated/twitch_user_vip.gd b/addons/twitcher/generated/twitch_user_vip.gd new file mode 100644 index 0000000..b210449 --- /dev/null +++ b/addons/twitcher/generated/twitch_user_vip.gd @@ -0,0 +1,47 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/UserVip +class_name TwitchUserVip + +## An ID that uniquely identifies the VIP user. +@export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + +## The user’s display name. +@export var user_name: String: + set(val): + user_name = val + track_data(&"user_name", val) + +## The user’s login name. +@export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_user_id: String, _user_name: String, _user_login: String) -> TwitchUserVip: + var twitch_user_vip: TwitchUserVip = TwitchUserVip.new() + twitch_user_vip.user_id = _user_id + twitch_user_vip.user_name = _user_name + twitch_user_vip.user_login = _user_login + return twitch_user_vip + + +static func from_json(d: Dictionary) -> TwitchUserVip: + var result: TwitchUserVip = TwitchUserVip.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_name", null) != null: + result.user_name = d["user_name"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + return result diff --git a/addons/twitcher/generated/twitch_user_vip.gd.uid b/addons/twitcher/generated/twitch_user_vip.gd.uid new file mode 100644 index 0000000..969014c --- /dev/null +++ b/addons/twitcher/generated/twitch_user_vip.gd.uid @@ -0,0 +1 @@ +uid://ej4brk0redqo diff --git a/addons/twitcher/generated/twitch_video.gd b/addons/twitcher/generated/twitch_video.gd new file mode 100644 index 0000000..6dac932 --- /dev/null +++ b/addons/twitcher/generated/twitch_video.gd @@ -0,0 +1,215 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +## +## #/components/schemas/Video +class_name TwitchVideo + +## An ID that identifies the video. +@export var id: String: + set(val): + id = val + track_data(&"id", val) + +## The ID of the stream that the video originated from if the video's type is "archive;" otherwise, **null**. +@export var stream_id: String: + set(val): + stream_id = val + track_data(&"stream_id", val) + +## The ID of the broadcaster that owns the video. +@export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + +## The broadcaster's login name. +@export var user_login: String: + set(val): + user_login = val + track_data(&"user_login", val) + +## The broadcaster's display name. +@export var user_name: String: + set(val): + user_name = val + track_data(&"user_name", val) + +## The video's title. +@export var title: String: + set(val): + title = val + track_data(&"title", val) + +## The video's description. +@export var description: String: + set(val): + description = val + track_data(&"description", val) + +## The date and time, in UTC, of when the video was created. The timestamp is in RFC3339 format. +@export var created_at: String: + set(val): + created_at = val + track_data(&"created_at", val) + +## The date and time, in UTC, of when the video was published. The timestamp is in RFC3339 format. +@export var published_at: String: + set(val): + published_at = val + track_data(&"published_at", val) + +## The video's URL. +@export var url: String: + set(val): + url = val + track_data(&"url", val) + +## A URL to a thumbnail image of the video. Before using the URL, you must replace the `%{width}` and `%{height}` placeholders with the width and height of the thumbnail you want returned. Due to current limitations, `${width}` must be 320 and `${height}` must be 180. +@export var thumbnail_url: String: + set(val): + thumbnail_url = val + track_data(&"thumbnail_url", val) + +## The video's viewable state. Always set to **public**. +@export var viewable: String: + set(val): + viewable = val + track_data(&"viewable", val) + +## The number of times that users have watched the video. +@export var view_count: int: + set(val): + view_count = val + track_data(&"view_count", val) + +## The ISO 639-1 two-letter language code that the video was broadcast in. For example, the language code is DE if the video was broadcast in German. For a list of supported languages, see [Supported Stream Language](https://help.twitch.tv/s/article/languages-on-twitch#streamlang). The language value is "other" if the video was broadcast in a language not in the list of supported languages. +@export var language: String: + set(val): + language = val + track_data(&"language", val) + +## The video's type. Possible values are: +## +## * archive — An on-demand video (VOD) of one of the broadcaster's past streams. +## * highlight — A highlight reel of one of the broadcaster's past streams. See [Creating Highlights](https://help.twitch.tv/s/article/creating-highlights-and-stream-markers). +## * upload — A video that the broadcaster uploaded to their video library. See Upload under [Video Producer](https://help.twitch.tv/s/article/video-on-demand?language=en%5FUS#videoproducer). +@export var type: String: + set(val): + type = val + track_data(&"type", val) + +## The video's length in ISO 8601 duration format. For example, 3m21s represents 3 minutes, 21 seconds. +@export var duration: String: + set(val): + duration = val + track_data(&"duration", val) + +## The segments that Twitch Audio Recognition muted; otherwise, **null**. +@export var muted_segments: Array[MutedSegments]: + set(val): + muted_segments = val + track_data(&"muted_segments", val) +var response: BufferedHTTPClient.ResponseData + + +## Constructor with all required fields. +static func create(_id: String, _stream_id: String, _user_id: String, _user_login: String, _user_name: String, _title: String, _description: String, _created_at: String, _published_at: String, _url: String, _thumbnail_url: String, _viewable: String, _view_count: int, _language: String, _type: String, _duration: String, _muted_segments: Array[MutedSegments]) -> TwitchVideo: + var twitch_video: TwitchVideo = TwitchVideo.new() + twitch_video.id = _id + twitch_video.stream_id = _stream_id + twitch_video.user_id = _user_id + twitch_video.user_login = _user_login + twitch_video.user_name = _user_name + twitch_video.title = _title + twitch_video.description = _description + twitch_video.created_at = _created_at + twitch_video.published_at = _published_at + twitch_video.url = _url + twitch_video.thumbnail_url = _thumbnail_url + twitch_video.viewable = _viewable + twitch_video.view_count = _view_count + twitch_video.language = _language + twitch_video.type = _type + twitch_video.duration = _duration + twitch_video.muted_segments = _muted_segments + return twitch_video + + +static func from_json(d: Dictionary) -> TwitchVideo: + var result: TwitchVideo = TwitchVideo.new() + if d.get("id", null) != null: + result.id = d["id"] + if d.get("stream_id", null) != null: + result.stream_id = d["stream_id"] + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("user_login", null) != null: + result.user_login = d["user_login"] + if d.get("user_name", null) != null: + result.user_name = d["user_name"] + if d.get("title", null) != null: + result.title = d["title"] + if d.get("description", null) != null: + result.description = d["description"] + if d.get("created_at", null) != null: + result.created_at = d["created_at"] + if d.get("published_at", null) != null: + result.published_at = d["published_at"] + if d.get("url", null) != null: + result.url = d["url"] + if d.get("thumbnail_url", null) != null: + result.thumbnail_url = d["thumbnail_url"] + if d.get("viewable", null) != null: + result.viewable = d["viewable"] + if d.get("view_count", null) != null: + result.view_count = d["view_count"] + if d.get("language", null) != null: + result.language = d["language"] + if d.get("type", null) != null: + result.type = d["type"] + if d.get("duration", null) != null: + result.duration = d["duration"] + if d.get("muted_segments", null) != null: + for value in d["muted_segments"]: + result.muted_segments.append(MutedSegments.from_json(value)) + return result + + + +## The segments that Twitch Audio Recognition muted; otherwise, **null**. +## #/components/schemas/Video/MutedSegments +class MutedSegments extends TwitchData: + + ## The duration of the muted segment, in seconds. + @export var duration: int: + set(val): + duration = val + track_data(&"duration", val) + + ## The offset, in seconds, from the beginning of the video to where the muted segment begins. + @export var offset: int: + set(val): + offset = val + track_data(&"offset", val) + + + + ## Constructor with all required fields. + static func create(_duration: int, _offset: int) -> MutedSegments: + var muted_segments: MutedSegments = MutedSegments.new() + muted_segments.duration = _duration + muted_segments.offset = _offset + return muted_segments + + + static func from_json(d: Dictionary) -> MutedSegments: + var result: MutedSegments = MutedSegments.new() + if d.get("duration", null) != null: + result.duration = d["duration"] + if d.get("offset", null) != null: + result.offset = d["offset"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_video.gd.uid b/addons/twitcher/generated/twitch_video.gd.uid new file mode 100644 index 0000000..aed5772 --- /dev/null +++ b/addons/twitcher/generated/twitch_video.gd.uid @@ -0,0 +1 @@ +uid://bxdf1uui8mwhr diff --git a/addons/twitcher/generated/twitch_warn_chat_user.gd b/addons/twitcher/generated/twitch_warn_chat_user.gd new file mode 100644 index 0000000..036eeee --- /dev/null +++ b/addons/twitcher/generated/twitch_warn_chat_user.gd @@ -0,0 +1,152 @@ +@tool +extends TwitchData + +# CLASS GOT AUTOGENERATED DON'T CHANGE MANUALLY. CHANGES CAN BE OVERWRITTEN EASILY. + +class_name TwitchWarnChatUser + + + +## +## #/components/schemas/WarnChatUserBody +class Body extends TwitchData: + + ## A list that contains information about the warning. + @export var data: BodyData: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: BodyData) -> Body: + var body: Body = Body.new() + body.data = _data + return body + + + static func from_json(d: Dictionary) -> Body: + var result: Body = Body.new() + if d.get("data", null) != null: + result.data = BodyData.from_json(d["data"]) + return result + + + +## A list that contains information about the warning. +## #/components/schemas/WarnChatUserBody/Data +class BodyData extends TwitchData: + + ## The ID of the twitch user to be warned. + @export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + + ## A custom reason for the warning. **Max 500 chars.** + @export var reason: String: + set(val): + reason = val + track_data(&"reason", val) + + + + ## Constructor with all required fields. + static func create(_user_id: String, _reason: String) -> BodyData: + var body_data: BodyData = BodyData.new() + body_data.user_id = _user_id + body_data.reason = _reason + return body_data + + + static func from_json(d: Dictionary) -> BodyData: + var result: BodyData = BodyData.new() + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("reason", null) != null: + result.reason = d["reason"] + return result + + + +## +## #/components/schemas/WarnChatUserResponse +class Response extends TwitchData: + + ## A list that contains information about the warning. + @export var data: Array[ResponseData]: + set(val): + data = val + track_data(&"data", val) + var response: BufferedHTTPClient.ResponseData + + + ## Constructor with all required fields. + static func create(_data: Array[ResponseData]) -> Response: + var response: Response = Response.new() + response.data = _data + return response + + + static func from_json(d: Dictionary) -> Response: + var result: Response = Response.new() + if d.get("data", null) != null: + for value in d["data"]: + result.data.append(ResponseData.from_json(value)) + return result + + + +## A list that contains information about the warning. +## #/components/schemas/WarnChatUserResponse/Data +class ResponseData extends TwitchData: + + ## The ID of the channel in which the warning will take effect. + @export var broadcaster_id: String: + set(val): + broadcaster_id = val + track_data(&"broadcaster_id", val) + + ## The ID of the warned user. + @export var user_id: String: + set(val): + user_id = val + track_data(&"user_id", val) + + ## The ID of the user who applied the warning. + @export var moderator_id: String: + set(val): + moderator_id = val + track_data(&"moderator_id", val) + + ## The reason provided for warning. + @export var reason: String: + set(val): + reason = val + track_data(&"reason", val) + + + + ## Constructor with all required fields. + static func create(_broadcaster_id: String, _user_id: String, _moderator_id: String, _reason: String) -> ResponseData: + var response_data: ResponseData = ResponseData.new() + response_data.broadcaster_id = _broadcaster_id + response_data.user_id = _user_id + response_data.moderator_id = _moderator_id + response_data.reason = _reason + return response_data + + + static func from_json(d: Dictionary) -> ResponseData: + var result: ResponseData = ResponseData.new() + if d.get("broadcaster_id", null) != null: + result.broadcaster_id = d["broadcaster_id"] + if d.get("user_id", null) != null: + result.user_id = d["user_id"] + if d.get("moderator_id", null) != null: + result.moderator_id = d["moderator_id"] + if d.get("reason", null) != null: + result.reason = d["reason"] + return result + \ No newline at end of file diff --git a/addons/twitcher/generated/twitch_warn_chat_user.gd.uid b/addons/twitcher/generated/twitch_warn_chat_user.gd.uid new file mode 100644 index 0000000..89e8865 --- /dev/null +++ b/addons/twitcher/generated/twitch_warn_chat_user.gd.uid @@ -0,0 +1 @@ +uid://s0ewsss5pv4q diff --git a/addons/twitcher/irc/twitch_irc.gd b/addons/twitcher/irc/twitch_irc.gd new file mode 100644 index 0000000..aa38de0 --- /dev/null +++ b/addons/twitcher/irc/twitch_irc.gd @@ -0,0 +1,461 @@ +@icon("res://addons/twitcher/assets/chat-icon.svg") +@tool +extends Twitcher + +## @deprecated: Twitch plans to remove IRC so use the eventsub solution instead +class_name TwitchIRC + +static var log: TwitchLogger = TwitchLogger.new("TwitchIRC") + +## Sent when the bot or moderator removes all messages from the chat room or removes all messages for the specified user. +signal received_clearchat(channel_name: String, banned_or_timeout_user: String, tags: TwitchTags.ClearChat) +## Sent when the bot removes a single message from the chat room. +signal received_clearmsg(channel_name: String, chat_message_removed: String, tags: TwitchTags.ClearMsg) +## Sent after the bot authenticates with the server. +signal received_global_userstate(tags: TwitchTags.GlobalUserState) +## Sent when a channel starts or stops hosting viewers from another channel. +signal received_host_target(channel_being_hosted: String, hosting_channel: String, number_of_viewers: int) +## Sent to indicate the outcome of an action like banning a user.[br] +## handled = when the Twitcher already handled the message. +signal received_notice(channel_name: String, message: String, tags: TwitchTags.Notice, handled: bool) +## Sent when the Twitch IRC server needs to terminate the connection for maintenance reasons. This gives your bot a chance to perform minimal clean up and save state before the server terminates the connection. The amount of time between receiving the message and the server closing the connection is indeterminate. +signal received_reconnect +## Sent when the bot joins a channel or when the channel’s chat settings change. +signal received_roomstate(channel_name: String, tags: TwitchTags.Roomstate) +## Sent when events like someone subscribing to the channel occurs. [br] +## - A user subscribes to the channel, re-subscribes to the channel, or gifts a subscription to another user.[br] +## - Another broadcaster raids the channel. Raid is a Twitch feature that lets broadcasters send their viewers to another channel to help support and grow other members in the community.[br] +## - A viewer milestone is celebrated such as a new viewer chatting for the first time. +signal received_usernotice(channel_name: String, message: String, tags: TwitchTags.Usernotice) +## Sent when the bot joins a channel or sends a PRIVMSG message. +signal received_userstate(channel_name: String, tags: TwitchTags.Userstate) +## Sent when a WHISPER message is directed specifically to your bot. Your bot will never receive whispers sent to other users.[br] +## from_user - The user that’s sending the whisper message.[br] +## to_user - The user that’s receiving the whisper message. +signal received_whisper(from_user: String, to_user: String, message: String, tags: TwitchTags.Whisper) +## The Twitch IRC server sends this message after a user posts a message to the chat room. +signal received_privmsg(channel_name: String, username: String, message: String, tags: TwitchTags.PrivMsg) +## When the token isn't valid anymore +signal unauthenticated +## When the token doesn't have enough permissions to join IRC +signal unauthorized +## Called when the connection got opened and the authorization was done +signal connection_opened +## Called when the connection got closed +signal connection_closed + + +enum JoinState { + NOT_JOINED, JOINING, JOINED +} + +class ChannelData extends RefCounted: + + signal has_joined + + var join_state: JoinState = JoinState.NOT_JOINED + var channel_name: String + var nodes: Array[TwitchIrcChannel] = [] + var user_state: TwitchTags.Userstate + var room_state: TwitchTags.Roomstate: + set(val): + room_state = val + if join_state != JoinState.JOINED && val != null: + join_state = JoinState.JOINED + has_joined.emit() + + func _init(channel: String) -> void: + channel_name = channel + + func leave() -> void: + room_state = null + join_state = JoinState.NOT_JOINED + for node in nodes: node.leave() + + func is_joined() -> void: + if join_state != JoinState.JOINED: await has_joined + + +class ParsedMessage extends RefCounted: + ## Parses all of the messages of IRC + ## Group1: Tags + ## Group2: Server / To User (Whisper) / From User (Chat) + ## Group3: Command + ## Group4: Channel / From User (Whisper) + ## Group5: Message / Payload + var _irc_message_parser_regex = RegEx.create_from_string("(@.*? )?:(.*?)( [A-Z0-9]*)( #?.*?)?( :.*?)?$") + + var tags: String: + get: return tags.trim_prefix("@") + + ## Server / To User (Whisper) / From User (Chat) + var server: String + + var command: String: + get: return command.strip_edges() + + ## Channel / From User (Whisper) + var channel: String: + get: return channel.strip_edges().trim_prefix("#") + + ## Message / Payload + var message: String: + get: return message.strip_edges().trim_prefix(":") + + func _init(msg: String) -> void: + var matches = _irc_message_parser_regex.search(msg) + if matches != null: + tags = matches.get_string(1) + server = matches.get_string(2) + command = matches.get_string(3) + channel = matches.get_string(4) + message = matches.get_string(5) + + +class EmoteLocation extends RefCounted: + var id : Variant + var start : int + var end : int + var sprite_frames: SpriteFrames + + func _init(emote_id: Variant, start_idx: int, end_idx: int): + self.id = emote_id + self.start = start_idx + self.end = end_idx + + static func smaller(a : EmoteLocation, b : EmoteLocation): + return a.start < b.start + + +@export var setting: TwitchIrcSetting = TwitchIrcSetting.new(): + set(val): + setting = val + _client.connection_url = setting.server + update_configuration_warnings() +@export var token: OAuthToken: + set(val): + token = val + update_configuration_warnings() +@export var irc_send_message_delay: int = 360 +## All connected channels of the bot. +## Key: channel_name as StringName | Value: ChannelData +var _channels := {} + +## will automatically reconnect in case of authorization problems +var _auto_reconnect: bool +var _ready_to_send: bool +var _client := WebsocketClient.new() + +## Timestamp when the next message should be sent. +var _next_message := Time.get_ticks_msec() + +## Messages to send with an interval for disconnection protection +## see TwitchIrcSetting.send_message_delay_ms. +var _chat_queue : Array[String] = [] + + +func _init() -> void: + _client.name = "Websocket" + _client.message_received.connect(_data_received) + _client.connection_established.connect(_on_connection_established) + _client.connection_closed.connect(_on_connection_closed) + + +func _ready() -> void: + token.authorized.connect(_on_authorized) + add_child(_client) + + +func _on_authorized() -> void: + log.i("Token got authorized reconnect to irc? Client Closed: %s, Auto Reconnect enabled: %s" % [_client.is_closed, _client.auto_reconnect]) + if _client.is_closed and _auto_reconnect: + open_connection() + + +## Propergated call from TwitchService +func do_setup() -> void: + await open_connection() + log.i("IRC setup") + + +func open_connection() -> void: + _auto_reconnect = true + log.i("Irc open connection") + await _client.open_connection() + + +func close_connection() -> void: + _auto_reconnect = false + _client.close(1000, "intentionally closed") + log.i("Irc closed connection") + + +func _on_connection_established() -> void: + _login() + _reconnect_to_channels() + connection_opened.emit() + + +func _on_connection_closed() -> void: + _ready_to_send = false + connection_closed.emit() + for channel_name: StringName in _channels: + _channels[channel_name].leave() + + +func _process(delta: float) -> void: + if _ready_to_send: _send_messages() + + +## Sends the login message for authorization pupose and sets an username +func _login() -> void: + _client.send_text("PASS oauth:%s" % await token.get_access_token()) + _send("NICK " + setting.username) + _send("CAP REQ :" + " ".join(setting.irc_capabilities)) + + +## Reconnect to all channels the bot was joined before (in case programatically joined channels) +func _reconnect_to_channels(): + for channel_name in _channels: join_channel(channel_name) + + +func _join_channels_on_connect(): + for channel_name: StringName in setting.auto_join_channels: + var channel = join_channel(channel_name) + await channel.is_joined() + log.i("%s joined" % channel_name) + + +## Receives data on the websocket aka new messages +func _data_received(data : PackedByteArray) -> void: + var messages : PackedStringArray = data.get_string_from_utf8().strip_edges(false).split("\r\n") + for message: String in messages: + # Reminder PONG messages is just different cant use match for it... + if message.begins_with("PING"): + _send("PONG :tmi.twitch.tv") + continue + + var parsed_message = ParsedMessage.new(message) + _handle_message(parsed_message) + + +## Tries to send messages as long as the websocket is open +func _send_messages() -> void: + if _chat_queue.is_empty(): + return + + if not _client.is_open: + log.e("Can't send message. Connection not open.") + # Maybe buggy when the websocket got opened but not authorized yet + # Can possible happen when we have a lot of load and a reconnect in the socket + return + + if _next_message <= Time.get_ticks_msec(): + var msg_to_send = _chat_queue.pop_front() + _send(msg_to_send) + _next_message = Time.get_ticks_msec() + irc_send_message_delay + + +## Sends join channel message +func join_channel(channel_name : StringName) -> ChannelData: + var lower_channel = channel_name.to_lower() + if not _channels.has(channel_name): + _channels[channel_name] = ChannelData.new(lower_channel) + + if _channels[channel_name].join_state == JoinState.NOT_JOINED: + _chat_queue.append("JOIN #" + lower_channel) + _channels[channel_name].join_state = JoinState.JOINING + + return _channels[channel_name] + + +## Sends leave channel message +func leave_channel(channel_name : StringName) -> void: + if not _channels.has(channel_name): + log.e("Can't leave %s channel cause we are not joined" % channel_name) + return + + var lower_channel : StringName = channel_name.to_lower() + _chat_queue.append("PART #" + lower_channel) + _channels.erase(lower_channel) + + +## Sends a chat message to a channel. Defaults to the only connected channel. +## Channel should be always without '#'. +func chat(message : String, channel_name : StringName = &""): + var channel_names : Array = _channels.keys() + if channel_name == &"" && channel_names.size() == 1: + channel_name = channel_names[0] + + if channel_name == &"": + log.e("No channel is specified to send %s" % message) + return + + _chat_queue.append("PRIVMSG #%s :%s\r\n" % [channel_name, message]) + + # Call it defered otherwise the response of the bot will be send before the command. + _send_message_to_channel.call_deferred(channel_name, message) + + +## send the message of the bot to the channel for display purpose +func _send_message_to_channel(channel_name: StringName, message: String) -> void: + if _channels.has(channel_name): + var channel = _channels[channel_name] as ChannelData + var username = channel.user_state.display_name + # Convert the tags in a dirty way + var tag = TwitchTags.PrivMsg.new(channel.user_state._raw) + tag.room_id = channel.room_state.room_id + received_privmsg.emit(channel_name, username, message, tag) + + +## Sends a string message to Twitch. +func _send(text : String) -> void: + _client.send_text(text) + log.i("< " + text.strip_edges(false)) + + +## Handles all the messages. Tags can be empty when not requested via capabilities +func _handle_message(parsed_message : ParsedMessage) -> void: + if parsed_message.command != "WHISPER": + log.i("> [%15s] %s: %s" % [parsed_message.command, parsed_message.server, parsed_message.message]) + + match parsed_message.command: + "001": + log.i("Authentication successful.") + _join_channels_on_connect() + _ready_to_send = true + + "CLEARCHAT": + var clear_chat_tags = TwitchTags.ClearChat.new(parsed_message.tags) + var user_to_ban_or_timeout = parsed_message.message + received_clearchat.emit(parsed_message.channel, parsed_message.message, clear_chat_tags) + + "CLEARMSG": + var clear_msg_tags = TwitchTags.ClearMsg.new(parsed_message.tags) + var message_to_remove = parsed_message.message + received_clearmsg.emit(parsed_message.channel, message_to_remove, clear_msg_tags) + + "GLOBALUSERSTATE": + var global_userstate = TwitchTags.GlobalUserState.new(parsed_message.tags) + received_global_userstate.emit(global_userstate) + + "HOSTTARGET": + # Example: [-|] + var host_target_message = parsed_message.message.split(" ") + var channel_being_hosted = host_target_message[0] + var number_of_viewers = int(host_target_message[1]) + var hosting_channel = parsed_message.channel + received_host_target.emit(channel_being_hosted, hosting_channel, number_of_viewers) + + "NOTICE": + var notice_tags = TwitchTags.Notice.new(parsed_message.tags) + var message = parsed_message.message + var handled := false + if not await _handle_cmd_notice(message): + handled = true + received_notice.emit(parsed_message.channel, message, notice_tags, handled) + + "RECONNECT": + received_reconnect.emit() + + "ROOMSTATE": + var roomstate_tags = TwitchTags.Roomstate.new(parsed_message.tags) + var channel_name = parsed_message.channel + received_roomstate.emit(channel_name, roomstate_tags) + + var channel = _channels[channel_name] as ChannelData + channel.room_state = roomstate_tags + + "USERNOTICE": + var user_notice_tags = TwitchTags.Usernotice.new(parsed_message.tags) + received_usernotice.emit(parsed_message.channel, parsed_message.message, user_notice_tags) + + "USERSTATE": + var userstate_tags = TwitchTags.Userstate.new(parsed_message.tags) + var channel_name = parsed_message.channel + received_usernotice.emit(channel_name, userstate_tags) + + var channel = _channels[channel_name] as ChannelData + channel.user_state = userstate_tags + + "WHISPER": + var whisper_tags = TwitchTags.Whisper.new(parsed_message.tags) + # Example: :!@.tmi.twitch.tv + var to_user = parsed_message.server + to_user = to_user.substr(0, to_user.find("!")) + # Special case for whisper + var from_user = parsed_message.channel + received_whisper.emit(from_user, to_user, parsed_message.message, whisper_tags) + + "PRIVMSG": + var privmsg_tags = TwitchTags.PrivMsg.new(parsed_message.tags) + var from_user = parsed_message.server + from_user = from_user.substr(0, from_user.find("!")) + received_privmsg.emit(parsed_message.channel, from_user, parsed_message.message, privmsg_tags) + + +## Handles the update of rooms when joining the channel or a moderator +## updates it (Example :tmi.twitch.tv ROOMSTATE #bar) +func _handle_cmd_state(command: String, channel_name: StringName, tags: Dictionary) -> void: + # right(-1) -> Remove the preceding # of the channel name + channel_name = channel_name.right(-1).to_lower() + if not _channels.has(channel_name): + _channels[channel_name] = _create_channel(channel_name) + + var channel: TwitchIrcChannel = _channels[channel_name] + channel.update_state(command, tags) + #channel_data_updated.emit(channel_name, channel.data) + log.i("Channel updated %s" % channel_name) + + +func _create_channel(channel_name: StringName) -> TwitchIrcChannel: + var channel = TwitchIrcChannel.new() + channel.channel_name = channel_name + _channels[channel_name] = channel + Engine.get_main_loop().root.add_child(channel) + return channel + + +## Tracks the channel. +func add_channel(channel: TwitchIrcChannel): + var channel_name = channel.channel_name + if not _channels.has(channel_name): + join_channel(channel_name) + var nodes = _channels[channel_name].nodes as Array[TwitchIrcChannel] + nodes.append(channel) + + +## Remove the channel from getting tracked within the service +func remove_channel(channel: TwitchIrcChannel): + var channel_name = channel.channel_name + var channel_data = _channels[channel_name] as ChannelData + channel_data.nodes.erase(channel) + if channel_data.nodes.is_empty(): + leave_channel(channel_name) + + +func _handle_cmd_notice(info: String) -> bool: + if info == "Login authentication failed" || info == "Login unsuccessful": + log.e("Authentication failed.") + unauthenticated.emit() + _client.close(1000, "Unauthenticated.") + return true + elif info == "You don't have permission to perform that action": + log.i("No permission. Please check if you have all required scopes (chat:read or chat:write).") + unauthorized.emit() + _client.close(1000, "Token became invalid.") + return true + return false + + +func get_client() -> WebsocketClient: + return _client + + +func _get_configuration_warnings() -> PackedStringArray: + var result: Array[String] = [] + if token == null: + result.append("Token is missing") + if setting == null: + result.append("IRC Settings are missing") + return result diff --git a/addons/twitcher/irc/twitch_irc.gd.uid b/addons/twitcher/irc/twitch_irc.gd.uid new file mode 100644 index 0000000..a0d8c1a --- /dev/null +++ b/addons/twitcher/irc/twitch_irc.gd.uid @@ -0,0 +1 @@ +uid://wkh0l2xsyapj diff --git a/addons/twitcher/irc/twitch_irc_channel.gd b/addons/twitcher/irc/twitch_irc_channel.gd new file mode 100644 index 0000000..3d5ff4b --- /dev/null +++ b/addons/twitcher/irc/twitch_irc_channel.gd @@ -0,0 +1,110 @@ +@icon("res://addons/twitcher/assets/chat-icon.svg") +extends Twitcher + +## Direct access to the chat for one specific channel +## +## Usefull when using multiple channels otherwise TwitchIRC has everything you need +## This one exists only for tracking user join and leave events. +## ## @deprecated: Twitch plans to remove IRC so use the eventsub solution instead +class_name TwitchIrcChannel + +static var _log: TwitchLogger = TwitchLogger.new("TwitchIrcChannel") + +## when a chat message in this channel got received +signal message_received(from_user: String, message: String, tags: TwitchTags.Message) + +## Sent when the bot joins a channel or sends a PRIVMSG message. +signal user_state_received(tags: TwitchTags.Userstate) + +## Sent when the bot joins a channel or when the channel’s chat settings change. +signal room_state_received(tags: TwitchTags.Roomstate) + +## Called when the bot joined the channel or atleast get the channel informations. +signal has_joined() + +## Called when thie bot left the channel. +signal has_left() + +@export var twitch_service: TwitchService +@export var channel_name: StringName: + set = _update_channel_name, + get = _get_channel_name + +var user_state: TwitchTags.Userstate +var room_state: TwitchTags.Roomstate: + set(val): + room_state = val + if !joined && val != null: + joined = true + has_joined.emit() + +var joined: bool +var irc: TwitchIRC + + +func _enter_tree() -> void: + _enter_channel() + + +func _get_channel_name() -> StringName: + return channel_name.to_lower() + + +func _update_channel_name(new_name: StringName) -> void: + if channel_name != "": irc.remove_channel(self) + channel_name = new_name + _enter_channel() + + +func _enter_channel() -> void: + if irc == null: return + if channel_name == &"": + _log.e("No channel is specified to join. The channel name can be set on the TwitchIrcChannel node.") + return + irc.add_channel(self) + + +func _ready() -> void: + irc = twitch_service.irc + irc.received_privmsg.connect(_on_message_received) + irc.received_roomstate.connect(_on_roomstate_received) + irc.received_userstate.connect(_on_userstate_received) + _enter_channel() + + +func _exit_tree() -> void: + irc.remove_channel(self) + + +func _on_message_received(channel: StringName, from_user: String, message: String, tags: TwitchTags.PrivMsg): + if channel_name != channel: return + var message_tag = TwitchTags.Message.from_priv_msg(tags) + await message_tag.load_sprites(twitch_service) + message_received.emit(from_user, message, message_tag) + + +func _on_roomstate_received(channel: StringName, tags: TwitchTags.Roomstate): + if channel != channel_name: return + room_state = tags + room_state_received.emit(room_state) + + +func _on_userstate_received(channel: StringName, tags: TwitchTags.Userstate): + if channel != channel_name: return + user_state = tags + user_state_received.emit(user_state) + + +func chat(message: String) -> void: + await is_joined() + irc.chat(message, channel_name) + + +func is_joined() -> void: + if not joined: await has_joined + + +func leave() -> void: + room_state = null + joined = false + has_left.emit() diff --git a/addons/twitcher/irc/twitch_irc_channel.gd.uid b/addons/twitcher/irc/twitch_irc_channel.gd.uid new file mode 100644 index 0000000..2ca03d4 --- /dev/null +++ b/addons/twitcher/irc/twitch_irc_channel.gd.uid @@ -0,0 +1 @@ +uid://cva5e053boj4u diff --git a/addons/twitcher/irc/twitch_irc_setting.gd b/addons/twitcher/irc/twitch_irc_setting.gd new file mode 100644 index 0000000..09eae0c --- /dev/null +++ b/addons/twitcher/irc/twitch_irc_setting.gd @@ -0,0 +1,38 @@ +extends Resource + +## @deprecated: Twitch plans to remove IRC so use the eventsub solution instead +class_name TwitchIrcSetting + +const CAP_COMMANDS := &"twitch.tv/commands" +const CAP_MEMBERSHIP := &"twitch.tv/membership" +const CAP_TAGS := &"twitch.tv/tags" + + +## The name of the bot within the chat +@export var username := "" + +## Join the channels after connect +@export var auto_join_channels: Array[StringName] = [] + +## Twitch IRC Server URL +@export var server := "wss://irc-ws.chat.twitch.tv:443" + +## Needed because IRC may disconnect on to many message per second +@export var send_message_delay_ms := 320 + +@export_flags(CAP_COMMANDS, CAP_MEMBERSHIP, CAP_TAGS) var capabilities := 0 + +var irc_capabilities: Array[StringName]: + get(): + var result : Array[StringName] = [] + if capabilities & 1 == 1: + result.append(CAP_COMMANDS) + if capabilities & 2 == 2: + result.append(CAP_MEMBERSHIP) + if capabilities & 4 == 4: + result.append(CAP_TAGS) + return result + + +static func get_all_capabillities() -> Array[StringName]: + return [CAP_COMMANDS, CAP_MEMBERSHIP, CAP_TAGS]; diff --git a/addons/twitcher/irc/twitch_irc_setting.gd.uid b/addons/twitcher/irc/twitch_irc_setting.gd.uid new file mode 100644 index 0000000..eccc8d8 --- /dev/null +++ b/addons/twitcher/irc/twitch_irc_setting.gd.uid @@ -0,0 +1 @@ +uid://c8mv0lq0a2l8f diff --git a/addons/twitcher/irc/twitch_tags.gd b/addons/twitcher/irc/twitch_tags.gd new file mode 100644 index 0000000..fc4ab20 --- /dev/null +++ b/addons/twitcher/irc/twitch_tags.gd @@ -0,0 +1,469 @@ +extends RefCounted + +class_name TwitchTags + +## A normal user +const USER_TYPE_NORMA := &"" +## A Twitch administrator +const USER_TYPE_ADMIN := &"admin" +## A global moderator +const USER_TYPE_GLOBAL_MOD := &"global_mod" +## A Twitch employee +const USER_TYPE_STAFF := &"staff" + +const MSG_ID_SUB := &"sub" +const MSG_ID_RESUB := &"resub" +const MSG_ID_SUBGIFT := &"subgift" +const MSG_ID_SUBMYSTERYGIFT := &"submysterygift" +const MSG_ID_GIFTPAIDUPGRADE := &"giftpaidupgrade" +const MSG_ID_REWARDGIFT := &"rewardgift" +const MSG_ID_ANONGIFTPAIDUPGRADE := &"anongiftpaidupgrade" +const MSG_ID_RAID := &"raid" +const MSG_ID_UNRAID := &"unraid" +const MSG_ID_RITUAL := &"ritual" +const MSG_ID_BITSBADGETIER := &"bitsbadgetier" +#region TagWrapper + +class Message extends RefCounted: + var color: String + var _badges: String + var _emotes: String + var room_id: String + var raw: Variant + + var badges: Array[SpriteFrames] + var emotes: Array[TwitchIRC.EmoteLocation] + + + static func from_priv_msg(tag: PrivMsg) -> Message: + var msg = Message.new() + msg.color = tag.color + msg._badges = tag.badges + msg._emotes = tag.emotes + msg.room_id = tag.room_id + msg.raw = tag + return msg + + + func load_sprites(twitch_service: TwitchService) -> void: + badges = await _load_badges(twitch_service) + emotes = await _load_emotes(twitch_service) + pass + + + func _load_badges(twitch_service: TwitchService) -> Array[SpriteFrames]: + var badge_definitions : Array[TwitchBadgeDefinition] = [] + for badge in _badges.split(",", false): + # Maybe Broke?! + var badge_info := badge.split("/") + var badge_definition = TwitchBadgeDefinition.new(badge_info[0], badge_info[1], 1, room_id) + badge_definitions.append(badge_definition) + var result = await twitch_service.media_loader.get_badges(badge_definitions) + var sprite_frames : Array[SpriteFrames] = [] + sprite_frames.assign(result.values()) + return sprite_frames + + + func _load_emotes(twitch_service: TwitchService) -> Array[TwitchIRC.EmoteLocation]: + var locations : Array[TwitchIRC.EmoteLocation] = [] + var emotes_to_load : Array[String] = [] + if _emotes != null && _emotes != "": + for emote in _emotes.split("/", false): + var data : Array = emote.split(":") + for d in data[1].split(","): + var start_end = d.split("-") + locations.append(TwitchIRC.EmoteLocation.new(data[0], int(start_end[0]), int(start_end[1]))) + emotes_to_load.append(data[0]) + locations.sort_custom(Callable(TwitchIRC.EmoteLocation, "smaller")) + + var emotes_definition: Dictionary = await twitch_service.media_loader.get_emotes(emotes_to_load) + for emote_location: TwitchIRC.EmoteLocation in locations: + emote_location.sprite_frames = emotes_definition[emote_location.id] + + return locations + + + + func get_color() -> String: + return color + +#endregion + +#region Lowlevel Tags + +class BaseTags: + var _raw: String + var _unmapped: Dictionary = {} + + + func parse_tags(tag_string: String, output: Object) -> void: + _raw = tag_string + if tag_string.left(1) == "@": + tag_string = tag_string.substr(1) + + var tags = tag_string.split(";") + for tag in tags: + if tag == "": continue + var tag_value = tag.split("=") + var property_name = tag_value[0].replace("-", "_") + if _has_property(output, property_name): + output.set(property_name, tag_value[1]) + elif tag_value.size() == 2: + output._unmapped[property_name] = tag_value[1] + else: + output._unmapped[property_name] = "" + + + func _has_property(obj: Object, property_name: String) -> bool: + var properties = obj.get_property_list() + for property in properties: + if property.name == property_name: + return true + return false + + + func get_unmapped(property: String) -> Variant: + return _unmapped[property] + + + func has_unmapped(property: String) -> bool: + return _unmapped.has(property) + +## Sent when the bot or moderator removes all messages from the chat room or removes all messages for the specified user. [br] +## @ban-duration=;room-id=;target-user-id=;tmi-sent-ts= [br] +## See: https://dev.twitch.tv/docs/irc/tags/#clearchat-tags +class ClearChat extends BaseTags: + ## Optional. The message includes this tag if the user was put in a timeout. The tag contains the duration of the timeout, in seconds. + var ban_duration: String + ## The ID of the channel where the messages were removed from. + var room_id: String + ## Optional. The ID of the user that was banned or put in a timeout. The user was banned if the message doesn’t include the ban-duration tag. + var target_user_id: String + ## The UNIX timestamp. + var tmi_sent_ts: String + + + func _init(tags: String) -> void: + parse_tags(tags, self) + + +## Sent when the bot removes a single message from the chat room. [br] +## @login=;room-id=;target-msg-id=;tmi-sent-ts= [br] +## See: https://dev.twitch.tv/docs/irc/tags/#clearmsg-tags +class ClearMsg extends BaseTags: + ## The name of the user who sent the message. + var login: String + ## Optional. The ID of the channel (chat room) where the message was removed from. + var room_id: String + ## A UUID that identifies the message that was removed. + var target_msg_id: String + ## The UNIX timestamp. + var tmi_sent_ts: String + + + func _init(tags: String) -> void: + parse_tags(tags, self) + + +## Sent when the bot authenticates with the server. [br] +## @badge-info=;badges=;color=;display-name=;emote-sets=;turbo=;user-id=;user-type= [br] +## See https://dev.twitch.tv/docs/irc/tags/#globaluserstate-tags +class GlobalUserState extends BaseTags: + ## Contains metadata related to the chat badges in the badges tag. [br] + ## Currently, this tag contains metadata only for subscriber badges, to indicate the number of months the user has been a subscriber. + var badge_info: String + ## Comma-separated list of chat badges in the form, /. For example, admin/1. There are many possible badge values. + var badges: String + ## The color of the user’s name in the chat room. This is a hexadecimal RGB color code in the form, #. This tag may be empty if it is never set. + var color: String + ## The user’s display name, escaped as described in the IRCv3 spec. This tag may be empty if it is never set. + var display_name: String + ## A comma-delimited list of IDs that identify the emote sets that the user has access to. Is always set to at least zero (0). To access the emotes in the set, use the Get Emote Sets API. + var emote_sets: String + ## A Boolean value that indicates whether the user has site-wide commercial free mode enabled. Is true (1) if enabled; otherwise, false (0). + var turbo: String + ## The user’s ID. + var user_id: String + ## The type of user. See TwitchTags.USER_TYPE_* + var user_type: String + + + func _init(tags: String) -> void: + parse_tags(tags, self) + + +## Sent to indicate the outcome of an action like banning a user. [br] +## @msg-id=;target-user-id= [br] +## See: https://dev.twitch.tv/docs/irc/tags/#notice-tags +class Notice extends BaseTags: + ## An ID that you can use to programmatically determine the action’s outcome. For a list of possible IDs, see NOTICE Message IDs. + var msg_id: String + ## The ID of the user that the action targeted. + var target_user_id: String + + + func _init(tags: String) -> void: + parse_tags(tags, self) + + +## Sent when a user posts a message to the chat room. [br] +## @badge-info=;badges=;bits=client-nonce=;color=;display-name=;emotes=;first-msg=;flags=;id=;mod=;room-id=;subscriber=;tmi-sent-ts=;turbo=;user-id=;user-type=;reply-parent-msg-id=;reply-parent-user-id=;reply-parent-user-login=;reply-parent-display-name=;reply-parent-msg-body=;reply-thread-parent-msg-id=;reply-thread-parent-user-login=;vip= [br] +## See: https://dev.twitch.tv/docs/irc/tags/#privmsg-tags +class PrivMsg extends BaseTags: + ## Contains metadata related to the chat badges in the badges tag. [br] + ##Currently, this tag contains metadata only for subscriber badges, to indicate the number of months the user has been a subscriber. + var badge_info: String + ## Comma-separated list of chat badges in the form, /. For example, admin/1. There are many possible badge values, + var badges: String + ## The amount of Bits the user cheered. Only a Bits cheer message includes this tag. To learn more about Bits, see the Extensions Monetization Guide. To get the cheermote, use the Get Cheermotes API. Match the cheer amount to the id field’s value in the response. Then, get the cheermote’s URL based on the cheermote theme, type, and size you want to use. + var bits: String + ## The color of the user’s name in the chat room. This is a hexadecimal RGB color code in the form, #. This tag may be empty if it is never set. + var color: String + ## The user’s display name, escaped as described in the IRCv3 spec. This tag may be empty if it is never set. + var display_name: String + ## A comma-delimited list of emotes and their positions in the message. Each emote is in the form, :-. The position indices are zero-based. + var emotes: String + ## An ID that uniquely identifies the message. + var id: String + ## A Boolean value that determines whether the user is a moderator. Is true (1) if the user is a moderator otherwise, false (0). + var mod: String + ## The value of the Hype Chat sent by the user. + var pinned_chat_paid_amount: String + ## The ISO 4217 alphabetic currency code the user has sent the Hype Chat in. + var pinned_chat_paid_currency: String + ## Indicates how many decimal points this currency represents partial amounts in. Decimal points start from the right side of the value defined in pinned-chat-paid-amount. + var pinned_chat_paid_exponent: String + ## The level of the Hype Chat, in English. Possible values are: ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN + var pinned_chat_paid_level: String + ##A Boolean value that determines if the message sent with the Hype Chat was filled in by the system. [br] + ##If true (1), the user entered no message and the body message was automatically filled in by the system. [br] + ##If false (0), the user provided their own message to send with the Hype Chat. + var pinned_chat_paid_is_system_message: String + ## An ID that uniquely identifies the direct parent message that this message is replying to. The message does not include this tag if this message is not a reply. + var reply_parent_msg_id: String + ## An ID that identifies the sender of the direct parent message. The message does not include this tag if this message is not a reply. + var reply_parent_user_id: String + ## The login name of the sender of the direct parent message. The message does not include this tag if this message is not a reply. + var reply_parent_user_login: String + ## The display name of the sender of the direct parent message. The message does not include this tag if this message is not a reply. + var reply_parent_display_name: String + ## The text of the direct parent message. The message does not include this tag if this message is not a reply. + var reply_parent_msg_body: String + ## An ID that uniquely identifies the top-level parent message of the reply thread that this message is replying to. The message does not include this tag if this message is not a reply. + var reply_thread_parent_msg_id: String + ## The login name of the sender of the top-level parent message. The message does not include this tag if this message is not a reply. + var reply_thread_parent_user_login: String + ## An ID that identifies the chat room (channel). + var room_id: String + ## A Boolean value that determines whether the user is a subscriber. Is true (1) if the user is a subscriber otherwise, false (0). + var subscriber: String + ## The UNIX timestamp. + var tmi_sent_ts: String + ## A Boolean value that indicates whether the user has site-wide commercial free mode enabled. Is true (1) if enabled otherwise, false (0). + var turbo: String + ## The user’s ID. + var user_id: String + ## The type of user. See TwitchTags.USER_TYPE_* + var user_type: String + ## A Boolean value that determines whether the user that sent the chat is a VIP. The message includes this tag if the user is a VIP otherwise, the message doesn’t include this tag (check for the presence of the tag instead of whether the tag is set to true or false). + var vip: String + ## Not documented by Twitch. + var first_msg: String + ## Not documented by Twitch. + var client_nonce: String + + + func _init(tags: String) -> void: + parse_tags(tags, self) + + +## Sent when the bot joins a channel or when the channel’s chat room settings change. [br] +## @emote-only=;followers-only=;r9k=;rituals=;room-id=;slow=;subs-only= [br] +## See: https://dev.twitch.tv/docs/irc/tags/#roomstate-tags +class Roomstate extends BaseTags: + ## A Boolean value that determines whether the chat room allows only messages with emotes. Is true (1) if only emotes are allowed otherwise, false (0). + var emote_only: String + ## An integer value that determines whether only followers can post messages in the chat room. The value indicates how long, in minutes, the user must have followed the broadcaster before posting chat messages. If the value is -1, the chat room is not restricted to followers only. + var followers_only: String + ## A Boolean value that determines whether a user’s messages must be unique. Applies only to messages with more than 9 characters. Is true (1) if users must post unique messages otherwise, false (0). + var r9k: String + ## An ID that identifies the chat room (channel). + var room_id: String + ## An integer value that determines how long, in seconds, users must wait between sending messages. + var slow: String + ## A Boolean value that determines whether only subscribers and moderators can chat in the chat room. Is true (1) if only subscribers and moderators can chat otherwise, false (0). + var subs_only: String + + + func _init(tags: String) -> void: + parse_tags(tags, self) + + +## Sent when events like someone subscribing to the channel occurs.[br] +## @badge-info=;badges=;color=;display-name=;emotes=;id=;login=;mod=;msg-id=;room-id=;subscriber=;system-msg=;tmi-sent-ts=;turbo=;user-id=;user-type=[br] +## See: https://dev.twitch.tv/docs/irc/tags/#usernotice-tags +class Usernotice extends BaseTags: + ## Contains metadata related to the chat badges in the badges tag. [br] + ## Currently, this tag contains metadata only for subscriber badges, to indicate the number of months the user has been a subscriber. + var badge_info: String + ## Comma-separated list of chat badges in the form, /. For example, admin/1. There are many possible badge values. + var badges: String + ## The color of the user’s name in the chat room. This is a hexadecimal RGB color code in the form, #. This tag may be empty if it is never set. + var color: String + ## The user’s display name, escaped as described in the IRCv3 spec. This tag may be empty if it is never set. + var display_name: String + ## A comma-delimited list of emotes and their positions in the message. Each emote is in the form, :-. The position indices are zero-based. + var emotes: String + ## An ID that uniquely identifies this message. + var id: String + ## The login name of the user whose action generated the message. + var login: String + ## A Boolean value that determines whether the user is a moderator. Is true (1) if the user is a moderator otherwise, false (0). + var mod: String + ## The type of notice (not the ID). Possible values are: TwitchTags.MSG_ID_* + var msg_id: String + ## An ID that identifies the chat room (channel). + var room_id: String + ## A Boolean value that determines whether the user is a subscriber. Is true (1) if the user is a subscriber otherwise, false (0). + var subscriber: String + ## The message Twitch shows in the chat room for this notice. + var system_msg: String + ## The UNIX timestamp for when the Twitch IRC server received the message. + var tmi_sent_ts: String + ## A Boolean value that indicates whether the user has site-wide commercial free mode enabled. Is true (1) if enabled otherwise, false (0). + var turbo: String + ## The user’s ID. + var user_id: String + ## The type of user. See TwitchTags.USER_TYPE_* + var user_type: String +# +# Depending on State +# + ## Included only with sub and resub notices. [br] + ## The total number of months the user has subscribed. This is the same as msg-param-months but sent for different types of user notices. + var msg_param_cumulative_months: String + ## Included only with raid notices. [br] + ## The display name of the broadcaster raiding this channel. + var msg_param_displayName: String + ## Included only with raid notices. [br] + ## The login name of the broadcaster raiding this channel. + var msg_param_login: String + ## Included only with subgift notices. [br] + ## The total number of months the user has subscribed. This is the same as msg-param-cumulative-months but sent for different types of user notices. + var msg_param_months: String + ## Included only with anongiftpaidupgrade and giftpaidupgrade notices. [br] + ## The number of gifts the gifter has given during the promo indicated by msg-param-promo-name. + var msg_param_promo_gift_total: String + ## Included only with anongiftpaidupgrade and giftpaidupgrade notices. [br] + ## The subscriptions promo, if any, that is ongoing (for example, Subtember 2018). + var msg_param_promo_name: String + ## Included only with subgift notices.[br] + ## The display name of the subscription gift recipient. + var msg_param_recipient_display_name: String + ## Included only with subgift notices.[br] + ## The user ID of the subscription gift recipient. + var msg_param_recipient_id: String + ## Included only with subgift notices.[br] + ## The user name of the subscription gift recipient. + var msg_param_recipient_user_name: String + ## Included only with giftpaidupgrade notices. [br] + ## The login name of the user who gifted the subscription. + var msg_param_sender_login: String + ## Include only with giftpaidupgrade notices.[br] + ## The display name of the user who gifted the subscription. + var msg_param_sender_name: String + ## Included only with sub and resub notices.[br] + ## A Boolean value that indicates whether the user wants their streaks shared. + var msg_param_should_share_streak: String + ## Included only with sub and resub notices. + ## The number of consecutive months the user has subscribed. This is zero (0) if msg-param-should-share-streak is 0. + var msg_param_streak_months: String + ## Included only with sub, resub and subgift notices.[br] + ## [br] + ## The type of subscription plan being used. Possible values are:[br] + ## [br] + ## Prime — Amazon Prime subscription[br] + ## 1000 — First level of paid subscription[br] + ## 2000 — Second level of paid subscription[br] + ## 3000 — Third level of paid subscription[br] + var msg_param_sub_plan: String + ## Included only with sub, resub, and subgift notices.[br] + ## The display name of the subscription plan. This may be a default name or one created by the channel owner. + var msg_param_sub_plan_name: String + ## Included only with raid notices.[br] + ## The number of viewers raiding this channel from the broadcaster’s channel. + var msg_param_viewerCount: String + ## Included only with ritual notices.[br] + ## The name of the ritual being celebrated. Possible values are: new_chatter. + var msg_param_ritual_name: String + ## Included only with bitsbadgetier notices.[br] + ## The tier of the Bits badge the user just earned. For example, 100, 1000, or 10000. + var msg_param_threshold: String + ## Included only with subgift notices.[br] + ## The number of months gifted as part of a single, multi-month gift. + var msg_param_gift_months: String + + + func _init(tags: String) -> void: + parse_tags(tags, self) + + +## Sent when the bot joins a channel or sends a PRIVMSG message. [br] +## @badge-info=;badges=;color=;display-name=;emote-sets=;id=;mod=;subscriber=;turbo=;user-type=[br][br] +## See: https://dev.twitch.tv/docs/irc/tags/#userstate-tags +class Userstate extends BaseTags: + ## Contains metadata related to the chat badges in the badges tag. [br] + ## Currently, this tag contains metadata only for subscriber badges, to indicate the number of months the user has been a subscriber. + var badge_info: String + ## Comma-separated list of chat badges in the form, /. For example, admin/1. There are many possible badge values. + var badges: String + ## The color of the user’s name in the chat room. This is a hexadecimal RGB color code in the form, #. This tag may be empty if it is never set. + var color: String + ## The user’s display name, escaped as described in the IRCv3 spec. This tag may be empty if it is never set. + var display_name: String + ## A comma-delimited list of IDs that identify the emote sets that the user has access to. Is always set to at least zero (0). To access the emotes in the set, use the Get Emote Sets API. + var emote_sets: String + ## If a privmsg was sent, an ID that uniquely identifies the message. + var id: String + ## A Boolean value that determines whether the user is a moderator. Is true (1) if the user is a moderator; otherwise, false (0). + var mod: String + ## A Boolean value that determines whether the user is a subscriber. Is true (1) if the user is a subscriber; otherwise, false (0). + var subscriber: String + ## A Boolean value that indicates whether the user has site-wide commercial free mode enabled. Is true (1) if enabled; otherwise, false (0). + var turbo: String + ## The type of user. See TwitchTags.USER_TYPE_* + var user_type: String + + + func _init(tags: String) -> void: + parse_tags(tags, self) + + +## Sent when someone sends your bot a whisper message. [br] +## @badges=;color=;display-name=;emotes=;message-id=;thread-id=;turbo=;user-id=;user-type=[br] +## See: https://dev.twitch.tv/docs/irc/tags/#whisper-tags +class Whisper extends BaseTags: + ## Comma-separated list of chat badges in the form, /. For example, admin/1. There are many possible badge values. + var badges: String + ## The color of the user’s name in the chat room. This is a hexadecimal RGB color code in the form, #. This tag may be empty if it is never set. + var color: String + ## The display name of the user sending the whisper message, escaped as described in the IRCv3 spec. This tag may be empty if it is never set. + var display_name: String + ## A comma-delimited list of emotes and their positions in the message. Each emote is in the form, :-. The position indices are zero-based. + var emotes: String + ## An ID that uniquely identifies the whisper message. + var message_id: String + ## An ID that uniquely identifies the whisper thread. The ID is in the form, _. + var thread_id: String + ## A Boolean value that indicates whether the user has site-wide commercial free mode enabled. Is true (1) if enabled; otherwise, false (0). + var turbo: String + ## The ID of the user sending the whisper message. + var user_id: String + ## The type of user. See TwitchTags.USER_TYPE_* + var user_type: String + + + func _init(tags: String) -> void: + parse_tags(tags, self) + +#endregion diff --git a/addons/twitcher/irc/twitch_tags.gd.uid b/addons/twitcher/irc/twitch_tags.gd.uid new file mode 100644 index 0000000..75c2279 --- /dev/null +++ b/addons/twitcher/irc/twitch_tags.gd.uid @@ -0,0 +1 @@ +uid://drb7ly83s17kp diff --git a/addons/twitcher/lib/README.md b/addons/twitcher/lib/README.md new file mode 100644 index 0000000..a7ea5d0 --- /dev/null +++ b/addons/twitcher/lib/README.md @@ -0,0 +1,6 @@ +Because Godot doesn't have a good system to handle dependencies and +I want to have standalone modules that could be technically their own plugins. + +Requirements: +twitcher requires http, oOuch +oOuch requires http diff --git a/addons/twitcher/lib/http/buffered-http-icon.svg b/addons/twitcher/lib/http/buffered-http-icon.svg new file mode 100644 index 0000000..7bf20cc --- /dev/null +++ b/addons/twitcher/lib/http/buffered-http-icon.svg @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + diff --git a/addons/twitcher/lib/http/buffered-http-icon.svg.import b/addons/twitcher/lib/http/buffered-http-icon.svg.import new file mode 100644 index 0000000..585c15b --- /dev/null +++ b/addons/twitcher/lib/http/buffered-http-icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://517onfw47ulp" +path="res://.godot/imported/buffered-http-icon.svg-338b6a52134b1dc8e217747ec727a304.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/twitcher/lib/http/buffered-http-icon.svg" +dest_files=["res://.godot/imported/buffered-http-icon.svg-338b6a52134b1dc8e217747ec727a304.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/twitcher/lib/http/buffered_http_client.gd b/addons/twitcher/lib/http/buffered_http_client.gd new file mode 100644 index 0000000..96f0110 --- /dev/null +++ b/addons/twitcher/lib/http/buffered_http_client.gd @@ -0,0 +1,204 @@ +@icon("./buffered-http-icon.svg") +@tool +extends Twitcher + +## Http client that bufferes the requests and sends them sequentialy +class_name BufferedHTTPClient + + +## Will be send when a new request was added to queue +signal request_added(request: RequestData) + +## Will be send when a request is done. +signal request_done(response: ResponseData) + + +## Contains the request data to be send +class RequestData extends RefCounted: + ## The client that the request belongs too + var client: BufferedHTTPClient + ## The request node that is executing the request + var http_request: HTTPRequest + ## Path of the request + var path: String + ## The method that is used to call request + var method: int + ## The request headers + var headers: Dictionary + ## The body that is requested (TODO does it make more sense to make a Byte Array out of it?) + var body: String = "" + ## Amount of retries + var retry: int + + ## When you are done free the request + func queue_free() -> void: + http_request.queue_free() + + +## Contains the response data +class ResponseData extends RefCounted: + ## Result of the request see `HTTPRequest.Result` + var result: int + ## Response code from the request like 200 for OK + var response_code: int + ## the initial request data + var request_data: RequestData + ## The body of the response as byte array + var response_data: PackedByteArray + ## The response header as dictionary, where multiple keys are concatenated with ';' + var response_header: Dictionary + ## Had the response an error + var error: bool + + ## When you are done free the request + func queue_free() -> void: + request_data.queue_free() + +## When a request fails max_error_count then cancel that request -1 for endless amount of tries. +@export var max_error_count : int = -1 +@export var custom_header : Dictionary[String, String] = { "Accept": "*/*" } + +var requests : Array[RequestData] = [] +var current_request : RequestData +var current_response_data : PackedByteArray = PackedByteArray() +var responses : Dictionary = {} +var error_count : int + + +## Only one poll at a time so block for all other tries to call it +var polling: bool +var processing: bool: + get: return not requests.is_empty() || current_request != null + + +## Starts a request that will be handled as soon as the client gets free. +## Use HTTPClient.METHOD_* for the method. +func request(path: String, method: int, headers: Dictionary, body: String) -> RequestData: + logInfo("[%s] start request " % [ path ]) + headers = headers.duplicate() + headers.merge(custom_header) + var req = RequestData.new() + req.path = path + req.method = method + req.body = body + req.headers = headers + req.client = self + req.http_request = HTTPRequest.new() + req.http_request.use_threads = true + req.http_request.timeout = 30 + req.http_request.request_completed.connect(_on_request_completed.bind(req)) + add_child(req.http_request) + var err : Error = req.http_request.request(req.path, _pack_headers(req.headers), req.method, req.body) + if err != OK: logError("Problems with request to %s cause of %s" % [path, error_string(err)]) + requests.append(req) + request_added.emit(req) + logDebug("[%s] request started " % [ path ]) + return req + + +## When the response is available return it otherwise wait for the response +func wait_for_request(request_data: RequestData) -> ResponseData: + if responses.has(request_data): + var response = responses[request_data] + responses.erase(request_data) + request_data.queue_free() + logDebug("response cached return directly from wait") + return response + + var latest_response : ResponseData = null + while (latest_response == null || request_data != latest_response.request_data): + latest_response = await request_done + logDebug("response received return from wait") + responses.erase(request_data) + request_data.queue_free() + return latest_response + + +func _on_request_completed(result: int, response_code: int, headers: PackedStringArray, body: PackedByteArray, request_data: RequestData) -> void: + var response_data : ResponseData = ResponseData.new() + if result != HTTPRequest.Result.RESULT_SUCCESS: + logInfo("[%s] problems with result \n\t> response code: %s \n\t> body: %s" % [request_data.path, response_code, body.get_string_from_utf8()]) + response_data.error = true + if result == HTTPRequest.Result.RESULT_CONNECTION_ERROR || result == HTTPRequest.Result.RESULT_TLS_HANDSHAKE_ERROR: + if request_data.retry == max_error_count: + printerr("Maximum amount of retries for the request. Abort request: %s" % [request_data.path]) + return + var wait_time = pow(2, request_data.retry) + wait_time = min(wait_time, 30) + logDebug("Error happend during connection. Wait for %s" % wait_time) + await get_tree().create_timer(wait_time, true, false, true).timeout + var http_request: HTTPRequest = request_data.http_request.duplicate() + add_child(http_request) + request_data.http_request = http_request + request_data.retry += 1 + http_request.request(request_data.path, _pack_headers(request_data.headers), request_data.method, request_data.body) + http_request.request_completed.connect(_on_request_completed.bind(http_request)) + + response_data.result = result + response_data.request_data = request_data + response_data.response_data = body + response_data.response_code = response_code + response_data.response_header = _get_response_headers_as_dictionary(headers) + responses[request_data] = response_data + logInfo("[%s] request done with result HTTPRequest.Result[%s] " % [ request_data.path, result]) + request_done.emit(response_data) + + +func _get_response_headers_as_dictionary(headers: PackedStringArray) -> Dictionary: + var header_dict: Dictionary = {} + if headers == null: + return header_dict + + for header in headers: + var header_data = header.split(":", true, 1) + var key = header_data[0] + var val = header_data[1] + if header_dict.has(key): + header_dict[key] += "; " + val + else: + header_dict[key] = val + return header_dict + + +func _pack_headers(headers: Dictionary) -> PackedStringArray: + var result: PackedStringArray = [] + for header_key in headers: + var header_value = headers[header_key] + result.append("%s: %s" % [header_key, header_value]) + return result + + +## The amount of requests that are pending +func queued_request_size() -> int: + var requests_size: int = requests.size() + if current_request != null: + requests_size += 1 + return requests_size + + +func empty_response(request_data: RequestData) -> ResponseData: + var response_data = ResponseData.new() + response_data.request_data = request_data + response_data.response_data = [] + response_data.response_code = 0 + response_data.response_header = {} + response_data.result = 0 + return response_data + + +# === LOGGER === + +static var logger: Dictionary = {} +static func set_logger(error: Callable, info: Callable, debug: Callable) -> void: + logger.debug = debug + logger.info = info + logger.error = error + +static func logDebug(text: String) -> void: + if logger.has("debug"): logger.debug.call(text) + +static func logInfo(text: String) -> void: + if logger.has("info"): logger.info.call(text) + +static func logError(text: String) -> void: + if logger.has("error"): logger.error.call(text) \ No newline at end of file diff --git a/addons/twitcher/lib/http/buffered_http_client.gd.uid b/addons/twitcher/lib/http/buffered_http_client.gd.uid new file mode 100644 index 0000000..097c20b --- /dev/null +++ b/addons/twitcher/lib/http/buffered_http_client.gd.uid @@ -0,0 +1 @@ +uid://b7i5j62lmuh71 diff --git a/addons/twitcher/lib/http/debug_buffered_http_client.gd b/addons/twitcher/lib/http/debug_buffered_http_client.gd new file mode 100644 index 0000000..1b2a9b0 --- /dev/null +++ b/addons/twitcher/lib/http/debug_buffered_http_client.gd @@ -0,0 +1,58 @@ +extends Control + +@onready var clients: Tree = %Clients + +## Key: BufferedHTTPClient | value: TreeItem +var client_map : Dictionary[BufferedHTTPClient, TreeItem] = {} +## Key: RequestData | value: TreeItem +var request_map : Dictionary[BufferedHTTPClient.RequestData, TreeItem] = {} + + +func _ready() -> void: + get_tree().root.child_entered_tree.connect(_on_child_enter) + _add_http_clients(get_tree().root) + + +func _add_http_clients(parent: Node) -> void: + for child in parent.get_children(): + _on_child_enter(child) + _add_http_clients(child) + + +func _on_child_enter(node: Node) -> void: + if node is BufferedHTTPClient: + _new_client(node) + + +func _new_client(client: BufferedHTTPClient): + var parent = clients.create_item() + parent.set_text(0, client.name) + + client_map[client] = parent + + client.request_added.connect(_on_add_request.bind(parent)) + client.request_done.connect(_on_done_request) + for request in client.requests: + _on_add_request(request, parent) + + +func _on_add_request(request: BufferedHTTPClient.RequestData, http_item: TreeItem): + var request_item = clients.create_item(http_item) + request_item.set_text(0, request.path) + request_item.set_text(1, "Queued") + request_map[request] = request_item + + +func _on_done_request(response: BufferedHTTPClient.ResponseData): + var request_item = request_map[response.request_data] as TreeItem + request_item.set_text(1, "DONE") + await get_tree().create_timer(60, true, false, true).timeout + if request_item != null: request_item.free() + + +func _close_client(client: BufferedHTTPClient): + var http_item = client_map[client] as TreeItem + client_map.erase(client) + http_item.set_text(1, "CLOSED") + await get_tree().create_timer(60, true, false, true).timeout + http_item.free() diff --git a/addons/twitcher/lib/http/debug_buffered_http_client.gd.uid b/addons/twitcher/lib/http/debug_buffered_http_client.gd.uid new file mode 100644 index 0000000..e6ee117 --- /dev/null +++ b/addons/twitcher/lib/http/debug_buffered_http_client.gd.uid @@ -0,0 +1 @@ +uid://bpvg80y7vsysx diff --git a/addons/twitcher/lib/http/debug_buffered_http_client.tscn b/addons/twitcher/lib/http/debug_buffered_http_client.tscn new file mode 100644 index 0000000..16461ad --- /dev/null +++ b/addons/twitcher/lib/http/debug_buffered_http_client.tscn @@ -0,0 +1,25 @@ +[gd_scene load_steps=2 format=3 uid="uid://b0ebhuv2yaow0"] + +[ext_resource type="Script" uid="uid://bpvg80y7vsysx" path="res://addons/twitcher/lib/http/debug_buffered_http_client.gd" id="1_ij68s"] + +[node name="DebugBufferedHttpClient" type="VBoxContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +script = ExtResource("1_ij68s") + +[node name="Label" type="Label" parent="."] +layout_mode = 2 +text = "Debug HTTP Clients" +horizontal_alignment = 1 + +[node name="Clients" type="Tree" parent="."] +unique_name_in_owner = true +layout_mode = 2 +size_flags_vertical = 3 +columns = 2 +hide_root = true diff --git a/addons/twitcher/lib/http/http_server.gd b/addons/twitcher/lib/http/http_server.gd new file mode 100644 index 0000000..225e158 --- /dev/null +++ b/addons/twitcher/lib/http/http_server.gd @@ -0,0 +1,177 @@ +@tool +extends Node + +## Provides a simple HTTP Service to serve web stuff +class_name HTTPServer + +## Key: int | Value: WeakRef(Server) +static var _servers : Dictionary = {} + + +class Server extends TCPServer: + var _bind_address: String + var _port: int + var _clients: Array[Client] = [] + var _listeners: int + + signal request_received(client: Client) + signal client_connected(client: Client) + signal client_disconnected(client: Client) + signal client_error_occured(client: Client, error: Error) + + + func _init(bind_address: String, port: int) -> void: + _bind_address = bind_address + _port = port + HTTPServer._servers[_port] = weakref(self) + + + func start_listening() -> void: + _listeners += 1 + if !is_listening(): + var status: Error = listen(_port, _bind_address) + Engine.get_main_loop().process_frame.connect(_process) + if status != OK: + HTTPServer.logError("Could not listen to port %d: %s" % [_port, error_string(status)]) + else: + HTTPServer.logInfo("{%s:%s} listening" % [ _bind_address, _port ]) + else: + HTTPServer.logDebug("{%s:%s} already listening" % [ _bind_address, _port ]) + + + func stop_listening() -> void: + _listeners -= 1 + HTTPServer.logDebug("{%s:%s} listener node detached %s left" % [ _bind_address, _port, _listeners ]) + if _listeners <= 0: + _stop_server() + + + func _stop_server() -> void: + HTTPServer.logInfo("{%s:%s} stop" % [ _bind_address, _port ]) + Engine.get_main_loop().process_frame.disconnect(_process) + for client in _clients: + client.peer.disconnect_from_host() + stop() + + + func _notification(what: int) -> void: + if what == NOTIFICATION_PREDELETE: + HTTPServer.logInfo("{%s:%s} removed" % [ _bind_address, _port ]) + HTTPServer._servers.erase(_port) + + + func _process() -> void: + if !is_listening(): return + + if is_connection_available(): + _handle_connect() + + for client in _clients: + _process_request(client) + _handle_disconnect(client) + + + func _process_request(client: Client) -> void: + var peer := client.peer + if peer.get_status() == StreamPeerTCP.STATUS_CONNECTED: + var error = peer.poll() + if error != OK: + HTTPServer.logError("Could not poll client %d: %s" % [_port, error_string(error)]) + client_error_occured.emit(client, error) + elif peer.get_available_bytes() > 0: + request_received.emit(client) + + + func _handle_connect() -> void: + var peer := take_connection() + var client := Client.new() + client.peer = peer + _clients.append(client) + client_connected.emit(client) + HTTPServer.logInfo("{%s:%s} client connected" % [ _bind_address, _port ]) + + + func _handle_disconnect(client: Client) -> void: + if client.peer.get_status() != StreamPeerTCP.STATUS_CONNECTED: + client_disconnected.emit(client) + HTTPServer.logInfo("{%s:%s} client disconnected" % [ _bind_address, _port ]) + _clients.erase(client) + + +class Client extends RefCounted: + var peer: StreamPeerTCP + + +## Called when a new request was made +signal request_received(client: Client) + + +@export var _port: int +@export var _bind_address: String + +var _server : Server +var _listening: bool + + +static func create(port: int, bind_address: String = "*") -> HTTPServer: + var server = HTTPServer.new() + server._bind_address = bind_address + server._port = port + return server + + +func _ready() -> void: + if _servers.has(_port) && _servers[_port] != null: + _server = _servers[_port].get_ref() + else: + _server = Server.new(_bind_address, _port) + _server.request_received.connect(_on_request_received) + logInfo("{%s:%s} start" % [ _bind_address, _port ]) + + +func _on_request_received(client: Client) -> void: + request_received.emit(client) + + +func _notification(what: int) -> void: + if what == NOTIFICATION_PREDELETE: + stop_listening() + + +func start_listening() -> void: + _listening = true + _server.start_listening() + + +func stop_listening() -> void: + if _listening: + _listening = false + _server.stop_listening() + + +func send_response(client: Client, response_code : String, body : PackedByteArray) -> void: + var peer = client.peer + peer.put_data(("HTTP/1.1 %s\r\n" % response_code).to_utf8_buffer()) + peer.put_data("Server: Godot Engine (Twitcher)\r\n".to_utf8_buffer()) + peer.put_data(("Content-Length: %d\r\n"% body.size()).to_utf8_buffer()) + peer.put_data("Connection: close\r\n".to_utf8_buffer()) + peer.put_data("Content-Type: text/html charset=UTF-8\r\n".to_utf8_buffer()) + peer.put_data("\r\n".to_utf8_buffer()) + peer.put_data(body) + + +# === LOGGER === +static var logger: Dictionary = {} +static func set_logger(error: Callable, info: Callable, debug: Callable) -> void: + logger.debug = debug + logger.info = info + logger.error = error + +static func logDebug(text: String) -> void: + if logger.has("debug"): logger.debug.call(text) + +static func logInfo(text: String) -> void: + if logger.has("info"): logger.info.call(text) + +static func logError(text: String) -> void: + if logger.has("error"): logger.error.call(text) diff --git a/addons/twitcher/lib/http/http_server.gd.uid b/addons/twitcher/lib/http/http_server.gd.uid new file mode 100644 index 0000000..e08f3ad --- /dev/null +++ b/addons/twitcher/lib/http/http_server.gd.uid @@ -0,0 +1 @@ +uid://bnepo370sikkb diff --git a/addons/twitcher/lib/http/http_util.gd b/addons/twitcher/lib/http/http_util.gd new file mode 100644 index 0000000..2d8342a --- /dev/null +++ b/addons/twitcher/lib/http/http_util.gd @@ -0,0 +1,25 @@ +extends Object + +## Parses a query string and returns a dictionary with the parameters. +static func parse_query(query: String) -> Dictionary: + var parameters = Dictionary() + # Split the query by '&' to separate different parameters. + var pairs = query.split("&") + # Iterate over each pair of key-value. + for pair in pairs: + # Split the pair by '=' to separate the key from the value. + var kv = pair.split("=") + if kv.size() == 2: + var key = kv[0].strip_edges() + var value = kv[1].strip_edges() + var decoded_key = key.uri_decode() + var decoded_value = value.uri_decode() + parameters[decoded_key] = decoded_value + return parameters + + +## Method to set all logger within this package +static func set_logger(error: Callable, info: Callable, debug: Callable) -> void: + BufferedHTTPClient.set_logger(error, info, debug) + HTTPServer.set_logger(error, info, debug) + WebsocketClient.set_logger(error, info, debug) diff --git a/addons/twitcher/lib/http/http_util.gd.uid b/addons/twitcher/lib/http/http_util.gd.uid new file mode 100644 index 0000000..3648771 --- /dev/null +++ b/addons/twitcher/lib/http/http_util.gd.uid @@ -0,0 +1 @@ +uid://5esrbr8ikth8 diff --git a/addons/twitcher/lib/http/websocket_client.gd b/addons/twitcher/lib/http/websocket_client.gd new file mode 100644 index 0000000..8c0aebc --- /dev/null +++ b/addons/twitcher/lib/http/websocket_client.gd @@ -0,0 +1,145 @@ +@tool +extends Node + +## Advanced websocket client that automatically reconnects to the server +class_name WebsocketClient + + +## Called as soon the websocket got a connection +signal connection_established + +## Called as soon the websocket closed the connection +signal connection_closed + +## Called when a complete message got received +signal message_received(message: PackedByteArray) + +## Called when the state of the websocket changed +signal connection_state_changed(state : WebSocketPeer.State) + +@export var connection_url: String: + set(val): + _logDebug("Set connection to %s" % val) + connection_url = val + +var connection_state : WebSocketPeer.State = WebSocketPeer.STATE_CLOSED: + set(new_state): + if new_state != connection_state: + connection_state_changed.emit(new_state) + if new_state == WebSocketPeer.STATE_OPEN: connection_established.emit() + if new_state == WebSocketPeer.STATE_CLOSED: connection_closed.emit() + connection_state = new_state + +## Determines if a connection should be established or not +@export var auto_reconnect: bool: + set(val): + auto_reconnect = val + _logDebug("New auto_reconnect value: %s" % val) + +## True if currently connecting to prevent 2 connectionen processes at the same time +var _is_already_connecting: bool +var is_open: bool: + get(): return _peer.get_ready_state() == WebSocketPeer.STATE_OPEN +var is_closed: bool: + get(): return _peer.get_ready_state() == WebSocketPeer.STATE_CLOSED + +var _peer: WebSocketPeer = WebSocketPeer.new() +var _tries: int + + +func open_connection() -> void: + if not is_closed: return + auto_reconnect = true + _logInfo("Open connection") + await _establish_connection() + + +func wait_connection_established() -> void: + if is_open: return + await connection_established + +func _establish_connection() -> void: + if _is_already_connecting || not is_closed: return + _is_already_connecting = true + var wait_time = pow(2, _tries) + _logDebug("Wait %s before connecting" % [wait_time]) + await get_tree().create_timer(wait_time, true, false, true).timeout + _logInfo("Connecting to %s" % connection_url) + var err = _peer.connect_to_url(connection_url) + if err != OK: + logError("Couldn't connect cause of %s" % [error_string(err)]) + _tries += 1 + _is_already_connecting = false + + +func _enter_tree() -> void: + if auto_reconnect: open_connection() + + +func _exit_tree() -> void: + if not is_open: return + _peer.close(1000, "resource got freed") + + +func _process(delta: float) -> void: + _poll() + + +func _poll() -> void: + if connection_url == "": return + + var state := _peer.get_ready_state() + if state == WebSocketPeer.STATE_CLOSED and auto_reconnect: + _establish_connection() + _peer.poll() + _handle_state_changes(state) + connection_state = state + if state == WebSocketPeer.STATE_OPEN: + _read_data() + + +func _handle_state_changes(state: WebSocketPeer.State) -> void: + if connection_state != WebSocketPeer.STATE_OPEN && state == WebSocketPeer.STATE_OPEN: + _logInfo("connected") + _tries = 0 + + if connection_state != WebSocketPeer.STATE_CLOSED && state == WebSocketPeer.STATE_CLOSED: + _logInfo("connection was closed [%s]: %s" % [_peer.get_close_code(), _peer.get_close_reason()]) + + +func _read_data() -> void: + while (_peer.get_available_packet_count()): + message_received.emit(_peer.get_packet()) + + +func send_text(message: String) -> Error: + return _peer.send_text(message) + + +func close(status: int = 1000, message: String = "Normal Closure") -> void: + _logDebug("Websocket activly closed") + auto_reconnect = false + _peer.close(status, message) + + +# === LOGGER === +static var logger: Dictionary = {} +static func set_logger(error: Callable, info: Callable, debug: Callable) -> void: + logger.debug = debug + logger.info = info + logger.error = error + +func _logDebug(text: String) -> void: + logDebug("[%s]: %s" % [connection_url, text]) + +static func logDebug(text: String) -> void: + if logger.has("debug"): logger.debug.call(text) + +func _logInfo(text: String) -> void: + logInfo("[%s]: %s" % [connection_url, text]) + +static func logInfo(text: String) -> void: + if logger.has("info"): logger.info.call(text) + +static func logError(text: String) -> void: + if logger.has("error"): logger.error.call(text) diff --git a/addons/twitcher/lib/http/websocket_client.gd.uid b/addons/twitcher/lib/http/websocket_client.gd.uid new file mode 100644 index 0000000..8c2ebb6 --- /dev/null +++ b/addons/twitcher/lib/http/websocket_client.gd.uid @@ -0,0 +1 @@ +uid://buqbforpa7b8a diff --git a/addons/twitcher/lib/oOuch/crypto_key_provider.gd b/addons/twitcher/lib/oOuch/crypto_key_provider.gd new file mode 100644 index 0000000..795c77c --- /dev/null +++ b/addons/twitcher/lib/oOuch/crypto_key_provider.gd @@ -0,0 +1,94 @@ +@icon("./security-icon.svg") +@tool +extends Resource + +## Provides a key to encrypt secrets in the application. +## Please don't store the key in the project, +## otherwise your secrets may revealed easily! +class_name CryptoKeyProvider + +## Identify oOuch library specifics without collisions +const _CONFIG_PACKAGE_KEY: String = "dev.kani.oouch" +const _CONFIG_SECRET_KEY: String = "encryption" +const _AES_BLOCK_SIZE : int = 16 + +## Location of the encryption secrets +@export_global_file var encrpytion_secret_location: String = "user://encryption_key.cfg" + +static var aes: AESContext = AESContext.new() + +## To prevent accidental spoiler in the debugger +class KeyData extends RefCounted: + var key: String + +var current_key_data: KeyData + +func _init() -> void: + # Call defered cause the setter of encrpytion_secret_location isn't set otherwise + _get_encryption_secret.call_deferred() + + +## Don't cache it in a variable so that you accidently leak your secret when you debug +func _get_encryption_secret() -> String: + if is_instance_valid(current_key_data): + return current_key_data.key + + var config = ConfigFile.new() + var error = config.load(encrpytion_secret_location) + if error == ERR_FILE_NOT_FOUND: + _create_secret(config) + elif error != OK: + printerr("Can't open %s cause of %s" % [encrpytion_secret_location, error_string(error)]) + return "" + + var key: String = config.get_value(_CONFIG_PACKAGE_KEY, _CONFIG_SECRET_KEY, "") + if key == "": + key = _create_secret(config) + + current_key_data = KeyData.new() + current_key_data.key = key + return key + + +func _create_secret(config: ConfigFile) -> String: + print("Creating a new secret for encryption you can find it %s" % encrpytion_secret_location) + var crypto : Crypto = Crypto.new() + + var secret_data : PackedByteArray = crypto.generate_random_bytes(16) + var secret : String = secret_data.hex_encode() + config.set_value(_CONFIG_PACKAGE_KEY, _CONFIG_SECRET_KEY, secret) + var err = config.save(encrpytion_secret_location) + if err != OK: push_error("Couldn't save encryption key cause of ", error_string(err)) + return secret + + +func _pad(value: PackedByteArray) -> PackedByteArray: + var pad_len : int = _AES_BLOCK_SIZE - (value.size() % _AES_BLOCK_SIZE) + for i in range(pad_len): + value.append(pad_len) + return value + + +func _unpad(value: PackedByteArray) -> PackedByteArray: + if value.is_empty(): + return value + var pad_len : int = value[-1] + if pad_len <= 0 or pad_len > _AES_BLOCK_SIZE or value.size() < pad_len: + push_error("Invalid padding detected (%s)" % pad_len) + return PackedByteArray() + return value.slice(0, -pad_len) + + +func encrypt(value: PackedByteArray) -> PackedByteArray: + var padded_value = _pad(value) + aes.start(AESContext.MODE_ECB_ENCRYPT, _get_encryption_secret().to_utf8_buffer()) + var encrypted_value: PackedByteArray = aes.update(padded_value) + aes.finish() + return encrypted_value + + +func decrypt(value: PackedByteArray) -> PackedByteArray: + aes.start(AESContext.MODE_ECB_DECRYPT, _get_encryption_secret().to_utf8_buffer()) + var decrypted_value: PackedByteArray = aes.update(value) + aes.finish() + return _unpad(decrypted_value) diff --git a/addons/twitcher/lib/oOuch/crypto_key_provider.gd.uid b/addons/twitcher/lib/oOuch/crypto_key_provider.gd.uid new file mode 100644 index 0000000..d49a165 --- /dev/null +++ b/addons/twitcher/lib/oOuch/crypto_key_provider.gd.uid @@ -0,0 +1 @@ +uid://dcrliedgr6eol diff --git a/addons/twitcher/lib/oOuch/default_key_provider.tres b/addons/twitcher/lib/oOuch/default_key_provider.tres new file mode 100644 index 0000000..ea2fb11 --- /dev/null +++ b/addons/twitcher/lib/oOuch/default_key_provider.tres @@ -0,0 +1,7 @@ +[gd_resource type="Resource" script_class="CryptoKeyProvider" load_steps=2 format=3 uid="uid://c4scwuk8q0r40"] + +[ext_resource type="Script" uid="uid://dcrliedgr6eol" path="res://addons/twitcher/lib/oOuch/crypto_key_provider.gd" id="1_q12uq"] + +[resource] +script = ExtResource("1_q12uq") +encrpytion_secret_location = "user://encryption_key.cfg" diff --git a/addons/twitcher/lib/oOuch/oauth.gd b/addons/twitcher/lib/oOuch/oauth.gd new file mode 100644 index 0000000..933832c --- /dev/null +++ b/addons/twitcher/lib/oOuch/oauth.gd @@ -0,0 +1,375 @@ +@icon("./security-icon.svg") +@tool +extends Node + +## Orchestrates the complete authentication process +class_name OAuth + +const OAuthHTTPServer = preload("res://addons/twitcher/lib/http/http_server.gd") +const OAuthHTTPClient = preload("res://addons/twitcher/lib/http/buffered_http_client.gd") +const OAuthDeviceCodeResponse = preload("./oauth_device_code_response.gd") + +## Called when the authorization for AuthCodeFlow is complete to handle the auth code +signal _auth_succeed(code: String) + +## In case the authorization wasn't succesfull +signal auth_error(error: String, error_description: String) + +## The requested devicecode to show to the user for authorization +signal device_code_requested(device_code: OAuthDeviceCodeResponse) + +## Called when the token has changed +signal token_changed(access_token: String) + +@export var oauth_setting: OAuthSetting +@export var scopes: OAuthScopes +@export var token_handler: OAuthTokenHandler +## Customize how you want to open the authorization page (advanced usage for example multi user authentication) +@export var shell_command: String +## Parameters for the shell command (advanced usage for example multi user authentication) +@export var shell_parameter: Array[String] = [] +## Some oauth provide doesn't return the provided scopes so you can disable the scope check +@export var check_scope_changed: bool = true + +var login_in_process: bool +## Special solution just for twitch ignore it in all other providers +var force_verify: String +var _query_parser = RegEx.create_from_string("GET (.*?/?)\\??(.*?)? HTTP/1\\.1.*?") +var _auth_http_server: OAuthHTTPServer +var _last_login_attempt: int +## State for the current authcode request to compare with +var _current_state: String +var _client: OAuthHTTPClient +var _crypto: Crypto = Crypto.new() +var _login_timeout_timer: Timer +var _initialized: bool + +enum AuthorizationFlow { + AUTHORIZATION_CODE_FLOW, + IMPLICIT_FLOW, + DEVICE_CODE_FLOW, + CLIENT_CREDENTIALS +} + + +func _on_unauthenticated() -> void: + login() + + +func _on_token_resolved(token: OAuthToken) -> void: + if token == null: return + token_changed.emit(await token.get_access_token()) + + +## Checks if the authentication is valid. +func is_authenticated() -> bool: + return token_handler.is_token_valid() + + +## Starts the token refresh process to rotate the tokens +func refresh_token() -> void: + await token_handler.refresh_tokens() + + +func _setup_nodes() -> void: + if _initialized: return + _initialized = true + + if _client == null: + _client = OAuthHTTPClient.new() + _client.name = "OAuthClient" + add_child(_client) + + if _auth_http_server == null: + _auth_http_server = OAuthHTTPServer.create(oauth_setting.redirect_port) + _auth_http_server.name = "OAuthServer" + add_child(_auth_http_server) + + if token_handler == null: + token_handler = OAuthTokenHandler.new() + add_child(token_handler) + + token_handler.unauthenticated.connect(_on_unauthenticated) + token_handler.token_resolved.connect(_on_token_resolved) + + _login_timeout_timer = Timer.new() + _login_timeout_timer.name = "LoginTimeoutTimer" + _login_timeout_timer.one_shot = true + _login_timeout_timer.wait_time = 30 + _login_timeout_timer.timeout.connect(_on_login_timeout) + add_child(_login_timeout_timer) + +## Depending on the authorization_flow it gets resolves the token via the different +## Flow types. Only one login process at the time. All other tries wait until the first process +## was succesful. +func login() -> bool: + if not is_node_ready(): await ready + _setup_nodes() + if token_handler.is_token_valid() && not _got_scopes_changed(): return true + logDebug("Token is valid (%s) and not scopes changed (%s)" % [ token_handler.is_token_valid(), _got_scopes_changed()]) + + if login_in_process: + logInfo("Another process tries already to login. Abort") + if (await token_handler.token_resolved) == null: + return false + return true + + if _last_login_attempt != 0 && Time.get_ticks_msec() - 60 * 1000 < _last_login_attempt: + print("[OAuth] Last Login attempt was within 1 minute wait 1 minute before trying again. Please enable and consult logs, cause there is an issue with your authentication!") + await get_tree().create_timer(60, true, false, true).timeout + + _last_login_attempt = Time.get_ticks_msec() + + login_in_process = true + _login_timeout_timer.start() + logInfo("do login") + match oauth_setting.authorization_flow: + AuthorizationFlow.AUTHORIZATION_CODE_FLOW: + await _start_login_process("code") + AuthorizationFlow.CLIENT_CREDENTIALS: + await token_handler.request_token("client_credentials") + AuthorizationFlow.IMPLICIT_FLOW: + await _start_login_process("token") + AuthorizationFlow.DEVICE_CODE_FLOW: + await _start_device_login_process() + + login_in_process = false + _login_timeout_timer.stop() + return true + + +func _got_scopes_changed() -> bool: + if not check_scope_changed: return false + + var existing_scopes = token_handler.get_scopes() + var requested_scopes = scopes.used_scopes + if existing_scopes.size() != requested_scopes.size(): + return true + + for scope in existing_scopes: + if requested_scopes.find(scope) == -1: + return true + + return false + + +## Called when the login process is timing out cause of misconfiguration or other natural catastrophes. +func _on_login_timeout() -> void: + if token_handler.is_token_valid(): return + logError("Login run into a timeout. Stop all login processes.") + _auth_succeed.emit("") + token_handler.token_resolved.emit(null) + + +func _start_login_process(response_type: String) -> void: + if scopes == null: scopes = OAuthScopes.new() + + _auth_http_server.start_listening() + + if response_type == "code": + _auth_http_server.request_received.connect(_process_code_request.bind(_auth_http_server)) + elif response_type == "token": + _auth_http_server.request_received.connect(_process_implicit_request.bind(_auth_http_server)) + + _current_state = _crypto.generate_random_bytes(16).hex_encode() + var query_param = "&".join([ + "force_verify=%s" % force_verify.uri_encode(), + "response_type=%s" % response_type.uri_encode(), + "client_id=%s" % oauth_setting.client_id.uri_encode(), + "scope=%s" % scopes.ssv_scopes().uri_encode(), + "redirect_uri=%s" % oauth_setting.redirect_url.uri_encode(), + "state=%s" % _current_state + ]) + + var url = oauth_setting.authorization_url + "?" + query_param + logInfo("start login process to get token for scopes %s" % (",".join(scopes.used_scopes))) + logDebug("login to %s" % url) + if not shell_command.is_empty(): + var parameters: PackedStringArray = shell_parameter.duplicate() \ + .map(func(param: String): return param.format({"url": url})) + OS.create_process(shell_command, parameters) + else: + OS.shell_open(url) + + logDebug("waiting for user to login.") + if response_type == "code": + var auth_code = await _auth_succeed + if auth_code == "": + logDebug("Auth code was empty. Abort Login.") + return + token_handler.request_token("authorization_code", auth_code) + await token_handler.token_resolved + _auth_http_server.request_received.disconnect(_process_code_request.bind(_auth_http_server)) + elif response_type == "token": + await token_handler.token_resolved + _auth_http_server.request_received.disconnect(_process_implicit_request.bind(_auth_http_server)) + logInfo("authorization is done stop server") + _auth_http_server.stop_listening() + +#region DeviceCodeFlow + + +## Starts the device flow. +func _start_device_login_process(): + var scopes = scopes.used_scopes + var device_code_response = await _fetch_device_code_response(scopes) + device_code_requested.emit(device_code_response) + + # print the information instead of opening the browser so that the developer can decide if + # he want to open the browser manually. Also use print not the logger so that the information + # is sent always. + print("Visit %s and enter the code %s for authorization." % [device_code_response.verification_uri, device_code_response.user_code]) + await token_handler.request_device_token(device_code_response, scopes) + + +func _fetch_device_code_response(scopes: String) -> OAuthDeviceCodeResponse: + logInfo("Start device code flow") + logDebug("Request Scopes: %s" % scopes) + var body = "client_id=%s&scopes=%s" % [oauth_setting.client_id, scopes.uri_encode()] + var request = _client.request(oauth_setting.device_authorization_url, HTTPClient.METHOD_POST, { + "Content-Type": "application/x-www-form-urlencoded" + }, body) + + var initial_response_data = await _client.wait_for_request(request) + if initial_response_data.response_code != 200: + logError("Couldn't initiate device code flow response code %s" % initial_response_data.response_code) + var initial_response_string = initial_response_data.response_data.get_string_from_ascii() + var initial_response_dict = JSON.parse_string(initial_response_string) as Dictionary + return OAuthDeviceCodeResponse.new(initial_response_dict) + +#endregion +#region ImplicitFlow + +## Handles the response after auth endpoint redirects to our server with the response +func _process_implicit_request(client: OAuthHTTPServer.Client, server: OAuthHTTPServer) -> void: + var request = client.peer.get_utf8_string(client.peer.get_available_bytes()) + if request == "": + logError("Empty response. Check if your redirect URL is set to %s." % oauth_setting.redirect_url) + client.peer.disconnect_from_host() + return + + var first_linebreak = request.find("\n") + var first_line = request.substr(0, first_linebreak) + if first_line.begins_with("GET"): + var matcher = _query_parser.search(first_line) + if matcher == null: + logDebug("Response from auth server was not right expected redirect url. It's ok browser asked probably for favicon etc.") + return + var redirect_path = oauth_setting.redirect_path + var request_path = matcher.get_string(1) + if redirect_path == request_path: + server.send_response(client, "200 OK", ("Login + + Redirect Token to Godot + ").to_utf8_buffer()) + logInfo("Send Response to send it via POST") + elif first_line.begins_with("POST"): + var parts = request.split("\r\n\r\n") + if parts.size() < 2: + return # Not a valid request + var json_body = parts[1] + var token_request = JSON.parse_string(json_body) + token_handler.update_tokens(token_request["access_token"]) + logInfo("Received Access Token update it") + server.send_response(client, "200 OK", "LoginSuccess!".to_utf8_buffer()) + +#endregion +#region AuthCodeFlow +## Handles the response after auth endpoint redirects to our server with the response +func _process_code_request(client: OAuthHTTPServer.Client, server: OAuthHTTPServer) -> void: + if client.peer.get_status() != StreamPeerTCP.STATUS_CONNECTED: + logError("Client not connected can't process code response.") + return + + var request = client.peer.get_utf8_string(client.peer.get_available_bytes()) + if request == "": + logError("Empty response. Check if your redirect URL is set to %s." % oauth_setting.redirect_url) + client.peer.disconnect_from_host() + return + + # Firstline contains request path and parameters + var first_line = request.substr(0, request.find("\n")) + var matcher = _query_parser.search(first_line) + if matcher == null: + logDebug("Response from auth server was not right expected query params. It's ok browser asked probably for favicon etc.") + client.peer.disconnect_from_host() + return + + var query_params_str = matcher.get_string(2) + var query_params = parse_query(query_params_str) + + var state = query_params.get("state") + if query_params.has("error"): + _handle_error(server, client, query_params) + elif state == _current_state: + _handle_success(server, client, query_params) + else: + _handle_other_requests(server, client, first_line) + client.peer.disconnect_from_host() + + +## Returns the response for the given auth request back to the browser also emits the auth code +func _handle_success(server: OAuthHTTPServer, client: OAuthHTTPServer.Client, query_params : Dictionary) -> void: + logInfo("Authentication success. Send auth code.") + if query_params.has("code"): + var succes_page = FileAccess.get_file_as_bytes("res://addons/twitcher/assets/success-page.txt") + server.send_response(client, "200 OK", succes_page) + _auth_succeed.emit(query_params['code']) + else: + var error_page = FileAccess.get_file_as_bytes("res://addons/twitcher/assets/error-page.txt") + server.send_response(client, "200 OK", error_page) + logError("Auth code expected wasn't send!") + + +## Handles the error in case that Auth API has a problem +func _handle_error(server: OAuthHTTPServer, client: OAuthHTTPServer.Client, query_params : Dictionary) -> void: + var msg = "Error %s: %s" % [query_params["error"], query_params["error_description"]] + logError(msg) + server.send_response(client, "400 BAD REQUEST", msg.to_utf8_buffer()) + +#endregion + +func _handle_other_requests(server: OAuthHTTPServer, client: OAuthHTTPServer.Client, fist_line: String) -> void: + if fist_line.contains("favicon.ico"): + var favicon: PackedByteArray = FileAccess.get_file_as_bytes("res://addons/twitcher/assets/favicon.ico") + server.send_response(client, "200", favicon) + + +## Parses a query string and returns a dictionary with the parameters. +static func parse_query(query: String) -> Dictionary: + var parameters = Dictionary() + # Split the query by '&' to separate different parameters. + var pairs = query.split("&") + # Iterate over each pair of key-value. + for pair in pairs: + # Split the pair by '=' to separate the key from the value. + var kv = pair.split("=") + if kv.size() == 2: + var key = kv[0].strip_edges() + var value = kv[1].strip_edges() + var decoded_key = key.uri_decode() + var decoded_value = value.uri_decode() + parameters[decoded_key] = decoded_value + return parameters + + +# === LOGGER === +static var logger: Dictionary = {} +static func set_logger(error: Callable, info: Callable, debug: Callable) -> void: + logger.debug = debug + logger.info = info + logger.error = error + OAuthTokenHandler.set_logger(error, info, debug) + +static func logDebug(text: String) -> void: + if logger.has("debug"): logger.debug.call(text) + +static func logInfo(text: String) -> void: + if logger.has("info"): logger.info.call(text) + +static func logError(text: String) -> void: + if logger.has("error"): logger.error.call(text) diff --git a/addons/twitcher/lib/oOuch/oauth.gd.uid b/addons/twitcher/lib/oOuch/oauth.gd.uid new file mode 100644 index 0000000..21cc596 --- /dev/null +++ b/addons/twitcher/lib/oOuch/oauth.gd.uid @@ -0,0 +1 @@ +uid://bf0wi70haua35 diff --git a/addons/twitcher/lib/oOuch/oauth_device_code_response.gd b/addons/twitcher/lib/oOuch/oauth_device_code_response.gd new file mode 100644 index 0000000..a469c69 --- /dev/null +++ b/addons/twitcher/lib/oOuch/oauth_device_code_response.gd @@ -0,0 +1,16 @@ +extends RefCounted + +## Response of the inital device code request + +var device_code: String; +var expires_in: int; +var interval: int; +var user_code: String; +var verification_uri: String; + +func _init(json: Dictionary): + device_code = json["device_code"]; + expires_in = int(json["expires_in"]); + interval = int(json["interval"]); + user_code = json["user_code"]; + verification_uri = json["verification_uri"]; diff --git a/addons/twitcher/lib/oOuch/oauth_device_code_response.gd.uid b/addons/twitcher/lib/oOuch/oauth_device_code_response.gd.uid new file mode 100644 index 0000000..cd39058 --- /dev/null +++ b/addons/twitcher/lib/oOuch/oauth_device_code_response.gd.uid @@ -0,0 +1 @@ +uid://doqj7o6fwi8dp diff --git a/addons/twitcher/lib/oOuch/oauth_scopes.gd b/addons/twitcher/lib/oOuch/oauth_scopes.gd new file mode 100644 index 0000000..21f946e --- /dev/null +++ b/addons/twitcher/lib/oOuch/oauth_scopes.gd @@ -0,0 +1,31 @@ +@icon("./scope-icon.svg") +@tool +extends Resource + +## Contains the information about a set of scopes. +class_name OAuthScopes + +## Called when new scopes was added or removed +signal scopes_changed + +@export var used_scopes: Array[StringName] = []: + set(val): + used_scopes = val; + scopes_changed.emit() + + +## Returns the scopes space separated +func ssv_scopes() -> String: + return " ".join(used_scopes) + + +func add_scopes(scopes: Array[StringName]) -> void: + for scope in scopes: + if used_scopes.find(scope) != -1: continue + used_scopes.append(scope) + scopes_changed.emit() + + +func remove_scopes(scopes: Array[StringName]) -> void: + used_scopes = used_scopes.filter(func(s): return scopes.find(s) != -1) + scopes_changed.emit() diff --git a/addons/twitcher/lib/oOuch/oauth_scopes.gd.uid b/addons/twitcher/lib/oOuch/oauth_scopes.gd.uid new file mode 100644 index 0000000..11cc80f --- /dev/null +++ b/addons/twitcher/lib/oOuch/oauth_scopes.gd.uid @@ -0,0 +1 @@ +uid://dexweyb521tu0 diff --git a/addons/twitcher/lib/oOuch/oauth_setting.gd b/addons/twitcher/lib/oOuch/oauth_setting.gd new file mode 100644 index 0000000..754f790 --- /dev/null +++ b/addons/twitcher/lib/oOuch/oauth_setting.gd @@ -0,0 +1,112 @@ +@icon("./scope-icon.svg") +@tool +extends Resource +class_name OAuthSetting + + +## That will be called when the authcode was received to send the code to the backend +@export var redirect_url: String = "http://localhost:7170": + set = _update_redirect_url +## Wellknown endpoint to receive the common paths for the IAM provider (optional) +@export var well_known_url: String +## Path where tokens can be get +@export var token_url: String +## Path to the authorization endpoint +@export var authorization_url: String +## Path to the device code flow URL. +@export var device_authorization_url: String +## Where should the tokens be cached +@export var cache_file: String = "res://auth.key" +## Client ID to authorize +@export var client_id: String: + set(val): + client_id = val + emit_changed() +## Defines the authorization flow. +@export var authorization_flow: OAuth.AuthorizationFlow = OAuth.AuthorizationFlow.AUTHORIZATION_CODE_FLOW: + set(val): + authorization_flow = val + notify_property_list_changed() + emit_changed() + +@export var _encryption_key_provider: CryptoKeyProvider = preload("res://addons/twitcher/lib/oOuch/default_key_provider.tres") + +# Calculated Values +var redirect_path: String: + get(): + if redirect_path == "" and redirect_url != "": _update_redirect_url(redirect_url) + return redirect_path +var redirect_port: int: + get(): + if redirect_port == 0 and redirect_url != "": _update_redirect_url(redirect_url) + return redirect_port + +## Client Secret to authorize (optional depending on flow) +@export_storage var client_secret: String: + set(val): + client_secret = val if val != null || val != "" else "" + emit_changed() + + +var _crypto: Crypto = Crypto.new() + +var _well_known_setting: Dictionary + +var _url_regex = RegEx.create_from_string("((https?://)?([^:/]+))(:([0-9]+))?(/.*)?") + + +func _update_redirect_url(value: String) -> void: + redirect_url = value; + var matches = _url_regex.search(value) + if matches == null: + redirect_path = "/" + redirect_port = 7170 + emit_changed() + return + + var path = matches.get_string(6) + var port = matches.get_string(5) + redirect_path = path if path != "" else "/" + redirect_port = int(port) if port != "" else 7170 + emit_changed() + + +func get_client_secret() -> String: + if client_secret == "" || client_secret == null: return "" + var value_raw = Marshalls.base64_to_raw(client_secret) + var value_bytes := _encryption_key_provider.decrypt(value_raw) + return value_bytes.get_string_from_utf8() + + +func set_client_secret(plain_secret: String) -> void: + var encrypted_value := _encryption_key_provider.encrypt(plain_secret.to_utf8_buffer()) + client_secret = Marshalls.raw_to_base64(encrypted_value) + + +func _validate_property(property: Dictionary) -> void: + if property.name == "client_secret": + if _is_client_secret_need(): + property.usage |= PROPERTY_USAGE_READ_ONLY + else: + property.usage &= ~PROPERTY_USAGE_READ_ONLY + + +func _is_client_secret_need() -> bool: + return authorization_flow == OAuth.AuthorizationFlow.AUTHORIZATION_CODE_FLOW || \ + authorization_flow == OAuth.AuthorizationFlow.CLIENT_CREDENTIALS + + +func is_valid() -> bool: + var problems = get_valididation_problems() + return problems.is_empty() + + +func get_valididation_problems() -> PackedStringArray: + var result: PackedStringArray = [] + if client_id == "" || client_id == null: + result.append("Client ID is missing") + if _is_client_secret_need() && (client_secret == "" || client_secret == null): + result.append("Client Secret is missing") + return result + + diff --git a/addons/twitcher/lib/oOuch/oauth_setting.gd.uid b/addons/twitcher/lib/oOuch/oauth_setting.gd.uid new file mode 100644 index 0000000..4a53d49 --- /dev/null +++ b/addons/twitcher/lib/oOuch/oauth_setting.gd.uid @@ -0,0 +1 @@ +uid://00xbijwpi8xa diff --git a/addons/twitcher/lib/oOuch/oauth_setting_inspector.gd b/addons/twitcher/lib/oOuch/oauth_setting_inspector.gd new file mode 100644 index 0000000..d99aade --- /dev/null +++ b/addons/twitcher/lib/oOuch/oauth_setting_inspector.gd @@ -0,0 +1,115 @@ +@tool +extends EditorInspectorPlugin + +const BufferedHttpClient = preload("res://addons/twitcher/lib/http/buffered_http_client.gd") +const EncryptionKeyProvider: CryptoKeyProvider = preload("res://addons/twitcher/lib/oOuch/default_key_provider.tres") + + +func _can_handle(object: Object) -> bool: + return object is OAuthSetting + + +func _parse_property(object: Object, type: Variant.Type, name: String, hint_type: PropertyHint, hint_string: String, usage_flags: int, wide: bool) -> bool: + if name == "well_known_url": + add_property_editor("well_known_url", WellKnownUriProperty.new()) + return true + if name == "client_id": + add_property_editor("client_secret", SecretProperty.new(), true, "Client Secret") + return false + + +class SecretProperty extends EditorProperty: + var _line_edit: LineEdit = LineEdit.new() + + + func _init() -> void: + _line_edit.secret = true + _line_edit.text_submitted.connect(_on_text_changed) + _line_edit.focus_exited.connect(_on_focus_exited) + add_child(_line_edit) + add_focusable(_line_edit) + + + func _update_property() -> void: + var secret = get_edited_object()[get_edited_property()] + + if secret == "": _line_edit.text = "" + var value_raw := Marshalls.base64_to_raw(secret) + var value_bytes := EncryptionKeyProvider.decrypt(value_raw) + _line_edit.text = value_bytes.get_string_from_utf8() + + + func _on_focus_exited() -> void: + _save() + + + func _on_text_changed(_new_text: String) -> void: + _save() + + + func _save() -> void: + var plain_value = _line_edit.text + if plain_value == "": + emit_changed(get_edited_property(), "") + return + var encrypted_value := EncryptionKeyProvider.encrypt(plain_value.to_utf8_buffer()) + emit_changed(get_edited_property(), Marshalls.raw_to_base64(encrypted_value)) + + +class WellKnownUriProperty extends EditorProperty: + var _url_regex = RegEx.create_from_string("((https?://)?([^:/]+))(:([0-9]+))?(/.*)?") + + var _container: VBoxContainer + var _well_known_url: LineEdit + var _submit: Button + var _client: BufferedHttpClient + + func _init() -> void: + _container = VBoxContainer.new() + _client = BufferedHttpClient.new() + _client.name = "OauthSettingInspectorClient" + add_child(_client) + + _well_known_url = LineEdit.new() + _well_known_url.placeholder_text = "https://id.twitch.tv/oauth2/.well-known/openid-configuration" + _well_known_url.text_changed.connect(_on_text_changed) + add_focusable(_well_known_url) + _container.add_child(_well_known_url) + + _submit = Button.new() + _submit.pressed.connect(_on_submit_clicked) + _submit.text = "Update URIs" + _container.add_child(_submit) + add_focusable(_submit) + add_child(_container) + + + func _on_text_changed(new_text: String) -> void: + emit_changed(get_edited_property(), new_text) + + + func _update_property() -> void: + _well_known_url.text = get_edited_object()[get_edited_property()] + + + func load_from_wellknown(wellknow_url: String) -> void: + var request = _client.request(wellknow_url, HTTPClient.METHOD_GET, {}, "") + var response = await _client.wait_for_request(request) as BufferedHttpClient.ResponseData + var json = JSON.parse_string(response.response_data.get_string_from_utf8()) + + var device_code = json.get("device_authorization_endpoint", "") + if device_code != "": + emit_changed(&"device_authorization_url", device_code) + var token_endpoint = json["token_endpoint"] + if token_endpoint != "": + emit_changed(&"token_url", token_endpoint) + var authorization_endpoint = json["authorization_endpoint"] + if authorization_endpoint != "": + emit_changed(&"authorization_url", authorization_endpoint) + + + func _on_submit_clicked() -> void: + _submit.disabled = true + var wellknownurl = _well_known_url.text if _well_known_url.text != "" else _well_known_url.placeholder_text + await load_from_wellknown(wellknownurl) + _submit.disabled = false diff --git a/addons/twitcher/lib/oOuch/oauth_setting_inspector.gd.uid b/addons/twitcher/lib/oOuch/oauth_setting_inspector.gd.uid new file mode 100644 index 0000000..d2d4d7b --- /dev/null +++ b/addons/twitcher/lib/oOuch/oauth_setting_inspector.gd.uid @@ -0,0 +1 @@ +uid://bi2tjog6pfa5a diff --git a/addons/twitcher/lib/oOuch/oauth_token.gd b/addons/twitcher/lib/oOuch/oauth_token.gd new file mode 100644 index 0000000..9b116e5 --- /dev/null +++ b/addons/twitcher/lib/oOuch/oauth_token.gd @@ -0,0 +1,141 @@ +@icon("./security-icon.svg") +@tool +extends Resource + +## Used to store and load token's and to exchange them through the code. +## Try to avoid debugging this object cause it leaks your access and refresh tokens +## Hint never store the token value as string in your code to reduce the chance +## to leak the tokens always use the getter. + +class_name OAuthToken + +static var CRYPTO: Crypto = Crypto.new() + +## Key for encryption purpose to save the tokens +@export var _crypto_key_provider: CryptoKeyProvider = preload("res://addons/twitcher/lib/oOuch/default_key_provider.tres") +## Unique identifier to store multiple tokens within one config file +@export var _identifier: String = "Auth-%s" % randi_range(0, 10000) +## Storage where the tokens should be saved encrypted (multiple secrets can be put in the same file see _identifier) +@export var _cache_path: String = "user://auth.conf": + set(val): + _cache_path = val + _load_tokens() + +var _scopes: PackedStringArray = [] +var _expire_date: int +var _config_file: ConfigFile = ConfigFile.new() + +var _access_token: String = "": + set(val): + _access_token = val + if val != "": authorized.emit() +var _refresh_token: String = "" + + +## Called when the token was resolved / accesstoken got refreshed +signal authorized + + +func update_values(access_token: String, refresh_token: String, expire_in: int, scopes: Array[String]): + _expire_date = roundi(Time.get_unix_time_from_system() + expire_in) + _access_token = access_token + _refresh_token = refresh_token + _scopes = scopes + _persist_tokens() + emit_changed() + + +## Persists the tokesn with the expire date +func _persist_tokens(): + var encrypted_access_token = _crypto_key_provider.encrypt(_access_token.to_utf8_buffer()) + var encrypted_refresh_token = _crypto_key_provider.encrypt(_refresh_token.to_utf8_buffer()) + _config_file.load(_cache_path) + _config_file.set_value(_identifier, "expire_date", _expire_date) + _config_file.set_value(_identifier, "access_token", Marshalls.raw_to_base64(encrypted_access_token)) + _config_file.set_value(_identifier, "refresh_token", Marshalls.raw_to_base64(encrypted_refresh_token)) + _config_file.set_value(_identifier, "scopes", ",".join(_scopes)) + var err = _config_file.save(_cache_path) + if err != OK: push_error("Couldn't save tokens cause of ", error_string(err)) + + +## Loads the tokens and returns the information if the file got created +func _load_tokens() -> bool: + var status = _config_file.load(_cache_path) + if status == OK && _config_file.has_section(_identifier): + _expire_date = _config_file.get_value(_identifier, "expire_date", 0) + var encrypted_access_token: PackedByteArray = Marshalls.base64_to_raw(_config_file.get_value(_identifier, "access_token")) + var encrypted_refresh_token: PackedByteArray = Marshalls.base64_to_raw(_config_file.get_value(_identifier, "refresh_token")) + _access_token = _crypto_key_provider.decrypt(encrypted_access_token).get_string_from_utf8() + _refresh_token = _crypto_key_provider.decrypt(encrypted_refresh_token).get_string_from_utf8() + _scopes = _config_file.get_value(_identifier, "scopes", "").split(",", false) + emit_changed() + return true + return false + + +func remove_tokens() -> void: + var status = _config_file.load(_cache_path) + if status == OK && _config_file.has_section(_identifier): + _access_token = "" + _refresh_token = "" + _expire_date = 0 + _scopes.clear() + + _config_file.erase_section(_identifier) + var err = _config_file.save(_cache_path) + if err != OK: push_error("Couldn't save tokens cause of ", error_string(err)) + emit_changed() + print("%s got revoked" % _identifier) + else: + print("%s not found" % _identifier) + + +func get_refresh_token() -> String: + return _refresh_token + + +func get_access_token() -> String: + if not is_token_valid(): await authorized + return _access_token + + +func get_scopes() -> PackedStringArray: + return _scopes + + +## The unix timestamp when the token is expiring +func get_expiration() -> int: + return _expire_date + + +func get_expiration_readable() -> String: + if _expire_date == 0: + return "Not available" + return Time.get_datetime_string_from_unix_time(_expire_date, true) + + +func invalidate() -> void: + _expire_date = 0 + _refresh_token = "" + _access_token = "" + _scopes = [] + emit_changed() + + +## Does this accesstoken has a refresh token +func has_refresh_token() -> bool: + return _refresh_token != "" && _refresh_token != null + + +## Checks if the access token is still valid +func is_token_valid() -> bool: + var current_time = Time.get_unix_time_from_system() + return current_time < _expire_date + + +## Get all token names within a config file +static func get_identifiers(cache_file: String) -> PackedStringArray: + var _config_file: ConfigFile = ConfigFile.new() + var status = _config_file.load(cache_file) + if status != OK: return [] + return _config_file.get_sections() diff --git a/addons/twitcher/lib/oOuch/oauth_token.gd.uid b/addons/twitcher/lib/oOuch/oauth_token.gd.uid new file mode 100644 index 0000000..64572cf --- /dev/null +++ b/addons/twitcher/lib/oOuch/oauth_token.gd.uid @@ -0,0 +1 @@ +uid://b52xp7c23ucfk diff --git a/addons/twitcher/lib/oOuch/oauth_token_handler.gd b/addons/twitcher/lib/oOuch/oauth_token_handler.gd new file mode 100644 index 0000000..323c7be --- /dev/null +++ b/addons/twitcher/lib/oOuch/oauth_token_handler.gd @@ -0,0 +1,245 @@ +@icon("./security-icon.svg") +@tool +extends Node + +class_name OAuthTokenHandler + +const OAuthHTTPClient = preload("res://addons/twitcher/lib/http/buffered_http_client.gd") +const OAuthDeviceCodeResponse = preload("./oauth_device_code_response.gd") + +## Handles refreshing and resolving access and refresh tokens. + +const HEADERS = { + "Accept": "*/*", + "Content-Type": "application/x-www-form-urlencoded" +} +const SECONDS_TO_CHECK_EARLIER = 60 + +## Called when new access token is available +signal token_resolved(tokens: OAuthToken) + +## Called when token can't be refreshed cause auth was removed or refresh token expired +signal unauthenticated() + +## Where to get the tokens from +@export var oauth_setting: OAuthSetting + +## Holds the current set of tokens +@export var token: OAuthToken: set = _update_token + +## Client to request new tokens +var _http_client : OAuthHTTPClient + +## Is currently requesting tokens +var _requesting_token: bool = false + +## Timer to refresh tokens +var _expiration_check_timer: Timer + +func _ready() -> void: + _http_client = OAuthHTTPClient.new() + _http_client.name = "OAuthTokenClient" + add_child(_http_client) + + _expiration_check_timer = Timer.new() + _expiration_check_timer.name = "ExpirationCheck" + _expiration_check_timer.timeout.connect(refresh_tokens) + add_child(_expiration_check_timer) + update_expiration_check() + + +func _enter_tree() -> void: + if not is_instance_valid(token): + token = OAuthToken.new() + else: + token.changed.connect(update_expiration_check) + + +func _exit_tree() -> void: + if is_instance_valid(token): + token.changed.disconnect(update_expiration_check) + + +func _update_token(val: OAuthToken) -> void: + if is_instance_valid(token) and is_inside_tree(): + token.changed.disconnect(update_expiration_check) + token = val + if is_instance_valid(token) and is_inside_tree(): + token.changed.connect(update_expiration_check) + + +func update_expiration_check() -> void: + var current_time = Time.get_unix_time_from_system() + var expiration = token.get_expiration() + if expiration == 0: + _expiration_check_timer.stop() + return + _expiration_check_timer.start(expiration - current_time - SECONDS_TO_CHECK_EARLIER) + logDebug("Refresh token (%s) in %s seconds" % [token._identifier, roundf(_expiration_check_timer.wait_time)]) + + +## Checks if tokens expires and starts refreshing it. (called often hold footprintt small) +func _check_token_refresh() -> void: + if _requesting_token: return + + if token_needs_refresh(): + logInfo("Token (%s) needs refresh" % token._identifier) + refresh_tokens() + + +## Requests the tokens +func request_token(grant_type: String, auth_code: String = ""): + if _requesting_token: return + _requesting_token = true + logInfo("Request token (for %s) via '%s'" % [token._identifier, grant_type]) + var request_params = [ + "grant_type=%s" % grant_type, + "client_id=%s" % oauth_setting.client_id, + "client_secret=%s" % oauth_setting.get_client_secret() + ] + + if auth_code != "": + request_params.append("code=%s" % auth_code) + if grant_type == "authorization_code": + request_params.append("&redirect_uri=%s" % oauth_setting.redirect_url) + + var request_body = "&".join(request_params) + var request = _http_client.request(oauth_setting.token_url, HTTPClient.METHOD_POST, HEADERS, request_body) + await _handle_token_request(request) + _requesting_token = false + + +func request_device_token(device_code_repsonse: OAuthDeviceCodeResponse, scopes: String, grant_type: String = "urn:ietf:params:oauth:grant-type:device_code") -> void: + if _requesting_token: return + _requesting_token = true + logInfo("request token (for %s) via urn:ietf:params:oauth:grant-type:device_code" % token._identifier) + var parameters = [ + "client_id=%s" % oauth_setting.client_id, + "grant_type=%s" % grant_type, + "device_code=%s" % device_code_repsonse.device_code, + "scopes=%s" % scopes + ] + + var request_body = "&".join(parameters) + + # Time when the code is expired and we don't poll anymore + var expire_data = Time.get_unix_time_from_system() + device_code_repsonse.expires_in + + while expire_data > Time.get_unix_time_from_system(): + var request = _http_client.request(oauth_setting.token_url, HTTPClient.METHOD_POST, HEADERS, request_body) + var response = await _http_client.wait_for_request(request) + var response_string: String = response.response_data.get_string_from_utf8() + var response_data = JSON.parse_string(response_string) + if response.response_code == 200: + _update_tokens_from_response(response_data) + _requesting_token = false + return + elif response.response_code == 400 && response_string.contains("authorization_pending"): + # Awaits for this amount of time until retry + await get_tree().create_timer(device_code_repsonse.interval, true, false, true).timeout + elif response.response_code == 400: + unauthenticated.emit() + _requesting_token = false + return + + # Handle Timeout + unauthenticated.emit() + _requesting_token = false + + +## Uses the refresh token if possible to refresh all tokens +func refresh_tokens() -> void: + if not oauth_setting.is_valid(): + logDebug("Try to refresh token (%s) but oauth settings are invalid. Can't refresh token." % token._identifier) + return + + if _requesting_token: return + _requesting_token = true + logInfo("use refresh (%s) token" % token._identifier) + if token.has_refresh_token(): + var request_body = "client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token" % [oauth_setting.client_id, oauth_setting.get_client_secret(), token.get_refresh_token()] + var request = _http_client.request(oauth_setting.token_url, HTTPClient.METHOD_POST, HEADERS, request_body) + if await _handle_token_request(request): + logInfo("token (%s) got refreshed" % token._identifier) + else: + unauthenticated.emit() + else: + unauthenticated.emit() + _requesting_token = false + + +## Gets information from the response and update values returns true when success otherwise false +func _handle_token_request(request: OAuthHTTPClient.RequestData) -> bool: + var response = await _http_client.wait_for_request(request) + var response_string = response.response_data.get_string_from_utf8() + var result = JSON.parse_string(response_string) + if response.response_code == 200: + _update_tokens_from_response(result) + return true + else: + # Reset expiration cause token wasn't refreshed correctly. + token.invalidate() + logError("token (for %s) could not be fetched ResponseCode %s / Body %s" % [token._identifier, response.response_code, response_string]) + return false + + +func _update_tokens_from_response(result: Dictionary): + var scopes: Array[String] = [] + for scope in result.get("scope", []): scopes.append(scope) + + update_tokens(result["access_token"], \ + result.get("refresh_token", ""), \ + result.get("expires_in", -1), \ + scopes) + + +## Updates the token. Result is the response data of an token request. +func update_tokens(access_token: String, refresh_token: String = "", expires_in: int = -1, scopes: Array[String] = []): + token.update_values(access_token, refresh_token, expires_in, scopes) + token_resolved.emit(token) + logInfo("token (%s) resolved" % token._identifier) + + +func get_token_expiration() -> String: + return Time.get_datetime_string_from_unix_time(token._expire_date) + + +## Checks if the token are valud +func is_token_valid() -> bool: + return token.is_token_valid() + + +## Checks if the token is expired and can be refreshed +func token_needs_refresh() -> bool: + return !token.is_token_valid() && token.has_refresh_token() + + +func get_access_token() -> String: return await token.get_access_token() + + +func has_refresh_token() -> bool: return token.has_refresh_token() + + +func get_scopes() -> PackedStringArray: return token.get_scopes() + + +# === LOGGER === +static var logger: Dictionary = {} + + +static func set_logger(error: Callable, info: Callable, debug: Callable) -> void: + logger.debug = debug + logger.info = info + logger.error = error + + +static func logDebug(text: String) -> void: + if logger.has("debug"): logger.debug.call(text) + + +static func logInfo(text: String) -> void: + if logger.has("info"): logger.info.call(text) + + +static func logError(text: String) -> void: + if logger.has("error"): logger.error.call(text) diff --git a/addons/twitcher/lib/oOuch/oauth_token_handler.gd.uid b/addons/twitcher/lib/oOuch/oauth_token_handler.gd.uid new file mode 100644 index 0000000..d95df45 --- /dev/null +++ b/addons/twitcher/lib/oOuch/oauth_token_handler.gd.uid @@ -0,0 +1 @@ +uid://bsfi3u26qkfrc diff --git a/addons/twitcher/lib/oOuch/oauth_token_info.gd b/addons/twitcher/lib/oOuch/oauth_token_info.gd new file mode 100644 index 0000000..2c3d7ea --- /dev/null +++ b/addons/twitcher/lib/oOuch/oauth_token_info.gd @@ -0,0 +1,87 @@ +@tool +extends Node + +signal revoked + +@export var token: OAuthToken: set = _update_token + +@onready var title: Label = %Title +@onready var token_valid_value: Label = %TokenValidValue +@onready var refresh_token_value: CheckBox = %RefreshTokenValue +@onready var token_scope_value: Node = %TokenScopeValue +@onready var reload_button: Button = %ReloadButton +@onready var revoke_button: Button = %RevokeButton + + +func _ready() -> void: + if token == null: + _reset_token() + return + update_token_view() + revoke_button.pressed.connect(_on_revoke_pressed) + reload_button.pressed.connect(_on_reload_pressed) + + +func _enter_tree() -> void: + if is_instance_valid(token): + token.changed.connect(_on_token_changed) + + +func _exit_tree() -> void: + if is_instance_valid(token): + token.changed.disconnect(_on_token_changed) + + +func _update_token(val: OAuthToken) -> void: + if is_instance_valid(token): + token.changed.disconnect(_on_token_changed) + token = val + if is_instance_valid(token) and is_inside_tree(): + token.changed.connect(_on_token_changed) + + +func update_token_view() -> void: + title.text = token._identifier + token_valid_value.text = token.get_expiration_readable() + if token.is_token_valid(): + token_valid_value.add_theme_color_override(&"font_color", Color.GREEN) + else: + token_valid_value.add_theme_color_override(&"font_color", Color.RED) + + if token.has_refresh_token(): + refresh_token_value.text = "Available" + refresh_token_value.add_theme_color_override(&"font_color", Color.GREEN) + refresh_token_value.button_pressed = true + else: + refresh_token_value.text = "Not Available" + refresh_token_value.add_theme_color_override(&"font_color", Color.YELLOW) + refresh_token_value.button_pressed = false + + for scope in token.get_scopes(): + var scope_name = Label.new() + scope_name.text = scope + token_scope_value.add_child(scope_name) + revoke_button.disabled = false + + +func _on_revoke_pressed() -> void: + token.remove_tokens() + _reset_token() + + +func _on_reload_pressed() -> void: + _reset_token() + token._load_tokens() + + +func _reset_token() -> void: + title.text = "" + token_valid_value.text = "" + refresh_token_value.button_pressed = false + revoke_button.disabled = true + for child in token_scope_value.get_children(): + child.queue_free() + + +func _on_token_changed() -> void: + update_token_view() diff --git a/addons/twitcher/lib/oOuch/oauth_token_info.gd.uid b/addons/twitcher/lib/oOuch/oauth_token_info.gd.uid new file mode 100644 index 0000000..7839f63 --- /dev/null +++ b/addons/twitcher/lib/oOuch/oauth_token_info.gd.uid @@ -0,0 +1 @@ +uid://cht8c01quk1mb diff --git a/addons/twitcher/lib/oOuch/oauth_token_info.tscn b/addons/twitcher/lib/oOuch/oauth_token_info.tscn new file mode 100644 index 0000000..ea76995 --- /dev/null +++ b/addons/twitcher/lib/oOuch/oauth_token_info.tscn @@ -0,0 +1,67 @@ +[gd_scene load_steps=2 format=3 uid="uid://6d2jst8ga4le"] + +[ext_resource type="Script" uid="uid://cht8c01quk1mb" path="res://addons/twitcher/lib/oOuch/oauth_token_info.gd" id="1_xfn6u"] + +[node name="TokenInfo" type="MarginContainer"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/margin_left = 5 +theme_override_constants/margin_top = 5 +theme_override_constants/margin_right = 5 +theme_override_constants/margin_bottom = 5 +script = ExtResource("1_xfn6u") + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 2 + +[node name="Title" type="Label" parent="VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +theme_type_variation = &"HeaderLarge" + +[node name="GridContainer" type="GridContainer" parent="VBoxContainer"] +layout_mode = 2 +columns = 2 + +[node name="TokenValidTitle" type="Label" parent="VBoxContainer/GridContainer"] +layout_mode = 2 +text = "Token Valid:" + +[node name="TokenValidValue" type="Label" parent="VBoxContainer/GridContainer"] +unique_name_in_owner = true +layout_mode = 2 + +[node name="RefreshTokenTitle" type="Label" parent="VBoxContainer/GridContainer"] +layout_mode = 2 +text = "Refresh Token Available:" + +[node name="RefreshTokenValue" type="CheckBox" parent="VBoxContainer/GridContainer"] +unique_name_in_owner = true +layout_mode = 2 +disabled = true + +[node name="TokenScopeTitle" type="Label" parent="VBoxContainer/GridContainer"] +layout_mode = 2 +text = "Token Scope:" + +[node name="TokenScopeValue" type="VBoxContainer" parent="VBoxContainer/GridContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="ReloadButton" type="Button" parent="VBoxContainer/GridContainer"] +unique_name_in_owner = true +layout_mode = 2 +tooltip_text = "Reloads the token from file use to update the infos when the token was fetched by an application run." +text = "Reload Info" + +[node name="RevokeButton" type="Button" parent="VBoxContainer/GridContainer"] +unique_name_in_owner = true +layout_mode = 2 +tooltip_text = "Will remove the cached access token / refresh token to fetch a new one" +disabled = true +text = "Revoke Token" diff --git a/addons/twitcher/lib/oOuch/oauth_token_inspector.gd b/addons/twitcher/lib/oOuch/oauth_token_inspector.gd new file mode 100644 index 0000000..31b404e --- /dev/null +++ b/addons/twitcher/lib/oOuch/oauth_token_inspector.gd @@ -0,0 +1,13 @@ +@tool +extends EditorInspectorPlugin + +var token_info_scene: PackedScene = preload("res://addons/twitcher/lib/oOuch/oauth_token_info.tscn") + +func _can_handle(object: Object) -> bool: + return object is OAuthToken + + +func _parse_begin(object: Object) -> void: + var token_info = token_info_scene.instantiate() + token_info.token = object + add_custom_control(token_info) diff --git a/addons/twitcher/lib/oOuch/oauth_token_inspector.gd.uid b/addons/twitcher/lib/oOuch/oauth_token_inspector.gd.uid new file mode 100644 index 0000000..be12b4d --- /dev/null +++ b/addons/twitcher/lib/oOuch/oauth_token_inspector.gd.uid @@ -0,0 +1 @@ +uid://djylbydr6sh64 diff --git a/addons/twitcher/lib/oOuch/scope-icon.svg b/addons/twitcher/lib/oOuch/scope-icon.svg new file mode 100644 index 0000000..8e1e6b3 --- /dev/null +++ b/addons/twitcher/lib/oOuch/scope-icon.svg @@ -0,0 +1,64 @@ + + + + + + + + + diff --git a/addons/twitcher/lib/oOuch/scope-icon.svg.import b/addons/twitcher/lib/oOuch/scope-icon.svg.import new file mode 100644 index 0000000..6573a27 --- /dev/null +++ b/addons/twitcher/lib/oOuch/scope-icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bdu2sqj8cfh80" +path="res://.godot/imported/scope-icon.svg-760ec336caee34c24da7cfc19dbbd818.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/twitcher/lib/oOuch/scope-icon.svg" +dest_files=["res://.godot/imported/scope-icon.svg-760ec336caee34c24da7cfc19dbbd818.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/twitcher/lib/oOuch/security-icon.svg b/addons/twitcher/lib/oOuch/security-icon.svg new file mode 100644 index 0000000..b142ebc --- /dev/null +++ b/addons/twitcher/lib/oOuch/security-icon.svg @@ -0,0 +1,92 @@ + + + + + + + + + + diff --git a/addons/twitcher/lib/oOuch/security-icon.svg.import b/addons/twitcher/lib/oOuch/security-icon.svg.import new file mode 100644 index 0000000..a198bc7 --- /dev/null +++ b/addons/twitcher/lib/oOuch/security-icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://ctgrmafl803p0" +path="res://.godot/imported/security-icon.svg-8d6ec29771c7aa01a3aece2fa8908f4c.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://addons/twitcher/lib/oOuch/security-icon.svg" +dest_files=["res://.godot/imported/security-icon.svg-8d6ec29771c7aa01a3aece2fa8908f4c.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/addons/twitcher/logger/twitch_logger.gd b/addons/twitcher/logger/twitch_logger.gd new file mode 100644 index 0000000..64ed286 --- /dev/null +++ b/addons/twitcher/logger/twitch_logger.gd @@ -0,0 +1,62 @@ +@tool +extends RefCounted + +## Logger class that can be enabled and disabled. (Works best with tool scripts) +class_name TwitchLogger + +## Name of the logger that will be shown in the logs +var context_name: String +var suffix: String +var enabled : bool +var debug: bool +var color: String + + +func _init(ctx_name: String) -> void: + context_name = ctx_name + color = string_to_hex_color(ctx_name) + TwitchLoggerManager.register(self) + + +func is_enabled() -> bool: + return enabled + + +func set_enabled(status: bool) -> void: + enabled = status + + +func set_suffix(s: String) -> void: + suffix = "-" + s + + +## log a message on info level +func i(text: String): + if is_enabled(): print_rich("I[color=%s][%s%s] %s[/color]" % [color, context_name, suffix, text]) + #else: print(context_name, " is not enabled") + + +## log a message on error level +func e(text: String): + if is_enabled(): print_rich("E[b][color=%s][%s%s] %s[/color][/b]" % [color, context_name, suffix, text]) + #else: print(context_name, " is not enabled") + + +func d(text: String): + if is_enabled() && debug: print_rich("D[i][color=%s][%s%s] %s[/color][/i]" % [color, context_name, suffix, text]) + + +func string_to_hex_color(text: String) -> String: + # Hash the text to generate a unique integer + var hash_value = text.hash() + var r = hash_value & 0xFF + var g = (hash_value >> 8) & 0xFF + var b = (hash_value >> 16) & 0xFF + const brighten_factor = 1.5 + r = clamp(r * brighten_factor, 0, 255) + g = clamp(g * brighten_factor, 0, 255) + b = clamp(b * brighten_factor, 0, 255) + var red = "%02x" % r + var green = "%02x" % g + var blue = "%02x" % b + return "#" + red + green + blue diff --git a/addons/twitcher/logger/twitch_logger.gd.uid b/addons/twitcher/logger/twitch_logger.gd.uid new file mode 100644 index 0000000..084fc37 --- /dev/null +++ b/addons/twitcher/logger/twitch_logger.gd.uid @@ -0,0 +1 @@ +uid://dvxh6uhvwiuyj diff --git a/addons/twitcher/logger/twitch_logger_manager.gd b/addons/twitcher/logger/twitch_logger_manager.gd new file mode 100644 index 0000000..f81b963 --- /dev/null +++ b/addons/twitcher/logger/twitch_logger_manager.gd @@ -0,0 +1,16 @@ +@tool +extends RefCounted + +## Couples the logger to the enabled state of the settings. +class_name TwitchLoggerManager + +static var log_registry : Dictionary = {} + +## Register the logger and set the enabled state +static func register(logger: TwitchLogger) -> void: + log_registry[logger.context_name] = logger + var property = TwitchProperty.new("twitcher/logs/%s" % logger.context_name, "off").as_select(["off", "info", "debug"]) + if property.get_val() != "off": + logger.set_enabled(true) + if property.get_val() == "debug": + logger.debug = true diff --git a/addons/twitcher/logger/twitch_logger_manager.gd.uid b/addons/twitcher/logger/twitch_logger_manager.gd.uid new file mode 100644 index 0000000..dfcb91f --- /dev/null +++ b/addons/twitcher/logger/twitch_logger_manager.gd.uid @@ -0,0 +1 @@ +uid://tyuiry12mvky diff --git a/addons/twitcher/media/imagemagick/gif_importer_imagemagick.gd b/addons/twitcher/media/imagemagick/gif_importer_imagemagick.gd new file mode 100644 index 0000000..3530fcd --- /dev/null +++ b/addons/twitcher/media/imagemagick/gif_importer_imagemagick.gd @@ -0,0 +1,52 @@ +@tool +extends EditorImportPlugin + +class_name GifImporterImagemagick + +enum Presets { DEFAULT } + +func _get_importer_name() -> String: + return "kani_dev.imagemagick" + +func _get_visible_name() -> String: + return "SpriteFrames (ImageMagick)" + +func _get_recognized_extensions() -> PackedStringArray: + return ["gif", "webp"] + +func _get_save_extension() -> String: + return "res" + +func _get_resource_type() -> String: + return "SpriteFrames" + +func _get_priority() -> float: + return 100.0 + +func _get_preset_count() -> int: + return Presets.size() + +func _get_preset_name(preset_index: int) -> String: + return "Default" + +func _get_import_options(path: String, preset_index: int) -> Array[Dictionary]: + return [] + +func _get_import_order() -> int: + return 0 + +func _get_option_visibility(path: String, option_name: StringName, options: Dictionary) -> bool: + return true + +func _import(source_file: String, save_path: String, options: Dictionary, platform_variants: Array[String], gen_files: Array[String]) -> Error: + var dumper = ImageMagickConverter.new() + + var tex = await dumper.dump_and_convert(source_file, [], "") + if tex: + return ResourceSaver.save( + tex, + "%s.%s" % [save_path, _get_save_extension()], + ResourceSaver.SaverFlags.FLAG_COMPRESS + ) + push_error("failed to import %s" % source_file) + return OK; diff --git a/addons/twitcher/media/imagemagick/gif_importer_imagemagick.gd.uid b/addons/twitcher/media/imagemagick/gif_importer_imagemagick.gd.uid new file mode 100644 index 0000000..6660064 --- /dev/null +++ b/addons/twitcher/media/imagemagick/gif_importer_imagemagick.gd.uid @@ -0,0 +1 @@ +uid://chveatddlbp1x diff --git a/addons/twitcher/media/imagemagick/image_magick_converter.gd b/addons/twitcher/media/imagemagick/image_magick_converter.gd new file mode 100644 index 0000000..cc24ee6 --- /dev/null +++ b/addons/twitcher/media/imagemagick/image_magick_converter.gd @@ -0,0 +1,174 @@ +@tool +extends RefCounted + +class_name ImageMagickConverter + +static var _log: TwitchLogger = TwitchLogger.new("ImageMagickConverter") + +## Current conversion in progress (key: path | value: mutex) +var converting: Dictionary = {} +var fallback_texture: Texture2D = preload("res://addons/twitcher/assets/fallback_texture.tres") +## Path to the imagemagic executable for example 'magick' when its in windows path +var imagemagic_path: String + +static var delete_mutex: Mutex = Mutex.new() +static var folder_to_delete: Array[String] = [] + +## After that amount of files it starts to delete them +const DELETE_COUNT = 10 + +## Converts a packed byte array to a SpirteFrames and writes it out to the destination path +## +## The byte array must represent an animated gif, webp, or any imagemagick supported format +## it dumps it into a binary resource consisting of PNG frames. +## +## The resource is automatically added to the ResourceLoader cache as the input path value +func dump_and_convert(path: String, buffer_in: PackedByteArray = [], output = "%s.res" % path, parallel = false) -> SpriteFrames: + var thread: Thread = Thread.new() + var buffer: PackedByteArray = buffer_in.duplicate() + var mutex: Mutex + if parallel: + mutex = converting.get(path, Mutex.new()) + converting[path] = mutex + + var err = thread.start(_do_work.bind(path, buffer, output, mutex)) + assert(err == OK, "could not start thread") + + # don't block the main thread while loading + while not thread.is_started() or thread.is_alive(): + await Engine.get_main_loop().process_frame + + var tex: SpriteFrames = thread.wait_to_finish() + if parallel: + mutex.unlock() + converting.erase(path) + + if not output.is_empty(): + _save_converted_file(tex, output) + return tex + + +func _do_work(path: String, buffer: PackedByteArray, output: String, mutex: Mutex) -> SpriteFrames: + if mutex != null: + mutex.lock() + # load from cache if another thread already completed converting this same resource + if not output.is_empty() and ResourceLoader.has_cached(output): + return ResourceLoader.load(output) + + # dump the buffer + if FileAccess.file_exists(path): + _log.i("File found at %s, loading it instead of using the buffer." % path) + buffer = FileAccess.get_file_as_bytes(path) + else: + DirAccess.make_dir_recursive_absolute(path.get_base_dir()) + var f = FileAccess.open(path, FileAccess.WRITE) + if f == null: + _log.e("Can't open file %s cause of %s" %[ path, FileAccess.get_open_error()]) + f.store_buffer(buffer) + f.close() + + var frame_delays: Array[int] = _get_frame_delay(path) + var folder_path: String = _create_temp_filename() + if not _extract_images(path, folder_path): + return _create_fallback_texture() + var sprite_frames: SpriteFrames = _build_frames(folder_path, frame_delays) + if not output.is_empty(): + sprite_frames.take_over_path(output) + + # delete the temp directory + delete_mutex.lock() + folder_to_delete.append(folder_path) + delete_mutex.unlock() + + _cleanup() + return sprite_frames + + +## Saves the texture to the output path +func _save_converted_file(tex: SpriteFrames, output: String): + if not output.is_empty() and tex: + ResourceSaver.save(tex, output, ResourceSaver.SaverFlags.FLAG_COMPRESS) + tex.take_over_path(output) + + +func _create_unique_key(length: int = 8) -> String: + var uniq = "" + for i in range(length): + uniq += "%d" % [randi() % 10] + return uniq + + +## Creates a folder to store the extracted images (needs the / at the end!) +func _create_temp_filename() -> String: + var folder_path: String = "" + var uniq = _create_unique_key() + if Engine.is_editor_hint(): + folder_path = "res://.godot/magick_tmp/%s_%d/" % [uniq, Time.get_unix_time_from_system()] + else: + folder_path = "user://.magick_tmp/%s_%d/" % [uniq, Time.get_unix_time_from_system()] + + _log.i("Create temp folder") + DirAccess.make_dir_recursive_absolute(folder_path) + return folder_path + + +## Extracts all delays from the file in seconds +func _get_frame_delay(file: String) -> Array[int]: + var out = [] + var glob_path = ProjectSettings.globalize_path(file) + OS.execute(imagemagic_path, [ glob_path, "-format", "%T\\n", "info:" ], out) + var frame_delays: Array[int] = [] + for delay in out[0].split("\n"): + # convert x100 to x1000(ms) + frame_delays.append(delay.to_int() * 10) + return frame_delays + + +## Extracts all images from the file and saves them to folder path +func _extract_images(file: String, target_folder: String) -> bool: + var out = [] + var glob_file_path = ProjectSettings.globalize_path(file) + var glob_extracted_file_path = ProjectSettings.globalize_path(target_folder + "%04d.png") + var code = OS.execute(imagemagic_path, [ "convert", "-coalesce", glob_file_path, glob_extracted_file_path ], out, true) + if code != 0: + _log.e("unable to convert: %s" % "\n".join(out)) + return false + return true + + +func _create_fallback_texture(): + var sprite_frames = SpriteFrames.new() + sprite_frames.add_frame(&"default", fallback_texture) + return sprite_frames + + +func _build_frames(folder_path: String, frame_delays: Array[int]): + _log.i("Build Frames") + var frames = DirAccess.get_files_at(folder_path) + if len(frames) == 0: + return _create_fallback_texture() + + var sprite_frames: SpriteFrames = SpriteFrames.new() + for filepath in frames: + var idx = filepath.substr(0, filepath.rfind(".")).to_int() + var delay = frame_delays[idx] / 1000.0 + var image = Image.new() + var error = image.load(folder_path + filepath) + if error != OK: + return _create_fallback_texture() + + var frame = ImageTexture.create_from_image(image) + sprite_frames.add_frame(&"default", frame, delay) + sprite_frames.set_animation_speed(&"default", 1) + return sprite_frames + + +## Cleans after DELETE_COUNT amount of folder entries +func _cleanup(force: bool = false): + if folder_to_delete.size() % DELETE_COUNT == 0 || force: + delete_mutex.lock() + for folder in folder_to_delete: + var glob_folder = ProjectSettings.globalize_path(folder) + OS.move_to_trash(glob_folder) + folder_to_delete.clear() + delete_mutex.unlock() diff --git a/addons/twitcher/media/imagemagick/image_magick_converter.gd.uid b/addons/twitcher/media/imagemagick/image_magick_converter.gd.uid new file mode 100644 index 0000000..8c87f59 --- /dev/null +++ b/addons/twitcher/media/imagemagick/image_magick_converter.gd.uid @@ -0,0 +1 @@ +uid://dydhjmb7b0ob0 diff --git a/addons/twitcher/media/magic_image_transformer.gd b/addons/twitcher/media/magic_image_transformer.gd new file mode 100644 index 0000000..2dd70aa --- /dev/null +++ b/addons/twitcher/media/magic_image_transformer.gd @@ -0,0 +1,44 @@ +@icon("res://addons/twitcher/assets/media-loader-icon.svg") +@tool +extends TwitchImageTransformer + +## A image transformer that uses a thirdparty program called ImageMagick +## (https://imagemagick.org/script/download.php) to transform GIF's and similar files into +## SpriteFrames. Battleproof very stable but uses an external program. +class_name MagicImageTransformer + + +## Path to the imagemagick program on windows its normally just 'magick' when it is available in the PATH +@export_global_file var imagemagic_path: String: + set = update_imagemagic_path + +var supported: bool +var converter: ImageMagickConverter + +func is_supporting_animation() -> bool: + return true + + +func update_imagemagic_path(path: String) -> void: + if imagemagic_path == path: return + imagemagic_path = path + if imagemagic_path != "": + var out = [] + var err = OS.execute(imagemagic_path, ['-version'], out) + if err == OK: + converter = ImageMagickConverter.new() + converter.fallback_texture = fallback_texture + converter.imagemagic_path = imagemagic_path + _log.i("Imagemagic detected: %s use it to transform gif/webm" % [ imagemagic_path ]) + supported = true + return + _log.i("Imagemagic at '%s' path was not detected or has a wrong result code: %s \n %s" % [ imagemagic_path, err, "\n".join(out) ]) + supported = false + + +func is_supported() -> bool: + return supported + + +func convert_image(path: String, buffer_in: PackedByteArray, output_path: String) -> SpriteFrames: + return await converter.dump_and_convert(path, buffer_in, output_path) diff --git a/addons/twitcher/media/magic_image_transformer.gd.uid b/addons/twitcher/media/magic_image_transformer.gd.uid new file mode 100644 index 0000000..eacd9f8 --- /dev/null +++ b/addons/twitcher/media/magic_image_transformer.gd.uid @@ -0,0 +1 @@ +uid://dqd4kovdhhy8o diff --git a/addons/twitcher/media/native/GIF2SpriteFramesPlugin.gd b/addons/twitcher/media/native/GIF2SpriteFramesPlugin.gd new file mode 100644 index 0000000..c8afe25 --- /dev/null +++ b/addons/twitcher/media/native/GIF2SpriteFramesPlugin.gd @@ -0,0 +1,53 @@ +# Derived from https://github.com/jegor377/godot-gdgifexporter + +@tool +extends EditorImportPlugin + +class_name GifImporterNative + +enum Presets { DEFAULT } + +func _get_importer_name() -> String: + return "gif.animated.texture.plugin" + +func _get_visible_name() -> String: + return "Sprite Frames (Native)" + +func _get_recognized_extensions() -> PackedStringArray: + return ["gif"] + +func _get_save_extension() -> String: + return "res" + +func _get_resource_type() -> String: + return "SpriteFrames" + +func _get_priority() -> float: + return 90.0; + +func _get_preset_count() -> int: + return Presets.size() + +func _get_preset_name(preset_index: int) -> String: + return "Default" + +func _get_import_options(path: String, preset_index: int) -> Array[Dictionary]: + return [] + +func _get_import_order() -> int: + return 0 + +func _get_option_visibility(path: String, option_name: StringName, options: Dictionary) -> bool: + return true + +func _import(source_file: String, save_path: String, options: Dictionary, platform_variants: Array[String], gen_files: Array[String]) -> Error: + var reader = GifReader.new() + var tex = reader.read(source_file) + if tex == null: + return FAILED + var filename = save_path + "." + _get_save_extension() + return ResourceSaver.save( + tex, + "%s.%s" % [save_path, _get_save_extension()], + ResourceSaver.SaverFlags.FLAG_COMPRESS + ) diff --git a/addons/twitcher/media/native/GIF2SpriteFramesPlugin.gd.uid b/addons/twitcher/media/native/GIF2SpriteFramesPlugin.gd.uid new file mode 100644 index 0000000..74b424a --- /dev/null +++ b/addons/twitcher/media/native/GIF2SpriteFramesPlugin.gd.uid @@ -0,0 +1 @@ +uid://cr3b26x6lrmf6 diff --git a/addons/twitcher/media/native/GIFReader.gd b/addons/twitcher/media/native/GIFReader.gd new file mode 100644 index 0000000..977f5bf --- /dev/null +++ b/addons/twitcher/media/native/GIFReader.gd @@ -0,0 +1,128 @@ +@tool +extends RefCounted + +class_name GifReader + +var lzw_module = preload("./gif-lzw/lzw.gd") +var lzw = lzw_module.new() + +func read(source_file) -> SpriteFrames: + var file = FileAccess.open(source_file, FileAccess.READ) + if file == null: + return null + var data = file.get_buffer(file.get_length()) + file.close() + return load_gif(data) + +func load_gif(data): + var pos = 0 + # Header 'GIF89a' + pos = pos + 6 + # Logical Screen Descriptor + var width = get_int(data, pos) + var height = get_int(data, pos + 2) + var packed_info = data[pos + 4] + var background_color_index = data[pos + 5] + pos = pos + 7 + # Global color table + var global_lut + if (packed_info & 0x80) != 0: + var lut_size = 1 << (1 + (packed_info & 0x07)) + global_lut = get_lut(data, pos, lut_size) + pos = pos + 3 * lut_size + # Frames + var repeat = -1 + var img = Image.new() + var frame_number = 0 + var frame_delay = -1 + var frame_anim_packed_info = -1 + var frame_transparent_color = -1 + var sprite_frame = SpriteFrames.new() + + img = Image.create(width, height, false, Image.FORMAT_RGBA8) + while pos < data.size(): + if data[pos] == 0x21: # Extension block + var ext_type = data[pos + 1] + pos = pos + 2 # 21 xx ... + match ext_type: + 0xF9: # Graphic extension + var subblock = get_subblock(data, pos) + frame_anim_packed_info = subblock[0] + frame_delay = get_int(subblock, 1) + frame_transparent_color = subblock[3] + 0xFF: # Application extension + var subblock = get_subblock(data, pos) + if subblock != null and subblock.get_string_from_ascii() == "NETSCAPE2.0": + subblock = get_subblock(data, pos + 1 + subblock.size()) + repeat = get_int(subblock, 1) + _: # Miscelaneous extension + #print("extension ", data[pos + 1]) + pass + var block_len = 0 + while data[pos + block_len] != 0: + block_len = block_len + data[pos + block_len] + 1 + pos = pos + block_len + 1 + elif data[pos] == 0x2C: # Image data + var img_left = get_int(data, pos + 1) + var img_top = get_int(data, pos + 3) + var img_width = get_int(data, pos + 5) + var img_height = get_int(data, pos + 7) + var img_packed_info = get_int(data, pos + 9) + pos = pos + 10 + # Local color table + var local_lut = global_lut + if (img_packed_info & 0x80) != 0: + var lut_size = 1 << (1 + (img_packed_info & 0x07)) + local_lut = get_lut(data, pos, lut_size) + pos = pos + 3 * lut_size + # Image data + var min_code_size = data[pos] + pos = pos + 1 + var colors = [] + for i in range(0, 1 << min_code_size): + colors.append(i) + var block = PackedByteArray() + while data[pos] != 0: + block.append_array(data.slice(pos + 1, pos + data[pos] + 1)) + pos = pos + data[pos] + 1 + pos = pos + 1 + var decompressed = lzw.decompress_lzw(block, min_code_size, colors) + var disposal = (frame_anim_packed_info >> 2) & 7 # 1 = Keep, 2 = Clear + var transparency = frame_anim_packed_info & 1 + if disposal == 2: + if transparency == 0 and background_color_index != frame_transparent_color: + img.fill(local_lut[background_color_index]) + else: + img.fill(Color(0,0,0,0)) + var p = 0 + for y in range(0, img_height): + for x in range(0, img_width): + var c = decompressed[p] + if transparency == 0 or c != frame_transparent_color: + img.set_pixel(img_left + x, img_top + y, local_lut[c]) + p = p + 1 + var frame = ImageTexture.create_from_image(img); + sprite_frame.add_frame(&"default", frame, frame_delay / 100.0); + frame_anim_packed_info = -1 + frame_transparent_color = -1 + frame_delay = -1 + frame_number = frame_number + 1 + elif data[pos] == 0x3B: # Trailer + pos = pos + 1 + sprite_frame.set_animation_speed(&"default", 1); + return sprite_frame + +func get_subblock(data: PackedByteArray, pos): + if data[pos] == 0: + return null + else: + return data.slice(pos + 1, pos + data[pos] + 1) + +func get_lut(data, pos, size): + var colors = Array() + for i in range(0, size): + colors.append(Color(data[pos + i * 3] / 255.0, data[pos + 1 + i * 3] / 255.0, data[pos + 2 + i * 3] / 255.0)) + return colors + +func get_int(data, pos): + return data[pos] + (data[pos + 1] << 8) diff --git a/addons/twitcher/media/native/GIFReader.gd.uid b/addons/twitcher/media/native/GIFReader.gd.uid new file mode 100644 index 0000000..1e9b647 --- /dev/null +++ b/addons/twitcher/media/native/GIFReader.gd.uid @@ -0,0 +1 @@ +uid://m6k2g1678fpc diff --git a/addons/twitcher/media/native/README.md b/addons/twitcher/media/native/README.md new file mode 100644 index 0000000..bbc4572 --- /dev/null +++ b/addons/twitcher/media/native/README.md @@ -0,0 +1,2 @@ +# Known Bugs +- https://github.com/ImageMagick/ImageMagick/issues/4634 exists in this lib too. Images that are not correctly encoded makes problems diff --git a/addons/twitcher/media/native/gif-lzw/LICENSE b/addons/twitcher/media/native/gif-lzw/LICENSE new file mode 100644 index 0000000..ca5b2ad --- /dev/null +++ b/addons/twitcher/media/native/gif-lzw/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Igor Santarek + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/addons/twitcher/media/native/gif-lzw/lsbbitpacker.gd b/addons/twitcher/media/native/gif-lzw/lsbbitpacker.gd new file mode 100644 index 0000000..4656f4d --- /dev/null +++ b/addons/twitcher/media/native/gif-lzw/lsbbitpacker.gd @@ -0,0 +1,31 @@ +@tool +extends RefCounted + +class LSBLZWBitPacker: + var bit_index: int = 0 + var stream: int = 0 + + var chunks: PackedByteArray = PackedByteArray([]) + + func put_byte(): + chunks.append(stream & 0xff) + bit_index -= 8 + stream >>= 8 + + func write_bits(value: int, bits_count: int) -> void: + value &= (1 << bits_count) - 1 + value <<= bit_index + stream |= value + bit_index += bits_count + while bit_index >= 8: + put_byte() + + func pack() -> PackedByteArray: + if bit_index != 0: + put_byte() + return chunks + + func reset() -> void: + bit_index = 0 + stream = 0 + chunks = PackedByteArray([]) diff --git a/addons/twitcher/media/native/gif-lzw/lsbbitpacker.gd.uid b/addons/twitcher/media/native/gif-lzw/lsbbitpacker.gd.uid new file mode 100644 index 0000000..2b54c12 --- /dev/null +++ b/addons/twitcher/media/native/gif-lzw/lsbbitpacker.gd.uid @@ -0,0 +1 @@ +uid://rbrgncjo0m63 diff --git a/addons/twitcher/media/native/gif-lzw/lsbbitunpacker.gd b/addons/twitcher/media/native/gif-lzw/lsbbitunpacker.gd new file mode 100644 index 0000000..a728a4b --- /dev/null +++ b/addons/twitcher/media/native/gif-lzw/lsbbitunpacker.gd @@ -0,0 +1,44 @@ +@tool +extends RefCounted + +class LSBLZWBitUnpacker: + var chunk_stream: PackedByteArray + var bit_index: int = 0 + var byte: int + var byte_index: int = 0 + + func _init(_chunk_stream: PackedByteArray): + chunk_stream = _chunk_stream + get_byte() + + func get_bit(value: int, index: int) -> int: + return (value >> index) & 1 + + func set_bit(value: int, index: int) -> int: + return value | (1 << index) + + func get_byte(): + byte = chunk_stream[byte_index] + byte_index += 1 + bit_index = 0 + + func read_bits(bits_count: int) -> int: + var result: int = 0 + var result_bit_index: int = 0 + + for _i in range(bits_count): + if get_bit(byte, bit_index) == 1: + result = set_bit(result, result_bit_index) + result_bit_index += 1 + bit_index += 1 + + if chunk_stream.size() == byte_index && result_bit_index == bits_count: + return result; + + if bit_index == 8: + get_byte() + + return result + + func remove_bits(bits_count: int) -> void: + read_bits(bits_count) diff --git a/addons/twitcher/media/native/gif-lzw/lsbbitunpacker.gd.uid b/addons/twitcher/media/native/gif-lzw/lsbbitunpacker.gd.uid new file mode 100644 index 0000000..2793653 --- /dev/null +++ b/addons/twitcher/media/native/gif-lzw/lsbbitunpacker.gd.uid @@ -0,0 +1 @@ +uid://cjogpplbpf7hp diff --git a/addons/twitcher/media/native/gif-lzw/lzw.gd b/addons/twitcher/media/native/gif-lzw/lzw.gd new file mode 100644 index 0000000..d07626e --- /dev/null +++ b/addons/twitcher/media/native/gif-lzw/lzw.gd @@ -0,0 +1,213 @@ +@tool +extends RefCounted + +var lsbbitpacker = preload("./lsbbitpacker.gd") +var lsbbitunpacker = preload("./lsbbitunpacker.gd") + +class CodeEntry: + var sequence: PackedByteArray + var raw_array: PackedByteArray + + func _init(_sequence : PackedByteArray) -> void: + raw_array = _sequence + sequence = _sequence + + func add(other) -> CodeEntry: + return CodeEntry.new(raw_array + other.raw_array) + + func to_string() -> String: + var result: String = "" + for element in sequence: + result += str(element) + ", " + return result.substr(0, result.length() - 2) + + +class CodeTable: + var entries: Dictionary = {} + var counter: int = 0 + var lookup: Dictionary = {} + + func add(entry: CodeEntry) -> int: + entries[counter] = entry + lookup[entry.raw_array] = counter + counter += 1 + return counter + + func find(entry: CodeEntry) -> int: + return lookup.get(entry.raw_array, -1) + + func has_entry(entry: CodeEntry) -> bool: + return find(entry) != -1 + + func get_entry(index: int) -> CodeEntry: + return entries.get(index, null) + + func to_string() -> String: + var result: String = "CodeTable:\n" + for id in entries: + result += str(id) + ": " + entries[id].to_string() + "\n" + result += "Counter: " + str(counter) + "\n" + return result + + +func log2(value: float) -> float: + return log(value) / log(2.0) + +func get_bits_number_for(value: int) -> int: + if value == 0: + return 1 + return int(ceil(log2(value + 1))) + +func initialize_color_code_table(colors: PackedByteArray) -> CodeTable: + var result_code_table: CodeTable = CodeTable.new() + for color_id in colors: + # warning-ignore:return_value_discarded + result_code_table.add(CodeEntry.new([color_id])) + # move counter to the first available compression code index + var last_color_index: int = colors.size() - 1 + var clear_code_index: int = pow(2, get_bits_number_for(last_color_index)) + result_code_table.counter = clear_code_index + 2 + return result_code_table + + +# compression and decompression done with source: +# http://www.matthewflickinger.com/lab/whatsinagif/lzw_image_data.asp + + +func compress_lzw(image: PackedByteArray, colors: PackedByteArray) -> Array: + # Initialize code table + var code_table: CodeTable = initialize_color_code_table(colors) + # Clear Code index is 2** + # is the amount of bits needed to write down all colors + # from color table. We use last color index because we can write + # all colors (for example 16 colors) with indexes from 0 to 15. + # Number 15 is in binary 0b1111, so we'll need 4 bits to write all + # colors down. + var last_color_index: int = colors.size() - 1 + var clear_code_index: int = pow(2, get_bits_number_for(last_color_index)) + var index_stream: PackedByteArray = image + var current_code_size: int = get_bits_number_for(clear_code_index) + var binary_code_stream = lsbbitpacker.LSBLZWBitPacker.new() + + # initialize with Clear Code + binary_code_stream.write_bits(clear_code_index, current_code_size) + + # Read first index from index stream. + var index_buffer: CodeEntry = CodeEntry.new([index_stream[0]]) + var data_index: int = 1 + # + while data_index < index_stream.size(): + # Get the next index from the index stream. + var k: CodeEntry = CodeEntry.new([index_stream[data_index]]) + data_index += 1 + # Is index buffer + k in our code table? + var new_index_buffer: CodeEntry = index_buffer.add(k) + if code_table.has_entry(new_index_buffer): # if YES + # Add k to the end of the index buffer + index_buffer = new_index_buffer + else: # if NO + # Add a row for index buffer + k into our code table + binary_code_stream.write_bits(code_table.find(index_buffer), current_code_size) + + # We don't want to add new code to code table if we've exceeded 4095 + # index. + var last_entry_index: int = code_table.counter - 1 + if last_entry_index != 4095: + # Output the code for just the index buffer to our code stream + # warning-ignore:return_value_discarded + code_table.add(new_index_buffer) + else: + # if we exceeded 4095 index (code table is full), we should + # output Clear Code and reset everything. + binary_code_stream.write_bits(clear_code_index, current_code_size) + code_table = initialize_color_code_table(colors) + # get_bits_number_for(clear_code_index) is the same as + # LZW code size + 1 + current_code_size = get_bits_number_for(clear_code_index) + + # Detect when you have to save new codes in bigger bits boxes + # change current code size when it happens because we want to save + # flexible code sized codes + var new_code_size_candidate: int = get_bits_number_for(code_table.counter - 1) + if new_code_size_candidate > current_code_size: + current_code_size = new_code_size_candidate + + # Index buffer is set to k + index_buffer = k + # Output code for contents of index buffer + binary_code_stream.write_bits(code_table.find(index_buffer), current_code_size) + + # output end with End Of Information Code + binary_code_stream.write_bits(clear_code_index + 1, current_code_size) + + var min_code_size: int = get_bits_number_for(clear_code_index) - 1 + + return [binary_code_stream.pack(), min_code_size] + + +# gdlint: ignore=max-line-length +func decompress_lzw(code_stream_data: PackedByteArray, min_code_size: int, colors: PackedByteArray) -> PackedByteArray: + var code_table: CodeTable = initialize_color_code_table(colors) + var index_stream: PackedByteArray = PackedByteArray([]) + var binary_code_stream = lsbbitunpacker.LSBLZWBitUnpacker.new(code_stream_data) + var current_code_size: int = min_code_size + 1 + var clear_code_index: int = pow(2, min_code_size) + + # CODE is an index of code table, {CODE} is sequence inside + # code table with index CODE. The same goes for PREVCODE. + + # let CODE be the first code in the code stream + var code: int = binary_code_stream.read_bits(current_code_size) + + # Remove first Clear Code from stream. We don't need it. + if code == clear_code_index: + code = binary_code_stream.read_bits(current_code_size); + + # output {CODE} to index stream + index_stream.append_array(code_table.get_entry(code).sequence) + # set PREVCODE = CODE + var prevcode: int = code + # + while true: + # let CODE be the next code in the code stream + code = binary_code_stream.read_bits(current_code_size) + # Detect Clear Code. When detected reset everything and get next code. + if code == clear_code_index: + code_table = initialize_color_code_table(colors) + current_code_size = min_code_size + 1 + code = binary_code_stream.read_bits(current_code_size) + index_stream.append_array(code_table.get_entry(code).sequence) + prevcode = code + continue + elif code == clear_code_index + 1: # Stop when detected EOI Code. + break + # is CODE in the code table? + var code_entry: CodeEntry = code_table.get_entry(code) + if code_entry != null: # if YES + # output {CODE} to index stream + index_stream.append_array(code_entry.sequence) + # let k be the first index in {CODE} + var k: CodeEntry = CodeEntry.new([code_entry.sequence[0]]) + # warning-ignore:return_value_discarded + # add {PREVCODE} + k to the code table + code_table.add(code_table.get_entry(prevcode).add(k)) + # set PREVCODE = CODE + prevcode = code + else: # if NO + # let k be the first index of {PREVCODE} + var prevcode_entry: CodeEntry = code_table.get_entry(prevcode) + var k: CodeEntry = CodeEntry.new([prevcode_entry.sequence[0]]) + # output {PREVCODE} + k to index stream + index_stream.append_array(prevcode_entry.add(k).sequence) + # add {PREVCODE} + k to code table + # warning-ignore:return_value_discarded + code_table.add(prevcode_entry.add(k)) + # set PREVCODE = CODE + prevcode = code + + # Detect when we should increase current code size and increase it. + var new_code_size_candidate: int = get_bits_number_for(code_table.counter) + if new_code_size_candidate > current_code_size: + current_code_size = new_code_size_candidate + + return index_stream diff --git a/addons/twitcher/media/native/gif-lzw/lzw.gd.uid b/addons/twitcher/media/native/gif-lzw/lzw.gd.uid new file mode 100644 index 0000000..23fae7b --- /dev/null +++ b/addons/twitcher/media/native/gif-lzw/lzw.gd.uid @@ -0,0 +1 @@ +uid://c2gildpalbfq1 diff --git a/addons/twitcher/media/native_image_transformer.gd b/addons/twitcher/media/native_image_transformer.gd new file mode 100644 index 0000000..ac86857 --- /dev/null +++ b/addons/twitcher/media/native_image_transformer.gd @@ -0,0 +1,28 @@ +@icon("res://addons/twitcher/assets/media-loader-icon.svg") +@tool +extends TwitchImageTransformer + +## Native GIF parser written in GDScript and ported to Godot 4. Most of the time stable but there +## are GIF's that may not work cause the file didn't follow the GIF specification. +class_name NativeImageTransformer + + +func is_supporting_animation() -> bool: + return true + + +func convert_image(path: String, buffer_in: PackedByteArray, output_path: String) -> SpriteFrames: + var reader = GifReader.new() + var tex: SpriteFrames; + if buffer_in.size() == 0: + tex = reader.read(path); + else: + tex = reader.load_gif(buffer_in) + _save_converted_file(tex, output_path); + return tex + + +func _save_converted_file(tex: SpriteFrames, output: String): + if not output.is_empty() and tex: + ResourceSaver.save(tex, output, ResourceSaver.SaverFlags.FLAG_COMPRESS); + tex.take_over_path(output); diff --git a/addons/twitcher/media/native_image_transformer.gd.uid b/addons/twitcher/media/native_image_transformer.gd.uid new file mode 100644 index 0000000..8808e01 --- /dev/null +++ b/addons/twitcher/media/native_image_transformer.gd.uid @@ -0,0 +1 @@ +uid://ddwa0dm0qhc3s diff --git a/addons/twitcher/media/twitch_badge_definition.gd b/addons/twitcher/media/twitch_badge_definition.gd new file mode 100644 index 0000000..4eda5ad --- /dev/null +++ b/addons/twitcher/media/twitch_badge_definition.gd @@ -0,0 +1,36 @@ +extends RefCounted + +## Definition to load or specify one specific badge +class_name TwitchBadgeDefinition + +var badge_set: String +var badge_id: String +var scale: int +var channel: String + +var _cache_id: String # This is maybe a bad idea, but solves the issue when the badge won't get found in cache and then it changes the channel to global during loading and so also the cache id + +func scale_1() -> TwitchBadgeDefinition: scale = 1; return self; +func scale_2() -> TwitchBadgeDefinition: scale = 2; return self; +func scale_4() -> TwitchBadgeDefinition: scale = 4; return self; + + +func _init(set_id: String, id: String, badge_scale: int, badge_channel: String) -> void: + badge_set = set_id + badge_id = id + assert(badge_scale == 1 || badge_scale == 2 || badge_scale == 4) + scale = badge_scale + channel = badge_channel + _cache_id = "_".join([ + channel, + badge_set, + badge_id, + scale + ]) + + +func _to_string() -> String: + return "Badge[%s/%s/%s]" % [channel, badge_set, badge_id] + +func get_cache_id() -> String: + return _cache_id diff --git a/addons/twitcher/media/twitch_badge_definition.gd.uid b/addons/twitcher/media/twitch_badge_definition.gd.uid new file mode 100644 index 0000000..d194d68 --- /dev/null +++ b/addons/twitcher/media/twitch_badge_definition.gd.uid @@ -0,0 +1 @@ +uid://dwx6jbouei2tf diff --git a/addons/twitcher/media/twitch_cheermote_definition.gd b/addons/twitcher/media/twitch_cheermote_definition.gd new file mode 100644 index 0000000..942597d --- /dev/null +++ b/addons/twitcher/media/twitch_cheermote_definition.gd @@ -0,0 +1,35 @@ +extends RefCounted + +## Definition of a specific cheermote +class_name TwitchCheermoteDefinition + + +var prefix: String +var tier: String +var theme: String = "dark" +var type: String = "animated_format" +var scale: String = "1" + + +func _init(pre: String, tir: String) -> void: + prefix = pre + tier = tir + +func theme_dark() -> TwitchCheermoteDefinition: theme = "dark"; return self; +func theme_light() -> TwitchCheermoteDefinition: theme = "light"; return self; + +func type_animated() -> TwitchCheermoteDefinition: type = "animated_format"; return self; +func type_static() -> TwitchCheermoteDefinition: type = "static_format"; return self; + +func scale_1() -> TwitchCheermoteDefinition: scale = "1"; return self; +func scale_2() -> TwitchCheermoteDefinition: scale = "2"; return self; +func scale_3() -> TwitchCheermoteDefinition: scale = "3"; return self; +func scale_4() -> TwitchCheermoteDefinition: scale = "4"; return self; +func scale_1_5() -> TwitchCheermoteDefinition: scale = "1.5"; return self; + + +func _to_string() -> String: + return "Cheer[%s/%s]" % [prefix, tier] + +func get_id() -> String: + return "/" + "/".join([ prefix, tier, theme, type, scale ]) diff --git a/addons/twitcher/media/twitch_cheermote_definition.gd.uid b/addons/twitcher/media/twitch_cheermote_definition.gd.uid new file mode 100644 index 0000000..7359c6f --- /dev/null +++ b/addons/twitcher/media/twitch_cheermote_definition.gd.uid @@ -0,0 +1 @@ +uid://cntpsdb4qwtex diff --git a/addons/twitcher/media/twitch_emote_definition.gd b/addons/twitcher/media/twitch_emote_definition.gd new file mode 100644 index 0000000..fb3a81d --- /dev/null +++ b/addons/twitcher/media/twitch_emote_definition.gd @@ -0,0 +1,31 @@ +extends RefCounted + +## Used to define what emotes to load to be typesafe and don't request invalid data. +class_name TwitchEmoteDefinition + +var id: String +var _scale: int +var _type: String +var _theme: String + +func _init(emote_id: String) -> void: + id = emote_id + scale_1().type_default().theme_dark() + +func scale_1() -> TwitchEmoteDefinition: _scale = 1; return self; +func scale_2() -> TwitchEmoteDefinition: _scale = 2; return self; +func scale_3() -> TwitchEmoteDefinition: _scale = 3; return self; + +func type_default() -> TwitchEmoteDefinition: _type = "default"; return self; +func type_static() -> TwitchEmoteDefinition: _type = "static"; return self; +func type_animated() -> TwitchEmoteDefinition: _type = "animated"; return self; + +func theme_dark() -> TwitchEmoteDefinition: _theme = "dark"; return self; +func theme_light() -> TwitchEmoteDefinition: _theme = "light"; return self; + +func _to_string() -> String: + return "Emote[%s]" % id + +## Returns its unique filename +func get_file_name() -> String: + return "%s_%s_%s_%s" % [_scale, _type, _theme, id] diff --git a/addons/twitcher/media/twitch_emote_definition.gd.uid b/addons/twitcher/media/twitch_emote_definition.gd.uid new file mode 100644 index 0000000..3022fe6 --- /dev/null +++ b/addons/twitcher/media/twitch_emote_definition.gd.uid @@ -0,0 +1 @@ +uid://dhyboroqtixko diff --git a/addons/twitcher/media/twitch_image_transformer.gd b/addons/twitcher/media/twitch_image_transformer.gd new file mode 100644 index 0000000..946a72d --- /dev/null +++ b/addons/twitcher/media/twitch_image_transformer.gd @@ -0,0 +1,39 @@ +@icon("res://addons/twitcher/assets/media-loader-icon.svg") +@tool +extends Resource + +## Most simple image transformer that doesn't support GIF's uses builtin functionalities of godot. +class_name TwitchImageTransformer + +static var _log: TwitchLogger = TwitchLogger.new("TwitchImageTransformer") + +## Used when the image can't be transformed +@export var fallback_texture: Texture2D = preload("res://addons/twitcher/assets/fallback_texture.tres") + + +func is_supporting_animation() -> bool: + return false + + +func is_supported() -> bool: + return true + + +func convert_image(path: String, buffer_in: PackedByteArray, output_path: String) -> SpriteFrames: + if ResourceLoader.has_cached(output_path): + return ResourceLoader.load(output_path) + var img := Image.new() + var err = img.load_png_from_buffer(buffer_in) + var sprite_frames = SpriteFrames.new() + var texture : Texture + if err == OK: + texture = ImageTexture.new() + texture.set_image(img) + sprite_frames.add_frame(&"default", texture) + ResourceSaver.save(sprite_frames, output_path, ResourceSaver.SaverFlags.FLAG_COMPRESS) + sprite_frames.take_over_path(path) + else: + sprite_frames.add_frame(&"default", fallback_texture) + _log.e("Can't load %s use fallback" % output_path) + + return sprite_frames diff --git a/addons/twitcher/media/twitch_image_transformer.gd.uid b/addons/twitcher/media/twitch_image_transformer.gd.uid new file mode 100644 index 0000000..32c0232 --- /dev/null +++ b/addons/twitcher/media/twitch_image_transformer.gd.uid @@ -0,0 +1 @@ +uid://6v8jnfjwbnhm diff --git a/addons/twitcher/media/twitch_media_loader.gd b/addons/twitcher/media/twitch_media_loader.gd new file mode 100644 index 0000000..af7d8f7 --- /dev/null +++ b/addons/twitcher/media/twitch_media_loader.gd @@ -0,0 +1,435 @@ +@icon("res://addons/twitcher/assets/media-loader-icon.svg") +@tool +extends Twitcher + +## Will load badges, icons and profile images +class_name TwitchMediaLoader + +static var _log: TwitchLogger = TwitchLogger.new("TwitchMediaLoader") + +static var instance: TwitchMediaLoader + +## Called when an emoji was succesfully loaded +signal emoji_loaded(definition: TwitchEmoteDefinition) + +const FALLBACK_TEXTURE = preload("res://addons/twitcher/assets/fallback_texture.tres") +const FALLBACK_PROFILE = preload("res://addons/twitcher/assets/no_profile.png") + +@export var api: TwitchAPI +@export var image_transformer: TwitchImageTransformer = TwitchImageTransformer.new(): + set(val): + image_transformer = val + update_configuration_warnings() +@export var fallback_texture: Texture2D = FALLBACK_TEXTURE +@export var fallback_profile: Texture2D = FALLBACK_PROFILE +@export var image_cdn_host: String = "https://static-cdn.jtvnw.net" +## Will preload the whole badge and emote cache also to editor time (use it when you make a Editor Plugin with Twitch Support) +@export var load_cache_in_editor: bool + +@export_global_dir var cache_emote: String = "user://emotes" +@export_global_dir var cache_badge: String = "user://badges" +@export_global_dir var cache_cheermote: String = "user://cheermote" + +## All requests that are currently in progress +var _requests_in_progress : Array[StringName] +## Badge definition for global and the channel. +var _cached_badges : Dictionary = {} +## Emote definition for global and the channel. +var _cached_emotes : Dictionary = {} +## Key: String Cheer Prefix | Value: TwitchCheermote +var _cached_cheermotes: Dictionary[String, TwitchCheermote] = {} + +## All cached emotes, badges, cheermotes +## Is needed that the garbage collector isn't deleting our cache. +var _cached_images : Array[SpriteFrames] = [] +var _host_parser = RegEx.create_from_string("(https://.*?)/") +var static_image_transformer = TwitchImageTransformer.new() +var _client: BufferedHTTPClient + + +func _ready() -> void: + _client = BufferedHTTPClient.new() + _client.name = "TwitchMediaLoaderClient" + add_child(_client) + _load_cache() + if api == null: api = TwitchAPI.instance + + +func _enter_tree() -> void: + if instance == null: instance = self + + +func _exit_tree() -> void: + if instance == self: instance = null + + +## Loading all images from the directory into the memory cache +func _load_cache() -> void: + if Engine.is_editor_hint() || load_cache_in_editor: + _cache_directory(cache_emote) + _cache_directory(cache_badge) + + +func _cache_directory(path: String): + DirAccess.make_dir_recursive_absolute(path) + var files = DirAccess.get_files_at(path) + for file in files: + if file.ends_with(".res"): + var res_path = path.path_join(file) + var sprite_frames: SpriteFrames = ResourceLoader.load(res_path, "SpriteFrames") + var spriteframe_path = res_path.trim_suffix(".res") + sprite_frames.take_over_path(spriteframe_path) + _cached_images.append(sprite_frames) + +#region Emotes + +func preload_emotes(channel_id: String = "global") -> void: + + if (!_cached_emotes.has(channel_id)): + var response + if channel_id == "global": + _log.i("Preload global emotes") + response = await api.get_global_emotes() + else: + _log.i("Preload channel(%s) emotes" % channel_id) + response = await api.get_channel_emotes(channel_id) + _cached_emotes[channel_id] = _map_emotes(response) + + +## Returns requested emotes. +## Key: EmoteID as String | Value: SpriteFrames +func get_emotes(emote_ids : Array[String]) -> Dictionary[String, SpriteFrames]: + _log.i("Get emotes: %s" % emote_ids) + var requests: Array[TwitchEmoteDefinition] = [] + for id: String in emote_ids: + requests.append(TwitchEmoteDefinition.new(id)) + var emotes: Dictionary[TwitchEmoteDefinition, SpriteFrames] = await get_emotes_by_definition(requests) + var result: Dictionary[String, SpriteFrames] = {} + # Remap the emotes to string value easier for processing + for requested_emote: TwitchEmoteDefinition in requests: + result[requested_emote.id] = emotes[requested_emote] + return result + + +## Returns requested emotes. +## Key: TwitchEmoteDefinition | Value: SpriteFrames +func get_emotes_by_definition(emote_definitions : Array[TwitchEmoteDefinition]) -> Dictionary[TwitchEmoteDefinition, SpriteFrames]: + var response: Dictionary[TwitchEmoteDefinition, SpriteFrames] = {} + var requests: Dictionary[TwitchEmoteDefinition, BufferedHTTPClient.RequestData] = {} + + for emote_definition: TwitchEmoteDefinition in emote_definitions: + var original_file_cache_path: String = _get_emote_cache_path(emote_definition) + var spriteframe_path: String = _get_emote_cache_path_spriteframe(emote_definition) + if ResourceLoader.has_cached(spriteframe_path): + _log.d("Use cached emote %s" % emote_definition) + response[emote_definition] = ResourceLoader.load(spriteframe_path) + continue + + if not image_transformer.is_supporting_animation(): + emote_definition.type_static() + + if _requests_in_progress.has(original_file_cache_path): continue + _requests_in_progress.append(original_file_cache_path) + _log.d("Request emote %s" % emote_definition) + var request : BufferedHTTPClient.RequestData = _load_emote(emote_definition) + requests[emote_definition] = request + + for emote_definition : TwitchEmoteDefinition in requests: + var original_file_cache_path : String = _get_emote_cache_path(emote_definition) + var spriteframe_path : String = _get_emote_cache_path_spriteframe(emote_definition) + var request : BufferedHTTPClient.RequestData = requests[emote_definition] + var sprite_frames : SpriteFrames = await _convert_response(request, original_file_cache_path, spriteframe_path) + response[emote_definition] = sprite_frames + _cached_images.append(sprite_frames) + _requests_in_progress.erase(original_file_cache_path) + emoji_loaded.emit(emote_definition) + + for emote_definition: TwitchEmoteDefinition in emote_definitions: + if not response.has(emote_definition): + var cache : String = _get_emote_cache_path_spriteframe(emote_definition) + response[emote_definition] = ResourceLoader.load(cache) + + return response + + +## Returns the path where the raw emoji should be cached +func _get_emote_cache_path(emote_definition: TwitchEmoteDefinition) -> String: + var file_name : String = emote_definition.get_file_name() + return cache_emote.path_join(file_name) + + +## Returns the path where the converted spriteframe should be cached +func _get_emote_cache_path_spriteframe(emote_definition: TwitchEmoteDefinition) -> String: + var file_name : String = emote_definition.get_file_name() + ".res" + return cache_emote.path_join(file_name) + + +func _load_emote(emote_definition : TwitchEmoteDefinition) -> BufferedHTTPClient.RequestData: + var request_path : String = "/emoticons/v2/%s/%s/%s/%1.1f" % [emote_definition.id, emote_definition._type, emote_definition._theme, emote_definition._scale] + return _client.request(image_cdn_host + request_path, HTTPClient.METHOD_GET, {}, "") + + +func _map_emotes(result: Variant) -> Dictionary: + var mappings : Dictionary = {} + var emotes : Array = result.get("data") + if emotes == null: + return mappings + for emote in emotes: + mappings[emote.get("id")] = emote + return mappings + + +func get_cached_emotes(channel_id) -> Dictionary: + if not _cached_emotes.has(channel_id): + await preload_emotes(channel_id) + return _cached_emotes[channel_id] + +#endregion + +#region Badges + +func preload_badges(channel_id: String = "global") -> void: + if not _cached_badges.has(channel_id): + var response: Variant # TwitchGetGlobalChatBadges.Response | TwitchGetChannelChatBadges.Response + if channel_id == "global": + _log.i("Preload global badges") + response = await(api.get_global_chat_badges()) + else: + _log.i("Preload channel(%s) badges" % channel_id) + response = await(api.get_channel_chat_badges(channel_id)) + _cached_badges[channel_id] = _cache_badges(response) + + +## Returns the requested badge either from cache or loads from web. Scale can be 1, 2 or 4. +## Key: TwitchBadgeDefinition | Value: SpriteFrames +func get_badges(badges: Array[TwitchBadgeDefinition]) -> Dictionary[TwitchBadgeDefinition, SpriteFrames]: + var response: Dictionary[TwitchBadgeDefinition, SpriteFrames] = {} + var requests: Dictionary[TwitchBadgeDefinition, BufferedHTTPClient.RequestData] = {} + + for badge_definition : TwitchBadgeDefinition in badges: + var cache_id : String = badge_definition.get_cache_id() + var badge_path : String = cache_badge.path_join(cache_id) + if ResourceLoader.has_cached(badge_path): + _log.d("Use cached badge %s" % badge_definition) + response[badge_definition] = ResourceLoader.load(badge_path) + else: + _log.d("Request badge %s" % badge_definition) + var request : BufferedHTTPClient.RequestData = await _load_badge(badge_definition) + requests[badge_definition] = request + + for badge_definition : TwitchBadgeDefinition in requests: + var request = requests[badge_definition] + var id : String = badge_definition.get_cache_id() + var cache_path : String = cache_badge.path_join(id) + var spriteframe_path : String = cache_badge.path_join(id) + ".res" + var sprite_frames : SpriteFrames = await _convert_response(request, cache_path, spriteframe_path) + response[badge_definition] = sprite_frames + _cached_images.append(sprite_frames) + + return response + + +func _load_badge(badge_definition: TwitchBadgeDefinition) -> BufferedHTTPClient.RequestData: + var channel_id : String = badge_definition.channel + var badge_set : String = badge_definition.badge_set + var badge_id : String = badge_definition.badge_id + var scale : int = badge_definition.scale + + var is_global_chanel : bool = channel_id == "global" + if not _cached_badges.has(channel_id): + await preload_badges(channel_id) + var channel_has_badge : bool = _cached_badges[channel_id].has(badge_set) && _cached_badges[channel_id][badge_set]["versions"].has(badge_id) + if not is_global_chanel and not channel_has_badge: + badge_definition.channel = "global" + return await _load_badge(badge_definition) + + var request_path : String = _cached_badges[channel_id][badge_set]["versions"][badge_id]["image_url_%sx" % scale] + return _client.request(request_path, HTTPClient.METHOD_GET, {}, "") + + +## Maps the badges into a dict of category / versions / badge_id +func _cache_badges(result: Variant) -> Dictionary: + var mappings : Dictionary = {} + var badges : Array = result["data"] + for badge in badges: + if not mappings.has(badge["set_id"]): + mappings[badge["set_id"]] = { + "set_id": badge["set_id"], + "versions" : {} + } + for version in badge["versions"]: + mappings[badge["set_id"]]["versions"][version["id"]] = version + return mappings + + +func get_cached_badges(channel_id: String) -> Dictionary: + if(!_cached_badges.has(channel_id)): + await preload_badges(channel_id) + return _cached_badges[channel_id] +#endregion + +#region Cheermote + +class CheerResult extends RefCounted: + var cheermote: TwitchCheermote + var tier: TwitchCheermote.Tiers + var spriteframes: SpriteFrames + func _init(cheer: TwitchCheermote, t: TwitchCheermote.Tiers, sprites: SpriteFrames): + cheermote = cheer + tier = t + spriteframes = sprites + + +func preload_cheemote() -> void: + if not _cached_cheermotes.is_empty(): return + _log.i("Preload cheermotes") + var cheermote_response: TwitchGetCheermotes.Response = await api.get_cheermotes(null) + for data: TwitchCheermote in cheermote_response.data: + _log.d("- found %s" % data.prefix) + _cached_cheermotes[data.prefix] = data + + +func all_cheermotes() -> Array[TwitchCheermote]: + var cheermotes: Array[TwitchCheermote] = [] + cheermotes.assign(_cached_cheermotes.values()) + return cheermotes + + +## Resolves a info with spriteframes for a specific cheer definition contains also spriteframes for the given tier. +## Can be null when not found. +func get_cheer_info(cheermote_definition: TwitchCheermoteDefinition) -> CheerResult: + await preload_cheemote() + var cheermote : TwitchCheermote = _cached_cheermotes[cheermote_definition.prefix] + for cheertier: TwitchCheermote.Tiers in cheermote.tiers: + if cheertier.id == cheermote_definition.tier: + var sprite_frames: SpriteFrames = await _get_cheermote_sprite_frames(cheertier, cheermote_definition) + return CheerResult.new(cheermote, cheertier, sprite_frames) + return null + + +## Finds the tier depending on the given number +func find_cheer_tier(number: int, cheer_data: TwitchCheermote) -> TwitchCheermote.Tiers: + var current_tier: TwitchCheermote.Tiers = cheer_data.tiers[0] + for tier: TwitchCheermote.Tiers in cheer_data.tiers: + if tier.min_bits < number && current_tier.min_bits < tier.min_bits: + current_tier = tier + return current_tier + + +## Returns spriteframes mapped by tier for a cheermote +## Key: TwitchCheermote.Tiers | Value: SpriteFrames +func get_cheermotes(cheermote_definition: TwitchCheermoteDefinition) -> Dictionary[TwitchCheermote.Tiers, SpriteFrames]: + await preload_cheemote() + var response : Dictionary[TwitchCheermote.Tiers, SpriteFrames] = {} + var requests : Dictionary[TwitchCheermote.Tiers, BufferedHTTPClient.RequestData] = {} + var cheer : TwitchCheermote = _cached_cheermotes[cheermote_definition.prefix] + for tier : TwitchCheermote.Tiers in cheer.tiers: + var id = cheermote_definition.get_id() + if ResourceLoader.has_cached(id): + _log.d("Use cached cheer %s" % cheermote_definition) + response[tier] = ResourceLoader.load(id) + if not image_transformer.is_supporting_animation(): + cheermote_definition.type_static() + else: + _log.d("Request cheer %s" % cheermote_definition) + requests[tier] = _request_cheermote(tier, cheermote_definition) + + for tier: TwitchCheermote.Tiers in requests: + var id = cheermote_definition.get_id() + var request = requests[tier] + var sprite_frames = await _wait_for_cheeremote(request, id) + response[tier] = sprite_frames + return response + + +func _get_cheermote_sprite_frames(tier: TwitchCheermote.Tiers, cheermote_definition: TwitchCheermoteDefinition) -> SpriteFrames: + var id = cheermote_definition.get_id() + if ResourceLoader.has_cached(id): + return ResourceLoader.load(id) + else: + var request : BufferedHTTPClient.RequestData = _request_cheermote(tier, cheermote_definition) + if request == null: + var frames : SpriteFrames = SpriteFrames.new() + frames.add_frame("default", fallback_texture) + return frames + return await _wait_for_cheeremote(request, id) + + +func _wait_for_cheeremote(request: BufferedHTTPClient.RequestData, cheer_id: String) -> SpriteFrames: + var response : BufferedHTTPClient.ResponseData = await _client.wait_for_request(request) + var cache_path : String = cache_cheermote.path_join(cheer_id) + var sprite_frames : SpriteFrames = await image_transformer.convert_image( + cache_path, + response.response_data, + cache_path + ".res") as SpriteFrames + sprite_frames.take_over_path(cheer_id) + _cached_images.append(sprite_frames) + return sprite_frames + + +func _request_cheermote(cheer_tier: TwitchCheermote.Tiers, cheermote: TwitchCheermoteDefinition) -> BufferedHTTPClient.RequestData: + var img_path : String = cheer_tier.images[cheermote.theme][cheermote.type][cheermote.scale] + var host_result : RegExMatch = _host_parser.search(img_path) + if host_result == null: return null + var host : String = host_result.get_string(1) + return _client.request(img_path, HTTPClient.METHOD_GET, {}, "") + + +#endregion + +#region Utilities + +func _get_configuration_warnings() -> PackedStringArray: + if image_transformer == null || not image_transformer.is_supported(): + return ["Image transformer is misconfigured"] + return [] + + +func load_image(url: String) -> Image: + var request : BufferedHTTPClient.RequestData = _client.request(url, HTTPClient.METHOD_GET, {}, "") + var response : BufferedHTTPClient.ResponseData = await _client.wait_for_request(request) + var temp_file : FileAccess = FileAccess.create_temp(FileAccess.ModeFlags.WRITE_READ, "image_", url.get_extension(), true) + temp_file.store_buffer(response.response_data) + temp_file.flush() + var image : Image = Image.load_from_file(temp_file.get_path()) + return image + + +## Get the image of an user +func load_profile_image(user: TwitchUser) -> ImageTexture: + if user == null: return fallback_profile + if ResourceLoader.has_cached(user.profile_image_url): + return ResourceLoader.load(user.profile_image_url) + var request := _client.request(user.profile_image_url, HTTPClient.METHOD_GET, {}, "") + var response_data := await _client.wait_for_request(request) + var texture : ImageTexture = ImageTexture.new() + var response := response_data.response_data + if not response.is_empty(): + var img := Image.new() + var content_type = response_data.response_header["Content-Type"] + + match content_type: + "image/png": img.load_png_from_buffer(response) + "image/jpeg": img.load_jpg_from_buffer(response) + _: return fallback_profile + texture.set_image(img) + else: + # Don't use `texture = fallback_profile` as texture cause the path will be taken over + # for caching purpose! + texture.set_image(fallback_profile.get_image()) + texture.take_over_path(user.profile_image_url) + return texture + + +const GIF_HEADER: PackedByteArray = [71, 73, 70] +func _convert_response(request: BufferedHTTPClient.RequestData, cache_path: String, spriteframe_path: String) -> SpriteFrames: + var response = await _client.wait_for_request(request) + var response_data = response.response_data as PackedByteArray + var file_head = response_data.slice(0, 3) + # REMARK: don't use content-type... twitch doesn't check and sends PNGs with GIF content type. + if file_head == GIF_HEADER: + return await image_transformer.convert_image(cache_path, response_data, spriteframe_path) as SpriteFrames + else: + return await static_image_transformer.convert_image(cache_path, response_data, spriteframe_path) as SpriteFrames + +#endregion diff --git a/addons/twitcher/media/twitch_media_loader.gd.uid b/addons/twitcher/media/twitch_media_loader.gd.uid new file mode 100644 index 0000000..615049f --- /dev/null +++ b/addons/twitcher/media/twitch_media_loader.gd.uid @@ -0,0 +1 @@ +uid://d4lyup0vy1wtu diff --git a/addons/twitcher/plugin.cfg b/addons/twitcher/plugin.cfg new file mode 100644 index 0000000..f99f5bd --- /dev/null +++ b/addons/twitcher/plugin.cfg @@ -0,0 +1,7 @@ +[plugin] + +name="Twitcher" +description="A plugin to use Twitch API in Godot." +author="kani_dev" +version="2.0.0" +script="plugin.gd" diff --git a/addons/twitcher/plugin.gd b/addons/twitcher/plugin.gd new file mode 100644 index 0000000..064d343 --- /dev/null +++ b/addons/twitcher/plugin.gd @@ -0,0 +1,98 @@ +@tool +extends EditorPlugin + +static var _log : TwitchLogger = TwitchLogger.new("Twitcher Plugin") + +const REGENERATE_API_LABEL: String = "Regenerate Twitch Api" +const OPEN_SETUP_LABEL: String = "Twitcher Setup" + +# oOuch imports +const OauthSettingInspector = preload("res://addons/twitcher/lib/oOuch/oauth_setting_inspector.gd") +const TokenInspector = preload("res://addons/twitcher/lib/oOuch/oauth_token_inspector.gd") + +# Twitcher imports +const TwitchScopeInspectorPlugin = preload("res://addons/twitcher/editor/inspector/twitch_scope_inspector.gd") +const TwitchEventsubInspectorPlugin = preload("res://addons/twitcher/editor/inspector/twitch_eventsub_inspector.gd") +const TwitchEventsubConfigInspectorPlugin = preload("res://addons/twitcher/editor/inspector/twitch_eventsub_config_inspector.gd") +const TwitchMediaLoaderInspector = preload("res://addons/twitcher/editor/inspector/twitch_media_loader_inspector.gd") +const TwitchEditorSettings = preload("res://addons/twitcher/editor/twitch_editor_settings.gd") +const TwitchUserInspector = preload("res://addons/twitcher/editor/inspector/twitch_user_inspector.gd") + +var generator: TwitchAPIGenerator +var parser: TwitchAPIParser + +var gif_importer_imagemagick: GifImporterImagemagick = GifImporterImagemagick.new() +var gif_importer_native: GifImporterNative = GifImporterNative.new() +var eventsub_config_inspector: TwitchEventsubConfigInspectorPlugin = TwitchEventsubConfigInspectorPlugin.new() +var eventsub_inspector: TwitchEventsubInspectorPlugin = TwitchEventsubInspectorPlugin.new() +var scope_inspector: TwitchScopeInspectorPlugin = TwitchScopeInspectorPlugin.new() +var oauth_setting_inspector: OauthSettingInspector = OauthSettingInspector.new() +var token_inspector: TokenInspector = TokenInspector.new() +var media_loader_inspector: TwitchMediaLoaderInspector = TwitchMediaLoaderInspector.new() +var user_inspector: TwitchUserInspector = TwitchUserInspector.new() +var settings: TwitchEditorSettings = TwitchEditorSettings.new() +var current_setup_window: Node + +func _enter_tree(): + _log.i("Start Twitcher loading...") + TwitchEditorSettings.setup() + + token_inspector.token_info_scene = preload("res://addons/twitcher/editor/inspector/twitch_token_info.tscn") + + add_tool_menu_item(REGENERATE_API_LABEL, generate_api) + add_tool_menu_item(OPEN_SETUP_LABEL, open_setup) + + add_inspector_plugin(eventsub_config_inspector) + add_inspector_plugin(eventsub_inspector) + add_inspector_plugin(scope_inspector) + add_inspector_plugin(oauth_setting_inspector) + add_inspector_plugin(token_inspector) + add_inspector_plugin(media_loader_inspector) + add_inspector_plugin(user_inspector) + add_import_plugin(gif_importer_native) + if is_magick_available(): + add_import_plugin(gif_importer_imagemagick) + + if TwitchEditorSettings.show_setup_on_startup: open_setup() + _log.i("Twitcher loading ended") + + +func _exit_tree(): + remove_import_plugin(gif_importer_native) + if is_magick_available(): + remove_import_plugin(gif_importer_imagemagick) + + remove_inspector_plugin(eventsub_config_inspector) + remove_inspector_plugin(eventsub_inspector) + remove_inspector_plugin(scope_inspector) + remove_inspector_plugin(oauth_setting_inspector) + remove_inspector_plugin(token_inspector) + remove_inspector_plugin(media_loader_inspector) + remove_inspector_plugin(user_inspector) + if Engine.is_editor_hint(): + remove_tool_menu_item(REGENERATE_API_LABEL) + + _log.i("Twitcher Unloaded") + + +func open_setup() -> void: + if is_instance_valid(current_setup_window): return + + current_setup_window = load("res://addons/twitcher/editor/setup/setup.tscn").instantiate() + add_child(current_setup_window) + + +func generate_api() -> void: + generator = TwitchAPIGenerator.new() + parser = TwitchAPIParser.new() + generator.parser = parser + add_child(generator) + add_child(parser) + await parser.parse_api() + generator.generate_api() + remove_child(generator) + remove_child(parser) + +func is_magick_available() -> bool: + var transformer = MagicImageTransformer.new() + return transformer.is_supported() diff --git a/addons/twitcher/plugin.gd.uid b/addons/twitcher/plugin.gd.uid new file mode 100644 index 0000000..5a59c64 --- /dev/null +++ b/addons/twitcher/plugin.gd.uid @@ -0,0 +1 @@ +uid://bm71dx6iwl1nh diff --git a/addons/twitcher/sprite_frame_effect.gd b/addons/twitcher/sprite_frame_effect.gd new file mode 100644 index 0000000..5252def --- /dev/null +++ b/addons/twitcher/sprite_frame_effect.gd @@ -0,0 +1,116 @@ +extends RichTextEffect + +## Shows spriteframes within richtext label.[br] +## @usage use prepare_message before to load the image and prepare the message accordingly +class_name SpriteFrameEffect + +const TRANSPARENT = preload("res://addons/twitcher/assets/transparent.tres") + +static var regex: RegEx = RegEx.create_from_string("\\[sprite id=(?.*?)\\](?.*?)\\[/sprite\\]") + +## Custom BB Code to use +var bbcode = "sprite" +## To track the emojis +## Key: Id as String Value: Emoji +var cache: Dictionary = {} +## To check if the message got already prepared +var ready: bool +## Save theme for calculating line height +var parent_label: RichTextLabel +## If you don't want to have spaces between images (made for Foolbox <3) +var no_space: bool + +func prepare_message(message: String, parent: RichTextLabel) -> String: + parent_label = parent + var found_matches = regex.search_all(message) as Array[RegExMatch] + + # We are changing the message content and want to preserve the match beginnings. + # So we need to handle them in reverse + found_matches.reverse() + for m: RegExMatch in found_matches: + var path = m.get_string("path") + var id = m.get_string("id") + var resource = ResourceLoader.load(path, "SpriteFrames") as SpriteFrames + if resource == null: continue + var tex = resource.get_frame_texture("default", 0) + var size = tex.get_size() + var start = m.get_start(0) + # Add an empty image to make the correct amount of space + message = message.replace(path, "[img width=%s height=%s]%s[/img]" % [size.x, size.y, TRANSPARENT.resource_path]) + var emoji = _create_emoji(resource) + emoji.name = id + emoji.set_meta("size", size) + cache[id] = emoji + parent.add_child(emoji) + + if no_space: message = message.replace("[/sprite] [sprite", "[/sprite][sprite") + + ready = true + return message + + +func _create_emoji(resource: SpriteFrames): + var node = AnimatedSprite2D.new() + node.sprite_frames = resource + node.centered = true + node.play() + return node + + +func _process_custom_fx(char_fx: CharFXTransform) -> bool: + if not ready: return true + var id = char_fx.env['id'] + # unknown image just ignore + if !cache.has(id): return true + + # Hide the original characters of the [sprite] tag content + # (which should just be the placeholder [img] tag now) + char_fx.visible = false + + # Only position the sprite once, using the first character's info + if char_fx.relative_index != 0: return true + + var node: AnimatedSprite2D = cache[id] + var image_size: Vector2 = node.get_meta("size") # Already stored in prepare_message + + # --- Get Font Metrics from RichTextLabel Theme --- + var font: Font = char_fx.font if char_fx.font else parent_label.get_theme_font(&"normal_font") + var font_size: int = parent_label.get_theme_font_size(&"normal_font_size") + + var font_ascent: float = 0.0 + var font_descent: float = 0.0 # Distance below baseline (positive value) + + if font: + if font_size <= 0: + font_size = parent_label.get_theme_default_font_size() + if font_size <= 0: font_size = 16 # Absolute fallback + + # Get ascent and descent, scaled by the RichTextLabel's scale + font_ascent = font.get_ascent(font_size) * parent_label.scale.y + font_descent = font.get_descent(font_size) * parent_label.scale.y + else: + # Fallback estimation + if font_size <= 0: font_size = 16 + var scaled_font_size = float(font_size) * parent_label.scale.y + font_ascent = scaled_font_size * 0.8 # Estimate + font_descent = scaled_font_size * 0.2 # Estimate + printerr("SpriteFrameEffect: Could not determine font for ascent/descent calculation, using estimate.") + + # --- Calculate Position --- + var baseline_origin: Vector2 = char_fx.transform.get_origin() + + # Horizontal center (remains the same) + var center_x: float = baseline_origin.x + image_size.x / 2.0 + + # Vertical position: Align sprite center with the vertical center of the font glyph box. + # The top of the font box is at baseline_origin.y - font_ascent. + # The bottom of the font box is at baseline_origin.y + font_descent. + # The total height of the font box is font_ascent + font_descent. + # The center relative to the baseline is baseline - ascent + (total_height / 2) + # = baseline - ascent + (ascent + descent) / 2 + # = baseline - (ascent / 2) + (descent / 2) + # = baseline - (ascent - descent) / 2.0 + var center_y: float = baseline_origin.y - (font_ascent - font_descent) / 2.0 + + node.position = Vector2(center_x, center_y) + return true diff --git a/addons/twitcher/sprite_frame_effect.gd.uid b/addons/twitcher/sprite_frame_effect.gd.uid new file mode 100644 index 0000000..af9dcf3 --- /dev/null +++ b/addons/twitcher/sprite_frame_effect.gd.uid @@ -0,0 +1 @@ +uid://bih5dayr8n246 diff --git a/addons/twitcher/twitch_data.gd b/addons/twitcher/twitch_data.gd new file mode 100644 index 0000000..065a655 --- /dev/null +++ b/addons/twitcher/twitch_data.gd @@ -0,0 +1,33 @@ +extends Resource + +## Base class to track which data got changed. +class_name TwitchData + +## Contains all values that got actually changed +var _tracked: Dictionary[StringName, Variant] = {} + + +func track_data(property: StringName, value: Variant) -> bool: + if value == null: + _tracked.erase(property) + elif value is Array: + var serialized_value = [] + for value_entry in value: + if "to_dict" in value_entry: + serialized_value.append(value_entry.to_dict()) + else: + serialized_value.append(value_entry) + _tracked[property] = serialized_value + elif typeof(value) == TYPE_OBJECT && value.is_class(self.get_class()): + _tracked[property] = value.to_dict() + else: + _tracked[property] = value + return false + + +func to_dict() -> Dictionary[StringName, Variant]: + return _tracked + + +func to_json() -> String: + return JSON.stringify(to_dict()) diff --git a/addons/twitcher/twitch_data.gd.uid b/addons/twitcher/twitch_data.gd.uid new file mode 100644 index 0000000..1301e63 --- /dev/null +++ b/addons/twitcher/twitch_data.gd.uid @@ -0,0 +1 @@ +uid://bnqet63fovbgp diff --git a/addons/twitcher/twitch_oauth_setting.tres b/addons/twitcher/twitch_oauth_setting.tres new file mode 100644 index 0000000..cebaeca --- /dev/null +++ b/addons/twitcher/twitch_oauth_setting.tres @@ -0,0 +1,21 @@ +[gd_resource type="Resource" script_class="OAuthSetting" load_steps=4 format=3 uid="uid://ry64ckbckh6m"] + +[ext_resource type="Script" uid="uid://dcrliedgr6eol" path="res://addons/twitcher/lib/oOuch/crypto_key_provider.gd" id="1_54bgt"] +[ext_resource type="Script" uid="uid://00xbijwpi8xa" path="res://addons/twitcher/lib/oOuch/oauth_setting.gd" id="2_wroyb"] + +[sub_resource type="Resource" id="Resource_54bgt"] +script = ExtResource("1_54bgt") +encrpytion_secret_location = "user://encryption_key.cfg" + +[resource] +script = ExtResource("2_wroyb") +redirect_url = "http://localhost:7170" +well_known_url = "" +token_url = "https://id.twitch.tv/oauth2/token" +authorization_url = "https://id.twitch.tv/oauth2/authorize" +device_authorization_url = "https://id.twitch.tv/oauth2/device" +cache_file = "user://auth.conf" +client_id = "xqh437vs83im368db89iwflm130ufb" +authorization_flow = 0 +_encryption_key_provider = SubResource("Resource_54bgt") +client_secret = "D8bwpU1vz2zu6P9l0D3ktvctJMCuFspuG//RPTsyP8w=" diff --git a/addons/twitcher/twitch_service.gd b/addons/twitcher/twitch_service.gd new file mode 100644 index 0000000..8d9dda5 --- /dev/null +++ b/addons/twitcher/twitch_service.gd @@ -0,0 +1,392 @@ +@icon("res://addons/twitcher/assets/service-icon.svg") +@tool +extends Twitcher + +## Access to the Twitch API. Combines all the stuff the library provides. +## Makes some actions easier to use. +class_name TwitchService + +const TwitchEditorSettings = preload("res://addons/twitcher/editor/twitch_editor_settings.gd") +## When the poll doesn't end after the offical endtime + POLL_TIMEOUT_MS. The wait loop for poll end +## event will be stopped to prevent endless loops. +const POLL_TIMEOUT_MS: int = 30000 + +static var _log: TwitchLogger = TwitchLogger.new("TwitchService") + +static var instance: TwitchService + +@export var oauth_setting: OAuthSetting: + set(val): + if oauth_setting != null: + oauth_setting.changed.disconnect(update_configuration_warnings) + oauth_setting = val + if val != null: + oauth_setting.changed.connect(update_configuration_warnings) + _set_in_child("oauth_setting", val) + update_configuration_warnings() +@export var scopes: OAuthScopes: + set(val): + scopes = val + if val != null: + _set_in_child("scopes", val) + update_configuration_warnings() +@export var token: OAuthToken: + set(val): + token = val + if val != null: + _set_in_child("token", val) + update_configuration_warnings() + +@onready var auth: TwitchAuth +@onready var eventsub: TwitchEventsub +@onready var api: TwitchAPI +@onready var irc: TwitchIRC +@onready var media_loader: TwitchMediaLoader + +var _user_cache: Dictionary[String, TwitchUser] = {} + +## Cache for the current user so that no roundtrip has to be done every time get_current_user will be called +var _current_user: TwitchUser + +var _commands: Dictionary[String, TwitchCommand] = {} + +func _init() -> void: + child_entered_tree.connect(_on_child_entered) + child_exiting_tree.connect(_on_child_exiting) + + +func _ready() -> void: + _log.d("is ready") + if not is_instance_valid(token): token = TwitchEditorSettings.game_oauth_token + if not is_instance_valid(oauth_setting): oauth_setting = TwitchEditorSettings.game_oauth_setting + + +func _enter_tree() -> void: + if instance == null: instance = self + + +func _exit_tree() -> void: + if instance == self: instance = null + + +func _on_child_entered(node: Node) -> void: + if node is TwitchAuth: auth = node + if node is TwitchAPI: api = node + if node is TwitchEventsub: eventsub = node + if node is TwitchIRC: irc = node + if node is TwitchMediaLoader: media_loader = node + + if "token" in node && token != null: + node.token = token + if "scopes" in node && scopes != null: + node.scopes = scopes + if "oauth_setting" in node && oauth_setting != null: + node.oauth_setting = oauth_setting + if node.has_signal(&"unauthenticated"): + node.unauthenticated.connect(_on_unauthenticated) + update_configuration_warnings() + + +func _set_in_child(property: String, value: Variant) -> void: + for child in get_children(): + if property in child: child[property] = value + + +func _on_child_exiting(node: Node) -> void: + if node is TwitchAuth: auth = null + if node is TwitchAPI: api = null + if node is TwitchEventsub: eventsub = null + if node is TwitchIRC: irc = null + if node is TwitchMediaLoader: media_loader = null + + if node.has_signal(&"unauthenticated"): + node.unauthenticated.disconnect(_on_unauthenticated) + update_configuration_warnings() + + +## Call this to setup the complete Twitch integration whenever you need. +## It boots everything up this Lib supports. +func setup() -> bool: + if is_instance_valid(auth): + if not await auth.authorize(): return false + else: + push_error("Authorization Node got removed, can't setup twitch service") + return false + await propagate_call(&"do_setup") + for child in get_children(): + if child.has_method(&"wait_setup"): + await child.wait_setup() + + _log.i("TwitchService setup") + return true + +## Checks if the correctly setup +func is_configured() -> bool: + return _get_configuration_warnings().is_empty() + + +func _get_configuration_warnings() -> PackedStringArray: + var result: PackedStringArray = [] + if oauth_setting == null: + result.append("OAuthSetting Resource is missing") + else: + var oauth_setting_problems : PackedStringArray = oauth_setting.get_valididation_problems() + if not oauth_setting_problems.is_empty(): + result.append("OAuthSetting Resource is invalid") + result.append_array(oauth_setting_problems) + if scopes == null: + result.append("OAuthScopes Resource is missing") + if token == null: + result.append("OAuthToken Resource is missing") + return result + + +func _on_unauthenticated() -> void: + auth.authorize() + +# +# Convinient Proxy Methods +# +#region User + + +## Get data about a user by USER_ID see get_user for by username +func get_user_by_id(user_id: String) -> TwitchUser: + if _user_cache.has(user_id): return _user_cache[user_id] + if api == null: + _log.e("Please setup a TwitchAPI Node into TwitchService.") + return null + if user_id == null || user_id == "": return null + var opt = TwitchGetUsers.Opt.new() + opt.id = [user_id] as Array[String] + var user_data : TwitchGetUsers.Response = await api.get_users(opt) + if user_data.data.is_empty(): return null + var user: TwitchUser = user_data.data[0] + _user_cache[user_id] = user + return user + + +## Get data about a user by USERNAME see get_user_by_id for by user_id +func get_user(username: String) -> TwitchUser: + username = username.trim_prefix("@") + if _user_cache.has(username): return _user_cache[username] + if api == null: + _log.e("Please setup a TwitchAPI Node into TwitchService.") + return null + var opt = TwitchGetUsers.Opt.new() + opt.login = [username] as Array[String] + var user_data : TwitchGetUsers.Response = await api.get_users(opt) + if user_data.data.is_empty(): + _log.e("Username was not found: %s" % username) + return null + var user: TwitchUser = user_data.data[0] + _user_cache[username] = user + return user + + + +## Get data about a currently authenticated user (caches the value) +func get_current_user() -> TwitchUser: + if _current_user != null: + return _current_user + + if api == null: + _log.e("Please setup a TwitchAPI Node into TwitchService.") + return null + + var user_data : TwitchGetUsers.Response = await api.get_users(null) + _current_user = user_data.data[0] + return _current_user + +## Get the image of an user +func load_profile_image(user: TwitchUser) -> ImageTexture: + return await media_loader.load_profile_image(user) + +#endregion +#region EventSub + + +## Refer to https://dev.twitch.tv/docs/eventsub/eventsub-subscription-types/ for details on +## which API versions are available and which conditions are required. +func subscribe_event(definition: TwitchEventsubDefinition, conditions: Dictionary) -> TwitchEventsubConfig: + if definition == null: + _log.e("TwitchEventsubDefinition is null") + return + + var config = TwitchEventsubConfig.create(definition, conditions) + await eventsub.subscribe(config) + return config + + +## Waits for connection to eventsub. Eventsub is ready to subscribe events. +func wait_for_eventsub_connection() -> void: + if eventsub == null: + _log.e("TwitchEventsub Node is missing") + return + await eventsub.wait_for_connection() + + +## Returns all of the eventsub subscriptions (variable is a copy so you can freely modify it) +func get_subscriptions() -> Array[TwitchEventsubConfig]: + if eventsub == null: + _log.e("TwitchEventsub Node is missing") + return [] + return eventsub.get_subscriptions() + +#endregion + +#region Chat + +func chat(message: String, broadcaster: TwitchUser = null, sender: TwitchUser = null) -> void: + var current_user = await get_current_user() + if not sender: + if not current_user: return + sender = current_user + if not broadcaster: + if not current_user: return + broadcaster = current_user + var body = TwitchSendChatMessage.Body.create(broadcaster.id, sender.id, message) + api.send_chat_message(body) + + +## Sends out a shoutout to a specific user +func shoutout(user: TwitchUser, broadcaster: TwitchUser = null, moderator: TwitchUser = null) -> void: + var current_user: TwitchUser = await get_current_user() + + if not broadcaster: + if not current_user: return + broadcaster = current_user + + if not moderator: + if not current_user: return + moderator = current_user + api.send_a_shoutout(broadcaster.id, moderator.id, user.id) + + +## Sends a announcement message to the chat +func announcment(message: String, color: TwitchAnnouncementColor = TwitchAnnouncementColor.PRIMARY, broadcaster: TwitchUser = null, moderator: TwitchUser = null): + var current_user: TwitchUser = await get_current_user() + if not broadcaster: + if not current_user: return + broadcaster = current_user + + if not moderator: + if not current_user: return + moderator = current_user + + var body = TwitchSendChatAnnouncement.Body.new() + body.message = message + body.color = color.value + api.send_chat_announcement(body, moderator.id, broadcaster.id) + + +## Add a new command handler and register it for a command. +## The callback will receive [code]from_username: String, info: TwitchCommandInfo, args: PackedStringArray[/code][br] +## Args are optional depending on the configuration.[br] +## args_max == -1 => no upper limit for arguments +func add_command(command: String, callback: Callable, args_min: int = 0, args_max: int = -1, + permission_level : TwitchCommand.PermissionFlag = TwitchCommand.PermissionFlag.EVERYONE, + where : TwitchCommand.WhereFlag = TwitchCommand.WhereFlag.CHAT) -> TwitchCommand: + var command_node = TwitchCommand.new() + command_node.command = command + command_node.command_received.connect(callback) + command_node.args_min = args_min + command_node.args_max = args_max + command_node.permission_level = permission_level + command_node.where = where + add_child(command_node) + _log.i("Register command %s" % command) + return command_node + + +## Removes a command +func remove_command(command: String) -> void: + _log.i("Remove command %s" % command) + var command_node: TwitchCommand = _commands.get(command, null) + if command_node != null: + command_node.queue_free() + _commands.erase(command) + + +## Whispers to another user. +## @deprecated not supported by twitch anymore +func whisper(message: String, username: String) -> void: + _log.e("Whipser from bots aren't supported by Twitch anymore. See https://dev.twitch.tv/docs/irc/chat-commands/ at /w") + + +## Returns the definition of emotes for given channel or for the global emotes. +## Key: EmoteID as String | Value: TwitchGlobalEmote / TwitchChannelEmote +func get_emotes_data(channel_id: String = "global") -> Dictionary: + return await media_loader.get_cached_emotes(channel_id) + + +## Returns the definition of badges for given channel or for the global bages. +## Key: category / versions / badge_id | Value: TwitchChatBadge +func get_badges_data(channel_id: String = "global") -> Dictionary[String, TwitchChatBadge]: + return await media_loader.get_cached_badges(channel_id) + + +## Gets the requested emotes. +## Key: EmoteID as String | Value: SpriteFrame +func get_emotes(ids: Array[String]) -> Dictionary[String, SpriteFrames]: + return await media_loader.get_emotes(ids) + + +## Gets the requested emotes in the specified theme, scale and type. +## Loads from cache if possible otherwise downloads and transforms them. +## Key: TwitchEmoteDefinition | Value SpriteFrames +func get_emotes_by_definition(emotes: Array[TwitchEmoteDefinition]) -> Dictionary[TwitchEmoteDefinition, SpriteFrames]: + return await media_loader.get_emotes_by_definition(emotes) + + +func poll(title: String, choices: Array[String], duration: int = 60, channel_points_voting_enabled: bool = false, channel_points_per_vote: int = 1000, broadcaster_id: String = "") -> Dictionary: + if broadcaster_id == "": broadcaster_id = _current_user.id + var body_choices: Array[TwitchCreatePoll.BodyChoices] = [] + for choice: String in choices: + var body_choice = TwitchCreatePoll.BodyChoices.create(choice) + body_choices.append(body_choice) + duration = clamp(duration, 15, 1800) + var poll_body: TwitchCreatePoll.Body = TwitchCreatePoll.Body.create(broadcaster_id, title, body_choices, duration) + if channel_points_voting_enabled: + poll_body.channel_points_per_vote = channel_points_per_vote + poll_body.channel_points_voting_enabled = channel_points_voting_enabled + var poll_response: TwitchCreatePoll.Response = await api.create_poll(poll_body) + if poll_response.response.response_code != 200: + var error_message: String = poll_response.response.response_data.get_string_from_utf8() + push_error("Can't create poll response cause of ", error_message) + return {} + var poll: TwitchPoll = poll_response.data[0] + var poll_end_time: int = Time.get_ticks_msec() + duration * 1000 + POLL_TIMEOUT_MS + var event: TwitchEventsub.Event + if eventsub && eventsub.has_subscription(TwitchEventsubDefinition.CHANNEL_POLL_END, {&"broadcaster_user_id": broadcaster_id}): + var poll_ended: bool + while not poll_ended: + if poll_end_time < Time.get_ticks_msec(): + return {} + event = await eventsub.event_received + if event.type != TwitchEventsubDefinition.CHANNEL_POLL_END: continue + if event.data[&"id"] != poll.id: continue + break + else: + _log.i("Can't wait for poll end. Either eventsub is not set ot it is not listenting to ending polls") + return {} + return event.data + +#endregion +#region Cheermotes + +## Returns the data of the Cheermotes. +func get_cheermote_data() -> Array[TwitchCheermote]: + if media_loader == null: + _log.e("TwitchMediaLoader was not set within %s" % get_tree_string()) + return [] + await media_loader.preload_cheemote() + return media_loader.all_cheermotes() + + +## Returns all cheertiers in form of: +## Key: TwitchCheermote.Tiers | Value: SpriteFrames +func get_cheermotes(definition: TwitchCheermoteDefinition) -> Dictionary: + return await media_loader.get_cheermotes(definition) + +#endregion diff --git a/addons/twitcher/twitch_service.gd.uid b/addons/twitcher/twitch_service.gd.uid new file mode 100644 index 0000000..8f3e366 --- /dev/null +++ b/addons/twitcher/twitch_service.gd.uid @@ -0,0 +1 @@ +uid://i8st3lv0lidh diff --git a/addons/twitcher/twitch_service.tscn b/addons/twitcher/twitch_service.tscn new file mode 100644 index 0000000..4503cd1 --- /dev/null +++ b/addons/twitcher/twitch_service.tscn @@ -0,0 +1,56 @@ +[gd_scene load_steps=14 format=3 uid="uid://djt5lvmwxbq4a"] + +[ext_resource type="Script" uid="uid://i8st3lv0lidh" path="res://addons/twitcher/twitch_service.gd" id="1_6jm7q"] +[ext_resource type="Script" uid="uid://cw30cwveway65" path="res://addons/twitcher/generated/twitch_api.gd" id="1_yq54x"] +[ext_resource type="Resource" uid="uid://ry64ckbckh6m" path="res://addons/twitcher/twitch_oauth_setting.tres" id="2_v2pwk"] +[ext_resource type="Resource" uid="uid://fcmfkstye4bq" path="res://addons/twitcher/auth/preset_overlay_scopes.tres" id="3_n5rs1"] +[ext_resource type="Script" uid="uid://blmhj3j00yk45" path="res://addons/twitcher/eventsub/twitch_eventsub.gd" id="3_x3t7l"] +[ext_resource type="Resource" uid="uid://m7epy882axmp" path="res://addons/twitcher/default_oauth_token.tres" id="4_j0p3d"] +[ext_resource type="Script" uid="uid://bf0wi70haua35" path="res://addons/twitcher/lib/oOuch/oauth.gd" id="8_v2pwk"] +[ext_resource type="Script" uid="uid://blnbogtrshw4r" path="res://addons/twitcher/auth/twitch_token_handler.gd" id="9_n5rs1"] +[ext_resource type="Script" uid="uid://iv0mgv0lu8b0" path="res://addons/twitcher/auth/twitch_auth.gd" id="10_bqnqx"] +[ext_resource type="Texture2D" uid="uid://g1dbcjksbotw" path="res://addons/twitcher/assets/fallback_texture.tres" id="11_j0p3d"] +[ext_resource type="Script" uid="uid://d4lyup0vy1wtu" path="res://addons/twitcher/media/twitch_media_loader.gd" id="12_2tq2g"] +[ext_resource type="Script" uid="uid://6v8jnfjwbnhm" path="res://addons/twitcher/media/twitch_image_transformer.gd" id="12_uvps8"] + +[sub_resource type="Resource" id="Resource_nmcm3"] +script = ExtResource("12_uvps8") +fallback_texture = ExtResource("11_j0p3d") + +[node name="TwitchService" type="Node"] +script = ExtResource("1_6jm7q") +oauth_setting = ExtResource("2_v2pwk") +scopes = ExtResource("3_n5rs1") +token = ExtResource("4_j0p3d") + +[node name="EventSub" type="Node" parent="." node_paths=PackedStringArray("api")] +script = ExtResource("3_x3t7l") +api = NodePath("../API") +scopes = ExtResource("3_n5rs1") + +[node name="API" type="Node" parent="."] +script = ExtResource("1_yq54x") +token = ExtResource("4_j0p3d") +oauth_setting = ExtResource("2_v2pwk") + +[node name="Auth" type="Node" parent="."] +script = ExtResource("10_bqnqx") +oauth_setting = ExtResource("2_v2pwk") +token = ExtResource("4_j0p3d") +scopes = ExtResource("3_n5rs1") + +[node name="OAuth" type="Node" parent="Auth" node_paths=PackedStringArray("token_handler")] +script = ExtResource("8_v2pwk") +oauth_setting = ExtResource("2_v2pwk") +scopes = ExtResource("3_n5rs1") +token_handler = NodePath("../TokenHandler") + +[node name="TokenHandler" type="Node" parent="Auth"] +script = ExtResource("9_n5rs1") +oauth_setting = ExtResource("2_v2pwk") +token = ExtResource("4_j0p3d") + +[node name="MediaLoader" type="Node" parent="." node_paths=PackedStringArray("api")] +script = ExtResource("12_2tq2g") +api = NodePath("../API") +image_transformer = SubResource("Resource_nmcm3") diff --git a/addons/twitcher/twitcher.gd b/addons/twitcher/twitcher.gd new file mode 100644 index 0000000..4bb3f1c --- /dev/null +++ b/addons/twitcher/twitcher.gd @@ -0,0 +1,5 @@ +@icon("res://addons/twitcher/assets/twitcher-icon.svg") +extends Node + +## Parent class to group all Twitcher relevant nodes. +class_name Twitcher diff --git a/addons/twitcher/twitcher.gd.uid b/addons/twitcher/twitcher.gd.uid new file mode 100644 index 0000000..ccc22d8 --- /dev/null +++ b/addons/twitcher/twitcher.gd.uid @@ -0,0 +1 @@ +uid://dv7ewgsctdjqr diff --git a/icon.png b/icon.png new file mode 100644 index 0000000..4c9a3b8 Binary files /dev/null and b/icon.png differ diff --git a/icon.png.import b/icon.png.import new file mode 100644 index 0000000..658b058 --- /dev/null +++ b/icon.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bubprkirv227g" +path="res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.png" +dest_files=["res://.godot/imported/icon.png-487276ed1e3a0c39cad0279d744ee560.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..0ea8257 --- /dev/null +++ b/project.godot @@ -0,0 +1,35 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=5 + +[application] + +config/name="PokePurple" +config/description="Poke`mon Twitch Community Game" +config/features=PackedStringArray("4.4") +config/icon="res://icon.png" + +[autoload] + +Globals="*res://Library/Singletons/globals.tscn" + +[dotnet] + +project/assembly_name="PokePurple" + +[editor_plugins] + +enabled=PackedStringArray("res://addons/twitcher/plugin.cfg") + +[twitcher] + +editor/game_oauth_token="res://addons/twitcher/default_oauth_token.tres" +editor/game_oauth_setting="res://addons/twitcher/twitch_oauth_setting.tres" +editor/show_setup_on_startup=false +editor/project_preset=&"Game"