From 5ccbbf1c1b1262362cc840ebde5400ff240f3de1 Mon Sep 17 00:00:00 2001 From: cranci1 <100066266+cranci1@users.noreply.github.com> Date: Mon, 23 Dec 2024 13:00:36 +0100 Subject: [PATCH] custom player start --- Sora.xcodeproj/project.pbxproj | 28 +++ .../UserInterfaceState.xcuserstate | Bin 59173 -> 68382 bytes .../Components/Double+Extension.swift | 30 +++ .../Components/MusicProgressSlider.swift | 101 ++++++++ Sora/Utils/CustomPlayer/CustomPlayer.swift | 233 ++++++++++++++++++ Sora/Utils/Player/VideoPlayerView.swift | 2 +- Sora/Views/AnimeViews/AnimeInfoView.swift | 13 + .../SubPages/SettingsPlayerView.swift | 28 ++- 8 files changed, 428 insertions(+), 7 deletions(-) create mode 100644 Sora/Utils/CustomPlayer/Components/Double+Extension.swift create mode 100644 Sora/Utils/CustomPlayer/Components/MusicProgressSlider.swift create mode 100644 Sora/Utils/CustomPlayer/CustomPlayer.swift diff --git a/Sora.xcodeproj/project.pbxproj b/Sora.xcodeproj/project.pbxproj index 658f976..755cd34 100644 --- a/Sora.xcodeproj/project.pbxproj +++ b/Sora.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 1308CFBC2D19844A004CD38C /* Double+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1308CFBB2D19844A004CD38C /* Double+Extension.swift */; }; + 1308CFBE2D19844D004CD38C /* MusicProgressSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1308CFBD2D19844D004CD38C /* MusicProgressSlider.swift */; }; + 1308CFC12D198466004CD38C /* CustomPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1308CFC02D198466004CD38C /* CustomPlayer.swift */; }; 132417842D13198000B4F2D2 /* SoraApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132417832D13198000B4F2D2 /* SoraApp.swift */; }; 132417862D13198000B4F2D2 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 132417852D13198000B4F2D2 /* ContentView.swift */; }; 132417882D13198200B4F2D2 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 132417872D13198200B4F2D2 /* Assets.xcassets */; }; @@ -39,6 +42,9 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 1308CFBB2D19844A004CD38C /* Double+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Double+Extension.swift"; sourceTree = ""; }; + 1308CFBD2D19844D004CD38C /* MusicProgressSlider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MusicProgressSlider.swift; sourceTree = ""; }; + 1308CFC02D198466004CD38C /* CustomPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomPlayer.swift; sourceTree = ""; }; 132417802D13198000B4F2D2 /* Sora.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Sora.app; sourceTree = BUILT_PRODUCTS_DIR; }; 132417832D13198000B4F2D2 /* SoraApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SoraApp.swift; sourceTree = ""; }; 132417852D13198000B4F2D2 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; @@ -83,6 +89,24 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 1308CFBA2D19843E004CD38C /* CustomPlayer */ = { + isa = PBXGroup; + children = ( + 1308CFC02D198466004CD38C /* CustomPlayer.swift */, + 1308CFBF2D198450004CD38C /* Components */, + ); + path = CustomPlayer; + sourceTree = ""; + }; + 1308CFBF2D198450004CD38C /* Components */ = { + isa = PBXGroup; + children = ( + 1308CFBD2D19844D004CD38C /* MusicProgressSlider.swift */, + 1308CFBB2D19844A004CD38C /* Double+Extension.swift */, + ); + path = Components; + sourceTree = ""; + }; 132417772D13198000B4F2D2 = { isa = PBXGroup; children = ( @@ -124,6 +148,7 @@ 132417912D1319E800B4F2D2 /* Utils */ = { isa = PBXGroup; children = ( + 1308CFBA2D19843E004CD38C /* CustomPlayer */, 132417922D1319E800B4F2D2 /* Miru */, 132417942D1319E800B4F2D2 /* Extensions */, 132417962D1319E800B4F2D2 /* History */, @@ -328,10 +353,12 @@ 132417BB2D131A0600B4F2D2 /* SettingsIUView.swift in Sources */, 132417C42D131A0600B4F2D2 /* AnimeInfoExtraction.swift in Sources */, 132417B82D131A0600B4F2D2 /* SearchView.swift in Sources */, + 1308CFBC2D19844A004CD38C /* Double+Extension.swift in Sources */, 132417D92D1328B900B4F2D2 /* VideoPlayerView.swift in Sources */, 1324179F2D1319E800B4F2D2 /* Notification.swift in Sources */, 132417BD2D131A0600B4F2D2 /* SettingsModuleView.swift in Sources */, 132417BC2D131A0600B4F2D2 /* SettingsLogsView.swift in Sources */, + 1308CFC12D198466004CD38C /* CustomPlayer.swift in Sources */, 132417A22D1319E800B4F2D2 /* ModulesManager.swift in Sources */, 132417862D13198000B4F2D2 /* ContentView.swift in Sources */, 132417C22D131A0600B4F2D2 /* LibraryView.swift in Sources */, @@ -347,6 +374,7 @@ 132417C12D131A0600B4F2D2 /* LibraryManager.swift in Sources */, 132417BA2D131A0600B4F2D2 /* SettingsAboutView.swift in Sources */, 1324179E2D1319E800B4F2D2 /* MiruDataStruct.swift in Sources */, + 1308CFBE2D19844D004CD38C /* MusicProgressSlider.swift in Sources */, 132417D52D13240200B4F2D2 /* EpisodeCell.swift in Sources */, 132417A02D1319E800B4F2D2 /* HistoryManager.swift in Sources */, ); diff --git a/Sora.xcodeproj/project.xcworkspace/xcuserdata/Francesco.xcuserdatad/UserInterfaceState.xcuserstate b/Sora.xcodeproj/project.xcworkspace/xcuserdata/Francesco.xcuserdatad/UserInterfaceState.xcuserstate index d7214770e53f4d7863e467e58f1cd3aa0942112f..553de8006b1749e1f83b9d1328d58868cf5add69 100644 GIT binary patch literal 68382 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Π}>Ak=q3Cz-iBYnuj1|2+txeQyViTw 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 diff --git a/Sora/Utils/CustomPlayer/Components/Double+Extension.swift b/Sora/Utils/CustomPlayer/Components/Double+Extension.swift new file mode 100644 index 0000000..5bf31ed --- /dev/null +++ b/Sora/Utils/CustomPlayer/Components/Double+Extension.swift @@ -0,0 +1,30 @@ +// +// Double+Extension.swift +// AppleMusicSlider +// +// Created by Pratik on 14/01/23. +// +// Thanks to pratikg29 for this code inside his open source project "https://github.com/pratikg29/Custom-Slider-Control?ref=iosexample.com" +// + +import Foundation + +extension Double { + func asTimeString(style: DateComponentsFormatter.UnitsStyle) -> String { + let formatter = DateComponentsFormatter() + formatter.allowedUnits = [.minute, .second] + formatter.unitsStyle = style + formatter.zeroFormattingBehavior = .pad + return formatter.string(from: self) ?? "" + } +} + +extension BinaryFloatingPoint { + func asTimeString(style: DateComponentsFormatter.UnitsStyle) -> String { + let formatter = DateComponentsFormatter() + formatter.allowedUnits = [.minute, .second] + formatter.unitsStyle = style + formatter.zeroFormattingBehavior = .pad + return formatter.string(from: TimeInterval(self)) ?? "" + } +} diff --git a/Sora/Utils/CustomPlayer/Components/MusicProgressSlider.swift b/Sora/Utils/CustomPlayer/Components/MusicProgressSlider.swift new file mode 100644 index 0000000..afb39dd --- /dev/null +++ b/Sora/Utils/CustomPlayer/Components/MusicProgressSlider.swift @@ -0,0 +1,101 @@ +// +// MusicProgressSlider.swift +// Custom Seekbar +// +// Created by Pratik on 08/01/23. +// +// Thanks to pratikg29 for this code inside his open source project "https://github.com/pratikg29/Custom-Slider-Control?ref=iosexample.com" +// + +import SwiftUI + +struct MusicProgressSlider: View { + @Binding var value: T + let inRange: ClosedRange + let activeFillColor: Color + let fillColor: Color + let emptyColor: Color + let height: CGFloat + let onEditingChanged: (Bool) -> Void + + @State private var localRealProgress: T = 0 + @State private var localTempProgress: T = 0 + @GestureState private var isActive: Bool = false + + var body: some View { + GeometryReader { bounds in + ZStack { + VStack { + ZStack(alignment: .center) { + Capsule() + .fill(emptyColor) + Capsule() + .fill(isActive ? activeFillColor : fillColor) + .mask({ + HStack { + Rectangle() + .frame(width: max(bounds.size.width * CGFloat((localRealProgress + localTempProgress)), 0), alignment: .leading) + Spacer(minLength: 0) + } + }) + } + + HStack { + Text(value.asTimeString(style: .positional)) + Spacer(minLength: 0) + Text("-" + (inRange.upperBound - value).asTimeString(style: .positional)) + } + .font(.system(size: 12)) + .foregroundColor(isActive ? fillColor : emptyColor) + } + .frame(width: isActive ? bounds.size.width * 1.04 : bounds.size.width, alignment: .center) + .animation(animation, value: isActive) + } + .frame(width: bounds.size.width, height: bounds.size.height, alignment: .center) + .contentShape(Rectangle()) + .gesture(DragGesture(minimumDistance: 0, coordinateSpace: .local) + .updating($isActive) { value, state, transaction in + state = true + } + .onChanged { gesture in + localTempProgress = T(gesture.translation.width / bounds.size.width) + value = max(min(getPrgValue(), inRange.upperBound), inRange.lowerBound) + }.onEnded { value in + localRealProgress = max(min(localRealProgress + localTempProgress, 1), 0) + localTempProgress = 0 + }) + .onChange(of: isActive) { newValue in + value = max(min(getPrgValue(), inRange.upperBound), inRange.lowerBound) + onEditingChanged(newValue) + } + .onAppear { + localRealProgress = getPrgPercentage(value) + } + .onChange(of: value) { newValue in + if !isActive { + localRealProgress = getPrgPercentage(newValue) + } + } + } + .frame(height: isActive ? height * 1.25 : height, alignment: .center) + } + + private var animation: Animation { + if isActive { + return .spring() + } else { + return .spring(response: 0.5, dampingFraction: 0.5, blendDuration: 0.6) + } + } + + private func getPrgPercentage(_ value: T) -> T { + let range = inRange.upperBound - inRange.lowerBound + let correctedStartValue = value - inRange.lowerBound + let percentage = correctedStartValue / range + return percentage + } + + private func getPrgValue() -> T { + return ((localRealProgress + localTempProgress) * (inRange.upperBound - inRange.lowerBound)) + inRange.lowerBound + } +} diff --git a/Sora/Utils/CustomPlayer/CustomPlayer.swift b/Sora/Utils/CustomPlayer/CustomPlayer.swift new file mode 100644 index 0000000..e902749 --- /dev/null +++ b/Sora/Utils/CustomPlayer/CustomPlayer.swift @@ -0,0 +1,233 @@ +// +// ContentView.swift +// test2 +// +// Created by Francesco on 20/12/24. +// + +import SwiftUI +import AVKit + +struct CustomVideoPlayer: UIViewControllerRepresentable { + let player: AVPlayer + + func makeUIViewController(context: Context) -> AVPlayerViewController { + let controller = CustomAVPlayerViewController() + controller.player = player + controller.showsPlaybackControls = false + player.play() + return controller + } + + func updateUIViewController(_ uiViewController: AVPlayerViewController, context: Context) { + // yes? Like the plural of the famous american rapper ye? -IBHRAD + } +} + +class CustomAVPlayerViewController: AVPlayerViewController { + override var supportedInterfaceOrientations: UIInterfaceOrientationMask { + if UserDefaults.standard.bool(forKey: "alwaysLandscape") { + return .landscape + } else { + return .all + } + } +} + +struct CustomMediaPlayer: View { + @State private var player: AVPlayer + @State private var isPlaying = true + @State private var currentTime: Double = 0.0 + @State private var duration: Double = 0.0 + @State private var showControls = false + @State private var inactivityTimer: Timer? + + init(urlString: String) { + guard let url = URL(string: urlString) else { + fatalError("Invalid URL string") + } + _player = State(initialValue: AVPlayer(url: url)) + } + + var body: some View { + VStack { + ZStack { + CustomVideoPlayer(player: player) + .onAppear { + player.addPeriodicTimeObserver(forInterval: CMTime(seconds: 1, preferredTimescale: 600), queue: .main) { time in + currentTime = time.seconds + if let itemDuration = player.currentItem?.duration.seconds, itemDuration.isFinite && !itemDuration.isNaN { + duration = itemDuration + } + } + startUpdatingCurrentTime() + } + .edgesIgnoringSafeArea(.all) + .overlay( + Group { + if showControls { + Color.black.opacity(0.5) + .edgesIgnoringSafeArea(.all) + HStack(spacing: 20) { + Button(action: { + currentTime = max(currentTime - 10, 0) + player.seek(to: CMTime(seconds: currentTime, preferredTimescale: 600)) + }) { + Image(systemName: "gobackward.10") + } + .foregroundColor(.white) + .font(.system(size: 25)) + .contentShape(Rectangle()) + .frame(width: 60, height: 60) + + Button(action: { + if isPlaying { + player.pause() + } else { + player.play() + } + isPlaying.toggle() + }) { + Image(systemName: isPlaying ? "pause.fill" : "play.fill") + } + .foregroundColor(.white) + .font(.system(size: 45)) + .contentShape(Rectangle()) + .frame(width: 80, height: 80) + + Button(action: { + currentTime = min(currentTime + 10, duration) + player.seek(to: CMTime(seconds: currentTime, preferredTimescale: 600)) + }) { + Image(systemName: "goforward.10") + } + .foregroundColor(.white) + .font(.system(size: 25)) + .contentShape(Rectangle()) + .frame(width: 60, height: 60) + } + } + }, + alignment: .center + ) + .onTapGesture { + showControls.toggle() + } + + VStack { + Spacer() + if showControls { + VStack { + Spacer() + HStack { + Spacer() + Menu { + Menu("Playback Speed") { + Button(action: { + player.rate = 0.25 + if player.timeControlStatus != .playing { + player.pause() + } + }) { + Label("0.25", systemImage: "tortoise") + } + Button(action: { + player.rate = 0.5 + if player.timeControlStatus != .playing { + player.pause() + } + }) { + Label("0.5", systemImage: "tortoise.fill") + } + Button(action: { + player.rate = 0.75 + if player.timeControlStatus != .playing { + player.pause() + } + }) { + Label("0.75", systemImage: "hare") + } + Button(action: { + player.rate = 1.0 + if player.timeControlStatus != .playing { + player.pause() + } + }) { + Label("1.0", systemImage: "hare.fill") + } + Button(action: { + player.rate = 1.25 + if player.timeControlStatus != .playing { + player.pause() + } + }) { + Label("1.25", systemImage: "speedometer") + } + Button(action: { + player.rate = 1.5 + if player.timeControlStatus != .playing { + player.pause() + } + }) { + Label("1.5", systemImage: "speedometer") + } + Button(action: { + player.rate = 1.75 + if player.timeControlStatus != .playing { + player.pause() + } + }) { + Label("1.75", systemImage: "speedometer") + } + Button(action: { + player.rate = 2.0 + if player.timeControlStatus != .playing { + player.pause() + } + }) { + Label("2.0", systemImage: "speedometer") + } + } + } label: { + Image(systemName: "ellipsis.circle") + .foregroundColor(.white) + .font(.system(size: 15)) + } + } + .padding(.trailing, 10) + + MusicProgressSlider( + value: $currentTime, + inRange: 0...duration, + activeFillColor: .white, + fillColor: .white.opacity(0.5), + emptyColor: .white.opacity(0.3), + height: 28, + onEditingChanged: { editing in + if !editing { + player.seek(to: CMTime(seconds: currentTime, preferredTimescale: 600)) + } + } + ) + .frame(height: 45) + .padding(.bottom, 10) + } + } + } + .onAppear { + startUpdatingCurrentTime() + } + .onDisappear { + player.pause() + inactivityTimer?.invalidate() + } + } + } + } + + private func startUpdatingCurrentTime() { + Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in + currentTime = player.currentTime().seconds + } + } +} \ No newline at end of file diff --git a/Sora/Utils/Player/VideoPlayerView.swift b/Sora/Utils/Player/VideoPlayerView.swift index 2dcc942..1d4f422 100644 --- a/Sora/Utils/Player/VideoPlayerView.swift +++ b/Sora/Utils/Player/VideoPlayerView.swift @@ -23,7 +23,7 @@ class VideoPlayerViewController: UIViewController { } player = AVPlayer(url: url) - playerViewController = AVPlayerViewController() + playerViewController = NormalPlayer() playerViewController?.player = player addPeriodicTimeObserver(fullURL: fullUrl) diff --git a/Sora/Views/AnimeViews/AnimeInfoView.swift b/Sora/Views/AnimeViews/AnimeInfoView.swift index 1a29de7..fd64d97 100644 --- a/Sora/Views/AnimeViews/AnimeInfoView.swift +++ b/Sora/Views/AnimeViews/AnimeInfoView.swift @@ -183,6 +183,19 @@ struct AnimeInfoView: View { openInExternalPlayer(scheme: scheme, url: streamUrl) Logger.shared.log("Opening external app with scheme: \(scheme)") return + } else if externalPlayer == "Custom" { + DispatchQueue.main.async { + let customMediaPlayer = CustomMediaPlayer(urlString: streamUrl) + let hostingController = UIHostingController(rootView: customMediaPlayer) + hostingController.modalPresentationStyle = .fullScreen + Logger.shared.log("Opening custom media player with url: \(streamUrl)") + + if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene, + let rootVC = windowScene.windows.first?.rootViewController { + rootVC.present(hostingController, animated: true, completion: nil) + } + } + return } DispatchQueue.main.async { diff --git a/Sora/Views/SettingsViews/SubPages/SettingsPlayerView.swift b/Sora/Views/SettingsViews/SubPages/SettingsPlayerView.swift index 9c6c8c9..cde1bcc 100644 --- a/Sora/Views/SettingsViews/SubPages/SettingsPlayerView.swift +++ b/Sora/Views/SettingsViews/SubPages/SettingsPlayerView.swift @@ -14,30 +14,46 @@ struct SettingsPlayerView: View { var body: some View { Form { - Section(header: Text("Player"), footer: Text("The ForceLandscape and HoldSpeed only work inside the default iOS player.")) { + Section(header: Text("Player"), footer: Text("The ForceLandscape and HoldSpeed only work inside the default iOS player and custom player.")) { HStack { Text("Media Player") Spacer() Menu(externalPlayer) { - Button("Default") { + Button(action: { externalPlayer = "Default" + }) { + Label("Default", systemImage: externalPlayer == "Default" ? "checkmark" : "") } - Button("VLC") { + Button(action: { externalPlayer = "VLC" + }) { + Label("VLC", systemImage: externalPlayer == "VLC" ? "checkmark" : "") } - Button("OutPlayer") { + Button(action: { externalPlayer = "OutPlayer" + }) { + Label("OutPlayer", systemImage: externalPlayer == "OutPlayer" ? "checkmark" : "") } - Button("Infuse") { + Button(action: { externalPlayer = "Infuse" + }) { + Label("Infuse", systemImage: externalPlayer == "Infuse" ? "checkmark" : "") } - Button("nPlayer") { + Button(action: { externalPlayer = "nPlayer" + }) { + Label("nPlayer", systemImage: externalPlayer == "nPlayer" ? "checkmark" : "") + } + Button(action: { + externalPlayer = "Custom" + }) { + Label("Custom", systemImage: externalPlayer == "Custom" ? "checkmark" : "") } } } Toggle("Force Landscape", isOn: $isAlwaysLandscape) + .tint(.accentColor) HStack { Text("Hold Speed:")