From e6b766ab94cd7079ab41893da32d63e7613481ec Mon Sep 17 00:00:00 2001 From: Francesco <100066266+cranci1@users.noreply.github.com> Date: Sun, 1 Jun 2025 18:32:42 +0200 Subject: [PATCH] test, idk if it compiles tbh --- Sora/Sora.entitlements | 2 - Sora/Utils/MediaPlayer/VideoPlayer.swift | 171 +------------------ Sora/Utils/MediaPlayer/WatchTogether.swift | 21 --- Sora/Views/MediaInfoView/MediaInfoView.swift | 47 ++++- Sulfur.xcodeproj/project.pbxproj | 4 - 5 files changed, 45 insertions(+), 200 deletions(-) delete mode 100644 Sora/Utils/MediaPlayer/WatchTogether.swift diff --git a/Sora/Sora.entitlements b/Sora/Sora.entitlements index af2968f..e384bb3 100644 --- a/Sora/Sora.entitlements +++ b/Sora/Sora.entitlements @@ -2,8 +2,6 @@ - com.apple.developer.group-session - com.apple.security.app-sandbox com.apple.security.assets.movies.read-write diff --git a/Sora/Utils/MediaPlayer/VideoPlayer.swift b/Sora/Utils/MediaPlayer/VideoPlayer.swift index 58eacf8..58a9a65 100644 --- a/Sora/Utils/MediaPlayer/VideoPlayer.swift +++ b/Sora/Utils/MediaPlayer/VideoPlayer.swift @@ -7,8 +7,6 @@ import UIKit import AVKit -import MediaPlayer -import GroupActivities class VideoPlayerViewController: UIViewController { let module: ScrapingModule @@ -21,16 +19,12 @@ class VideoPlayerViewController: UIViewController { var subtitles: String = "" var aniListID: Int = 0 var headers: [String:String]? = nil - var totalEpisodes: Int = 0 + var episodeNumber: Int = 0 var episodeImageUrl: String = "" var mediaTitle: String = "" - private var currentArtwork: MPMediaItemArtwork? - private var groupSession: GroupSession? - private var messenger: GroupSessionMessenger? - init(module: ScrapingModule) { self.module = module super.init(nibName: nil, bundle: nil) @@ -43,10 +37,6 @@ class VideoPlayerViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - setupSharePlay() - setupNowPlaying() - setupRemoteTransportControls() - guard let streamUrl = streamUrl, let url = URL(string: streamUrl) else { return } @@ -60,21 +50,12 @@ class VideoPlayerViewController: UIViewController { request.addValue("\(module.metadata.baseUrl)", forHTTPHeaderField: "Referer") request.addValue("\(module.metadata.baseUrl)", forHTTPHeaderField: "Origin") } - request.addValue("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36", forHTTPHeaderField: "User-Agent") let asset = AVURLAsset(url: url, options: ["AVURLAssetHTTPHeaderFieldsKey": request.allHTTPHeaderFields ?? [:]]) let playerItem = AVPlayerItem(asset: asset) player = AVPlayer(playerItem: playerItem) - player?.allowsExternalPlayback = false - - do { - try AVAudioSession.sharedInstance().setCategory(.playback, mode: .moviePlayback) - try AVAudioSession.sharedInstance().setActive(true) - } catch { - print("Failed to set audio session category: \(error)") - } playerViewController = NormalPlayer() playerViewController?.player = player @@ -99,153 +80,6 @@ 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) { - 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() { - var nowPlayingInfo: [String: Any] = [ - MPMediaItemPropertyTitle: mediaTitle, - MPMediaItemPropertyArtist: "Episode \(episodeNumber)", - MPNowPlayingInfoPropertyPlaybackRate: player?.rate ?? 1.0 - ] - - if let player = player, let currentItem = player.currentItem { - nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = currentItem.currentTime().seconds - nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = currentItem.duration.seconds - } - - MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo - - if let imageUrl = URL(string: episodeImageUrl) { - URLSession.custom.dataTask(with: imageUrl) { [weak self] data, _, _ in - guard let self = self, - let data = data, - let image = UIImage(data: data) else { return } - - DispatchQueue.main.async { - self.currentArtwork = MPMediaItemArtwork(boundsSize: image.size) { _ in - return image - } - self.updateNowPlayingInfo() - } - }.resume() - } - - let interval = CMTime(seconds: 0.5, preferredTimescale: CMTimeScale(NSEC_PER_SEC)) - player?.addPeriodicTimeObserver(forInterval: interval, queue: .main) { [weak self] _ in - self?.updateNowPlayingInfo() - } - } - - func updateNowPlayingInfo() { - guard let player = player, - let currentItem = player.currentItem else { return } - - var nowPlayingInfo: [String: Any] = [ - MPMediaItemPropertyTitle: mediaTitle, - MPMediaItemPropertyArtist: "Episode \(episodeNumber)", - MPNowPlayingInfoPropertyElapsedPlaybackTime: currentItem.currentTime().seconds, - MPMediaItemPropertyPlaybackDuration: currentItem.duration.seconds, - MPNowPlayingInfoPropertyPlaybackRate: player.rate - ] - - if let artwork = currentArtwork { - nowPlayingInfo[MPMediaItemPropertyArtwork] = artwork - } - - MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo - } - - private func setupRemoteTransportControls() { - let commandCenter = MPRemoteCommandCenter.shared() - - commandCenter.playCommand.addTarget { [weak self] _ in - self?.player?.play() - self?.updateNowPlayingInfo() - return .success - } - - commandCenter.pauseCommand.addTarget { [weak self] _ in - self?.player?.pause() - self?.updateNowPlayingInfo() - return .success - } - - commandCenter.seekForwardCommand.isEnabled = false - commandCenter.seekBackwardCommand.isEnabled = false - } - override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) player?.play() @@ -254,7 +88,6 @@ class VideoPlayerViewController: UIViewController { override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) - groupSession?.leave() if let playbackSpeed = player?.rate { UserDefaults.standard.set(playbackSpeed, forKey: "lastPlaybackSpeed") } @@ -342,11 +175,9 @@ class VideoPlayerViewController: UIViewController { } deinit { - groupSession?.leave() player?.pause() if let timeObserverToken = timeObserverToken { player?.removeTimeObserver(timeObserverToken) } - MPNowPlayingInfoCenter.default().nowPlayingInfo = nil } } diff --git a/Sora/Utils/MediaPlayer/WatchTogether.swift b/Sora/Utils/MediaPlayer/WatchTogether.swift deleted file mode 100644 index 23d5b6d..0000000 --- a/Sora/Utils/MediaPlayer/WatchTogether.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// 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 - } -} diff --git a/Sora/Views/MediaInfoView/MediaInfoView.swift b/Sora/Views/MediaInfoView/MediaInfoView.swift index 6d7275e..fbf6ba1 100644 --- a/Sora/Views/MediaInfoView/MediaInfoView.swift +++ b/Sora/Views/MediaInfoView/MediaInfoView.swift @@ -20,7 +20,7 @@ struct MediaItem: Identifiable { struct MediaInfoView: View { let title: String - let imageUrl: String + @State var imageUrl: String let href: String let module: ScrapingModule @@ -77,6 +77,7 @@ struct MediaInfoView: View { @State private var showRangeInput: Bool = false @State private var isBulkDownloading: Bool = false @State private var bulkDownloadProgress: String = "" + @State private var tmdbType: TMDBFetcher.MediaType? = nil private var isGroupedBySeasons: Bool { return groupedEpisodes().count > 1 @@ -494,10 +495,19 @@ struct MediaInfoView: View { Label("Open in AniList", systemImage: "link") } } + + if UserDefaults.standard.string(forKey: "metadataProviders") ?? "TMDB" == "AniList" { + Button(action: { + isMatchingPresented = true + }) { + Label("Match with AniList", systemImage: "magnifyingglass") + } + } + Button(action: { - isMatchingPresented = true + fetchTMDBPosterImageAndSet() }) { - Label("Match with AniList", systemImage: "magnifyingglass") + Label("Use TMDB Poster Image", systemImage: "photo") } Divider() @@ -781,11 +791,13 @@ struct MediaInfoView: View { private func fetchMetadataIDIfNeeded() { let provider = UserDefaults.standard.string(forKey: "metadataProviders") ?? "TMDB" let cleaned = cleanTitle(title) + if provider == "TMDB" { tmdbID = nil tmdbFetcher.fetchBestMatchID(for: cleaned) { id, type in DispatchQueue.main.async { self.tmdbID = id + self.tmdbType = type Logger.shared.log("Fetched TMDB ID: \(id ?? -1) (\(type?.rawValue ?? "unknown")) for title: \(cleaned)", type: "Debug") } } @@ -805,6 +817,35 @@ struct MediaInfoView: View { } } + private func fetchTMDBPosterImageAndSet() { + guard let tmdbID = tmdbID, let tmdbType = tmdbType else { return } + let apiType = tmdbType.rawValue + let urlString = "https://api.themoviedb.org/3/\(apiType)/\(tmdbID)?api_key=738b4edd0a156cc126dc4a4b8aea4aca" + guard let url = URL(string: urlString) else { return } + + let tmdbImageWidth = UserDefaults.standard.string(forKey: "tmdbImageWidth") ?? "780" + + URLSession.custom.dataTask(with: url) { data, _, error in + guard let data = data, error == nil else { return } + do { + if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any], + let posterPath = json["poster_path"] as? String { + let imageUrl: String + if tmdbImageWidth == "original" { + imageUrl = "https://image.tmdb.org/t/p/original\(posterPath)" + } else { + imageUrl = "https://image.tmdb.org/t/p/w\(tmdbImageWidth)\(posterPath)" + } + DispatchQueue.main.async { + self.imageUrl = imageUrl + } + } + } catch { + Logger.shared.log("Failed to parse TMDB poster: \(error.localizedDescription)", type: "Error") + } + }.resume() + } + private func markAllPreviousEpisodesAsWatched(ep: EpisodeLink, inSeason: Bool) { let userDefaults = UserDefaults.standard var updates = [String: Double]() diff --git a/Sulfur.xcodeproj/project.pbxproj b/Sulfur.xcodeproj/project.pbxproj index c262b56..ddc6997 100644 --- a/Sulfur.xcodeproj/project.pbxproj +++ b/Sulfur.xcodeproj/project.pbxproj @@ -22,7 +22,6 @@ 04F08EDF2DE10C1D006B29D9 /* TabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04F08EDE2DE10C1A006B29D9 /* TabBar.swift */; }; 04F08EE22DE10C40006B29D9 /* TabItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04F08EE12DE10C27006B29D9 /* TabItem.swift */; }; 04F08EE42DE10D6F006B29D9 /* AllBookmarks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04F08EE32DE10D6B006B29D9 /* AllBookmarks.swift */; }; - 130A810B2DE5F32400614732 /* WatchTogether.swift in Sources */ = {isa = PBXBuildFile; fileRef = 130A810A2DE5F32400614732 /* WatchTogether.swift */; }; 130C6BFA2D53AB1F00DC1432 /* SettingsViewData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 130C6BF92D53AB1F00DC1432 /* SettingsViewData.swift */; }; 13103E8B2D58E028000F0673 /* ScrollViewBottomPadding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13103E8A2D58E028000F0673 /* ScrollViewBottomPadding.swift */; }; 13103E8E2D58E04A000F0673 /* SkeletonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13103E8D2D58E04A000F0673 /* SkeletonCell.swift */; }; @@ -121,7 +120,6 @@ 04F08EDE2DE10C1A006B29D9 /* TabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBar.swift; sourceTree = ""; }; 04F08EE12DE10C27006B29D9 /* TabItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabItem.swift; sourceTree = ""; }; 04F08EE32DE10D6B006B29D9 /* AllBookmarks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AllBookmarks.swift; sourceTree = ""; }; - 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 = ""; }; 130C6BF92D53AB1F00DC1432 /* SettingsViewData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewData.swift; sourceTree = ""; }; 13103E8A2D58E028000F0673 /* ScrollViewBottomPadding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollViewBottomPadding.swift; sourceTree = ""; }; @@ -556,7 +554,6 @@ isa = PBXGroup; children = ( 13EA2BD02D32D97400C1EBD7 /* CustomPlayer */, - 130A810A2DE5F32400614732 /* WatchTogether.swift */, 13DC0C452D302C7500D0F966 /* VideoPlayer.swift */, 13EA2BD82D32D98400C1EBD7 /* NormalPlayer.swift */, ); @@ -720,7 +717,6 @@ 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 */,