From: Debayan Sutradhar Date: Sat, 13 Mar 2021 18:56:50 +0530 Subject: Merge pull request #21 from j4ckofalltrades/implement-twitch-chat-commands --- Merge pull request #21 from j4ckofalltrades/implement-twitch-chat-commands Implement Twitch chat commands --- Binary files /dev/null and b/PreBuiltPlugins/twitch-add-stream-marker.jar differ Binary files /dev/null and b/PreBuiltPlugins/twitch-chat-connect.jar differ Binary files /dev/null and b/PreBuiltPlugins/twitch-clear-chat.jar differ Binary files /dev/null and b/PreBuiltPlugins/twitch-host-channel.jar differ Binary files /dev/null and b/PreBuiltPlugins/twitch-raid-channel.jar differ Binary files 'a/PreBuiltPlugins/twitch-send-channel-msg.jar' and b/PreBuiltPlugins/twitch-send-channel-msg.jar differ Binary files /dev/null and b/PreBuiltPlugins/twitch-set-color.jar differ Binary files /dev/null and b/PreBuiltPlugins/twitch-start-commercial.jar differ Binary files /dev/null and b/PreBuiltPlugins/twitch-unhost.jar differ Binary files /dev/null and b/PreBuiltPlugins/twitch-unraid.jar differ Binary files /dev/null and b/PreBuiltPlugins/twitch-whisper.jar differ --- 'a/README.md' +++ b/README.md @@ -25,11 +25,33 @@ Set of trusted, pre-bundled actions and The first step is to acquire an OAuth token from https://twitchapps.com/tmi/, the generated OAuth token should look something like `oauth:xxxxx`. -In the Stream-Pi Server's Plugin page enter your Twitch username, and the generated token then click on `Save Twitch chat credentials` button. You should then be able to use the pre-bundled Twitch chat actions. +In the Stream-Pi Server's Plugin page enter your Twitch username, and the generated token then click on `Save Twitch Chat credentials` button. You should then be able to use the pre-bundled Twitch chat actions. -### Supported actions +### Supported actions (see [Chat Commands](https://help.twitch.tv/s/article/chat-commands?language=en_US) for full documentation) +#### All Users + +- Set username color + - Normal users can choose between Blue, Coral, DodgerBlue, SpringGreen, YellowGreen, Green, OrangeRed, Red, GoldenRod, HotPink, CadetBlue, SeaGreen, Chocolate, BlueViolet, and Firebrick. Twitch Turbo users can use any Hex value (i.e: #000000). - Send channel message +- Whisper (send user message) + +#### Broadcaster and Mods + +- Clear chat +- Toggle slow mode (TBA - pending toggle-button functionality) +- Toggle followers-only mode (TBA - pending toggle-button functionality) +- Toggle subs-only mode (TBA - pending toggle-button functionality) +- Toggle emotes-only mode (TBA - pending toggle-button functionality) + +#### Broadcaster and channel editors + +- Run commercial +- Host +- Unhost +- Raid +- Unraid +- Add stream marker ### Running locally --- 'a/build.sh' +++ b/build.sh @@ -91,8 +91,35 @@ twitchchat() { cd twitch/twitch-chat-connect && mvn clean install package mv target/twitch-chat-connect-1.0.0.jar ../$FOLD/twitch-chat-connect.jar - cd ../send-channel-msg && mvn clean package + cd ../send-channel-msg && mvn clean install package mv target/twitch-send-channel-msg-1.0.0.jar ../$FOLD/twitch-send-channel-msg.jar + + cd ../clear-chat && mvn clean install package + mv target/twitch-clear-chat-1.0.0.jar ../$FOLD/twitch-clear-chat.jar + + cd ../set-color && mvn clean install package + mv target/twitch-set-color-1.0.0.jar ../$FOLD/twitch-set-color.jar + + cd ../whisper && mvn clean install package + mv target/twitch-whisper-1.0.0.jar ../$FOLD/twitch-whisper.jar + + cd ../unraid && mvn clean install package + mv target/twitch-unraid-1.0.0.jar ../$FOLD/twitch-unraid.jar + + cd ../unhost && mvn clean install package + mv target/twitch-unhost-1.0.0.jar ../$FOLD/twitch-unhost.jar + + cd ../add-stream-marker && mvn clean install package + mv target/twitch-add-stream-marker-1.0.0.jar ../$FOLD/twitch-add-stream-marker.jar + + cd ../host-channel && mvn clean install package + mv target/twitch-host-channel-1.0.0.jar ../$FOLD/twitch-host-channel.jar + + cd ../raid-channel && mvn clean install package + mv target/twitch-raid-channel-1.0.0.jar ../$FOLD/twitch-raid-channel.jar + + cd ../start-commercial && mvn clean install package + mv target/twitch-start-commercial-1.0.0.jar ../$FOLD/twitch-start-commercial.jar popd || exit } --- /dev/null +++ b/twitch/add-stream-marker/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + com.stream-pi + twitch-add-stream-marker + 1.0.0 + + + 11 + 11 + 1.0.0 + 1.0.0 + 1.0.0 + 0.6.3 + + + + + jitpack.io + https://jitpack.io + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + test-jar + package + + test-jar + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 11 + + + + + + + + com.stream-pi + util + ${streamPiUtilVersion} + + + + com.stream-pi + action-api + ${streamPiActionApiVersion} + + + + com.github.gikkman + Java-Twirk + ${javaTwirkVersion} + + + + com.stream-pi + twitch-chat-connect + ${streamPiTwitchChatConnectVersion} + + + + --- /dev/null +++ b/twitch/add-stream-marker/src/main/java/addstreammarker/AddStreamMarkerAction.java @@ -0,0 +1,89 @@ +package addstreammarker; + +import com.gikk.twirk.Twirk; +import com.gikk.twirk.TwirkBuilder; +import com.stream_pi.action_api.actionproperty.property.Property; +import com.stream_pi.action_api.actionproperty.property.Type; +import com.stream_pi.action_api.normalaction.NormalAction; +import com.stream_pi.util.exception.StreamPiException; +import com.stream_pi.util.version.Version; +import connect.chat.TwitchChatCredentials; + +public class AddStreamMarkerAction extends NormalAction +{ + + private final String channelNameKey = "channel_name_asm"; + private final String descriptionKey = "description_asm"; + + private Twirk twirk; + + public AddStreamMarkerAction() + { + setName("Add stream marker"); + setCategory("Twitch Chat"); + setVisibilityInServerSettingsPane(false); + setAuthor("j4ckofalltrades"); + setVersion(new Version(1, 0, 0)); + setHelpLink("https://github.com/stream-pi/essentialactions#twitch-chat-integration"); + } + + @Override + public void initProperties() throws Exception + { + Property channelName = new Property(channelNameKey, Type.STRING); + channelName.setDisplayName("Channel Name"); + channelName.setDefaultValueStr("channel_name"); + channelName.setCanBeBlank(false); + + Property description = new Property(descriptionKey, Type.STRING); + description.setDisplayName("Description (Optional, max 140 chars)"); + + addClientProperties(channelName, description); + } + + @Override + public void initAction() throws Exception + { + + } + + @Override + public void onActionClicked() throws Exception + { + final TwitchChatCredentials.ChatCredentials credentials = TwitchChatCredentials.getCredentials(); + credentials.ensureCredentialsInitialized(); + + final String channel = getClientProperties().getSingleProperty(channelNameKey).getStringValue(); + final String description = getClientProperties().getSingleProperty(descriptionKey).getStringValue(); + + try + { + twirk = new TwirkBuilder(channel, credentials.getNickname(), credentials.getOauthToken()).build(); + twirk.connect(); + + if (description != null && !description.isEmpty()) { + twirk.channelMessage(String.format("/marker %s", description)); + } else { + twirk.channelMessage("/marker"); + } + } catch (Exception ex) + { + throw new StreamPiException( + "Failed to add marker to stream", "Could not add stream marker, please try again." + ); + } + } + + @Override + public void onShutDown() throws Exception + { + if (twirk != null) { + try + { + twirk.disconnect(); + } catch (Exception ex) { + throw new StreamPiException("Twitch connection error", "Please try again."); + } + } + } +} --- /dev/null +++ b/twitch/add-stream-marker/src/main/java/module-info.java @@ -0,0 +1,9 @@ +module com.stream_pi.twitch.addstreammarkeraction { + requires com.stream_pi.util; + requires com.stream_pi.action_api; + + requires com.stream_pi.twitchchatconnectaction; + requires Java.Twirk; + + provides com.stream_pi.action_api.normalaction.NormalAction with addstreammarker.AddStreamMarkerAction; +} --- /dev/null +++ b/twitch/clear-chat/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + com.stream-pi + twitch-clear-chat + 1.0.0 + + + 11 + 11 + 1.0.0 + 1.0.0 + 1.0.0 + 0.6.3 + + + + + jitpack.io + https://jitpack.io + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + test-jar + package + + test-jar + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 11 + + + + + + + + com.stream-pi + util + ${streamPiUtilVersion} + + + + com.stream-pi + action-api + ${streamPiActionApiVersion} + + + + com.github.gikkman + Java-Twirk + ${javaTwirkVersion} + + + + com.stream-pi + twitch-chat-connect + ${streamPiTwitchChatConnectVersion} + + + + --- /dev/null +++ b/twitch/clear-chat/src/main/java/clearchat/ClearChatAction.java @@ -0,0 +1,75 @@ +package clearchat; + +import com.gikk.twirk.Twirk; +import com.gikk.twirk.TwirkBuilder; +import com.stream_pi.action_api.actionproperty.property.Property; +import com.stream_pi.action_api.actionproperty.property.Type; +import com.stream_pi.action_api.normalaction.NormalAction; +import com.stream_pi.util.exception.StreamPiException; +import com.stream_pi.util.version.Version; +import connect.chat.TwitchChatCredentials; + +public class ClearChatAction extends NormalAction +{ + + private final String channelNameKey = "channel_name_cc"; + + private Twirk twirk; + + @Override + public void initProperties() throws Exception + { + setName("Clear Chat"); + setCategory("Twitch Chat"); + setVisibilityInServerSettingsPane(false); + setAuthor("j4ckofalltrades"); + setVersion(new Version(1, 0, 0)); + setHelpLink("https://github.com/stream-pi/essentialactions#twitch-chat-integration"); + } + + @Override + public void initAction() throws Exception + { + Property channelName = new Property(channelNameKey, Type.STRING); + channelName.setDisplayName("Channel Name"); + channelName.setDefaultValueStr("channel_name"); + channelName.setCanBeBlank(false); + + addClientProperties(channelName); + } + + @Override + public void onActionClicked() throws Exception + { + final TwitchChatCredentials.ChatCredentials credentials = TwitchChatCredentials.getCredentials(); + credentials.ensureCredentialsInitialized(); + + final String channel = getClientProperties().getSingleProperty(channelNameKey).getStringValue(); + + try + { + twirk = new TwirkBuilder(channel, credentials.getNickname(), credentials.getOauthToken()).build(); + twirk.connect(); + twirk.channelMessage("/clear"); + } catch (Exception ex) + { + throw new StreamPiException( + "Failed to clear channel chat", + String.format("Could not clear chat for '%s' channel, please try again.", channel) + ); + } + } + + @Override + public void onShutDown() throws Exception + { + if (twirk != null) { + try + { + twirk.disconnect(); + } catch (Exception ex) { + throw new StreamPiException("Twitch Connection error", "Please try again."); + } + } + } +} --- /dev/null +++ b/twitch/clear-chat/src/main/java/module-info.java @@ -0,0 +1,9 @@ +module com.stream_pi.twitch.clearchataction { + requires com.stream_pi.util; + requires com.stream_pi.action_api; + + requires com.stream_pi.twitchchatconnectaction; + requires Java.Twirk; + + provides com.stream_pi.action_api.normalaction.NormalAction with clearchat.ClearChatAction; +} --- /dev/null +++ b/twitch/host-channel/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + com.stream-pi + twitch-host-channel + 1.0.0 + + + 11 + 11 + 1.0.0 + 1.0.0 + 1.0.0 + 0.6.3 + + + + + jitpack.io + https://jitpack.io + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + test-jar + package + + test-jar + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 11 + + + + + + + + com.stream-pi + util + ${streamPiUtilVersion} + + + + com.stream-pi + action-api + ${streamPiActionApiVersion} + + + + com.github.gikkman + Java-Twirk + ${javaTwirkVersion} + + + + com.stream-pi + twitch-chat-connect + ${streamPiTwitchChatConnectVersion} + + + + --- /dev/null +++ b/twitch/host-channel/src/main/java/hostchannel/HostChannelAction.java @@ -0,0 +1,86 @@ +package hostchannel; + +import com.gikk.twirk.Twirk; +import com.gikk.twirk.TwirkBuilder; +import com.stream_pi.action_api.actionproperty.property.Property; +import com.stream_pi.action_api.actionproperty.property.Type; +import com.stream_pi.action_api.normalaction.NormalAction; +import com.stream_pi.util.exception.StreamPiException; +import com.stream_pi.util.version.Version; +import connect.chat.TwitchChatCredentials; + +public class HostChannelAction extends NormalAction +{ + + private final String channelKey = "channel_hc"; + private final String channelToHostKey = "channel_to_host_hc"; + + private Twirk twirk; + + public HostChannelAction() + { + setName("Host Channel"); + setCategory("Twitch Chat"); + setVisibilityInServerSettingsPane(false); + setAuthor("j4ckofalltrades"); + setVersion(new Version(1, 0, 0)); + setHelpLink("https://github.com/stream-pi/essentialactions#twitch-chat-integration"); + } + + @Override + public void initProperties() throws Exception + { + Property channel = new Property(channelKey, Type.STRING); + channel.setDisplayName("Channel"); + channel.setDefaultValueStr("channel"); + channel.setCanBeBlank(false); + + Property channelToHost = new Property(channelToHostKey, Type.STRING); + channelToHost.setDisplayName("Channel to host"); + channelToHost.setDefaultValueStr("channel_to_host"); + channelToHost.setCanBeBlank(false); + + addClientProperties(channel, channelToHost); + } + + @Override + public void initAction() throws Exception + { + + } + + @Override + public void onActionClicked() throws Exception + { + final TwitchChatCredentials.ChatCredentials credentials = TwitchChatCredentials.getCredentials(); + credentials.ensureCredentialsInitialized(); + + final String channel = getClientProperties().getSingleProperty(channelKey).getStringValue(); + final String channelToHost = getClientProperties().getSingleProperty(channelToHostKey).getStringValue(); + + try + { + twirk = new TwirkBuilder(channel, credentials.getNickname(), credentials.getOauthToken()).build(); + twirk.connect(); + twirk.channelMessage(String.format("/host %s", channelToHost)); + } catch (Exception ex) + { + throw new StreamPiException( + "Failed to host channel", + String.format("Could not host channel '%s', please try again.", channelToHost)); + } + } + + @Override + public void onShutDown() throws Exception + { + if (twirk != null) { + try + { + twirk.disconnect(); + } catch (Exception ex) { + throw new StreamPiException("Twitch connection error", "Please try again."); + } + } + } +} --- /dev/null +++ b/twitch/host-channel/src/main/java/module-info.java @@ -0,0 +1,9 @@ +module com.stream_pi.twitch.hostchannelaction { + requires com.stream_pi.util; + requires com.stream_pi.action_api; + + requires com.stream_pi.twitchchatconnectaction; + requires Java.Twirk; + + provides com.stream_pi.action_api.normalaction.NormalAction with hostchannel.HostChannelAction; +} --- /dev/null +++ b/twitch/raid-channel/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + com.stream-pi + twitch-raid-channel + 1.0.0 + + + 11 + 11 + 1.0.0 + 1.0.0 + 1.0.0 + 0.6.3 + + + + + jitpack.io + https://jitpack.io + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + test-jar + package + + test-jar + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 11 + + + + + + + + com.stream-pi + util + ${streamPiUtilVersion} + + + + com.stream-pi + action-api + ${streamPiActionApiVersion} + + + + com.github.gikkman + Java-Twirk + ${javaTwirkVersion} + + + + com.stream-pi + twitch-chat-connect + ${streamPiTwitchChatConnectVersion} + + + + --- /dev/null +++ b/twitch/raid-channel/src/main/java/module-info.java @@ -0,0 +1,9 @@ +module com.stream_pi.twitch.raidchannelaction { + requires com.stream_pi.util; + requires com.stream_pi.action_api; + + requires com.stream_pi.twitchchatconnectaction; + requires Java.Twirk; + + provides com.stream_pi.action_api.normalaction.NormalAction with raidchannel.RaidChannelAction; +} --- /dev/null +++ b/twitch/raid-channel/src/main/java/raidchannel/RaidChannelAction.java @@ -0,0 +1,86 @@ +package raidchannel; + +import com.gikk.twirk.Twirk; +import com.gikk.twirk.TwirkBuilder; +import com.stream_pi.action_api.actionproperty.property.Property; +import com.stream_pi.action_api.actionproperty.property.Type; +import com.stream_pi.action_api.normalaction.NormalAction; +import com.stream_pi.util.exception.StreamPiException; +import com.stream_pi.util.version.Version; +import connect.chat.TwitchChatCredentials; + +public class RaidChannelAction extends NormalAction +{ + + private final String channelKey = "channel_rc"; + private final String channelToRaidKey = "channel_to_raid_rc"; + + private Twirk twirk; + + public RaidChannelAction() + { + setName("Raid Channel"); + setCategory("Twitch Chat"); + setVisibilityInServerSettingsPane(false); + setAuthor("j4ckofalltrades"); + setVersion(new Version(1, 0, 0)); + setHelpLink("https://github.com/stream-pi/essentialactions#twitch-chat-integration"); + } + + @Override + public void initProperties() throws Exception + { + Property channel = new Property(channelKey, Type.STRING); + channel.setDisplayName("Channel"); + channel.setDefaultValueStr("channel"); + channel.setCanBeBlank(false); + + Property channelToRaid = new Property(channelToRaidKey, Type.STRING); + channelToRaid.setDisplayName("Channel to raid"); + channelToRaid.setDefaultValueStr("channel_to_raid"); + channelToRaid.setCanBeBlank(false); + + addClientProperties(channel, channelToRaid); + } + + @Override + public void initAction() throws Exception + { + + } + + @Override + public void onActionClicked() throws Exception + { + final TwitchChatCredentials.ChatCredentials credentials = TwitchChatCredentials.getCredentials(); + credentials.ensureCredentialsInitialized(); + + final String channel = getClientProperties().getSingleProperty(channelKey).getStringValue(); + final String channelToRaid = getClientProperties().getSingleProperty(channelToRaidKey).getStringValue(); + + try + { + twirk = new TwirkBuilder(channel, credentials.getNickname(), credentials.getOauthToken()).build(); + twirk.connect(); + twirk.channelMessage(String.format("/raid %s", channelToRaid)); + } catch (Exception ex) + { + throw new StreamPiException( + "Failed to raid channel", + String.format("Could not raid channel '%s', please try again.", channelToRaid)); + } + } + + @Override + public void onShutDown() throws Exception + { + if (twirk != null) { + try + { + twirk.disconnect(); + } catch (Exception ex) { + throw new StreamPiException("Twitch connection error", "Please try again."); + } + } + } +} --- 'a/twitch/send-channel-msg/pom.xml' +++ b/twitch/send-channel-msg/pom.xml @@ -11,8 +11,8 @@ 11 11 - 1.0.0-SNAPSHOT - 1.0.0-SNAPSHOT + 1.0.0 + 1.0.0 1.0.0 0.6.3 --- 'a/twitch/send-channel-msg/src/main/java/module-info.java' +++ b/twitch/send-channel-msg/src/main/java/module-info.java @@ -6,4 +6,4 @@ module com.stream_pi.twitch.sendchannelm requires Java.Twirk; provides com.stream_pi.action_api.normalaction.NormalAction with sendchannelmsg.SendChannelMessageAction; -} \ No newline at end of file +} --- 'a/twitch/send-channel-msg/src/main/java/sendchannelmsg/SendChannelMessageAction.java' +++ b/twitch/send-channel-msg/src/main/java/sendchannelmsg/SendChannelMessageAction.java @@ -9,14 +9,11 @@ import com.stream_pi.util.exception.Stre import com.stream_pi.util.version.Version; import connect.chat.TwitchChatCredentials; -import static connect.chat.TwitchChatCredentials.DEFAULT_TWITCH_NICKNAME; -import static connect.chat.TwitchChatCredentials.DEFAULT_TWITCH_TOKEN; - public class SendChannelMessageAction extends NormalAction { - private static final String TWITCH_CHANNEL_NAME_KEY = "twitch_channel_name"; - private static final String TWITCH_CHANNEL_MSG_KEY = "twitch_channel_msg"; + private final String channelNameKey = "channel_name_scm"; + private final String channelMsgKey = "channel_msg_scm"; private Twirk twirk; @@ -27,18 +24,18 @@ public class SendChannelMessageAction ex setVisibilityInServerSettingsPane(false); setAuthor("j4ckofalltrades"); setVersion(new Version(1, 0, 0)); - setHelpLink("https://github.com/stream-pi/essentialactions"); + setHelpLink("https://github.com/stream-pi/essentialactions#twitch-chat-integration"); } @Override public void initProperties() throws Exception { - Property channelName = new Property(TWITCH_CHANNEL_NAME_KEY, Type.STRING); + Property channelName = new Property(channelNameKey, Type.STRING); channelName.setDisplayName("Channel Name"); channelName.setDefaultValueStr("channel_name"); channelName.setCanBeBlank(false); - Property channelMessage = new Property(TWITCH_CHANNEL_MSG_KEY, Type.STRING); + Property channelMessage = new Property(channelMsgKey, Type.STRING); channelMessage.setDisplayName("Message"); channelMessage.setDefaultValueStr("channel_msg"); channelMessage.setCanBeBlank(false); @@ -55,22 +52,15 @@ public class SendChannelMessageAction ex @Override public void onActionClicked() throws Exception { - TwitchChatCredentials.ChatCredentials credentials = TwitchChatCredentials.getCredentials(); - if (!isChatCredentialsInitialized(credentials)) - { - throw new StreamPiException("Twitch Chat uninitialized.","Please check that the Twitch Chat plugin configuration is correct."); - } + final TwitchChatCredentials.ChatCredentials credentials = TwitchChatCredentials.getCredentials(); + credentials.ensureCredentialsInitialized(); - final String channel = getClientProperties().getSingleProperty(TWITCH_CHANNEL_NAME_KEY).getStringValue(); - final String message = getClientProperties().getSingleProperty(TWITCH_CHANNEL_MSG_KEY).getStringValue(); + final String channel = getClientProperties().getSingleProperty(channelNameKey).getStringValue(); + final String message = getClientProperties().getSingleProperty(channelMsgKey).getStringValue(); try { - twirk = new TwirkBuilder( - getClientProperties().getSingleProperty(TWITCH_CHANNEL_NAME_KEY).getStringValue(), - credentials.getNickname(), - credentials.getOauthToken()) - .build(); + twirk = new TwirkBuilder(channel, credentials.getNickname(), credentials.getOauthToken()).build(); twirk.connect(); twirk.channelMessage(message); } catch (Exception ex) @@ -83,31 +73,16 @@ public class SendChannelMessageAction ex } } - private boolean isChatCredentialsInitialized(TwitchChatCredentials.ChatCredentials credentials) - { - if (credentials == null) - { - return false; - } - - final String twitchNickname = credentials.getNickname(); - boolean isNicknameInitialized = twitchNickname != null && - !twitchNickname.isEmpty() && - !twitchNickname.equalsIgnoreCase(DEFAULT_TWITCH_NICKNAME); - - final String twitchChatOauthToken = credentials.getOauthToken(); - boolean isTokenInitialized = twitchChatOauthToken != null && - !twitchChatOauthToken.isEmpty() && - !twitchChatOauthToken.equalsIgnoreCase(DEFAULT_TWITCH_TOKEN); - - return isNicknameInitialized && isTokenInitialized; - } - @Override public void onShutDown() throws Exception { - twirk.close(); + if (twirk != null) { + try + { + twirk.disconnect(); + } catch (Exception ex) { + throw new StreamPiException("Twitch connection error", "Please try again."); + } + } } } - - --- /dev/null +++ b/twitch/set-color/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + com.stream-pi + twitch-set-color + 1.0.0 + + + 11 + 11 + 1.0.0 + 1.0.0 + 1.0.0 + 0.6.3 + + + + + jitpack.io + https://jitpack.io + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + test-jar + package + + test-jar + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 11 + + + + + + + + com.stream-pi + util + ${streamPiUtilVersion} + + + + com.stream-pi + action-api + ${streamPiActionApiVersion} + + + + com.github.gikkman + Java-Twirk + ${javaTwirkVersion} + + + + com.stream-pi + twitch-chat-connect + ${streamPiTwitchChatConnectVersion} + + + + --- /dev/null +++ b/twitch/set-color/src/main/java/module-info.java @@ -0,0 +1,9 @@ +module com.stream_pi.twitch.setcoloraction { + requires com.stream_pi.util; + requires com.stream_pi.action_api; + + requires com.stream_pi.twitchchatconnectaction; + requires Java.Twirk; + + provides com.stream_pi.action_api.normalaction.NormalAction with setcolor.SetColorAction; +} --- /dev/null +++ b/twitch/set-color/src/main/java/setcolor/SetColorAction.java @@ -0,0 +1,83 @@ +package setcolor; + +import com.gikk.twirk.Twirk; +import com.gikk.twirk.TwirkBuilder; +import com.stream_pi.action_api.actionproperty.property.Property; +import com.stream_pi.action_api.actionproperty.property.Type; +import com.stream_pi.action_api.normalaction.NormalAction; +import com.stream_pi.util.exception.StreamPiException; +import com.stream_pi.util.version.Version; +import connect.chat.TwitchChatCredentials; + +public class SetColorAction extends NormalAction +{ + + private final String channelNameKey = "channel_name_sc"; + private final String usernameColorKey = "username_color_sc"; + + private Twirk twirk; + + @Override + public void initProperties() throws Exception + { + setName("Set Color"); + setCategory("Twitch Chat"); + setVisibilityInServerSettingsPane(false); + setAuthor("j4ckofalltrades"); + setVersion(new Version(1, 0, 0)); + setHelpLink("https://github.com/stream-pi/essentialactions#twitch-chat-integration"); + } + + @Override + public void initAction() throws Exception + { + Property channelName = new Property(channelNameKey, Type.STRING); + channelName.setDisplayName("Channel Name"); + channelName.setDefaultValueStr("channel_name"); + channelName.setCanBeBlank(false); + + Property usernameColor = new Property(usernameColorKey, Type.STRING); + usernameColor.setDisplayName("Color"); + usernameColor.setDefaultValueStr("color"); + usernameColor.setCanBeBlank(false); + + addClientProperties(channelName, usernameColor); + } + + @Override + public void onActionClicked() throws Exception + { + final TwitchChatCredentials.ChatCredentials credentials = TwitchChatCredentials.getCredentials(); + credentials.ensureCredentialsInitialized(); + + final String channel = getClientProperties().getSingleProperty(channelNameKey).getStringValue(); + final String color = getClientProperties().getSingleProperty(usernameColorKey).getStringValue(); + + try + { + twirk = new TwirkBuilder(channel, credentials.getNickname(), credentials.getOauthToken()).build(); + twirk.connect(); + twirk.channelMessage(String.format("/color %s", color)); + } catch (Exception ex) + { + throw new StreamPiException( + "Failed to change username color", + String.format("Could not change username color to '%s' for '%s' channel, please try again.", + color, channel) + ); + } + } + + @Override + public void onShutDown() throws Exception + { + if (twirk != null) { + try + { + twirk.disconnect(); + } catch (Exception ex) { + throw new StreamPiException("Twitch connection error", "Please try again."); + } + } + } +} --- /dev/null +++ b/twitch/start-commercial/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + com.stream-pi + twitch-start-commercial + 1.0.0 + + + 11 + 11 + 1.0.0 + 1.0.0 + 1.0.0 + 0.6.3 + + + + + jitpack.io + https://jitpack.io + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + test-jar + package + + test-jar + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 11 + + + + + + + + com.stream-pi + util + ${streamPiUtilVersion} + + + + com.stream-pi + action-api + ${streamPiActionApiVersion} + + + + com.github.gikkman + Java-Twirk + ${javaTwirkVersion} + + + + com.stream-pi + twitch-chat-connect + ${streamPiTwitchChatConnectVersion} + + + + --- /dev/null +++ b/twitch/start-commercial/src/main/java/module-info.java @@ -0,0 +1,9 @@ +module com.stream_pi.twitch.startcommercialaction { + requires com.stream_pi.util; + requires com.stream_pi.action_api; + + requires com.stream_pi.twitchchatconnectaction; + requires Java.Twirk; + + provides com.stream_pi.action_api.normalaction.NormalAction with startcommercial.StartCommercialAction; +} --- /dev/null +++ b/twitch/start-commercial/src/main/java/startcommercial/StartCommercialAction.java @@ -0,0 +1,92 @@ +package startcommercial; + +import com.gikk.twirk.Twirk; +import com.gikk.twirk.TwirkBuilder; +import com.stream_pi.action_api.actionproperty.property.Property; +import com.stream_pi.action_api.actionproperty.property.Type; +import com.stream_pi.action_api.normalaction.NormalAction; +import com.stream_pi.util.exception.StreamPiException; +import com.stream_pi.util.version.Version; +import connect.chat.TwitchChatCredentials; + +import java.util.List; + +public class StartCommercialAction extends NormalAction +{ + + private final String channelNameKey = "channel_name_sca"; + private final String durationKey = "duration_sca"; + + private Twirk twirk; + + public StartCommercialAction() + { + setName("Start commercial"); + setCategory("Twitch Chat"); + setVisibilityInServerSettingsPane(false); + setAuthor("j4ckofalltrades"); + setVersion(new Version(1, 0, 0)); + setHelpLink("https://github.com/stream-pi/essentialactions#twitch-chat-integration"); + } + + @Override + public void initProperties() throws Exception + { + Property channelName = new Property(channelNameKey, Type.STRING); + channelName.setDisplayName("Channel Name"); + channelName.setDefaultValueStr("channel_name"); + channelName.setCanBeBlank(false); + + Property duration = new Property(durationKey, Type.LIST); + duration.setDisplayName("Duration"); + duration.setListValue(List.of( + String.valueOf(30), + String.valueOf(60), + String.valueOf(90), + String.valueOf(120), + String.valueOf(150), + String.valueOf(180))); + + addClientProperties(channelName, duration); + } + + @Override + public void initAction() throws Exception + { + + } + + @Override + public void onActionClicked() throws Exception + { + final TwitchChatCredentials.ChatCredentials credentials = TwitchChatCredentials.getCredentials(); + credentials.ensureCredentialsInitialized(); + + final String channel = getClientProperties().getSingleProperty(channelNameKey).getStringValue(); + final String duration = getClientProperties().getSingleProperty(durationKey).getStringValue(); + + try + { + twirk = new TwirkBuilder(channel, credentials.getNickname(), credentials.getOauthToken()).build(); + twirk.connect(); + twirk.channelMessage(String.format("/commercial %s", duration)); + } catch (Exception ex) + { + throw new StreamPiException( + "Failed to start commercial", "Could not start commercial, please try again."); + } + } + + @Override + public void onShutDown() throws Exception + { + if (twirk != null) { + try + { + twirk.disconnect(); + } catch (Exception ex) { + throw new StreamPiException("Twitch connection error", "Please try again."); + } + } + } +} --- 'a/twitch/twitch-chat-connect/src/main/java/connect/TwitchChatConnectAction.java' +++ b/twitch/twitch-chat-connect/src/main/java/connect/TwitchChatConnectAction.java @@ -13,8 +13,8 @@ import javafx.scene.control.Button; public class TwitchChatConnectAction extends NormalAction { - private static final String TWITCH_ACCESS_TOKEN_KEY = "twitch_access_token"; - private static final String TWITCH_NICKNAME_KEY = "twitch_nickname"; + private static final String ACCESS_TOKEN_KEY = "twitch_chat_access_token"; + private static final String NICKNAME_KEY = "twitch_chat_nickname"; private final Button clearCredentialsBtn; @@ -25,7 +25,7 @@ public class TwitchChatConnectAction ext setVisibilityInPluginsPane(false); setAuthor("j4ckofalltrades"); setVersion(new Version(1, 0, 0)); - setHelpLink("https://github.com/Stream-Pi/essentialactions"); + setHelpLink("https://github.com/stream-pi/essentialactions#twitch-chat-integration"); clearCredentialsBtn = new Button("Clear Twitch chat credentials"); onClearCredentials(); @@ -35,10 +35,10 @@ public class TwitchChatConnectAction ext @Override public void initProperties() { - Property twitchNicknameProp = new Property(TWITCH_NICKNAME_KEY, Type.STRING); + Property twitchNicknameProp = new Property(NICKNAME_KEY, Type.STRING); twitchNicknameProp.setDisplayName("Twitch Username"); - Property twitchAccessTokenProp = new Property(TWITCH_ACCESS_TOKEN_KEY, Type.STRING); + Property twitchAccessTokenProp = new Property(ACCESS_TOKEN_KEY, Type.STRING); twitchAccessTokenProp.setDisplayName("Access Token"); addServerProperties(twitchNicknameProp, twitchAccessTokenProp); @@ -51,13 +51,13 @@ public class TwitchChatConnectAction ext TwitchChatCredentials.setCredentials( new TwitchChatCredentials.ChatCredentials() - .setOauthToken(getServerProperties().getSingleProperty(TWITCH_ACCESS_TOKEN_KEY).getStringValue()) - .setNickname(getServerProperties().getSingleProperty(TWITCH_NICKNAME_KEY).getStringValue())); + .setOauthToken(getServerProperties().getSingleProperty(ACCESS_TOKEN_KEY).getStringValue()) + .setNickname(getServerProperties().getSingleProperty(NICKNAME_KEY).getStringValue())); } private boolean isEmptyCredentials() throws MinorException { - final String twitchNickname = getServerProperties().getSingleProperty(TWITCH_NICKNAME_KEY).getStringValue(); - final String twitchChatOauthToken = getServerProperties().getSingleProperty(TWITCH_ACCESS_TOKEN_KEY).getStringValue(); + final String twitchNickname = getServerProperties().getSingleProperty(NICKNAME_KEY).getStringValue(); + final String twitchChatOauthToken = getServerProperties().getSingleProperty(ACCESS_TOKEN_KEY).getStringValue(); return (twitchNickname == null || twitchNickname.isEmpty()) && (twitchChatOauthToken == null || twitchChatOauthToken.isEmpty()); } @@ -68,8 +68,8 @@ public class TwitchChatConnectAction ext { try { - getServerProperties().getSingleProperty(TWITCH_ACCESS_TOKEN_KEY).setStringValue(""); - getServerProperties().getSingleProperty(TWITCH_NICKNAME_KEY).setStringValue(""); + getServerProperties().getSingleProperty(ACCESS_TOKEN_KEY).setStringValue(""); + getServerProperties().getSingleProperty(NICKNAME_KEY).setStringValue(""); saveServerProperties(); new StreamPiAlert( "Twitch chat credentials cleared", --- 'a/twitch/twitch-chat-connect/src/main/java/connect/chat/TwitchChatCredentials.java' +++ b/twitch/twitch-chat-connect/src/main/java/connect/chat/TwitchChatCredentials.java @@ -1,9 +1,9 @@ package connect.chat; +import com.stream_pi.util.exception.StreamPiException; + public final class TwitchChatCredentials { - public static final String DEFAULT_TWITCH_NICKNAME = "twitch_username"; - public static final String DEFAULT_TWITCH_TOKEN = "twitch_token"; private static ChatCredentials credentials; @@ -22,6 +22,20 @@ public final class TwitchChatCredentials String nickname; String oauthToken; + public void ensureCredentialsInitialized() throws Exception { + final String twitchNickname = nickname; + boolean isNicknameInitialized = twitchNickname != null && !twitchNickname.isEmpty(); + + final String twitchChatOauthToken = oauthToken; + boolean isTokenInitialized = twitchChatOauthToken != null && !twitchChatOauthToken.isEmpty(); + + if (!isNicknameInitialized && !isTokenInitialized) { + throw new StreamPiException( + "Twitch Chat config uninitialized.", + "Please check that the Twitch Chat plugin configuration is correct."); + } + } + public String getNickname() { return nickname; --- 'a/twitch/twitch-chat-connect/src/main/java/module-info.java' +++ b/twitch/twitch-chat-connect/src/main/java/module-info.java @@ -8,4 +8,4 @@ module com.stream_pi.twitchchatconnectac exports connect.chat; provides com.stream_pi.action_api.normalaction.NormalAction with connect.TwitchChatConnectAction; -} \ No newline at end of file +} --- /dev/null +++ b/twitch/unhost/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + com.stream-pi + twitch-unhost + 1.0.0 + + + 11 + 11 + 1.0.0 + 1.0.0 + 1.0.0 + 0.6.3 + + + + + jitpack.io + https://jitpack.io + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + test-jar + package + + test-jar + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 11 + + + + + + + + com.stream-pi + util + ${streamPiUtilVersion} + + + + com.stream-pi + action-api + ${streamPiActionApiVersion} + + + + com.github.gikkman + Java-Twirk + ${javaTwirkVersion} + + + + com.stream-pi + twitch-chat-connect + ${streamPiTwitchChatConnectVersion} + + + + --- /dev/null +++ b/twitch/unhost/src/main/java/module-info.java @@ -0,0 +1,9 @@ +module com.stream_pi.twitch.unhostaction { + requires com.stream_pi.util; + requires com.stream_pi.action_api; + + requires com.stream_pi.twitchchatconnectaction; + requires Java.Twirk; + + provides com.stream_pi.action_api.normalaction.NormalAction with unhost.UnhostAction; +} --- /dev/null +++ b/twitch/unhost/src/main/java/unhost/UnhostAction.java @@ -0,0 +1,79 @@ +package unhost; + +import com.gikk.twirk.Twirk; +import com.gikk.twirk.TwirkBuilder; +import com.stream_pi.action_api.actionproperty.property.Property; +import com.stream_pi.action_api.actionproperty.property.Type; +import com.stream_pi.action_api.normalaction.NormalAction; +import com.stream_pi.util.exception.StreamPiException; +import com.stream_pi.util.version.Version; +import connect.chat.TwitchChatCredentials; + +public class UnhostAction extends NormalAction +{ + + private final String channelNameKey = "channel_name_uh"; + + private Twirk twirk; + + public UnhostAction() + { + setName("Unhost"); + setCategory("Twitch Chat"); + setVisibilityInServerSettingsPane(false); + setAuthor("j4ckofalltrades"); + setVersion(new Version(1, 0, 0)); + setHelpLink("https://github.com/stream-pi/essentialactions#twitch-chat-integration"); + } + + @Override + public void initProperties() throws Exception + { + Property channel = new Property(channelNameKey, Type.STRING); + channel.setDisplayName("Channel"); + channel.setDefaultValueStr("channel_name"); + channel.setCanBeBlank(false); + + addClientProperties(channel); + } + + @Override + public void initAction() throws Exception + { + + } + + @Override + public void onActionClicked() throws Exception + { + final TwitchChatCredentials.ChatCredentials credentials = TwitchChatCredentials.getCredentials(); + credentials.ensureCredentialsInitialized(); + + final String channel = getClientProperties().getSingleProperty(channelNameKey).getStringValue(); + + try + { + twirk = new TwirkBuilder(channel, credentials.getNickname(), credentials.getOauthToken()).build(); + twirk.connect(); + twirk.channelMessage("/unhost"); + } catch (Exception ex) + { + throw new StreamPiException( + "Failed to cancel channel hosting", + "Could not cancel channel hosting, please try again."); + } + } + + @Override + public void onShutDown() throws Exception + { + if (twirk != null) { + try + { + twirk.disconnect(); + } catch (Exception ex) { + throw new StreamPiException("Twitch connection error", "Please try again."); + } + } + } +} --- /dev/null +++ b/twitch/unraid/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + com.stream-pi + twitch-unraid + 1.0.0 + + + 11 + 11 + 1.0.0 + 1.0.0 + 1.0.0 + 0.6.3 + + + + + jitpack.io + https://jitpack.io + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + test-jar + package + + test-jar + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 11 + + + + + + + + com.stream-pi + util + ${streamPiUtilVersion} + + + + com.stream-pi + action-api + ${streamPiActionApiVersion} + + + + com.github.gikkman + Java-Twirk + ${javaTwirkVersion} + + + + com.stream-pi + twitch-chat-connect + ${streamPiTwitchChatConnectVersion} + + + + --- /dev/null +++ b/twitch/unraid/src/main/java/module-info.java @@ -0,0 +1,9 @@ +module com.stream_pi.twitch.unraidaction { + requires com.stream_pi.util; + requires com.stream_pi.action_api; + + requires com.stream_pi.twitchchatconnectaction; + requires Java.Twirk; + + provides com.stream_pi.action_api.normalaction.NormalAction with unraid.UnraidAction; +} --- /dev/null +++ b/twitch/unraid/src/main/java/unraid/UnraidAction.java @@ -0,0 +1,79 @@ +package unraid; + +import com.gikk.twirk.Twirk; +import com.gikk.twirk.TwirkBuilder; +import com.stream_pi.action_api.actionproperty.property.Property; +import com.stream_pi.action_api.actionproperty.property.Type; +import com.stream_pi.action_api.normalaction.NormalAction; +import com.stream_pi.util.exception.StreamPiException; +import com.stream_pi.util.version.Version; +import connect.chat.TwitchChatCredentials; + +public class UnraidAction extends NormalAction +{ + + private final String channelNameKey = "channel_name_ur"; + + private Twirk twirk; + + public UnraidAction() + { + setName("Unraid"); + setCategory("Twitch Chat"); + setVisibilityInServerSettingsPane(false); + setAuthor("j4ckofalltrades"); + setVersion(new Version(1, 0, 0)); + setHelpLink("https://github.com/stream-pi/essentialactions#twitch-chat-integration"); + } + + @Override + public void initProperties() throws Exception + { + Property channel = new Property(channelNameKey, Type.STRING); + channel.setDisplayName("Channel"); + channel.setDefaultValueStr("channel_name"); + channel.setCanBeBlank(false); + + addClientProperties(channel); + } + + @Override + public void initAction() throws Exception + { + + } + + @Override + public void onActionClicked() throws Exception + { + final TwitchChatCredentials.ChatCredentials credentials = TwitchChatCredentials.getCredentials(); + credentials.ensureCredentialsInitialized(); + + final String channel = getClientProperties().getSingleProperty(channelNameKey).getStringValue(); + + try + { + twirk = new TwirkBuilder(channel, credentials.getNickname(), credentials.getOauthToken()).build(); + twirk.connect(); + twirk.channelMessage("/unraid"); + } catch (Exception ex) + { + throw new StreamPiException( + "Failed to cancel channel raid", + "Could not cancel channel raid, please try again."); + } + } + + @Override + public void onShutDown() throws Exception + { + if (twirk != null) { + try + { + twirk.disconnect(); + } catch (Exception ex) { + throw new StreamPiException("Twitch connection error", "Please try again."); + } + } + } +} --- /dev/null +++ b/twitch/whisper/pom.xml @@ -0,0 +1,81 @@ + + + 4.0.0 + + com.stream-pi + twitch-whisper + 1.0.0 + + + 11 + 11 + 1.0.0 + 1.0.0 + 1.0.0 + 0.6.3 + + + + + jitpack.io + https://jitpack.io + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.0 + + + test-jar + package + + test-jar + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 11 + + + + + + + + com.stream-pi + util + ${streamPiUtilVersion} + + + + com.stream-pi + action-api + ${streamPiActionApiVersion} + + + + com.github.gikkman + Java-Twirk + ${javaTwirkVersion} + + + + com.stream-pi + twitch-chat-connect + ${streamPiTwitchChatConnectVersion} + + + + --- /dev/null +++ b/twitch/whisper/src/main/java/module-info.java @@ -0,0 +1,9 @@ +module com.stream_pi.twitch.whisperaction { + requires com.stream_pi.util; + requires com.stream_pi.action_api; + + requires com.stream_pi.twitchchatconnectaction; + requires Java.Twirk; + + provides com.stream_pi.action_api.normalaction.NormalAction with whisper.WhisperAction; +} --- /dev/null +++ b/twitch/whisper/src/main/java/whisper/WhisperAction.java @@ -0,0 +1,88 @@ +package whisper; + +import com.gikk.twirk.Twirk; +import com.gikk.twirk.TwirkBuilder; +import com.stream_pi.action_api.actionproperty.property.Property; +import com.stream_pi.action_api.actionproperty.property.Type; +import com.stream_pi.action_api.normalaction.NormalAction; +import com.stream_pi.util.exception.StreamPiException; +import com.stream_pi.util.version.Version; +import connect.chat.TwitchChatCredentials; + +public class WhisperAction extends NormalAction +{ + + private final String usernameKey = "username_wa"; + private final String messageKey = "message_wa"; + + private Twirk twirk; + + public WhisperAction() + { + setName("Whisper"); + setCategory("Twitch Chat"); + setVisibilityInServerSettingsPane(false); + setAuthor("j4ckofalltrades"); + setVersion(new Version(1, 0, 0)); + setHelpLink("https://github.com/stream-pi/essentialactions#twitch-chat-integration"); + } + + @Override + public void initProperties() throws Exception + { + Property usernameProp = new Property(usernameKey, Type.STRING); + usernameProp.setDisplayName("Twitch Username"); + usernameProp.setDefaultValueStr("username"); + usernameProp.setCanBeBlank(false); + + Property messageProp = new Property(messageKey, Type.STRING); + messageProp.setDisplayName("Message"); + messageProp.setDefaultValueStr("message"); + messageProp.setCanBeBlank(false); + + addClientProperties(usernameProp, messageProp); + } + + @Override + public void initAction() throws Exception + { + + } + + @Override + public void onActionClicked() throws Exception + { + final TwitchChatCredentials.ChatCredentials credentials = TwitchChatCredentials.getCredentials(); + credentials.ensureCredentialsInitialized(); + + final String username = getClientProperties().getSingleProperty(usernameKey).getStringValue(); + final String message = getClientProperties().getSingleProperty(messageKey).getStringValue(); + + try + { + twirk = new TwirkBuilder(username, credentials.getNickname(), credentials.getOauthToken()).build(); + twirk.connect(); + twirk.whisper(username, message); + } catch (Exception ex) + { + throw new StreamPiException( + "Failed to send message to user", + String.format("Could not send message '%s' to user '%s', please try again.", + username, message) + ); + } + } + + @Override + public void onShutDown() throws Exception + { + if (twirk != null) { + try + { + twirk.disconnect(); + } catch (Exception ex) { + throw new StreamPiException("Twitch connection error", "Please try again."); + } + } + } +}