No internet connection
  1. Home
  2. How to

Save a variable to a file on the hard drive until it needs to change again

By Andrew Sherman @Andrew_Sherman
    2021-05-10 18:29:54.956Z

    I'm looking for a way to make a "saved" variable that stays the same until I need to intentionally change it.

    I'm thinking of making a plain text file and saving it on the hard drive, and putting the variable in the text file, saving it, and then copying the value when I need it.

    How can I write/modify a text file like this, and then copy that for use elsewhere?

    Solved in post #17, click to view
    • 27 replies

    There are 27 replies. Estimated reading time: 15 minutes

    1. samuel henriques @samuel_henriques
        2021-05-10 19:51:45.547Z2021-05-10 20:52:30.472Z

        Hey Andrew,

        To save something definitely, maybe this is a good option. You should check out the forum for something called globalState there are a few threads where Christian explains how it works. They can store anything on soundFlow's memory. But if you restart or quit soundFlow you'll loose the info you stored.

        To write/read a txt you keep on your computer, you can use;

        let txtPath = "~/Desktop/Untitled.txt"
        
        sf.file.writeText({
            path: txtPath,
            text: "wasuupp"
        })
        
        
        let txt = sf.file.readText({ path: txtPath }).text;
        
        log(txt)
        
        1. AAndrew Sherman @Andrew_Sherman
            2021-05-10 20:23:06.111Z

            This is great, Samuel - thank you. I think I'll go with the text file for now but the other method is good to know as well.

            1. AAndrew Sherman @Andrew_Sherman
                2021-05-13 12:22:44.004Z

                Hi Samuel,

                I'm have the text file version of this working fine, but it's a little slow and I think global state might work better. I'm getting stuck though, can you see where I'm going wrong?

                Workflow:
                In Finder select folder, press trigger while holding command to "set current project". Then once "current project" is set, just press the trigger to open the folder in Finder.

                if (event.keyboardState.asString == 'cmd') {
                
                    // Set folder
                    // Copy path
                
                    sf.keyboard.modifiers({ isOption: true })
                
                    sf.ui.finder.menuClick({
                        looseMatch: true,
                        menuPath: ["Edit", "Copy "],
                    });
                
                    sf.keyboard.modifiers({ isOption: false })
                
                    // I'm getting stuck here, I don't think globalState is set up correctly. I want to put the contents of the clipboard into aa globalState variable.
                
                    globalState.currentPath = sf.clipboard.getText().text;
                    var currentPath = globalState.currentPath;
                
                } else {
                
                    // Open folder
                
                    sf.directory.open({ path: currentPath });
                
                }
                
                1. samuel henriques @samuel_henriques
                    2021-05-13 13:49:24.655Z

                    hello @Andrew_Sherman,

                    You want to open the folder of the opened pro tools session?

                    I'm not getting what you are trying to do, sorry.

                    1. AAndrew Sherman @Andrew_Sherman
                        2021-05-13 13:54:57.634Z

                        Hi Samuel,

                        Apologies for not making it clear.

                        It's a script for opening a folder in Finder.

                        The first part of the workflow defines the path (only used if CMD is pressed; I use a stream deck trigger for it while pressing CMD).
                        The second part of the workflow is to open the folder in Finder. (I press the same stream deck trigger, but not while using command).

                        Where I'm getting stuck is how to use globalState - I don't know how to properly use it. I tried various links on the forum bus couldn't get it right. I need the folder path to go into a global state variable.

                        1. samuel henriques @samuel_henriques
                            2021-05-13 14:01:11.581Z

                            ok, I'm getting it now.

                            And the folder doesn't have any relationship with the opened session?
                            Or you don't want it to depend on any session?

                            1. AAndrew Sherman @Andrew_Sherman
                                2021-05-13 14:08:15.680Z

                                No, it doesn't need to be related to any session, just a folder.

                                1. samuel henriques @samuel_henriques
                                    2021-05-13 14:13:55.430Z

                                    and, the original script was getting the path of the open finder window.

                                    If you want to get the selected folder it is easier, code wise, and much more stable.

                                    with one do you intend to use?

                                    1. AAndrew Sherman @Andrew_Sherman
                                        2021-05-13 14:22:15.924Z

                                        This is a different version I currently have which uses a text file instead of globalState (it's working fine, excepting sometimes it doesn't reliably choose the selected folder, I think maybe it's not opening or saving the text file on the disk quickly enough if I'm working fast / clicking fast). Hard drive is an SSD. But as I say, it is working. The thing is that my "current project" changes quite frequently (sometimes I'm editing videos, sometimes I'm doing audio postproduction, sometimes I'm doing music etc).

                                        let settingsDoc = "/Users/andrewsherman/Make Perceive Dropbox/Andrew Sherman/Application Settings/Finder/Current-Project.txt"
                                        
                                        if (event.keyboardState.asString == 'cmd') {
                                        
                                            // Set folder
                                        
                                            sf.keyboard.modifiers({ isOption: true })
                                        
                                            sf.ui.finder.menuClick({
                                                looseMatch: true,
                                                menuPath: ["Edit", "Copy "],
                                            });
                                        
                                            sf.keyboard.modifiers({ isOption: false })
                                        
                                            const finderPathCopied = sf.clipboard.getText().text
                                        
                                            sf.file.writeText({
                                                path: settingsDoc,
                                                text: finderPathCopied
                                            })
                                        
                                        } else {
                                        
                                            // Open folder
                                        
                                            let currentProject = sf.file.readText({ path: settingsDoc }).text;
                                            sf.directory.open({ path: currentProject });
                                        
                                        }
                                        

                                        Which method do you recommend I use, globalState or the text file?

                                        1. samuel henriques @samuel_henriques
                                            2021-05-13 15:12:48.494Z

                                            hey @Andrew_Sherman

                                            this is working here:

                                            const cmdIsEnabled = event.keyboardState.hasCommand
                                            
                                            if (cmdIsEnabled || globalState.folderPath == undefined) {
                                            
                                                globalState.folderPath = ""
                                            
                                                sf.keyboard.modifiers({ isOption: true, isCommand: true })
                                            
                                                sf.ui.finder.menuClick({
                                                    looseMatch: true,
                                                    menuPath: ["Edit", "Copy "],
                                                });
                                            
                                                sf.wait({ intervalMs: 100 })
                                            
                                                globalState.folderPath = sf.clipboard.getText().text;
                                            
                                            
                                            
                                            } else {
                                            
                                                sf.directory.open({ path: globalState.folderPath });
                                            
                                            
                                            }
                                            

                                            From my testing just now, you might need to add a wait on the text version to give a bit of time for the clipboard to get the new text.

                                            1. AAndrew Sherman @Andrew_Sherman
                                                2021-05-13 15:23:04.006Z

                                                Thank you Samuel, as always it's much appreciated. I see where I was going wrong with global state.

                                2. AAndrew Sherman @Andrew_Sherman
                                    2021-06-23 10:09:14.252Z

                                    Hi Samuel,

                                    Hope you're doing well! How can I add a second line of text to this code?

                                    let txtPath = "~/Desktop/Untitled.txt"
                                    
                                    sf.file.writeText({
                                        path: txtPath,
                                        text: "wasuupp"
                                        // I'd like add a second line of text here on a new line
                                    })
                                    
                                    
                                    let txt = sf.file.readText({ path: txtPath }).text;
                                    
                                    log(txt)
                                    
                                    1. samuel henriques @samuel_henriques
                                        2021-06-23 11:12:03.576Z

                                        Hey @Andrew_Sherman,

                                        All good, hope the same for you.

                                        "\n" makes a new line. Or check this article:
                                        https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals

                                        let txtPath = "~/Desktop/Untitled.txt"
                                        
                                        sf.file.writeText({
                                            path: txtPath,
                                            text: "wasuupp\nmore stuff"
                                            // I'd like add a second line of text here on a new line
                                        })
                                        
                                        
                                        let txt = sf.file.readText({ path: txtPath }).text;
                                        
                                        log(txt)
                                        

                                        Or with the template literals:

                                        let txtPath = "~/Desktop/Untitled.txt"
                                        
                                        sf.file.writeText({
                                            path: txtPath,
                                            text: `wasuupp
                                        more stuff
                                        even more`
                                        
                                            // I'd like add a second line of text here on a new line
                                        })
                                        
                                        
                                        let txt = sf.file.readText({ path: txtPath }).text;
                                        
                                        log(txt)
                                        
                                        1. AAndrew Sherman @Andrew_Sherman
                                            2021-06-23 11:19:55.850Z

                                            Excellent, thank you Samuel!

                                            1. Dustin Harris @Dustin_Harris
                                                2021-06-25 04:08:59.019Z

                                                I’m on my phone and can’t remember the syntax off the top of my head, but maybe look into read/write JSON files instead of text. The advantage is you can store key:value pairs and don’t have to split the text file by line breaks to separate values…

                                                1. In reply toAndrew_Sherman:
                                                  Dustin Harris @Dustin_Harris
                                                    2021-06-25 12:20:10.910Z

                                                    this is an easy and elegant way to handle multiple settings being saved/recalled. This assumes both parts of the code are in the same package, but the save / recall file path can be anywhere you want really :)

                                                    
                                                    //save settings (goes in the script that saves the settings)
                                                    
                                                    let setting_one = "This";
                                                    let setting_two = "Is";
                                                    let setting_three = "Cool";
                                                    
                                                    let settingsToSave = {
                                                        setting_one,
                                                        setting_two,
                                                        setting_three,
                                                    };
                                                    
                                                    //this saves the settings file in the package directory of the command it is run from
                                                    let jsonSavePath = sf.soundflow.thisPackage.getDirectory().path + '/savedSettings.json';
                                                    
                                                    
                                                    let success = sf.file.writeJson({
                                                        path: jsonSavePath,
                                                        json: settingsToSave
                                                    }).success;
                                                    
                                                    if (!success) throw `Error saving settings`
                                                    
                                                    
                                                    
                                                    
                                                    //recall settings (goes in the script that needs to use the settings)
                                                    
                                                    let recallSettings = sf.file.readJson({
                                                        path: sf.soundflow.thisPackage.getDirectory().path + '/savedSettings.json'
                                                    }).json
                                                    
                                                    
                                                    let {setting_one, setting_two, setting_three} = recallSettings;
                                                    
                                                    log(setting_one)
                                                    
                                                    Reply2 LikesSolution
                                                    1. samuel henriques @samuel_henriques
                                                        2021-06-25 12:50:28.429Z

                                                        Nice one,
                                                        Wold this file open on any computer you log your account from?
                                                        Or you wold need to carry the file with you?

                                                        Thank you so much.

                                                        1. Dustin Harris @Dustin_Harris
                                                            2021-06-25 12:56:41.372Z

                                                            I don't think the package folder is actively synced when you save files in it's own path... but in theory you could set the save path to a dropbox folder so it does get actively synced?

                                                            1. samuel henriques @samuel_henriques
                                                                2021-06-25 13:02:16.746Z

                                                                Cool. Dropbox could work.

                                                            2. In reply toDustin_Harris:
                                                              AAndrew Sherman @Andrew_Sherman
                                                                2021-06-25 13:17:35.070Z

                                                                This looks very cool Dustin, I'll need a while to get my head around it.

                                                                1. Dustin Harris @Dustin_Harris
                                                                    2021-06-25 13:41:45.213Z

                                                                    It might look a little daunting but it's really no different than using a text file like you were earlier. In fact is IS just a text file, but formatted in a way that makes it easy for scripts to read and write to :)

                                                                    1. AAndrew Sherman @Andrew_Sherman
                                                                        2021-06-25 14:00:51.174Z

                                                                        Putting the filepath in Dropbox works great. This is going to be very handy for me, I was looking for something that handles key value pairs but had no idea that's what it was called. First time json file user... seems easy and lightweight, can edit with text editor if needed as well.

                                                                        1. Dustin Harris @Dustin_Harris
                                                                            2021-06-25 14:04:23.509Z

                                                                            You probably have already realized this, but in case you haven't: the script that READS the JSON file should test that it exists at the beginning of the script, and if it doesn't, it should create the file with default values so the script doesn't throw an error :)

                                                                            1. AAndrew Sherman @Andrew_Sherman
                                                                                2021-06-25 14:44:00.082Z

                                                                                Yes, it's a nice failsafe.

                                                                                1. In reply toDustin_Harris:
                                                                                  AAndrew Sherman @Andrew_Sherman
                                                                                    2021-10-15 09:28:21.502Z

                                                                                    Hi Dustin, I hope you're well!

                                                                                    I'm trying a variation on this script where I need a variable to change depending on whether or not it's been run before.

                                                                                    I will use Script A to write the saved json file, and this will generate the "current" version of the variable value (in my case I'm measuring the size of a folder that's syncing / uploading).

                                                                                    Then at a later stage, I will run Script B which checks the current size of the folder again and measures it against the previous value.

                                                                                    So when Script 1 is run, the folder could be 20GB. Then when Script 2 is run again, the same folder could be 25GB. And then when Script 2 is run again after that (in case the sync is not yet complete), the folder could be 30GB. And I may run Script 2 multiple times until the upload is complete (some folders are very large, TBs in size, hence the need for checking and babysitting them!).

                                                                                    I know how to determine the folder sizes via command line and do most of the script; what I don't know is how to name the variables in such a way that their name or value can change based on whether or not the script was previously run.

                                                                                    I suppose it's dependent on date and time. Would I need to create a new variable each time I run it? In that case how do I get the script to automatically generate variables? Or is there a way of using only the current value, and previous value?

                                                                                    1. Dustin Harris @Dustin_Harris
                                                                                        2021-10-15 12:04:14.004Z

                                                                                        Heyya!
                                                                                        So I assume script A sets the path of the folder being watched (and it's initial size value) and then script B just checks if the file size has changed?

                                                                                        if so, you only need 2 variables. Pseudocode below:

                                                                                        let previousFolderSize = get_this_from_JSON_file();
                                                                                        
                                                                                        let currentFolderSize = get_this_from_terminal_command();
                                                                                        
                                                                                        if (currentFolderSize === previousFolderSize) {
                                                                                        
                                                                                            log('done uploading!')
                                                                                        
                                                                                        } else {
                                                                                        
                                                                                            write_to_JSON_file(currentFolderSize)
                                                                                        }
                                                                                        

                                                                                        does that answer it? :)

                                                                                        1. AAndrew Sherman @Andrew_Sherman
                                                                                            2021-10-16 05:34:23.558Z

                                                                                            Thanks Dustin, much appreciated! I've done something based on that approach. I added in a third variable that is an "old" result and then at the end of the script it gets overwritten with the current result, so that I can see if the upload has stalled instead of just showing overall progress.