Remove dead code found by Periphery on all platforms

Delete declarations that Periphery reports unused on every platform that
compiles them (iOS, macOS, tvOS), including nine views used only by their
own previews. Platform-gated code still used on another platform, device-
only MPV render paths, migration models, CloudKit record names, App
Intents metadata and unused parameters are kept.
This commit is contained in:
Arkadiusz Fal
2026-10-08 23:57:56 +02:00
parent 45e19e6536
commit 4770bbe3b9
141 changed files with 14 additions and 4191 deletions

View File

@@ -8,25 +8,7 @@
import Foundation
/// Protocol defining the common content fetching interface.
protocol ContentServiceProtocol: Sendable {
func trending(for instance: Instance) async throws -> [Video]
func popular(for instance: Instance) async throws -> [Video]
func feed(for instance: Instance, credential: String) async throws -> [Video]
func subscriptions(for instance: Instance, credential: String) async throws -> [Channel]
func search(query: String, instance: Instance, page: Int, filters: SearchFilters) async throws -> SearchResult
func searchSuggestions(query: String, instance: Instance) async throws -> [String]
func video(id: String, instance: Instance) async throws -> Video
func channel(id: String, instance: Instance) async throws -> Channel
func channelVideos(id: String, instance: Instance, continuation: String?) async throws -> ChannelVideosPage
func channelPlaylists(id: String, instance: Instance, continuation: String?) async throws -> ChannelPlaylistsPage
func channelShorts(id: String, instance: Instance, continuation: String?) async throws -> ChannelVideosPage
func channelStreams(id: String, instance: Instance, continuation: String?) async throws -> ChannelVideosPage
func playlist(id: String, instance: Instance) async throws -> Playlist
func comments(videoID: String, instance: Instance, continuation: String?) async throws -> CommentsPage
func streams(videoID: String, instance: Instance) async throws -> [Stream]
func captions(videoID: String, instance: Instance) async throws -> [Caption]
func channelSearch(id: String, query: String, instance: Instance, page: Int) async throws -> ChannelSearchPage
}
protocol ContentServiceProtocol: Sendable {}
/// Unified content service that routes requests to the appropriate API based on instance type.
actor ContentService: ContentServiceProtocol {
@@ -55,17 +37,6 @@ actor ContentService: ContentServiceProtocol {
self.basicAuthCredentialsManager = basicAuthCredentialsManager
}
init(httpClientFactory: HTTPClientFactory, basicAuthCredentialsManager: BasicAuthCredentialsManager? = nil) {
self.httpClientFactory = httpClientFactory
// Create default client for instances that don't need insecure SSL
self.defaultHTTPClient = httpClientFactory.createClient(allowInvalidCertificates: false)
self.defaultInvidiousAPI = InvidiousAPI(httpClient: defaultHTTPClient)
self.defaultPipedAPI = PipedAPI(httpClient: defaultHTTPClient)
self.defaultPeerTubeAPI = PeerTubeAPI(httpClient: defaultHTTPClient)
self.defaultYatteeServerAPI = YatteeServerAPI(httpClient: defaultHTTPClient)
self.basicAuthCredentialsManager = basicAuthCredentialsManager
}
// MARK: - Routing
/// Builds a per-instance HTTPClient with the basic-auth `Authorization` header baked in,
@@ -256,10 +227,6 @@ actor ContentService: ContentServiceProtocol {
try await api(for: instance).comments(videoID: videoID, instance: instance, continuation: continuation)
}
func streams(videoID: String, instance: Instance) async throws -> [Stream] {
try await api(for: instance).streams(videoID: videoID, instance: instance)
}
func captions(videoID: String, instance: Instance) async throws -> [Caption] {
try await api(for: instance).captions(videoID: videoID, instance: instance)
}
@@ -590,17 +557,6 @@ actor ContentService: ContentServiceProtocol {
}
}
/// Fetches streams with proxy URLs for downloads (Yattee Server: hits /proxy/fast/
/// so the server caches the file on disk; other backends apply Invidious URL rewriting).
func proxyStreams(videoID: String, instance: Instance) async throws -> [Stream] {
if instance.type == .yatteeServer {
return try await yatteeServerAPI(for: instance)
.proxyStreams(videoID: videoID, instance: instance, mode: .download)
}
let fetchedStreams = try await streams(videoID: videoID, instance: instance)
return await InvidiousAPI.proxyStreamsIfNeeded(fetchedStreams, instance: instance)
}
/// Fetches video details + streams for downloads. For Yattee Server this routes
/// through `/proxy/fast/`, which caches the file on disk on the server.
func videoWithProxyStreamsAndCaptionsAndStoryboards(id: String, instance: Instance) async throws -> (video: Video, streams: [Stream], captions: [Caption], storyboards: [Storyboard]) {

View File

@@ -77,9 +77,4 @@ actor GitHubAPI {
throw APIError.decodingError(error)
}
}
/// Clears the cache.
func clearCache() {
contributorsCache = nil
}
}

