Edit: ignore this post and read the next one. I'll leave this here just in case.
I've edited my script a bit to remove certain specifics. Install this as a menu script, save it as "LK_ChangeServerPaths.lua". You'll also need to install this utility file:
FO_Utilities.lua
Code: Select all
-- **************************************************
-- Provide Moho with the name of this script object
-- **************************************************
ScriptName = "LK_ChangeServerPaths"
-- **************************************************
-- General information about this script
-- **************************************************
LK_ChangeServerPaths = {}
function LK_ChangeServerPaths:Name()
return "Change Server Path"
end
function LK_ChangeServerPaths:Version()
return "0.1"
end
function LK_ChangeServerPaths:Description()
return "Change Server Path"
end
function LK_ChangeServerPaths:Creator()
return "Lukas Krepel, Frame Order"
end
function LK_ChangeServerPaths:UILabel()
return "Change Server Path"
end
LK_ChangeServerPaths.projectsServerPaths = {
"A:/", -- * 1
"/Volumes/PROJECTS/", -- * 2
"D:/dropbox/animations/", -- * 3
"/Users/SomeGuy/Dropbox/Projects/", -- * 4
"D:/lalala/", -- * 5
}
LK_ChangeServerPaths.ResourcesServerPaths = {
"B:/", -- * 1
"/Volumes/RESOURCES/", -- * 2
"A:/Dropbox/Resources/", -- * 3
"/Users/SomeGuy/Dropbox/Resources/", -- * 4
"B:/a weird folder name/every pc is different/", -- * 5
}
LK_ChangeServerPaths.choices = {
"Studio (Windows)", -- * 1
"Studio (macOS)", -- * 2
"SomePersonWorkingAtHome (Dropbox)", -- * 3
"AnotherWorkingAtHome (Dropbox)", -- * 4
"YepWorkingAtHome (Dropbox)", -- * 5
}
LK_ChangeServerPaths.choice = 0
LK_ChangeServerPaths.projectsServerPath = nil
LK_ChangeServerPaths.resourcesServerPath = nil
LK_ChangeServerPaths.changedScale = false
function LK_ChangeServerPaths:LoadPrefs(prefs)
self.choice = prefs:GetInt("LK_ChangeServerPaths.choice", 0)
self.projectsServerPath = prefs:GetString("LK_ChangeServerPaths.projectsServerPath", nil)
self.resourcesServerPath = prefs:GetString("LK_ChangeServerPaths.resourcesServerPath", nil)
end
function LK_ChangeServerPaths:SavePrefs(prefs)
prefs:SetInt("LK_ChangeServerPaths.choice", self.choice)
prefs:SetString("LK_ChangeServerPaths.projectsServerPath", self.projectsServerPath)
prefs:SetString("LK_ChangeServerPaths.resourcesServerPath", self.resourcesServerPath)
end
-- **************************************************
-- Offset Amount Dialog
-- **************************************************
local LK_ServerPathDialog = {}
LK_ChangeServerPaths.images = 0
LK_ChangeServerPaths.changedImages = 0
LK_ChangeServerPaths.scripts = 0
LK_ChangeServerPaths.changedScripts = 0
LK_ChangeServerPaths.scaledLayerNames = {}
LK_ChangeServerPaths.undoPrepped = false
LK_ServerPathDialog.SELECTPATH = MOHO.MSG_BASE + 100 -- 100 t/m 199 gereserveerd
function LK_ServerPathDialog:new(moho)
local d = LM.GUI.SimpleDialog("Change project folder:", LK_ServerPathDialog)
local l = d:GetLayout()
d.moho = moho
--
local layer = moho.document:GetSelectedLayer()
--
d.explanation1 = LM.GUI.StaticText("Change the path for files on the Projects server, they will be replaced for every image layer.")
d.projectsServerPathLabel = LM.GUI.DynamicText("LABEL:", 80)
d.projectsServerPathLabel:SetValue("Projects path:")
d.projectsServerPathTextBox = LM.GUI.DynamicText(LK_ChangeServerPaths.projectsServerPaths[LK_ChangeServerPaths.choice], 500)
--
d.resourcesLabel = LM.GUI.DynamicText("LABEL:", 80)
d.resourcesLabel:SetValue("Resources path:")
d.resourcesTextBox = LM.GUI.DynamicText(LK_ChangeServerPaths.ResourcesServerPaths[LK_ChangeServerPaths.choice], 500)
--
l:PushH()
l:AddChild(d.explanation1)
l:Pop() -- New line
l:PushH()
l:AddChild(d.projectsServerPathLabel)
l:AddChild(d.projectsServerPathTextBox)
--
l:Pop() -- New line
l:PushH()
l:AddChild(d.resourcesLabel)
l:AddChild(d.resourcesTextBox)
--
l:Pop() -- New line
--
l:PushH(LM.GUI.ALIGN_CENTER, -1)
for i, string in ipairs(LK_ChangeServerPaths.projectsServerPaths) do
l:AddChild(LM.GUI.Button(LK_ChangeServerPaths.choices[i], self.SELECTPATH + i))
end
l:Pop() -- New line
-- This is where a "Cancel" and "OK" button show up
return d
end
function LK_ServerPathDialog:HandleMessage(msg)
if msg > self.SELECTPATH and msg < (self.SELECTPATH + 99) then
local option = (msg - self.SELECTPATH)
LK_ChangeServerPaths.choice = option
local projectsPath = LK_ChangeServerPaths.projectsServerPaths[option]
local resourcesPath = LK_ChangeServerPaths.ResourcesServerPaths[option]
self.projectsServerPathTextBox:SetValue(projectsPath)
self.resourcesTextBox:SetValue(resourcesPath)
end
end
function LK_ServerPathDialog:OnOK()
--
end
-- **************************************************
-- The guts of this script
-- **************************************************
function LK_ChangeServerPaths:Run(moho)
moho.document:PrepUndo(moho.layer, false)
moho.document:SetDirty()
self.choice = 0 -- DISABLE THIS LINE ONCE EVERYTHING IS WORKING CORRECTLY BY ADDING "--" IN FRONT OF IT
if (self.choice == 0) then
local dlog = LK_ServerPathDialog:new(moho)
if (dlog:DoModal() == LM.GUI.MSG_CANCEL) then
return
end
end
--
local newProjectsPath = LK_ChangeServerPaths.projectsServerPaths[self.choice]
local newResourcesPath = LK_ChangeServerPaths.ResourcesServerPaths[self.choice]
--
self.projectsServerPath = newProjectsPath
self.resourcesServerPath = newResourcesPath
--
newProjectsPath = self:CorrectSlashesPath(newProjectsPath)
newResourcesPath = self:CorrectSlashesPath(newResourcesPath)
--
self.images = 0
self.changedImages = 0
self.scaledLayerNames = {}
--
self.scripts = 0
self.changedScripts = 0
--
self.undoPrepped = false
self.changedScale = false
--
local layers = FO_Utilities:AllLayers(moho)
self.layersDone = {}
for i = 1, #layers do
local layer = layers[i]
-- *** Images
if (layer:LayerType() == MOHO.LT_IMAGE) then
-- * Set Image Quality to high:
LK_Render:SetHighImageQuality(moho, layer)
-- print ("___"..layer:Name())
self.images = self.images + 1
-- *** Projects
local newPath = newProjectsPath
for j, string in ipairs(LK_ChangeServerPaths.projectsServerPaths) do
if not table.contains(self.layersDone, layer) then
if (j ~= LK_ChangeServerPaths.choice) then
local oldPath = LK_ChangeServerPaths.projectsServerPaths[j]
self:ChangeImagePath(moho, layer, oldPath, newPath)
end
end
end
--
if not table.contains(self.layersDone, layer) then
-- *** Resources
local newPath = newResourcesPath
for j, string in ipairs(LK_ChangeServerPaths.ResourcesServerPaths) do
if not table.contains(self.layersDone, layer) then
if (j ~= LK_ChangeServerPaths.choice) then
local oldPath = LK_ChangeServerPaths.ResourcesServerPaths[j]
self:ChangeImagePath(moho, layer, oldPath, newPath)
end
end
end
end
--
end
-- *** Layerscripts
local scriptPath = layer:LayerScript()
if (scriptPath ~= "") then
self.scripts = self.scripts + 1
self:ChangeLayerscriptPath(moho, layer)
end
end
if (self.changedImages > 0 or self.changedScripts > 0) then
local alertMessage = "Changed paths for " .. self.changedImages .. " / " .. self.images .. " images and " .. self.changedScripts .. " / " .. self.scripts .. " layerscripts."
local scaleAlert = nil
if self.changedScale then
scaleAlert = "WARNING, SCALE HAS BEEN CHANGED FOR "..#self.scaledLayerNames.." IMAGES TO FIX SIZE."
local scaleData = "\n"
for i = 1, #self.scaledLayerNames do
-- print (i.."/"..#self.scaledLayerNames)
local line = self.scaledLayerNames[i]
-- print (line)
scaleData = scaleData..line.."\n"
end
LM.GUI.Alert(LM.GUI.ALERT_WARNING, alertMessage, scaleAlert, scaleData, "OK", nil, nil)
else
LM.GUI.Alert(LM.GUI.ALERT_INFO, alertMessage, scaleAlert, nil, "OK", nil, nil)
end
end
end
-- **************************************************
-- Changing the path on an image layer
-- **************************************************
function LK_ChangeServerPaths:ChangeImagePath(moho, layer, oldPath, newPath)
-- print (" - ChangeImagePath:"..layer:Name())
oldPath = self:CorrectSlashesPath(oldPath)
local imageLayer = moho:LayerAsImage(layer)
local imagePath = (imageLayer:SourceImage())
imagePath = string.gsub(imagePath, oldPath, newPath)
-- * Check if path has changed:
if (imagePath == imageLayer:SourceImage()) then
return
end
-- * Check if file exists:
if not FO_Utilities:FileExists(moho, imagePath) then
print ("Unable to locate image file for layer ["..layer:Name().."] File doesn't exist: ["..imagePath.."]")
return
end
-- print (layer:Name() .. " -> NEW IMAGE PATH: " .. imagePath)
-- * Check old size:
local oldHeight = imageLayer:Height()
-- * Change image source:
if not self.undoPrepped then
moho.document:PrepUndo(moho.layer, true)
moho.document:SetDirty()
self.undoPrepped = true
end
imageLayer:SetSourceImage(imagePath)
-- * Compare to new size:
local newHeight = imageLayer:Height()
-- * Check if difference is significant:
local heightDifference = math.abs (oldHeight - newHeight)
if heightDifference < 0.1 then
heightDifference = 0
end
-- * Change size on frame 0 and timeline:
if heightDifference ~= 0 then --newHeight ~= oldHeight then
self.changedScale = true
local heightChange = oldHeight / newHeight
local scaleChannel = imageLayer.fScale
local oldScale = scaleChannel:GetValue(0)
local newScale = oldScale * heightChange
-- * Main timeline scale channel for this image layer:
local endKey = scaleChannel:Duration()
local thisKey = 0
local keyCount = scaleChannel:CountKeys()
local keysFound = 0
local frameNum = endKey
while keysFound < keyCount do
thisKey = scaleChannel:GetClosestKeyID(frameNum)
keyFrameNum = scaleChannel:GetKeyWhen(thisKey)
keysFound = 1 + keysFound
-- * Scale it:
local oldScale = scaleChannel:GetValue(keyFrameNum)
local newScale = oldScale * heightChange
scaleChannel:SetValue(keyFrameNum, newScale)
frameNum = keyFrameNum - 1
end
-- * Do all action scale channels for this image layer too:
for i = 0, scaleChannel:CountActions()-1 do
local actionChannel = moho:ChannelAsAnimVec3(scaleChannel:Action(i))
local endKey = actionChannel:Duration()
local thisKey = 0
local keyCount = actionChannel:CountKeys()-1 -- * -1 because we don't want to modify frame 0 in actions!
local keysFound = 0
local frameNum = endKey
while keysFound < keyCount do
thisKey = actionChannel:GetClosestKeyID(frameNum)
keyFrameNum = actionChannel:GetKeyWhen(thisKey)
keysFound = 1 + keysFound
-- * Scale it:
local oldScale = actionChannel:GetValue(keyFrameNum)
local newScale = oldScale * heightChange
actionChannel:SetValue(keyFrameNum, newScale)
frameNum = keyFrameNum - 1
end
end
table.insert(self.scaledLayerNames, "- "..layer:Name().." S.old: "..oldScale.y.." S.new: "..newScale.y.." H.diff: "..heightDifference)
end
self.changedImages = self.changedImages + 1
table.insert(self.layersDone, layer)
end
-- **************************************************
-- Changing the path on an image layer
-- **************************************************
function LK_ChangeServerPaths:ChangeLayerscriptPath(moho, layer)
local userPath = string.gsub(moho:UserAppDir(), '\\', '/')
local scriptsFolder = "/Shared Resources/Embedded Scripts/"
local newPath = userPath .. scriptsFolder
newPath = self:CorrectSlashesPath(newPath)
local scriptPath = layer:LayerScript()
local embeddedscript = string.gsub(scriptPath, '\\', '/')
local lastslashpos = (embeddedscript:reverse()):find("%/") -- find last slash
embeddedscript = (embeddedscript:sub(-lastslashpos+1)) -- filename only
oldPath = string.gsub(scriptPath, embeddedscript, "") -- path without filename
oldPath = self:CorrectSlashesPath(oldPath)
-- TODO: ALSO CHECK IF LAYERSCRIPT EXISTS IN NEW LOCATION
if (oldPath ~= newPath) then
scriptPath = string.gsub(scriptPath, oldPath, newPath) -- ***
Debug:Log(layer:Name() .. " -> NEW LAYERSCRIPT PATH: " .. newPath .. embeddedscript)
if not self.undoPrepped then
moho.document:PrepUndo(moho.layer, true)
moho.document:SetDirty()
self.undoPrepped = true
end
layer:SetLayerScript(scriptPath)
self.changedScripts = self.changedScripts + 1
end
end
function LK_ChangeServerPaths:CorrectSlashesPath(path)
if (FO_Utilities:getOS() == "unix") then
path = string.gsub(path, "\\", "/")
else
path = string.gsub(path, "/", "\\")
end
return path
end
-- **************************************************
-- Change a single path
-- (Don't use this when looping trough layers)
-- (Used in other scripts like LK_RenderLocal)
-- **************************************************
function LK_ChangeServerPaths:FixPath(moho, path, choice)
choice = choice or self.choice
-- *** Projects
local newProjectsPath = self.projectsServerPaths[choice]
local newPath = newProjectsPath
for i, string in ipairs(self.projectsServerPaths) do
if not table.contains(self.layersDone, layer) then
if (i ~= choice) then
local oldPath = self.projectsServerPaths[i]
path = string.gsub(path, oldPath, newPath)
end
end
end
local newResourcesPath = self.ResourcesServerPaths[choice]
-- *** Resources
local newPath = newResourcesPath
for i, string in ipairs(self.ResourcesServerPaths) do
if (i ~= choice) then
local oldPath = self.ResourcesServerPaths[i]
path = string.gsub(path, oldPath, newPath)
end
end
return path
end
You'll need to edit this part:
Code: Select all
LK_ChangeServerPaths.projectsServerPaths = {
"A:/", -- * 1
"/Volumes/PROJECTS/", -- * 2
"D:/dropbox/animations/", -- * 3
"/Users/SomeGuy/Dropbox/Projects/", -- * 4
"D:/lalala/", -- * 5
}
LK_ChangeServerPaths.ResourcesServerPaths = {
"B:/", -- * 1
"/Volumes/RESOURCES/", -- * 2
"A:/Dropbox/Resources/", -- * 3
"/Users/SomeGuy/Dropbox/Resources/", -- * 4
"B:/a weird folder name/every pc is different/", -- * 5
}
LK_ChangeServerPaths.choices = {
"Studio (Windows)", -- * 1
"Studio (macOS)", -- * 2
"SomePersonWorkingAtHome (Dropbox)", -- * 3
"AnotherWorkingAtHome (Dropbox)", -- * 4
"YepWorkingAtHome (Dropbox)", -- * 5
}
What you see here is 5 options for 5 different setups. Make sure the order is consistent. We use 2 different servers, but you might only need to use the Projects paths. Just fill in some nonsense for the Resources paths. (Make sure you have the same amount of entries in each list though, and the order should match. So person 4 is using projectpath 4 and resourcepath 4.)
Make sure you always import images in a 1080p project. (You can always render in 4K or whatever, but import everything in the same dimension or you'll be sorry down the line).
Whenever opening an unlinked broken moho file. Tell it "No" when a file is missing, and check the "Don't ask again" box. Then run this script.
Also, NEVER save a file with a few unlinked images. It will mess up the dimensions and it's impossible to get them back.
When everything is working for you, disable this line in the Run function:
Code: Select all
self.choice = 0 -- DISABLE THIS LINE ONCE EVERYTHING IS WORKING CORRECTLY BY ADDING "--" IN FRONT OF IT
I hope at some point we'll get relative paths (either relative to a moho file's location, even if it means going 'up' a few folders before digging back into the folder structure, or relative to a customizable project(s) destination)
Use this script at your own risk and keep backups. It might resize images on frame 0 and all keys in all actions. We use it on a daily basis (in a mix of windows/mac machines that mount/sync from linux servers and it works flawlessly, but your setup and projects might be completely different.