mirror of
https://github.com/cranci1/Sora.git
synced 2026-03-11 17:45:37 +00:00
ok well lets test
This commit is contained in:
parent
634bda6a94
commit
0ca54ea38d
15 changed files with 351 additions and 9 deletions
|
|
@ -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<AnyCancellable>()
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
78
Sora/MediaUtils/SharePlay/SharePlayCoordinator.swift
Normal file
78
Sora/MediaUtils/SharePlay/SharePlayCoordinator.swift
Normal file
|
|
@ -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<AnyCancellable>()
|
||||
private var groupSession: GroupSession<VideoWatchingActivity>?
|
||||
|
||||
@Published var isEligibleForGroupSession = false
|
||||
@Published var groupSessionState: GroupSession<VideoWatchingActivity>.State = .waiting
|
||||
|
||||
private var playbackCoordinator: AVPlayerPlaybackCoordinator?
|
||||
|
||||
func configureGroupSession() {
|
||||
Task {
|
||||
for await session in VideoWatchingActivity.sessions() {
|
||||
await configureGroupSession(session)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func configureGroupSession(_ groupSession: GroupSession<VideoWatchingActivity>) 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
|
||||
}
|
||||
}
|
||||
77
Sora/MediaUtils/SharePlay/SharePlayManager.swift
Normal file
77
Sora/MediaUtils/SharePlay/SharePlayManager.swift
Normal file
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
68
Sora/MediaUtils/SharePlay/VideoWatchingActivity.swift
Normal file
68
Sora/MediaUtils/SharePlay/VideoWatchingActivity.swift
Normal file
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,10 @@
|
|||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.developer.group-session</key>
|
||||
<true/>
|
||||
<key>com.apple.developer.group-session.video</key>
|
||||
<true/>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.assets.movies.read-write</key>
|
||||
|
|
|
|||
|
|
@ -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 = "<group>"; };
|
||||
132AF1222D9995C300A0140B /* JSController-Details.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSController-Details.swift"; sourceTree = "<group>"; };
|
||||
132AF1242D9995F900A0140B /* JSController-Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JSController-Search.swift"; sourceTree = "<group>"; };
|
||||
133CF6A32DFEBE8F00BD13F9 /* VideoWatchingActivity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoWatchingActivity.swift; sourceTree = "<group>"; };
|
||||
133CF6A42DFEBE8F00BD13F9 /* SharePlayManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharePlayManager.swift; sourceTree = "<group>"; };
|
||||
133CF6A52DFEBE9000BD13F9 /* SharePlayCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharePlayCoordinator.swift; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
133D7C6F2D2BE2500075467E /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -349,6 +355,27 @@
|
|||
path = Analytics;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
133CF6A22DFEBE8100BD13F9 /* SharePlay */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
133CF6A42DFEBE8F00BD13F9 /* SharePlayManager.swift */,
|
||||
133CF6A52DFEBE9000BD13F9 /* SharePlayCoordinator.swift */,
|
||||
133CF6A32DFEBE8F00BD13F9 /* VideoWatchingActivity.swift */,
|
||||
);
|
||||
path = SharePlay;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
133CF6A92DFEBEAB00BD13F9 /* MediaUtils */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
133CF6A22DFEBE8100BD13F9 /* SharePlay */,
|
||||
13DC0C442D302C6A00D0F966 /* NormalPlayer */,
|
||||
13EA2BD02D32D97400C1EBD7 /* CustomPlayer */,
|
||||
13C0E5E82D5F85DD00E7F619 /* ContinueWatching */,
|
||||
);
|
||||
path = MediaUtils;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
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 = "<group>";
|
||||
|
|
@ -593,14 +619,13 @@
|
|||
path = Auth;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
13DC0C442D302C6A00D0F966 /* MediaPlayer */ = {
|
||||
13DC0C442D302C6A00D0F966 /* NormalPlayer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13EA2BD02D32D97400C1EBD7 /* CustomPlayer */,
|
||||
13DC0C452D302C7500D0F966 /* VideoPlayer.swift */,
|
||||
13EA2BD82D32D98400C1EBD7 /* NormalPlayer.swift */,
|
||||
);
|
||||
path = MediaPlayer;
|
||||
path = NormalPlayer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
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 */,
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue