
New to DaVinci Resolve, new to Lua scripting.
Asked ChatGPT to write a script to let me import Titles from a text file. (My goal is to create lyric videos for my original songs, and avoid copy/pasting one line of the song at a time into a 3-6-minute video timeline.) It created the script below. Running it from "Workspace | Scripts" doesn't appear to do anything. Running it in the console thusly
throws this error
Running v20 Build 49 on Mac Sequoia 15.5
The script:
Asked ChatGPT to write a script to let me import Titles from a text file. (My goal is to create lyric videos for my original songs, and avoid copy/pasting one line of the song at a time into a 3-6-minute video timeline.) It created the script below. Running it from "Workspace | Scripts" doesn't appear to do anything. Running it in the console thusly
- Code: Select all
Lua> lua TimelineTitlesFromCSV.lua
throws this error
- Code: Select all
[string "???"]:1: '=' expected near 'TimelineTitlesFromCSV'
Running v20 Build 49 on Mac Sequoia 15.5
The script:
- Code: Select all
-- DaVinci Resolve Script: Import Titles with Multiline, Justification, Font, and Font Size
resolve = Resolve()
pm = resolve:GetProjectManager()
proj = pm:GetCurrentProject()
tl = proj:GetCurrentTimeline()
if not tl then
print("No active timeline.")
return
end
-- === CONFIGURATION ===
io.write("Enter the name of the CSV file (e.g., titles.csv): ")
local userInput = io.read()
local csvPath = "/Users/joel/Documents/Blackmagic Design/DaVinci Resolve/Import/" .. userInput
local defaultFont = "Open Sans"
local defaultFontSize = 0.08
local color = {1, 1, 1, 1}
local position = {0.5, 0.85}
local durationFrames = 60
local fadeFrames = 12
-- Justification mapping
local justificationMap = {
["Left"] = "Left",
["Center"] = "Center",
["Right"] = "Right"
}
-- === Helpers ===
function decodeMultiline(str)
return str:gsub("\\n", "\n")
end
function trim(s)
return s and s:match("^%s*(.-)%s*$") or nil
end
-- === CSV PARSER ===
function parseCSV(file)
local titles = {}
for line in io.lines(file) do
-- Match 5 columns: timecode,"text",justification,font,fontSize
local timecode, text, justify, font, size = line:match('^([^,]+),"(.-)",?([^,]*),?([^,]*),?([^,]*)$')
if timecode and text then
table.insert(titles, {
timecode = trim(timecode),
text = decodeMultiline(trim(text)),
justify = justificationMap[trim(justify or "")] or "Center",
font = trim(font) ~= "" and trim(font) or defaultFont,
fontSize = tonumber(trim(size)) or defaultFontSize
})
end
end
return titles
end
-- === ADD TITLE CLIP ===
function addStyledTitle(timeline, item)
local fps = tonumber(timeline:GetSetting("timelineFrameRate"))
local startFrame = timeline:TimecodeToFrame(item.timecode)
local titleClip = timeline:AddFusionTitleClip("Text+", 1, startFrame, durationFrames)
if titleClip then
titleClip:SetProperty("StyledText", item.text)
titleClip:SetProperty("Font", item.font)
titleClip:SetProperty("FontSize", item.fontSize)
titleClip:SetProperty("ColorRed", color[1])
titleClip:SetProperty("ColorGreen", color[2])
titleClip:SetProperty("ColorBlue", color[3])
titleClip:SetProperty("ColorAlpha", color[4])
titleClip:SetProperty("PositionX", position[1])
titleClip:SetProperty("PositionY", position[2])
titleClip:SetProperty("HorizontalJustification", item.justify)
-- Fade animation
local fusionComp = titleClip:GetFusionCompByIndex(1)
if fusionComp then
local textNode = fusionComp:FindTool("Text1")
if textNode then
local opacity = textNode.StyledText:FindModifier("Opacity") or textNode:AddModifier("Opacity", "BezierSpline")
if opacity then
local fadeInStart = 0
local fadeInEnd = fadeFrames
local fadeOutStart = durationFrames - fadeFrames
local fadeOutEnd = durationFrames
opacity[fadeInStart] = 0
opacity[fadeInEnd] = 1
opacity[fadeOutStart] = 1
opacity[fadeOutEnd] = 0
end
end
end
print(string.format("Added: \"%s\" at %s | %s | %s @ %.2f",
item.text:gsub("\n", " / "),
item.timecode,
item.justify,
item.font,
item.fontSize))
else
print("Failed to add title at:", item.timecode)
end
end
-- === MAIN ===
local titles = parseCSV(csvPath)
for _, entry in ipairs(titles) do
addStyledTitle(tl, entry)
end