idk is this SharePlay?

This commit is contained in:
Francesco 2025-05-27 15:23:19 +02:00
parent 50cd96bee7
commit 76e2b3ed3b
4 changed files with 108 additions and 3 deletions

View file

@ -8,6 +8,7 @@
import UIKit
import AVKit
import MediaPlayer
import GroupActivities
class VideoPlayerViewController: UIViewController {
let module: ScrapingModule
@ -27,6 +28,8 @@ class VideoPlayerViewController: UIViewController {
var mediaTitle: String = ""
private var currentArtwork: MPMediaItemArtwork?
private var groupSession: GroupSession<WatchTogetherActivity>?
private var messenger: GroupSessionMessenger?
init(module: ScrapingModule) {
self.module = module
@ -40,6 +43,7 @@ class VideoPlayerViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupSharePlay()
setupNowPlaying()
setupRemoteTransportControls()
@ -95,6 +99,80 @@ class VideoPlayerViewController: UIViewController {
}
}
private func setupSharePlay() {
guard let streamUrl = streamUrl else { return }
let activity = WatchTogetherActivity(
streamUrl: streamUrl,
mediaTitle: mediaTitle,
episodeNumber: episodeNumber
)
Task {
switch await activity.prepareForActivation() {
case .activationPreferred:
do {
_ = try await activity.activate()
Logger.shared.log("SharePlay session activated successfully", type: "General")
} catch {
Logger.shared.log("Failed to activate SharePlay: \(error)", type: "Error")
}
case .activationDisabled:
Logger.shared.log("SharePlay activation disabled", type: "General")
case .cancelled:
Logger.shared.log("SharePlay activation cancelled", type: "General")
@unknown default:
Logger.shared.log("SharePlay activation unknown state", type: "Info")
}
}
Task {
for await session in WatchTogetherActivity.sessions() {
configureGroupSession(session)
}
}
}
private func configureGroupSession(_ session: GroupSession<WatchTogetherActivity>) {
groupSession = session
messenger = GroupSessionMessenger(session: session)
session.join()
Task {
guard let messenger = messenger else { return }
for await (timeString, _) in messenger.messages(of: String.self) {
if let seconds = Double(timeString) {
let time = CMTime(seconds: seconds, preferredTimescale: 600)
await handlePlaybackMessage(time)
}
}
}
player?.addPeriodicTimeObserver(
forInterval: CMTime(seconds: 1, preferredTimescale: 600),
queue: .main
) { [weak self] time in
guard let self = self else { return }
Task {
let timeString = String(time.seconds)
try? await self.messenger?.send(timeString)
}
}
}
private func handlePlaybackMessage(_ time: CMTime) async {
await MainActor.run {
guard let player = player else { return }
let currentTime = player.currentTime()
let difference = abs(CMTimeSubtract(time, currentTime).seconds)
if difference > 1.0 {
player.seek(to: time)
}
}
}
private func setupNowPlaying() {
if let imageUrl = URL(string: episodeImageUrl) {
URLSession.custom.dataTask(with: imageUrl) { [weak self] data, _, _ in
@ -136,7 +214,7 @@ class VideoPlayerViewController: UIViewController {
MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
}
let interval = CMTime(seconds: 1.0, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
player?.addPeriodicTimeObserver(forInterval: interval, queue: .main) { [weak self] _ in
self?.updateNowPlayingInfo()
@ -170,6 +248,7 @@ class VideoPlayerViewController: UIViewController {
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
groupSession?.leave()
if let playbackSpeed = player?.rate {
UserDefaults.standard.set(playbackSpeed, forKey: "lastPlaybackSpeed")
}
@ -269,6 +348,7 @@ class VideoPlayerViewController: UIViewController {
}
deinit {
groupSession?.leave()
player?.pause()
if let timeObserverToken = timeObserverToken {
player?.removeTimeObserver(timeObserverToken)

View file

@ -0,0 +1,21 @@
//
// VideoPlayer.swift
// Sora
//
// Created by Francesco on 27/005/25.
import GroupActivities
struct WatchTogetherActivity: GroupActivity {
let streamUrl: String
let mediaTitle: String
let episodeNumber: Int
var metadata: GroupActivityMetadata {
var metadata = GroupActivityMetadata()
metadata.type = .watchTogether
metadata.title = mediaTitle
metadata.subtitle = "Episode \(episodeNumber)"
return metadata
}
}

View file

@ -28,8 +28,8 @@ struct SettingsViewAbout: View {
Text("Sora")
.font(.title)
.bold()
Text("Version \(version)")
.font(.subheadline)
Text("AKA Sulfur")
.font(.caption)
.foregroundColor(.secondary)
}
}

View file

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
130A810B2DE5F32400614732 /* WatchTogether.swift in Sources */ = {isa = PBXBuildFile; fileRef = 130A810A2DE5F32400614732 /* WatchTogether.swift */; };
130C6BFA2D53AB1F00DC1432 /* SettingsViewData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 130C6BF92D53AB1F00DC1432 /* SettingsViewData.swift */; };
13103E8B2D58E028000F0673 /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13103E8A2D58E028000F0673 /* View.swift */; };
13103E8E2D58E04A000F0673 /* SkeletonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13103E8D2D58E04A000F0673 /* SkeletonCell.swift */; };
@ -88,6 +89,7 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
130A810A2DE5F32400614732 /* WatchTogether.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WatchTogether.swift; path = Sora/Utils/MediaPlayer/WatchTogether.swift; sourceTree = SOURCE_ROOT; };
130C6BF82D53A4C200DC1432 /* Sora.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Sora.entitlements; sourceTree = "<group>"; };
130C6BF92D53AB1F00DC1432 /* SettingsViewData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewData.swift; sourceTree = "<group>"; };
13103E8A2D58E028000F0673 /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = "<group>"; };
@ -447,6 +449,7 @@
isa = PBXGroup;
children = (
13EA2BD02D32D97400C1EBD7 /* CustomPlayer */,
130A810A2DE5F32400614732 /* WatchTogether.swift */,
13DC0C452D302C7500D0F966 /* VideoPlayer.swift */,
13EA2BD82D32D98400C1EBD7 /* NormalPlayer.swift */,
);
@ -610,6 +613,7 @@
buildActionMask = 2147483647;
files = (
135CCBE22D4D1138008B9C0E /* SettingsViewPlayer.swift in Sources */,
130A810B2DE5F32400614732 /* WatchTogether.swift in Sources */,
131270172DC13A010093AA9C /* DownloadManager.swift in Sources */,
1327FBA72D758CEA00FC6689 /* Analytics.swift in Sources */,
13DC0C462D302C7500D0F966 /* VideoPlayer.swift in Sources */,