diff --git a/index.html b/index.html index 3f6baf4..eeff1bd 100644 --- a/index.html +++ b/index.html @@ -4725,7 +4725,13 @@ const url = `https://stooq.com/q/d/l/?s=${encodeURIComponent(sym)}&i=d`; try { - const csv = await fetchTextFirstOk(url, {}, 11000); + const csv = await fetchTextFirstOk( + url, + {}, + 11000, + ["local", "allorigins"], + (text) => !!text && text.includes("Date,Open,High,Low,Close") && !text.includes(""), + ); if (!csv || csv.length < 20 || csv.includes("")) { throw new Error("CSV inválido ou página de erro recebida"); } @@ -4747,9 +4753,7 @@ lsSet(cacheKey, sliced); return sliced; } - } catch (e) { - console.warn("[fetchStooqDailySeries] failed", e); - } + } catch {} throw new Error("Stooq histórico indisponível"); } @@ -5127,6 +5131,16 @@ /* Estado global — preenchido pela API ou pelo fallback */ var EURIBOR_DATA=null; +function isBceEuriborLiveEnabled(){ + try { + const qs = new URLSearchParams(location.search || ""); + if (qs.has("liveEuribor")) return (qs.get("liveEuribor") || "1") !== "0"; + return localStorage.getItem(PFX + "live_euribor_bce") === "1"; + } catch { + return false; + } +} + /* ── Parser SDMX JSON (formato BCE) ──────────────────────────── */ function parseBCEseries(json){ try{ @@ -5461,6 +5475,11 @@ if(ref) ref.textContent=EURIBOR_FALLBACK.updated; renderEuribor(); + if(!isBceEuriborLiveEnabled()){ + console.log("📐 Euribor: fallback EMMI (BCE live desativado)"); + return; + } + /* 3. Tentar BCE em background e actualizar se responder */ try{ console.log("📐 Euribor: a actualizar do BCE em background..."); @@ -7724,17 +7743,16 @@ /* ── Fetch TTF via Stooq CSV (tg.f = EUR/MWh) ──────────── */ async function fetchTTFStooq(){ const url=`https://stooq.com/q/l/?s=tg.f&f=sd2t2ohlcv&h&e=csv`; - const proxies=[ - ...(IS_LOCAL_DEV?[localProxyUrl(url)]:[]), - "https://api.allorigins.win/raw?url="+encodeURIComponent(url), - "https://corsproxy.io/?url="+encodeURIComponent(url), - "https://api.allorigins.win/raw?url="+encodeURIComponent(url.replace("stooq.com","stooq.pl")), - ]; - for(const p of proxies){ + const candidates=[url, url.replace("stooq.com","stooq.pl")]; + for(const candidate of candidates){ try{ - const r=await fetch(p,{signal:AbortSignal.timeout(9000)}); - if(!r.ok) continue; - const csv=await r.text(); + const csv=await fetchTextFirstOk( + candidate, + {}, + 9000, + ["local", "allorigins"], + (text) => !!text && text.includes("Symbol,Date,Time") && !text.includes(""), + ); const rows=csv.trim().split("\n"); if(rows.length<2) continue; /* CSV: Symbol,Date,Time,Open,High,Low,Close,Volume */ @@ -9586,11 +9604,13 @@ let d=force?null:lsGet(ck); if(!d){ try { - const url = "https://opensky-network.org/api/states/all?lamin=36&lomin=-12&lamax=44&lomax=-5"; - const j = await fetchJsonFirstOk(url, {}, 14000); - if(j && j.states?.length){ - d={ts:Date.now(),states:j.states,live:true}; - lsSet(ck,d); + if (IS_LOCAL_DEV) { + const url = "https://opensky-network.org/api/states/all?lamin=36&lomin=-12&lamax=44&lomax=-5"; + const j = await fetchJsonFirstOk(url, {}, 14000, ["local"], (jj) => Array.isArray(jj?.states)); + if(j && j.states?.length){ + d={ts:Date.now(),states:j.states,live:true}; + lsSet(ck,d); + } } } catch(e) { console.warn("⚠️ OpenSky falhou:", e.message); @@ -10585,11 +10605,13 @@ if(!d){ try { - const url = "https://datahub.ren.pt/service/renewable/"; - const j = await fetchJsonFirstOk(url, {}, 10000); - if(j && (j.value || j.data || Array.isArray(j))){ - d={src:"ren", raw:j}; - lsSet(ck, d); + if (IS_LOCAL_DEV) { + const url = "https://datahub.ren.pt/service/renewable/"; + const j = await fetchJsonFirstOk(url, {}, 10000, ["local"]); + if(j && (j.value || j.data || Array.isArray(j))){ + d={src:"ren", raw:j}; + lsSet(ck, d); + } } } catch(e) { console.warn("⚠️ REN DataHub falhou:", e.message); diff --git a/src/cards/elec.js b/src/cards/elec.js index c448418..830f339 100644 --- a/src/cards/elec.js +++ b/src/cards/elec.js @@ -276,10 +276,17 @@ `?start_date=${d}T00:00&end_date=${d}T23:59&time_trunc=hour`, ), ); - const mixFetch = fetchREE( - `/en/datos/generacion/estructura-generacion` + - `?start_date=${todayStr}T00:00&end_date=${todayStr}T23:59&time_trunc=hour`, - ); + const mixFetch = (async () => { + const mixDates = [todayStr, yesterStr]; + for (const d of mixDates) { + const data = await fetchREE( + `/en/datos/generacion/estructura-generacion` + + `?start_date=${d}T00:00&end_date=${d}T23:59&time_trunc=hour`, + ); + if (data) return data; + } + return null; + })(); const [todayData, yesterData, tomorrowData, mixData] = await Promise.all([...fetches, mixFetch]); @@ -674,4 +681,3 @@ window.loadElecTrend = loadElecTrend; window.loadElec = loadElec; })(); - diff --git a/src/cards/news.js b/src/cards/news.js index a01a9f2..fd72814 100644 --- a/src/cards/news.js +++ b/src/cards/news.js @@ -31,7 +31,7 @@ async function fetchRSS(url) { const isGoogleNews = /(^|\/\/)news\.google\.com\//i.test(url); const sources = isGoogleNews - ? ["direct", "local", "allorigins", "corsproxy"] + ? ["local", "jina", "allorigins"] : ["direct", "local", "allorigins", "jina", "corsproxy"]; const candidates = (buildFetchPlan(url, sources) || []).map((x) => x.url); @@ -102,26 +102,34 @@ } if (!arts.length) throw new Error("Sem artigos"); - el.innerHTML = `