alperall commited on
Commit
003da9d
·
verified ·
1 Parent(s): 08df97a

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +1040 -19
index.html CHANGED
@@ -1,19 +1,1040 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="tr">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Akıllı Futbol Analiz & Tahmin Platformu</title>
7
+ <!-- Bootstrap 5 CSS -->
8
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
9
+ <!-- Font Awesome -->
10
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
11
+ <!-- Chart.js -->
12
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
13
+ <style>
14
+ /* Custom CSS for modern look */
15
+ :root {
16
+ --primary-color: #1e3a8a;
17
+ --secondary-color: #3b82f6;
18
+ --success-color: #10b981;
19
+ --warning-color: #f59e0b;
20
+ --danger-color: #ef4444;
21
+ }
22
+
23
+ body {
24
+ background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
25
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
26
+ }
27
+
28
+ .header-gradient {
29
+ background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
30
+ color: white;
31
+ box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
32
+ }
33
+
34
+ .live-badge {
35
+ animation: pulse 2s infinite;
36
+ }
37
+
38
+ @keyframes pulse {
39
+ 0% { opacity: 1; }
40
+ 50% { opacity: 0.7; }
41
+ 100% { opacity: 1; }
42
+ }
43
+
44
+ .card {
45
+ border: none;
46
+ border-radius: 15px;
47
+ box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
48
+ transition: transform 0.2s;
49
+ }
50
+
51
+ .card:hover {
52
+ transform: translateY(-2px);
53
+ }
54
+
55
+ .prediction-bar {
56
+ height: 30px;
57
+ border-radius: 15px;
58
+ margin-bottom: 10px;
59
+ position: relative;
60
+ overflow: hidden;
61
+ }
62
+
63
+ .prediction-fill {
64
+ height: 100%;
65
+ display: flex;
66
+ align-items: center;
67
+ justify-content: center;
68
+ color: white;
69
+ font-weight: bold;
70
+ transition: width 1s ease-in-out;
71
+ }
72
+
73
+ .team-form-badge {
74
+ width: 30px;
75
+ height: 30px;
76
+ display: inline-flex;
77
+ align-items: center;
78
+ justify-content: center;
79
+ border-radius: 50%;
80
+ margin: 0 2px;
81
+ font-weight: bold;
82
+ font-size: 0.8rem;
83
+ }
84
+
85
+ .form-win { background-color: var(--success-color); color: white; }
86
+ .form-draw { background-color: var(--warning-color); color: white; }
87
+ .form-loss { background-color: var(--danger-color); color: white; }
88
+
89
+ .match-row:hover {
90
+ background-color: #f8fafc;
91
+ cursor: pointer;
92
+ }
93
+
94
+ .loading-spinner {
95
+ display: none;
96
+ }
97
+
98
+ .stats-card {
99
+ background: linear-gradient(135deg, #ffffff 0%, #f8fafc 100%);
100
+ }
101
+ </style>
102
+ </head>
103
+ <body>
104
+ <!-- Header -->
105
+ <nav class="navbar navbar-expand-lg header-gradient py-3">
106
+ <div class="container">
107
+ <a class="navbar-brand text-white fw-bold fs-4" href="#">
108
+ <i class="fas fa-futbol me-2"></i>Akıllı Futbol Analiz & Tahmin Platformu
109
+ </a>
110
+ <div class="d-flex align-items-center gap-3">
111
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="text-white text-decoration-none small bg-dark bg-opacity-25 px-3 py-1 rounded">
112
+ <i class="fas fa-code me-1"></i>Built with anycoder
113
+ </a>
114
+ <span class="badge bg-success live-badge px-3 py-2">
115
+ <i class="fas fa-circle me-1" style="font-size: 8px;"></i>7/24 Canlı Veri
116
+ </span>
117
+ </div>
118
+ </div>
119
+ </nav>
120
+
121
+ <div class="container my-4">
122
+ <!-- Control Panel -->
123
+ <div class="row mb-4">
124
+ <div class="col-12">
125
+ <div class="card">
126
+ <div class="card-header bg-white border-bottom-0 pt-4">
127
+ <h5 class="card-title mb-0">
128
+ <i class="fas fa-filter text-primary me-2"></i>Filtreleme ve Kontrol
129
+ </h5>
130
+ </div>
131
+ <div class="card-body">
132
+ <div class="row align-items-end">
133
+ <div class="col-md-4 mb-3">
134
+ <label class="form-label">Lig Seçimi</label>
135
+ <select class="form-select" id="leagueFilter">
136
+ <option value="all">Tüm Ligler</option>
137
+ <!-- Options will be populated dynamically -->
138
+ </select>
139
+ </div>
140
+ <div class="col-md-4 mb-3">
141
+ <label class="form-label">Manuel Takım Analizi</label>
142
+ <div class="input-group">
143
+ <input type="text" class="form-control" id="manualHomeTeam" placeholder="Ev Sahibi Takım">
144
+ <input type="text" class="form-control" id="manualAwayTeam" placeholder="Deplasman Takım">
145
+ </div>
146
+ </div>
147
+ <div class="col-md-4 mb-3">
148
+ <button class="btn btn-primary w-100" onclick="analyzeManualTeams()">
149
+ <i class="fas fa-search me-2"></i>Manuel Analiz Yap
150
+ </button>
151
+ </div>
152
+ </div>
153
+ <div class="row">
154
+ <div class="col-12">
155
+ <button class="btn btn-outline-primary" onclick="refreshData()">
156
+ <i class="fas fa-sync-alt me-2"></i>Verileri Yenile
157
+ </button>
158
+ <span class="text-muted ms-3 small" id="lastUpdateTime">
159
+ <i class="fas fa-clock me-1"></i>Son Güncelleme: -
160
+ </span>
161
+ </div>
162
+ </div>
163
+ </div>
164
+ </div>
165
+ </div>
166
+ </div>
167
+
168
+ <div class="row">
169
+ <!-- Upcoming Matches -->
170
+ <div class="col-lg-5 mb-4">
171
+ <div class="card h-100">
172
+ <div class="card-header bg-white border-bottom-0 pt-4 d-flex justify-content-between align-items-center">
173
+ <h5 class="card-title mb-0">
174
+ <i class="fas fa-calendar-alt text-primary me-2"></i>Önümüzdeki Maçlar
175
+ </h5>
176
+ <div class="loading-spinner text-primary" id="matchesLoading">
177
+ <i class="fas fa-spinner fa-spin"></i>
178
+ </div>
179
+ </div>
180
+ <div class="card-body p-0">
181
+ <div class="table-responsive">
182
+ <table class="table table-hover mb-0" id="matchesTable">
183
+ <thead class="table-light">
184
+ <tr>
185
+ <th>Tarih & Saat</th>
186
+ <th>Lig</th>
187
+ <th>Ev Sahibi</th>
188
+ <th>Deplasman</th>
189
+ <th>İşlem</th>
190
+ </tr>
191
+ </thead>
192
+ <tbody id="matchesTableBody">
193
+ <!-- Matches will be populated here -->
194
+ </tbody>
195
+ </table>
196
+ </div>
197
+ <div id="noMatchesMessage" class="text-center py-5 text-muted" style="display: none;">
198
+ <i class="fas fa-inbox fa-3x mb-3 opacity-25"></i>
199
+ <p>Maç bulunamadı</p>
200
+ </div>
201
+ </div>
202
+ </div>
203
+ </div>
204
+
205
+ <!-- Analysis Dashboard -->
206
+ <div class="col-lg-7 mb-4">
207
+ <div class="card h-100" id="analysisCard" style="display: none;">
208
+ <div class="card-header bg-white border-bottom-0 pt-4">
209
+ <h5 class="card-title mb-0">
210
+ <i class="fas fa-chart-line text-primary me-2"></i>Analiz Panosu
211
+ </h5>
212
+ </div>
213
+ <div class="card-body">
214
+ <!-- Match Info -->
215
+ <div class="text-center mb-4 p-3 bg-light rounded">
216
+ <h3 class="mb-3">
217
+ <span id="analysisHomeTeam" class="fw-bold text-primary">-</span>
218
+ <span class="mx-3 text-muted">vs</span>
219
+ <span id="analysisAwayTeam" class="fw-bold text-danger">-</span>
220
+ </h3>
221
+ <p class="text-muted mb-0" id="analysisMatchInfo">-</p>
222
+ </div>
223
+
224
+ <!-- Predictions -->
225
+ <div class="mb-4">
226
+ <h6 class="fw-bold mb-3"><i class="fas fa-percentage me-2"></i>Tahmin Olasılıkları</h6>
227
+
228
+ <div class="mb-2">
229
+ <div class="d-flex justify-content-between mb-1">
230
+ <span id="homeWinLabel">Ev Sahibi Kazanır</span>
231
+ <span class="fw-bold" id="homeWinPercent">0%</span>
232
+ </div>
233
+ <div class="prediction-bar bg-light">
234
+ <div class="prediction-fill bg-primary" id="homeWinBar" style="width: 0%"></div>
235
+ </div>
236
+ </div>
237
+
238
+ <div class="mb-2">
239
+ <div class="d-flex justify-content-between mb-1">
240
+ <span>Beraberlik</span>
241
+ <span class="fw-bold" id="drawPercent">0%</span>
242
+ </div>
243
+ <div class="prediction-bar bg-light">
244
+ <div class="prediction-fill bg-warning" id="drawBar" style="width: 0%"></div>
245
+ </div>
246
+ </div>
247
+
248
+ <div class="mb-2">
249
+ <div class="d-flex justify-content-between mb-1">
250
+ <span id="awayWinLabel">Deplasman Kazanır</span>
251
+ <span class="fw-bold" id="awayWinPercent">0%</span>
252
+ </div>
253
+ <div class="prediction-bar bg-light">
254
+ <div class="prediction-fill bg-danger" id="awayWinBar" style="width: 0%"></div>
255
+ </div>
256
+ </div>
257
+ </div>
258
+
259
+ <!-- Charts -->
260
+ <div class="row mb-4">
261
+ <div class="col-md-6 mb-3">
262
+ <canvas id="homeTeamChart"></canvas>
263
+ </div>
264
+ <div class="col-md-6 mb-3">
265
+ <canvas id="awayTeamChart"></canvas>
266
+ </div>
267
+ </div>
268
+
269
+ <!-- Detailed Stats -->
270
+ <div class="row">
271
+ <div class="col-md-6 mb-3">
272
+ <div class="card stats-card h-100">
273
+ <div class="card-body">
274
+ <h6 class="card-title text-primary" id="homeStatsTitle">Ev Sahibi İstatistikleri</h6>
275
+ <ul class="list-unstyled mb-0 mt-3">
276
+ <li class="mb-2"><i class="fas fa-futbol me-2 text-muted"></i>Ort. Gol: <span id="homeAvgGoals" class="fw-bold">-</span></li>
277
+ <li class="mb-2"><i class="fas fa-shield-alt me-2 text-muted"></i>Ort. Yenilen Gol: <span id="homeAvgConceded" class="fw-bold">-</span></li>
278
+ <li class="mb-2"><i class="fas fa-chart-bar me-2 text-muted"></i>Form: <span id="homeForm" class="fw-bold">-</span></li>
279
+ <li><i class="fas fa-trophy me-2 text-muted"></i>Puan Ort.: <span id="homeAvgPoints" class="fw-bold">-</span></li>
280
+ </ul>
281
+ </div>
282
+ </div>
283
+ </div>
284
+ <div class="col-md-6 mb-3">
285
+ <div class="card stats-card h-100">
286
+ <div class="card-body">
287
+ <h6 class="card-title text-danger" id="awayStatsTitle">Deplasman İstatistikleri</h6>
288
+ <ul class="list-unstyled mb-0 mt-3">
289
+ <li class="mb-2"><i class="fas fa-futbol me-2 text-muted"></i>Ort. Gol: <span id="awayAvgGoals" class="fw-bold">-</span></li>
290
+ <li class="mb-2"><i class="fas fa-shield-alt me-2 text-muted"></i>Ort. Yenilen Gol: <span id="awayAvgConceded" class="fw-bold">-</span></li>
291
+ <li class="mb-2"><i class="fas fa-chart-bar me-2 text-muted"></i>Form: <span id="awayForm" class="fw-bold">-</span></li>
292
+ <li><i class="fas fa-trophy me-2 text-muted"></i>Puan Ort.: <span id="awayAvgPoints" class="fw-bold">-</span></li>
293
+ </ul>
294
+ </div>
295
+ </div>
296
+ </div>
297
+ </div>
298
+
299
+ <!-- Head to Head -->
300
+ <div class="mt-3" id="h2hSection" style="display: none;">
301
+ <h6 class="fw-bold mb-3"><i class="fas fa-history me-2"></i>Önceki Karşılaşmalar</h6>
302
+ <div class="table-responsive">
303
+ <table class="table table-sm table-bordered" id="h2hTable">
304
+ <thead class="table-light">
305
+ <tr>
306
+ <th>Tarih</th>
307
+ <th>Ev Sahibi</th>
308
+ <th>Skor</th>
309
+ <th>Deplasman</th>
310
+ </tr>
311
+ </thead>
312
+ <tbody id="h2hTableBody"></tbody>
313
+ </table>
314
+ </div>
315
+ </div>
316
+
317
+ <button class="btn btn-primary w-100 mt-3" onclick="refreshCurrentAnalysis()">
318
+ <i class="fas fa-sync-alt me-2"></i>Analizi Yenile
319
+ </button>
320
+ </div>
321
+ </div>
322
+
323
+ <!-- Empty State -->
324
+ <div class="card h-100" id="emptyAnalysisCard">
325
+ <div class="card-body d-flex flex-column justify-content-center align-items-center text-center p-5">
326
+ <i class="fas fa-chart-pie fa-4x text-muted mb-3 opacity-25"></i>
327
+ <h5 class="text-muted">Analiz için bir maç seçin</h5>
328
+ <p class="text-muted small">Sol taraftan bir maç seçerek veya yukarıdan manuel takım girerek analiz başlatabilirsiniz.</p>
329
+ </div>
330
+ </div>
331
+ </div>
332
+ </div>
333
+
334
+ <!-- Live Data Indicator -->
335
+ <div class="row">
336
+ <div class="col-12">
337
+ <div class="alert alert-info d-flex align-items-center mb-4" role="alert">
338
+ <i class="fas fa-info-circle me-2"></i>
339
+ <div>
340
+ <strong>Canlı Veri:</strong> Veriler her 60 saniyede bir otomatik olarak güncellenmektedir.
341
+ <span class="ms-2 badge bg-primary" id="nextUpdateCountdown">Sonraki güncelleme: 60s</span>
342
+ </div>
343
+ </div>
344
+ </div>
345
+ </div>
346
+
347
+ <!-- Disclaimer -->
348
+ <div class="row">
349
+ <div class="col-12">
350
+ <div class="alert alert-warning" role="alert">
351
+ <i class="fas fa-exclamation-triangle me-2"></i>
352
+ <strong>Uyarı:</strong> Bu platform Football-Data.org'dan alınan gerçek verilerle istatistiksel simülasyon yapar.
353
+ Kesin bir tahmin aracı veya bahis önerisi <strong>DEĞİLDİR</strong>. Sonuçlar garanti etmez.
354
+ Sorumlu oyun oynayınız.
355
+ </div>
356
+ </div>
357
+ </div>
358
+ </div>
359
+
360
+ <script>
361
+ // Configuration
362
+ const API_TOKEN = '326546a82e2848f1b66d2e859a8f0832';
363
+ const API_BASE_URL = 'https://api.football-data.org/v4';
364
+ let currentMatches = [];
365
+ let selectedMatch = null;
366
+ let homeTeamChart = null;
367
+ let awayTeamChart = null;
368
+ let autoRefreshInterval = null;
369
+ let countdownInterval = null;
370
+ let countdownValue = 60;
371
+
372
+ // DOM Elements
373
+ const matchesTableBody = document.getElementById('matchesTableBody');
374
+ const leagueFilter = document.getElementById('leagueFilter');
375
+ const lastUpdateTime = document.getElementById('lastUpdateTime');
376
+ const matchesLoading = document.getElementById('matchesLoading');
377
+ const noMatchesMessage = document.getElementById('noMatchesMessage');
378
+
379
+ // Initialize
380
+ document.addEventListener('DOMContentLoaded', () => {
381
+ initializeApp();
382
+ });
383
+
384
+ async function initializeApp() {
385
+ try {
386
+ await fetchUpcomingMatches();
387
+ startAutoRefresh();
388
+ updateLastUpdateTime();
389
+ } catch (error) {
390
+ console.error('Initialization error:', error);
391
+ showError('Uygulama başlatılırken bir hata oluştu. Lütfen sayfayı yenileyin.');
392
+ }
393
+ }
394
+
395
+ // Fetch upcoming matches for next 7 days
396
+ async function fetchUpcomingMatches() {
397
+ showLoading(true);
398
+
399
+ try {
400
+ // Calculate date range (today to +7 days)
401
+ const today = new Date();
402
+ const nextWeek = new Date(today);
403
+ nextWeek.setDate(today.getDate() + 7);
404
+
405
+ const dateFrom = formatDateForAPI(today);
406
+ const dateTo = formatDateForAPI(nextWeek);
407
+
408
+ // Fetch matches from API
409
+ const response = await fetch(`${API_BASE_URL}/matches?dateFrom=${dateFrom}&dateTo=${dateTo}`, {
410
+ headers: {
411
+ 'X-Auth-Token': API_TOKEN
412
+ }
413
+ });
414
+
415
+ if (!response.ok) {
416
+ throw new Error(`API Error: ${response.status}`);
417
+ }
418
+
419
+ const data = await response.json();
420
+ currentMatches = data.matches || [];
421
+
422
+ // Populate league filter
423
+ populateLeagueFilter(currentMatches);
424
+
425
+ // Display matches
426
+ displayMatches(currentMatches);
427
+
428
+ updateLastUpdateTime();
429
+
430
+ } catch (error) {
431
+ console.error('Error fetching matches:', error);
432
+ showError('Maç verileri çekilirken bir hata oluştu. API limiti aşılmış olabilir veya bağlantı hatası vardır.');
433
+ } finally {
434
+ showLoading(false);
435
+ }
436
+ }
437
+
438
+ // Format date for API (YYYY-MM-DD)
439
+ function formatDateForAPI(date) {
440
+ return date.toISOString().split('T')[0];
441
+ }
442
+
443
+ // Format date for display
444
+ function formatDateForDisplay(dateString) {
445
+ const date = new Date(dateString);
446
+ return date.toLocaleDateString('tr-TR', {
447
+ day: '2-digit',
448
+ month '2-digit',
449
+ hour: '2-digit',
450
+ minute: '2-digit'
451
+ });
452
+ }
453
+
454
+ // Populate league filter dropdown
455
+ function populateLeagueFilter(matches) {
456
+ const competitions = [...new Set(matches.map(m => m.competition.name))].sort();
457
+ const currentValue = leagueFilter.value;
458
+
459
+ leagueFilter.innerHTML = '<option value="all">Tüm Ligler</option>';
460
+
461
+ competitions.forEach(comp => {
462
+ const option = document.createElement('option');
463
+ option.value = comp;
464
+ option.textContent = comp;
465
+ leagueFilter.appendChild(option);
466
+ });
467
+
468
+ leagueFilter.value = currentValue;
469
+ }
470
+
471
+ // Display matches in table
472
+ function displayMatches(matches) {
473
+ matchesTableBody.innerHTML = '';
474
+
475
+ if (matches.length === 0) {
476
+ noMatchesMessage.style.display = 'block';
477
+ return;
478
+ }
479
+
480
+ noMatchesMessage.style.display = 'none';
481
+
482
+ matches.forEach(match => {
483
+ const row = document.createElement('tr');
484
+ row.className = 'match-row';
485
+
486
+ const homeTeam = match.homeTeam.name;
487
+ const awayTeam = match.awayTeam.name;
488
+ const competition = match.competition.name;
489
+ const matchDate = formatDateForDisplay(match.utcDate);
490
+
491
+ row.innerHTML = `
492
+ <td class="align-middle">${matchDate}</td>
493
+ <td class="align-middle"><span class="badge bg-secondary">${competition}</span></td>
494
+ <td class="align-middle fw-bold">${homeTeam}</td>
495
+ <td class="align-middle fw-bold">${awayTeam}</td>
496
+ <td class="align-middle">
497
+ <button class="btn btn-sm btn-primary" onclick="analyzeMatch('${match.id}')">
498
+ <i class="fas fa-chart-bar me-1"></i>Analiz Et
499
+ </button>
500
+ </td>
501
+ `;
502
+
503
+ matchesTableBody.appendChild(row);
504
+ });
505
+ }
506
+
507
+ // Filter matches by league
508
+ leagueFilter.addEventListener('change', (e) => {
509
+ const selectedLeague = e.target.value;
510
+ if (selectedLeague === 'all') {
511
+ displayMatches(currentMatches);
512
+ } else {
513
+ const filtered = currentMatches.filter(m => m.competition.name === selectedLeague);
514
+ displayMatches(filtered);
515
+ }
516
+ });
517
+
518
+ // Analyze specific match
519
+ async function analyzeMatch(matchId) {
520
+ const match = currentMatches.find(m => m.id == matchId);
521
+ if (!match) return;
522
+
523
+ selectedMatch = match;
524
+
525
+ document.getElementById('analysisHomeTeam').textContent = match.homeTeam.name;
526
+ document.getElementById('analysisAwayTeam').textContent = match.awayTeam.name;
527
+ document.getElementById('analysisMatchInfo').textContent = `${match.competition.name} - ${formatDateForDisplay(match.utcDate)}`;
528
+
529
+ await performAnalysis(match.homeTeam.id, match.awayTeam.id, match.homeTeam.name, match.awayTeam.name);
530
+ }
531
+
532
+ // Manual team analysis
533
+ async function analyzeManualTeams() {
534
+ const homeTeamName = document.getElementById('manualHomeTeam').value.trim();
535
+ const awayTeamName = document.getElementById('manualAwayTeam').value.trim();
536
+
537
+ if (!homeTeamName || !awayTeamName) {
538
+ alert('Lütfen her iki takımın da adını girin.');
539
+ return;
540
+ }
541
+
542
+ document.getElementById('analysisHomeTeam').textContent = homeTeamName;
543
+ document.getElementById('analysisAwayTeam').textContent = awayTeamName;
544
+ document.getElementById('analysisMatchInfo').textContent = 'Manuel Analiz';
545
+
546
+ // For manual analysis, we'll try to find team IDs from current matches or use a generic approach
547
+ // Since we don't have a search endpoint in the free tier easily accessible without team IDs,
548
+ // we'll simulate the analysis with placeholder data or try to match from existing matches
549
+
550
+ // Try to find matching teams in current matches
551
+ const homeMatch = currentMatches.find(m =>
552
+ m.homeTeam.name.toLowerCase().includes(homeTeamName.toLowerCase()) ||
553
+ m.awayTeam.name.toLowerCase().includes(homeTeamName.toLowerCase())
554
+ );
555
+
556
+ const awayMatch = currentMatches.find(m =>
557
+ m.homeTeam.name.toLowerCase().includes(awayTeamName.toLowerCase()) ||
558
+ m.awayTeam.name.toLowerCase().includes(awayTeamName.toLowerCase())
559
+ );
560
+
561
+ if (homeMatch && awayMatch) {
562
+ const homeId = homeMatch.homeTeam.name.toLowerCase().includes(homeTeamName.toLowerCase()) ?
563
+ homeMatch.homeTeam.id : homeMatch.awayTeam.id;
564
+ const awayId = awayMatch.homeTeam.name.toLowerCase().includes(awayTeamName.toLowerCase()) ?
565
+ awayMatch.homeTeam.id : awayMatch.awayTeam.id;
566
+
567
+ await performAnalysis(homeId, awayId, homeTeamName, awayTeamName);
568
+ } else {
569
+ // If teams not found in current matches, show alert
570
+ alert('Takımlar mevcut maç listesinde bulunamadı. Lütfen listeden bir maç seçin veya geçerli takım adları girin.');
571
+ }
572
+ }
573
+
574
+ // Perform analysis for two teams
575
+ async function performAnalysis(homeTeamId, awayTeamId, homeTeamName, awayTeamName) {
576
+ showAnalysisLoading(true);
577
+
578
+ try {
579
+ // Fetch last 5 matches for both teams
580
+ const [homeMatches, awayMatches] = await Promise.all([
581
+ fetchTeamMatches(homeTeamId),
582
+ fetchTeamMatches(awayTeamId)
583
+ ]);
584
+
585
+ // Calculate statistics
586
+ const homeStats = calculateTeamStats(homeMatches, homeTeamId);
587
+ const awayStats = calculateTeamStats(awayMatches, awayTeamId);
588
+
589
+ // Calculate predictions
590
+ const predictions = calculatePredictions(homeStats, awayStats);
591
+
592
+ // Update UI
593
+ updateAnalysisUI(homeStats, awayStats, predictions, homeTeamName, awayTeamName);
594
+
595
+ // Fetch and display H2H if possible
596
+ await fetchHeadToHead(homeTeamId, awayTeamId);
597
+
598
+ // Show analysis card
599
+ document.getElementById('analysisCard').style.display = 'block';
600
+ document.getElementById('emptyAnalysisCard').style.display = 'none';
601
+
602
+ } catch (error) {
603
+ console.error('Analysis error:', error);
604
+ showError('Analiz yapılırken bir hata oluştu.');
605
+ } finally {
606
+ showAnalysisLoading(false);
607
+ }
608
+ }
609
+
610
+ // Fetch team matches (finished matches)
611
+ async function fetchTeamMatches(teamId) {
612
+ const today = new Date();
613
+ const lastMonth = new Date(today);
614
+ lastMonth.setMonth(today.getMonth() - 3); // Look back 3 months to ensure we get 5 matches
615
+
616
+ const dateFrom = formatDateForAPI(lastMonth);
617
+ const dateTo = formatDateForAPI(today);
618
+
619
+ const response = await fetch(`${API_BASE_URL}/teams/${teamId}/matches?dateFrom=${dateFrom}&dateTo=${dateTo}&status=FINISHED`, {
620
+ headers: {
621
+ 'X-Auth-Token': API_TOKEN
622
+ }
623
+ });
624
+
625
+ if (!response.ok) {
626
+ throw new Error(`API Error: ${response.status}`);
627
+ }
628
+
629
+ const data = await response.json();
630
+ return data.matches ? data.matches.slice(0, 5) : []; // Last 5 matches
631
+ }
632
+
633
+ // Calculate team statistics from matches
634
+ function calculateTeamStats(matches, teamId) {
635
+ if (!matches || matches.length === 0) {
636
+ return {
637
+ matches: [],
638
+ avgGoals: 0,
639
+ avgConceded: 0,
640
+ avgPoints: 0,
641
+ form: '',
642
+ goalsScored: [],
643
+ goalsConceded: [],
644
+ results: []
645
+ };
646
+ }
647
+
648
+ let totalGoals = 0;
649
+ let totalConceded = 0;
650
+ let totalPoints = 0;
651
+ let form = '';
652
+ const goalsScored = [];
653
+ const goalsConceded = [];
654
+ const results = [];
655
+
656
+ matches.forEach(match => {
657
+ const isHome = match.homeTeam.id == teamId;
658
+ const teamScore = isHome ? match.score.fullTime.home : match.score.fullTime.away;
659
+ const opponentScore = isHome ? match.score.fullTime.away : match.score.fullTime.home;
660
+
661
+ totalGoals += teamScore;
662
+ totalConceded += opponentScore;
663
+ goalsScored.push(teamScore);
664
+ goalsConceded.push(opponentScore);
665
+
666
+ let result;
667
+ if (teamScore > opponentScore) {
668
+ totalPoints += 3;
669
+ result = 'W';
670
+ form += 'G-';
671
+ } else if (teamScore === opponentScore) {
672
+ totalPoints += 1;
673
+ result = 'D';
674
+ form += 'B-';
675
+ } else {
676
+ result = 'L';
677
+ form += 'M-';
678
+ }
679
+ results.push(result);
680
+ });
681
+
682
+ const matchCount = matches.length;
683
+ form = form.slice(0, -1); // Remove last dash
684
+
685
+ return {
686
+ matches: matches,
687
+ avgGoals: (totalGoals / matchCount).toFixed(2),
688
+ avgConceded: (totalConceded / matchCount).toFixed(2),
689
+ avgPoints: (totalPoints / matchCount).toFixed(2),
690
+ form: form,
691
+ goalsScored: goalsScored.reverse(), // Most recent last
692
+ goalsConceded: goalsConceded.reverse(),
693
+ results: results.reverse()
694
+ };
695
+ }
696
+
697
+ // Calculate prediction probabilities
698
+ function calculatePredictions(homeStats, awayStats) {
699
+ // Simple weighted algorithm
700
+ // Factors: Points average (40%), Goals scored/conceded difference (30%), Home advantage (20%), Recent form (10%)
701
+
702
+ // Normalize stats (handle empty data)
703
+ const homePoints = parseFloat(homeStats.avgPoints) || 1.5;
704
+ const awayPoints = parseFloat(awayStats.avgPoints) || 1.5;
705
+ const homeGoals = parseFloat(homeStats.avgGoals) || 1;
706
+ const awayGoals = parseFloat(awayStats.avgGoals) || 1;
707
+ const homeConceded = parseFloat(homeStats.avgConceded) || 1;
708
+ const awayConceded = parseFloat(awayStats.avgConceded) || 1;
709
+
710
+ // Points factor (40%)
711
+ const totalPoints = homePoints + awayPoints;
712
+ const homePointsProb = (homePoints / totalPoints) * 40;
713
+ const awayPointsProb = (awayPoints / totalPoints) * 40;
714
+
715
+ // Goals factor (30%) - based on attack vs defense
716
+ const homeAttackStrength = homeGoals / (homeGoals + awayConceded);
717
+ const awayAttackStrength = awayGoals / (awayGoals + homeConceded);
718
+ const totalAttack = homeAttackStrength + awayAttackStrength;
719
+ const homeGoalsProb = (homeAttackStrength / totalAttack) * 30;
720
+ const awayGoalsProb = (awayAttackStrength / totalAttack) * 30;
721
+
722
+ // Home advantage (20%)
723
+ const homeAdvantage = 12; // 60% of 20%
724
+ const awayDisadvantage = 8; // 40% of 20%
725
+
726
+ // Form factor (10%) - based on last 5 results
727
+ const homeFormScore = calculateFormScore(homeStats.results);
728
+ const awayFormScore = calculateFormScore(awayStats.results);
729
+ const totalForm = homeFormScore + awayFormScore || 2;
730
+ const homeFormProb = (homeFormScore / totalForm) * 10;
731
+ const awayFormProb = (awayFormScore / totalForm) * 10;
732
+
733
+ // Calculate raw probabilities
734
+ let homeWin = homePointsProb + homeGoalsProb + homeAdvantage + homeFormProb;
735
+ let awayWin = awayPointsProb + awayGoalsProb + awayDisadvantage + awayFormProb;
736
+
737
+ // Normalize to ensure they sum to less than 100, leaving room for draw
738
+ const totalWin = homeWin + awayWin;
739
+ const normalizationFactor = 85 / totalWin; // Reserve 15% for draw minimum
740
+
741
+ homeWin = homeWin * normalizationFactor;
742
+ awayWin = awayWin * normalizationFactor;
743
+
744
+ // Draw probability based on how close the teams are
745
+ const diff = Math.abs(homeWin - awayWin);
746
+ let draw = 15 + (diff < 10 ? 10 : 0) - (diff > 20 ? 5 : 0);
747
+
748
+ // Adjust win probabilities to ensure sum is 100
749
+ const remaining = 100 - draw;
750
+ const winTotal = homeWin + awayWin;
751
+ homeWin = (homeWin / winTotal) * remaining;
752
+ awayWin = (awayWin / winTotal) * remaining;
753
+
754
+ return {
755
+ homeWin: Math.round(homeWin),
756
+ draw: Math.round(draw),
757
+ awayWin: Math.round(awayWin)
758
+ };
759
+ }
760
+
761
+ // Calculate form score from results array (W, D, L)
762
+ function calculateFormScore(results) {
763
+ if (!results || results.length === 0) return 1;
764
+
765
+ let score = 0;
766
+ // Weight recent matches more
767
+ const weights = [1, 1.1, 1.2, 1.3, 1.4];
768
+
769
+ results.forEach((result, index) => {
770
+ const weight = weights[index] || 1;
771
+ if (result === 'W') score += 3 * weight;
772
+ else if (result === 'D') score += 1 * weight;
773
+ else score += 0;
774
+ });
775
+
776
+ return score / results.length;
777
+ }
778
+
779
+ // Update analysis UI
780
+ function updateAnalysisUI(homeStats, awayStats, predictions, homeName, awayName) {
781
+ // Update prediction bars
782
+ document.getElementById('homeWinLabel').textContent = `${homeName} Kazanır`;
783
+ document.getElementById('awayWinLabel').textContent = `${awayName} Kazanır`;
784
+
785
+ document.getElementById('homeWinPercent').textContent = `${predictions.homeWin}%`;
786
+ document.getElementById('drawPercent').textContent = `${predictions.draw}%`;
787
+ document.getElementById('awayWinPercent').textContent = `${predictions.awayWin}%`;
788
+
789
+ // Animate bars
790
+ setTimeout(() => {
791
+ document.getElementById('homeWinBar').style.width = `${predictions.homeWin}%`;
792
+ document.getElementById('drawBar').style.width = `${predictions.draw}%`;
793
+ document.getElementById('awayWinBar').style.width = `${predictions.awayWin}%`;
794
+ }, 100);
795
+
796
+ // Update stats
797
+ document.getElementById('homeStatsTitle').textContent = `${homeName} İstatistikleri`;
798
+ document.getElementById('awayStatsTitle').textContent = `${awayName} İstatistikleri`;
799
+
800
+ document.getElementById('homeAvgGoals').textContent = homeStats.avgGoals;
801
+ document.getElementById('homeAvgConceded').textContent = homeStats.avgConceded;
802
+ document.getElementById('homeAvgPoints').textContent = homeStats.avgPoints;
803
+ document.getElementById('awayAvgGoals').textContent = awayStats.avgGoals;
804
+ document.getElementById('awayAvgConceded').textContent = awayStats.avgConceded;
805
+ document.getElementById('awayAvgPoints').textContent = awayStats.avgPoints;
806
+
807
+ // Update form badges
808
+ document.getElementById('homeForm').innerHTML = createFormBadges(homeStats.form);
809
+ document.getElementById('awayForm').innerHTML = createFormBadges(awayStats.form);
810
+
811
+ // Update charts
812
+ updateCharts(homeStats, awayStats, homeName, awayName);
813
+ }
814
+
815
+ // Create form badges HTML
816
+ function createFormBadges(formString) {
817
+ if (!formString) return '-';
818
+
819
+ const parts = formString.split('-');
820
+ let html = '';
821
+
822
+ parts.forEach(part => {
823
+ let className = '';
824
+ let text = '';
825
+
826
+ switch(part) {
827
+ case 'G':
828
+ className = 'form-win';
829
+ text = 'G';
830
+ break;
831
+ case 'B':
832
+ className = 'form-draw';
833
+ text = 'B';
834
+ break;
835
+ case 'M':
836
+ className = 'form-loss';
837
+ text = 'M';
838
+ break;
839
+ }
840
+
841
+ html += `<span class="team-form-badge ${className}">${text}</span>`;
842
+ });
843
+
844
+ return html;
845
+ }
846
+
847
+ // Update charts
848
+ function updateCharts(homeStats, awayStats, homeName, awayName) {
849
+ // Destroy existing charts if they exist
850
+ if (homeTeamChart) homeTeamChart.destroy();
851
+ if (awayTeamChart) awayTeamChart.destroy();
852
+
853
+ // Home team chart
854
+ const homeCtx = document.getElementById('homeTeamChart').getContext('2d');
855
+ homeTeamChart = new Chart(homeCtx, {
856
+ type: 'bar',
857
+ data: {
858
+ labels: ['Maç 1', 'Maç 2', 'Maç 3', 'Maç 4', 'Maç 5 (Son)'],
859
+ datasets: [{
860
+ label: 'Atılan Gol',
861
+ data: homeStats.goalsScored,
862
+ backgroundColor: 'rgba(59, 130, 246, 0.7)',
863
+ borderColor: 'rgba(59, 130, 246, 1)',
864
+ borderWidth: 1
865
+ }, {
866
+ label: 'Yenilen Gol',
867
+ data: homeStats.goalsConceded,
868
+ backgroundColor: 'rgba(239, 68, 68, 0.7)',
869
+ borderColor: 'rgba(239, 68, 68, 1)',
870
+ borderWidth: 1
871
+ }]
872
+ },
873
+ options: {
874
+ responsive: true,
875
+ plugins: {
876
+ title: {
877
+ display: true,
878
+ text: `${homeName} - Son 5 Maç`
879
+ }
880
+ },
881
+ scales: {
882
+ y: {
883
+ beginAtZero: true,
884
+ ticks: {
885
+ stepSize: 1
886
+ }
887
+ }
888
+ }
889
+ }
890
+ });
891
+
892
+ // Away team chart
893
+ const awayCtx = document.getElementById('awayTeamChart').getContext('2d');
894
+ awayTeamChart = new Chart(awayCtx, {
895
+ type: 'bar',
896
+ data: {
897
+ labels: ['Maç 1', 'Maç 2', 'Maç 3', 'Maç 4', 'Maç 5 (Son)'],
898
+ datasets: [{
899
+ label: 'Atılan Gol',
900
+ data: awayStats.goalsScored,
901
+ backgroundColor: 'rgba(59, 130, 246, 0.7)',
902
+ borderColor: 'rgba(59, 130, 246, 1)',
903
+ borderWidth: 1
904
+ }, {
905
+ label: 'Yenilen Gol',
906
+ data: awayStats.goalsConceded,
907
+ backgroundColor: 'rgba(239, 68, 68, 0.7)',
908
+ borderColor: 'rgba(239, 68, 68, 1)',
909
+ borderWidth: 1
910
+ }]
911
+ },
912
+ options: {
913
+ responsive: true,
914
+ plugins: {
915
+ title: {
916
+ display: true,
917
+ text: `${awayName} - Son 5 Maç`
918
+ }
919
+ },
920
+ scales: {
921
+ y: {
922
+ beginAtZero: true,
923
+ ticks: {
924
+ stepSize: 1
925
+ }
926
+ }
927
+ }
928
+ }
929
+ });
930
+ }
931
+
932
+ // Fetch head to head matches
933
+ async function fetchHeadToHead(team1Id, team2Id) {
934
+ try {
935
+ // Note: H2H endpoint might require different permissions in free tier
936
+ // We'll try to find H2H from the matches we already have or fetch recent matches between them
937
+ const today = new Date();
938
+ const lastYear = new Date(today);
939
+ lastYear.setFullYear(today.getFullYear() - 1);
940
+
941
+ const response = await fetch(`${API_BASE_URL}/matches?dateFrom=${formatDateForAPI(lastYear)}&dateTo=${formatDateForAPI(today)}&status=FINISHED`, {
942
+ headers: {
943
+ 'X-Auth-Token': API_TOKEN
944
+ }
945
+ });
946
+
947
+ if (!response.ok) return;
948
+
949
+ const data = await response.json();
950
+ const allMatches = data.matches || [];
951
+
952
+ // Filter matches between these two teams
953
+ const h2hMatches = allMatches.filter(m =>
954
+ (m.homeTeam.id == team1Id && m.awayTeam.id == team2Id) ||
955
+ (m.homeTeam.id == team2Id && m.awayTeam.id == team1Id)
956
+ ).slice(0, 5); // Last 5 H2H
957
+
958
+ if (h2hMatches.length > 0) {
959
+ displayH2H(h2hMatches);
960
+ } else {
961
+ document.getElementById('h2hSection').style.display = 'none';
962
+ }
963
+
964
+ } catch (error) {
965
+ console.error('H2H fetch error:', error);
966
+ document.getElementById('h2hSection').style.display = 'none';
967
+ }
968
+ }
969
+
970
+ // Display H2H matches
971
+ function displayH2H(matches) {
972
+ const tbody = document.getElementById('h2hTableBody');
973
+ tbody.innerHTML = '';
974
+
975
+ matches.forEach(match => {
976
+ const row = document.createElement('tr');
977
+ row.innerHTML = `
978
+ <td>${formatDateForDisplay(match.utcDate)}</td>
979
+ <td>${match.homeTeam.name}</td>
980
+ <td class="fw-bold">${match.score.fullTime.home} - ${match.score.fullTime.away}</td>
981
+ <td>${match.awayTeam.name}</td>
982
+ `;
983
+ tbody.appendChild(row);
984
+ });
985
+
986
+ document.getElementById('h2hSection').style.display = 'block';
987
+ }
988
+
989
+ // Refresh current analysis
990
+ async function refreshCurrentAnalysis() {
991
+ if (selectedMatch) {
992
+ await analyzeMatch(selectedMatch.id);
993
+ }
994
+ }
995
+
996
+ // Refresh all data
997
+ async function refreshData() {
998
+ await fetchUpcomingMatches();
999
+ if (selectedMatch) {
1000
+ await refreshCurrentAnalysis();
1001
+ }
1002
+ }
1003
+
1004
+ // Auto refresh every 60 seconds
1005
+ function startAutoRefresh() {
1006
+ // Clear existing intervals if any
1007
+ if (autoRefreshInterval) clearInterval(autoRefreshInterval);
1008
+ if (countdownInterval) clearInterval(countdownInterval);
1009
+
1010
+ countdownValue = 60;
1011
+ updateCountdown();
1012
+
1013
+ countdownInterval = setInterval(() => {
1014
+ countdownValue--;
1015
+ updateCountdown();
1016
+ if (countdownValue <= 0) countdownValue = 60;
1017
+ }, 1000);
1018
+
1019
+ autoRefreshInterval = setInterval(() => {
1020
+ refreshData();
1021
+ countdownValue = 60;
1022
+ }, 60000);
1023
+ }
1024
+
1025
+ function updateCountdown() {
1026
+ document.getElementById('nextUpdateCountdown').textContent = `Sonraki güncelleme: ${countdownValue}s`;
1027
+ }
1028
+
1029
+ // Update last update time display
1030
+ function updateLastUpdateTime() {
1031
+ const now = new Date();
1032
+ lastUpdateTime.innerHTML = `<i class="fas fa-clock me-1"></i>Son Güncelleme: ${now.toLocaleTimeString('tr-TR')}`;
1033
+ }
1034
+
1035
+ // Show/hide loading states
1036
+ function showLoading(show) {
1037
+ matchesLoading.style.display = show ? 'block' : 'none';
1038
+ }
1039
+
1040
+ function showAnalysisLoading(show) {