Permalink
Browse files

Week 5 updates, fixed input box, default tabs, and starting work on t…

…opic.
  • Loading branch information...
roncli committed Apr 21, 2017
1 parent 402bf17 commit 5f2586f752cde90b8f0d088ef9c22306302e22d4
Showing with 203 additions and 47 deletions.
  1. +48 −1 app/site/css/index.css
  2. +3 −5 app/site/index.htm
  3. +4 −3 app/site/js/extensions.js
  4. +98 −30 app/site/js/index.js
  5. +50 −8 app/site/modules/chat/twitch/index.js
@@ -14,7 +14,10 @@ body {
}

#display {
display: flex;
flex-direction: row;
flex-grow: 1;
margin-bottom: 0;
}

#display > .tab-pane.active {
@@ -24,10 +27,51 @@ body {
}

#display > .tab-pane > .chat {
display: flex;
flex-direction: column;
flex-grow: 1;
}

#display > .tab-pane > .chat > .text {
overflow-x: hidden;
overflow-y: auto;
}

#display > .tab-pane > .chat > .topic {
height: 48px;
flex-shrink: 0;
}

#display > .tab-pane > .chat > .topic .topic-background {
position: absolute;
width: 100%;
height: 48px;
opacity: 0.2;
background-size: 100% auto;
background-repeat: no-repeat;
background-position: center center;
}

#display > .tab-pane > .chat > .topic .topic-foreground {
position: absolute;
width: 100%;
white-space: nowrap;
}

#display > .tab-pane > .chat > .topic .topic-foreground > .topic-logo {
display: inline-block;
margin-right: 10px;
width: 48px;
height: 48px;
}

#display > .tab-pane > .chat > .topic .topic-foreground > .topic-text {
display: inline-block;
vertical-align: middle;
}

#display > .tab-pane > .users {
overflow: auto;
width: 100px;
}

@@ -37,5 +81,8 @@ body {

#inputbox {
width: 100%;
height: 1.2em;
min-height: 24px;
height: 24px;
overflow-y: none;
resize: none;
}
@@ -10,12 +10,10 @@
</head>
<body>
<div id="menu">Menu</div>
<ul id="channels" class="nav nav-tabs">
</ul>
<div id="display" class="tab-content panel">
</div>
<ul id="channels" class="nav nav-tabs"></ul>
<div id="display" class="tab-content panel"></div>
<div id="input">
<input type="text" id="inputbox" />
<textarea id="inputbox"></textarea>
</div>
</body>
</html>
@@ -1,14 +1,15 @@
JSON.tryParse = (str) => {
var initialStr = str;
return new Promise((resolve, reject) => {
var initialStr = str;

if (!str || str.length === 0) {
reject();
};
}
str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, '');
if ((/^[\],:{}\s]*$/).test(str)) {
resolve(JSON.parse(initialStr));
} else {
reject();
reject("JSON was not valid.");
}
});
};
@@ -7,53 +7,108 @@ var electron = require("electron"),
userSettings = new File(path.join(electron.remote.app.getPath("userData"), "userSettings.js"));
channels = {},
getTab = (username) => {
return `<li id="tab-${username}"><a data-toggle="tab" href="#channel-${username}">#${username}</a></li>`;
return `<li id="tab-${username}" class="channel-tab"><a data-toggle="tab" href="#channel-${username}">#${username}</a></li>`;
},
getPanel = (username) => {
return `<div role="tabpanel" class="tab-pane" id="channel-${username}">
<div class="chat" class="chat">
<div class="chat">
<div class="topic"></div>
<div class="text"></div>
</div>
<div class="users" class="users"></div>
<div class="users"></div>
</div>`;
},
updateStream = (channel) => {
var channelName = channel.substring(1);
client.getStream(channelName).then((stream) => {
if (stream) {
channels[channel].stream = stream;
channels[channel].channel = stream.channel;
updateTitle(channel);
} else {
delete channels[channel].stream;
client.getChannel(channelName).then((channelData) => {
channels[channel].channel = channelData;
updateTitle(channel);
});
}
});

client.getChatters(channelName).then((chatters) => {
channels[channel].chatters = chatters;
updateTitle(channel);
});
},
getTimeSince = (time) => {
var diff = new Date().getTime() - new Date(time).getTime();

return `${Math.floor(diff / 3600000)}:${("0" + Math.floor(diff % 3600000 / 60000)).slice(-2)}`;
},
updateTitle = (channel) => {
var channelName = channel.substring(1);
$(`#channel-${channelName} .topic`).html(
`<div style="position: relative;">
${channels[channel].channel && channels[channel].channel.profile_banner ? `<div class="topic-background" style="background-image: url('${channels[channel].channel.profile_banner}');"></div>` : ""}
<div class="topic-foreground">
${channels[channel].channel && channels[channel].channel.logo ? `<img src="${channels[channel].channel.logo}" class="topic-logo">` : ""}
${channels[channel].channel ? `<div class="topic-text">
${channel} - ${channels[channel].channel.status} (${channels[channel].channel.game})<br />
${channels[channel].stream ? `Online: ${getTimeSince(channels[channel].stream.created_at)} - Viewers: ${channels[channel].stream.viewers} - ` : ""}${channels[channel].chatters ? `Chatters: ${channels[channel].chatters.chatter_count} - ` : ""}Followers: ${channels[channel].channel.followers} - Views: ${channels[channel].channel.views}
</div>` : ""}
</div>
</div>`);
};

