From a0491ff8144d112be8d3d58358417ccec8593aea Mon Sep 17 00:00:00 2001
From: tduva
Date: Mon, 11 Apr 2016 10:48:36 +0200
Subject: [PATCH] Whispers to Main Chat, some other stuff - Hide userlist for
Whisper Tabs - Change Whisper display mode to per user by default - Change
Whispers to Main Chat - Fix $[whisper] Tab opening inadvertently - Replace
WhisperConnection by WhisperManager, using the main connection - Reorganize
Settings definition - Increase max reconnection attempts to 40 - Clean up,
remove some unused TwitchConnection code - Update help
---
src/chatty/SettingsManager.java | 344 ++++++++++-------
src/chatty/TwitchClient.java | 38 +-
src/chatty/TwitchConnection.java | 165 ++------
src/chatty/WhisperConnection.java | 357 ------------------
src/chatty/WhisperManager.java | 188 +++++++++
src/chatty/gui/Channels.java | 2 +-
src/chatty/gui/MainGui.java | 19 +-
.../gui/components/help/help-whisper.html | 99 +----
.../components/settings/AdvancedSettings.java | 196 +---------
.../components/settings/SettingsDialog.java | 1 -
src/chatty/util/settings/Settings.java | 2 +-
11 files changed, 459 insertions(+), 952 deletions(-)
delete mode 100644 src/chatty/WhisperConnection.java
create mode 100644 src/chatty/WhisperManager.java
diff --git a/src/chatty/SettingsManager.java b/src/chatty/SettingsManager.java
index eb7fbd1a6..4de007251 100644
--- a/src/chatty/SettingsManager.java
+++ b/src/chatty/SettingsManager.java
@@ -70,12 +70,29 @@ void defineSettings() {
settings.addFile(historyFile);
settings.addFile(statusPresetsFile);
- // Global
- settings.addBoolean("ontop", false);
+ //========
+ // General
+ //========
+
settings.addBoolean("dontSaveSettings",false);
settings.addBoolean("debugCommands", false, false);
- settings.addString("laf","default");
+ settings.addBoolean("debugLogIrc", false);
+ settings.addBoolean("debugLogIrcFile", false);
+ settings.addBoolean("autoRequestMods", false);
+ // Backup
+ settings.addLong("backupDelay", 1);
+ settings.addLong("backupCount", 5);
+
+ // Version/News
+ settings.addLong("versionLastChecked", 0);
+ settings.addString("updateAvailable", "");
+ settings.addBoolean("checkNewVersion", true);
+ settings.addBoolean("newsAutoRequest", true);
+ settings.addLong("newsLastRead", 0);
+ settings.addString("currentVersion", "");
+
+ // Hotkeys
addDefaultHotkeyAppWide("0.7.3", "dialog.streams", "ctrl L");
addDefaultHotkey("0.7.3", "dialog.toggleEmotes", "ctrl E");
addDefaultHotkey("0.7.3", "dialog.search", "ctrl F");
@@ -92,29 +109,25 @@ void defineSettings() {
settings.addList("hotkeys", getDefaultHotkeySettingValue(), Setting.LIST);
settings.addBoolean("globalHotkeysEnabled", true);
- // Connecting/Login data
+
+ //===========
+ // Connecting
+ //===========
+
settings.addString("serverDefault", "irc.chat.twitch.tv");
settings.addString("portDefault", "6697,6667,443,80");
+
// Seperate settings for commandline/temp so others can be saved
settings.addString("server", "", false);
settings.addString("port", "", false);
- settings.addList("securedPorts", new LinkedHashSet<>(Arrays.asList((long)6697, (long)443)), Setting.LONG);
- settings.addList("securedPortsWhisper", new LinkedHashSet<>(Arrays.asList()), Setting.LONG);
- settings.addBoolean("userlistConnection", true);
- settings.addList("userlistConnectionBlacklist", new ArrayList(), Setting.STRING);
+ settings.addList("securedPorts", new LinkedHashSet<>(Arrays.asList((long)6697, (long)443)), Setting.LONG);
settings.addBoolean("membershipEnabled", true);
- settings.addBoolean("botBadgeEnabled", true);
- settings.addBoolean("botNamesBTTV", true);
- settings.addBoolean("botNamesFFZ", true);
- settings.addList("botNames", new ArrayList<>(Arrays.asList("nightbot", "moobot", "kabukibot", "slowton2", "xanbot")), Setting.STRING);
-
- settings.addBoolean("debugLogIrcFile", false);
-
- settings.addBoolean("tc3", false);
-
+ // Auto-join channels
settings.addString("channel", "");
+
+ // Login Data
settings.addString("username", "");
settings.setFile("username", loginFile);
settings.addString("password", "", false);
@@ -126,7 +139,8 @@ void defineSettings() {
settings.setFile("token", loginFile);
// Don't save setting, login with password isn't possible anymore
settings.addBoolean("usePassword", false, false);
- // Scopes
+
+ // Token
settings.addBoolean("token_editor", false);
settings.setFile("token_editor", loginFile);
settings.addBoolean("token_commercials", false);
@@ -137,31 +151,17 @@ void defineSettings() {
settings.setFile("token_subs", loginFile);
settings.addBoolean("token_chat", false);
settings.setFile("token_chat", loginFile);
+
+ //=================
+ // Appearance / GUI
+ //=================
- // Chat messages
- // Not really used anymore, kept for compatability
- settings.addBoolean("ignoreJoinsParts",false);
- settings.addBoolean("showJoinsParts", false);
- settings.addBoolean("showModMessages", false);
- settings.addBoolean("debugLogIrc", false);
- settings.addBoolean("showBanMessages", false);
- settings.addBoolean("combineBanMessages", true);
- settings.addBoolean("deleteMessages", false);
- settings.addString("deletedMessagesMode", "keepShortened");
- settings.addLong("deletedMessagesMaxLength", 50);
- settings.addBoolean("clearChatOnChannelCleared", false);
- settings.addLong("bufferSize", 500);
- settings.addBoolean("twitchnotifyAsInfo", true);
- settings.addBoolean("printStreamStatus", true);
- settings.addLong("filterCombiningCharacters", Helper.FILTER_COMBINING_CHARACTERS_LENIENT);
+ settings.addBoolean("ontop", false);
+ settings.addString("laf","default");
- // Chat appearance
- settings.addBoolean("emoticonsEnabled",true);
- settings.addLong("emoteMaxHeight", 0);
- settings.addLong("emoteScale", 100);
- settings.addLong("emoteScaleDialog", 100);
- settings.addBoolean("closeEmoteDialogOnDoubleClick", false);
- settings.addBoolean("usericonsEnabled",true);
+ settings.addLong("dialogFontSize", -1);
+
+ // Chat Appearance
settings.addString("font","Consolas");
settings.addLong("fontSize",14);
settings.addString("inputFont", "Dialog 14");
@@ -172,24 +172,32 @@ void defineSettings() {
settings.addBoolean("ircv3CapitalizedNames", true);
settings.addBoolean("correctlyCapitalizedNames", false);
settings.addMap("customNames", new HashMap<>(), Setting.STRING);
+ settings.addBoolean("actionColored", false);
+
+ // Badges/Emotes
+ settings.addBoolean("emoticonsEnabled",true);
+ settings.addLong("emoteMaxHeight", 0);
+ settings.addLong("emoteScale", 100);
+ settings.addLong("emoteScaleDialog", 100);
+ settings.addBoolean("closeEmoteDialogOnDoubleClick", false);
settings.addBoolean("ffz", true);
settings.addBoolean("ffzModIcon", true);
settings.addBoolean("bttvEmotes", true);
settings.addBoolean("showAnimatedEmotes", false);
settings.addList("ignoredEmotes", new ArrayList(), Setting.STRING);
settings.addList("favoriteEmotes", new ArrayList(), Setting.LIST);
- settings.addString("tabOrder", "normal");
- settings.addBoolean("tabsMwheelScrolling", false);
- settings.addBoolean("tabsMwheelScrollingAnywhere", false);
- settings.addBoolean("actionColored", false);
- settings.addBoolean("customUsercolors", false);
- settings.addList("usercolors", new LinkedList(), Setting.STRING);
+ settings.addBoolean("usericonsEnabled",true);
settings.addList("customUsericons", new ArrayList(), Setting.LIST);
settings.addBoolean("customUsericonsEnabled", false);
- settings.addLong("dialogFontSize", -1);
+ settings.addBoolean("botBadgeEnabled", true);
+ settings.addBoolean("botNamesBTTV", true);
+ settings.addBoolean("botNamesFFZ", true);
+ settings.addList("botNames", new LinkedHashSet<>(Arrays.asList(
+ "nightbot", "moobot", "kabukibot", "slowton2", "xanbot")),
+ Setting.STRING);
settings.addBoolean("imageCache", true);
@@ -205,19 +213,53 @@ void defineSettings() {
settings.addString("searchResultColor2", "#FFFF80");
settings.addBoolean("colorCorrection", true);
+ // Usercolors
+ settings.addBoolean("customUsercolors", false);
+ settings.addList("usercolors", new LinkedList(), Setting.STRING);
+
+ //====================
+ // Other Customization
+ //====================
- // History and Favorites
+ // Addressbook
+ settings.addString("abCommandsChannel", "");
+ settings.addString("abCommands", "add,set,remove");
+ settings.addString("abUniqueCats", "");
+ settings.addBoolean("abAutoImport", false);
+ settings.addString("abSubMonthsChan", "");
+ settings.addList("abSubMonths", new TreeSet(), Setting.LONG);
+ settings.addString("subNotificationPattern", "([^\\s]+) (?:just )?subscribed(?: for (\\d+) months in a row)?!");
+
+ // Custom Commands
+ settings.addList("commands", new ArrayList(), Setting.STRING);
+ // Default entries, will only be set if setting is not loaded from file
+ settings.setAdd("commands", "/slap /me slaps $$1- around a bit with a large trout");
+ settings.setAdd("commands", "/permit !permit $$1");
+
+ // Menu Entries
+ settings.addString("timeoutButtons","/Ban[B], /Unban[U], 5s[1], 2m[2], 10m[3], 30m[4]");
+ settings.addString("userContextMenu", "");
+ settings.addString("channelContextMenu", "");
+
+ // History / Favorites
settings.addMap("channelHistory",new TreeMap(), Setting.LONG);
settings.setFile("channelHistory", historyFile);
settings.addList("channelFavorites", new ArrayList(), Setting.STRING);
settings.setFile("channelFavorites", historyFile);
- settings.addList("gamesFavorites",new ArrayList(), Setting.STRING);
- settings.setFile("gamesFavorites", historyFile);
settings.addLong("channelHistoryKeepDays", 30);
settings.addBoolean("saveChannelHistory", true);
settings.addBoolean("historyClear", true);
settings.addLong("favoritesSorting", 20);
+ //=======================
+ // Channel Admin Features
+ //=======================
+
+ // Game Presets
+ settings.addList("gamesFavorites",new ArrayList(), Setting.STRING);
+ settings.setFile("gamesFavorites", historyFile);
+
+ // Stream Status Presets
settings.addList("statusPresets", new ArrayList(), Setting.LIST);
settings.setFile("statusPresets", statusPresetsFile);
@@ -230,28 +272,17 @@ void defineSettings() {
settings.addString("commercialHotkey","");
settings.addBoolean("adDelay", false);
settings.addLong("adDelayLength", 300);
-
- // Other
- settings.addBoolean("channelsWarning", true);
- settings.addBoolean("autoScroll", true);
- settings.addLong("autoScrollTimeout", 30);
- settings.addBoolean("pauseChatOnMouseMove", false);
- settings.addBoolean("pauseChatOnMouseMoveCtrlRequired", false);
- settings.addString("commandOnCtrlClick", "");
- settings.addLong("versionLastChecked", 0);
- settings.addString("updateAvailable", "");
- settings.addBoolean("checkNewVersion", true);
- settings.addString("liveStreamsSorting", "recent");
- settings.addLong("historyRange", 0);
- settings.addString("spamProtection", "18/30");
- settings.addString("currentVersion", "");
+ //=======
+ // Window
+ //=======
+ // Open URLs
settings.addBoolean("urlPrompt", true);
settings.addBoolean("urlCommandEnabled", false);
settings.addString("urlCommand", "");
- // Window
+ // Main Window
settings.addBoolean("attachedWindows", false);
settings.addBoolean("maximized", false);
settings.addBoolean("nod3d", true);
@@ -259,44 +290,43 @@ void defineSettings() {
settings.addBoolean("bufferStrategy1", false);
settings.addBoolean("mainResizable", true);
+ // Tray
settings.addBoolean("closeToTray", false);
settings.addBoolean("minimizeToTray", false);
+ // Window State
settings.addMap("windows", new HashMap<>(), Setting.STRING);
settings.addLong("restoreMode", WindowStateManager.RESTORE_ON_START);
+ // Popouts
settings.addBoolean("popoutSaveAttributes", true);
settings.addBoolean("popoutCloseLastChannel", true);
settings.addList("popoutAttributes", new ArrayList(), Setting.STRING);
+ // Titlebar
settings.addBoolean("simpleTitle", false);
settings.addBoolean("titleShowUptime", true);
settings.addBoolean("titleLongerUptime", true);
settings.addBoolean("titleShowViewerCount", true);
settings.addBoolean("titleShowChannelState", true);
+
+ // Tabs
+ settings.addString("tabOrder", "normal");
+ settings.addBoolean("tabsMwheelScrolling", false);
+ settings.addBoolean("tabsMwheelScrollingAnywhere", false);
+
+ // Chat Window
settings.addBoolean("chatScrollbarAlways", false);
settings.addLong("userlistWidth", 120);
settings.addLong("userlistMinWidth", 0);
+ settings.addLong("bufferSize", 500);
- // Highlight
- settings.addList("highlight",new ArrayList(), Setting.STRING);
- settings.addBoolean("highlightEnabled", true);
- settings.addBoolean("highlightUsername", true);
- settings.addBoolean("highlightOwnText", false);
- settings.addBoolean("highlightNextMessages", false);
- settings.addBoolean("highlightIgnored", false);
- settings.addList("noHighlightUsers", new ArrayList(), Setting.STRING);
-
- // Ignore
- settings.addList("ignore", new ArrayList(), Setting.STRING);
- settings.addBoolean("ignoreEnabled", false);
- settings.addBoolean("ignoreOwnText", false);
- settings.addLong("ignoreMode", 1);
- settings.addBoolean("ignoreShowNotDialog", false);
- settings.addList("ignoredUsers", new ArrayList(), Setting.STRING);
- settings.addList("ignoredUsersWhisper", new ArrayList(), Setting.STRING);
-
+ settings.addString("liveStreamsSorting", "recent");
+ settings.addLong("historyRange", 0);
+
+ //=======
// Sounds
+ //=======
settings.addBoolean("sounds", false);
settings.addString("highlightSound", "off");
settings.addString("highlightSoundFile", "ding.wav");
@@ -320,7 +350,9 @@ void defineSettings() {
settings.addLong("followerSoundVolume",100);
settings.addLong("followerSoundDelay", 10);
+ //==============
// Notifications
+ //==============
settings.addString("highlightNotification", "either");
settings.addString("statusNotification", "either");
settings.addBoolean("ignoreOfflineNotifications", false);
@@ -340,11 +372,66 @@ void defineSettings() {
settings.addList("notificationProperties", new ArrayList<>(), Setting.LIST);
- settings.addLong("v0.5", 0);
settings.addBoolean("tips", true);
settings.addLong("lastTip", 0);
- // Logging
+
+ //=====================
+ // Basic Chat Behaviour
+ //=====================
+
+ settings.addString("spamProtection", "18/30");
+
+ settings.addBoolean("autoScroll", true);
+ settings.addLong("autoScrollTimeout", 30);
+ settings.addBoolean("pauseChatOnMouseMove", false);
+ settings.addBoolean("pauseChatOnMouseMoveCtrlRequired", false);
+ settings.addString("commandOnCtrlClick", "");
+
+ // Not really used anymore, kept for compatability
+ settings.addBoolean("ignoreJoinsParts",false);
+
+ // Message Types
+ settings.addBoolean("showJoinsParts", false);
+ settings.addBoolean("showModMessages", false);
+ settings.addBoolean("twitchnotifyAsInfo", true);
+ settings.addBoolean("printStreamStatus", true);
+
+ // Timeouts/Bans
+ settings.addBoolean("showBanMessages", false);
+ settings.addBoolean("combineBanMessages", true);
+ settings.addBoolean("deleteMessages", false);
+ settings.addString("deletedMessagesMode", "keepShortened");
+ settings.addLong("deletedMessagesMaxLength", 50);
+ settings.addBoolean("clearChatOnChannelCleared", false);
+
+ // Message filtering
+ settings.addLong("filterCombiningCharacters", Helper.FILTER_COMBINING_CHARACTERS_LENIENT);
+
+
+ //==============
+ // Chat Features
+ //==============
+
+ // Highlight
+ settings.addList("highlight",new ArrayList(), Setting.STRING);
+ settings.addBoolean("highlightEnabled", true);
+ settings.addBoolean("highlightUsername", true);
+ settings.addBoolean("highlightOwnText", false);
+ settings.addBoolean("highlightNextMessages", false);
+ settings.addBoolean("highlightIgnored", false);
+ settings.addList("noHighlightUsers", new ArrayList(), Setting.STRING);
+
+ // Ignore
+ settings.addList("ignore", new ArrayList(), Setting.STRING);
+ settings.addBoolean("ignoreEnabled", false);
+ settings.addBoolean("ignoreOwnText", false);
+ settings.addLong("ignoreMode", 1);
+ settings.addBoolean("ignoreShowNotDialog", false);
+ settings.addList("ignoredUsers", new ArrayList(), Setting.STRING);
+ settings.addList("ignoredUsersWhisper", new ArrayList(), Setting.STRING);
+
+ // Chat Logging
settings.addString("logMode", "always");
settings.addBoolean("logMod", true);
settings.addBoolean("logJoinPart", false);
@@ -357,74 +444,57 @@ void defineSettings() {
settings.addList("logBlacklist",new ArrayList(), Setting.STRING);
settings.addString("logPath", "");
settings.addString("logTimestamp", "[HH:mm:ss]");
-
- // Addressbook
- settings.addString("abCommandsChannel", "");
- settings.addString("abCommands", "add,set,remove");
- settings.addString("abUniqueCats", "");
- settings.addBoolean("abAutoImport", false);
- settings.addString("abSubMonthsChan", "");
- settings.addList("abSubMonths", new TreeSet(), Setting.LONG);
- settings.addString("subNotificationPattern", "([^\\s]+) (?:just )?subscribed(?: for (\\d+) months in a row)?!");
-
- // Backup
- settings.addLong("backupDelay", 1);
- settings.addLong("backupCount", 5);
-
- // Livestreamer
- settings.addBoolean("livestreamer", false);
- settings.addString("livestreamerQualities", "Best, Worst, Select");
- settings.addString("livestreamerCommand", "livestreamer");
- settings.addBoolean("livestreamerUseAuth", false);
- settings.addBoolean("livestreamerShowDialog", true);
-
- // Custom Commands and Menu Customization
- settings.addList("commands", new ArrayList(), Setting.STRING);
- // Default entries, will only be set if setting is not loaded from file
- settings.setAdd("commands", "/slap /me slaps $$1- around a bit with a large trout");
- settings.setAdd("commands", "/permit !permit $$1");
-
- settings.addString("timeoutButtons","/Ban[B], /Unban[U], 5s[1], 2m[2], 10m[3], 30m[4]");
- settings.addString("userContextMenu", "");
- settings.addString("channelContextMenu", "");
-
- settings.addBoolean("enableStatusWriter", false);
- settings.addString("statusWriter", "");
-
- settings.addBoolean("autoRequestMods", false);
-
- settings.addLong("streamChatMessageTimeout", -1);
- settings.addList("streamChatChannels", new ArrayList(), Setting.STRING);
- settings.addBoolean("streamChatBottom", true);
- settings.addBoolean("streamChatResizable", true);
-
- settings.addString("streamHighlightCommand", "!highlight");
- settings.addString("streamHighlightChannel", "");
- settings.addBoolean("streamHighlightChannelRespond", false);
+ // TAB Completion
settings.addMap("customCompletion", new HashMap(), Setting.STRING);
settings.addLong("completionMaxItemsShown", 5);
settings.addBoolean("completionShowPopup", true);
settings.addBoolean("completionCommonPrefix", false);
settings.addString("completionSorting", "predictive");
+ // Stream Chat
+ settings.addLong("streamChatMessageTimeout", -1);
+ settings.addList("streamChatChannels", new ArrayList(), Setting.STRING);
+ settings.addBoolean("streamChatBottom", true);
+ settings.addBoolean("streamChatResizable", true);
+
+ // Whispering
settings.addBoolean("whisperEnabled", false);
settings.addBoolean("whisperWhitelist", false);
- settings.addLong("whisperDisplayMode", WhisperConnection.DISPLAY_IN_CHAT);
+ settings.addLong("whisperDisplayMode", WhisperManager.DISPLAY_PER_USER);
settings.addString("groupChatServer", "");
settings.addString("groupChatPort", "");
settings.addBoolean("whisperAutoRespond", false);
- settings.addBoolean("autoUnhost", false);
- settings.addList("autoUnhostStreams", new ArrayList(), Setting.STRING);
-
+ // Copy Messages
settings.addBoolean("cmEnabled", false);
settings.addString("cmChannel", "");
settings.addString("cmTemplate", "{user}: {message}");
settings.addBoolean("cmHighlightedOnly", false);
- settings.addBoolean("newsAutoRequest", true);
- settings.addLong("newsLastRead", 0);
+ //===============
+ // Other Features
+ //===============
+
+ // Livestreamer
+ settings.addBoolean("livestreamer", false);
+ settings.addString("livestreamerQualities", "Best, Worst, Select");
+ settings.addString("livestreamerCommand", "livestreamer");
+ settings.addBoolean("livestreamerUseAuth", false);
+ settings.addBoolean("livestreamerShowDialog", true);
+
+ // Stream Highlights
+ settings.addString("streamHighlightCommand", "!highlight");
+ settings.addString("streamHighlightChannel", "");
+ settings.addBoolean("streamHighlightChannelRespond", false);
+
+ // Stream Status Writer
+ settings.addBoolean("enableStatusWriter", false);
+ settings.addString("statusWriter", "");
+
+ // Auto-Unhost
+ settings.addBoolean("autoUnhost", false);
+ settings.addList("autoUnhostStreams", new ArrayList(), Setting.STRING);
}
/**
diff --git a/src/chatty/TwitchClient.java b/src/chatty/TwitchClient.java
index bd9ec2385..ac17e7de0 100644
--- a/src/chatty/TwitchClient.java
+++ b/src/chatty/TwitchClient.java
@@ -10,7 +10,7 @@
import chatty.util.api.ChannelInfo;
import chatty.util.api.TwitchApi;
import chatty.Version.VersionListener;
-import chatty.WhisperConnection.WhisperListener;
+import chatty.WhisperManager.WhisperListener;
import chatty.gui.GuiUtil;
import chatty.gui.MainGui;
import chatty.gui.components.Channel;
@@ -150,7 +150,7 @@ public class TwitchClient {
private final Set refreshRequests = Collections.synchronizedSet(new HashSet());
- private final WhisperConnection w;
+ private final WhisperManager w;
private final IrcLogger ircLogger = new IrcLogger();
private boolean fixServer = false;
@@ -238,10 +238,7 @@ public TwitchClient(Map args) {
c.addChannelStateListener(new ChannelStateUpdater());
c.setSubNotificationPattern(settings.getString("subNotificationPattern"));
- w = new WhisperConnection(new MyWhisperListener(), settings);
- w.setUsericonManager(usericonManager);
- w.setAddressbook(addressbook);
- w.setUsercolorManager(usercolorManager);
+ w = new WhisperManager(new MyWhisperListener(), settings, c);
streamStatusWriter = new StreamStatusWriter(Chatty.getUserDataDirectory(), api);
streamStatusWriter.setSetting(settings.getString("statusWriter"));
@@ -630,12 +627,10 @@ public boolean prepareConnection(String name, String password,
}
c.connect(server, ports, name, password, autojoin);
- w.connect(name, password);
return true;
}
public boolean disconnect() {
- w.disconnect();
return c.disconnect();
}
@@ -761,11 +756,7 @@ else if (command.equals("reconnect")) {
commandReconnect();
}
else if (command.equals("connection")) {
- if (!w.isOffline()) {
- g.printLine(c.getConnectionInfo()+" {Whisper: "+w.getConnectionInfo()+"}");
- } else {
- g.printLine(c.getConnectionInfo());
- }
+ g.printLine(c.getConnectionInfo());
}
else if (command.equals("join")) {
commandJoinChannel(parameter);
@@ -1890,7 +1881,6 @@ public void exit() {
saveSettings(true);
logAllViewerstats();
c.disconnect();
- w.disconnect();
g.cleanUp();
chatLog.close();
System.exit(0);
@@ -2158,6 +2148,7 @@ public void onChannelCleared(String channel) {
@Override
public void onWhisper(User user, String message, String emotes) {
+ w.whisperReceived(user, message, emotes);
}
@Override
@@ -2239,10 +2230,8 @@ private class MyWhisperListener implements WhisperListener {
@Override
public void whisperReceived(User user, String message, String emotes) {
- g.printMessage(WhisperConnection.WHISPER_CHANNEL, user, message, false, emotes);
- if (settings.getLong("whisperDisplayMode") == WhisperConnection.DISPLAY_ONE_WINDOW) {
- g.updateUser(user);
- }
+ g.printMessage(WhisperManager.WHISPER_CHANNEL, user, message, false, emotes);
+ g.updateUser(user);
}
@Override
@@ -2252,19 +2241,8 @@ public void info(String message) {
@Override
public void whisperSent(User to, String message) {
- g.printMessage(WhisperConnection.WHISPER_CHANNEL, to, message, true, null);
+ g.printMessage(WhisperManager.WHISPER_CHANNEL, to, message, true, null);
}
-
- @Override
- public void onRawSent(String text) {
- ircLogger.onRawSent(text);
- }
-
- @Override
- public void onRawReceived(String text) {
- ircLogger.onRawReceived(text);
- }
-
}
}
diff --git a/src/chatty/TwitchConnection.java b/src/chatty/TwitchConnection.java
index bd5b7e392..89797b63a 100644
--- a/src/chatty/TwitchConnection.java
+++ b/src/chatty/TwitchConnection.java
@@ -6,7 +6,6 @@
import chatty.util.settings.Settings;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
@@ -14,7 +13,6 @@
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -26,13 +24,6 @@
*/
public class TwitchConnection {
- /**
- * Disable userlist connection altogether, since it should not be required
- * anymore with the membership CAP, however still keeping the code around
- * for now, just never actually connect.
- */
- private static final boolean USERLIST_CONNECTION = false;
-
public enum JoinError {
NOT_REGISTERED, ALREADY_JOINED, INVALID_NAME
}
@@ -54,7 +45,7 @@ public enum JoinError {
/**
* How many times to try to reconnect
*/
- private final int maxReconnectionAttempts = 30;
+ private final int maxReconnectionAttempts = 40;
/**
* The time in seconds between reconnection attempts. The first entry is the
* time for the first attempt, second entry for the second attempt and so
@@ -63,8 +54,6 @@ public enum JoinError {
private final static int[] RECONNECTION_DELAY = new int[]{1, 5, 5, 10, 10, 60};
private volatile Timer reconnectionTimer;
-
- private static final int SECONDARY_CONNECTION_UPDATE_DELAY = 10*1000;
/**
* The username to send to the server. This is stored to reconnect.
@@ -87,22 +76,16 @@ public enum JoinError {
protected UserManager users = new UserManager();
private final IrcConnection irc;
- private final IrcConnection irc2;
- private final IrcConnection userlistConnection;
private final TwitchCommands twitchCommands;
private final SpamProtection spamProtection;
private final ChannelStateManager channelStates = new ChannelStateManager();
- private boolean whisperConnection;
-
private Pattern subNotificationPattern;
public TwitchConnection(final ConnectionListener listener, Settings settings,
String label) {
irc = new IrcConnection(label);
- irc2 = new IrcConnection(label+"-secondary");
- userlistConnection = irc;
this.listener = listener;
this.settings = settings;
this.twitchCommands = new TwitchCommands(this);
@@ -120,19 +103,6 @@ public void userUpdated(User user) {
}
}
});
-
- // Start timer to update secondary connection
- TimerTask updateSecondaryConnectionTask = new TimerTask() {
-
- @Override
- public void run() {
- updateSecondaryConnection();
- }
- };
- final Timer timer = new Timer("update secondary connection", true);
- timer.schedule(updateSecondaryConnectionTask,
- SECONDARY_CONNECTION_UPDATE_DELAY,
- SECONDARY_CONNECTION_UPDATE_DELAY);
}
private TimerTask getReconnectionTimerTask() {
@@ -145,10 +115,6 @@ public void run() {
};
}
- public void setWhisperConnection(boolean value) {
- this.whisperConnection = value;
- }
-
public void setSubNotificationPattern(String text) {
try {
subNotificationPattern = Pattern.compile(text);
@@ -217,7 +183,7 @@ public String getUsername() {
}
public boolean isUserlistLoaded(String channel) {
- return userlistConnection.isRegistered() && userlistConnection.userlistReceived.contains(channel);
+ return irc.isRegistered() && irc.userlistReceived.contains(channel);
}
public Set getOpenChannels() {
@@ -270,6 +236,9 @@ public boolean isChannelOpen(String channel) {
}
public void closeChannel(String channel) {
+ if (channel.equals(WhisperManager.WHISPER_CHANNEL)) {
+ return;
+ }
partChannel(channel);
openChannels.remove(channel);
users.clear(channel);
@@ -365,8 +334,7 @@ private void connect() {
}
private Collection getSecuredPorts() {
- List setting = settings.getList(
- whisperConnection ? "securedPortsWhisper" : "securedPorts");
+ List setting = settings.getList("securedPorts");
Collection result = new HashSet<>();
for (Object value : setting) {
result.add(((Long)value).intValue());
@@ -401,59 +369,18 @@ public boolean disconnect() {
irc.connectionAttempts = 0;
}
boolean success = irc.disconnect();
- irc2.disconnect();
return success;
}
public void quit() {
irc.disconnect();
- irc2.disconnect();
}
-
- /**
- * Synchronizes the userlist connection with the primary connection, joining
- * and leaving channels accordingly.
- */
- private void updateSecondaryConnection() {
- if (!USERLIST_CONNECTION) {
- return;
- }
- //LOGGER.info("Updating secondary connection..");
- if (irc.isRegistered() && settings.getBoolean("userlistConnection")) {
- if (irc2.isOffline()) {
- int delay = getReconnectionDelay(irc2.connectionAttempts);
- if (irc2.getLastConnectionAttemptAgo() > delay) {
- irc2.connect(server, serverPorts, username, password, getSecuredPorts());
- }
- } else if (irc2.isRegistered()) {
- Set currentChannels = irc.getJoinedChannels();
- Set toLeave = irc2.getJoinedChannels();
- for (String channel : currentChannels) {
- if (!settings.listContains("userlistConnectionBlacklist", channel)) {
- if (!irc2.onChannel(channel)) {
- irc2.joinChannel(channel);
- }
- toLeave.remove(channel);
- }
- }
- for (String channel : toLeave) {
- irc2.partChannel(channel);
- }
- }
- } else if (irc2.isRegistered()) {
- irc2.disconnect();
- }
- }
-
+
public String getConnectionInfo() {
String regular = irc.getConnectionInfo();
- String secondary = irc2.getConnectionInfo();
if (regular == null) {
return "Not connected.";
}
- if (secondary != null) {
- return "Connected to: "+regular+" ("+secondary+")";
- }
return "Connected to: "+regular;
}
@@ -470,10 +397,6 @@ public void sendRaw(String text) {
}
public boolean command(String channel, String command, String parameters) {
- if (command.equals("getsecondarychannels")) {
- info(irc2.getJoinedChannels().toString());
- return true;
- }
return twitchCommands.command(channel, command, parameters);
}
@@ -499,7 +422,7 @@ public void sendCommandMessage(String channel, String message, String echo) {
* Tries to send a spam protected message, which will either be send or not,
* depending on the status of the spam protection.
*
- * This doesn't check if you're actually on the channel.
+ * This doesn't check if you're actually on the channel.
*
* @param channel The channel to send the message to
* @param message The message to send
@@ -657,7 +580,7 @@ public boolean primaryOnChannel(String channel) {
@Override
void onUserlist(String channel, String[] nicknames) {
channel = channel.toLowerCase();
- if ((this == userlistConnection) && isChannelOpen(channel)) {
+ if (isChannelOpen(channel)) {
/**
* Don't clear userlist just yet if only local name is in the
@@ -758,8 +681,6 @@ void onDisconnect(int reason, String reasonMessage) {
connectionAttempts = 0;
}
listener.onDisconnect(reason, reasonMessage);
- } else if (this == userlistConnection) {
- //clearUserlist(null);
}
}
@@ -808,7 +729,7 @@ void onJoin(String channel, String nick, String prefix) {
/**
* Another user has joined a channel we are currently in.
*/
- if ((this == userlistConnection) && isChannelOpen(channel)) {
+ if (isChannelOpen(channel)) {
if (!userlistReceived.contains(channel)) {
clearUserlist(channel);
// Add local user again, must be on this channel but
@@ -859,20 +780,17 @@ void onPart(String channel, String nick, String prefix, String message) {
listener.onChannelLeft(channel);
channelStates.reset(channel);
}
- if (this == userlistConnection) {
- // Leaving the channel on the userlist connection means
- // the userlist can no longer be considered as received for
- // this channel.
- userlistReceived.remove(channel);
- }
+ // Leaving the channel on the userlist connection means
+ // the userlist can no longer be considered as received for
+ // this channel.
+ userlistReceived.remove(channel);
debug("PARTED: "+channel);
} else {
- if ((this == userlistConnection) && isChannelOpen(channel)) {
+ if (isChannelOpen(channel)) {
User user = userOffline(channel, nick);
listener.onPart(user);
}
}
-
}
@Override
@@ -960,8 +878,8 @@ private void updateUserFromTags(User user, Map tags) {
}
}
- private boolean checkTagsState(String state, Map tags) {
- return "1".equals(tags.get(state));
+ private boolean checkTagsState(String key, Map tags) {
+ return "1".equals(tags.get(key));
}
@Override
@@ -994,8 +912,6 @@ void onChannelMessage(String channel, String nick, String from, String text,
}
}
}
- } else if (nick.equals("jtv")) {
- specialMessage(text, channel);
} else {
User user = userJoined(channel, nick);
updateUserFromTags(user, tags);
@@ -1020,8 +936,10 @@ void onNotice(String channel, String text, Map tags) {
if (this != irc) {
return;
}
- if (onChannel(channel) || whisperConnection) {
+ if (onChannel(channel)) {
infoMessage(channel, text);
+ } else if (channel.equals("#jtv")) {
+ listener.onInfo(text);
} else {
listener.onInfo(String.format("[Info/%s] %s", channel, text));
}
@@ -1032,48 +950,11 @@ void onQueryMessage(String nick, String from, String text) {
if (this != irc) {
return;
}
- /**
- * Any messages from jtv shown directly or used appropriatly, don't think
- * there can be any private messages from other users anyway
- * (although it might be renamed some time)
- */
- if (nick.equals("jtv")) {
- specialMessage(text, null);
- }
if (nick.startsWith("*")) {
listener.onSpecialMessage(nick, text);
}
}
- private void specialMessage(String text, String channel) {
- String[] split = text.split(" ");
-
- /**
- * This is still returned when changing color (instead of a
- * USERSTATE command).
- */
- if (split[0].equals("USERCOLOR") && split.length == 3) {
- String colorNick = split[1];
- String color = split[2];
- users.setColorForUsername(colorNick, color);
- }
-
- // Decide whether to output the message directly to the user
- if (split[0].length() > 2 && Helper.isAllUppercaseLetters(split[0])) {
- /**
- * Commands are usually all uppercase letters with a length of
- * more than two, so don't show those to the user directly.
- */
- return;
- } else {
- /**
- * Show anything else, since it's probably a message that's
- * useful to the user.
- */
- infoMessage(channel, text);
- }
- }
-
/**
* Any kind of info message. This can be either from jtv (legacy) or the
* new NOTICE messages to the channel.
@@ -1154,7 +1035,7 @@ private void channelCleared(String channel) {
@Override
void onWhoResponse(String channel, String nickname) {
-
+ // Not working on Twitch Chat anyway
}
@Override
@@ -1173,8 +1054,6 @@ public boolean isChannelOpen(String channel) {
return openChannels.contains(channel);
}
-
-
@Override
public void raw(String text) {
listener.onRawReceived(idPrefix+text);
@@ -1307,7 +1186,7 @@ public void onCommand(String nick, String command, String parameter, String text
return;
}
if (command.equals("WHISPER")) {
- User user = userJoined(WhisperConnection.WHISPER_CHANNEL, nick);
+ User user = userJoined(WhisperManager.WHISPER_CHANNEL, nick);
updateUserFromTags(user, tags);
String emotesTag = tags != null ? tags.get("emotes") : null;
listener.onWhisper(user, text, emotesTag);
diff --git a/src/chatty/WhisperConnection.java b/src/chatty/WhisperConnection.java
deleted file mode 100644
index 4c8b01605..000000000
--- a/src/chatty/WhisperConnection.java
+++ /dev/null
@@ -1,357 +0,0 @@
-
-package chatty;
-
-import chatty.util.settings.Settings;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- *
- * @author tduva
- */
-public class WhisperConnection {
-
- public static final String WHISPER_CHANNEL = "$[whisper]";
-
- public static final int DISPLAY_IN_CHAT = 0;
- public static final int DISPLAY_ONE_WINDOW = 1;
- public static final int DISPLAY_PER_USER = 2;
-
- private final TwitchConnection c;
- private final WhisperListener listener;
- private final Settings settings;
-
- private final String AUTO_RESPOND_MESSAGE = "[Auto-Message] This user has "
- + "not allowed to receive whispers from you.";
- private final Set autoRespondedTo = new HashSet<>();
-
- public WhisperConnection(WhisperListener listener, Settings settings) {
- this.listener = listener;
- this.settings = settings;
- c = new TwitchConnection(new Events(), settings, "whisper");
- c.setWhisperConnection(true);
- }
-
- public void disconnect() {
- c.disconnect();
- }
-
- public void setUsericonManager(UsericonManager m) {
- c.setUsericonManager(m);
- }
-
- public void setAddressbook(Addressbook a) {
- c.setAddressbook(a);
- }
-
- public void setUsercolorManager(UsercolorManager m) {
- c.setUsercolorManager(m);
- }
-
- public String getConnectionInfo() {
- return c.getConnectionInfo();
- }
-
- public boolean isOffline() {
- return c.isOffline();
- }
-
- public boolean isAvailable() {
- //return !c.isOffline() && c.onChannel("#jtv");
- return c.isRegistered();
- }
-
- /**
- * Check whether the whisper feature is enabled and configured correctly.
- *
- * @return true if enabled and configured correctly, false otherwise
- */
- public boolean isEnabled() {
- if (!settings.getBoolean("whisperEnabled")) {
- return false;
- }
- String server = settings.getString("groupChatServer");
- String port = settings.getString("groupChatPort");
- if (server.isEmpty() || port.isEmpty()) {
- return false;
- }
- return true;
- }
-
- /**
- * Connect to the Group Chat Server (specified in the settings) using the
- * given name and password. If already connected, this will simply store
- * the given name/password and not connect. It may use the stored data to
- * reconnect.
- *
- * @param username
- * @param password
- */
- public void connect(String username, String password) {
- if (settings.getBoolean("whisperEnabled")) {
- String server = settings.getString("groupChatServer");
- String port = settings.getString("groupChatPort");
- if (server.isEmpty() || port.isEmpty()) {
- listener.info("Whisper feature: No server/port defined (read help)");
- return;
- }
- c.connect(server, port, username, password, new String[]{});
- }
- }
-
- /**
- * The whisper command in the form: {@code /w }
- *
- * @param parameter The target and message in a String
- * @param onlyReply Whether to only send a whisper to people you already
- * have whispered with this session
- */
- public void whisperCommand(String parameter, boolean onlyReply) {
- if (parameter == null) {
- listener.info("Whisper: Invalid parameters.");
- return;
- }
- String[] split = parameter.split(" ", 2);
- if (split.length == 2) {
- whisper(split[0], split[1], onlyReply);
- } else {
- listener.info("Whisper: Invalid parameters.");
- }
- }
-
- /**
- * Whisper entered directly into the channel input box of a whisper tab, so
- * get the target of the whisper.
- *
- * If a whisper is entered in the combined whisper channel, then the message
- * has to be in the format {@code }. In case the user only
- * types the message, whispers entered this way will only be send to users
- * that the local user has already whispered with this session.
- *
- * @param channel The channel
- * @param message The message entered, which may be the {@code } or
- * {@code } depending on the channel
- */
- public void whisperChannel(String channel, String message) {
- if (channel.equals(WHISPER_CHANNEL)) {
- whisperCommand(message, true);
- } else if (channel.startsWith("$") && channel.length() > 1) {
- String nick = channel.substring(1);
- whisper(nick, message, false);
- } else {
- listener.info("Whisper: Invalid parameters.");
- }
- }
-
- /**
- * Send a whisper.
- *
- * @param nick The target of the whisper
- * @param message The message
- * @param onlyReply If true, it will only send a whisper to people that have
- * already whispered with you this session
- */
- public void whisper(String nick, String message, boolean onlyReply) {
- if (!isEnabled()) {
- listener.info("Whisper feature not enabled ()");
- return;
- }
- if (onlyReply && c.getExistingUser(WHISPER_CHANNEL, nick) == null) {
- listener.info("Didn't receive any whisper from '"+nick+"', use /w command");
- return;
- }
- if (isAvailable()) {
- if (!rawWhisper(nick, message)) {
- listener.info("# Whisper not sent (spam protection): " + message);
- } else {
- User user = c.getUser(WHISPER_CHANNEL, nick);
- listener.whisperSent(user, message);
- if (isUserIgnored(user)) {
- listener.info("You haven't allowed to receive whispers from " + user);
- }
- }
- } else {
- listener.info("Can't send whisper: not connected");
- }
- }
-
- private boolean rawWhisper(String nick, String message) {
- return c.sendSpamProtectedMessage("#jtv", "/w "+nick+" "+message, false);
- }
-
- /**
- * Check if whispers from the given user should be output or ignored.
- * @param user The user to check
- * @return true if whispers from the given user should be output, false
- * otherwise
- */
- private boolean isUserAllowed(User user) {
- if (user.hasCategory("blockwhisper")) {
- return false;
- }
- if (settings.getBoolean("whisperWhitelist") && !user.hasCategory("whisper")) {
- return false;
- }
- return true;
- }
-
- private boolean isUserIgnored(User user) {
- if (settings.listContains("ignoredUsersWhisper", user.nick)) {
- return true;
- }
- return !isUserAllowed(user);
- }
-
- private class Events implements TwitchConnection.ConnectionListener {
-
- @Override
- public void onJoinAttempt(String channel) {
- }
-
- @Override
- public void onChannelJoined(String channel) {
- }
-
- @Override
- public void onChannelLeft(String channel) {
- }
-
- @Override
- public void onJoin(User user) {
- }
-
- @Override
- public void onPart(User user) {
- }
-
- @Override
- public void onUserAdded(User user) {
- }
-
- @Override
- public void onUserRemoved(User user) {
- }
-
- @Override
- public void onUserlistCleared(String channel) {
- }
-
- @Override
- public void onUserUpdated(User user) {
- }
-
- @Override
- public void onChannelMessage(User user, String message, boolean action, String emotes) {
-
- }
-
- @Override
- public void onNotice(String message) {
- }
-
- @Override
- public void onInfo(String channel, String infoMessage) {
- if (channel.equals("#jtv")) {
- listener.info(infoMessage);
- }
- }
-
- @Override
- public void onInfo(String message) {
-
- }
-
- @Override
- public void onGlobalInfo(String message) {
- }
-
- @Override
- public void onBan(User user) {
- }
-
- @Override
- public void onRegistered() {
- listener.info("Whisper feature: connected");
- }
-
- @Override
- public void onDisconnect(int reason, String reasonMessage) {
- listener.info("Whisper feature: Disconnected ("+reasonMessage+")");
- }
-
- @Override
- public void onMod(User user) {
- }
-
- @Override
- public void onUnmod(User user) {
- }
-
- @Override
- public void onConnectionStateChanged(int state) {
- }
-
- @Override
- public void onSpecialUserUpdated() {
- }
-
- @Override
- public void onConnectError(String message) {
- }
-
- @Override
- public void onJoinError(Set toJoin, String errorChannel, TwitchConnection.JoinError error) {
- }
-
- @Override
- public void onRawReceived(String text) {
- listener.onRawReceived(text);
- }
-
- @Override
- public void onRawSent(String text) {
- listener.onRawSent(text);
- }
-
- @Override
- public void onHost(String channel, String target) {
- }
-
- @Override
- public void onChannelCleared(String channel) {
- }
-
- @Override
- public void onWhisper(User user, String message, String emotes) {
- if (isUserAllowed(user)) {
- listener.whisperReceived(user, message, emotes);
- }
- if (isUserIgnored(user) && settings.getBoolean("whisperAutoRespond")) {
- if (!autoRespondedTo.contains(user.nick)) {
- rawWhisper(user.nick, AUTO_RESPOND_MESSAGE);
- autoRespondedTo.add(user.nick);
- }
- } else {
- autoRespondedTo.remove(user.nick);
- }
- }
-
- @Override
- public void onSubscriberNotification(String channel, String name, int months) {
- }
-
- @Override
- public void onSpecialMessage(String name, String message) {
- }
-
- }
-
- public interface WhisperListener {
- public void whisperReceived(User user, String message, String emotes);
- public void whisperSent(User to, String message);
- public void info(String message);
- public void onRawSent(String text);
- public void onRawReceived(String text);
- }
-
-}
diff --git a/src/chatty/WhisperManager.java b/src/chatty/WhisperManager.java
new file mode 100644
index 000000000..8aff62716
--- /dev/null
+++ b/src/chatty/WhisperManager.java
@@ -0,0 +1,188 @@
+
+package chatty;
+
+import chatty.util.settings.Settings;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ *
+ * @author tduva
+ */
+public class WhisperManager {
+
+ public static final String WHISPER_CHANNEL = "$[whisper]";
+
+ public static final int DISPLAY_IN_CHAT = 0;
+ public static final int DISPLAY_ONE_WINDOW = 1;
+ public static final int DISPLAY_PER_USER = 2;
+
+ private final String AUTO_RESPOND_MESSAGE = "[Auto-Message] This user has "
+ + "not allowed to receive whispers from you.";
+ private final Set autoRespondedTo = new HashSet<>();
+
+ //-----------
+ // References
+ //-----------
+ private final WhisperListener listener;
+ private final Settings settings;
+ private final TwitchConnection c;
+
+ public WhisperManager(WhisperListener listener, Settings settings,
+ TwitchConnection c) {
+ this.listener = listener;
+ this.settings = settings;
+ this.c = c;
+ }
+
+ public boolean isAvailable() {
+ return c.isRegistered() && isEnabled();
+ }
+
+ /**
+ * Check whether the whisper feature is enabled and configured correctly.
+ *
+ * @return true if enabled and configured correctly, false otherwise
+ */
+ public boolean isEnabled() {
+ return settings.getBoolean("whisperEnabled");
+ }
+
+ /**
+ * The whisper command in the form: {@code /w }
+ *
+ * @param parameter The target and message in a String
+ * @param onlyReply Whether to only send a whisper to people you already
+ * have whispered with this session
+ */
+ public void whisperCommand(String parameter, boolean onlyReply) {
+ if (parameter == null) {
+ listener.info("Whisper: Invalid parameters.");
+ return;
+ }
+ String[] split = parameter.split(" ", 2);
+ if (split.length == 2) {
+ whisper(split[0], split[1], onlyReply);
+ } else {
+ listener.info("Whisper: Invalid parameters.");
+ }
+ }
+
+ /**
+ * Whisper entered directly into the channel input box of a whisper tab, so
+ * get the target of the whisper.
+ *
+ * If a whisper is entered in the combined whisper channel, then the message
+ * has to be in the format {@code }. In case the user only
+ * types the message, whispers entered this way will only be send to users
+ * that the local user has already whispered with this session.
+ *
+ * @param channel The channel
+ * @param message The message entered, which may be the {@code } or
+ * {@code } depending on the channel
+ */
+ public void whisperChannel(String channel, String message) {
+ if (channel.equals(WHISPER_CHANNEL)) {
+ whisperCommand(message, true);
+ } else if (channel.startsWith("$") && channel.length() > 1) {
+ String nick = channel.substring(1);
+ whisper(nick, message, false);
+ } else {
+ listener.info("Whisper: Invalid parameters.");
+ }
+ }
+
+ /**
+ * Send a whisper, while checking some stuff.
+ *
+ * @param nick The target of the whisper
+ * @param message The message
+ * @param onlyReply If true, it will only send a whisper to people that have
+ * already whispered with you this session
+ */
+ public void whisper(String nick, String message, boolean onlyReply) {
+ if (!isEnabled()) {
+ listener.info("Whisper feature not enabled ()");
+ return;
+ }
+ if (onlyReply && c.getExistingUser(WHISPER_CHANNEL, nick) == null) {
+ listener.info("Didn't receive any whisper from '"+nick+"', use /w command");
+ return;
+ }
+ if (isAvailable()) {
+ if (!rawWhisper(nick, message)) {
+ listener.info("# Whisper not sent (spam protection): " + message);
+ } else {
+ User user = c.getUser(WHISPER_CHANNEL, nick);
+ listener.whisperSent(user, message);
+ if (isUserIgnored(user)) {
+ listener.info("You haven't allowed to receive whispers from " + user);
+ }
+ }
+ } else {
+ listener.info("Can't send whisper: not connected");
+ }
+ }
+
+ /**
+ * Check if whispers from the given user should be output or ignored.
+ *
+ * @param user The user to check
+ * @return true if whispers from the given user should be output, false
+ * otherwise
+ */
+ private boolean isUserAllowed(User user) {
+ if (user.hasCategory("blockwhisper")) {
+ return false;
+ }
+ if (settings.getBoolean("whisperWhitelist") && !user.hasCategory("whisper")) {
+ return false;
+ }
+ return true;
+ }
+
+ private boolean isUserIgnored(User user) {
+ if (settings.listContains("ignoredUsersWhisper", user.nick)) {
+ return true;
+ }
+ return !isUserAllowed(user);
+ }
+
+ public void whisperReceived(User user, String message, String emotes) {
+ if (!isEnabled()) {
+ return;
+ }
+ if (isUserAllowed(user)) {
+ listener.whisperReceived(user, message, emotes);
+ }
+ if (isUserIgnored(user) && settings.getBoolean("whisperAutoRespond")) {
+ if (!autoRespondedTo.contains(user.nick)) {
+ rawWhisper(user.nick, AUTO_RESPOND_MESSAGE);
+ autoRespondedTo.add(user.nick);
+ }
+ } else {
+ autoRespondedTo.remove(user.nick);
+ }
+ }
+
+ /**
+ * Send a whisper without any checks.
+ *
+ * @param nick
+ * @param message
+ * @return
+ */
+ private boolean rawWhisper(String nick, String message) {
+ return c.sendSpamProtectedMessage("#jtv", "/w " + nick + " " + message, false);
+ }
+
+
+ public interface WhisperListener {
+
+ public void whisperReceived(User user, String message, String emotes);
+
+ public void whisperSent(User to, String message);
+
+ public void info(String message);
+ }
+}
diff --git a/src/chatty/gui/Channels.java b/src/chatty/gui/Channels.java
index e49ca354a..78c834b88 100644
--- a/src/chatty/gui/Channels.java
+++ b/src/chatty/gui/Channels.java
@@ -160,7 +160,7 @@ private Channel createChannel(String name, Channel.Type type) {
channel.setUserlistWidth(defaultUserlistWidth, minUserlistWidth);
channel.setMouseClickedListener(mouseClickedListener);
channel.setScrollbarAlways(chatScrollbarAlaways);
- if (type == Channel.Type.SPECIAL) {
+ if (type == Channel.Type.SPECIAL || type == Channel.Type.WHISPER) {
channel.setUserlistEnabled(false);
}
return channel;
diff --git a/src/chatty/gui/MainGui.java b/src/chatty/gui/MainGui.java
index 0b2f6dfaa..440d2b514 100644
--- a/src/chatty/gui/MainGui.java
+++ b/src/chatty/gui/MainGui.java
@@ -28,7 +28,7 @@
import chatty.StatusHistory;
import chatty.UsercolorItem;
import chatty.Usericon;
-import chatty.WhisperConnection;
+import chatty.WhisperManager;
import chatty.gui.components.AddressbookDialog;
import chatty.gui.components.EmotesDialog;
import chatty.gui.components.ErrorMessage;
@@ -56,7 +56,6 @@
import chatty.util.api.EmoticonUpdate;
import chatty.util.api.Emoticons.TagEmotes;
import chatty.util.api.FollowerInfo;
-import chatty.util.api.TwitchApi;
import chatty.util.api.TwitchApi.RequestResult;
import chatty.util.hotkeys.HotkeyManager;
import chatty.util.settings.Setting;
@@ -65,8 +64,6 @@
import chatty.util.settings.SettingsListener;
import java.awt.*;
import java.awt.event.*;
-import java.time.LocalDateTime;
-import java.time.Month;
import java.util.*;
import java.util.logging.LogRecord;
import javax.swing.AbstractAction;
@@ -2374,11 +2371,11 @@ public void run() {
* Check if special channel and change target according to
* settings
*/
- if (channel.equals(WhisperConnection.WHISPER_CHANNEL)) {
+ if (channel.equals(WhisperManager.WHISPER_CHANNEL)) {
int whisperSetting = (int)client.settings.getLong("whisperDisplayMode");
- if (whisperSetting == WhisperConnection.DISPLAY_ONE_WINDOW) {
+ if (whisperSetting == WhisperManager.DISPLAY_ONE_WINDOW) {
chan = channels.getChannel(channel);
- } else if (whisperSetting == WhisperConnection.DISPLAY_PER_USER) {
+ } else if (whisperSetting == WhisperManager.DISPLAY_PER_USER) {
if (!userIgnored(user, true)) {
chan = channels.getChannel("$"+user.getNick());
} else {
@@ -2753,6 +2750,7 @@ public void addUser(final String channel, final User user) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
+ if (!shouldUpdateUser(user)) return;
Channel c = channels.getChannel(channel);
c.addUser(user);
if (channels.getActiveChannel() == c) {
@@ -2772,6 +2770,7 @@ public void removeUser(final String channel, final User user) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
+ if (!shouldUpdateUser(user)) return;
Channel c = channels.getChannel(channel);
c.removeUser(user);
if (channels.getActiveChannel() == c) {
@@ -2791,12 +2790,18 @@ public void updateUser(final User user) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
+ if (!shouldUpdateUser(user)) return;
channels.getChannel(user.getChannel()).updateUser(user);
state.update();
}
});
}
+ private boolean shouldUpdateUser(User user) {
+ return !user.getChannel().equals(WhisperManager.WHISPER_CHANNEL)
+ || client.settings.getLong("whisperDisplayMode") == WhisperManager.DISPLAY_ONE_WINDOW;
+ }
+
/**
* Resort users in the userlist of the given channel.
*
diff --git a/src/chatty/gui/components/help/help-whisper.html b/src/chatty/gui/components/help/help-whisper.html
index 6d0dcdf7e..85bc46fe5 100644
--- a/src/chatty/gui/components/help/help-whisper.html
+++ b/src/chatty/gui/components/help/help-whisper.html
@@ -7,73 +7,28 @@
- Getting started / Settings |
+ Settings |
Usage |
Troubleshooting
- It is recommended that you read and understand this whole section
- before enabling this feature.
-
- Chatty implements the new /w
command that Twitch Chat
+
Chatty implements the /w
command that Twitch Chat
provides, allowing you to send private messages in chat to other users.
- However, it is disabled by default, since it has a few problems:
+ Chatty does not provide the Whisper History as on the website and is
+ only a very basic implementation in general.
-
- - Twitch is planning to move Whispering to a whole different system
- soon, which means in the current state it is not really encouraged
- to be used by third-party applications. It is unclear what the new
- system will be and whether it will be possible to implement it in
- Chatty. Also, due to these circumstances, not too much development
- time will be put into the Whisper feature in Chatty at this time.
- - Whispering currently runs on the Group Chat servers, so Chatty can't
- just use
irc.twitch.tv
to connect as for regular chat.
- Since there is no easy official way to get the server data
- automatically, you have enter the IP and port yourself if you want
- to use this feature.
-
+ The Whisper Feature is disabled by default.
+
+ In April 2016 Twitch moved Whispers from the Group Chat servers to the
+ new AWS Twitch Chat servers. There is no additional server configuration
+ required anymore.
-
- You have to change a few settings in order to use this feature
- (all under Main - Settings - Advanced
):
-
- Required settings
-
- - Whisper Enabled: Connect to the given Group Chat
- server to send and receive whispers. Enable when you configured the
- server. Disable this it if you run into problems.
- - Server/Port: You can click on
-
Select server..
and select a server from the list (all
- listed should work). This is using an unsupported Twitch
- API which is not guaranteed to stay the same.
-
-
- Once these settings are correctly configured, Chatty will connect to
- Whispers when you connect to regular chat. It will disconnect when you
- disconnect from regular chat via the Main-menu. If the Whisper Feature
- is properly connected and ready to use, [W]
will be shown
- in the titlebar and the /connection
command will show the
- Whisper connection in addition to the regular chat connection.
-
- If you were already connected when you changed these settings, either
- disconnect and connect again (via the Main menu) or restart Chatty.
-
- If Select server..
is not working, configure the server manually:
-
- - Server: The Group Chat server IP to connect to. You can check:
-
- - Twitchstatus.com (unofficial site) at the bottom of the page,
- "Group Chat" tab, "irc" Protocol (not "ws_irc")
- - Get an IP from the Twitch API using this guide
- (you will need a token and be member of a Group Chat, you won't need to get a channelname)
-
- - Port: The port for the Group Chat server you
- are using (you should get it along with the IP).
-
-
- Optional settings
+
+ - Whisper Enabled: Allow sending and receiving
+ Whispers. With this disabled, you won't be able to send Whispers and
+ any received Whispers will be entirely ignored.
- Whitelist: If enabled, only users that have the
Addressbook category
whisper
will be able to send whispers to you.
@@ -143,34 +98,6 @@
(*), which is usually used to mark action messages
(/me
).
-
-
- If you get a lot of errors like Whisper feature: Disconnected
this
- may be due to different reasons:
-
-
- - A temporary problem with Twitch or your internet connection, in which
- case just wait a while.
- - Wrong server/port entered, follow the Getting Started
- guide to check if the data you entered is still correct.
- - Twitch changed the system and it is not working as implemented in Chatty
- anymore (in which case you should disable the feature).
-
-
- How to proceed:
-
- - Check Twitchstatus.com (mainly Group Chat Tab),
- @ChattyClient and
- other usual places to find out if the problem lies with Twitch.
- Disable the Whisper Feature if necessary.
- - If the
[W]
in the titlebar isn't there, but it also
- doesn't output errors anymore, it may have given up trying to connect,
- in which case you should connect to regular chat through the Main
- menu (disconnect first if necessary). Connecting to whispers is
- currently somewhat tied to connecting to regular chat. Disconnecting
- from regular chat from the Main
menu will also disconnect
- from whispers.
-