-- ************************************************** -- Provide Moho with the name of this script object -- ************************************************** ScriptName = "LK_Render" -- ************************************************** -- General information about this script -- ************************************************** LK_Render = {} function LK_Render:ColorizeIcon() return true end function LK_Render:Name() return "Render Current Shot" end function LK_Render:Version() return "0.3" end function LK_Render:Description() return "Render Current Shot" end function LK_Render:Creator() return "Lukas Krepel, Frame Order" end function LK_Render:UILabel() return "Render Current Shot" end function LK_Render:IsRelevant() if MohoMode ~= nil then return MohoMode.animation end return true end function LK_Render:IsEnabled() return true end LK_Render.machine = "locally" -- * "locally" or "gestion" LK_Render.shotName = "" LK_Render.start = 1 LK_Render.startTXT = "" LK_Render.stop = 1 LK_Render.stopTXT = "" LK_Render.range = 1 LK_Render.split = 0 LK_Render.output = "" LK_Render.format = "png" LK_Render.halfResolution = false LK_Render.singleThread = true LK_Render.hasComps = false LK_Render.comps = {} LK_Render.rendersDirectory = "" LK_Render.lookForDirectory = "Shots" LK_Render.createDirectory = "Renders" -- ************************************************** -- Render Options Dialog -- ************************************************** local LK_RenderOptionsDialog = {} LK_RenderOptionsDialog.UPDATE = MOHO.MSG_BASE LK_RenderOptionsDialog.LOCAL = MOHO.MSG_BASE + 1 LK_RenderOptionsDialog.GESTION = MOHO.MSG_BASE + 2 LK_RenderOptionsDialog.TOGGLE_HALF_RES = MOHO.MSG_BASE + 3 LK_RenderOptionsDialog.TOGGLE_SINGLETHREAD = MOHO.MSG_BASE + 4 LK_RenderOptionsDialog.GO_TO_DIRECTORY = MOHO.MSG_BASE + 5 function LK_RenderOptionsDialog:new(moho) local d = LM.GUI.SimpleDialog("Render", LK_RenderOptionsDialog) local l = d:GetLayout() d.moho = moho -- d.docPath = d.moho.document:Path() l:Indent() l:AddChild(LM.GUI.StaticText("Choose Renderer:"), LM.GUI.ALIGN_LEFT) d.gestion = LM.GUI.RadioButton("Add to Gestion queue", self.GESTION) -- * Gestion is Frame Order only: if LK_RenderStatus ~= nil then l:AddChild(d.gestion, LM.GUI.ALIGN_LEFT) else LK_Render.machine = "locally" end d.locally = LM.GUI.RadioButton("Local Moho", self.LOCAL) l:AddChild(d.locally, LM.GUI.ALIGN_LEFT) l:Unindent() l:Indent() l:AddChild(LM.GUI.StaticText("Options:"), LM.GUI.ALIGN_LEFT) d.halfRes = LM.GUI.CheckBox("Half resolution ("..(moho.document:Width()/2).." ✕ "..(moho.document:Height()/2)..") (faster)", self.TOGGLE_HALF_RES) l:AddChild(d.halfRes, LM.GUI.ALIGN_LEFT) d.singleThreadCheckbox = LM.GUI.CheckBox("Don't multithread (slower)", self.TOGGLE_SINGLETHREAD) l:AddChild(d.singleThreadCheckbox, LM.GUI.ALIGN_LEFT) l:Unindent() l:PushH(LM.GUI.ALIGN_CENTER, 0) d.destination = LM.GUI.DynamicText(LK_Render.msg1, 800) l:AddChild(d.destination, LM.GUI.ALIGN_LEFT) local buttonLabel = "Reveal in Finder" if FO_Utilities:getOS() == "win" then buttonLabel = "Open location in Explorer" end d.openDestinationDirectoryButton = LM.GUI.Button(buttonLabel, self.GO_TO_DIRECTORY) l:AddChild(d.openDestinationDirectoryButton) l:Pop() d.compWidgets = {} if LK_Render.hasComps then for i = 1, #LK_Render.compNames do local compName = LK_Render.compNames[i] local compDestination = "Layercomp: \'"..LK_Render.sequenceDirectory.."/"..compName.."/"..LK_Render.shotName.."-"..compName.."_"..string.format("%05d", LK_Render.start).."."..LK_Render.format.."\'" d.compDestination = LM.GUI.DynamicText(compDestination, 800) l:AddChild(d.compDestination, LM.GUI.ALIGN_LEFT) table.insert(d.compWidgets, d.compDestination) end end d.frames = LM.GUI.DynamicText(LK_Render.msg2, 800) l:AddChild(d.frames, LM.GUI.ALIGN_LEFT) d.locally:SetValue(LK_Render.machine == "locally") d.gestion:SetValue(LK_Render.machine == "gestion") if (LK_Render.machine == "gestion") then LK_Render.halfResolution = false end d.halfRes:SetValue(LK_Render.halfResolution) d.singleThreadCheckbox:SetValue(LK_Render.singleThread) d.halfRes:Enable(LK_Render.machine == "locally") d.singleThreadCheckbox:Enable(LK_Render.machine == "locally") return d end function LK_RenderOptionsDialog:HandleMessage(msg) if msg == self.GESTION then LK_Render.machine = "gestion" LK_Render.halfResolution = false LK_Render.singleThread = false elseif msg == self.LOCAL then LK_Render.machine = "locally" elseif msg == self.TOGGLE_HALF_RES then LK_Render.halfResolution = not LK_Render.halfResolution elseif msg == self.TOGGLE_SINGLETHREAD then LK_Render.singleThread = not LK_Render.singleThread elseif msg == self.GO_TO_DIRECTORY then FO_Utilities:RevealDirectory(LK_Render.revealDirectory) end -- * Update dialog widgets: self.locally:SetValue(LK_Render.machine == "locally") self.gestion:SetValue(LK_Render.machine == "gestion") self.halfRes:SetValue(LK_Render.halfResolution) self.singleThreadCheckbox:SetValue(LK_Render.singleThread) self.halfRes:Enable(LK_Render.machine == "locally") self.singleThreadCheckbox:Enable(LK_Render.machine == "locally") if LK_Render.machine == "locally" then LK_Render.sequenceDirectory = LK_Render:FixLocalPath(self.moho.document:Path(), LK_Render.sequenceDirectory) else LK_Render.sequenceDirectory = LK_Render:RevertToServerPath(moho, LK_Render.sequenceDirectory) end LK_Render.output = LK_Render.sequenceDirectory.."/"..LK_Render.shotName--LK_Render.sequenceDirectory.."/"..LK_Render.shotName.."/"..LK_Render.shotName local destinationMsg = "Destination: \'"..LK_Render.output.."_"..string.format("%05d", LK_Render.start).."."..LK_Render.format.."\'" if LK_Render.hasComps then for i = 1, #LK_Render.compNames do local compName = LK_Render.compNames[i] local compDestination = "Layercomp: \'"..LK_Render.sequenceDirectory.."/"..compName.."/"..LK_Render.shotName.."-"..compName.."_"..string.format("%05d", LK_Render.start).."."..LK_Render.format.."\'" self.compWidgets[i]:SetValue(compDestination) end end self.destination:SetValue(destinationMsg) end function LK_RenderOptionsDialog:OnOK() if (self.locally:Value()) then LK_Render.machine = "locally" end if (self.gestion:Value()) then LK_Render.machine = "gestion" end LK_Render.halfResolution = self.halfRes:Value() end -- ************************************************** -- The guts of this script -- ************************************************** function LK_Render:LoadPrefs(prefs) LK_Render.machine = prefs:GetString("LK_Render.machine", "locally") end function LK_Render:SavePrefs(prefs) prefs:SetString("LK_Render.machine", LK_Render.machine) end function LK_Render:Run(moho) local path = moho.document:Path() if not string.match(path, "_v%d%d%d_%u+.moho") then -- * (%d%d%d = 3 digits, %u+ unlimited amount of uppercase-letters) FO_Utilities:Alert( "Please save your file with correct formatting: *_v001_X.moho", "For example:", "", "Whatever_v001_L.moho", "EP01_001_Intro_v003_P.moho", "Crazy-Guy_v006_M.moho", "", "This makes it easy to keep track of versions and see who the last animator of a shot was.", "", "Everything before '_v001_X' will be considered the 'Shotname' of the file.", "This means rendering file Hello_v002_X.moho will always overwrite Hello_v001_X.moho", "", "A 'Renders' directory will be created in the same location as the highest 'Shots' directory in the file's path. If no 'Shots' directory is found, the 'Renders' directory is created in the same location as the moho file.", "", "Inside the 'Renders' directory another directory will be created with the 'Shotname'.", "", "If the file contains Layercomps, they will be rendered in subfolders of the sequence folder. The regular sequence will also still be rendered, but without the layers specified in the layercomps. This sequence could be considered the background in most cases." ) return end self.hasComps = moho.document:CountLayerComps() > 0 if self.hasComps then self.comps = FO_Utilities:AllComps(moho) self.compNames = {} for i = 1, #self.comps do table.insert(self.compNames, self.comps[i]:Name()) end end local lookFor = self.lookForDirectory local lastShotsPos = (string.lower(path):reverse()):find(string.lower(lookFor):reverse()) if lastShotsPos ~= nil then self.rendersDirectory = string.sub(path, 0, -lastShotsPos-string.len(lookFor)-1).."/"..self.createDirectory else self.rendersDirectory = FO_Utilities:FileDirectory(path).."/"..self.createDirectory end -- * Get shotname by stripping "_v000_X.moho" of filename: self.shotName = FO_Utilities:ShotName(moho) -- * Render location: self.sequenceDirectory = self.rendersDirectory.."/"..self.shotName -- * Reveal directory: self.revealDirectory = self.sequenceDirectory -- * if self.machine == "locally" then self.sequenceDirectory = self:FixLocalPath(moho.document:Path(), self.sequenceDirectory) -- * Check if renders location exists: FO_Utilities:CreateDirectory(moho, self.rendersDirectory) local directoryExists = FO_Utilities:FileExists(moho, self.rendersDirectory) if not directoryExists then local msg1 = "Render directory does not exist: \n\n\""..self.rendersDirectory.."\"" local msg2 = "Make sure it exists and try again." FO_Utilities:Alert(msg1, msg2) return end FO_Utilities:CreateDirectory(moho, self.sequenceDirectory) -- print ("sequenceDirectory = "..self.sequenceDirectory) else self.sequenceDirectory = LK_Render:RevertToServerPath(moho, self.sequenceDirectory) end -- * Get frame range: self.start = MOHO.MohoGlobals.PlayStart self.stop = MOHO.MohoGlobals.PlayEnd self.startTXT = "PlayStart" self.stopTXT = "PlayEnd" if self.start == -1 then self.start = moho.document:StartFrame() self.startTXT = "DocumentStart" end if self.stop == -1 then self.stop = moho.document:EndFrame() self.stopTXT = "DocumentEnd" end self.range = self.stop-self.start+1 -- * Set up messages: self.output = self.sequenceDirectory.."/"..self.shotName self.msg1 = "Destination: \'"..self.output.."_"..string.format("%05d", self.start).."."..self.format.."\'" self.msg2 = "Range: "..self.start.." - "..self.stop.." ("..self.range.." Frames)" -- *************** -- *** OPTIONS *** -- *************** local optionsDlog = LK_RenderOptionsDialog:new(moho) if (optionsDlog:DoModal() == LM.GUI.MSG_CANCEL) then return end -- *** DISABLED *** -- self:PrepForRendering(moho) -- * LOCAL: if LK_Render.machine == "locally" then LK_Render:Local(moho) elseif LK_Render.machine == "gestion" then -- * GESTION: LK_Render:Gestion(moho) end end -- ************************************************** -- Prepare file for rendering -- ************************************************** function LK_Render:PrepForRendering(moho) -- * Fix image quality: self:FixImageQuality(moho) LK_ToggleRefLayers:Run(moho) self:CleanLayerComps(moho) -- * Make sure we're not in design mode: if moho.frame == 0 then moho:SetCurFrame(1) end -- * Save file: moho:FileSave() end -- **************************************************************************** -- Removes layers from layercomp of which parents are not part of the layercomp -- **************************************************************************** function LK_Render:CleanLayerComps(moho) local comps = FO_Utilities:AllComps(moho) local layers = FO_Utilities:AllLayers(moho) for i = 1, #comps do local comp = comps[i] for i = 1, #layers do layer = layers[i] if comp:ContainsLayer(layer) then local parent = layer:Parent() while parent ~= nil do if not comp:ContainsLayer(parent) then comp:RemoveLayer(layer) end parent = parent:Parent() end end end end end -- ************************************************** -- Fix image quality -- ************************************************** function LK_Render:FixImageQuality(moho) local layers = FO_Utilities:AllLayers(moho) for i = 1, #layers do local layer = layers[i] if (layer:LayerType() == MOHO.LT_IMAGE) then self:SetHighImageQuality(moho, layer) end end end function LK_Render:SetHighImageQuality(moho, imageLayer) imageLayer = moho:LayerAsImage(imageLayer) imageLayer:SetQualityLevel(2) -- * Change image sampling mode: -- * 0 = SM_NEAREST (Nearest neighbor sampling) -- * 1 = SM_BILINEAR (Bilinear sampling) imageLayer:SetSamplingMode(0) end -- ************************************************** -- Render locally -- ************************************************** function LK_Render:Local(moho) -- * Command-line rendering: local mohopath = "" local render = moho.document:Path() -- * Create shot directory within renders-directory if it doesn't exist: -- print ("output = "..self.output) FO_Utilities:CreateDirectory(moho, self.output) -- * Add extension to output: self.output = self.output.."."..self.format if FO_Utilities:getOS(moho) == "win" then -- **************** -- *** Windows: *** -- **************** mohopath = "C:/Program Files/Moho/Moho.exe" mohopath = "\""..string.gsub(mohopath, "/", "\\").."\"" render = "\""..string.gsub(render, "/", "\\").."\"" self.output = "\""..string.gsub(self.output, "/", "\\").."\"" else -- ************** -- *** MacOS: *** -- ************** mohopath = "/Applications/Moho.app/Contents/MacOS/Moho" mohopath = string.gsub(mohopath, " ", "\\ ") render = string.gsub(render, " ", "\\ ") self.output = string.gsub(self.output, " ", "\\ ") end -- * Extra settings: local halfsize = "no" if LK_Render.halfResolution then halfsize = "yes" end local multiThread = "no" if LK_Render.singleThread then multiThread = "yes" end local command = mohopath.." -r "..render.." -o "..self.output.." -f "..self.format.." -start "..self.start.." -end "..self.stop.." -halfsize "..halfsize.." -multithread "..multiThread.." -extrasmooth yes" local command2 = command.." -layercomp AllComps -createfolderforlayercomp yes -addlayercompsuffix yes" if FO_Utilities:getOS() == "win" then command = ' "start "any title" '..command..' " ' command2 = ' "start "any title" '..command2..' " ' end -- *********************** -- *** EXECUTE COMMAND *** -- *********************** local startTime = os.time() local ask = false local feedback = false if self.hasComps then local layers = FO_Utilities:AllLayers(moho) for i = 1, #layers do layer = layers[i] layer:SetVisible(true) for j = 1, #self.comps do local comp = self.comps[j] if comp:ContainsLayer(layer) then layer:SetVisible(false) break end end end -- for i = 1, #layers do layer = layers[i] if layer:IsVisible() then self:SetParentVisible(layer) end end -- * Save file: moho:FileSave() end FO_Utilities:Execute(command, ask, feedback) if self.hasComps then FO_Utilities:Execute(command2, ask, feedback) end -- * Change reveal path to server: FO_Utilities:RevealDirectory(self.revealDirectory) -- * if self.hasComps then local layers = FO_Utilities:AllLayers(moho) for i = 1, #layers do layer = layers[i] layer:SetVisible(true) end LK_ToggleRefLayers:Run(moho) end end function LK_Render:SetParentVisible(layer) local parent = layer:Parent() if parent ~= nil then if not parent:IsVisible() then parent:SetVisible(true) else return self:SetParentVisible(parent) end else return false end end -- ************************************************** -- Gestion: Add to Render Queue -- ************************************************** function LK_Render:Gestion(moho) local python = FO_Utilities:Python(moho, "addtoqueue.py") -- * (Returns string "python addtoqueue.py" correctly for either Windows or macOS) -- * Build command: local currentFile = " --file ".."\""..moho.document:Path().."\"" local startFrame = " --start "..tostring(LK_Render.start) local endFrame = " --end "..tostring(LK_Render.stop) local split = " --split "..tostring(LK_Render.split) local project = " --project Baboo" -- * Full command: local command = python..currentFile..startFrame..endFrame..split..project -- * Execute: local ask = false local feedback = false if FO_Utilities:getOS() == "unix" then ask = true feedback = true end local output = FO_Utilities:Execute(command, ask, feedback) end --[[ **************************** *** COMMAND LINE OPTIONS *** **************************** ******************** *** MAIN OPTIONS *** ******************** -r <moho project file> or -render <moho project file> This is the only required option. It tells Moho to render the given project file and then quit. The Moho project file can be a .moho project or one of the legacy document formats (.anime, .anme, or .moho) back to version 4 of the format. -f <format> This tells Moho what format to render the output as. Valid formats are any of the presets specified in the Export Animation dialog. Here are the some examples that work on both Mac and Windows: • JPEG • TGA • BMP • PNG • PSD • QT • MP4 (H.264-AAC) • Animated GIF • SWF (Flash) The video, Animated GIF, and SWF formats generate a single output file, while the other formats create numbered sequences of still images. If you don’t specify a format on the command-line, the default format used will be “MP4 (H.264-AAC)”. -o <output> or -output <output> Specifies an output file or folder. The output file should include the file extension of the desired output format. If the output format is PNG the output should be named something like MyScene.png. If you skip this option, the output file will automatically have the same name as the input file, but with an extension matching the format you choose. For example, if you are rendering a file named MyScene.moho to a format of “MP4 (H.264-AAC)”, the output will be placed in the same folder as the document file with the name MyScene.mp4. If a folder is specified instead of a file name, the output will be placed within the folder with a name matching the document file and the appropriate output extension. -start <frame number> Specifies the starting frame to render. If omitted, Moho will start rendering at the document’s start frame (usually 1). -end <frame number> Specifies the last frame to render. If omitted, Moho will render up through the last frame of the document. -v or -verbose Runs the rendering job in “verbose” mode. In this mode, Moho will print out the render option values along with messages about its status. This includes an estimate of the time remaining in the rendering job. -q or -quiet Runs the renderer in “quiet” mode. “quiet” mode disables all command-line output, both information and errors. “quiet” mode overrides “verbose” mode. This option was introduced in Anime Studio Pro 9.5. -log <logfile> Specifies a log file for the render. Information and errors that are normally shown as command-line output are instead logged to the log file. This option was introduced in Anime Studio Pro 9.5. ********************** *** RENDER OPTIONS *** ********************** The following options control rendering options, just like you see in the Export Animation or Moho Exporter dialog in Moho Pro. Most of the options can be turned on or off with a value of yes or no. If an option is not specified, the render will perform the default. -multithread <yes|no> or -multithreaded <yes|no> Used to turn on or off multithreaded rendering. If multi-threaded rendering is on, the render will use up to 5 threads (4 image frame threads + 1 movie encoding thread) to render your output files. Set this option to no if you wish to increase the system’s performance while a render is taking place. The default is yes. -halfsize <yes|no> Render the output at half size. If the project dimensions of the document is set to 720p (1280x720), the output dimensions of the render would be 640x360 when using this option. This option is useful if you want to get a quick overview of your scene as it will dramatically reduce the time it takes to render. The default is no. -halffps <yes|no> Render at half frame rate. If the project frame rate is set to 30 FPS, the output format would be 15 FPS when using this option. The default is no. -shapefx <yes|no> Render shape effects. The default is yes. -layerfx <yes|no> Render layer effects. The default is yes. -fewparticles <yes|no> Use reduced particles. The default is no. -layercomp <comp name> Render a specific layer comp defined within the document. If AllComps or AllLayerComps is specified as the comp name, all layer comps will be exported during one run of the renderer. It is highly recommended that you use either -addlayercompsuffix OR -createfolderforlayercomp when specifying these comp names, otherwise multiple layer comp exports could overwrite each other. The recommended way to render all layer comps in Moho 13.5 is AllComps or AllLayerComps). This option was introduced in Anime Studio Pro 10.0. -aa <yes|no> Antialiased edges. The default is yes. -extrasmooth <yes|no> Extra-smooth images. The default is no. -premultiply <yes|no> Premultiply alpha. The default is yes. -ntscsafe -ntscsafe <yes|no> NTSC safe colors. The default is no. -variablewidths <yes|no> Variable line widths (only applies to SWF format). The default is no. ********************************* *** (INFO FROM MOHO HELP PDF) *** ********************************* --]] function LK_Render:FixLocalPath(docPath, path) if LK_ChangeServerPaths ~= nil then if LK_ChangeServerPaths.choice ~= 0 and LK_ChangeServerPaths.choice ~= 1 then path = LK_ChangeServerPaths:FixPath(path, nil, docPath) end end return path end function LK_Render:RevertToServerPath(moho, path) if LK_ChangeServerPaths ~= nil then path = LK_ChangeServerPaths:FixPath(path, LK_ChangeServerPaths.serverPaths[1]) -- * Revert to studio paths end return path end
Render
Listed
Author: Lukas
View Script
Script type: Button/Menu
Uploaded: Apr 19 2022, 07:12
Last modified: Jun 29 2022, 03:50
Render and overwrite .PNG sequences
Please save your file with correct formatting: *_v001_X.moho
For example:
Whatever_v001_L.moho
EP01_001_Intro_v003_P.moho
Crazy-Guy_v006_M.moho
This makes it easy to keep track of versions and see who the last animator of a shot was.
Everything before _v001_X will be considered the Shotname of the file.
This means rendering file Hello_v002_X.moho will always overwrite the render of Hello_v001_X.moho
A Renders directory will be created in the same location as the highest Shots directory in the file's path. If no Shots directory is found the Renders directory is created in the same location as the moho file.
Inside the Renders directory another directory will be created with the Shotname.
If the file contains Layercomps they will be rendered in subfolders of the sequence folder. The regular sequence will also still be rendered but without the layers specified in the layercomps. This sequence could be considered the background in most cases.
This script has some stuff in it that sends a render to our studio's render server, which is of course disabled, but could be modified to use your own system. That's why I left it in. Feel free to modify it to your specific needs.
The script will assume your Moho install is located at:
Windows: C:/Program Files/Moho/Moho.exe
macOS: /Applications/Moho.app/Contents/MacOS/Moho
This script, and all other scripts on this site are distributed as free software under the GNU General Public License 3.0 or later.
Downloads count: 395

