Skip to main content
All tasks extend the SceneGraph Task node. They are created with CreateObject("roSGNode", "<TaskName>"), have their input fields set, and are started with task.control = "RUN". Completion is signaled by setting a done field or — for long-running tasks — by writing output fields that the caller observes.
File: components/tasks/AuthTask.*
Function: RunAuth

Purpose

Authenticates a username/password pair against the backend. Resolves the active server first (LAN probe → WAN fallback, up to SERVER_LAN_FORCE_RETRIES = 3 LAN attempts), then performs a GET to /auth/{user}/{pass} with TIMEOUT_AUTH = 15 000 ms.

XML interface

<component name="AuthTask" extends="Task">
  <interface>
    <!-- inputs -->
    <field id="username"      type="string"    value="" />
    <field id="password"      type="string"    value="" />
    <!-- outputs -->
    <field id="result"        type="assocarray" />
    <field id="done"          type="boolean"   value="false" />
    <field id="statusMessage" type="string"    value="" />
    <field id="statusTick"    type="integer"   value="0" />
  </interface>
</component>

Input fields

FieldTypeDescription
usernamestringPlain-text username.
passwordstringPlain-text password.

Output fields

FieldTypeDescription
resultassocarrayFull auth result (see structure below).
donebooleanSet to true when the task finishes (success or failure).
statusMessagestringHuman-readable progress text (e.g. “Conectando con servidor local…”).
statusTickintegerIncremented each time statusMessage changes; observe this to detect updates.

Result structure

result = {
    success                  : false,
    userId                   : "",
    streamUrl                : "",
    subscriberActive         : false,
    subscriberDisabledReason : "",
    errorCode                : -1,      ' AUTH_REASON_* constant
    authReason               : 0,
    errorMsg                 : "",
    rawBody                  : "",
    resolvedServer           : ""
}

Completion signal

Observe done. When done = true, read result. result.success = true means authentication passed; result.subscriberActive confirms the subscriber account is active.

Auth reason codes

ConstantValueMeaning
AUTH_REASON_NONE0No error.
AUTH_REASON_CREDENTIALS401Wrong username or password.
AUTH_REASON_INACTIVE470Account is inactive.
AUTH_REASON_PASSWORD_CHANGED471Password was changed; must re-login.
AUTH_REASON_NETWORK_DOWN460Network or server unreachable.
File: components/tasks/PlaylistTask.*
Function: RunPlaylist

Purpose

Downloads the authenticated M3U8 playlist from /auth/{user}/{pass}/playlist/m3u8/hls and parses it into channel and category arrays. Supports server failover: up to RETRY_MAX = 3 attempts across the server sequence.

XML interface

<component name="PlaylistTask" extends="Task">
  <interface>
    <!-- inputs -->
    <field id="username" type="string" value="" />
    <field id="password" type="string" value="" />
    <!-- outputs -->
    <field id="result"   type="assocarray" />
    <field id="done"     type="boolean"   value="false" />
  </interface>
</component>

Input fields

FieldTypeDescription
usernamestringCredential for the playlist URL.
passwordstringCredential for the playlist URL.

Output fields

FieldTypeDescription
resultassocarrayFull playlist result (see structure below).
donebooleanSet to true on completion.

Result structure

result = {
    success    : false,
    channels   : [],      ' array of channel objects
    categories : [],      ' array of category name strings
    errorMsg   : "",
    errorCode  : 0,       ' AUTH_REASON_* constant
    authReason : 0,
    rawBody    : "",
    httpCode   : 0
}
Each entry in result.channels is a channel object:
{
    id        : "",      ' tvg-id
    name      : "",      ' tvg-name (or from #EXTINF trailing label)
    logo      : "",      ' tvg-logo URL
    group     : "General",
    number    : -1,       ' channel-number attribute
    url       : "",       ' HLS stream URL
    streamId  : "",       ' extracted from URL path
    contentId : ""        ' streamId if found, else channel number string
}

Completion signal

Observe done. On success, result.channels and result.categories are populated and also written directly to m.global.channelList / m.global.categories.

Logging

