A suite to track Project Diva score statistics and ratings / D4DJ event data.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
projectdivar/server/node_modules/twitch-get-stream/index.js

110 lines
3.6 KiB

var axios = require('axios');
var M3U = require('playlist-parser').M3U;
var qs = require('querystring');
const clientId = 'kimne78kx3ncx6brgo4mv6wki5h1ko';
// Thanks michaelowens, :)
// Simple titlecase thing, capitalize first letter
var titleCase = function(str) {
return str.split(' ').map(function(word) { return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(); }).join(' ');
}
// Twitch functions
var getAccessToken = function(channel) {
// Get access token
return axios.get('https://api.twitch.tv/api/channels/' + channel + '/access_token', {
headers: {
'Client-ID': clientId
}
}).then(function(res) {
return res.data;
});
}
var getPlaylist = function(channel, accessToken) {
// Get the playlist with given access token data (parsed /access_token response)
var query = {
player: 'twitchweb',
token: accessToken.token,
sig: accessToken.sig,
allow_audio_only: 'true',
allow_source: 'true',
type: 'any',
p: Math.floor(Math.random() * 99999) + 1
};
return axios.get('https://usher.ttvnw.net/api/channel/hls/' + channel + '.m3u8?' + qs.stringify(query), {
headers: {
'Client-ID': clientId
}
}).then(function(res) {
return res.data;
});
}
// Exposed functions
// Just get the playlist, return the string nothing else
var getPlaylistOnly = function(channel) {
if (!channel)
return Promise.reject(new Error('No channel defined.'));
var channel = channel.toLowerCase(); // Twitch API only takes lowercase
return getAccessToken(channel)
.then(function(token) {
return getPlaylist(channel, token);
});
}
// Above get playlist, but then parses it and gives the object
var getPlaylistParsed = function(channel) {
if (!channel)
return Promise.reject(new Error('No channel defined.'));
return getPlaylistOnly(channel)
.then(function(data) {
// basically parse then _.compact (remove falsy values)
return M3U.parse(data).filter(function(d) { return d; });
});
}
var getStreamUrls = function(channel) { // This returns the one with a custom fully parsed object
return getPlaylistParsed(channel)
.then(function(playlist) {
if (playlist.length < 1)
throw new Error('There were no results, maybe the channel is offline?');
// Parse playlist with quality options and send to new array of objects
var streamLinks = [];
for (var i = 0; i < playlist.length; i++) {
// Quality option
var name = playlist[i].title.match(/VIDEO=('|")(.*?)('|")/); // Raw quality name
name = name[2]; // Get regex captured group
// Rename checks
// chunked = source
if (name === 'chunked') name = 'source';
// audio_only = Audio Only
else if (name === 'audio_only') name = 'audio only';
// Resolution
var resMatch = playlist[i].title.match(/RESOLUTION=(.*?),/);
var res = resMatch ? resMatch[1] : null // Audio only does not have a res so we need this check
streamLinks.push({
quality: titleCase(name), // Title case the quality
resolution: res,
url: playlist[i].file
});
}
return streamLinks;
});
}
module.exports = {
get: getStreamUrls,
raw: getPlaylistOnly,
rawParsed: getPlaylistParsed
}