Created
July 3, 2016 23:18
-
-
Save erik-sn/a5aa73977df6cab46ae0cf40df634f0d to your computer and use it in GitHub Desktop.
Twitch.TV Stream Tracker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div id="loading-container"></div> | |
<div id="error-container"></div> | |
<div id="page-container"> | |
<div id="search-container"> | |
<fieldset class="form-group"> | |
<div id="logo-container"><img height="200" src="https://maxcdn.icons8.com/Share/icon/Logos//twitch1600.png" /></div> | |
<input type="search" class="form-control" id="channel-search" placeholder="Search a game to find related channels" autocomplete="off"> | |
<small id="search-error" class="text-muted"></small> | |
</fieldset> | |
<div id="search-results-container"> | |
<ul id="search-results"></ul> | |
</div> | |
</div> | |
<div id="list-container"> | |
<h1 id="active-streams-label">Active Streams</h1> | |
<ul id="stream-list-active"></ul> | |
<h1>Inactive Streams</h1> | |
<ul id="stream-list-inactive"></ul> | |
</div> | |
</div> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let channels = ["ESL_SC2", "OgamingSC2", "cretetion", "freecodecamp", "storbeck", "habathcx", "RobotCaleb", "noobs2ninjas", "towlie", "brunofin", "comster404"]; | |
const baseUrl = 'https://api.twitch.tv/kraken/streams?channel='; | |
const gameSearch = 'https://api.twitch.tv/kraken/search/games?type=suggest&q=' | |
const channelSearch = 'https://api.twitch.tv/kraken/search/channels?q=' | |
const channelInfo = 'https://api.twitch.tv/kraken/channels/'; | |
$(document).ready(function() { | |
$('#channel-search').on('input', function(event) { | |
const term = event.target.value; | |
if (term.length >= 3) { | |
searchTwitch(term); | |
} | |
}); | |
$('html, body, #page-container').on('click', function() { | |
$('#search-results').hide(); | |
}); | |
getStreamData(); | |
}); | |
$(document).on('click', '#channel-search', function() { | |
$('#search-results').show(); | |
}); | |
$(document).on('click', '.preview-image', function () { | |
const channel = $(this).context.name; | |
window.open('https://www.twitch.tv/' + channel, '_blank'); | |
}); | |
$(document).on('click', '#channel-search', function() { | |
$('.channel-search-result').show(); | |
}); | |
$(document).on('click', '.channel-search-result', function() { | |
const channel = $(this).attr('name'); | |
if (channels.indexOf(channel) === -1) { | |
channels.push(channel); | |
getStreamData(); | |
$('.channel-search-result').remove(); | |
$('#channel-search').val(''); | |
} | |
}); | |
function getStreamData() { | |
const url = channels.reduce(function(prev, current) { | |
return prev + ','+ current; | |
}, baseUrl); | |
getData(url, 'jsonp', function(twitchData) { | |
if(twitchData) { | |
const activeNames = twitchData.streams.map(stream => { | |
return stream.channel.display_name; | |
}); | |
const active = twitchData.streams.reduce((prev, current) => { | |
return generateActiveStream(prev, current); | |
}, ''); | |
$('#stream-list-active').html(active); | |
const inactiveNames = channels.filter(channel => { | |
if (activeNames.indexOf(channel) === -1) { | |
return true; | |
} | |
}); | |
$('.inactive-stream').remove(); | |
for (let i = 0; i < inactiveNames.length; i++) { | |
const title = inactiveNames[i]; | |
const element = generateInactiveStream(title); | |
getData(channelInfo + title, 'jsonp', streamInfo => { | |
let image = '' | |
let label; | |
let status; | |
if (streamInfo.error) { | |
label = '<span class="offline-label">' + title + ' </span>'; | |
status = '<span class="offline-status">Account Closed</span>'; | |
} else { | |
label = '<span class="offline-label">' + streamInfo.display_name + ' </span>'; | |
status = '<span class="offline-status">Offline</span>'; | |
if (streamInfo.logo) { | |
image = '<img class="offline-image" height="40" src="' + streamInfo.logo + '" />' | |
} | |
} | |
const element = '<li class="list-group-item inactive-stream">' + image + label + status + '</li>'; | |
$('#stream-list-inactive').append(element); | |
}); | |
} | |
} | |
}); | |
} | |
function generateActiveStream(prev, current) { | |
var preview = '<div class="col-sm-4"><img class="preview-image" src="' + current.preview.medium + '" name="' + current.channel.name + '"/></div>'; | |
var description = '<div class="active-description col-sm-5"><div class="active-title">' + current.channel.name + '<span class="active-language"> - ' + current.channel.language + '</span></div><div class="active-game">' + current.channel.game + '</div>'; | |
var status = '<div class="active-status" >' + current.channel.status + '</div>'; | |
var viewers = '<div class="active-viewers" >Viewers: ' + current.viewers + '</div></div>'; | |
return prev + '<li class="list-group-item active-stream container-fluid"><div class="row">' + preview + description + status + viewers + '</div></div></li>'; | |
} | |
function generateInactiveStream(title) { | |
} | |
function searchTwitch(term) { | |
getData(gameSearch + term, 'jsonp', gameResults => { | |
const game = gameResults.games[0]; | |
getData(channelSearch + game.name, 'jsonp', channelResults => { | |
const channels = channelResults.channels.reduce((prev, current) => { | |
return prev + generateChannelSearch(current); | |
}, ''); | |
$("#search-results").html(channels); | |
}); | |
}); | |
} | |
function generateChannelSearch(current) { | |
const status = current.status.substring(0, 25) + '...'; | |
return '<li name="' + current.name + '" class="list-group-item channel-search-result"><img height="40" src="' + current.logo + '" /><div class="search-info"><div>' + current.display_name + ' Followers: ' + current.followers + '</div><div>' + status + '</div></div></li>'; | |
} | |
function getData(url, dataType, returnData) { | |
$.ajax({ | |
url: url, | |
type: 'GET', | |
dataType: dataType, | |
success: function(data) { | |
returnData(data) | |
}, | |
error: function(jqXHR, textStatus, errorThrown) { | |
returnData(undefined); | |
} | |
}); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$primaryColor: #5F0376; | |
$secondaryColor: #2E4172; | |
$tertiaryColor: white; | |
@mixin shadow($blur, $opacity) { | |
-webkit-box-shadow: 0px 0px $blur 0px rgba(0,0,0,$opacity); | |
-moz-box-shadow: 0px 0px $blur 0px rgba(0,0,0,$opacity); | |
box-shadow: 0px 0px 10px $blur rgba(0,0,0,$opacity); | |
} | |
body { | |
background-color: #8E24AA; | |
} | |
#logo-container { | |
text-align: center; | |
} | |
#page-container { | |
@include shadow(5px, 0.75); | |
opacity: 0.9; | |
margin: 0% 15% 0% 15%; | |
padding: 0px 25px 25px 25px; | |
background-color: $primaryColor; | |
min-height: 100vh; | |
min-width: 400px; | |
color: $tertiaryColor; | |
} | |
#list-container { | |
padding-top: 20px; | |
} | |
#stream-container { | |
color: $tertiaryColor; | |
font-size: 28px; | |
text-align: center; | |
width: 100%; | |
height: 50%; | |
} | |
h1 { | |
text-align: center; | |
} | |
#search-results { | |
@include shadow(3px, 0.25); | |
} | |
#search-results { | |
z-index: 2; | |
width: 50%; | |
position: absolute; | |
margin-top: -15px; | |
padding-left: 0px; | |
min-width: 300px !important; | |
} | |
.channel-search-result { | |
padding: 0px !important; | |
color: black; | |
} | |
#channel-search { | |
font-size: 24px; | |
height: 50px; | |
} | |
.channel-search-result img { | |
margin-top: -20px; | |
} | |
.search-info { | |
margin-left: 10px; | |
display: inline-block; | |
} | |
#active-streams-label { | |
margin-top: 0px; | |
} | |
#stream-container-label { | |
padding-top: 40px; | |
} | |
#stream-list-active { | |
padding-left: 0px; | |
color: black; | |
} | |
#stream-list-inactive { | |
padding-left: 0px; | |
color: black; | |
} | |
.offline-image { | |
margin-right: 10px; | |
} | |
.offline-label { | |
font-weight: bold; | |
font-size: 18px; | |
margin-right: 25px; | |
} | |
.offline-status { | |
font-style: italic; | |
} | |
.active-stream { | |
} | |
.preview-image { | |
cursor: pointer; | |
display: inline-block; | |
margin-right: 10px; | |
} | |
.col-sm-4 { | |
width: 350px !important; | |
} | |
.active-description { | |
margin-left: 25px; | |
} | |
.active-title { | |
font-size: 30px; | |
font-weight: bold; | |
} | |
.active-language { | |
font-weight: 100; | |
} | |
.active-game { | |
font-size: 20px; | |
width: 100%; | |
} | |
.active-viewers { | |
font-size: 16px; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment