From 416039ae0c5dfdf9769b0ba4c42751086edd02ea Mon Sep 17 00:00:00 2001 From: Sergey Armodin Date: Thu, 24 Nov 2022 14:31:19 +0300 Subject: [PATCH] 0.9.1 (#106) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove utm that aren't working * Update README.md * integration test for file info upload API method * refactoring * tabs * refactoring * tabs * tabs * refactoring * test fixed * defaultError with status for UploadError * pass RequestManager to UploadAPI * separate validation methods for REST API and Upload API requests * refactoring * refactoring * refactoring * uploadStatus method updated * formatting * refactoring * refactoring and fixes for integration tests * integration test for multipart upload * startMulipartUpload refactoring * uploadIndividualFilePart refactoring * completeMultipartUpload refactoring * integratin tests for file groups added * refactoring * refactoring * refactoring * Alamofire is finally removed from dependencies * cleanup * Update test.yml * tests refactoring * tabs * fixes * tests accepts keys as arguments * … * Update test.yml * Update test.yml * pod version bump, removed Alamofire from dependencies * removed Alamofire from Carthage dependencies * Carthage project updated * try to remove Cartfile * Revert "try to remove Cartfile" This reverts commit 7125783e955399d47efa600e29a2130274609839. * build library for distribution * … * tabs * test updated * wip * more methods implemented with Result type * wip * wip * wip * wip * refactoring * refactoring * refactoring * wip * wip * refactoring * wip * wip * wip * wip * wip * version * wip * wip * wip * wip * wip * refactoring * Update test.yml * tests updated * tests updated * tests updated * Carthage build fixed * documentation updated * demo app updated with new lib methods * Readme updated * cleanup * update files list on main thread in demo app * allow setting signature from external source * lib version bump * Update README.md * Update Upload API.md * formatting * Update Upload API.md * custom uploadSignature can be provided for methods: - Upload file from url - Multipart file uploading - Create files group from a set of files - Create files group from a set of files UUIDs. - Files group info * custom uploadSignature can be provided for main uploadFile method that decides which upload method to use internally * custom uploadSignature can be provided for upload method of UploadedFile object * increase timeout for video conversion integration test * documentation updated * Update Sources/Uploadcare/Uploadcare.swift Co-authored-by: Roman Sedykh * Update README.md Co-authored-by: Roman Sedykh * Update Documentation/Upload API.md Co-authored-by: Roman Sedykh * Update README.md * Update README.md * Update README.md * Update Upload API.md * Update README.md * Update README.md * Update Upload API.md * Update REST API.md * Update Documentation/REST API.md Co-authored-by: Roman Sedykh * Update Documentation/REST API.md Co-authored-by: Roman Sedykh * Update Documentation/Upload API.md Co-authored-by: Roman Sedykh * Update Documentation/Upload API.md Co-authored-by: Roman Sedykh * Update README.md Co-authored-by: Roman Sedykh * Update README.md Co-authored-by: Roman Sedykh * fixed when storing behavour param was missing for direct upload request * version bump * removed deprecated files for tests * Swift version 5.1 -> 5.6 * removed unused allTests property in tests * refactoring * refactoring * refactoring * bumped api version to 0.7 * - removed sorting by size for getting list of files method - data param for dateTimeUploadedASC ordering is optional now * removed rekognitionInfo from File model * removed imageInfo from File model * removed videoInfo from File model * warning * metadata added to File model * docs * order * Improvements for handling responses in RequestManager * Added methods for REST API to get/update/delete File metadata * store group method is not available for REST API anymore * use keyDecodingStrategy for decoders * Revert "use keyDecodingStrategy for decoders" This reverts commit d210ca21efc0fccdc888bf1a30aa21a65b4c1463. * added contentInfo property to File data model * delete group method added for REST API * models updated * added FileInfoQuery to set request query to include appdata * new models for AppData added * refactoring * appData field added for File model * refactoring * execute AWS recognition method added * added method to check aws recognition status * integration tests for aws recognition execution and and status check * Added execution of ClamAV addon, checking it’s status and integration tests for it * RemoveBGAddonExecutionParams model added * remove.bg addon execution and status + refactoring * integration tests for remove.bg addon methods * done field added to UploadedFile model * added contentInfo file to UploadedFile model * added metadata property to UploadedFile model * bump lib version * metadata can be provided for upload from url method * metadata can be provided for direct upload method * metadata can be provided for multipart uploads * set swift version 5.5 * demo app fixed * updated project for carthage * more swift versions * podfile updated * warning removed * set lib version 0.9.0 * metadata param for main upload method - metadata param for main upload method - don’t get fileinfo if only public key provided after direct upload integration test for direct upload when only public key provided * pass metadata from UploadedFile when calling upload * added integratin test for multipart uploading if only public key provided * Update README.md * Update REST API.md * Update REST API.md * Update REST API.md * Update REST API.md * Update Upload API.md * Update README.md * Update test.yml * Update REST API.md * Update REST API.md * Update Upload API.md * Update REST API.md * Update REST API.md * couple links updated * test updated * fixed parsing of UploadedFile model * added new integration test to upload a video file and check that parsing of response works * version bump * spaces Co-authored-by: Roman Sedykh Co-authored-by: Ivan Tse --- Sources/Uploadcare/Constants.swift | 2 +- .../Uploadcare/models/REST/ContentInfo.swift | 178 +++++++++++++++++- Sources/Uploadcare/models/VideoInfo.swift | 51 ++++- .../RESTAPIIntegrationTests.swift | 2 +- .../UploadAPIIntegrationTests.swift | 25 +++ Uploadcare.podspec | 2 +- 6 files changed, 248 insertions(+), 12 deletions(-) diff --git a/Sources/Uploadcare/Constants.swift b/Sources/Uploadcare/Constants.swift index 553d5e87..50dc2294 100644 --- a/Sources/Uploadcare/Constants.swift +++ b/Sources/Uploadcare/Constants.swift @@ -19,7 +19,7 @@ internal let RESTAPIHost = "api.uploadcare.com" /// Library name internal let libraryName = "UploadcareSwift" /// Library version -internal let libraryVersion = "0.9.0" +internal let libraryVersion = "0.9.1" /// API version internal let APIVersion = "0.7" diff --git a/Sources/Uploadcare/models/REST/ContentInfo.swift b/Sources/Uploadcare/models/REST/ContentInfo.swift index 09a09a82..2c508a32 100644 --- a/Sources/Uploadcare/models/REST/ContentInfo.swift +++ b/Sources/Uploadcare/models/REST/ContentInfo.swift @@ -11,10 +11,184 @@ import Foundation public struct ContentInfo: Codable { /// MIME type. public let mime: Mime? - + /// Image metadata. public let image: ImageInfo? /// Video metadata. - public let video: VideoInfo? + public let video: Video? +} + +extension ContentInfo { + /// Video metadata. + public struct Video: Codable, CustomDebugStringConvertible { + /// Video duration in milliseconds. + public var duration: Int + + /// Video format(MP4 for example). + public var format: String + + /// Video bitrate. + public var bitrate: Int + + /// Audio stream metadata. + public var audio: [AudioMetadata]? + + /// Video stream metadata. + public var video: [VideoMetadata] + + + enum CodingKeys: String, CodingKey { + case duration + case format + case bitrate + case audio + case video + } + + + init( + duration: Int, + format: String, + bitrate: Int, + audio: [AudioMetadata]?, + video: [VideoMetadata] + ) { + self.duration = duration + self.format = format + self.bitrate = bitrate + self.audio = audio + self.video = video + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + let duration = try container.decodeIfPresent(Int.self, forKey: .duration) ?? 0 + let format = try container.decodeIfPresent(String.self, forKey: .format) ?? "" + let bitrate = try container.decodeIfPresent(Int.self, forKey: .bitrate) ?? 0 + let audio = try container.decodeIfPresent([AudioMetadata].self, forKey: .audio) + let video = try container.decodeIfPresent([VideoMetadata].self, forKey: .video) ?? [VideoMetadata(height: 0, width: 0, frameRate: 0, bitrate: 0, codec: "")] + + self.init( + duration: duration, + format: format, + bitrate: bitrate, + audio: audio, + video: video + ) + } + + public var debugDescription: String { + return """ + \(type(of: self)): + duration: \(duration) + format: \(format) + bitrate: \(bitrate) + audio: \(String(describing: audio)) + video: \(video) + """ + } + } +} + + +extension ContentInfo { + /// Video stream metadata. + public struct VideoMetadata: Codable, CustomDebugStringConvertible { + /// Video stream image height. + public var height: Int + /// Video stream image width. + public var width: Int + /// Video stream frame rate. + public var frameRate: Int + /// Video stream bitrate. + public var bitrate: Int? + /// Video stream codec. + public var codec: String? + + + enum CodingKeys: String, CodingKey { + case height + case width + case frameRate = "frame_rate" + case bitrate + case codec + } + + init( + height: Int, + width: Int, + frameRate: Int, + bitrate: Int?, + codec: String? + ) { + self.height = height + self.width = width + self.frameRate = frameRate + self.bitrate = bitrate + self.codec = codec + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + let height = try container.decodeIfPresent(Int.self, forKey: .height) ?? 0 + let width = try container.decodeIfPresent(Int.self, forKey: .width) ?? 0 + let frameRate = try container.decodeIfPresent(Int.self, forKey: .frameRate) ?? 0 + let bitrate = try container.decodeIfPresent(Int.self, forKey: .bitrate) + let codec = try container.decodeIfPresent(String.self, forKey: .codec) + + self.init( + height: height, + width: width, + frameRate: frameRate, + bitrate: bitrate, + codec: codec + ) + } + + public var debugDescription: String { + return """ + \(type(of: self)): + height: \(height) + width: \(width) + frameRate: \(frameRate) + bitrate: \(bitrate as Any) + codec: \(codec as Any) + """ + } + } +} + + +extension ContentInfo { + /// Audio stream metadata. + public struct Audio: Codable, CustomDebugStringConvertible { + /// Audio stream's bitrate. + public var bitrate: Int? + /// Audio stream's codec. + public var codec: String? + /// Audio stream's sample rate. + public var sampleRate: Int? + /// Audio stream's number of channels. + public var channels: String? + + enum CodingKeys: String, CodingKey { + case bitrate + case codec + case sampleRate = "sample_rate" + case channels + } + + public var debugDescription: String { + return """ + \(type(of: self)): + bitrate: \(String(describing: bitrate)) + codec: \(String(describing: codec)) + sampleRate: \(String(describing: sampleRate)) + channels: \(String(describing: channels)) + """ + } + } } diff --git a/Sources/Uploadcare/models/VideoInfo.swift b/Sources/Uploadcare/models/VideoInfo.swift index 3a10a188..68e83b71 100644 --- a/Sources/Uploadcare/models/VideoInfo.swift +++ b/Sources/Uploadcare/models/VideoInfo.swift @@ -21,10 +21,10 @@ public struct VideoInfo: Codable { public var bitrate: Int /// Audio stream metadata. - public var audio: [AudioMetadata] - + public var audio: Audio? + /// Video stream metadata. - public var video: [VideoMetadata] + public var video: VideoMetadata enum CodingKeys: String, CodingKey { @@ -40,8 +40,8 @@ public struct VideoInfo: Codable { duration: Int, format: String, bitrate: Int, - audio: [AudioMetadata], - video: [VideoMetadata] + audio: Audio?, + video: VideoMetadata ) { self.duration = duration self.format = format @@ -56,8 +56,8 @@ public struct VideoInfo: Codable { let duration = try container.decodeIfPresent(Int.self, forKey: .duration) ?? 0 let format = try container.decodeIfPresent(String.self, forKey: .format) ?? "" let bitrate = try container.decodeIfPresent(Int.self, forKey: .bitrate) ?? 0 - let audio = try container.decodeIfPresent([AudioMetadata].self, forKey: .audio) ?? [AudioMetadata()] - let video = try container.decodeIfPresent([VideoMetadata].self, forKey: .video) ?? [VideoMetadata(height: 0, width: 0, frameRate: 0, bitrate: 0, codec: "")] + let audio = try container.decodeIfPresent(Audio.self, forKey: .audio) + let video = try container.decodeIfPresent(VideoMetadata.self, forKey: .video) ?? VideoMetadata(height: 0, width: 0, frameRate: 0, bitrate: 0, codec: "") self.init( duration: duration, @@ -83,3 +83,40 @@ extension VideoInfo: CustomDebugStringConvertible { """ } } + + +extension VideoInfo { + /// Audio stream metadata. + public struct Audio: Codable, CustomDebugStringConvertible { + /// Audio bitrate. + public var bitrate: Int? + + /// Audio stream codec. + public var codec: String? + + /// Audio stream sample rate. + public var sampleRate: Int? + + /// Audio stream number of channels. + public var channels: String? + + + enum CodingKeys: String, CodingKey { + case bitrate + case codec + case sampleRate = "sample_rate" + case channels + } + + public var debugDescription: String { + return """ + \(type(of: self)): + bitrate: \(String(describing: bitrate)) + codec: \(String(describing: codec)) + sampleRate: \(String(describing: sampleRate)) + channels: \(String(describing: channels)) + """ + } + } + +} diff --git a/Tests/UploadcareTests/RESTAPIIntegrationTests.swift b/Tests/UploadcareTests/RESTAPIIntegrationTests.swift index 3a395ed4..5bf07ee6 100644 --- a/Tests/UploadcareTests/RESTAPIIntegrationTests.swift +++ b/Tests/UploadcareTests/RESTAPIIntegrationTests.swift @@ -666,7 +666,7 @@ final class RESTAPIIntegrationTests: XCTestCase { XCTFail(error.detail) expectation.fulfill() case .success(let list): - let videoFile = list.results.first(where: { $0.mimeType == "video/mp4" })! + let videoFile = list.results.first(where: { $0.mimeType == "video/mp4" || $0.mimeType == "video/quicktime" })! let convertSettings = VideoConversionJobSettings(forFile: videoFile) .format(.webm) diff --git a/Tests/UploadcareTests/UploadAPIIntegrationTests.swift b/Tests/UploadcareTests/UploadAPIIntegrationTests.swift index de54c5b0..ac035b26 100644 --- a/Tests/UploadcareTests/UploadAPIIntegrationTests.swift +++ b/Tests/UploadcareTests/UploadAPIIntegrationTests.swift @@ -415,6 +415,31 @@ final class UploadAPIIntegrationTests: XCTestCase { wait(for: [expectation], timeout: 120.0) } + + func test13_multipartUpload_videoFile() { + let url = URL(string: "https://ucarecdn.com/3e8a90e7-f5ce-422e-a3ed-5eee952f9f3b/")! + let data = try! Data(contentsOf: url) + + let expectation = XCTestExpectation(description: "test13_multipartUpload_videoFile") + + let onProgress: (Double)->Void = { (progress) in + DLog("progress: \(progress)") + } + + let metadata = ["multipart": "upload"] + + uploadcare.uploadAPI.multipartUpload(data, withName: "video.MP4", store: .doNotStore, metadata: metadata, onProgress) { result in + defer { expectation.fulfill() } + + switch result { + case .failure(let error): + XCTFail(error.detail) + case .success(_): + break + } + } + wait(for: [expectation], timeout: 180.0) + } } #endif diff --git a/Uploadcare.podspec b/Uploadcare.podspec index a2aa70be..11c4c65b 100644 --- a/Uploadcare.podspec +++ b/Uploadcare.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Uploadcare' - s.version = '0.9.0' + s.version = '0.9.1' s.summary = 'Swift integration for Uploadcare' # This description is used to generate tags and improve search results.