diff --git a/Shared/BlurHashKit/BlurHash.swift b/Shared/BlurHashKit/BlurHash.swift deleted file mode 100755 index e5a03f98..00000000 --- a/Shared/BlurHashKit/BlurHash.swift +++ /dev/null @@ -1,63 +0,0 @@ -// -// 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) 2022 Jellyfin & Jellyfin Contributors -// - -import Foundation - -public struct BlurHash { - public let components: [[(Float, Float, Float)]] - - public var numberOfHorizontalComponents: Int { components.first!.count } - public var numberOfVerticalComponents: Int { components.count } - - public init(components: [[(Float, Float, Float)]]) { - self.components = components - } - - public func punch(_ factor: Float) -> BlurHash { - BlurHash(components: components.enumerated().map { j, horizontalComponents -> [(Float, Float, Float)] in - horizontalComponents.enumerated().map { i, component -> (Float, Float, Float) in - if i == 0 && j == 0 { - return component - } else { - return component * factor - } - } - }) - } -} - -public func + (lhs: BlurHash, rhs: BlurHash) throws -> BlurHash { - BlurHash(components: paddedZip(lhs.components, rhs.components, [], []).map { - paddedZip($0.0, $0.1, (0, 0, 0) as (Float, Float, Float), (0, 0, 0) as (Float, Float, Float)) - .map { ($0.0.0 + $0.1.0, $0.0.1 + $0.1.1, $0.0.2 + $0.1.2) } - }) -} - -public func - (lhs: BlurHash, rhs: BlurHash) throws -> BlurHash { - BlurHash(components: paddedZip(lhs.components, rhs.components, [], []).map { - paddedZip($0.0, $0.1, (0, 0, 0) as (Float, Float, Float), (0, 0, 0) as (Float, Float, Float)) - .map { ($0.0.0 - $0.1.0, $0.0.1 - $0.1.1, $0.0.2 - $0.1.2) } - }) -} - -private func paddedZip( - _ collection1: Collection1, - _ collection2: Collection2, - _ padding1: Collection1.Element, - _ padding2: Collection2.Element -) -> Zip2Sequence<[Collection1.Element], [Collection2.Element]> where Collection1: Collection, Collection2: Collection { - if collection1.count < collection2.count { - let padded = collection1 + Array(repeating: padding1, count: collection2.count - collection1.count) - return zip(padded, Array(collection2)) - } else if collection2.count < collection1.count { - let padded = collection2 + Array(repeating: padding2, count: collection1.count - collection2.count) - return zip(Array(collection1), padded) - } else { - return zip(Array(collection1), Array(collection2)) - } -} diff --git a/Shared/BlurHashKit/ColourProbes.swift b/Shared/BlurHashKit/ColourProbes.swift deleted file mode 100755 index 26817493..00000000 --- a/Shared/BlurHashKit/ColourProbes.swift +++ /dev/null @@ -1,102 +0,0 @@ -// -// 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) 2022 Jellyfin & Jellyfin Contributors -// - -import Foundation - -public extension BlurHash { - func linearRGB(atX x: Float) -> (Float, Float, Float) { - return components[0].enumerated().reduce((0, 0, 0)) { sum, horizontalEnumerated -> (Float, Float, Float) in - let (i, component) = horizontalEnumerated - return sum + component * cos(Float.pi * Float(i) * x) - } - } - - func linearRGB(atY y: Float) -> (Float, Float, Float) { - return components.enumerated().reduce((0, 0, 0)) { sum, verticalEnumerated in - let (j, horizontalComponents) = verticalEnumerated - return sum + horizontalComponents[0] * cos(Float.pi * Float(j) * y) - } - } - - func linearRGB(at position: (Float, Float)) -> (Float, Float, Float) { - return components.enumerated().reduce((0, 0, 0)) { sum, verticalEnumerated in - let (j, horizontalComponents) = verticalEnumerated - return horizontalComponents.enumerated().reduce(sum) { sum, horizontalEnumerated in - let (i, component) = horizontalEnumerated - return sum + component * cos(Float.pi * Float(i) * position.0) * cos(Float.pi * Float(j) * position.1) - } - } - } - - func linearRGB(from upperLeft: (Float, Float), to lowerRight: (Float, Float)) -> (Float, Float, Float) { - return components.enumerated().reduce((0, 0, 0)) { sum, verticalEnumerated in - let (j, horizontalComponents) = verticalEnumerated - return horizontalComponents.enumerated().reduce(sum) { sum, horizontalEnumerated in - let (i, component) = horizontalEnumerated - let horizontalAverage: Float = i == 0 ? 1 : - (sin(Float.pi * Float(i) * lowerRight.0) - sin(Float.pi * Float(i) * upperLeft.0)) / - (Float(i) * Float.pi * (lowerRight.0 - upperLeft.0)) - let veritcalAverage: Float = j == 0 ? 1 : - (sin(Float.pi * Float(j) * lowerRight.1) - sin(Float.pi * Float(j) * upperLeft.1)) / - (Float(j) * Float.pi * (lowerRight.1 - upperLeft.1)) - return sum + component * horizontalAverage * veritcalAverage - } - } - } - - func linearRGB(at upperLeft: (Float, Float), size: (Float, Float)) -> (Float, Float, Float) { - return linearRGB(from: upperLeft, to: (upperLeft.0 + size.0, upperLeft.1 + size.1)) - } - - var averageLinearRGB: (Float, Float, Float) { - return components[0][0] - } - - var leftEdgeLinearRGB: (Float, Float, Float) { return linearRGB(atX: 0) } - var rightEdgeLinearRGB: (Float, Float, Float) { return linearRGB(atX: 1) } - var topEdgeLinearRGB: (Float, Float, Float) { return linearRGB(atY: 0) } - var bottomEdgeLinearRGB: (Float, Float, Float) { return linearRGB(atY: 1) } - var topLeftCornerLinearRGB: (Float, Float, Float) { return linearRGB(at: (0, 0)) } - var topRightCornerLinearRGB: (Float, Float, Float) { return linearRGB(at: (1, 0)) } - var bottomLeftCornerLinearRGB: (Float, Float, Float) { return linearRGB(at: (0, 1)) } - var bottomRightCornerLinearRGB: (Float, Float, Float) { return linearRGB(at: (1, 1)) } -} - -public extension BlurHash { - func isDark(linearRGB rgb: (Float, Float, Float), threshold: Float = 0.3) -> Bool { - rgb.0 * 0.299 + rgb.1 * 0.587 + rgb.2 * 0.114 < threshold - } - - func isDark(threshold: Float = 0.3) -> Bool { isDark(linearRGB: averageLinearRGB, threshold: threshold) } - - func isDark(atX x: Float, threshold: Float = 0.3) -> Bool { isDark(linearRGB: linearRGB(atX: x), threshold: threshold) } - func isDark(atY y: Float, threshold: Float = 0.3) -> Bool { isDark(linearRGB: linearRGB(atY: y), threshold: threshold) } - func isDark( - at position: (Float, Float), - threshold: Float = 0.3 - ) -> Bool { isDark(linearRGB: linearRGB(at: position), threshold: threshold) } - func isDark( - from upperLeft: (Float, Float), - to lowerRight: (Float, Float), - threshold: Float = 0.3 - ) -> Bool { isDark(linearRGB: linearRGB(from: upperLeft, to: lowerRight), threshold: threshold) } - func isDark( - at upperLeft: (Float, Float), - size: (Float, Float), - threshold: Float = 0.3 - ) -> Bool { isDark(linearRGB: linearRGB(at: upperLeft, size: size), threshold: threshold) } - - var isLeftEdgeDark: Bool { isDark(atX: 0) } - var isRightEdgeDark: Bool { isDark(atX: 1) } - var isTopEdgeDark: Bool { isDark(atY: 0) } - var isBottomEdgeDark: Bool { isDark(atY: 1) } - var isTopLeftCornerDark: Bool { isDark(at: (0, 0)) } - var isTopRightCornerDark: Bool { isDark(at: (1, 0)) } - var isBottomLeftCornerDark: Bool { isDark(at: (0, 1)) } - var isBottomRightCornerDark: Bool { isDark(at: (1, 1)) } -} diff --git a/Shared/BlurHashKit/ColourSpace.swift b/Shared/BlurHashKit/ColourSpace.swift deleted file mode 100755 index dc2f464b..00000000 --- a/Shared/BlurHashKit/ColourSpace.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// 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) 2022 Jellyfin & Jellyfin Contributors -// - -import Foundation - -func signPow(_ value: Float, _ exp: Float) -> Float { - copysign(pow(abs(value), exp), value) -} - -func linearTosRGB(_ value: Float) -> Int { - let v = max(0, min(1, value)) - if v <= 0.0031308 { return Int(v * 12.92 * 255 + 0.5) } - else { return Int((1.055 * pow(v, 1 / 2.4) - 0.055) * 255 + 0.5) } -} - -func sRGBToLinear(_ value: Type) -> Float { - let v = Float(Int64(value)) / 255 - if v <= 0.04045 { return v / 12.92 } - else { return pow((v + 0.055) / 1.055, 2.4) } -} diff --git a/Shared/BlurHashKit/EscapeSequences.swift b/Shared/BlurHashKit/EscapeSequences.swift deleted file mode 100755 index 8185a922..00000000 --- a/Shared/BlurHashKit/EscapeSequences.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// 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) 2022 Jellyfin & Jellyfin Contributors -// - -import Foundation - -extension BlurHash { - var twoByThreeEscapeSequence: String { - let areas: [(from: (Float, Float), to: (Float, Float))] = [ - (from: (0, 0), to: (0.333, 0.5)), - (from: (0, 0.5), to: (0.333, 1.0)), - (from: (0.333, 0), to: (0.666, 0.5)), - (from: (0.333, 0.5), to: (0.666, 1.0)), - (from: (0.666, 0), to: (1.0, 0.5)), - (from: (0.666, 0.5), to: (1.0, 1.0)), - ] - - let rgb: [(Float, Float, Float)] = areas.map { area in - linearRGB(from: area.from, to: area.to) - } - - let maxRgb: (Float, Float, Float) = rgb.reduce((-Float.infinity, -Float.infinity, -Float.infinity), max) - let minRgb: (Float, Float, Float) = rgb.reduce((Float.infinity, Float.infinity, Float.infinity), min) - - let positiveScale: (Float, Float, Float) = ((1, 1, 1) - averageLinearRGB) / (maxRgb - averageLinearRGB) - let negativeScale: (Float, Float, Float) = averageLinearRGB / (averageLinearRGB - minRgb) - let scale: (Float, Float, Float) = min(positiveScale, negativeScale) - - let scaledRgb: [(Float, Float, Float)] = rgb.map { rgb in - (rgb - averageLinearRGB) * scale + averageLinearRGB - } - - let c = scaledRgb.map { rgb in - (linearTosRGB(rgb.0) / 51) * 36 + (linearTosRGB(rgb.1) / 51) * 6 + (linearTosRGB(rgb.2) / 51) + 16 - } - - return "\u{1b}[38;5;\(c[1]);48;5;\(c[0])m▄\u{1b}[38;5;\(c[3]);48;5;\(c[2])m▄\u{1b}[38;5;\(c[5]);48;5;\(c[4])m▄\u{1b}[m" - } -} diff --git a/Shared/BlurHashKit/FromString.swift b/Shared/BlurHashKit/FromString.swift deleted file mode 100755 index 756a793c..00000000 --- a/Shared/BlurHashKit/FromString.swift +++ /dev/null @@ -1,76 +0,0 @@ -// -// 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) 2022 Jellyfin & Jellyfin Contributors -// - -import Foundation - -public extension BlurHash { - init?(string: String) { - guard string.count >= 6 else { return nil } - - let sizeFlag = String(string[0]).decode83() - let numberOfHorizontalComponents = (sizeFlag % 9) + 1 - let numberOfVerticalComponents = (sizeFlag / 9) + 1 - - let quantisedMaximumValue = String(string[1]).decode83() - let maximumValue = Float(quantisedMaximumValue + 1) / 166 - - guard string.count == 4 + 2 * numberOfHorizontalComponents * numberOfVerticalComponents else { return nil } - - self.components = (0 ..< numberOfVerticalComponents).map { j in - (0 ..< numberOfHorizontalComponents).map { i in - if i == 0 && j == 0 { - let value = String(string[2 ..< 6]).decode83() - return BlurHash.decodeDC(value) - } else { - let index = i + j * numberOfHorizontalComponents - let value = String(string[4 + index * 2 ..< 4 + index * 2 + 2]).decode83() - return BlurHash.decodeAC(value, maximumValue: maximumValue) - } - } - } - } - - private static func decodeDC(_ value: Int) -> (Float, Float, Float) { - let intR = value >> 16 - let intG = (value >> 8) & 255 - let intB = value & 255 - return (sRGBToLinear(intR), sRGBToLinear(intG), sRGBToLinear(intB)) - } - - private static func decodeAC(_ value: Int, maximumValue: Float) -> (Float, Float, Float) { - let quantR = value / (19 * 19) - let quantG = (value / 19) % 19 - let quantB = value % 19 - - let rgb = ( - signPow((Float(quantR) - 9) / 9, 2) * maximumValue, - signPow((Float(quantG) - 9) / 9, 2) * maximumValue, - signPow((Float(quantB) - 9) / 9, 2) * maximumValue - ) - - return rgb - } -} - -private extension String { - subscript(offset: Int) -> Character { - self[index(startIndex, offsetBy: offset)] - } - - subscript(bounds: CountableClosedRange) -> Substring { - let start = index(startIndex, offsetBy: bounds.lowerBound) - let end = index(startIndex, offsetBy: bounds.upperBound) - return self[start ... end] - } - - subscript(bounds: CountableRange) -> Substring { - let start = index(startIndex, offsetBy: bounds.lowerBound) - let end = index(startIndex, offsetBy: bounds.upperBound) - return self[start ..< end] - } -} diff --git a/Shared/BlurHashKit/FromUIImage.swift b/Shared/BlurHashKit/FromUIImage.swift deleted file mode 100755 index 799efa4d..00000000 --- a/Shared/BlurHashKit/FromUIImage.swift +++ /dev/null @@ -1,92 +0,0 @@ -// -// 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) 2022 Jellyfin & Jellyfin Contributors -// - -import UIKit - -public extension BlurHash { - init?(image: UIImage, numberOfComponents components: (Int, Int)) { - guard components.0 >= 1, components.0 <= 9, - components.1 >= 1, components.1 <= 9 - else { - fatalError("Number of components bust be between 1 and 9 inclusive on each axis") - } - - let pixelWidth = Int(round(image.size.width * image.scale)) - let pixelHeight = Int(round(image.size.height * image.scale)) - - let context = CGContext( - data: nil, - width: pixelWidth, - height: pixelHeight, - bitsPerComponent: 8, - bytesPerRow: pixelWidth * 4, - space: CGColorSpace(name: CGColorSpace.sRGB)!, - bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue - )! - context.scaleBy(x: image.scale, y: -image.scale) - context.translateBy(x: 0, y: -image.size.height) - - UIGraphicsPushContext(context) - image.draw(at: .zero) - UIGraphicsPopContext() - - guard let cgImage = context.makeImage(), - let dataProvider = cgImage.dataProvider, - let data = dataProvider.data, - let pixels = CFDataGetBytePtr(data) - else { - assertionFailure("Unexpected error!") - return nil - } - - let width = cgImage.width - let height = cgImage.height - let bytesPerRow = cgImage.bytesPerRow - - self.components = (0 ..< components.1).map { j -> [(Float, Float, Float)] in - (0 ..< components.0).map { i -> (Float, Float, Float) in - let normalisation: Float = (i == 0 && j == 0) ? 1 : 2 - return BlurHash.multiplyBasisFunction( - pixels: pixels, - width: width, - height: height, - bytesPerRow: bytesPerRow, - bytesPerPixel: cgImage.bitsPerPixel / 8 - ) { x, y in - normalisation * cos(Float.pi * Float(i) * x / Float(width)) as Float * - cos(Float.pi * Float(j) * y / Float(height)) as Float - } - } - } - } - - private static func multiplyBasisFunction( - pixels: UnsafePointer, - width: Int, - height: Int, - bytesPerRow: Int, - bytesPerPixel: Int, - basisFunction: (Float, Float) -> Float - ) -> (Float, Float, Float) { - var c: (Float, Float, Float) = (0, 0, 0) - - let buffer = UnsafeBufferPointer(start: pixels, count: height * bytesPerRow) - - for x in 0 ..< width { - for y in 0 ..< height { - c += basisFunction(Float(x), Float(y)) * ( - sRGBToLinear(buffer[bytesPerPixel * x + 0 + y * bytesPerRow]), - sRGBToLinear(buffer[bytesPerPixel * x + 1 + y * bytesPerRow]), - sRGBToLinear(buffer[bytesPerPixel * x + 2 + y * bytesPerRow]) - ) - } - } - - return c / Float(width * height) - } -} diff --git a/Shared/BlurHashKit/Generation.swift b/Shared/BlurHashKit/Generation.swift deleted file mode 100755 index 92b27cd8..00000000 --- a/Shared/BlurHashKit/Generation.swift +++ /dev/null @@ -1,115 +0,0 @@ -// -// 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) 2022 Jellyfin & Jellyfin Contributors -// - -import UIKit - -public extension BlurHash { - init(blendingTop top: BlurHash, bottom: BlurHash) { - guard top.components.count == 1, bottom.components.count == 1 else { - fatalError("Blended BlurHashses must have only one vertical component") - } - - let average = zip(top.components[0], bottom.components[0]).map { ($0 + $1) / 2 } - let difference = zip(top.components[0], bottom.components[0]).map { ($0 - $1) / 2 } - self.init(components: [average, difference]) - } - - init(blendingLeft left: BlurHash, right: BlurHash) { - self = BlurHash(blendingTop: left.transposed, bottom: right.transposed).transposed - } -} - -public extension BlurHash { - init(colour: UIColor) { - self.init(components: [[colour.linear]]) - } - - init(blendingTop topColour: UIColor, bottom bottomColour: UIColor) { - self = BlurHash(blendingTop: .init(colour: topColour), bottom: .init(colour: bottomColour)) - } - - init(blendingLeft leftColour: UIColor, right rightColour: UIColor) { - self = BlurHash(blendingLeft: .init(colour: leftColour), right: .init(colour: rightColour)) - } - - init( - blendingTopLeft topLeftColour: UIColor, - topRight topRightColour: UIColor, - bottomLeft bottomLeftColour: UIColor, - bottomRight bottomRightColour: UIColor - ) { - self = BlurHash( - blendingTop: BlurHash(blendingTop: topLeftColour, bottom: topRightColour).transposed, - bottom: BlurHash(blendingTop: bottomLeftColour, bottom: bottomRightColour).transposed - ) - } -} - -public extension BlurHash { - init(horizontalColours colours: [(Float, Float, Float)], numberOfComponents: Int) { - guard numberOfComponents >= 1, numberOfComponents <= 9 else { - fatalError("Number of components bust be between 1 and 9 inclusive") - } - - self.init(components: [(0 ..< numberOfComponents).map { i in - let normalisation: Float = i == 0 ? 1 : 2 - var sum: (Float, Float, Float) = (0, 0, 0) - for x in 0 ..< colours.count { - let basis = normalisation * cos(Float.pi * Float(i) * Float(x) / Float(colours.count - 1)) - sum += basis * colours[x] - } - - return sum / Float(colours.count) - }]) - } -} - -public extension BlurHash { - var mirroredHorizontally: BlurHash { - .init(components: (0 ..< numberOfVerticalComponents).map { j -> [(Float, Float, Float)] in - (0 ..< numberOfHorizontalComponents).map { i -> (Float, Float, Float) in - components[j][i] * (i % 2 == 0 ? 1 : -1) - } - }) - } - - var mirroredVertically: BlurHash { - .init(components: (0 ..< numberOfVerticalComponents).map { j -> [(Float, Float, Float)] in - (0 ..< numberOfHorizontalComponents).map { i -> (Float, Float, Float) in - components[j][i] * (j % 2 == 0 ? 1 : -1) - } - }) - } - - var transposed: BlurHash { - .init(components: (0 ..< numberOfHorizontalComponents).map { i in - (0 ..< numberOfVerticalComponents).map { j in - components[j][i] - } - }) - } -} - -extension UIColor { - var linear: (Float, Float, Float) { - guard let c = cgColor.converted(to: CGColorSpace(name: CGColorSpace.sRGB)!, intent: .defaultIntent, options: nil)?.components - else { return (0, 0, 0) } - - switch c.count { - case 1, 2: return (sRGBToLinear(c[0]), sRGBToLinear(c[0]), sRGBToLinear(c[0])) - case 3, 4: return (sRGBToLinear(c[0]), sRGBToLinear(c[1]), sRGBToLinear(c[2])) - default: return (0, 0, 0) - } - } -} - -func sRGBToLinear(_ value: CGFloat) -> Float { - let v = Float(value) - if v <= 0.04045 { return v / 12.92 } - else { return pow((v + 0.055) / 1.055, 2.4) } -} diff --git a/Shared/BlurHashKit/StringCoding.swift b/Shared/BlurHashKit/StringCoding.swift deleted file mode 100755 index 857a7295..00000000 --- a/Shared/BlurHashKit/StringCoding.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// 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) 2022 Jellyfin & Jellyfin Contributors -// - -import Foundation - -private let encodeCharacters: [String] = { - "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz#$%*+,-.:;=?@[]^_{|}~".map { String($0) } -}() - -private let decodeCharacters: [String: Int] = { - var dict: [String: Int] = [:] - for (index, character) in encodeCharacters.enumerated() { - dict[character] = index - } - return dict -}() - -extension BinaryInteger { - func encode83(length: Int) -> String { - var result = "" - for i in 1 ... length { - let digit = (Int(self) / pow(83, length - i)) % 83 - result += encodeCharacters[Int(digit)] - } - return result - } -} - -extension String { - func decode83() -> Int { - var value: Int = 0 - for character in self { - if let digit = decodeCharacters[String(character)] { - value = value * 83 + digit - } - } - return value - } -} - -private func pow(_ base: Int, _ exponent: Int) -> Int { - (0 ..< exponent).reduce(1) { value, _ in value * base } -} diff --git a/Shared/BlurHashKit/ToString.swift b/Shared/BlurHashKit/ToString.swift deleted file mode 100755 index 8c8adfb1..00000000 --- a/Shared/BlurHashKit/ToString.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// 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) 2022 Jellyfin & Jellyfin Contributors -// - -import Foundation - -public extension BlurHash { - var string: String { - let flatComponents = components.reduce([]) { $0 + $1 } - let dc = flatComponents.first! - let ac = flatComponents.dropFirst() - - var hash = "" - - let sizeFlag = (numberOfHorizontalComponents - 1) + (numberOfVerticalComponents - 1) * 9 - hash += sizeFlag.encode83(length: 1) - - let maximumValue: Float - if !ac.isEmpty { - let actualMaximumValue = ac.map { max(abs($0.0), abs($0.1), abs($0.2)) }.max()! - let quantisedMaximumValue = Int(max(0, min(82, floor(actualMaximumValue * 166 - 0.5)))) - maximumValue = Float(quantisedMaximumValue + 1) / 166 - hash += quantisedMaximumValue.encode83(length: 1) - } else { - maximumValue = 1 - hash += 0.encode83(length: 1) - } - - hash += encodeDC(dc).encode83(length: 4) - - for factor in ac { - hash += encodeAC(factor, maximumValue: maximumValue).encode83(length: 2) - } - - return hash - } - - private func encodeDC(_ value: (Float, Float, Float)) -> Int { - let roundedR = linearTosRGB(value.0) - let roundedG = linearTosRGB(value.1) - let roundedB = linearTosRGB(value.2) - return (roundedR << 16) + (roundedG << 8) + roundedB - } - - private func encodeAC(_ value: (Float, Float, Float), maximumValue: Float) -> Int { - let quantR = Int(max(0, min(18, floor(signPow(value.0 / maximumValue, 0.5) * 9 + 9.5)))) - let quantG = Int(max(0, min(18, floor(signPow(value.1 / maximumValue, 0.5) * 9 + 9.5)))) - let quantB = Int(max(0, min(18, floor(signPow(value.2 / maximumValue, 0.5) * 9 + 9.5)))) - - return quantR * 19 * 19 + quantG * 19 + quantB - } -} diff --git a/Shared/BlurHashKit/ToUIImage.swift b/Shared/BlurHashKit/ToUIImage.swift deleted file mode 100755 index 79bbf51b..00000000 --- a/Shared/BlurHashKit/ToUIImage.swift +++ /dev/null @@ -1,101 +0,0 @@ -// -// 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) 2022 Jellyfin & Jellyfin Contributors -// - -import UIKit - -public extension BlurHash { - func cgImage(size: CGSize) -> CGImage? { - let width = Int(size.width) - let height = Int(size.height) - let bytesPerRow = width * 3 - - guard let data = CFDataCreateMutable(kCFAllocatorDefault, bytesPerRow * height) else { return nil } - CFDataSetLength(data, bytesPerRow * height) - - guard let pixels = CFDataGetMutableBytePtr(data) else { return nil } - - for y in 0 ..< height { - for x in 0 ..< width { - var c: (Float, Float, Float) = (0, 0, 0) - - for j in 0 ..< numberOfVerticalComponents { - for i in 0 ..< numberOfHorizontalComponents { - let basis = cos(Float.pi * Float(x) * Float(i) / Float(width)) * cos(Float.pi * Float(y) * Float(j) / Float(height)) - let component = components[j][i] - c += component * basis - } - } - - let intR = UInt8(linearTosRGB(c.0)) - let intG = UInt8(linearTosRGB(c.1)) - let intB = UInt8(linearTosRGB(c.2)) - - pixels[3 * x + 0 + y * bytesPerRow] = intR - pixels[3 * x + 1 + y * bytesPerRow] = intG - pixels[3 * x + 2 + y * bytesPerRow] = intB - } - } - - let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.none.rawValue) - - guard let provider = CGDataProvider(data: data) else { return nil } - guard let cgImage = CGImage( - width: width, - height: height, - bitsPerComponent: 8, - bitsPerPixel: 24, - bytesPerRow: bytesPerRow, - space: CGColorSpaceCreateDeviceRGB(), - bitmapInfo: bitmapInfo, - provider: provider, - decode: nil, - shouldInterpolate: true, - intent: .defaultIntent - ) else { return nil } - - return cgImage - } - - func cgImage(numberOfPixels: Int = 1024, originalSize size: CGSize) -> CGImage? { - let width: CGFloat - let height: CGFloat - if size.width > size.height { - width = floor(sqrt(CGFloat(numberOfPixels) * size.width / size.height) + 0.5) - height = floor(CGFloat(numberOfPixels) / width + 0.5) - } else { - height = floor(sqrt(CGFloat(numberOfPixels) * size.height / size.width) + 0.5) - width = floor(CGFloat(numberOfPixels) / height + 0.5) - } - return cgImage(size: CGSize(width: width, height: height)) - } - - func image(size: CGSize) -> UIImage? { - guard let cgImage = cgImage(size: size) else { return nil } - return UIImage(cgImage: cgImage) - } - - func image(numberOfPixels: Int = 1024, originalSize size: CGSize) -> UIImage? { - guard let cgImage = cgImage(numberOfPixels: numberOfPixels, originalSize: size) else { return nil } - return UIImage(cgImage: cgImage) - } -} - -@objc -public extension UIImage { - convenience init?(blurHash string: String, size: CGSize, punch: Float = 1) { - guard let blurHash = BlurHash(string: string), - let cgImage = blurHash.punch(punch).cgImage(size: size) else { return nil } - self.init(cgImage: cgImage) - } - - convenience init?(blurHash string: String, numberOfPixels: Int = 1024, originalSize size: CGSize, punch: Float = 1) { - guard let blurHash = BlurHash(string: string), - let cgImage = blurHash.punch(punch).cgImage(numberOfPixels: numberOfPixels, originalSize: size) else { return nil } - self.init(cgImage: cgImage) - } -} diff --git a/Shared/BlurHashKit/TupleMaths.swift b/Shared/BlurHashKit/TupleMaths.swift deleted file mode 100755 index 9cbfb18d..00000000 --- a/Shared/BlurHashKit/TupleMaths.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// 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) 2022 Jellyfin & Jellyfin Contributors -// - -import Foundation - -func + (lhs: (Float, Float, Float), rhs: (Float, Float, Float)) -> (Float, Float, Float) { - return (lhs.0 + rhs.0, lhs.1 + rhs.1, lhs.2 + rhs.2) -} - -func - (lhs: (Float, Float, Float), rhs: (Float, Float, Float)) -> (Float, Float, Float) { - return (lhs.0 - rhs.0, lhs.1 - rhs.1, lhs.2 - rhs.2) -} - -func * (lhs: (Float, Float, Float), rhs: (Float, Float, Float)) -> (Float, Float, Float) { - return (lhs.0 * rhs.0, lhs.1 * rhs.1, lhs.2 * rhs.2) -} - -func * (lhs: (Float, Float, Float), rhs: Float) -> (Float, Float, Float) { - return (lhs.0 * rhs, lhs.1 * rhs, lhs.2 * rhs) -} - -func * (lhs: Float, rhs: (Float, Float, Float)) -> (Float, Float, Float) { - return (lhs * rhs.0, lhs * rhs.1, lhs * rhs.2) -} - -func / (lhs: (Float, Float, Float), rhs: (Float, Float, Float)) -> (Float, Float, Float) { - return (lhs.0 / rhs.0, lhs.1 / rhs.1, lhs.2 / rhs.2) -} - -func / (lhs: (Float, Float, Float), rhs: Float) -> (Float, Float, Float) { - return (lhs.0 / rhs, lhs.1 / rhs, lhs.2 / rhs) -} - -func += (lhs: inout (Float, Float, Float), rhs: (Float, Float, Float)) { - lhs = lhs + rhs -} - -func -= (lhs: inout (Float, Float, Float), rhs: (Float, Float, Float)) { - lhs = lhs - rhs -} - -func *= (lhs: inout (Float, Float, Float), rhs: Float) { - lhs = lhs * rhs -} - -func /= (lhs: inout (Float, Float, Float), rhs: Float) { - lhs = lhs / rhs -} - -func min(_ a: (Float, Float, Float), _ b: (Float, Float, Float)) -> (Float, Float, Float) { - return (min(a.0, b.0), min(a.1, b.1), min(a.2, b.2)) -} - -func max(_ a: (Float, Float, Float), _ b: (Float, Float, Float)) -> (Float, Float, Float) { - return (max(a.0, b.0), max(a.1, b.1), max(a.2, b.2)) -} diff --git a/Shared/Views/BlurHashView.swift b/Shared/Views/BlurHashView.swift index edc22b95..d013a1b7 100644 --- a/Shared/Views/BlurHashView.swift +++ b/Shared/Views/BlurHashView.swift @@ -6,6 +6,7 @@ // Copyright (c) 2022 Jellyfin & Jellyfin Contributors // +import BlurHashKit import SwiftUI import UIKit diff --git a/Swiftfin tvOS/Components/HomeCinematicView/CinematicBackgroundView.swift b/Swiftfin tvOS/Components/HomeCinematicView/CinematicBackgroundView.swift index 9b580cdf..b1718a12 100644 --- a/Swiftfin tvOS/Components/HomeCinematicView/CinematicBackgroundView.swift +++ b/Swiftfin tvOS/Components/HomeCinematicView/CinematicBackgroundView.swift @@ -8,6 +8,7 @@ import JellyfinAPI import Nuke +import NukeExtensions import SwiftUI import UIKit @@ -18,6 +19,7 @@ class DynamicCinematicBackgroundViewModel: ObservableObject { @Published var currentImageView: UIImageView? + @MainActor func select(item: BaseItemDto) { guard item.id != currentItem?.id else { return } @@ -36,7 +38,7 @@ class DynamicCinematicBackgroundViewModel: ObservableObject { let options = ImageLoadingOptions(transition: .fadeIn(duration: 0.2)) - Nuke.loadImage(with: backdropImage, options: options, into: itemImageView, completion: { _ in }) + loadImage(with: backdropImage, options: options, into: itemImageView, completion: { _ in }) currentImageView = itemImageView } diff --git a/Swiftfin.xcodeproj/project.pbxproj b/Swiftfin.xcodeproj/project.pbxproj index 6ea201a1..636c898d 100644 --- a/Swiftfin.xcodeproj/project.pbxproj +++ b/Swiftfin.xcodeproj/project.pbxproj @@ -272,7 +272,6 @@ E11CEB9428999D9E003E74C7 /* EpisodeItemContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11CEB9328999D9E003E74C7 /* EpisodeItemContentView.swift */; }; E11D224227378428003F9CB3 /* ServerDetailCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11D224127378428003F9CB3 /* ServerDetailCoordinator.swift */; }; E11D224327378428003F9CB3 /* ServerDetailCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11D224127378428003F9CB3 /* ServerDetailCoordinator.swift */; }; - E11D83AF278FA998006E9776 /* NukeUI in Frameworks */ = {isa = PBXBuildFile; productRef = E11D83AE278FA998006E9776 /* NukeUI */; }; E12186DE2718F1C50010884C /* Defaults in Frameworks */ = {isa = PBXBuildFile; productRef = E12186DD2718F1C50010884C /* Defaults */; }; E1218C9E271A2CD600EA0737 /* CombineExt in Frameworks */ = {isa = PBXBuildFile; productRef = E1218C9D271A2CD600EA0737 /* CombineExt */; }; E122A9132788EAAD0060FA63 /* MediaStreamExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E122A9122788EAAD0060FA63 /* MediaStreamExtension.swift */; }; @@ -282,13 +281,16 @@ E126F742278A656C00A522BF /* ServerStreamType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E126F740278A656C00A522BF /* ServerStreamType.swift */; }; E1347DB2279E3C6200BC6161 /* Puppy in Frameworks */ = {isa = PBXBuildFile; productRef = E1347DB1279E3C6200BC6161 /* Puppy */; }; E1347DB6279E3CA500BC6161 /* Puppy in Frameworks */ = {isa = PBXBuildFile; productRef = E1347DB5279E3CA500BC6161 /* Puppy */; }; - E1361DA7278FA7A300BEC523 /* NukeUI in Frameworks */ = {isa = PBXBuildFile; productRef = E1361DA6278FA7A300BEC523 /* NukeUI */; }; E1384944278036C70024FB48 /* VLCPlayerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1384943278036C70024FB48 /* VLCPlayerViewController.swift */; }; E13849452780370B0024FB48 /* PlaybackSpeed.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1C812B4277A8E5D00918266 /* PlaybackSpeed.swift */; }; E1399474289B1EA900401ABC /* Defaults+Workaround.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1399473289B1EA900401ABC /* Defaults+Workaround.swift */; }; E1399475289B1EA900401ABC /* Defaults+Workaround.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1399473289B1EA900401ABC /* Defaults+Workaround.swift */; }; E13AD72E2798BC8D00FDCEE8 /* NativePlayerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13AD72D2798BC8D00FDCEE8 /* NativePlayerViewController.swift */; }; E13AD7302798C60F00FDCEE8 /* NativePlayerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13AD72F2798C60F00FDCEE8 /* NativePlayerViewController.swift */; }; + E13AF3B628A0C598009093AB /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = E13AF3B528A0C598009093AB /* Nuke */; }; + E13AF3B828A0C598009093AB /* NukeExtensions in Frameworks */ = {isa = PBXBuildFile; productRef = E13AF3B728A0C598009093AB /* NukeExtensions */; }; + E13AF3BA28A0C598009093AB /* NukeUI in Frameworks */ = {isa = PBXBuildFile; productRef = E13AF3B928A0C598009093AB /* NukeUI */; }; + E13AF3BC28A0C59E009093AB /* BlurHashKit in Frameworks */ = {isa = PBXBuildFile; productRef = E13AF3BB28A0C59E009093AB /* BlurHashKit */; }; E13DD3BF27163DD7009D4DAF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3BE27163DD7009D4DAF /* AppDelegate.swift */; }; E13DD3C227164941009D4DAF /* SwiftfinStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3C127164941009D4DAF /* SwiftfinStore.swift */; }; E13DD3C327164941009D4DAF /* SwiftfinStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13DD3C127164941009D4DAF /* SwiftfinStore.swift */; }; @@ -411,29 +413,10 @@ E193D5502719430400900D82 /* ServerDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E193D54F2719430400900D82 /* ServerDetailView.swift */; }; E193D5512719432400900D82 /* ServerDetailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E173DA5326D050F500CC4EB7 /* ServerDetailViewModel.swift */; }; E193D553271943D500900D82 /* tvOSMainTabCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E193D552271943D500900D82 /* tvOSMainTabCoordinator.swift */; }; - E19E550428972B97003CE330 /* ColourSpace.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E54F828972B97003CE330 /* ColourSpace.swift */; }; - E19E550528972B97003CE330 /* ColourSpace.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E54F828972B97003CE330 /* ColourSpace.swift */; }; - E19E550628972B97003CE330 /* BlurHash.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E54F928972B97003CE330 /* BlurHash.swift */; }; - E19E550728972B97003CE330 /* BlurHash.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E54F928972B97003CE330 /* BlurHash.swift */; }; - E19E550828972B97003CE330 /* StringCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E54FA28972B97003CE330 /* StringCoding.swift */; }; - E19E550928972B97003CE330 /* StringCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E54FA28972B97003CE330 /* StringCoding.swift */; }; - E19E550A28972B97003CE330 /* FromString.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E54FB28972B97003CE330 /* FromString.swift */; }; - E19E550B28972B97003CE330 /* FromString.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E54FB28972B97003CE330 /* FromString.swift */; }; - E19E550C28972B97003CE330 /* EscapeSequences.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E54FC28972B97003CE330 /* EscapeSequences.swift */; }; - E19E550D28972B97003CE330 /* EscapeSequences.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E54FC28972B97003CE330 /* EscapeSequences.swift */; }; - E19E550E28972B97003CE330 /* ColourProbes.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E54FD28972B97003CE330 /* ColourProbes.swift */; }; - E19E550F28972B97003CE330 /* ColourProbes.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E54FD28972B97003CE330 /* ColourProbes.swift */; }; - E19E551028972B97003CE330 /* ToString.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E54FE28972B97003CE330 /* ToString.swift */; }; - E19E551128972B97003CE330 /* ToString.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E54FE28972B97003CE330 /* ToString.swift */; }; - E19E551228972B97003CE330 /* ToUIImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E54FF28972B97003CE330 /* ToUIImage.swift */; }; - E19E551328972B97003CE330 /* ToUIImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E54FF28972B97003CE330 /* ToUIImage.swift */; }; - E19E551428972B97003CE330 /* FromUIImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E550028972B97003CE330 /* FromUIImage.swift */; }; - E19E551528972B97003CE330 /* FromUIImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E550028972B97003CE330 /* FromUIImage.swift */; }; - E19E551828972B97003CE330 /* Generation.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E550228972B97003CE330 /* Generation.swift */; }; - E19E551928972B97003CE330 /* Generation.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E550228972B97003CE330 /* Generation.swift */; }; - E19E551A28972B97003CE330 /* TupleMaths.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E550328972B97003CE330 /* TupleMaths.swift */; }; - E19E551B28972B97003CE330 /* TupleMaths.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E550328972B97003CE330 /* TupleMaths.swift */; }; E19E551F2897326C003CE330 /* BottomEdgeGradientModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E19E551E2897326C003CE330 /* BottomEdgeGradientModifier.swift */; }; + E19E6E0528A0B958005C10C8 /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = E19E6E0428A0B958005C10C8 /* Nuke */; }; + E19E6E0728A0B958005C10C8 /* NukeUI in Frameworks */ = {isa = PBXBuildFile; productRef = E19E6E0628A0B958005C10C8 /* NukeUI */; }; + E19E6E0A28A0BEFF005C10C8 /* BlurHashKit in Frameworks */ = {isa = PBXBuildFile; productRef = E19E6E0928A0BEFF005C10C8 /* BlurHashKit */; }; E1A16C9D2889AF1E00EA4679 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1A16C9C2889AF1E00EA4679 /* AboutView.swift */; }; E1A16CA1288A7CFD00EA4679 /* AboutViewCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1A16CA0288A7CFD00EA4679 /* AboutViewCard.swift */; }; E1A2C154279A7D5A005EC829 /* UIApplicationExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1A2C153279A7D5A005EC829 /* UIApplicationExtensions.swift */; }; @@ -447,8 +430,6 @@ E1AD104D26D96CE3003E4A08 /* BaseItemDtoExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD104C26D96CE3003E4A08 /* BaseItemDtoExtensions.swift */; }; E1AD104E26D96CE3003E4A08 /* BaseItemDtoExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD104C26D96CE3003E4A08 /* BaseItemDtoExtensions.swift */; }; E1AD105F26D9ADDD003E4A08 /* NameGUIDPairExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1AD105E26D9ADDD003E4A08 /* NameGUIDPairExtensions.swift */; }; - E1AE8E7C2789135A00FBDDAA /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = E1AE8E7B2789135A00FBDDAA /* Nuke */; }; - E1AE8E7E2789136D00FBDDAA /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = E1AE8E7D2789136D00FBDDAA /* Nuke */; }; E1B2AB9928808E150072B3B9 /* GoogleCast.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = E1B2AB9628808CDF0072B3B9 /* GoogleCast.xcframework */; }; E1B59FD52786ADE500A5287E /* ContinueWatchingCard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1B59FD42786ADE500A5287E /* ContinueWatchingCard.swift */; }; E1B6DCE8271A23780015B715 /* CombineExt in Frameworks */ = {isa = PBXBuildFile; productRef = E1B6DCE7271A23780015B715 /* CombineExt */; }; @@ -864,17 +845,6 @@ E193D54C2719426600900D82 /* LibraryFilterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryFilterView.swift; sourceTree = ""; }; E193D54F2719430400900D82 /* ServerDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerDetailView.swift; sourceTree = ""; }; E193D552271943D500900D82 /* tvOSMainTabCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = tvOSMainTabCoordinator.swift; sourceTree = ""; }; - E19E54F828972B97003CE330 /* ColourSpace.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColourSpace.swift; sourceTree = ""; }; - E19E54F928972B97003CE330 /* BlurHash.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlurHash.swift; sourceTree = ""; }; - E19E54FA28972B97003CE330 /* StringCoding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringCoding.swift; sourceTree = ""; }; - E19E54FB28972B97003CE330 /* FromString.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FromString.swift; sourceTree = ""; }; - E19E54FC28972B97003CE330 /* EscapeSequences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EscapeSequences.swift; sourceTree = ""; }; - E19E54FD28972B97003CE330 /* ColourProbes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColourProbes.swift; sourceTree = ""; }; - E19E54FE28972B97003CE330 /* ToString.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToString.swift; sourceTree = ""; }; - E19E54FF28972B97003CE330 /* ToUIImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToUIImage.swift; sourceTree = ""; }; - E19E550028972B97003CE330 /* FromUIImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FromUIImage.swift; sourceTree = ""; }; - E19E550228972B97003CE330 /* Generation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Generation.swift; sourceTree = ""; }; - E19E550328972B97003CE330 /* TupleMaths.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TupleMaths.swift; sourceTree = ""; }; E19E551E2897326C003CE330 /* BottomEdgeGradientModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BottomEdgeGradientModifier.swift; sourceTree = ""; }; E1A16C9C2889AF1E00EA4679 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = ""; }; E1A16CA0288A7CFD00EA4679 /* AboutViewCard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewCard.swift; sourceTree = ""; }; @@ -949,7 +919,6 @@ buildActionMask = 2147483647; files = ( 62666E1727E501CC00EC0ECD /* CFNetwork.framework in Frameworks */, - E11D83AF278FA998006E9776 /* NukeUI in Frameworks */, C409CE9C284EA6EA00CABC12 /* SwiftUICollection in Frameworks */, 62666DFA27E5013700EC0ECD /* TVVLCKit.xcframework in Frameworks */, 62666E3227E5021E00EC0ECD /* UIKit.framework in Frameworks */, @@ -963,6 +932,8 @@ 6220D0C926D63F3700B8E046 /* Stinsen in Frameworks */, 637FCAF5287B5B2600C0A353 /* UDPBroadcast.xcframework in Frameworks */, 535870912669D7A800D05A09 /* Introspect in Frameworks */, + E13AF3B828A0C598009093AB /* NukeExtensions in Frameworks */, + E13AF3BA28A0C598009093AB /* NukeUI in Frameworks */, 62666E1B27E501D400EC0ECD /* CoreGraphics.framework in Frameworks */, 62666E2C27E5021000EC0ECD /* QuartzCore.framework in Frameworks */, 62666E1927E501D000EC0ECD /* CoreFoundation.framework in Frameworks */, @@ -971,8 +942,9 @@ 62666E1F27E501DF00EC0ECD /* CoreText.framework in Frameworks */, E13DD3CD27164CA7009D4DAF /* CoreStore in Frameworks */, 62666E1527E501C800EC0ECD /* AVFoundation.framework in Frameworks */, + E13AF3BC28A0C59E009093AB /* BlurHashKit in Frameworks */, 62666E1327E501C300EC0ECD /* AudioToolbox.framework in Frameworks */, - E1AE8E7E2789136D00FBDDAA /* Nuke in Frameworks */, + E13AF3B628A0C598009093AB /* Nuke in Frameworks */, E178857D278037FD0094FBCF /* JellyfinAPI in Frameworks */, E12186DE2718F1C50010884C /* Defaults in Frameworks */, E1347DB6279E3CA500BC6161 /* Puppy in Frameworks */, @@ -989,7 +961,6 @@ 62666DFF27E5016400EC0ECD /* CFNetwork.framework in Frameworks */, E13DD3D327168E65009D4DAF /* Defaults in Frameworks */, E1101177281B1E8A006A3584 /* Puppy in Frameworks */, - E1361DA7278FA7A300BEC523 /* NukeUI in Frameworks */, E1002B682793CFBA00E47059 /* Algorithms in Frameworks */, 62666E1127E501B900EC0ECD /* UIKit.framework in Frameworks */, 62666DF727E5012C00EC0ECD /* MobileVLCKit.xcframework in Frameworks */, @@ -1001,6 +972,7 @@ 62666E1027E501B400EC0ECD /* VideoToolbox.framework in Frameworks */, 62666E0C27E501A500EC0ECD /* OpenGLES.framework in Frameworks */, C409CE9E285044C800CABC12 /* SwiftUICollection in Frameworks */, + E19E6E0A28A0BEFF005C10C8 /* BlurHashKit in Frameworks */, 62666E0127E5016900EC0ECD /* CoreFoundation.framework in Frameworks */, 62400C4B287ED19600F6AD3D /* UDPBroadcast.xcframework in Frameworks */, E1B6DCEA271A23880015B715 /* SwiftyJSON in Frameworks */, @@ -1012,8 +984,9 @@ E1B2AB9928808E150072B3B9 /* GoogleCast.xcframework in Frameworks */, 62666DFE27E5015700EC0ECD /* AVFoundation.framework in Frameworks */, 62666DFD27E5014F00EC0ECD /* AudioToolbox.framework in Frameworks */, + E19E6E0528A0B958005C10C8 /* Nuke in Frameworks */, 62666E0D27E501AA00EC0ECD /* QuartzCore.framework in Frameworks */, - E1AE8E7C2789135A00FBDDAA /* Nuke in Frameworks */, + E19E6E0728A0B958005C10C8 /* NukeUI in Frameworks */, 62666E3F27E5040300EC0ECD /* SystemConfiguration.framework in Frameworks */, 625CB57A2678C4A400530A6E /* ActivityIndicator in Frameworks */, 62666E3927E502CE00EC0ECD /* SwizzleSwift in Frameworks */, @@ -1152,7 +1125,6 @@ 535870752669D60C00D05A09 /* Shared */ = { isa = PBXGroup; children = ( - E19E54F728972B97003CE330 /* BlurHashKit */, 62C29E9D26D0FE5900C1D2E7 /* Coordinators */, E1FCD08E26C466F3007C8DCF /* Errors */, 621338912660106C00A81A2A /* Extensions */, @@ -1961,24 +1933,6 @@ path = ItemView; sourceTree = ""; }; - E19E54F728972B97003CE330 /* BlurHashKit */ = { - isa = PBXGroup; - children = ( - E19E54F828972B97003CE330 /* ColourSpace.swift */, - E19E54F928972B97003CE330 /* BlurHash.swift */, - E19E54FA28972B97003CE330 /* StringCoding.swift */, - E19E54FB28972B97003CE330 /* FromString.swift */, - E19E54FC28972B97003CE330 /* EscapeSequences.swift */, - E19E54FD28972B97003CE330 /* ColourProbes.swift */, - E19E54FE28972B97003CE330 /* ToString.swift */, - E19E54FF28972B97003CE330 /* ToUIImage.swift */, - E19E550028972B97003CE330 /* FromUIImage.swift */, - E19E550228972B97003CE330 /* Generation.swift */, - E19E550328972B97003CE330 /* TupleMaths.swift */, - ); - path = BlurHashKit; - sourceTree = ""; - }; E1A16C9328875F2F00EA4679 /* Objects */ = { isa = PBXGroup; children = ( @@ -2179,11 +2133,13 @@ E12186DD2718F1C50010884C /* Defaults */, E1218C9D271A2CD600EA0737 /* CombineExt */, E178857C278037FD0094FBCF /* JellyfinAPI */, - E1AE8E7D2789136D00FBDDAA /* Nuke */, - E11D83AE278FA998006E9776 /* NukeUI */, E1002B6A2793E36600E47059 /* Algorithms */, E1347DB5279E3CA500BC6161 /* Puppy */, C409CE9B284EA6EA00CABC12 /* SwiftUICollection */, + E13AF3B528A0C598009093AB /* Nuke */, + E13AF3B728A0C598009093AB /* NukeExtensions */, + E13AF3B928A0C598009093AB /* NukeUI */, + E13AF3BB28A0C59E009093AB /* BlurHashKit */, ); productName = "JellyfinPlayer tvOS"; productReference = 535870602669D21600D05A09 /* Swiftfin tvOS.app */; @@ -2216,13 +2172,14 @@ E1B6DCE9271A23880015B715 /* SwiftyJSON */, E10EAA44277BB646000269ED /* JellyfinAPI */, E10EAA4C277BB716000269ED /* Sliders */, - E1AE8E7B2789135A00FBDDAA /* Nuke */, - E1361DA6278FA7A300BEC523 /* NukeUI */, E1002B672793CFBA00E47059 /* Algorithms */, 62666E3827E502CE00EC0ECD /* SwizzleSwift */, E1101176281B1E8A006A3584 /* Puppy */, C4D0CE4A2848570700345D11 /* ASCollectionView */, C409CE9D285044C800CABC12 /* SwiftUICollection */, + E19E6E0428A0B958005C10C8 /* Nuke */, + E19E6E0628A0B958005C10C8 /* NukeUI */, + E19E6E0928A0BEFF005C10C8 /* BlurHashKit */, ); productName = JellyfinPlayer; productReference = 5377CBF1263B596A003A4E83 /* Swiftfin iOS.app */; @@ -2282,13 +2239,13 @@ E1C16B89271A2180009A5D25 /* XCRemoteSwiftPackageReference "SwiftyJSON" */, E10EAA43277BB646000269ED /* XCRemoteSwiftPackageReference "jellyfin-sdk-swift" */, E10EAA4B277BB716000269ED /* XCRemoteSwiftPackageReference "swiftui-sliders" */, - E1AE8E7A2789135A00FBDDAA /* XCRemoteSwiftPackageReference "Nuke" */, - E1361DA5278FA7A300BEC523 /* XCRemoteSwiftPackageReference "NukeUI" */, E1002B662793CFBA00E47059 /* XCRemoteSwiftPackageReference "swift-algorithms" */, 62666E3727E502CE00EC0ECD /* XCRemoteSwiftPackageReference "SwizzleSwift" */, E1101175281B1E8A006A3584 /* XCRemoteSwiftPackageReference "Puppy" */, C4D0CE492848570700345D11 /* XCRemoteSwiftPackageReference "ASCollectionView" */, C409CE9A284EA6EA00CABC12 /* XCRemoteSwiftPackageReference "SwiftUICollection" */, + E19E6E0328A0B958005C10C8 /* XCRemoteSwiftPackageReference "Nuke" */, + E19E6E0828A0BEFF005C10C8 /* XCRemoteSwiftPackageReference "BlurHashKit" */, ); productRefGroup = 5377CBF2263B596A003A4E83 /* Products */; projectDirPath = ""; @@ -2413,7 +2370,6 @@ E1A2C15A279A7D76005EC829 /* BundleExtensions.swift in Sources */, C40CD929271F8DAB000FB198 /* MovieLibrariesView.swift in Sources */, C4E5081D2703F8370045C9AB /* LibrarySearchView.swift in Sources */, - E19E550728972B97003CE330 /* BlurHash.swift in Sources */, 53ABFDE9267974EF00886593 /* HomeViewModel.swift in Sources */, E13DD3F027178F87009D4DAF /* SwiftfinNotificationCenter.swift in Sources */, E1A16CA1288A7CFD00EA4679 /* AboutViewCard.swift in Sources */, @@ -2431,7 +2387,6 @@ E193D53527193F8100900D82 /* ItemCoordinator.swift in Sources */, E1C926162887565C002A7A66 /* SeriesItemView.swift in Sources */, E1EBCB4A278BE443009FE6E9 /* ItemOverviewCoordinator.swift in Sources */, - E19E550928972B97003CE330 /* StringCoding.swift in Sources */, C4BE07772725EBEA003F4AD1 /* LiveTVProgramsViewModel.swift in Sources */, E11CEB9128999D84003E74C7 /* EpisodeItemView.swift in Sources */, E1C9260C2887565C002A7A66 /* MovieItemContentView.swift in Sources */, @@ -2469,16 +2424,13 @@ E1C925F528875037002A7A66 /* ItemViewType.swift in Sources */, 535870A82669D8AE00D05A09 /* StringExtensions.swift in Sources */, 53A83C33268A309300DF3D92 /* LibraryView.swift in Sources */, - E19E550B28972B97003CE330 /* FromString.swift in Sources */, 62E632ED267D410B0063E547 /* SeriesItemViewModel.swift in Sources */, 5398514526B64DA100101B49 /* SettingsView.swift in Sources */, 62E632F0267D43320063E547 /* LibraryFilterViewModel.swift in Sources */, E193D54B271941D300900D82 /* ServerListView.swift in Sources */, 53ABFDE6267974EF00886593 /* SettingsViewModel.swift in Sources */, C400DB6B27FE8C97007B65FE /* LiveTVChannelItemElement.swift in Sources */, - E19E551928972B97003CE330 /* Generation.swift in Sources */, 62E632F4267D54030063E547 /* ItemViewModel.swift in Sources */, - E19E550F28972B97003CE330 /* ColourProbes.swift in Sources */, 6267B3D826710B9800A7371D /* CollectionExtensions.swift in Sources */, 62E632E7267D3F5B0063E547 /* EpisodeItemViewModel.swift in Sources */, E1C926122887565C002A7A66 /* SeriesItemContentView.swift in Sources */, @@ -2490,12 +2442,10 @@ E103A6A0278A7E4500820EC7 /* UICinematicBackgroundView.swift in Sources */, E11CEB9428999D9E003E74C7 /* EpisodeItemContentView.swift in Sources */, E17885A02780F55C0094FBCF /* tvOSVLCOverlay.swift in Sources */, - E19E551328972B97003CE330 /* ToUIImage.swift in Sources */, E1BDE359278E9ED2004E4022 /* MissingItemsSettingsView.swift in Sources */, E193D54D2719426600900D82 /* LibraryFilterView.swift in Sources */, C4BE07892728448B003F4AD1 /* LiveTVChannelsCoordinator.swift in Sources */, E193D53927193F8E00900D82 /* SearchCoordinator.swift in Sources */, - E19E551128972B97003CE330 /* ToString.swift in Sources */, C4BE078C272844AF003F4AD1 /* LiveTVChannelsView.swift in Sources */, E1D4BF852719D25A00A11E64 /* TrackLanguage.swift in Sources */, E1C926142887565C002A7A66 /* FocusGuide.swift in Sources */, @@ -2555,7 +2505,6 @@ E13DD3C927164B1E009D4DAF /* UIDeviceExtensions.swift in Sources */, E193D53A27193F9000900D82 /* ServerListCoordinator.swift in Sources */, 6220D0AE26D5EABB00B8E046 /* ViewExtensions.swift in Sources */, - E19E551528972B97003CE330 /* FromUIImage.swift in Sources */, E11895B42893844A0042947B /* BackgroundParallaxHeaderModifier.swift in Sources */, 5321753E2671DE9C005491E6 /* Typings.swift in Sources */, E1C812CA277AE40900918266 /* PlayerOverlayDelegate.swift in Sources */, @@ -2565,7 +2514,6 @@ 53ABFDEB2679753200886593 /* ConnectToServerView.swift in Sources */, E1C9260D2887565C002A7A66 /* CinematicScrollView.swift in Sources */, 6264E88D273850380081A12A /* Strings.swift in Sources */, - E19E550D28972B97003CE330 /* EscapeSequences.swift in Sources */, E1C926102887565C002A7A66 /* PlayButton.swift in Sources */, E193D5512719432400900D82 /* ServerDetailViewModel.swift in Sources */, C4E5081B2703F82A0045C9AB /* LibraryListView.swift in Sources */, @@ -2575,7 +2523,6 @@ E10D87E327852FD000BD264C /* EpisodesRowManager.swift in Sources */, 535870632669D21600D05A09 /* JellyfinPlayer_tvOSApp.swift in Sources */, E1D4BF8F271A079A00A11E64 /* BasicAppSettingsView.swift in Sources */, - E19E550528972B97003CE330 /* ColourSpace.swift in Sources */, E193D547271941C500900D82 /* UserListView.swift in Sources */, E1C926152887565C002A7A66 /* EpisodeCard.swift in Sources */, E1D4BF7F2719D1DD00A11E64 /* BasicAppSettingsViewModel.swift in Sources */, @@ -2585,7 +2532,6 @@ 5364F456266CA0DC0026ECBA /* BaseItemPersonExtensions.swift in Sources */, E1937A62288F32DB00CB80AA /* Poster.swift in Sources */, C4BE0764271FC0BB003F4AD1 /* TVLibrariesCoordinator.swift in Sources */, - E19E551B28972B97003CE330 /* TupleMaths.swift in Sources */, E1E5D5512783E67700692DFE /* ExperimentalSettingsView.swift in Sources */, E1A2C160279A7DCA005EC829 /* AboutAppView.swift in Sources */, C4BE076A271FC164003F4AD1 /* TVLibrariesView.swift in Sources */, @@ -2628,14 +2574,11 @@ E18E0208288749200022598C /* BlurView.swift in Sources */, E18E01E7288747230022598C /* CollectionItemContentView.swift in Sources */, 53F866442687A45F00DCD1D7 /* PortraitPosterButton.swift in Sources */, - E19E551A28972B97003CE330 /* TupleMaths.swift in Sources */, E18E01DF288747230022598C /* iPadOSMovieItemView.swift in Sources */, E168BD13289A4162001A6922 /* ContinueWatchingView.swift in Sources */, - E19E550C28972B97003CE330 /* EscapeSequences.swift in Sources */, C45942CD27F6994A00C54FE7 /* LiveTVPlayerView.swift in Sources */, 62C29EA126D102A500C1D2E7 /* iOSMainTabCoordinator.swift in Sources */, E18E01E8288747230022598C /* SeriesItemContentView.swift in Sources */, - E19E550428972B97003CE330 /* ColourSpace.swift in Sources */, E18E01E5288747230022598C /* CinematicScrollView.swift in Sources */, E1C812C0277A8E5D00918266 /* VLCPlayerView.swift in Sources */, E176DE6D278E30D2001EFD8D /* EpisodeCard.swift in Sources */, @@ -2668,7 +2611,6 @@ 62133890265F83A900A81A2A /* LibraryListView.swift in Sources */, 62C29EA326D1030F00C1D2E7 /* ConnectToServerCoodinator.swift in Sources */, E1047E2027E584AF00CB0D4A /* BlurHashView.swift in Sources */, - E19E551028972B97003CE330 /* ToString.swift in Sources */, E18E01E1288747230022598C /* EpisodeItemContentView.swift in Sources */, 62E632DA267D2BC40063E547 /* LatestMediaViewModel.swift in Sources */, C400DB6A27FE894F007B65FE /* LiveTVChannelsView.swift in Sources */, @@ -2690,7 +2632,6 @@ 6264E88C273850380081A12A /* Strings.swift in Sources */, C4AE2C3227498D6A00AE13CF /* LiveTVProgramsView.swift in Sources */, 62ECA01826FA685A00E8EBB7 /* DeepLink.swift in Sources */, - E19E550A28972B97003CE330 /* FromString.swift in Sources */, 62E632E6267D3F5B0063E547 /* EpisodeItemViewModel.swift in Sources */, 5321753B2671BCFC005491E6 /* SettingsViewModel.swift in Sources */, E107BB9327880A8F00354E07 /* CollectionItemViewModel.swift in Sources */, @@ -2701,7 +2642,6 @@ E11895A9289383BC0042947B /* ScrollViewOffsetModifier.swift in Sources */, E1C812C3277A8E5D00918266 /* VLCPlayerOverlayView.swift in Sources */, E18E01F0288747230022598C /* AttributeHStack.swift in Sources */, - E19E551228972B97003CE330 /* ToUIImage.swift in Sources */, 6334175B287DDFB9000603CE /* QuickConnectSettingsView.swift in Sources */, E18E0205288749200022598C /* AppIcon.swift in Sources */, E168BD10289A4162001A6922 /* HomeView.swift in Sources */, @@ -2727,10 +2667,7 @@ E11895AC289383EE0042947B /* NavBarOffsetModifier.swift in Sources */, E13DD3FC2717EAE8009D4DAF /* UserListView.swift in Sources */, E18E01DE288747230022598C /* iPadOSSeriesItemView.swift in Sources */, - E19E550828972B97003CE330 /* StringCoding.swift in Sources */, - E19E551428972B97003CE330 /* FromUIImage.swift in Sources */, 6220D0CC26D640C400B8E046 /* AppURLHandler.swift in Sources */, - E19E550628972B97003CE330 /* BlurHash.swift in Sources */, 53DE4BD2267098F300739748 /* SearchBarView.swift in Sources */, E1E48CC9271E6D410021A2F9 /* RefreshHelper.swift in Sources */, 631759CF2879DB6A00A621AD /* PublicUserSignInCellView.swift in Sources */, @@ -2791,11 +2728,9 @@ E13DD3D5271693CD009D4DAF /* SwiftfinStoreDefaults.swift in Sources */, 62E1DCC3273CE19800C9AE76 /* URLExtensions.swift in Sources */, E1267D3E271A1F46003C492E /* PreferenceUIHostingController.swift in Sources */, - E19E551828972B97003CE330 /* Generation.swift in Sources */, E18E01E6288747230022598C /* CollectionItemView.swift in Sources */, 6220D0BA26D6092100B8E046 /* FilterCoordinator.swift in Sources */, E1E5D54C2783E27200692DFE /* ExperimentalSettingsView.swift in Sources */, - E19E550E28972B97003CE330 /* ColourProbes.swift in Sources */, E1E00A35278628A40022235B /* DoubleExtensions.swift in Sources */, 62EC353426766B03000E9F2D /* DeviceRotationViewModifier.swift in Sources */, E1D4BF8A2719D3D000A11E64 /* BasicAppSettingsCoordinator.swift in Sources */, @@ -3328,14 +3263,6 @@ kind = branch; }; }; - E1361DA5278FA7A300BEC523 /* XCRemoteSwiftPackageReference "NukeUI" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/kean/NukeUI"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 0.7.0; - }; - }; E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/JohnEstropia/CoreStore.git"; @@ -3352,12 +3279,20 @@ minimumVersion = 6.0.0; }; }; - E1AE8E7A2789135A00FBDDAA /* XCRemoteSwiftPackageReference "Nuke" */ = { + E19E6E0328A0B958005C10C8 /* XCRemoteSwiftPackageReference "Nuke" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/kean/Nuke"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 10.0.0; + minimumVersion = 11.1.0; + }; + }; + E19E6E0828A0BEFF005C10C8 /* XCRemoteSwiftPackageReference "BlurHashKit" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/LePips/BlurHashKit"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; }; }; E1C16B89271A2180009A5D25 /* XCRemoteSwiftPackageReference "SwiftyJSON" */ = { @@ -3446,11 +3381,6 @@ package = E1101175281B1E8A006A3584 /* XCRemoteSwiftPackageReference "Puppy" */; productName = Puppy; }; - E11D83AE278FA998006E9776 /* NukeUI */ = { - isa = XCSwiftPackageProductDependency; - package = E1361DA5278FA7A300BEC523 /* XCRemoteSwiftPackageReference "NukeUI" */; - productName = NukeUI; - }; E12186DD2718F1C50010884C /* Defaults */ = { isa = XCSwiftPackageProductDependency; package = E13DD3D127168E65009D4DAF /* XCRemoteSwiftPackageReference "Defaults" */; @@ -3471,11 +3401,26 @@ package = E1347DB0279E3C6200BC6161 /* XCRemoteSwiftPackageReference "Puppy" */; productName = Puppy; }; - E1361DA6278FA7A300BEC523 /* NukeUI */ = { + E13AF3B528A0C598009093AB /* Nuke */ = { isa = XCSwiftPackageProductDependency; - package = E1361DA5278FA7A300BEC523 /* XCRemoteSwiftPackageReference "NukeUI" */; + package = E19E6E0328A0B958005C10C8 /* XCRemoteSwiftPackageReference "Nuke" */; + productName = Nuke; + }; + E13AF3B728A0C598009093AB /* NukeExtensions */ = { + isa = XCSwiftPackageProductDependency; + package = E19E6E0328A0B958005C10C8 /* XCRemoteSwiftPackageReference "Nuke" */; + productName = NukeExtensions; + }; + E13AF3B928A0C598009093AB /* NukeUI */ = { + isa = XCSwiftPackageProductDependency; + package = E19E6E0328A0B958005C10C8 /* XCRemoteSwiftPackageReference "Nuke" */; productName = NukeUI; }; + E13AF3BB28A0C59E009093AB /* BlurHashKit */ = { + isa = XCSwiftPackageProductDependency; + package = E19E6E0828A0BEFF005C10C8 /* XCRemoteSwiftPackageReference "BlurHashKit" */; + productName = BlurHashKit; + }; E13DD3C52716499E009D4DAF /* CoreStore */ = { isa = XCSwiftPackageProductDependency; package = E13DD3C42716499E009D4DAF /* XCRemoteSwiftPackageReference "CoreStore" */; @@ -3496,15 +3441,20 @@ package = E10EAA43277BB646000269ED /* XCRemoteSwiftPackageReference "jellyfin-sdk-swift" */; productName = JellyfinAPI; }; - E1AE8E7B2789135A00FBDDAA /* Nuke */ = { + E19E6E0428A0B958005C10C8 /* Nuke */ = { isa = XCSwiftPackageProductDependency; - package = E1AE8E7A2789135A00FBDDAA /* XCRemoteSwiftPackageReference "Nuke" */; + package = E19E6E0328A0B958005C10C8 /* XCRemoteSwiftPackageReference "Nuke" */; productName = Nuke; }; - E1AE8E7D2789136D00FBDDAA /* Nuke */ = { + E19E6E0628A0B958005C10C8 /* NukeUI */ = { isa = XCSwiftPackageProductDependency; - package = E1AE8E7A2789135A00FBDDAA /* XCRemoteSwiftPackageReference "Nuke" */; - productName = Nuke; + package = E19E6E0328A0B958005C10C8 /* XCRemoteSwiftPackageReference "Nuke" */; + productName = NukeUI; + }; + E19E6E0928A0BEFF005C10C8 /* BlurHashKit */ = { + isa = XCSwiftPackageProductDependency; + package = E19E6E0828A0BEFF005C10C8 /* XCRemoteSwiftPackageReference "BlurHashKit" */; + productName = BlurHashKit; }; E1B6DCE7271A23780015B715 /* CombineExt */ = { isa = XCSwiftPackageProductDependency; diff --git a/Swiftfin.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Swiftfin.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 82b35677..f928dca4 100644 --- a/Swiftfin.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Swiftfin.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -27,6 +27,15 @@ "version" : "2.1.1" } }, + { + "identity" : "blurhashkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/LePips/BlurHashKit", + "state" : { + "revision" : "ee9f34f4f8fc03f3d67622e2a6eeb65f5108f2a3", + "version" : "1.0.0" + } + }, { "identity" : "combineext", "kind" : "remoteSourceControl", @@ -63,15 +72,6 @@ "version" : "1.3.0" } }, - { - "identity" : "gifu", - "kind" : "remoteSourceControl", - "location" : "https://github.com/kaishin/Gifu", - "state" : { - "revision" : "51f2eab32903e336f590c013267cfa4d7f8b06c4", - "version" : "3.3.1" - } - }, { "identity" : "jellyfin-sdk-swift", "kind" : "remoteSourceControl", @@ -86,17 +86,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/kean/Nuke", "state" : { - "revision" : "a002b7fd786f2df2ed4333fe73a9727499fd9d97", - "version" : "10.11.2" - } - }, - { - "identity" : "nukeui", - "kind" : "remoteSourceControl", - "location" : "https://github.com/kean/NukeUI", - "state" : { - "revision" : "db55022a8e483774ebbf3568727071477546d9ea", - "version" : "0.8.3" + "revision" : "8ea514737c2011ff7d7544aa065ad44905bdae0b", + "version" : "11.1.0" } }, { diff --git a/Swiftfin/Views/HomeView/Components/ContinueWatchingView/ContinueWatchingView.swift b/Swiftfin/Views/HomeView/Components/ContinueWatchingView/ContinueWatchingView.swift index 210a044e..74c67bc1 100644 --- a/Swiftfin/Views/HomeView/Components/ContinueWatchingView/ContinueWatchingView.swift +++ b/Swiftfin/Views/HomeView/Components/ContinueWatchingView/ContinueWatchingView.swift @@ -7,7 +7,6 @@ // import JellyfinAPI -import NukeUI import SwiftUI struct ContinueWatchingView: View { diff --git a/Swiftfin/Views/ItemView/iOS/ScrollViews/CinematicScrollView.swift b/Swiftfin/Views/ItemView/iOS/ScrollViews/CinematicScrollView.swift index 85dd9336..7298b88f 100644 --- a/Swiftfin/Views/ItemView/iOS/ScrollViews/CinematicScrollView.swift +++ b/Swiftfin/Views/ItemView/iOS/ScrollViews/CinematicScrollView.swift @@ -6,6 +6,7 @@ // Copyright (c) 2022 Jellyfin & Jellyfin Contributors // +import BlurHashKit import SwiftUI extension ItemView { diff --git a/Swiftfin/Views/ItemView/iOS/ScrollViews/CompactLogoScrollView.swift b/Swiftfin/Views/ItemView/iOS/ScrollViews/CompactLogoScrollView.swift index e62a003e..a6c60f48 100644 --- a/Swiftfin/Views/ItemView/iOS/ScrollViews/CompactLogoScrollView.swift +++ b/Swiftfin/Views/ItemView/iOS/ScrollViews/CompactLogoScrollView.swift @@ -6,6 +6,7 @@ // Copyright (c) 2022 Jellyfin & Jellyfin Contributors // +import BlurHashKit import SwiftUI extension ItemView { diff --git a/Swiftfin/Views/ItemView/iOS/ScrollViews/CompactPortraitScrollView.swift b/Swiftfin/Views/ItemView/iOS/ScrollViews/CompactPortraitScrollView.swift index 40f55ff9..fe460c38 100644 --- a/Swiftfin/Views/ItemView/iOS/ScrollViews/CompactPortraitScrollView.swift +++ b/Swiftfin/Views/ItemView/iOS/ScrollViews/CompactPortraitScrollView.swift @@ -6,6 +6,7 @@ // Copyright (c) 2022 Jellyfin & Jellyfin Contributors // +import BlurHashKit import SwiftUI extension ItemView {