Skip to content

Commit 8637bd3

Browse files
author
Shugo Kawamura
authored
Merge pull request #28 from utage-tech/afx-csgo-broadcast
Supported some of hidden args(A,C,F) B is not supported yet!
2 parents 11fd574 + 61453af commit 8637bd3

File tree

5 files changed

+169
-55
lines changed

5 files changed

+169
-55
lines changed

public/js/hostname.js

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,49 @@
11

22
const steamplay = "steam://rungame/730/76561202255233023/+playcast%20%22"
33

4-
function RewriteIp(element,prefix){ // aタグのリンクを現在のホスト名に書き換える
4+
function RewriteIp(element,prefix,postfix){ // aタグのリンクを現在のホスト名に書き換える
55
var href = steamplay + prefix + element.attr("href");
6-
console.log("href :" + href + "%22")
7-
element.attr("href", href + "%22")
6+
console.log("href :" + href + postfix)
7+
element.attr("href", href + postfix)
88
}
99

10-
var ip = location.href;
10+
const ip = location.href;
1111
var match = ip + "match/"
12-
var replay = ip + "match/"
12+
var replay = ip + "replay/"
1313

1414
console.log(ip);
1515

1616
$(function () {
17-
$('#a_match').each(function(index, element) {
18-
RewriteIp($(element),match)
19-
})
20-
21-
$('#a_replay').each(function(index, element) {
22-
RewriteIp($(element),replay)
23-
})
24-
});
17+
$("a[data-type='a_match']").each(function(i){
18+
RewriteIp($(this),match,"%22")
19+
});
20+
21+
$("a[data-type='a_replay']").each(function(i){
22+
RewriteIp($(this),replay,"%22")
23+
});
24+
25+
$("a[data-type='a_replay-a']").each(function(i){
26+
RewriteIp($(this), match,"%22%20a") // [" a"]
27+
});
28+
29+
$("a[data-type='a_replay-c']").each(function(i){
30+
RewriteIp($(this),match,"%22%20c") // [" c"]
31+
});
32+
33+
replay_f(0);
34+
})
35+
36+
$("th[data-type='a_replay-f']").children('input').keyup(function () {
37+
replay_f($(this).val())
38+
console.log($(this).val())
39+
});
40+
41+
function replay_f(frag) {
42+
$("th[data-type='a_replay-f']").each(function(i){
43+
//console.log('test')
44+
var token = $(this).children('a').attr("data-token")
45+
var play = steamplay + match + token + "%22%20f" + frag
46+
console.log(play)
47+
$(this).children('a').attr("href",play)
48+
});
49+
}

readme.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## Counter-Strike: Global Offensive tv_broadcast GOTV+ Server
2+
https://developer.valvesoftware.com/wiki/Counter-Strike:_Global_Offensive_Broadcast
3+
GOTV+,HTTP and dem based GOTV. Supports CDN,HLAE,Reshade and other external softwere.
4+
15
# Todo
26

37
-> Save matches as a demo replay
@@ -9,7 +13,7 @@
913
### Installation
1014
1. `npm i`
1115
2. `npm i -g typescript`
12-
3. `build`
16+
3. `npm run build`
1317

1418
### Usage
1519
1. `npm start` to start tv_broadcast server

src/config.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
module.exports = {
2+
port: 3000,
23
EnableAuth : false,
34
auth: "SuperStrongPassword",
4-
DropS1Frag: false
5+
DropS1Frag: false,
6+
frag_delay: 10
57
}

src/server.ts

