Spaces:
Sleeping
Sleeping
| // index.php | |
| error_reporting(0); | |
| ini_set('display_errors', 0); | |
| if (isset($_GET['action']) && $_GET['action'] == 'get_json') { | |
| header('Content-Type: application/json; charset=utf-8'); | |
| header('Access-Control-Allow-Origin: *'); | |
| if (isset($_GET['type']) && $_GET['type'] === 'live') { | |
| // يمكنك تعديل رابط المباشر هنا اذا كان لديك API مخصص للمباشر بنفس هيكل الجديد | |
| // حالياً سنستخدم نفس المنطق ولكن يفضل توحيد المصدر | |
| // كمثال سنستخدم نفس الرابط ولكن يجب أن يكون لديك رابط مباشر، | |
| // أو سنعتمد على جلب بيانات اليوم ونفلترها في الجافاسكربت (وهو الأضمن حالياً لعدم توفر رابط Live منفصل في طلبك) | |
| $reqDate = date('Y-m-d'); | |
| $apiUrl = "https://yallalive24.com/api/match.php/match.php/matches_date_get/$reqDate?key=BlackCode_Secret_2026"; | |
| } else { | |
| $reqDate = isset($_GET['date']) ? $_GET['date'] : ''; | |
| $reqDate = preg_replace('/[^0-9\-]/', '', $reqDate); | |
| if(empty($reqDate)) $reqDate = date('Y-m-d'); | |
| // الرابط الجديد كما طلبته | |
| $apiUrl = "https://yallalive24.com/api/match.php/match.php/matches_date_get/$reqDate?key=BlackCode_Secret_2026"; | |
| } | |
| $ch = curl_init(); | |
| curl_setopt($ch, CURLOPT_URL, $apiUrl); | |
| curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); | |
| curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); | |
| curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); | |
| curl_setopt($ch, CURLOPT_TIMEOUT, 15); | |
| curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'); | |
| $response = curl_exec($ch); | |
| if ($response === false) { | |
| echo json_encode(['status' => false, 'message' => 'Curl Error: ' . curl_error($ch)]); | |
| } else { | |
| echo $response; | |
| } | |
| curl_close($ch); | |
| exit; | |
| } | |
| <!DOCTYPE html> | |
| <html lang="ar" dir="rtl"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> | |
| <meta name="theme-color" content="#000000"> | |
| <meta name="description" content="جدول مباريات اليوم، نتائج مباشرة وترتيب الفرق"> | |
| <title>مباريات اليوم - Black Code</title> | |
| <link href="https://fonts.googleapis.com/css2?family=Cairo:wght@400;600;700;800&display=swap" rel="stylesheet"> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"> | |
| <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css"> | |
| <style> | |
| :root { | |
| /* تم تغيير الخلفية للأسود */ | |
| --bg-body: #000000; | |
| --bg-card: #16192; | |
| --bg-header: #1f232e; | |
| --text-white: #ffffff; | |
| --text-gray: #8a9099; | |
| --color-live: #e74c3c; | |
| --color-break: #f39c12; | |
| --color-cancelled: #ff4757; | |
| --color-teal: #1affc6; | |
| --color-success: #00e676; | |
| --color-miss: #ff1744; | |
| --bottom-nav-height: 60px; | |
| --radius: 12px; | |
| } | |
| * { | |
| box-sizing: border-box; | |
| -webkit-tap-highlight-color: transparent; | |
| outline: none; | |
| user-select: none; | |
| } | |
| body { | |
| font-family: 'Cairo', sans-serif; | |
| background-color: var(--bg-body); | |
| color: var(--text-white); | |
| margin: 0; | |
| padding: 0; | |
| font-size: 12px; | |
| padding-bottom: calc(var(--bottom-nav-height) + 20px); | |
| overflow-x: hidden; | |
| } | |
| a { text-decoration: none; color: inherit; } | |
| .main-wrapper { max-width: 500px; margin: 0 auto; min-height: 100vh; position: relative; } | |
| .top-navbar { | |
| display: flex; justify-content: space-between; align-items: center; | |
| padding: 10px 15px; background-color: var(--bg-body); | |
| position: sticky; top: 0; z-index: 50; border-bottom: 1px solid #1a1d26; | |
| } | |
| .nav-logo img { height: 24px; width: auto; pointer-events: none; } | |
| .nav-controls { display: flex; align-items: center; gap: 8px; } | |
| .nav-btn { | |
| background: var(--bg-header); border: 1px solid #2a2e3b; color: #ccc; | |
| width: 32px; height: 32px; border-radius: 8px; display: flex; align-items: center; justify-content: center; | |
| font-size: 13px; cursor: pointer; transition: 0.2s; | |
| } | |
| .nav-btn:active { transform: scale(0.95); background: var(--color-teal); color: #000; } | |
| .btn-live-wrapper { | |
| position: relative; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| background: #191c24; | |
| border: 1px solid #2c3140; | |
| border-radius: 20px; | |
| padding: 4px 12px; | |
| cursor: pointer; | |
| transition: 0.3s; | |
| height: 32px; | |
| } | |
| .btn-live-wrapper.is-live-mode { | |
| border-color: rgba(231, 76, 60, 0.5); | |
| box-shadow: 0 0 10px rgba(231, 76, 60, 0.2); | |
| } | |
| .live-content { | |
| display: flex; | |
| align-items: center; | |
| gap: 6px; | |
| font-weight: 700; | |
| font-size: 12px; | |
| } | |
| .live-text { | |
| color: var(--color-live); | |
| text-shadow: 0 0 8px rgba(231, 76, 60, 0.6); | |
| } | |
| .live-icon-svg { | |
| width: 10px; | |
| height: 10px; | |
| fill: var(--color-live); | |
| animation: livePulse 1.5s infinite; | |
| } | |
| .btn-live-wrapper.is-all-mode { | |
| background: var(--bg-header); | |
| border-color: #2a2e3b; | |
| } | |
| .btn-live-wrapper.is-all-mode .live-text { | |
| color: #ccc; | |
| text-shadow: none; | |
| } | |
| .btn-live-wrapper.is-all-mode .live-icon-svg { | |
| display: none; | |
| } | |
| @keyframes livePulse { | |
| 0% { opacity: 1; transform: scale(1); } | |
| 50% { opacity: 0.5; transform: scale(0.8); } | |
| 100% { opacity: 1; transform: scale(1); } | |
| } | |
| .date-header-container { display: flex; align-items: center; justify-content: space-between; padding: 12px 15px 5px 15px; } | |
| .date-display { font-size: 14px; font-weight: 700; color: #fff; } | |
| .today-badge { font-size: 10px; background: var(--color-break); color: #000; padding: 2px 6px; border-radius: 4px; font-weight: bold; display: none; } | |
| .matches-container { padding: 5px 10px 20px 10px; } | |
| .champ-block { margin-bottom: 12px; animation: fadeUp 0.4s ease; } | |
| .champ-header { | |
| display: flex; align-items: center; background-color: var(--bg-header); | |
| padding: 6px 10px; border-radius: var(--radius); margin-bottom: 5px; | |
| border: 1px solid #252936; cursor: pointer; position: relative; height: 40px; | |
| z-index: 2; | |
| transition: background-color 0.2s; | |
| } | |
| .champ-header:active { background-color: #2a2e3b; } | |
| .champ-header img { width: 18px; height: 18px; margin-left: 10px; object-fit: contain; } | |
| .champ-title { font-weight: 700; color: #ddd; font-size: 11px; flex: 1; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } | |
| .champ-actions { padding: 5px; color: #666; font-size: 14px; position: relative; z-index: 10; display: flex; align-items: center; cursor: pointer; } | |
| .dropdown-menu { display: none; position: absolute; left: 0; top: 30px; background: #252a36; border: 1px solid #333; border-radius: 8px; box-shadow: 0 5px 20px rgba(0,0,0,0.6); width: 160px; z-index: 50; } | |
| .dropdown-menu.show { display: block; animation: fadeIn 0.2s; } | |
| .dropdown-item { padding: 10px; color: #ccc; font-size: 11px; border-bottom: 1px solid #2f3442; transition: 0.2s; cursor: pointer; display: flex; align-items: center; gap: 8px; } | |
| .match-link { display: block; width: 100%; text-decoration: none; color: inherit; } | |
| .match-card { | |
| background-color: var(--bg-card); | |
| border-radius: var(--radius); | |
| margin-bottom: 8px; | |
| border: 1px solid #1f232e; | |
| position: relative; | |
| cursor: pointer; | |
| transition: background 0.2s ease, transform 0.1s; | |
| } | |
| .match-card:active { background-color: #20242e; transform: scale(0.99); } | |
| .match-card.regular-layout { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| min-height: 55px; | |
| padding: 5px 8px; | |
| } | |
| .regular-layout .team-name-box { | |
| flex: 1; | |
| font-size: 11px; | |
| font-weight: 700; | |
| color: #eee; | |
| white-space: nowrap; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| } | |
| .regular-layout .home-name { text-align: left; padding-left: 5px; } | |
| .regular-layout .away-name { text-align: right; padding-right: 5px; } | |
| .regular-layout .logo-box { width: 30px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; } | |
| .regular-layout .team-logo { width: 26px; height: 26px; object-fit: contain; } | |
| .regular-layout .match-center { | |
| width: 80px; | |
| display: flex; flex-direction: column; align-items: center; justify-content: center; | |
| flex-shrink: 0; | |
| } | |
| .match-card.penalty-layout { | |
| display: flex; | |
| align-items: flex-start; | |
| justify-content: space-between; | |
| padding: 12px 8px; | |
| } | |
| .penalty-layout .team-col { | |
| flex: 1; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| min-width: 0; | |
| gap: 6px; | |
| } | |
| .penalty-layout .center-col { | |
| width: 100px; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: flex-start; | |
| padding-top: 5px; | |
| flex-shrink: 0; | |
| } | |
| .penalty-layout .team-top-row { display: flex; align-items: center; gap: 8px; width: 100%; } | |
| .penalty-layout .team-col.home .team-top-row { flex-direction: row; justify-content: flex-start; } | |
| .penalty-layout .team-col.away .team-top-row { flex-direction: row-reverse; justify-content: flex-start; } | |
| .penalty-layout .team-logo { width: 32px; height: 32px; object-fit: contain; } | |
| .penalty-layout .team-name { font-size: 12px; font-weight: 700; color: #eee; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } | |
| .pen-label { font-size: 9px; color: #888; margin-top: 4px; margin-bottom: 2px; } | |
| .pen-score-box { | |
| background: #232836; | |
| border: 1px solid #353a4a; | |
| border-radius: 6px; | |
| padding: 3px 10px; | |
| font-size: 13px; | |
| font-weight: 800; | |
| color: var(--color-teal); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| margin-top: 2px; | |
| min-width: 45px; | |
| } | |
| .pen-dots-row { display: flex; align-items: center; gap: 4px; margin-top: 5px; height: 14px; } | |
| .penalty-layout .team-col.home .pen-dots-row { justify-content: flex-start; padding-right: 5px; } | |
| .penalty-layout .team-col.away .pen-dots-row { justify-content: flex-end; padding-left: 5px; } | |
| .pen-icon { font-size: 11px; } | |
| .pen-icon.scored { color: var(--color-success); filter: drop-shadow(0 0 2px rgba(0,230,118,0.3)); } | |
| .pen-icon.missed { color: var(--color-miss); } | |
| .upcoming-time { font-size: 12px; font-weight: 700; color: #fff; direction: ltr; } | |
| .status-text { | |
| font-size: 9px; | |
| font-weight: 700; | |
| color: var(--text-gray); | |
| margin-bottom: 3px; | |
| min-height: 12px; | |
| order: 1; | |
| transition: color 0.3s; | |
| } | |
| .score-container, .score-main { | |
| display: flex; align-items: center; justify-content: center; | |
| font-weight: 800; color: #fff; line-height: 1; | |
| order: 2; | |
| } | |
| .score-container { font-size: 18px; gap: 5px; } | |
| .score-main { font-size: 20px; gap: 8px; margin-bottom: 4px; } | |
| .box-live { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| justify-content: center; | |
| width: 100%; | |
| } | |
| .status-live { color: var(--color-live); } | |
| .status-break { color: var(--color-break); } | |
| .status-cancelled { color: var(--color-cancelled); } | |
| .status-ended { color: var(--text-gray); } | |
| .blink-dot { display: inline-block; width: 6px; height: 6px; background-color: var(--color-live); border-radius: 50%; margin-left: 3px; animation: blinker 1s infinite; vertical-align: middle; } | |
| @keyframes blinker { 50% { opacity: 0; } } | |
| @keyframes fadeUp { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } | |
| @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } | |
| .skeleton-block { margin-bottom: 15px; } | |
| .skeleton-header { height: 40px; background: #1f232e; border-radius: 12px; margin-bottom: 8px; position: relative; overflow: hidden; } | |
| .skeleton-card { height: 55px; background: #161922; border-radius: 12px; margin-bottom: 8px; position: relative; overflow: hidden; } | |
| .skeleton-header::after, .skeleton-card::after { | |
| content: ""; position: absolute; top: 0; left: 0; width: 100%; height: 100%; | |
| background: linear-gradient(90deg, transparent, rgba(255,255,255,0.05), transparent); | |
| animation: loading 1.5s infinite; | |
| } | |
| @keyframes loading { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } } | |
| .bottom-nav { position: fixed; bottom: 0; left: 0; width: 100%; height: var(--bottom-nav-height); background-color: #12141a; border-top: 1px solid #1f232e; display: flex; justify-content: space-around; align-items: center; z-index: 100; padding-bottom: env(safe-area-inset-bottom); } | |
| .nav-item { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; color: #666; text-decoration: none; height: 100%; transition: 0.2s; } | |
| .nav-item i { font-size: 18px; margin-bottom: 4px; } | |
| .nav-item span { font-size: 10px; font-weight: 600; } | |
| .nav-item.active { color: var(--color-teal); } | |
| .modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.7); z-index: 999; display: flex; align-items: flex-end; justify-content: center; opacity: 0; visibility: hidden; transition: opacity 0.3s; } | |
| .modal-overlay.active { opacity: 1; visibility: visible; } | |
| .modal-content { background: #11131a; width: 100%; max-width: 500px; border-radius: 20px 20px 0 0; padding: 20px; transform: translateY(100%); transition: transform 0.3s ease-out; } | |
| .modal-overlay.active .modal-content { transform: translateY(0); } | |
| .modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } | |
| .modal-title { font-size: 16px; font-weight: 700; color: #eee; } | |
| .modal-close { font-size: 20px; color: #888; cursor: pointer; } | |
| .filter-btn { width: 100%; background-color: var(--color-teal); color: #000; border: none; padding: 12px; border-radius: 12px; font-size: 14px; font-weight: 700; cursor: pointer; margin-top: 15px; } | |
| .flatpickr-calendar.inline { width: 100% !important; background: transparent !important; border: none !important; box-shadow: none !important; } | |
| .flatpickr-day { color: #fff !important; border-radius: 8px !important; } | |
| .flatpickr-day.selected { background: var(--color-teal) !important; color: #000 !important; border: none !important; font-weight: 800 !important; } | |
| .hidden { display: none !important; } | |
| .no-matches { text-align: center; padding-top: 80px; color: var(--text-gray); } | |
| .no-matches i { font-size: 40px; margin-bottom: 15px; opacity: 0.3; } | |
| .fav-icon { color: #f1c40f; font-size: 12px; margin-left: 5px; display: none; } | |
| .is-pinned .fav-icon { display: inline-block; } | |
| /* تنسيق الحقوق */ | |
| .black-code-rights { | |
| text-align: center; | |
| padding: 20px 0; | |
| margin-bottom: 10px; | |
| color: #888; | |
| font-family: 'Cairo', sans-serif; | |
| font-size: 12px; | |
| } | |
| .black-code-rights a { | |
| color: #ffffff; | |
| font-weight: bold; | |
| text-decoration: none; | |
| font-family: sans-serif; | |
| } | |
| .black-code-rights a:hover { | |
| color: var(--color-teal); | |
| } | |
| </style> | |
| </head> | |
| <body oncontextmenu="return false;" ondragstart="return false;" onselectstart="return false;"> | |
| <div class="main-wrapper"> | |
| <div class="top-navbar"> | |
| <div class="nav-logo"><img src="https://i.imgur.com/7J6w5wR.png" alt="Logo"></div> | |
| <div class="nav-controls"> | |
| <div class="btn-live-wrapper is-live-mode" id="live-toggle-btn" onclick="toggleLiveMode()"> | |
| <div class="live-content"> | |
| <svg class="live-icon-svg" viewBox="0 0 24 24"> | |
| <circle cx="12" cy="12" r="10" /> | |
| </svg> | |
| <span class="live-text" id="live-btn-text">مباشر</span> | |
| </div> | |
| </div> | |
| <button class="nav-btn" onclick="changeDate(-1)"><i class="fa-solid fa-chevron-right"></i></button> | |
| <button class="nav-btn" id="calendar-trigger"><i class="fa-regular fa-calendar"></i></button> | |
| <button class="nav-btn" onclick="changeDate(1)"><i class="fa-solid fa-chevron-left"></i></button> | |
| </div> | |
| </div> | |
| <div class="date-header-container"> | |
| <div class="date-display" id="date-label">--</div> | |
| <div class="today-badge" id="today-badge">اليوم</div> | |
| </div> | |
| <div class="matches-container" id="matches-wrapper"></div> | |
| <!-- قسم الحقوق --> | |
| <div class="black-code-rights"> | |
| صنع بواسطة | |
| <a href="https://t.me/Black_Code2" target="_blank">𝕭𝖑𝖆𝖈𝖐 𝕮𝖔𝖉𝖊</a> | |
| </div> | |
| </div> | |
| <div class="bottom-nav"> | |
| <a href="#" class="nav-item active"> | |
| <i class="fa-solid fa-futbol"></i> | |
| <span>المباريات</span> | |
| </a> | |
| <a href="stdieng.php" class="nav-item"> | |
| <i class="fa-solid fa-chart-simple"></i> | |
| <span>الترتيب</span> | |
| </a> | |
| <a href="news.php" class="nav-item"> | |
| <i class="fa-regular fa-newspaper"></i> | |
| <span>الأخبار</span> | |
| </a> | |
| <a href="#" class="nav-item"> | |
| <i class="fa-solid fa-bars"></i> | |
| <span>المزيد</span> | |
| </a> | |
| </div> | |
| <div class="modal-overlay" id="date-modal"> | |
| <div class="modal-content"> | |
| <div class="modal-header"> | |
| <div class="modal-close" onclick="closeModal()"><i class="fa-solid fa-xmark"></i></div> | |
| <div class="modal-title">اختر التاريخ</div> | |
| </div> | |
| <div id="inline-calendar-container"></div> | |
| <button class="filter-btn" onclick="applyDateFilter()">تطبيق الفلتر</button> | |
| </div> | |
| </div> | |
| <script src="https://cdn.jsdelivr.net/npm/flatpickr"></script> | |
| <script src="https://npmcdn.com/flatpickr/dist/l10n/ar.js"></script> | |
| <script> | |
| document.addEventListener('keydown', function(e) { | |
| if(e.ctrlKey && (e.key === 'c' || e.key === 'v' || e.key === 'u' || e.key === 's')) e.preventDefault(); | |
| if(e.keyCode == 123) e.preventDefault(); | |
| }); | |
| let userCurrentDate = new Date(); | |
| let tempSelectedDate = new Date(); | |
| let refreshInterval, timerInterval, calendarInstance; | |
| let currentData = []; | |
| let isLiveMode = false; | |
| document.addEventListener('DOMContentLoaded', () => { | |
| initCalendar(); | |
| updatePageContent(); | |
| document.getElementById('calendar-trigger').addEventListener('click', openModal); | |
| document.getElementById('date-modal').addEventListener('click', (e) => { | |
| if(e.target.id === 'date-modal') closeModal(); | |
| }); | |
| document.addEventListener('click', (e) => { | |
| if (!e.target.closest('.champ-actions')) { | |
| document.querySelectorAll('.dropdown-menu').forEach(menu => menu.classList.remove('show')); | |
| } | |
| }); | |
| }); | |
| function escapeHtml(text) { | |
| if (!text) return ""; | |
| return text | |
| .replace(/&/g, "&") | |
| .replace(/</g, "<") | |
| .replace(/>/g, ">") | |
| .replace(/"/g, """) | |
| .replace(/'/g, "'"); | |
| } | |
| function goToLeagueDetails(leagueId, leagueTitle) { | |
| window.location.href = `league-details.php?id=${leagueId}&title=${encodeURIComponent(leagueTitle)}`; | |
| } | |
| function toggleLiveMode() { | |
| const btnWrapper = document.getElementById('live-toggle-btn'); | |
| const btnText = document.getElementById('live-btn-text'); | |
| if (!isLiveMode) { | |
| isLiveMode = true; | |
| btnWrapper.classList.remove('is-live-mode'); | |
| btnWrapper.classList.add('is-all-mode'); | |
| btnText.innerText = "الكل"; | |
| document.getElementById('date-label').innerText = "مباريات جارية الآن"; | |
| document.getElementById('today-badge').style.display = "none"; | |
| loadLiveMatches(); | |
| } else { | |
| isLiveMode = false; | |
| btnWrapper.classList.remove('is-all-mode'); | |
| btnWrapper.classList.add('is-live-mode'); | |
| btnText.innerText = "مباشر"; | |
| updatePageContent(); | |
| } | |
| } | |
| function initCalendar() { | |
| calendarInstance = flatpickr("#inline-calendar-container", { | |
| locale: "ar", inline: true, defaultDate: userCurrentDate, disableMobile: true, dateFormat: "Y-m-d", | |
| onChange: function(selectedDates) { tempSelectedDate = selectedDates[0]; } | |
| }); | |
| } | |
| function openModal() { calendarInstance.setDate(userCurrentDate); tempSelectedDate = userCurrentDate; document.getElementById('date-modal').classList.add('active'); } | |
| function closeModal() { document.getElementById('date-modal').classList.remove('active'); } | |
| function applyDateFilter() { | |
| if (isLiveMode) { | |
| isLiveMode = false; | |
| const btnWrapper = document.getElementById('live-toggle-btn'); | |
| const btnText = document.getElementById('live-btn-text'); | |
| btnWrapper.classList.remove('is-all-mode'); | |
| btnWrapper.classList.add('is-live-mode'); | |
| btnText.innerText = "مباشر"; | |
| } | |
| userCurrentDate = tempSelectedDate; | |
| updatePageContent(); | |
| closeModal(); | |
| } | |
| function changeDate(offset) { | |
| if(isLiveMode) { | |
| toggleLiveMode(); | |
| return; | |
| } | |
| userCurrentDate.setDate(userCurrentDate.getDate() + offset); | |
| updatePageContent(); | |
| } | |
| function updatePageContent() { | |
| updateDateLabel(); | |
| loadMatches(formatDateForAPI(userCurrentDate)); | |
| } | |
| function updateDateLabel() { | |
| const options = { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' }; | |
| document.getElementById('date-label').innerText = userCurrentDate.toLocaleDateString('ar-EG', options); | |
| const today = new Date(); | |
| const isToday = (userCurrentDate.toDateString() === today.toDateString()); | |
| document.getElementById('today-badge').style.display = isToday ? 'inline-block' : 'none'; | |
| } | |
| function formatDateForAPI(date) { | |
| const offset = date.getTimezoneOffset(); | |
| const d = new Date(date.getTime() - (offset*60*1000)); | |
| return d.toISOString().split('T')[0]; | |
| } | |
| function getLeaguePrefs() { return JSON.parse(localStorage.getItem('league_prefs') || '{}'); } | |
| function setLeaguePref(id, type) { | |
| let prefs = getLeaguePrefs(); | |
| if (type === 'normal') delete prefs[id]; else prefs[id] = type; | |
| localStorage.setItem('league_prefs', JSON.stringify(prefs)); | |
| renderMatches(currentData); | |
| } | |
| function showSkeleton() { | |
| let html = ''; | |
| for(let i=0; i<3; i++) { | |
| html += `<div class="skeleton-block"> | |
| <div class="skeleton-header"></div> | |
| <div class="skeleton-card"></div> | |
| <div class="skeleton-card"></div> | |
| </div>`; | |
| } | |
| document.getElementById('matches-wrapper').innerHTML = html; | |
| } | |
| function loadMatches(dateStr) { | |
| showSkeleton(); | |
| clearInterval(refreshInterval); clearInterval(timerInterval); | |
| fetch(`?action=get_json&date=${dateStr}`).then(res => res.json()).then(json => { | |
| // تحديث: قراءة الهيكل الجديد للبيانات (json.data.data) | |
| if(!json.data || !json.data.data || json.data.data.length === 0) { | |
| document.getElementById('matches-wrapper').innerHTML = `<div class="no-matches"><i class="fa-regular fa-calendar-xmark"></i><p>لا توجد مباريات في هذا اليوم</p></div>`; | |
| currentData = []; | |
| } else { | |
| currentData = json.data.data; | |
| renderMatches(currentData); | |
| if(dateStr === formatDateForAPI(new Date())) startLiveUpdates(dateStr, false); | |
| } | |
| }).catch(err => { console.error(err); document.getElementById('matches-wrapper').innerHTML = `<div class="no-matches"><p>حدث خطأ في الاتصال</p></div>`; }); | |
| } | |
| function loadLiveMatches() { | |
| showSkeleton(); | |
| clearInterval(refreshInterval); clearInterval(timerInterval); | |
| fetch(`?action=get_json&type=live`).then(res => res.json()).then(json => { | |
| // تحديث: قراءة الهيكل الجديد للبيانات (json.data.data) | |
| if(!json.data || !json.data.data || json.data.data.length === 0) { | |
| document.getElementById('matches-wrapper').innerHTML = `<div class="no-matches"><i class="fa-solid fa-satellite-dish"></i><p>لا توجد مباريات جارية الآن</p></div>`; | |
| currentData = []; | |
| } else { | |
| currentData = json.data.data; | |
| // تصفية المباريات المباشرة في حالة جلب كل المباريات | |
| let liveMatches = currentData.filter(m => m.status != 0 && m.status != 10 && m.status != 4); | |
| if(liveMatches.length === 0) { | |
| // إذا لم نفلتر أو كان الرابط يعيد الكل، نعرض الكل أو نعتمد على الفلترة | |
| // هنا سنعرض الكل كما يأتي من الرابط إذا لم تنجح الفلترة أو إذا كان الرابط مخصصاً | |
| } | |
| renderMatches(currentData); | |
| startLiveUpdates(null, true); | |
| } | |
| }).catch(err => { | |
| console.error(err); | |
| document.getElementById('matches-wrapper').innerHTML = `<div class="no-matches"><p>حدث خطأ في الاتصال</p></div>`; | |
| }); | |
| } | |
| function renderMatches(matches) { | |
| const grouped = {}; | |
| matches.forEach(m => { | |
| if(!grouped[m.championship_id]) grouped[m.championship_id] = { info: m.championship, matches: [] }; | |
| grouped[m.championship_id].matches.push(m); | |
| }); | |
| const prefs = getLeaguePrefs(); | |
| const champIds = Object.keys(grouped); | |
| const topLeagues = [], normalLeagues = [], bottomLeagues = []; | |
| champIds.forEach(id => { | |
| const status = prefs[id] || 'normal'; | |
| if (status === 'top') topLeagues.push(id); | |
| else if (status === 'bottom') bottomLeagues.push(id); | |
| else normalLeagues.push(id); | |
| }); | |
| const sortedIds = [...topLeagues, ...normalLeagues, ...bottomLeagues]; | |
| let html = ''; | |
| sortedIds.forEach(id => { | |
| const grp = grouped[id]; | |
| const cImg = `https://imgs.ysscores.com/championship/48/${grp.info.image}`; | |
| const safeTitle = escapeHtml(grp.info.title); | |
| const safeTitleJs = safeTitle.replace(/'/g, "\\'"); | |
| const menuId = `menu-${id}`; | |
| const currentStatus = prefs[id] || 'normal'; | |
| const isPinned = (currentStatus === 'top') ? 'is-pinned' : ''; | |
| let menuItems = ''; | |
| const itemTop = `<div class="dropdown-item" onclick="setLeaguePref('${id}', 'top')"><i class="fa-solid fa-arrow-up"></i> ضعه في البداية</div>`; | |
| const itemBottom = `<div class="dropdown-item" onclick="setLeaguePref('${id}', 'bottom')"><i class="fa-solid fa-arrow-down"></i> ضعه في النهاية</div>`; | |
| const itemNormal = `<div class="dropdown-item" onclick="setLeaguePref('${id}', 'normal')"><i class="fa-solid fa-rotate-left"></i> رجوع للطبيعي</div>`; | |
| if (currentStatus === 'top') menuItems = itemNormal + itemBottom; | |
| else if (currentStatus === 'bottom') menuItems = itemTop + itemNormal; | |
| else menuItems = itemTop + itemBottom; | |
| html += `<div class="champ-block ${isPinned}"> | |
| <div class="champ-header" onclick="goToLeagueDetails('${grp.info.url_id}', '${safeTitleJs}')"> | |
| <img src="${cImg}" onerror="this.src='https://via.placeholder.com/18'"> | |
| <span class="champ-title">${safeTitle} <i class="fa-solid fa-star fav-icon"></i></span> | |
| <div class="champ-actions" onclick="toggleMenu(event, '${menuId}')"> | |
| <i class="fa-solid fa-ellipsis"></i> | |
| <div class="dropdown-menu" id="${menuId}">${menuItems}</div> | |
| </div> | |
| </div>`; | |
| grp.matches.forEach(m => { html += buildCard(m); }); | |
| html += `</div>`; | |
| }); | |
| document.getElementById('matches-wrapper').innerHTML = html; | |
| updateTimers(); | |
| timerInterval = setInterval(updateTimers, 1000); | |
| } | |
| function getPenaltiesDots(penaltiesArr) { | |
| if (!penaltiesArr || penaltiesArr.length === 0) return ''; | |
| let html = ''; | |
| penaltiesArr.forEach(obj => { | |
| const val = Object.values(obj)[0]; | |
| const cls = (val == 1) ? 'scored' : 'missed'; | |
| html += `<i class="fa-solid fa-futbol pen-icon ${cls}"></i>`; | |
| }); | |
| return html; | |
| } | |
| function getPenaltiesScore(pensArr) { | |
| let score = 0; | |
| if(pensArr) { | |
| pensArr.forEach(obj => { score += Object.values(obj)[0]; }); | |
| } | |
| return score; | |
| } | |
| function buildCard(m) { | |
| const hImg = `https://imgs.ysscores.com/teams/64/${m.home_team.image}`; | |
| const aImg = `https://imgs.ysscores.com/teams/64/${m.away_team.image}`; | |
| const homeName = escapeHtml(m.home_team.title); | |
| const awayName = escapeHtml(m.away_team.title); | |
| let timeStr; | |
| if (m.match_timestamp && m.match_timestamp > 0) { | |
| let dateObj = new Date(m.match_timestamp * 1000); | |
| timeStr = dateObj.toLocaleTimeString('en-US', {hour: '2-digit', minute:'2-digit'}); | |
| } else { timeStr = m.match_time; } | |
| timeStr = timeStr.replace('AM', 'ص').replace('PM', 'م'); | |
| let hasPens = false; | |
| let homeDots = '', awayDots = ''; | |
| let penScoreBox = '', penLabel = ''; | |
| if (m.penalties && Object.keys(m.penalties).length > 0) { | |
| const homeIdStr = m.home_team.row_id.toString(); | |
| const awayIdStr = m.away_team.row_id.toString(); | |
| const homePensArr = m.penalties[homeIdStr] || []; | |
| const awayPensArr = m.penalties[awayIdStr] || []; | |
| if (homePensArr.length > 0 || awayPensArr.length > 0) { | |
| hasPens = true; | |
| homeDots = getPenaltiesDots(homePensArr); | |
| awayDots = getPenaltiesDots(awayPensArr); | |
| let hPenScore = getPenaltiesScore(homePensArr); | |
| let aPenScore = getPenaltiesScore(awayPensArr); | |
| penLabel = `<div class="pen-label">ضربات جزاء</div>`; | |
| penScoreBox = `<div class="pen-score-box">${hPenScore} - ${aPenScore}</div>`; | |
| } | |
| } | |
| const upClass = (m.status == 0) ? '' : 'hidden'; | |
| const liveClass = (m.status != 0) ? '' : 'hidden'; | |
| const exTimeVal = m.ex_time ? m.ex_time : 0; | |
| if (hasPens) { | |
| return `<a href="match-details.php?id=${m.match_id}" class="match-link"> | |
| <div class="match-card penalty-layout" id="card-${m.match_id}" | |
| data-status="${m.status}" | |
| data-ht="${m.ht_time || 0}" | |
| data-start="${m.match_timestamp || 0}" | |
| data-ext="${exTimeVal}"> | |
| <div class="team-col home"> | |
| <div class="team-top-row"> | |
| <div class="logo-box"><img src="${hImg}" class="team-logo"></div> | |
| <div class="team-name">${homeName}</div> | |
| </div> | |
| <div class="pen-dots-row">${homeDots}</div> | |
| </div> | |
| <div class="center-col"> | |
| <div class="box-upcoming ${upClass}"> | |
| <span class="upcoming-time">${timeStr}</span> | |
| </div> | |
| <div class="box-live ${liveClass}"> | |
| <div class="status-text" id="st-${m.match_id}">--</div> | |
| <div class="score-main"> | |
| <span id="sh-${m.match_id}">${m.home_scores}</span> | |
| <span>-</span> | |
| <span id="sa-${m.match_id}">${m.away_scores}</span> | |
| </div> | |
| ${penLabel} | |
| ${penScoreBox} | |
| </div> | |
| </div> | |
| <div class="team-col away"> | |
| <div class="team-top-row"> | |
| <div class="logo-box"><img src="${aImg}" class="team-logo"></div> | |
| <div class="team-name">${awayName}</div> | |
| </div> | |
| <div class="pen-dots-row">${awayDots}</div> | |
| </div> | |
| </div> | |
| </a>`; | |
| } | |
| else { | |
| return `<a href="match-details.php?id=${m.match_id}" class="match-link"> | |
| <div class="match-card regular-layout" id="card-${m.match_id}" | |
| data-status="${m.status}" | |
| data-ht="${m.ht_time || 0}" | |
| data-start="${m.match_timestamp || 0}" | |
| data-ext="${exTimeVal}"> | |
| <div class="team-name-box home-name">${homeName}</div> | |
| <div class="logo-box"><img src="${hImg}" class="team-logo"></div> | |
| <div class="match-center"> | |
| <div class="box-upcoming ${upClass}"> | |
| <span class="upcoming-time">${timeStr}</span> | |
| </div> | |
| <div class="box-live ${liveClass}"> | |
| <div class="status-text" id="st-${m.match_id}">--</div> | |
| <div class="score-container"> | |
| <span id="sh-${m.match_id}">${m.home_scores}</span> | |
| <span style="font-size:12px; color:#555;">-</span> | |
| <span id="sa-${m.match_id}">${m.away_scores}</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="logo-box"><img src="${aImg}" class="team-logo"></div> | |
| <div class="team-name-box away-name">${awayName}</div> | |
| </div> | |
| </a>`; | |
| } | |
| } | |
| function toggleMenu(event, menuId) { | |
| event.stopPropagation(); | |
| event.preventDefault(); | |
| document.querySelectorAll('.dropdown-menu').forEach(m => { if(m.id !== menuId) m.classList.remove('show'); }); | |
| document.getElementById(menuId).classList.toggle('show'); | |
| } | |
| function startLiveUpdates(dateStr, liveMode) { | |
| refreshInterval = setInterval(() => { | |
| let url = `?action=get_json`; | |
| if (liveMode) { | |
| url += `&type=live`; | |
| } else { | |
| url += `&date=${dateStr}`; | |
| } | |
| fetch(url).then(r => r.json()).then(json => { | |
| // تحديث: قراءة الهيكل الجديد للبيانات (json.data.data) | |
| if(json.data && json.data.data) { | |
| updateMatchesDOM(json.data.data); | |
| } | |
| }); | |
| }, 15000); | |
| } | |
| function updateMatchesDOM(matches) { | |
| matches.forEach(m => { | |
| const card = document.getElementById(`card-${m.match_id}`); | |
| if(!card) return; | |
| card.setAttribute('data-status', m.status); | |
| if(m.ht_time) card.setAttribute('data-ht', m.ht_time); | |
| if(m.ex_time) card.setAttribute('data-ext', m.ex_time); | |
| const sh = document.getElementById(`sh-${m.match_id}`); | |
| const sa = document.getElementById(`sa-${m.match_id}`); | |
| if(sh && sh.innerText != m.home_scores) sh.innerText = m.home_scores; | |
| if(sa && sa.innerText != m.away_scores) sa.innerText = m.away_scores; | |
| const upBox = card.querySelector('.box-upcoming'); | |
| const liveBox = card.querySelector('.box-live'); | |
| if(m.status == 0) { | |
| if(upBox) upBox.classList.remove('hidden'); | |
| if(liveBox) liveBox.classList.add('hidden'); | |
| } else { | |
| if(upBox) upBox.classList.add('hidden'); | |
| if(liveBox) liveBox.classList.remove('hidden'); | |
| } | |
| }); | |
| currentData = matches; | |
| } | |
| function updateTimers() { | |
| const now = Math.floor(Date.now() / 1000); | |
| document.querySelectorAll('.match-card').forEach(card => { | |
| const status = parseInt(card.getAttribute('data-status')); | |
| if(status === 0) return; | |
| const mid = card.id.replace('card-', ''); | |
| const ht = parseInt(card.getAttribute('data-ht')); | |
| const start = parseInt(card.getAttribute('data-start')); | |
| const exTime = parseInt(card.getAttribute('data-ext')) || 0; | |
| const stEl = document.getElementById(`st-${mid}`); | |
| if(!stEl) return; | |
| stEl.className = "status-text"; | |
| if (status === 10 || status === 4 || status === 8) { | |
| stEl.innerText = "انتهت"; | |
| stEl.classList.add("status-ended"); | |
| return; | |
| } | |
| else if (status === 14) { | |
| stEl.innerText = "تأجلت"; | |
| stEl.classList.add("status-break"); | |
| return; | |
| } | |
| else if (status === 15) { | |
| stEl.innerText = "أُلغيت"; | |
| stEl.className = "status-text status-cancelled"; | |
| return; | |
| } | |
| else if (!ht && start > 0 && (now - start) > (200*60)) { | |
| stEl.innerText = "انتهت"; | |
| stEl.classList.add("status-ended"); | |
| return; | |
| } | |
| let txt = ""; | |
| let cls = "status-live"; | |
| let showDot = true; | |
| let diffSec = (ht > 0) ? (now - ht) : 0; | |
| let minutes = Math.floor(diffSec / 60); | |
| switch (status) { | |
| case 1: | |
| if (minutes >= 45) { | |
| let extra = minutes - 45; | |
| txt = "45+" + (extra > 0 ? extra : 1); | |
| } else { | |
| txt = (minutes + 1) + "'"; | |
| } | |
| break; | |
| case 2: | |
| txt = "استراحة"; | |
| cls = "status-break"; | |
| showDot = false; | |
| break; | |
| case 3: | |
| minutes = 46 + minutes; | |
| if (minutes >= 90) { | |
| let extra = minutes - 90; | |
| txt = "90+" + (extra > 0 ? extra : 1); | |
| } else { | |
| txt = minutes + "'"; | |
| } | |
| break; | |
| case 5: | |
| minutes = 90 + minutes + 1; | |
| if (minutes > 105) { | |
| let extra = minutes - 105; | |
| txt = "105+" + extra; | |
| } else { | |
| txt = minutes + "'"; | |
| } | |
| break; | |
| case 6: | |
| minutes = 105 + minutes + 1; | |
| if (minutes > 120) { | |
| let extra = minutes - 120; | |
| txt = "120+" + extra; | |
| } else { | |
| txt = minutes + "'"; | |
| } | |
| break; | |
| case 7: | |
| txt = "ضربات جزاء"; | |
| cls = "status-live"; | |
| showDot = true; | |
| break; | |
| case 55: case 66: | |
| txt = "استراحة"; | |
| cls = "status-break"; | |
| showDot = false; | |
| break; | |
| default: | |
| let totalMin = (start > 0) ? Math.floor((now - start) / 60) : 0; | |
| txt = totalMin + "'"; | |
| break; | |
| } | |
| if(txt !== "") { | |
| if (showDot) stEl.innerHTML = `<span class="blink-dot"></span> ${txt}`; | |
| else stEl.innerText = txt; | |
| stEl.className = `status-text ${cls}`; | |
| } else { | |
| stEl.innerText = ""; | |
| } | |
| }); | |
| } | |
| </script> | |
| </body> | |
| </html> |