Hello There, Guest!
View New Posts  |  View Today's Posts
[Project] Justin.tv and Twitch.tv chat client.

  • 0 Vote(s) - 0 Average


10-30-2013, 01:21 AM #1
KoBE
¯\_(ツ)_/¯
******
Global Moderators
Posts: 4,862 Threads:494 Joined: Jun 2011 Reputation: 67

Justin.tv and Twitch.tv chat client.
Alright guys, I was working on a Justin.tv application to chat with instead of using the browser. I've got the actual application needs work however the framework is pretty much done. Maybe a few things to clean up here or there.

Basically what I did was write a wrapper class that works on top of the IrcClient class found here: http://tech.reboot.pro/showthread.php?tid=1706 What I want to end up doing eventually is completely re-write the IrcClient class and add built-in multi-threading. This wrapper client (JtvClient) adds the multi-threading support that I eventually want to build in. Also, on top of that it handles the cross thread stuff so the end-user won't have to deal with it. You're welcome, you're welcome.

The JtvClient only has 4 events that the user needs to listen to.
  • UpdateUsers - Fires when the user list changes (includes Joins and Parts)
  • MesssageReceived - Fires when a message is received
  • ExceptionThrown - Fires when the client catches an exception
  • OnConnected - Fires when the servers sends the MOTD.

None of the other IrcClient events are worried about since they are not needed for the Justin.tv server.

Update:
Have a demo attached to this thread now. People are free to check it out and use/modify the classes contained.

Here is the source for the classes if you want to create your own example and don't wish to download the RAR attached.

JtvClient.cs
Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TechLifeForum
{
    public class JtvClient
    {
        #region Private Variables

        private IrcClient jtvClient;    // probablly could have named this better

        // this handles the cross-thread stuff (beautifully)
        // so the actual application doesn't have to
        private AsyncOperation op;

        // this keeps the users in a list so
        // we don't have to rely on updating
        // it via IRC
        private List<string> userList;

        #endregion

        #region Properties

        private string _Username;
        public string Username { get { return _Username; } }

        private string _Password;
        public string Password { get { return _Password; } }

        private string _Server = "irc.justin.tv";
        public string Server
        {
            get { return _Server; }
            set
            {
                if (!string.IsNullOrEmpty(value))
                    _Server = value;
            }
        }
        #endregion

        #region Events

        public event ExceptionThrownEventDelegate ExceptionThrown;
        public event MessageReceivedDelegate MessageReceived;
        public event UpdateUsersDelegate UpdateUsers;
        public event ConnectedEventDelegate OnConnected;
        #endregion

        #region Constructors

        public JtvClient(string Username, string Password)
        {
            if (string.IsNullOrEmpty(Username) || string.IsNullOrEmpty(Password))
                throw new Exception("Invalid Username or Password"); // not thrown async so they can catch it w/ try/catch

            _Username = Username;
            _Password = Password;

            // instantiate variables for awsomeness
            op = AsyncOperationManager.CreateOperation(null);
            userList = new List<string>();
        }

        #endregion

        #region Public Methods

        public void Connect()
        {
            jtvClient = new IrcClient(_Server);
            jtvClient.ServerPass = _Password;
            jtvClient.Nick = _Username;
            jtvClient.AltNick = _Username;

            // add listeners before we connect
            AddListeners();

            Thread t = new Thread(DoConnect);
            t.IsBackground = true;
            t.Start();
            //DoConnect(); // debug only, comment out t.Start() if you uncomment this

        }
        public void Disconnect()
        {
            jtvClient.Disconnect();
            jtvClient = null;
        }

        /// <summary>
        /// Sends a message to the Justin.Tv server
        /// </summary>
        /// <param name="Message">Message to send the server</param>
        public void Send(string Message)
        {
            jtvClient.SendMessage("#" + _Username, Message);
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Method that is called on a new thread to
        /// avoid tieing up the UI thread
        /// </summary>
        private void DoConnect()
        {
            try
            {
                jtvClient.Connect();
                jtvClient.JoinChannel("#" + _Username);
            }
            catch (Exception ex)
            {
                op.Post(x => OnExceptionThrown((Exception)x), ex);  // TODO: double check that exceptions
            }                                                       //       actually show up at this level
        }

        /// <summary>
        /// Method to add the required listeners
        /// </summary>
        private void AddListeners()
        {
            jtvClient.OnConnect += () =>
                {
                    jtvClient.JoinChannel("#" + _Username);
                    op.Post(x => OnConnectedFire(), null);
                };
            // listen for messages on the channel
            // we don't care about which channel it comes from
            // since we are only listening to our room
            jtvClient.ChannelMessage += (channel, user, message) =>
                {
                    op.Post(x => OnMessageReceived((ChannelMessage)x), new ChannelMessage(user, message));
                };
            jtvClient.UpdateUsers += (channel, users) =>
                {
                    userList.Clear();
                    userList.AddRange(users);
                    userList.Sort();
                    op.Post(x => OnUsersUpdate((List<string>)x), userList);
                };
            jtvClient.UserJoined += (channel, user) =>
                {
                    if (userList.Contains(user)) return;
                    userList.Add(user);
                    userList.Sort();
                    op.Post(x => OnUsersUpdate((List<string>)x), userList);
                };
            jtvClient.UserLeft += (channel, user) =>
                {
                    if (!userList.Contains(user)) return;
                    userList.Remove(user);
                    userList.Sort();
                    op.Post(x => OnUsersUpdate((List<string>)x), userList);
                };
        }

        /// <summary>
        /// Triggers the JtvClient Event (UpdateUsers)
        /// </summary>
        /// <param name="users">A list of users</param>
        private void OnUsersUpdate(List<string> users)
        {
            //
            // op.Post(x => OnUsersUpdate((string[])x), users); <- code to trigger this event
            //

            // the actual event takes a string array.
            if (UpdateUsers != null) UpdateUsers(users.ToArray());
        }
        private void OnMessageReceived(ChannelMessage channelMessage)
        {
            //
            // op.Post(x => OnMessageReceived((ChannelMessage)x), channelMessage); <- code to trigger this event
            //

            if (MessageReceived != null) MessageReceived(channelMessage.From, channelMessage.Message);
        }
        private void OnConnectedFire()
        {
            if (OnConnected != null) OnConnected();
        }

        /// <summary>
        /// Used to raise an exception event to the user. These are done asyncronously.
        /// </summary>
        /// <param name="e"></param>
        private void OnExceptionThrown(Exception e)
        {
            //
            // op.Post(x => OnExceptionThrown((Exception)x),e); <- code to throw the exception
            //
            if (ExceptionThrown != null) ExceptionThrown(e);
        }

        #endregion

        /// <summary>
        /// Stuct to contain a channel message object.
        /// Needed it to be a single object so this worked great
        /// </summary>
        public struct ChannelMessage
        {
            public string From;
            public string Message;
            public ChannelMessage(string From, string Message)
            {
                this.From = From;
                this.Message = Message;
            }
        }
    }
}

IrcClient.cs
https://github.com/cshivers/IrcClient-csharp


Attached Files
.rar   JustinTVExample.rar (Size: 33.37 KB / Downloads: 150)
This post was last modified: 02-10-2015, 02:38 PM by KoBE.

10-31-2013, 09:16 AM #2
Kret
Member
**
Posts: 51 Threads:5 Joined: Mar 2012 Reputation: 3

RE: Justin.tv and Twitch.tv chat client.
Lol i was looking for IRC class to make the same thing, then I saw this post. Im really lucky :)

