Compare commits

...
Sign in to create a new pull request.

128 commits

Author SHA1 Message Date
Lanta
7fd84e8bed
Merge pull request #278 from OpzekerIT/dev
error afhandeling
2026-01-29 18:04:06 +01:00
Lanta
5691559437 error afhandeling 2026-01-29 18:03:24 +01:00
Lanta
5b2de5199b
Merge pull request #277 from OpzekerIT/dev
loterij
2026-01-29 10:58:48 +01:00
Lanta
3f2a210486 loterij 2026-01-29 10:57:07 +01:00
Lanta
355f2e8868
Merge pull request #276 from OpzekerIT/dev
Dev
2025-10-17 13:39:18 +02:00
Lanta
ca8ae31e9e win filter 2025-10-17 13:37:45 +02:00
Lanta
c4ed5551ae tdm 2025-10-17 13:37:34 +02:00
Lanta
d286bc6079
Merge pull request #275 from OpzekerIT/dev
tdm
2025-10-08 16:36:19 +02:00
Lanta
20a050148b tdm 2025-10-08 16:35:48 +02:00
Lanta
8859b603dc
Merge pull request #274 from OpzekerIT/dev
tdm be gone
2025-10-08 16:32:03 +02:00
Lanta
8499e9f073 tdm be gone 2025-10-08 16:31:19 +02:00
Lanta
209cb5f86a
Merge pull request #273 from OpzekerIT/dev
s
2025-10-08 15:55:36 +02:00
Lanta
c175319cd9 s 2025-10-08 15:54:39 +02:00
Lanta
633ab16523
Merge pull request #272 from OpzekerIT/dev
geen events
2025-10-08 15:33:56 +02:00
Lanta
890d445c78 geen events 2025-10-08 15:22:32 +02:00
Lanta
f60ac1d44d
Merge pull request #271 from OpzekerIT/dev
s
2025-10-06 09:43:42 +02:00
Lanta
cf975bccce s 2025-10-06 09:40:51 +02:00
Lanta
99a15ae703
Merge pull request #270 from OpzekerIT/dev
prompt
2025-10-06 09:34:36 +02:00
Lanta
4ce21087f4 prompt 2025-10-06 09:33:57 +02:00
Lanta
c52eaa61a4
Merge pull request #269 from OpzekerIT/dev
betere system prompt
2025-10-03 12:15:14 +02:00
Lanta
c724cd6bcb betere system prompt 2025-10-03 12:14:45 +02:00
Lanta
190e774739
Merge pull request #268 from OpzekerIT/dev
options not supported
2025-10-03 09:05:40 +02:00
Lanta
0870891747 options not supported 2025-10-03 09:05:16 +02:00
Lanta
48df01a3f6
Merge pull request #267 from OpzekerIT/dev
rate limit
2025-10-03 09:04:43 +02:00
Lanta
a36425d798 rate limit 2025-10-03 09:03:31 +02:00
Lanta
e8c0bd148d
Merge pull request #266 from OpzekerIT/dev
temp
2025-10-03 08:59:51 +02:00
Lanta
8fdc97067a temp 2025-10-03 08:55:47 +02:00
Lanta
29e370bbc2
Merge pull request #265 from OpzekerIT/dev
voice online
2025-10-02 21:36:42 +02:00
Lanta
5d2258ca1d voice online 2025-10-02 21:36:03 +02:00
Lanta
b2f6202d8d
Merge pull request #264 from OpzekerIT/dev
up
2025-10-02 21:32:42 +02:00
Lanta
2c1f956938 up 2025-10-02 21:32:18 +02:00
Lanta
1168fa4101
Merge pull request #263 from OpzekerIT/dev
s
2025-10-02 21:03:29 +02:00
Lanta
e8e4d3bcf7 s 2025-10-02 21:02:44 +02:00
Lanta
5c81889587
Merge pull request #262 from OpzekerIT/dev
onnline members in context
2025-10-02 20:53:56 +02:00
Lanta
d33030c746 onnline members in context 2025-10-02 20:52:50 +02:00
Lanta
71e32fcdb3
Merge pull request #261 from OpzekerIT/dev
Dev
2025-10-02 17:47:24 +02:00
Lanta
94c57710db context anders 2025-10-02 17:46:43 +02:00
Lanta
4c347e42af typing 2025-10-02 17:46:05 +02:00
Lanta
f106fd60c0
Merge pull request #260 from OpzekerIT/dev
s
2025-10-02 17:23:46 +02:00
Lanta
5993f6fd76 s 2025-10-02 17:22:17 +02:00
Lanta
3a395a9f61
Merge pull request #259 from OpzekerIT/dev
Dev
2025-10-02 17:18:20 +02:00
Lanta
ab8378f550 s 2025-10-02 17:17:32 +02:00
Lanta
8d7a838237 gpt 5 nano 2025-10-02 17:15:48 +02:00
Lanta
76bb2705b1
Merge pull request #258 from OpzekerIT/dev
meer stats
2025-10-02 17:00:26 +02:00
Lanta
596d7514a8 meer stats 2025-10-02 16:59:02 +02:00
Lanta
b1d7c40bb6
Merge pull request #257 from OpzekerIT/dev
Dev
2025-10-02 16:37:09 +02:00
Lanta
2b584df1a2 squad stats 2025-10-02 16:36:33 +02:00
Lanta
fbfde36813 squad 2025-10-02 16:36:16 +02:00
Lanta
de99550450
Merge pull request #256 from OpzekerIT/dev
clanmembers:
2025-10-02 16:24:03 +02:00
Lanta
65ebc9784f clanmembers: 2025-10-02 16:23:05 +02:00
Lanta
f70fba9d85
Merge pull request #255 from OpzekerIT/dev
Dev
2025-10-02 16:08:15 +02:00
Lanta
88cace125c s 2025-10-02 16:07:41 +02:00
Lanta
78debfcb09 s 2025-10-02 16:07:21 +02:00
Lanta
68381f3f3d
Merge pull request #254 from OpzekerIT/dev
opgegeven pars
2025-10-02 16:01:27 +02:00
Lanta
775d332f02 opgegeven pars 2025-10-02 16:00:50 +02:00
Lanta
cf72aa9c9e
Merge pull request #253 from OpzekerIT/dev
Dev
2025-10-02 15:47:47 +02:00
Lanta
466235dd25 ai 2025-10-02 15:47:14 +02:00
Lanta
5ef611c727 topx 2025-10-02 15:46:44 +02:00
Lanta
9c4fd72319
Merge pull request #252 from OpzekerIT/dev
ahd
2025-10-02 15:32:56 +02:00
Lanta
afed25d8ee ahd 2025-10-02 15:31:49 +02:00
Lanta
3a12f8c4c5
Merge pull request #251 from OpzekerIT/dev
Dev
2025-10-02 15:27:39 +02:00
Lanta
4757ccc9cb s 2025-10-02 15:27:13 +02:00
Lanta
c2487ade22 s 2025-10-02 15:26:57 +02:00
Lanta
ca365704f4
Merge pull request #250 from OpzekerIT/dev
stats test
2025-10-02 15:23:55 +02:00
Lanta
837f136b70 stats test 2025-10-02 15:23:13 +02:00
Lanta
7d3cbe24e1
Merge pull request #249 from OpzekerIT/dev
vraag antwoord direkt
2025-10-02 14:40:27 +02:00
Lanta
046691b068 vraag antwoord direkt 2025-10-02 14:39:15 +02:00
Lanta
db68e66ba3
Merge pull request #248 from OpzekerIT/dev
Dev
2025-10-02 14:30:12 +02:00
Lanta
2a80f52c9a discord bot 2025-10-02 14:29:30 +02:00
Lanta
83922cac1d lanta01 goed 2025-10-02 14:28:49 +02:00
Lanta
45428464fb
Merge pull request #247 from OpzekerIT/dev
denigrerende
2025-10-02 14:20:01 +02:00
Lanta
bdcad50f98 denigrerende 2025-10-02 14:17:58 +02:00
Lanta
967f79071b
Merge pull request #246 from OpzekerIT/dev
AI
2025-10-02 14:08:00 +02:00
Lanta
b4036047c7 AI 2025-10-02 14:07:40 +02:00
Lanta
294dda5354
Merge pull request #245 from OpzekerIT/dev
beh
2025-10-02 13:45:24 +02:00
Lanta
d1b153c322 beh 2025-10-02 13:44:52 +02:00
Lanta
db6e770bf9
Merge pull request #244 from OpzekerIT/dev
kanaalid
2025-10-02 13:42:33 +02:00
Lanta
7d48158e57 kanaalid 2025-10-02 13:41:41 +02:00
Lanta
7c0e9558f5
Merge pull request #243 from OpzekerIT/dev
return
2025-10-02 13:37:30 +02:00
Lanta
9794e9337a return 2025-10-02 13:37:06 +02:00
Lanta
91e04d849a
Merge pull request #242 from OpzekerIT/dev
Dev
2025-10-02 13:34:34 +02:00
Lanta
91b2a4cb40 ben er weer 2025-10-02 13:34:01 +02:00
Lanta
c82b1cd5ea text 2025-10-02 13:30:47 +02:00
Lanta
fe62e841e5 new member 2025-10-02 13:28:28 +02:00
Lanta
a59812f4ad
Merge pull request #241 from OpzekerIT/dev
dtch help
2025-10-02 13:21:48 +02:00
Lanta
4d02286ce2 dtch help 2025-10-02 13:21:24 +02:00
Lanta
4f1bc5d7c1
Merge pull request #240 from OpzekerIT/dev
help command
2025-10-02 12:00:47 +02:00
Lanta
872b87ee09 help command 2025-10-02 12:00:09 +02:00
Lanta
1e09e73ac2
Merge pull request #239 from OpzekerIT/dev
tourists
2025-10-02 10:56:52 +02:00
Lanta
56f40244c0 tourists 2025-10-02 10:54:15 +02:00
Lanta
62cc56a4af
Merge pull request #238 from OpzekerIT/dev
clanmember change
2025-09-23 12:35:39 +02:00
Lanta
7359204a9a clanmember change 2025-09-23 12:32:46 +02:00
Lanta
51bfc37ef8
Merge pull request #237 from OpzekerIT/dev
winwithurl
2025-06-19 11:24:27 +02:00
Lanta
21dd9b990b winwithurl 2025-06-19 11:23:58 +02:00
Lanta
e9991c9b31
Merge pull request #236 from OpzekerIT/dev
to pubg meta
2025-06-18 14:21:34 +02:00
Lanta
d6d9ada748 to pubg meta 2025-06-18 14:19:58 +02:00
Lanta
37e652a830
Merge pull request #235 from OpzekerIT/dev
Ghost_0223
2025-06-18 14:14:50 +02:00
Lanta
b3918e611d Ghost_0223 2025-06-18 14:13:42 +02:00
Lanta
1ab0947d12
Merge pull request #234 from OpzekerIT/dev
Theater modus
2025-06-17 19:49:08 +02:00
Lanta
f72fb0bb7d theather modus 2025-06-17 19:46:03 +02:00
Lanta
ff327d1886 theathermode 2025-06-17 19:25:00 +02:00
Lanta
af8c9ff61a video format 2025-06-17 19:11:09 +02:00
Lanta
7ef1ade9e0 theater modus 2025-06-17 18:48:52 +02:00
Lanta
fd190d2636 video dingen 2025-06-17 18:35:42 +02:00
Lanta
a76dce010d
Merge pull request #233 from OpzekerIT/dev
2d url fix
2025-06-17 17:46:16 +02:00
Lanta
dbf36ec5db 2d url fix 2025-06-17 17:45:38 +02:00
Lanta
962abb6eab
Merge pull request #232 from OpzekerIT/dev
Dev
2025-06-17 16:51:14 +02:00
Lanta
0eb08f3d2f k 2025-06-17 16:46:51 +02:00
Lanta
05796a7881 videos 2025-06-17 16:37:38 +02:00
Lanta
136c5f47d2 videos 2025-06-17 16:28:35 +02:00
Lanta
655371f229
Merge pull request #231 from OpzekerIT/dev
fix
2025-04-18 20:51:24 +02:00
Lanta
a496c39b3e fix 2025-04-18 20:50:51 +02:00
Lanta
b29cf11c87
Merge pull request #230 from OpzekerIT/dev
wtf is hier gebeurd ?!
2025-04-18 20:43:14 +02:00
Lanta
4001cde34f wtf is hier gebeurd ?! 2025-04-18 20:42:35 +02:00
Lanta
a3de04bbfb
Merge pull request #229 from OpzekerIT/dev
fix for win matches
2025-04-18 20:36:15 +02:00
Lanta
0d7981091b fix 2025-04-18 20:35:21 +02:00
Lanta
cdd9750089 losers be gone 2025-04-18 13:11:34 +02:00
Lanta
2c9b875831
Merge pull request #228 from OpzekerIT/dev
disable losers
2025-04-18 13:09:02 +02:00
Lanta
db3cc79398 disable losers 2025-04-18 13:08:25 +02:00
Lanta
f79cc64dca
Merge pull request #227 from OpzekerIT/dev
payloud empty
2025-04-18 13:05:55 +02:00
Lanta
32c2b51666 payloud empty 2025-04-18 13:05:11 +02:00
Lanta
411fbf0059
Merge pull request #226 from OpzekerIT/dev
debugging
2025-04-18 12:07:05 +02:00
Lanta
6de61e5ee0 debugging 2025-04-18 12:06:26 +02:00
Lanta
0aaea5306f
Merge pull request #225 from OpzekerIT/dev
fix
2025-04-15 19:15:08 +02:00
Lanta
9529f95c01 fix 2025-04-15 19:14:41 +02:00
Lanta
c3964d12e2
Merge pull request #224 from OpzekerIT/dev
Dev
2025-04-15 19:08:54 +02:00
Lanta
65fa001a18 test 2025-04-15 19:08:22 +02:00
Lanta
48ede491fa Force empty commit voor PR 2025-04-15 19:02:45 +02:00
10 changed files with 691 additions and 156 deletions

