const axios = require('axios'); const he = require('he'); // HTML entity decode etmek için (npm install he) const cheerio = require('cheerio'); // HTML içinden data-settings almak için const MATCH_ID = '18rkqb1lhon6ne1hdb6d15as'; // Barcelona - Real Madrid // 1. ADIM: TANIMLARI (METADATA) ÇEK VE HARİTALAMA YAP async function createMarketMap() { // Bu URL bize HTML döndürür, ama içinde data-settings JSON'u vardır. const url = `https://www.mackolik.com/ajax/iddaa/markets/soccer/all/${MATCH_ID}?template=all`; const response = await axios.get(url, { headers: { 'X-Requested-With': 'XMLHttpRequest', 'User-Agent': 'Mozilla/5.0' } }); // Cheerio ile HTML'i yükle const $ = cheerio.load(response.data.data.html); // data-settings özniteliğini bul (Genelde "all" marketlerinde bulunur) // Not: Bazen widget-iddaa-markets--all bazen başka class olabilir, genel arıyoruz: const settingsRaw = $('.widget-iddaa-markets').first().attr('data-settings'); if (!settingsRaw) { console.error("Data settings bulunamadı!"); return null; } // HTML Entity'lerini temizle (" -> ") const settingsJson = JSON.parse(he.decode(settingsRaw)); // Şimdi elimizde ALTIN DEĞERİNDE bir sözlük var: marketCollection const definitions = settingsJson.iddaaEventId.marketCollection; // Bizim kullanacağımız Harita (Dictionary) let marketMap = {}; // Sözlüğü oluşturuyoruz: ID -> İSİM for (const key in definitions) { const market = definitions[key]; const marketId = market.iddaaId || market.id; // Bazen iddaaId, bazen id kullanılır marketMap[marketId] = { name: market.name, // "Maç Sonucu" outcomes: {} }; // Seçenekleri de haritalayalım (1, X, 2, Alt, Üst) // selectionCollectionAll varsa onu, yoksa selectionCollection kullan const selections = market.selectionCollectionAll || market.selectionCollection; for (const selKey in selections) { const selection = selections[selKey]; // Outcome shortcode (Örn: 1.1) veya iddaaMarketId ile eşleşme yapabiliriz // Live JSON'da outcome ID'leri "1.1", "1.2" gibi shortcode olarak geliyor. marketMap[marketId].outcomes[selection.shortcode] = selection.name; } } console.log("✅ Market Haritası Başarıyla Oluşturuldu (HTML'den)."); return marketMap; } // 2. ADIM: CANLI VERİYİ ÇEK VE HARİTA İLE BİRLEŞTİR async function fetchLiveOdds(marketMap) { // Bu URL sadece sayıları (oranları) verir, çok hızlıdır. const url = `https://www.mackolik.com/ajax/iddaa/outcomes/soccer/all/${MATCH_ID}`; const response = await axios.get(url, { headers: { 'X-Requested-With': 'XMLHttpRequest', 'User-Agent': 'Mozilla/5.0' } }); const liveMarkets = response.data.data.markets; console.log("\n📊 GÜNCEL ORANLAR (Dinamik Eşleştirme İle):\n"); console.log(`| ${"BAHİS TÜRÜ".padEnd(35)} | ${"SEÇENEK".padEnd(15)} | ${"ORAN".padEnd(6)} |`); console.log("-".repeat(65)); // Canlı veriyi dönüyoruz for (const [marketId, data] of Object.entries(liveMarkets)) { // Haritamızdan bu ID'nin adını buluyoruz // JSON'daki marketId bazen Mackolik ID'si bazen Iddaa ID'si olabiliyor. // Genelde 'code' alanı ile bizim map'teki ID eşleşir veya key ile. // Senin attığın JSON'da keyler (örn: 1, 3, 184.5) Mapping ID'si olarak kullanılıyor. // DİKKAT: Senin attığın JSON'da Keyler (1, 184.5) bizim Map'teki ID'ler olmayabilir. // HTML JSON'undaki "id" alanı (örn: 1) ile Canlı JSON'daki Key (örn: 1) eşleşir. // Eşleşme Algoritması: // HTML'deki `market.id` == LiveJSON'daki `key` // HTML Map'imizi ID bazlı (1, 3, 184.5 gibi) tekrar düzenlememiz gerekebilir ama // senin HTML JSON'una baktığımda "id": 18, "iddaaId": 55512092 var. // Live JSON key'i "184.5" (Bu aslında 18 nolu marketin 4.5 barajı). // Basit Eşleştirme Denemesi (ID üzerinden): // Live JSON'daki key (örn "1" veya "184.5") HTML map'te yoksa, "code" (50465) üzerinden arama yapabiliriz. // Ama en garantisi HTML'deki marketCollection içindeki key yapısıdır. // Şimdilik basit ID eşleştirmesi yapalım, eğer map'te yoksa "Bilinmeyen" yazarız. // Live JSON Key'i ile Map arıyoruz. // Ancak HTML'deki "id" (örn: 1) ile Live JSON key (1) tutuyor. // Fakat "184.5" gibi olanlar HTML'de "id: 18, sov: 4.5" olarak geçiyor. let definitions = findDefinition(marketMap, marketId, data); let marketName = definitions ? definitions.name : `Bilinmeyen (${marketId})`; // Eğer barajlı bir bahisse (184.5 gibi) isme barajı ekle // (Zaten HTML'den gelen isimde "4,5 Alt/Üst" yazıyor olacak) for (const [outcomeKey, outcomeData] of Object.entries(data.outcomes)) { if (outcomeData.outcome !== '-') { let label = outcomeData.label; // Eğer label mapping'den gelirse daha doğru olur ama outcomeData.label da genelde doğrudur. console.log(`| ${marketName.padEnd(35)} | ${label.padEnd(15)} | ${outcomeData.outcome.padEnd(6)} |`); } } } } // Yardımcı Fonksiyon: Live JSON Key'ini HTML Map içinde bulma function findDefinition(marketMap, liveKey, liveData) { // 1. Doğrudan ID eşleşmesi (Örn: "1" == "1") // HTML'i parse ederken ID'leri key olarak ayarlamalıyız. // Yukarıdaki createMarketMap fonksiyonunu buna göre revize ettim aşağıda. // Asıl sorun: HTML JSON'da keyler "0", "1", "2" diye gidiyor array indexi gibi. // Ama içlerinde "id": 1, "id": 18 var. // Biz map'i oluştururken liveKey ile eşleşecek şekilde kurmalıyız. // LiveKey "184.5" ise -> id=18 ve sov=4.5 olanı bulmalıyız. // Bu karmaşıklığı çözmek için MarketMap'i bir Array olarak tutup find ile aramak en iyisi. for (const def of Object.values(marketMap)) { // Eğer ID tutuyorsa (Örn: 1 == 1) if (def.rawId == liveKey) return def; // Eğer ID ve Baraj (sov) tutuyorsa (Örn: LiveKey "184.5", Def id=18, sov=4.5) if (liveKey.includes('.')) { const [mainId, sov] = liveKey.split('.'); // Tamam float problemleri olabilir ama string olarak "18" == def.rawId // Bu kısım biraz manuel mapping gerektirebilir ama HTML içindeki "name" zaten barajı içeriyor. // HTML'deki iddaaMarketNo veya iddaaId ile LiveData'daki code eşleşebilir! if (def.iddaaCode == liveData.code) return def; // EN GARANTİ YÖNTEM BU! } if (def.iddaaCode == liveData.code) return def; } return null; } // ------------------------------------------------------------------ // REVIZE EDİLMİŞ HARİTA OLUŞTURUCU (EN SAĞLAMI) // ------------------------------------------------------------------ async function main() { const url = `https://www.mackolik.com/ajax/iddaa/markets/soccer/all/${MATCH_ID}?template=all`; const response = await axios.get(url, { headers: { 'X-Requested-With': 'XMLHttpRequest', 'User-Agent': 'Mozilla/5.0' } }); const $ = cheerio.load(response.data.data.html); const settingsRaw = $('.widget-iddaa-markets').first().attr('data-settings'); if (!settingsRaw) return; const settingsJson = JSON.parse(he.decode(settingsRaw)); const definitions = settingsJson.iddaaEventId.marketCollection; // Haritamızı bir dizi (array) yapalım, içinde arama yapacağız. let marketDefinitions = []; for (const key in definitions) { const m = definitions[key]; marketDefinitions.push({ name: m.name, // Örn: "Maç Sonucu" veya "4,5 Alt/Üst" rawId: m.id, // Örn: 1 veya 18 iddaaCode: m.iddaaNo, // Örn: "10313" (HTML'deki code) -> LiveData'da "code" ile eşleşecek mi bakacağız. iddaaMarketId: m.iddaaId, // Örn: 21983276 -> LiveData'da code olarak gelebilir. sov: m.sov // Baraj değeri (4.5) }); } // --- LIVE DATA ÇEK --- const liveUrl = `https://www.mackolik.com/ajax/iddaa/outcomes/soccer/all/${MATCH_ID}`; const liveRes = await axios.get(liveUrl, { headers: { 'X-Requested-With': 'XMLHttpRequest', 'User-Agent': 'Mozilla/5.0' } }); const liveMarkets = liveRes.data.data.markets; // --- EŞLEŞTİRME VE YAZDIRMA --- console.log(`\nMAÇ: ${MATCH_ID} | DATA ANALİZİ SONUCU`); console.log("=".repeat(70)); for (const [liveKey, liveData] of Object.entries(liveMarkets)) { // EŞLEŞTİRME MANTIĞI: // Live Data içindeki "code" (Örn: 50465) ile HTML'deki "iddaaId" (Örn: 55507607) veya "iddaaNo" (Örn: 18660) eşleşmeli. // Senin attığın son örneklerde: // HTML JSON: "iddaaId": 55507607, "iddaaNo": "18660" // LIVE JSON: "code": "50465" // HATA: Kodlar (Code) maç başladığında (Live) ve başlamadan önce (Pre-match) değişiyor olabilir! // Bu durumda en güvenilir eşleşme "Market Tipi" (ID) ve "Baraj" (SOV) üzerinden olur. let matchedDef = marketDefinitions.find(def => { // 1. Ana ID eşleşiyor mu? (1 == 1) if (def.rawId == liveKey) return true; // 2. Barajlı ID kontrolü (184.5 -> id:18, sov:4.5) if (liveKey.includes('.')) { // Float çevirmeden string karşılaştırması riskli olabilir, dikkat. // LiveKey "184.5" // Def: rawId=18, sov=4.5 // 18 == 18 AND 4.5 == 4.5 if (def.rawId == Math.floor(parseFloat(liveKey)) && def.sov == parseFloat(liveKey.split('.')[1] + '.' + (liveKey.split('.')[2] || '0'))) { // Basitçe string match daha güvenli olabilir return def.rawId == 18 && def.sov == 4.5 && liveKey == "184.5"; // Örnek mantık } // Daha basit: Mackolik Live Key yapısı: {MARKET_ID}{BARAJ} // "18" + "4.5" -> "184.5" if (def.rawId == 18 && liveKey == `18${def.sov}`) return true; if (def.rawId == 19 && liveKey == `19${def.sov}`) return true; // 1. Yarı Alt üst } return false; }); // Eğer yukarıdaki ID mantığı tutmazsa manuel düzeltme: // Mackolik LiveKey formatı: {ID} veya {ID}{SOV} // Örn: Market 1 -> Key "1" // Örn: Market 18 (Alt/Üst), Sov 4.5 -> Key "184.5" // Hızlı çözüm için bir Map oluşturuyorum: const name = getMarketNameFromKey(liveKey, marketDefinitions); for (const [k, v] of Object.entries(liveData.outcomes)) { if (v.outcome !== '-') { console.log(`| ${name.padEnd(35)} | ${v.label.padEnd(10)} | ${v.outcome} |`); } } } } function getMarketNameFromKey(key, definitions) { // 1. Tam eşleşme (ID 1, 3, 11 vb.) let exact = definitions.find(d => d.rawId == key); if (exact) return exact.name; // 2. Noktalı Eşleşme (184.5, 191.5 vb.) if (key.includes('.')) { // key: 184.5 -> id: 18, sov: 4.5 // key: 190.5 -> id: 19, sov: 0.5 // Püf nokta: String olarak sov'u ayıklamak. // Genelde sonu .5 ile biter. // Ama ID 18, 19, 28, 29 gibi alt/üst türleri var. // Bu kısmı senin için basitleştiriyorum: // HTML'deki isimleri tara, hangisinin sov değeri key ile uyuşuyorsa onu al. for (let def of definitions) { if (def.sov !== null) { // Basit bir string contains kontrolü bile çoğu zaman yeter. // Örneğin key="184.5", def.rawId=18, def.sov=4.5 -> Eşleşir. // key="280.5", def.rawId=28, def.sov=0.5 -> Eşleşir. // Formül: Key, Def.ID ile başlıyor mu VE Key, Def.Sov ile bitiyor mu? if (key.startsWith(def.rawId) && key.endsWith(def.sov)) { return def.name; } } } } return `Bilinmeyen Market (${key})`; } main();