client.on("message", (channel, username, displayname, text) => {
console.log("message", channel, username, text);
$(`#channel-${channel.substring(1)} .text`).append(`<b>${displayname}</b>: ${text}<br />`);
var channelName = channel.substring(1);
$(`#channel-${channelName} .text`).append(`<b>${displayname}</b>: ${text}<br />`);
});

client.on("join", (channel, username, self) => {
console.log("join", channel, username);
var channelName = channel.substring(1);
if (self) {
channels[channel] = {
users: []
users: [],
interval: setInterval(() => updateStream(channel), 60000)
};
$("#channels").append(getTab(channel.substring(1)));
$("#display").append(getPanel(channel.substring(1)));
$("#channels").append(getTab(channelName));
$("#display").append(getPanel(channelName));
if (Object.keys(channels).length === 1) {
$(`#tab-${channelName} > a`).tab("show");
}
updateStream(channel);
}
channels[channel].users.push(username);
$(`#channel-${channel.substring(1)} .text`).append(`<i>${(self ? "You have" : `${username} has`)} joined ${channel}<br />`);
$(`#channel-${channel.substring(1)} .users`).html(channels[channel].users.join("<br />"));
$(`#channel-${channelName} .text`).append(`<i>${(self ? "You have" : `${username} has`)} joined ${channel}<br />`);
$(`#channel-${channelName} .users`).html(channels[channel].users.join("<br />"));
});

client.on("part", (channel, username, self) => {
channels[channel].users.splice(channels[channel].users.indexOf(username), 1);
var channelName = channel.substring(1);
if (self) {
$(`#tab-${channel.substring(1)}`).remove();
$(`#channel-${channel.substring(1)}`).remove();
let index = $(`#tab-${channelName}`).index();
$(`#tab-${channelName}`).remove();
$(`#channel-${channelName}`).remove();
clearInterval(channels[channel].interval);
delete channels[channel];
if ($(".channel-tab.active").length === 0) {
$(`.channel-tab:nth-child(${index === Object.keys(channels).length ? index : index + 1}) > a`).tab("show");
}
} else {
channels[channel].users.splice(channels[channel].users.indexOf(username), 1);
$(`#channel-${channelName} .text`).append(`<i>${`${username}`} has left ${channel}<br />`);
$(`#channel-${channelName} .users`).html(channels[channel].users.join("<br />"));
}
$(`#channel-${channel.substring(1)} .text`).append(`<i>${(self ? "You have" : `${username} has`)} left ${channel}<br />`);
$(`#channel-${channel.substring(1)} .users`).html(channels[channel].users.join("<br />"));
});