View File

@@ -21,7 +21,6 @@ protocol InstanceAPI: Sendable {
func channelStreams(id: String, instance: Instance, continuation: String?) async throws -> ChannelVideosPage
func playlist(id: String, instance: Instance) async throws -> Playlist
func comments(videoID: String, instance: Instance, continuation: String?) async throws -> CommentsPage
func streams(videoID: String, instance: Instance) async throws -> [Stream]
func captions(videoID: String, instance: Instance) async throws -> [Caption]
func channelSearch(id: String, query: String, instance: Instance, page: Int) async throws -> ChannelSearchPage
}

View File

@@ -50,12 +50,9 @@ enum DetectionError: Error, Sendable {
/// Result of instance detection including type and authentication requirements.
struct InstanceDetectionResult: Sendable {
let type: InstanceType
/// Whether this instance requires authentication (Basic Auth for Yattee Server).
let requiresAuth: Bool
init(type: InstanceType, requiresAuth: Bool = false) {
self.type = type
self.requiresAuth = requiresAuth
}
}
@@ -67,27 +64,6 @@ actor InstanceDetector {
self.httpClient = httpClient
}
/// Detects the instance type for a given URL.
/// - Parameter url: The base URL of the instance.
/// - Returns: The detected instance type, or nil if detection failed.
func detect(url: URL) async -> InstanceType? {
let result = await detectWithAuth(url: url)
return result?.type
}
/// Detects the instance type and authentication requirements for a given URL.
/// - Parameter url: The base URL of the instance.
/// - Returns: The detection result including type and auth requirements, or nil if detection failed.
func detectWithAuth(url: URL) async -> InstanceDetectionResult? {
let result = await detectWithResult(url: url)
switch result {
case .success(let detectionResult):
return detectionResult
case .failure:
return nil
}
}
/// Detects the instance type with detailed error reporting.
/// - Parameters:
/// - url: The base URL of the instance.

View File

@@ -234,22 +234,11 @@ actor InvidiousAPI: InstanceAPI {
).toPlaylist(baseURL: instance.url)
}
/// Fetches a user's playlist using authenticated endpoint.
/// Required for private playlists (IVPL* IDs).
/// - Parameters:
/// - id: The playlist ID
/// - instance: The Invidious instance
/// - sid: The session ID from login
/// - Returns: The playlist with videos
func userPlaylist(id: String, instance: Instance, sid: String) async throws -> Playlist {
try await userPlaylistSnapshot(id: id, instance: instance, sid: sid).playlist
}
/// Fetches a user's playlist along with the per-entry identities needed to
/// mutate it.
///
/// Same request as ``userPlaylist(id:instance:sid:)`` — that one is a thin
/// wrapper over this — but it keeps the `index`/`indexId` tokens Invidious
/// Uses the authenticated endpoint (required for private IVPL* playlists)
/// and keeps the `index`/`indexId` tokens Invidious
/// hands out for every row instead of dropping them on conversion.
/// - Parameters:
/// - id: The playlist ID
@@ -455,14 +444,6 @@ actor InvidiousAPI: InstanceAPI {
return ChannelSearchPage(items: items, nextPage: hasResults ? page + 1 : nil)
}
/// Fetches video details, streams, and captions in a single API call.
/// This is more efficient than calling video(), streams(), and captions() separately
/// since they all fetch from the same endpoint.
func videoWithStreamsAndCaptions(id: String, instance: Instance) async throws -> (video: Video, streams: [Stream], captions: [Caption]) {
let result = try await videoWithStreamsAndCaptionsAndStoryboards(id: id, instance: instance)
return (video: result.video, streams: result.streams, captions: result.captions)
}
func videoWithStreamsAndCaptionsAndStoryboards(id: String, instance: Instance) async throws -> (video: Video, streams: [Stream], captions: [Caption], storyboards: [Storyboard]) {
let endpoint = GenericEndpoint.get("/api/v1/videos/\(id)")
let response: InvidiousVideoDetails = try await httpClient.fetch(endpoint, baseURL: instance.url)
@@ -1854,10 +1835,6 @@ private struct InvidiousChannel: Decodable, Sendable {
}
}
private struct InvidiousChannelVideos: Decodable, Sendable {
let videos: [InvidiousVideo]
}
private struct InvidiousChannelVideosWithContinuation: Decodable, Sendable {
let videos: [InvidiousVideo]
let continuation: String?

View File

@@ -385,21 +385,10 @@ actor PipedAPI: InstanceAPI {
return response.map { $0.toPlaylist() }
}
/// Fetches a user playlist with its videos.
/// - Parameters:
/// - id: The playlist ID (UUID)
/// - instance: The Piped instance
/// - authToken: The auth token from login
/// - Returns: Playlist with videos
func userPlaylist(id: String, instance: Instance, authToken: String) async throws -> Playlist {
try await userPlaylistSnapshot(id: id, instance: instance, authToken: authToken).playlist
}
/// Fetches a user playlist along with the per-entry identities needed to
/// mutate it.
///
/// Same request as ``userPlaylist(id:instance:authToken:)`` — that one is a
/// thin wrapper over this. Piped has no per-entry token, so entries are
/// Piped has no per-entry token, so entries are
/// addressed by their position in this fetch and are only valid until the
/// playlist next changes.
/// - Parameters:

View File

@@ -45,13 +45,6 @@ actor ProxyDetectionCache {
return entry.decision
}
/// Most-recently-seen CDN URL for this instance. Used by ``prewarm`` so we
/// don't have to wait for the current video's API response just to learn a
/// URL to probe.
func lastSampleURL(for instance: Instance) -> URL? {
entries[instance.id]?.sampleURL
}
/// Records a verdict (decision + the URL we probed against, kept as a
/// future probe sample). Refreshes the TTL.
func record(decision: Bool, sampleURL: URL?, for instance: Instance) {
@@ -115,12 +108,4 @@ actor ProxyDetectionCache {
inFlight[instance.id]?.cancel()
inFlight.removeValue(forKey: instance.id)
}
/// Drop all entries — e.g. after a network reachability change or when the
/// instances collection mutates broadly.
func invalidateAll() {
entries.removeAll()
for (_, task) in inFlight { task.cancel() }
inFlight.removeAll()
}
}

View File

@@ -206,12 +206,6 @@ actor YatteeServerAPI: InstanceAPI {
}
}
func streams(videoID: String, instance: Instance) async throws -> [Stream] {
let endpoint = GenericEndpoint.get("/api/v1/videos/\(videoID)")
let response: YatteeVideoDetails = try await httpClient.fetch(endpoint, baseURL: instance.url)
return response.toStreams()
}
func captions(videoID: String, instance: Instance) async throws -> [Caption] {
let endpoint = GenericEndpoint.get("/api/v1/videos/\(videoID)")
let response: YatteeVideoDetails = try await httpClient.fetch(endpoint, baseURL: instance.url)
@@ -237,12 +231,6 @@ actor YatteeServerAPI: InstanceAPI {
return ChannelSearchPage(items: items, nextPage: hasResults ? page + 1 : nil)
}
/// Fetches video details, streams, and captions in a single API call.
func videoWithStreamsAndCaptions(id: String, instance: Instance) async throws -> (video: Video, streams: [Stream], captions: [Caption]) {
let result = try await videoWithStreamsAndCaptionsAndStoryboards(id: id, instance: instance)
return (video: result.video, streams: result.streams, captions: result.captions)
}
func videoWithStreamsAndCaptionsAndStoryboards(id: String, instance: Instance) async throws -> (video: Video, streams: [Stream], captions: [Caption], storyboards: [Storyboard]) {
let endpoint = GenericEndpoint.get("/api/v1/videos/\(id)")
let response: YatteeVideoDetails = try await httpClient.fetch(endpoint, baseURL: instance.url)
@@ -268,16 +256,6 @@ actor YatteeServerAPI: InstanceAPI {
case download
}
/// Fetches streams with URLs that proxy through the Yattee Server.
func proxyStreams(videoID: String, instance: Instance, mode: ProxyMode) async throws -> [Stream] {
let endpoint = GenericEndpoint.get(
"/api/v1/videos/\(videoID)",
query: ["proxy": "true", "proxy_mode": mode.rawValue]
)
let response: YatteeVideoDetails = try await httpClient.fetch(endpoint, baseURL: instance.url)
return response.toStreams()
}
/// Fetches video details, proxy streams, captions, and storyboards in a single API call.
func videoWithProxyStreamsAndCaptionsAndStoryboards(id: String, instance: Instance, mode: ProxyMode) async throws -> (video: Video, streams: [Stream], captions: [Caption], storyboards: [Storyboard]) {
let endpoint = GenericEndpoint.get(
@@ -1324,10 +1302,6 @@ private struct YatteeChannel: Decodable, Sendable {
}
}
private struct YatteeChannelVideos: Decodable, Sendable {
let videos: [YatteeVideo]
}
private struct YatteeChannelSearchResponse: Decodable, Sendable {
let videos: [YatteeVideo]
}