From 0ca54ea38d1502dcbd4843b98b70cd5485163bec Mon Sep 17 00:00:00 2001 From: cranci1 <100066266+cranci1@users.noreply.github.com> Date: Sun, 15 Jun 2025 10:50:35 +0200 Subject: [PATCH] ok well lets test --- .../ContinueWatchingItem.swift | 0 .../ContinueWatchingManager.swift | 0 .../Components/Double+Extension.swift | 0 .../Components/MusicProgressSlider.swift | 0 .../Components/VolumeSlider.swift | 0 .../CustomPlayer/CustomPlayer.swift | 0 .../Helpers/SubtitleSettingsManager.swift | 0 .../Helpers/VTTSubtitlesLoader.swift | 0 .../NormalPlayer}/NormalPlayer.swift | 0 .../NormalPlayer}/VideoPlayer.swift | 87 +++++++++++++++++++ .../SharePlay/SharePlayCoordinator.swift | 78 +++++++++++++++++ .../SharePlay/SharePlayManager.swift | 77 ++++++++++++++++ .../SharePlay/VideoWatchingActivity.swift | 68 +++++++++++++++ Sora/Sora.entitlements | 4 + Sulfur.xcodeproj/project.pbxproj | 46 ++++++++-- 15 files changed, 351 insertions(+), 9 deletions(-) rename Sora/{Utils => MediaUtils}/ContinueWatching/ContinueWatchingItem.swift (100%) rename Sora/{Utils => MediaUtils}/ContinueWatching/ContinueWatchingManager.swift (100%) rename Sora/{Utils/MediaPlayer => MediaUtils}/CustomPlayer/Components/Double+Extension.swift (100%) rename Sora/{Utils/MediaPlayer => MediaUtils}/CustomPlayer/Components/MusicProgressSlider.swift (100%) rename Sora/{Utils/MediaPlayer => MediaUtils}/CustomPlayer/Components/VolumeSlider.swift (100%) rename Sora/{Utils/MediaPlayer => MediaUtils}/CustomPlayer/CustomPlayer.swift (100%) rename Sora/{Utils/MediaPlayer => MediaUtils}/CustomPlayer/Helpers/SubtitleSettingsManager.swift (100%) rename Sora/{Utils/MediaPlayer => MediaUtils}/CustomPlayer/Helpers/VTTSubtitlesLoader.swift (100%) rename Sora/{Utils/MediaPlayer => MediaUtils/NormalPlayer}/NormalPlayer.swift (100%) rename Sora/{Utils/MediaPlayer => MediaUtils/NormalPlayer}/VideoPlayer.swift (79%) create mode 100644 Sora/MediaUtils/SharePlay/SharePlayCoordinator.swift create mode 100644 Sora/MediaUtils/SharePlay/SharePlayManager.swift create mode 100644 Sora/MediaUtils/SharePlay/VideoWatchingActivity.swift diff --git a/Sora/Utils/ContinueWatching/ContinueWatchingItem.swift b/Sora/MediaUtils/ContinueWatching/ContinueWatchingItem.swift similarity index 100% rename from Sora/Utils/ContinueWatching/ContinueWatchingItem.swift rename to Sora/MediaUtils/ContinueWatching/ContinueWatchingItem.swift diff --git a/Sora/Utils/ContinueWatching/ContinueWatchingManager.swift b/Sora/MediaUtils/ContinueWatching/ContinueWatchingManager.swift similarity index 100% rename from Sora/Utils/ContinueWatching/ContinueWatchingManager.swift rename to Sora/MediaUtils/ContinueWatching/ContinueWatchingManager.swift diff --git a/Sora/Utils/MediaPlayer/CustomPlayer/Components/Double+Extension.swift b/Sora/MediaUtils/CustomPlayer/Components/Double+Extension.swift similarity index 100% rename from Sora/Utils/MediaPlayer/CustomPlayer/Components/Double+Extension.swift rename to Sora/MediaUtils/CustomPlayer/Components/Double+Extension.swift diff --git a/Sora/Utils/MediaPlayer/CustomPlayer/Components/MusicProgressSlider.swift b/Sora/MediaUtils/CustomPlayer/Components/MusicProgressSlider.swift similarity index 100% rename from Sora/Utils/MediaPlayer/CustomPlayer/Components/MusicProgressSlider.swift rename to Sora/MediaUtils/CustomPlayer/Components/MusicProgressSlider.swift diff --git a/Sora/Utils/MediaPlayer/CustomPlayer/Components/VolumeSlider.swift b/Sora/MediaUtils/CustomPlayer/Components/VolumeSlider.swift similarity index 100% rename from Sora/Utils/MediaPlayer/CustomPlayer/Components/VolumeSlider.swift rename to Sora/MediaUtils/CustomPlayer/Components/VolumeSlider.swift diff --git a/Sora/Utils/MediaPlayer/CustomPlayer/CustomPlayer.swift b/Sora/MediaUtils/CustomPlayer/CustomPlayer.swift similarity index 100% rename from Sora/Utils/MediaPlayer/CustomPlayer/CustomPlayer.swift rename to Sora/MediaUtils/CustomPlayer/CustomPlayer.swift diff --git a/Sora/Utils/MediaPlayer/CustomPlayer/Helpers/SubtitleSettingsManager.swift b/Sora/MediaUtils/CustomPlayer/Helpers/SubtitleSettingsManager.swift similarity index 100% rename from Sora/Utils/MediaPlayer/CustomPlayer/Helpers/SubtitleSettingsManager.swift rename to Sora/MediaUtils/CustomPlayer/Helpers/SubtitleSettingsManager.swift diff --git a/Sora/Utils/MediaPlayer/CustomPlayer/Helpers/VTTSubtitlesLoader.swift b/Sora/MediaUtils/CustomPlayer/Helpers/VTTSubtitlesLoader.swift similarity index 100% rename from Sora/Utils/MediaPlayer/CustomPlayer/Helpers/VTTSubtitlesLoader.swift rename to Sora/MediaUtils/CustomPlayer/Helpers/VTTSubtitlesLoader.swift diff --git a/Sora/Utils/MediaPlayer/NormalPlayer.swift b/Sora/MediaUtils/NormalPlayer/NormalPlayer.swift similarity index 100% rename from Sora/Utils/MediaPlayer/NormalPlayer.swift rename to Sora/MediaUtils/NormalPlayer/NormalPlayer.swift diff --git a/Sora/Utils/MediaPlayer/VideoPlayer.swift b/Sora/MediaUtils/NormalPlayer/VideoPlayer.swift similarity index 79% rename from Sora/Utils/MediaPlayer/VideoPlayer.swift rename to Sora/MediaUtils/NormalPlayer/VideoPlayer.swift index 518c778..c7e036c 100644 --- a/Sora/Utils/MediaPlayer/VideoPlayer.swift +++ b/Sora/MediaUtils/NormalPlayer/VideoPlayer.swift @@ -7,6 +7,8 @@ import UIKit import AVKit +import Combine +import GroupActivities class VideoPlayerViewController: UIViewController { let module: ScrapingModule @@ -29,6 +31,9 @@ class VideoPlayerViewController: UIViewController { var subtitlesLoader: VTTSubtitlesLoader? var subtitleLabel: UILabel? + private var sharePlayCoordinator: SharePlayCoordinator? + private var subscriptions = Set() + private var aniListUpdateSent = false private var aniListUpdatedSuccessfully = false private var traktUpdateSent = false @@ -40,6 +45,7 @@ class VideoPlayerViewController: UIViewController { if UserDefaults.standard.object(forKey: "subtitlesEnabled") == nil { UserDefaults.standard.set(true, forKey: "subtitlesEnabled") } + setupSharePlay() } required init?(coder: NSCoder) { @@ -129,6 +135,10 @@ class VideoPlayerViewController: UIViewController { if !subtitles.isEmpty && UserDefaults.standard.bool(forKey: "subtitlesEnabled") { setupSubtitles() } + + // Configure SharePlay after player setup + setupSharePlayButton(in: playerViewController) + configureSharePlayForPlayer() } addPeriodicTimeObserver(fullURL: fullUrl) @@ -275,6 +285,79 @@ class VideoPlayerViewController: UIViewController { } } + @MainActor + private func setupSharePlay() { + sharePlayCoordinator = SharePlayCoordinator() + sharePlayCoordinator?.configureGroupSession() + + if let playerViewController = playerViewController { + setupSharePlayButton(in: playerViewController) + } + } + + private func setupSharePlayButton(in playerViewController: NormalPlayer) { + // WIP + } + + @MainActor + private func startSharePlay() { + guard let streamUrl = streamUrl else { return } + + Task { + var episodeImageData: Data? + if !episodeImageUrl.isEmpty, let imageUrl = URL(string: episodeImageUrl) { + episodeImageData = try? await URLSession.shared.data(from: imageUrl).0 + } + + let activity = VideoWatchingActivity( + mediaTitle: mediaTitle, + episodeNumber: episodeNumber, + streamUrl: streamUrl, + subtitles: subtitles, + aniListID: aniListID, + fullUrl: fullUrl, + headers: headers, + episodeImageUrl: episodeImageUrl, + episodeImageData: episodeImageData, + totalEpisodes: totalEpisodes, + tmdbID: tmdbID, + isMovie: isMovie, + seasonNumber: seasonNumber + ) + + await sharePlayCoordinator?.startSharePlay(with: activity) + } + } + + private func configureSharePlayForPlayer() { + guard let player = player else { return } + sharePlayCoordinator?.coordinatePlayback(with: player) + } + + @MainActor + func presentSharePlayInvitation() { + guard let streamUrl = streamUrl else { + Logger.shared.log("Cannot start SharePlay: Stream URL is nil", type: "Error") + return + } + + SharePlayManager.shared.presentSharePlayInvitation( + from: self, + mediaTitle: mediaTitle, + episodeNumber: episodeNumber, + streamUrl: streamUrl, + subtitles: subtitles, + aniListID: aniListID, + fullUrl: fullUrl, + headers: headers, + episodeImageUrl: episodeImageUrl, + totalEpisodes: totalEpisodes, + tmdbID: tmdbID, + isMovie: isMovie, + seasonNumber: seasonNumber + ) + } + override var supportedInterfaceOrientations: UIInterfaceOrientationMask { if UserDefaults.standard.bool(forKey: "alwaysLandscape") { return .landscape @@ -299,5 +382,9 @@ class VideoPlayerViewController: UIViewController { subtitleLabel?.removeFromSuperview() subtitleLabel = nil subtitlesLoader = nil + + sharePlayCoordinator?.leaveGroupSession() + sharePlayCoordinator = nil + subscriptions.removeAll() } } diff --git a/Sora/MediaUtils/SharePlay/SharePlayCoordinator.swift b/Sora/MediaUtils/SharePlay/SharePlayCoordinator.swift new file mode 100644 index 0000000..dea9d61 --- /dev/null +++ b/Sora/MediaUtils/SharePlay/SharePlayCoordinator.swift @@ -0,0 +1,78 @@ +// +// SharePlayCoordinator.swift +// Sora +// +// Created by Francesco on 15/06/25. +// + +import Combine +import Foundation +import AVFoundation +import GroupActivities + +@MainActor +class SharePlayCoordinator: ObservableObject { + private var subscriptions = Set() + private var groupSession: GroupSession? + + @Published var isEligibleForGroupSession = false + @Published var groupSessionState: GroupSession.State = .waiting + + private var playbackCoordinator: AVPlayerPlaybackCoordinator? + + func configureGroupSession() { + Task { + for await session in VideoWatchingActivity.sessions() { + await configureGroupSession(session) + } + } + } + + private func configureGroupSession(_ groupSession: GroupSession) async { + self.groupSession = groupSession + + groupSession.$state + .receive(on: DispatchQueue.main) + .assign(to: &$groupSessionState) + + groupSession.$activeParticipants + .receive(on: DispatchQueue.main) + .sink { participants in + Logger.shared.log("Active participants: \(participants.count)", type: "SharePlay") + } + .store(in: &subscriptions) + + groupSession.join() + } + + func startSharePlay(with activity: VideoWatchingActivity) async { + do { + _ = try await activity.activate() + Logger.shared.log("SharePlay activity activated successfully", type: "SharePlay") + } catch { + Logger.shared.log("Failed to activate SharePlay: \(error.localizedDescription)", type: "Error") + } + } + + func coordinatePlayback(with player: AVPlayer) { + guard let groupSession = groupSession else { return } + + playbackCoordinator = player.playbackCoordinator + playbackCoordinator?.coordinateWithSession(groupSession) + + Logger.shared.log("Playback coordination established", type: "SharePlay") + } + + nonisolated func leaveGroupSession() { + Task { @MainActor in + self.groupSession?.leave() + self.playbackCoordinator = nil + Logger.shared.log("Left SharePlay session", type: "SharePlay") + } + } + + deinit { + subscriptions.removeAll() + playbackCoordinator = nil + } +} diff --git a/Sora/MediaUtils/SharePlay/SharePlayManager.swift b/Sora/MediaUtils/SharePlay/SharePlayManager.swift new file mode 100644 index 0000000..415510c --- /dev/null +++ b/Sora/MediaUtils/SharePlay/SharePlayManager.swift @@ -0,0 +1,77 @@ +// +// SharePlayManager.swift +// Sora +// +// Created by Francesco on 15/06/25. +// + +import UIKit +import Foundation +import GroupActivities + +class SharePlayManager { + static let shared = SharePlayManager() + + private init() {} + + func isSharePlayAvailable() -> Bool { + return true + } + + func presentSharePlayInvitation(from viewController: UIViewController, + mediaTitle: String, + episodeNumber: Int, + streamUrl: String, + subtitles: String = "", + aniListID: Int = 0, + fullUrl: String, + headers: [String: String]? = nil, + episodeImageUrl: String = "", + totalEpisodes: Int = 0, + tmdbID: Int? = nil, + isMovie: Bool = false, + seasonNumber: Int = 1) { + + Task { @MainActor in + var episodeImageData: Data? + if !episodeImageUrl.isEmpty, let imageUrl = URL(string: episodeImageUrl) { + do { + episodeImageData = try await URLSession.shared.data(from: imageUrl).0 + } catch { + Logger.shared.log("Failed to load episode image for SharePlay: \(error.localizedDescription)", type: "Error") + } + } + + let activity = VideoWatchingActivity( + mediaTitle: mediaTitle, + episodeNumber: episodeNumber, + streamUrl: streamUrl, + subtitles: subtitles, + aniListID: aniListID, + fullUrl: fullUrl, + headers: headers, + episodeImageUrl: episodeImageUrl, + episodeImageData: episodeImageData, + totalEpisodes: totalEpisodes, + tmdbID: tmdbID, + isMovie: isMovie, + seasonNumber: seasonNumber + ) + + do { + _ = try await activity.activate() + Logger.shared.log("SharePlay invitation sent successfully", type: "SharePlay") + } catch { + Logger.shared.log("Failed to send SharePlay invitation: \(error.localizedDescription)", type: "Error") + + let alert = UIAlertController( + title: "SharePlay Unavailable", + message: "SharePlay is not available right now. Make sure you're connected to FaceTime or have SharePlay enabled in Control Center.", + preferredStyle: .alert + ) + alert.addAction(UIAlertAction(title: "OK", style: .default)) + viewController.present(alert, animated: true) + } + } + } +} diff --git a/Sora/MediaUtils/SharePlay/VideoWatchingActivity.swift b/Sora/MediaUtils/SharePlay/VideoWatchingActivity.swift new file mode 100644 index 0000000..f055604 --- /dev/null +++ b/Sora/MediaUtils/SharePlay/VideoWatchingActivity.swift @@ -0,0 +1,68 @@ +// +// VideoWatchingActivity.swift +// Sora +// +// Created by Francesco on 15/06/25. +// + +import UIKit +import Foundation +import GroupActivities + +struct VideoWatchingActivity: GroupActivity { + var metadata: GroupActivityMetadata { + var metadata = GroupActivityMetadata() + metadata.title = mediaTitle + metadata.subtitle = "Episode \(episodeNumber)" + + if let imageData = episodeImageData, + let uiImage = UIImage(data: imageData) { + metadata.previewImage = uiImage.cgImage + } + + metadata.type = .watchTogether + return metadata + } + + let mediaTitle: String + let episodeNumber: Int + let streamUrl: String + let subtitles: String + let aniListID: Int + let fullUrl: String + let headers: [String: String]? + let episodeImageUrl: String + let episodeImageData: Data? + let totalEpisodes: Int + let tmdbID: Int? + let isMovie: Bool + let seasonNumber: Int + + init(mediaTitle: String, + episodeNumber: Int, + streamUrl: String, + subtitles: String = "", + aniListID: Int = 0, + fullUrl: String, + headers: [String: String]? = nil, + episodeImageUrl: String = "", + episodeImageData: Data? = nil, + totalEpisodes: Int = 0, + tmdbID: Int? = nil, + isMovie: Bool = false, + seasonNumber: Int = 1) { + self.mediaTitle = mediaTitle + self.episodeNumber = episodeNumber + self.streamUrl = streamUrl + self.subtitles = subtitles + self.aniListID = aniListID + self.fullUrl = fullUrl + self.headers = headers + self.episodeImageUrl = episodeImageUrl + self.episodeImageData = episodeImageData + self.totalEpisodes = totalEpisodes + self.tmdbID = tmdbID + self.isMovie = isMovie + self.seasonNumber = seasonNumber + } +} diff --git a/Sora/Sora.entitlements b/Sora/Sora.entitlements index b14b07a..4c847eb 100644 --- a/Sora/Sora.entitlements +++ b/Sora/Sora.entitlements @@ -2,6 +2,10 @@ + com.apple.developer.group-session + + com.apple.developer.group-session.video + com.apple.security.app-sandbox com.apple.security.assets.movies.read-write diff --git a/Sulfur.xcodeproj/project.pbxproj b/Sulfur.xcodeproj/project.pbxproj index fb50560..5f2a3d8 100644 --- a/Sulfur.xcodeproj/project.pbxproj +++ b/Sulfur.xcodeproj/project.pbxproj @@ -40,6 +40,9 @@ 132AF1252D9995F900A0140B /* JSController-Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132AF1242D9995F900A0140B /* JSController-Search.swift */; }; 13367ECC2DF70698009CB33F /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = 13367ECB2DF70698009CB33F /* Nuke */; }; 13367ECE2DF70698009CB33F /* NukeUI in Frameworks */ = {isa = PBXBuildFile; productRef = 13367ECD2DF70698009CB33F /* NukeUI */; }; + 133CF6A62DFEBE9000BD13F9 /* VideoWatchingActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133CF6A32DFEBE8F00BD13F9 /* VideoWatchingActivity.swift */; }; + 133CF6A72DFEBE9000BD13F9 /* SharePlayManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133CF6A42DFEBE8F00BD13F9 /* SharePlayManager.swift */; }; + 133CF6A82DFEBE9000BD13F9 /* SharePlayCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133CF6A52DFEBE9000BD13F9 /* SharePlayCoordinator.swift */; }; 133D7C6E2D2BE2500075467E /* SoraApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133D7C6D2D2BE2500075467E /* SoraApp.swift */; }; 133D7C702D2BE2500075467E /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 133D7C6F2D2BE2500075467E /* ContentView.swift */; }; 133D7C722D2BE2520075467E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 133D7C712D2BE2520075467E /* Assets.xcassets */; }; @@ -137,6 +140,9 @@ 132AF1202D99951700A0140B /* JSController-Streams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSController-Streams.swift"; sourceTree = ""; }; 132AF1222D9995C300A0140B /* JSController-Details.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSController-Details.swift"; sourceTree = ""; }; 132AF1242D9995F900A0140B /* JSController-Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSController-Search.swift"; sourceTree = ""; }; + 133CF6A32DFEBE8F00BD13F9 /* VideoWatchingActivity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoWatchingActivity.swift; sourceTree = ""; }; + 133CF6A42DFEBE8F00BD13F9 /* SharePlayManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharePlayManager.swift; sourceTree = ""; }; + 133CF6A52DFEBE9000BD13F9 /* SharePlayCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharePlayCoordinator.swift; sourceTree = ""; }; 133D7C6A2D2BE2500075467E /* Sulfur.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sulfur.app; sourceTree = BUILT_PRODUCTS_DIR; }; 133D7C6D2D2BE2500075467E /* SoraApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoraApp.swift; sourceTree = ""; }; 133D7C6F2D2BE2500075467E /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; @@ -349,6 +355,27 @@ path = Analytics; sourceTree = ""; }; + 133CF6A22DFEBE8100BD13F9 /* SharePlay */ = { + isa = PBXGroup; + children = ( + 133CF6A42DFEBE8F00BD13F9 /* SharePlayManager.swift */, + 133CF6A52DFEBE9000BD13F9 /* SharePlayCoordinator.swift */, + 133CF6A32DFEBE8F00BD13F9 /* VideoWatchingActivity.swift */, + ); + path = SharePlay; + sourceTree = ""; + }; + 133CF6A92DFEBEAB00BD13F9 /* MediaUtils */ = { + isa = PBXGroup; + children = ( + 133CF6A22DFEBE8100BD13F9 /* SharePlay */, + 13DC0C442D302C6A00D0F966 /* NormalPlayer */, + 13EA2BD02D32D97400C1EBD7 /* CustomPlayer */, + 13C0E5E82D5F85DD00E7F619 /* ContinueWatching */, + ); + path = MediaUtils; + sourceTree = ""; + }; 133D7C612D2BE2500075467E = { isa = PBXGroup; children = ( @@ -368,15 +395,16 @@ 133D7C6C2D2BE2500075467E /* Sora */ = { isa = PBXGroup; children = ( - 0488FA9B2DFDF385007575E1 /* ar.lproj */, - 0488FA972DFDF334007575E1 /* fr.lproj */, - 0488FA912DFDE724007575E1 /* en.lproj */, 0488FA942DFDE724007575E1 /* nl.lproj */, + 0488FA912DFDE724007575E1 /* en.lproj */, + 0488FA972DFDF334007575E1 /* fr.lproj */, + 0488FA9B2DFDF385007575E1 /* ar.lproj */, 130C6BF82D53A4C200DC1432 /* Sora.entitlements */, 13DC0C412D2EC9BA00D0F966 /* Info.plist */, 13103E802D589D6C000F0673 /* Tracking Services */, - 133D7C852D2BE2640075467E /* Utils */, + 133CF6A92DFEBEAB00BD13F9 /* MediaUtils */, 133D7C7B2D2BE2630075467E /* Views */, + 133D7C852D2BE2640075467E /* Utils */, 133D7C6D2D2BE2500075467E /* SoraApp.swift */, 133D7C6F2D2BE2500075467E /* ContentView.swift */, 133D7C712D2BE2520075467E /* Assets.xcassets */, @@ -446,10 +474,8 @@ 133D7C8A2D2BE2640075467E /* JSLoader */, 1327FBA52D758CEA00FC6689 /* Analytics */, 133D7C862D2BE2640075467E /* Extensions */, - 13DC0C442D302C6A00D0F966 /* MediaPlayer */, 13103E8C2D58E037000F0673 /* SkeletonCells */, 72443C832DC8046500A61321 /* DownloadUtils */, - 13C0E5E82D5F85DD00E7F619 /* ContinueWatching */, ); path = Utils; sourceTree = ""; @@ -593,14 +619,13 @@ path = Auth; sourceTree = ""; }; - 13DC0C442D302C6A00D0F966 /* MediaPlayer */ = { + 13DC0C442D302C6A00D0F966 /* NormalPlayer */ = { isa = PBXGroup; children = ( - 13EA2BD02D32D97400C1EBD7 /* CustomPlayer */, 13DC0C452D302C7500D0F966 /* VideoPlayer.swift */, 13EA2BD82D32D98400C1EBD7 /* NormalPlayer.swift */, ); - path = MediaPlayer; + path = NormalPlayer; sourceTree = ""; }; 13E62FBF2DABC3A20007E259 /* Trakt */ = { @@ -806,6 +831,7 @@ 138AA1B82D2D66FD0021F9DF /* EpisodeCell.swift in Sources */, 722248662DCBC13E00CABE2D /* JSController-Downloads.swift in Sources */, 133D7C8C2D2BE2640075467E /* SearchView.swift in Sources */, + 133CF6A62DFEBE9000BD13F9 /* VideoWatchingActivity.swift in Sources */, 13DB468E2D90093A008CBC03 /* Anilist-Token.swift in Sources */, 1EAC7A322D888BC50083984D /* MusicProgressSlider.swift in Sources */, 722248632DCBAA4700CABE2D /* JSController-HeaderManager.swift in Sources */, @@ -813,6 +839,7 @@ 133D7C922D2BE2640075467E /* URLSession.swift in Sources */, 0457C5A12DE78385000AFBD9 /* BookmarksDetailView.swift in Sources */, 133D7C912D2BE2640075467E /* SettingsViewModule.swift in Sources */, + 133CF6A82DFEBE9000BD13F9 /* SharePlayCoordinator.swift in Sources */, 13E62FC22DABC5830007E259 /* Trakt-Login.swift in Sources */, 133F55BB2D33B55100E08EEA /* LibraryManager.swift in Sources */, 13E62FC42DABC58C0007E259 /* Trakt-Token.swift in Sources */, @@ -840,6 +867,7 @@ 13C0E5EA2D5F85EA00E7F619 /* ContinueWatchingManager.swift in Sources */, 13637B8A2DE0EA1100BDA2FC /* UserDefaults.swift in Sources */, 0457C59D2DE78267000AFBD9 /* BookmarkGridView.swift in Sources */, + 133CF6A72DFEBE9000BD13F9 /* SharePlayManager.swift in Sources */, 0457C59E2DE78267000AFBD9 /* BookmarkLink.swift in Sources */, 0457C59F2DE78267000AFBD9 /* BookmarkGridItemView.swift in Sources */, );