Swift Google Drive downloading file - swift

I can't figure out how to download a Google Drive file in Swift. I followed the modified quickstart from Google Objective-C API 'GTL' with Swift and that worked. I can't translate the objective C code from the google drive API on downloading files. I've searched around and can't find anything. How can I get this to work?

You can use this function for downloading files with the Google Drive API in Swift:
func downloadFile(file: GTLDriveFile){
let url = "https://www.googleapis.com/drive/v3/files/\(file.identifier!)?alt=media"
let fetcher = drive.fetcherService.fetcherWithURLString(url)
fetcher.beginFetchWithDelegate(
self,
didFinishSelector: #selector(ViewController.finishedFileDownload(_:finishedWithData:error:)))
}
(In this case drive is the GTLServiceDrive - the same as in the Documentation)
Then you need to implement the function finishedFileDownload that will be called once the download is completed:
func finishedFileDownload(fetcher: GTMSessionFetcher, finishedWithData data: NSData, error: NSError?){
if let error = error {
//show an alert with the error message or something similar
return
}
//do something with data (save it...)
}

Actual for Swift 5.
func download(file: GTLRDrive_File) {
let url = "https://www.googleapis.com/drive/v3/files/\(file.identifier!)?alt=media"
let fetcher = drive.fetcherService.fetcher(withURLString: url)
fetcher.beginFetch(completionHandler: { data, error in
if let error = error {
print(error.localizedDescription)
}
//Do something with data
})
}

Swift 5 with progress block. file.size returns nil for some reason so I used fetcher.response?.expectedContentLength instead.
func download(file: GTLRDrive_File, service: GTLRDriveService) {
let url = "https://www.googleapis.com/drive/v3/files/\(file.identifier)?alt=media"
let fetcher = service.fetcherService.fetcher(withURLString: url)
fetcher.beginFetch(completionHandler: { fileData, error in
if error == nil {
print("finished downloading Data...")
print(fileData as Any)
} else {
print("Error: \(String(describing: error?.localizedDescription))")
}
})
fetcher.receivedProgressBlock = { _, totalBytesReceived in
if let fileSize = fetcher.response?.expectedContentLength {
let progress: Double = Double(totalBytesReceived) / Double(fileSize)
// update progress bar here
print(progress)
}
}
}

Related

Is there a more detailed way to debug SFSpeechRecognizer?

Updated info below, and new code
I am trying to incorporate SFSpeechRecognizer into my app, and the errors/results I am getting from three pre-recorded audiofiles aren't enough for me to figure out what's going on. From the results I am getting I can't figure out what's wrong, and info via Google is sparse.
The code where I loop through three files is at the bottom. Here are the responses I get for my three audio files. I've made sure in each file to speak loudly and clearly, yet I still get: No speech detected or no text returned.
SS-X-03.m4a : There was an error: Optional(Error
Domain=kAFAssistantErrorDomain Code=1110 "No speech detected"
UserInfo={NSLocalizedDescription=No speech detected})
SS-X-20221125000.m4a : There was an error: Optional(Error
Domain=kAFAssistantErrorDomain Code=1110 "No speech detected"
UserInfo={NSLocalizedDescription=No speech detected})
SS-X-20221125001.m4a : (there is some text here if I set
request.requiresOnDeviceRecognition to false)
My code:
func findAudioFiles(){
let fm = FileManager.default
var aFiles : URL
print ("\(urlPath)")
do {
let items = try fm.contentsOfDirectory(atPath: documentsPath)
let filteredInterestArray1 = items.filter({$0.hasSuffix(".m4a")})
let filteredInterestArray2 = filteredInterestArray1.filter({$0.contains("SS-X-")})
let sortedItems = filteredInterestArray2.sorted()
for item in sortedItems {
audioFiles.append(item)
}
NotificationCenter.default.post(name: Notification.Name("goAndRead"), object: nil, userInfo: myDic)
} catch {
print ("\(error)")
}
}
#objc func goAndRead(){
audioIndex += 1
if audioIndex != audioFiles.count {
let fileURL = NSURL.fileURL(withPath: documentsPath + "/" + audioFiles[audioIndex], isDirectory: false)
transcribeAudio(url: fileURL, item: audioFiles[audioIndex])
}
}
func requestTranscribePermissions() {
SFSpeechRecognizer.requestAuthorization { [unowned self] authStatus in
DispatchQueue.main.async {
if authStatus == .authorized {
print("Good to go!")
} else {
print("Transcription permission was declined.")
}
}
}
}
func transcribeAudio(url: URL, item: String) {
guard let recognizer = SFSpeechRecognizer(locale: Locale(identifier: "en-US")) else {return}
let request = SFSpeechURLRecognitionRequest(url: url)
if !recognizer.supportsOnDeviceRecognition { print ("offline not available") ; return }
if !recognizer.isAvailable { print ("not available") ; return }
request.requiresOnDeviceRecognition = true
request.shouldReportPartialResults = true
recognizer.recognitionTask(with: request) {(result, error) in
guard let result = result else {
print("\(item) : There was an error: \(error.debugDescription)")
return
}
if result.isFinal {
print("\(item) : \(result.bestTranscription.formattedString)")
NotificationCenter.default.post(name: Notification.Name("goAndRead"), object: nil, userInfo: self.myDic)
}
}
}
Updated info
It appears that I was calling SFSpeechURLRecognitionRequest too often, and before I completed the first request. Perhaps I need to create a new instance of SFSpeechRecognizer? Unsure.
Regardless I quickly/sloppily adjusted the code to only run it once the previous instance returned its results.
The results were much better, except one audio file still came up as no results. Not an error, just no text.
This file is the same as the previous file, in that I took an audio recording and split it in two. So the formats and volumes are the same.
So I still need a better way to debug this, to find out what it going wrong with that file.

