clone

a desktop tv and program guide for over-the-air broadcasts: what's on air, what your tuner gets, live tv, recordings

Show the fuller listings on TV, and logos on the dark

FelineStateMachine committed d0bba5f
The banner gains a short cast line (put away while the controls are up),
and the details (I) show the whole description now that Schedules
Direct's run long. Network names are matched whatever their case, so
Schedules Direct's "Public Broadcasting Service" is PBS again.

Schedules Direct also has each station's logo drawn for a dark
background, in white: the guide shows that one on itself rather than the
colored one on a light chip, which stays for listings without one.
commit
d0bba5f90c9f7ba23be0e1def006e7a9d7cc0166
parent
2d030fb47ff44863b02338be3c070a8a50642d14
author
FelineStateMachine <226808055+FelineStateMachine@users.noreply.github.com>
kind
feat risk score 1.5 of 3, Jev's estimate
8 files changed, +33 -9
Mfrontend/dist/app.js6++++--
Mfrontend/dist/index.html1+
Mfrontend/dist/style.css7+++++++
Minternal/guide/gracenote.go7++++++-
Minternal/guide/gracenote_test.go4++++
Minternal/lineup/tuner.go6++++--
Minternal/sd/sd_test.go2+-
Minternal/sd/state.go9++++++---
M frontend/dist/app.js +4 -2
@@ -747,7 +747,7 @@ function firstAired(d) {
747747 }748748 749749 // castLine names a program's cast: "With Missy Peregrym, Zeeko Zaki".750-const castLine = (p) => (p && p.cast && p.cast.length ? `With ${p.cast.slice(0, 5).map((c) => c.replace(/ \(.*\)$/, '')).join(', ')}` : '');750+const castLine = (p, n = 5) => (p && p.cast && p.cast.length ? `With ${p.cast.slice(0, n).map((c) => c.replace(/ \(.*\)$/, '')).join(', ')}` : '');751751 752752 function renderBanner() {753753 updateMediaSession();
@@ -772,6 +772,7 @@ function renderBanner() {
772772 f(b, 'chips').innerHTML = (rec ? `<span class="chip live">${rec.status === 'recording' ? 'Recording' : 'Will record'}</span>` : '') + chipsFor(p, ch);773773 f(b, 'title').textContent = p ? p.title : 'No listings';774774 f(b, 'ep').textContent = episodeLine(p);775+ f(b, 'cast').textContent = castLine(p, 3);775776 f(b, 'progress').style.width = p ? `${Math.min(100, ((now - p._s) / (p._e - p._s)) * 100)}%` : '0';776777 f(b, 'desc').textContent = p ? p.description || '' : ch.description || '';777778 f(b, 'next').textContent = nx ? `${clock(nx._s)} ${nx.title}` : '';
@@ -2090,7 +2091,8 @@ function renderGuide() {
20902091 html += `<div class="${cls}"><div class="g-ch" data-row="${r}">20912092 <div class="num${ch.number.length > 4 ? ' long' : ''}">${esc(ch.number)}</div>20922093 <div class="who"><div class="net">${isFav(ch) ? '<span class="fav">★</span>' : ''}${esc(ch.network || displayCall(ch))}</div><div class="call"${bad ? ` title="${esc(`${sig.label}: ${sigDetail(sig)}`)}"` : ''}>${bad ? meter(sig) : ''}<span>${esc(displayCall(ch))}</span></div></div>2093- ${ch.logo ? `<div class="logo${ch.own ? ' own' : ''}" style="background-image:url('${esc(ch.logo)}')"></div>` : '<div></div>'}2094+ ${ch.logoDark ? `<div class="logo own" style="background-image:url('${esc(ch.logoDark)}')"></div>`2095+ : ch.logo ? `<div class="logo${ch.own ? ' own' : ''}" style="background-image:url('${esc(ch.logo)}')"></div>` : '<div></div>'}20942096 </div><div class="g-progs">`;20952097 const progs = programsFor(ch).filter((p) => p._e > lo && p._s < hi);20962098 if (!progs.length) {
M frontend/dist/index.html +1 -0
M frontend/dist/style.css +7 -0
@@ -153,6 +153,10 @@ body.mode-tv #banner.show { transform: none; opacity: 1; }
153153 .bn-progress { height: 3px; background: var(--line-2); margin: 12px 0 10px; border-radius: 2px; overflow: hidden; }154154 .bn-progress i { display: block; height: 100%; background: var(--amber); width: 0; transition: width .6s; }155155 .bn-desc { margin: 0; color: var(--muted); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; max-width: 72ch; }156+.bn-cast { color: var(--muted); font-size: .92em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 72ch; margin-top: 2px; }157+.bn-cast:empty, #banner.osd .bn-cast { display: none; }158+/* The details (I) have room for the whole description. */159+#banner.detail .bn-desc { -webkit-line-clamp: 6; }156160 .bn-next { display: flex; gap: 10px; align-items: center; margin-top: 12px; font-size: 14px; }157161 .bn-signal { border-left: 1px solid var(--line); padding-left: 24px; display: none; flex-direction: column; gap: 8px; justify-content: center; }158162 #banner.detail, #banner.warn { grid-template-columns: 210px minmax(0, 1fr) 270px; }
@@ -243,6 +247,9 @@ body.mode-guide #guide, body.mode-antenna #antenna, body.mode-settings #settings
243247 .g-ch .who { min-width: 0; }244248 .g-ch .call { font: 400 11px var(--f-mono); letter-spacing: .06em; color: var(--muted); display: flex; gap: 6px; align-items: center; }245249 .g-ch .net { font-size: 13px; font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }250+/* A station's logo drawn for a light background sits on a light chip; one251+ drawn for the dark (white, from Schedules Direct) and the server's own252+ channels' sit on the guide itself. */246253 .g-ch .logo { width: 44px; height: 26px; border-radius: 2px; background: #e9e3d4 center/80% no-repeat; }247254 .g-ch .logo.own { background: center/contain no-repeat; }248255 .g-ch .num.long { font-size: 22px; }
M internal/guide/gracenote.go +6 -1
M internal/guide/gracenote_test.go +4 -0
M internal/lineup/tuner.go +4 -2
M internal/sd/sd_test.go +1 -1
M internal/sd/state.go +6 -3