11-04-2013, 10:48 PM #3
KoBE
¯\_(ツ)_/¯
******
Global Moderators
Posts: 4,862 Threads:494 Joined: Jun 2011 Reputation: 67

RE: Justin.tv and Twitch.tv chat client.
Well, stay posted! I'm sure I'll have the code up soon.

11-10-2013, 06:04 PM #4
KoBE
¯\_(ツ)_/¯
******
Global Moderators
Posts: 4,862 Threads:494 Joined: Jun 2011 Reputation: 67

RE: Justin.tv and Twitch.tv chat client.
Alright, for those that are interested I've updated the OP with an example and source code. Keep in mind the code is very lightly tested. It's pretty basic by design. If anyone wants more functionality you'll probably have to build onto it yourself. I don't plan on progressing much more on this project.

01-06-2014, 01:08 AM #5
AceInfinity
Developer
*******
Administrators
Posts: 9,733 Threads:1,026 Joined: Jun 2011 Reputation: 76

RE: Justin.tv and Twitch.tv chat client.
First time I tested this, but it appears they have added a level of security to prevent things like this? I get disconnected immediately after logging in. I'll test some more when I have free time. Back to another week of work starting tomorrow...


Microsoft MVP .NET Programming - (2012 - Present)
®Crestron DMC-T Certified Automation Programmer

Development Site: aceinfinity.net

 ▲
 ▲ ▲

01-06-2014, 11:07 AM #6
KoBE
¯\_(ツ)_/¯
******
Global Moderators
Posts: 4,862 Threads:494 Joined: Jun 2011 Reputation: 67

RE: Justin.tv and Twitch.tv chat client.
Interesting. If I get a chance I'll check it out later tonight. My team is playing in the National Championship tonight. Can't miss that game. :D

01-07-2014, 11:23 PM #7
KoBE
¯\_(ツ)_/¯
******
Global Moderators
Posts: 4,862 Threads:494 Joined: Jun 2011 Reputation: 67

RE: Justin.tv and Twitch.tv chat client.
Alright, so I've finally had a chance to look at this. And they have changed their security. They don't have a very good system in place to spread the word with this stuff. Here is the link that I found that explains how to fix this: https://help.justin.tv/entries/23035369-...To-Connect

Basically, you just go to your channel and view the source.. From there you do a search for password_hash and that is the password required to log in. Mine was on line 449.
This post was last modified: 01-07-2014, 11:23 PM by KoBE.