Lines changed: 90 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,14 @@ app.get('/replay/:token/sync', function (req:any, res:any) {
2626
var r_sync = match[req.params.token].firstsync
2727
const r = {
2828
tick: r_sync.tick,
29-
rtdelay: sync.rtdelay,
30-
rcvage: sync.rcvage,
29+
//rtdelay: sync.rtdelay,
30+
rtdelay: 2,
31+
//rcvage: r_sync.rcvage,
32+
rcvage: 2,
3133
fragment: r_sync.fragment,
3234
signup_fragment: sync.signup_fragment,
3335
tps: sync.tps,
34-
protocool: sync.protocool,
36+
protocol: sync.protocol,
3537
}
3638
//console.log(r)
3739
res.send(r);
@@ -65,18 +67,19 @@ app.get('/replay/:token/:fragment_number/:frametype', function (req:any, res:any
6567
// playcast "http://586f7685.ngrok.io/match/s85568392920768736t1477086968"
6668
app.post('/reset/:token/', (req:any, res:any) => {
6769
res.send("ACK");
68-
match[req.params.token].sync.signup_fragment = null;
70+
match[req.params.token].sync.signup_fragment = -1;
6971
})
7072

7173

7274
class Matches{
73-
sync: match_sync
74-
firstsync: replay_sync // sync for replay
75-
start:any = []
76-
full:any = []
77-
delta: any = []
78-
token: string
79-
time: string;
75+
public sync: match_sync
76+
public firstsync: replay_sync // sync for replay
77+
public start:any = []
78+
public full:any = []
79+
public delta: any = []
80+
public token: string
81+
public auth: string
82+
public time: string
8083

8184
constructor() {
8285
this.sync = new match_sync();
@@ -85,27 +88,54 @@ class Matches{
8588
this.full[-1] = Buffer.alloc(16, 0, "binary")
8689
this.delta[-1] = Buffer.alloc(16, 0, "binary")
8790
this.token = ""
91+
this.auth = ""
8892
this.time = new Date().toJSON()
8993
}
9094
}
9195

9296
class match_sync{
93-
tick: number
94-
rtdelay: number
95-
rcvage: number
96-
fragment: number
97-
signup_fragment: number
98-
tps: number
99-
protocool: number;
100-
97+
public tick: number
98+
//public rtdelay: number
99+
private _rtdelay: Date
100+
private _rcvage: Date
101+
public fragment: number
102+
public signup_fragment: number
103+
public tps: number
104+
public protocol : number;
105+
public full_received: any
106+
public full_received_tick: any
107+
101108
constructor() {
102109
this.tick = -1
103-
this.rtdelay = 2
104-
this.rcvage = 2
110+
this._rtdelay = new Date()
111+
//this.rtdelay = 2
112+
this._rcvage = new Date()
105113
this.fragment = -1
106114
this.signup_fragment = -1
107115
this.tps = 32
108-
this.protocool = 4
116+
this.protocol = 4
117+
this.full_received = {};
118+
this.full_received_tick = {}
119+
}
120+
121+
122+
public rtdelay(i:number) {
123+
var now = new Date()
124+
//var i = this.fragment - config.frag_delay
125+
var selected_full = this.full_received[i];
126+
var sec = ((now.getTime() - selected_full.getTime()) / 1000);
127+
console.log(sec)
128+
return sec;
129+
}
130+
131+
132+
public rcvage() {
133+
var now = new Date()
134+
var i = this.fragment;
135+
var last_full = this.full_received[i];
136+
var sec = ((now.getTime() - last_full.getTime()) / 1000);
137+
console.log(sec)
138+
return sec;
109139
}
110140
}
111141

@@ -118,19 +148,47 @@ class replay_sync{
118148
this.fragment = -1 }
119149
}
120150

121-
var match: any = {}
151+
var match: Imatches = {};
152+
interface Imatches{
153+
[x:string]:Matches
154+
}
122155

123156
app.get('/match/:token/sync', function (req:any, res:any) {
124157
console.log("match sync!")
125-
res.set('Cache-Control', 'public, max-age=1'); // cache 1sec for delayed live
126-
const r = match[req.params.token].sync
127-
//console.log(r)
158+
var sync = match[req.params.token].sync
159+
var r: any;
160+
res.set('Cache-Control', 'public, max-age=5'); // cache 5sec for delayed live
161+
if (req.query.fragment) {
162+
r = {
163+
tick: sync.full_received_tick[req.query.fragment],
164+
rtdelay: sync.rtdelay(req.query.fragment),
165+
rcvage: sync.rcvage(),
166+
fragment: req.query.fragment,
167+
signup_fragment: sync.signup_fragment,
168+
tps: sync.tps,
169+
protocol: sync.protocol,
170+
}
171+
}
172+
else {
173+
var frag = sync.fragment - config.frag_delay;
174+
r = {
175+
tick: sync.tick,
176+
rtdelay: sync.rtdelay(frag),
177+
rcvage: sync.rcvage(),
178+
fragment: frag,
179+
signup_fragment: sync.signup_fragment,
180+
tps: sync.tps,
181+
protocol: sync.protocol,
182+
}
183+
}
184+
185+
console.log(r)
128186
res.send(r);
129187
})
130188

131189
app.get('/match/:token/:fragment_number/:frametype', function (req:any, res:any) {
132190
console.log('Fragment request for',req.params.fragment_number)
133-
res.set('Cache-Control', 'public, max-age=1'); // cache 1sec for delayed live
191+
res.set('Cache-Control', 'public, max-age=86400'); // cache 1sec for delayed live
134192
res.setHeader('Content-Type', 'application/octet-stream')
135193
var p = Buffer.alloc(16, 0, 'binary');
136194
if (req.params.frametype == 'start') {
@@ -172,6 +230,7 @@ app.post('/:token/:fragment_number/:frametype', function (req:any, res:any) {
172230
match[req.params.token].sync.signup_fragment = req.params.fragment_number
173231
match[req.params.token].start[req.params.fragment_number] = req.body
174232
match[req.params.token].token = req.params.token
233+
match[req.params.token].auth = req.headers["x-origin-auth"]
175234
}
176235
else {
177236
if (match[req.params.token].sync.signup_fragment == -1) {
@@ -195,6 +254,8 @@ app.post('/:token/:fragment_number/:frametype', function (req:any, res:any) {
195254
res.status(200).send("OK");
196255
match[req.params.token].sync.fragment = req.params.fragment_number
197256
match[req.params.token].full[req.params.fragment_number] = req.body
257+
match[req.params.token].sync.full_received[req.params.fragment_number] = new Date()
258+
match[req.params.token].sync.full_received_tick[req.params.fragment_number] = req.query.tick
198259
if (match[req.params.token].firstsync.fragment == -1) {
199260
match[req.params.token].firstsync.fragment = req.params.fragment_number
200261
}
@@ -207,6 +268,6 @@ app.post('/:token/:fragment_number/:frametype', function (req:any, res:any) {
207268
}
208269
})
209270

210-
app.listen(3000, function () {
211-
console.log('CSGO broadcast server listening on port 3000!');
271+
app.listen(config.port, function () {
272+
console.log(`CSGO broadcast server listening on port ${config.port}!`);
212273
});

views/plays.pug

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,42 @@
11
head
22
title #{title}
3-
script(src="https://code.jquery.com/jquery-3.4.1.min.js")
4-
script(src="./public/js/hostname.js ")
3+
meta(charset="utf-8")
4+
meta(name="viewport" content="width=device-width, initial-scale=1.0")
5+
// Compiled and minified CSS
6+
link( rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css")
7+
// Compiled and minified JavaScript
8+
script(src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js")
9+
link(rel='stylesheet', href="css/style.css")
510
body
611
table
712
thead
813
tr
9-
th Play
10-
td timestamp
14+
th Play w/Delay
15+
th Replay
16+
th Replay-A (f=1 with /sync)
17+
th Replay-C (f=0 w/o /sync)
18+
th Replay-F (specific frag with /sync)
19+
td time
20+
td auth
1121
td token
1222
tbody
1323
each item in matches
14-
tr
15-
th
16-
a(id="a_match" href=`${item.token}`) Play
17-
th
18-
a(id="a_replay" href=`${item.token}`) Replay
19-
td=item.time
20-
td=item.token
24+
tr
25+
th
26+
a(data-type="a_match" href=`${item.token}`) Play
27+
th
28+
a(data-type="a_replay" href=`${item.token}`) Replay
29+
th
30+
a(data-type="a_replay-a" href=`${item.token}`) Replay-A
31+
th
32+
a(data-type="a_replay-c" href=`${item.token}`) Replay-C
33+
th(data-type="a_replay-f")
34+
a(href=`${item.token}` data-token=`${item.token}`) Replay-F
35+
input(type="number" placeholder="frag number" data-type="a_replay-f-specify")
36+
td=item.time
37+
td=item.auth
38+
td=item.token
39+
40+
script(src="https://code.jquery.com/jquery-3.4.1.min.js")
41+
script(src="./public/js/hostname.js")
42+

0 commit comments

Comments
 (0)