How to run a terminal program like FFMPEG from Xcode coco app using swift? - swift

I am working on making a Xcode app using swift. I am trying to run FFMPEG when someone clicks on a button. In terminal it would look like
ffmpeg -i input.mp4 output.mp4
But after searching everywhere, I can't seem to find how to run a command as if you were typing it into Terminal.
So my question is, how do you run a command (probably from a textfield) just as if you typed it into Terminal?
Here is my code so far:
import Foundation
import Cocoa
class ViewController: NSViewController {
#IBOutlet weak var inURL: NSTextField!
#IBOutlet weak var inText: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
#IBAction func clickURL(_ sender: Any) {
var musicURL = inURL.stringValue
if musicURL.isEmpty {
musicURL = "No URL entered!"
}
let textReplace = "Downloading music from: \(musicURL)..."
inText.stringValue = textReplace
Process.launchedProcess(launchPath: "/usr/local/Cellar/ffmpeg/4.0.2/bin/ffmpeg", arguments: ["-i","input.mp4","output.mp4"])
}
}
I will also be using youtube-dl from GitHub, if I can get FFMPEG working.

var p = Process.launchedProcess(launchPath: "/a/path/to/ffmpeg", arguments: ["-i", "input.mp4", "output.mp4"])

I am also trying to do this at the moment and it seems to be a permission issue, has nothing to do with swift. I recently read it here. The idea is that sandboxed apps cannot read files from just anywhere. For some standard paths, you can enable access (see here), but for others you cannot. Also, seems like it is possible to launch executables from /usr/bin by default, but not for /usr/local/bin, at least not without specifically enabling it. I'll be looking into this some more and come back if I find a proper solution.
Edit:
An option that I just tested an works for me, is to bundle ffmpeg in my app sandbox and use it from there. I downloaded ffmpeg from here and added it to Xcode in the target Build Phases > Copy Bundle Resources, then accessed it programmatically from this path
let ffmpegPath = Bundle.main.bundlePath + "/Contents/Resources/ffmpeg"

Related

why in xcode, home directory is showing as /Users/myname/Library/Containers/... and not the main folder?

I searched a lot and couldn't find the answer.
I just started using xcode and have a very very simple program named "Image Test".
---> It has a button, and a textField. I want to show my system home directory path in the textField. This is my code:
#IBOutlet weak var textField1: NSTextField!
#IBAction func Button1(_ sender: Any) {
do{
let home = try FileManager.default.homeDirectoryForCurrentUser
textField1.stringValue = home.path
}
catch{}
}
it works but the returned path is like:
/Users/myname/Library/Containers/com.Image-Test/Data
I have tested this code before in Xcode Playground and it was correct. Its the same code but not throwing the right path.
It's because of sandboxing. The documentation states:
The App Sandbox Container Directory
It is located at a system-defined path, within the user’s home directory. In a sandboxed app, this path is returned when your app calls the NSHomeDirectory function.
You can verify this by removing the App Sandbox capability (note: I am not suggesting that this is what you should do for your app).
PS: If you intend to submit your app to the AppStore, sandboxing must be enabled.

Unable to find resource located in assets.xcassets

Hey guys I am still kind of new to Stackoverflow so please bear with me if I am doing something wrong, I am trying my best.
I am trying to make a simple app with the new apple watchOS6 and swiftUI in the new Xcode11 beta that plays a sound file from assets.xcassets.
I think I am doing something wrong when trying to find the file I have in the assets, here's the error code:
Fatal error: Unexpectedly found nil while unwrapping an Optional value: file /Users/phillipeismark/Desktop/WatchOS6/WatchOS6Demo/WatchOS6Demo WatchKit Extension/Model/AudioPlayer.swift, line 21
2019-08-28 15:06:58.396058+0200 WatchOS6Demo WatchKit Extension[12691:794523] Fatal error: Unexpectedly found nil while unwrapping an Optional value: file /Users/phillipeismark/Desktop/WatchOS6/WatchOS6Demo/WatchOS6Demo WatchKit Extension/Model/AudioPlayer.swift, line 21
My code is built like this:
I have a ContentView that is a list that just displays my button that calls the my audioplayer when its pressed. The code for ContentView is not included.
The AudioPlayerButton struct looks like this and it basically just calls play() on the player:
struct AudioPlayerButton: View {
#State var player = AudioPlayer()
var body: some View {
Button(action: player.play) {
Image("newPlayButton")
}
}
}
This is my AudioPlayer class where I get the error:
import Foundation
import AVFoundation
import Combine
import SwiftUI
class AudioPlayer {
var didChange = PassthroughSubject <Void, Never>()
var isPlaying: Bool = false
var AudioPlayer: AVAudioPlayer?
let url = URL.init(fileURLWithPath: Bundle.main.path(forResource: "Glad", ofType: ".wav")!)
//let url = URL.init(fileURLWithPath: Bundle.main.path(forResource: "Glad", ofType: ".wav", inDirectory:"/Users/phillipeismark/Desktop/WatchOS6/WatchOS6Demo/WatchOS6Demo WatchKit Extension/Assets.xcassets/" )!)
func play() {
do {
AudioPlayer = try AVAudioPlayer(contentsOf: url)
AudioPlayer?.play()
} catch {
print(error)
}
}
}
I noticed that there are multiple asset.xcassets folders, one inside watchOS6 WatchKit App and one inside of WatchOS6 WatchKit Extension, to be sure I hadn't put it in the wrong place I just added the file to both of the folders.
Here is what I have tried:
1: I noticed that there is multiple asset.xcassets folders and I have tried to add the file to both of them.
2: I have tried to set both the ForResource and ofType parameters as nil to kind of try to "hit more targets" as the Documentation says: "If you specify nil, the method returns the first resource file it finds that matches the remaining criteria".
3: I tried to give a value to the the 3rd parameter in path(forResource:ofType:inDirectory:) as you can see in my AudioPlayer class with the outcommented line.
4: I took an old sound from an old project that I knew worked. I also tested if that project could run and it could.
Anything that could send me in the right direction are very much appreciated! Thanks.
I uploaded the project to GitHub if anybody wanted to look at it.
Update: IT WORKS I ran the normal iPhone simulator in another project. I did not do anything but make a new project and start the simulator. Then I opened the browser went on YouTube and played a video. It still didn't work so I let the video play in the simulator and continued to google around. Then when the video ended and YouTube had to play an add the sound magically started to work - there was an add even before the video started but that one didn't make it work, it was at the videos end. I was speechless. my GUESS is that the iPhone simulator made a configuration but I have no idea. Any theories about how this work or could work is very much appreciated

