Files
yattee/Shared/Settings/InstanceSettings.swift
Arkadiusz Fal b0dfd2f9d2 Add experimental setting to hide videos without duration in Invidious
This adds a new instance setting for Invidious that filters out videos
without duration information from feeds, popular, trending, search results,
and channel pages. This can be used to hide YouTube Shorts.

The setting is labeled as "Experimental: Hide videos without duration" and
includes an explanation that it can be used to hide shorts.

Key changes:
- Added hideVideosWithoutDuration property to Instance model
- Updated InstancesBridge to serialize/deserialize the new setting
- Added UI toggle in InstanceSettings with explanatory footer text
- Implemented filtering in InvidiousAPI for:
  * Popular videos
  * Trending videos
  * Search results
  * Subscription feed
  * Channel content
- Videos accessed directly by URL are not filtered
2025-11-22 19:42:18 +01:00

139 lines
5.2 KiB
Swift

import SwiftUI
struct InstanceSettings: View {
let instance: Instance
@State private var accountsChanged = false
@State private var presentingAccountForm = false
@State private var frontendURL = ""
@State private var proxiesVideos = false
@State private var invidiousCompanion = false
@State private var hideVideosWithoutDuration = false
var body: some View {
List {
Section(header: Text("Accounts".localized())) {
if instance.app.supportsAccounts {
ForEach(InstancesModel.shared.accounts(instance.id), id: \.self) { account in
#if os(tvOS)
Button(account.description) {}
.contextMenu {
Button("Remove") { removeAccount(account) }
Button("Cancel", role: .cancel) {}
}
#else
ZStack {
NavigationLink(destination: EmptyView()) {
EmptyView()
}
.disabled(true)
.hidden()
HStack {
Text(account.description)
Spacer()
}
.contextMenu {
Button {
removeAccount(account)
} label: {
Label("Remove", systemImage: "trash")
}
}
}
#endif
}
.redrawOn(change: accountsChanged)
Button {
presentingAccountForm = true
} label: {
Label("Add Account...", systemImage: "plus")
}
.sheet(isPresented: $presentingAccountForm, onDismiss: { accountsChanged.toggle() }) {
AccountForm(instance: instance)
}
#if !os(tvOS)
.listStyle(.insetGrouped)
#endif
} else {
Text("Accounts are not supported for the application of this instance")
.foregroundColor(.secondary)
}
}
if instance.app.hasFrontendURL {
Section(header: Text("Frontend URL".localized())) {
TextField(
"Frontend URL",
text: $frontendURL
)
.onAppear {
frontendURL = instance.frontendURL ?? ""
}
.onChange(of: frontendURL) { newValue in
InstancesModel.shared.setFrontendURL(instance, newValue)
}
.labelsHidden()
.autocapitalization(.none)
.keyboardType(.URL)
}
}
if instance.app.allowsDisablingVidoesProxying {
proxiesVideosToggle
.onAppear {
proxiesVideos = instance.proxiesVideos
}
.onChange(of: proxiesVideos) { newValue in
InstancesModel.shared.setProxiesVideos(instance, newValue)
}
}
if instance.app == .invidious {
invidiousCompanionToggle
.onAppear {
invidiousCompanion = instance.invidiousCompanion
}
.onChange(of: invidiousCompanion) { newValue in
InstancesModel.shared.setInvidiousCompanion(instance, newValue)
}
Section(footer: Text("This can be used to hide shorts".localized())) {
hideVideosWithoutDurationToggle
.onAppear {
hideVideosWithoutDuration = instance.hideVideosWithoutDuration
}
.onChange(of: hideVideosWithoutDuration) { newValue in
InstancesModel.shared.setHideVideosWithoutDuration(instance, newValue)
}
}
}
}
#if os(tvOS)
.frame(maxWidth: 1000)
#elseif os(iOS)
.listStyle(.insetGrouped)
#endif
.navigationTitle(instance.description)
}
private var proxiesVideosToggle: some View {
Toggle("Proxy videos", isOn: $proxiesVideos)
}
private var invidiousCompanionToggle: some View {
Toggle("Invidious companion", isOn: $invidiousCompanion)
}
private var hideVideosWithoutDurationToggle: some View {
Toggle("Experimental: Hide videos without duration", isOn: $hideVideosWithoutDuration)
}
private func removeAccount(_ account: Account) {
AccountsModel.remove(account)
accountsChanged.toggle()
}
}