SwiftAudio - Open filename which contains whitespaces - swift

I'm using SwiftAudio library to open local url but I have a problem when I try to open an url that contains whitespaces in filename.
So, for example, if I try to open a file which name is "example_file.mp3" this audio is successfully opened.
But, if I try to open a file which name is "example file.mp3" an error occurs: "The requested URL was not found on this server".
I've also tried to replace the name with "example%20file.mp3" but I have the same error.
I wrote this code:
var urlPath = "/Users/manuela/Library/Developer/CoreSimulator/Devices/64E0D907-16AD-41A9-9667-4B3C701D4F1B/data/Containers/Data/Application/488A8AAD-EF4B-452D-9A8A-67307C489C72/Library/example file.mp3"
urlPath = urlPath.addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed)!
print(urlPath) // this prints "/Users/manuela/Library/Developer/CoreSimulator/Devices/64E0D907-16AD-41A9-9667-4B3C701D4F1B/data/Containers/Data/Application/488A8AAD-EF4B-452D-9A8A-67307C489C72/Library/example%20file.mp3"
let url = URL(string: urlPath)!
let item = DefaultAudioItem(audioUrl: filePath, sourceType: .file)
let controller = AudioController()
try? controller.player.load(item: item, playWhenReady: true)
I'm sure that the problem is the whitespaces but I don't know with which character substitutes it.
Can someone help me, please?

Related

URL(filePath: strPath) vs URL(fileURLWithPath: strPath)

let url = URL(filePath: pathString!)
let url2 = URL(fileURLWithPath: pathString!)
I tried both and they worked both.
What's the difference between the two ways creating such an URL-object?
String file paths are outmoded. Use file URLs. And not file URLs derived from a string file path; construct or obtain the URL legitimately. So the real answer is: don't use either of those methods.

Creating a temporary txt file, from a String, to use as an NSSharingService item?

When the user is confronted with an unexpected error, I'm providing them with the option to send the error log contents as an email body of an NSSharingService item as such:
let errorLog = "[Extensive log output with many symbols and new lines]"
let service = NSSharingService(named: NSSharingService.Name.composeEmail)
service?.recipients = ["help#email.com"]
service?.subject = "Help: App Error"
service?.perform(withItems: [errorLog])
Is there an efficient way to go about sending the error log contents as an attached text file, using temporary file references; as opposed to having to work with directories and permissions? Something along the lines of:
let txtFile = String(errorLog) as? file(name: "ErrorLog", withExtension: "txt")
service?.perform(withItems: [txtFile])
Swift has constantly surprised me with how simple and easy some of its implementation can be, so I thought I'd ask.
Thank you!
Swift 5.2
Updated: September 4, 2022
Using the solution found here, I was able to create a String extension using FileManager.default.temporary:
extension String {
func createTxtFile(_ withName: String = "temp") -> URL {
let url = FileManager.default.temporaryDirectory
.appendingPathComponent(withName)
.appendingPathExtension("txt")
let string = self
try? string.write(to: url, atomically: true, encoding: .utf8)
return url
}
}
Which can be called from any String; ie.
let myString = "My txt file contents"
// Creates a URL reference to temporary file: My-File-Name.txt
let txtFile = myString.createTxtFile("My-File-Name")
Conclusion: NSSharingService
All together, this will end up looking something like:
let messageContents = "Email body with some newlines to separate this sentence and the attached txt file.\n\n\n"
let txtFileContents = "The contents of your txt file as a String"
// Create a URL reference to the txt file using the extension
let txtFile = txtFileContents.createTxtFile("Optional-File-Name")
// Compose mail client request with message body and attached txt file
let service = NSSharingService(named: NSSharingService.Name.composeEmail)
service?.recipients = ["my#email.com"]
service?.subject = "Email Subject Title"
service?.perform(withItems: [messageContents, txtFile])

Find a string value on a webpage with swift

