Eyeon:Script/Tutorials/Get Loader Filenames/Functions and Tables
From VFXPedia
Lesson 2.5 : Functions and Tables
The information in the eyeon.eyeonscriptlib is a collection of functions that are run whenever a composition is opened. As a user, you can easily create functions in a similar way that can be used multiple times within a composition script.
Functions are a good idea to write as they can be accessed multiple times within the same script and they help to break up code, making it more readable.
One of the problems with the previous incarnation of this script is that it might write the same piece of footage to the text file multiple times if the user has multiple loaders with the same clip in their comp.
To solve this problem, we could read in the file first, put all its information (line by line) into a table that will be compared against all loaders in a composition. If a given loader has a clip that is not in the table, it will be added to both the table and the output file.
A function that would aid this would be one that checks a table to see if a given string value is already present. We could theoretically call this function "isin".
Function names (and variable names, for that matter) should be as readable as possible for debugging purposes.
If we were to define the function isin (to check to see if a value is in a table), then we would do the following.
function isin(t, val) end
The argument variable t is equal to a table and val is equal to the value of the string that is being checked. The operation that we would want to do would go as such:
function isin(t, val) if type(t) == "table" then for i,v in t do end end end
The first thing that needs to be done is to check if the variable t is even a table. This is accomplished by utilizing the type function, which will return a string with the type of value a variable is. Next, the function will cycle through the table.
The function can be stopped at any point by using the return command, which will then return whatever is specified to wherever the function was called. For this function, true should be returned if it's found that the string is in the given table, and false should be returned if it's not.
function isin(t, val) if type(t) == "table" then for i,v in t do if (type(v) == "string") and (type(val) == "string") then if string.lower(v) == string.lower(val) then return true end else if v == val then return true end end end end return false end
There's a bit more error handling in this than is needed for the purposes of this script, but the idea is that if the value is a string, it should be converted to lower case before it is compared (using the string.lower function) in case the user has used any interesting text formatting when they input the name of the file. If, for whatever reason, the type is anything other than a string, then the two values should be compared. If at any point these two values do equal each other, than the function should return true.
If the function gets through the "if" statements without ever returning a "true" value, it should return false instead.
If you now examine the eyeon.eyeonscriptlib file now, you can probably see that the above function already exists. However, sometimes for scripts that will be distributed across studios including the function in the script itself is a good idea in case the user does not have the eyeon.eyeonscriptlib file installed, or has a different version of the library.
Now that the function has been defined, the table that will store the footage will also have to be defined.
clipTable = {}
The squiggly brackets are a way to define that the variable we'll be putting information into is a table.
For example, we could also do the following:
myTable = {"hey", "this is the second entry", "this is the third"} dump(mytable)
Returns:
table: 07CDF928 1 = hey 2 = this is the second entry 3 = this is the third
To add information to a table, you could employ the table.insert function. In order to properly call it, you need to pass the table that will have the new value inserted into it as well as the new value.
table.insert(myTable,1+12) dump(mytable) table: 07CDF928 1 = hey 2 = this is the second entry 3 = this is the third 4 = 13
Or, you could redefine individual table entries by using the square brackets.
myTable[1] = "no longer hey" dump(myTable) table: 07CDF928 1 = no longer hey 2 = this is the second entry 3 = this is the third 4 = 13
You can also print individual table entries in a similar way.
=myTable[4] 13
Now, try integrating these concepts into the code that's already been written. The method that we using to read through the text file will now be the line method ("*l") so that it can be properly stored in the table. The full script and an explanation is below.
function isin(t, val) if type(t) == "table" then for i,v in t do if (type(v) == "string") and (type(val) == "string") then if string.lower(v) == string.lower(val) then return true end else if v == val then return true end end end end return false end print("\n\n----------------------------------------------\nLIST LOADER FOOTAGE:\n----------------------------------------------\n\n") clipTable = {} -- Define the file to write to. -- Check to see i it exists. if fileexists("c:\\LoaderList.txt") == true then -- If it does exist, append new information to the end of the file. fh, errormessage = io.open("c:\\LoaderList.txt","a+") -- Print all the information in the text file. print("TEXT FROM FILE:\n") -- Cycle through the text file until the line returned is equal to nil -- (meaning there is no text on the line ) line = fh:read("*l") if line then while line do print(line) table.insert(clipTable,line) line = fh:read("*l") end end -- Divide the Script print("\n\nLOADERS:") else -- Set the output fh, errormessage = io.output("c:\\LoaderList.txt") end -- check to see if it returned a value for fh if not fh then -- if fh is equal to nil print(errormessage) return end -- Get a list of all loaders loaderlist = eyeon.GetLoaders(composition) -- Cycle through all the loaders for i, tool in loaderlist do -- Get the tool's Clip List attribute attrs = tool:GetAttrs() -- check to see if there's a clip list if attrs["TOOLST_Clip_Name"] then -- print the loader's name print(attrs.TOOLS_Name) -- cycle through that table for j = 1, table.getn(attrs["TOOLST_Clip_Name"]) do -- print each entry to the console. we should still do this -- even if the text file already has the loader in it print("--"..attrs["TOOLST_Clip_Name"][j]) -- Check to see if it's already been written to the file. if isin(clipTable, attrs["TOOLST_Clip_Name"][j]) == false then -- Write the data. fh:write("\n"..attrs["TOOLST_Clip_Name"][j]) table.insert(clipTable, attrs["TOOLST_Clip_Name"][j]) end end end end fh:close() print("\n----------------------------------------------\nSCRIPT COMPLETE\n----------------------------------------------\n")
The key points of change are in this chunk:
line = fh:read("*l") if line then while line do print(line) table.insert(clipTable,line) line = fh:read("*l") end end
Where it's printing the first line and adding it to the clipTable using the table.insert function. It will not do this if the variable line is equal to nil (this would mean that the text file's next line is empty and therefore equal to nil).
Additionally:
if isin(clipTable, attrs["TOOLST_Clip_Name"][j]) == false then -- Write the data. fh:write("\n"..attrs["TOOLST_Clip_Name"][j]) table.insert(clipTable, attrs["TOOLST_Clip_Name"][j]) end
This is the other addition. If the clip is not in the table (if isin returns false) then it will write the data and insert the new clip into the clipTable variable.
However, the user may want to save this file somewhere other than on their C: drive. Additionally, they might not want to append this information onto their file.
In the next exercise, we'll create a prompt that will ask the user what they want to do with the information from the loaders.
Tips for Functions and Tables (edit)
EyeonTips:Script/Tutorials/Get Loader Filenames/Functions and Tables
