diff --git a/common/src/main/java/com/github/twitch4j/common/util/TwitchUtils.java b/common/src/main/java/com/github/twitch4j/common/util/TwitchUtils.java index ce405aed6..8367c8acb 100644 --- a/common/src/main/java/com/github/twitch4j/common/util/TwitchUtils.java +++ b/common/src/main/java/com/github/twitch4j/common/util/TwitchUtils.java @@ -13,6 +13,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.function.Function; public class TwitchUtils { @@ -69,105 +70,112 @@ public static Set getPermissionsFromTags(@NonNull Map getPermissionsFromTags(@Nullable CharSequence badgesTag, String userId, Collection botOwnerIds, @NonNull Map badges) { - Set permissionSet = EnumSet.of(CommandPermission.EVERYONE); + @ApiStatus.Internal + public static Set getPermissions(Iterable badges, Function badgeName, Function badgeValue) { + Set perms = EnumSet.of(CommandPermission.EVERYONE); + for (T badge : badges) { + String key = badgeName.apply(badge); + switch (key) { + case "premium": + case "turbo": + perms.add(CommandPermission.PRIME_TURBO); + break; + + case "partner": + case "ambassador": + perms.add(CommandPermission.PARTNER); + break; + + case "subscriber": + perms.add(CommandPermission.SUBSCRIBER); + break; + + case "founder": + // note: value contains tier + perms.add(CommandPermission.FOUNDER); + break; + + case "sub-gifter": + case "sub-gift-leader": + perms.add(CommandPermission.SUBGIFTER); + break; + + case "bits": + case "bits-leader": + case "anonymous-cheerer": + perms.add(CommandPermission.BITS_CHEERER); + break; + + case "hype-train": + String hypeBadge = badgeValue.apply(badge); + if ("1".equals(hypeBadge)) { + perms.add(CommandPermission.CURRENT_HYPE_TRAIN_CONDUCTOR); + } else if ("2".equals(hypeBadge)) { + perms.add(CommandPermission.FORMER_HYPE_TRAIN_CONDUCTOR); + } + break; + + case "predictions": + String predictionBadge = badgeValue.apply(badge); + if (predictionBadge != null && !predictionBadge.isEmpty()) { + char first = predictionBadge.charAt(0); + if (first == 'b') { + perms.add(CommandPermission.PREDICTIONS_BLUE); + } else if (first == 'p') { + perms.add(CommandPermission.PREDICTIONS_PINK); + } + } + break; + + case "no_audio": + perms.add(CommandPermission.NO_AUDIO); + break; + + case "no_video": + perms.add(CommandPermission.NO_VIDEO); + break; + + case "moments": + perms.add(CommandPermission.MOMENTS); + break; + + case "artist-badge": + perms.add(CommandPermission.ARTIST); + break; + + case "vip": + perms.add(CommandPermission.VIP); + break; + + case "staff": + case "admin": + perms.add(CommandPermission.TWITCHSTAFF); + break; + case "moderator": + perms.add(CommandPermission.MODERATOR); + break; + + case "broadcaster": + perms.add(CommandPermission.BROADCASTER); + perms.add(CommandPermission.MODERATOR); + break; + + default: + break; + } + } + return perms; + } + + private static Set getPermissionsFromTags(@Nullable CharSequence badgesTag, String userId, Collection botOwnerIds, @NonNull Map badges) { // Parse badges tag if (badgesTag != null) { badges.putAll(parseBadges(badgesTag.toString())); } // Check for Permissions - if (!badges.isEmpty()) { - // Broadcaster - if (badges.containsKey("broadcaster")) { - permissionSet.add(CommandPermission.BROADCASTER); - permissionSet.add(CommandPermission.MODERATOR); - } - // Twitch Prime - if (badges.containsKey("premium") || badges.containsKey("turbo")) { - permissionSet.add(CommandPermission.PRIME_TURBO); - } - // Moderator - if (badges.containsKey("moderator")) { - permissionSet.add(CommandPermission.MODERATOR); - } - // Partner - if (badges.containsKey("partner") || badges.containsKey("ambassador")) { - permissionSet.add(CommandPermission.PARTNER); - } - // VIP - if (badges.containsKey("vip")) { - permissionSet.add(CommandPermission.VIP); - } - // Turbo - if (badges.containsKey("turbo")) { - permissionSet.add(CommandPermission.PRIME_TURBO); - } - // Twitch Staff - if (badges.containsKey("staff") || badges.containsKey("admin")) { - permissionSet.add(CommandPermission.TWITCHSTAFF); - } - // Subscriber - if (badges.containsKey("subscriber")) { - permissionSet.add(CommandPermission.SUBSCRIBER); - } - // SubGifter - if (badges.containsKey("sub-gifter") || badges.containsKey("sub-gift-leader")) { - permissionSet.add(CommandPermission.SUBGIFTER); - } - // Cheerer - if (badges.containsKey("bits") || badges.containsKey("bits-leader") || badges.containsKey("anonymous-cheerer")) { - permissionSet.add(CommandPermission.BITS_CHEERER); - } - // Founder - if (badges.containsKey("founder")) { - permissionSet.add(CommandPermission.FOUNDER); - - // also contains info about the tier if needed - /* - if (badges.get("founder").equals("0")) { - // Tier 1 Founder - } else if (badges.get("founder").equals("1")) { - // Tier 2 Founder - } else if (badges.get("founder").equals("2")) { - // Tier 3 Founder - } - */ - } - // Hype Train Conductor - String hypeBadge = badges.get("hype-train"); - if ("1".equals(hypeBadge)) { - permissionSet.add(CommandPermission.CURRENT_HYPE_TRAIN_CONDUCTOR); - } else if ("2".equals(hypeBadge)) { - permissionSet.add(CommandPermission.FORMER_HYPE_TRAIN_CONDUCTOR); - } - // Predictions Participation - String predictionBadge = badges.get("predictions"); - if (StringUtils.isNotEmpty(predictionBadge)) { - char first = predictionBadge.charAt(0); - if (first == 'b') { - permissionSet.add(CommandPermission.PREDICTIONS_BLUE); - } else if (first == 'p') { - permissionSet.add(CommandPermission.PREDICTIONS_PINK); - } - } - // Accessibility - if (badges.containsKey("no_audio")) { - permissionSet.add(CommandPermission.NO_AUDIO); - } - if (badges.containsKey("no_video")) { - permissionSet.add(CommandPermission.NO_VIDEO); - } - // Present for Channel Moment - if (badges.containsKey("moments")) { - permissionSet.add(CommandPermission.MOMENTS); - } - // Channel Emote Artist - if (badges.containsKey("artist-badge")) { - permissionSet.add(CommandPermission.ARTIST); - } - } + Set permissionSet = getPermissions(badges.entrySet(), Map.Entry::getKey, Map.Entry::getValue); if (userId != null && botOwnerIds != null && botOwnerIds.contains(userId)) permissionSet.add(CommandPermission.OWNER); diff --git a/eventsub-common/src/main/java/com/github/twitch4j/eventsub/domain/chat/Badge.java b/eventsub-common/src/main/java/com/github/twitch4j/eventsub/domain/chat/Badge.java new file mode 100644 index 000000000..e6d0fd10f --- /dev/null +++ b/eventsub-common/src/main/java/com/github/twitch4j/eventsub/domain/chat/Badge.java @@ -0,0 +1,36 @@ +package com.github.twitch4j.eventsub.domain.chat; + +import lombok.AccessLevel; +import lombok.Data; +import lombok.Setter; + +@Data +@Setter(AccessLevel.PRIVATE) +public class Badge { + + /** + * An ID that identifies this set of chat badges. + *

+ * For example: "bits", "subscriber", "vip", "moderator", "broadcaster", "partner", "ambassador", "turbo", + * "hype-train", "no_audio", "no_video", "sub-gifter", "sub-gift-leader", "premium" (i.e., twitch prime) + */ + private String setId; + + /** + * An ID that identifies this version of the badge. + * The ID can be any value. + *

+ * For example, for Bits, the ID is the Bits tier level, + * but for World of Warcraft, it could be Alliance or Horde. + */ + private String id; + + /** + * Contains metadata related to the chat badges in the badges tag. + *

+ * Currently, this tag contains metadata only for subscriber badges, + * to indicate the number of months the user has been a subscriber. + */ + private String info; + +} diff --git a/eventsub-common/src/main/java/com/github/twitch4j/eventsub/events/ChannelChatNotificationEvent.java b/eventsub-common/src/main/java/com/github/twitch4j/eventsub/events/ChannelChatNotificationEvent.java index f47eb8b22..ad7cc1082 100644 --- a/eventsub-common/src/main/java/com/github/twitch4j/eventsub/events/ChannelChatNotificationEvent.java +++ b/eventsub-common/src/main/java/com/github/twitch4j/eventsub/events/ChannelChatNotificationEvent.java @@ -1,6 +1,8 @@ package com.github.twitch4j.eventsub.events; import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.twitch4j.common.enums.CommandPermission; +import com.github.twitch4j.common.util.TwitchUtils; import com.github.twitch4j.eventsub.domain.chat.*; import lombok.AccessLevel; import lombok.Data; @@ -11,6 +13,9 @@ import lombok.experimental.Accessors; import org.jetbrains.annotations.Nullable; +import java.util.List; +import java.util.Set; + @Data @Setter(AccessLevel.PRIVATE) @NoArgsConstructor @@ -19,17 +24,22 @@ public class ChannelChatNotificationEvent extends ChannelChatUserEvent { /** - * Whether or not the chatter is anonymous. + * Whether the chatter is anonymous. */ @Accessors(fluent = true) @JsonProperty("chatter_is_anonymous") private Boolean isChatterAnonymous; /** - * The color of the user’s name in the chat room. + * The color of the user's name in the chat room. */ private String color; + /** + * The user's visible badges in the chat room. + */ + private List badges; + /** * The message Twitch shows in the chat room for this notice. */ @@ -134,4 +144,12 @@ public class ChannelChatNotificationEvent extends ChannelChatUserEvent { @Nullable private BitsBadge bitsBadgeTier; + /** + * @return {@link #getBadges()} as {@link CommandPermission}, if {@link #getBadges()} is not null. + */ + @Nullable + public Set getPermissions() { + return badges != null ? TwitchUtils.getPermissions(badges, Badge::getSetId, Badge::getId) : null; + } + }