View file

@ -12,11 +12,12 @@
"THAIlux", "THAIlux",
"Reijn7000", "Reijn7000",
"McPikkie", "McPikkie",
"Brabo-Gamer",
"SquadKiller101", "SquadKiller101",
"HeteKip", "HeteKip",
"Pettie1972", "Pettie1972",
"Reijn7000" "Reijn7001",
"Ghost_0223",
"Bossoemang"
], ],
"alts": [ "alts": [

View file

@ -24,7 +24,7 @@ if ($fileContent -match "\`$apiKey\s*=\s*\'([^\']+)\'") {
$apiKey = $matches[1] $apiKey = $matches[1]
} }
else { else {
Write-Output "API Key not found" write-output "API Key not found"
} }
$headers = @{ $headers = @{
@ -38,15 +38,17 @@ $fileContent = Get-Content -Path "$scriptroot/../discord/config.php" -Raw
# Use regex to match the apiKey value # Use regex to match the apiKey value
if ($fileContent -match "\`$webhookurl\s*=\s*'([^']+)'") { if ($fileContent -match "\`$webhookurl\s*=\s*'([^']+)'") {
$webhookurl = $matches[1] $webhookurl = $matches[1]
} else { }
Write-Output "No web url found" else {
write-output "No web url found"
} }
# Use regex to match the losers webhook url # Use regex to match the losers webhook url
if ($fileContent -match "\`$webhookurl_losers\s*=\s*'([^']+)'") { if ($fileContent -match "\`$webhookurl_losers\s*=\s*'([^']+)'") {
$webhookurl_losers = $matches[1] $webhookurl_losers = $matches[1]
} else { }
Write-Output "No losers web url found" else {
write-output "No losers web url found"
} }
function send-discord { function send-discord {
@ -69,7 +71,13 @@ function send-discord-losers {
$payload = [PSCustomObject]@{ $payload = [PSCustomObject]@{
content = $content content = $content
} }
if ($payload.content -eq "") {
$payload = [PSCustomObject]@{
content = "Nothing to report"
}
}
Invoke-RestMethod -Uri $webhookurl_losers -Method Post -Body ($payload | ConvertTo-Json) -ContentType 'Application/Json' Invoke-RestMethod -Uri $webhookurl_losers -Method Post -Body ($payload | ConvertTo-Json) -ContentType 'Application/Json'
} }
$map_map = @{ $map_map = @{
@ -91,142 +99,142 @@ try {
$player_matches = get-content "$scriptroot/../data/player_matches.json" | convertfrom-json -Depth 100 $player_matches = get-content "$scriptroot/../data/player_matches.json" | convertfrom-json -Depth 100
} }
catch { catch {
Write-Output 'Unable to read file exitin' write-output 'Unable to read file exitin'
} }
Write-Output $player_matches write-output $player_matches
Write-Output $new_win_matches write-output $new_win_matches
$new_win_matches = $player_matches[-1].new_win_matches $new_win_matches = $player_matches[-2].new_win_matches
# Gebruik nu de lijst van nieuwe verloren matches uit het JSON-bestand # Gebruik nu de lijst van nieuwe verloren matches uit het JSON-bestand
$new_loss_matches = $player_matches[-1].new_loss_matches $new_loss_matches = $player_matches[-1].new_loss_matches
# Post verloren matches naar #losers kanaal # Post verloren matches naar #losers kanaal
foreach ($lossid in $new_loss_matches) { # foreach ($lossid in $new_loss_matches) {
$lossmatch = $player_matches.player_matches | Where-Object { $_.id -eq $lossid } # $lossmatch = $player_matches.player_matches | Where-Object { $_.id -eq $lossid }
if ($null -eq $lossmatch) { continue } # if ($null -eq $lossmatch) { continue }
if ($lossmatch[0].gameMode -eq 'tdm') { continue } # if ($lossmatch[0].gameMode -eq 'tdm') { continue }
# Fetch detailed match stats and telemetry for the loss # # Fetch detailed match stats and telemetry for the loss
$loss_match_stats = $null # $loss_match_stats = $null
$loss_telemetry = $null # $loss_telemetry = $null
try { # try {
$loss_match_stats = Invoke-RestMethod -Uri "https://api.pubg.com/shards/steam/matches/$lossid" -Method GET -Headers $headers # $loss_match_stats = Invoke-RestMethod -Uri "https://api.pubg.com/shards/steam/matches/$lossid" -Method GET -Headers $headers
$loss_telemetry = (invoke-webrequest @($lossmatch.telemetry_url)[0]).content | convertfrom-json | where-object { ($_._T -eq 'LOGPLAYERTAKEDAMAGE') -or ($_._T -eq 'LOGPLAYERKILLV2') } # $loss_telemetry = (invoke-webrequest @($lossmatch.telemetry_url)[0]).content | convertfrom-json | where-object { ($_._T -eq 'LOGPLAYERTAKEDAMAGE') -or ($_._T -eq 'LOGPLAYERKILLV2') }
} catch { # } catch {
$errorMessage = $_.Exception.Message # $errorMessage = $_.Exception.Message
Write-Warning ("Failed to fetch API/telemetry data for loss match {0}: {1}" -f $lossid, $errorMessage) # Write-Warning ("Failed to fetch API/telemetry data for loss match {0}: {1}" -f $lossid, $errorMessage)
} # }
$loss_stats_table = @() # $loss_stats_table = @()
$loss_victims = @() # For team damage # $loss_victims = @() # For team damage
# Iterate through players found in the locally stored match data for this loss # # Iterate through players found in the locally stored match data for this loss
foreach ($player_stat in $lossmatch[0].stats) { # foreach ($player_stat in $lossmatch[0].stats) {
$player_name = $player_stat.name # $player_name = $player_stat.name
# Find the corresponding detailed stats from the API response # # Find the corresponding detailed stats from the API response
$detailed_player_stats = $null # $detailed_player_stats = $null
if ($null -ne $loss_match_stats) { # if ($null -ne $loss_match_stats) {
$detailed_player_stats = $loss_match_stats.included | Where-Object {$_.type -eq 'participant'} | ForEach-Object {$_.attributes.stats} | Where-Object { $_.name -eq $player_name } # $detailed_player_stats = $loss_match_stats.included | Where-Object {$_.type -eq 'participant'} | ForEach-Object {$_.attributes.stats} | Where-Object { $_.name -eq $player_name }
} # }
if ($null -eq $detailed_player_stats) { # if ($null -eq $detailed_player_stats) {
Write-Warning "Could not find detailed stats for player $player_name in loss match $lossid. Using basic stats." # Write-Warning "Could not find detailed stats for player $player_name in loss match $lossid. Using basic stats."
# Fallback to basic stats if detailed stats are missing # # Fallback to basic stats if detailed stats are missing
$loss_stats_table += [PSCustomObject]@{ # $loss_stats_table += [PSCustomObject]@{
Name = $player_name # Name = $player_name
'Human dmg' = "N/A" # 'Human dmg' = "N/A"
'Human Kills' = "N/A" # 'Human Kills' = "N/A"
'Dmg' = "$([math]::Round($player_stat.damageDealt))" # Use basic stat # 'Dmg' = "$([math]::Round($player_stat.damageDealt))" # Use basic stat
'Kills' = "$($player_stat.kills)" # Use basic stat # 'Kills' = "$($player_stat.kills)" # Use basic stat
'alive' = "$([math]::Round(($player_stat.timeSurvived / 60)))" # Use basic stat # 'alive' = "$([math]::Round(($player_stat.timeSurvived / 60)))" # Use basic stat
} # }
continue # Skip telemetry processing if detailed stats failed # continue # Skip telemetry processing if detailed stats failed
} # }
# Calculate stats (similar to win stats calculation) # # Calculate stats (similar to win stats calculation)
$human_dmg = "N/A" # $human_dmg = "N/A"
$human_kills = "N/A" # $human_kills = "N/A"
if ($null -ne $loss_telemetry) { # if ($null -ne $loss_telemetry) {
try { # try {
$human_dmg = [math]::Round(($loss_telemetry | Where-Object { $_._T -eq 'LOGPLAYERTAKEDAMAGE' -and $_.attacker.name -eq $player_name -and $_.victim.accountId -notlike "ai.*" -and $_.victim.teamId -ne $_.attacker.teamId } | Measure-Object -Property damage -Sum).Sum) # $human_dmg = [math]::Round(($loss_telemetry | Where-Object { $_._T -eq 'LOGPLAYERTAKEDAMAGE' -and $_.attacker.name -eq $player_name -and $_.victim.accountId -notlike "ai.*" -and $_.victim.teamId -ne $_.attacker.teamId } | Measure-Object -Property damage -Sum).Sum)
$human_kills = ($loss_telemetry | Where-Object { $_._T -eq 'LOGPLAYERKILLV2' -and $_.killer.name -eq $player_name -and $_.victim.accountId -notlike "ai.*" }).count # $human_kills = ($loss_telemetry | Where-Object { $_._T -eq 'LOGPLAYERKILLV2' -and $_.killer.name -eq $player_name -and $_.victim.accountId -notlike "ai.*" }).count
} catch { # } catch {
$errorMessage = $_.Exception.Message # $errorMessage = $_.Exception.Message
Write-Warning ("Error processing telemetry stats for {0} in loss {1}: {2}" -f $player_name, $lossid, $errorMessage) # Write-Warning ("Error processing telemetry stats for {0} in loss {1}: {2}" -f $player_name, $lossid, $errorMessage)
} # }
} # }
$loss_stats_table += [PSCustomObject]@{ # $loss_stats_table += [PSCustomObject]@{
Name = $player_name # Name = $player_name
'Human dmg' = "$human_dmg" # 'Human dmg' = "$human_dmg"
'Human Kills' = "$human_kills" # 'Human Kills' = "$human_kills"
'Dmg' = "$([math]::Round($detailed_player_stats.damageDealt))" # 'Dmg' = "$([math]::Round($detailed_player_stats.damageDealt))"
'Kills' = "$($detailed_player_stats.kills)" # 'Kills' = "$($detailed_player_stats.kills)"
'alive' = "$([math]::Round(($detailed_player_stats.timeSurvived / 60)))" # 'alive' = "$([math]::Round(($detailed_player_stats.timeSurvived / 60)))"
} # }
# Calculate team damage # # Calculate team damage
if ($null -ne $loss_telemetry) { # if ($null -ne $loss_telemetry) {
try { # try {
$teamdmg = $loss_telemetry | Where-Object { # $teamdmg = $loss_telemetry | Where-Object {
$_._T -eq 'LOGPLAYERTAKEDAMAGE' -and # $_._T -eq 'LOGPLAYERTAKEDAMAGE' -and
$_.victim.teamId -eq $_.attacker.teamId -and # $_.victim.teamId -eq $_.attacker.teamId -and
$_.victim.accountId -notlike "ai.*" -and # $_.victim.accountId -notlike "ai.*" -and
$_.victim.name -ne $_.attacker.name -and # $_.victim.name -ne $_.attacker.name -and
$_.attacker.name -eq $player_name # $_.attacker.name -eq $player_name
} # }
if ($teamdmg.count -ge 1) { # if ($teamdmg.count -ge 1) {
foreach ($victim_name in ($teamdmg.victim.name | Select-Object -Unique)) { # foreach ($victim_name in ($teamdmg.victim.name | Select-Object -Unique)) {
$loss_victims += [PSCustomObject]@{ # $loss_victims += [PSCustomObject]@{
attacker = $player_name # attacker = $player_name
victim = $victim_name # victim = $victim_name
Damage = "$([math]::Round((($teamdmg | Where-Object { $_.victim.name -eq $victim_name }).damage | Measure-Object -Sum).Sum))" # Damage = "$([math]::Round((($teamdmg | Where-Object { $_.victim.name -eq $victim_name }).damage | Measure-Object -Sum).Sum))"
} # }
} # }
} # }
} catch { # } catch {
$errorMessage = $_.Exception.Message # $errorMessage = $_.Exception.Message
Write-Warning ("Error processing team damage for {0} in loss {1}: {2}" -f $player_name, $lossid, $errorMessage) # Write-Warning ("Error processing team damage for {0} in loss {1}: {2}" -f $player_name, $lossid, $errorMessage)
} # }
} # }
} # }
# Format the stats table # # Format the stats table
$content_lossstats = "" # $content_lossstats = ""
if ($loss_stats_table.Count -gt 0) { # if ($loss_stats_table.Count -gt 0) {
$content_lossstats = '```' + ($loss_stats_table | Format-Table -AutoSize | Out-String) + '```' # $content_lossstats = '```' + ($loss_stats_table | Format-Table -AutoSize | Out-String) + '```'
} # }
# Format team damage table # # Format team damage table
$content_loss_victims = "" # $content_loss_victims = ""
if ($loss_victims.Count -gt 0) { # if ($loss_victims.Count -gt 0) {
$content_loss_victims = ":skull::skull: Team Damage :skull::skull:`n" + '```' + ($loss_victims | Format-Table -AutoSize | Out-String) + '```' # $content_loss_victims = ":skull::skull: Team Damage :skull::skull:`n" + '```' + ($loss_victims | Format-Table -AutoSize | Out-String) + '```'
} # }
# Original message construction variables # # Original message construction variables
$losers = $lossmatch[0].stats.name -join ', ' # Join names for display # $losers = $lossmatch[0].stats.name -join ', ' # Join names for display
$map = $map_map[$lossmatch[0].mapName] # $map = $map_map[$lossmatch[0].mapName]
$place = ($lossmatch[0].stats | Select-Object -First 1).winPlace # Get placement from the first player stat # $place = ($lossmatch[0].stats | Select-Object -First 1).winPlace # Get placement from the first player stat
$first_player_name = ($lossmatch[0].stats | Select-Object -First 1).name # $first_player_name = ($lossmatch[0].stats | Select-Object -First 1).name
$replay_url = $lossmatch[0].telemetry_url -replace 'https://telemetry-cdn.pubg.com/bluehole-pubg', 'https://chickendinner.gg' # $replay_url = $lossmatch[0].telemetry_url -replace 'https://telemetry-cdn.pubg.com/bluehole-pubg', 'https://chickendinner.gg'
$replay_url = $replay_url -replace '-telemetry.json', '' # $replay_url = $replay_url -replace '-telemetry.json', ''
$replay_url = $replay_url + "?follow=$first_player_name" # Follow the first player # $replay_url = $replay_url + "?follow=$first_player_name" # Follow the first player
$match_settings = @" # $match_settings = @"
`````` # ``````
match mode $($lossmatch[0].gameMode) # match mode $($lossmatch[0].gameMode)
match type $($lossmatch[0].matchType) # match type $($lossmatch[0].matchType)
map $($map_map[$lossmatch[0].mapName]) # map $($map_map[$lossmatch[0].mapName])
id $($lossmatch[0].id) # id $($lossmatch[0].id)
`````` # ``````
"@ # "@
send-discord-losers -content "We hebben een LOSERT! Geen Kip voor jou! :skull::skull:" # send-discord-losers -content "We hebben een LOSERT! Geen Kip voor jou! :skull::skull:"
send-discord-losers -content ":partying_face::partying_face::partying_face: Helaas, $($losers) :partying_face::partying_face::partying_face:" # send-discord-losers -content ":partying_face::partying_face::partying_face: Helaas, $($losers) :partying_face::partying_face::partying_face:"
send-discord-losers -content $match_settings # send-discord-losers -content $match_settings
send-discord-losers -content $content_lossstats # send-discord-losers -content $content_lossstats
send-discord-losers -content $content_loss_victims # send-discord-losers -content $content_loss_victims
send-discord-losers -content "[2D replay](<$replay_url>)" # send-discord-losers -content "[2D replay](<$replay_url>)"
send-discord-losers -content "Meer match details [DTCH_STATS](<https://dtch.online/matchinfo.php?matchid=$($lossmatch[0].id)>)" # send-discord-losers -content "Meer match details [DTCH_STATS](<https://dtch.online/matchinfo.php?matchid=$($lossmatch[0].id)>)"
} # }
foreach ($winid in $new_win_matches) { foreach ($winid in $new_win_matches) {
@ -237,13 +245,20 @@ foreach ($winid in $new_win_matches) {
$winmatches = $player_matches.player_matches | Where-Object { $_.id -eq $winid } $winmatches = $player_matches.player_matches | Where-Object { $_.id -eq $winid }
$telemetry = (invoke-webrequest @($winmatches.telemetry_url)[0]).content | convertfrom-json | where-object { ($_._T -eq 'LOGPLAYERTAKEDAMAGE') -or ($_._T -eq 'LOGPLAYERKILLV2') } $telemetry = (invoke-webrequest @($winmatches.telemetry_url)[0]).content | convertfrom-json | where-object { ($_._T -eq 'LOGPLAYERTAKEDAMAGE') -or ($_._T -eq 'LOGPLAYERKILLV2') }
$winners = @(($winmatches | where-object { $_.stats.winPlace -eq 1 }).stats.name) $winners = @(($winmatches | where-object { $_.stats.winPlace -eq 1 }).stats.name)
$2D_replay_url = @($winmatches.telemetry_url)[0] -replace 'https://telemetry-cdn.pubg.com/bluehole-pubg', 'https://chickendinner.gg' # $2D_replay_url = @($winmatches.telemetry_url)[0] -replace 'https://telemetry-cdn.pubg.com/bluehole-pubg', 'https://chickendinner.gg'
$2D_replay_url = $2D_replay_url -replace '-telemetry.json', '' # $2D_replay_url = $2D_replay_url -replace '-telemetry.json', ''
$2D_replay_url = $2D_replay_url + "?follow=$($winners[0])" # $2D_replay_url = $2D_replay_url + "?follow=$($winners[0])"
$2D_replay_url = 'https://chickendinner.gg/' + $winid
$match_stats = Invoke-RestMethod -Uri "https://api.pubg.com/shards/steam/matches/$winid" -Method GET -Headers $headers $match_stats = Invoke-RestMethod -Uri "https://api.pubg.com/shards/steam/matches/$winid" -Method GET -Headers $headers
if ($winmatches[0].gameMode -eq 'tdm' ) { if ($winmatches[0].gameMode -eq 'tdm' ) {
continue continue
}
if (
($winmatches[0].matchtype -eq 'event' -and $winmatches[0].gameMode -ne 'ibr') -or
($winmatches[0].gameMode -eq 'tdm')
) {
Write-Output 'Skipping because of event or tdm'
continue
} #skip tdm matches } #skip tdm matches
if ($winmatches[0].matchType -eq 'custom') { if ($winmatches[0].matchType -eq 'custom') {
$players_to_report = $match_stats.included.attributes.stats | where-object { $_.playerId -notlike "ai.*" } $players_to_report = $match_stats.included.attributes.stats | where-object { $_.playerId -notlike "ai.*" }
@ -251,11 +266,15 @@ foreach ($winid in $new_win_matches) {
else { else {
$players_to_report = $match_stats.included.attributes.stats | where-object { $_.winplace -eq 1 } $players_to_report = $match_stats.included.attributes.stats | where-object { $_.winplace -eq 1 }
} }
$2D_replay_url = 'https://chickendinner.gg/' + $winid + "/" + $players_to_report[0].name
if ($new_win_matches.count -le 10) { if ($new_win_matches.count -le 10) {
#fail safe #fail safe
$winnerswithurl = @()
foreach ($winner in $winners) {
$winnerswithurl += "[$winner](<https://dtch.online/latestmatches.php?selected_player=$($winner)>)"
}
send-discord -content ":chicken: :chicken: **WINNER WINNER CHICKEN DINNER!!** :chicken: :chicken:" send-discord -content ":chicken: :chicken: **WINNER WINNER CHICKEN DINNER!!** :chicken: :chicken:"
send-discord -content ":partying_face::partying_face::partying_face: Gefeliciteerd $($winners -join ', ') :partying_face::partying_face::partying_face:" send-discord -content ":partying_face::partying_face::partying_face: Gefeliciteerd $($winnerswithurl -join ', ') :partying_face::partying_face::partying_face:"
$match_settings = @" $match_settings = @"
`````` ``````
match mode $($winmatches[0].gameMode) match mode $($winmatches[0].gameMode)
@ -336,6 +355,8 @@ k_t = Team eliminaties
foreach ($item in $player_matches) { foreach ($item in $player_matches) {
if ($item.PSObject.Properties.Name -contains "new_win_matches") { if ($item.PSObject.Properties.Name -contains "new_win_matches") {
$item.new_win_matches = $null $item.new_win_matches = $null
}
if ($item.PSObject.Properties.Name -contains "new_loss_matches") {
$item.new_loss_matches = $null $item.new_loss_matches = $null
} }
} }
@ -347,4 +368,5 @@ $newJson = $player_matches | ConvertTo-Json -Depth 100
$newJson | out-file "$scriptroot/../data/player_matches.json" $newJson | out-file "$scriptroot/../data/player_matches.json"
remove-lock remove-lock
Stop-Transcript Stop-Transcript

View file

@ -4,9 +4,11 @@ import discord
import random import random
import asyncio import asyncio
import re import re
from textwrap import dedent
from discord.ext import commands from discord.ext import commands
from openai import OpenAI
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
def get_token(): def get_token():
with open("config.php", "r") as file: with open("config.php", "r") as file:
content = file.read() content = file.read()
@ -29,10 +31,13 @@ intents.presences = True # Nodig als de bot presences moet zien
intents.members = True # Nodig om leden in een voice channel te zien intents.members = True # Nodig om leden in een voice channel te zien
bot = commands.Bot(command_prefix="!", intents=intents) bot = commands.Bot(command_prefix="!", intents=intents)
client = OpenAI(api_key=OPENAI_API_KEY)
@bot.event @bot.event
async def on_ready(): async def on_ready():
print(f'Bot is ingelogd als {bot.user}') print(f'Bot is ingelogd als {bot.user}')
channel = bot.get_channel(759006368832159745)
if channel:
await channel.send("Ben er weer!")
@bot.command() @bot.command()
async def test(ctx): async def test(ctx):
@ -125,19 +130,19 @@ async def teamify(ctx, *args):
await ctx.send(f"Kanaal {channel.name} is opgeruimd omdat het leeg was!") await ctx.send(f"Kanaal {channel.name} is opgeruimd omdat het leeg was!")
@bot.command() @bot.command()
async def whoisbest(ctx, category="Casual", matchesback=18): async def whoisbest(ctx, category="Casual", matchesback=18, top=3):
if category.lower() == "help": if category.lower() == "help":
help_message = ( help_message = (
"**Gebruik van het commando `whoisbest`:**\n" "**Gebruik van het commando `whoisbest`:**\n"
"`!whoisbest [category] [matchesback]`\n\n" "`!whoisbest [category] [matchesback] [top]`\n\n"
"**Parameters:**\n" "**Parameters:**\n"
"`category` - De categorie van de stats, bijv. 'Casual' of 'Ranked'. Niet hoofdlettergevoelig.\n" "`category` - De categorie van de stats, bijv. 'Casual' of 'Ranked'. Niet hoofdlettergevoelig.\n"
"`matchesback` - Het minimum aantal matches dat een speler gespeeld moet hebben om mee te tellen (standaard 18).\n\n" "`matchesback` - Het minimum aantal matches dat een speler gespeeld moet hebben om mee te tellen (standaard 18).\n\n"
"**Voorbeeld:**\n" "**Voorbeeld:**\n"
"`!whoisbest Casual 18`\n" "`!whoisbest Casual 18`\n"
"Laat de top 3 spelers zien op basis van winratio en gemiddelde damage in de Casual categorie met minimaal 18 matches.\n\n" "Laat de top 3 spelers zien op basis van winratio en gemiddelde damage in de Casual categorie met minimaal 18 matches.\n"
"Typ `!whoisbest help` om deze uitleg opnieuw te zien." "Typ `!whoisbest help` om deze uitleg opnieuw te zien."
) )
await ctx.send(help_message) await ctx.send(help_message)
@ -173,10 +178,10 @@ async def whoisbest(ctx, category="Casual", matchesback=18):
return return
# Sorteer spelers op winratio (aflopend) # Sorteer spelers op winratio (aflopend)
top_winratio = sorted(players, key=lambda x: x.get("winratio", 0), reverse=True)[:3] top_winratio = sorted(players, key=lambda x: x.get("winratio", 0), reverse=True)[:top]
# Sorteer spelers op gemiddelde damage (aflopend) # Sorteer spelers op gemiddelde damage (aflopend)
top_ahd = sorted(players, key=lambda x: x.get("ahd", 0), reverse=True)[:3] top_ahd = sorted(players, key=lambda x: x.get("ahd", 0), reverse=True)[:top]
# Bouw het bericht op # Bouw het bericht op
message = f"**\U0001F3C6 Top 3 Winratio ({actual_category})**\n" message = f"**\U0001F3C6 Top 3 Winratio ({actual_category})**\n"
@ -186,11 +191,55 @@ async def whoisbest(ctx, category="Casual", matchesback=18):
message += f"\n**\U0001F480 Top 3 AHD ({actual_category})**\n" message += f"\n**\U0001F480 Top 3 AHD ({actual_category})**\n"
for i, player in enumerate(top_ahd, start=1): for i, player in enumerate(top_ahd, start=1):
message += f"{i}. **{player['playername']}** - {player['ahd']:.2f}\n" message += f"{i}. **{player['playername']}** - {player['ahd']:.2f}\n"
##AI
await ctx.send(message) system_prompt = dedent(f"""
Je bent een Discord announcer-bot op de PUBG-server van DTCH.
Stijl: brutaal/competitief, licht denigrerend maar leesbaar.
AHD = Average Human Damage
Regels:
- Gebruik uitsluitend de meegeleverde stats-tekst.
- Output ALLEEN Discord-markdown (geen JSON, geen codeblokken).
- Structuur:
1) Titel met category en korte snedige ondertitel.
2) **🏆 Top {top} Winratio** en **💀 Top {top} AHD** (exact die koppen).
3) Per regel: 🥇/🥈/🥉 + **naam** + waarde (winratio met %).
4) De rest van de regels doe je zonder medaille gewoon een cijfer
5) Sluit af met 1 of 2 regels analyse van de stats, gebruik humor.
- Opgegeven parameters:
Categorie: {category}
Minimaal aantal matches: {matchesback}
Top: {top}
- verdere info
1) Als de aantal matches laag is (onder de 15) dan zijn cijfers niet echt meer representatief. Meld dat dan ook.
- Max ~1800 tekens.
""").strip()
user_prompt = dedent(f"""
Verpak onderstaande stats-tekst in één strakke Discord-post volgens de regels.
Wijzig geen waardes, haal alles uit de tekst tussen START/EINDE.
[STATS-TEKST START]
{message}
[STATS-TEKST EINDE]
""").strip()
response = client.chat.completions.create(
model="gpt-5-nano",
#temperature=0.6,
#presence_penalty=0.2,
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt},
],
)
antwoord = response.choices[0].message.content
await ctx.send(f"{ctx.author.mention} {antwoord[:1900]}")
except Exception as e: except Exception as e:
await ctx.send(f"Fout bij het laden van de statistieken: {str(e)}") await ctx.send(f"{ctx.author.mention} Er ging iets mis: {e}")
##AIEND
@bot.event @bot.event
async def on_voice_state_update(member, before, after): async def on_voice_state_update(member, before, after):
@ -215,7 +264,15 @@ async def on_voice_state_update(member, before, after):
async def on_member_join(member): async def on_member_join(member):
logging_channel = discord.utils.get(member.guild.text_channels, name="raadhuisplein") logging_channel = discord.utils.get(member.guild.text_channels, name="raadhuisplein")
if logging_channel: if logging_channel:
await logging_channel.send(f"🎉 Welkom {member.mention} op de server! We hopen dat je een leuke tijd hebt!") welcome_message = (
f"🎉 Welcome {member.mention} to **{member.guild.name}**!\n\n"
"👋 We're glad to have you here.\n"
"👉 Want to jump right in? Type `!iamgamer` in the chat and you'll get the **Tourists** role.\n"
"With that role you can join the fun and games with everyone else. 🎮\n"
"Use !dtch_help for more info\n\n"
"Enjoy your stay and have a great time! 🚀"
)
await logging_channel.send(welcome_message)
@bot.event @bot.event
async def on_member_remove(member): async def on_member_remove(member):
@ -251,5 +308,203 @@ async def moveall(ctx):
await ctx.send(f"{moved_members} speler(s) zijn verplaatst naar het teamify kanaal.") await ctx.send(f"{moved_members} speler(s) zijn verplaatst naar het teamify kanaal.")
else: else:
await ctx.send("Er waren geen spelers om te verplaatsen.") await ctx.send("Er waren geen spelers om te verplaatsen.")
@bot.command()
async def iamgamer(ctx):
role = discord.utils.get(ctx.guild.roles, name="Tourists")
if role is None:
await ctx.send("De rol **Tourists** bestaat niet!")
return
try:
await ctx.author.add_roles(role)
await ctx.send(f"{ctx.author.mention}, je bent nu een **Tourist**! Veel plezier! 🎮")
except Exception as e:
await ctx.send(f"Er is iets misgegaan bij het toekennen van de rol: {e}")
@bot.command(name="dtch_help", aliases=["commands"])
async def dtch_help_command(ctx):
embed = discord.Embed(
title="📖 DTCH Bot Command Help",
description="Heres a list of all available commands and how to use them:",
color=discord.Color.blue()
)
embed.add_field(
name="👉 !teamify",
value=(
"`!teamify` - Split players into random teams of max 4.\n"
"`!teamify <number_of_teams>` - Split players into a given number of teams.\n"
"`!teamify <number_of_teams> move` - Split & move players into temporary voice channels.\n"
"`!teamify move` - Auto split & move players.\n"
"🔹 Works only in the **#teamify** channel."
),
inline=False
)
embed.add_field(
name="👉 !moveall",
value="`!moveall` - Moves all players from other voice channels into the **teamify** channel.",
inline=False
)
embed.add_field(
name="👉 !whoisbest",
value=(
"`!whoisbest [category] [matchesback]`\n"
"Shows the top 3 players based on win ratio and average damage.\n"
"`category` = e.g. Casual, Ranked\n"
"`matchesback` = minimum matches required (default: 18)\n"
"Example: `!whoisbest Casual 18`"
),
inline=False
)
embed.add_field(
name="👉 !iamgamer",
value="`!iamgamer` - Gives you the **Tourists** role 🎮 so you can join games and unlock more fun.",
inline=False
)
embed.set_footer(text="✨ For advanced options, use: !teamify help or !whoisbest help")
await ctx.send(embed=embed)
@bot.command()
@commands.cooldown(1, 15, commands.BucketType.user)
async def ask(ctx, *, vraag: str):
## CLAN MEMBERS
file_path = os.path.join("..", "config", "clanmembers.json")
# Inlezen als string
with open(file_path, "r", encoding="utf-8") as f:
clanmembers_str = f.read()
#LIFETIME STATS
file_path_lifetimestats = os.path.join("..", "data", "player_lifetime_data.json")
with open(file_path_lifetimestats, "r", encoding="utf-8") as file:
data_lifetimestats = json.load(file)
squad_str = json.dumps(data_lifetimestats.get("squad", {}), indent=2)
#Last stats
file_path_laststats = os.path.join("..", "data", "player_last_stats.json")
with open(file_path_laststats, "r", encoding="utf-8") as file:
data_laststat = json.load(file)
casual_str = json.dumps(data_laststat.get("Casual", []), indent=2)
ranked_str = json.dumps(data_laststat.get("Ranked", []), indent=2)
custom_str = json.dumps(data_laststat.get("custom", []), indent=2)
# Online members
voice_members = [
member.display_name
for vc in ctx.guild.voice_channels
for member in vc.members
]
voice_str = ", ".join(voice_members) if voice_members else "Niemand zit in een voice kanaal"
"""Stuur een vraag naar OpenAI"""
try:
async with ctx.typing():
response = client.chat.completions.create(
model="gpt-5-nano",
messages=[
{
"role": "system",
"content": (
"Je bent een licht denigrerende chatbot in Discord, actief op de PUBG server van clan DTCH. "
f"De vraag is gesteld door {ctx.author.display_name}. "
# Context
f"Clanleden: {clanmembers_str}. "
f"Momenteel in voice: {voice_str}. "
f"Lifetime stats (squad): {squad_str}. "
f"Casual (spelen we toch wel het vaakst met elkaar, belangrijke stat dus) stats: {casual_str}. "
f"Ranked stats: {ranked_str}. "
f"Custom stats (clan games meestal tegen elkaar): {custom_str}. "
# Richtlijnen voor antwoord
"Houd je antwoorden kort en bondig, met maximaal 1600 tekens. "
"Kill Death Human (KD_H) en winrato zijn de belangrijkste stats omdat bots heel makkelijk te killen zijn vinden de Human Kill death het belangrijkste"
"Gebruik Discord markdown (``` of **vetgedrukt**) wanneer je stats of tabellen toont. "
"Wees een beetje sarcastisch, maar wel begrijpelijk. "
"Stel geen vragen want je hebt geen context bij de volgende prompt."
)
},
{"role": "user", "content": vraag},
],
)
antwoord = response.choices[0].message.content
await ctx.send(f"{ctx.author.mention} {antwoord[:1900]}")
except Exception as e:
await ctx.send(f"{ctx.author.mention} Er ging iets mis: {e}")
@ask.error
async def ask_error(ctx, error):
if isinstance(error, commands.CommandOnCooldown):
retry_after = int(error.retry_after + 0.999)
await ctx.reply(f"Rustig {ctx.author.display_name}, probeer het over {retry_after}s nog eens.")
else:
raise error
@bot.command()
async def loterij(ctx, *members: discord.Member):
"""
Gebruik:
!loterij @naam1 @naam2 @naam3
"""
# Alleen in #teamify? -> uncomment als je dat ook wilt
# if ctx.channel.name != "teamify":
# await ctx.send("Dit commando kan alleen worden gebruikt in het #teamify kanaal.")
# return
if not members or len(members) < 2:
await ctx.send("Gebruik: `!loterij @naam1 @naam2 ...` (minimaal 2 mensen, anders is het wel héél zielig).")
return
# Uniek maken (als iemand 2x getagd wordt telt 'ie maar 1x mee)
unique_members = []
seen_ids = set()
for m in members:
if m.id not in seen_ids:
unique_members.append(m)
seen_ids.add(m.id)
# Tekst “tussen A, B en C” netjes bouwen
mentions = [m.mention for m in unique_members]
if len(mentions) == 2:
between_text = f"{mentions[0]} en {mentions[1]}"
else:
between_text = f"{', '.join(mentions[:-1])} en {mentions[-1]}"
winnaar = random.choice(unique_members)
await ctx.send(f"En de loterij gaat tussen {between_text}.")
# Countdown
await asyncio.sleep(1)
await ctx.send("in 3")
await asyncio.sleep(1)
await ctx.send("2")
await asyncio.sleep(1)
await ctx.send("1")
await asyncio.sleep(1)
await ctx.send("trom gerofel 🥁")
await asyncio.sleep(1)
await ctx.send(f"De winnaar is {winnaar.mention} 🎆🎇")
@loterij.error
async def loterij_error(ctx, error):
if isinstance(error, commands.BadArgument):
await ctx.send(
"Ik snap er niks van 🤨\n"
"Gebruik het zo:\n"
"`!loterij @naam1 @naam2 @naam3`\n"
"Zorg dat je **echte Discord-mentions** gebruikt."
)
else:
raise error
bot.run(token) bot.run(token)

View file

@ -12,7 +12,8 @@ if ($host == 'dev.dtch.online') {
<a href="last_stats.php">Last quarter %</a> <a href="last_stats.php">Last quarter %</a>
<a href="latestmatches.php">Last Matches</a> <a href="latestmatches.php">Last Matches</a>
<a href="topstats.php">Top20</a> <a href="topstats.php">Top20</a>
<a href="user_stats.php">User Stats</a> <a href="user_stats.php">User Stats</a>
<a href="videos.php">Videos</a>
</div> </div>
<a href="javascript:void(0);" class="icon" onclick="myFunction()"> <a href="javascript:void(0);" class="icon" onclick="myFunction()">
<i class="fa fa-bars"></i> <i class="fa fa-bars"></i>

View file

@ -240,3 +240,87 @@ td, th {
background-color: #0f0f0f; background-color: #0f0f0f;
color: #e69109; color: #e69109;
} }
/* Videos page styles */
.videos-container {
display: flex;
flex-wrap: wrap;
gap: 16px;
justify-content: center;
padding: 1rem;
}
.video-item {
flex: 1 1 300px;
max-width: 100%;
}
.video-item video {
max-width: 100%;
max-height: 80vh;
width: auto;
height: auto;
object-fit: contain;
display: block;
margin: 0 auto;
}
/* Share and theatre button styles */
.video-controls {
display: flex;
justify-content: center;
align-items: center;
margin-top: 0.5rem;
gap: 0.5rem;
}
/* Theatre mode styles */
.video-item.theatre-mode {
flex: 1 1 100%;
max-width: 100%;
}
.video-item.theatre-mode video {
width: 100%;
height: auto;
max-height: none;
}
.video-title {
text-align: center;
font-size: 1.2em;
font-weight: bold;
margin-top: 10px;
margin-bottom: 10px;
}
.video-item.theatre-mode {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.9);
z-index: 1000;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20px;
box-sizing: border-box;
}
.video-item.theatre-mode video {
max-width: 90%;
max-height: 80vh;
width: auto;
height: auto;
}
.video-item.theatre-mode .video-title {
color: #fff;
order: -1; /* Display title above the video */
}
.video-item.theatre-mode .video-controls {
position: relative;
bottom: auto;
margin-top: 15px;
}

View file

@ -5,6 +5,16 @@ table {
td, th { td, th {
padding: 8px; padding: 8px;
} }
/* Theatre mode mobile styles */
.video-item.theatre-mode {
flex: 1 1 100%;
max-width: 100%;
}
.video-item.theatre-mode video {
width: 100%;
height: auto;
max-height: none;
}
.topnav { .topnav {
overflow: hidden; overflow: hidden;
@ -81,4 +91,50 @@ table {
section h2 { section h2 {
margin-top: 10px; margin-top: 10px;
}
/* Videos page responsive adjustments */
.videos-container {
display: flex;
flex-wrap: wrap;
gap: 16px;
justify-content: center;
padding: 1rem;
}
.video-item {
flex: 1 1 100%;
max-width: 100%;
}
.video-item video {
width: 100%;
max-width: 100%;
height: auto;
display: block;
margin: 0 auto;
}
/* Share and theatre button mobile styles */
.video-controls {
display: flex;
justify-content: center;
align-items: center;
margin-top: 0.5rem;
gap: 0.5rem;
}
.video-title {
text-align: center;
font-size: 1.1em;
font-weight: bold;
margin-top: 8px;
margin-bottom: 8px;
}
.video-item.theatre-mode {
padding: 10px;
}
.video-item.theatre-mode video {
max-width: 100%;
max-height: 70vh;
}
.video-item.theatre-mode .video-controls {
margin-top: 10px;
} }

View file

@ -157,15 +157,15 @@ $lastMatches = array_slice($allMatches, 0, 8);
if (substr($playerStats['playerId'], 0, 2) !== 'ai') { if (substr($playerStats['playerId'], 0, 2) !== 'ai') {
// Create links for each stat // Create links for each stat
echo "<tr>"; echo "<tr>";
echo "<td><a href='https://pubg.op.gg/user/" . urlencode($playerStats['name']) . "' target='_blank'>" . htmlspecialchars($playerStats['name']) . "</a></td>"; echo "<td><a href='https://www.pubg-meta.com/player-stats/steam/" . urlencode($playerStats['name']) . "' target='_blank'>" . htmlspecialchars($playerStats['name']) . "</a></td>";
echo "<td><a href='https://pubg.op.gg/user/" . urlencode($playerStats['name']) . "' target='_blank'> Human </a></td>"; echo "<td><a href='https://www.pubg-meta.com/player-stats/steam/" . urlencode($playerStats['name']) . "' target='_blank'> Human </a></td>";
echo "<td><a href='https://pubg.op.gg/user/" . urlencode($playerStats['name']) . "' target='_blank'>" . htmlspecialchars($playerStats['kills']) . "</a></td>"; echo "<td><a href='https://www.pubg-meta.com/player-stats/steam/" . urlencode($playerStats['name']) . "' target='_blank'>" . htmlspecialchars($playerStats['kills']) . "</a></td>";
echo "<td><a href='https://pubg.op.gg/user/" . urlencode($playerStats['name']) . "' target='_blank'>" . htmlspecialchars($playerStats['HumanDmg']) . "</a></td>"; echo "<td><a href='https://www.pubg-meta.com/player-stats/steam/" . urlencode($playerStats['name']) . "' target='_blank'>" . htmlspecialchars($playerStats['HumanDmg']) . "</a></td>";
echo "<td><a href='https://pubg.op.gg/user/" . urlencode($playerStats['name']) . "' target='_blank'>" . htmlspecialchars($playerStats['timeSurvived']) . "</a></td>"; echo "<td><a href='https://www.pubg-meta.com/player-stats/steam/" . urlencode($playerStats['name']) . "' target='_blank'>" . htmlspecialchars($playerStats['timeSurvived']) . "</a></td>";
echo "<td><a href='https://pubg.op.gg/user/" . urlencode($playerStats['name']) . "' target='_blank'>" . htmlspecialchars($playerStats['winPlace']) . "</a></td>"; echo "<td><a href='https://www.pubg-meta.com/player-stats/steam/" . urlencode($playerStats['name']) . "' target='_blank'>" . htmlspecialchars($playerStats['winPlace']) . "</a></td>";
echo "<td><a href='https://pubg.op.gg/user/" . urlencode($playerStats['name']) . "' target='_blank'>" . htmlspecialchars($playerStats['revives']) . "</a></td>"; echo "<td><a href='https://www.pubg-meta.com/player-stats/steam/" . urlencode($playerStats['name']) . "' target='_blank'>" . htmlspecialchars($playerStats['revives']) . "</a></td>";
echo "<td><a href='https://pubg.op.gg/user/" . urlencode($playerStats['name']) . "' target='_blank'>" . htmlspecialchars($playerStats['DBNOs']) . "</a></td>"; echo "<td><a href='https://www.pubg-meta.com/player-stats/steam/" . urlencode($playerStats['name']) . "' target='_blank'>" . htmlspecialchars($playerStats['DBNOs']) . "</a></td>";
echo "<td><a href='https://pubg.op.gg/user/" . urlencode($playerStats['name']) . "' target='_blank'>" . htmlspecialchars($playerStats['assists']) . "</a></td>"; echo "<td><a href='https://www.pubg-meta.com/player-stats/steam/" . urlencode($playerStats['name']) . "' target='_blank'>" . htmlspecialchars($playerStats['assists']) . "</a></td>";
echo "</tr>"; echo "</tr>";
} else { } else {
// Display without link // Display without link

View file

@ -48,7 +48,13 @@ foreach ($player in $player_data) {
$stats.included = $sortedStats $stats.included = $sortedStats
$stats | ConvertTo-Json -Depth 100 | Out-File "$scriptroot/../data/matches/$match.json" $stats | ConvertTo-Json -Depth 100 | Out-File "$scriptroot/../data/matches/$match.json"
} }
if (
($stats.data.attributes.matchtype -eq 'event' -and $stats.data.attributes.gameMode -ne 'ibr') -or
($stats.data.attributes.gameMode -eq 'tdm')
) {
Write-Output 'Skipping because of event or tdm'
continue
}
$playermatches += [PSCustomObject]@{ $playermatches += [PSCustomObject]@{
stats = $stats.included.ATTRIBUTES.stats | where-object { $_.name -eq $player.attributes.name } stats = $stats.included.ATTRIBUTES.stats | where-object { $_.name -eq $player.attributes.name }
matchType = $stats.data.attributes.matchtype matchType = $stats.data.attributes.matchtype

View file

@ -161,6 +161,14 @@ $groupedGuids_clan_matches_gt_3 = $guids | Group-Object | Where-Object { $_.Coun
$last_month = (get-date).AddMonths($monthsback) $last_month = (get-date).AddMonths($monthsback)
foreach ($file in $matchfiles) { foreach ($file in $matchfiles) {
$json = get-content $file | ConvertFrom-Json $json = get-content $file | ConvertFrom-Json
if (
($stats.data.attributes.matchtype -eq 'event' -and $stats.data.attributes.gameMode -ne 'ibr') -or
($stats.data.attributes.gameMode -eq 'tdm')
) {
Write-Output 'Skipping because of event or tdm'
continue
}
if ($json.created -gt $last_month) { if ($json.created -gt $last_month) {
$killstats += $json $killstats += $json
if ($groupedGuids_clan_matches_gt_1.Name -contains $json.matchid) { if ($groupedGuids_clan_matches_gt_1.Name -contains $json.matchid) {

102
videos.php Normal file
View file

@ -0,0 +1,102 @@
<?php
$ogDescription = "Bekijk alle video's";
// Scan the media/videos directory for mp4 files
$videosDir = __DIR__ . '/media/videos';
$allFiles = scandir($videosDir);
$videoFiles = array_filter($allFiles, function($file) use ($videosDir) {
return is_file($videosDir . '/' . $file) && strtolower(pathinfo($file, PATHINFO_EXTENSION)) === 'mp4';
});
// Build array with creation time and sort by creation date descending
$videoData = [];
foreach ($videoFiles as $file) {
$path = $videosDir . '/' . $file;
$videoData[] = [
'filename' => $file,
'ctime' => filectime($path)
];
}
usort($videoData, function($a, $b) {
return $b['ctime'] - $a['ctime'];
});
?>
<!DOCTYPE html>
<html lang="en">
<?php include './includes/head.php'; ?>
<body>
<?php include './includes/navigation.php'; ?>
<?php include './includes/header.php'; ?>
<main>
<section>
<h2>Videos</h2>
<?php if (!empty($videoData)): ?>
<div class="videos-container">
<?php foreach ($videoData as $video): ?>
<div class="video-item">
<video controls>
<source src="media/videos/<?php echo htmlspecialchars($video['filename']); ?>" type="video/mp4">
Your browser does not support the video tag.
</video>
<p class="video-title"><?php echo pathinfo($video['filename'], PATHINFO_FILENAME); ?></p>
<div class="video-controls">
<button class="btn share-btn">Delen</button>
<button class="btn theatre-btn">Theatermodus</button>
</div>
</div>
<?php endforeach; ?>
</div>
<?php else: ?>
<p>No videos found.</p>
<?php endif; ?>
</section>
</main>
<?php include './includes/footer.php'; ?>
<script>
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('.share-btn').forEach(function(btn) {
btn.addEventListener('click', function() {
var videoItem = btn.closest('.video-item');
var src = videoItem.querySelector('video source').src;
if (navigator.share) {
navigator.share({ title: videoItem.querySelector('p').innerText, url: src })
.catch(function(error) { console.error('Error sharing', error); });
} else if (navigator.clipboard) {
navigator.clipboard.writeText(src).then(function() {
alert('Videolink gekopieerd naar klembord');
}, function(err) {
alert('Kon link niet kopiëren: ' + err);
});
} else {
prompt('Kopieer deze link:', src);
}
});
});
document.querySelectorAll('.theatre-btn').forEach(function(btn) {
btn.addEventListener('click', function() {
var clickedVideoItem = btn.closest('.video-item');
// Remove theatre mode from all other videos
document.querySelectorAll('.video-item.theatre-mode').forEach(function(item) {
if (item !== clickedVideoItem) {
item.classList.remove('theatre-mode');
item.querySelector('.theatre-btn').innerText = 'Theatermodus';
}
});
// Toggle theatre mode for the clicked video
var isActive = clickedVideoItem.classList.toggle('theatre-mode');
btn.innerText = isActive ? 'Sluit theatermodus' : 'Theatermodus';
});
});
});
</script>
</body>
</html>