Skip to main content

Getting Started

Welcome to the official documentation for the TV Labs' TV Automation Language (TVAL). If you're venturing into the realm of automation or are a seasoned developer looking for an adept scripting tool, you've come to the right place.

Background

TVAL is built upon the strengths of the renowned Lua programming language. It merges Lua's inherent simplicity with specialized modules tailored for streaming service development and QA tasks such as video analysis, automation, device control, and spatial navigation. For those familiar with Lua, you'll find the transition seamless. For newcomers, here's a taste of its elegance:

Please note that this example is for explanation purposes only. There are easier and more effective/efficent macros for capturing app start up time. Please see the examples folder.

local time, textWasFound = Timer.record(function ()
device.launchApp("Netflix")

-- Exclude this region from the test
local ignoreRegion = region.absolute(10, 10, 10, 10):invert()

local textFound = wait.forText("Home", { mask=ignoreRegion })

return textFound
end)

if textWasFound then
metric.record("appStartUp", time)
end

Key Features

Vision First

Unlike other platforms, TVAL is built upon vision instead of DOM traversal. This means that you'll approach problems in a more natural way leveraging your eyes and ears.

describe("Starting an episode", function ()
beforeEach(function ()
navigateTo(Pages.Episode(ANY))
end)

it("should start playing content", function ()
highlight(Pages.Episode.Start)
remote.press(Key.OK)

status = wait.forContent(Content.Start)

assert(status)
end)

it("should start playing content within 5 seconds", function ()
highlight(Pages.Episode.Start)

wait(seconds(10))

assert(content.isPlaying())
end)
end)

Because TVAL truly test end-user experience, the platform/tv os is no longer relevant. A single TVAL can be used across every device/platform as long as the interfaces are similar. Additionally, vision tests don't require refactoring when you change the structure of your code!

However, should you require access to HTML, TVAL implements the standard appium drivers under the hood.

Module-based Architecture

Our language is segmented into intuitive namespaces like remote, screen, and wait, making functionalities easy to locate and implement. For example:

remote.press(Key.VolumeUp, Press.Long)

wait.forAudio(Volume.Increase)

local frame = screen.capture()

storage.put(frame, { name="Example Frame", key="example_frame_1" })

Abstracted Complexities

Through our vision interface we've abstracted away the majority of discrepencies between TV models. This allows you to write a script once and leverage it everywhere.

describe("Testing video progress bar ascross all tvs", function ()
setup(function ()
launchApp("Netflix")
end)

it("should show progress", function ()
app.playContent()

wait.forContent(Content.Playing)

progressBarRegion = region({ left=10, bottom=10, right=10, height=30 })

-- invert the region of the progress bar to mask everything else
mask = progressBarRegion:invert()

progressBarGrew = false

for currentFrame, lastFrame in motion({ mask=mask, duration=seconds(5) }) do
-- when it's the first frame there is no last frame
if not lastFrame then
return
end

-- Get the color from the masked region to see if the progress bar has grown
currentColorRegions = detect.color(App.Theme.PrimaryColor, currentFrame)
previousColorRegions = detect.color(App.Theme.PrimaryColor, lastFrame)

-- Check to see if the region has grown
if compare.isLarger(currentColorRegions, previousColorRegions) then
progressBarGrew = true

end()
end
end

assert(progressBarGrew)
end)
end)

Interact with Frames and Video

Screen Feedback

No more arbitrary delays! Introduce controlled pauses:

--- Instead of
remote.press(Key.OK)
wait(5000)

-- Do
remote.press(Key.OK)
wait.forContent(Content.Playing)

Remote Simulation

Simulate an array of remote control actions without physical interfaces:

remote.press(Key.OK)
remote.press(Key.OK, Press.Long)

remote.holdUntil(Key.OK, function (frame)
mask = region({ top=5, left=5, width=500, height=10 }):invert()

didFindText = detect.text("Home", frame, { mask: mask })

return didFindText
end)

remote.enterText("Hello World') -- automatically enter text into an onscreen keyboard

Please see the Remote API for full details

Community & Contributions

Echoing the spirit of open-source, we're open to contributions. Whether it's innovative feature suggestions, module expansions, or bug spotting, do refer to our contribution guidelines and get involved.

Conclusion

By harnessing the simplicity of Lua and enhancing it with our specialized modules, this scripting language stands as a robust tool for various applications. From intricate automation sequences to on-the-fly device management, the Custom Lua Scripting Language is geared to facilitate and elevate your projects.

Happy scripting, and we look forward to witnessing your innovations!