damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

commit 35c581066a748e68478359aba37bafcd42d519e3
parent d6c72403a3598531c019a54462e82c0c1775df9c
Author: Fishcake <me@fshck.com>
Date:   Tue, 26 Sep 2023 16:14:18 +0900

fix video size detection, and audio track detection to work with HLS, add live stream indicator

Closes: https://github.com/damus-io/damus/pull/1560
Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Mdamus/Views/Video/DamusVideoPlayer.swift | 22++++++++++++++++++++++
Mdamus/Views/Video/DamusVideoPlayerViewModel.swift | 56++++++++++++++++++++++++++++++++++++++++++--------------
2 files changed, 64 insertions(+), 14 deletions(-)

diff --git a/damus/Views/Video/DamusVideoPlayer.swift b/damus/Views/Video/DamusVideoPlayer.swift @@ -43,6 +43,9 @@ struct DamusVideoPlayer: View { if model.has_audio { mute_button } + if model.is_live { + live_indicator + } } .onChange(of: centerY) { _ in update_is_visible(centerY: centerY) @@ -93,6 +96,25 @@ struct DamusVideoPlayer: View { } } } + + private var live_indicator: some View { + VStack { + HStack { + Text("LIVE") + .bold() + .foregroundColor(.red) + .padding(.horizontal) + .padding(.vertical, 5) + .background( + Capsule() + .fill(Color.black.opacity(0.5)) + ) + .padding([.top, .leading]) + Spacer() + } + Spacer() + } + } } struct DamusVideoPlayer_Previews: PreviewProvider { static var previews: some View { diff --git a/damus/Views/Video/DamusVideoPlayerViewModel.swift b/damus/Views/Video/DamusVideoPlayerViewModel.swift @@ -10,16 +10,15 @@ import Combine import Foundation import SwiftUI -func get_video_size(player: AVPlayer) async -> CGSize? { - let res = Task.detached(priority: .background) { - return player.currentImage?.size - } - return await res.value -} - func video_has_audio(player: AVPlayer) async -> Bool { - let tracks = try? await player.currentItem?.asset.load(.tracks) - return tracks?.filter({ t in t.mediaType == .audio }).first != nil + do { + let hasAudibleTracks = ((try await player.currentItem?.asset.loadMediaSelectionGroup(for: .audible)) != nil) + let tracks = try? await player.currentItem?.asset.load(.tracks) + let hasAudioTrack = tracks?.filter({ t in t.mediaType == .audio }).first != nil // Deal with odd cases of audio only MOV + return hasAudibleTracks || hasAudioTrack + } catch { + return false + } } @MainActor @@ -32,12 +31,16 @@ final class DamusVideoPlayerViewModel: ObservableObject { let id = UUID() @Published var has_audio = false + @Published var is_live = false @Binding var video_size: CGSize? @Published var is_muted = true @Published var is_loading = true private var cancellables = Set<AnyCancellable>() + private var videoSizeObserver: NSKeyValueObservation? + private var videoDurationObserver: NSKeyValueObservation? + private var is_scrolled_into_view = false { didSet { if is_scrolled_into_view && !oldValue { @@ -78,6 +81,31 @@ final class DamusVideoPlayerViewModel: ObservableObject { model_id == self?.id ? self?.player.play() : self?.player.pause() } .store(in: &cancellables) + + observeVideoSize() + observeDuration() + } + + private func observeVideoSize() { + videoSizeObserver = player.currentItem?.observe(\.presentationSize, options: [.new], changeHandler: { [weak self] (playerItem, change) in + guard let self else { return } + if let newSize = change.newValue, newSize != .zero { + DispatchQueue.main.async { + self.video_size = newSize // Update the bound value + } + } + }) + } + + private func observeDuration() { + videoDurationObserver = player.currentItem?.observe(\.duration, options: [.new], changeHandler: { [weak self] (playerItem, change) in + guard let self else { return } + if let newDuration = change.newValue, newDuration != .zero { + DispatchQueue.main.async { + self.is_live = newDuration == .indefinite + } + } + }) } private func load() async { @@ -86,11 +114,6 @@ final class DamusVideoPlayerViewModel: ObservableObject { video_size = meta.size } else { has_audio = await video_has_audio(player: player) - if let video_size = await get_video_size(player: player) { - self.video_size = video_size - let meta = VideoMetadata(has_audio: has_audio, size: video_size) - controller.set_metadata(meta, url: url) - } } is_loading = false @@ -114,4 +137,9 @@ final class DamusVideoPlayerViewModel: ObservableObject { player.seek(to: CMTime.zero) player.play() } + + deinit { + videoSizeObserver?.invalidate() + videoDurationObserver?.invalidate() + } }