Render
Listed
Author: Lukas
View Script
Script type: Button/Menu
Uploaded: Apr 19 2022, 07:12
Last modified: Jun 29 2022, 03:50
Render and overwrite .PNG sequences
Please save your file with correct formatting: *_v001_X.moho
For example:
Whatever_v001_L.moho
EP01_001_Intro_v003_P.moho
Crazy-Guy_v006_M.moho
This makes it easy to keep track of versions and see who the last animator of a shot was.
Everything before _v001_X will be considered the Shotname of the file.
This means rendering file Hello_v002_X.moho will always overwrite the render of Hello_v001_X.moho
A Renders directory will be created in the same location as the highest Shots directory in the file's path. If no Shots directory is found the Renders directory is created in the same location as the moho file.
Inside the Renders directory another directory will be created with the Shotname.
If the file contains Layercomps they will be rendered in subfolders of the sequence folder. The regular sequence will also still be rendered but without the layers specified in the layercomps. This sequence could be considered the background in most cases.
This script has some stuff in it that sends a render to our studio's render server, which is of course disabled, but could be modified to use your own system. That's why I left it in. Feel free to modify it to your specific needs.
The script will assume your Moho install is located at:
Windows: C:/Program Files/Moho/Moho.exe
macOS: /Applications/Moho.app/Contents/MacOS/Moho
For example:
Whatever_v001_L.moho
EP01_001_Intro_v003_P.moho
Crazy-Guy_v006_M.moho
This makes it easy to keep track of versions and see who the last animator of a shot was.
Everything before _v001_X will be considered the Shotname of the file.
This means rendering file Hello_v002_X.moho will always overwrite the render of Hello_v001_X.moho
A Renders directory will be created in the same location as the highest Shots directory in the file's path. If no Shots directory is found the Renders directory is created in the same location as the moho file.
Inside the Renders directory another directory will be created with the Shotname.
If the file contains Layercomps they will be rendered in subfolders of the sequence folder. The regular sequence will also still be rendered but without the layers specified in the layercomps. This sequence could be considered the background in most cases.
This script has some stuff in it that sends a render to our studio's render server, which is of course disabled, but could be modified to use your own system. That's why I left it in. Feel free to modify it to your specific needs.
The script will assume your Moho install is located at:
Windows: C:/Program Files/Moho/Moho.exe
macOS: /Applications/Moho.app/Contents/MacOS/Moho
This script, and all other scripts on this site are distributed as free software under the GNU General Public License 3.0 or later.
Downloads count: 395