In swift, is there a way to log into a website with a token gotten with OAuth2 library?

is there someone who can help me with the OAuth2 library in swift
I'm doing that to handle the end of OAuth
appDelegate.oauth2!.afterAuthorizeOrFail = { authParameters, error in
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let myString = formatter.string(from: appDelegate.oauth2!.accessTokenExpiry!)
print("t \(appDelegate.oauth2!.accessToken)")
print("td \(myString)")
//login me here with oauth2.accessToken
}
In this block I want to log into my website with an url like that :
"http://my-website.com/authme.php?token=\(oauth2!.accessToken!)"
I've try webview.load and no success but if I do the request in another function evrything works like a charm
Thank in advance
EDIT More info
I think it is due to the fact that afterAuthorizeOrFail seems to be called in background
Here is how afterAuthorizeOrFail is called didFail and didAuthorize which only differences are the arguments of the function in those methods
public final func didFail(with error: OAuth2Error?) {
var finalError = error
if let error = finalError {
logger?.debug("OAuth2", msg: "\(error)")
}
else {
finalError = OAuth2Error.requestCancelled
}
callOnMainThread() {
self.didAuthorizeOrFail?(nil, finalError)
self.didAuthorizeOrFail = nil
self.internalAfterAuthorizeOrFail?(true, finalError)
self.afterAuthorizeOrFail?(nil, finalError)
}
}
Here is the source file with this method
https://github.com/p2/OAuth2/blob/master/Sources/Base/OAuth2Base.swift
and callOnMainThread is that:
public func callOnMainThread(_ callback: (() -> Void)) {
if Thread.isMainThread {
callback()
}
else {
DispatchQueue.main.sync(execute: callback)
}
}
Here is the source file with this method
https://github.com/p2/OAuth2/blob/master/Sources/Base/OAuth2Requestable.swift
And here is how I do the request
let requrl=URL(string: "http://my-website.com/authme.php?token=\(oauth2!.accessToken!)")
do{
let request = try URLRequest(url: requrl!,method: .post)
self.webView!.load(request)
}catch let error {
DispatchQueue.main.async {
print("ERROR loading site \(error)")
}
}
The issue was that I used a wrong WKWebview (not the one on the storyboard)
Changing that fix my issue

Profile Pic and upload button : firebase : swift 4.0 : problem with jpeg converting to data

Im trying to implement a profile picture complete with upload button to firebase. I'm using swift 4.0 and im stuck on the syntax which is required for converting the jpeg image into data.
an error message is displayed providing the fix to the new replacement code, and following the instructions another error is played.
#IBAction func uploadButtonWasTapped(_ sender: Any) {
progressView.isHidden = false
let randomID = UUID.init().uuidString
let uploadRef = Storage.storage().reference(withPath:
"images/(randomID).jpg")
guard let imageData =
imageView.image?.jpegData(compressionQuality:
0.75) else { return }
let uploadMetadata = StorageMetadata.init()
uploadMetadata.contentType = "image/jpeg"
let taskReference = uploadRef.putData(imageData, metadata:
uploadMetadata) { (downloadMetadata, error) in
if let error = error {
print("Oh no! Got and Error! \(error.localizedDescription)")
return
}
print("Put is complete: \(String(describing: downloadMetadata))")
}
the line I am having issued with is the
'guard let imageData =
imageView.image?.jpegData(compressionQuality:
0.75) else { return }'
error received : 'jpegData(compressionQuality:)' has been renamed to
'UIImageJPEGRepresentation(::)'
code is changed to
'guard let imageData =
imageView.image?.UIImageJPEGRepresentation(compressionQuality:
0.75) else { return }
enter image description hereerror received : Value of type 'UIImage' has no member
'UIImageJPEGRepresentation'
any ideas?
Use it like this, as your syntax is wrong. That's why you are getting this error.
guard let imageData = UIImageJPEGRepresentation(imageView.image, 0.75) else { return }
Change your code to be:
guard let imageDate = imageView.image?.jpegData(compressionQuality: 0.75) else
{
return
}
UIImageJPEGRepresentation has been replaced with jpegData. See also the answer in this thread: https://stackoverflow.com/a/51531204/2399348
From Apple's documentation:
Objective-C syntax: https://developer.apple.com/documentation/uikit/1624115-uiimagejpegrepresentation?language=objc
Swift syntax: https://developer.apple.com/documentation/uikit/uiimage/1624115-jpegdata
Although it seems like it was renamed going from Objective-C to Swift, it seems like it's only the case for iOS 12.0 and later. (See the previously mentioned SO thread). Since you state you're supporting iOS 13.0 and higher, you need to use the new syntax.

How to use a JSON file from an Onine server like turbo360?

I am using a do catch scenario to try a JSONDecoder(), the only >problem is that I keep catching the error, but when I review my code I >can't see the error, maybe I need another set of eyes to help me out >of this one!
I placed my JSON file in a storage folder in turbo360, I've also tried gitHub, but neither is working, I believe.
import UIKit
class ViewController: UIViewController {
final let url = URL(string: "https://storage.turbo360.co/portfolio-website-hxoc6m/actors")
override func viewDidLoad() {
super.viewDidLoad()
downloadJson()
}
func downloadJson() {
guard let downloadURL = url else { return }
URLSession.shared.dataTask(with: downloadURL) { data, urlResponse, error in
guard let data = data, error == nil, urlResponse != nil else {
print("something is wrong")
return
}
print("downloaded")
print(downloadURL)
do
{
let decoder = JSONDecoder()
let actors = try decoder.decode(Actors.self, from: data)
print(actors)
} catch {
print("Something wrong after downloaded")
}
}.resume()
}
}
I supposed to get: JSONDonloadingSwift4.Actors
as confirmation that my JSON file has been accessed and decoded
Your JSON is invalid. You are missing an opening " on the last image URL. Fix that and as long as your Actor definition matches you should be good. jsonlint is very useful for checking JSON structure.

amazon S3 Swift - simple upload take ages and finally doesnt show up in bucket

