The Yattee2.icon/ Icon Composer file is the correct source for app
icons. The previous change to AppIcon was incorrect — AppIcon.appiconset
is an empty legacy placeholder with no actual PNGs.
Without explicit identity, xcodebuild defaults to "iOS Development"
which doesn't exist on CI. Set "Apple Distribution" for App Store
builds and "Developer ID Application" for notarized builds.
Replaced sed-based CODE_SIGN_STYLE override with fastlane's
update_code_signing_settings which also sets PROVISIONING_PROFILE_SPECIFIER.
This fixes the YatteeShareExtension build failure where it couldn't
find a provisioning profile under manual signing.
- Write latest_build_number.txt to repo root using explicit path
(fastlane runs from fastlane/ subdir, so relative path was wrong)
- Remove update_fastlane from before_all to avoid CI instability
Query App Store Connect for the latest TestFlight build number across
all platforms (iOS, tvOS, macOS) and auto-increment it, eliminating
the need for the separate bump-build workflow.
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.
Pending deletes were lost across app restarts because
recoverPersistedPendingChanges() never reconstructed CKRecord.ID
objects from persisted record names. Additionally, incoming iCloud
records for deleted playlists were blindly applied, and orphaned
playlist items in CloudKit would recreate placeholder playlists.
- Rebuild pendingDeletes array from UserDefaults on recovery
- Guard applyRemoteRecord against records pending local deletion
- Skip deferred items whose parent playlist is pending deletion
- Queue all playlist item deletions when deleting a playlist
- Clean up placeholder playlists for pending-delete playlists
The filter strip was passing the Invidious instance URL as serverURL to
AvatarURLBuilder, which built a Yattee Server-style /avatar/ path that
doesn't exist on Invidious. Now passes the actual Yattee Server URL
(matching SubscriptionsView pattern) and enriches channels from
CachedChannelData as a fallback when the API doesn't return thumbnails.
Single unified "Yattee" scheme replaces per-platform schemes.
Release workflow now has toggleable platform inputs instead of
matrix strategy. Standalone mac notarized workflow removed in
favor of the build_mac_notarized toggle. Share extension bundle
ID updated from Open-in-Yattee to ShareExtension.
When PiP is active, the MPV render view shows a black frame since
rendering goes to the PiP sample buffer layer. Overlay the video
thumbnail (preferring DeArrow) on top to cover the black area,
fading it in/out smoothly when PiP starts/stops.
Use URLComponents/URLQueryItem for standard form-URL encoding instead
of manual percent-encoding with CharacterSet.alphanumerics, which
included non-ASCII Unicode letters and had an unsafe raw-value fallback.
Back the in-memory authorCache with a JSON file in ~/Library/Caches/AuthorCache/.
Disk is lazy-loaded on first lookup and saved asynchronously on each cache update.
Capped at 500 entries to prevent unbounded growth.
- Cache author data from video detail API responses (PlayerService, VideoInfoView)
- Replace ChannelView's private CachedChannelHeader with shared CachedChannelData
- Enrich author with cached avatar/subscriber count in VideoChannelRow, TVDetailsPanel, VideoInfoView
When a cancelled load task fell through to `isLoading = false`, it
created a 1-frame gap where the empty view rendered before the
replacement task set `isLoading` back to `true`. Return early on
cancellation so the surviving task controls loading state.
Reset isCommentsExpanded and commentsFrame on the NavigationCoordinator
directly when the portrait panel is dismissed, since PortraitDetailsPanel
owns its own @State that doesn't sync back through .onChange during dismiss.
Also track comments overlay frame via GeometryReader so the dismiss gesture
can allow swipes outside the comments area instead of blanket-blocking.
Playlists only loaded the first page of videos. Add full pagination for
both Invidious and Piped playlist endpoints (public and authenticated).
Deduplicate Invidious results by playlist index to handle its overlapping
page windows. Also fix URL encoding in Invidious login to use strict
form-encoding charset.
Move .refreshable from the outer GeometryReader onto the ScrollView
itself so SwiftUI can properly coordinate the scroll offset bounce-back.
The ScrollView was inside an .overlay() which doesn't participate in
the parent's layout system, breaking the offset reset.
Closes#917
Route HTTPS YouTube URLs through yattee://open?url= scheme since simctl
can't trigger Universal Links. Improve wait strategies: use player
expansion check for video tests, tree length threshold for channel/
playlist content loading. Add retry logic to cleanup_after_video.
Test yattee:// custom scheme URLs navigate to correct screens:
playlists, bookmarks, history, downloads, channels, subscriptions,
continue-watching, and search. Handles iOS system confirmation dialog
via coordinate taps since it's invisible to AXe. Settings deep link
is excluded (known app bug - doesn't render when pushed to nav stack).
- Skip onboarding in tests by setting UserDefaults before launch
- Update all addSource.* identifiers to addRemoteServer.* for new flow
- Switch from identifier-based to text-based element lookups (iOS 26 AXe limitation)
- Add Yattee Server credential support in instance setup
- Update baseline screenshots for Home tab and settings
- Create standalone update-altstore.yml workflow (workflow_dispatch + workflow_call)
that gets version from latest GitHub release tag instead of project.pbxproj
- Replace inline update_altstore job in release.yml with workflow_call reference
- Add altstore-source.json with app metadata and initial version entry
- Update README with revised features, TestFlight install link, and new logo assets
For context, Invidious performs a type check of its configuration during
bootup, and allows the "domain" to be unspecified, in which case the API
and HTML it generates includes path-only URLs. This is valid: in these
cases we should assume that the Host for those URLs is the same as
the Host we used to access the endpoint called.
This commit adds support for servers configured in such a way, by
defaulting the host of thumbnail URLs, to that used for authentication.