diff --git a/Shared/Generated/Images+Generated.swift b/Shared/Generated/Images+Generated.swift
new file mode 100644
index 00000000..646209d2
--- /dev/null
+++ b/Shared/Generated/Images+Generated.swift
@@ -0,0 +1,217 @@
+//
+// Swiftfin is subject to the terms of the Mozilla Public
+// License, v2.0. If a copy of the MPL was not distributed with this
+// file, you can obtain one at https://mozilla.org/MPL/2.0/.
+//
+// Copyright (c) 2025 Jellyfin & Jellyfin Contributors
+//
+
+// swiftlint:disable all
+// Generated using SwiftGen — https://github.com/SwiftGen/SwiftGen
+
+#if os(macOS)
+import AppKit
+#elseif os(iOS)
+import UIKit
+#elseif os(tvOS) || os(watchOS)
+import UIKit
+#endif
+#if canImport(SwiftUI)
+import SwiftUI
+#endif
+
+// Deprecated typealiases
+@available(*, deprecated, renamed: "ImageAsset.Image", message: "This typealias will be removed in SwiftGen 7.0")
+typealias AssetImageTypeAlias = ImageAsset.Image
+
+// swiftlint:disable superfluous_disable_command file_length implicit_return
+
+// MARK: - Asset Catalogs
+
+// swiftlint:disable identifier_name line_length nesting type_body_length type_name
+enum Asset {
+ static let deviceBrowserChrome = ImageAsset(name: "Device-browser-chrome")
+ static let deviceBrowserEdge = ImageAsset(name: "Device-browser-edge")
+ static let deviceBrowserEdgechromium = ImageAsset(name: "Device-browser-edgechromium")
+ static let deviceBrowserFirefox = ImageAsset(name: "Device-browser-firefox")
+ static let deviceBrowserHtml5 = ImageAsset(name: "Device-browser-html5")
+ static let deviceBrowserMsie = ImageAsset(name: "Device-browser-msie")
+ static let deviceBrowserOpera = ImageAsset(name: "Device-browser-opera")
+ static let deviceBrowserSafari = ImageAsset(name: "Device-browser-safari")
+ static let deviceClientAndroid = ImageAsset(name: "Device-client-android")
+ static let deviceClientApple = ImageAsset(name: "Device-client-apple")
+ static let deviceClientFinamp = ImageAsset(name: "Device-client-finamp")
+ static let deviceClientKodi = ImageAsset(name: "Device-client-kodi")
+ static let deviceClientPlaystation = ImageAsset(name: "Device-client-playstation")
+ static let deviceClientRoku = ImageAsset(name: "Device-client-roku")
+ static let deviceClientSamsungtv = ImageAsset(name: "Device-client-samsungtv")
+ static let deviceClientWebos = ImageAsset(name: "Device-client-webos")
+ static let deviceClientWindows = ImageAsset(name: "Device-client-windows")
+ static let deviceClientXbox = ImageAsset(name: "Device-client-xbox")
+ static let deviceOtherHomeassistant = ImageAsset(name: "Device-other-homeassistant")
+ static let deviceOtherOther = ImageAsset(name: "Device-other-other")
+ static let jellyfinBlobBlue = ImageAsset(name: "jellyfin-blob-blue")
+ static let tomatoFresh = SymbolAsset(name: "tomato.fresh")
+ static let tomatoRotten = SymbolAsset(name: "tomato.rotten")
+}
+
+// swiftlint:enable identifier_name line_length nesting type_body_length type_name
+
+// MARK: - Implementation Details
+
+struct ImageAsset {
+ fileprivate(set) var name: String
+
+ #if os(macOS)
+ typealias Image = NSImage
+ #elseif os(iOS) || os(tvOS) || os(watchOS)
+ typealias Image = UIImage
+ #endif
+
+ @available(iOS 8.0, tvOS 9.0, watchOS 2.0, macOS 10.7, *)
+ var image: Image {
+ let bundle = BundleToken.bundle
+ #if os(iOS) || os(tvOS)
+ let image = Image(named: name, in: bundle, compatibleWith: nil)
+ #elseif os(macOS)
+ let name = NSImage.Name(self.name)
+ let image = (bundle == .main) ? NSImage(named: name) : bundle.image(forResource: name)
+ #elseif os(watchOS)
+ let image = Image(named: name)
+ #endif
+ guard let result = image else {
+ fatalError("Unable to load image asset named \(name).")
+ }
+ return result
+ }
+
+ #if os(iOS) || os(tvOS)
+ @available(iOS 8.0, tvOS 9.0, *)
+ func image(compatibleWith traitCollection: UITraitCollection) -> Image {
+ let bundle = BundleToken.bundle
+ guard let result = Image(named: name, in: bundle, compatibleWith: traitCollection) else {
+ fatalError("Unable to load image asset named \(name).")
+ }
+ return result
+ }
+ #endif
+
+ #if canImport(SwiftUI)
+ @available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
+ var swiftUIImage: SwiftUI.Image {
+ SwiftUI.Image(asset: self)
+ }
+ #endif
+}
+
+extension ImageAsset.Image {
+ @available(iOS 8.0, tvOS 9.0, watchOS 2.0, *)
+ @available(
+ macOS,
+ deprecated,
+ message: "This initializer is unsafe on macOS, please use the ImageAsset.image property"
+ )
+ convenience init?(asset: ImageAsset) {
+ #if os(iOS) || os(tvOS)
+ let bundle = BundleToken.bundle
+ self.init(named: asset.name, in: bundle, compatibleWith: nil)
+ #elseif os(macOS)
+ self.init(named: NSImage.Name(asset.name))
+ #elseif os(watchOS)
+ self.init(named: asset.name)
+ #endif
+ }
+}
+
+#if canImport(SwiftUI)
+@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
+extension SwiftUI.Image {
+ init(asset: ImageAsset) {
+ let bundle = BundleToken.bundle
+ self.init(asset.name, bundle: bundle)
+ }
+
+ init(asset: ImageAsset, label: Text) {
+ let bundle = BundleToken.bundle
+ self.init(asset.name, bundle: bundle, label: label)
+ }
+
+ init(decorative asset: ImageAsset) {
+ let bundle = BundleToken.bundle
+ self.init(decorative: asset.name, bundle: bundle)
+ }
+}
+#endif
+
+struct SymbolAsset {
+ fileprivate(set) var name: String
+
+ #if os(iOS) || os(tvOS) || os(watchOS)
+ @available(iOS 13.0, tvOS 13.0, watchOS 6.0, *)
+ typealias Configuration = UIImage.SymbolConfiguration
+ typealias Image = UIImage
+
+ @available(iOS 12.0, tvOS 12.0, watchOS 5.0, *)
+ var image: Image {
+ let bundle = BundleToken.bundle
+ #if os(iOS) || os(tvOS)
+ let image = Image(named: name, in: bundle, compatibleWith: nil)
+ #elseif os(watchOS)
+ let image = Image(named: name)
+ #endif
+ guard let result = image else {
+ fatalError("Unable to load symbol asset named \(name).")
+ }
+ return result
+ }
+
+ @available(iOS 13.0, tvOS 13.0, watchOS 6.0, *)
+ func image(with configuration: Configuration) -> Image {
+ let bundle = BundleToken.bundle
+ guard let result = Image(named: name, in: bundle, with: configuration) else {
+ fatalError("Unable to load symbol asset named \(name).")
+ }
+ return result
+ }
+ #endif
+
+ #if canImport(SwiftUI)
+ @available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
+ var swiftUIImage: SwiftUI.Image {
+ SwiftUI.Image(asset: self)
+ }
+ #endif
+}
+
+#if canImport(SwiftUI)
+@available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *)
+extension SwiftUI.Image {
+ init(asset: SymbolAsset) {
+ let bundle = BundleToken.bundle
+ self.init(asset.name, bundle: bundle)
+ }
+
+ init(asset: SymbolAsset, label: Text) {
+ let bundle = BundleToken.bundle
+ self.init(asset.name, bundle: bundle, label: label)
+ }
+
+ init(decorative asset: SymbolAsset) {
+ let bundle = BundleToken.bundle
+ self.init(decorative: asset.name, bundle: bundle)
+ }
+}
+#endif
+
+// swiftlint:disable convenience_type
+private final class BundleToken {
+ static let bundle: Bundle = {
+ #if SWIFT_PACKAGE
+ return Bundle.module
+ #else
+ return Bundle(for: BundleToken.self)
+ #endif
+ }()
+}
+
+// swiftlint:enable convenience_type
diff --git a/jellypig tvOS/Resources/Info.plist b/jellypig tvOS/Resources/Info.plist
index 00bbd172..264c6b20 100644
--- a/jellypig tvOS/Resources/Info.plist
+++ b/jellypig tvOS/Resources/Info.plist
@@ -25,6 +25,8 @@
NSAllowsArbitraryLoads
+ UIDesignRequiresCompatibility
+
UILaunchScreen
UIColorName
diff --git a/swiftgen.yml b/swiftgen.yml
index 6a5d425d..4e476234 100644
--- a/swiftgen.yml
+++ b/swiftgen.yml
@@ -3,3 +3,9 @@ strings:
outputs:
- templateName: structured-swift5
output: Shared/Strings/Strings.swift
+
+xcassets:
+ inputs: "jellypig tvOS/Resources/Assets.xcassets"
+ outputs:
+ - templateName: swift5
+ output: Shared/Generated/Images+Generated.swift