I m trying to send a photo on an S3 bucket. Well, this is hell of undocumented in swift, and sdks are fragmented here and there, it s a big mess on my side and nothing works so far :
My uploading process goes on, but extremely slow (let s say a 5 meg image takes 10 minutes) and most of the time, the upload freezes and starts over again.
But the weird thing is when It finally succeeds, the file doesn t show up in my bucket. I ve tried uploading files to non existing buckets and the process still goes on (???)
here are my credentials loc (bucket is in east california)
let credentialsProvider = AWSCognitoCredentialsProvider(
regionType: AWSRegionType.USEast1, identityPoolId: "us-east-1:47e88493-xxxx-xxxx-xxxx-xxxxxxxxx")
let defaultServiceConfiguration = AWSServiceConfiguration(
region: AWSRegionType.USEast1, credentialsProvider: credentialsProvider)
AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = defaultServiceConfiguration
now here s my upload function
func uploadImage(){
//defining bucket and upload file name
let S3BucketName: String = "witnesstestbucket"
let S3UploadKeyName: String = "public/testImage.jpg"
let expression = AWSS3TransferUtilityUploadExpression()
expression.uploadProgress = {(task: AWSS3TransferUtilityTask, bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) in
dispatch_async(dispatch_get_main_queue(), {
let progress = Float(totalBytesSent) / Float(totalBytesExpectedToSend)
print("Progress is: \(progress)")
print (Float(totalBytesExpectedToSend))
})
}
self.uploadCompletionHandler = { (task, error) -> Void in
dispatch_async(dispatch_get_main_queue(), {
if ((error) != nil){
print("Failed with error")
print("Error: \(error!)");
}
else{
print("Sucess")
}
})
}
let transferUtility = AWSS3TransferUtility.defaultS3TransferUtility()
transferUtility.uploadData(imagedata, bucket: S3BucketName, key: S3UploadKeyName, contentType: "image/jpeg", expression: expression, completionHander: uploadCompletionHandler).continueWithBlock { (task) -> AnyObject! in
if let error = task.error {
print("Error: \(error.localizedDescription)")
}
if let exception = task.exception {
print("Exception: \(exception.description)")
}
if let _ = task.result {
print("Upload Starting!")
}
return nil;
}
}
#IBAction func post(sender: UIButton) {
// AW S3 upload
uploadImage()
}
to make it clear, My imagedata NSData comes from a uiimage, fetched from a collectionviewcell:
self.imagedata = UIImageJPEGRepresentation(img!, 05.0)!
Is there anything I could update to understand where I am wrong ?
thanks in advance :)
ok, was trying to upload NSData file using the uploaddata request, here is the working code with proper URL swift2 conversion :
func uploadImage(){
let img:UIImage = fullimage!.image!
// create a local image that we can use to upload to s3
let path:NSString = NSTemporaryDirectory().stringByAppendingString("image2.jpg")
let imageD:NSData = UIImageJPEGRepresentation(img, 0.2)!
imageD.writeToFile(path as String, atomically: true)
// once the image is saved we can use the path to create a local fileurl
let url:NSURL = NSURL(fileURLWithPath: path as String)
// next we set up the S3 upload request manager
uploadRequest = AWSS3TransferManagerUploadRequest()
// set the bucket
uploadRequest?.bucket = "witnesstest"
// I want this image to be public to anyone to view it so I'm setting it to Public Read
uploadRequest?.ACL = AWSS3ObjectCannedACL.PublicRead
// set the image's name that will be used on the s3 server. I am also creating a folder to place the image in
uploadRequest?.key = "foldername/image2.jpeg"
// set the content type
uploadRequest?.contentType = "image/jpeg"
// and finally set the body to the local file path
uploadRequest?.body = url;
// we will track progress through an AWSNetworkingUploadProgressBlock
uploadRequest?.uploadProgress = {[unowned self](bytesSent:Int64, totalBytesSent:Int64, totalBytesExpectedToSend:Int64) in
dispatch_sync(dispatch_get_main_queue(), { () -> Void in
self.amountUploaded = totalBytesSent
self.filesize = totalBytesExpectedToSend;
print(self.filesize)
print(self.amountUploaded)
})
}
// now the upload request is set up we can creat the transfermanger, the credentials are already set up in the app delegate
let transferManager:AWSS3TransferManager = AWSS3TransferManager.defaultS3TransferManager()
// start the upload
transferManager.upload(uploadRequest).continueWithBlock { (task) -> AnyObject? in
// once the uploadmanager finishes check if there were any errors
if(task.error != nil){
print("%#", task.error);
}else{ // if there aren't any then the image is uploaded!
// this is the url of the image we just uploaded
print("https://s3.amazonaws.com/witnesstest/foldername/image2.jpeg");
}
return "all done";
}
}
I would like to thank Barrett Breshears for the Help, and his GithubSource is from 2014 but I could manage to convert it easily because of this clear and well commented piece of code