From 19bd79c05628fb21142cff59e6ddb9fc96e4244d Mon Sep 17 00:00:00 2001
From: Akurosia Kamo
Date: Fri, 22 May 2026 08:43:45 +0200
Subject: [PATCH] if tank is selected track also tankbuster on login keep url
params
---
api/analysis.php | 33 +++++++++++++++++++++++++++------
auth/callback.php | 21 +++++++++++++--------
auth/start.php | 1 +
js/analysis.js | 5 +++--
js/app.js | 9 +++++++--
templates/login.php | 2 +-
templates/report-form.php | 2 +-
7 files changed, 53 insertions(+), 20 deletions(-)
diff --git a/api/analysis.php b/api/analysis.php
index 282d02f..3fcefbc 100644
--- a/api/analysis.php
+++ b/api/analysis.php
@@ -333,6 +333,7 @@ if (!empty($shieldStatusIds)) {
// Group events by abilityId, then cluster by time proximity (≤ 1000ms from
// the first event in the cluster) to avoid fixed-window boundary splits.
const CLUSTER_WINDOW_MS = 1000;
+const HEAVY_TANKBUSTER_MIN_HP_RATIO = 0.33;
$byAbility = []; // abilityId → [{ts, tgtId, amount, hp, maxHp, buffs, name}]
foreach ($allEvents as $ev) {
@@ -404,7 +405,26 @@ foreach ($byAbility as $abId => $events) {
$aoeEvents = [];
foreach ($clusters as $group) {
- if (count($group['targets']) < 3) continue;
+ $targetCount = count($group['targets']);
+ $isHeavyTankbuster = false;
+ if ($targetCount < 3) {
+ foreach ($group['targets'] as $tgtId => $tgt) {
+ $p = $players[$tgtId] ?? null;
+ if (($p['role'] ?? null) !== 'tank') continue;
+
+ $tankMaxHp = (int)($tgt['maxHp'] ?? 0);
+ $rawDamage = max(
+ (int)($tgt['unmitigatedAmount'] ?? 0),
+ (int)($tgt['amount'] ?? 0) + (int)($tgt['absorbed'] ?? 0) + (int)($tgt['mitigated'] ?? 0)
+ );
+ if ($tankMaxHp > 0 && $rawDamage >= $tankMaxHp * HEAVY_TANKBUSTER_MIN_HP_RATIO) {
+ $isHeavyTankbuster = true;
+ break;
+ }
+ }
+ }
+
+ if ($targetCount < 3 && !$isHeavyTankbuster) continue;
$targets = [];
foreach ($group['targets'] as $tgtId => $tgt) {
@@ -443,11 +463,12 @@ foreach ($clusters as $group) {
});
$aoeEvents[] = [
- 'timestamp' => $group['timestamp'],
- 'abilityId' => $group['abilityId'],
- 'abilityName' => $group['abilityName'],
- 'targets' => $targets,
- 'totalDamage' => array_sum(array_column($targets, 'amount')),
+ 'timestamp' => $group['timestamp'],
+ 'abilityId' => $group['abilityId'],
+ 'abilityName' => $group['abilityName'],
+ 'targets' => $targets,
+ 'totalDamage' => array_sum(array_column($targets, 'amount')),
+ 'isHeavyTankbuster' => $isHeavyTankbuster,
];
}
usort($aoeEvents, fn($a, $b) => $a['timestamp'] <=> $b['timestamp']);
diff --git a/auth/callback.php b/auth/callback.php
index 795a115..b96897d 100644
--- a/auth/callback.php
+++ b/auth/callback.php
@@ -2,10 +2,17 @@
require_once __DIR__ . '/../config.php';
session_start_safe();
+function redirect_with_error(string $returnPath, string $error): void {
+ $separator = str_contains($returnPath, '?') ? '&' : '?';
+ header('Location: ' . $returnPath . $separator . 'error=' . rawurlencode($error));
+ exit;
+}
+
+$returnPath = safe_return_path($_SESSION['oauth_return'] ?? null);
+
// user denied access
if (isset($_GET['error'])) {
- header('Location: ../index.php?error=' . urlencode($_GET['error']));
- exit;
+ redirect_with_error($returnPath, $_GET['error']);
}
// CSRF check
@@ -21,12 +28,11 @@ if (
}
if (empty($_GET['code'])) {
- header('Location: ../index.php?error=missing_code');
- exit;
+ redirect_with_error($returnPath, 'missing_code');
}
$verifier = $_SESSION['pkce_verifier'];
-unset($_SESSION['pkce_verifier'], $_SESSION['oauth_state']);
+unset($_SESSION['pkce_verifier'], $_SESSION['oauth_state'], $_SESSION['oauth_return']);
$post = http_build_query([
'grant_type' => 'authorization_code',
@@ -56,12 +62,11 @@ if ($curlError || $status !== 200 || empty($data['access_token'])) {
'http_status' => $status,
'response_body' => $body,
];
- header('Location: ../index.php?error=token_failed');
- exit;
+ redirect_with_error($returnPath, 'token_failed');
}
$_SESSION['access_token'] = $data['access_token'];
$_SESSION['token_expires'] = time() + ($data['expires_in'] ?? 3600);
-header('Location: ../index.php');
+header('Location: ' . $returnPath);
exit;
diff --git a/auth/start.php b/auth/start.php
index fa39fda..a3f96da 100644
--- a/auth/start.php
+++ b/auth/start.php
@@ -8,6 +8,7 @@ $state = bin2hex(random_bytes(16));
$_SESSION['pkce_verifier'] = $verifier;
$_SESSION['oauth_state'] = $state;
+$_SESSION['oauth_return'] = safe_return_path($_GET['return'] ?? ($_SERVER['HTTP_REFERER'] ?? null));
$params = http_build_query([
'response_type' => 'code',
diff --git a/js/analysis.js b/js/analysis.js
index fdef6f6..258cda5 100644
--- a/js/analysis.js
+++ b/js/analysis.js
@@ -341,7 +341,7 @@
body: new URLSearchParams({ report_code: code, language: window.App.language }),
});
const json = await res.json();
- if (json.reauth) { window.location.href = 'auth/start.php'; return; }
+ if (json.reauth) { window.location.href = window.App?.authStartUrl?.() ?? 'auth/start.php'; return; }
const fights = json?.data?.reportData?.report?.fights ?? [];
extFights = fights;
@@ -459,6 +459,7 @@
!hiddenPlayers.has(t.id) &&
(!playerFilter || t.name.toLowerCase().includes(playerFilter))
);
+ if (ev.isHeavyTankbuster && !visibleTargets.some(t => t.role === 'tank')) return '';
if (!visibleTargets.length) return '';
// Collect boss debuffs (Reprisal/Feint/Addle) once at event level
@@ -675,7 +676,7 @@
return;
}
- if (json.reauth) { window.location.href = 'auth/start.php'; return; }
+ if (json.reauth) { window.location.href = window.App?.authStartUrl?.() ?? 'auth/start.php'; return; }
if (json.error) { setEmpty('Fehler: ' + json.error); return; }
lastFightId = fightId;
diff --git a/js/app.js b/js/app.js
index 701f0c5..0c7b0f7 100644
--- a/js/app.js
+++ b/js/app.js
@@ -60,6 +60,11 @@ document.addEventListener('DOMContentLoaded', () => {
}
window.App.setUrlState = setUrlState;
+ function authStartUrl() {
+ return 'auth/start.php?return=' + encodeURIComponent(window.location.pathname + window.location.search);
+ }
+ window.App.authStartUrl = authStartUrl;
+
function fflogsReportUrl(reportCode, fightId = 0) {
const code = String(reportCode || '').trim();
if (!code) return '#';
@@ -237,7 +242,7 @@ document.addEventListener('DOMContentLoaded', () => {
body: new URLSearchParams(params),
});
const json = await res.json();
- if (json.reauth) { window.location.href = 'auth/start.php'; return; }
+ if (json.reauth) { window.location.href = authStartUrl(); return; }
output.textContent = JSON.stringify(json, null, 2);
} catch (err) {
output.textContent = '// Fehler: ' + err.message;
@@ -287,7 +292,7 @@ document.addEventListener('DOMContentLoaded', () => {
if (json.reauth) {
output.textContent = '// session expired — redirecting...';
- setTimeout(() => { window.location.href = 'auth/start.php'; }, 1500);
+ setTimeout(() => { window.location.href = authStartUrl(); }, 1500);
return;
}
diff --git a/templates/login.php b/templates/login.php
index ef804a3..336f18c 100644
--- a/templates/login.php
+++ b/templates/login.php
@@ -21,7 +21,7 @@
-
+
= $tokenExpired ? 'Reconnect to FFLogs' : 'Connect to FFLogs' ?>
diff --git a/templates/report-form.php b/templates/report-form.php
index 09da893..9f0c275 100644
--- a/templates/report-form.php
+++ b/templates/report-form.php
@@ -23,7 +23,7 @@
- Reconnect
+ Reconnect