diff --git a/Pocket Poster/Controllers/PosterBoardManager.swift b/Pocket Poster/Controllers/PosterBoardManager.swift index 4260e12..df51564 100644 --- a/Pocket Poster/Controllers/PosterBoardManager.swift +++ b/Pocket Poster/Controllers/PosterBoardManager.swift @@ -8,44 +8,6 @@ import Foundation import ZIPFoundation import UIKit -import CoreTransferable - -struct Movie: Transferable { - let url: URL - - static var transferRepresentation: some TransferRepresentation { - FileRepresentation(contentType: .movie) { movie in - SentTransferredFile(movie.url) - } importing: { received in - let videoFolder = SymHandler.getDocumentsDirectory().appendingPathComponent("Videos", conformingTo: .directory) - if !FileManager.default.fileExists(atPath: videoFolder.path()) { - try? FileManager.default.createDirectory(at: videoFolder, withIntermediateDirectories: true) - } - let copy = videoFolder.appending(path: "\(UUID()).mp4") - - if FileManager.default.fileExists(atPath: copy.path()) { - try FileManager.default.removeItem(at: copy) - } - - try FileManager.default.copyItem(at: received.file, to: copy) - return Self.init(url: copy) - } - } -} - -enum LoadState { - case unknown, loading, loaded(Movie), failed -} - -struct LoadInfo: Identifiable, Equatable { - static func == (lhs: LoadInfo, rhs: LoadInfo) -> Bool { - lhs.id == rhs.id - } - - var id = UUID() - var autoReverses: Bool = false - var loadState: LoadState -} class PosterBoardManager: ObservableObject { static let ShortcutURL = "https://www.icloud.com/shortcuts/a28d2c02ca11453cb5b8f91c12cfa692" diff --git a/Pocket Poster/Controllers/VideoHandler.swift b/Pocket Poster/Controllers/VideoHandler.swift index 709f09c..c911b19 100644 --- a/Pocket Poster/Controllers/VideoHandler.swift +++ b/Pocket Poster/Controllers/VideoHandler.swift @@ -8,6 +8,7 @@ import Foundation import AVFoundation import UIKit +import CoreTransferable extension CGImage { var png: Data? { @@ -23,7 +24,55 @@ extension CGImage { } } +struct Movie: Transferable { + let url: URL + + static var transferRepresentation: some TransferRepresentation { + FileRepresentation(contentType: .movie) { movie in + SentTransferredFile(movie.url) + } importing: { received in + let videoFolder = SymHandler.getDocumentsDirectory().appendingPathComponent("Videos", conformingTo: .directory) + if !FileManager.default.fileExists(atPath: videoFolder.path()) { + try? FileManager.default.createDirectory(at: videoFolder, withIntermediateDirectories: true) + } + let copy = videoFolder.appending(path: "\(UUID()).mp4") + + if FileManager.default.fileExists(atPath: copy.path()) { + try FileManager.default.removeItem(at: copy) + } + + try FileManager.default.copyItem(at: received.file, to: copy) + return Self.init(url: copy) + } + } +} + +enum LoadState { + case unknown, loading, loaded(Movie), failed +} + +struct LoadInfo: Identifiable, Equatable { + static func == (lhs: LoadInfo, rhs: LoadInfo) -> Bool { + lhs.id == rhs.id + } + + var id = UUID() + var autoReverses: Bool = false + var loadState: LoadState +} + class VideoHandler { + static let MaxDurationSecs = 12.0 + + static func isVideoTooLong(at url: URL) -> Bool { + let asset = AVAsset(url: url) + + let duration = asset.duration + let durationTime = CMTimeGetSeconds(duration) + + return durationTime > MaxDurationSecs + } + static func createCaml(from url: URL, autoReverses: Bool) throws -> URL { // copy the resources let descrURL = SymHandler.getDocumentsDirectory().appendingPathComponent(UUID().uuidString, conformingTo: .directory) diff --git a/Pocket Poster/Localizable.xcstrings b/Pocket Poster/Localizable.xcstrings index 6d84001..5394f48 100644 --- a/Pocket Poster/Localizable.xcstrings +++ b/Pocket Poster/Localizable.xcstrings @@ -706,6 +706,9 @@ } } } + }, + "Failed to Import Video" : { + }, "Fallback Shortcut Creator" : { "localizations" : { @@ -1509,6 +1512,9 @@ } } } + }, + "The video you imported is too long! Your video must be %@ seconds or less." : { + }, "To apply, PosterBoard will need to open.\n\nYou can install an optional shortcut if the original method fails." : { diff --git a/Pocket Poster/Views/NavigatorViews/VideoView.swift b/Pocket Poster/Views/NavigatorViews/VideoView.swift index 9841c61..97267b8 100644 --- a/Pocket Poster/Views/NavigatorViews/VideoView.swift +++ b/Pocket Poster/Views/NavigatorViews/VideoView.swift @@ -11,6 +11,7 @@ import AVKit struct VideoView: View { @ObservedObject var pbManager = PosterBoardManager.shared + @AppStorage("ignoreDurationLimit") var ignoreDurationLimit: Bool = false @State var selectedVideo: PhotosPickerItem? @@ -103,7 +104,12 @@ struct VideoView: View { do { if let movie = try await selectedVideo?.loadTransferable(type: Movie.self) { await MainActor.run { - pbManager.videos[id].loadState = .loaded(movie) + if !ignoreDurationLimit && VideoHandler.isVideoTooLong(at: movie.url) { + pbManager.videos.remove(at: id) + UIApplication.shared.alert(title: NSLocalizedString("Failed to Import Video", comment: ""), body: String(format: NSLocalizedString("The video you imported is too long! Your video must be %@ seconds or less.", comment: ""), "\(Int(VideoHandler.MaxDurationSecs))")) + } else { + pbManager.videos[id].loadState = .loaded(movie) + } } } else { await MainActor.run {