01-07-2014, 11:39 PM #8
AceInfinity
Developer
*******
Administrators
Posts: 9,733 Threads:1,026 Joined: Jun 2011 Reputation: 76

RE: Justin.tv and Twitch.tv chat client.
So you could still integrate this with the IRC client by dynamically making a GET request to the channel that is associated with a certain page to get the hash before joining with the specified password. I didn't look at it in depth too much, I just noticed that it was disconnecting me immediately after joining.

What's the point of this honestly? lol. It's just more hassle than it does any added benefit.
This post was last modified: 01-07-2014, 11:40 PM by AceInfinity.


Microsoft MVP .NET Programming - (2012 - Present)
®Crestron DMC-T Certified Automation Programmer

Development Site: aceinfinity.net

 ▲
 ▲ ▲

01-08-2014, 12:11 AM #9
KoBE
¯\_(ツ)_/¯
******
Global Moderators
Posts: 4,862 Threads:494 Joined: Jun 2011 Reputation: 67

RE: Justin.tv and Twitch.tv chat client.
It'd be a little more than a GET request since you have to be logged in to see it. But definitely still do-able. It's not a password for the channel it's your specific password hash.
This post was last modified: 01-08-2014, 12:12 AM by KoBE.

01-08-2014, 12:37 AM #10
AceInfinity
Developer
*******
Administrators
Posts: 9,733 Threads:1,026 Joined: Jun 2011 Reputation: 76

RE: Justin.tv and Twitch.tv chat client.
You have to be logged in? If that's the case, can you see other's keys? If you can, then this implementation is damn silly... lol. Otherwise, I could see it preventing other's from using such clients on to connect to your channel, unless you gave them your key.

edit: Interesting, it appears that this key doesn't change at all regardless of what channel you view. So it must then be specific to the user which is logged in, meaning, you wouldn't need to keep using webrequests to get a channel pass hash because it's always static.

This leads me to believe that they are using this to "track" people in some way perhaps... ? Unsure Otherwise, I really can't see why they would add such a "stupid"/useless feature. If the password hash sent in when someone views your page through a webbrowser is the same as the one I'm seeing in the page source, then what purpose would it serve if that was the case? Unsure There would have to be some kind of other request sent in, instead of this hash, to differentiate between joining via some custom programmed IRC client like yours, but then they would have to have something else in place to separate someone chatting through a webbrowser and program X still, and make sure that this couldn't be emulated with program X too.

Without testing further though, it's hard to say, but if my assumptions are correct, I really don't see what this does... As far as I can see it has no defined purpose. Hopefully I'm wrong, but maybe it's a bad thing if I am not, who knows. Laugh

edit: I just read this:
Quote:Apparently, every time I sign into an account on the website after being logged out, I get a new password hash.

This means that hash is session based, which makes me wonder if some feature of the IRC server itself will kick you out of the session that this hash belongs to, is no longer active? Confused

AFAIK, once you are joined to the server and you're in a channel, there's really nothing that they can do to kick you out based on a web session, unless they've also configured their IRC portion...

This needs more testing, but I can't do any today, it'll have to be tomorrow after work.

If for some reason a "feature" kicks you out, then it wouldn't be hard to keep a session while you're talking through the client. I just don't know yet if there is interaction that goes on between the two worlds... Else, this may require periodic IRC messages to be sent out to keep you on their server, and some debugging to figure out what must be sent.

No sense rambling on with all these assumptions though until someone can verify something. I'll stop here. :)

I had thought some IRC implementations were specialized for preventing certain clients from connecting via several methods of authentication, such as chatspace... So we'll see...

From their support user I had read this:
Quote:More details available soon...

Dated: November 21, 2013 16:53

Maybe there is some further information about this floating around someplace? If not, that's pretty sad. No heads up, no information as to what this is for or anything in nearly ~2 months.

cheers
This post was last modified: 01-08-2014, 12:57 AM by AceInfinity.


Microsoft MVP .NET Programming - (2012 - Present)
®Crestron DMC-T Certified Automation Programmer

Development Site: aceinfinity.net

 ▲
 ▲ ▲




Forum Jump:


Possibly Related Threads...
Thread Author Replies Views Last Post
   Create your own IRC Client [C#/VB.Net] KoBE 185 109,540 10-01-2016, 06:57 PM
Last Post: AceInfinity
   IRC Client Class KoBE 110 66,693 10-01-2016, 06:52 PM
Last Post: AceInfinity
Star  Multi-Client Server Async Socket Example KoBE 165 157,119 09-10-2016, 05:17 AM
Last Post: R4TK3N
  Telnet Client AceInfinity 5 2,326 06-05-2016, 07:48 PM
Last Post: AceInfinity
   Twitch chat bot (irc client) dmgvol 11 18,426 08-24-2015, 11:59 PM
Last Post: Signal_20


Users browsing this thread: 1 Guest(s)