Last active
December 3, 2017 21:37
-
-
Save benjamingwynn/cc93b45b42d59f7619d60c54dc77ae1a to your computer and use it in GitHub Desktop.
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
/* TeamSteam - written by Benjamin Gwynn for ts3.xenxier.com */ | |
const TeamspeakQuery = require('teamspeak-query') | |
, query = new TeamspeakQuery('127.0.0.1', 10011) | |
, TARGET_CLIENT = 1 | |
, TARGET_CHANNEL = 2 | |
, TARGET_SERVER = 3 | |
, Steam = require("steam-webapi") | |
, console = require("better-console") | |
, jsonfile = require("jsonfile") | |
, SQ_PASSWD = "XXXXXXXXXXXXXX" | |
let games = {}, clients = {}, gamegroups = {}, gamecachednames = {} | |
try { | |
games = jsonfile.readFileSync("games.json") | |
clients = jsonfile.readFileSync("clients.json") | |
gamegroups = jsonfile.readFileSync("gamegroups.json") | |
gamecachednames = jsonfile.readFileSync("gamecachednames.json") | |
} catch (ex) { | |
console.warn("No files. Will make new ones.") | |
console.warn(ex) | |
} | |
// delete all last played games when starting script | |
Object.keys(clients).forEach((clientKey) => { | |
const client = clients[clientKey] | |
delete client.lastgame | |
}) | |
setInterval(() => { | |
jsonfile.writeFileSync("games.json", games) | |
jsonfile.writeFileSync("clients.json", clients) | |
jsonfile.writeFileSync("gamegroups.json", gamegroups) | |
jsonfile.writeFileSync("gamecachednames.json", gamecachednames) | |
}, 30000) // flush to disk every 30 sec | |
// register API key | |
Steam.key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" | |
// hello steam! | |
Steam.ready(function(err) { | |
if (err) { | |
console.warn("Failed to connect to Steam!") | |
console.error(err) | |
process.exit(1) | |
} | |
const steam = new Steam(); | |
console.info("We've logged into steam!") | |
// connect to the teamspeak server | |
query.send('login', 'serveradmin', SQ_PASSWD) | |
.then(() => query.send('use', 1)) | |
.then(() => query.send('servernotifyregister', { 'event': 'server' })) | |
.then(() => query.send("servernotifyregister", { "event": "textprivate" })) | |
.then(() => query.send("clientupdate", {"client_nickname": "TeamSteam"})) | |
.then(() => console.info("We've logged into our local Teamspeak server!")) | |
.catch(err => console.error('An error occured:', err)) | |
function replaceAll (current, replacement, target) { | |
return target.split(current).join(replacement) | |
} | |
function awaitSteamInput (client) { | |
function storeClientSteamID (steamid) { | |
// XXX: this is an ugly way to verify an id but whatever who cares | |
steam.getPlayerBans({ | |
"steamids": steamid, | |
}, function (error, data) { | |
if (error) { | |
query.send("sendtextmessage", { | |
targetmode: TARGET_CLIENT, | |
target: client.clid, | |
msg: `WTF? Can't check bans. Steam is probably fucked.` | |
}) | |
throw error | |
} | |
if (data.players.length) { | |
console.log("verified ID!") | |
query.send("sendtextmessage", { | |
targetmode: TARGET_CLIENT, | |
target: client.clid, | |
msg: `Done. Your Steam account is now linked.` | |
}) | |
client.steamid = steamid | |
} else { | |
query.send("sendtextmessage", { | |
targetmode: TARGET_CLIENT, | |
target: client.clid, | |
msg: `Invalid client ID. Please try again...` | |
}) | |
awaitSteamInput(client) | |
} | |
}) | |
} | |
console.log("awaiting steam input message!") | |
query.once("textmessage", (data) => { | |
console.info("I got a response!") | |
console.log(data) | |
query.send("sendtextmessage", { | |
targetmode: TARGET_CLIENT, | |
target: client.clid, | |
msg: `Please wait...` | |
}) | |
// XXX: this url parsing logic is kind of shit, but works, so who cares | |
let msg = data | |
.msg | |
.trim() | |
.toLowerCase() | |
.replace("[/url]", "") | |
.replace("[url]", "") | |
// remove last / from urls | |
if (msg.lastIndexOf("/") === msg.length - 1) { | |
msg = msg.substr(0, msg.length - 1) | |
} | |
if (msg.indexOf("://steamcommunity.com/profiles/") > -1) { | |
const id = msg | |
.replace("https://steamcommunity.com/profiles/", "") | |
.replace("http://steamcommunity.com/profiles/", "") | |
console.info("given id", id) | |
storeClientSteamID(id) | |
} else { | |
// if (msg === "Please wait..." || msg === "I couldn't finsd your steam profile. Try again...") return | |
const nick = msg | |
.replace("https://steamcommunity.com/id/", "") | |
.replace("http://steamcommunity.com/id/", "") | |
console.info("given nick", nick) | |
// okay now lets ask steam if thats valid | |
console.log("resolveVanityURL", nick) | |
steam.resolveVanityURL({ | |
"vanityurl": nick | |
}, function(err, data) { | |
if (err) { | |
query.send("sendtextmessage", { | |
targetmode: TARGET_CLIENT, | |
target: client.clid, | |
msg: `WTF? Can't get vanityurl. Steam is probably fucked.` | |
}) | |
throw err; | |
} | |
console.info(data) | |
// Not found handler | |
if (data.success === 42) { | |
query.send("sendtextmessage", { | |
targetmode: TARGET_CLIENT, | |
target: client.clid, | |
msg: "I couldn't find your steam profile. Try again..." | |
}).then(() => awaitSteamInput(client)) | |
} else if (data.success === 1 && data.steamid) { | |
storeClientSteamID(data.steamid) | |
} | |
}) | |
} | |
}) | |
} | |
function getGroupForGame (name, callback) { | |
// ts3 groups have a 30 character limit | |
const gameName = name.substr(0, 30) | |
if (gamegroups[gameName]) { | |
console.log("Returning game group from cache", gameName) | |
callback(null, gamegroups[gameName]) | |
} else { | |
query.send("servergrouplist", {}).then((sgl) => { | |
let found | |
sgl.name.forEach((name, index) => { | |
if (name === gameName) { | |
found = sgl.sgid[index] | |
} | |
}) | |
if (found) { | |
gamegroups[gameName] = found | |
callback(null, found) | |
} else { | |
console.log("group doesnt exist creating new group") | |
query.send("servergroupadd", { | |
"name": gameName | |
}).then((data) => { | |
// show after name! | |
query.send("servergroupaddperm", { | |
sgid: data.sgid, | |
permsid: "i_group_show_name_in_tree", | |
permvalue: 2, | |
permnegated: 0, | |
permskip: 0, | |
}) | |
// fix perms | |
query.send("servergroupaddperm", { | |
sgid: data.sgid, | |
permsid: "i_group_needed_modify_power", permvalue: 50, permnegated: 0, permskip: 0, | |
}) | |
gamegroups[gameName] = data.sgid | |
callback(null, data.sgid) | |
}).catch(callback) | |
} | |
}).catch(callback) | |
} | |
} | |
// on client connect | |
query.on('cliententerview', data => { | |
const uid = data.client_unique_identifier | |
if (!clients[uid]) { | |
console.log("Creating new data for", data.client_unique_identifier) | |
clients[uid] = { | |
"nick": data.client_nickname | |
} | |
} | |
const client = clients[uid] | |
// update information | |
client.clid = data.clid | |
client.nick = data.client_nickname | |
query.send("clientgetdbidfromuid", { | |
cluid: uid, | |
}).then((data) => { | |
console.log(data) | |
client.dbid = data.cldbid | |
}) | |
if (!client.sentWelcomeMessage) { | |
client.sentWelcomeMessage = true | |
if (!client.steamid) { | |
query.send("sendtextmessage", { | |
targetmode: TARGET_CLIENT, | |
target: client.clid, | |
msg: `Hey ${client.nick}! To show everyone what game you're currently playing while you're on the Teamspeak server; please reply with your Steam ID or a link to your steam profile. | |
This won't work if your Steam account is private, and it won't access any information which isn't publically accessible. | |
[b]Please message Xenxier if there are any problems with this.[/b] | |
----------------------------------------------------------------------------------------------------------------------------` | |
}).then(() => { | |
console.log("sent the welcome message") | |
awaitSteamInput(client) | |
}) | |
} | |
} | |
console.log(data) | |
console.log(client.nick, "connected!") | |
}); | |
function getGameName (summary) { | |
// sometimes summary.gameextrainfo isn't returned for some reason. probably a bug in the steamapi. | |
// we can work around this using a caching mechanism | |
if (summary.gameextrainfo) { | |
// cache this | |
if (summary.gameid) { | |
gamecachednames[summary.gameid] = summary.gameextrainfo | |
} | |
return summary.gameextrainfo | |
} else if (summary.gameid) { | |
if (gamecachednames[summary.gameid]) { | |
return gamecachednames[summary.gameid] // resolve using cache from other clients | |
} else { | |
// we couldn't find the game | |
return null | |
} | |
} | |
} | |
// every few seconds | |
// TODO: refactor? | |
setInterval(() => { | |
const steamids = [] | |
, clientKeys = Object.keys(clients) | |
clientKeys.forEach((clientID) => { | |
const client = clients[clientID] | |
console.log("client", client) | |
if (!client.steamid) { | |
// the client has no steam id | |
console.error("client", client.nick, "has no steam ID!") | |
return | |
} | |
steam.getPlayerSummaries({ | |
"steamids": client.steamid, | |
}, (error, summaries) => { | |
if (error) { | |
console.error(error) | |
return | |
} | |
const summary = summaries.players[0] | |
, name = getGameName(summary) | |
console.log("client" , client.steamid , "(" + client.nick + ") is playing game", name) | |
// console.warn(summary) | |
if (client.lastgame === name && name) { | |
// we're still playing the same game | |
return | |
} | |
console.log("last game is not current game! removing game groups...") | |
// if we're not playing the game we think we're playing... | |
let queriesFinished = 0 | |
const nQueries = Object.keys(gamegroups).length | |
delete client.lastgame | |
function allDone () { | |
console.log("all pending server queries are finished...") | |
// if we're playing a new game | |
if (!name) { | |
console.log("we're playing the same game") | |
return | |
} | |
console.log("hey we're playing a new game!") | |
// save this game | |
client.lastgame = name | |
console.log("game name", name) | |
getGroupForGame(name, (err, groupid) => { | |
if (err) throw err | |
console.log("groupid", groupid) | |
query.send("servergroupaddclient", { | |
cldbid: client.dbid, | |
sgid: groupid | |
}).catch(err => console.error('An error occured at group add:', err)) | |
}) | |
} | |
if (nQueries === 0) { | |
allDone() | |
return | |
} | |
Object.keys(gamegroups).forEach((key) => { | |
const gid = gamegroups[key] | |
query.send("servergroupdelclient", { | |
cldbid: client.dbid, | |
sgid: gid | |
}) | |
.catch(err => { | |
// do nothing on error | |
// console.log('An error occured at group del:', err) | |
// queriesFinished += 1 | |
// if (queriesFinished === nQueries) allDone() | |
}) | |
.then(() => { | |
queriesFinished += 1 | |
if (queriesFinished !== nQueries) { | |
// keep waiting | |
return | |
} | |
allDone() | |
}) | |
}) | |
}) | |
}) | |
}, 5000) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
dank af 🔥