mirror of
https://github.com/yattee/yattee.git
synced 2025-08-06 10:44:06 +00:00
Display more details in player view
This commit is contained in:
25
Model/PlaybackState.swift
Normal file
25
Model/PlaybackState.swift
Normal file
@@ -0,0 +1,25 @@
|
||||
import CoreMedia
|
||||
import Foundation
|
||||
|
||||
final class PlaybackState: ObservableObject {
|
||||
@Published var stream: Stream?
|
||||
@Published var time: CMTime?
|
||||
|
||||
var aspectRatio: CGFloat? {
|
||||
let tracks = stream?.videoAsset.tracks(withMediaType: .video)
|
||||
|
||||
guard tracks != nil else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let size: CGSize! = tracks!.first.flatMap {
|
||||
tracks!.isEmpty ? nil : $0.naturalSize.applying($0.preferredTransform)
|
||||
}
|
||||
|
||||
guard size != nil else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return size.width / size.height
|
||||
}
|
||||
}
|
@@ -14,19 +14,21 @@ final class PlayerState: ObservableObject {
|
||||
|
||||
private var compositions = [Stream: AVMutableComposition]()
|
||||
|
||||
private(set) var currentTime: CMTime?
|
||||
private(set) var savedTime: CMTime?
|
||||
|
||||
private(set) var currentRate: Float = 0.0
|
||||
static let availableRates: [Double] = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2]
|
||||
|
||||
let maxResolution: Stream.Resolution?
|
||||
var playbackState: PlaybackState?
|
||||
var timeObserver: Any?
|
||||
|
||||
let maxResolution: Stream.Resolution?
|
||||
|
||||
var playingOutsideViewController = false
|
||||
|
||||
init(_ video: Video? = nil, maxResolution: Stream.Resolution? = nil) {
|
||||
init(_ video: Video? = nil, playbackState: PlaybackState? = nil, maxResolution: Stream.Resolution? = nil) {
|
||||
self.video = video
|
||||
self.playbackState = playbackState
|
||||
self.maxResolution = maxResolution
|
||||
}
|
||||
|
||||
@@ -101,6 +103,10 @@ final class PlayerState: ObservableObject {
|
||||
DispatchQueue.main.async {
|
||||
self.saveTime()
|
||||
self.player?.replaceCurrentItem(with: self.playerItemWithMetadata(for: stream))
|
||||
self.playbackState?.stream = stream
|
||||
if self.timeObserver == nil {
|
||||
self.addTimeObserver()
|
||||
}
|
||||
self.player?.playImmediately(atRate: 1.0)
|
||||
self.seekToSavedTime()
|
||||
}
|
||||
@@ -245,9 +251,15 @@ final class PlayerState: ObservableObject {
|
||||
let interval = CMTime(value: 1, timescale: 1)
|
||||
|
||||
timeObserver = player.addPeriodicTimeObserver(forInterval: interval, queue: .main) { _ in
|
||||
guard self.player != nil else {
|
||||
return
|
||||
}
|
||||
|
||||
if self.player.rate != self.currentRate, self.player.rate != 0, self.currentRate != 0 {
|
||||
self.player.rate = self.currentRate
|
||||
}
|
||||
|
||||
self.playbackState?.time = self.player.currentTime()
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -24,6 +24,11 @@ struct Video: Identifiable, Equatable {
|
||||
var streams = [Stream]()
|
||||
var hlsUrl: URL?
|
||||
|
||||
var publishedAt: Date?
|
||||
var likes: Int?
|
||||
var dislikes: Int?
|
||||
var keywords = [String]()
|
||||
|
||||
init(
|
||||
id: String,
|
||||
title: String,
|
||||
@@ -37,7 +42,11 @@ struct Video: Identifiable, Equatable {
|
||||
thumbnails: [Thumbnail] = [],
|
||||
indexID: String? = nil,
|
||||
live: Bool = false,
|
||||
upcoming: Bool = false
|
||||
upcoming: Bool = false,
|
||||
publishedAt: Date? = nil,
|
||||
likes: Int? = nil,
|
||||
dislikes: Int? = nil,
|
||||
keywords: [String] = []
|
||||
) {
|
||||
self.id = id
|
||||
self.title = title
|
||||
@@ -52,6 +61,10 @@ struct Video: Identifiable, Equatable {
|
||||
self.indexID = indexID
|
||||
self.live = live
|
||||
self.upcoming = upcoming
|
||||
self.publishedAt = publishedAt
|
||||
self.likes = likes
|
||||
self.dislikes = dislikes
|
||||
self.keywords = keywords
|
||||
}
|
||||
|
||||
init(_ json: JSON) {
|
||||
@@ -79,6 +92,15 @@ struct Video: Identifiable, Equatable {
|
||||
live = json["liveNow"].boolValue
|
||||
upcoming = json["isUpcoming"].boolValue
|
||||
|
||||
likes = json["likeCount"].int
|
||||
dislikes = json["dislikeCount"].int
|
||||
|
||||
keywords = json["keywords"].arrayValue.map { $0.stringValue }
|
||||
|
||||
if let publishedInterval = json["published"].double {
|
||||
publishedAt = Date(timeIntervalSince1970: publishedInterval)
|
||||
}
|
||||
|
||||
streams = Video.extractFormatStreams(from: json["formatStreams"].arrayValue)
|
||||
streams.append(contentsOf: Video.extractAdaptiveFormats(from: json["adaptiveFormats"].arrayValue))
|
||||
|
||||
@@ -103,7 +125,23 @@ struct Video: Identifiable, Equatable {
|
||||
(published.isEmpty || published == "0 seconds ago") ? nil : published
|
||||
}
|
||||
|
||||
var viewsCount: String {
|
||||
var viewsCount: String? {
|
||||
views != 0 ? formattedCount(views) : nil
|
||||
}
|
||||
|
||||
var likesCount: String? {
|
||||
formattedCount(likes)
|
||||
}
|
||||
|
||||
var dislikesCount: String? {
|
||||
formattedCount(dislikes)
|
||||
}
|
||||
|
||||
func formattedCount(_ count: Int!) -> String? {
|
||||
guard count != nil else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let formatter = NumberFormatter()
|
||||
formatter.numberStyle = .decimal
|
||||
formatter.maximumFractionDigits = 1
|
||||
@@ -111,11 +149,13 @@ struct Video: Identifiable, Equatable {
|
||||
var number: NSNumber
|
||||
var unit: String
|
||||
|
||||
if views < 1_000_000 {
|
||||
number = NSNumber(value: Double(views) / 1000.0)
|
||||
if count < 1000 {
|
||||
return "\(count!)"
|
||||
} else if count < 1_000_000 {
|
||||
number = NSNumber(value: Double(count) / 1000.0)
|
||||
unit = "K"
|
||||
} else {
|
||||
number = NSNumber(value: Double(views) / 1_000_000.0)
|
||||
number = NSNumber(value: Double(count) / 1_000_000.0)
|
||||
unit = "M"
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user