From dca4c77ff446cb45adc479f0a674c541168099a1 Mon Sep 17 00:00:00 2001 From: Broadstone Date: Sun, 21 May 2017 14:10:35 -0500 Subject: [PATCH 1/4] Fix parameter documentation for badges being loaded --- .../java/com/glitchcog/fontificator/config/ConfigEmoji.java | 4 ++-- .../com/glitchcog/fontificator/gui/emoji/EmojiWorker.java | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/glitchcog/fontificator/config/ConfigEmoji.java b/src/main/java/com/glitchcog/fontificator/config/ConfigEmoji.java index fec03b8..3771ef3 100644 --- a/src/main/java/com/glitchcog/fontificator/config/ConfigEmoji.java +++ b/src/main/java/com/glitchcog/fontificator/config/ConfigEmoji.java @@ -812,7 +812,7 @@ public boolean isFfzBadgesLoaded(String testChannel) /** * Set whether the Twitch badges have been loaded * - * @param twitchLoadedChannel + * @param twitchBadgesLoadedChannel * from which the Twitch emotes are loaded */ public void setTwitchBadgesLoaded(String twitchBadgesLoadedChannel) @@ -823,7 +823,7 @@ public void setTwitchBadgesLoaded(String twitchBadgesLoadedChannel) /** * Set whether the FrankerFaceZ badges have been loaded * - * @param ffzLoadedChannel + * @param ffzBadgesLoadedChannel * from which the FrankerFaceZ emotes are loaded */ public void setFfzBadgesLoaded(String ffzBadgesLoadedChannel) diff --git a/src/main/java/com/glitchcog/fontificator/gui/emoji/EmojiWorker.java b/src/main/java/com/glitchcog/fontificator/gui/emoji/EmojiWorker.java index ac7f5bb..f104b8d 100644 --- a/src/main/java/com/glitchcog/fontificator/gui/emoji/EmojiWorker.java +++ b/src/main/java/com/glitchcog/fontificator/gui/emoji/EmojiWorker.java @@ -152,9 +152,7 @@ public class EmojiWorker extends SwingWorker * * @param manager * @param progressPanel - * @param channel - * @param emojiType - * @param opType + * @param job * @param logBox * @param initialReport */ From 27054f3d04ba158ca7bbf17951e4a10b968303f5 Mon Sep 17 00:00:00 2001 From: Broadstone Date: Sun, 28 May 2017 13:48:55 -0500 Subject: [PATCH 2/4] Handle new Twitch Badges This patch handles new twitch badges from their newer API called Badge V1 Fix EmojiJob comparison to include channel_id Better errors out of new badge parsing --- .../fontificator/bot/ChatViewerBot.java | 11 +-- .../glitchcog/fontificator/bot/Message.java | 52 ++++++------ .../fontificator/bot/TwitchPrivmsg.java | 18 +++- .../glitchcog/fontificator/bot/UserType.java | 14 +++- .../fontificator/config/ConfigEmoji.java | 44 +++++++++- .../fontificator/emoji/EmojiJob.java | 26 +++++- .../fontificator/emoji/EmojiType.java | 22 ++++- .../fontificator/emoji/LazyLoadEmoji.java | 24 ++++-- .../fontificator/emoji/TypedEmojiMap.java | 84 ++++--------------- .../emoji/loader/EmojiApiLoader.java | 46 ++++++++-- .../emoji/loader/EmojiParser.java | 80 ++++++++++++++---- .../emoji/loader/twitch/TwitchBadgesNew.java | 77 +++++++++++++++++ .../gui/controls/panel/ControlPanelEmoji.java | 22 +++++ .../fontificator/gui/emoji/EmojiWorker.java | 5 +- 14 files changed, 376 insertions(+), 149 deletions(-) create mode 100644 src/main/java/com/glitchcog/fontificator/emoji/loader/twitch/TwitchBadgesNew.java diff --git a/src/main/java/com/glitchcog/fontificator/bot/ChatViewerBot.java b/src/main/java/com/glitchcog/fontificator/bot/ChatViewerBot.java index e0bfb47..5d8e7e9 100644 --- a/src/main/java/com/glitchcog/fontificator/bot/ChatViewerBot.java +++ b/src/main/java/com/glitchcog/fontificator/bot/ChatViewerBot.java @@ -462,16 +462,13 @@ private TwitchPrivmsg parseRawTwitchMessage(String rawMessage) log("Error parsing subscriber value \"" + turboStr + "\" in Twitch header"); } } - privmsg.setPrime(paramMap.get("badges") != null && paramMap.get("badges").contains("premium")); - String userTypeStr = paramMap.get("user-type"); - if (displayName != null && !displayName.trim().isEmpty() && displayName.equalsIgnoreCase(this.controlPanel.getChannelNoHash())) + if( paramMap.get("badges") != null ) { - // Set the broadcaster badge based on the display name matching the channel connected to, since Twitch - // doesn't put this usertype into its IRC tags. - privmsg.setUserType(UserType.BROADCASTER); + privmsg.addBadges( paramMap.get("badges").split(",") ); } - else if (userTypeStr != null && !userTypeStr.trim().isEmpty()) + String userTypeStr = paramMap.get("user-type"); + if (userTypeStr != null && !userTypeStr.trim().isEmpty()) { // If the string value is something weird, the enum will just return NONE privmsg.setUserType(UserType.getByKey(userTypeStr)); diff --git a/src/main/java/com/glitchcog/fontificator/bot/Message.java b/src/main/java/com/glitchcog/fontificator/bot/Message.java index f2d4687..2cdbcae 100644 --- a/src/main/java/com/glitchcog/fontificator/bot/Message.java +++ b/src/main/java/com/glitchcog/fontificator/bot/Message.java @@ -409,22 +409,20 @@ private SpriteCharacterKey[] parseIntoText(EmojiManager emojiManager, ConfigMess final boolean userIsModerator = privmsg.getUserType() == UserType.MOD; // Bank to pull Twitch badges from - TypedEmojiMap twitchBadgeBank = emojiManager.getEmojiByType(EmojiType.TWITCH_BADGE); + TypedEmojiMap twitchLocalBadgeBank = emojiManager.getEmojiByType(EmojiType.TWITCH_BADGE); + TypedEmojiMap twitchBadgeBank = emojiManager.getEmojiByType(EmojiType.TWITCH_BADGE_GLOBAL); + // Bank to pull FrankerFaceZ badges from TypedEmojiMap ffzBadgeBank = emojiManager.getEmojiByType(EmojiType.FRANKERFACEZ_BADGE); // Get the badge for the type of user, if the usertype has a badge (but not if it's an ffzBot) if (privmsg.getUserType() != null && privmsg.getUserType() != UserType.NONE) { - LazyLoadEmoji testBadge; + //LazyLoadEmoji testBadge; // FFZ badges are enabled, the user is a moderator, and the custom FFZ moderator badge exists if (emojiConfig.isFfzBadgesEnabled() && userIsModerator && ffzBadgeBank.getEmoji(UserType.MOD.getKey()) != null) { - badges.put(UserType.MOD.getKey(), ffzBadgeBank.getEmoji(UserType.MOD.getKey())); - } - else if (emojiConfig.isTwitchBadgesEnabled() && (testBadge = twitchBadgeBank.getEmoji(privmsg.getUserType().getKey())) != null) - { - badges.put(privmsg.getUserType().getKey(), testBadge); + badges.put(UserType.MOD.getBadge(), ffzBadgeBank.getEmoji(UserType.MOD.getKey())); } } @@ -443,7 +441,7 @@ else if (emojiConfig.isTwitchBadgesEnabled() && (testBadge = twitchBadgeBank.get if (ffzBadge.isReplacement() && badges.containsKey(ffzBadge.getReplaces())) { badges.put(ffzBadge.getReplaces(), ffzBadge); - if (userIsModerator && true) + if (userIsModerator) { replacementBadge = ffzBadge; } @@ -456,27 +454,27 @@ else if (emojiConfig.isTwitchBadgesEnabled() && (testBadge = twitchBadgeBank.get } } - // Optional subscriber badge - if (emojiConfig.isTwitchBadgesEnabled()) - { - final String subStr = "subscriber"; - if (privmsg.isSubscriber() && twitchBadgeBank.getEmoji(subStr) != null) - { - badges.put(subStr, twitchBadgeBank.getEmoji(subStr)); - } - } + if (emojiConfig.isTwitchBadgesEnabled()) { + for(String badgestr : privmsg.getBadges()) { + LazyLoadEmoji globalbadge = twitchBadgeBank.getEmoji(badgestr); + LazyLoadEmoji localbadge = twitchLocalBadgeBank.getEmoji(badgestr); + LazyLoadEmoji target_badge = null; - // Optional turbo badge - final String turboStr = "turbo"; - if (emojiConfig.isTwitchBadgesEnabled() && privmsg.isTurbo() && twitchBadgeBank.getEmoji(turboStr) != null) - { - badges.put(turboStr, twitchBadgeBank.getEmoji(turboStr)); - } + if( localbadge != null ) { + target_badge = localbadge; + } else if( globalbadge != null ) { + target_badge = globalbadge; + } - final String primeStr = "prime"; - if (emojiConfig.isTwitchBadgesEnabled() && privmsg.isPrime() && twitchBadgeBank.getEmoji(primeStr) != null) - { - badges.put(primeStr, twitchBadgeBank.getEmoji(primeStr)); + if( target_badge != null ) { + // Handle the special case of an FFZ badge replacing a twitch badge. + // Note that the twitch badge's key might be moderator/0 or moderator/1, but the FFZ badge + // with identifier "moderator" overrides them + if( replacementBadge == null || !target_badge.getPrimaryidentifier().equals(replacementBadge.getPrimaryidentifier()) ) { + badges.put(badgestr, target_badge); + } + } + } } // Add each badges map item onto the sprite character key list diff --git a/src/main/java/com/glitchcog/fontificator/bot/TwitchPrivmsg.java b/src/main/java/com/glitchcog/fontificator/bot/TwitchPrivmsg.java index dddc7c8..59fb35c 100644 --- a/src/main/java/com/glitchcog/fontificator/bot/TwitchPrivmsg.java +++ b/src/main/java/com/glitchcog/fontificator/bot/TwitchPrivmsg.java @@ -1,7 +1,9 @@ package com.glitchcog.fontificator.bot; import java.awt.Color; +import java.util.Arrays; import java.util.HashMap; +import java.util.ArrayList; import java.util.Map; /** @@ -33,6 +35,11 @@ public class TwitchPrivmsg */ private Map emotes; + /** + * The list of badges + */ + private ArrayList badges; + /** * Whether the user has a Twitch subscription to the channel to which the message is posted */ @@ -85,6 +92,7 @@ public void setDefaults() postCount = 0; color = null; emotes = new HashMap(); + badges = new ArrayList(); turbo = false; prime = false; subscriber = false; @@ -171,13 +179,21 @@ public Map getEmotes() /** * Add to the list of emotes * - * @param emoteSets + * @param emoteSet */ public void addEmote(EmoteAndIndices emoteSet) { emotes.put(emoteSet.getBegin(), emoteSet); } + public ArrayList getBadges() { + return badges; + } + + public void addBadges(String newbadges[]) { + this.badges.addAll( Arrays.asList(newbadges) ); + } + /** * Get whether the user has a Twitch subscription to the channel to which the message is posted * diff --git a/src/main/java/com/glitchcog/fontificator/bot/UserType.java b/src/main/java/com/glitchcog/fontificator/bot/UserType.java index 1383867..5399b08 100644 --- a/src/main/java/com/glitchcog/fontificator/bot/UserType.java +++ b/src/main/java/com/glitchcog/fontificator/bot/UserType.java @@ -2,13 +2,20 @@ public enum UserType { - NONE(""), MOD("mod"), GLOBAL_MOD("global_mod"), ADMIN("admin"), STAFF("staff"), BROADCASTER("broadcaster"); + NONE(""), MOD("mod", "moderator"), GLOBAL_MOD("global_mod"), ADMIN("admin"), STAFF("staff"); private final String key; + private final String badge; private UserType(String key) + { + this(key, key); + } + + private UserType(String key, String badge) { this.key = key; + this.badge = badge; } public String getKey() @@ -16,6 +23,11 @@ public String getKey() return key; } + public String getBadge() + { + return badge; + } + public static UserType getByKey(String key) { for (UserType type : values()) diff --git a/src/main/java/com/glitchcog/fontificator/config/ConfigEmoji.java b/src/main/java/com/glitchcog/fontificator/config/ConfigEmoji.java index 3771ef3..cb34a6a 100644 --- a/src/main/java/com/glitchcog/fontificator/config/ConfigEmoji.java +++ b/src/main/java/com/glitchcog/fontificator/config/ConfigEmoji.java @@ -108,6 +108,11 @@ public class ConfigEmoji extends Config */ private String twitchBadgesLoadedChannel; + /** + * The loaded Twitch badges channel, or null if none is loaded + */ + private String twitchBadgesLoadedGlobal; + /** * The loaded FrankerFaceZ badges channel, or null if none is loaded */ @@ -404,6 +409,8 @@ public boolean isTypeEnabledAndLoaded(EmojiType type) // return ControlPanelEmoji.TWITCH_EMOTE_VERSION.equals(type) && twitchEnabled != null && twitchEnabled && twitchLoaded != null && twitchLoaded; case TWITCH_BADGE: return twitchBadgesEnabled != null && twitchBadgesEnabled && twitchBadgesLoadedChannel != null; + case TWITCH_BADGE_GLOBAL: + return twitchBadgesEnabled != null && twitchBadgesEnabled && twitchBadgesLoadedGlobal != null; default: // If it doesn't have a coded EmojiType, then we don't know it return false; @@ -506,6 +513,7 @@ public int hashCode() result = prime * result + ((twitchEnabled == null) ? 0 : twitchEnabled.hashCode()); result = prime * result + ((twitchLoaded == null) ? 0 : twitchLoaded.hashCode()); result = prime * result + ((twitchBadgesLoadedChannel == null) ? 0 : twitchBadgesLoadedChannel.hashCode()); + result = prime * result + ((twitchBadgesLoadedGlobal == null) ? 0 : twitchBadgesLoadedGlobal.hashCode()); return result; } @@ -712,10 +720,21 @@ else if (!twitchLoaded.equals(other.twitchLoaded)) return false; } } + if (twitchBadgesLoadedGlobal == null) + { + if (other.twitchBadgesLoadedGlobal != null) + { + return false; + } + } else if (!twitchBadgesLoadedChannel.equals(other.twitchBadgesLoadedChannel)) { return false; } + else if (!twitchBadgesLoadedGlobal.equals(other.twitchBadgesLoadedGlobal)) + { + return false; + } return true; } @@ -740,6 +759,7 @@ public void deepCopy(ConfigEmoji copy) this.ffzEnabled = copy.ffzEnabled; this.twitchLoaded = copy.twitchLoaded; this.twitchBadgesLoadedChannel = copy.twitchBadgesLoadedChannel; + this.twitchBadgesLoadedChannel = copy.twitchBadgesLoadedGlobal; this.ffzLoadedChannel = copy.ffzLoadedChannel; this.ffzGlobalLoaded = copy.ffzGlobalLoaded; this.bttvEnabled = copy.bttvEnabled; @@ -810,16 +830,27 @@ public boolean isFfzBadgesLoaded(String testChannel) } /** - * Set whether the Twitch badges have been loaded + * Set whether the Twitch channel badges have been loaded * * @param twitchBadgesLoadedChannel - * from which the Twitch emotes are loaded + * from which the Twitch channel badges are loaded */ - public void setTwitchBadgesLoaded(String twitchBadgesLoadedChannel) + public void setTwitchBadgesLoadedChannel(String twitchBadgesLoadedChannel) { this.twitchBadgesLoadedChannel = twitchBadgesLoadedChannel; } + /** + * Set whether the Twitch global badges have been loaded + * + * @param twitchBadgesLoadedGlobal + * from which the Twitch global badges are loaded + */ + public void setTwitchBadgesLoadedGlobal(String twitchBadgesLoadedGlobal) + { + this.twitchBadgesLoadedGlobal = twitchBadgesLoadedGlobal; + } + /** * Set whether the FrankerFaceZ badges have been loaded * @@ -960,6 +991,10 @@ public void setWorkCompleted(EmojiJob job) { this.twitchBadgesLoadedChannel = job.getChannel(); } + else if (EmojiType.TWITCH_BADGE_GLOBAL.equals(emojiType)) + { + this.twitchBadgesLoadedGlobal = job.getChannel(); + } else if (EmojiType.FRANKERFACEZ_BADGE.equals(emojiType)) { this.ffzBadgesLoadedChannel = job.getChannel(); @@ -1022,6 +1057,7 @@ public void resetWorkCompleted() this.twitchLoaded = false; this.twitchCached = false; this.twitchBadgesLoadedChannel = null; + this.twitchBadgesLoadedGlobal = null; this.ffzBadgesLoadedChannel = null; this.ffzLoadedChannel = null; this.ffzGlobalLoaded = false; @@ -1039,7 +1075,7 @@ public void resetWorkCompleted() public boolean isAnyWorkDone() { // @formatter:off - return twitchBadgesLoadedChannel != null || isTwitchLoaded() || isTwitchCached() || + return twitchBadgesLoadedChannel != null || twitchBadgesLoadedGlobal != null || isTwitchLoaded() || isTwitchCached() || ffzBadgesLoadedChannel != null || ffzLoadedChannel != null || isFfzGlobalLoaded() || isFfzCached() || bttvLoadedChannel != null || isBttvGlobalLoaded() || isBttvCached(); // @formatter:on diff --git a/src/main/java/com/glitchcog/fontificator/emoji/EmojiJob.java b/src/main/java/com/glitchcog/fontificator/emoji/EmojiJob.java index 24107bf..ee179d5 100644 --- a/src/main/java/com/glitchcog/fontificator/emoji/EmojiJob.java +++ b/src/main/java/com/glitchcog/fontificator/emoji/EmojiJob.java @@ -18,17 +18,26 @@ public class EmojiJob */ private final String channel; + /** + * Can be null if no channel ID is required + */ + private final String channel_id; + public EmojiJob(String oauth, EmojiType type, EmojiOperation op) { - this(oauth, type, op, null); + this(oauth, type, op, null, null); } - public EmojiJob(String oauth, EmojiType type, EmojiOperation op, String channel) + { + this(oauth, type, op, channel, null); + } + public EmojiJob(String oauth, EmojiType type, EmojiOperation op, String channel, String channel_id) { this.type = type; this.op = op; this.oauth = oauth; this.channel = channel; + this.channel_id = channel_id; } public String getOauth() @@ -51,12 +60,18 @@ public String getChannel() return channel; } + public String getChannelId() + { + return channel_id; + } + @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((channel == null) ? 0 : channel.hashCode()); + result = prime * result + ((channel_id == null) ? 0 : channel_id.hashCode()); result = prime * result + ((op == null) ? 0 : op.hashCode()); result = prime * result + ((type == null) ? 0 : type.hashCode()); return result; @@ -79,6 +94,13 @@ public boolean equals(Object obj) } else if (!channel.equals(other.channel)) return false; + if (channel_id == null) + { + if (other.channel_id != null) + return false; + } + else if (!channel_id.equals(other.channel_id)) + return false; if (op != other.op) return false; if (type != other.type) diff --git a/src/main/java/com/glitchcog/fontificator/emoji/EmojiType.java b/src/main/java/com/glitchcog/fontificator/emoji/EmojiType.java index bbd267c..df755dd 100644 --- a/src/main/java/com/glitchcog/fontificator/emoji/EmojiType.java +++ b/src/main/java/com/glitchcog/fontificator/emoji/EmojiType.java @@ -8,20 +8,21 @@ public enum EmojiType { // @formatter:off - TWITCH_V1("Twitch Emotes from Chat V1", EmojiGroup.TWITCH, false, false), + TWITCH_V1("Twitch Emotes from Chat V1", EmojiGroup.TWITCH, false, false, true), /** * Twitch V2 API retired on February 14, 2017 */ @Deprecated - TWITCH_V2("Twitch Emotes V2", EmojiGroup.TWITCH, false, false), + TWITCH_V2("Twitch Emotes V2", EmojiGroup.TWITCH, false, false, true), /** * Twitch V3 API retired on February 14, 2017 */ @Deprecated - TWITCH_V3("Twitch Emotes V3", EmojiGroup.TWITCH, false, true), + TWITCH_V3("Twitch Emotes V3", EmojiGroup.TWITCH, false, true, true), - TWITCH_BADGE("Twitch Badge", EmojiGroup.TWITCH, true, false), + TWITCH_BADGE("Twitch Badge", EmojiGroup.TWITCH, true, false), + TWITCH_BADGE_GLOBAL("Twitch Global Badge", EmojiGroup.TWITCH, true, false), FRANKERFACEZ_CHANNEL("FrankerFaceZ Emotes", EmojiGroup.FFZ, false, false), FRANKERFACEZ_GLOBAL("FrankerFaceZ Global Emotes", EmojiGroup.FFZ, false, false), FRANKERFACEZ_BADGE("FrankerFaceZ Badge", EmojiGroup.FFZ, true, false), @@ -38,6 +39,8 @@ public enum EmojiType private final String description; + private final boolean canRegEx; + /** * These are the types of emoji words to check against for manual messages. */ @@ -51,11 +54,17 @@ public enum EmojiType public static EmojiType[] THIRD_PARTY_EMOJI_TYPES = new EmojiType[] { EmojiType.FRANKERFACEZ_CHANNEL, EmojiType.FRANKERFACEZ_GLOBAL, EmojiType.BETTER_TTV_CHANNEL, EmojiType.BETTER_TTV_GLOBAL }; private EmojiType(String description, EmojiGroup group, boolean badge, boolean loadSetMap) + { + this(description, group, badge, loadSetMap, false); + } + + private EmojiType(String description, EmojiGroup group, boolean badge, boolean loadSetMap, boolean canRegEx) { this.group = group; this.description = description; this.badge = badge; this.loadSetMap = loadSetMap; + this.canRegEx = canRegEx; } public boolean isTwitchEmote() @@ -87,4 +96,9 @@ public String getDescription() { return description; } + + public boolean canRegEx() + { + return canRegEx; + } } \ No newline at end of file diff --git a/src/main/java/com/glitchcog/fontificator/emoji/LazyLoadEmoji.java b/src/main/java/com/glitchcog/fontificator/emoji/LazyLoadEmoji.java index 8a894c5..1966517 100644 --- a/src/main/java/com/glitchcog/fontificator/emoji/LazyLoadEmoji.java +++ b/src/main/java/com/glitchcog/fontificator/emoji/LazyLoadEmoji.java @@ -61,6 +61,8 @@ public class LazyLoadEmoji private boolean firstLoadFailureReported; + private String primaryidentifier; + /** * Used for FFZ badges only */ @@ -70,23 +72,23 @@ public LazyLoadEmoji(String id, String url, EmojiType type) throws MalformedURLE { this(id, null, url, null, type); } - public LazyLoadEmoji(String id, String replaces, String url, Color bgColor, EmojiType type) throws MalformedURLException { - this(id, replaces, url, DEFAULT_EMOJI_SIZE, DEFAULT_EMOJI_SIZE, bgColor, type); + this(id, replaces, url, DEFAULT_EMOJI_SIZE, DEFAULT_EMOJI_SIZE, bgColor, type, null); } - public LazyLoadEmoji(String identifier, String url, int width, int height, EmojiType type) throws MalformedURLException { - this(identifier, url, width, height, null, type); + this(identifier, url, width, height, null, type, null); } - - public LazyLoadEmoji(String identifier, String url, int width, int height, Color bgColor, EmojiType type) throws MalformedURLException + public LazyLoadEmoji(String identifier, String url, int width, int height, EmojiType type, String primaryidentifier) throws MalformedURLException { - this(identifier, null, url, width, height, bgColor, type); + this(identifier, url, width, height, null, type, primaryidentifier); } - - public LazyLoadEmoji(String identifier, String replaces, String url, int width, int height, Color bgColor, EmojiType type) throws MalformedURLException + public LazyLoadEmoji(String identifier, String url, int width, int height, Color bgColor, EmojiType type, String primaryidentifier) throws MalformedURLException + { + this(identifier, null, url, width, height, bgColor, type, primaryidentifier); + } + public LazyLoadEmoji(String identifier, String replaces, String url, int width, int height, Color bgColor, EmojiType type, String primaryidentifier) throws MalformedURLException { this.identifier = identifier; this.replaces = replaces; @@ -96,6 +98,7 @@ public LazyLoadEmoji(String identifier, String replaces, String url, int width, this.height = height; this.firstLoadFailureReported = false; this.bgColor = bgColor; + this.primaryidentifier = primaryidentifier == null ? identifier : primaryidentifier; } public void cacheImage() @@ -265,4 +268,7 @@ public String getReplaces() return replaces; } + public String getPrimaryidentifier() { + return primaryidentifier; + } } diff --git a/src/main/java/com/glitchcog/fontificator/emoji/TypedEmojiMap.java b/src/main/java/com/glitchcog/fontificator/emoji/TypedEmojiMap.java index d95673c..c2f87a4 100644 --- a/src/main/java/com/glitchcog/fontificator/emoji/TypedEmojiMap.java +++ b/src/main/java/com/glitchcog/fontificator/emoji/TypedEmojiMap.java @@ -24,15 +24,12 @@ public class TypedEmojiMap { private final EmojiType type; - private Map normalMap; - - private Map regexMap; + private Map map; public TypedEmojiMap(EmojiType type) { this.type = type; - normalMap = new HashMap(); - regexMap = new HashMap(); + map = new HashMap(); } /** @@ -72,91 +69,40 @@ public LazyLoadEmoji getEmoji(String testKey, ConfigEmoji config) return null; } - LazyLoadEmoji emoji = normalMap.get(testKey); - - if (emoji == null) + LazyLoadEmoji emoji = null; + if (type.canRegEx()) { - for (String regex : regexMap.keySet()) + for (String regex : map.keySet()) { if (testKey.matches(regex)) { - emoji = regexMap.get(regex); + emoji = map.get(regex); break; } } } + else + { + emoji = map.get(testKey); + } return emoji; } public LazyLoadEmoji put(String key, LazyLoadEmoji value) { - if (isRegularExpression(key)) - { - key = fixRegularExpression(key); - return regexMap.put(key, value); - } - else - { - return normalMap.put(key, value); - } + return map.put(key, value); } public Collection keySet() { - Set keys = new HashSet(normalMap.keySet().size() + regexMap.keySet().size()); - keys.addAll(normalMap.keySet()); - keys.addAll(regexMap.keySet()); + Set keys = new HashSet(map.keySet().size()); + keys.addAll(map.keySet()); return keys; } - /** - * Determine whether the specified key is a regular expression or just a word, based on whether it is comprised - * entirely of alpha numeric characters indicating it's just a word - * - * @param key - * @return is a regular expression - */ - private static boolean isRegularExpression(String key) + public Map getMap() { - return !key.matches("^[a-zA-Z0-9_]*$"); + return map; } - - /** - * Remove extraneous escape characters and decode xml entities. This may need to be tinkered with. - * - * @param regex - * @return fixed regex - */ - private String fixRegularExpression(String regex) - { - // Remove redundant slashes - regex = regex.replaceAll("\\\\\\\\", "\\\\"); - // Un-escape semicolons - regex = regex.replaceAll("\\\\;", ";"); - regex = regex.replaceAll("\\\\:", ":"); - regex = regex.replaceAll("\\\\&", "&"); - // Greater than and less than xml entities - regex = regex.replaceAll("<", "<"); - regex = regex.replaceAll(">", ">"); - // Needed for BTTV emotes like "(puke)" - if (type.isBetterTtvEmote()) - { - regex = regex.replaceAll("\\(", "\\\\("); - regex = regex.replaceAll("\\)", "\\\\)"); - } - - return regex; - } - - public Map getNormalMap() - { - return normalMap; - } - - public Map getRegexMap() - { - return regexMap; - } - } diff --git a/src/main/java/com/glitchcog/fontificator/emoji/loader/EmojiApiLoader.java b/src/main/java/com/glitchcog/fontificator/emoji/loader/EmojiApiLoader.java index 09bb4fa..11e771e 100644 --- a/src/main/java/com/glitchcog/fontificator/emoji/loader/EmojiApiLoader.java +++ b/src/main/java/com/glitchcog/fontificator/emoji/loader/EmojiApiLoader.java @@ -23,6 +23,8 @@ public class EmojiApiLoader private static final String CHANNEL_NAME_REPLACE = "%CHANNEL_NAME%"; + private static final String ID_REPLACE = "%ID_NUMBER%"; + public static final String OAUTH_REPLACE = "%OAUTH%"; public static final String EMOTE_ID_REPLACE = "%EMOTE_ID%"; @@ -52,6 +54,16 @@ public class EmojiApiLoader */ private static final String TWITCH_URL_BADGES = "https://api.twitch.tv/kraken/chat/" + CHANNEL_NAME_REPLACE + "/badges" + OAUTH_REPLACE; + /** + * The base URL for getting the channel specific Twitch badges from the new API + */ + private static final String TWITCH_URL_BADGES2 = "https://badges.twitch.tv/v1/badges/channels/"+ ID_REPLACE + "/display" + OAUTH_REPLACE; + + /** + * The base URL for getting the channel specific Twitch badges from the new API + */ + private static final String TWITCH_URL_BADGES_GLOBAL = "https://badges.twitch.tv/v1/badges/global/display" + OAUTH_REPLACE; + /** * The URL for getting the global FrankerFaceZ emotes from the API */ @@ -146,15 +158,20 @@ public void prepLoad(String url) this.url = url; } - public void prepLoad(EmojiType emojiType, String channel, String oauth) + public void prepLoad(EmojiType emojiType, String channel, String oauth, String id) { // FrankerFaceZ API requires the channel name to be all lowercase, Twitch V2 is case agnostic channel = channel == null ? null : channel.toLowerCase(); - String chanUrl = getUrl(emojiType, channel, oauth); + String chanUrl = getUrl(emojiType, channel, oauth, id); prepLoad(chanUrl); } - private String getUrl(EmojiType emojiType, String channel, String oauth) + public void prepLoad(EmojiType emojiType, String channel, String oauth) + { + this.prepLoad(emojiType, channel, oauth, null); + } + + private String getUrl(EmojiType emojiType, String channel, String oauth, String id) { final String oauthLabel = "oauth:"; if (oauth.contains(oauthLabel)) @@ -179,12 +196,31 @@ private String getUrl(EmojiType emojiType, String channel, String oauth) // case TWITCH_V3: // return TWITCH_URL_V3; case TWITCH_BADGE: - return TWITCH_URL_BADGES.replaceAll(CHANNEL_NAME_REPLACE, channel).replaceAll(OAUTH_REPLACE, oauth); + if (id != null) + { + return TWITCH_URL_BADGES2.replaceAll(ID_REPLACE, id).replaceAll(OAUTH_REPLACE, oauth); + } + else + { + return TWITCH_URL_BADGES.replaceAll(CHANNEL_NAME_REPLACE, channel).replaceAll(OAUTH_REPLACE, oauth); + } + case TWITCH_BADGE_GLOBAL: + if (id != null) + { + return TWITCH_URL_BADGES_GLOBAL.replaceAll(ID_REPLACE, id).replaceAll(OAUTH_REPLACE, oauth); + } + else + { + return null; + } default: return null; } } - + private String getUrl(EmojiType emojiType, String channel, String oauth) + { + return this.getUrl(emojiType, channel, oauth, null); + } public boolean initLoad() throws IOException, MalformedURLException, FileNotFoundException { if (this.url != null) diff --git a/src/main/java/com/glitchcog/fontificator/emoji/loader/EmojiParser.java b/src/main/java/com/glitchcog/fontificator/emoji/loader/EmojiParser.java index b25bc4f..c71d947 100644 --- a/src/main/java/com/glitchcog/fontificator/emoji/loader/EmojiParser.java +++ b/src/main/java/com/glitchcog/fontificator/emoji/loader/EmojiParser.java @@ -8,6 +8,7 @@ import java.util.Map; import java.util.Map.Entry; +import com.google.gson.*; import org.apache.log4j.Logger; import com.glitchcog.fontificator.bot.UserType; @@ -23,15 +24,11 @@ import com.glitchcog.fontificator.emoji.loader.frankerfacez.FfzEmote; import com.glitchcog.fontificator.emoji.loader.frankerfacez.Room; import com.glitchcog.fontificator.emoji.loader.twitch.TwitchBadges; +import com.glitchcog.fontificator.emoji.loader.twitch.TwitchBadgesNew; import com.glitchcog.fontificator.emoji.loader.twitch.TwitchEmoteV2; import com.glitchcog.fontificator.emoji.loader.twitch.TwitchEmoteV3; import com.glitchcog.fontificator.emoji.loader.twitch.TwitchIdSetLink; import com.glitchcog.fontificator.gui.controls.panel.LogBox; -import com.google.gson.Gson; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; /** @@ -63,7 +60,7 @@ public EmojiParser(LogBox logBox) * the type of the emoji * @param jsonData * the JSON data of the emoji to parse - * @param mapData + * @param jsonMapData * can be null for non-Twitch emoji * @throws IOException */ @@ -86,6 +83,7 @@ public void putJsonEmojiIntoManager(EmojiManager manager, EmojiType type, String // parseTwitchEmoteJsonV3(manager, jsonData, jsonMapData); // break; case TWITCH_BADGE: + case TWITCH_BADGE_GLOBAL: parseTwitchBadges(emojiMap, jsonData); break; case BETTER_TTV_CHANNEL: @@ -224,24 +222,70 @@ private void parseTwitchBadges(TypedEmojiMap badgeMap, String jsonData) throws I { JsonElement jsonElement = new JsonParser().parse(jsonData); + Boolean isNewStyle = jsonElement.getAsJsonObject().has("badge_sets"); + Gson gson = new Gson(); + int badgeCount = 0; - Type emoteType = new TypeToken>() + if (!isNewStyle) { - }.getType(); - Map jsonMap = gson.fromJson(jsonElement, emoteType); - - int badgeCount = 0; - for (Entry badge : jsonMap.entrySet()) + Type emoteType = new TypeToken>() { + }.getType(); + Map jsonMap = gson.fromJson(jsonElement, emoteType); + + for (Entry badge : jsonMap.entrySet()) { + if (badge.getValue() != null && badge.getValue().getImage() != null) { + badgeCount++; + LazyLoadEmoji llBadge = new LazyLoadEmoji(badge.getKey(), badge.getValue().getImage(), TWITCH_BADGE_PIXEL_SIZE, TWITCH_BADGE_PIXEL_SIZE, EmojiType.TWITCH_BADGE); + badgeMap.put(badge.getKey(), llBadge); + } + } + } + else { - if (badge.getValue() != null && badge.getValue().getImage() != null) + JsonElement badge_sets = jsonElement.getAsJsonObject().get("badge_sets"); + JsonObject badge_sets_object = badge_sets.isJsonObject() ? badge_sets.getAsJsonObject() : new JsonObject(); + + for (Map.Entry entry : badge_sets_object.entrySet()) { - badgeCount++; - LazyLoadEmoji llBadge = new LazyLoadEmoji(badge.getKey(), badge.getValue().getImage(), TWITCH_BADGE_PIXEL_SIZE, TWITCH_BADGE_PIXEL_SIZE, EmojiType.TWITCH_BADGE); - badgeMap.put(badge.getKey(), llBadge); + String unversioned_key = entry.getKey(); + JsonElement badge_set_element = entry.getValue(); + if (!badge_set_element.isJsonObject() || !badge_set_element.getAsJsonObject().has("versions")) + { + // TODO: Error message? + continue; + } + JsonElement versions_element = badge_set_element.getAsJsonObject().get("versions"); + if (!versions_element.isJsonObject()) + { + // TODO: Error message? + continue; + } + Type emoteType = new TypeToken>() { + }.getType(); + Map jsonMap; + try { + jsonMap = gson.fromJson(versions_element, emoteType); + } + catch( JsonSyntaxException e ) { + // TODO: Error message? + continue; + } + + for (Entry sub_badge : jsonMap.entrySet()) { + // The unversioned key is something like "subscriber". + // The sub_badge is something like "1" or "6". + // In the specific case of subscriber badges, "subscriber/1" is a 1 month badge and + // "subscriber/6" is a 6 month badge + if (sub_badge.getValue() != null && sub_badge.getValue().getImage_url_1x() != null) { + String badge_key = unversioned_key + "/" + sub_badge.getKey(); + LazyLoadEmoji llBadge = new LazyLoadEmoji(badge_key, sub_badge.getValue().getImage_url_1x(), TWITCH_BADGE_PIXEL_SIZE, TWITCH_BADGE_PIXEL_SIZE, EmojiType.TWITCH_BADGE, unversioned_key); + badgeMap.put(badge_key, llBadge); + badgeCount++; + } + } } } - logBox.log(badgeCount + " Twitch badge" + (badgeCount == 1 ? "" : "s") + " loaded"); } @@ -258,7 +302,7 @@ private void parseFrankerFaceZBadges(EmojiManager manager, String jsonData) thro for (Badge b : badgesAndUsers.getBadges()) { - manager.getEmojiByType(EmojiType.FRANKERFACEZ_BADGE).put("" + b.getId(), new LazyLoadEmoji(b.getName(), "moderator".equals(b.getReplaces()) ? UserType.MOD.getKey() : b.getReplaces(), "http:" + b.getImage(), b.getColorParsed(), EmojiType.FRANKERFACEZ_BADGE)); + manager.getEmojiByType(EmojiType.FRANKERFACEZ_BADGE).put("" + b.getId(), new LazyLoadEmoji(b.getName(), b.getReplaces(), "http:" + b.getImage(), b.getColorParsed(), EmojiType.FRANKERFACEZ_BADGE)); } manager.setFfzBadgeUsers(badgesAndUsers.getUsers()); diff --git a/src/main/java/com/glitchcog/fontificator/emoji/loader/twitch/TwitchBadgesNew.java b/src/main/java/com/glitchcog/fontificator/emoji/loader/twitch/TwitchBadgesNew.java new file mode 100644 index 0000000..3b3439b --- /dev/null +++ b/src/main/java/com/glitchcog/fontificator/emoji/loader/twitch/TwitchBadgesNew.java @@ -0,0 +1,77 @@ + + package com.glitchcog.fontificator.emoji.loader.twitch; + + +public class TwitchBadgesNew { + + private String image_url_1x; + private String image_url_2x; + private String image_url_4x; + private String description; + private String title; + + /** + * No args constructor for use in serialization + * + */ + public TwitchBadgesNew() { + } + + /** + * + * @param image_url_2x + * @param title + * @param description + * @param image_url_4x + * @param image_url_1x + */ + public TwitchBadgesNew(String image_url_1x, String image_url_2x, String image_url_4x, String description, String title) { + super(); + this.image_url_1x = image_url_1x; + this.image_url_2x = image_url_2x; + this.image_url_4x = image_url_4x; + this.description = description; + this.title = title; + } + + public String getImage_url_1x() { + return image_url_1x; + } + + public void setImage_url_1x(String image_url_1x) { + this.image_url_1x = image_url_1x; + } + + public String getImage_url_2x() { + return image_url_2x; + } + + public void setImage_url_2x(String image_url_2x) { + this.image_url_2x = image_url_2x; + } + + public String getImage_url_4x() { + return image_url_4x; + } + + public void setImage_url_4x(String image_url_4x) { + this.image_url_4x = image_url_4x; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + +} diff --git a/src/main/java/com/glitchcog/fontificator/gui/controls/panel/ControlPanelEmoji.java b/src/main/java/com/glitchcog/fontificator/gui/controls/panel/ControlPanelEmoji.java index c330ec8..9254e92 100644 --- a/src/main/java/com/glitchcog/fontificator/gui/controls/panel/ControlPanelEmoji.java +++ b/src/main/java/com/glitchcog/fontificator/gui/controls/panel/ControlPanelEmoji.java @@ -389,6 +389,20 @@ public void actionPerformed(ActionEvent e) } } + if (clickTwitchBadges && !config.isTwitchBadgesLoaded(getConnectChannel())) + { + EmojiJob job = new EmojiJob(oauth, EmojiType.TWITCH_BADGE_GLOBAL, EmojiOperation.LOAD, getConnectChannel()); + // No check for enable all here, because badges are independent of the emoji enableAll toggle + if (enableTwitchBadges.isSelected()) + { + jobsToRun.add(job); + } + else + { + jobsToCancel.add(job); + } + } + if (clickFfzBadges && !config.isFfzBadgesLoaded(getConnectChannel())) { EmojiJob job = new EmojiJob(oauth, EmojiType.FRANKERFACEZ_BADGE, EmojiOperation.LOAD, getConnectChannel()); @@ -723,6 +737,14 @@ public Set collectJobs() jobs.clear(); return jobs; } + jobs.add(new EmojiJob(oauth, EmojiType.TWITCH_BADGE_GLOBAL, EmojiOperation.LOAD, channel, null)); /* TODO: Need ID somehow */ + if (channel == null) + { + /* TODO: Error message not good enough */ + ChatWindow.popup.handleProblem("Please specify a channel ID on the Connection tab to load badges"); + jobs.clear(); + return jobs; + } } if (workFfzBadges) diff --git a/src/main/java/com/glitchcog/fontificator/gui/emoji/EmojiWorker.java b/src/main/java/com/glitchcog/fontificator/gui/emoji/EmojiWorker.java index f104b8d..d795376 100644 --- a/src/main/java/com/glitchcog/fontificator/gui/emoji/EmojiWorker.java +++ b/src/main/java/com/glitchcog/fontificator/gui/emoji/EmojiWorker.java @@ -187,6 +187,7 @@ protected Integer doInBackground() throws Exception final EmojiType emojiType = job.getType(); final String channel = job.getChannel(); final String oauth = job.getOauth(); + final String channel_id = job.getChannelId(); if (EmojiOperation.LOAD == opType) { @@ -199,7 +200,7 @@ protected Integer doInBackground() throws Exception } // The proper load for the emoji - loader.prepLoad(emojiType, channel, oauth); + loader.prepLoad(emojiType, channel, oauth, channel_id); String data = runLoader(emojiType); if (data != null) { @@ -218,7 +219,7 @@ protected Integer doInBackground() throws Exception if (emojiType == EmojiType.TWITCH_BADGE) { TypedEmojiMap tbMap = manager.getEmojiByType(EmojiType.TWITCH_BADGE); - tbMap.put("prime", new LazyLoadEmoji("prime", TWITCH_BADGE_PRIME, EmojiType.TWITCH_BADGE)); + //tbMap.put("prime", new LazyLoadEmoji("prime", TWITCH_BADGE_PRIME, EmojiType.TWITCH_BADGE)); } Thread.sleep(1L); From 95375105493bd6d06baa6fe6d2fd8fa67131548d Mon Sep 17 00:00:00 2001 From: Broadstone Date: Tue, 30 May 2017 18:42:46 -0500 Subject: [PATCH 3/4] Fix the FFZ badge replacement 1. Put FFZ badges in a list 2. Upon attempting to insert twitch badges, consume FFZ badges instead 3. Assign FFZ badges to SpriteCharacterKeys 4. Assign other badges (Twitch badges) to SpriteCharacterKeys Assumes FFZ badges are to be displayed before Twitch badges and that the FFZ moderator replacement badge is of a lower priority than the FFZ bot badge. Note that the moderator badge is now "moderator" not "mod" in most cases. --- .../glitchcog/fontificator/bot/Message.java | 47 +++++++++---------- .../emoji/loader/EmojiParser.java | 2 +- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/glitchcog/fontificator/bot/Message.java b/src/main/java/com/glitchcog/fontificator/bot/Message.java index 2cdbcae..e80d775 100644 --- a/src/main/java/com/glitchcog/fontificator/bot/Message.java +++ b/src/main/java/com/glitchcog/fontificator/bot/Message.java @@ -414,22 +414,17 @@ private SpriteCharacterKey[] parseIntoText(EmojiManager emojiManager, ConfigMess // Bank to pull FrankerFaceZ badges from TypedEmojiMap ffzBadgeBank = emojiManager.getEmojiByType(EmojiType.FRANKERFACEZ_BADGE); + Map ffzBadgeMap = new LinkedHashMap(); - // Get the badge for the type of user, if the usertype has a badge (but not if it's an ffzBot) - if (privmsg.getUserType() != null && privmsg.getUserType() != UserType.NONE) + if (emojiConfig.isFfzBadgesEnabled()) { - //LazyLoadEmoji testBadge; - // FFZ badges are enabled, the user is a moderator, and the custom FFZ moderator badge exists - if (emojiConfig.isFfzBadgesEnabled() && userIsModerator && ffzBadgeBank.getEmoji(UserType.MOD.getKey()) != null) + // Channel-specific mod badge override + if( userIsModerator && ffzBadgeBank.getEmoji(UserType.MOD.getBadge()) != null) { - badges.put(UserType.MOD.getBadge(), ffzBadgeBank.getEmoji(UserType.MOD.getKey())); + ffzBadgeMap.put(UserType.MOD.getBadge(), ffzBadgeBank.getEmoji(UserType.MOD.getBadge())); } - } - LazyLoadEmoji replacementBadge = null; - - if (emojiConfig.isFfzBadgesEnabled()) - { + // User badges Map> ffzBadgeUsers = emojiManager.getFfzBadgeUsers(); for (Integer ffzBadgeType : ffzBadgeUsers.keySet()) { @@ -437,19 +432,7 @@ private SpriteCharacterKey[] parseIntoText(EmojiManager emojiManager, ConfigMess Set users = ffzBadgeUsers.get(ffzBadgeType); if (users.contains(username.toLowerCase())) { - LazyLoadEmoji ffzBadge = ffzBadgeBank.getEmoji(ffzBadgeType); - if (ffzBadge.isReplacement() && badges.containsKey(ffzBadge.getReplaces())) - { - badges.put(ffzBadge.getReplaces(), ffzBadge); - if (userIsModerator) - { - replacementBadge = ffzBadge; - } - } - else - { - badges.put(ffzBadgeKey, ffzBadge); - } + ffzBadgeMap.put(ffzBadgeKey, ffzBadgeBank.getEmoji(ffzBadgeType)); } } } @@ -470,7 +453,15 @@ private SpriteCharacterKey[] parseIntoText(EmojiManager emojiManager, ConfigMess // Handle the special case of an FFZ badge replacing a twitch badge. // Note that the twitch badge's key might be moderator/0 or moderator/1, but the FFZ badge // with identifier "moderator" overrides them - if( replacementBadge == null || !target_badge.getPrimaryidentifier().equals(replacementBadge.getPrimaryidentifier()) ) { + LazyLoadEmoji ffzReplacement = ffzBadgeMap.remove(target_badge.getPrimaryidentifier()); + + if( ffzReplacement != null ) { + // The FFZ badge is there and overrides + badges.put(target_badge.getPrimaryidentifier(), ffzReplacement); + } + else + { + // Other twitch badges are just inserted in the list badges.put(badgestr, target_badge); } } @@ -478,10 +469,14 @@ private SpriteCharacterKey[] parseIntoText(EmojiManager emojiManager, ConfigMess } // Add each badges map item onto the sprite character key list + for (LazyLoadEmoji lle : ffzBadgeMap.values()) + { + keyList.add(new SpriteCharacterKey(lle, true)); + } for (LazyLoadEmoji lle : badges.values()) { SpriteCharacterKey sck = new SpriteCharacterKey(lle, true); - if (userIsModerator && lle == replacementBadge) + if (userIsModerator && lle.isReplacement()) { sck.setEmojiBgColorOverride(ConfigEmoji.MOD_BADGE_COLOR); } diff --git a/src/main/java/com/glitchcog/fontificator/emoji/loader/EmojiParser.java b/src/main/java/com/glitchcog/fontificator/emoji/loader/EmojiParser.java index c71d947..6e5c4cd 100644 --- a/src/main/java/com/glitchcog/fontificator/emoji/loader/EmojiParser.java +++ b/src/main/java/com/glitchcog/fontificator/emoji/loader/EmojiParser.java @@ -328,7 +328,7 @@ public void parseFrankerFaceZModBadge(EmojiManager manager, String jsonData) thr final boolean customFfzModBadgeExists = room != null && room.getModerator_badge() != null; if (customFfzModBadgeExists) { - LazyLoadEmoji modLle = new LazyLoadEmoji(UserType.MOD.getKey(), UserType.MOD.getKey(), "https:" + room.getModerator_badge(), ConfigEmoji.MOD_BADGE_COLOR, EmojiType.FRANKERFACEZ_BADGE); + LazyLoadEmoji modLle = new LazyLoadEmoji(UserType.MOD.getBadge(), UserType.MOD.getBadge(), "https:" + room.getModerator_badge(), ConfigEmoji.MOD_BADGE_COLOR, EmojiType.FRANKERFACEZ_BADGE); manager.getEmojiByType(EmojiType.FRANKERFACEZ_BADGE).put(UserType.MOD.getKey(), modLle); logBox.log("Loaded the custom FrankerFaceZ moderator badge"); } From 9612d66e4ab04cea462743382aaa407851c9524e Mon Sep 17 00:00:00 2001 From: Broadstone Date: Mon, 12 Jun 2017 18:35:11 -0500 Subject: [PATCH 4/4] Fix typo pointed out by growf --- .../java/com/glitchcog/fontificator/config/ConfigEmoji.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/glitchcog/fontificator/config/ConfigEmoji.java b/src/main/java/com/glitchcog/fontificator/config/ConfigEmoji.java index cb34a6a..b8cfe9d 100644 --- a/src/main/java/com/glitchcog/fontificator/config/ConfigEmoji.java +++ b/src/main/java/com/glitchcog/fontificator/config/ConfigEmoji.java @@ -759,7 +759,7 @@ public void deepCopy(ConfigEmoji copy) this.ffzEnabled = copy.ffzEnabled; this.twitchLoaded = copy.twitchLoaded; this.twitchBadgesLoadedChannel = copy.twitchBadgesLoadedChannel; - this.twitchBadgesLoadedChannel = copy.twitchBadgesLoadedGlobal; + this.twitchBadgesLoadedGlobal = copy.twitchBadgesLoadedGlobal; this.ffzLoadedChannel = copy.ffzLoadedChannel; this.ffzGlobalLoaded = copy.ffzGlobalLoaded; this.bttvEnabled = copy.bttvEnabled;