Spaces:
Running
Running
Upload index.html
Browse files- index.html +91 -3
index.html
CHANGED
|
@@ -3142,10 +3142,46 @@ function safeImgHTML(urls, alt, lazy){
|
|
| 3142 |
* matokeo tayari yamechujwa, tunayabadilisha tu kuwa muundo wa
|
| 3143 |
* poster card (sawa na toCard()).
|
| 3144 |
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3145 |
async function searchMovieBoxRaw(keyword) {
|
| 3146 |
-
|
| 3147 |
-
|
| 3148 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3149 |
if (!Array.isArray(arr)) return [];
|
| 3150 |
return arr.map(x => {
|
| 3151 |
const year = x.releaseDate ? String(x.releaseDate).slice(0, 4) : null;
|
|
@@ -4254,7 +4290,58 @@ async function shareTranslatedTitle(d) {
|
|
| 4254 |
// ββ MICHEZO (fawa-live) ββ
|
| 4255 |
// Inarudisha orodha bapa (flat) ya mechi zote β inatumika na loadSports()
|
| 4256 |
// (kuonyesha kwa rails, kikundi kwa ligi) na search (kuchuja kwa query).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4257 |
async function fetchAllSportsItemsRaw() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4258 |
const res = await fetch(FAWA_BASE + '/matches', { headers: { Authorization: 'Bearer ' + FAWA_KEY } });
|
| 4259 |
if (!res.ok) throw new Error(T('err_generic') + ' ' + res.status);
|
| 4260 |
const d = await res.json();
|
|
@@ -6402,6 +6489,7 @@ async function playHlsUrl(url, opts = {}) {
|
|
| 6402 |
}
|
| 6403 |
|
| 6404 |
async function openFawaMatch(item) {
|
|
|
|
| 6405 |
openPlayerShell(item.title);
|
| 6406 |
// Jaribu Worker (Cloudflare) kwanza; ikishindwa (mf. 502) jaribu Supabase
|
| 6407 |
let url, opts, r = null;
|
|
|
|
| 3142 |
* matokeo tayari yamechujwa, tunayabadilisha tu kuwa muundo wa
|
| 3143 |
* poster card (sawa na toCard()).
|
| 3144 |
*/
|
| 3145 |
+
// Fallback: 'movies.search' ya dodolive kupitia jaynes-max-tv-api-. Muundo wa jibu
|
| 3146 |
+
// haujulikani kwa hakika, kwa hiyo tunapitia jibu lote kutafuta objects zenye id + title + picha.
|
| 3147 |
+
function collectDodoSubjects(node, depth, seen, out) {
|
| 3148 |
+
if (node == null || depth > 10) return;
|
| 3149 |
+
if (Array.isArray(node)) { node.forEach(n => collectDodoSubjects(n, depth + 1, seen, out)); return; }
|
| 3150 |
+
if (typeof node !== 'object') return;
|
| 3151 |
+
const o = (node.subject && typeof node.subject === 'object') ? node.subject : node;
|
| 3152 |
+
const id = o.subjectId != null ? o.subjectId : o.id;
|
| 3153 |
+
const title = typeof o.title === 'string' ? o.title : (typeof o.name === 'string' ? o.name : '');
|
| 3154 |
+
const cover = (o.cover && o.cover.url) || o.poster || o.coverUrl || o.image || null;
|
| 3155 |
+
if (id != null && title && cover && !seen.has(String(id))) {
|
| 3156 |
+
seen.add(String(id));
|
| 3157 |
+
out.push({
|
| 3158 |
+
id: String(id), title, cover: typeof cover === 'string' ? cover : null,
|
| 3159 |
+
genre: o.genre ?? null, rating: o.imdbRatingValue ?? o.rating ?? null,
|
| 3160 |
+
releaseDate: o.releaseDate ?? o.year ?? null, subjectType: o.subjectType ?? null,
|
| 3161 |
+
detailPath: o.detailPath ?? null, description: o.description ?? null,
|
| 3162 |
+
});
|
| 3163 |
+
}
|
| 3164 |
+
Object.keys(node).forEach(k => collectDodoSubjects(node[k], depth + 1, seen, out));
|
| 3165 |
+
}
|
| 3166 |
+
async function searchViaDodo(keyword) {
|
| 3167 |
+
const r = await rpcRaw('movies.search', { keyword, keywords: keyword, query: keyword, q: keyword, page: 1, perPage: 20 });
|
| 3168 |
+
const out = [];
|
| 3169 |
+
collectDodoSubjects(r && r.data !== undefined ? r.data : r, 0, new Set(), out);
|
| 3170 |
+
return out;
|
| 3171 |
+
}
|
| 3172 |
+
|
| 3173 |
async function searchMovieBoxRaw(keyword) {
|
| 3174 |
+
let arr = [];
|
| 3175 |
+
try {
|
| 3176 |
+
const url = SEARCH_FN_URL + '?keyword=' + encodeURIComponent(keyword);
|
| 3177 |
+
const res = await fetch(url, { headers: { 'apikey': SUPABASE_ANON_KEY }, cache: 'no-store' });
|
| 3178 |
+
const j = await res.json();
|
| 3179 |
+
if (Array.isArray(j)) arr = j;
|
| 3180 |
+
} catch (_) {}
|
| 3181 |
+
// movie-box ikirudisha tupu au kushindwa -> jaribu dodolive
|
| 3182 |
+
if (!arr.length) {
|
| 3183 |
+
try { arr = await searchViaDodo(keyword); } catch (_) {}
|
| 3184 |
+
}
|
| 3185 |
if (!Array.isArray(arr)) return [];
|
| 3186 |
return arr.map(x => {
|
| 3187 |
const year = x.releaseDate ? String(x.releaseDate).slice(0, 4) : null;
|
|
|
|
| 4290 |
// ββ MICHEZO (fawa-live) ββ
|
| 4291 |
// Inarudisha orodha bapa (flat) ya mechi zote β inatumika na loadSports()
|
| 4292 |
// (kuonyesha kwa rails, kikundi kwa ligi) na search (kuchuja kwa query).
|
| 4293 |
+
// ββ EMBEDS za Michezo: YouTube Live (inachezwa ndani ya app) na WhatsApp (kiungo cha kufungua nje) ββ
|
| 4294 |
+
// Hariri orodha hii tu. type: 'youtube' | 'whatsapp'
|
| 4295 |
+
// youtube : url = kiungo cha YouTube (watch?v=, youtu.be/, /live/, /embed/) AU channel ID (UC...)
|
| 4296 |
+
// whatsapp: url = kiungo cha WhatsApp Channel / group / wa.me (haiwezi ku-embed β inafunguliwa nje)
|
| 4297 |
+
const SPORTS_EMBEDS = [
|
| 4298 |
+
// { type: 'youtube', title: 'Mechi Live', url: 'https://www.youtube.com/watch?v=VIDEO_ID', league: 'Live YouTube', time: 'LIVE' },
|
| 4299 |
+
// { type: 'whatsapp', title: 'Kundi la Mechi', url: 'https://whatsapp.com/channel/XXXXXXXX', league: 'WhatsApp' },
|
| 4300 |
+
];
|
| 4301 |
+
function youtubeEmbedUrl(u) {
|
| 4302 |
+
u = String(u || '').trim();
|
| 4303 |
+
let id = null, channel = null;
|
| 4304 |
+
if (/^UC[\w-]{22}$/.test(u)) channel = u;
|
| 4305 |
+
else {
|
| 4306 |
+
const m = u.match(/(?:youtu\.be\/|[?&]v=|\/embed\/|\/live\/|\/shorts\/)([\w-]{11})/);
|
| 4307 |
+
if (m) id = m[1];
|
| 4308 |
+
else if (/^[\w-]{11}$/.test(u)) id = u;
|
| 4309 |
+
else { const c = u.match(/channel\/(UC[\w-]{22})/); if (c) channel = c[1]; }
|
| 4310 |
+
}
|
| 4311 |
+
if (id) return 'https://www.youtube.com/embed/' + id + '?autoplay=1&playsinline=1&rel=0&modestbranding=1';
|
| 4312 |
+
if (channel) return 'https://www.youtube.com/embed/live_stream?channel=' + channel + '&autoplay=1&playsinline=1&rel=0';
|
| 4313 |
+
return null;
|
| 4314 |
+
}
|
| 4315 |
+
function sportsEmbedItems() {
|
| 4316 |
+
return SPORTS_EMBEDS.map((e, i) => ({
|
| 4317 |
+
id: 'embed-' + i, kind: 'sport', title: e.title, poster: e.poster || null,
|
| 4318 |
+
subtitle: e.time || (e.type === 'youtube' ? 'LIVE' : 'WhatsApp'), imgFallbackOn: true,
|
| 4319 |
+
_league: e.league || (e.type === 'youtube' ? 'Live YouTube' : 'WhatsApp'), _embed: e
|
| 4320 |
+
}));
|
| 4321 |
+
}
|
| 4322 |
+
function openSportsEmbed(item) {
|
| 4323 |
+
const e = item._embed;
|
| 4324 |
+
openPlayerShell(item.title);
|
| 4325 |
+
if (e.type === 'youtube') {
|
| 4326 |
+
const src = youtubeEmbedUrl(e.url);
|
| 4327 |
+
if (!src) return statusMsg('Kiungo cha YouTube si sahihi.');
|
| 4328 |
+
stage.innerHTML = '<iframe allowfullscreen allow="autoplay; encrypted-media; picture-in-picture; fullscreen" referrerpolicy="strict-origin-when-cross-origin" src="' + esc(src) + '"></iframe>';
|
| 4329 |
+
} else {
|
| 4330 |
+
stage.innerHTML = '<div class="status">WhatsApp hairuhusu video kuwekwa ndani ya app.<br><br>' +
|
| 4331 |
+
'<a href="' + esc(e.url) + '" target="_blank" rel="noopener" style="display:inline-block;padding:12px 20px;border-radius:999px;background:#25d366;color:#04210f;font-weight:800;text-decoration:none">Fungua WhatsApp</a></div>';
|
| 4332 |
+
}
|
| 4333 |
+
}
|
| 4334 |
+
|
| 4335 |
async function fetchAllSportsItemsRaw() {
|
| 4336 |
+
const embeds = sportsEmbedItems();
|
| 4337 |
+
try {
|
| 4338 |
+
return (await fetchFawaMatchItems()).concat(embeds);
|
| 4339 |
+
} catch (e) {
|
| 4340 |
+
if (embeds.length) return embeds; // fawa-live ikishindwa, embeds bado zinaonekana
|
| 4341 |
+
throw e;
|
| 4342 |
+
}
|
| 4343 |
+
}
|
| 4344 |
+
async function fetchFawaMatchItems() {
|
| 4345 |
const res = await fetch(FAWA_BASE + '/matches', { headers: { Authorization: 'Bearer ' + FAWA_KEY } });
|
| 4346 |
if (!res.ok) throw new Error(T('err_generic') + ' ' + res.status);
|
| 4347 |
const d = await res.json();
|
|
|
|
| 6489 |
}
|
| 6490 |
|
| 6491 |
async function openFawaMatch(item) {
|
| 6492 |
+
if (item && item._embed) return openSportsEmbed(item);
|
| 6493 |
openPlayerShell(item.title);
|
| 6494 |
// Jaribu Worker (Cloudflare) kwanza; ikishindwa (mf. 502) jaribu Supabase
|
| 6495 |
let url, opts, r = null;
|