' MediaCore Digital Signage - BrightSign Autorun ' For BrightSignOS 8.x (XT/XD/HD Series) ' Server: https://mediacore.fixittech.us ' Generated: 2026-02-03T05:22:13.640Z Sub Main() print "============================================" print "MediaCore Digital Signage" print "BrightSign Native Player v1.0" print "============================================" g = GetGlobalAA() g.msgPort = CreateObject("roMessagePort") g.serverUrl = "https://mediacore.fixittech.us" di = CreateObject("roDeviceInfo") g.serialNumber = di.GetDeviceUniqueId() g.model = di.GetModel() g.firmware = di.GetVersion() g.family = di.GetFamily() print "Serial: "; g.serialNumber print "Model: "; g.model print "Firmware: "; g.firmware ' Log available audio outputs (safe, read-only) LogAudioOutputs() SetupVideoMode() SetupNetwork() CreateDirectory("content") EnableZoneSupport() InitializeVideoPlayer() InitializeHtmlWidget() InitializeUdpCommunication() MainEventLoop() End Sub Sub SetupVideoMode() print "[Video] Setting up video mode..." g = GetGlobalAA() vm = CreateObject("roVideoMode") g.screenWidth = vm.GetResX() g.screenHeight = vm.GetResY() if g.screenWidth >= 3840 then print "[Video] 4K mode active" g.is4K = true else print "[Video] HD mode active" g.is4K = false end if vm = invalid End Sub Sub SetupNetwork() print "[Network] Setting up network..." g = GetGlobalAA() g.ipAddress = "" gotIp = false nc = CreateObject("roNetworkConfiguration", 0) if nc <> invalid then currentConfig = nc.GetCurrentConfig() if currentConfig <> invalid and currentConfig.ip4_address <> invalid and currentConfig.ip4_address <> "" then g.ipAddress = currentConfig.ip4_address print "[Network] Wired IP: "; g.ipAddress gotIp = true end if end if if not gotIp then nc = CreateObject("roNetworkConfiguration", 1) if nc <> invalid then currentConfig = nc.GetCurrentConfig() if currentConfig <> invalid and currentConfig.ip4_address <> invalid and currentConfig.ip4_address <> "" then g.ipAddress = currentConfig.ip4_address print "[Network] Wireless IP: "; g.ipAddress gotIp = true end if end if end if if not gotIp then print "[Network] Waiting for network..." retries = 0 while g.ipAddress = "" and retries < 60 sleep(1000) retries = retries + 1 nc = CreateObject("roNetworkConfiguration", 0) if nc <> invalid then currentConfig = nc.GetCurrentConfig() if currentConfig <> invalid and currentConfig.ip4_address <> invalid and currentConfig.ip4_address <> "" then g.ipAddress = currentConfig.ip4_address print "[Network] Got IP: "; g.ipAddress end if end if end while end if End Sub Sub EnableZoneSupport() print "[Zones] Enabling zone support..." vm = CreateObject("roVideoMode") vm.SetGraphicsZOrder("front") vm = invalid End Sub Sub InitializeVideoPlayer() print "[Video] Initializing native video player..." g = GetGlobalAA() g.videoRect = CreateObject("roRectangle", 0, 0, g.screenWidth, g.screenHeight) g.videoPlayer = CreateObject("roVideoPlayer") if g.videoPlayer <> invalid then g.videoPlayer.SetRectangle(g.videoRect) g.videoPlayer.SetPort(g.msgPort) g.videoPlayer.SetLoopMode(0) g.videoPlayer.SetViewMode(0) g.videoPlayer.SetAudioOutput(0) g.videoPlayer.SetVolume(100) print "[Video] Native video player ready" end if g.imagePlayer = CreateObject("roImagePlayer") if g.imagePlayer <> invalid then g.imagePlayer.SetDefaultMode(1) g.imagePlayer.SetRectangle(g.videoRect) print "[Image] Native image player ready" end if End Sub Sub InitializeHtmlWidget() print "[HTML] Initializing HTML widget with Node.js..." g = GetGlobalAA() config = CreateObject("roAssociativeArray") config.nodejs_enabled = true config.brightsign_js_objects_enabled = true config.javascript_enabled = true config.mouse_enabled = false config.storage_path = "SD:/content" config.storage_quota = 10737418240 config.port = g.msgPort ' Load index.html from server for automatic updates across all devices ' Falls back to local file if server URL not configured config.url = g.serverUrl + "/brightsign/index.html" config.hwz_default = "on" security = CreateObject("roAssociativeArray") security.websecurity = false security.insecure_https_enabled = true config.security_params = security ' Make HTML widget full screen for branded waiting screen htmlRect = CreateObject("roRectangle", 0, 0, g.screenWidth, g.screenHeight) g.htmlWidget = CreateObject("roHtmlWidget", htmlRect, config) if g.htmlWidget <> invalid then print "[HTML] HTML widget with Node.js created" g.htmlWidget.Show() end if End Sub Sub InitializeUdpCommunication() print "[UDP] Setting up UDP communication..." g = GetGlobalAA() g.udpReceiver = CreateObject("roDatagramReceiver", 5000) if g.udpReceiver <> invalid then g.udpReceiver.SetPort(g.msgPort) print "[UDP] Listening on port 5000" end if g.udpSender = CreateObject("roDatagramSender") if g.udpSender <> invalid then g.udpSender.SetDestination("127.0.0.1", 5001) print "[UDP] Sender configured for port 5001" end if g.currentPlaylist = CreateObject("roArray", 0, true) g.currentIndex = 0 g.isPlaying = false g.layoutMode = false g.zonePlayers = invalid ' IPTV state g.iptvMode = false g.currentIptvChannel = invalid End Sub Sub MainEventLoop() print "[Main] Starting event loop..." g = GetGlobalAA() ' HTML widget shows branded waiting screen, no need for text widget initially SendToNodeJs("ready", g.serialNumber) g.contentTimer = CreateObject("roTimer") g.contentTimer.SetPort(g.msgPort) contentTimerId = g.contentTimer.GetIdentity() while true msg = wait(0, g.msgPort) msgType = type(msg) if msgType = "roVideoEvent" then ' Check if we're in layout mode if g.layoutMode = true then HandleZoneVideoEvent(msg) else HandleVideoEvent(msg) end if else if msgType = "roDatagramEvent" then HandleUdpCommand(msg) else if msgType = "roTimerEvent" then ' Check if this is a zone timer if g.layoutMode = true then HandleZoneTimerEvent(msg) else if msg.GetSourceIdentity() = contentTimerId then PlayNextContent() end if else if msgType = "roHtmlWidgetEvent" then HandleHtmlEvent(msg) end if end while End Sub Sub HandleVideoEvent(event As Object) g = GetGlobalAA() eventCode = event.GetInt() ' BrightSign roVideoEvent codes: ' 1 = MediaStarted (loading) ' 3 = MediaPlaying (SUCCESS - now playing) ' 8 = MediaEnded (finished) ' 4 = MediaError (actual error) ' Handle IPTV events separately if g.iptvMode then if eventCode = 3 then print "[IPTV] Stream now playing" channelStr = "" if g.currentIptvChannel <> invalid then channelStr = g.currentIptvChannel SendToNodeJs("iptv_playing", channelStr) else if eventCode = 4 then print "[IPTV] Stream error" SendToNodeJs("iptv_error", "Stream playback error") else if eventCode = 1 then print "[IPTV] Stream loading..." end if return end if ' Normal signage video events if eventCode = 8 then print "[Video] Playback ended" SendToNodeJs("playback_complete", Str(g.currentIndex)) PlayNextContent() else if eventCode = 3 then print "[Video] Now playing" g.isPlaying = true SendToNodeJs("playback_started", Str(g.currentIndex)) else if eventCode = 1 then print "[Video] Media started loading" else if eventCode = 4 then print "[Video] Playback error" SendToNodeJs("playback_error", Str(g.currentIndex)) PlayNextContent() end if End Sub Sub HandleUdpCommand(event As Object) g = GetGlobalAA() data = event.GetString() print "[UDP] Received: "; data json = ParseJson(data) if json <> invalid then command = "" if json.command <> invalid then command = json.command if command = "play_video" then if json.path <> invalid then PlayVideo(json.path) else if command = "play_image" then duration = 10 if json.duration <> invalid then duration = json.duration if json.path <> invalid then PlayImage(json.path, duration) else if command = "set_playlist" then if json.items <> invalid then StopLayoutPlayback() g.currentPlaylist = json.items g.currentIndex = 0 g.layoutMode = false print "[Playlist] Set "; g.currentPlaylist.Count(); " items" if g.currentPlaylist.Count() > 0 then PlayCurrentContent() end if else if command = "set_layout" then if json.layout <> invalid then SetupLayout(json.layout) end if else if command = "stop" then StopPlayback() else if command = "next" then PlayNextContent() else if command = "previous" then PlayPreviousContent() else if command = "status" then SendStatus() else if command = "reboot" then RebootSystem() else if command = "play_iptv" then if json.stream_url <> invalid then channelName = "" if json.channel_name <> invalid then channelName = json.channel_name PlayIptvStream(json.stream_url, channelName) end if else if command = "stop_iptv" then StopIptvPlayback() else if command = "set_mode" then if json.mode <> invalid then g.iptvMode = (json.mode = "iptv") if not g.iptvMode then StopIptvPlayback() end if end if end if end if End Sub Sub HandleHtmlEvent(event As Object) eventData = event.GetData() if type(eventData) = "roAssociativeArray" then if eventData.reason <> invalid then print "[HTML] Event: "; eventData.reason end if end if End Sub Sub PlayVideo(filePath As String) print "[Video] Playing: "; filePath g = GetGlobalAA() if g.videoPlayer <> invalid then g.videoPlayer.Stop() g.contentTimer.Stop() ' Hide HTML widget so video is visible if g.htmlWidget <> invalid then g.htmlWidget.Hide() aa = CreateObject("roAssociativeArray") aa.Filename = filePath ok = g.videoPlayer.PlayFile(aa) if ok then g.isPlaying = true print "[Video] Started: "; filePath else print "[Video] ERROR: Failed to play: "; filePath SendToNodeJs("playback_error", filePath) end if end if End Sub Sub PlayImage(filePath As String, duration As Integer) print "[Image] Displaying: "; filePath g = GetGlobalAA() if g.imagePlayer <> invalid then if g.videoPlayer <> invalid then g.videoPlayer.Stop() g.contentTimer.Stop() ' Hide HTML widget so image is visible if g.htmlWidget <> invalid then g.htmlWidget.Hide() ok = g.imagePlayer.DisplayFile(filePath) if ok then g.isPlaying = true g.imagePlayer.Show() if duration > 0 then g.contentTimer.SetElapsed(duration, 0) g.contentTimer.Start() end if SendToNodeJs("playback_started", filePath) else SendToNodeJs("playback_error", filePath) end if end if End Sub Sub PlayCurrentContent() g = GetGlobalAA() if g.currentPlaylist.Count() = 0 then ShowWaitingScreen() else if g.currentIndex >= g.currentPlaylist.Count() then g.currentIndex = 0 item = g.currentPlaylist[g.currentIndex] itemPath = "" itemType = "video" itemDuration = 10 if item.path <> invalid then itemPath = item.path if item.type <> invalid then itemType = item.type if item.duration <> invalid then itemDuration = item.duration print "[Playlist] Playing item "; Str(g.currentIndex + 1); "/"; Str(g.currentPlaylist.Count()) ' Notify Node.js of item change for real-time diagnostics SendItemChange(g.currentIndex) if itemType = "video" then PlayVideo(itemPath) else PlayImage(itemPath, itemDuration) end if end if End Sub Sub PlayNextContent() g = GetGlobalAA() g.currentIndex = g.currentIndex + 1 if g.currentIndex >= g.currentPlaylist.Count() then g.currentIndex = 0 PlayCurrentContent() End Sub Sub PlayPreviousContent() g = GetGlobalAA() g.currentIndex = g.currentIndex - 1 if g.currentIndex < 0 then g.currentIndex = g.currentPlaylist.Count() - 1 if g.currentIndex < 0 then g.currentIndex = 0 PlayCurrentContent() End Sub Sub StopPlayback() g = GetGlobalAA() StopLayoutPlayback() if g.videoPlayer <> invalid then g.videoPlayer.Stop() g.contentTimer.Stop() g.isPlaying = false g.layoutMode = false ' Show HTML widget for waiting screen if g.htmlWidget <> invalid then g.htmlWidget.Show() End Sub Sub StopLayoutPlayback() g = GetGlobalAA() ' Stop all zone players if g.zonePlayers <> invalid then for each zonePlayer in g.zonePlayers if zonePlayer.videoPlayer <> invalid then zonePlayer.videoPlayer.Stop() end if if zonePlayer.timer <> invalid then zonePlayer.timer.Stop() end if end for g.zonePlayers = invalid end if End Sub Sub SetupLayout(layout As Object) print "[Layout] Setting up layout: "; layout.name g = GetGlobalAA() ' Stop any existing playback StopPlayback() g.layoutMode = true g.isPlaying = true ' Hide HTML widget to show video zones if g.htmlWidget <> invalid then g.htmlWidget.Hide() ' Initialize zone players array g.zonePlayers = CreateObject("roArray", 0, true) ' Get screen dimensions screenWidth = g.screenWidth screenHeight = g.screenHeight ' Process each zone zones = layout.zones if zones <> invalid then for i = 0 to zones.Count() - 1 zone = zones[i] CreateZonePlayer(zone, screenWidth, screenHeight, i) end for end if print "[Layout] Setup complete with "; g.zonePlayers.Count(); " zones" SendToNodeJs("layout_started", layout.name) End Sub Sub CreateZonePlayer(zone As Object, screenWidth As Integer, screenHeight As Integer, index As Integer) g = GetGlobalAA() print "[Zone] Creating zone: "; zone.name; " type: "; zone.content_type ' Calculate pixel coordinates from percentages x = Int(zone.x * screenWidth / 100) y = Int(zone.y * screenHeight / 100) w = Int(zone.width * screenWidth / 100) h = Int(zone.height * screenHeight / 100) print "[Zone] Position: "; x; ","; y; " Size: "; w; "x"; h ' Create zone player object zonePlayer = CreateObject("roAssociativeArray") zonePlayer.zone = zone zonePlayer.index = index zonePlayer.currentIndex = 0 zonePlayer.items = zone.items zonePlayer.rect = CreateObject("roRectangle", x, y, w, h) zonePlayer.isPlaying = false ' Create player based on content type contentType = zone.content_type if contentType = "video" or contentType = "image" or contentType = "playlist" then if zone.items <> invalid and zone.items.Count() > 0 then zonePlayer.videoPlayer = CreateObject("roVideoPlayer") if zonePlayer.videoPlayer <> invalid then zonePlayer.videoPlayer.SetRectangle(zonePlayer.rect) zonePlayer.videoPlayer.SetPort(g.msgPort) zonePlayer.videoPlayer.SetLoopMode(0) zonePlayer.videoPlayer.SetViewMode(0) zonePlayer.videoPlayer.SetVolume(100) if zone.muted = true then zonePlayer.videoPlayer.SetVolume(0) ' Create timer for image durations zonePlayer.timer = CreateObject("roTimer") zonePlayer.timer.SetPort(g.msgPort) ' Store player identity for event matching zonePlayer.playerId = zonePlayer.videoPlayer.GetIdentity() zonePlayer.timerId = zonePlayer.timer.GetIdentity() end if ' Create image player for images in this zone zonePlayer.imagePlayer = CreateObject("roImagePlayer") if zonePlayer.imagePlayer <> invalid then zonePlayer.imagePlayer.SetDefaultMode(1) zonePlayer.imagePlayer.SetRectangle(zonePlayer.rect) end if end if else if contentType = "clock" then ' Create HTML widget for clock display clockHtml = "data:text/html," + CreateClockHtml() config = CreateObject("roAssociativeArray") config.nodejs_enabled = false config.javascript_enabled = true config.mouse_enabled = false config.url = clockHtml zonePlayer.htmlWidget = CreateObject("roHtmlWidget", zonePlayer.rect, config) if zonePlayer.htmlWidget <> invalid then zonePlayer.htmlWidget.Show() print "[Zone] Clock widget created" end if else if contentType = "text" then ' Create text widget for text/ticker display textContent = "MediaCore" if zone.config <> invalid and zone.config.text <> invalid then textContent = zone.config.text end if twParams = CreateObject("roAssociativeArray") twParams.LineCount = 1 twParams.TextMode = 2 twParams.Rotation = 0 twParams.Alignment = 1 zonePlayer.textWidget = CreateObject("roTextWidget", zonePlayer.rect, 1, 2, twParams) if zonePlayer.textWidget <> invalid then zonePlayer.textWidget.PushString(textContent) zonePlayer.textWidget.Show() print "[Zone] Text widget created: "; textContent end if else if contentType = "weather" then ' Create HTML widget for weather display location = "auto" if zone.config <> invalid and zone.config.location <> invalid then location = zone.config.location end if weatherHtml = "data:text/html," + CreateWeatherHtml(location) config = CreateObject("roAssociativeArray") config.nodejs_enabled = false config.javascript_enabled = true config.mouse_enabled = false config.url = weatherHtml zonePlayer.htmlWidget = CreateObject("roHtmlWidget", zonePlayer.rect, config) if zonePlayer.htmlWidget <> invalid then zonePlayer.htmlWidget.Show() print "[Zone] Weather widget created for: "; location end if end if g.zonePlayers.Push(zonePlayer) ' Start playing content in this zone if zonePlayer.items <> invalid and zonePlayer.items.Count() > 0 then PlayZoneContent(index) end if End Sub Function CreateClockHtml() As String html = "
" html = html + "" html = html + "" return html End Function Function CreateWeatherHtml(location As String) As String html = "" html = html + "