Video Uploads

Changelog-Added: Add support for video uploads
This commit is contained in:
Swift
2023-03-24 18:39:22 -04:00
committed by William Casarin
parent 6517dcba3f
commit 5e0ff1a6a0
5 changed files with 65 additions and 43 deletions

View File

@@ -15,23 +15,24 @@ enum ImageUploadResult {
case failed(Error?)
}
fileprivate func create_upload_body(imageDataKey: Data, boundary: String, imageUploader: ImageUploader) -> Data {
fileprivate func create_upload_body(mediaData: Data, boundary: String, mediaUploader: MediaUploader, mediaIsImage: Bool) -> Data {
let body = NSMutableData();
let contentType = "image/jpg"
let contentType = mediaIsImage ? "image/jpg" : "video/mp4"
let genericFileName = mediaIsImage ? "damus_generic_filename.jpg" : "damus_generic_filename.mp4"
body.appendString(string: "Content-Type: multipart/form-data; boundary=\(boundary)\r\n\r\n")
body.appendString(string: "--\(boundary)\r\n")
body.appendString(string: "Content-Disposition: form-data; name=\(imageUploader.nameParam); filename=\"damus_generic_filename.jpg\"\r\n")
body.appendString(string: "Content-Disposition: form-data; name=\(mediaUploader.nameParam); filename=\(genericFileName)\r\n")
body.appendString(string: "Content-Type: \(contentType)\r\n\r\n")
body.append(imageDataKey as Data)
body.append(mediaData as Data)
body.appendString(string: "\r\n")
body.appendString(string: "--\(boundary)--\r\n")
return body as Data
}
func create_image_upload_request(imageToUpload: UIImage, imageUploader: ImageUploader, progress: URLSessionTaskDelegate) async -> ImageUploadResult {
guard let url = URL(string: imageUploader.postAPI) else {
func create_upload_request(mediaToUpload: Any, mediaUploader: MediaUploader, progress: URLSessionTaskDelegate) async -> ImageUploadResult {
var mediaIsImage: Bool = false
var mediaData: Data?
guard let url = URL(string: mediaUploader.postAPI) else {
return .failed(nil)
}
@@ -39,14 +40,19 @@ func create_image_upload_request(imageToUpload: UIImage, imageUploader: ImageUpl
request.httpMethod = "POST";
let boundary = "Boundary-\(UUID().description)"
request.setValue("multipart/form-data; boundary=\(boundary)", forHTTPHeaderField: "Content-Type")
// otherwise convert to jpg
guard let jpegData = imageToUpload.jpegData(compressionQuality: 0.8) else {
// somehow failed, just return original
if let imageToUpload = mediaToUpload as? UIImage {
mediaData = imageToUpload.jpegData(compressionQuality: 0.8)
mediaIsImage = true
} else if let videoToUpload = mediaToUpload as? URL {
mediaData = try? Data(contentsOf: videoToUpload)
}
guard let mediaData = mediaData else {
return .failed(nil)
}
request.httpBody = create_upload_body(imageDataKey: jpegData, boundary: boundary, imageUploader: imageUploader)
request.httpBody = create_upload_body(mediaData: mediaData, boundary: boundary, mediaUploader: mediaUploader, mediaIsImage: mediaIsImage)
do {
let (data, _) = try await URLSession.shared.data(for: request, delegate: progress)
@@ -56,8 +62,8 @@ func create_image_upload_request(imageToUpload: UIImage, imageUploader: ImageUpl
return .failed(nil)
}
guard let url = imageUploader.getImageURL(from: responseString) else {
print("Upload failed getting image url")
guard let url = mediaUploader.getMediaURL(from: responseString, mediaIsImage: mediaIsImage) else {
print("Upload failed getting media url")
return .failed(nil)
}
@@ -66,7 +72,6 @@ func create_image_upload_request(imageToUpload: UIImage, imageUploader: ImageUpl
} catch {
return .failed(error)
}
}
extension PostView {
@@ -76,7 +81,9 @@ extension PostView {
private var presentationMode
let sourceType: UIImagePickerController.SourceType
let damusState: DamusState
let onImagePicked: (UIImage) -> Void
let onVideoPicked: (URL) -> Void
final class Coordinator: NSObject,
UINavigationControllerDelegate,
@@ -86,19 +93,27 @@ extension PostView {
private var presentationMode: PresentationMode
private let sourceType: UIImagePickerController.SourceType
private let onImagePicked: (UIImage) -> Void
private let onVideoPicked: (URL) -> Void
init(presentationMode: Binding<PresentationMode>,
sourceType: UIImagePickerController.SourceType,
onImagePicked: @escaping (UIImage) -> Void) {
onImagePicked: @escaping (UIImage) -> Void,
onVideoPicked: @escaping (URL) -> Void) {
_presentationMode = presentationMode
self.sourceType = sourceType
self.onImagePicked = onImagePicked
self.onVideoPicked = onVideoPicked
}
func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let uiImage = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
onImagePicked(uiImage)
if let videoURL = info[UIImagePickerController.InfoKey.mediaURL] as? URL {
// Handle the selected video
onVideoPicked(videoURL)
} else if let uiImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
// Handle the selected image
onImagePicked(uiImage)
}
presentationMode.dismiss()
}
@@ -112,12 +127,17 @@ extension PostView {
func makeCoordinator() -> Coordinator {
return Coordinator(presentationMode: presentationMode,
sourceType: sourceType,
onImagePicked: onImagePicked)
onImagePicked: onImagePicked, onVideoPicked: onVideoPicked)
}
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let picker = UIImagePickerController()
picker.sourceType = sourceType
let mediaUploader = get_media_uploader(damusState.keypair.pubkey)
picker.mediaTypes = ["public.image"]
if mediaUploader.supportsVideo {
picker.mediaTypes.append("public.movie")
}
picker.delegate = context.coordinator
return picker
}
@@ -138,7 +158,7 @@ extension NSMutableData {
}
}
enum ImageUploader: String, CaseIterable, Identifiable {
enum MediaUploader: String, CaseIterable, Identifiable {
var id: String { self.rawValue }
case nostrBuild
case nostrImg
@@ -152,12 +172,12 @@ enum ImageUploader: String, CaseIterable, Identifiable {
}
}
var displayImageUploaderName: String {
var supportsVideo: Bool {
switch self {
case .nostrBuild:
return "NostrBuild"
return true
case .nostrImg:
return "NostrImg"
return false
}
}
@@ -187,7 +207,7 @@ enum ImageUploader: String, CaseIterable, Identifiable {
}
}
func getImageURL(from responseString: String) -> String? {
func getMediaURL(from responseString: String, mediaIsImage: Bool) -> String? {
switch self {
case .nostrBuild:
guard let startIndex = responseString.range(of: "nostr.build_")?.lowerBound else {
@@ -199,7 +219,7 @@ enum ImageUploader: String, CaseIterable, Identifiable {
return nil
}
let nostrBuildImageName = responseString[startIndex..<endIndex]
let nostrBuildURL = "https://nostr.build/i/\(nostrBuildImageName)"
let nostrBuildURL = mediaIsImage ? "https://nostr.build/i/\(nostrBuildImageName)" : "https://nostr.build/av/\(nostrBuildImageName)"
return nostrBuildURL
case .nostrImg: