mirror of
https://github.com/yattee/yattee.git
synced 2026-10-26 14:42:53 +00:00
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:
@@ -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]) {
|
||||
|
||||
@@ -77,9 +77,4 @@ actor GitHubAPI {
|
||||
throw APIError.decodingError(error)
|
||||
}
|
||||
}
|
||||
|
||||
/// Clears the cache.
|
||||
func clearCache() {
|
||||
contributorsCache = nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user