let dgen = 0; async function openDetail(it) { const t = it._t; if (!ov.classList.contains('show')) ov._prev = cur; ov.classList.add('show'); side.classList.remove('open'); const my = ++dgen; ov.innerHTML = `
${ic('')}
` + SK.detail(it); $('#dback')._a = closeDetail; ov.scrollTop = 0; const d = await api(`/${t}/${it.id}`, `&append_to_response=videos,credits,recommendations,images,${t === 'movie' ? 'release_dates' : 'content_ratings'}&include_image_language=en,null`); if (my !== dgen || !ov.classList.contains('show')) return; if (!d.id) { closeDetail(); return } const title = d.title || d.name, year = ((d.release_date || d.first_air_date) || '').slice(0, 4); const cert = t === 'movie' ? (((d.release_dates || {}).results || []).find(r => r.iso_3166_1 === 'US') || { release_dates: [] }).release_dates.map(x => x.certification).find(Boolean) : (((d.content_ratings || {}).results || []).find(r => r.iso_3166_1 === 'US') || {}).rating; const rt = t === 'movie' ? (d.runtime ? `${Math.floor(d.runtime / 60)}h ${d.runtime % 60}m` : '') : (d.number_of_seasons ? `${d.number_of_seasons} Season${d.number_of_seasons > 1 ? 's' : ''}` : ''); const lg = ((d.images || {}).logos || []).find(x => x.iso_639_1 === 'en') || ((d.images || {}).logos || [])[0]; const bp = d.backdrop_path || d.poster_path; ov.innerHTML = `
${ic('')}
${(d.vote_average || 0).toFixed(1)}${year}${cert ? `${cert}` : ''}${rt}${(d.genres || []).slice(0, 3).map(g => g.name).join(', ')}
⋮

${d.overview || ''}

MORE
`; $('#dback')._a = closeDetail; const secs = $('#dsecs'); const rowOf = (name, kids) => { if (!kids.length) return; const s = document.createElement('section'); s.className = 'ds'; s.innerHTML = `

${name}

`; s.lastChild.append(...kids); secs.appendChild(s) }; const el = (c, h) => { const e = document.createElement('div'); e.className = c + ' f'; e.tabIndex = -1; e.innerHTML = h; e._a = () => { }; return e }; if (t === 'tv') { const ss = (d.seasons || []).filter(x => x.season_number > 0 && x.episode_count); if (ss.length) { const sec = document.createElement('section'); sec.className = 'ds eps'; sec.innerHTML = '

Episodes

'; secs.appendChild(sec); const ddb = $('#ddb'), ddl = $('#ddl'), list = $('#el'); let cs = null; const nm = x => x.name || 'Season ' + x.season_number; const loadEps = async x => { cs = x; ddb.innerHTML = `${esc(nm(x))}` + ic(''); [...ddl.children].forEach((c, i) => c.classList.toggle('cur', ss[i] === x)); list.innerHTML = SK.eps(10); const r = await api(`/tv/${it.id}/season/${x.season_number}`); if (cs !== x || !list.isConnected) return; list.innerHTML = ''; (r.episodes || []).forEach((p, ix) => { const n = p.episode_number, img = p.still_path ? I + 'w300' + p.still_path : (it.backdrop_path ? I + 'w300' + it.backdrop_path : PH); const e = el('ep', `
${esc(p.name || 'Episode ' + n)}${['Episode ' + n, p.runtime ? p.runtime + 'm' : ''].filter(Boolean).join(' \u2022 ')}`); e.title = p.overview || ''; e._a = () => openPlayer(it, `S${x.season_number} E${n} \u2022 ${p.name || ''}`, { it, seasons: ss, s: x.season_number, eps: r.episodes, i: ix, cache: { [x.season_number]: r.episodes } }); list.appendChild(e) }); const f0 = list.firstChild; if (f0 && f0._a && $('#dplay')) $('#dplay')._a = () => f0._a(); if (!list.children.length) list.innerHTML = '

No episodes listed.

' }; ss.forEach(x => ddl.appendChild(mkf('ddi', `${esc(nm(x))}${x.episode_count} eps`, () => { closeDD(); loadEps(x) }))); ddb._a = () => { if (!closeDD()) { ddl.classList.add('open'); setFocus(ddl.children[Math.max(0, ss.indexOf(cs))]) } }; loadEps(ss[0]) } } rowOf('Trailers', ((d.videos || {}).results || []).filter(v => v.site === 'YouTube' && /Trailer|Teaser|Clip/.test(v.type)).sort((a, b) => (b.type === 'Trailer') - (a.type === 'Trailer')).slice(0, 8).map(v => el('tr', `
${v.name}▶ ${v.type}`))); rowOf('Related', ((d.recommendations || {}).results || []).filter(x => x.poster_path).map(x => { x._t = t; return card(x, false) })); rowOf('Cast', ((d.credits || {}).cast || []).slice(0, 20).map(p => el('cs', `
${p.profile_path ? '' : p.name[0]}
${p.name}${p.character || ''}`))); $('#dplay')._a = () => openPlayer(it); const sync = () => [['dwl', 'wl', P_WL], ['dfv', 'fav', P_FV]].forEach(([id, k, p]) => { const e = $('#' + id), v = has(k, it); e.classList.toggle('sv', v); e.dataset.l = (v ? 'Remove from ' : 'Add to ') + LN[k]; e.innerHTML = ic(p) }); sync(); $('#dmenu')._a = () => { const o = $('#dmx').classList.toggle('open'); $('#dmenu').classList.toggle('sv', o) }; $('#dwl')._a = () => { toggleLib('wl', it); sync() }; $('#dfv')._a = () => { toggleLib('fav', it); sync() }; $('#dmore')._a = () => { const o = $('#otx'), m = $('#dmore'); o.classList.toggle('x'); m.textContent = o.classList.contains('x') ? 'LESS' : 'MORE' }; ov.scrollTop = 0; setFocus($('#dplay')) } function closeDetail() { ov.classList.remove('show'); const p = ov._prev; setTimeout(() => { if (!ov.classList.contains('show')) ov.innerHTML = '' }, 400); if (p && document.body.contains(p)) setFocus(p); else if (lib.classList.contains('show')) setFocus($('#lgrid .card') || navAct) } function closeDD() { const l = $('#ddl'); if (l && l.classList.contains('open')) { l.classList.remove('open'); setFocus($('#ddb')); return true } return false }