client.on("mod", (channel, username) => {
$(`#channel-${channel.substring(1)} .text`).append(`<i>${username} is now a moderator of ${channel}<br />`);
var channelName = channel.substring(1);
$(`#channel-${channelName} .text`).append(`<i>${username} is now a moderator of ${channel}<br />`);
});

client.on("unmod", (channel, username) => {
$(`#channel-${channel.substring(1)} .text`).append(`<i>${username} is no longer a moderator of ${channel}<br />`);
var channelName = channel.substring(1);
$(`#channel-${channelName} .text`).append(`<i>${username} is no longer a moderator of ${channel}<br />`);
});

client.on("credentials", (username, accessToken) => {
@@ -84,33 +139,46 @@ userSettings.load().then(() => {
});

$(document).ready(() => {
var $inputbox = $("#inputbox");
var $inputbox = $("#inputbox"),
patterns = {
join: /^\/join #?([a-z0-9_]+)$/i,
part: /^\/part$/i
},
setSize = ($el) => {
setTimeout(() => {
$el.css({height: "1px"});
$el.css({height: `${$el.prop("scrollHeight") + 2}px`});
}, 0);
};

$inputbox.on("keypress", (ev) => {
if (ev.keyCode === 13 && client.connected) {
let input = $inputbox.val(),
matches;

matches = /^\/join #?([a-z0-9_]+)$/i.exec(input);

if (matches) {
if (matches = patterns.join.exec(input)) {
let channel = matches[1].toLowerCase();
client.join(`#${channel}`);
return;
}

matches = /^\/part$/i.exec(input);

if (matches) {
} else if (matches = patterns.part.exec(input)) {
client.part($("#channels li.active").text());
return;
} else {
client.send($("#channels li.active").text(), $inputbox.val());
}

client.send($("#channels li.active").text(), $inputbox.val());
$inputbox.val("");

ev.preventDefault();
return false;
}
});

$inputbox.on("change", () => setSize($inputbox));
$inputbox.on("cut", () => setSize($inputbox));
$inputbox.on("paste", () => setSize($inputbox));
$inputbox.on("drop", () => setSize($inputbox));
$inputbox.on("keydown", () => setSize($inputbox));
$inputbox.on("keyup", () => setSize($inputbox));

$("#channels").on("click", "a", (ev) => {
ev.preventDefault();
$(this).tab("show");
@@ -1,8 +1,11 @@
var electron = require("electron"),
var http = require("http"),
electron = require("electron"),
Tmi = require("tmi.js"),
TwitchApi = require("twitch-api"),
Chat = require("../../../js/base/chat");


require("../../../js/extensions");

class Twitch extends Chat {
constructor (settings) {
super();
@@ -78,12 +81,6 @@ class Twitch extends Chat {
twitch.emit("unmod", channel, username);
});

/*
twitch.tmi.on("notice", (a, b, c) => {
console.log(a, b, c);
});
*/

twitch.tmi.connect().then(() => {
twitch.tmi.raw("CAP REQ :twitch.tv/membership twitch.tv/commands twitch.tv/tags");

@@ -173,6 +170,51 @@ twitch.tmi.on("notice", (a, b, c) => {
send(channel, command) {
return this.tmi.say(channel, command);
}

getStream(channel) {
var api = this.api;

return new Promise((resolve, reject) => {
api.getChannelStream(channel, (err, stream) => {
if (err) {
reject(err);
return;
}

resolve(stream.stream);
});
});
}

getChannel(channel) {
var api = this.api;

return new Promise((resolve, reject) => {
api.getChannel(channel, (err, channelData) => {
if (err) {
reject(err);
return;
}

resolve(channelData);
});
});
}

getChatters(channel) {
return new Promise((resolve, reject) => {
http.get("http://tmi.twitch.tv/group/user/" + channel + "/chatters", (res) => {
var body = "";
res.on("data", (chunk) => {
body += chunk;
});
res.on("end", () => {
JSON.tryParse(body).then(resolve).catch(reject);
});
// TODO: Handle errors on res
});
});
}
}

module.exports = Twitch;

0 comments on commit 5f2586f

Please sign in to comment.