The task logs extinf_sample lines (first 3 #EXTINF entries), a logo_summary, and up to 5 channel_sample lines at the GTV_Log level.
File: components/tasks/AdsPollingTask.*
Function: RunAdsPolling

Purpose

Long-running polling task. Performs the initial ads handshake (if ADS_HANDSHAKE_ENABLED = true), then polls the active snapshot endpoint every ADS_POLL_MS = 10 000 ms. Tracks impression versioning and signals session-level auth failures back to MainScene.

XML interface

<component name="AdsPollingTask" extends="Task">
  <interface>
    <!-- inputs -->
    <field id="streamId"            type="string"  value="" />
    <field id="streamPosition"      type="string"  value="" />
    <field id="resetChannel"        type="boolean" value="false" onChange="onResetChannel" />
    <!-- ad output -->
    <field id="adData"              type="assocarray" />
    <field id="adsSnapshot"         type="assocarray" />
    <!-- clear signal -->
    <field id="adsCleared"          type="boolean" value="false" />
    <field id="clearedStreamPosition" type="string" value="" />
    <field id="clearedStreamId"     type="string" value="" />
    <!-- session signals -->
    <field id="userInactive"        type="boolean" value="false" />
    <field id="userInactiveReason"  type="string"  value="" />
    <field id="sessionInvalid"      type="boolean" value="false" />
    <field id="sessionInvalidReason" type="string" value="" />
  </interface>
</component>

Input fields

FieldTypeDescription
streamIdstringCurrent stream identifier (from channel streamId).
streamPositionstringChannel number string; fallback stream identifier.
resetChannelbooleanSet to true when the channel changes; resets sinceVersion and triggers an immediate poll.

Output fields

FieldTypeDescription
adDataassocarrayNormalized first ad from the latest snapshot.
adsSnapshotassocarrayFull snapshot object (version, ads array, stream info).
adsClearedbooleanToggled false → true when the server signals no active ads.
clearedStreamPositionstringStream position from the clear event.
clearedStreamIdstringStream ID from the clear event.
userInactivebooleanToggled when the polling response indicates account inactivity.
userInactiveReasonstringLocalized reason string for the inactive state.
sessionInvalidbooleanToggled when the response signals credential/password invalidation.
sessionInvalidReasonstringLocalized reason string.

Completion signal

This is a long-running task; it does not use a done field. Stop it by setting control = "stop".

Poll endpoint

Requests are sent to ADS_API_BASE_URL + ADS_PATH_ACTIVE (default: https://ads.globaltv.lat/api/v1/app/ads/active) with query parameters:
?device_id=<id>&stream_id=<id>&since_version=<ver>
or, if stream_id is unavailable:
?device_id=<id>&stream_position=<number>&since_version=<ver>

Handshake

Before the first poll, TryAdsHandshake() POSTs to ADS_PATH_HANDSHAKE with device and subscriber info. Failures are logged but do not block polling.
File: components/tasks/ConnectivityTask.*
Function: RunConnectivityTask

Purpose

Periodic network health checker. Pings the active server’s health endpoint every 10 seconds and updates m.global.hasInternet / m.global.isOnline. Suppresses log spam by only logging on state transitions.

XML interface

<component name="ConnectivityTask" extends="Task">
  <interface>
    <!-- output -->
    <field id="hasInternet" type="boolean" value="true" />
    <!-- trigger -->
    <field id="checkNow"    type="boolean" value="false" />
  </interface>
</component>

Fields

FieldDirectionTypeDescription
hasInternetoutputbooleantrue if the last health ping succeeded. Also written to m.global.hasInternet.
checkNowinputbooleanSet to true to trigger an immediate check outside the 10-second cycle.

Completion signal

Long-running task. Stopped via control = "stop". Output is written continuously to hasInternet and m.global.

Check logic

sub DoCheck()
    server = GTV_ServerNormalizeBaseUrl(m.global.activeServer)
    if server = ""
        server = GTV_ServerPrimaryConnectivityUrl()
    end if
    result = GTV_PingServer(server)   ' GET to server + PATH_HEALTH, 2500ms timeout
    m.top.hasInternet    = result
    m.global.hasInternet = result
    m.global.isOnline    = GTV_IsOnline()
end sub
File: components/tasks/HandshakeTask.*
Function: RunHandshake

Purpose

Performs the initial device handshake with the backend. Probes the server list to find a reachable endpoint, then POSTs device information to PATH_HANDSHAKE = /api/v1/app/devices/handshake. Sets m.global.activeServer, m.global.deviceId, m.global.realtimeMode, and device metadata.

XML interface

<component name="HandshakeTask" extends="Task">
  <interface>
    <!-- output -->
    <field id="result"          type="assocarray" />
    <field id="done"            type="boolean"    value="false" />
    <!-- optional input -->
    <field id="forcedServerUrl" type="string"     value="" />
  </interface>
</component>

Input fields

FieldTypeDescription
forcedServerUrlstringIf set, bypasses auto-probe and connects only to this URL (used when the user manually selects a server in Settings).

Output fields

FieldTypeDescription
resultassocarrayHandshake result (see structure below).
donebooleanSet to true on completion.

Result structure

result = {
    success      : false,
    server       : "",         ' resolved server base URL
    realtimeMode : "polling",  ' from backend response
    errorCode    : -1,
    errorMsg     : ""
}

Completion signal

Observe done. result.success = true means the handshake succeeded. HTTP 401/403 responses set result.errorCode to that HTTP code but are treated as “auth required” (not a hard failure) by MainScene.

POST payload

payload = {
    platform     : "roku",
    device_id    : deviceId,
    device_model : GTV_GetBrandedDeviceModel(di),
    os_version   : osVersion,
    app_version  : GTV_GetAppVersion()   ' e.g. "1.0.7"
}
File: components/tasks/MetricsTask.*
Function: RunMetrics

Purpose

Long-running event sink. Waits for trackEvent field writes and POSTs each event to PATH_METRICS = /api/v1/app/metrics/track. Handles ad impression batch events separately via ADS_PATH_IMPRESSIONS.

XML interface

<component name="MetricsTask" extends="Task">
  <interface>
    <!-- input -->
    <field id="trackEvent" type="assocarray" />
    <!-- output -->
    <field id="lastResult" type="assocarray" />
  </interface>
</component>

Fields

FieldDirectionTypeDescription
trackEventinputassocarrayEvent object to post. Writing this field triggers PostEvent.
lastResultoutputassocarrayResult of the most recent post: {ok, code, server}.

Event object structure

event = {
    eventType  : "ad_shown",    ' or event_type
    adId       : "<id>",
    adFormat   : "A",
    extraData  : {}              ' optional extra key-value pairs
}
For impression batch events, use eventType = "ad_impression_closed" and add:
{
    eventType  : "ad_impression_closed",
    adId       : "<id>",
    stream_id  : "<id>",
    visible_ms : 4200,
    event_uuid : "<uuid>"
}
Impression events with visible_ms < 1000 are silently dropped. Duplicate event_uuid values within a session are deduplicated.

Completion signal

Long-running task. Stopped via control = "stop". Auth failures (HTTP 401/403) permanently disable metric posting for the remainder of the session.
File: components/tasks/ServerProbeTask.*
Function: RunServerProbe

Purpose

One-shot task that probes a single server URL by calling GTV_PingServer(). Used by SettingsScreen to test connectivity to a specific server profile before applying it.

XML interface

<component name="ServerProbeTask" extends="Task">
  <interface>
    <field id="baseUrl" type="string"    value="" />
    <field id="result"  type="assocarray" />
    <field id="done"    type="boolean"   value="false" />
  </interface>
</component>

Input fields

FieldTypeDescription
baseUrlstringServer base URL to probe (e.g. https://admin.globaltv.lat).

Output fields

FieldTypeDescription
resultassocarrayProbe result (see structure below).
donebooleanSet to true when the probe completes.

Result structure

result = {
    success : false,
    baseUrl : "<normalized url>",
    message : "Servidor no disponible"
}
success = true means GTV_PingServer() received an HTTP response in the range 200–499 within TIMEOUT_HEALTH = 2 500 ms.

Completion signal

Observe done. Check result.success for the probe outcome.