mirror of
https://github.com/yattee/yattee.git
synced 2025-12-16 21:18:16 +00:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3369e23e74 | ||
|
|
4381511c91 | ||
|
|
af99df9b8a | ||
|
|
21f21cc944 | ||
|
|
e1d8bb8125 | ||
|
|
d948ea6887 | ||
|
|
66eb8051bf | ||
|
|
95d3170d31 | ||
|
|
74b6adb247 | ||
|
|
a45522f710 |
25
CHANGELOG.md
25
CHANGELOG.md
@@ -1,15 +1,8 @@
|
|||||||
## Build 189
|
## Build 190
|
||||||
* Improved thumbnail handling by @stonerl in https://github.com/yattee/yattee/pull/740
|
* Improved stream resolution handling by @stonerl in https://github.com/yattee/yattee/pull/747
|
||||||
* iOS: make timestamps in comments touchable by @stonerl in https://github.com/yattee/yattee/pull/741
|
* Fix some potential crashes by @stonerl in https://github.com/yattee/yattee/pull/748
|
||||||
* Improvements to opening channels from Videos by @stonerl in https://github.com/yattee/yattee/pull/742
|
* Fix regression and improve curentChapter handling by @stonerl in https://github.com/yattee/yattee/pull/749
|
||||||
* Allow hiding comments by @stonerl in https://github.com/yattee/yattee/pull/744
|
* Refined chapter font scaling by @stonerl in https://github.com/yattee/yattee/pull/750
|
||||||
* Add option to exit fullscreen on end by @stonerl in https://github.com/yattee/yattee/pull/570
|
|
||||||
* Only updateWatch status while video is playing by @stonerl in https://github.com/yattee/yattee/pull/745
|
|
||||||
* Xcode 16 - update recommended settings by @stonerl in https://github.com/yattee/yattee/pull/737
|
|
||||||
* Translations update from Hosted Weblate by @weblate in https://github.com/yattee/yattee/pull/724
|
|
||||||
* Updated dependencies
|
|
||||||
* Fixed crashes
|
|
||||||
* Other minor changes and improvements
|
|
||||||
|
|
||||||
## Previous builds
|
## Previous builds
|
||||||
* Add skip, play/pause, and fullscreen shortcuts to macOS player (by @rickykresslein)
|
* Add skip, play/pause, and fullscreen shortcuts to macOS player (by @rickykresslein)
|
||||||
@@ -28,6 +21,14 @@
|
|||||||
* Add import export of missing settings
|
* Add import export of missing settings
|
||||||
* macOS: Fix settings windows layout
|
* macOS: Fix settings windows layout
|
||||||
* Fix seek OSD layout on tvOS, revert OSD position
|
* Fix seek OSD layout on tvOS, revert OSD position
|
||||||
|
* Improved thumbnail handling by @stonerl in https://github.com/yattee/yattee/pull/740
|
||||||
|
* iOS: make timestamps in comments touchable by @stonerl in https://github.com/yattee/yattee/pull/741
|
||||||
|
* Improvements to opening channels from Videos by @stonerl in https://github.com/yattee/yattee/pull/742
|
||||||
|
* Allow hiding comments by @stonerl in https://github.com/yattee/yattee/pull/744
|
||||||
|
* Add option to exit fullscreen on end by @stonerl in https://github.com/yattee/yattee/pull/570
|
||||||
|
* Only updateWatch status while video is playing by @stonerl in https://github.com/yattee/yattee/pull/745
|
||||||
|
* Xcode 16 - update recommended settings by @stonerl in https://github.com/yattee/yattee/pull/737
|
||||||
|
* Translations update from Hosted Weblate by @weblate in https://github.com/yattee/yattee/pull/724
|
||||||
* tvOS: Allow account picker by long pressing channels button in subscriptions view by @patelhiren in https://github.com/yattee/yattee/pull/704
|
* tvOS: Allow account picker by long pressing channels button in subscriptions view by @patelhiren in https://github.com/yattee/yattee/pull/704
|
||||||
* tvOS: Refined Subscriptions View by @patelhiren in https://github.com/yattee/yattee/pull/697
|
* tvOS: Refined Subscriptions View by @patelhiren in https://github.com/yattee/yattee/pull/697
|
||||||
* More responsive UI when Favorites are used. by @stonerl in https://github.com/yattee/yattee/pull/695
|
* More responsive UI when Favorites are used. by @stonerl in https://github.com/yattee/yattee/pull/695
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import Foundation
|
|||||||
|
|
||||||
final class MenuModel: ObservableObject {
|
final class MenuModel: ObservableObject {
|
||||||
static let shared = MenuModel()
|
static let shared = MenuModel()
|
||||||
private var cancellables = [AnyCancellable]()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
registerChildModel(AccountsModel.shared)
|
registerChildModel(AccountsModel.shared)
|
||||||
@@ -12,10 +12,16 @@ final class MenuModel: ObservableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func registerChildModel<T: ObservableObject>(_ model: T?) {
|
func registerChildModel<T: ObservableObject>(_ model: T?) {
|
||||||
guard !model.isNil else {
|
guard let model else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
cancellables.append(model!.objectWillChange.sink { [weak self] _ in self?.objectWillChange.send() })
|
model.objectWillChange
|
||||||
|
.receive(on: DispatchQueue.main) // Ensure the update occurs on the main thread
|
||||||
|
.debounce(for: .milliseconds(10), scheduler: DispatchQueue.main) // Debounce to avoid immediate feedback loops
|
||||||
|
.sink { [weak self] _ in
|
||||||
|
self?.objectWillChange.send()
|
||||||
|
}
|
||||||
|
.store(in: &cancellables)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -464,6 +464,8 @@ final class MPVBackend: PlayerBackend {
|
|||||||
timeObserverThrottle.execute {
|
timeObserverThrottle.execute {
|
||||||
self.model.updateWatch(time: self.currentTime)
|
self.model.updateWatch(time: self.currentTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.model.updateTime(self.currentTime!)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func stopClientUpdates() {
|
private func stopClientUpdates() {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import CoreMedia
|
import CoreMedia
|
||||||
import Defaults
|
import Defaults
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import Logging
|
||||||
#if !os(macOS)
|
#if !os(macOS)
|
||||||
import UIKit
|
import UIKit
|
||||||
#endif
|
#endif
|
||||||
@@ -75,6 +76,10 @@ protocol PlayerBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension PlayerBackend {
|
extension PlayerBackend {
|
||||||
|
var logger: Logger {
|
||||||
|
return Logger(label: "stream.yattee.player.backend")
|
||||||
|
}
|
||||||
|
|
||||||
func seek(to time: CMTime, seekType: SeekType, completionHandler: ((Bool) -> Void)? = nil) {
|
func seek(to time: CMTime, seekType: SeekType, completionHandler: ((Bool) -> Void)? = nil) {
|
||||||
model.seek.registerSeek(at: time, type: seekType, restore: currentTime)
|
model.seek.registerSeek(at: time, type: seekType, restore: currentTime)
|
||||||
seek(to: time, seekType: seekType, completionHandler: completionHandler)
|
seek(to: time, seekType: seekType, completionHandler: completionHandler)
|
||||||
@@ -140,55 +145,87 @@ extension PlayerBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func bestPlayable(_ streams: [Stream], maxResolution: ResolutionSetting, formatOrder: [QualityProfile.Format]) -> Stream? {
|
func bestPlayable(_ streams: [Stream], maxResolution: ResolutionSetting, formatOrder: [QualityProfile.Format]) -> Stream? {
|
||||||
// filter out non-HLS streams and streams with resolution more than maxResolution
|
logger.info("Starting bestPlayable function")
|
||||||
let nonHLSStreams = streams.filter {
|
logger.info("Total streams received: \(streams.count)")
|
||||||
$0.kind != .hls && $0.resolution <= maxResolution.value
|
logger.info("Max resolution allowed: \(String(describing: maxResolution.value))")
|
||||||
}
|
logger.info("Format order: \(formatOrder)")
|
||||||
|
|
||||||
// find max resolution and bitrate from non-HLS streams
|
// Filter out non-HLS streams and streams with resolution more than maxResolution
|
||||||
|
let nonHLSStreams = streams.filter {
|
||||||
|
let isHLS = $0.kind == .hls
|
||||||
|
let isWithinResolution = $0.resolution <= maxResolution.value
|
||||||
|
logger.info("Stream ID: \($0.id) - Kind: \(String(describing: $0.kind)) - Resolution: \(String(describing: $0.resolution)) - Bitrate: \($0.bitrate ?? 0)")
|
||||||
|
logger.info("Is HLS: \(isHLS), Is within resolution: \(isWithinResolution)")
|
||||||
|
return !isHLS && isWithinResolution
|
||||||
|
}
|
||||||
|
logger.info("Non-HLS streams after filtering: \(nonHLSStreams.count)")
|
||||||
|
|
||||||
|
// Find max resolution and bitrate from non-HLS streams
|
||||||
let bestResolutionStream = nonHLSStreams.max { $0.resolution < $1.resolution }
|
let bestResolutionStream = nonHLSStreams.max { $0.resolution < $1.resolution }
|
||||||
let bestBitrateStream = nonHLSStreams.max { $0.bitrate ?? 0 < $1.bitrate ?? 0 }
|
let bestBitrateStream = nonHLSStreams.max { $0.bitrate ?? 0 < $1.bitrate ?? 0 }
|
||||||
|
|
||||||
|
logger.info("Best resolution stream: \(String(describing: bestResolutionStream?.id)) with resolution: \(String(describing: bestResolutionStream?.resolution))")
|
||||||
|
logger.info("Best bitrate stream: \(String(describing: bestBitrateStream?.id)) with bitrate: \(String(describing: bestBitrateStream?.bitrate))")
|
||||||
|
|
||||||
let bestResolution = bestResolutionStream?.resolution ?? maxResolution.value
|
let bestResolution = bestResolutionStream?.resolution ?? maxResolution.value
|
||||||
let bestBitrate = bestBitrateStream?.bitrate ?? bestResolutionStream?.resolution.bitrate ?? maxResolution.value.bitrate
|
let bestBitrate = bestBitrateStream?.bitrate ?? bestResolutionStream?.resolution.bitrate ?? maxResolution.value.bitrate
|
||||||
|
|
||||||
return streams.map { stream in
|
logger.info("Final best resolution selected: \(String(describing: bestResolution))")
|
||||||
|
logger.info("Final best bitrate selected: \(bestBitrate)")
|
||||||
|
|
||||||
|
let adjustedStreams = streams.map { stream in
|
||||||
if stream.kind == .hls {
|
if stream.kind == .hls {
|
||||||
|
logger.info("Adjusting HLS stream ID: \(stream.id)")
|
||||||
stream.resolution = bestResolution
|
stream.resolution = bestResolution
|
||||||
stream.bitrate = bestBitrate
|
stream.bitrate = bestBitrate
|
||||||
stream.format = .hls
|
stream.format = .hls
|
||||||
} else if stream.kind == .stream {
|
} else if stream.kind == .stream {
|
||||||
|
logger.info("Adjusting non-HLS stream ID: \(stream.id)")
|
||||||
stream.format = .stream
|
stream.format = .stream
|
||||||
}
|
}
|
||||||
return stream
|
return stream
|
||||||
}
|
}
|
||||||
.filter { stream in
|
|
||||||
stream.resolution <= maxResolution.value
|
let filteredStreams = adjustedStreams.filter { stream in
|
||||||
|
let isWithinResolution = stream.resolution <= maxResolution.value
|
||||||
|
logger.info("Filtered stream ID: \(stream.id) - Is within max resolution: \(isWithinResolution)")
|
||||||
|
return isWithinResolution
|
||||||
}
|
}
|
||||||
.max { lhs, rhs in
|
|
||||||
|
logger.info("Filtered streams count after adjustments: \(filteredStreams.count)")
|
||||||
|
|
||||||
|
let bestStream = filteredStreams.max { lhs, rhs in
|
||||||
if lhs.resolution == rhs.resolution {
|
if lhs.resolution == rhs.resolution {
|
||||||
guard let lhsFormat = QualityProfile.Format(rawValue: lhs.format.rawValue),
|
guard let lhsFormat = QualityProfile.Format(rawValue: lhs.format.rawValue),
|
||||||
let rhsFormat = QualityProfile.Format(rawValue: rhs.format.rawValue)
|
let rhsFormat = QualityProfile.Format(rawValue: rhs.format.rawValue)
|
||||||
else {
|
else {
|
||||||
print("Failed to extract lhsFormat or rhsFormat")
|
logger.info("Failed to extract lhsFormat or rhsFormat for streams \(lhs.id) and \(rhs.id)")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
let lhsFormatIndex = formatOrder.firstIndex(of: lhsFormat) ?? Int.max
|
let lhsFormatIndex = formatOrder.firstIndex(of: lhsFormat) ?? Int.max
|
||||||
let rhsFormatIndex = formatOrder.firstIndex(of: rhsFormat) ?? Int.max
|
let rhsFormatIndex = formatOrder.firstIndex(of: rhsFormat) ?? Int.max
|
||||||
|
|
||||||
|
logger.info("Comparing formats for streams \(lhs.id) and \(rhs.id) - LHS Format Index: \(lhsFormatIndex), RHS Format Index: \(rhsFormatIndex)")
|
||||||
|
|
||||||
return lhsFormatIndex > rhsFormatIndex
|
return lhsFormatIndex > rhsFormatIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.info("Comparing resolutions for streams \(lhs.id) and \(rhs.id) - LHS Resolution: \(String(describing: lhs.resolution)), RHS Resolution: \(String(describing: rhs.resolution))")
|
||||||
|
|
||||||
return lhs.resolution < rhs.resolution
|
return lhs.resolution < rhs.resolution
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.info("Best stream selected: \(String(describing: bestStream?.id)) with resolution: \(String(describing: bestStream?.resolution)) and format: \(String(describing: bestStream?.format))")
|
||||||
|
|
||||||
|
return bestStream
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateControls(completionHandler: (() -> Void)? = nil) {
|
func updateControls(completionHandler: (() -> Void)? = nil) {
|
||||||
print("updating controls")
|
logger.info("updating controls")
|
||||||
|
|
||||||
guard model.presentingPlayer, !model.controls.presentingOverlays else {
|
guard model.presentingPlayer, !model.controls.presentingOverlays else {
|
||||||
print("ignored controls update")
|
logger.info("ignored controls update")
|
||||||
completionHandler?()
|
completionHandler?()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -196,7 +233,7 @@ extension PlayerBackend {
|
|||||||
DispatchQueue.main.async(qos: .userInteractive) {
|
DispatchQueue.main.async(qos: .userInteractive) {
|
||||||
#if !os(macOS)
|
#if !os(macOS)
|
||||||
guard UIApplication.shared.applicationState != .background else {
|
guard UIApplication.shared.applicationState != .background else {
|
||||||
print("not performing controls updates in background")
|
logger.info("not performing controls updates in background")
|
||||||
completionHandler?()
|
completionHandler?()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,6 +127,7 @@ extension PlayerModel {
|
|||||||
var streamByQualityProfile: Stream? {
|
var streamByQualityProfile: Stream? {
|
||||||
let profile = qualityProfile ?? .defaultProfile
|
let profile = qualityProfile ?? .defaultProfile
|
||||||
|
|
||||||
|
// First attempt: Filter by both `canPlay` and `isPreferred`
|
||||||
if let streamPreferredForProfile = backend.bestPlayable(
|
if let streamPreferredForProfile = backend.bestPlayable(
|
||||||
availableStreams.filter { backend.canPlay($0) && profile.isPreferred($0) },
|
availableStreams.filter { backend.canPlay($0) && profile.isPreferred($0) },
|
||||||
maxResolution: profile.resolution, formatOrder: profile.formats
|
maxResolution: profile.resolution, formatOrder: profile.formats
|
||||||
@@ -134,7 +135,24 @@ extension PlayerModel {
|
|||||||
return streamPreferredForProfile
|
return streamPreferredForProfile
|
||||||
}
|
}
|
||||||
|
|
||||||
return backend.bestPlayable(availableStreams.filter { backend.canPlay($0) }, maxResolution: profile.resolution, formatOrder: profile.formats)
|
// Fallback: Filter by `canPlay` only
|
||||||
|
let fallbackStream = backend.bestPlayable(
|
||||||
|
availableStreams.filter { backend.canPlay($0) },
|
||||||
|
maxResolution: profile.resolution, formatOrder: profile.formats
|
||||||
|
)
|
||||||
|
|
||||||
|
// If no stream is found, trigger the error handler
|
||||||
|
guard let finalStream = fallbackStream else {
|
||||||
|
let error = RequestError(
|
||||||
|
userMessage: "No supported streams available.",
|
||||||
|
cause: NSError(domain: "stream.yatte.app", code: -1, userInfo: [NSLocalizedDescriptionKey: "No supported streams available"])
|
||||||
|
)
|
||||||
|
videoLoadFailureHandler(error, video: currentVideo)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the found stream
|
||||||
|
return finalStream
|
||||||
}
|
}
|
||||||
|
|
||||||
func advanceToNextItem() {
|
func advanceToNextItem() {
|
||||||
|
|||||||
@@ -5,26 +5,153 @@ import Foundation
|
|||||||
// swiftlint:disable:next final_class
|
// swiftlint:disable:next final_class
|
||||||
class Stream: Equatable, Hashable, Identifiable {
|
class Stream: Equatable, Hashable, Identifiable {
|
||||||
enum Resolution: String, CaseIterable, Comparable, Defaults.Serializable {
|
enum Resolution: String, CaseIterable, Comparable, Defaults.Serializable {
|
||||||
|
// Some 16:19 and 16:10 resolutions are also used in 2:1 videos
|
||||||
|
|
||||||
|
// 8K UHD (16:9) Resolutions
|
||||||
|
case hd4320p60
|
||||||
|
case hd4320p50
|
||||||
|
case hd4320p48
|
||||||
|
case hd4320p30
|
||||||
|
case hd4320p25
|
||||||
|
case hd4320p24
|
||||||
|
|
||||||
|
// 5K (16:9) Resolutions
|
||||||
|
case hd2560p60
|
||||||
|
case hd2560p50
|
||||||
|
case hd2560p48
|
||||||
|
case hd2560p30
|
||||||
|
case hd2560p25
|
||||||
|
case hd2560p24
|
||||||
|
|
||||||
|
// 2:1 Aspect Ratio (Univisium) Resolutions
|
||||||
|
case hd2880p60
|
||||||
|
case hd2880p50
|
||||||
|
case hd2880p48
|
||||||
|
case hd2880p30
|
||||||
|
case hd2880p25
|
||||||
|
case hd2880p24
|
||||||
|
|
||||||
|
// 16:10 Resolutions
|
||||||
|
case hd2400p60
|
||||||
|
case hd2400p50
|
||||||
|
case hd2400p48
|
||||||
|
case hd2400p30
|
||||||
|
case hd2400p25
|
||||||
|
case hd2400p24
|
||||||
|
|
||||||
|
// 16:9 Resolutions
|
||||||
case hd2160p60
|
case hd2160p60
|
||||||
case hd2160p50
|
case hd2160p50
|
||||||
case hd2160p48
|
case hd2160p48
|
||||||
case hd2160p30
|
case hd2160p30
|
||||||
|
case hd2160p25
|
||||||
|
case hd2160p24
|
||||||
|
|
||||||
|
// 16:10 Resolutions
|
||||||
|
case hd1600p60
|
||||||
|
case hd1600p50
|
||||||
|
case hd1600p48
|
||||||
|
case hd1600p30
|
||||||
|
case hd1600p25
|
||||||
|
case hd1600p24
|
||||||
|
|
||||||
|
// 16:9 Resolutions
|
||||||
case hd1440p60
|
case hd1440p60
|
||||||
case hd1440p50
|
case hd1440p50
|
||||||
case hd1440p48
|
case hd1440p48
|
||||||
case hd1440p30
|
case hd1440p30
|
||||||
|
case hd1440p25
|
||||||
|
case hd1440p24
|
||||||
|
|
||||||
|
// 16:10 Resolutions
|
||||||
|
case hd1280p60
|
||||||
|
case hd1280p50
|
||||||
|
case hd1280p48
|
||||||
|
case hd1280p30
|
||||||
|
case hd1280p25
|
||||||
|
case hd1280p24
|
||||||
|
|
||||||
|
// 16:10 Resolutions
|
||||||
|
case hd1200p60
|
||||||
|
case hd1200p50
|
||||||
|
case hd1200p48
|
||||||
|
case hd1200p30
|
||||||
|
case hd1200p25
|
||||||
|
case hd1200p24
|
||||||
|
|
||||||
|
// 16:9 Resolutions
|
||||||
case hd1080p60
|
case hd1080p60
|
||||||
case hd1080p50
|
case hd1080p50
|
||||||
case hd1080p48
|
case hd1080p48
|
||||||
case hd1080p30
|
case hd1080p30
|
||||||
|
case hd1080p25
|
||||||
|
case hd1080p24
|
||||||
|
|
||||||
|
// 16:10 Resolutions
|
||||||
|
case hd1050p60
|
||||||
|
case hd1050p50
|
||||||
|
case hd1050p48
|
||||||
|
case hd1050p30
|
||||||
|
case hd1050p25
|
||||||
|
case hd1050p24
|
||||||
|
|
||||||
|
// 16:9 Resolutions
|
||||||
|
case hd960p60
|
||||||
|
case hd960p50
|
||||||
|
case hd960p48
|
||||||
|
case hd960p30
|
||||||
|
case hd960p25
|
||||||
|
case hd960p24
|
||||||
|
|
||||||
|
// 16:10 Resolutions
|
||||||
|
case hd900p60
|
||||||
|
case hd900p50
|
||||||
|
case hd900p48
|
||||||
|
case hd900p30
|
||||||
|
case hd900p25
|
||||||
|
case hd900p24
|
||||||
|
|
||||||
|
// 16:10 Resolutions
|
||||||
|
case hd800p60
|
||||||
|
case hd800p50
|
||||||
|
case hd800p48
|
||||||
|
case hd800p30
|
||||||
|
case hd800p25
|
||||||
|
case hd800p24
|
||||||
|
|
||||||
|
// 16:9 Resolutions
|
||||||
case hd720p60
|
case hd720p60
|
||||||
case hd720p50
|
case hd720p50
|
||||||
case hd720p48
|
case hd720p48
|
||||||
case hd720p30
|
case hd720p30
|
||||||
|
case hd720p25
|
||||||
|
case hd720p24
|
||||||
|
|
||||||
|
// Standard Definition (SD) Resolutions
|
||||||
|
case sd854p30
|
||||||
|
case sd854p25
|
||||||
|
case sd768p30
|
||||||
|
case sd768p25
|
||||||
|
case sd640p30
|
||||||
|
case sd640p25
|
||||||
case sd480p30
|
case sd480p30
|
||||||
|
case sd480p25
|
||||||
|
|
||||||
|
case sd428p30
|
||||||
|
case sd428p25
|
||||||
case sd360p30
|
case sd360p30
|
||||||
|
case sd360p25
|
||||||
|
case sd320p30
|
||||||
|
case sd320p25
|
||||||
case sd240p30
|
case sd240p30
|
||||||
|
case sd240p25
|
||||||
|
case sd214p30
|
||||||
|
case sd214p25
|
||||||
case sd144p30
|
case sd144p30
|
||||||
|
case sd144p25
|
||||||
|
case sd128p30
|
||||||
|
case sd128p25
|
||||||
|
|
||||||
case unknown
|
case unknown
|
||||||
|
|
||||||
var name: String {
|
var name: String {
|
||||||
@@ -59,22 +186,94 @@ class Stream: Equatable, Hashable, Identifiable {
|
|||||||
|
|
||||||
var bitrate: Int {
|
var bitrate: Int {
|
||||||
switch self {
|
switch self {
|
||||||
case .hd2160p60, .hd2160p50, .hd2160p48, .hd2160p30:
|
// 8K UHD (16:9) Resolutions
|
||||||
|
case .hd4320p60, .hd4320p50, .hd4320p48, .hd4320p30, .hd4320p25, .hd4320p24:
|
||||||
|
return 85_000_000 // 85 Mbit/s
|
||||||
|
|
||||||
|
// 5K (16:9) Resolutions
|
||||||
|
case .hd2880p60, .hd2880p50, .hd2880p48, .hd2880p30, .hd2880p25, .hd2880p24:
|
||||||
|
return 45_000_000 // 45 Mbit/s
|
||||||
|
|
||||||
|
// 2:1 Aspect Ratio (Univisium) Resolutions
|
||||||
|
case .hd2560p60, .hd2560p50, .hd2560p48, .hd2560p30, .hd2560p25, .hd2560p24:
|
||||||
|
return 30_000_000 // 30 Mbit/s
|
||||||
|
|
||||||
|
// 16:10 Resolutions
|
||||||
|
case .hd2400p60, .hd2400p50, .hd2400p48, .hd2400p30, .hd2400p25, .hd2400p24:
|
||||||
|
return 35_000_000 // 35 Mbit/s
|
||||||
|
|
||||||
|
// 4K UHD (16:9) Resolutions
|
||||||
|
case .hd2160p60, .hd2160p50, .hd2160p48, .hd2160p30, .hd2160p25, .hd2160p24:
|
||||||
return 56_000_000 // 56 Mbit/s
|
return 56_000_000 // 56 Mbit/s
|
||||||
case .hd1440p60, .hd1440p50, .hd1440p48, .hd1440p30:
|
|
||||||
|
// 16:10 Resolutions
|
||||||
|
case .hd1600p60, .hd1600p50, .hd1600p48, .hd1600p30, .hd1600p25, .hd1600p24:
|
||||||
|
return 20_000_000 // 20 Mbit/s
|
||||||
|
|
||||||
|
// 1440p (16:9) Resolutions
|
||||||
|
case .hd1440p60, .hd1440p50, .hd1440p48, .hd1440p30, .hd1440p25, .hd1440p24:
|
||||||
return 24_000_000 // 24 Mbit/s
|
return 24_000_000 // 24 Mbit/s
|
||||||
case .hd1080p60, .hd1080p50, .hd1080p48, .hd1080p30:
|
|
||||||
|
// 1280p (16:10) Resolutions
|
||||||
|
case .hd1280p60, .hd1280p50, .hd1280p48, .hd1280p30, .hd1280p25, .hd1280p24:
|
||||||
|
return 15_000_000 // 15 Mbit/s
|
||||||
|
|
||||||
|
// 1200p (16:10) Resolutions
|
||||||
|
case .hd1200p60, .hd1200p50, .hd1200p48, .hd1200p30, .hd1200p25, .hd1200p24:
|
||||||
|
return 18_000_000 // 18 Mbit/s
|
||||||
|
|
||||||
|
// 1080p (16:9) Resolutions
|
||||||
|
case .hd1080p60, .hd1080p50, .hd1080p48, .hd1080p30, .hd1080p25, .hd1080p24:
|
||||||
return 12_000_000 // 12 Mbit/s
|
return 12_000_000 // 12 Mbit/s
|
||||||
case .hd720p60, .hd720p50, .hd720p48, .hd720p30:
|
|
||||||
|
// 1050p (16:10) Resolutions
|
||||||
|
case .hd1050p60, .hd1050p50, .hd1050p48, .hd1050p30, .hd1050p25, .hd1050p24:
|
||||||
|
return 10_000_000 // 10 Mbit/s
|
||||||
|
|
||||||
|
// 960p Resolutions
|
||||||
|
case .hd960p60, .hd960p50, .hd960p48, .hd960p30, .hd960p25, .hd960p24:
|
||||||
|
return 8_000_000 // 8 Mbit/s
|
||||||
|
|
||||||
|
// 900p (16:10) Resolutions
|
||||||
|
case .hd900p60, .hd900p50, .hd900p48, .hd900p30, .hd900p25, .hd900p24:
|
||||||
|
return 7_000_000 // 7 Mbit/s
|
||||||
|
|
||||||
|
// 800p (16:10) Resolutions
|
||||||
|
case .hd800p60, .hd800p50, .hd800p48, .hd800p30, .hd800p25, .hd800p24:
|
||||||
|
return 6_000_000 // 6 Mbit/s
|
||||||
|
|
||||||
|
// 720p (16:9) Resolutions
|
||||||
|
case .hd720p60, .hd720p50, .hd720p48, .hd720p30, .hd720p25, .hd720p24:
|
||||||
return 9_500_000 // 9.5 Mbit/s
|
return 9_500_000 // 9.5 Mbit/s
|
||||||
case .sd480p30:
|
|
||||||
|
// Standard Definition (SD) Resolutions
|
||||||
|
case .sd854p30, .sd854p25, .sd768p30, .sd768p25, .sd640p30, .sd640p25:
|
||||||
return 4_000_000 // 4 Mbit/s
|
return 4_000_000 // 4 Mbit/s
|
||||||
case .sd360p30:
|
|
||||||
|
case .sd480p30, .sd480p25:
|
||||||
|
return 2_500_000 // 2.5 Mbit/s
|
||||||
|
|
||||||
|
case .sd428p30, .sd428p25:
|
||||||
|
return 2_000_000 // 2 Mbit/s
|
||||||
|
|
||||||
|
case .sd360p30, .sd360p25:
|
||||||
return 1_500_000 // 1.5 Mbit/s
|
return 1_500_000 // 1.5 Mbit/s
|
||||||
case .sd240p30:
|
|
||||||
|
case .sd320p30, .sd320p25:
|
||||||
|
return 1_200_000 // 1.2 Mbit/s
|
||||||
|
|
||||||
|
case .sd240p30, .sd240p25:
|
||||||
return 1_000_000 // 1 Mbit/s
|
return 1_000_000 // 1 Mbit/s
|
||||||
case .sd144p30:
|
|
||||||
|
case .sd214p30, .sd214p25:
|
||||||
|
return 800_000 // 0.8 Mbit/s
|
||||||
|
|
||||||
|
case .sd144p30, .sd144p25:
|
||||||
return 600_000 // 0.6 Mbit/s
|
return 600_000 // 0.6 Mbit/s
|
||||||
|
|
||||||
|
case .sd128p30, .sd128p25:
|
||||||
|
return 400_000 // 0.4 Mbit/s
|
||||||
|
|
||||||
case .unknown:
|
case .unknown:
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,18 +29,14 @@ struct ChaptersView: View {
|
|||||||
ScrollView(.horizontal) {
|
ScrollView(.horizontal) {
|
||||||
ScrollViewReader { scrollViewProxy in
|
ScrollViewReader { scrollViewProxy in
|
||||||
LazyHStack(spacing: 20) {
|
LazyHStack(spacing: 20) {
|
||||||
chapterViews(for: chapters[...], scrollViewProxy: scrollViewProxy)
|
chapterViews(for: chapters[...])
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 15)
|
.padding(.horizontal, 15)
|
||||||
.onAppear {
|
.onAppear {
|
||||||
if let currentChapterIndex = player.currentChapterIndex {
|
scrollToCurrentChapter(scrollViewProxy)
|
||||||
scrollViewProxy.scrollTo(currentChapterIndex, anchor: .center)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.onChange(of: player.currentChapterIndex) { currentChapterIndex in
|
|
||||||
if let index = currentChapterIndex {
|
|
||||||
scrollViewProxy.scrollTo(index, anchor: .center)
|
|
||||||
}
|
}
|
||||||
|
.onChange(of: player.currentChapterIndex) { _ in
|
||||||
|
scrollToCurrentChapter(scrollViewProxy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,7 +49,8 @@ struct ChaptersView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
Section { chapterViews(for: chapters[...]) }.padding(.horizontal)
|
Section { chapterViews(for: chapters[...]) }
|
||||||
|
.padding(.horizontal)
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@@ -80,7 +77,7 @@ struct ChaptersView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
private func chapterViews(for chaptersToShow: ArraySlice<Chapter>, opacity: Double = 1.0, clickable: Bool = true, scrollViewProxy _: ScrollViewProxy? = nil) -> some View {
|
private func chapterViews(for chaptersToShow: ArraySlice<Chapter>, opacity: Double = 1.0, clickable: Bool = true) -> some View {
|
||||||
ForEach(Array(chaptersToShow.indices), id: \.self) { index in
|
ForEach(Array(chaptersToShow.indices), id: \.self) { index in
|
||||||
let chapter = chaptersToShow[index]
|
let chapter = chaptersToShow[index]
|
||||||
ChapterView(chapter: chapter, chapterIndex: index, showThumbnail: showThumbnails)
|
ChapterView(chapter: chapter, chapterIndex: index, showThumbnail: showThumbnails)
|
||||||
@@ -89,6 +86,14 @@ struct ChaptersView: View {
|
|||||||
.allowsHitTesting(clickable)
|
.allowsHitTesting(clickable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func scrollToCurrentChapter(_ scrollViewProxy: ScrollViewProxy) {
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { // Slight delay to ensure the view is fully rendered
|
||||||
|
if let currentChapterIndex = player.currentChapterIndex {
|
||||||
|
scrollViewProxy.scrollTo(currentChapterIndex, anchor: .center)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -361,9 +361,9 @@ struct PlayerSettings: View {
|
|||||||
|
|
||||||
private var captionsFontScaleSizePicker: some View {
|
private var captionsFontScaleSizePicker: some View {
|
||||||
Picker("Size", selection: $captionsFontScaleSize) {
|
Picker("Size", selection: $captionsFontScaleSize) {
|
||||||
Text("Small").tag(String("0.5"))
|
Text("Small").tag(String("0.725"))
|
||||||
Text("Medium").tag(String("1.0"))
|
Text("Medium").tag(String("1.0"))
|
||||||
Text("Large").tag(String("2.0"))
|
Text("Large").tag(String("1.5"))
|
||||||
}
|
}
|
||||||
.onChange(of: captionsFontScaleSize) { _ in
|
.onChange(of: captionsFontScaleSize) { _ in
|
||||||
PlayerModel.shared.mpvBackend.client.setSubFontSize(scaleSize: captionsFontScaleSize)
|
PlayerModel.shared.mpvBackend.client.setSubFontSize(scaleSize: captionsFontScaleSize)
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ struct YatteeApp: App {
|
|||||||
|
|
||||||
NavigationModel.shared.tabSelection = section ?? .search
|
NavigationModel.shared.tabSelection = section ?? .search
|
||||||
|
|
||||||
DispatchQueue.global(qos: .userInitiated).async {
|
DispatchQueue.main.async {
|
||||||
playlists.load()
|
playlists.load()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4103,7 +4103,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = "Open in Yattee/Open in Yattee.entitlements";
|
CODE_SIGN_ENTITLEMENTS = "Open in Yattee/Open in Yattee.entitlements";
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 189;
|
CURRENT_PROJECT_VERSION = 190;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = "Open in Yattee/Info.plist";
|
INFOPLIST_FILE = "Open in Yattee/Info.plist";
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = "Open in Yattee";
|
INFOPLIST_KEY_CFBundleDisplayName = "Open in Yattee";
|
||||||
@@ -4134,7 +4134,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = 189;
|
CURRENT_PROJECT_VERSION = 190;
|
||||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 78Z5H3M6RJ;
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 78Z5H3M6RJ;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = "Open in Yattee/Info.plist";
|
INFOPLIST_FILE = "Open in Yattee/Info.plist";
|
||||||
@@ -4165,7 +4165,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 189;
|
CURRENT_PROJECT_VERSION = 190;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||||
@@ -4185,7 +4185,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 189;
|
CURRENT_PROJECT_VERSION = 190;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||||
@@ -4348,7 +4348,7 @@
|
|||||||
CODE_SIGN_ENTITLEMENTS = "iOS/Yattee (iOS).entitlements";
|
CODE_SIGN_ENTITLEMENTS = "iOS/Yattee (iOS).entitlements";
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 189;
|
CURRENT_PROJECT_VERSION = 190;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
"DEBUG=1",
|
"DEBUG=1",
|
||||||
@@ -4400,7 +4400,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = 189;
|
CURRENT_PROJECT_VERSION = 190;
|
||||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 78Z5H3M6RJ;
|
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 78Z5H3M6RJ;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = "GLES_SILENCE_DEPRECATION=1";
|
GCC_PREPROCESSOR_DEFINITIONS = "GLES_SILENCE_DEPRECATION=1";
|
||||||
@@ -4452,7 +4452,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 189;
|
CURRENT_PROJECT_VERSION = 190;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
ENABLE_APP_SANDBOX = YES;
|
ENABLE_APP_SANDBOX = YES;
|
||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
@@ -4491,7 +4491,7 @@
|
|||||||
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application";
|
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "3rd Party Mac Developer Application";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 189;
|
CURRENT_PROJECT_VERSION = 190;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
"DEVELOPMENT_TEAM[sdk=macosx*]" = 78Z5H3M6RJ;
|
"DEVELOPMENT_TEAM[sdk=macosx*]" = 78Z5H3M6RJ;
|
||||||
ENABLE_APP_SANDBOX = YES;
|
ENABLE_APP_SANDBOX = YES;
|
||||||
@@ -4525,7 +4525,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 189;
|
CURRENT_PROJECT_VERSION = 190;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@@ -4548,7 +4548,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 189;
|
CURRENT_PROJECT_VERSION = 190;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@@ -4573,7 +4573,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 189;
|
CURRENT_PROJECT_VERSION = 190;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@@ -4597,7 +4597,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 189;
|
CURRENT_PROJECT_VERSION = 190;
|
||||||
DEAD_CODE_STRIPPING = YES;
|
DEAD_CODE_STRIPPING = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
@@ -4623,7 +4623,7 @@
|
|||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 189;
|
CURRENT_PROJECT_VERSION = 190;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@@ -4663,7 +4663,7 @@
|
|||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "iPhone Distribution";
|
"CODE_SIGN_IDENTITY[sdk=appletvos*]" = "iPhone Distribution";
|
||||||
CODE_SIGN_STYLE = Manual;
|
CODE_SIGN_STYLE = Manual;
|
||||||
CURRENT_PROJECT_VERSION = 189;
|
CURRENT_PROJECT_VERSION = 190;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
"DEVELOPMENT_TEAM[sdk=appletvos*]" = 78Z5H3M6RJ;
|
"DEVELOPMENT_TEAM[sdk=appletvos*]" = 78Z5H3M6RJ;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
@@ -4703,7 +4703,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 189;
|
CURRENT_PROJECT_VERSION = 190;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@@ -4726,7 +4726,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 189;
|
CURRENT_PROJECT_VERSION = 190;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
|
|||||||
Reference in New Issue
Block a user