GOTV & Demos
GOTV Broadcast
Get5 makes no changes to the broadcasting part of the GOTV, but will automatically adjust the
mp_match_restart_delay
when a map ends if GOTV is enabled to
ensure that it won't be shorter than what is required for the GOTV broadcast to finish. Players will also not
be kicked from the server before this delay has passed.
Don't mess too much with the TV!
Changing tv_delay
or tv_enable
in warmup.cfg
, live.cfg
etc. is going to cause problems with your demos.
We recommend you set tv_delay
either on your server in general or only once in the cvars
section of your
match configuration. You should also not set tv_delaymapchange
as Get5 handles this
automatically.
We recommend that you do not set tv_enable
in your match configuration, as it requires a map change for
the GOTV bot to join the server. You should enable GOTV in your general server config and refrain from turning it on
and off with Get5. Note that setting tv_enable 1
won't allow people to join your server's GOTV. You must also set
tv_advertise_watchable 1
, so you don't have to worry about ghosting if this is disabled.
Recording Demos
Get5 can be configured to automatically record matches. This is enabled by default based on the state
of get5_demo_name_format
and can be disabled by setting that parameter to
an empty string.
Demo recording starts once all teams have readied up and ends following a map result. When a demo file is written to
disk, the Get5_OnDemoFinished
forward is called shortly after. The filename can also be
found in the map-section of the KeyValue stats system.
Broadcast delay on GOTV recording
When the GOTV recording stops, the server will flush its framebuffer to disk. This may cause a lag spike or a
complete freeze of the GOTV broadcast if you have a substantial tv_delay
, so Get5 will wait until the entire match
has been broadcast before it stops recording the demo.
Automatic Upload
In addition to recording demos, Get5 can also upload them to a URL when the recording stops. To enable this feature, you
must have the SteamWorks extension installed and define the URL with
get5_demo_upload_url
. The HTTP body will be the raw demo file, and you can
read the headers for file metadata.
Headers
Get5 will add these HTTP headers to its demo upload request:
Get5-FileName
is the name of the file as defined byget5_demo_name_format
, i.e.2022-09-11_20-49-49_1564_map1_de_vertigo.dem
.Get5-MapNumber
is the zero-indexed map number in the series.Get5-MatchId
if the match ID is not an empty string.Get5-ServerId
ifget5_server_id
is not an empty string.Get5-Version
is the version of Get5, i.e.0.12.0
.
Authorization
If you wish to authenticate your upload request, you can define both
get5_demo_upload_header_key
and
get5_demo_upload_header_value
as a header key-value pair which
Get5 will add to the request.
Cleanup
If you set get5_demo_delete_after_upload
,
the demo file will be removed from the game server after successful upload.
Example
This is an example of how a Node.js web server using Express might read the demo upload request sent by Get5.
Proof of concept only
This is a simple proof-of-concept and should not be blindly copied to a production system. It has no HTTPS support and is only meant to demonstrate the key aspects of reading a potentially large POST request.
const express = require('express');
const fs = require('fs');
const path = require("path");
const app = express();
// Accept POST requests at http://domain.tld/upload-file
app.post('/upload-file', function (req, res) {
// Check that the authorization header configured in Get5 matches.
// Note that header names are not case-sensitive.
const authorization = req.header('Authorization');
if (authorization !== 'super_secret_key') {
res.status(403);
res.end('Invalid authorization header.');
return;
}
// Read the Get5 headers to know what to do with the file and potentially identify the server.
const filename = req.header('Get5-FileName');
const matchId = req.header('Get5-MatchId');
const mapNumber = req.header('Get5-MapNumber');
const serverId = req.header('Get5-ServerId');
// Put all demos for the same match in a folder.
const folder = path.join(__dirname, 'demos', matchId);
if (!fs.existsSync(folder)) {
fs.mkdirSync(folder, {recursive: true});
}
// Create a stream and point it to a file, using the filename from the header.
let writeStream = fs.createWriteStream(path.join(folder, filename));
// Pipe the request body into the stream.
req.pipe(writeStream);
// Wait for the request to end and reply with 200.
req.on('end', () => {
writeStream.end();
res.status(200);
res.end('Success');
});
// If there is a problem writing the file, reply with 500.
writeStream.on('error', function (err) {
res.status(500);
res.end('Error writing demo file: ' + err.message);
});
})
app.listen(8080);