From c4df31a2260806a3e6944bf55a40af120454d2bc Mon Sep 17 00:00:00 2001 From: pajlada Date: Tue, 24 Sep 2024 19:49:00 +0200 Subject: [PATCH 1/4] fix: grammar in user highlights page (#5602) --- CHANGELOG.md | 1 + src/widgets/settingspages/HighlightingPage.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a11f72ffd3b..1a7c25f55f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ - Bugfix: Fixed account switch not being saved if no other settings were changed. (#5558) - Bugfix: Fixed some tooltips not being readable. (#5578) - Bugfix: Fixed log files being locked longer than needed. (#5592) +- Bugfix: Fixed grammar in the user highlight page. (#5602) - Dev: Update Windows build from Qt 6.5.0 to Qt 6.7.1. (#5420) - Dev: Update vcpkg build Qt from 6.5.0 to 6.7.0, boost from 1.83.0 to 1.85.0, openssl from 3.1.3 to 3.3.0. (#5422) - Dev: Unsingletonize `ISoundController`. (#5462) diff --git a/src/widgets/settingspages/HighlightingPage.cpp b/src/widgets/settingspages/HighlightingPage.cpp index 2a1b6884b00..a6459d9b4fe 100644 --- a/src/widgets/settingspages/HighlightingPage.cpp +++ b/src/widgets/settingspages/HighlightingPage.cpp @@ -110,8 +110,8 @@ HighlightingPage::HighlightingPage() pingUsers.emplace( "Play notification sounds and highlight messages from " "certain users.\n" - "User highlights are prioritized badge highlights, but " - "under message highlights."); + "User highlights are prioritized over badge highlights, " + "but under message highlights."); EditableModelView *view = pingUsers .emplace( From edf18a7a0f240d13747f1ab30ae8f26ea11fbeaa Mon Sep 17 00:00:00 2001 From: nerix Date: Sat, 28 Sep 2024 12:12:13 +0200 Subject: [PATCH 2/4] fix: properly display global badges for anon users (#5599) --- CHANGELOG.md | 1 + resources/twitch-badges.json | 2 +- scripts/update-badges.py | 28 +++++++++ src/providers/twitch/TwitchBadges.cpp | 86 +++++++++++++-------------- src/providers/twitch/TwitchBadges.hpp | 4 +- 5 files changed, 76 insertions(+), 45 deletions(-) create mode 100644 scripts/update-badges.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a7c25f55f5..1f4b479f218 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ - Bugfix: Fixed account switch not being saved if no other settings were changed. (#5558) - Bugfix: Fixed some tooltips not being readable. (#5578) - Bugfix: Fixed log files being locked longer than needed. (#5592) +- Bugfix: Fixed global badges not showing in anonymous mode. (#5599) - Bugfix: Fixed grammar in the user highlight page. (#5602) - Dev: Update Windows build from Qt 6.5.0 to Qt 6.7.1. (#5420) - Dev: Update vcpkg build Qt from 6.5.0 to 6.7.0, boost from 1.83.0 to 1.85.0, openssl from 3.1.3 to 3.3.0. (#5422) diff --git a/resources/twitch-badges.json b/resources/twitch-badges.json index b90fa1f25a4..4bef96a717a 100644 --- a/resources/twitch-badges.json +++ b/resources/twitch-badges.json @@ -1 +1 @@ -{"data":[{"set_id":"1979-revolution_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/1979%20Revolution/details","description":"1979 Revolution","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/7833bb6e-d20d-48ff-a58d-67fe827a4f84/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/7833bb6e-d20d-48ff-a58d-67fe827a4f84/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/7833bb6e-d20d-48ff-a58d-67fe827a4f84/3","title":"1979 Revolution"}]},{"set_id":"60-seconds_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/60%20Seconds!/details","description":"60 Seconds!","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/1e7252f9-7e80-4d3d-ae42-319f030cca99/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/1e7252f9-7e80-4d3d-ae42-319f030cca99/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/1e7252f9-7e80-4d3d-ae42-319f030cca99/3","title":"60 Seconds!"}]},{"set_id":"60-seconds_2","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/60%20Seconds!/details","description":"60 Seconds!","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/64513f7d-21dd-4a05-a699-d73761945cf9/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/64513f7d-21dd-4a05-a699-d73761945cf9/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/64513f7d-21dd-4a05-a699-d73761945cf9/3","title":"60 Seconds!"}]},{"set_id":"60-seconds_3","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/60%20Seconds!/details","description":"60 Seconds!","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/f4306617-0f96-476f-994e-5304f81bcc6e/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/f4306617-0f96-476f-994e-5304f81bcc6e/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/f4306617-0f96-476f-994e-5304f81bcc6e/3","title":"60 Seconds!"}]},{"set_id":"H1Z1_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/H1Z1/details","description":"H1Z1","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/fc71386c-86cd-11e7-a55d-43f591dc0c71/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/fc71386c-86cd-11e7-a55d-43f591dc0c71/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/fc71386c-86cd-11e7-a55d-43f591dc0c71/3","title":"H1Z1"}]},{"set_id":"admin","versions":[{"click_action":null,"click_url":null,"description":"Twitch Admin","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/9ef7e029-4cdf-4d4d-a0d5-e2b3fb2583fe/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/9ef7e029-4cdf-4d4d-a0d5-e2b3fb2583fe/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/9ef7e029-4cdf-4d4d-a0d5-e2b3fb2583fe/3","title":"Admin"}]},{"set_id":"ambassador","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/team/ambassadors","description":"Twitch Ambassador","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/2cbc339f-34f4-488a-ae51-efdf74f4e323/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/2cbc339f-34f4-488a-ae51-efdf74f4e323/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/2cbc339f-34f4-488a-ae51-efdf74f4e323/3","title":"Twitch Ambassador"}]},{"set_id":"anomaly-2_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Anomaly%202/details","description":"Anomaly 2","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/d1d1ad54-40a6-492b-882e-dcbdce5fa81e/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/d1d1ad54-40a6-492b-882e-dcbdce5fa81e/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/d1d1ad54-40a6-492b-882e-dcbdce5fa81e/3","title":"Anomaly 2"}]},{"set_id":"anomaly-warzone-earth_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Anomaly:%20Warzone%20Earth/details","description":"Anomaly Warzone Earth","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/858be873-fb1f-47e5-ad34-657f40d3d156/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/858be873-fb1f-47e5-ad34-657f40d3d156/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/858be873-fb1f-47e5-ad34-657f40d3d156/3","title":"Anomaly Warzone Earth"}]},{"set_id":"anonymous-cheerer","versions":[{"click_action":null,"click_url":null,"description":"Anonymous Cheerer","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/ca3db7f7-18f5-487e-a329-cd0b538ee979/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/ca3db7f7-18f5-487e-a329-cd0b538ee979/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/ca3db7f7-18f5-487e-a329-cd0b538ee979/3","title":"Anonymous Cheerer"}]},{"set_id":"artist-badge","versions":[{"click_action":null,"click_url":null,"description":"Artist on this Channel","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/4300a897-03dc-4e83-8c0e-c332fee7057f/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/4300a897-03dc-4e83-8c0e-c332fee7057f/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/4300a897-03dc-4e83-8c0e-c332fee7057f/3","title":"Artist"}]},{"set_id":"axiom-verge_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Axiom%20Verge/details","description":"Axiom Verge","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/f209b747-45ee-42f6-8baf-ea7542633d10/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/f209b747-45ee-42f6-8baf-ea7542633d10/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/f209b747-45ee-42f6-8baf-ea7542633d10/3","title":"Axiom Verge"}]},{"set_id":"battlechefbrigade_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Battle%20Chef%20Brigade/details","description":"Battle Chef Brigade","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/24e32e67-33cd-4227-ad96-f0a7fc836107/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/24e32e67-33cd-4227-ad96-f0a7fc836107/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/24e32e67-33cd-4227-ad96-f0a7fc836107/3","title":"Battle Chef Brigade"}]},{"set_id":"battlechefbrigade_2","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Battle%20Chef%20Brigade/details","description":"Battle Chef Brigade","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/ef1e96e8-a0f9-40b6-87af-2977d3c004bb/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/ef1e96e8-a0f9-40b6-87af-2977d3c004bb/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/ef1e96e8-a0f9-40b6-87af-2977d3c004bb/3","title":"Battle Chef Brigade"}]},{"set_id":"battlechefbrigade_3","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Battle%20Chef%20Brigade/details","description":"Battle Chef Brigade","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/107ebb20-4fcd-449a-9931-cd3f81b84c70/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/107ebb20-4fcd-449a-9931-cd3f81b84c70/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/107ebb20-4fcd-449a-9931-cd3f81b84c70/3","title":"Battle Chef Brigade"}]},{"set_id":"battlerite_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Battlerite/details","description":"Battlerite","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/484ebda9-f7fa-4c67-b12b-c80582f3cc61/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/484ebda9-f7fa-4c67-b12b-c80582f3cc61/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/484ebda9-f7fa-4c67-b12b-c80582f3cc61/3","title":"Battlerite"}]},{"set_id":"bits","versions":[{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/73b5c3fb-24f9-4a82-a852-2f475b59411c/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/73b5c3fb-24f9-4a82-a852-2f475b59411c/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/73b5c3fb-24f9-4a82-a852-2f475b59411c/3","title":"cheer 1"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"100","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/09d93036-e7ce-431c-9a9e-7044297133f2/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/09d93036-e7ce-431c-9a9e-7044297133f2/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/09d93036-e7ce-431c-9a9e-7044297133f2/3","title":"cheer 100"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"1000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/0d85a29e-79ad-4c63-a285-3acd2c66f2ba/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/0d85a29e-79ad-4c63-a285-3acd2c66f2ba/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/0d85a29e-79ad-4c63-a285-3acd2c66f2ba/3","title":"cheer 1000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"10000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/68af213b-a771-4124-b6e3-9bb6d98aa732/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/68af213b-a771-4124-b6e3-9bb6d98aa732/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/68af213b-a771-4124-b6e3-9bb6d98aa732/3","title":"cheer 10000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"100000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/96f0540f-aa63-49e1-a8b3-259ece3bd098/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/96f0540f-aa63-49e1-a8b3-259ece3bd098/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/96f0540f-aa63-49e1-a8b3-259ece3bd098/3","title":"cheer 100000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"1000000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/494d1c8e-c3b2-4d88-8528-baff57c9bd3f/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/494d1c8e-c3b2-4d88-8528-baff57c9bd3f/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/494d1c8e-c3b2-4d88-8528-baff57c9bd3f/3","title":"cheer 1000000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"1250000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/ce217209-4615-4bf8-81e3-57d06b8b9dc7/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/ce217209-4615-4bf8-81e3-57d06b8b9dc7/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/ce217209-4615-4bf8-81e3-57d06b8b9dc7/3","title":"cheer 1250000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"1500000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/c4eba5b4-17a7-40a1-a668-bc1972c1e24d/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/c4eba5b4-17a7-40a1-a668-bc1972c1e24d/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/c4eba5b4-17a7-40a1-a668-bc1972c1e24d/3","title":"cheer 1500000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"1750000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/183f1fd8-aaf4-450c-a413-e53f839f0f82/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/183f1fd8-aaf4-450c-a413-e53f839f0f82/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/183f1fd8-aaf4-450c-a413-e53f839f0f82/3","title":"cheer 1750000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"200000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/4a0b90c4-e4ef-407f-84fe-36b14aebdbb6/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/4a0b90c4-e4ef-407f-84fe-36b14aebdbb6/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/4a0b90c4-e4ef-407f-84fe-36b14aebdbb6/3","title":"cheer 200000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"2000000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/7ea89c53-1a3b-45f9-9223-d97ae19089f2/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/7ea89c53-1a3b-45f9-9223-d97ae19089f2/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/7ea89c53-1a3b-45f9-9223-d97ae19089f2/3","title":"cheer 2000000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"25000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/64ca5920-c663-4bd8-bfb1-751b4caea2dd/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/64ca5920-c663-4bd8-bfb1-751b4caea2dd/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/64ca5920-c663-4bd8-bfb1-751b4caea2dd/3","title":"cheer 25000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"2500000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/cf061daf-d571-4811-bcc2-c55c8792bc8f/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/cf061daf-d571-4811-bcc2-c55c8792bc8f/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/cf061daf-d571-4811-bcc2-c55c8792bc8f/3","title":"cheer 2500000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"300000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/ac13372d-2e94-41d1-ae11-ecd677f69bb6/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/ac13372d-2e94-41d1-ae11-ecd677f69bb6/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/ac13372d-2e94-41d1-ae11-ecd677f69bb6/3","title":"cheer 300000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"3000000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/5671797f-5e9f-478c-a2b5-eb086c8928cf/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/5671797f-5e9f-478c-a2b5-eb086c8928cf/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/5671797f-5e9f-478c-a2b5-eb086c8928cf/3","title":"cheer 3000000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"3500000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/c3d218f5-1e45-419d-9c11-033a1ae54d3a/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/c3d218f5-1e45-419d-9c11-033a1ae54d3a/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/c3d218f5-1e45-419d-9c11-033a1ae54d3a/3","title":"cheer 3500000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"400000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/a8f393af-76e6-4aa2-9dd0-7dcc1c34f036/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/a8f393af-76e6-4aa2-9dd0-7dcc1c34f036/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/a8f393af-76e6-4aa2-9dd0-7dcc1c34f036/3","title":"cheer 400000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"4000000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/79fe642a-87f3-40b1-892e-a341747b6e08/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/79fe642a-87f3-40b1-892e-a341747b6e08/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/79fe642a-87f3-40b1-892e-a341747b6e08/3","title":"cheer 4000000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"4500000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/736d4156-ac67-4256-a224-3e6e915436db/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/736d4156-ac67-4256-a224-3e6e915436db/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/736d4156-ac67-4256-a224-3e6e915436db/3","title":"cheer 4500000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"5000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/57cd97fc-3e9e-4c6d-9d41-60147137234e/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/57cd97fc-3e9e-4c6d-9d41-60147137234e/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/57cd97fc-3e9e-4c6d-9d41-60147137234e/3","title":"cheer 5000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"50000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/62310ba7-9916-4235-9eba-40110d67f85d/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/62310ba7-9916-4235-9eba-40110d67f85d/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/62310ba7-9916-4235-9eba-40110d67f85d/3","title":"cheer 50000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"500000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/f6932b57-6a6e-4062-a770-dfbd9f4302e5/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/f6932b57-6a6e-4062-a770-dfbd9f4302e5/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/f6932b57-6a6e-4062-a770-dfbd9f4302e5/3","title":"cheer 500000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"5000000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/3f085f85-8d15-4a03-a829-17fca7bf1bc2/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/3f085f85-8d15-4a03-a829-17fca7bf1bc2/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/3f085f85-8d15-4a03-a829-17fca7bf1bc2/3","title":"cheer 5000000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"600000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/4d908059-f91c-4aef-9acb-634434f4c32e/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/4d908059-f91c-4aef-9acb-634434f4c32e/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/4d908059-f91c-4aef-9acb-634434f4c32e/3","title":"cheer 600000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"700000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/a1d2a824-f216-4b9f-9642-3de8ed370957/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/a1d2a824-f216-4b9f-9642-3de8ed370957/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/a1d2a824-f216-4b9f-9642-3de8ed370957/3","title":"cheer 700000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"75000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/ce491fa4-b24f-4f3b-b6ff-44b080202792/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/ce491fa4-b24f-4f3b-b6ff-44b080202792/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/ce491fa4-b24f-4f3b-b6ff-44b080202792/3","title":"cheer 75000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"800000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/5ec2ee3e-5633-4c2a-8e77-77473fe409e6/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/5ec2ee3e-5633-4c2a-8e77-77473fe409e6/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/5ec2ee3e-5633-4c2a-8e77-77473fe409e6/3","title":"cheer 800000"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":" ","id":"900000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/088c58c6-7c38-45ba-8f73-63ef24189b84/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/088c58c6-7c38-45ba-8f73-63ef24189b84/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/088c58c6-7c38-45ba-8f73-63ef24189b84/3","title":"cheer 900000"}]},{"set_id":"bits-charity","versions":[{"click_action":"visit_url","click_url":"https://link.twitch.tv/blizzardofbits","description":"Supported their favorite streamer during the 2018 Blizzard of Bits","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/a539dc18-ae19-49b0-98c4-8391a594332b/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/a539dc18-ae19-49b0-98c4-8391a594332b/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/a539dc18-ae19-49b0-98c4-8391a594332b/3","title":"Direct Relief - Charity 2018"}]},{"set_id":"bits-leader","versions":[{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":"Ranked as a top cheerer on this channel","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/8bedf8c3-7a6d-4df2-b62f-791b96a5dd31/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/8bedf8c3-7a6d-4df2-b62f-791b96a5dd31/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/8bedf8c3-7a6d-4df2-b62f-791b96a5dd31/3","title":"Bits Leader 1"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":"Ranked as a top cheerer on this channel","id":"2","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/f04baac7-9141-4456-a0e7-6301bcc34138/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/f04baac7-9141-4456-a0e7-6301bcc34138/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/f04baac7-9141-4456-a0e7-6301bcc34138/3","title":"Bits Leader 2"},{"click_action":"visit_url","click_url":"https://bits.twitch.tv","description":"Ranked as a top cheerer on this channel","id":"3","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/f1d2aab6-b647-47af-965b-84909cf303aa/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/f1d2aab6-b647-47af-965b-84909cf303aa/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/f1d2aab6-b647-47af-965b-84909cf303aa/3","title":"Bits Leader 3"}]},{"set_id":"brawlhalla_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Brawlhalla/details","description":"Brawlhalla","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/bf6d6579-ab02-4f0a-9f64-a51c37040858/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/bf6d6579-ab02-4f0a-9f64-a51c37040858/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/bf6d6579-ab02-4f0a-9f64-a51c37040858/3","title":"Brawlhalla"}]},{"set_id":"broadcaster","versions":[{"click_action":null,"click_url":null,"description":"Broadcaster","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/5527c58c-fb7d-422d-b71b-f309dcb85cc1/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/5527c58c-fb7d-422d-b71b-f309dcb85cc1/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/5527c58c-fb7d-422d-b71b-f309dcb85cc1/3","title":"Broadcaster"}]},{"set_id":"broken-age_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Broken%20Age/details","description":"Broken Age","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/56885ed2-9a09-4c8e-8131-3eb9ec15af94/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/56885ed2-9a09-4c8e-8131-3eb9ec15af94/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/56885ed2-9a09-4c8e-8131-3eb9ec15af94/3","title":"Broken Age"}]},{"set_id":"bubsy-the-woolies_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Bubsy:%20The%20Woolies%20Strike%20Back/details","description":"Bubsy: The Woolies Strike Back","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/c8129382-1f4e-4d15-a8d2-48bdddba9b81/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/c8129382-1f4e-4d15-a8d2-48bdddba9b81/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/c8129382-1f4e-4d15-a8d2-48bdddba9b81/3","title":"Bubsy: The Woolies Strike Back"}]},{"set_id":"chatter-cs-go-2022","versions":[{"click_action":null,"click_url":null,"description":"Chatted during CS:GO Week Brazil 2022","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/57b6bd6b-a1b5-4204-9e6c-eb8ed5831603/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/57b6bd6b-a1b5-4204-9e6c-eb8ed5831603/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/57b6bd6b-a1b5-4204-9e6c-eb8ed5831603/3","title":"CS:GO Week Brazil 2022"}]},{"set_id":"clip-champ","versions":[{"click_action":"visit_url","click_url":"https://help.twitch.tv/customer/portal/articles/2918323-clip-champs-guide","description":"Power Clipper","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/f38976e0-ffc9-11e7-86d6-7f98b26a9d79/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/f38976e0-ffc9-11e7-86d6-7f98b26a9d79/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/f38976e0-ffc9-11e7-86d6-7f98b26a9d79/3","title":"Power Clipper"}]},{"set_id":"creator-cs-go-2022","versions":[{"click_action":null,"click_url":null,"description":"Streamed during CS:GO Week Brazil 2022","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/a2ea6df9-ac0a-4956-bfe9-e931f50b94fa/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/a2ea6df9-ac0a-4956-bfe9-e931f50b94fa/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/a2ea6df9-ac0a-4956-bfe9-e931f50b94fa/3","title":"CS:GO Week Brazil 2022"}]},{"set_id":"cuphead_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Cuphead/details","description":"Cuphead","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/4384659a-a2e3-11e7-a564-87f6b1288bab/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/4384659a-a2e3-11e7-a564-87f6b1288bab/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/4384659a-a2e3-11e7-a564-87f6b1288bab/3","title":"Cuphead"}]},{"set_id":"darkest-dungeon_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Darkest%20Dungeon/details","description":"Darkest Dungeon","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/52a98ddd-cc79-46a8-9fe3-30f8c719bc2d/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/52a98ddd-cc79-46a8-9fe3-30f8c719bc2d/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/52a98ddd-cc79-46a8-9fe3-30f8c719bc2d/3","title":"Darkest Dungeon"}]},{"set_id":"deceit_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Deceit/details","description":"Deceit","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/b14fef48-4ff9-4063-abf6-579489234fe9/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/b14fef48-4ff9-4063-abf6-579489234fe9/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/b14fef48-4ff9-4063-abf6-579489234fe9/3","title":"Deceit"}]},{"set_id":"devil-may-cry-hd_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Devil%20May%20Cry%20HD%20Collection/details","description":"Devil May Cry HD Collection","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/633877d4-a91c-4c36-b75b-803f82b1352f/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/633877d4-a91c-4c36-b75b-803f82b1352f/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/633877d4-a91c-4c36-b75b-803f82b1352f/3","title":"Devil May Cry HD Collection"}]},{"set_id":"devil-may-cry-hd_2","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Devil%20May%20Cry%20HD%20Collection/details","description":"Devil May Cry HD Collection","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/408548fe-aa74-4d53-b5e9-960103d9b865/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/408548fe-aa74-4d53-b5e9-960103d9b865/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/408548fe-aa74-4d53-b5e9-960103d9b865/3","title":"Devil May Cry HD Collection"}]},{"set_id":"devil-may-cry-hd_3","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Devil%20May%20Cry%20HD%20Collection/details","description":"Devil May Cry HD Collection","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/df84c5bf-8d66-48e2-b9fb-c014cc9b3945/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/df84c5bf-8d66-48e2-b9fb-c014cc9b3945/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/df84c5bf-8d66-48e2-b9fb-c014cc9b3945/3","title":"Devil May Cry HD Collection"}]},{"set_id":"devil-may-cry-hd_4","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Devil%20May%20Cry%20HD%20Collection/details","description":"Devil May Cry HD Collection","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/af836b94-8ffd-4c0a-b7d8-a92fad5e3015/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/af836b94-8ffd-4c0a-b7d8-a92fad5e3015/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/af836b94-8ffd-4c0a-b7d8-a92fad5e3015/3","title":"Devil May Cry HD Collection"}]},{"set_id":"devilian_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Devilian/details","description":"Devilian","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/3cb92b57-1eef-451c-ac23-4d748128b2c5/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/3cb92b57-1eef-451c-ac23-4d748128b2c5/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/3cb92b57-1eef-451c-ac23-4d748128b2c5/3","title":"Devilian"}]},{"set_id":"duelyst_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Duelyst/details","description":"Duelyst","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/7d9c12f4-a2ac-4e88-8026-d1a330468282/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/7d9c12f4-a2ac-4e88-8026-d1a330468282/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/7d9c12f4-a2ac-4e88-8026-d1a330468282/3","title":"Duelyst"}]},{"set_id":"duelyst_2","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Duelyst/details","description":"Duelyst","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/1938acd3-2d18-471d-b1af-44f2047c033c/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/1938acd3-2d18-471d-b1af-44f2047c033c/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/1938acd3-2d18-471d-b1af-44f2047c033c/3","title":"Duelyst"}]},{"set_id":"duelyst_3","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Duelyst/details","description":"Duelyst","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/344c07fc-1632-47c6-9785-e62562a6b760/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/344c07fc-1632-47c6-9785-e62562a6b760/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/344c07fc-1632-47c6-9785-e62562a6b760/3","title":"Duelyst"}]},{"set_id":"duelyst_4","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Duelyst/details","description":"Duelyst","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/39e717a8-00bc-49cc-b6d4-3ea91ee1be25/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/39e717a8-00bc-49cc-b6d4-3ea91ee1be25/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/39e717a8-00bc-49cc-b6d4-3ea91ee1be25/3","title":"Duelyst"}]},{"set_id":"duelyst_5","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Duelyst/details","description":"Duelyst","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/290419b6-484a-47da-ad14-a99d6581f758/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/290419b6-484a-47da-ad14-a99d6581f758/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/290419b6-484a-47da-ad14-a99d6581f758/3","title":"Duelyst"}]},{"set_id":"duelyst_6","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Duelyst/details","description":"Duelyst","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/c5e54a4b-0bf1-463a-874a-38524579aed0/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/c5e54a4b-0bf1-463a-874a-38524579aed0/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/c5e54a4b-0bf1-463a-874a-38524579aed0/3","title":"Duelyst"}]},{"set_id":"duelyst_7","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Duelyst/details","description":"Duelyst","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/cf508179-3183-4987-97e0-56ca44babb9f/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/cf508179-3183-4987-97e0-56ca44babb9f/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/cf508179-3183-4987-97e0-56ca44babb9f/3","title":"Duelyst"}]},{"set_id":"enter-the-gungeon_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Enter%20the%20Gungeon/details","description":"Enter The Gungeon","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/53c9af0b-84f6-4f9d-8c80-4bc51321a37d/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/53c9af0b-84f6-4f9d-8c80-4bc51321a37d/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/53c9af0b-84f6-4f9d-8c80-4bc51321a37d/3","title":"Enter The Gungeon"}]},{"set_id":"eso_1","versions":[{"click_action":null,"click_url":null,"description":"Elder Scrolls Online","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/18647a68-a35f-48d7-bf97-ae5deb6b277d/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/18647a68-a35f-48d7-bf97-ae5deb6b277d/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/18647a68-a35f-48d7-bf97-ae5deb6b277d/3","title":"Elder Scrolls Online"}]},{"set_id":"extension","versions":[{"click_action":null,"click_url":null,"description":"Extension","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/ea8b0f8c-aa27-11e8-ba0c-1370ffff3854/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/ea8b0f8c-aa27-11e8-ba0c-1370ffff3854/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/ea8b0f8c-aa27-11e8-ba0c-1370ffff3854/3","title":"Extension"}]},{"set_id":"firewatch_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Firewatch/details","description":"Firewatch","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/b6bf4889-4902-49e2-9658-c0132e71c9c4/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/b6bf4889-4902-49e2-9658-c0132e71c9c4/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/b6bf4889-4902-49e2-9658-c0132e71c9c4/3","title":"Firewatch"}]},{"set_id":"founder","versions":[{"click_action":"visit_url","click_url":"https://help.twitch.tv/s/article/founders-badge","description":"Founder","id":"0","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/511b78a9-ab37-472f-9569-457753bbe7d3/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/511b78a9-ab37-472f-9569-457753bbe7d3/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/511b78a9-ab37-472f-9569-457753bbe7d3/3","title":"Founder"}]},{"set_id":"frozen-cortext_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Frozen%20Cortex/details","description":"Frozen Cortext","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/2015f087-01b5-4a01-a2bb-ecb4d6be5240/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/2015f087-01b5-4a01-a2bb-ecb4d6be5240/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/2015f087-01b5-4a01-a2bb-ecb4d6be5240/3","title":"Frozen Cortext"}]},{"set_id":"frozen-synapse_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Frozen%20Synapse/details","description":"Frozen Synapse","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/d4bd464d-55ea-4238-a11d-744f034e2375/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/d4bd464d-55ea-4238-a11d-744f034e2375/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/d4bd464d-55ea-4238-a11d-744f034e2375/3","title":"Frozen Synapse"}]},{"set_id":"game-developer","versions":[{"click_action":null,"click_url":null,"description":"Game Developer for:","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/85856a4a-eb7d-4e26-a43e-d204a977ade4/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/85856a4a-eb7d-4e26-a43e-d204a977ade4/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/85856a4a-eb7d-4e26-a43e-d204a977ade4/3","title":"Game Developer"}]},{"set_id":"getting-over-it_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Getting%20Over%20It/details","description":"Getting Over It","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/8d4e178c-81ec-4c71-af68-745b40733984/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/8d4e178c-81ec-4c71-af68-745b40733984/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/8d4e178c-81ec-4c71-af68-745b40733984/3","title":"Getting Over It"}]},{"set_id":"getting-over-it_2","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Getting%20Over%20It/details","description":"Getting Over It","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/bb620b42-e0e1-4373-928e-d4a732f99ccb/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/bb620b42-e0e1-4373-928e-d4a732f99ccb/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/bb620b42-e0e1-4373-928e-d4a732f99ccb/3","title":"Getting Over It"}]},{"set_id":"glhf-pledge","versions":[{"click_action":"visit_url","click_url":"https://www.anykey.org/pledge","description":"Signed the GLHF pledge in support for inclusive gaming communities","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/3158e758-3cb4-43c5-94b3-7639810451c5/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/3158e758-3cb4-43c5-94b3-7639810451c5/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/3158e758-3cb4-43c5-94b3-7639810451c5/3","title":"GLHF Pledge"}]},{"set_id":"glitchcon2020","versions":[{"click_action":"visit_url","click_url":"https://www.twitchcon.com/","description":"Earned for Watching Glitchcon 2020","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/1d4b03b9-51ea-42c9-8f29-698e3c85be3d/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/1d4b03b9-51ea-42c9-8f29-698e3c85be3d/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/1d4b03b9-51ea-42c9-8f29-698e3c85be3d/3","title":"GlitchCon 2020"}]},{"set_id":"global_mod","versions":[{"click_action":null,"click_url":null,"description":"Global Moderator","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/9384c43e-4ce7-4e94-b2a1-b93656896eba/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/9384c43e-4ce7-4e94-b2a1-b93656896eba/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/9384c43e-4ce7-4e94-b2a1-b93656896eba/3","title":"Global Moderator"}]},{"set_id":"gold-pixel-heart","versions":[{"click_action":"visit_url","click_url":"https://help.twitch.tv/s/article/twitch-charity","description":"Thank you for donating via the Twitch Charity tool during Twitch Together for Good 2023!","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/1687873b-cf38-412c-aad3-f9a4ce17f8b6/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/1687873b-cf38-412c-aad3-f9a4ce17f8b6/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/1687873b-cf38-412c-aad3-f9a4ce17f8b6/3","title":"Gold Pixel Heart"}]},{"set_id":"heavy-bullets_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Heavy%20Bullets/details","description":"Heavy Bullets","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/fc83b76b-f8b2-4519-9f61-6faf84eef4cd/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/fc83b76b-f8b2-4519-9f61-6faf84eef4cd/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/fc83b76b-f8b2-4519-9f61-6faf84eef4cd/3","title":"Heavy Bullets"}]},{"set_id":"hello_neighbor_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Hello%20Neighbor/details","description":"Hello Neighbor","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/030cab2c-5d14-11e7-8d91-43a5a4306286/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/030cab2c-5d14-11e7-8d91-43a5a4306286/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/030cab2c-5d14-11e7-8d91-43a5a4306286/3","title":"Hello Neighbor"}]},{"set_id":"hype-train","versions":[{"click_action":"visit_url","click_url":"https://help.twitch.tv/s/article/hype-train-guide","description":"Top supporter during the most recent hype train","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/fae4086c-3190-44d4-83c8-8ef0cbe1a515/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/fae4086c-3190-44d4-83c8-8ef0cbe1a515/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/fae4086c-3190-44d4-83c8-8ef0cbe1a515/3","title":"Current Hype Train Conductor"},{"click_action":"visit_url","click_url":"https://help.twitch.tv/s/article/hype-train-guide","description":"Top supporter during prior hype trains","id":"2","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/9c8d038a-3a29-45ea-96d4-5031fb1a7a81/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/9c8d038a-3a29-45ea-96d4-5031fb1a7a81/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/9c8d038a-3a29-45ea-96d4-5031fb1a7a81/3","title":"Former Hype Train Conductor"}]},{"set_id":"innerspace_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Innerspace/details","description":"Innerspace","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/97532ccd-6a07-42b5-aecf-3458b6b3ebea/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/97532ccd-6a07-42b5-aecf-3458b6b3ebea/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/97532ccd-6a07-42b5-aecf-3458b6b3ebea/3","title":"Innerspace"}]},{"set_id":"innerspace_2","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Innerspace/details","description":"Innerspace","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/fc7d6018-657a-40e4-9246-0acdc85886d1/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/fc7d6018-657a-40e4-9246-0acdc85886d1/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/fc7d6018-657a-40e4-9246-0acdc85886d1/3","title":"Innerspace"}]},{"set_id":"jackbox-party-pack_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/The%20Jackbox%20Party%20Pack/details","description":"Jackbox Party Pack","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/0f964fc1-f439-485f-a3c0-905294ee70e8/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/0f964fc1-f439-485f-a3c0-905294ee70e8/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/0f964fc1-f439-485f-a3c0-905294ee70e8/3","title":"Jackbox Party Pack"}]},{"set_id":"kingdom-new-lands_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Kingdom:%20New%20Lands/details","description":"Kingdom: New Lands","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/e3c2a67e-ef80-4fe3-ae41-b933cd11788a/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/e3c2a67e-ef80-4fe3-ae41-b933cd11788a/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/e3c2a67e-ef80-4fe3-ae41-b933cd11788a/3","title":"Kingdom: New Lands"}]},{"set_id":"moderator","versions":[{"click_action":null,"click_url":null,"description":"Moderator","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/3267646d-33f0-4b17-b3df-f923a41db1d0/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/3267646d-33f0-4b17-b3df-f923a41db1d0/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/3267646d-33f0-4b17-b3df-f923a41db1d0/3","title":"Moderator"}]},{"set_id":"moments","versions":[{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 1 moment on a channel","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/bf370830-d79a-497b-81c6-a365b2b60dda/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/bf370830-d79a-497b-81c6-a365b2b60dda/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/bf370830-d79a-497b-81c6-a365b2b60dda/3","title":"Moments Badge - Tier 1"},{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 75 moments on a channel","id":"10","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/9c13f2b6-69cd-4537-91b4-4a8bd8b6b1fd/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/9c13f2b6-69cd-4537-91b4-4a8bd8b6b1fd/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/9c13f2b6-69cd-4537-91b4-4a8bd8b6b1fd/3","title":"Moments Badge - Tier 10"},{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 90 moments on a channel","id":"11","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/7573e7a2-0f1f-4508-b833-d822567a1e03/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/7573e7a2-0f1f-4508-b833-d822567a1e03/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/7573e7a2-0f1f-4508-b833-d822567a1e03/3","title":"Moments Badge - Tier 11"},{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 105 moments on a channel","id":"12","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/f2c91d14-85c8-434b-a6c0-6d7930091150/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/f2c91d14-85c8-434b-a6c0-6d7930091150/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/f2c91d14-85c8-434b-a6c0-6d7930091150/3","title":"Moments Badge - Tier 12"},{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 120 moments on a channel","id":"13","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/35eb3395-a1d3-4170-969a-86402ecfb11a/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/35eb3395-a1d3-4170-969a-86402ecfb11a/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/35eb3395-a1d3-4170-969a-86402ecfb11a/3","title":"Moments Badge - Tier 13"},{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 140 moments on a channel","id":"14","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/cb40eb03-1015-45ba-8793-51c66a24a3d5/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/cb40eb03-1015-45ba-8793-51c66a24a3d5/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/cb40eb03-1015-45ba-8793-51c66a24a3d5/3","title":"Moments Badge - Tier 14"},{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 160 moments on a channel","id":"15","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/b241d667-280b-4183-96ae-2d0053631186/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/b241d667-280b-4183-96ae-2d0053631186/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/b241d667-280b-4183-96ae-2d0053631186/3","title":"Moments Badge - Tier 15"},{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 180 moments on a channel","id":"16","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/5684d1bc-8132-4a4f-850c-18d3c5bd04f3/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/5684d1bc-8132-4a4f-850c-18d3c5bd04f3/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/5684d1bc-8132-4a4f-850c-18d3c5bd04f3/3","title":"Moments Badge - Tier 16"},{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 200 moments on a channel","id":"17","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/3b08c1ee-0f77-451b-9226-b5b22d7f023c/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/3b08c1ee-0f77-451b-9226-b5b22d7f023c/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/3b08c1ee-0f77-451b-9226-b5b22d7f023c/3","title":"Moments Badge - Tier 17"},{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 225 moments on a channel","id":"18","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/14057e75-080c-42da-a412-6232c6f33b68/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/14057e75-080c-42da-a412-6232c6f33b68/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/14057e75-080c-42da-a412-6232c6f33b68/3","title":"Moments Badge - Tier 18"},{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 250 moments on a channel","id":"19","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/6100cc6f-6b4b-4a3d-a55b-a5b34edb5ea1/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/6100cc6f-6b4b-4a3d-a55b-a5b34edb5ea1/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/6100cc6f-6b4b-4a3d-a55b-a5b34edb5ea1/3","title":"Moments Badge - Tier 19"},{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 5 moments on a channel","id":"2","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/fc46b10c-5b45-43fd-81ad-d5cb0de6d2f4/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/fc46b10c-5b45-43fd-81ad-d5cb0de6d2f4/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/fc46b10c-5b45-43fd-81ad-d5cb0de6d2f4/3","title":"Moments Badge - Tier 2"},{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 275 moments on a channel","id":"20","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/43399796-e74c-4741-a975-56202f0af30e/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/43399796-e74c-4741-a975-56202f0af30e/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/43399796-e74c-4741-a975-56202f0af30e/3","title":"Moments Badge - Tier 20"},{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 10 moments on a channel","id":"3","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/d08658d7-205f-4f75-ad44-8c6e0acd8ef6/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/d08658d7-205f-4f75-ad44-8c6e0acd8ef6/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/d08658d7-205f-4f75-ad44-8c6e0acd8ef6/3","title":"Moments Badge - Tier 3"},{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 15 moments on a channel","id":"4","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/fe5b5ddc-93e7-4aaf-9b3e-799cd41808b1/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/fe5b5ddc-93e7-4aaf-9b3e-799cd41808b1/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/fe5b5ddc-93e7-4aaf-9b3e-799cd41808b1/3","title":"Moments Badge - Tier 4"},{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 20 moments on a channel","id":"5","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/c8a0d95a-856e-4097-9fc0-7765300a4f58/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/c8a0d95a-856e-4097-9fc0-7765300a4f58/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/c8a0d95a-856e-4097-9fc0-7765300a4f58/3","title":"Moments Badge - Tier 5"},{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 30 moments on a channel","id":"6","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/f9e3b4e4-200e-4045-bd71-3a6b480c23ae/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/f9e3b4e4-200e-4045-bd71-3a6b480c23ae/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/f9e3b4e4-200e-4045-bd71-3a6b480c23ae/3","title":"Moments Badge - Tier 6"},{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 40 moments on a channel","id":"7","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/a90a26a4-fdf7-4ac3-a782-76a413da16c1/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/a90a26a4-fdf7-4ac3-a782-76a413da16c1/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/a90a26a4-fdf7-4ac3-a782-76a413da16c1/3","title":"Moments Badge - Tier 7"},{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 50 moments on a channel","id":"8","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/f22286cd-6aa3-42ce-b3fb-10f5d18c4aa0/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/f22286cd-6aa3-42ce-b3fb-10f5d18c4aa0/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/f22286cd-6aa3-42ce-b3fb-10f5d18c4aa0/3","title":"Moments Badge - Tier 8"},{"click_action":null,"click_url":null,"description":"Earned for being a part of at least 60 moments on a channel","id":"9","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/5cb2e584-1efd-469b-ab1d-4d1b59a944e7/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/5cb2e584-1efd-469b-ab1d-4d1b59a944e7/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/5cb2e584-1efd-469b-ab1d-4d1b59a944e7/3","title":"Moments Badge - Tier 9"}]},{"set_id":"no_audio","versions":[{"click_action":null,"click_url":null,"description":"Individuals with unreliable or no sound can select this badge","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/aef2cd08-f29b-45a1-8c12-d44d7fd5e6f0/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/aef2cd08-f29b-45a1-8c12-d44d7fd5e6f0/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/aef2cd08-f29b-45a1-8c12-d44d7fd5e6f0/3","title":"Watching without audio"}]},{"set_id":"no_video","versions":[{"click_action":null,"click_url":null,"description":"Individuals with unreliable or no video can select this badge","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/199a0dba-58f3-494e-a7fc-1fa0a1001fb8/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/199a0dba-58f3-494e-a7fc-1fa0a1001fb8/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/199a0dba-58f3-494e-a7fc-1fa0a1001fb8/3","title":"Listening only"}]},{"set_id":"okhlos_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Okhlos/details","description":"Okhlos","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/dc088bd6-8965-4907-a1a2-c0ba83874a7d/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/dc088bd6-8965-4907-a1a2-c0ba83874a7d/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/dc088bd6-8965-4907-a1a2-c0ba83874a7d/3","title":"Okhlos"}]},{"set_id":"overwatch-league-insider_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/overwatchleague","description":"OWL All-Access Pass 2018","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/51e9e0aa-12e3-48ce-b961-421af0787dad/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/51e9e0aa-12e3-48ce-b961-421af0787dad/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/51e9e0aa-12e3-48ce-b961-421af0787dad/3","title":"OWL All-Access Pass 2018"}]},{"set_id":"overwatch-league-insider_2018B","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/overwatchleague","description":"OWL All-Access Pass 2018","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/34ec1979-d9bb-4706-ad15-464de814a79d/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/34ec1979-d9bb-4706-ad15-464de814a79d/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/34ec1979-d9bb-4706-ad15-464de814a79d/3","title":"OWL All-Access Pass 2018"}]},{"set_id":"overwatch-league-insider_2019A","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/overwatchleague","description":"OWL All-Access Pass 2019","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/ca980da1-3639-48a6-95a3-a03b002eb0e5/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/ca980da1-3639-48a6-95a3-a03b002eb0e5/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/ca980da1-3639-48a6-95a3-a03b002eb0e5/3","title":"OWL All-Access Pass 2019"},{"click_action":"visit_url","click_url":"https://www.twitch.tv/overwatchleague","description":"OWL All-Access Pass 2019","id":"2","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/ab7fa7a7-c2d9-403f-9f33-215b29b43ce4/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/ab7fa7a7-c2d9-403f-9f33-215b29b43ce4/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/ab7fa7a7-c2d9-403f-9f33-215b29b43ce4/3","title":"OWL All-Access Pass 2019"}]},{"set_id":"overwatch-league-insider_2019B","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/overwatchleague","description":"OWL All-Access Pass 2019","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/c5860811-d714-4413-9433-d6b1c9fc803c/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/c5860811-d714-4413-9433-d6b1c9fc803c/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/c5860811-d714-4413-9433-d6b1c9fc803c/3","title":"OWL All-Access Pass 2019"},{"click_action":"visit_url","click_url":"https://www.twitch.tv/overwatchleague","description":"OWL All-Access Pass 2019","id":"2","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/75f05d4b-3042-415c-8b0b-e87620a24daf/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/75f05d4b-3042-415c-8b0b-e87620a24daf/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/75f05d4b-3042-415c-8b0b-e87620a24daf/3","title":"OWL All-Access Pass 2019"},{"click_action":"visit_url","click_url":"https://www.twitch.tv/overwatchleague","description":"OWL All-Access Pass 2019","id":"3","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/765a0dcf-2a94-43ff-9b9c-ef6c209b90cd/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/765a0dcf-2a94-43ff-9b9c-ef6c209b90cd/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/765a0dcf-2a94-43ff-9b9c-ef6c209b90cd/3","title":"OWL All-Access Pass 2019"},{"click_action":"visit_url","click_url":"https://www.twitch.tv/overwatchleague","description":"OWL All-Access Pass 2019","id":"4","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/a8ae0ccd-783d-460d-93ee-57c485c558a6/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/a8ae0ccd-783d-460d-93ee-57c485c558a6/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/a8ae0ccd-783d-460d-93ee-57c485c558a6/3","title":"OWL All-Access Pass 2019"},{"click_action":"visit_url","click_url":"https://www.twitch.tv/overwatchleague","description":"OWL All-Access Pass 2019","id":"5","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/be87fd6d-1560-4e33-9ba4-2401b58d901f/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/be87fd6d-1560-4e33-9ba4-2401b58d901f/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/be87fd6d-1560-4e33-9ba4-2401b58d901f/3","title":"OWL All-Access Pass 2019"}]},{"set_id":"partner","versions":[{"click_action":"visit_url","click_url":"https://blog.twitch.tv/2017/04/24/the-verified-badge-is-here-13381bc05735","description":"Verified","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/d12a2e27-16f6-41d0-ab77-b780518f00a3/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/d12a2e27-16f6-41d0-ab77-b780518f00a3/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/d12a2e27-16f6-41d0-ab77-b780518f00a3/3","title":"Verified"}]},{"set_id":"power-rangers","versions":[{"click_action":null,"click_url":null,"description":"Black Ranger","id":"0","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/9edf3e7f-62e4-40f5-86ab-7a646b10f1f0/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/9edf3e7f-62e4-40f5-86ab-7a646b10f1f0/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/9edf3e7f-62e4-40f5-86ab-7a646b10f1f0/3","title":"Black Ranger"},{"click_action":null,"click_url":null,"description":"Blue Ranger","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/1eeae8fe-5bc6-44ed-9c88-fb84d5e0df52/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/1eeae8fe-5bc6-44ed-9c88-fb84d5e0df52/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/1eeae8fe-5bc6-44ed-9c88-fb84d5e0df52/3","title":"Blue Ranger"},{"click_action":null,"click_url":null,"description":"Green Ranger","id":"2","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/21bbcd6d-1751-4d28-a0c3-0b72453dd823/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/21bbcd6d-1751-4d28-a0c3-0b72453dd823/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/21bbcd6d-1751-4d28-a0c3-0b72453dd823/3","title":"Green Ranger"},{"click_action":null,"click_url":null,"description":"Pink Ranger","id":"3","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/5c58cb40-9028-4d16-af67-5bc0c18b745e/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/5c58cb40-9028-4d16-af67-5bc0c18b745e/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/5c58cb40-9028-4d16-af67-5bc0c18b745e/3","title":"Pink Ranger"},{"click_action":null,"click_url":null,"description":"Red Ranger","id":"4","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/8843d2de-049f-47d5-9794-b6517903db61/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/8843d2de-049f-47d5-9794-b6517903db61/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/8843d2de-049f-47d5-9794-b6517903db61/3","title":"Red Ranger"},{"click_action":null,"click_url":null,"description":"White Ranger","id":"5","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/06c85e34-477e-4939-9537-fd9978976042/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/06c85e34-477e-4939-9537-fd9978976042/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/06c85e34-477e-4939-9537-fd9978976042/3","title":"White Ranger"},{"click_action":null,"click_url":null,"description":"Yellow Ranger","id":"6","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/d6dca630-1ca4-48de-94e7-55ed0a24d8d1/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/d6dca630-1ca4-48de-94e7-55ed0a24d8d1/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/d6dca630-1ca4-48de-94e7-55ed0a24d8d1/3","title":"Yellow Ranger"}]},{"set_id":"predictions","versions":[{"click_action":null,"click_url":null,"description":"Predicted Outcome One","id":"blue-1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/e33d8b46-f63b-4e67-996d-4a7dcec0ad33/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/e33d8b46-f63b-4e67-996d-4a7dcec0ad33/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/e33d8b46-f63b-4e67-996d-4a7dcec0ad33/3","title":"Predicted Blue (1)"},{"click_action":null,"click_url":null,"description":"Predicted Outcome Ten","id":"blue-10","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/072ae906-ecf7-44f1-ac69-a5b2261d8892/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/072ae906-ecf7-44f1-ac69-a5b2261d8892/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/072ae906-ecf7-44f1-ac69-a5b2261d8892/3","title":"Predicted Blue (10)"},{"click_action":null,"click_url":null,"description":"Predicted Outcome Two","id":"blue-2","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/ffdda3fe-8012-4db3-981e-7a131402b057/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/ffdda3fe-8012-4db3-981e-7a131402b057/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/ffdda3fe-8012-4db3-981e-7a131402b057/3","title":"Predicted Blue (2)"},{"click_action":null,"click_url":null,"description":"Predicted Outcome Three","id":"blue-3","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/f2ab9a19-8ef7-4f9f-bd5d-9cf4e603f845/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/f2ab9a19-8ef7-4f9f-bd5d-9cf4e603f845/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/f2ab9a19-8ef7-4f9f-bd5d-9cf4e603f845/3","title":"Predicted Blue (3)"},{"click_action":null,"click_url":null,"description":"Predicted Outcome Four","id":"blue-4","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/df95317d-9568-46de-a421-a8520edb9349/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/df95317d-9568-46de-a421-a8520edb9349/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/df95317d-9568-46de-a421-a8520edb9349/3","title":"Predicted Blue (4)"},{"click_action":null,"click_url":null,"description":"Predicted Outcome Five","id":"blue-5","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/88758be8-de09-479b-9383-e3bb6d9e6f06/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/88758be8-de09-479b-9383-e3bb6d9e6f06/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/88758be8-de09-479b-9383-e3bb6d9e6f06/3","title":"Predicted Blue (5)"},{"click_action":null,"click_url":null,"description":"Predicted Outcome Six","id":"blue-6","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/46b1537e-d8b0-4c0d-8fba-a652e57b9df0/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/46b1537e-d8b0-4c0d-8fba-a652e57b9df0/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/46b1537e-d8b0-4c0d-8fba-a652e57b9df0/3","title":"Predicted Blue (6)"},{"click_action":null,"click_url":null,"description":"Predicted Outcome Seven","id":"blue-7","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/07cd34b2-c6a1-45f5-8d8a-131e3c8b2279/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/07cd34b2-c6a1-45f5-8d8a-131e3c8b2279/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/07cd34b2-c6a1-45f5-8d8a-131e3c8b2279/3","title":"Predicted Blue (7)"},{"click_action":null,"click_url":null,"description":"Predicted Outcome Eight","id":"blue-8","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/4416dfd7-db97-44a0-98e7-40b4e250615e/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/4416dfd7-db97-44a0-98e7-40b4e250615e/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/4416dfd7-db97-44a0-98e7-40b4e250615e/3","title":"Predicted Blue (8)"},{"click_action":null,"click_url":null,"description":"Predicted Outcome Nine","id":"blue-9","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/fc74bd90-2b74-4f56-8e42-04d405e10fae/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/fc74bd90-2b74-4f56-8e42-04d405e10fae/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/fc74bd90-2b74-4f56-8e42-04d405e10fae/3","title":"Predicted Blue (9)"},{"click_action":null,"click_url":null,"description":"Predicted Gray (1)","id":"gray-1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/144f77a2-e324-4a6b-9c17-9304fa193a27/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/144f77a2-e324-4a6b-9c17-9304fa193a27/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/144f77a2-e324-4a6b-9c17-9304fa193a27/3","title":"Predicted Gray (1)"},{"click_action":null,"click_url":null,"description":"Predicted Gray (2)","id":"gray-2","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/097a4b14-b458-47eb-91b6-fe74d3dbb3f5/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/097a4b14-b458-47eb-91b6-fe74d3dbb3f5/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/097a4b14-b458-47eb-91b6-fe74d3dbb3f5/3","title":"Predicted Gray (2)"},{"click_action":null,"click_url":null,"description":"Predicted Outcome One","id":"pink-1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/75e27613-caf7-4585-98f1-cb7363a69a4a/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/75e27613-caf7-4585-98f1-cb7363a69a4a/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/75e27613-caf7-4585-98f1-cb7363a69a4a/3","title":"Predicted Pink (1)"},{"click_action":null,"click_url":null,"description":"Predicted Outcome Two","id":"pink-2","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/4b76d5f2-91cc-4400-adf2-908a1e6cfd1e/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/4b76d5f2-91cc-4400-adf2-908a1e6cfd1e/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/4b76d5f2-91cc-4400-adf2-908a1e6cfd1e/3","title":"Predicted Pink (2)"}]},{"set_id":"premium","versions":[{"click_action":"visit_url","click_url":"https://gaming.amazon.com","description":"Prime Gaming","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/bbbe0db0-a598-423e-86d0-f9fb98ca1933/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/bbbe0db0-a598-423e-86d0-f9fb98ca1933/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/bbbe0db0-a598-423e-86d0-f9fb98ca1933/3","title":"Prime Gaming"}]},{"set_id":"psychonauts_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Psychonauts/details","description":"Psychonauts","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/a9811799-dce3-475f-8feb-3745ad12b7ea/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/a9811799-dce3-475f-8feb-3745ad12b7ea/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/a9811799-dce3-475f-8feb-3745ad12b7ea/3","title":"Psychonauts"}]},{"set_id":"raiden-v-directors-cut_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Raiden%20V/details","description":"Raiden V","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/441b50ae-a2e3-11e7-8a3e-6bff0c840878/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/441b50ae-a2e3-11e7-8a3e-6bff0c840878/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/441b50ae-a2e3-11e7-8a3e-6bff0c840878/3","title":"Raiden V"}]},{"set_id":"rift_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Rift/details","description":"RIFT","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/f939686b-2892-46a4-9f0d-5f582578173e/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/f939686b-2892-46a4-9f0d-5f582578173e/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/f939686b-2892-46a4-9f0d-5f582578173e/3","title":"RIFT"}]},{"set_id":"rplace-2023","versions":[{"click_action":"visit_url","click_url":"https://www.reddit.com/r/place/","description":"A very delicious badge earned by watching Reddit's r/place 2023 event on Twitch Rivals or other participating channels.","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/e33e0c67-c380-4241-828a-099c46e51c66/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/e33e0c67-c380-4241-828a-099c46e51c66/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/e33e0c67-c380-4241-828a-099c46e51c66/3","title":"r/place 2023 Cake"}]},{"set_id":"samusoffer_beta","versions":[{"click_action":"visit_url","click_url":"https://twitch.amazon.com/prime","description":"beta_title1","id":"0","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/aa960159-a7b8-417e-83c1-035e4bc2deb5/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/aa960159-a7b8-417e-83c1-035e4bc2deb5/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/aa960159-a7b8-417e-83c1-035e4bc2deb5/3","title":"beta_title1"}]},{"set_id":"staff","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/jobs?ref=chat_badge","description":"Twitch Staff","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/d97c37bd-a6f5-4c38-8f57-4e4bef88af34/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/d97c37bd-a6f5-4c38-8f57-4e4bef88af34/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/d97c37bd-a6f5-4c38-8f57-4e4bef88af34/3","title":"Staff"}]},{"set_id":"starbound_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Starbound/details","description":"Starbound","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/e838e742-0025-4646-9772-18a87ba99358/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/e838e742-0025-4646-9772-18a87ba99358/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/e838e742-0025-4646-9772-18a87ba99358/3","title":"Starbound"}]},{"set_id":"strafe_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/strafe/details","description":"Strafe","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/0051508d-2d42-4e4b-a328-c86b04510ca4/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/0051508d-2d42-4e4b-a328-c86b04510ca4/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/0051508d-2d42-4e4b-a328-c86b04510ca4/3","title":"Strafe"}]},{"set_id":"sub-gift-leader","versions":[{"click_action":null,"click_url":null,"description":"Ranked as a top subscription gifter in this community","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/21656088-7da2-4467-acd2-55220e1f45ad/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/21656088-7da2-4467-acd2-55220e1f45ad/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/21656088-7da2-4467-acd2-55220e1f45ad/3","title":"Gifter Leader 1"},{"click_action":null,"click_url":null,"description":"Ranked as a top subscription gifter in this community","id":"2","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/0d9fe96b-97b7-4215-b5f3-5328ebad271c/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/0d9fe96b-97b7-4215-b5f3-5328ebad271c/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/0d9fe96b-97b7-4215-b5f3-5328ebad271c/3","title":"Gifter Leader 2"},{"click_action":null,"click_url":null,"description":"Ranked as a top subscription gifter in this community","id":"3","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/4c6e4497-eed9-4dd3-ac64-e0599d0a63e5/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/4c6e4497-eed9-4dd3-ac64-e0599d0a63e5/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/4c6e4497-eed9-4dd3-ac64-e0599d0a63e5/3","title":"Gifter Leader 3"}]},{"set_id":"sub-gifter","versions":[{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/a5ef6c17-2e5b-4d8f-9b80-2779fd722414/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/a5ef6c17-2e5b-4d8f-9b80-2779fd722414/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/a5ef6c17-2e5b-4d8f-9b80-2779fd722414/3","title":"Sub Gifter"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"10","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/d333288c-65d7-4c7b-b691-cdd7b3484bf8/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/d333288c-65d7-4c7b-b691-cdd7b3484bf8/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/d333288c-65d7-4c7b-b691-cdd7b3484bf8/3","title":"10 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"100","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/8343ada7-3451-434e-91c4-e82bdcf54460/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/8343ada7-3451-434e-91c4-e82bdcf54460/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/8343ada7-3451-434e-91c4-e82bdcf54460/3","title":"100 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"1000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/bfb7399a-c632-42f7-8d5f-154610dede81/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/bfb7399a-c632-42f7-8d5f-154610dede81/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/bfb7399a-c632-42f7-8d5f-154610dede81/3","title":"1000 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"150","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/514845ba-0fc3-4771-bce1-14d57e91e621/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/514845ba-0fc3-4771-bce1-14d57e91e621/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/514845ba-0fc3-4771-bce1-14d57e91e621/3","title":"150 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"200","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/c6b1893e-8059-4024-b93c-39c84b601732/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/c6b1893e-8059-4024-b93c-39c84b601732/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/c6b1893e-8059-4024-b93c-39c84b601732/3","title":"200 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"2000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/4e8b3a32-1513-44ad-8a12-6c90232c77f9/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/4e8b3a32-1513-44ad-8a12-6c90232c77f9/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/4e8b3a32-1513-44ad-8a12-6c90232c77f9/3","title":"2000 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"25","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/052a5d41-f1cc-455c-bc7b-fe841ffaf17f/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/052a5d41-f1cc-455c-bc7b-fe841ffaf17f/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/052a5d41-f1cc-455c-bc7b-fe841ffaf17f/3","title":"25 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"250","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/cd479dc0-4a15-407d-891f-9fd2740bddda/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/cd479dc0-4a15-407d-891f-9fd2740bddda/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/cd479dc0-4a15-407d-891f-9fd2740bddda/3","title":"250 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"300","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/9e1bb24f-d238-4078-871a-ac401b76ecf2/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/9e1bb24f-d238-4078-871a-ac401b76ecf2/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/9e1bb24f-d238-4078-871a-ac401b76ecf2/3","title":"300 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"3000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/b18852ba-65d2-4b84-97d2-aeb6c44a0956/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/b18852ba-65d2-4b84-97d2-aeb6c44a0956/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/b18852ba-65d2-4b84-97d2-aeb6c44a0956/3","title":"3000 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"350","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/6c4783cd-0aba-4e75-a7a4-f48a70b665b0/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/6c4783cd-0aba-4e75-a7a4-f48a70b665b0/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/6c4783cd-0aba-4e75-a7a4-f48a70b665b0/3","title":"350 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"400","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/6f4cab6b-def9-4d99-ad06-90b0013b28c8/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/6f4cab6b-def9-4d99-ad06-90b0013b28c8/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/6f4cab6b-def9-4d99-ad06-90b0013b28c8/3","title":"400 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"4000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/efbf3c93-ecfa-4b67-8d0a-1f732fb07397/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/efbf3c93-ecfa-4b67-8d0a-1f732fb07397/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/efbf3c93-ecfa-4b67-8d0a-1f732fb07397/3","title":"4000 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"450","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/b593d68a-f8fb-4516-a09a-18cce955402c/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/b593d68a-f8fb-4516-a09a-18cce955402c/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/b593d68a-f8fb-4516-a09a-18cce955402c/3","title":"450 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"5","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/ee113e59-c839-4472-969a-1e16d20f3962/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/ee113e59-c839-4472-969a-1e16d20f3962/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/ee113e59-c839-4472-969a-1e16d20f3962/3","title":"5 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"50","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/c4a29737-e8a5-4420-917a-314a447f083e/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/c4a29737-e8a5-4420-917a-314a447f083e/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/c4a29737-e8a5-4420-917a-314a447f083e/3","title":"50 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"500","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/60e9504c-8c3d-489f-8a74-314fb195ad8d/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/60e9504c-8c3d-489f-8a74-314fb195ad8d/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/60e9504c-8c3d-489f-8a74-314fb195ad8d/3","title":"500 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"5000","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/d775275d-fd19-4914-b63a-7928a22135c3/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/d775275d-fd19-4914-b63a-7928a22135c3/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/d775275d-fd19-4914-b63a-7928a22135c3/3","title":"5000 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"550","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/024d2563-1794-43ed-b8dc-33df3efae900/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/024d2563-1794-43ed-b8dc-33df3efae900/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/024d2563-1794-43ed-b8dc-33df3efae900/3","title":"550 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"600","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/3ecc3aab-09bf-4823-905e-3a4647171fc1/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/3ecc3aab-09bf-4823-905e-3a4647171fc1/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/3ecc3aab-09bf-4823-905e-3a4647171fc1/3","title":"600 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"650","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/eeabf43c-8e4c-448d-9790-4c2172c57944/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/eeabf43c-8e4c-448d-9790-4c2172c57944/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/eeabf43c-8e4c-448d-9790-4c2172c57944/3","title":"650 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"700","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/4a9acdc7-30be-4dd1-9898-fc9e42b3d304/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/4a9acdc7-30be-4dd1-9898-fc9e42b3d304/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/4a9acdc7-30be-4dd1-9898-fc9e42b3d304/3","title":"700 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"750","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/ca17277c-53e5-422b-8bb4-7c5dcdb0ac67/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/ca17277c-53e5-422b-8bb4-7c5dcdb0ac67/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/ca17277c-53e5-422b-8bb4-7c5dcdb0ac67/3","title":"750 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"800","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/9c1fb96d-0579-43d7-ba94-94672eaef63a/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/9c1fb96d-0579-43d7-ba94-94672eaef63a/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/9c1fb96d-0579-43d7-ba94-94672eaef63a/3","title":"800 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"850","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/cc924aaf-dfd4-4f3f-822a-f5a87eb24069/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/cc924aaf-dfd4-4f3f-822a-f5a87eb24069/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/cc924aaf-dfd4-4f3f-822a-f5a87eb24069/3","title":"850 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"900","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/193d86f6-83e1-428c-9638-d6ca9e408166/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/193d86f6-83e1-428c-9638-d6ca9e408166/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/193d86f6-83e1-428c-9638-d6ca9e408166/3","title":"900 Gift Subs"},{"click_action":null,"click_url":null,"description":"Has gifted a subscription to another viewer in this community","id":"950","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/7ce130bd-6f55-40cc-9231-e2a4cb712962/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/7ce130bd-6f55-40cc-9231-e2a4cb712962/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/7ce130bd-6f55-40cc-9231-e2a4cb712962/3","title":"950 Gift Subs"}]},{"set_id":"subscriber","versions":[{"click_action":"subscribe_to_channel","click_url":null,"description":"Subscriber","id":"0","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/5d9f2208-5dd8-11e7-8513-2ff4adfae661/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/5d9f2208-5dd8-11e7-8513-2ff4adfae661/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/5d9f2208-5dd8-11e7-8513-2ff4adfae661/3","title":"Subscriber"},{"click_action":"subscribe_to_channel","click_url":null,"description":"Subscriber","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/5d9f2208-5dd8-11e7-8513-2ff4adfae661/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/5d9f2208-5dd8-11e7-8513-2ff4adfae661/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/5d9f2208-5dd8-11e7-8513-2ff4adfae661/3","title":"Subscriber"},{"click_action":"subscribe_to_channel","click_url":null,"description":"2-Month Subscriber","id":"2","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/25a03e36-2bb2-4625-bd37-d6d9d406238d/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/25a03e36-2bb2-4625-bd37-d6d9d406238d/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/25a03e36-2bb2-4625-bd37-d6d9d406238d/3","title":"2-Month Subscriber"},{"click_action":"subscribe_to_channel","click_url":null,"description":"3-Month Subscriber","id":"3","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/e8984705-d091-4e54-8241-e53b30a84b0e/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/e8984705-d091-4e54-8241-e53b30a84b0e/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/e8984705-d091-4e54-8241-e53b30a84b0e/3","title":"3-Month Subscriber"},{"click_action":"subscribe_to_channel","click_url":null,"description":"6-Month Subscriber","id":"4","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/2d2485f6-d19b-4daa-8393-9493b019156b/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/2d2485f6-d19b-4daa-8393-9493b019156b/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/2d2485f6-d19b-4daa-8393-9493b019156b/3","title":"6-Month Subscriber"},{"click_action":"subscribe_to_channel","click_url":null,"description":"9-Month Subscriber","id":"5","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/b4e6b13a-a76f-4c56-87e1-9375a7aaa610/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/b4e6b13a-a76f-4c56-87e1-9375a7aaa610/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/b4e6b13a-a76f-4c56-87e1-9375a7aaa610/3","title":"9-Month Subscriber"},{"click_action":"subscribe_to_channel","click_url":null,"description":"1-Year Subscriber","id":"6","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/ed51a614-2c44-4a60-80b6-62908436b43a/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/ed51a614-2c44-4a60-80b6-62908436b43a/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/ed51a614-2c44-4a60-80b6-62908436b43a/3","title":"6-Month Subscriber"}]},{"set_id":"superhot_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/superhot/details","description":"Superhot","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/c5a06922-83b5-40cb-885f-bcffd3cd6c68/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/c5a06922-83b5-40cb-885f-bcffd3cd6c68/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/c5a06922-83b5-40cb-885f-bcffd3cd6c68/3","title":"Superhot"}]},{"set_id":"superultracombo-2023","versions":[{"click_action":null,"click_url":null,"description":"This user joined Twitch's SuperUltraCombo 2023","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/5864739a-5e58-4623-9450-a2c0555ef90b/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/5864739a-5e58-4623-9450-a2c0555ef90b/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/5864739a-5e58-4623-9450-a2c0555ef90b/3","title":"SuperUltraCombo 2023"}]},{"set_id":"the-game-awards-2023","versions":[{"click_action":"visit_url","click_url":"https://blog.twitch.tv/2023/11/30/the-2023-game-awards-is-live-on-twitch-december-7th/","description":"You’ve completed all categories of the 2023 Twitch Predicts: The Game Awards extension!","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/10cf46de-61e7-4a42-807a-7898408ce352/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/10cf46de-61e7-4a42-807a-7898408ce352/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/10cf46de-61e7-4a42-807a-7898408ce352/3","title":"The Game Awards 2023"}]},{"set_id":"the-golden-predictor-of-the-game-awards-2023","versions":[{"click_action":"visit_url","click_url":"https://blog.twitch.tv/2023/11/30/the-2023-game-awards-is-live-on-twitch-december-7th/","description":"You've predicted the entire 2023 Game Awards perfectly, here is a special gift for your work. Go ahead, show it off!","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/c84c4dd7-9318-4e8b-9f01-1612d3f83dae/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/c84c4dd7-9318-4e8b-9f01-1612d3f83dae/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/c84c4dd7-9318-4e8b-9f01-1612d3f83dae/3","title":"The Golden Predictor of the Game Awards 2023"}]},{"set_id":"the-surge_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/The%20Surge/details","description":"The Surge","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/c9f69d89-31c8-41aa-843b-fee956dfbe23/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/c9f69d89-31c8-41aa-843b-fee956dfbe23/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/c9f69d89-31c8-41aa-843b-fee956dfbe23/3","title":"The Surge"}]},{"set_id":"the-surge_2","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/The%20Surge/details","description":"The Surge","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/2c4d7e95-e138-4dde-a783-7956a8ecc408/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/2c4d7e95-e138-4dde-a783-7956a8ecc408/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/2c4d7e95-e138-4dde-a783-7956a8ecc408/3","title":"The Surge"}]},{"set_id":"the-surge_3","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/The%20Surge/details","description":"The Surge","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/0a8fc2d4-3125-4ccb-88db-e970dfbee189/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/0a8fc2d4-3125-4ccb-88db-e970dfbee189/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/0a8fc2d4-3125-4ccb-88db-e970dfbee189/3","title":"The Surge"}]},{"set_id":"this-war-of-mine_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/This%20War%20of%20Mine/details","description":"This War of Mine","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/6a20f814-cb2c-414e-89cc-f8dd483e1785/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/6a20f814-cb2c-414e-89cc-f8dd483e1785/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/6a20f814-cb2c-414e-89cc-f8dd483e1785/3","title":"This War of Mine"}]},{"set_id":"titan-souls_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Titan%20Souls/details","description":"Titan Souls","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/092a7ce2-709c-434f-8df4-a6b075ef867d/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/092a7ce2-709c-434f-8df4-a6b075ef867d/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/092a7ce2-709c-434f-8df4-a6b075ef867d/3","title":"Titan Souls"}]},{"set_id":"treasure-adventure-world_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Treasure%20Adventure%20World/details","description":"Treasure Adventure World","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/59810027-2988-4b0d-b88d-fc414c751305/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/59810027-2988-4b0d-b88d-fc414c751305/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/59810027-2988-4b0d-b88d-fc414c751305/3","title":"Treasure Adventure World"}]},{"set_id":"turbo","versions":[{"click_action":"turbo","click_url":null,"description":"A subscriber of Twitch's monthly premium user service","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/bd444ec6-8f34-4bf9-91f4-af1e3428d80f/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/bd444ec6-8f34-4bf9-91f4-af1e3428d80f/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/bd444ec6-8f34-4bf9-91f4-af1e3428d80f/3","title":"Turbo"}]},{"set_id":"twitch-intern-2023","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/jobs/early-career/","description":"This user was an intern at Twitch for the summer of 2023","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/e239e7e0-e373-4fdf-b95e-3469aec28485/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/e239e7e0-e373-4fdf-b95e-3469aec28485/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/e239e7e0-e373-4fdf-b95e-3469aec28485/3","title":"Twitch Intern 2023"}]},{"set_id":"twitch-recap-2023","versions":[{"click_action":"visit_url","click_url":"https://twitch-web.app.link/e/twitch-recap","description":"This user bled purple like it was their job, and was one of the most engaged members of Twitch in 2023!","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/4d9e9812-ba9b-48a6-8690-13f3f338ee65/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/4d9e9812-ba9b-48a6-8690-13f3f338ee65/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/4d9e9812-ba9b-48a6-8690-13f3f338ee65/3","title":"Twitch Recap 2023"}]},{"set_id":"twitchbot","versions":[{"click_action":"visit_url","click_url":"http://link.twitch.tv/automod_blog","description":"AutoMod","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/df9095f6-a8a0-4cc2-bb33-d908c0adffb8/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/df9095f6-a8a0-4cc2-bb33-d908c0adffb8/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/df9095f6-a8a0-4cc2-bb33-d908c0adffb8/3","title":"AutoMod"}]},{"set_id":"twitchcon2017","versions":[{"click_action":"visit_url","click_url":"https://www.twitchcon.com/","description":"Attended TwitchCon Long Beach 2017","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/0964bed0-5c31-11e7-a90b-0739918f1d9b/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/0964bed0-5c31-11e7-a90b-0739918f1d9b/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/0964bed0-5c31-11e7-a90b-0739918f1d9b/3","title":"TwitchCon 2017 - Long Beach"}]},{"set_id":"twitchcon2018","versions":[{"click_action":"visit_url","click_url":"https://www.twitchcon.com/?utm_source=twitch-chat&utm_medium=badge&utm_campaign=tc18","description":"Attended TwitchCon San Jose 2018","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/e68164e4-087d-4f62-81da-d3557efae3cb/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/e68164e4-087d-4f62-81da-d3557efae3cb/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/e68164e4-087d-4f62-81da-d3557efae3cb/3","title":"TwitchCon 2018 - San Jose"}]},{"set_id":"twitchconAmsterdam2020","versions":[{"click_action":"visit_url","click_url":"https://www.twitchcon.com/amsterdam/?utm_source=twitch-chat&utm_medium=badge&utm_campaign=tcamsterdam20","description":"Registered for TwitchCon Amsterdam 2020","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/ed917c9a-1a45-4340-9c64-ca8be4348c51/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/ed917c9a-1a45-4340-9c64-ca8be4348c51/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/ed917c9a-1a45-4340-9c64-ca8be4348c51/3","title":"TwitchCon 2020 - Amsterdam"}]},{"set_id":"twitchconEU2019","versions":[{"click_action":"visit_url","click_url":"https://europe.twitchcon.com/?utm_source=twitch-chat&utm_medium=badge&utm_campaign=tceu19","description":"Attended TwitchCon Berlin 2019","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/590eee9e-f04d-474c-90e7-b304d9e74b32/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/590eee9e-f04d-474c-90e7-b304d9e74b32/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/590eee9e-f04d-474c-90e7-b304d9e74b32/3","title":"TwitchCon 2019 - Berlin"}]},{"set_id":"twitchconEU2022","versions":[{"click_action":"visit_url","click_url":"https://www.twitchcon.com/amsterdam-2022/?utm_source=twitch-chat&utm_medium=badge&utm_campaign=tceu22","description":"Attended TwitchCon Amsterdam 2022","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/e4744003-50b7-4eb8-9b47-a7b1616a30c6/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/e4744003-50b7-4eb8-9b47-a7b1616a30c6/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/e4744003-50b7-4eb8-9b47-a7b1616a30c6/3","title":"TwitchCon 2022 - Amsterdam"}]},{"set_id":"twitchconEU2023","versions":[{"click_action":"visit_url","click_url":"https://www.twitchcon.com/paris-2023/?utm_source=chat_badge","description":"TwitchCon 2023 - Paris","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/a8f2084e-46b9-4bb9-ae5e-00d594aafc64/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/a8f2084e-46b9-4bb9-ae5e-00d594aafc64/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/a8f2084e-46b9-4bb9-ae5e-00d594aafc64/3","title":"TwitchCon 2023 - Paris"}]},{"set_id":"twitchconNA2019","versions":[{"click_action":"visit_url","click_url":"https://www.twitchcon.com/?utm_source=twitch-chat&utm_medium=badge&utm_campaign=tcna19","description":"Attended TwitchCon San Diego 2019","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/569c829d-c216-4f56-a191-3db257ed657c/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/569c829d-c216-4f56-a191-3db257ed657c/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/569c829d-c216-4f56-a191-3db257ed657c/3","title":"TwitchCon 2019 - San Diego"}]},{"set_id":"twitchconNA2020","versions":[{"click_action":"visit_url","click_url":"https://www.twitchcon.com/?utm_source=twitch-chat&utm_medium=badge&utm_campaign=tcna20","description":"Registered for TwitchCon North America 2020","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/ed917c9a-1a45-4340-9c64-ca8be4348c51/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/ed917c9a-1a45-4340-9c64-ca8be4348c51/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/ed917c9a-1a45-4340-9c64-ca8be4348c51/3","title":"TwitchCon 2020 - North America"}]},{"set_id":"twitchconNA2022","versions":[{"click_action":"visit_url","click_url":"https://www.twitchcon.com/san-diego-2022/?utm_source=twitch-chat&utm_medium=badge&utm_campaign=tcna22","description":"Attended TwitchCon San Diego 2022","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/344d429a-0b34-48e5-a84c-14a1b5772a3a/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/344d429a-0b34-48e5-a84c-14a1b5772a3a/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/344d429a-0b34-48e5-a84c-14a1b5772a3a/3","title":"TwitchCon 2022 - San Diego"}]},{"set_id":"twitchconNA2023","versions":[{"click_action":"visit_url","click_url":"https://www.twitchcon.com/en/las-vegas-2023/","description":"Attended TwitchCon Las Vegas 2023","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/c90a753f-ab20-41bc-9c42-ede062485d2c/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/c90a753f-ab20-41bc-9c42-ede062485d2c/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/c90a753f-ab20-41bc-9c42-ede062485d2c/3","title":"TwitchCon 2023 - Las Vegas"}]},{"set_id":"tyranny_1","versions":[{"click_action":"visit_url","click_url":"https://www.twitch.tv/directory/game/Tyranny/details","description":"Tyranny","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/0c79afdf-28ce-4b0b-9e25-4f221c30bfde/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/0c79afdf-28ce-4b0b-9e25-4f221c30bfde/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/0c79afdf-28ce-4b0b-9e25-4f221c30bfde/3","title":"Tyranny"}]},{"set_id":"user-anniversary","versions":[{"click_action":null,"click_url":null,"description":"Staff badge celebrating Twitch tenure","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/ccbbedaa-f4db-4d0b-9c2a-375de7ad947c/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/ccbbedaa-f4db-4d0b-9c2a-375de7ad947c/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/ccbbedaa-f4db-4d0b-9c2a-375de7ad947c/3","title":"Twitchiversary Badge"}]},{"set_id":"vga-champ-2017","versions":[{"click_action":"visit_url","click_url":"https://blog.twitch.tv/watch-and-co-stream-the-game-awards-this-thursday-on-twitch-3d8e34d2345d","description":"2017 VGA Champ","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/03dca92e-dc69-11e7-ac5b-9f942d292dc7/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/03dca92e-dc69-11e7-ac5b-9f942d292dc7/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/03dca92e-dc69-11e7-ac5b-9f942d292dc7/3","title":"2017 VGA Champ"}]},{"set_id":"vip","versions":[{"click_action":"visit_url","click_url":"https://help.twitch.tv/customer/en/portal/articles/659115-twitch-chat-badges-guide","description":"VIP","id":"1","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/b817aba4-fad8-49e2-b88a-7cc744dfa6ec/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/b817aba4-fad8-49e2-b88a-7cc744dfa6ec/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/b817aba4-fad8-49e2-b88a-7cc744dfa6ec/3","title":"VIP"}]},{"set_id":"warcraft","versions":[{"click_action":"visit_url","click_url":"http://warcraftontwitch.tv/","description":"For Lordaeron!","id":"alliance","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/c4816339-bad4-4645-ae69-d1ab2076a6b0/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/c4816339-bad4-4645-ae69-d1ab2076a6b0/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/c4816339-bad4-4645-ae69-d1ab2076a6b0/3","title":"Alliance"},{"click_action":"visit_url","click_url":"http://warcraftontwitch.tv/","description":"For the Horde!","id":"horde","image_url_1x":"https://static-cdn.jtvnw.net/badges/v1/de8b26b6-fd28-4e6c-bc89-3d597343800d/1","image_url_2x":"https://static-cdn.jtvnw.net/badges/v1/de8b26b6-fd28-4e6c-bc89-3d597343800d/2","image_url_4x":"https://static-cdn.jtvnw.net/badges/v1/de8b26b6-fd28-4e6c-bc89-3d597343800d/3","title":"Horde"}]}]} +{"1979-revolution_1":[{"id":"1","title":"1979 Revolution","image":"https://static-cdn.jtvnw.net/badges/v1/7833bb6e-d20d-48ff-a58d-67fe827a4f84/","url":"https://www.twitch.tv/directory/game/1979%20Revolution/details"}],"60-seconds_1":[{"id":"1","title":"60 Seconds!","image":"https://static-cdn.jtvnw.net/badges/v1/1e7252f9-7e80-4d3d-ae42-319f030cca99/","url":"https://www.twitch.tv/directory/game/60%20Seconds!/details"}],"60-seconds_2":[{"id":"1","title":"60 Seconds!","image":"https://static-cdn.jtvnw.net/badges/v1/64513f7d-21dd-4a05-a699-d73761945cf9/","url":"https://www.twitch.tv/directory/game/60%20Seconds!/details"}],"60-seconds_3":[{"id":"1","title":"60 Seconds!","image":"https://static-cdn.jtvnw.net/badges/v1/f4306617-0f96-476f-994e-5304f81bcc6e/","url":"https://www.twitch.tv/directory/game/60%20Seconds!/details"}],"H1Z1_1":[{"id":"1","title":"H1Z1","image":"https://static-cdn.jtvnw.net/badges/v1/fc71386c-86cd-11e7-a55d-43f591dc0c71/","url":"https://www.twitch.tv/directory/game/H1Z1/details"}],"admin":[{"id":"1","title":"Admin","image":"https://static-cdn.jtvnw.net/badges/v1/9ef7e029-4cdf-4d4d-a0d5-e2b3fb2583fe/"}],"ambassador":[{"id":"1","title":"Twitch Ambassador","image":"https://static-cdn.jtvnw.net/badges/v1/2cbc339f-34f4-488a-ae51-efdf74f4e323/","url":"https://www.twitch.tv/team/ambassadors"}],"anomaly-2_1":[{"id":"1","title":"Anomaly 2","image":"https://static-cdn.jtvnw.net/badges/v1/d1d1ad54-40a6-492b-882e-dcbdce5fa81e/","url":"https://www.twitch.tv/directory/game/Anomaly%202/details"}],"anomaly-warzone-earth_1":[{"id":"1","title":"Anomaly Warzone Earth","image":"https://static-cdn.jtvnw.net/badges/v1/858be873-fb1f-47e5-ad34-657f40d3d156/","url":"https://www.twitch.tv/directory/game/Anomaly:%20Warzone%20Earth/details"}],"anonymous-cheerer":[{"id":"1","title":"Anonymous Cheerer","image":"https://static-cdn.jtvnw.net/badges/v1/ca3db7f7-18f5-487e-a329-cd0b538ee979/"}],"artist-badge":[{"id":"1","title":"Artist","image":"https://static-cdn.jtvnw.net/badges/v1/4300a897-03dc-4e83-8c0e-c332fee7057f/"}],"axiom-verge_1":[{"id":"1","title":"Axiom Verge","image":"https://static-cdn.jtvnw.net/badges/v1/f209b747-45ee-42f6-8baf-ea7542633d10/","url":"https://www.twitch.tv/directory/game/Axiom%20Verge/details"}],"battlechefbrigade_1":[{"id":"1","title":"Battle Chef Brigade","image":"https://static-cdn.jtvnw.net/badges/v1/24e32e67-33cd-4227-ad96-f0a7fc836107/","url":"https://www.twitch.tv/directory/game/Battle%20Chef%20Brigade/details"}],"battlechefbrigade_2":[{"id":"1","title":"Battle Chef Brigade","image":"https://static-cdn.jtvnw.net/badges/v1/ef1e96e8-a0f9-40b6-87af-2977d3c004bb/","url":"https://www.twitch.tv/directory/game/Battle%20Chef%20Brigade/details"}],"battlechefbrigade_3":[{"id":"1","title":"Battle Chef Brigade","image":"https://static-cdn.jtvnw.net/badges/v1/107ebb20-4fcd-449a-9931-cd3f81b84c70/","url":"https://www.twitch.tv/directory/game/Battle%20Chef%20Brigade/details"}],"battlerite_1":[{"id":"1","title":"Battlerite","image":"https://static-cdn.jtvnw.net/badges/v1/484ebda9-f7fa-4c67-b12b-c80582f3cc61/","url":"https://www.twitch.tv/directory/game/Battlerite/details"}],"bits":[{"id":"1","title":"cheer 1","image":"https://static-cdn.jtvnw.net/badges/v1/73b5c3fb-24f9-4a82-a852-2f475b59411c/","url":"https://bits.twitch.tv"},{"id":"100","title":"cheer 100","image":"https://static-cdn.jtvnw.net/badges/v1/09d93036-e7ce-431c-9a9e-7044297133f2/","url":"https://bits.twitch.tv"},{"id":"1000","title":"cheer 1000","image":"https://static-cdn.jtvnw.net/badges/v1/0d85a29e-79ad-4c63-a285-3acd2c66f2ba/","url":"https://bits.twitch.tv"},{"id":"10000","title":"cheer 10000","image":"https://static-cdn.jtvnw.net/badges/v1/68af213b-a771-4124-b6e3-9bb6d98aa732/","url":"https://bits.twitch.tv"},{"id":"100000","title":"cheer 100000","image":"https://static-cdn.jtvnw.net/badges/v1/96f0540f-aa63-49e1-a8b3-259ece3bd098/","url":"https://bits.twitch.tv"},{"id":"1000000","title":"cheer 1000000","image":"https://static-cdn.jtvnw.net/badges/v1/494d1c8e-c3b2-4d88-8528-baff57c9bd3f/","url":"https://bits.twitch.tv"},{"id":"1250000","title":"cheer 1250000","image":"https://static-cdn.jtvnw.net/badges/v1/ce217209-4615-4bf8-81e3-57d06b8b9dc7/","url":"https://bits.twitch.tv"},{"id":"1500000","title":"cheer 1500000","image":"https://static-cdn.jtvnw.net/badges/v1/c4eba5b4-17a7-40a1-a668-bc1972c1e24d/","url":"https://bits.twitch.tv"},{"id":"1750000","title":"cheer 1750000","image":"https://static-cdn.jtvnw.net/badges/v1/183f1fd8-aaf4-450c-a413-e53f839f0f82/","url":"https://bits.twitch.tv"},{"id":"200000","title":"cheer 200000","image":"https://static-cdn.jtvnw.net/badges/v1/4a0b90c4-e4ef-407f-84fe-36b14aebdbb6/","url":"https://bits.twitch.tv"},{"id":"2000000","title":"cheer 2000000","image":"https://static-cdn.jtvnw.net/badges/v1/7ea89c53-1a3b-45f9-9223-d97ae19089f2/","url":"https://bits.twitch.tv"},{"id":"25000","title":"cheer 25000","image":"https://static-cdn.jtvnw.net/badges/v1/64ca5920-c663-4bd8-bfb1-751b4caea2dd/","url":"https://bits.twitch.tv"},{"id":"2500000","title":"cheer 2500000","image":"https://static-cdn.jtvnw.net/badges/v1/cf061daf-d571-4811-bcc2-c55c8792bc8f/","url":"https://bits.twitch.tv"},{"id":"300000","title":"cheer 300000","image":"https://static-cdn.jtvnw.net/badges/v1/ac13372d-2e94-41d1-ae11-ecd677f69bb6/","url":"https://bits.twitch.tv"},{"id":"3000000","title":"cheer 3000000","image":"https://static-cdn.jtvnw.net/badges/v1/5671797f-5e9f-478c-a2b5-eb086c8928cf/","url":"https://bits.twitch.tv"},{"id":"3500000","title":"cheer 3500000","image":"https://static-cdn.jtvnw.net/badges/v1/c3d218f5-1e45-419d-9c11-033a1ae54d3a/","url":"https://bits.twitch.tv"},{"id":"400000","title":"cheer 400000","image":"https://static-cdn.jtvnw.net/badges/v1/a8f393af-76e6-4aa2-9dd0-7dcc1c34f036/","url":"https://bits.twitch.tv"},{"id":"4000000","title":"cheer 4000000","image":"https://static-cdn.jtvnw.net/badges/v1/79fe642a-87f3-40b1-892e-a341747b6e08/","url":"https://bits.twitch.tv"},{"id":"4500000","title":"cheer 4500000","image":"https://static-cdn.jtvnw.net/badges/v1/736d4156-ac67-4256-a224-3e6e915436db/","url":"https://bits.twitch.tv"},{"id":"5000","title":"cheer 5000","image":"https://static-cdn.jtvnw.net/badges/v1/57cd97fc-3e9e-4c6d-9d41-60147137234e/","url":"https://bits.twitch.tv"},{"id":"50000","title":"cheer 50000","image":"https://static-cdn.jtvnw.net/badges/v1/62310ba7-9916-4235-9eba-40110d67f85d/","url":"https://bits.twitch.tv"},{"id":"500000","title":"cheer 500000","image":"https://static-cdn.jtvnw.net/badges/v1/f6932b57-6a6e-4062-a770-dfbd9f4302e5/","url":"https://bits.twitch.tv"},{"id":"5000000","title":"cheer 5000000","image":"https://static-cdn.jtvnw.net/badges/v1/3f085f85-8d15-4a03-a829-17fca7bf1bc2/","url":"https://bits.twitch.tv"},{"id":"600000","title":"cheer 600000","image":"https://static-cdn.jtvnw.net/badges/v1/4d908059-f91c-4aef-9acb-634434f4c32e/","url":"https://bits.twitch.tv"},{"id":"700000","title":"cheer 700000","image":"https://static-cdn.jtvnw.net/badges/v1/a1d2a824-f216-4b9f-9642-3de8ed370957/","url":"https://bits.twitch.tv"},{"id":"75000","title":"cheer 75000","image":"https://static-cdn.jtvnw.net/badges/v1/ce491fa4-b24f-4f3b-b6ff-44b080202792/","url":"https://bits.twitch.tv"},{"id":"800000","title":"cheer 800000","image":"https://static-cdn.jtvnw.net/badges/v1/5ec2ee3e-5633-4c2a-8e77-77473fe409e6/","url":"https://bits.twitch.tv"},{"id":"900000","title":"cheer 900000","image":"https://static-cdn.jtvnw.net/badges/v1/088c58c6-7c38-45ba-8f73-63ef24189b84/","url":"https://bits.twitch.tv"}],"bits-charity":[{"id":"1","title":"Direct Relief - Charity 2018","image":"https://static-cdn.jtvnw.net/badges/v1/a539dc18-ae19-49b0-98c4-8391a594332b/","url":"https://link.twitch.tv/blizzardofbits"}],"bits-leader":[{"id":"1","title":"Bits Leader 1","image":"https://static-cdn.jtvnw.net/badges/v1/8bedf8c3-7a6d-4df2-b62f-791b96a5dd31/","url":"https://bits.twitch.tv"},{"id":"2","title":"Bits Leader 2","image":"https://static-cdn.jtvnw.net/badges/v1/f04baac7-9141-4456-a0e7-6301bcc34138/","url":"https://bits.twitch.tv"},{"id":"3","title":"Bits Leader 3","image":"https://static-cdn.jtvnw.net/badges/v1/f1d2aab6-b647-47af-965b-84909cf303aa/","url":"https://bits.twitch.tv"}],"brawlhalla_1":[{"id":"1","title":"Brawlhalla","image":"https://static-cdn.jtvnw.net/badges/v1/bf6d6579-ab02-4f0a-9f64-a51c37040858/","url":"https://www.twitch.tv/directory/game/Brawlhalla/details"}],"broadcaster":[{"id":"1","title":"Broadcaster","image":"https://static-cdn.jtvnw.net/badges/v1/5527c58c-fb7d-422d-b71b-f309dcb85cc1/"}],"broken-age_1":[{"id":"1","title":"Broken Age","image":"https://static-cdn.jtvnw.net/badges/v1/56885ed2-9a09-4c8e-8131-3eb9ec15af94/","url":"https://www.twitch.tv/directory/game/Broken%20Age/details"}],"bubsy-the-woolies_1":[{"id":"1","title":"Bubsy: The Woolies Strike Back","image":"https://static-cdn.jtvnw.net/badges/v1/c8129382-1f4e-4d15-a8d2-48bdddba9b81/","url":"https://www.twitch.tv/directory/game/Bubsy:%20The%20Woolies%20Strike%20Back/details"}],"chatter-cs-go-2022":[{"id":"1","title":"CS:GO Week Brazil 2022","image":"https://static-cdn.jtvnw.net/badges/v1/57b6bd6b-a1b5-4204-9e6c-eb8ed5831603/"}],"clip-champ":[{"id":"1","title":"Power Clipper","image":"https://static-cdn.jtvnw.net/badges/v1/f38976e0-ffc9-11e7-86d6-7f98b26a9d79/","url":"https://help.twitch.tv/customer/portal/articles/2918323-clip-champs-guide"}],"creator-cs-go-2022":[{"id":"1","title":"CS:GO Week Brazil 2022","image":"https://static-cdn.jtvnw.net/badges/v1/a2ea6df9-ac0a-4956-bfe9-e931f50b94fa/"}],"cuphead_1":[{"id":"1","title":"Cuphead","image":"https://static-cdn.jtvnw.net/badges/v1/4384659a-a2e3-11e7-a564-87f6b1288bab/","url":"https://www.twitch.tv/directory/game/Cuphead/details"}],"darkest-dungeon_1":[{"id":"1","title":"Darkest Dungeon","image":"https://static-cdn.jtvnw.net/badges/v1/52a98ddd-cc79-46a8-9fe3-30f8c719bc2d/","url":"https://www.twitch.tv/directory/game/Darkest%20Dungeon/details"}],"deceit_1":[{"id":"1","title":"Deceit","image":"https://static-cdn.jtvnw.net/badges/v1/b14fef48-4ff9-4063-abf6-579489234fe9/","url":"https://www.twitch.tv/directory/game/Deceit/details"}],"destiny-2-final-shape-raid-race":[{"id":"1","title":"Destiny 2: The Final Shape Raid Race","image":"https://static-cdn.jtvnw.net/badges/v1/e79ee64f-31f1-4485-9c81-b93957e69f8a/","url":"https://www.twitch.tv/directory/category/destiny-2"}],"destiny-2-the-final-shape-streamer":[{"id":"1","title":"Destiny 2: The Final Shape Streamer","image":"https://static-cdn.jtvnw.net/badges/v1/b1bcaf3c-d7a2-442b-b407-03f2b8ff624d/","url":"https://www.twitch.tv/directory/category/destiny-2\t"}],"devil-may-cry-hd_1":[{"id":"1","title":"Devil May Cry HD Collection","image":"https://static-cdn.jtvnw.net/badges/v1/633877d4-a91c-4c36-b75b-803f82b1352f/","url":"https://www.twitch.tv/directory/game/Devil%20May%20Cry%20HD%20Collection/details"}],"devil-may-cry-hd_2":[{"id":"1","title":"Devil May Cry HD Collection","image":"https://static-cdn.jtvnw.net/badges/v1/408548fe-aa74-4d53-b5e9-960103d9b865/","url":"https://www.twitch.tv/directory/game/Devil%20May%20Cry%20HD%20Collection/details"}],"devil-may-cry-hd_3":[{"id":"1","title":"Devil May Cry HD Collection","image":"https://static-cdn.jtvnw.net/badges/v1/df84c5bf-8d66-48e2-b9fb-c014cc9b3945/","url":"https://www.twitch.tv/directory/game/Devil%20May%20Cry%20HD%20Collection/details"}],"devil-may-cry-hd_4":[{"id":"1","title":"Devil May Cry HD Collection","image":"https://static-cdn.jtvnw.net/badges/v1/af836b94-8ffd-4c0a-b7d8-a92fad5e3015/","url":"https://www.twitch.tv/directory/game/Devil%20May%20Cry%20HD%20Collection/details"}],"devilian_1":[{"id":"1","title":"Devilian","image":"https://static-cdn.jtvnw.net/badges/v1/3cb92b57-1eef-451c-ac23-4d748128b2c5/","url":"https://www.twitch.tv/directory/game/Devilian/details"}],"dreamcon-2024":[{"id":"1","title":"Dream Con 2024","image":"https://static-cdn.jtvnw.net/badges/v1/5dfbd056-8ac1-407f-bdf3-f83183fa97ae/"}],"duelyst_1":[{"id":"1","title":"Duelyst","image":"https://static-cdn.jtvnw.net/badges/v1/7d9c12f4-a2ac-4e88-8026-d1a330468282/","url":"https://www.twitch.tv/directory/game/Duelyst/details"}],"duelyst_2":[{"id":"1","title":"Duelyst","image":"https://static-cdn.jtvnw.net/badges/v1/1938acd3-2d18-471d-b1af-44f2047c033c/","url":"https://www.twitch.tv/directory/game/Duelyst/details"}],"duelyst_3":[{"id":"1","title":"Duelyst","image":"https://static-cdn.jtvnw.net/badges/v1/344c07fc-1632-47c6-9785-e62562a6b760/","url":"https://www.twitch.tv/directory/game/Duelyst/details"}],"duelyst_4":[{"id":"1","title":"Duelyst","image":"https://static-cdn.jtvnw.net/badges/v1/39e717a8-00bc-49cc-b6d4-3ea91ee1be25/","url":"https://www.twitch.tv/directory/game/Duelyst/details"}],"duelyst_5":[{"id":"1","title":"Duelyst","image":"https://static-cdn.jtvnw.net/badges/v1/290419b6-484a-47da-ad14-a99d6581f758/","url":"https://www.twitch.tv/directory/game/Duelyst/details"}],"duelyst_6":[{"id":"1","title":"Duelyst","image":"https://static-cdn.jtvnw.net/badges/v1/c5e54a4b-0bf1-463a-874a-38524579aed0/","url":"https://www.twitch.tv/directory/game/Duelyst/details"}],"duelyst_7":[{"id":"1","title":"Duelyst","image":"https://static-cdn.jtvnw.net/badges/v1/cf508179-3183-4987-97e0-56ca44babb9f/","url":"https://www.twitch.tv/directory/game/Duelyst/details"}],"enter-the-gungeon_1":[{"id":"1","title":"Enter The Gungeon","image":"https://static-cdn.jtvnw.net/badges/v1/53c9af0b-84f6-4f9d-8c80-4bc51321a37d/","url":"https://www.twitch.tv/directory/game/Enter%20the%20Gungeon/details"}],"eso_1":[{"id":"1","title":"Elder Scrolls Online","image":"https://static-cdn.jtvnw.net/badges/v1/18647a68-a35f-48d7-bf97-ae5deb6b277d/"}],"extension":[{"id":"1","title":"Extension","image":"https://static-cdn.jtvnw.net/badges/v1/ea8b0f8c-aa27-11e8-ba0c-1370ffff3854/"}],"firewatch_1":[{"id":"1","title":"Firewatch","image":"https://static-cdn.jtvnw.net/badges/v1/b6bf4889-4902-49e2-9658-c0132e71c9c4/","url":"https://www.twitch.tv/directory/game/Firewatch/details"}],"founder":[{"id":"0","title":"Founder","image":"https://static-cdn.jtvnw.net/badges/v1/511b78a9-ab37-472f-9569-457753bbe7d3/","url":"https://help.twitch.tv/s/article/founders-badge"}],"frozen-cortext_1":[{"id":"1","title":"Frozen Cortext","image":"https://static-cdn.jtvnw.net/badges/v1/2015f087-01b5-4a01-a2bb-ecb4d6be5240/","url":"https://www.twitch.tv/directory/game/Frozen%20Cortex/details"}],"frozen-synapse_1":[{"id":"1","title":"Frozen Synapse","image":"https://static-cdn.jtvnw.net/badges/v1/d4bd464d-55ea-4238-a11d-744f034e2375/","url":"https://www.twitch.tv/directory/game/Frozen%20Synapse/details"}],"game-developer":[{"id":"1","title":"Game Developer","image":"https://static-cdn.jtvnw.net/badges/v1/85856a4a-eb7d-4e26-a43e-d204a977ade4/"}],"getting-over-it_1":[{"id":"1","title":"Getting Over It","image":"https://static-cdn.jtvnw.net/badges/v1/8d4e178c-81ec-4c71-af68-745b40733984/","url":"https://www.twitch.tv/directory/game/Getting%20Over%20It/details"}],"getting-over-it_2":[{"id":"1","title":"Getting Over It","image":"https://static-cdn.jtvnw.net/badges/v1/bb620b42-e0e1-4373-928e-d4a732f99ccb/","url":"https://www.twitch.tv/directory/game/Getting%20Over%20It/details"}],"glhf-pledge":[{"id":"1","title":"GLHF Pledge","image":"https://static-cdn.jtvnw.net/badges/v1/3158e758-3cb4-43c5-94b3-7639810451c5/","url":"https://www.anykey.org/pledge"}],"glitchcon2020":[{"id":"1","title":"GlitchCon 2020","image":"https://static-cdn.jtvnw.net/badges/v1/1d4b03b9-51ea-42c9-8f29-698e3c85be3d/","url":"https://www.twitchcon.com/"}],"global_mod":[{"id":"1","title":"Global Moderator","image":"https://static-cdn.jtvnw.net/badges/v1/9384c43e-4ce7-4e94-b2a1-b93656896eba/"}],"gold-pixel-heart":[{"id":"1","title":"Gold Pixel Heart","image":"https://static-cdn.jtvnw.net/badges/v1/1687873b-cf38-412c-aad3-f9a4ce17f8b6/","url":"https://help.twitch.tv/s/article/twitch-charity"}],"heavy-bullets_1":[{"id":"1","title":"Heavy Bullets","image":"https://static-cdn.jtvnw.net/badges/v1/fc83b76b-f8b2-4519-9f61-6faf84eef4cd/","url":"https://www.twitch.tv/directory/game/Heavy%20Bullets/details"}],"hello_neighbor_1":[{"id":"1","title":"Hello Neighbor","image":"https://static-cdn.jtvnw.net/badges/v1/030cab2c-5d14-11e7-8d91-43a5a4306286/","url":"https://www.twitch.tv/directory/game/Hello%20Neighbor/details"}],"hype-train":[{"id":"1","title":"Current Hype Train Conductor","image":"https://static-cdn.jtvnw.net/badges/v1/fae4086c-3190-44d4-83c8-8ef0cbe1a515/","url":"https://help.twitch.tv/s/article/hype-train-guide"},{"id":"2","title":"Former Hype Train Conductor","image":"https://static-cdn.jtvnw.net/badges/v1/9c8d038a-3a29-45ea-96d4-5031fb1a7a81/","url":"https://help.twitch.tv/s/article/hype-train-guide"}],"innerspace_1":[{"id":"1","title":"Innerspace","image":"https://static-cdn.jtvnw.net/badges/v1/97532ccd-6a07-42b5-aecf-3458b6b3ebea/","url":"https://www.twitch.tv/directory/game/Innerspace/details"}],"innerspace_2":[{"id":"1","title":"Innerspace","image":"https://static-cdn.jtvnw.net/badges/v1/fc7d6018-657a-40e4-9246-0acdc85886d1/","url":"https://www.twitch.tv/directory/game/Innerspace/details"}],"jackbox-party-pack_1":[{"id":"1","title":"Jackbox Party Pack","image":"https://static-cdn.jtvnw.net/badges/v1/0f964fc1-f439-485f-a3c0-905294ee70e8/","url":"https://www.twitch.tv/directory/game/The%20Jackbox%20Party%20Pack/details"}],"kingdom-new-lands_1":[{"id":"1","title":"Kingdom: New Lands","image":"https://static-cdn.jtvnw.net/badges/v1/e3c2a67e-ef80-4fe3-ae41-b933cd11788a/","url":"https://www.twitch.tv/directory/game/Kingdom:%20New%20Lands/details"}],"la-velada-iv":[{"id":"1","title":"La Velada del A\u00c3\u00b1o IV","image":"https://static-cdn.jtvnw.net/badges/v1/655dac77-0b2f-4b62-8871-6ae21f82b34e/"}],"minecraft-15th-anniversary-celebration":[{"id":"1","title":"Minecraft 15th Anniversary Celebration","image":"https://static-cdn.jtvnw.net/badges/v1/178077b2-8b86-4f8d-927c-66ed6c1b025f/","url":"https://twitch-web.app.link/e/vkOhfCa7nJb"}],"moderator":[{"id":"1","title":"Moderator","image":"https://static-cdn.jtvnw.net/badges/v1/3267646d-33f0-4b17-b3df-f923a41db1d0/"}],"moments":[{"id":"1","title":"Moments Badge - Tier 1","image":"https://static-cdn.jtvnw.net/badges/v1/bf370830-d79a-497b-81c6-a365b2b60dda/"},{"id":"10","title":"Moments Badge - Tier 10","image":"https://static-cdn.jtvnw.net/badges/v1/9c13f2b6-69cd-4537-91b4-4a8bd8b6b1fd/"},{"id":"11","title":"Moments Badge - Tier 11","image":"https://static-cdn.jtvnw.net/badges/v1/7573e7a2-0f1f-4508-b833-d822567a1e03/"},{"id":"12","title":"Moments Badge - Tier 12","image":"https://static-cdn.jtvnw.net/badges/v1/f2c91d14-85c8-434b-a6c0-6d7930091150/"},{"id":"13","title":"Moments Badge - Tier 13","image":"https://static-cdn.jtvnw.net/badges/v1/35eb3395-a1d3-4170-969a-86402ecfb11a/"},{"id":"14","title":"Moments Badge - Tier 14","image":"https://static-cdn.jtvnw.net/badges/v1/cb40eb03-1015-45ba-8793-51c66a24a3d5/"},{"id":"15","title":"Moments Badge - Tier 15","image":"https://static-cdn.jtvnw.net/badges/v1/b241d667-280b-4183-96ae-2d0053631186/"},{"id":"16","title":"Moments Badge - Tier 16","image":"https://static-cdn.jtvnw.net/badges/v1/5684d1bc-8132-4a4f-850c-18d3c5bd04f3/"},{"id":"17","title":"Moments Badge - Tier 17","image":"https://static-cdn.jtvnw.net/badges/v1/3b08c1ee-0f77-451b-9226-b5b22d7f023c/"},{"id":"18","title":"Moments Badge - Tier 18","image":"https://static-cdn.jtvnw.net/badges/v1/14057e75-080c-42da-a412-6232c6f33b68/"},{"id":"19","title":"Moments Badge - Tier 19","image":"https://static-cdn.jtvnw.net/badges/v1/6100cc6f-6b4b-4a3d-a55b-a5b34edb5ea1/"},{"id":"2","title":"Moments Badge - Tier 2","image":"https://static-cdn.jtvnw.net/badges/v1/fc46b10c-5b45-43fd-81ad-d5cb0de6d2f4/"},{"id":"20","title":"Moments Badge - Tier 20","image":"https://static-cdn.jtvnw.net/badges/v1/43399796-e74c-4741-a975-56202f0af30e/"},{"id":"3","title":"Moments Badge - Tier 3","image":"https://static-cdn.jtvnw.net/badges/v1/d08658d7-205f-4f75-ad44-8c6e0acd8ef6/"},{"id":"4","title":"Moments Badge - Tier 4","image":"https://static-cdn.jtvnw.net/badges/v1/fe5b5ddc-93e7-4aaf-9b3e-799cd41808b1/"},{"id":"5","title":"Moments Badge - Tier 5","image":"https://static-cdn.jtvnw.net/badges/v1/c8a0d95a-856e-4097-9fc0-7765300a4f58/"},{"id":"6","title":"Moments Badge - Tier 6","image":"https://static-cdn.jtvnw.net/badges/v1/f9e3b4e4-200e-4045-bd71-3a6b480c23ae/"},{"id":"7","title":"Moments Badge - Tier 7","image":"https://static-cdn.jtvnw.net/badges/v1/a90a26a4-fdf7-4ac3-a782-76a413da16c1/"},{"id":"8","title":"Moments Badge - Tier 8","image":"https://static-cdn.jtvnw.net/badges/v1/f22286cd-6aa3-42ce-b3fb-10f5d18c4aa0/"},{"id":"9","title":"Moments Badge - Tier 9","image":"https://static-cdn.jtvnw.net/badges/v1/5cb2e584-1efd-469b-ab1d-4d1b59a944e7/"}],"no_audio":[{"id":"1","title":"Watching without audio","image":"https://static-cdn.jtvnw.net/badges/v1/aef2cd08-f29b-45a1-8c12-d44d7fd5e6f0/"}],"no_video":[{"id":"1","title":"Listening only","image":"https://static-cdn.jtvnw.net/badges/v1/199a0dba-58f3-494e-a7fc-1fa0a1001fb8/"}],"okhlos_1":[{"id":"1","title":"Okhlos","image":"https://static-cdn.jtvnw.net/badges/v1/dc088bd6-8965-4907-a1a2-c0ba83874a7d/","url":"https://www.twitch.tv/directory/game/Okhlos/details"}],"overwatch-league-insider_1":[{"id":"1","title":"OWL All-Access Pass 2018","image":"https://static-cdn.jtvnw.net/badges/v1/51e9e0aa-12e3-48ce-b961-421af0787dad/","url":"https://www.twitch.tv/overwatchleague"}],"overwatch-league-insider_2018B":[{"id":"1","title":"OWL All-Access Pass 2018","image":"https://static-cdn.jtvnw.net/badges/v1/34ec1979-d9bb-4706-ad15-464de814a79d/","url":"https://www.twitch.tv/overwatchleague"}],"overwatch-league-insider_2019A":[{"id":"1","title":"OWL All-Access Pass 2019","image":"https://static-cdn.jtvnw.net/badges/v1/ca980da1-3639-48a6-95a3-a03b002eb0e5/","url":"https://www.twitch.tv/overwatchleague"},{"id":"2","title":"OWL All-Access Pass 2019","image":"https://static-cdn.jtvnw.net/badges/v1/ab7fa7a7-c2d9-403f-9f33-215b29b43ce4/","url":"https://www.twitch.tv/overwatchleague"}],"overwatch-league-insider_2019B":[{"id":"1","title":"OWL All-Access Pass 2019","image":"https://static-cdn.jtvnw.net/badges/v1/c5860811-d714-4413-9433-d6b1c9fc803c/","url":"https://www.twitch.tv/overwatchleague"},{"id":"2","title":"OWL All-Access Pass 2019","image":"https://static-cdn.jtvnw.net/badges/v1/75f05d4b-3042-415c-8b0b-e87620a24daf/","url":"https://www.twitch.tv/overwatchleague"},{"id":"3","title":"OWL All-Access Pass 2019","image":"https://static-cdn.jtvnw.net/badges/v1/765a0dcf-2a94-43ff-9b9c-ef6c209b90cd/","url":"https://www.twitch.tv/overwatchleague"},{"id":"4","title":"OWL All-Access Pass 2019","image":"https://static-cdn.jtvnw.net/badges/v1/a8ae0ccd-783d-460d-93ee-57c485c558a6/","url":"https://www.twitch.tv/overwatchleague"},{"id":"5","title":"OWL All-Access Pass 2019","image":"https://static-cdn.jtvnw.net/badges/v1/be87fd6d-1560-4e33-9ba4-2401b58d901f/","url":"https://www.twitch.tv/overwatchleague"}],"partner":[{"id":"1","title":"Verified","image":"https://static-cdn.jtvnw.net/badges/v1/d12a2e27-16f6-41d0-ab77-b780518f00a3/","url":"https://blog.twitch.tv/2017/04/24/the-verified-badge-is-here-13381bc05735"}],"power-rangers":[{"id":"0","title":"Black Ranger","image":"https://static-cdn.jtvnw.net/badges/v1/9edf3e7f-62e4-40f5-86ab-7a646b10f1f0/"},{"id":"1","title":"Blue Ranger","image":"https://static-cdn.jtvnw.net/badges/v1/1eeae8fe-5bc6-44ed-9c88-fb84d5e0df52/"},{"id":"2","title":"Green Ranger","image":"https://static-cdn.jtvnw.net/badges/v1/21bbcd6d-1751-4d28-a0c3-0b72453dd823/"},{"id":"3","title":"Pink Ranger","image":"https://static-cdn.jtvnw.net/badges/v1/5c58cb40-9028-4d16-af67-5bc0c18b745e/"},{"id":"4","title":"Red Ranger","image":"https://static-cdn.jtvnw.net/badges/v1/8843d2de-049f-47d5-9794-b6517903db61/"},{"id":"5","title":"White Ranger","image":"https://static-cdn.jtvnw.net/badges/v1/06c85e34-477e-4939-9537-fd9978976042/"},{"id":"6","title":"Yellow Ranger","image":"https://static-cdn.jtvnw.net/badges/v1/d6dca630-1ca4-48de-94e7-55ed0a24d8d1/"}],"predictions":[{"id":"blue-1","title":"Predicted Blue (1)","image":"https://static-cdn.jtvnw.net/badges/v1/e33d8b46-f63b-4e67-996d-4a7dcec0ad33/"},{"id":"blue-10","title":"Predicted Blue (10)","image":"https://static-cdn.jtvnw.net/badges/v1/072ae906-ecf7-44f1-ac69-a5b2261d8892/"},{"id":"blue-2","title":"Predicted Blue (2)","image":"https://static-cdn.jtvnw.net/badges/v1/ffdda3fe-8012-4db3-981e-7a131402b057/"},{"id":"blue-3","title":"Predicted Blue (3)","image":"https://static-cdn.jtvnw.net/badges/v1/f2ab9a19-8ef7-4f9f-bd5d-9cf4e603f845/"},{"id":"blue-4","title":"Predicted Blue (4)","image":"https://static-cdn.jtvnw.net/badges/v1/df95317d-9568-46de-a421-a8520edb9349/"},{"id":"blue-5","title":"Predicted Blue (5)","image":"https://static-cdn.jtvnw.net/badges/v1/88758be8-de09-479b-9383-e3bb6d9e6f06/"},{"id":"blue-6","title":"Predicted Blue (6)","image":"https://static-cdn.jtvnw.net/badges/v1/46b1537e-d8b0-4c0d-8fba-a652e57b9df0/"},{"id":"blue-7","title":"Predicted Blue (7)","image":"https://static-cdn.jtvnw.net/badges/v1/07cd34b2-c6a1-45f5-8d8a-131e3c8b2279/"},{"id":"blue-8","title":"Predicted Blue (8)","image":"https://static-cdn.jtvnw.net/badges/v1/4416dfd7-db97-44a0-98e7-40b4e250615e/"},{"id":"blue-9","title":"Predicted Blue (9)","image":"https://static-cdn.jtvnw.net/badges/v1/fc74bd90-2b74-4f56-8e42-04d405e10fae/"},{"id":"gray-1","title":"Predicted Gray (1)","image":"https://static-cdn.jtvnw.net/badges/v1/144f77a2-e324-4a6b-9c17-9304fa193a27/"},{"id":"gray-2","title":"Predicted Gray (2)","image":"https://static-cdn.jtvnw.net/badges/v1/097a4b14-b458-47eb-91b6-fe74d3dbb3f5/"},{"id":"pink-1","title":"Predicted Pink (1)","image":"https://static-cdn.jtvnw.net/badges/v1/75e27613-caf7-4585-98f1-cb7363a69a4a/"},{"id":"pink-2","title":"Predicted Pink (2)","image":"https://static-cdn.jtvnw.net/badges/v1/4b76d5f2-91cc-4400-adf2-908a1e6cfd1e/"}],"premium":[{"id":"1","title":"Prime Gaming","image":"https://static-cdn.jtvnw.net/badges/v1/bbbe0db0-a598-423e-86d0-f9fb98ca1933/","url":"https://gaming.amazon.com"}],"psychonauts_1":[{"id":"1","title":"Psychonauts","image":"https://static-cdn.jtvnw.net/badges/v1/a9811799-dce3-475f-8feb-3745ad12b7ea/","url":"https://www.twitch.tv/directory/game/Psychonauts/details"}],"raging-wolf-helm":[{"id":"1","title":"Raging Wolf Helm","image":"https://static-cdn.jtvnw.net/badges/v1/3ff668be-59a3-4e3e-96af-e6b2908b3171/"}],"raiden-v-directors-cut_1":[{"id":"1","title":"Raiden V","image":"https://static-cdn.jtvnw.net/badges/v1/441b50ae-a2e3-11e7-8a3e-6bff0c840878/","url":"https://www.twitch.tv/directory/game/Raiden%20V/details"}],"rift_1":[{"id":"1","title":"RIFT","image":"https://static-cdn.jtvnw.net/badges/v1/f939686b-2892-46a4-9f0d-5f582578173e/","url":"https://www.twitch.tv/directory/game/Rift/details"}],"rplace-2023":[{"id":"1","title":"r/place 2023 Cake","image":"https://static-cdn.jtvnw.net/badges/v1/e33e0c67-c380-4241-828a-099c46e51c66/","url":"https://www.reddit.com/r/place/"}],"samusoffer_beta":[{"id":"0","title":"beta_title1","image":"https://static-cdn.jtvnw.net/badges/v1/aa960159-a7b8-417e-83c1-035e4bc2deb5/","url":"https://twitch.amazon.com/prime"}],"staff":[{"id":"1","title":"Staff","image":"https://static-cdn.jtvnw.net/badges/v1/d97c37bd-a6f5-4c38-8f57-4e4bef88af34/","url":"https://www.twitch.tv/jobs?ref=chat_badge"}],"starbound_1":[{"id":"1","title":"Starbound","image":"https://static-cdn.jtvnw.net/badges/v1/e838e742-0025-4646-9772-18a87ba99358/","url":"https://www.twitch.tv/directory/game/Starbound/details"}],"strafe_1":[{"id":"1","title":"Strafe","image":"https://static-cdn.jtvnw.net/badges/v1/0051508d-2d42-4e4b-a328-c86b04510ca4/","url":"https://www.twitch.tv/directory/game/strafe/details"}],"streamer-awards-2024":[{"id":"1","title":"Streamer Awards 2024","image":"https://static-cdn.jtvnw.net/badges/v1/efc07d3d-46e4-4738-827b-a5bf3508983a/","url":"https://thestreamerawards.com/home"}],"sub-gift-leader":[{"id":"1","title":"Gifter Leader 1","image":"https://static-cdn.jtvnw.net/badges/v1/21656088-7da2-4467-acd2-55220e1f45ad/"},{"id":"2","title":"Gifter Leader 2","image":"https://static-cdn.jtvnw.net/badges/v1/0d9fe96b-97b7-4215-b5f3-5328ebad271c/"},{"id":"3","title":"Gifter Leader 3","image":"https://static-cdn.jtvnw.net/badges/v1/4c6e4497-eed9-4dd3-ac64-e0599d0a63e5/"}],"sub-gifter":[{"id":"1","title":"Sub Gifter","image":"https://static-cdn.jtvnw.net/badges/v1/a5ef6c17-2e5b-4d8f-9b80-2779fd722414/"},{"id":"10","title":"10 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/d333288c-65d7-4c7b-b691-cdd7b3484bf8/"},{"id":"100","title":"100 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/8343ada7-3451-434e-91c4-e82bdcf54460/"},{"id":"1000","title":"1000 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/bfb7399a-c632-42f7-8d5f-154610dede81/"},{"id":"150","title":"150 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/514845ba-0fc3-4771-bce1-14d57e91e621/"},{"id":"200","title":"200 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/c6b1893e-8059-4024-b93c-39c84b601732/"},{"id":"2000","title":"2000 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/4e8b3a32-1513-44ad-8a12-6c90232c77f9/"},{"id":"25","title":"25 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/052a5d41-f1cc-455c-bc7b-fe841ffaf17f/"},{"id":"250","title":"250 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/cd479dc0-4a15-407d-891f-9fd2740bddda/"},{"id":"300","title":"300 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/9e1bb24f-d238-4078-871a-ac401b76ecf2/"},{"id":"3000","title":"3000 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/b18852ba-65d2-4b84-97d2-aeb6c44a0956/"},{"id":"350","title":"350 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/6c4783cd-0aba-4e75-a7a4-f48a70b665b0/"},{"id":"400","title":"400 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/6f4cab6b-def9-4d99-ad06-90b0013b28c8/"},{"id":"4000","title":"4000 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/efbf3c93-ecfa-4b67-8d0a-1f732fb07397/"},{"id":"450","title":"450 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/b593d68a-f8fb-4516-a09a-18cce955402c/"},{"id":"5","title":"5 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/ee113e59-c839-4472-969a-1e16d20f3962/"},{"id":"50","title":"50 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/c4a29737-e8a5-4420-917a-314a447f083e/"},{"id":"500","title":"500 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/60e9504c-8c3d-489f-8a74-314fb195ad8d/"},{"id":"5000","title":"5000 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/d775275d-fd19-4914-b63a-7928a22135c3/"},{"id":"550","title":"550 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/024d2563-1794-43ed-b8dc-33df3efae900/"},{"id":"600","title":"600 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/3ecc3aab-09bf-4823-905e-3a4647171fc1/"},{"id":"650","title":"650 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/eeabf43c-8e4c-448d-9790-4c2172c57944/"},{"id":"700","title":"700 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/4a9acdc7-30be-4dd1-9898-fc9e42b3d304/"},{"id":"750","title":"750 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/ca17277c-53e5-422b-8bb4-7c5dcdb0ac67/"},{"id":"800","title":"800 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/9c1fb96d-0579-43d7-ba94-94672eaef63a/"},{"id":"850","title":"850 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/cc924aaf-dfd4-4f3f-822a-f5a87eb24069/"},{"id":"900","title":"900 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/193d86f6-83e1-428c-9638-d6ca9e408166/"},{"id":"950","title":"950 Gift Subs","image":"https://static-cdn.jtvnw.net/badges/v1/7ce130bd-6f55-40cc-9231-e2a4cb712962/"}],"subscriber":[{"id":"0","title":"Subscriber","image":"https://static-cdn.jtvnw.net/badges/v1/5d9f2208-5dd8-11e7-8513-2ff4adfae661/"},{"id":"1","title":"Subscriber","image":"https://static-cdn.jtvnw.net/badges/v1/5d9f2208-5dd8-11e7-8513-2ff4adfae661/"},{"id":"2","title":"2-Month Subscriber","image":"https://static-cdn.jtvnw.net/badges/v1/25a03e36-2bb2-4625-bd37-d6d9d406238d/"},{"id":"3","title":"3-Month Subscriber","image":"https://static-cdn.jtvnw.net/badges/v1/e8984705-d091-4e54-8241-e53b30a84b0e/"},{"id":"4","title":"6-Month Subscriber","image":"https://static-cdn.jtvnw.net/badges/v1/2d2485f6-d19b-4daa-8393-9493b019156b/"},{"id":"5","title":"9-Month Subscriber","image":"https://static-cdn.jtvnw.net/badges/v1/b4e6b13a-a76f-4c56-87e1-9375a7aaa610/"},{"id":"6","title":"6-Month Subscriber","image":"https://static-cdn.jtvnw.net/badges/v1/ed51a614-2c44-4a60-80b6-62908436b43a/"}],"superhot_1":[{"id":"1","title":"Superhot","image":"https://static-cdn.jtvnw.net/badges/v1/c5a06922-83b5-40cb-885f-bcffd3cd6c68/","url":"https://www.twitch.tv/directory/game/superhot/details"}],"superultracombo-2023":[{"id":"1","title":"SuperUltraCombo 2023","image":"https://static-cdn.jtvnw.net/badges/v1/5864739a-5e58-4623-9450-a2c0555ef90b/"}],"the-game-awards-2023":[{"id":"1","title":"The Game Awards 2023","image":"https://static-cdn.jtvnw.net/badges/v1/10cf46de-61e7-4a42-807a-7898408ce352/","url":"https://blog.twitch.tv/2023/11/30/the-2023-game-awards-is-live-on-twitch-december-7th/"}],"the-golden-predictor-of-the-game-awards-2023":[{"id":"1","title":"The Golden Predictor of the Game Awards 2023","image":"https://static-cdn.jtvnw.net/badges/v1/c84c4dd7-9318-4e8b-9f01-1612d3f83dae/","url":"https://blog.twitch.tv/2023/11/30/the-2023-game-awards-is-live-on-twitch-december-7th/"}],"the-surge_1":[{"id":"1","title":"The Surge","image":"https://static-cdn.jtvnw.net/badges/v1/c9f69d89-31c8-41aa-843b-fee956dfbe23/","url":"https://www.twitch.tv/directory/game/The%20Surge/details"}],"the-surge_2":[{"id":"1","title":"The Surge","image":"https://static-cdn.jtvnw.net/badges/v1/2c4d7e95-e138-4dde-a783-7956a8ecc408/","url":"https://www.twitch.tv/directory/game/The%20Surge/details"}],"the-surge_3":[{"id":"1","title":"The Surge","image":"https://static-cdn.jtvnw.net/badges/v1/0a8fc2d4-3125-4ccb-88db-e970dfbee189/","url":"https://www.twitch.tv/directory/game/The%20Surge/details"}],"this-war-of-mine_1":[{"id":"1","title":"This War of Mine","image":"https://static-cdn.jtvnw.net/badges/v1/6a20f814-cb2c-414e-89cc-f8dd483e1785/","url":"https://www.twitch.tv/directory/game/This%20War%20of%20Mine/details"}],"titan-souls_1":[{"id":"1","title":"Titan Souls","image":"https://static-cdn.jtvnw.net/badges/v1/092a7ce2-709c-434f-8df4-a6b075ef867d/","url":"https://www.twitch.tv/directory/game/Titan%20Souls/details"}],"treasure-adventure-world_1":[{"id":"1","title":"Treasure Adventure World","image":"https://static-cdn.jtvnw.net/badges/v1/59810027-2988-4b0d-b88d-fc414c751305/","url":"https://www.twitch.tv/directory/game/Treasure%20Adventure%20World/details"}],"turbo":[{"id":"1","title":"Turbo","image":"https://static-cdn.jtvnw.net/badges/v1/bd444ec6-8f34-4bf9-91f4-af1e3428d80f/"}],"twitch-dj":[{"id":"1","title":"Twitch DJ","image":"https://static-cdn.jtvnw.net/badges/v1/cf91bbc0-0332-413a-a7f3-e36bac08b624/","url":"https://www.twitch.tv/dj-program"}],"twitch-intern-2023":[{"id":"1","title":"Twitch Intern 2023","image":"https://static-cdn.jtvnw.net/badges/v1/e239e7e0-e373-4fdf-b95e-3469aec28485/","url":"https://www.twitch.tv/jobs/early-career/"}],"twitch-intern-2024":[{"id":"1","title":"Twitch Intern 2024","image":"https://static-cdn.jtvnw.net/badges/v1/ae96ce48-e764-4232-aa48-d9abf9a5fdab/","url":"https://www.twitch.tv/jobs/early-career/"}],"twitch-recap-2023":[{"id":"1","title":"Twitch Recap 2023","image":"https://static-cdn.jtvnw.net/badges/v1/4d9e9812-ba9b-48a6-8690-13f3f338ee65/","url":"https://twitch-web.app.link/e/twitch-recap"}],"twitchbot":[{"id":"1","title":"AutoMod","image":"https://static-cdn.jtvnw.net/badges/v1/df9095f6-a8a0-4cc2-bb33-d908c0adffb8/","url":"http://link.twitch.tv/automod_blog"}],"twitchcon-2024---rotterdam":[{"id":"1","title":"TwitchCon 2024 - Rotterdam","image":"https://static-cdn.jtvnw.net/badges/v1/95b10c66-775c-4652-9b86-10bd3a709422/","url":"https://twitchcon.com/rotterdam-2024/?utm_source=twitch&utm_medium=chat-badge&utm_campaign=tceu24-chat-badge"}],"twitchcon-2024---san-diego":[{"id":"1","title":"TwitchCon 2024 - San Diego","image":"https://static-cdn.jtvnw.net/badges/v1/6575f0d1-2dc2-4f45-a13f-a1a969dcf8fa/","url":"https://twitchcon.com/san-diego-2024/?utm_source=twitch&utm_medium=chat-badge&utm_campaign=tcsd24-chat-badge"}],"twitchcon2017":[{"id":"1","title":"TwitchCon 2017 - Long Beach","image":"https://static-cdn.jtvnw.net/badges/v1/0964bed0-5c31-11e7-a90b-0739918f1d9b/","url":"https://www.twitchcon.com/"}],"twitchcon2018":[{"id":"1","title":"TwitchCon 2018 - San Jose","image":"https://static-cdn.jtvnw.net/badges/v1/e68164e4-087d-4f62-81da-d3557efae3cb/","url":"https://www.twitchcon.com/?utm_source=twitch-chat&utm_medium=badge&utm_campaign=tc18"}],"twitchconAmsterdam2020":[{"id":"1","title":"TwitchCon 2020 - Amsterdam","image":"https://static-cdn.jtvnw.net/badges/v1/ed917c9a-1a45-4340-9c64-ca8be4348c51/","url":"https://www.twitchcon.com/amsterdam/?utm_source=twitch-chat&utm_medium=badge&utm_campaign=tcamsterdam20"}],"twitchconEU2019":[{"id":"1","title":"TwitchCon 2019 - Berlin","image":"https://static-cdn.jtvnw.net/badges/v1/590eee9e-f04d-474c-90e7-b304d9e74b32/","url":"https://europe.twitchcon.com/?utm_source=twitch-chat&utm_medium=badge&utm_campaign=tceu19"}],"twitchconEU2022":[{"id":"1","title":"TwitchCon 2022 - Amsterdam","image":"https://static-cdn.jtvnw.net/badges/v1/e4744003-50b7-4eb8-9b47-a7b1616a30c6/","url":"https://www.twitchcon.com/amsterdam-2022/?utm_source=twitch-chat&utm_medium=badge&utm_campaign=tceu22"}],"twitchconEU2023":[{"id":"1","title":"TwitchCon 2023 - Paris","image":"https://static-cdn.jtvnw.net/badges/v1/a8f2084e-46b9-4bb9-ae5e-00d594aafc64/","url":"https://www.twitchcon.com/paris-2023/?utm_source=chat_badge"}],"twitchconNA2019":[{"id":"1","title":"TwitchCon 2019 - San Diego","image":"https://static-cdn.jtvnw.net/badges/v1/569c829d-c216-4f56-a191-3db257ed657c/","url":"https://www.twitchcon.com/?utm_source=twitch-chat&utm_medium=badge&utm_campaign=tcna19"}],"twitchconNA2020":[{"id":"1","title":"TwitchCon 2020 - North America","image":"https://static-cdn.jtvnw.net/badges/v1/ed917c9a-1a45-4340-9c64-ca8be4348c51/","url":"https://www.twitchcon.com/?utm_source=twitch-chat&utm_medium=badge&utm_campaign=tcna20"}],"twitchconNA2022":[{"id":"1","title":"TwitchCon 2022 - San Diego","image":"https://static-cdn.jtvnw.net/badges/v1/344d429a-0b34-48e5-a84c-14a1b5772a3a/","url":"https://www.twitchcon.com/san-diego-2022/?utm_source=twitch-chat&utm_medium=badge&utm_campaign=tcna22"}],"twitchconNA2023":[{"id":"1","title":"TwitchCon 2023 - Las Vegas","image":"https://static-cdn.jtvnw.net/badges/v1/c90a753f-ab20-41bc-9c42-ede062485d2c/","url":"https://www.twitchcon.com/en/las-vegas-2023/"}],"tyranny_1":[{"id":"1","title":"Tyranny","image":"https://static-cdn.jtvnw.net/badges/v1/0c79afdf-28ce-4b0b-9e25-4f221c30bfde/","url":"https://www.twitch.tv/directory/game/Tyranny/details"}],"user-anniversary":[{"id":"1","title":"Twitchiversary Badge","image":"https://static-cdn.jtvnw.net/badges/v1/ccbbedaa-f4db-4d0b-9c2a-375de7ad947c/"}],"vga-champ-2017":[{"id":"1","title":"2017 VGA Champ","image":"https://static-cdn.jtvnw.net/badges/v1/03dca92e-dc69-11e7-ac5b-9f942d292dc7/","url":"https://blog.twitch.tv/watch-and-co-stream-the-game-awards-this-thursday-on-twitch-3d8e34d2345d"}],"vip":[{"id":"1","title":"VIP","image":"https://static-cdn.jtvnw.net/badges/v1/b817aba4-fad8-49e2-b88a-7cc744dfa6ec/","url":"https://help.twitch.tv/customer/en/portal/articles/659115-twitch-chat-badges-guide"}],"warcraft":[{"id":"alliance","title":"Alliance","image":"https://static-cdn.jtvnw.net/badges/v1/c4816339-bad4-4645-ae69-d1ab2076a6b0/","url":"http://warcraftontwitch.tv/"},{"id":"horde","title":"Horde","image":"https://static-cdn.jtvnw.net/badges/v1/de8b26b6-fd28-4e6c-bc89-3d597343800d/","url":"http://warcraftontwitch.tv/"}],"zevent-2024":[{"id":"1","title":"ZEVENT 2024","image":"https://static-cdn.jtvnw.net/badges/v1/2040d479-b815-4617-8a55-9aed027e30d0/"}]} \ No newline at end of file diff --git a/scripts/update-badges.py b/scripts/update-badges.py new file mode 100644 index 00000000000..5c5f5cc3ce7 --- /dev/null +++ b/scripts/update-badges.py @@ -0,0 +1,28 @@ +import sys +import json +from pathlib import Path + + +def trim_version(version): + base_url = version["image_url_1x"].removesuffix("1") + assert version["image_url_2x"] == base_url + "2" + assert version["image_url_4x"] == base_url + "3" + v = { + "id": version["id"], + "title": version["title"], + "image": base_url, + } + if version["click_url"]: + v["url"] = version["click_url"] + return v + + +raw = sys.stdin.read() +assert len(raw) > 0, "Response from Helix' chat/badges/global needs to be piped" +base = json.loads(raw)["data"] +out = {set["set_id"]: [trim_version(v) for v in set["versions"]] for set in base} + +with open( + Path(__file__).parent.parent / "resources" / "twitch-badges.json", mode="w" +) as f: + f.write(json.dumps(out, separators=(",", ":"))) diff --git a/src/providers/twitch/TwitchBadges.cpp b/src/providers/twitch/TwitchBadges.cpp index 6e2b4c4aad8..95e42af68f0 100644 --- a/src/providers/twitch/TwitchBadges.cpp +++ b/src/providers/twitch/TwitchBadges.cpp @@ -79,59 +79,59 @@ void TwitchBadges::loadTwitchBadges() break; } qCWarning(chatterinoTwitch) << errorMessage; - QFile file(":/twitch-badges.json"); - if (!file.open(QFile::ReadOnly)) - { - // Despite erroring out, we still want to reach the same point - // Loaded should still be set to true to not build up an endless queue, and the quuee should still be flushed. - qCWarning(chatterinoTwitch) - << "Error loading Twitch Badges from the local backup file"; - this->loaded(); - return; - } - auto bytes = file.readAll(); - auto doc = QJsonDocument::fromJson(bytes); - - this->parseTwitchBadges(doc.object()); - - this->loaded(); + this->loadLocalBadges(); }); } -void TwitchBadges::parseTwitchBadges(QJsonObject root) +void TwitchBadges::loadLocalBadges() { - auto badgeSets = this->badgeSets_.access(); + QFile file(":/twitch-badges.json"); + if (!file.open(QFile::ReadOnly)) + { + // Despite erroring out, we still want to reach the same point + // Loaded should still be set to true to not build up an endless queue, and the quuee should still be flushed. + qCWarning(chatterinoTwitch) + << "Error loading Twitch Badges from the local backup file"; + this->loaded(); + return; + } + auto bytes = file.readAll(); + auto doc = QJsonDocument::fromJson(bytes); - auto jsonSets = root.value("badge_sets").toObject(); - for (auto sIt = jsonSets.begin(); sIt != jsonSets.end(); ++sIt) { - auto key = sIt.key(); - auto versions = sIt.value().toObject().value("versions").toObject(); + const auto &root = doc.object(); + auto badgeSets = this->badgeSets_.access(); - for (auto vIt = versions.begin(); vIt != versions.end(); ++vIt) + for (auto setIt = root.begin(); setIt != root.end(); setIt++) { - auto versionObj = vIt.value().toObject(); - auto emote = Emote{ - .name = {""}, - .images = - ImageSet{ - Image::fromUrl( - {versionObj.value("image_url_1x").toString()}, 1, - BADGE_BASE_SIZE), - Image::fromUrl( - {versionObj.value("image_url_2x").toString()}, .5, - BADGE_BASE_SIZE * 2), - Image::fromUrl( - {versionObj.value("image_url_4x").toString()}, .25, - BADGE_BASE_SIZE * 4), - }, - .tooltip = Tooltip{versionObj.value("title").toString()}, - .homePage = Url{versionObj.value("click_url").toString()}, - }; - - (*badgeSets)[key][vIt.key()] = std::make_shared(emote); + auto key = setIt.key(); + + for (auto versionValue : setIt.value().toArray()) + { + const auto versionObj = versionValue.toObject(); + auto id = versionObj["id"].toString(); + auto baseImage = versionObj["image"].toString(); + auto emote = Emote{ + .name = {}, + .images = + ImageSet{ + Image::fromUrl({baseImage + '1'}, 1, + BADGE_BASE_SIZE), + Image::fromUrl({baseImage + '2'}, .5, + BADGE_BASE_SIZE * 2), + Image::fromUrl({baseImage + '3'}, .25, + BADGE_BASE_SIZE * 4), + }, + .tooltip = Tooltip{versionObj["title"].toString()}, + .homePage = Url{versionObj["url"].toString()}, + }; + + (*badgeSets)[key][id] = std::make_shared(emote); + } } } + + this->loaded(); } void TwitchBadges::loaded() diff --git a/src/providers/twitch/TwitchBadges.hpp b/src/providers/twitch/TwitchBadges.hpp index fff0f5aff0b..b9519a90650 100644 --- a/src/providers/twitch/TwitchBadges.hpp +++ b/src/providers/twitch/TwitchBadges.hpp @@ -46,7 +46,9 @@ class TwitchBadges void loadTwitchBadges(); private: - void parseTwitchBadges(QJsonObject root); + /// Loads the badges shipped with Chatterino (twitch-badges.json) + void loadLocalBadges(); + void loaded(); void loadEmoteImage(const QString &name, const ImagePtr &image, BadgeIconCallback &&callback); From e149be38200986d3f256a2e9d5756c0a44f4bd65 Mon Sep 17 00:00:00 2001 From: nerix Date: Sat, 28 Sep 2024 12:40:15 +0200 Subject: [PATCH 3/4] feat: include more data when copying messages as JSON (#5600) --- CHANGELOG.md | 1 + src/messages/Emote.cpp | 37 ++++ src/messages/Emote.hpp | 4 + src/messages/ImageSet.cpp | 20 ++ src/messages/ImageSet.hpp | 4 + src/messages/Message.cpp | 78 +++++++ src/messages/Message.hpp | 4 + src/messages/MessageColor.cpp | 17 ++ src/messages/MessageColor.hpp | 3 + src/messages/MessageElement.cpp | 221 ++++++++++++++++++++ src/messages/MessageElement.hpp | 47 ++++- src/messages/MessageThread.cpp | 33 +++ src/messages/MessageThread.hpp | 4 + src/providers/twitch/ChannelPointReward.cpp | 24 +++ src/providers/twitch/ChannelPointReward.hpp | 2 + src/widgets/helper/ChannelView.cpp | 38 +--- 16 files changed, 504 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f4b479f218..e8c08c93b5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -90,6 +90,7 @@ - Dev: The timer for `StreamerMode` is now destroyed on the correct thread. (#5571) - Dev: Cleanup some parts of the `magic_enum` adaptation for Qt. (#5587) - Dev: Refactored `static`s in headers to only be present once in the final app. (#5588) +- Dev: The JSON output when copying a message (SHIFT + right-click) is now more extensive. (#5600) ## 2.5.1 diff --git a/src/messages/Emote.cpp b/src/messages/Emote.cpp index f19fc3027b5..4d7a7bbb90f 100644 --- a/src/messages/Emote.cpp +++ b/src/messages/Emote.cpp @@ -1,9 +1,15 @@ #include "messages/Emote.hpp" +#include "common/Literals.hpp" + +#include + #include namespace chatterino { +using namespace literals; + bool operator==(const Emote &a, const Emote &b) { return std::tie(a.homePage, a.name, a.tooltip, a.images) == @@ -15,6 +21,37 @@ bool operator!=(const Emote &a, const Emote &b) return !(a == b); } +QJsonObject Emote::toJson() const +{ + QJsonObject obj{ + {"name"_L1, this->name.string}, + {"images"_L1, this->images.toJson()}, + {"tooltip"_L1, this->tooltip.string}, + }; + if (!this->homePage.string.isEmpty()) + { + obj["homePage"_L1] = this->homePage.string; + } + if (this->zeroWidth) + { + obj["zeroWidth"_L1] = this->zeroWidth; + } + if (!this->id.string.isEmpty()) + { + obj["id"_L1] = this->id.string; + } + if (!this->author.string.isEmpty()) + { + obj["author"_L1] = this->author.string; + } + if (this->baseName) + { + obj["baseName"_L1] = this->baseName->string; + } + + return obj; +} + EmotePtr cachedOrMakeEmotePtr(Emote &&emote, const EmoteMap &cache) { // reuse old shared_ptr if nothing changed diff --git a/src/messages/Emote.hpp b/src/messages/Emote.hpp index d0861849bfe..c2fd3885ad1 100644 --- a/src/messages/Emote.hpp +++ b/src/messages/Emote.hpp @@ -9,6 +9,8 @@ #include #include +class QJsonObject; + namespace chatterino { struct Emote { @@ -30,6 +32,8 @@ struct Emote { { return name.string; } + + QJsonObject toJson() const; }; bool operator==(const Emote &a, const Emote &b); diff --git a/src/messages/ImageSet.cpp b/src/messages/ImageSet.cpp index 7e25e3f86b6..1c591f64400 100644 --- a/src/messages/ImageSet.cpp +++ b/src/messages/ImageSet.cpp @@ -3,6 +3,8 @@ #include "messages/Image.hpp" #include "singletons/Settings.hpp" +#include + namespace chatterino { ImageSet::ImageSet() @@ -135,4 +137,22 @@ bool ImageSet::operator!=(const ImageSet &other) const return !this->operator==(other); } +QJsonObject ImageSet::toJson() const +{ + QJsonObject obj; + if (!this->imageX1_->isEmpty()) + { + obj[u"1x"] = this->imageX1_->url().string; + } + if (!this->imageX2_->isEmpty()) + { + obj[u"2x"] = this->imageX2_->url().string; + } + if (!this->imageX3_->isEmpty()) + { + obj[u"3x"] = this->imageX3_->url().string; + } + return obj; +} + } // namespace chatterino diff --git a/src/messages/ImageSet.hpp b/src/messages/ImageSet.hpp index 49c94eed0cb..c5cba49e2f4 100644 --- a/src/messages/ImageSet.hpp +++ b/src/messages/ImageSet.hpp @@ -4,6 +4,8 @@ #include +class QJsonObject; + namespace chatterino { class Image; @@ -34,6 +36,8 @@ class ImageSet bool operator==(const ImageSet &other) const; bool operator!=(const ImageSet &other) const; + QJsonObject toJson() const; + private: ImagePtr imageX1_; ImagePtr imageX2_; diff --git a/src/messages/Message.cpp b/src/messages/Message.cpp index 8840c6919fa..8d3d201bd0a 100644 --- a/src/messages/Message.cpp +++ b/src/messages/Message.cpp @@ -1,13 +1,23 @@ #include "messages/Message.hpp" +#include "Application.hpp" +#include "common/Literals.hpp" +#include "messages/MessageThread.hpp" #include "providers/colors/ColorProvider.hpp" #include "providers/twitch/TwitchBadge.hpp" #include "singletons/Settings.hpp" #include "util/DebugCount.hpp" +#include "util/QMagicEnum.hpp" #include "widgets/helper/ScrollbarHighlight.hpp" +#include +#include +#include + namespace chatterino { +using namespace literals; + Message::Message() : parseTime(QTime::currentTime()) { @@ -80,4 +90,72 @@ ScrollbarHighlight Message::getScrollBarHighlight() const return {}; } +QJsonObject Message::toJson() const +{ + QJsonObject msg{ + {"flags"_L1, qmagicenum::enumFlagsName(this->flags.value())}, + {"id"_L1, this->id}, + {"searchText"_L1, this->searchText}, + {"messageText"_L1, this->messageText}, + {"loginName"_L1, this->loginName}, + {"displayName"_L1, this->displayName}, + {"localizedName"_L1, this->localizedName}, + {"timeoutUser"_L1, this->timeoutUser}, + {"channelName"_L1, this->channelName}, + {"usernameColor"_L1, this->usernameColor.name(QColor::HexArgb)}, + {"count"_L1, static_cast(this->count)}, + {"serverReceivedTime"_L1, + this->serverReceivedTime.toString(Qt::ISODate)}, + }; + + QJsonArray badges; + for (const auto &badge : this->badges) + { + badges.append(badge.key_); + } + msg["badges"_L1] = badges; + + QJsonObject badgeInfos; + for (const auto &[key, value] : this->badgeInfos) + { + badgeInfos.insert(key, value); + } + msg["badgeInfos"_L1] = badgeInfos; + + if (this->highlightColor) + { + msg["highlightColor"_L1] = this->highlightColor->name(QColor::HexArgb); + } + + if (this->replyThread) + { + msg["replyThread"_L1] = this->replyThread->toJson(); + } + + if (this->replyParent) + { + msg["replyParent"_L1] = this->replyParent->id; + } + + if (this->reward) + { + msg["reward"_L1] = this->reward->toJson(); + } + + // XXX: figure out if we can add this in tests + if (!getApp()->isTest()) + { + msg["parseTime"_L1] = this->parseTime.toString(Qt::ISODate); + } + + QJsonArray elements; + for (const auto &element : this->elements) + { + elements.append(element->toJson()); + } + msg["elements"_L1] = elements; + + return msg; +} + } // namespace chatterino diff --git a/src/messages/Message.hpp b/src/messages/Message.hpp index 898f1221789..dd0fa26ff2c 100644 --- a/src/messages/Message.hpp +++ b/src/messages/Message.hpp @@ -12,6 +12,8 @@ #include #include +class QJsonObject; + namespace chatterino { class MessageElement; class MessageThread; @@ -62,6 +64,8 @@ struct Message { ScrollbarHighlight getScrollBarHighlight() const; std::shared_ptr reward = nullptr; + + QJsonObject toJson() const; }; } // namespace chatterino diff --git a/src/messages/MessageColor.cpp b/src/messages/MessageColor.cpp index 6e2f01c6737..674f4a6867e 100644 --- a/src/messages/MessageColor.cpp +++ b/src/messages/MessageColor.cpp @@ -33,4 +33,21 @@ const QColor &MessageColor::getColor(Theme &themeManager) const return _default; } +QString MessageColor::toString() const +{ + switch (this->type_) + { + case Type::Custom: + return this->customColor_.name(QColor::HexArgb); + case Type::Text: + return QStringLiteral("Text"); + case Type::System: + return QStringLiteral("System"); + case Type::Link: + return QStringLiteral("Link"); + default: + return {}; + } +} + } // namespace chatterino diff --git a/src/messages/MessageColor.hpp b/src/messages/MessageColor.hpp index dd19692c95e..5592b973515 100644 --- a/src/messages/MessageColor.hpp +++ b/src/messages/MessageColor.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include namespace chatterino { class Theme; @@ -13,6 +14,8 @@ struct MessageColor { const QColor &getColor(Theme &themeManager) const; + QString toString() const; + private: Type type_; QColor customColor_; diff --git a/src/messages/MessageElement.cpp b/src/messages/MessageElement.cpp index a8beed9c011..a4fd6fe846d 100644 --- a/src/messages/MessageElement.cpp +++ b/src/messages/MessageElement.cpp @@ -1,6 +1,7 @@ #include "messages/MessageElement.hpp" #include "Application.hpp" +#include "common/Literals.hpp" #include "controllers/moderationactions/ModerationAction.hpp" #include "debug/Benchmark.hpp" #include "messages/Emote.hpp" @@ -14,8 +15,14 @@ #include "util/DebugCount.hpp" #include "util/Variant.hpp" +#include +#include +#include + namespace chatterino { +using namespace literals; + namespace { // Computes the bounding box for the given vector of images @@ -88,6 +95,22 @@ void MessageElement::addFlags(MessageElementFlags flags) this->flags_.set(flags); } +QJsonObject MessageElement::toJson() const +{ + return { + {"trailingSpace"_L1, this->trailingSpace}, + { + "link"_L1, + {{ + {"type"_L1, qmagicenum::enumNameString(this->link_.type)}, + {"value"_L1, this->link_.value}, + }}, + }, + {"tooltip"_L1, this->tooltip_}, + {"flags"_L1, qmagicenum::enumFlagsName(this->flags_.value())}, + }; +} + // IMAGE ImageElement::ImageElement(ImagePtr image, MessageElementFlags flags) : MessageElement(flags) @@ -108,6 +131,15 @@ void ImageElement::addToContainer(MessageLayoutContainer &container, } } +QJsonObject ImageElement::toJson() const +{ + auto base = MessageElement::toJson(); + base["type"_L1] = u"ImageElement"_s; + base["url"_L1] = this->image_->url().string; + + return base; +} + CircularImageElement::CircularImageElement(ImagePtr image, int padding, QColor background, MessageElementFlags flags) @@ -131,6 +163,17 @@ void CircularImageElement::addToContainer(MessageLayoutContainer &container, } } +QJsonObject CircularImageElement::toJson() const +{ + auto base = MessageElement::toJson(); + base["type"_L1] = u"CircularImageElement"_s; + base["url"_L1] = this->image_->url().string; + base["padding"_L1] = this->padding_; + base["background"_L1] = this->background_.name(QColor::HexArgb); + + return base; +} + // EMOTE EmoteElement::EmoteElement(const EmotePtr &emote, MessageElementFlags flags, const MessageColor &textElementColor) @@ -187,6 +230,19 @@ MessageLayoutElement *EmoteElement::makeImageLayoutElement( return new ImageLayoutElement(*this, image, size); } +QJsonObject EmoteElement::toJson() const +{ + auto base = MessageElement::toJson(); + base["type"_L1] = u"EmoteElement"_s; + base["emote"_L1] = this->emote_->toJson(); + if (this->textElement_) + { + base["text"_L1] = this->textElement_->toJson(); + } + + return base; +} + LayeredEmoteElement::LayeredEmoteElement( std::vector &&emotes, MessageElementFlags flags, const MessageColor &textElementColor) @@ -350,6 +406,38 @@ std::vector LayeredEmoteElement::getUniqueEmotes() return unique; } +QJsonObject LayeredEmoteElement::toJson() const +{ + auto base = MessageElement::toJson(); + base["type"_L1] = u"LayeredEmoteElement"_s; + + QJsonArray emotes; + for (const auto &emote : this->emotes_) + { + emotes.append({{ + {"flags"_L1, qmagicenum::enumFlagsName(emote.flags.value())}, + {"emote"_L1, emote.ptr->toJson()}, + }}); + } + base["emotes"_L1] = emotes; + + QJsonArray tooltips; + for (const auto &tooltip : this->emoteTooltips_) + { + emotes.append(tooltip); + } + base["tooltips"_L1] = tooltips; + + if (this->textElement_) + { + base["text"_L1] = this->textElement_->toJson(); + } + + base["textElementColor"_L1] = this->textElementColor_.toString(); + + return base; +} + // BADGE BadgeElement::BadgeElement(const EmotePtr &emote, MessageElementFlags flags) : MessageElement(flags) @@ -390,6 +478,15 @@ MessageLayoutElement *BadgeElement::makeImageLayoutElement( return element; } +QJsonObject BadgeElement::toJson() const +{ + auto base = MessageElement::toJson(); + base["type"_L1] = u"BadgeElement"_s; + base["emote"_L1] = this->emote_->toJson(); + + return base; +} + // MOD BADGE ModBadgeElement::ModBadgeElement(const EmotePtr &data, MessageElementFlags flags_) @@ -408,6 +505,14 @@ MessageLayoutElement *ModBadgeElement::makeImageLayoutElement( return element; } +QJsonObject ModBadgeElement::toJson() const +{ + auto base = BadgeElement::toJson(); + base["type"_L1] = u"ModBadgeElement"_s; + + return base; +} + // VIP BADGE VipBadgeElement::VipBadgeElement(const EmotePtr &data, MessageElementFlags flags_) @@ -423,6 +528,14 @@ MessageLayoutElement *VipBadgeElement::makeImageLayoutElement( return element; } +QJsonObject VipBadgeElement::toJson() const +{ + auto base = BadgeElement::toJson(); + base["type"_L1] = u"VipBadgeElement"_s; + + return base; +} + // FFZ Badge FfzBadgeElement::FfzBadgeElement(const EmotePtr &data, MessageElementFlags flags_, QColor color_) @@ -440,6 +553,15 @@ MessageLayoutElement *FfzBadgeElement::makeImageLayoutElement( return element; } +QJsonObject FfzBadgeElement::toJson() const +{ + auto base = BadgeElement::toJson(); + base["type"_L1] = u"FfzBadgeElement"_s; + base["color"_L1] = this->color.name(QColor::HexArgb); + + return base; +} + // TEXT TextElement::TextElement(const QString &text, MessageElementFlags flags, const MessageColor &color, FontStyle style) @@ -549,6 +671,17 @@ void TextElement::addToContainer(MessageLayoutContainer &container, } } +QJsonObject TextElement::toJson() const +{ + auto base = MessageElement::toJson(); + base["type"_L1] = u"TextElement"_s; + base["words"_L1] = QJsonArray::fromStringList(this->words_); + base["color"_L1] = this->color_.toString(); + base["style"_L1] = qmagicenum::enumNameString(this->style_); + + return base; +} + SingleLineTextElement::SingleLineTextElement(const QString &text, MessageElementFlags flags, const MessageColor &color, @@ -677,6 +810,22 @@ void SingleLineTextElement::addToContainer(MessageLayoutContainer &container, } } +QJsonObject SingleLineTextElement::toJson() const +{ + auto base = MessageElement::toJson(); + base["type"_L1] = u"SingleLineTextElement"_s; + QJsonArray words; + for (const auto &word : this->words_) + { + words.append(word.text); + } + base["words"_L1] = words; + base["color"_L1] = this->color_.toString(); + base["style"_L1] = qmagicenum::enumNameString(this->style_); + + return base; +} + LinkElement::LinkElement(const Parsed &parsed, const QString &fullUrl, MessageElementFlags flags, const MessageColor &color, FontStyle style) @@ -701,6 +850,17 @@ Link LinkElement::getLink() const return {Link::Url, this->linkInfo_.url()}; } +QJsonObject LinkElement::toJson() const +{ + auto base = TextElement::toJson(); + base["type"_L1] = u"LinkElement"_s; + base["link"_L1] = this->linkInfo_.originalUrl(); + base["lowercase"_L1] = QJsonArray::fromStringList(this->lowercase_); + base["original"_L1] = QJsonArray::fromStringList(this->original_); + + return base; +} + MentionElement::MentionElement(const QString &displayName, QString loginName_, MessageColor fallbackColor_, MessageColor userColor_) @@ -756,7 +916,24 @@ Link MentionElement::getLink() const return {Link::UserInfo, this->userLoginName}; } +QJsonObject MentionElement::toJson() const +{ + auto base = TextElement::toJson(); + base["type"_L1] = u"MentionElement"_s; + base["fallbackColor"_L1] = this->fallbackColor.toString(); + base["userColor"_L1] = this->userColor.toString(); + base["userLoginName"_L1] = this->userLoginName; + + return base; +} + // TIMESTAMP +TimestampElement::TimestampElement() + : TimestampElement(getApp()->isTest() ? QTime::fromMSecsSinceStartOfDay(0) + : QTime::currentTime()) +{ +} + TimestampElement::TimestampElement(QTime time) : MessageElement(MessageElementFlag::Timestamp) , time_(time) @@ -790,6 +967,17 @@ TextElement *TimestampElement::formatTime(const QTime &time) MessageColor::System, FontStyle::ChatMedium); } +QJsonObject TimestampElement::toJson() const +{ + auto base = MessageElement::toJson(); + base["type"_L1] = u"TimestampElement"_s; + base["time"_L1] = this->time_.toString(Qt::ISODate); + base["element"_L1] = this->element_->toJson(); + base["format"_L1] = this->format_; + + return base; +} + // TWITCH MODERATION TwitchModerationElement::TwitchModerationElement() : MessageElement(MessageElementFlag::ModeratorTools) @@ -824,6 +1012,14 @@ void TwitchModerationElement::addToContainer(MessageLayoutContainer &container, } } +QJsonObject TwitchModerationElement::toJson() const +{ + auto base = MessageElement::toJson(); + base["type"_L1] = u"TwitchModerationElement"_s; + + return base; +} + LinebreakElement::LinebreakElement(MessageElementFlags flags) : MessageElement(flags) { @@ -838,6 +1034,14 @@ void LinebreakElement::addToContainer(MessageLayoutContainer &container, } } +QJsonObject LinebreakElement::toJson() const +{ + auto base = MessageElement::toJson(); + base["type"_L1] = u"LinebreakElement"_s; + + return base; +} + ScalingImageElement::ScalingImageElement(ImageSet images, MessageElementFlags flags) : MessageElement(flags) @@ -864,6 +1068,15 @@ void ScalingImageElement::addToContainer(MessageLayoutContainer &container, } } +QJsonObject ScalingImageElement::toJson() const +{ + auto base = MessageElement::toJson(); + base["type"_L1] = u"ScalingImageElement"_s; + base["image"_L1] = this->images_.getImage1()->url().string; + + return base; +} + ReplyCurveElement::ReplyCurveElement() : MessageElement(MessageElementFlag::RepliedMessage) { @@ -886,4 +1099,12 @@ void ReplyCurveElement::addToContainer(MessageLayoutContainer &container, } } +QJsonObject ReplyCurveElement::toJson() const +{ + auto base = MessageElement::toJson(); + base["type"_L1] = u"ReplyCurveElement"_s; + + return base; +} + } // namespace chatterino diff --git a/src/messages/MessageElement.hpp b/src/messages/MessageElement.hpp index 49ce762cb91..041593cac20 100644 --- a/src/messages/MessageElement.hpp +++ b/src/messages/MessageElement.hpp @@ -7,6 +7,7 @@ #include "providers/links/LinkInfo.hpp" #include "singletons/Fonts.hpp" +#include #include #include #include @@ -16,6 +17,8 @@ #include #include +class QJsonObject; + namespace chatterino { class Channel; struct MessageLayoutContainer; @@ -183,6 +186,8 @@ class MessageElement virtual void addToContainer(MessageLayoutContainer &container, MessageElementFlags flags) = 0; + virtual QJsonObject toJson() const; + protected: MessageElement(MessageElementFlags flags); bool trailingSpace = true; @@ -202,6 +207,8 @@ class ImageElement : public MessageElement void addToContainer(MessageLayoutContainer &container, MessageElementFlags flags) override; + QJsonObject toJson() const override; + private: ImagePtr image_; }; @@ -216,6 +223,8 @@ class CircularImageElement : public MessageElement void addToContainer(MessageLayoutContainer &container, MessageElementFlags flags) override; + QJsonObject toJson() const override; + private: ImagePtr image_; int padding_; @@ -234,6 +243,8 @@ class TextElement : public MessageElement void addToContainer(MessageLayoutContainer &container, MessageElementFlags flags) override; + QJsonObject toJson() const override; + protected: QStringList words_; @@ -253,6 +264,8 @@ class SingleLineTextElement : public MessageElement void addToContainer(MessageLayoutContainer &container, MessageElementFlags flags) override; + QJsonObject toJson() const override; + private: MessageColor color_; FontStyle style_; @@ -294,6 +307,8 @@ class LinkElement : public TextElement return &this->linkInfo_; } + QJsonObject toJson() const override; + private: LinkInfo linkInfo_; // these are implicitly shared @@ -328,6 +343,8 @@ class MentionElement : public TextElement MessageElement *setLink(const Link &link) override; Link getLink() const override; + QJsonObject toJson() const override; + private: /** * The color of the element in case the "Colorize @usernames" is disabled @@ -355,6 +372,8 @@ class EmoteElement : public MessageElement MessageElementFlags flags_) override; EmotePtr getEmote() const; + QJsonObject toJson() const override; + protected: virtual MessageLayoutElement *makeImageLayoutElement(const ImagePtr &image, const QSize &size); @@ -390,6 +409,8 @@ class LayeredEmoteElement : public MessageElement std::vector getUniqueEmotes() const; const std::vector &getEmoteTooltips() const; + QJsonObject toJson() const override; + private: MessageLayoutElement *makeImageLayoutElement( const std::vector &image, const std::vector &sizes, @@ -416,6 +437,8 @@ class BadgeElement : public MessageElement EmotePtr getEmote() const; + QJsonObject toJson() const override; + protected: virtual MessageLayoutElement *makeImageLayoutElement(const ImagePtr &image, const QSize &size); @@ -429,6 +452,8 @@ class ModBadgeElement : public BadgeElement public: ModBadgeElement(const EmotePtr &data, MessageElementFlags flags_); + QJsonObject toJson() const override; + protected: MessageLayoutElement *makeImageLayoutElement(const ImagePtr &image, const QSize &size) override; @@ -439,6 +464,8 @@ class VipBadgeElement : public BadgeElement public: VipBadgeElement(const EmotePtr &data, MessageElementFlags flags_); + QJsonObject toJson() const override; + protected: MessageLayoutElement *makeImageLayoutElement(const ImagePtr &image, const QSize &size) override; @@ -450,6 +477,8 @@ class FfzBadgeElement : public BadgeElement FfzBadgeElement(const EmotePtr &data, MessageElementFlags flags_, QColor color_); + QJsonObject toJson() const override; + protected: MessageLayoutElement *makeImageLayoutElement(const ImagePtr &image, const QSize &size) override; @@ -460,7 +489,8 @@ class FfzBadgeElement : public BadgeElement class TimestampElement : public MessageElement { public: - TimestampElement(QTime time_ = QTime::currentTime()); + TimestampElement(); + TimestampElement(QTime time_); ~TimestampElement() override = default; void addToContainer(MessageLayoutContainer &container, @@ -468,6 +498,8 @@ class TimestampElement : public MessageElement TextElement *formatTime(const QTime &time); + QJsonObject toJson() const override; + private: QTime time_; std::unique_ptr element_; @@ -483,6 +515,8 @@ class TwitchModerationElement : public MessageElement void addToContainer(MessageLayoutContainer &container, MessageElementFlags flags) override; + + QJsonObject toJson() const override; }; // Forces a linebreak @@ -493,6 +527,8 @@ class LinebreakElement : public MessageElement void addToContainer(MessageLayoutContainer &container, MessageElementFlags flags) override; + + QJsonObject toJson() const override; }; // Image element which will pick the quality of the image based on ui scale @@ -504,6 +540,8 @@ class ScalingImageElement : public MessageElement void addToContainer(MessageLayoutContainer &container, MessageElementFlags flags) override; + QJsonObject toJson() const override; + private: ImageSet images_; }; @@ -515,6 +553,13 @@ class ReplyCurveElement : public MessageElement void addToContainer(MessageLayoutContainer &container, MessageElementFlags flags) override; + + QJsonObject toJson() const override; }; } // namespace chatterino + +template <> +struct magic_enum::customize::enum_range { + static constexpr bool is_flags = true; // NOLINT(readability-identifier-*) +}; diff --git a/src/messages/MessageThread.cpp b/src/messages/MessageThread.cpp index e1227ab09e0..c59a3a26a03 100644 --- a/src/messages/MessageThread.cpp +++ b/src/messages/MessageThread.cpp @@ -1,12 +1,20 @@ #include "messages/MessageThread.hpp" +#include "common/Literals.hpp" #include "messages/Message.hpp" #include "util/DebugCount.hpp" +#include "util/QMagicEnum.hpp" + +#include +#include +#include #include namespace chatterino { +using namespace literals; + MessageThread::MessageThread(std::shared_ptr rootMessage) : rootMessageId_(rootMessage->id) , rootMessage_(std::move(rootMessage)) @@ -80,4 +88,29 @@ void MessageThread::markUnsubscribed() this->subscriptionUpdated(); } +QJsonObject MessageThread::toJson() const +{ + QJsonObject obj{ + {"rootId"_L1, this->rootMessageId_}, + {"subscription"_L1, qmagicenum::enumNameString(this->subscription_)}, + }; + + QJsonArray replies; + for (const auto &msg : this->replies_) + { + auto locked = msg.lock(); + if (locked) + { + replies.append(locked->id); + } + else + { + replies.append(QJsonValue::Null); + } + } + obj["replies"_L1] = replies; + + return obj; +} + } // namespace chatterino diff --git a/src/messages/MessageThread.hpp b/src/messages/MessageThread.hpp index 442db46a67d..56b088c0f60 100644 --- a/src/messages/MessageThread.hpp +++ b/src/messages/MessageThread.hpp @@ -6,6 +6,8 @@ #include #include +class QJsonObject; + namespace chatterino { struct Message; @@ -62,6 +64,8 @@ class MessageThread return replies_; } + QJsonObject toJson() const; + boost::signals2::signal subscriptionUpdated; private: diff --git a/src/providers/twitch/ChannelPointReward.cpp b/src/providers/twitch/ChannelPointReward.cpp index 8849b8b62a0..0d4ab132b95 100644 --- a/src/providers/twitch/ChannelPointReward.cpp +++ b/src/providers/twitch/ChannelPointReward.cpp @@ -1,5 +1,6 @@ #include "providers/twitch/ChannelPointReward.hpp" +#include "common/Literals.hpp" #include "messages/Image.hpp" #include @@ -15,6 +16,8 @@ QString twitchChannelPointRewardUrl(const QString &file) namespace chatterino { +using namespace literals; + ChannelPointReward::ChannelPointReward(const QJsonObject &redemption) { auto reward = redemption.value("reward").toObject(); @@ -113,4 +116,25 @@ ChannelPointReward::ChannelPointReward(const QJsonObject &redemption) } } +QJsonObject ChannelPointReward::toJson() const +{ + return { + {"id"_L1, this->id}, + {"channelId"_L1, this->channelId}, + {"title"_L1, this->title}, + {"cost"_L1, this->cost}, + {"image"_L1, this->image.toJson()}, + {"isUserInputRequired"_L1, this->isUserInputRequired}, + {"isBits"_L1, this->isBits}, + {"emoteId"_L1, this->emoteId}, + {"emoteName"_L1, this->emoteName}, + {"user"_L1, + {{ + {"id"_L1, this->user.id}, + {"login"_L1, this->user.login}, + {"displayName"_L1, this->user.displayName}, + }}}, + }; +} + } // namespace chatterino diff --git a/src/providers/twitch/ChannelPointReward.hpp b/src/providers/twitch/ChannelPointReward.hpp index 6fdd985b6e7..9015adfc83a 100644 --- a/src/providers/twitch/ChannelPointReward.hpp +++ b/src/providers/twitch/ChannelPointReward.hpp @@ -24,6 +24,8 @@ struct ChannelPointReward { QString login; QString displayName; } user; + + QJsonObject toJson() const; }; } // namespace chatterino diff --git a/src/widgets/helper/ChannelView.cpp b/src/widgets/helper/ChannelView.cpp index ab0e632260c..026af4c1061 100644 --- a/src/widgets/helper/ChannelView.cpp +++ b/src/widgets/helper/ChannelView.cpp @@ -256,40 +256,14 @@ void addHiddenContextMenuItems(QMenu *menu, }); } - const auto *message = layout->getMessage(); + auto message = layout->getMessagePtr(); - if (message != nullptr) + if (message) { - QJsonDocument jsonDocument; - - QJsonObject jsonObject; - - jsonObject["id"] = message->id; - jsonObject["searchText"] = message->searchText; - jsonObject["messageText"] = message->messageText; - jsonObject["flags"] = qmagicenum::enumFlagsName(message->flags.value()); - if (message->reward) - { - QJsonObject reward; - reward["id"] = message->reward->id; - reward["title"] = message->reward->title; - reward["cost"] = message->reward->cost; - reward["isUserInputRequired"] = - message->reward->isUserInputRequired; - jsonObject["reward"] = reward; - } - else - { - jsonObject["reward"] = QJsonValue(); - } - - jsonDocument.setObject(jsonObject); - - auto jsonString = - jsonDocument.toJson(QJsonDocument::JsonFormat::Indented); - - menu->addAction("Copy message &JSON", [jsonString] { - crossPlatformCopy(jsonString); + menu->addAction("Copy message &JSON", [message] { + auto jsonString = QJsonDocument{message->toJson()}.toJson( + QJsonDocument::Indented); + crossPlatformCopy(QString::fromUtf8(jsonString)); }); } } From d0bcf35fdc6e556b5701c9f4580b1d374877f5b0 Mon Sep 17 00:00:00 2001 From: nerix Date: Sat, 28 Sep 2024 14:49:26 +0200 Subject: [PATCH 4/4] refactor: move zero width replacement to a function (#5594) --- CHANGELOG.md | 1 + src/providers/recentmessages/Impl.cpp | 17 +------ src/providers/twitch/IrcMessageHandler.cpp | 18 ++----- src/providers/twitch/TwitchChannel.hpp | 18 ------- src/util/Helpers.cpp | 18 +++++++ src/util/Helpers.hpp | 7 +++ tests/src/Helpers.cpp | 56 ++++++++++++++++++++++ 7 files changed, 89 insertions(+), 46 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8c08c93b5f..116d9e20692 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -90,6 +90,7 @@ - Dev: The timer for `StreamerMode` is now destroyed on the correct thread. (#5571) - Dev: Cleanup some parts of the `magic_enum` adaptation for Qt. (#5587) - Dev: Refactored `static`s in headers to only be present once in the final app. (#5588) +- Dev: Refactored legacy Unicode zero-width-joiner replacement. (#5594) - Dev: The JSON output when copying a message (SHIFT + right-click) is now more extensive. (#5600) ## 2.5.1 diff --git a/src/providers/recentmessages/Impl.cpp b/src/providers/recentmessages/Impl.cpp index 6971b55473b..410a34aac75 100644 --- a/src/providers/recentmessages/Impl.cpp +++ b/src/providers/recentmessages/Impl.cpp @@ -1,22 +1,13 @@ #include "providers/recentmessages/Impl.hpp" #include "common/Env.hpp" -#include "common/QLogging.hpp" #include "messages/MessageBuilder.hpp" #include "providers/twitch/IrcMessageHandler.hpp" -#include "providers/twitch/TwitchChannel.hpp" -#include "util/FormatTime.hpp" +#include "util/Helpers.hpp" #include #include -namespace { - -// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -const auto &LOG = chatterinoRecentMessages; - -} // namespace - namespace chatterino::recentmessages::detail { // Parse the IRC messages returned in JSON form into Communi messages @@ -33,11 +24,7 @@ std::vector parseRecentMessages( for (const auto &jsonMessage : jsonMessages) { - auto content = jsonMessage.toString(); - - // For explanation of why this exists, see src/providers/twitch/TwitchChannel.hpp, - // where these constants are defined - content.replace(COMBINED_FIXER, ZERO_WIDTH_JOINER); + auto content = unescapeZeroWidthJoiner(jsonMessage.toString()); auto *message = Communi::IrcMessage::fromData(content.toUtf8(), nullptr); diff --git a/src/providers/twitch/IrcMessageHandler.cpp b/src/providers/twitch/IrcMessageHandler.cpp index 0e4571cfff2..279584c350b 100644 --- a/src/providers/twitch/IrcMessageHandler.cpp +++ b/src/providers/twitch/IrcMessageHandler.cpp @@ -702,15 +702,8 @@ void IrcMessageHandler::handlePrivMessage(Communi::IrcPrivateMessage *message, } } - // This is for compatibility with older Chatterino versions. Twitch didn't use - // to allow ZERO WIDTH JOINER unicode character, so Chatterino used ESCAPE_TAG - // instead. - // See https://github.com/Chatterino/chatterino2/issues/3384 and - // https://mm2pl.github.io/emoji_rfc.pdf for more details - this->addMessage( - message, chan, - message->content().replace(COMBINED_FIXER, ZERO_WIDTH_JOINER), - twitchServer, false, message->isAction()); + this->addMessage(message, chan, unescapeZeroWidthJoiner(message->content()), + twitchServer, false, message->isAction()); if (message->tags().contains(u"pinned-chat-paid-amount"_s)) { @@ -915,10 +908,9 @@ void IrcMessageHandler::handleWhisperMessage(Communi::IrcMessage *ircMessage) auto *c = getApp()->getTwitch()->getWhispersChannel().get(); - MessageBuilder builder( - c, ircMessage, args, - ircMessage->parameter(1).replace(COMBINED_FIXER, ZERO_WIDTH_JOINER), - false); + MessageBuilder builder(c, ircMessage, args, + unescapeZeroWidthJoiner(ircMessage->parameter(1)), + false); if (builder.isIgnored()) { diff --git a/src/providers/twitch/TwitchChannel.hpp b/src/providers/twitch/TwitchChannel.hpp index 37b6d363515..20f43079e14 100644 --- a/src/providers/twitch/TwitchChannel.hpp +++ b/src/providers/twitch/TwitchChannel.hpp @@ -27,24 +27,6 @@ namespace chatterino { -// This is for compatibility with older Chatterino versions. Twitch didn't use -// to allow ZERO WIDTH JOINER unicode character, so Chatterino used ESCAPE_TAG -// instead. -// See https://github.com/Chatterino/chatterino2/issues/3384 and -// https://mm2pl.github.io/emoji_rfc.pdf for more details -const QString ZERO_WIDTH_JOINER = QString(QChar(0x200D)); - -// Here be MSVC: Do NOT replace with "\U" literal, it will fail silently. -namespace { - const QChar ESCAPE_TAG_CHARS[2] = {QChar::highSurrogate(0xE0002), - QChar::lowSurrogate(0xE0002)}; -} -const QString ESCAPE_TAG = QString(ESCAPE_TAG_CHARS, 2); - -const static QRegularExpression COMBINED_FIXER( - QString("(? #include +namespace { + +const QString ZERO_WIDTH_JOINER = QStringLiteral("\u200D"); + +// Note: \U requires /utf-8 for MSVC +// See https://mm2pl.github.io/emoji_rfc.pdf +const QRegularExpression ESCAPE_TAG_REGEX( + QStringLiteral("(?> makeConditionedOptional(bool condition, return std::nullopt; } +/// @brief Unescapes zero width joiners (ZWJ; U+200D) from Twitch messages +/// +/// Older Chatterino versions escape ZWJ with an ESCAPE TAG (U+E0002), following +/// https://mm2pl.github.io/emoji_rfc.pdf. This function unescapes all tags with +/// a ZWJ. See also: https://github.com/Chatterino/chatterino2/issues/3384. +QString unescapeZeroWidthJoiner(QString escaped); + } // namespace chatterino diff --git a/tests/src/Helpers.cpp b/tests/src/Helpers.cpp index 4327bf51a1e..c2cf5694007 100644 --- a/tests/src/Helpers.cpp +++ b/tests/src/Helpers.cpp @@ -2,6 +2,8 @@ #include "Test.hpp" +#include + using namespace chatterino; using namespace helpers::detail; @@ -500,3 +502,57 @@ TEST(Helpers, parseDurationToSeconds) << c.output; } } + +TEST(Helpers, unescapeZeroWidthJoiner) +{ + struct TestCase { + QStringView input; + QStringView output; + }; + + std::vector tests{ + {u"foo bar", u"foo bar"}, + {u"", u""}, + {u"a", u"a"}, + {u"\U000E0002", u"\u200D"}, + {u"foo\U000E0002bar", u"foo\u200Dbar"}, + {u"foo \U000E0002 bar", u"foo \u200D bar"}, + {u"\U0001F468\U000E0002\U0001F33E", u"\U0001F468\u200D\U0001F33E"}, + // don't replace ZWJ + {u"\U0001F468\u200D\U0001F33E", u"\U0001F468\u200D\U0001F33E"}, + // only replace the first escape tag in sequences + { + u"\U0001F468\U000E0002\U000E0002\U0001F33E", + u"\U0001F468\u200D\U000E0002\U0001F33E", + }, + { + u"\U0001F468\U000E0002\U000E0002\U000E0002\U0001F33E", + u"\U0001F468\u200D\U000E0002\U000E0002\U0001F33E", + }, + }; + + // sanity check that the compiler supports unicode string literals + static_assert( + [] { + constexpr std::span zwj = u"\u200D"; + static_assert(zwj.size() == 2); + static_assert(zwj[0] == u'\x200D'); + static_assert(zwj[1] == u'\0'); + + constexpr std::span escapeTag = u"\U000E0002"; + static_assert(escapeTag.size() == 3); + static_assert(escapeTag[0] == u'\xDB40'); + static_assert(escapeTag[1] == u'\xDC02'); + static_assert(escapeTag[2] == u'\0'); + + return true; + }(), + "The compiler must support Unicode string literals"); + + for (const auto &c : tests) + { + const auto actual = unescapeZeroWidthJoiner(c.input.toString()); + + EXPECT_EQ(actual, c.output); + } +}