feat: 4K downloads, watch progress, player controls, new icon

Window chrome: titleBarStyle Overlay (Transparent left the native bar in
place, white in dark mode, with a dead strip beneath it). The app now
paints that strip itself, so it matches the page background.

Player: prev/next through the feed, a full-screen button, a spinner
while a stream resolves, Open on YouTube on downloaded videos too, and
the description collapsed behind a disclosure.

Downloads default to Best, which reaches real 4K — above 1080p YouTube
serves VP9/AV1, verified to play natively in WKWebView here. Audio stays
pinned to AAC because Opus in MP4 would be silent. A Compatible setting
keeps the old 1080p H.264 behaviour. Files are now named
'<ISO date> - <title> [<id>].mp4'.

Watch progress is recorded and drawn under thumbnails like YouTube's,
and reopening a video resumes where it left off.

Tiles clamp every text line to a fixed height so they share a baseline,
and the search field no longer clips its placeholder.

Fixes a Picture-in-Picture leak: WebKit kept a detached video playing
after the player closed, so a second video could play over the first
with no way to stop it. Every exit path now tears the element down.
This commit is contained in:
vincent
2026-08-29 04:03:45 +02:00
parent d0bad64d7c
commit 5b09acd28d
69 changed files with 582 additions and 89 deletions
+52
View File
@@ -0,0 +1,52 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" width="1024" height="1024">
<title>FlightTube</title>
<defs>
<!-- Deep slate, matching the app's dark page background. -->
<linearGradient id="bg" x1="0" y1="0" x2="0.35" y2="1">
<stop offset="0" stop-color="#1e293b"/>
<stop offset="0.55" stop-color="#0f172b"/>
<stop offset="1" stop-color="#020618"/>
</linearGradient>
<!-- A single soft light source, upper left, so the mark has somewhere to sit. -->
<radialGradient id="glow" cx="0.26" cy="0.2" r="0.85">
<stop offset="0" stop-color="#38bdf8" stop-opacity="0.30"/>
<stop offset="0.55" stop-color="#38bdf8" stop-opacity="0.06"/>
<stop offset="1" stop-color="#38bdf8" stop-opacity="0"/>
</radialGradient>
<!-- The lit face: white falling to the accent, following the same light. -->
<linearGradient id="face" x1="0.15" y1="0" x2="0.9" y2="1">
<stop offset="0" stop-color="#ffffff"/>
<stop offset="1" stop-color="#e0f2fe"/>
</linearGradient>
<!-- The folded-under face, in the accent so the plane reads as one object. -->
<linearGradient id="fold" x1="0.2" y1="0" x2="0.85" y2="1">
<stop offset="0" stop-color="#38bdf8"/>
<stop offset="1" stop-color="#0284c7"/>
</linearGradient>
<filter id="lift" x="-25%" y="-25%" width="150%" height="150%">
<feDropShadow dx="0" dy="18" stdDeviation="26" flood-color="#020618" flood-opacity="0.45"/>
</filter>
</defs>
<!-- macOS-style rounded square; the platform does not mask for us. -->
<rect width="1024" height="1024" rx="228" ry="228" fill="url(#bg)"/>
<rect width="1024" height="1024" rx="228" ry="228" fill="url(#glow)"/>
<!--
One paper plane, two faces. The upper face is a clean right-pointing
triangle, so the same silhouette reads as a play button — the app is
"watch your subscriptions on a flight" in a single shape.
-->
<g filter="url(#lift)">
<path d="M 832 206 L 192 486 L 446 566 Z" fill="url(#face)"/>
<path d="M 832 206 L 446 566 L 556 828 Z" fill="url(#fold)"/>
</g>
<!-- Hairline inner edge, the same trick the UI uses: a border, not a shadow. -->
<rect x="6" y="6" width="1012" height="1012" rx="222" ry="222"
fill="none" stroke="#ffffff" stroke-opacity="0.07" stroke-width="12"/>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB