Include filename extension for attachments

Fixes posting attachments on pleroma resulting in them served as
application/octet-stream, even though we're sending the mime type as well
This commit is contained in:
Shadowfacts 2022-06-20 00:00:34 -04:00
parent 9fa352d4f8
commit 037b717e60
2 changed files with 16 additions and 15 deletions

View File

@ -48,13 +48,13 @@ enum CompositionAttachmentData {
}
}
func getData(completion: @escaping (Result<(Data, String), Error>) -> Void) {
func getData(completion: @escaping (Result<(Data, UTType), Error>) -> Void) {
switch self {
case let .image(image):
// Export as JPEG instead of PNG, otherweise photos straight from the camera are too large
// for Mastodon in its default configuration (max of 10MB).
// The quality of 0.8 was chosen completely arbitrarily, it may need to be tuned in the future.
completion(.success((image.jpegData(compressionQuality: 0.8)!, "image/jpeg")))
completion(.success((image.jpegData(compressionQuality: 0.8)!, .jpeg)))
case let .asset(asset):
if asset.mediaType == .image {
let options = PHImageRequestOptions()
@ -68,19 +68,19 @@ enum CompositionAttachmentData {
return
}
let mimeType: String
let utType: UTType
if dataUTI == "public.heic" {
// neither Mastodon nor Pleroma handles HEIC well, so convert to JPEG
let image = CIImage(data: data)!
let context = CIContext()
let colorSpace = image.colorSpace ?? CGColorSpace(name: CGColorSpace.sRGB)!
data = context.jpegRepresentation(of: image, colorSpace: colorSpace, options: [:])!
mimeType = "image/jpeg"
utType = .jpeg
} else {
mimeType = UTType(dataUTI)!.preferredMIMEType!
utType = UTType(dataUTI)!
}
completion(.success((data, mimeType)))
completion(.success((data, utType)))
}
} else if asset.mediaType == .video {
let options = PHVideoRequestOptions()
@ -109,11 +109,11 @@ enum CompositionAttachmentData {
case let .drawing(drawing):
let image = drawing.imageInLightMode(from: drawing.bounds, scale: 1)
completion(.success((image.pngData()!, "image/png")))
completion(.success((image.pngData()!, .png)))
}
}
private static func exportVideoData(session: AVAssetExportSession, completion: @escaping (Result<(Data, String), Error>) -> Void) {
private static func exportVideoData(session: AVAssetExportSession, completion: @escaping (Result<(Data, UTType), Error>) -> Void) {
session.outputFileType = .mp4
session.outputURL = FileManager.default.temporaryDirectory.appendingPathComponent("exported_video_\(UUID())").appendingPathExtension("mp4")
session.exportAsynchronously {
@ -123,7 +123,7 @@ enum CompositionAttachmentData {
}
do {
let data = try Data(contentsOf: session.outputURL!)
completion(.success((data, "video/mp4")))
completion(.success((data, .mpeg4Movie)))
} catch {
completion(.failure(.videoExport(error)))
}

View File

@ -8,6 +8,7 @@
import Foundation
import Pachyderm
import UniformTypeIdentifiers
class PostService: ObservableObject {
private let mastodonController: MastodonController
@ -66,15 +67,15 @@ class PostService: ObservableObject {
attachments.reserveCapacity(draft.attachments.count)
for (index, attachment) in draft.attachments.enumerated() {
let data: Data
let mimeType: String
let utType: UTType
do {
(data, mimeType) = try await getData(for: attachment)
(data, utType) = try await getData(for: attachment)
currentStep += 1
} catch let error as CompositionAttachmentData.Error {
throw Error.attachmentData(index: index, cause: error)
}
do {
let uploaded = try await uploadAttachment(data: data, mimeType: mimeType, description: attachment.attachmentDescription)
let uploaded = try await uploadAttachment(data: data, utType: utType, description: attachment.attachmentDescription)
attachments.append(uploaded)
currentStep += 1
} catch let error as Client.Error {
@ -84,7 +85,7 @@ class PostService: ObservableObject {
return attachments
}
private func getData(for attachment: CompositionAttachment) async throws -> (Data, String) {
private func getData(for attachment: CompositionAttachment) async throws -> (Data, UTType) {
return try await withCheckedThrowingContinuation { continuation in
attachment.data.getData { result in
switch result {
@ -97,8 +98,8 @@ class PostService: ObservableObject {
}
}
private func uploadAttachment(data: Data, mimeType: String, description: String?) async throws -> Attachment {
let formAttachment = FormAttachment(mimeType: mimeType, data: data, fileName: "file")
private func uploadAttachment(data: Data, utType: UTType, description: String?) async throws -> Attachment {
let formAttachment = FormAttachment(mimeType: utType.preferredMIMEType!, data: data, fileName: "file.\(utType.preferredFilenameExtension!)")
let req = Client.upload(attachment: formAttachment, description: description)
return try await mastodonController.run(req).0
}