I want to pull the balance value from a website: https://nimiq.watch/#NQ74+FLQL+DRE3+99PF+CET0+3N7D+JKLF+MQP6+87KS
The number after hash is the wallet address
I tried to use this to find the balance
wallet_address = "NQ48+8CKH+BA24+2VR3+N249+N8MN+J5XX+74DB+5XJ8"
let myURLString = "https://nimiq.watch/#"+wallet_address
let myURL = NSURL(string: myURLString)
var myHTMLString = try String(contentsOf: myURL! as URL)
print(myHTMLString)
when I inspect element in browser it shows this..
<span>340510.29275 NIM</span>
But when I pull with the script I get this
<span>{%=_formatBalance(Nimiq.Policy.satoshisToCoins(o.balance))%} NIM</span>
any suggestions? or is this just not possible.. thanks!

How do I parse out only the files actual name and not the full path?

I have some code that (I thought) could split a filename from its file type. For example, "filename.txt" -> ["filename, "txt"].
However, I didn't realize that when I use a dialog box to open a file name, I get the full path (rookie mistake, I know). For example, this is what my function is returning:
filename_array: ["/home/user/Downloads/filename", "txt"]
How do I remove the path stuff and only return the filename part?
Apple has been trying to get rid of all the "path as string" style and migrate them into URL. The path manipulation API has been removed from String and moved to URL:
let path = "/home/user/Downloads/filename.txt"
let url = URL(fileURLWithPath: path)
let fileNameOnly = url.deletingPathExtension().lastPathComponent // filename
let fileExtention = url.pathExtension // txt
Or you can do it old-school style with NSString:
let path = "/home/user/Downloads/filename.txt"
let fileName = (path as NSString).lastPathComponent as NSString // filename.txt
let fileNameOnly = fileName.deletingPathExtension // filename
let fileExtension = fileName.pathExtension // txt

How to Use SwiftyDropbox's "destination" with a Download

In reviewing the SwiftyDropbox tutorial in the v2 Dropbox API, it shows how to perform a download:
// Download a file
let destination : (NSURL, NSHTTPURLResponse) -> NSURL = { temporaryURL, response in
let fileManager = NSFileManager.defaultManager()
let directoryURL = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
// generate a unique name for this file in case we've seen it before
let UUID = NSUUID().UUIDString
let pathComponent = "\(UUID)-\(response.suggestedFilename!)"
return directoryURL.URLByAppendingPathComponent(pathComponent)
}
client.files.download(path: "/MyFile.db", destination: destination).response { response, error in
if let (metadata, url) = response {
print("*** Download file ***")
let data = NSData(contentsOfURL: url)
print("Downloaded file name: \(metadata.name)")
print("Downloaded file url: \(url)")
print("Downloaded file data: \(data)")
} else {
print(error!)
}
}
I'm unclear what's going on with the destination part. Why do I need to generate a random string for the filename?
When I try to specify my own filename, the download doesn't seem to work:
let destination : (NSURL, NSHTTPURLResponse) -> NSURL = { temporaryURL, response in
let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
return directoryURL.URLByAppendingPathComponent("MyFile.db")
}
I want to download a file from Dropbox named MyFile.db and I want to put it in my device's documents directory with the name MyFile.db and overwrite it if it's already there.
How can I do that?
When you say it doesn't seem to work, I expect you mean you get an error like this:
Error Domain=NSCocoaErrorDomain Code=516 "“CFNetworkDownload_bPYhu1.tmp” couldn’t be moved to “Documents” because an item with the same name already exists." UserInfo={NSSourceFilePathErrorKey=..., NSUserStringVariant=(
Move
), NSDestinationFilePath=..., NSUnderlyingError=0x7fda0a67cea0 {Error Domain=NSPOSIXErrorDomain Code=17 "File exists"}}
SwiftyDropbox, by virtue of using AlamoFire, doesn't currently let you overwrite files using the download function.
Specifically, SwiftyDropbox calls download in AlamoFire, and AlamoFire calls NSFileManager.moveItemAtURL. The documentation for NSFileManager.moveItemAtURL says:
If an item with the same name already exists at dstURL, this method aborts the move attempt and returns an appropriate error.
So, it seems like it's just being cautious, and making it hard for your app to accidentally overwrite (ad potentially lose) data. If you definitely know you want to overwrite a particular file, you'll need to do so explicitly, after the Dropbox API call. We'll consider this a feature request though.
Update: SwiftyDropbox now offers the ability to overwrite the files directly as of version 3.1.0, e.g., using download(path:rev:overwrite:destination:).