Lets the Apple TV switch its HDMI output to match the playing video's
frame rate and dynamic range via AVDisplayManager.preferredDisplayCriteria,
driven from MPV's container-fps and video-params/gamma. Two opt-in toggles
(default off) live under Playback → Display on tvOS; both are no-ops on
other platforms. Anchor an AVKit class symbol so the linker keeps AVKit
linked — Swift only autolinks AVFoundation here, and without AVKit the
UIWindow.avDisplayManager category isn't loaded at runtime.
Lets the auto stream selector pick formats whose codec isn't hardware
decoded on the current device. Defaults off; when on, 4K VP9/AV1 can be
auto-selected on Apple TV models without those decoders. Software-decoded
streams also move into the Recommended section so the selection stays
visible without enabling advanced stream details.
Pointing AddRemoteServer at a Piped Vue SPA (e.g. the frontend host
rather than the API host) used to fail with a generic
"could not detect instance type" — every JSON probe got the same
index.html back. On the failure path, fetch `/` once more and look
for `<title>Piped</title>`; if matched, return a new
`pipedFrontendDetected` error that tells the user to enter the
Piped API URL instead.
Piped's session token reuses the Authorization header, so a fronting basic
auth proxy can't coexist with logged-in Piped use — the two would clobber
each other's credentials on every authenticated request.
Add a supportsHTTPBasicAuthProxy capability on Instance/InstanceType (false
for Piped, true for everything else) and route it through:
- AddRemoteServerView refuses Piped if detection only succeeded behind basic
auth, surfacing a localized "not supported" error instead of a silently
broken instance, and hides the optional credentials section for Piped.
- EditSourceView hides the basic auth fields for Piped instances and clears
any legacy stored credentials on save, in case a Piped source was added
with credentials before this change.
Also swap the icon to puzzlepiece.extension, which better conveys that
this section houses third-party service hookups (SponsorBlock, Return
YouTube Dislike, DeArrow, short-link resolution) rather than being
YouTube-specific.
Hide the Resolve Short Links toggle on tvOS — there's no way to tap
inline description links or reach a system browser there — and tighten
the openInSystemBrowser platform guards so the iOS-only UIApplication
path isn't compiled on tvOS.
Tapping bit.ly/tinyurl/t.co/etc. in a description or comment previously
opened Safari even when the destination was a playable YouTube URL.
Added an opt-in "Resolve Short Links" toggle under YouTube Enhancements
(off by default) that follows the redirect on tap: if the target is a
YouTube/PeerTube/direct-media URL, open it in-app; otherwise prompt the
user before falling back to yt-dlp extraction or the browser.
Also added a confirmation dialog for non-shortener links that only
matched the loose .externalVideo yt-dlp fallback, so arbitrary web
pages in descriptions no longer silently kick off extraction.
Prompts live on NavigationCoordinator and are dual-hosted by YatteeApp
and ExpandedPlayerSheet so they remain visible whether or not the
expanded player is covering the main view.
New Release-DeveloperID configuration gates Sparkle behind a SPARKLE
compile flag so the App Store Release build stays Sparkle-free. Adds
SPUStandardUpdaterController wrapper, Check for Updates menu command,
Advanced Settings section with beta channel toggle, and a Ruby script
plus GitHub Actions job that signs each release and publishes the
appcast to gh-pages for consumption by Sparkle and Homebrew cask.
Add shared SettingsFormContainer/SettingsFormSection helpers that mirror
the Sources screen styling (uppercase subheadline headers, divider-
bracketed cards, ScrollView + LazyVStack) on macOS while keeping the
standard Form/Section layout on iOS and tvOS.
Convert PlaybackSettingsView and SubtitlesSettingsView to the new
helpers, wrap the macOS Settings detail pane in a NavigationStack so
NavigationLink pushes (Subtitles Appearance) render in the detail
column, fold the macOS-only Player Mode + Auto-resize player controls
into the Behavior section, and drop the unused queue footer.
Adds a Show Sidebar toggle (iPad regular and macOS) that controls
channels sidebar visibility. When the sidebar is shown, the channel
strip picker is disabled and the redundant channel header link above
the feed is hidden. Layout picker now uses inline menu style for
consistency with other options.
Render a focusable empty state on tvOS Home when no sections have content,
with an "Open Sources" button that switches the sidebar selection. Without
a focusable view the tvOS focus engine had no target, leaving the sidebar
unreachable after the initial iCloud alert was dismissed.
Also wire the selectedSidebarItem onChange handler into the tvOS TabView,
which was missing and prevented programmatic sidebar selection.
When enabled, the Siri remote Menu button stops playback and clears the
queue instead of only collapsing the player, and the explicit top-bar
close (X) button is hidden.
Exposes ContinueWatchingView as an opt-in compact tab bar item,
hidden by default. Uses a short "Continue" label since the full
"Continue Watching" string does not fit as a tab bar title.
- Move Close to a top-right circular icon; bottom row reorganizes into
left (Settings/Info/Comments), center transport (Previous/PlayPause/Next),
and right (Queue) clusters with equal side frames so transport stays
geometrically centered.
- Introduce a circular icon-only `TVTransportButtonStyle` (primary variant
for Play/Pause) mirroring the new Close button look.
- Always render Previous/Next so Play/Pause position is fixed; dim and
disable when unavailable.
- Share `isTransportDisabled` on `PlayerState` and reuse it on iOS and
tvOS; apply it (plus symbol replace transition) to the tvOS Play/Pause
button.
Delete the multi-page onboarding sheet. On first launch the app now
silently imports any v1 instances from UserDefaults (splitting embedded
basic-auth credentials out of the URL and into the Keychain) and then,
if the device is signed in to iCloud, shows a single alert offering to
enable sync. Accepting shows a blocking progress overlay until the
initial upload completes.
Surfaces Continue Watching, Recent Feed, and Recent Bookmarks in the
Apple TV Home top shelf when Yattee is focused. Tapping a tile opens
the video via the existing yattee://video/{id} deep link.
- New YatteeTopShelf app extension target (tvOS only). LD_ENTRY_POINT is
overridden to _NSExtensionMain; the tv-app-extension product type
defaults to _TVExtensionMain which is for the pre-tvOS-13 legacy API
and crashes modern TVTopShelfContentProvider subclasses at launch.
- Main app writes per-section JSON snapshots (capped at 10 items each)
to a shared App Group UserDefaults suite after bookmark, watch-history,
and feed-cache changes, plus an initial write on launch.
- Enabled-sections list is mirrored to the same App Group so the
extension can respect the user's selection without touching SwiftData.
- Settings → Top Shelf (tvOS only) lets the user toggle sections.
- Deep link playback shows a loading toast while video details are
fetched, and an error toast if no source is configured.
Surface the existing in-channel search feature on tvOS as a final tab
after Playlists. Selecting it reveals a search field and results area
below the tab row, reusing the same API and result views as iOS/macOS.
Introduces a "Display sections as" picker in Home settings with List and
Grid modes. Grid renders each section as a horizontal shelf of video
cards, defaulting to Grid on tvOS and List on iOS/macOS. Per-platform
defaults are preserved via a platform-specific settings key.
On tvOS the shelf is a focus section so swiping up/down between rows of
different lengths works without getting stuck at the end of a row.
After disabling home shortcuts on tvOS, Open URL and Remote Control had
no entry point. Add them as configurable sidebar main items. Remote
Control defaults to visible on tvOS; Open URL defaults to hidden on all
platforms.
Close button is now the rightmost action (after Queue), matching the
user-requested layout. A Previous button sits before Next and appears
whenever a queue is present, disabled until history accumulates.
Replace the tvOS bottom action bar with Settings / Info / Comments /
Next / Close. Settings reuses QualitySelectorView (video, audio,
subtitles, speed); Comments opens TVDetailsPanel directly on the
comments tab; Close stops playback and dismisses.
Debug button is hidden by default and can be re-enabled via a new
tvOS-only Advanced Settings > Developer toggle.
Present the settings sheet as a fullScreenCover with a centered
material card, fix the "Normal" hyphenation, and restyle row selection
throughout the quality selector on tvOS: per-row rounded backgrounds
with focus tint + stroke, vertical spacing instead of dividers, and a
focusable speed-rate menu.
EditSourceView now exposes the basic-auth username/password fields for every
instance type (Invidious, Piped, PeerTube, Yattee Server), keeping the
existing required-credentials UI for Yattee Server and adding an optional
section for the others. Credentials are loaded and persisted via
BasicAuthCredentialsManager regardless of type, and clearing both fields
deletes stored credentials for non-Yattee types.
AddRemoteServerView gains a new basicAuthRequired UI state: when instance
detection hits a 401 (the entire instance is behind a reverse proxy), the
view reveals username/password fields and a Retry Detection button. The
retry calls the detector with the credentials injected as an Authorization
header; on success the form transitions into the normal detected state with
the credentials pre-populated. A repeat 401 shows an inline "invalid
credentials" message instead of restarting the flow. For non-Yattee types,
any credentials entered during the flow are persisted alongside the new
instance.
When an instance sits behind a reverse proxy that requires HTTP Basic Auth,
every detection probe (/info, /api/v1/config, /api/v1/stats, /healthcheck,
/config) returns 401 before reaching the real backend, so the type cannot be
identified. Re-throw APIError.unauthorized from each probe instead of
swallowing it, and have detectWithResult convert the first 401 it sees into
DetectionError.basicAuthRequired. Add a basicAuthHeader parameter so the
caller can retry detection after the user provides credentials; if a retry
also returns 401, surface basicAuthInvalid instead.
Remove 32 non-dotted keys (16 unused format specifiers, 16 word keys)
and replace with properly namespaced dotted keys following the existing
convention (common.*, player.*, search.*).
Display the view options button, channel menu, and content type tabs
immediately when the cached header is shown, instead of waiting for
the full channel data to load. The spinner now appears only in the
content area below the tabs.
Adds a "Proxy videos" toggle in instance settings that routes video
streams through the instance instead of connecting directly to YouTube
CDN. Includes auto-detection of 403 blocks and live re-application of
proxy settings without requiring app restart or video reload.
Shows an orange "DEV" capsule next to the iCloud row in Settings and a
development environment notice at the top of iCloud settings, helping
distinguish CloudKit dev environment from production during development.