AWS Amplify / iOS SDK tutorial missing steps

I am following this Getting Started guide for building an iOS app using the AWS Amplify CLI and the AWS SDK for iOS.
And I had previously followed the steps in this Apple Getting Started guide for simply creating the basic framework for a Single View Application.
Everything works without a hitch: I was able to build my empty project in Xcode, launch the simulator, see my white blank screen, both before and after starting the AWS iOS SDK Swift tutorial.
My problem is that the AWS tutorial presumes more Swift knowledge than I have. So when it says the following toward the end—
Call the runMutation(), runQuery(), and subscribe() methods from your
app code, such as from a button click or when your app starts in
viewDidLoad().
—the guide has essentially skipped some steps.
I've already created the required AWS resources for this tutorial but I don't know how to call the functions and update the DynamoDB table that gets set up.
Assuming I can add two text fields to the UI View (one for the ToDo 'name' and one for the 'description') and tie a button to them, can someone help me go the rest of the way?
UPDATE
Answered below. I received a down-vote for asking this question, but one might argue that a Getting Started guide should be self-contained. No biggie; I worked across the two tutorials and solved my problem and posted an answer for those who are confused as I was.
So, I was able to successfully complete the AWS Amplify / iOS SDK Getting Started guide after leveraging the Apple iOS Swift Getting Started guide to create the necessary view elements required by AWS. What that means is this:
Two text fields: 'name' and 'description'; a label; and a button. Here are my outlet properties:
//MARK: Properties
#IBOutlet weak var nameTextField: UITextField!
#IBOutlet weak var descTextField: UITextField!
#IBOutlet weak var todoItemLabel: UILabel!
My viewDidLoad():
override func viewDidLoad() {
super.viewDidLoad()
// Handle the text field’s user input through delegate callbacks.
nameTextField.delegate = self
descTextField.delegate = self
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appSyncClient = appDelegate.appSyncClient
}
My button action which calls runMutation():
//MARK: Actions
#IBAction func addToDoItem(_ sender: UIButton) {
runMutation()
}
And changes to runMutation() to update DynamoDB with the entered values:
let mutationInput = CreateTodoInput(name: nameTextField.text ?? "No Entry", description: descTextField.text)
If you have followed Steps 1 - 4 of the AWS Amplify / iOS SDK Getting Started guide and added the necessary UI elements then the code above will seal the deal.
Also note that the API reference pointed at by #dennis-w in the comments above takes care of those deprecated references in AppDelegate from the Getting Started guide.

Swift environment variable returns nil when building app

Description
I have a problem with environment variables. When I build my app and it's running, everything goes fine, but when I press "stop" or I archive it for app store, the environment variable returns nil (or an empty string, I'm not quite sure yet).
How to reproduce:
Build the app
Run it on the simulator ("Hello world" will appear)
Stop the app
In the simulator, go back in the app ("Hello word" won't appear)
Minimal reproduction:
class ViewController: UIViewController {
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
label.text = ProcessInfo.processInfo.environment["testVariable"]
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
The label Outlet references a simple storyboard
storyboard screenshot
And here is the config for my env variables
Variables configuration
Finally, here is a minimal reproduction of the problem on a github repo
https://github.com/MasterBroki/test-environment-variable
Thanks for your answers!
Xcode passes environment variables from a scheme to the iOS runtime. When you run the application outside of Xcode, they are not passed. I've also run into this limitation, and you can find a similar question here.
An alternative to this approach is to use pairings of configurations (such as Debug, Release, or one you make for a specific purpose) and "Preprocessor Flags" OR "Other Swift Flags." You can find some guidance for this approach here.
Running into the same problem. Using normal Debug and Release config options with checks like
#if DEBUG
<logic>
#else
<logic>
#endif
works for me

MusicSequenceFileLoad Works in Playgrounds but not in Project

what am i doing wrong?
i'm trying to open a midi file and read it's contents. so far i can open the file in playgrounds but i get "Open::fopen failed" in my project
override func viewDidLoad() {
super.viewDidLoad()
let path = NSURL.fileURL(withPath: "/users/me/file.mid")
var midfile: MusicSequence?
NewMusicSequence(&midfile)
MusicSequenceFileLoad(midfile!, path as CFURL, .midiType , .smf_ChannelsToTracks)
}
i do have import AudioToolbox and CoreMIDI
EDIT: some progress
I'm able to open midi files from bundle with CFBundleCopyResourceURL, but i want to be able to open files from anywhere in finder
fileManager also fails, it returns nil when used inside a project and works in playgrounds.
figured it out.
code fails because the app runs sandboxed and the NSURL can't be accessed