diff --git a/export.php b/export.php index 6f3a54c..e86618c 100644 --- a/export.php +++ b/export.php @@ -119,6 +119,47 @@ function export_hour_slots(DateTimeImmutable $start, DateTimeImmutable $end): ar return $slots; } +function export_programme_weight(array $programme): int { + $duration = max(1, (int) round(($programme['stop']->getTimestamp() - $programme['start']->getTimestamp()) / 60)); + $weight = min($duration, 240); + if (!empty($programme['subtitle'])) $weight += 10; + if (!empty($programme['categories'])) $weight += 8; + if (!empty($programme['desc'])) $weight += min(40, (int) floor(strlen($programme['desc']) / 20)); + return $weight; +} + +function export_build_magazine(array $channels): array { + $all = []; + foreach ($channels as $channel) { + foreach ($channel['programmes'] as $programme) { + $all[] = [ + 'channel_name' => $channel['name'], + 'channel_icon' => $channel['icon'], + 'programme' => $programme, + 'weight' => export_programme_weight($programme), + ]; + } + } + + usort($all, static function ($a, $b) { + return $b['weight'] <=> $a['weight'] + ?: $a['programme']['start'] <=> $b['programme']['start'] + ?: strcmp($a['channel_name'], $b['channel_name']); + }); + + $highlights = array_slice($all, 0, 5); + $by_channel = []; + foreach ($channels as $channel) { + $by_channel[] = [ + 'name' => $channel['name'], + 'icon' => $channel['icon'], + 'programmes' => array_slice($channel['programmes'], 0, 6), + ]; + } + + return ['highlights' => $highlights, 'channels' => $by_channel]; +} + $sources = array_values($config['epg_sources'] ?? []); $source_index = max(0, min((int) ($_GET['source'] ?? 0), max(count($sources) - 1, 0))); $source = $sources[$source_index] ?? null; @@ -126,7 +167,7 @@ $target_day = preg_match('/^\d{4}-\d{2}-\d{2}$/', (string) ($_GET['day'] ?? '')) $layout_input = isset($_GET['layout']) ? (string) $_GET['layout'] : 'cards'; $limit_input = isset($_GET['limit']) ? (string) $_GET['limit'] : '8'; $window_input = isset($_GET['window']) ? (string) $_GET['window'] : 'full'; -$layout = in_array($layout_input, ['cards', 'timeline'], true) ? $layout_input : 'cards'; +$layout = in_array($layout_input, ['cards', 'timeline', 'magazine'], true) ? $layout_input : 'cards'; $limit = in_array($limit_input, ['4', '8', 'all'], true) ? $limit_input : '8'; $windows = export_window_definitions($target_day); $window_key = array_key_exists($window_input, $windows) ? $window_input : 'full'; @@ -148,7 +189,8 @@ if ($limit !== 'all') { } $day_label = (new DateTimeImmutable($target_day))->format('l d F Y'); -$layout_label = $layout === 'cards' ? 'Readable cards' : 'Dense timeline'; +$layout_label = $layout === 'cards' ? 'Readable cards' : ($layout === 'timeline' ? 'Dense timeline' : 'TV magazine'); +$magazine = export_build_magazine($visible_channels); ?> @@ -192,6 +234,26 @@ $layout_label = $layout === 'cards' ? 'Readable cards' : 'Dense timeline'; .prog-title{font-size:16px;font-weight:700;line-height:1.08} .prog-sub,.prog-cats,.prog-desc{font-size:12px;color:var(--ink-soft);line-height:1.3;margin-top:2px} .prog-desc{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden} +.magazine{display:grid;gap:18px} +.mag-hero{display:grid;grid-template-columns:1.3fr .9fr;gap:18px} +.mag-lead,.mag-side,.mag-channel{background:rgba(255,255,255,.35);border:1px solid var(--line);padding:16px} +.mag-kicker{font-family:'Share Tech Mono',monospace;font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--accent-2);margin-bottom:8px} +.mag-title{font-family:'IM Fell English',serif;font-size:34px;line-height:1.02;margin-bottom:10px} +.mag-meta{font-family:'Share Tech Mono',monospace;font-size:11px;color:var(--ink-soft);letter-spacing:.04em;margin-bottom:10px} +.mag-desc{font-size:14px;line-height:1.45;color:var(--ink-soft)} +.mag-side-list,.mag-channels{display:grid;gap:14px} +.mag-mini-title{font-size:18px;font-weight:700;line-height:1.08} +.mag-mini{padding-top:12px;border-top:1px dashed var(--line)} +.mag-mini:first-child{padding-top:0;border-top:none} +.mag-channels{grid-template-columns:repeat(2,minmax(0,1fr))} +.mag-channel-head{display:flex;gap:10px;align-items:center;border-bottom:2px solid var(--accent-2);padding-bottom:8px;margin-bottom:10px} +.mag-channel-head img{width:38px;height:38px;object-fit:contain;background:#fff;border:1px solid var(--line);padding:4px} +.mag-channel-name{font-size:20px;font-weight:700;line-height:1.05} +.mag-list{display:grid;gap:8px} +.mag-item{display:grid;grid-template-columns:74px 1fr;gap:10px;padding-top:8px;border-top:1px dashed var(--line)} +.mag-item:first-child{padding-top:0;border-top:none} +.mag-time{font-family:'Share Tech Mono',monospace;font-size:11px;color:var(--accent-2)} +.mag-item-title{font-size:15px;font-weight:700;line-height:1.08} .timeline-wrap{display:grid;gap:14px} .timeline-row{display:grid;grid-template-columns:180px 1fr;gap:14px;align-items:stretch} .timeline-channel{border-top:2px solid var(--accent-2);padding-top:8px} @@ -203,7 +265,7 @@ $layout_label = $layout === 'cards' ? 'Readable cards' : 'Dense timeline'; .mini-title{font-size:13px;font-weight:700;line-height:1.05} .mini-meta{font-family:'Share Tech Mono',monospace;font-size:10px;color:var(--ink-soft);margin-top:3px} @media print{body{background:#fff}.page{padding:0}.toolbar{display:none}.sheet{box-shadow:none;border:none;width:auto;margin:0}.sheet-wrap{overflow:visible}.cards-grid{grid-template-columns:1fr 1fr}} -@media (max-width:1200px){.sheet{width:100%}.cards-grid{grid-template-columns:1fr}.timeline-row{grid-template-columns:1fr}.timeline-grid{overflow:auto}} +@media (max-width:1200px){.sheet{width:100%}.cards-grid,.mag-channels,.mag-hero{grid-template-columns:1fr}.timeline-row{grid-template-columns:1fr}.timeline-grid{overflow:auto}} @@ -233,6 +295,7 @@ $layout_label = $layout === 'cards' ? 'Readable cards' : 'Dense timeline'; @@ -300,7 +363,7 @@ $cats = $programme['categories'] ? implode(' · ', $programme['categories']) : ' - +
@@ -336,9 +399,61 @@ $items = array_values(array_filter($channel['programmes'], static fn($p) => $p['
+ +
+
+
+
Cover story
+ +
+
· format('H:i') . ' - ' . $p['stop']->format('H:i')) ?>
+
+
+ +
No highlight available for this selection.
+ +
+ +
+ +
Channel picks
+
+ +
+
+ +
+
+
+ +
+
format('H:i')) ?>
format('H:i')) ?>
+
+
+
+
+
+
+ +
+
+ +
+
-
Astuce: pour un rendu vraiment propre, choisis “Readable cards” avec 4 ou 8 chaînes, puis exporte en PDF.
+
Astuce: “TV magazine” est parfait pour une belle feuille éditoriale. “Readable cards” reste le plus propre pour une impression exhaustive.