I have a class created through a few different sources to connect, stay connected, read, and interact with a selected Twitch channel, but there seems to be no information as to how to do certain things.
One of the issues is that the names of the chatters are always in all lowercase characters. The other issue is that there doesnt seem to be any information of users. Ie are they a mod, subscriber, VIP?
While the roles parts arent that high priority for me, I want for the names to be properly capitalized.
Is there any trick that can do this?
using System;
using System.IO;
using System.Net.Sockets;
using UnityEngine;
public class TwitchConnect : MonoBehaviour
{
public static TwitchConnect instance;
public TwitchAccountData TwitchSettings = new();
public event Action<string, string> OnChatMessage;
public event Action<string> OnLoggedIn;
public event Action OnLoggedOut;
public event Action<string> OnInvalidLogin;
public bool loggedIn = false;
private TcpClient Twitch;
private StreamReader Reader;
private StreamWriter Writer;
//private const string URL = "irc.chat.twitch.tv";
private const string URL = "irc.twitch.tv";
private const int PORT = 6667;
private float PingCounter = 0;
private string saveTwitchPath = "twitchauth.json";
private void Awake()
{
DontDestroyOnLoad(gameObject);
instance = this;
saveTwitchPath = Application.persistentDataPath "/twitchauth.json";
LoadAccount();
}
public void UpdateAccount(string nUser, string nOAuth, string nChannel)
{
TwitchSettings.User = nUser;
TwitchSettings.OAuth = nOAuth;
TwitchSettings.Channel = nChannel;
}
public void ConnectToTwitch()
{
DisconnectFromTwitch();
Twitch = new TcpClient(URL, PORT);
Reader = new StreamReader(Twitch.GetStream());
Writer = new StreamWriter(Twitch.GetStream());
TwitchSettings.User = TwitchSettings.User.ToLower();
TwitchSettings.Channel = TwitchSettings.Channel.ToLower();
Writer.WriteLine("PASS " TwitchSettings.OAuth);
Writer.WriteLine("NICK " TwitchSettings.User);
Writer.WriteLine($"USER {TwitchSettings.User} 8 * :{TwitchSettings.User}");
Writer.WriteLine("JOIN #" TwitchSettings.Channel);
Writer.Flush();//initiate connection
}
public void DisconnectFromTwitch()
{
loggedIn = false;
PingCounter = 0;
Twitch?.Dispose();
Reader?.Dispose();
Writer?.Dispose();
Twitch = null;
Reader = null;
Writer = null;
OnLoggedOut?.Invoke();
}
public void SaveAccount()
{
string jsonTwitch = JsonUtility.ToJson(TwitchSettings, true);
File.WriteAllText(saveTwitchPath, jsonTwitch, System.Text.Encoding.Unicode);
Debug.LogWarning("Twitch account settings saved!");
}
public void LoadAccount()
{
//twitch saved account settings - user, oauth, channel
if (File.Exists(saveTwitchPath))
{
string jsonSettings = File.ReadAllText(saveTwitchPath, System.Text.Encoding.Unicode);
JsonUtility.FromJsonOverwrite(jsonSettings, TwitchSettings);
Debug.LogWarning("Twitch account loaded, logging in...");
ConnectToTwitch();
}
}
public void SendIrcMessage(string message)
{
Writer.WriteLine(message);
Writer.Flush();
}
public void SendChatMessage(string message)
{
Writer.WriteLine($":{TwitchSettings.User}!{TwitchSettings.User}@{TwitchSettings.User}.tmi.twitch.tv PRIVMSG #{TwitchSettings.Channel} :{message}");
Writer.Flush();
}
private void Update()
{
if (Twitch == null) return;
if (!Twitch.Connected && loggedIn)
{
ConnectToTwitch();
}
PingCounter = Time.deltaTime;
if (PingCounter > 50)
{
Writer.WriteLine("PING " URL);
Writer.Flush();
PingCounter = 0;
}
if (Twitch.Available > 0)
{
string message = Reader.ReadLine();
#if UNITY_EDITOR
Debug.Log(message);//DEBUG
#endif
if (message.Contains("PRIVMSG"))
{
int splitPoint = message.IndexOf("!");
string chatter = message[1..splitPoint];//get chatter name
splitPoint = message.IndexOf(":", 1);
string msg = message[(splitPoint 1)..];//get message only
OnChatMessage?.Invoke(chatter, msg);
}
else if (message.Contains(":Welcome, GLHF!"))//successful login
{
SaveAccount();
loggedIn = true;
OnLoggedIn?.Invoke(TwitchSettings.User);
}
else if (message.Contains(":Invalid NICK"))
{
OnInvalidLogin?.Invoke("Invalid NICK");
}
else if (message.Contains(":Improperly formatted auth"))
{
OnInvalidLogin?.Invoke("Improperly formatted auth");
}
}
}
private void OnDestroy()
{
DisconnectFromTwitch();
}
}
CodePudding user response:
For TMI - Twitch Messaging Interface to get DisplayName and Role information you need to enable some IRCv3 capabilities then updates your parser to extract the data.
Before PASS you should send
CAP REQ :twitch.tv/commands twitch.tv/tags
So,
Writer.WriteLine("PASS " TwitchSettings.OAuth);
becomes
Writer.WriteLine("CAP REQ :twitch.tv/commands twitch.tv/tags");
Writer.WriteLine("PASS " TwitchSettings.OAuth);
To enable additional data - https://dev.twitch.tv/docs/irc/capabilities
This will then add additioanl data to PRIVMSG
s sent by Twitch.
These are commonly referered to as IRCv3 Tags.
This is an example from the documentations
@badge-info=;badges=broadcaster/1;client-nonce=28e05b1c83f1e916ca1710c44b014515;color=#0000FF;display-name=foofoo;emotes=62835:0-10;first-msg=0;flags=;id=f80a19d6-e35a-4273-82d0-cd87f614e767;mod=0;room-id=713936733;subscriber=0;tmi-sent-ts=1642696567751;turbo=0;user-id=713936733;user-type= :[email protected] PRIVMSG #bar :bleedPurple
https://dev.twitch.tv/docs/irc/send-receive-messages#receiving-chat-messages
This user:
- sent the message
bleedpurple
in the channelbar
- has the
display-name
offoofoo
this will be the Capitislation of the user if any is set by the user - has the badges of
broadcaster
(version 1 of said badge)
So for VIP or moderator you would monitor for the badges of vip
or moderator
and so on for whatever roles you are looking for.
Further reading is on https://dev.twitch.tv/docs/irc/tags#privmsg-tags
Some badge examples:
Comma-separated list of chat badges in the form, <badge>/<version>. For example, admin/1. There are many possible badge values, but here are few:
admin
bits
broadcaster
moderator
subscriber
staff
turbo
You would normally poke the badges API (channel or global) for available badges nad versions of those badges.
But the salient role based badges are in this non exhuastive list.