<!DOCTYPE html>
<html lang="no">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Oddsvurdering - Testet og Fungerende</title>
<style>
body {
margin: 0;
font-family: 'Arial', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
min-height: 100vh;
}
.header {
text-align: center;
padding: 20px;
background: rgba(0,0,0,0.3);
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.card {
background: rgba(255,255,255,0.1);
border-radius: 15px;
padding: 20px;
margin: 15px 0;
backdrop-filter: blur(10px);
border: 1px solid rgba(255,255,255,0.2);
}
.status {
padding: 10px;
border-radius: 5px;
margin: 10px 0;
}
.success { background: rgba(0,255,0,0.2); }
.error { background: rgba(255,0,0,0.2); }
.loading { background: rgba(255,255,0,0.2); }
button {
background: linear-gradient(45deg, #667eea, #764ba2);
color: white;
border: none;
padding: 12px 24px;
border-radius: 25px;
cursor: pointer;
font-weight: bold;
margin: 10px 5px;
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}
.odds-display {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-top: 20px;
}
.match-card {
background: rgba(255,255,255,0.05);
padding: 15px;
border-radius: 10px;
border-left: 4px solid #667eea;
}
</style>
</head>
<body>
<div class="header">
<h1>🏆 Oddsvurdering Topp 3</h1>
<p>Live sports data og odds-analyse</p>
</div>
<div class="container">
<!-- Test Status -->
<div class="card">
<h2>📊 System Status</h2>
<div id="api-status" class="status loading">🔄 Tester API-forbindelse...</div>
<div id="data-status" class="status loading">🔄 Tester datainnhenting...</div>
<div id="calc-status" class="status loading">🔄 Tester odds-utregning...</div>
</div>
<!-- Kontroller -->
<div class="card">
<h2>🎮 Kontroller</h2>
<button onclick="testApiConnection()">Test API</button>
<button onclick="fetchEliteserienData()">Hent Eliteserien</button>
<button onclick="calculateOdds()">Beregn Odds</button>
<button onclick="runFullTest()">Kjør Full Test</button>
</div>
<!-- Data Display -->
<div class="card">
<h2>⚽ Eliteserien Data</h2>
<div id="eliteserien-data">
<div class="loading">🔄 Laster...</div>
</div>
</div>
<!-- Odds Display -->
<div class="card">
<h2>🎯 Odds & Analyser</h2>
<div id="odds-analysis" class="odds-display">
<div class="loading">🔄 Laster odds...</div>
</div>
</div>
</div>
<script>
// API Konfigurasjon
const API_CONFIG = {
footballData: {
token: 'aea61606efbc41e3b26ab0150ae8c749',
baseUrl: 'https://api.football-data.org/v4',
eliteserienId: 2163
}
};
// Test API-forbindelse
async function testApiConnection() {
updateStatus('api-status', 'loading', '🔄 Tester API-forbindelse...');
try {
const response = await fetch(
`${API_CONFIG.footballData.baseUrl}/competitions/${API_CONFIG.footballData.eliteserienId}`,
{
headers: {
'X-Auth-Token': API_CONFIG.footballData.token
}
}
);
if (response.ok) {
const data = await response.json();
updateStatus('api-status', 'success', `✅ API OK - ${data.name}`);
return true;
} else {
throw new Error(`HTTP ${response.status}`);
}
} catch (error) {
updateStatus('api-status', 'error', `❌ API-feil: ${error.message}`);
return false;
}
}
// Hent Eliteserien data
async function fetchEliteserienData() {
updateStatus('data-status', 'loading', '🔄 Henter Eliteserien data...');
try {
// Hent både tabell og kamper parallelt
const [standingsResponse, matchesResponse] = await Promise.all([
fetch(`${API_CONFIG.footballData.baseUrl}/competitions/${API_CONFIG.footballData.eliteserienId}/standings`, {
headers: { 'X-Auth-Token': API_CONFIG.footballData.token }
}),
fetch(`${API_CONFIG.footballData.baseUrl}/competitions/${API_CONFIG.footballData.eliteserienId}/matches`, {
headers: { 'X-Auth-Token': API_CONFIG.footballData.token }
})
]);
if (!standingsResponse.ok || !matchesResponse.ok) {
throw new Error('Feil ved henting av data');
}
const standingsData = await standingsResponse.json();
const matchesData = await matchesResponse.json();
// Behandle data
const table = standingsData.standings?.[0]?.table || [];
const matches = matchesData.matches || [];
displayEliteserienData(table, matches);
updateStatus('data-status', 'success', `✅ Data hentet - ${table.length} lag, ${matches.length} kamper`);
return { table, matches };
} catch (error) {
updateStatus('data-status', 'error', `❌ Data-feil: ${error.message}`);
return null;
}
}
// Vis Eliteserien data
function displayEliteserienData(table, matches) {
const container = document.getElementById('eliteserien-data');
// Topp 5 i tabellen
const top5 = table.slice(0, 5);
// Kommende kamper
const upcomingMatches = matches
.filter(match => match.status === 'SCHEDULED')
.slice(0, 3);
// Siste resultater
const recentMatches = matches
.filter(match => match.status === 'FINISHED')
.sort((a, b) => new Date(b.utcDate) - new Date(a.utcDate))
.slice(0, 3);
container.innerHTML = `
<h3>🏆 Topp 5</h3>
${top5.map(team => `
<div style="display: flex; justify-content: space-between; padding: 5px 0; border-bottom: 1px solid rgba(255,255,255,0.1);">
<span>${team.position}. ${team.team.name}</span>
<span>${team.points}p (${team.won}-${team.draw}-${team.lost})</span>
</div>
`).join('')}
<h3>⚽ Kommende kamper</h3>
${upcomingMatches.length > 0 ? upcomingMatches.map(match => `
<div style="padding: 10px; background: rgba(255,255,255,0.05); margin: 5px 0; border-radius: 5px;">
<strong>${match.homeTeam.name}</strong> vs <strong>${match.awayTeam.name}</strong><br>
<small>${new Date(match.utcDate).toLocaleDateString('no-NO')} ${new Date(match.utcDate).toLocaleTimeString('no-NO', {hour: '2-digit', minute: '2-digit'})}</small>
</div>
`).join('') : '<p>Ingen kommende kamper</p>'}
<h3>📊 Siste resultater</h3>
${recentMatches.map(match => `
<div style="padding: 8px; background: rgba(255,255,255,0.03); margin: 3px 0; border-radius: 3px;">
${match.homeTeam.name} ${match.score.fullTime.homeTeam}-${match.score.fullTime.awayTeam} ${match.awayTeam.name}
</div>
`).join('')}
`;
}
// Beregn odds
async function calculateOdds() {
updateStatus('calc-status', 'loading', '🔄 Beregner odds...');
try {
const data = await fetchEliteserienData();
if (!data) {
throw new Error('Ingen data tilgjengelig');
}
const { table, matches } = data;
const upcomingMatches = matches.filter(match => match.status === 'SCHEDULED').slice(0, 5);
const oddsAnalysis = upcomingMatches.map(match => {
const homeTeam = table.find(team => team.team.name === match.homeTeam.name);
const awayTeam = table.find(team => team.team.name === match.awayTeam.name);
// Beregn sannsynligheter basert på tabellposisjon og form
let homeWinProbability = 33.33; // Base
if (homeTeam && awayTeam) {
const positionDifference = awayTeam.position - homeTeam.position;
const pointsDifference = homeTeam.points - awayTeam.points;
// Hjemmefordel: +10%
homeWinProbability += 10;
// Tabellposisjon påvirkning
homeWinProbability += positionDifference * 2;
// Poengforskjell påvirkning
homeWinProbability += pointsDifference * 0.5;
// Begrens mellom 15% og 85%
homeWinProbability = Math.max(15, Math.min(85, homeWinProbability));
}
const drawProbability = 25;
const awayWinProbability = 100 - homeWinProbability - drawProbability;
// Konverter til odds (decimal)
const homeOdds = (100 / homeWinProbability).toFixed(2);
const drawOdds = (100 / drawProbability).toFixed(2);
const awayOdds = (100 / awayWinProbability).toFixed(2);
return {
match,
homeTeam,
awayTeam,
probabilities: {
home: homeWinProbability.toFixed(1),
draw: drawProbability.toFixed(1),
away: awayWinProbability.toFixed(1)
},
odds: {
home: homeOdds,
draw: drawOdds,
away: awayOdds
}
};
});
displayOddsAnalysis(oddsAnalysis);
updateStatus('calc-status', 'success', `✅ Odds beregnet for ${oddsAnalysis.length} kamper`);
return oddsAnalysis;
} catch (error) {
updateStatus('calc-status', 'error', `❌ Odds-feil: ${error.message}`);
return null;
}
}
// Vis odds-analyse
function displayOddsAnalysis(analysis) {
const container = document.getElementById('odds-analysis');
container.innerHTML = analysis.map(item => `
<div class="match-card">
<h4>${item.match.homeTeam.name} vs ${item.match.awayTeam.name}</h4>
<p><strong>Dato:</strong> ${new Date(item.match.utcDate).toLocaleDateString('no-NO')}</p>
<div style="margin: 10px 0;">
<div>🏠 Hjemme: ${item.probabilities.home}% (odds ${item.odds.home})</div>
<div>🤝 Uavgjort: ${item.probabilities.draw}% (odds ${item.odds.draw})</div>
<div>✈️ Borte: ${item.probabilities.away}% (odds ${item.odds.away})</div>
</div>
${item.homeTeam && item.awayTeam ? `
<div style="font-size: 0.9em; opacity: 0.8; margin-top: 10px;">
Tabellpos: ${item.homeTeam.position}. vs ${item.awayTeam.position}. plass<br>
Poeng: ${item.homeTeam.points} vs ${item.awayTeam.points}
</div>
` : ''}
</div>
`).join('');
}
// Kjør full test
async function runFullTest() {
console.log('🔄 Starter full test...');
const apiOk = await testApiConnection();
if (!apiOk) return;
await new Promise(resolve => setTimeout(resolve, 1000));
const data = await fetchEliteserienData();
if (!data) return;
await new Promise(resolve => setTimeout(resolve, 1000));
await calculateOdds();
console.log('✅ Full test fullført!');
}
// Hjelpefunksjon for status-oppdatering
function updateStatus(elementId, type, message) {
const element = document.getElementById(elementId);
element.className = `status ${type}`;
element.textContent = message;
}
// Start automatisk test ved lasting
window.addEventListener('load', () => {
console.log('🚀 Starter automatisk test...');
setTimeout(runFullTest, 1000);
});
</script>
</body>
</html>