Skip to content

Instantly share code, notes, and snippets.

@benjamingwynn
Last active December 3, 2017 21:37
Show Gist options
  • Save benjamingwynn/cc93b45b42d59f7619d60c54dc77ae1a to your computer and use it in GitHub Desktop.
Save benjamingwynn/cc93b45b42d59f7619d60c54dc77ae1a to your computer and use it in GitHub Desktop.
/* 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)
})
@benjamingwynn
Copy link
Author

dank af 🔥

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment