jf-roku/docs/api/quicksearch.html
2023-10-29 22:25:19 +00:00

32 lines
1.3 MiB
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<html>
<head>
</head>
<body style="background: transparent;">
<script src="scripts/docstrap.lib.js"></script>
<script src="scripts/lunr.min.js"></script>
<script src="scripts/fulltext-search.js"></script>
<script type="text/x-docstrap-searchdb">
{"components_data_AlbumData.brs.html":{"id":"components_data_AlbumData.brs.html","title":"Source: components/data/AlbumData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/AlbumData.brs sub setFields() datum = m.top.json m.top.id = datum.id m.top.title = datum.name end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_music_AlbumGrid.brs.html":{"id":"components_music_AlbumGrid.brs.html","title":"Source: components/music/AlbumGrid.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/music/AlbumGrid.brs import \"pkg:/source/utils/misc.brs\" sub init() getData() end sub function getData() ' If we have no album data, return a blank node if m.top.MusicArtistAlbumData = invalid data = CreateObject(\"roSGNode\", \"ContentNode\") return data end if albumData = m.top.MusicArtistAlbumData data = CreateObject(\"roSGNode\", \"ContentNode\") for each album in albumData.items gridAlbum = CreateObject(\"roSGNode\", \"ContentNode\") if not isValid(album.posterURL) or album.posterURL = \"\" album.posterURL = \"pkg:/images/icons/album.png\" end if gridAlbum.shortdescriptionline1 = album.title gridAlbum.HDGRIDPOSTERURL = album.posterURL gridAlbum.hdposterurl = album.posterURL gridAlbum.SDGRIDPOSTERURL = album.posterURL gridAlbum.sdposterurl = album.posterURL data.appendChild(gridAlbum) end for m.top.content = data return data end function function onKeyEvent(key as string, press as boolean) as boolean if not press then return false if key = \"up\" if m.top.itemFocused &lt;= 4 m.top.escape = key return true end if else if key = \"left\" if m.top.itemFocused mod 5 = 0 m.top.escape = key return true end if else if key = \"right\" if m.top.itemFocused + 1 mod 5 = 0 m.top.escape = key return true end if else if key = \"down\" totalCount = m.top.MusicArtistAlbumData.items.count() totalRows = div_ceiling(totalCount, 5) currentRow = div_ceiling(m.top.itemFocused + 1, 5) if currentRow = totalRows m.top.escape = key return true end if end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_music_AlbumTrackList.brs.html":{"id":"components_music_AlbumTrackList.brs.html","title":"Source: components/music/AlbumTrackList.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/music/AlbumTrackList.brs sub init() m.top.content = getData() m.top.setfocus(true) end sub function getData() if m.top.MusicArtistAlbumData = invalid data = CreateObject(\"roSGNode\", \"ContentNode\") return data end if albumData = m.top.MusicArtistAlbumData data = CreateObject(\"roSGNode\", \"ContentNode\") for each song in albumData.items songcontent = data.createChild(\"MusicSongData\") songcontent.json = song.json end for m.top.content = data m.top.doneLoading = true return data end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_music_AlbumView.brs.html":{"id":"components_music_AlbumView.brs.html","title":"Source: components/music/AlbumView.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/music/AlbumView.brs import \"pkg:/source/utils/misc.brs\" sub init() m.top.optionsAvailable = false setupMainNode() m.playAlbum = m.top.findNode(\"playAlbum\") m.instantMix = m.top.findNode(\"instantMix\") m.albumCover = m.top.findNode(\"albumCover\") m.songList = m.top.findNode(\"songList\") m.infoGroup = m.top.FindNode(\"infoGroup\") m.songListRect = m.top.FindNode(\"songListRect\") m.songList.observeField(\"doneLoading\", \"onDoneLoading\") m.spinner = m.top.findNode(\"spinner\") m.spinner.visible = true m.dscr = m.top.findNode(\"overview\") createDialogPallete() end sub sub setupMainNode() main = m.top.findNode(\"toplevel\") main.translation = [96, 175] end sub ' Set values for displayed values on screen sub pageContentChanged() item = m.top.pageContent setPosterImage(item.posterURL) setScreenTitle(item.json) setOnScreenTextValues(item.json) ' Only 1 song shown, so hide Play Album button if item.json.ChildCount = 1 m.playAlbum.visible = false end if end sub ' Set poster image on screen sub setPosterImage(posterURL) if isValid(posterURL) m.albumCover.uri = posterURL end if end sub ' Set screen's title text sub setScreenTitle(json) newTitle = \"\" if isValid(json) if isValid(json.AlbumArtist) newTitle = json.AlbumArtist end if if isValid(json.AlbumArtist) and isValid(json.name) newTitle = newTitle + \" / \" end if if isValid(json.name) newTitle = newTitle + json.name end if end if m.top.overhangTitle = newTitle end sub ' Adjust scene by removing overview node and showing more songs sub adjustScreenForNoOverview() m.infoGroup.removeChild(m.dscr) m.songListRect.height = 800 m.songList.numRows = 12 end sub ' Populate on screen text variables sub setOnScreenTextValues(json) if isValid(json) if isValid(json.overview) and json.overview &lt;&gt; \"\" ' We have overview text setFieldTextValue(\"overview\", json.overview) else ' We don't have overview text adjustScreenForNoOverview() end if setFieldTextValue(\"numberofsongs\", stri(json.ChildCount) + \" Tracks\") if type(json.ProductionYear) = \"roInt\" setFieldTextValue(\"released\", \"Released \" + stri(json.ProductionYear)) end if if json.genres.count() &gt; 0 setFieldTextValue(\"genres\", json.genres.join(\", \")) end if if type(json.RunTimeTicks) = \"LongInteger\" setFieldTextValue(\"runtime\", stri(getMinutes(json.RunTimeTicks)) + \" mins\") end if end if end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false if m.spinner.visible then return false if key = \"options\" if m.dscr.isTextEllipsized createFullDscrDlg() return true end if return false end if if key = \"right\" if m.playAlbum.hasFocus() or m.instantMix.hasFocus() m.songList.setFocus(true) return true end if else if key = \"left\" and m.songList.hasFocus() if m.playAlbum.visible m.playAlbum.setFocus(true) else if m.instantMix.visible m.instantMix.setFocus(true) else return false end if return true else if key = \"down\" and m.playAlbum.hasFocus() m.instantMix.setFocus(true) return true else if key = \"up\" and m.instantMix.hasFocus() m.playAlbum.setFocus(true) return true end if return false end function sub createFullDscrDlg() dlg = CreateObject(\"roSGNode\", \"OverviewDialog\") dlg.Title = tr(\"Press 'Back' to Close\") dlg.width = 1290 dlg.palette = m.dlgPalette dlg.overview = [m.dscr.text] m.fullDscrDlg = dlg m.top.getScene().dialog = dlg border = createObject(\"roSGNode\", \"Poster\") border.uri = \"pkg:/images/hd_focul_9.png\" border.blendColor = \"#c9c9c9ff\" border.width = dlg.width + 6 border.height = dlg.height + 6 border.translation = [dlg.translation[0] - 3, dlg.translation[1] - 3] border.visible = true end sub sub createDialogPallete() m.dlgPalette = createObject(\"roSGNode\", \"RSGPalette\") m.dlgPalette.colors = { DialogBackgroundColor: \"0x262828FF\", DialogItemColor: \"0x00EF00FF\", DialogTextColor: \"0xb0b0b0FF\", DialogFocusColor: \"0xcececeFF\", DialogFocusItemColor: \"0x202020FF\", DialogSecondaryTextColor: \"0xf8f8f8ff\", DialogSecondaryItemColor: \"0xcc7ecc4D\", DialogInputFieldColor: \"0x80FF8080\", DialogKeyboardColor: \"0x80FF804D\", DialogFootprintColor: \"0x80FF804D\" } end sub sub onDoneLoading() m.songList.unobservefield(\"doneLoading\") m.spinner.visible = false end sub sub OnScreenHidden() m.spinner.visible = false end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_ItemGrid_Alpha.brs.html":{"id":"components_ItemGrid_Alpha.brs.html","title":"Source: components/ItemGrid/Alpha.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/ItemGrid/Alpha.brs sub init() m.top.visible = true m.Alphamenu = m.top.findNode(\"Alphamenu\") m.Alphamenu.focusable = true m.Alphatext = m.top.findNode(\"alphatext\") m.focusedChild = m.top.findNode(\"focusedChild\") m.Alphamenu.focusedFont.size = 25 m.Alphamenu.font.size = 25 end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false if key = \"OK\" child = m.Alphatext.getChild(m.Alphamenu.itemFocused) if child.title = m.top.itemAlphaSelected m.top.itemAlphaSelected = \"\" m.Alphamenu.focusFootprintBitmapUri = \"\" else m.Alphamenu.focusFootprintBitmapUri = \"pkg:/images/white.png\" m.top.itemAlphaSelected = child.title end if return true end if if key = \"up\" if m.Alphamenu.itemFocused = 0 m.Alphamenu.jumpToItem = m.Alphamenu.numRows - 1 return true end if end if if key = \"down\" if m.Alphamenu.itemFocused = m.Alphamenu.numRows - 1 m.Alphamenu.jumpToItem = 0 return true end if end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_music_ArtistView.brs.html":{"id":"components_music_ArtistView.brs.html","title":"Source: components/music/ArtistView.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/music/ArtistView.brs import \"pkg:/source/utils/misc.brs\" sub init() m.top.optionsAvailable = false setupMainNode() setupButtons() m.remoteButtonsActive = true m.albumHeader = m.top.findNode(\"albumHeader\") m.albumHeader.text = tr(\"Albums\") m.appearsOnHeader = m.top.findNode(\"appearsOnHeader\") m.appearsOnHeader.text = tr(\"AppearsOn\") m.appearsOn = m.top.findNode(\"appearsOn\") m.appearsOn.observeField(\"escape\", \"onAppearsOnEscape\") m.appearsOn.observeField(\"MusicArtistAlbumData\", \"onAppearsOnData\") m.albums = m.top.findNode(\"albums\") m.albums.observeField(\"escape\", \"onAlbumsEscape\") m.albums.observeField(\"MusicArtistAlbumData\", \"onAlbumsData\") m.pageLoadAnimation = m.top.findNode(\"pageLoad\") m.pageLoadAnimation.control = \"start\" m.sectionNavigation = m.top.findNode(\"sectionNavigation\") m.sectionNavigation.observeField(\"escape\", \"onSectionNavigationEscape\") m.sectionNavigation.observeField(\"selected\", \"onSectionNavigationSelected\") m.sectionScroller = m.top.findNode(\"sectionScroller\") m.sectionScroller.observeField(\"displayedIndex\", \"onSectionScrollerChange\") m.overhang = m.top.getScene().findNode(\"overhang\") ' Load background image m.LoadBackdropImageTask = CreateObject(\"roSGNode\", \"LoadItemsTask\") m.LoadBackdropImageTask.itemsToLoad = \"backdropImage\" m.backDrop = m.top.findNode(\"backdrop\") m.artistImage = m.top.findNode(\"artistImage\") m.dscr = m.top.findNode(\"overview\") m.dscr.observeField(\"isTextEllipsized\", \"onEllipsisChanged\") createDialogPallete() end sub sub onAlbumsData() ' We have no album data if m.albums.MusicArtistAlbumData.TotalRecordCount = 0 m.sectionScroller.removeChild(m.top.findNode(\"albumsSlide\")) m.sectionNavigation.removeChild(m.top.findNode(\"albumsLink\")) m.top.findNode(\"appearsOnSlide\").callFunc(\"scrollUpToOnDeck\") end if end sub sub onAppearsOnData() ' We have no appears on data if m.appearsOn.MusicArtistAlbumData.TotalRecordCount = 0 m.sectionScroller.removeChild(m.top.findNode(\"appearsOnSlide\")) m.sectionNavigation.removeChild(m.top.findNode(\"appearsOnLink\")) end if end sub sub onSectionScrollerChange() m.overhang.isVisible = (m.sectionScroller.displayedIndex = 0) end sub sub OnScreenShown() m.sectionScroller.focus = true if m.sectionScroller.displayedIndex = 0 m.previouslySelectedButtonIndex = m.top.selectedButtonIndex m.top.selectedButtonIndex = 0 m.buttonGrp.setFocus(true) else m.overhang.opacity = \"0\" m.overhang.isVisible = false m.overhang.opacity = \"1\" end if end sub sub OnScreenHidden() if not m.overhang.isVisible m.overhang.disableMoveAnimation = true m.overhang.isVisible = true m.overhang.disableMoveAnimation = false m.overhang.opacity = \"1\" end if end sub sub onAlbumsEscape() if m.albums.escape = \"up\" m.sectionNavigation.selected = m.sectionScroller.displayedIndex - 1 else if m.albums.escape = \"left\" m.sectionNavigation.setFocus(true) else if m.albums.escape = \"down\" if m.sectionScroller.displayedIndex + 1 &lt; m.sectionNavigation.getChildCount() m.sectionNavigation.selected = m.sectionScroller.displayedIndex + 1 end if end if end sub sub onAppearsOnEscape() if m.appearsOn.escape = \"up\" m.sectionNavigation.selected = m.sectionScroller.displayedIndex - 1 else if m.appearsOn.escape = \"left\" m.sectionNavigation.setFocus(true) end if end sub ' Setup playback buttons, default to Play button selected sub setupButtons() m.buttonGrp = m.top.findNode(\"buttons\") m.buttonCount = m.buttonGrp.getChildCount() m.playButton = m.top.findNode(\"play\") m.previouslySelectedButtonIndex = -1 m.top.observeField(\"selectedButtonIndex\", \"onButtonSelectedChange\") m.top.selectedButtonIndex = 0 end sub ' Event handler when user selected a different playback button sub onButtonSelectedChange() ' Change previously selected button back to default image if m.previouslySelectedButtonIndex &gt; -1 previousSelectedButton = m.buttonGrp.getChild(m.previouslySelectedButtonIndex) previousSelectedButton.focus = false end if ' Change selected button image to selected image selectedButton = m.buttonGrp.getChild(m.top.selectedButtonIndex) selectedButton.focus = true end sub sub setupMainNode() m.main = m.top.findNode(\"toplevel\") m.main.translation = [120, 175] end sub ' Event fired when page data is loaded sub pageContentChanged() item = m.top.pageContent ' Use metadata to load backdrop image m.LoadBackdropImageTask.itemId = item.json.id m.LoadBackdropImageTask.observeField(\"content\", \"onBackdropImageLoaded\") m.LoadBackdropImageTask.control = \"RUN\" ' Populate scene data setScreenTitle(item.json) setPosterImage(item.posterURL) end sub sub setScreenTitle(json) if isValid(json) m.top.overhangTitle = json.name end if end sub sub setPosterImage(posterURL) if not isValid(posterURL) or posterURL = \"\" posterURL = \"pkg:/images/missingArtist.png\" end if m.artistImage.uri = posterURL end sub sub onBackdropImageLoaded() data = m.LoadBackdropImageTask.content[0] m.LoadBackdropImageTask.unobserveField(\"content\") if isValid(data) and data &lt;&gt; \"\" setBackdropImage(data) end if end sub ' Add backdrop image to screen sub setBackdropImage(data) if isValid(data) if m.backDrop.uri &lt;&gt; data m.backDrop.uri = data end if end if end sub ' Event fired when page data is loaded sub artistOverviewChanged() overviewContent = m.top.artistOverview if isValid(overviewContent) setFieldTextValue(\"overview\", overviewContent) end if end sub sub onEllipsisChanged() if m.dscr.isTextEllipsized dscrShowFocus() end if end sub sub onSectionNavigationEscape() if m.sectionNavigation.escape = \"right\" m.sectionNavigation.setFocus(false) m.remoteButtonsActive = false m.sectionScroller.focus = true end if end sub sub onSectionNavigationSelected() m.sectionScroller.displayedIndex = m.sectionNavigation.selected end sub sub dscrShowFocus() if m.dscr.isTextEllipsized m.dscr.setFocus(true) m.dscr.opacity = 1.0 end if end sub sub createFullDscrDlg() dlg = CreateObject(\"roSGNode\", \"OverviewDialog\") dlg.Title = tr(\"Press 'Back' to Close\") dlg.width = 1290 dlg.palette = m.dlgPalette dlg.overview = [m.dscr.text] m.fullDscrDlg = dlg m.top.getScene().dialog = dlg border = createObject(\"roSGNode\", \"Poster\") border.uri = \"pkg:/images/hd_focul_9.png\" border.blendColor = \"#c9c9c9ff\" border.width = dlg.width + 6 border.height = dlg.height + 6 border.translation = [dlg.translation[0] - 3, dlg.translation[1] - 3] border.visible = true end sub sub createDialogPallete() m.dlgPalette = createObject(\"roSGNode\", \"RSGPalette\") m.dlgPalette.colors = { DialogBackgroundColor: \"0x262828FF\", DialogItemColor: \"0x00EF00FF\", DialogTextColor: \"0xb0b0b0FF\", DialogFocusColor: \"0xcececeFF\", DialogFocusItemColor: \"0x202020FF\", DialogSecondaryTextColor: \"0xf8f8f8ff\", DialogSecondaryItemColor: \"0xcc7ecc4D\", DialogInputFieldColor: \"0x80FF8080\", DialogKeyboardColor: \"0x80FF804D\", DialogFootprintColor: \"0x80FF804D\" } end sub function onKeyEvent(key as string, press as boolean) as boolean if m.buttonGrp.isInFocusChain() if key = \"OK\" if press selectedButton = m.buttonGrp.getChild(m.top.selectedButtonIndex) selectedButton.selected = not selectedButton.selected return true end if end if if key = \"left\" if m.top.selectedButtonIndex &gt; 0 m.previouslySelectedButtonIndex = m.top.selectedButtonIndex m.top.selectedButtonIndex = m.top.selectedButtonIndex - 1 return true end if if press selectedButton = m.buttonGrp.getChild(m.top.selectedButtonIndex) selectedButton.focus = false m.sectionNavigation.setFocus(true) return true end if return false end if if key = \"right\" if m.top.pageContent.count() = 1 then return false if m.buttonGrp.getChild(m.top.selectedButtonIndex).escape = \"right\" m.buttonGrp.getChild(m.top.selectedButtonIndex).escape = \"\" m.previouslySelectedButtonIndex = m.top.selectedButtonIndex if m.top.selectedButtonIndex &lt; m.buttonCount - 1 m.top.selectedButtonIndex = m.top.selectedButtonIndex + 1 end if return true end if end if if key = \"down\" if m.sectionNavigation.getChildCount() &gt; 1 selectedButton = m.buttonGrp.getChild(m.top.selectedButtonIndex) selectedButton.focus = false m.top.selectedButtonIndex = 0 m.sectionNavigation.selected = m.sectionScroller.displayedIndex + 1 end if end if end if if not press then return false if key = \"options\" if m.dscr.isTextEllipsized createFullDscrDlg() return true end if end if if key = \"play\" print \"play button pressed from ArtistView\" itemToPlay = invalid if isValid(m.albums) and m.albums.isInFocusChain() itemToPlay = m.albums.MusicArtistAlbumData.items[m.albums.itemFocused] else if isValid(m.appearsOn) and m.appearsOn.isInFocusChain() itemToPlay = m.appearsOn.MusicArtistAlbumData.items[m.appearsOn.itemFocused] end if if isValid(itemToPlay) m.top.quickPlayNode = itemToPlay return true end if end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_mediaPlayers_AudioPlayer.brs.html":{"id":"components_mediaPlayers_AudioPlayer.brs.html","title":"Source: components/mediaPlayers/AudioPlayer.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/mediaPlayers/AudioPlayer.brs import \"pkg:/source/utils/misc.brs\" sub init() m.playReported = false m.top.observeField(\"state\", \"audioStateChanged\") end sub ' State Change Event Handler sub audioStateChanged() currentState = LCase(m.top.state) reportedPlaybackState = \"update\" m.top.disableScreenSaver = (currentState = \"playing\") if currentState = \"playing\" and not m.playReported reportedPlaybackState = \"start\" m.playReported = true else if currentState = \"stopped\" or currentState = \"finished\" reportedPlaybackState = \"stop\" m.playReported = false end if ReportPlayback(reportedPlaybackState) end sub ' Report playback to server sub ReportPlayback(state as string) if not isValid(m.top.position) then return params = { \"ItemId\": m.global.queueManager.callFunc(\"getCurrentItem\").id, \"PlaySessionId\": m.top.content.id, \"PositionTicks\": int(m.top.position) * 10000000&amp;, 'Ensure a LongInteger is used \"IsPaused\": (LCase(m.top.state) = \"paused\") } ' Report playstate via global task playstateTask = m.global.playstateTask playstateTask.setFields({ status: state, params: params }) playstateTask.control = \"RUN\" end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_music_AudioPlayerView.brs.html":{"id":"components_music_AudioPlayerView.brs.html","title":"Source: components/music/AudioPlayerView.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/music/AudioPlayerView.brs import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/api/Image.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" sub init() m.top.optionsAvailable = false setupAudioNode() setupAnimationTasks() setupButtons() setupInfoNodes() setupDataTasks() setupScreenSaver() m.playlistTypeCount = m.global.queueManager.callFunc(\"getQueueUniqueTypes\").count() m.buttonCount = m.buttons.getChildCount() m.screenSaverTimeout = 300 m.LoadScreenSaverTimeoutTask.observeField(\"content\", \"onScreensaverTimeoutLoaded\") m.LoadScreenSaverTimeoutTask.control = \"RUN\" m.di = CreateObject(\"roDeviceInfo\") ' Write screen tracker for screensaver WriteAsciiFile(\"tmp:/scene.temp\", \"nowplaying\") MoveFile(\"tmp:/scene.temp\", \"tmp:/scene\") loadButtons() pageContentChanged() setShuffleIconState() setLoopButtonImage() end sub sub onScreensaverTimeoutLoaded() data = m.LoadScreenSaverTimeoutTask.content m.LoadScreenSaverTimeoutTask.unobserveField(\"content\") if isValid(data) m.screenSaverTimeout = data end if end sub sub setupScreenSaver() m.screenSaverBackground = m.top.FindNode(\"screenSaverBackground\") ' Album Art Screensaver m.screenSaverAlbumCover = m.top.FindNode(\"screenSaverAlbumCover\") m.screenSaverAlbumAnimation = m.top.findNode(\"screenSaverAlbumAnimation\") m.screenSaverAlbumCoverFadeIn = m.top.findNode(\"screenSaverAlbumCoverFadeIn\") ' Jellyfin Screensaver m.PosterOne = m.top.findNode(\"PosterOne\") m.PosterOne.uri = \"pkg:/images/logo.png\" m.BounceAnimation = m.top.findNode(\"BounceAnimation\") m.PosterOneFadeIn = m.top.findNode(\"PosterOneFadeIn\") end sub sub setupAnimationTasks() m.displayButtonsAnimation = m.top.FindNode(\"displayButtonsAnimation\") m.playPositionAnimation = m.top.FindNode(\"playPositionAnimation\") m.playPositionAnimationWidth = m.top.FindNode(\"playPositionAnimationWidth\") m.bufferPositionAnimation = m.top.FindNode(\"bufferPositionAnimation\") m.bufferPositionAnimationWidth = m.top.FindNode(\"bufferPositionAnimationWidth\") m.screenSaverStartAnimation = m.top.FindNode(\"screenSaverStartAnimation\") end sub ' Creates tasks to gather data needed to render Scene and play song sub setupDataTasks() ' Load meta data m.LoadMetaDataTask = CreateObject(\"roSGNode\", \"LoadItemsTask\") m.LoadMetaDataTask.itemsToLoad = \"metaData\" ' Load background image m.LoadBackdropImageTask = CreateObject(\"roSGNode\", \"LoadItemsTask\") m.LoadBackdropImageTask.itemsToLoad = \"backdropImage\" ' Load audio stream m.LoadAudioStreamTask = CreateObject(\"roSGNode\", \"LoadItemsTask\") m.LoadAudioStreamTask.itemsToLoad = \"audioStream\" m.LoadScreenSaverTimeoutTask = CreateObject(\"roSGNode\", \"LoadScreenSaverTimeoutTask\") end sub ' Creates audio node used to play song(s) sub setupAudioNode() m.global.audioPlayer.observeField(\"state\", \"audioStateChanged\") m.global.audioPlayer.observeField(\"position\", \"audioPositionChanged\") m.global.audioPlayer.observeField(\"bufferingStatus\", \"bufferPositionChanged\") end sub ' Setup playback buttons, default to Play button selected sub setupButtons() m.buttons = m.top.findNode(\"buttons\") m.top.observeField(\"selectedButtonIndex\", \"onButtonSelectedChange\") m.previouslySelectedButtonIndex = 1 m.top.selectedButtonIndex = 2 end sub ' Event handler when user selected a different playback button sub onButtonSelectedChange() ' Change previously selected button back to default image selectedButton = m.buttons.getChild(m.previouslySelectedButtonIndex) selectedButton.uri = selectedButton.uri.Replace(\"-selected\", \"-default\") ' Change selected button image to selected image selectedButton = m.buttons.getChild(m.top.selectedButtonIndex) selectedButton.uri = selectedButton.uri.Replace(\"-default\", \"-selected\") end sub sub setupInfoNodes() m.albumCover = m.top.findNode(\"albumCover\") m.backDrop = m.top.findNode(\"backdrop\") m.playPosition = m.top.findNode(\"playPosition\") m.bufferPosition = m.top.findNode(\"bufferPosition\") m.seekBar = m.top.findNode(\"seekBar\") m.shuffleIndicator = m.top.findNode(\"shuffleIndicator\") m.loopIndicator = m.top.findNode(\"loopIndicator\") m.positionTimestamp = m.top.findNode(\"positionTimestamp\") m.totalLengthTimestamp = m.top.findNode(\"totalLengthTimestamp\") end sub sub bufferPositionChanged() if not isValid(m.global.audioPlayer.bufferingStatus) bufferPositionBarWidth = m.seekBar.width else bufferPositionBarWidth = m.seekBar.width * m.global.audioPlayer.bufferingStatus.percentage end if ' Ensure position bar is never wider than the seek bar if bufferPositionBarWidth &gt; m.seekBar.width bufferPositionBarWidth = m.seekBar.width end if ' Use animation to make the display smooth m.bufferPositionAnimationWidth.keyValue = [m.bufferPosition.width, bufferPositionBarWidth] m.bufferPositionAnimation.control = \"start\" end sub sub audioPositionChanged() if m.global.audioPlayer.position = 0 m.playPosition.width = 0 end if if not isValid(m.global.audioPlayer.position) playPositionBarWidth = 0 else if not isValid(m.songDuration) playPositionBarWidth = 0 else songPercentComplete = m.global.audioPlayer.position / m.songDuration playPositionBarWidth = m.seekBar.width * songPercentComplete end if ' Ensure position bar is never wider than the seek bar if playPositionBarWidth &gt; m.seekBar.width playPositionBarWidth = m.seekBar.width end if ' Use animation to make the display smooth m.playPositionAnimationWidth.keyValue = [m.playPosition.width, playPositionBarWidth] m.playPositionAnimation.control = \"start\" ' Update displayed position timestamp if isValid(m.global.audioPlayer.position) m.positionTimestamp.text = secondsToHuman(m.global.audioPlayer.position) else m.positionTimestamp.text = \"0:00\" end if ' Only fall into screensaver logic if the user has screensaver enabled in Roku settings if m.screenSaverTimeout &gt; 0 if m.di.TimeSinceLastKeypress() &gt;= m.screenSaverTimeout - 2 if not screenSaverActive() startScreenSaver() end if end if end if end sub function screenSaverActive() as boolean return m.screenSaverBackground.visible or m.screenSaverAlbumCover.opacity &gt; 0 or m.PosterOne.opacity &gt; 0 end function sub startScreenSaver() m.screenSaverBackground.visible = true m.top.overhangVisible = false if m.albumCover.uri = \"\" ' Jellyfin Logo Screensaver m.PosterOne.visible = true m.PosterOneFadeIn.control = \"start\" m.BounceAnimation.control = \"start\" else ' Album Art Screensaver m.screenSaverAlbumCoverFadeIn.control = \"start\" m.screenSaverAlbumAnimation.control = \"start\" end if end sub sub endScreenSaver() m.PosterOneFadeIn.control = \"pause\" m.screenSaverAlbumCoverFadeIn.control = \"pause\" m.screenSaverAlbumAnimation.control = \"pause\" m.BounceAnimation.control = \"pause\" m.screenSaverBackground.visible = false m.screenSaverAlbumCover.opacity = 0 m.PosterOne.opacity = 0 m.top.overhangVisible = true end sub sub audioStateChanged() ' Song Finished, attempt to move to next song if m.global.audioPlayer.state = \"finished\" ' User has enabled single song loop, play current song again if m.global.audioPlayer.loopMode = \"one\" playAction() return end if if m.global.queueManager.callFunc(\"getPosition\") &lt; m.global.queueManager.callFunc(\"getCount\") - 1 m.top.state = \"finished\" else ' We are at the end of the song queue ' User has enabled loop for entire song queue, move back to first song if m.global.audioPlayer.loopMode = \"all\" m.global.queueManager.callFunc(\"setPosition\", -1) LoadNextSong() return end if ' Return to previous screen m.top.state = \"finished\" end if end if end sub function playAction() as boolean if m.global.audioPlayer.state = \"playing\" m.global.audioPlayer.control = \"pause\" ' Allow screen to go to real screensaver WriteAsciiFile(\"tmp:/scene.temp\", \"nowplaying-paused\") MoveFile(\"tmp:/scene.temp\", \"tmp:/scene\") else if m.global.audioPlayer.state = \"paused\" m.global.audioPlayer.control = \"resume\" ' Write screen tracker for screensaver WriteAsciiFile(\"tmp:/scene.temp\", \"nowplaying\") MoveFile(\"tmp:/scene.temp\", \"tmp:/scene\") else if m.global.audioPlayer.state = \"finished\" m.global.audioPlayer.control = \"play\" ' Write screen tracker for screensaver WriteAsciiFile(\"tmp:/scene.temp\", \"nowplaying\") MoveFile(\"tmp:/scene.temp\", \"tmp:/scene\") end if return true end function function previousClicked() as boolean if m.playlistTypeCount &gt; 1 then return false if m.global.queueManager.callFunc(\"getPosition\") = 0 then return false if m.global.audioPlayer.state = \"playing\" m.global.audioPlayer.control = \"stop\" end if ' Reset loop mode due to manual user interaction if m.global.audioPlayer.loopMode = \"one\" resetLoopModeToDefault() end if m.global.queueManager.callFunc(\"moveBack\") pageContentChanged() return true end function sub resetLoopModeToDefault() m.global.audioPlayer.loopMode = \"\" setLoopButtonImage() end sub function loopClicked() as boolean if m.global.audioPlayer.loopMode = \"\" m.global.audioPlayer.loopMode = \"all\" else if m.global.audioPlayer.loopMode = \"all\" m.global.audioPlayer.loopMode = \"one\" else m.global.audioPlayer.loopMode = \"\" end if setLoopButtonImage() return true end function sub setLoopButtonImage() if m.global.audioPlayer.loopMode = \"all\" m.loopIndicator.opacity = \"1\" m.loopIndicator.uri = m.loopIndicator.uri.Replace(\"-off\", \"-on\") else if m.global.audioPlayer.loopMode = \"one\" m.loopIndicator.uri = m.loopIndicator.uri.Replace(\"-on\", \"1-on\") else m.loopIndicator.uri = m.loopIndicator.uri.Replace(\"1-on\", \"-off\") end if end sub function nextClicked() as boolean if m.playlistTypeCount &gt; 1 then return false ' Reset loop mode due to manual user interaction if m.global.audioPlayer.loopMode = \"one\" resetLoopModeToDefault() end if if m.global.queueManager.callFunc(\"getPosition\") &lt; m.global.queueManager.callFunc(\"getCount\") - 1 LoadNextSong() end if return true end function sub toggleShuffleEnabled() m.global.queueManager.callFunc(\"toggleShuffle\") end sub function findCurrentSongIndex(songList) as integer if not isValidAndNotEmpty(songList) then return 0 for i = 0 to songList.count() - 1 if songList[i].id = m.global.queueManager.callFunc(\"getCurrentItem\").id return i end if end for return 0 end function function shuffleClicked() as boolean currentSongIndex = findCurrentSongIndex(m.global.queueManager.callFunc(\"getUnshuffledQueue\")) toggleShuffleEnabled() if not m.global.queueManager.callFunc(\"getIsShuffled\") m.shuffleIndicator.opacity = \".4\" m.shuffleIndicator.uri = m.shuffleIndicator.uri.Replace(\"-on\", \"-off\") m.global.queueManager.callFunc(\"setPosition\", currentSongIndex) setTrackNumberDisplay() return true end if m.shuffleIndicator.opacity = \"1\" m.shuffleIndicator.uri = m.shuffleIndicator.uri.Replace(\"-off\", \"-on\") setTrackNumberDisplay() return true end function sub setShuffleIconState() if m.global.queueManager.callFunc(\"getIsShuffled\") m.shuffleIndicator.opacity = \"1\" m.shuffleIndicator.uri = m.shuffleIndicator.uri.Replace(\"-off\", \"-on\") end if end sub sub setTrackNumberDisplay() setFieldTextValue(\"numberofsongs\", \"Track \" + stri(m.global.queueManager.callFunc(\"getPosition\") + 1) + \"/\" + stri(m.global.queueManager.callFunc(\"getCount\"))) end sub sub LoadNextSong() if m.global.audioPlayer.state = \"playing\" m.global.audioPlayer.control = \"stop\" end if ' Reset playPosition bar without animation m.playPosition.width = 0 m.global.queueManager.callFunc(\"moveForward\") pageContentChanged() end sub ' Update values on screen when page content changes sub pageContentChanged() ' Reset buffer bar without animation m.bufferPosition.width = 0 useMetaTask = false currentItem = m.global.queueManager.callFunc(\"getCurrentItem\") if not isValid(currentItem.RunTimeTicks) useMetaTask = true end if if not isValid(currentItem.AlbumArtist) useMetaTask = true end if if not isValid(currentItem.name) useMetaTask = true end if if not isValid(currentItem.Artists) useMetaTask = true end if if useMetaTask m.LoadMetaDataTask.itemId = currentItem.id m.LoadMetaDataTask.observeField(\"content\", \"onMetaDataLoaded\") m.LoadMetaDataTask.control = \"RUN\" else if isValid(currentItem.ParentBackdropItemId) setBackdropImage(ImageURL(currentItem.ParentBackdropItemId, \"Backdrop\", { \"maxHeight\": \"720\", \"maxWidth\": \"1280\" })) end if setPosterImage(ImageURL(currentItem.id, \"Primary\", { \"maxHeight\": 500, \"maxWidth\": 500 })) setScreenTitle(currentItem) setOnScreenTextValues(currentItem) m.songDuration = currentItem.RunTimeTicks / 10000000.0 ' Update displayed total audio length m.totalLengthTimestamp.text = ticksToHuman(currentItem.RunTimeTicks) end if m.LoadAudioStreamTask.itemId = currentItem.id m.LoadAudioStreamTask.observeField(\"content\", \"onAudioStreamLoaded\") m.LoadAudioStreamTask.control = \"RUN\" end sub ' If we have more and 1 song to play, fade in the next and previous controls sub loadButtons() ' Don't show audio buttons if we have a mixed playlist if m.playlistTypeCount &gt; 1 then return if m.global.queueManager.callFunc(\"getCount\") &gt; 1 m.shuffleIndicator.opacity = \".4\" m.loopIndicator.opacity = \".4\" m.displayButtonsAnimation.control = \"start\" setLoopButtonImage() end if end sub sub onAudioStreamLoaded() data = m.LoadAudioStreamTask.content[0] m.LoadAudioStreamTask.unobserveField(\"content\") if data &lt;&gt; invalid and data.count() &gt; 0 m.global.audioPlayer.content = data m.global.audioPlayer.control = \"none\" m.global.audioPlayer.control = \"play\" end if end sub sub onBackdropImageLoaded() data = m.LoadBackdropImageTask.content[0] m.LoadBackdropImageTask.unobserveField(\"content\") if isValid(data) and data &lt;&gt; \"\" setBackdropImage(data) end if end sub sub onMetaDataLoaded() data = m.LoadMetaDataTask.content[0] m.LoadMetaDataTask.unobserveField(\"content\") if isValid(data) and data.count() &gt; 0 and isValid(data.json) ' Use metadata to load backdrop image if isValid(data.json.ArtistItems) and isValid(data.json.ArtistItems[0]) and isValid(data.json.ArtistItems[0].id) m.LoadBackdropImageTask.itemId = data.json.ArtistItems[0].id m.LoadBackdropImageTask.observeField(\"content\", \"onBackdropImageLoaded\") m.LoadBackdropImageTask.control = \"RUN\" end if setPosterImage(data.posterURL) setScreenTitle(data.json) setOnScreenTextValues(data.json) if isValid(data.json.RunTimeTicks) m.songDuration = data.json.RunTimeTicks / 10000000.0 ' Update displayed total audio length m.totalLengthTimestamp.text = ticksToHuman(data.json.RunTimeTicks) end if end if end sub ' Set poster image on screen sub setPosterImage(posterURL) if isValid(posterURL) if m.albumCover.uri &lt;&gt; posterURL m.albumCover.uri = posterURL m.screenSaverAlbumCover.uri = posterURL end if end if end sub ' Set screen's title text sub setScreenTitle(json) newTitle = \"\" if isValid(json) if isValid(json.AlbumArtist) newTitle = json.AlbumArtist end if if isValid(json.AlbumArtist) and isValid(json.name) newTitle = newTitle + \" / \" end if if isValid(json.name) newTitle = newTitle + json.name end if end if if m.top.overhangTitle &lt;&gt; newTitle m.top.overhangTitle = newTitle end if end sub ' Populate on screen text variables sub setOnScreenTextValues(json) if isValid(json) if m.playlistTypeCount = 1 setTrackNumberDisplay() end if setFieldTextValue(\"artist\", json.Artists[0]) setFieldTextValue(\"song\", json.name) end if end sub ' Add backdrop image to screen sub setBackdropImage(data) if isValid(data) if m.backDrop.uri &lt;&gt; data m.backDrop.uri = data end if end if end sub ' Process key press events function onKeyEvent(key as string, press as boolean) as boolean ' Key bindings for remote control buttons if press ' If user presses key to turn off screensaver, don't do anything else with it if screenSaverActive() endScreenSaver() return true end if if key = \"play\" return playAction() else if key = \"back\" m.global.audioPlayer.control = \"stop\" m.global.audioPlayer.loopMode = \"\" else if key = \"rewind\" return previousClicked() else if key = \"fastforward\" return nextClicked() else if key = \"left\" if m.global.queueManager.callFunc(\"getCount\") = 1 then return false if m.top.selectedButtonIndex &gt; 0 m.previouslySelectedButtonIndex = m.top.selectedButtonIndex m.top.selectedButtonIndex = m.top.selectedButtonIndex - 1 end if return true else if key = \"right\" if m.global.queueManager.callFunc(\"getCount\") = 1 then return false m.previouslySelectedButtonIndex = m.top.selectedButtonIndex if m.top.selectedButtonIndex &lt; m.buttonCount - 1 then m.top.selectedButtonIndex = m.top.selectedButtonIndex + 1 return true else if key = \"OK\" if m.buttons.getChild(m.top.selectedButtonIndex).id = \"play\" return playAction() else if m.buttons.getChild(m.top.selectedButtonIndex).id = \"previous\" return previousClicked() else if m.buttons.getChild(m.top.selectedButtonIndex).id = \"next\" return nextClicked() else if m.buttons.getChild(m.top.selectedButtonIndex).id = \"shuffle\" return shuffleClicked() else if m.buttons.getChild(m.top.selectedButtonIndex).id = \"loop\" return loopClicked() end if end if end if return false end function sub OnScreenHidden() ' Write screen tracker for screensaver WriteAsciiFile(\"tmp:/scene.temp\", \"\") MoveFile(\"tmp:/scene.temp\", \"tmp:/scene\") end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_movies_AudioTrackListItem.brs.html":{"id":"components_movies_AudioTrackListItem.brs.html","title":"Source: components/movies/AudioTrackListItem.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/movies/AudioTrackListItem.brs sub init() m.title = m.top.findNode(\"title\") m.description = m.top.findNode(\"description\") m.selectedIcon = m.top.findNode(\"selectedIcon\") end sub sub itemContentChanged() m.title.text = m.top.itemContent.title m.description.text = m.top.itemContent.description if m.top.itemContent.description = \"\" m.title.translation = [50, 20] end if if m.top.itemContent.selected m.selectedIcon.uri = m.global.constants.icons.check_white else m.selectedIcon.uri = \"\" end if end sub ' 'Scroll description if focused sub focusChanged() if m.top.itemHasFocus = true m.description.repeatCount = -1 else m.description.repeatCount = 0 end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_ButtonGroupHoriz.brs.html":{"id":"components_ButtonGroupHoriz.brs.html","title":"Source: components/ButtonGroupHoriz.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/ButtonGroupHoriz.brs sub init() m.top.layoutDirection = \"horiz\" end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false if key = \"right\" i = m.top.buttonFocused target = i + 1 if target &gt;= m.top.getChildCount() then return false m.top.focusButton = target return true else if key = \"left\" i = m.top.buttonFocused target = i - 1 if target &lt; 0 then return false m.top.focusButton = target return true else if key = \"up\" or key = \"down\" m.top.escape = key return true end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_ChannelData.brs.html":{"id":"components_data_ChannelData.brs.html","title":"Source: components/data/ChannelData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/ChannelData.brs import \"pkg:/source/api/Image.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" sub setFields() json = m.top.json m.top.id = json.id m.top.title = json.name m.top.live = true m.top.Type = \"TvChannel\" setPoster() end sub sub setPoster() if m.top.image &lt;&gt; invalid m.top.posterURL = m.top.image.url else if m.top.json.ImageTags &lt;&gt; invalid and m.top.json.ImageTags.Primary &lt;&gt; invalid imgParams = { \"maxHeight\": 60, \"Tag\": m.top.json.ImageTags.Primary } m.top.hdsmalliconurl = ImageURL(m.top.json.id, \"Primary\", imgParams) imgParams = { \"maxHeight\": 440, \"maxWidth\": 295, \"Tag\": m.top.json.ImageTags.Primary } m.top.posterURL = ImageURL(m.top.json.id, \"Primary\", imgParams) end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_CollectionData.brs.html":{"id":"components_data_CollectionData.brs.html","title":"Source: components/data/CollectionData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/CollectionData.brs import \"pkg:/source/api/Image.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" sub setFields() json = m.top.json m.top.id = json.id m.top.Title = json.name m.top.overview = json.overview m.top.Description = json.overview m.top.favorite = json.UserData.isFavorite m.top.watched = json.UserData.played m.top.Type = \"Boxset\" setPoster() end sub sub setPoster() if m.top.image &lt;&gt; invalid m.top.posterURL = m.top.image.url else if m.top.json.ImageTags.Primary &lt;&gt; invalid imgParams = { \"maxHeight\": 440, \"maxWidth\": 295, \"Tag\": m.top.json.ImageTags.Primary } m.top.posterURL = ImageURL(m.top.json.id, \"Primary\", imgParams) else if m.top.json.BackdropImageTags &lt;&gt; invalid imgParams = { \"maxHeight\": 440, \"Tag\": m.top.json.BackdropImageTags[0] } m.top.posterURL = ImageURL(m.top.json.id, \"Backdrop\", imgParams) end if ' Add Backdrop Image if m.top.json.BackdropImageTags &lt;&gt; invalid imgParams = { \"maxHeight\": 720, \"maxWidth\": 1280, \"Tag\": m.top.json.BackdropImageTags[0] } m.top.backdropURL = ImageURL(m.top.json.id, \"Backdrop\", imgParams) end if end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_config_ConfigData.brs.html":{"id":"components_config_ConfigData.brs.html","title":"Source: components/config/ConfigData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/config/ConfigData.brs sub init() end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_config_ConfigItem.brs.html":{"id":"components_config_ConfigItem.brs.html","title":"Source: components/config/ConfigItem.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/config/ConfigItem.brs sub init() m.name = m.top.findNode(\"label\") m.value = m.top.findNode(\"value\") m.name.width = 240 m.name.height = 75 m.name.vertAlign = \"center\" m.name.horizAlign = \"center\" m.value.hintText = tr(\"Enter a username\") m.value.maxTextLength = 120 end sub sub itemContentChanged() data = m.top.itemContent m.name.text = data.label if data.type = \"password\" m.value.hintText = tr(\"Enter a password\") m.value.secureMode = true end if m.value.text = data.value end sub sub setColors() if m.top.itemHasFocus color = \"#101010FF\" else color = \"#ffffffFF\" end if m.name.color = color m.value.textColor = color end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_config_ConfigList.brs.html":{"id":"components_config_ConfigList.brs.html","title":"Source: components/config/ConfigList.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/config/ConfigList.brs import \"pkg:/source/utils/config.brs\" sub init() m.top.itemComponentName = \"ConfigItem\" m.top.drawFocusFeedback = True m.top.vertFocusAnimationStyle = \"floatingFocus\" m.top.observeField(\"itemSelected\", \"onItemSelected\") m.top.itemSize = [750, 75] m.top.itemSpacing = [0, 25] m.top.setfocus(true) end sub sub setData() items = m.top.configItems data = CreateObject(\"roSGNode\", \"ContentNode\") data.appendChildren(items) m.top.content = data end sub sub onItemSelected() i = m.top.itemSelected itemField = m.top.content.getchild(i) configListShowDialog(itemField) end sub function onDialogButton() d = m.dialog button_text = d.buttons[d.buttonSelected] if button_text = tr(\"OK\") m.configField.value = d.text dismiss_dialog() return true else if button_text = tr(\"Cancel\") dismiss_dialog() return true end if return false end function sub configListShowDialog(configField) dialog = createObject(\"roSGNode\", \"StandardKeyboardDialog\") m.configField = configField dialog.title = configField.label dialog.buttons = [tr(\"OK\"), tr(\"Cancel\")] m.greenPalette = createObject(\"roSGNode\", \"RSGPalette\") m.greenPalette.colors = { DialogBackgroundColor: \"#2A2B2A\" } dialog.palette = m.greenPalette if configField.type = \"password\" dialog.textEditBox.secureMode = true end if if configField.value &lt;&gt; \"\" dialog.text = configField.value end if m.top.getscene().dialog = dialog m.dialog = dialog dialog.observeField(\"buttonSelected\", \"onDialogButton\") end sub sub dismiss_dialog() m.dialog.close = true end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_extras_ExtrasItem.brs.html":{"id":"components_extras_ExtrasItem.brs.html","title":"Source: components/extras/ExtrasItem.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/extras/ExtrasItem.brs sub init() m.posterImg = m.top.findNode(\"posterImg\") m.name = m.top.findNode(\"pLabel\") m.role = m.top.findNode(\"subTitle\") end sub sub showContent() if m.top.itemContent &lt;&gt; invalid cont = m.top.itemContent m.name.text = cont.labelText m.name.maxWidth = cont.imageWidth m.role.maxWidth = cont.imageWidth m.posterImg.uri = cont.posterUrl m.posterImg.width = cont.imageWidth m.role.Text = cont.subTitle else m.role.text = tr(\"Unknown\") m.posterImg.uri = \"pkg:/images/baseline_person_white_48dp.png\" end if end sub sub focusChanged() if m.top.itemHasFocus = true m.name.repeatCount = -1 m.role.repeatCount = -1 else m.name.repeatCount = 0 m.role.repeatCount = 0 end if if m.global.device.isAudioGuideEnabled = true txt2Speech = CreateObject(\"roTextToSpeech\") txt2Speech.Flush() txt2Speech.Say(m.name.text) txt2Speech.Say(m.role.text) end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_extras_ExtrasRowList.brs.html":{"id":"components_extras_ExtrasRowList.brs.html","title":"Source: components/extras/ExtrasRowList.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/extras/ExtrasRowList.brs sub init() m.top.visible = true updateSize() m.top.rowFocusAnimationStyle = \"fixedFocus\" m.top.observeField(\"rowItemSelected\", \"onRowItemSelected\") m.top.observeField(\"rowItemFocused\", \"onRowItemFocused\") ' Set up all Tasks m.LoadPeopleTask = CreateObject(\"roSGNode\", \"LoadItemsTask\") m.LoadPeopleTask.itemsToLoad = \"people\" m.LoadPeopleTask.observeField(\"content\", \"onPeopleLoaded\") m.LikeThisTask = CreateObject(\"roSGNode\", \"LoadItemsTask\") m.LikeThisTask.itemsToLoad = \"likethis\" m.LikeThisTask.observeField(\"content\", \"onLikeThisLoaded\") m.SpecialFeaturesTask = CreateObject(\"roSGNode\", \"LoadItemsTask\") m.SpecialFeaturesTask.itemsToLoad = \"specialfeatures\" m.SpecialFeaturesTask.observeField(\"content\", \"onSpecialFeaturesLoaded\") m.LoadAdditionalPartsTask = CreateObject(\"roSGNode\", \"LoadItemsTask\") m.LoadAdditionalPartsTask.itemsToLoad = \"additionalparts\" m.LoadAdditionalPartsTask.observeField(\"content\", \"onAdditionalPartsLoaded\") m.LoadMoviesTask = CreateObject(\"roSGNode\", \"LoadItemsTask\") m.LoadMoviesTask.itemsToLoad = \"personMovies\" m.LoadShowsTask = CreateObject(\"roSGNode\", \"LoadItemsTask\") m.LoadShowsTask.itemsToLoad = \"personTVShows\" m.LoadSeriesTask = CreateObject(\"roSGNode\", \"LoadItemsTask\") m.LoadSeriesTask.itemsToLoad = \"personSeries\" end sub sub updateSize() itemHeight = 396 m.top.itemSize = [1710, itemHeight] m.top.rowItemSpacing = [36, 36] end sub sub loadParts(data as object) m.top.parentId = data.id m.people = data.People m.LoadAdditionalPartsTask.itemId = m.top.parentId m.LoadAdditionalPartsTask.control = \"RUN\" end sub sub loadPersonVideos(personId) m.personId = personId m.LoadMoviesTask.itemId = m.personId m.LoadMoviesTask.observeField(\"content\", \"onMoviesLoaded\") m.LoadMoviesTask.control = \"RUN\" end sub sub onAdditionalPartsLoaded() parts = m.LoadAdditionalPartsTask.content m.LoadAdditionalPartsTask.unobserveField(\"content\") data = CreateObject(\"roSGNode\", \"ContentNode\") ' The row Node m.top.content = data if parts &lt;&gt; invalid and parts.count() &gt; 0 row = buildRow(\"Additional Parts\", parts, 464) addRowSize([464, 291]) m.top.content.appendChild(row) m.top.rowItemSize = [[464, 291]] else m.top.rowItemSize = [[234, 396]] end if ' Load Cast and Crew and everything else... m.LoadPeopleTask.peopleList = m.people m.LoadPeopleTask.control = \"RUN\" end sub sub onPeopleLoaded() people = m.LoadPeopleTask.content m.loadPeopleTask.unobserveField(\"content\") if people &lt;&gt; invalid and people.count() &gt; 0 row = m.top.content.createChild(\"ContentNode\") row.Title = tr(\"Cast &amp; Crew\") for each person in people if person.json.type = \"Actor\" and person.json.Role &lt;&gt; invalid and person.json.Role.ToStr().Trim() &lt;&gt; \"\" person.subTitle = \"as \" + person.json.Role else person.subTitle = person.json.Type end if person.Type = \"Person\" row.appendChild(person) end for end if m.LikeThisTask.itemId = m.top.parentId m.LikeThisTask.control = \"RUN\" end sub sub onLikeThisLoaded() data = m.LikeThisTask.content m.LikeThisTask.unobserveField(\"content\") if data &lt;&gt; invalid and data.count() &gt; 0 row = m.top.content.createChild(\"ContentNode\") row.Title = tr(\"More Like This\") for each item in data item.Id = item.json.Id item.labelText = item.json.Name if item.json.ProductionYear &lt;&gt; invalid item.subTitle = stri(item.json.ProductionYear) else if item.json.PremiereDate &lt;&gt; invalid premierYear = CreateObject(\"roDateTime\") premierYear.FromISO8601String(item.json.PremiereDate) item.subTitle = stri(premierYear.GetYear()) end if item.Type = item.json.Type row.appendChild(item) end for addRowSize([234, 396]) end if ' Special Features next... m.SpecialFeaturesTask.itemId = m.top.parentId m.SpecialFeaturesTask.control = \"RUN\" end sub function onSpecialFeaturesLoaded() data = m.SpecialFeaturesTask.content m.SpecialFeaturesTask.unobserveField(\"content\") if data &lt;&gt; invalid and data.count() &gt; 0 row = m.top.content.createChild(\"ContentNode\") row.Title = tr(\"Special Features\") for each item in data m.top.visible = true item.Id = item.json.Id item.labelText = item.json.Name item.subTitle = \"\" item.Type = item.json.Type item.imageWidth = 450 row.appendChild(item) end for addRowSize([462, 372]) end if return m.top.content end function sub onMoviesLoaded() data = m.LoadMoviesTask.content m.LoadMoviesTask.unobserveField(\"content\") rlContent = CreateObject(\"roSGNode\", \"ContentNode\") if data &lt;&gt; invalid and data.count() &gt; 0 row = rlContent.createChild(\"ContentNode\") row.title = tr(\"Movies\") for each mov in data mov.Id = mov.json.Id mov.labelText = mov.json.Name mov.subTitle = mov.json.ProductionYear mov.Type = mov.json.Type row.appendChild(mov) end for m.top.rowItemSize = [[234, 396]] end if m.top.content = rlContent m.LoadShowsTask.itemId = m.personId m.LoadShowsTask.observeField(\"content\", \"onShowsLoaded\") m.LoadShowsTask.control = \"RUN\" end sub sub onShowsLoaded() data = m.LoadShowsTask.content m.LoadShowsTask.unobserveField(\"content\") if data &lt;&gt; invalid and data.count() &gt; 0 row = buildRow(\"TV Shows\", data, 502) addRowSize([502, 396]) m.top.content.appendChild(row) end if m.LoadSeriesTask.itemId = m.personId m.LoadSeriesTask.observeField(\"content\", \"onSeriesLoaded\") m.LoadSeriesTask.control = \"RUN\" end sub sub onSeriesLoaded() data = m.LoadSeriesTask.content m.LoadSeriesTask.unobserveField(\"content\") if data &lt;&gt; invalid and data.count() &gt; 0 row = buildRow(\"Series\", data) addRowSize([234, 396]) m.top.content.appendChild(row) end if m.top.visible = true end sub function buildRow(rowTitle as string, items, imgWdth = 0) row = CreateObject(\"roSGNode\", \"ContentNode\") row.Title = tr(rowTitle) for each mov in items mov.Id = mov.json.Id mov.labelText = mov.json.Name mov.subTitle = mov.json.ProductionYear mov.Type = mov.json.Type if imgWdth &gt; 0 mov.imageWidth = imgWdth end if row.appendChild(mov) end for return row end function sub addRowSize(newRow) sizeArray = m.top.rowItemSize newSizeArray = [] for each size in sizeArray newSizeArray.push(size) end for newSizeArray.push(newRow) m.top.rowItemSize = newSizeArray end sub sub onRowItemSelected() m.top.selectedItem = m.top.content.getChild(m.top.rowItemSelected[0]).getChild(m.top.rowItemSelected[1]) end sub sub onRowItemFocused() m.top.focusedItem = m.top.content.getChild(m.top.rowItemFocused[0]).getChild(m.top.rowItemFocused[1]) end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_ItemGrid_FavoriteItemsTask.brs.html":{"id":"components_ItemGrid_FavoriteItemsTask.brs.html","title":"Source: components/ItemGrid/FavoriteItemsTask.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/ItemGrid/FavoriteItemsTask.brs import \"pkg:/source/api/UserLibrary.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" sub init() m.top.functionName = \"setFavoriteStatus\" end sub sub setFavoriteStatus() task = m.top.favTask if task = \"Favorite\" MarkItemFavorite(m.top.itemId) else if task = \"Unfavorite\" UnmarkItemFavorite(m.top.itemId) end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_FolderData.brs.html":{"id":"components_data_FolderData.brs.html","title":"Source: components/data/FolderData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/FolderData.brs import \"pkg:/source/api/Image.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" sub setFields() json = m.top.json m.top.id = json.id m.top.Title = json.name m.top.Type = \"Folder\" m.top.iconUrl = \"pkg:/images/media_type_icons/folder_white.png\" ' This is a temporary measure to avoid displaying landscape photos ' in GridItem components that only support portrait. It will be fixed ' after the ItemGrid is reworked. if m.top.json.Type &lt;&gt; \"CollectionFolder\" setPoster() end if end sub sub setPoster() if m.top.image &lt;&gt; invalid m.top.posterURL = m.top.image.url else if m.top.json.Type = \"Studio\" imgParams = { \"maxHeight\": 440, \"maxWidth\": 295, \"Tag\": m.top.json.ParentThumbImageTag } m.top.posterURL = ImageURL(m.top.json.id, \"Thumb\", imgParams) else if m.top.json.ImageTags.Primary &lt;&gt; invalid imgParams = { \"maxHeight\": 440, \"maxWidth\": 295, \"Tag\": m.top.json.ImageTags.Primary } m.top.posterURL = ImageURL(m.top.json.id, \"Primary\", imgParams) end if end sub 'TODO Set network Poster image × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_GetFiltersTask.brs.html":{"id":"components_data_GetFiltersTask.brs.html","title":"Source: components/data/GetFiltersTask.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/GetFiltersTask.brs import \"pkg:/source/utils/config.brs\" import \"pkg:/source/api/sdk.bs\" sub init() m.top.functionName = \"getFiltersTask\" end sub sub getFiltersTask() m.filters = api.items.GetFilters(m.top.params) m.top.filters = m.filters end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_GetNextEpisodeTask.brs.html":{"id":"components_GetNextEpisodeTask.brs.html","title":"Source: components/GetNextEpisodeTask.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/GetNextEpisodeTask.brs import \"pkg:/source/utils/config.brs\" import \"pkg:/source/api/sdk.bs\" sub init() m.top.functionName = \"getNextEpisodeTask\" end sub sub getNextEpisodeTask() m.nextEpisodeData = api.shows.GetEpisodes(m.top.showID, { UserId: m.global.session.user.id, StartItemId: m.top.videoID, Limit: 2 }) m.top.nextEpisodeData = m.nextEpisodeData end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_GetPlaybackInfoTask.brs.html":{"id":"components_GetPlaybackInfoTask.brs.html","title":"Source: components/GetPlaybackInfoTask.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/GetPlaybackInfoTask.brs import \"pkg:/source/utils/config.brs\" import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/utils/deviceCapabilities.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/api/sdk.bs\" sub init() m.top.functionName = \"getPlaybackInfoTask\" end sub function ItemPostPlaybackInfo(id as string, mediaSourceId = \"\" as string, audioTrackIndex = -1 as integer, startTimeTicks = 0 as longinteger) currentView = m.global.sceneManager.callFunc(\"getActiveScene\") currentItem = m.global.queueManager.callFunc(\"getCurrentItem\") body = { \"DeviceProfile\": getDeviceProfile() } params = { \"UserId\": m.global.session.user.id, \"StartTimeTicks\": currentItem.startingPoint, \"IsPlayback\": true, \"AutoOpenLiveStream\": true, \"MaxStreamingBitrate\": \"140000000\", \"MaxStaticBitrate\": \"140000000\", \"SubtitleStreamIndex\": currentView.selectedSubtitle, \"MediaSourceId\": currentItem.id, \"AudioStreamIndex\": currentItem.selectedAudioStreamIndex } req = APIRequest(Substitute(\"Items/{0}/PlaybackInfo\", id), params) req.SetRequest(\"POST\") return postJson(req, FormatJson(body)) end function ' Returns an array of playback info to be displayed during playback. ' In the future, with a custom playback info view, we can return an associated array. sub getPlaybackInfoTask() sessions = api.sessions.Get({ \"deviceId\": m.global.device.serverDeviceName }) m.playbackInfo = ItemPostPlaybackInfo(m.top.videoID) if isValid(sessions) and sessions.Count() &gt; 0 m.top.data = { playbackInfo: GetTranscodingStats(sessions[0]) } else m.top.data = { playbackInfo: [tr(\"Unable to get playback information\")] } end if end sub function GetTranscodingStats(deviceSession) sessionStats = { data: [] } if isValid(deviceSession.TranscodingInfo) and deviceSession.TranscodingInfo.Count() &gt; 0 transcodingReasons = deviceSession.TranscodingInfo.TranscodeReasons videoCodec = deviceSession.TranscodingInfo.VideoCodec audioCodec = deviceSession.TranscodingInfo.AudioCodec totalBitrate = deviceSession.TranscodingInfo.Bitrate audioChannels = deviceSession.TranscodingInfo.AudioChannels if isValid(transcodingReasons) and transcodingReasons.Count() &gt; 0 sessionStats.data.push(\"&lt;header&gt;\" + tr(\"Transcoding Information\") + \"&lt;/header&gt;\") for each item in transcodingReasons sessionStats.data.push(\"&lt;b&gt;• \" + tr(\"Reason\") + \":&lt;/b&gt; \" + item) end for end if if isValid(videoCodec) data = \"&lt;b&gt;• \" + tr(\"Video Codec\") + \":&lt;/b&gt; \" + videoCodec if deviceSession.TranscodingInfo.IsVideoDirect data = data + \" (\" + tr(\"direct\") + \")\" end if sessionStats.data.push(data) end if if isValid(audioCodec) data = \"&lt;b&gt;• \" + tr(\"Audio Codec\") + \":&lt;/b&gt; \" + audioCodec if deviceSession.TranscodingInfo.IsAudioDirect data = data + \" (\" + tr(\"direct\") + \")\" end if sessionStats.data.push(data) end if if isValid(totalBitrate) data = \"&lt;b&gt;• \" + tr(\"Total Bitrate\") + \":&lt;/b&gt; \" + getDisplayBitrate(totalBitrate) sessionStats.data.push(data) end if if isValid(audioChannels) data = \"&lt;b&gt;• \" + tr(\"Audio Channels\") + \":&lt;/b&gt; \" + Str(audioChannels) sessionStats.data.push(data) end if else sessionStats.data.push(\"&lt;header&gt;\" + tr(\"Direct playing\") + \"&lt;/header&gt;\") sessionStats.data.push(\"&lt;b&gt;\" + tr(\"The source file is entirely compatible with this client and the session is receiving the file without modifications.\") + \"&lt;/b&gt;\") end if if havePlaybackInfo() stream = m.playbackInfo.mediaSources[0].MediaStreams[0] sessionStats.data.push(\"&lt;header&gt;\" + tr(\"Stream Information\") + \"&lt;/header&gt;\") if isValid(stream.Container) data = \"&lt;b&gt;• \" + tr(\"Container\") + \":&lt;/b&gt; \" + stream.Container sessionStats.data.push(data) end if if isValid(stream.Size) data = \"&lt;b&gt;• \" + tr(\"Size\") + \":&lt;/b&gt; \" + stream.Size sessionStats.data.push(data) end if if isValid(stream.BitRate) data = \"&lt;b&gt;• \" + tr(\"Bit Rate\") + \":&lt;/b&gt; \" + getDisplayBitrate(stream.BitRate) sessionStats.data.push(data) end if if isValid(stream.Codec) data = \"&lt;b&gt;• \" + tr(\"Codec\") + \":&lt;/b&gt; \" + stream.Codec sessionStats.data.push(data) end if if isValid(stream.CodecTag) data = \"&lt;b&gt;• \" + tr(\"Codec Tag\") + \":&lt;/b&gt; \" + stream.CodecTag sessionStats.data.push(data) end if if isValid(stream.VideoRangeType) data = \"&lt;b&gt;• \" + tr(\"Video range type\") + \":&lt;/b&gt; \" + stream.VideoRangeType sessionStats.data.push(data) end if if isValid(stream.PixelFormat) data = \"&lt;b&gt;• \" + tr(\"Pixel format\") + \":&lt;/b&gt; \" + stream.PixelFormat sessionStats.data.push(data) end if if isValid(stream.Width) and isValid(stream.Height) data = \"&lt;b&gt;• \" + tr(\"WxH\") + \":&lt;/b&gt; \" + Str(stream.Width) + \" x \" + Str(stream.Height) sessionStats.data.push(data) end if if isValid(stream.Level) data = \"&lt;b&gt;• \" + tr(\"Level\") + \":&lt;/b&gt; \" + Str(stream.Level) sessionStats.data.push(data) end if end if return sessionStats end function function havePlaybackInfo() if not isValid(m.playbackInfo) return false end if if not isValid(m.playbackInfo.mediaSources) return false end if if m.playbackInfo.mediaSources.Count() &lt;= 0 return false end if if not isValid(m.playbackInfo.mediaSources[0].MediaStreams) return false end if if m.playbackInfo.mediaSources[0].MediaStreams.Count() &lt;= 0 return false end if return true end function function getDisplayBitrate(bitrate) if bitrate &gt; 1000000 return Str(Fix(bitrate / 1000000)) + \" Mbps\" else return Str(Fix(bitrate / 1000)) + \" Kbps\" end if end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_GetShuffleEpisodesTask.brs.html":{"id":"components_GetShuffleEpisodesTask.brs.html","title":"Source: components/GetShuffleEpisodesTask.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/GetShuffleEpisodesTask.brs import \"pkg:/source/utils/config.brs\" import \"pkg:/source/api/sdk.bs\" sub init() m.top.functionName = \"getShuffleEpisodesTask\" end sub sub getShuffleEpisodesTask() data = api.shows.GetEpisodes(m.top.showID, { UserId: m.global.session.user.id, SortBy: \"Random\", Limit: 200 }) m.top.data = data end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_ItemGrid_GridItem.brs.html":{"id":"components_ItemGrid_GridItem.brs.html","title":"Source: components/ItemGrid/GridItem.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/ItemGrid/GridItem.brs import \"pkg:/source/utils/config.brs\" import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/roku_modules/log/LogMixin.brs\" sub init() m.log = log.Logger(\"GridItem\") m.posterMask = m.top.findNode(\"posterMask\") m.itemPoster = m.top.findNode(\"itemPoster\") m.itemIcon = m.top.findNode(\"itemIcon\") m.posterText = m.top.findNode(\"posterText\") m.itemText = m.top.findNode(\"itemText\") m.backdrop = m.top.findNode(\"backdrop\") m.itemPoster.observeField(\"loadStatus\", \"onPosterLoadStatusChanged\") m.unplayedCount = m.top.findNode(\"unplayedCount\") m.unplayedEpisodeCount = m.top.findNode(\"unplayedEpisodeCount\") m.itemText.translation = [0, m.itemPoster.height + 7] m.gridTitles = m.global.session.user.settings[\"itemgrid.gridTitles\"] m.itemText.visible = m.gridTitles = \"showalways\" ' Add some padding space when Item Titles are always showing if m.itemText.visible then m.itemText.maxWidth = 250 'Parent is MarkupGrid and it's parent is the ItemGrid m.topParent = m.top.GetParent().GetParent() 'Get the imageDisplayMode for these grid items if isValid(m.topParent.imageDisplayMode) m.itemPoster.loadDisplayMode = m.topParent.imageDisplayMode end if end sub sub itemContentChanged() ' Set Random background colors from pallet posterBackgrounds = m.global.constants.poster_bg_pallet m.backdrop.blendColor = posterBackgrounds[rnd(posterBackgrounds.count()) - 1] itemData = m.top.itemContent if itemData = invalid then return if itemData.type = \"Movie\" m.itemPoster.uri = itemData.PosterUrl m.itemIcon.uri = itemData.iconUrl m.itemText.text = itemData.Title else if itemData.type = \"Series\" if m.global.session.user.settings[\"ui.tvshows.disableUnwatchedEpisodeCount\"] = false if isValid(itemData.json) and isValid(itemData.json.UserData) and isValid(itemData.json.UserData.UnplayedItemCount) if itemData.json.UserData.UnplayedItemCount &gt; 0 m.unplayedCount.visible = true m.unplayedEpisodeCount.text = itemData.json.UserData.UnplayedItemCount else m.unplayedCount.visible = false m.unplayedEpisodeCount.text = \"\" end if end if end if m.itemPoster.uri = itemData.PosterUrl m.itemIcon.uri = itemData.iconUrl m.itemText.text = itemData.Title else if itemData.type = \"Boxset\" m.itemPoster.uri = itemData.PosterUrl m.itemIcon.uri = itemData.iconUrl m.itemText.text = itemData.Title else if itemData.type = \"TvChannel\" m.itemPoster.uri = itemData.PosterUrl m.itemIcon.uri = itemData.iconUrl m.itemText.text = itemData.Title else if itemData.type = \"Folder\" m.itemPoster.uri = itemData.PosterUrl 'm.itemIcon.uri = itemData.iconUrl m.itemText.text = itemData.Title m.itemPoster.loadDisplayMode = m.topParent.imageDisplayMode else if itemData.type = \"Video\" m.itemPoster.uri = itemData.PosterUrl m.itemIcon.uri = itemData.iconUrl m.itemText.text = itemData.Title else if itemData.type = \"Playlist\" m.itemPoster.uri = itemData.PosterUrl m.itemIcon.uri = itemData.iconUrl m.itemText.text = itemData.Title else if itemData.type = \"Photo\" m.itemPoster.uri = itemData.PosterUrl m.itemIcon.uri = itemData.iconUrl m.itemText.text = itemData.Title else if itemData.type = \"Episode\" m.itemPoster.uri = itemData.PosterUrl m.itemIcon.uri = itemData.iconUrl if isValid(itemData.json) and isValid(itemData.json.SeriesName) m.itemText.text = itemData.json.SeriesName + \" - \" + itemData.Title else m.itemText.text = itemData.Title end if else if itemData.type = \"MusicArtist\" m.itemPoster.uri = itemData.PosterUrl m.itemText.text = itemData.Title m.itemPoster.height = 290 m.itemPoster.width = 290 m.itemText.translation = [0, m.itemPoster.height + 7] m.backdrop.height = 290 m.backdrop.width = 290 m.posterText.height = 200 m.posterText.width = 280 else if isValid(itemData.json.type) and itemData.json.type = \"MusicAlbum\" m.itemPoster.uri = itemData.PosterUrl m.itemText.text = itemData.Title m.itemPoster.height = 290 m.itemPoster.width = 290 m.itemText.translation = [0, m.itemPoster.height + 7] m.backdrop.height = 290 m.backdrop.width = 290 m.posterText.height = 200 m.posterText.width = 280 else m.log.warn(\"Unhandled Grid Item Type\", itemData.type) end if 'If Poster not loaded, ensure \"blue box\" is shown until loaded if m.itemPoster.loadStatus &lt;&gt; \"ready\" m.backdrop.visible = true m.posterText.visible = true end if m.posterText.text = m.itemText.text end sub ' 'Use FocusPercent to animate scaling of Poser Image sub focusChanging() scaleFactor = 0.85 + (m.top.focusPercent * 0.15) m.posterMask.scale = [scaleFactor, scaleFactor] end sub ' 'Display or hide title Visibility on focus change sub focusChanged() if m.top.itemHasFocus = true m.itemText.repeatCount = -1 m.posterMask.scale = [1, 1] else m.itemText.repeatCount = 0 if m.topParent.alphaActive = true m.posterMask.scale = [0.85, 0.85] end if end if if m.gridTitles = \"showonhover\" m.itemText.visible = m.top.itemHasFocus end if end sub 'Hide backdrop and text when poster loaded sub onPosterLoadStatusChanged() if m.itemPoster.loadStatus = \"ready\" m.backdrop.visible = false m.posterText.visible = false end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_ItemGrid_GridItemSmall.brs.html":{"id":"components_ItemGrid_GridItemSmall.brs.html","title":"Source: components/ItemGrid/GridItemSmall.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/ItemGrid/GridItemSmall.brs import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/utils/config.brs\" sub init() m.itemPoster = m.top.findNode(\"itemPoster\") m.posterText = m.top.findNode(\"posterText\") m.title = m.top.findNode(\"title\") m.posterText.font.size = 30 m.title.font.size = 25 m.backdrop = m.top.findNode(\"backdrop\") m.itemPoster.observeField(\"loadStatus\", \"onPosterLoadStatusChanged\") 'Parent is MarkupGrid and it's parent is the ItemGrid m.topParent = m.top.GetParent().GetParent() m.title.visible = false 'Get the imageDisplayMode for these grid items if m.topParent.imageDisplayMode &lt;&gt; invalid m.itemPoster.loadDisplayMode = m.topParent.imageDisplayMode end if end sub sub itemContentChanged() m.backdrop.blendColor = \"#101010\" m.title.visible = false if isValid(m.topParent.showItemTitles) if LCase(m.topParent.showItemTitles) = \"showalways\" m.title.visible = true end if end if itemData = m.top.itemContent if not isValid(itemData) then return m.itemPoster.uri = itemData.PosterUrl m.posterText.text = itemData.title m.title.text = itemData.title 'If Poster not loaded, ensure \"blue box\" is shown until loaded if m.itemPoster.loadStatus &lt;&gt; \"ready\" m.backdrop.visible = true m.posterText.visible = true end if end sub sub focusChanged() if m.top.itemHasFocus = true m.title.repeatCount = -1 else m.title.repeatCount = 0 end if if isValid(m.topParent.showItemTitles) if LCase(m.topParent.showItemTitles) = \"showonhover\" m.title.visible = m.top.itemHasFocus end if end if end sub 'Hide backdrop and text when poster loaded sub onPosterLoadStatusChanged() if m.itemPoster.loadStatus = \"ready\" m.backdrop.visible = false m.posterText.visible = false end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_home_Home.brs.html":{"id":"components_home_Home.brs.html","title":"Source: components/home/Home.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/home/Home.brs import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" import \"pkg:/source/utils/misc.brs\" sub init() m.top.overhangTitle = \"Home\" m.top.optionsAvailable = true if m.global.session.user.settings[\"ui.home.splashBackground\"] = true m.backdrop = m.top.findNode(\"backdrop\") m.backdrop.uri = buildURL(\"/Branding/Splashscreen?format=jpg&amp;foregroundLayer=0.15&amp;fillWidth=1280&amp;width=1280&amp;fillHeight=720&amp;height=720&amp;tag=splash\") end if end sub sub refresh() m.top.findNode(\"homeRows\").callFunc(\"updateHomeRows\") end sub sub loadLibraries() m.top.findNode(\"homeRows\").callFunc(\"loadLibraries\") end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_HomeData.brs.html":{"id":"components_data_HomeData.brs.html","title":"Source: components/data/HomeData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/HomeData.brs import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" import \"pkg:/source/api/Image.brs\" sub setData() ' We keep json around just as a reference, ' but ideally everything should be going through one of the interfaces datum = m.top.json m.top.id = datum.id m.top.name = datum.name m.top.type = datum.type if datum.CollectionType = invalid m.top.CollectionType = datum.type else m.top.CollectionType = datum.CollectionType end if ' Set appropriate Images for Wide and Tall based on type if datum.type = \"CollectionFolder\" or datum.type = \"UserView\" params = { \"Tag\": datum.ImageTags.Primary, \"maxHeight\": 261, \"maxWidth\": 464 } m.top.thumbnailURL = ImageURL(datum.id, \"Primary\", params) m.top.widePosterUrl = m.top.thumbnailURL ' Add Icon URLs for display if there is no Poster if datum.CollectionType = \"livetv\" m.top.iconUrl = \"pkg:/images/media_type_icons/live_tv_white.png\" else if datum.CollectionType = \"folders\" m.top.iconUrl = \"pkg:/images/media_type_icons/folder_white.png\" end if else if datum.type = \"Episode\" or datum.type = \"MusicVideo\" m.top.isWatched = datum.UserData.Played imgParams = {} imgParams.Append({ \"maxHeight\": 261 }) imgParams.Append({ \"maxWidth\": 464 }) if datum.ImageTags.Primary &lt;&gt; invalid param = { \"Tag\": datum.ImageTags.Primary } imgParams.Append(param) end if m.top.thumbnailURL = ImageURL(datum.id, \"Primary\", imgParams) ' Add Wide Poster (Series Backdrop) if datum.ParentThumbImageTag &lt;&gt; invalid imgParams[\"Tag\"] = datum.ParentThumbImageTag m.top.widePosterUrl = ImageURL(datum.ParentThumbItemId, \"Thumb\", imgParams) else if datum.ParentBackdropImageTags &lt;&gt; invalid imgParams[\"Tag\"] = datum.ParentBackdropImageTags[0] m.top.widePosterUrl = ImageURL(datum.ParentBackdropItemId, \"Backdrop\", imgParams) else if datum.ImageTags.Primary &lt;&gt; invalid imgParams[\"Tag\"] = datum.SeriesPrimaryImageTag m.top.widePosterUrl = ImageURL(datum.id, \"Primary\", imgParams) end if else if datum.type = \"Series\" imgParams = { \"maxHeight\": 261 } imgParams.Append({ \"maxWidth\": 464 }) m.top.posterURL = ImageURL(datum.id, \"Primary\", imgParams) ' Add Wide Poster (Series Backdrop) if datum.ImageTags &lt;&gt; invalid and datum.imageTags.Thumb &lt;&gt; invalid imgParams[\"Tag\"] = datum.imageTags.Thumb m.top.widePosterUrl = ImageURL(datum.Id, \"Thumb\", imgParams) else if datum.BackdropImageTags &lt;&gt; invalid imgParams[\"Tag\"] = datum.BackdropImageTags[0] m.top.widePosterUrl = ImageURL(datum.Id, \"Backdrop\", imgParams) end if else if datum.type = \"Movie\" or datum.type = \"Video\" m.top.isWatched = datum.UserData.Played imgParams = {} imgParams.Append({ \"maxHeight\": 261 }) imgParams.Append({ \"maxWidth\": 175 }) if datum.ImageTags.Primary &lt;&gt; invalid param = { \"Tag\": datum.ImageTags.Primary } imgParams.Append(param) end if m.top.posterURL = ImageURL(datum.id, \"Primary\", imgParams) ' For wide image, use backdrop imgParams[\"maxWidth\"] = 464 if datum.ImageTags &lt;&gt; invalid and datum.imageTags.Thumb &lt;&gt; invalid imgParams[\"Tag\"] = datum.imageTags.Thumb m.top.thumbnailUrl = ImageURL(datum.Id, \"Thumb\", imgParams) else if datum.BackdropImageTags[0] &lt;&gt; invalid imgParams[\"Tag\"] = datum.BackdropImageTags[0] m.top.thumbnailUrl = ImageURL(datum.id, \"Backdrop\", imgParams) end if else if datum.type = \"MusicAlbum\" params = { \"Tag\": datum.ImageTags.Primary, \"maxHeight\": 261, \"maxWidth\": 261 } m.top.thumbnailURL = ImageURL(datum.id, \"Primary\", params) m.top.widePosterUrl = m.top.thumbnailURL m.top.posterUrl = m.top.thumbnailURL else if datum.type = \"TvChannel\" or datum.type = \"Channel\" params = { \"Tag\": datum.ImageTags.Primary, \"maxHeight\": 261, \"maxWidth\": 464 } m.top.thumbnailURL = ImageURL(datum.id, \"Primary\", params) m.top.widePosterUrl = m.top.thumbnailURL m.top.iconUrl = \"pkg:/images/media_type_icons/live_tv_white.png\" end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_home_HomeItem.brs.html":{"id":"components_home_HomeItem.brs.html","title":"Source: components/home/HomeItem.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/home/HomeItem.brs import \"pkg:/source/api/Image.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/roku_modules/log/LogMixin.brs\" sub init() m.log = log.Logger(\"HomeItem\") m.itemText = m.top.findNode(\"itemText\") m.itemPoster = m.top.findNode(\"itemPoster\") m.itemProgress = m.top.findNode(\"progress\") m.itemProgressBackground = m.top.findNode(\"progressBackground\") m.itemIcon = m.top.findNode(\"itemIcon\") m.itemTextExtra = m.top.findNode(\"itemTextExtra\") m.itemPoster.observeField(\"loadStatus\", \"onPosterLoadStatusChanged\") m.unplayedCount = m.top.findNode(\"unplayedCount\") m.unplayedEpisodeCount = m.top.findNode(\"unplayedEpisodeCount\") m.playedIndicator = m.top.findNode(\"playedIndicator\") m.showProgressBarAnimation = m.top.findNode(\"showProgressBar\") m.showProgressBarField = m.top.findNode(\"showProgressBarField\") ' Randomize the background colors m.backdrop = m.top.findNode(\"backdrop\") posterBackgrounds = m.global.constants.poster_bg_pallet m.backdrop.color = posterBackgrounds[rnd(posterBackgrounds.count()) - 1] end sub sub itemContentChanged() itemData = m.top.itemContent if itemData = invalid then return itemData.Title = itemData.name ' Temporarily required while we move from \"HomeItem\" to \"JFContentItem\" m.itemPoster.width = itemData.imageWidth m.itemText.maxWidth = itemData.imageWidth m.itemTextExtra.width = itemData.imageWidth m.itemTextExtra.visible = true m.backdrop.width = itemData.imageWidth if isValid(itemData.iconUrl) m.itemIcon.uri = itemData.iconUrl end if if itemData.isWatched m.playedIndicator.visible = true m.unplayedCount.visible = false else m.playedIndicator.visible = false if LCase(itemData.type) = \"series\" if m.global.session.user.settings[\"ui.tvshows.disableUnwatchedEpisodeCount\"] = false if isValid(itemData.json.UserData) and isValid(itemData.json.UserData.UnplayedItemCount) if itemData.json.UserData.UnplayedItemCount &gt; 0 m.unplayedCount.visible = true m.unplayedEpisodeCount.text = itemData.json.UserData.UnplayedItemCount end if end if end if end if end if ' Format the Data based on the type of Home Data if itemData.type = \"CollectionFolder\" or itemData.type = \"UserView\" or itemData.type = \"Channel\" m.itemText.text = itemData.name m.itemPoster.uri = itemData.widePosterURL return end if if itemData.type = \"UserView\" m.itemPoster.width = \"96\" m.itemPoster.height = \"96\" m.itemPoster.translation = \"[192, 88]\" m.itemText.text = itemData.name m.itemPoster.uri = itemData.widePosterURL return end if playedIndicatorLeftPosition = m.itemPoster.width - 60 m.playedIndicator.translation = [playedIndicatorLeftPosition, 0] m.itemText.height = 34 m.itemText.font.size = 25 m.itemText.horizAlign = \"left\" m.itemText.vertAlign = \"bottom\" m.itemTextExtra.visible = true m.itemTextExtra.font.size = 22 ' \"Program\" is from clicking on an \"On Now\" item on the Home Screen if itemData.type = \"Program\" m.itemText.Text = itemData.json.name m.itemTextExtra.Text = itemData.json.ChannelName if itemData.widePosterURL &lt;&gt; \"\" m.itemPoster.uri = ImageURL(itemData.widePosterURL) else m.itemPoster.uri = ImageURL(itemData.json.ChannelId) m.itemPoster.loadDisplayMode = \"scaleToFill\" end if ' Set Episode title if available if isValid(itemData.json.EpisodeTitle) m.itemTextExtra.text = itemData.json.EpisodeTitle end if return end if if itemData.type = \"Episode\" m.itemText.text = itemData.json.SeriesName if itemData.PlayedPercentage &gt; 0 drawProgressBar(itemData) end if if itemData.usePoster = true m.itemPoster.uri = itemData.widePosterURL else m.itemPoster.uri = itemData.thumbnailURL end if ' Set Series and Episode Number for Extra Text extraPrefix = \"\" if isValid(itemData.json.ParentIndexNumber) extraPrefix = \"S\" + StrI(itemData.json.ParentIndexNumber).trim() end if if isValid(itemData.json.IndexNumber) extraPrefix = extraPrefix + \"E\" + StrI(itemData.json.IndexNumber).trim() end if if extraPrefix.len() &gt; 0 extraPrefix = extraPrefix + \" - \" end if m.itemTextExtra.text = extraPrefix + itemData.name return end if if itemData.type = \"Movie\" or itemData.type = \"MusicVideo\" m.itemText.text = itemData.name if itemData.PlayedPercentage &gt; 0 drawProgressBar(itemData) end if ' Use best image, but fallback to secondary if it's empty if (itemData.imageWidth = 180 and itemData.posterURL &lt;&gt; \"\") or itemData.thumbnailURL = \"\" m.itemPoster.uri = itemData.posterURL else m.itemPoster.uri = itemData.thumbnailURL end if ' Set Release Year and Age Rating for Extra Text textExtra = \"\" if isValid(itemData.json.ProductionYear) textExtra = StrI(itemData.json.ProductionYear).trim() end if if isValid(itemData.json.OfficialRating) if textExtra &lt;&gt; \"\" textExtra = textExtra + \" - \" + itemData.json.OfficialRating else textExtra = itemData.json.OfficialRating end if end if m.itemTextExtra.text = textExtra return end if if itemData.type = \"Video\" m.itemText.text = itemData.name if itemData.PlayedPercentage &gt; 0 drawProgressBar(itemData) end if if itemData.imageWidth = 180 m.itemPoster.uri = itemData.posterURL else m.itemPoster.uri = itemData.thumbnailURL end if return end if if itemData.type = \"BoxSet\" m.itemText.text = itemData.name m.itemPoster.uri = itemData.posterURL ' Set small text to number of items in the collection if isValid(itemData.json) and isValid(itemData.json.ChildCount) m.itemTextExtra.text = StrI(itemData.json.ChildCount).trim() + \" item\" if itemData.json.ChildCount &gt; 1 m.itemTextExtra.text += \"s\" end if end if return end if if itemData.type = \"Series\" m.itemText.text = itemData.name if itemData.usePoster = true if itemData.imageWidth = 180 m.itemPoster.uri = itemData.posterURL else m.itemPoster.uri = itemData.widePosterURL end if else m.itemPoster.uri = itemData.thumbnailURL end if textExtra = \"\" if isValid(itemData.json.ProductionYear) textExtra = StrI(itemData.json.ProductionYear).trim() end if ' Set Years Run for Extra Text if itemData.json.Status = \"Continuing\" textExtra = textExtra + \" - Present\" else if itemData.json.Status = \"Ended\" and isValid(itemData.json.EndDate) textExtra = textExtra + \" - \" + LEFT(itemData.json.EndDate, 4) end if m.itemTextExtra.text = textExtra return end if if itemData.type = \"MusicAlbum\" m.itemText.text = itemData.name m.itemTextExtra.text = itemData.json.AlbumArtist m.itemPoster.uri = itemData.posterURL return end if if itemData.type = \"MusicArtist\" m.itemText.text = itemData.name m.itemTextExtra.text = itemData.json.AlbumArtist m.itemPoster.uri = ImageURL(itemData.id) return end if if itemData.type = \"Audio\" m.itemText.text = itemData.name m.itemTextExtra.text = itemData.json.AlbumArtist m.itemPoster.uri = ImageURL(itemData.id) return end if if itemData.type = \"TvChannel\" m.itemText.text = itemData.name m.itemTextExtra.text = itemData.json.AlbumArtist m.itemPoster.uri = ImageURL(itemData.id) return end if if itemData.type = \"Season\" m.itemText.text = itemData.json.SeriesName m.itemTextExtra.text = itemData.name m.itemPoster.uri = ImageURL(itemData.id) return end if m.log.warn(\"Unhandled Home Item Type\", itemData.type) end sub ' ' Draws and animates item progress bar sub drawProgressBar(itemData) m.itemProgressBackground.width = itemData.imageWidth m.itemProgressBackground.visible = true m.showProgressBarField.keyValue = [0, m.itemPoster.width * (itemData.PlayedPercentage / 100)] m.showProgressBarAnimation.control = \"Start\" end sub ' ' Enable title scrolling based on item Focus sub focusChanged() if m.top.itemHasFocus = true m.itemText.repeatCount = -1 else m.itemText.repeatCount = 0 end if end sub 'Hide backdrop and icon when poster loaded sub onPosterLoadStatusChanged() if m.itemPoster.loadStatus = \"ready\" and m.itemPoster.uri &lt;&gt; \"\" m.backdrop.visible = false m.itemIcon.visible = false else m.backdrop.visible = true m.itemIcon.visible = true end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_home_HomeRows.brs.html":{"id":"components_home_HomeRows.brs.html","title":"Source: components/home/HomeRows.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/home/HomeRows.brs import \"pkg:/source/utils/misc.brs\" sub init() m.top.itemComponentName = \"HomeItem\" ' how many rows are visible on the screen m.top.numRows = 2 m.top.rowFocusAnimationStyle = \"fixedFocusWrap\" m.top.vertFocusAnimationStyle = \"fixedFocus\" m.top.showRowLabel = [true] m.top.rowLabelOffset = [0, 20] m.top.showRowCounter = [true] m.homeSectionIndexes = { count: 0 } updateSize() m.top.setfocus(true) m.top.observeField(\"rowItemSelected\", \"itemSelected\") ' Load the Libraries from API via task m.LoadLibrariesTask = createObject(\"roSGNode\", \"LoadItemsTask\") m.LoadLibrariesTask.observeField(\"content\", \"onLibrariesLoaded\") ' set up tesk nodes for other rows m.LoadContinueWatchingTask = createObject(\"roSGNode\", \"LoadItemsTask\") m.LoadContinueWatchingTask.itemsToLoad = \"continue\" m.LoadNextUpTask = createObject(\"roSGNode\", \"LoadItemsTask\") m.LoadNextUpTask.itemsToLoad = \"nextUp\" m.LoadOnNowTask = createObject(\"roSGNode\", \"LoadItemsTask\") m.LoadOnNowTask.itemsToLoad = \"onNow\" m.LoadFavoritesTask = createObject(\"roSGNode\", \"LoadItemsTask\") m.LoadFavoritesTask.itemsToLoad = \"favorites\" end sub sub loadLibraries() m.LoadLibrariesTask.control = \"RUN\" end sub sub updateSize() m.top.translation = [111, 180] itemHeight = 330 'Set width of Rows to cut off at edge of Safe Zone m.top.itemSize = [1703, itemHeight] ' spacing between rows m.top.itemSpacing = [0, 105] ' spacing between items in a row m.top.rowItemSpacing = [20, 0] m.top.visible = true end sub sub onLibrariesLoaded() ' save data for other functions m.libraryData = m.LoadLibrariesTask.content m.LoadLibrariesTask.unobserveField(\"content\") m.LoadLibrariesTask.content = [] content = CreateObject(\"roSGNode\", \"ContentNode\") sizeArray = [] loadedSections = 0 ' Add sections in order based on user settings for i = 0 to 6 sectionName = LCase(m.global.session.user.settings[\"homesection\" + i.toStr()]) sectionLoaded = addHomeSection(content, sizeArray, sectionName) ' Count how many sections with data are loaded if sectionLoaded then loadedSections++ ' If 2 sections with data are loaded or we're at the end of the web client section data, consider the home view loaded if loadedSections = 2 or i = 6 if not m.global.app_loaded m.top.signalBeacon(\"AppLaunchComplete\") ' Roku Performance monitoring m.global.app_loaded = true end if end if end for ' Favorites isn't an option on Web settings, so we must manually add it for now addHomeSection(content, sizeArray, \"favorites\") m.top.rowItemSize = sizeArray m.top.content = content end sub ' Removes a home section from the home rows sub removeHomeSection(sectionType as string) sectionName = LCase(sectionType) removedSectionIndex = m.homeSectionIndexes[sectionName] if not isValid(removedSectionIndex) then return for each section in m.homeSectionIndexes if m.homeSectionIndexes[section] &gt; removedSectionIndex m.homeSectionIndexes[section]-- end if end for m.homeSectionIndexes.Delete(sectionName) m.homeSectionIndexes.AddReplace(\"count\", m.homeSectionIndexes.count - 1) m.top.content.removeChildIndex(removedSectionIndex) end sub ' Adds a new home section to the home rows. ' Returns a boolean indicating whether the section was handled. function addHomeSection(content as dynamic, sizeArray as dynamic, sectionName as string) as boolean ' Poster size library items if sectionName = \"livetv\" createLiveTVRow(content, sizeArray) return true end if ' Poster size library items if sectionName = \"smalllibrarytiles\" createLibraryRow(content, sizeArray) return true end if ' Continue Watching items if sectionName = \"resume\" createContinueWatchingRow(content, sizeArray) return true end if ' Next Up items if sectionName = \"nextup\" createNextUpRow(content, sizeArray) return true end if ' Latest items in each library if sectionName = \"latestmedia\" createLatestInRows(content, sizeArray) return true end if ' Favorite Items if sectionName = \"favorites\" createFavoritesRow(content, sizeArray) return true end if return false end function ' Create a row displaying the user's libraries sub createLibraryRow(content as dynamic, sizeArray as dynamic) ' Ensure we have data if not isValidAndNotEmpty(m.libraryData) then return mediaRow = content.CreateChild(\"HomeRow\") mediaRow.title = tr(\"My Media\") m.homeSectionIndexes.AddReplace(\"library\", m.homeSectionIndexes.count) m.homeSectionIndexes.count++ sizeArray.push([464, 331]) filteredMedia = filterNodeArray(m.libraryData, \"id\", m.global.session.user.configuration.MyMediaExcludes) for each item in filteredMedia mediaRow.appendChild(item) end for end sub ' Create a row displaying latest items in each of the user's libraries sub createLatestInRows(content as dynamic, sizeArray as dynamic) ' Ensure we have data if not isValidAndNotEmpty(m.libraryData) then return ' create a \"Latest In\" row for each library filteredLatest = filterNodeArray(m.libraryData, \"id\", m.global.session.user.configuration.LatestItemsExcludes) for each lib in filteredLatest if lib.collectionType &lt;&gt; \"boxsets\" and lib.collectionType &lt;&gt; \"livetv\" and lib.json.CollectionType &lt;&gt; \"Program\" latestInRow = content.CreateChild(\"HomeRow\") latestInRow.title = tr(\"Latest in\") + \" \" + lib.name + \" &gt;\" m.homeSectionIndexes.AddReplace(\"latestin\" + LCase(lib.name).Replace(\" \", \"\"), m.homeSectionIndexes.count) m.homeSectionIndexes.count++ sizeArray.Push([464, 331]) loadLatest = createObject(\"roSGNode\", \"LoadItemsTask\") loadLatest.itemsToLoad = \"latest\" loadLatest.itemId = lib.id metadata = { \"title\": lib.name } metadata.Append({ \"contentType\": lib.json.CollectionType }) loadLatest.metadata = metadata loadLatest.observeField(\"content\", \"updateLatestItems\") loadLatest.control = \"RUN\" end if end for end sub ' Create a row displaying the live tv now on section sub createLiveTVRow(content as dynamic, sizeArray as dynamic) contentRow = content.CreateChild(\"HomeRow\") contentRow.title = tr(\"On Now\") m.homeSectionIndexes.AddReplace(\"livetv\", m.homeSectionIndexes.count) m.homeSectionIndexes.count++ sizeArray.push([464, 331]) m.LoadOnNowTask.observeField(\"content\", \"updateOnNowItems\") m.LoadOnNowTask.control = \"RUN\" end sub ' Create a row displaying items the user can continue watching sub createContinueWatchingRow(content as dynamic, sizeArray as dynamic) continueWatchingRow = content.CreateChild(\"HomeRow\") continueWatchingRow.title = tr(\"Continue Watching\") m.homeSectionIndexes.AddReplace(\"resume\", m.homeSectionIndexes.count) m.homeSectionIndexes.count++ sizeArray.push([464, 331]) ' Load the Continue Watching Data m.LoadContinueWatchingTask.observeField(\"content\", \"updateContinueWatchingItems\") m.LoadContinueWatchingTask.control = \"RUN\" end sub ' Create a row displaying next episodes up to watch sub createNextUpRow(content as dynamic, sizeArray as dynamic) nextUpRow = content.CreateChild(\"HomeRow\") nextUpRow.title = tr(\"Next Up &gt;\") m.homeSectionIndexes.AddReplace(\"nextup\", m.homeSectionIndexes.count) m.homeSectionIndexes.count++ sizeArray.push([464, 331]) ' Load the Next Up Data m.LoadNextUpTask.observeField(\"content\", \"updateNextUpItems\") m.LoadNextUpTask.control = \"RUN\" end sub ' Create a row displaying items from the user's favorites list sub createFavoritesRow(content as dynamic, sizeArray as dynamic) favoritesRow = content.CreateChild(\"HomeRow\") favoritesRow.title = tr(\"Favorites\") sizeArray.Push([464, 331]) m.homeSectionIndexes.AddReplace(\"favorites\", m.homeSectionIndexes.count) m.homeSectionIndexes.count++ ' Load the Favorites Data m.LoadFavoritesTask.observeField(\"content\", \"updateFavoritesItems\") m.LoadFavoritesTask.control = \"RUN\" end sub ' Update home row data sub updateHomeRows() if m.global.playstateTask.state = \"run\" m.global.playstateTask.observeField(\"state\", \"updateHomeRows\") return end if m.global.playstateTask.unobserveField(\"state\") ' If resume section exists, reload row's data if m.homeSectionIndexes.doesExist(\"resume\") m.LoadContinueWatchingTask.observeField(\"content\", \"updateContinueWatchingItems\") m.LoadContinueWatchingTask.control = \"RUN\" end if ' If next up section exists, reload row's data if m.homeSectionIndexes.doesExist(\"nextup\") m.LoadNextUpTask.observeField(\"content\", \"updateNextUpItems\") m.LoadNextUpTask.control = \"RUN\" end if ' If favorites section exists, reload row's data if m.homeSectionIndexes.doesExist(\"favorites\") m.LoadFavoritesTask.observeField(\"content\", \"updateFavoritesItems\") m.LoadFavoritesTask.control = \"RUN\" end if ' If live tv's on now section exists, reload row's data if m.homeSectionIndexes.doesExist(\"livetv\") m.LoadOnNowTask.observeField(\"content\", \"updateOnNowItems\") m.LoadOnNowTask.control = \"RUN\" end if ' If latest in library section exists, reload row's data hasLatestHomeSection = false for each section in m.homeSectionIndexes if LCase(Left(section, 6)) = \"latest\" hasLatestHomeSection = true exit for end if end for if hasLatestHomeSection updateLatestInRows() end if end sub sub updateFavoritesItems() itemData = m.LoadFavoritesTask.content m.LoadFavoritesTask.unobserveField(\"content\") m.LoadFavoritesTask.content = [] if itemData = invalid then return rowIndex = m.homeSectionIndexes.favorites if itemData.count() &lt; 1 removeHomeSection(\"favorites\") return else ' remake row using the new data row = CreateObject(\"roSGNode\", \"HomeRow\") row.title = tr(\"Favorites\") for each item in itemData usePoster = true if lcase(item.type) = \"episode\" or lcase(item.type) = \"audio\" or lcase(item.type) = \"musicartist\" usePoster = false end if item.usePoster = usePoster item.imageWidth = row.imageWidth row.appendChild(item) end for ' replace the old row m.top.content.replaceChild(row, rowIndex) end if end sub sub updateContinueWatchingItems() itemData = m.LoadContinueWatchingTask.content m.LoadContinueWatchingTask.unobserveField(\"content\") m.LoadContinueWatchingTask.content = [] if itemData = invalid then return if itemData.count() &lt; 1 removeHomeSection(\"resume\") return end if ' remake row using the new data row = CreateObject(\"roSGNode\", \"HomeRow\") row.title = tr(\"Continue Watching\") for each item in itemData if isValid(item.json) and isValid(item.json.UserData) and isValid(item.json.UserData.PlayedPercentage) item.PlayedPercentage = item.json.UserData.PlayedPercentage end if item.usePoster = row.usePoster item.imageWidth = row.imageWidth row.appendChild(item) end for ' replace the old row m.top.content.replaceChild(row, m.homeSectionIndexes.resume) end sub sub updateNextUpItems() itemData = m.LoadNextUpTask.content m.LoadNextUpTask.unobserveField(\"content\") m.LoadNextUpTask.content = [] if itemData = invalid then return if itemData.count() &lt; 1 removeHomeSection(\"nextup\") return else ' remake row using the new data row = CreateObject(\"roSGNode\", \"HomeRow\") row.title = tr(\"Next Up\") + \" &gt;\" for each item in itemData item.usePoster = row.usePoster item.imageWidth = row.imageWidth row.appendChild(item) end for ' replace the old row m.top.content.replaceChild(row, m.homeSectionIndexes.nextup) end if end sub ' Iterate over user's libraries and update data for each Latest In section sub updateLatestInRows() ' Ensure we have data if not isValidAndNotEmpty(m.libraryData) then return ' Load new data for each library filteredLatest = filterNodeArray(m.libraryData, \"id\", m.global.session.user.configuration.LatestItemsExcludes) for each lib in filteredLatest if lib.collectionType &lt;&gt; \"boxsets\" and lib.collectionType &lt;&gt; \"livetv\" and lib.json.CollectionType &lt;&gt; \"Program\" loadLatest = createObject(\"roSGNode\", \"LoadItemsTask\") loadLatest.itemsToLoad = \"latest\" loadLatest.itemId = lib.id metadata = { \"title\": lib.name } metadata.Append({ \"contentType\": lib.json.CollectionType }) loadLatest.metadata = metadata loadLatest.observeField(\"content\", \"updateLatestItems\") loadLatest.control = \"RUN\" end if end for end sub sub updateLatestItems(msg) itemData = msg.GetData() node = msg.getRoSGNode() node.unobserveField(\"content\") node.content = [] if itemData = invalid then return sectionName = \"latestin\" + LCase(node.metadata.title).Replace(\" \", \"\") rowIndex = m.homeSectionIndexes[sectionName] if itemData.count() &lt; 1 removeHomeSection(sectionName) return else ' remake row using new data row = CreateObject(\"roSGNode\", \"HomeRow\") row.title = tr(\"Latest in\") + \" \" + node.metadata.title + \" &gt;\" row.usePoster = true ' Handle specific types with different item widths if node.metadata.contentType = \"movies\" row.imageWidth = 180 itemSize = [188, 331] else if node.metadata.contentType = \"music\" row.imageWidth = 261 itemSize = [261, 331] else row.imageWidth = 464 itemSize = [464, 331] end if for each item in itemData item.usePoster = row.usePoster item.imageWidth = row.imageWidth row.appendChild(item) end for ' replace the old row updateSizeArray(itemSize, rowIndex, \"replace\") m.top.content.replaceChild(row, rowIndex) end if end sub sub updateOnNowItems() itemData = m.LoadOnNowTask.content m.LoadOnNowTask.unobserveField(\"content\") m.LoadOnNowTask.content = [] if itemData = invalid then return if itemData.count() &lt; 1 removeHomeSection(\"livetv\") return else ' remake row using the new data row = CreateObject(\"roSGNode\", \"HomeRow\") row.title = tr(\"On Now\") for each item in itemData item.usePoster = row.usePoster item.imageWidth = row.imageWidth row.appendChild(item) end for ' replace the old row m.top.content.replaceChild(row, m.homeSectionIndexes.livetv) end if end sub sub updateSizeArray(rowItemSize, rowIndex = invalid, action = \"insert\") sizeArray = m.top.rowItemSize ' append by default if rowIndex = invalid rowIndex = sizeArray.count() end if newSizeArray = [] for i = 0 to sizeArray.count() if rowIndex = i if action = \"replace\" newSizeArray.Push(rowItemSize) else if action = \"insert\" newSizeArray.Push(rowItemSize) if isValid(sizeArray[i]) newSizeArray.Push(sizeArray[i]) end if end if else if isValid(sizeArray[i]) newSizeArray.Push(sizeArray[i]) end if end for m.top.rowItemSize = newSizeArray end sub sub itemSelected() m.top.selectedItem = m.top.content.getChild(m.top.rowItemSelected[0]).getChild(m.top.rowItemSelected[1]) 'Prevent the selected item event from double firing m.top.selectedItem = invalid end sub function onKeyEvent(key as string, press as boolean) as boolean if press if key = \"play\" print \"play was pressed from homerow\" itemToPlay = m.top.content.getChild(m.top.rowItemFocused[0]).getChild(m.top.rowItemFocused[1]) if isValid(itemToPlay) m.top.quickPlayNode = itemToPlay end if return true else if key = \"replay\" m.top.jumpToRowItem = [m.top.rowItemFocused[0], 0] return true end if end if return false end function function filterNodeArray(nodeArray as object, nodeKey as string, excludeArray as object) as object if excludeArray.IsEmpty() then return nodeArray newNodeArray = [] for each node in nodeArray excludeThisNode = false for each exclude in excludeArray if node[nodeKey] = exclude excludeThisNode = true end if end for if excludeThisNode = false newNodeArray.Push(node) end if end for return newNodeArray end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_IconButton.brs.html":{"id":"components_IconButton.brs.html","title":"Source: components/IconButton.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/IconButton.brs sub init() m.buttonBackground = m.top.findNode(\"buttonBackground\") m.buttonIcon = m.top.findNode(\"buttonIcon\") m.buttonText = m.top.findNode(\"buttonText\") m.top.observeField(\"background\", \"onBackgroundChanged\") m.top.observeField(\"icon\", \"onIconChanged\") m.top.observeField(\"text\", \"onTextChanged\") m.top.observeField(\"height\", \"onHeightChanged\") m.top.observeField(\"width\", \"onWidthChanged\") m.top.observeField(\"padding\", \"onPaddingChanged\") m.top.observeField(\"focus\", \"onFocusChanged\") end sub sub onFocusChanged() if m.top.focus m.buttonBackground.blendColor = m.top.focusBackground else m.buttonBackground.blendColor = m.top.background end if end sub sub onBackgroundChanged() m.buttonBackground.blendColor = m.top.background m.top.unobserveField(\"background\") end sub sub onIconChanged() m.buttonIcon.uri = m.top.icon end sub sub onTextChanged() m.buttonText.text = m.top.text end sub sub setIconSize() height = m.buttonBackground.height width = m.buttonBackground.width if height &gt; 0 and width &gt; 0 ' TODO: Use smallest number between them m.buttonIcon.height = m.top.height if m.top.padding &gt; 0 m.buttonIcon.height = m.buttonIcon.height - m.top.padding end if m.buttonIcon.width = m.buttonIcon.height m.buttonIcon.translation = [((width - m.buttonIcon.width) / 2), ((height - m.buttonIcon.height) / 2)] m.buttonText.translation = [0, height + 10] m.buttonText.width = width end if end sub sub onHeightChanged() m.buttonBackground.height = m.top.height setIconSize() end sub sub onWidthChanged() m.buttonBackground.width = m.top.width setIconSize() end sub sub onPaddingChanged() setIconSize() end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false if key = \"right\" and m.top.focus m.top.escape = \"right\" end if if key = \"left\" and m.top.focus m.top.escape = \"left\" end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"source_api_Image.brs.html":{"id":"source_api_Image.brs.html","title":"Source: source/api/Image.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: source/api/Image.brs function ItemImages(id = \"\" as string, params = {} as object) ' This seems to cause crazy core dumps ' if there is a conflict between on disk images, and library.db resp = APIRequest(Substitute(\"Items/{0}/Images\", id)) data = getJson(resp) if data = invalid then return invalid results = [] for each item in data tmp = CreateObject(\"roSGNode\", \"ImageData\") tmp.json = item tmp.url = ImageURL(id, tmp.imagetype, params) results.push(tmp) end for return results end function function PosterImage(id as string, params = {} as object) images = ItemImages(id, params) if images = invalid then return invalid primary_image = invalid for each image in images if image.imagetype = \"Primary\" primary_image = image else if image.imagetype = \"Logo\" and primary_image = invalid primary_image = image else if image.imagetype = \"Thumb\" and primary_image = invalid primary_image = image ' maybe find more fallback images end if end for return primary_image end function function ImageURL(id, version = \"Primary\", params = {}) ' set defaults if params.maxHeight = invalid param = { \"maxHeight\": \"384\" } params.append(param) end if if params.maxWidth = invalid param = { \"maxWidth\": \"196\" } params.append(param) end if if params.quality = invalid param = { \"quality\": \"90\" } params.append(param) end if url = Substitute(\"Items/{0}/Images/{1}\", id, version) ' ?maxHeight=384&amp;maxWidth=256&amp;tag=&lt;tag&gt;&amp;quality=90\" return buildURL(url, params) end function function UserImageURL(id, params = {}) ' set defaults if params.maxHeight = invalid params.append({ \"maxHeight\": \"300\" }) end if if params.maxWidth = invalid params.append({ \"maxWidth\": \"300\" }) end if if params.quality = invalid params.append({ \"quality\": \"90\" }) end if url = Substitute(\"Users/{0}/Images/Primary\", id) return buildURL(url, params) end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_ImageData.brs.html":{"id":"components_data_ImageData.brs.html","title":"Source: components/data/ImageData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/ImageData.brs sub setFields() json = m.top.json m.top.imagetype = json.imagetype m.top.size = json.size m.top.height = json.height m.top.width = json.width end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_ItemGrid_ItemGrid.brs.html":{"id":"components_ItemGrid_ItemGrid.brs.html","title":"Source: components/ItemGrid/ItemGrid.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/ItemGrid/ItemGrid.brs import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/utils/config.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/deviceCapabilities.brs\" import \"pkg:/source/roku_modules/log/LogMixin.brs\" sub init() m.log = log.Logger(\"ItemGrid\") m.options = m.top.findNode(\"options\") m.showItemCount = m.global.session.user.settings[\"itemgrid.showItemCount\"] m.tvGuide = invalid m.channelFocused = invalid m.itemGrid = m.top.findNode(\"itemGrid\") m.backdrop = m.top.findNode(\"backdrop\") m.newBackdrop = m.top.findNode(\"backdropTransition\") m.emptyText = m.top.findNode(\"emptyText\") m.genreList = m.top.findNode(\"genrelist\") m.genreList.observeField(\"itemSelected\", \"onGenreItemSelected\") m.genreData = CreateObject(\"roSGNode\", \"ContentNode\") m.genreList.content = m.genreData m.swapAnimation = m.top.findNode(\"backroundSwapAnimation\") m.swapAnimation.observeField(\"state\", \"swapDone\") m.loadedRows = 0 m.loadedItems = 0 m.data = CreateObject(\"roSGNode\", \"ContentNode\") m.itemGrid.content = m.data m.itemGrid.setFocus(true) m.itemGrid.observeField(\"itemFocused\", \"onItemFocused\") m.itemGrid.observeField(\"itemSelected\", \"onItemSelected\") m.itemGrid.observeField(\"alphaSelected\", \"onItemalphaSelected\") 'Voice filter setup m.voiceBox = m.top.findNode(\"voiceBox\") m.voiceBox.voiceEnabled = true m.voiceBox.active = true m.voiceBox.observeField(\"text\", \"onvoiceFilter\") 'set voice help text m.voiceBox.hintText = tr(\"Use voice remote to search\") 'backdrop m.newBackdrop.observeField(\"loadStatus\", \"newBGLoaded\") 'Background Image Queued for loading m.queuedBGUri = \"\" 'Item sort - maybe load defaults from user prefs? m.sortField = \"SortName\" m.sortAscending = true m.filter = \"All\" m.favorite = \"Favorite\" m.loadItemsTask = createObject(\"roSGNode\", \"LoadItemsTask2\") 'set inital counts for overhang before content is loaded. m.loadItemsTask.totalRecordCount = 0 m.spinner = m.top.findNode(\"spinner\") m.spinner.visible = true m.Alpha = m.top.findNode(\"AlphaMenu\") m.AlphaSelected = m.top.findNode(\"AlphaSelected\") 'Get reset folder setting m.resetGrid = m.global.session.user.settings[\"itemgrid.reset\"] m.micButton = m.top.findNode(\"micButton\") m.micButtonText = m.top.findNode(\"micButtonText\") 'Hide voice search if device does not have voice remote if m.global.device.hasVoiceRemote = false m.micButton.visible = false m.micButtonText.visible = false end if end sub ' 'Genre Item Selected sub onGenreItemSelected() m.top.selectedItem = m.genreList.content.getChild(m.genreList.rowItemSelected[0]).getChild(m.genreList.rowItemSelected[1]) end sub ' 'Load initial set of Data sub loadInitialItems() m.loadItemsTask.control = \"stop\" m.spinner.visible = true if m.top.parentItem.json.Type = \"CollectionFolder\" 'or m.top.parentItem.json.Type = \"Folder\" m.top.HomeLibraryItem = m.top.parentItem.Id end if if m.top.parentItem.backdropUrl &lt;&gt; invalid SetBackground(m.top.parentItem.backdropUrl) end if ' Read view/sort/filter settings if m.top.parentItem.collectionType = \"livetv\" ' Translate between app and server nomenclature viewSetting = m.global.session.user.settings[\"display.livetv.landing\"] 'Move mic to be visiable on TV Guide screen if m.global.device.hasVoiceRemote = true m.micButton.translation = \"[1540, 92]\" m.micButtonText.visible = true m.micButtonText.translation = \"[1600,130]\" m.micButtonText.font.size = 22 m.micButtonText.text = tr(\"Search\") end if if viewSetting = \"guide\" m.view = \"tvGuide\" else m.view = \"livetv\" end if m.sortField = m.global.session.user.settings[\"display.livetv.sortField\"] sortAscendingStr = m.global.session.user.settings[\"display.livetv.sortAscending\"] m.filter = m.global.session.user.settings[\"display.livetv.filter\"] else if m.top.parentItem.collectionType = \"music\" m.view = m.global.session.user.settings[\"display.music.view\"] m.sortField = m.global.session.user.settings[\"display.\" + m.top.parentItem.Id + \".sortField\"] sortAscendingStr = m.global.session.user.settings[\"display.\" + m.top.parentItem.Id + \".sortAscending\"] m.filter = m.global.session.user.settings[\"display.\" + m.top.parentItem.Id + \".filter\"] else m.sortField = m.global.session.user.settings[\"display.\" + m.top.parentItem.Id + \".sortField\"] sortAscendingStr = m.global.session.user.settings[\"display.\" + m.top.parentItem.Id + \".sortAscending\"] m.filter = m.global.session.user.settings[\"display.\" + m.top.parentItem.Id + \".filter\"] m.view = m.global.session.user.settings[\"display.\" + m.top.parentItem.Id + \".landing\"] end if if m.sortField = invalid ' Set the default order for boxsets to the Release Date - API calls it PremiereDate if LCase(m.top.parentItem.json.Type) = \"boxset\" m.sortField = \"PremiereDate\" else m.sortField = \"SortName\" end if end if if m.filter = invalid then m.filter = \"All\" if sortAscendingStr = invalid or sortAscendingStr = true m.sortAscending = true else m.sortAscending = false end if ' Set Studio Id if m.top.parentItem.json.type = \"Studio\" m.loadItemsTask.studioIds = m.top.parentItem.id m.loadItemsTask.itemId = m.top.parentItem.parentFolder m.loadItemsTask.genreIds = \"\" ' Set Genre Id else if m.top.parentItem.json.type = \"Genre\" m.loadItemsTask.genreIds = m.top.parentItem.id m.loadItemsTask.itemId = m.top.parentItem.parentFolder m.loadItemsTask.studioIds = \"\" else if (m.view = \"Shows\" or m.options.view = \"Shows\") or (m.view = \"Movies\" or m.options.view = \"Movies\") m.loadItemsTask.studioIds = \"\" m.loadItemsTask.genreIds = \"\" else m.loadItemsTask.itemId = m.top.parentItem.Id end if updateTitle() m.loadItemsTask.nameStartsWith = m.top.alphaSelected m.loadItemsTask.searchTerm = m.voiceBox.text m.emptyText.visible = false m.loadItemsTask.sortField = m.sortField m.loadItemsTask.sortAscending = m.sortAscending m.loadItemsTask.filter = m.filter m.loadItemsTask.startIndex = 0 ' Load Item Types if getCollectionType() = \"movies\" m.loadItemsTask.itemType = \"Movie\" m.loadItemsTask.itemId = m.top.parentItem.Id else if getCollectionType() = \"tvshows\" m.loadItemsTask.itemType = \"Series\" m.loadItemsTask.itemId = m.top.parentItem.Id else if getCollectionType() = \"music\" ' Default Settings m.loadItemsTask.recursive = true m.itemGrid.itemSize = \"[290, 290]\" m.loadItemsTask.itemType = \"MusicArtist\" m.loadItemsTask.itemId = m.top.parentItem.Id m.view = m.global.session.user.settings[\"display.music.view\"] if m.view = \"music-album\" m.loadItemsTask.itemType = \"MusicAlbum\" end if else if m.top.parentItem.collectionType = \"livetv\" m.loadItemsTask.itemType = \"TvChannel\" m.loadItemsTask.itemId = \" \" ' For LiveTV, we want to \"Fit\" the item images, not zoom m.top.imageDisplayMode = \"scaleToFit\" if m.global.session.user.settings[\"display.livetv.landing\"] = \"guide\" and m.options.view &lt;&gt; \"livetv\" showTvGuide() end if else if m.top.parentItem.collectionType = \"CollectionFolder\" or m.top.parentItem.type = \"CollectionFolder\" or m.top.parentItem.collectionType = \"boxsets\" or m.top.parentItem.Type = \"Boxset\" or m.top.parentItem.Type = \"Boxsets\" or m.top.parentItem.Type = \"Folder\" or m.top.parentItem.Type = \"Channel\" if m.voiceBox.text &lt;&gt; \"\" m.loadItemsTask.recursive = true else ' non recursive for collections (folders, boxsets, photo albums, etc) m.loadItemsTask.recursive = false end if else if m.top.parentItem.json.type = \"Studio\" m.loadItemsTask.itemId = m.top.parentItem.parentFolder m.loadItemsTask.itemType = \"Series,Movie\" m.top.imageDisplayMode = \"scaleToFit\" else if m.top.parentItem.json.type = \"Genre\" m.loadItemsTask.itemType = \"Series,Movie\" m.loadItemsTask.itemId = m.top.parentItem.parentFolder else m.log.warn(\"Unknown Item Type\", m.top.parentItem) end if if m.top.parentItem.type &lt;&gt; \"Folder\" and (m.options.view = \"Networks\" or m.view = \"Networks\" or m.options.view = \"Studios\" or m.view = \"Studios\") m.loadItemsTask.view = \"Networks\" m.top.imageDisplayMode = \"scaleToFit\" else if m.top.parentItem.type &lt;&gt; \"Folder\" and (m.options.view = \"Genres\" or m.view = \"Genres\") m.loadItemsTask.StudioIds = m.top.parentItem.Id m.loadItemsTask.view = \"Genres\" else if m.top.parentItem.type &lt;&gt; \"Folder\" and (m.options.view = \"Shows\" or m.view = \"Shows\") m.loadItemsTask.studioIds = \"\" m.loadItemsTask.view = \"Shows\" else if m.top.parentItem.type &lt;&gt; \"Folder\" and (m.options.view = \"Movies\" or m.view = \"Movies\") m.loadItemsTask.studioIds = \"\" m.loadItemsTask.view = \"Movies\" end if m.loadItemsTask.observeField(\"content\", \"ItemDataLoaded\") m.spinner.visible = true m.loadItemsTask.control = \"RUN\" SetUpOptions() end sub ' Set Movies view, sort, and filter options sub setMoviesOptions(options) options.views = [ { \"Title\": tr(\"Movies\"), \"Name\": \"Movies\" }, { \"Title\": tr(\"Studios\"), \"Name\": \"Studios\" }, { \"Title\": tr(\"Genres\"), \"Name\": \"Genres\" } ] options.sort = [ { \"Title\": tr(\"TITLE\"), \"Name\": \"SortName\" }, { \"Title\": tr(\"IMDB_RATING\"), \"Name\": \"CommunityRating\" }, { \"Title\": tr(\"CRITIC_RATING\"), \"Name\": \"CriticRating\" }, { \"Title\": tr(\"DATE_ADDED\"), \"Name\": \"DateCreated\" }, { \"Title\": tr(\"DATE_PLAYED\"), \"Name\": \"DatePlayed\" }, { \"Title\": tr(\"OFFICIAL_RATING\"), \"Name\": \"OfficialRating\" }, { \"Title\": tr(\"PLAY_COUNT\"), \"Name\": \"PlayCount\" }, { \"Title\": tr(\"RELEASE_DATE\"), \"Name\": \"PremiereDate\" }, { \"Title\": tr(\"RUNTIME\"), \"Name\": \"Runtime\" } ] options.filter = [ { \"Title\": tr(\"All\"), \"Name\": \"All\" }, { \"Title\": tr(\"Favorites\"), \"Name\": \"Favorites\" }, { \"Title\": tr(\"Played\"), \"Name\": \"Played\" }, { \"Title\": tr(\"Unplayed\"), \"Name\": \"Unplayed\" }, { \"Title\": tr(\"Resumable\"), \"Name\": \"Resumable\" } ] end sub ' Set Boxset view, sort, and filter options sub setBoxsetsOptions(options) options.views = [{ \"Title\": tr(\"Shows\"), \"Name\": \"shows\" }] options.sort = [ { \"Title\": tr(\"TITLE\"), \"Name\": \"SortName\" }, { \"Title\": tr(\"DATE_ADDED\"), \"Name\": \"DateCreated\" }, { \"Title\": tr(\"DATE_PLAYED\"), \"Name\": \"DatePlayed\" }, { \"Title\": tr(\"RELEASE_DATE\"), \"Name\": \"PremiereDate\" }, ] options.filter = [ { \"Title\": tr(\"All\"), \"Name\": \"All\" }, { \"Title\": tr(\"Favorites\"), \"Name\": \"Favorites\" }, { \"Title\": tr(\"Played\"), \"Name\": \"Played\" }, { \"Title\": tr(\"Unplayed\"), \"Name\": \"Unplayed\" } ] end sub ' Set TV Show view, sort, and filter options sub setTvShowsOptions(options) options.views = [ { \"Title\": tr(\"Shows\"), \"Name\": \"Shows\" }, { \"Title\": tr(\"Networks\"), \"Name\": \"Networks\" }, { \"Title\": tr(\"Genres\"), \"Name\": \"Genres\" } ] options.sort = [ { \"Title\": tr(\"TITLE\"), \"Name\": \"SortName\" }, { \"Title\": tr(\"IMDB_RATING\"), \"Name\": \"CommunityRating\" }, { \"Title\": tr(\"DATE_ADDED\"), \"Name\": \"DateCreated\" }, { \"Title\": tr(\"DATE_PLAYED\"), \"Name\": \"DatePlayed\" }, { \"Title\": tr(\"OFFICIAL_RATING\"), \"Name\": \"OfficialRating\" }, { \"Title\": tr(\"RELEASE_DATE\"), \"Name\": \"PremiereDate\" }, ] options.filter = [ { \"Title\": tr(\"All\"), \"Name\": \"All\" }, { \"Title\": tr(\"Favorites\"), \"Name\": \"Favorites\" }, { \"Title\": tr(\"Played\"), \"Name\": \"Played\" }, { \"Title\": tr(\"Unplayed\"), \"Name\": \"Unplayed\" } ] if isValid(m.view) if LCase(m.options.view) = \"genres\" or LCase(m.view) = \"genres\" options.sort = [{ \"Title\": tr(\"TITLE\"), \"Name\": \"SortName\" }] options.filter = [] end if end if end sub ' Set Live TV view, sort, and filter options sub setLiveTvOptions(options) options.views = [ { \"Title\": tr(\"Channels\"), \"Name\": \"livetv\" }, { \"Title\": tr(\"TV Guide\"), \"Name\": \"tvGuide\" } ] options.sort = [ { \"Title\": tr(\"TITLE\"), \"Name\": \"SortName\" } ] options.filter = [ { \"Title\": tr(\"All\"), \"Name\": \"All\" }, { \"Title\": tr(\"Favorites\"), \"Name\": \"Favorites\" } ] options.favorite = [ { \"Title\": tr(\"Favorite\"), \"Name\": \"Favorite\" } ] end sub ' Set Music view, sort, and filter options sub setMusicOptions(options) options.views = [ { \"Title\": tr(\"Artists\"), \"Name\": \"music-artist\" }, { \"Title\": tr(\"Albums\"), \"Name\": \"music-album\" }, ] options.sort = [ { \"Title\": tr(\"TITLE\"), \"Name\": \"SortName\" }, { \"Title\": tr(\"DATE_ADDED\"), \"Name\": \"DateCreated\" }, { \"Title\": tr(\"DATE_PLAYED\"), \"Name\": \"DatePlayed\" }, { \"Title\": tr(\"RELEASE_DATE\"), \"Name\": \"PremiereDate\" }, ] options.filter = [ { \"Title\": tr(\"All\"), \"Name\": \"All\" }, { \"Title\": tr(\"Favorites\"), \"Name\": \"Favorites\" } ] end sub ' Set Photo Album view, sort, and filter options sub setPhotoAlbumOptions(options) options.views = [ { \"Title\": tr(\"Slideshow Off\"), \"Name\": \"singlephoto\" } { \"Title\": tr(\"Slideshow On\"), \"Name\": \"slideshowphoto\" } { \"Title\": tr(\"Random Off\"), \"Name\": \"singlephoto\" } { \"Title\": tr(\"Random On\"), \"Name\": \"randomphoto\" } ] options.sort = [] options.filter = [] end sub ' Set Default view, sort, and filter options sub setDefaultOptions(options) options.views = [ { \"Title\": tr(\"Default\"), \"Name\": \"default\" } ] options.sort = [ { \"Title\": tr(\"TITLE\"), \"Name\": \"SortName\" } ] end sub ' Return parent collection type function getCollectionType() as string if m.top.parentItem.collectionType = invalid return m.top.parentItem.Type else return m.top.parentItem.CollectionType end if end function ' Search string array for search value. Return if it's found function inStringArray(array, searchValue) as boolean for each item in array if lcase(item) = lcase(searchValue) then return true end for return false end function ' Data to display when options button selected sub SetUpOptions() options = {} options.filter = [] options.favorite = [] if getCollectionType() = \"movies\" setMoviesOptions(options) else if inStringArray([\"boxsets\", \"Boxset\"], getCollectionType()) setBoxsetsOptions(options) else if getCollectionType() = \"tvshows\" setTvShowsOptions(options) else if getCollectionType() = \"livetv\" setLiveTvOptions(options) else if inStringArray([\"photoalbum\", \"photo\", \"homevideos\"], getCollectionType()) setPhotoAlbumOptions(options) else if getCollectionType() = \"music\" setMusicOptions(options) else setDefaultOptions(options) end if ' Set selected view option for each o in options.views if o.Name = m.view o.Selected = true o.Ascending = m.sortAscending m.options.view = o.Name end if end for ' Set selected sort option for each o in options.sort if o.Name = m.sortField o.Selected = true o.Ascending = m.sortAscending m.options.sortField = o.Name end if end for ' Set selected filter option for each o in options.filter if o.Name = m.filter o.Selected = true m.options.filter = o.Name end if end for m.options.options = options end sub ' 'Handle loaded data, and add to Grid sub ItemDataLoaded(msg) m.top.alphaActive = false itemData = msg.GetData() m.loadItemsTask.unobserveField(\"content\") m.loadItemsTask.content = [] if itemData = invalid m.Loading = false return end if if m.loadItemsTask.view = \"Genres\" ' Reset genre list data m.genreData.removeChildren(m.genreData.getChildren(-1, 0)) for each item in itemData m.genreData.appendChild(item) end for m.itemGrid.opacity = \"0\" m.genreList.opacity = \"1\" m.itemGrid.setFocus(false) m.genreList.setFocus(true) m.loading = false m.spinner.visible = false return end if for each item in itemData m.data.appendChild(item) end for m.itemGrid.opacity = \"1\" m.genreList.opacity = \"0\" 'Update the stored counts m.loadedItems = m.itemGrid.content.getChildCount() m.loadedRows = m.loadedItems / m.itemGrid.numColumns m.Loading = false 'If there are no items to display, show message if m.loadedItems = 0 m.emptyText.text = tr(\"NO_ITEMS\").Replace(\"%1\", m.top.parentItem.Type) m.emptyText.visible = true end if m.itemGrid.setFocus(true) m.genreList.setFocus(false) m.spinner.visible = false end sub ' 'Set Background Image sub SetBackground(backgroundUri as string) 'If a new image is being loaded, or transitioned to, store URL to load next if m.swapAnimation.state &lt;&gt; \"stopped\" or m.newBackdrop.loadStatus = \"loading\" m.queuedBGUri = backgroundUri return end if m.newBackdrop.uri = backgroundUri end sub ' 'Handle new item being focused sub onItemFocused() focusedRow = m.itemGrid.currFocusRow itemInt = m.itemGrid.itemFocused updateTitle() ' If no selected item, set background to parent backdrop if itemInt = -1 return end if m.selectedFavoriteItem = m.itemGrid.content.getChild(m.itemGrid.itemFocused) ' Set Background to item backdrop SetBackground(m.itemGrid.content.getChild(m.itemGrid.itemFocused).backdropUrl) ' Load more data if focus is within last 5 rows, and there are more items to load if focusedRow &gt;= m.loadedRows - 5 and m.loadeditems &lt; m.loadItemsTask.totalRecordCount loadMoreData() end if end sub ' 'When Image Loading Status changes sub newBGLoaded() 'If image load was sucessful, start the fade swap if m.newBackdrop.loadStatus = \"ready\" m.swapAnimation.control = \"start\" end if end sub ' 'Swap Complete sub swapDone() if m.swapAnimation.state = \"stopped\" 'Set main BG node image and hide transitioning node m.backdrop.uri = m.newBackdrop.uri m.backdrop.opacity = 0.25 m.newBackdrop.opacity = 0 'If there is another one to load if m.newBackdrop.uri &lt;&gt; m.queuedBGUri and m.queuedBGUri &lt;&gt; \"\" SetBackground(m.queuedBGUri) m.queuedBGUri = \"\" end if end if end sub ' 'Load next set of items sub loadMoreData() m.spinner.visible = true if m.Loading = true then return m.Loading = true m.loadItemsTask.startIndex = m.loadedItems m.loadItemsTask.observeField(\"content\", \"ItemDataLoaded\") m.loadItemsTask.control = \"RUN\" end sub ' 'Item Selected sub onItemSelected() m.top.selectedItem = m.itemGrid.content.getChild(m.itemGrid.itemSelected) end sub sub onItemalphaSelected() if m.top.alphaSelected &lt;&gt; \"\" m.loadedRows = 0 m.loadedItems = 0 m.data = CreateObject(\"roSGNode\", \"ContentNode\") m.itemGrid.content = m.data m.loadItemsTask.searchTerm = \"\" m.VoiceBox.text = \"\" m.loadItemsTask.nameStartsWith = m.alpha.itemAlphaSelected m.spinner.visible = true loadInitialItems() end if end sub sub onvoiceFilter() if m.VoiceBox.text &lt;&gt; \"\" m.loadedRows = 0 m.loadedItems = 0 m.data = CreateObject(\"roSGNode\", \"ContentNode\") m.itemGrid.content = m.data m.top.alphaSelected = \"\" m.loadItemsTask.NameStartsWith = \" \" m.loadItemsTask.searchTerm = m.voiceBox.text m.loadItemsTask.recursive = true m.spinner.visible = true loadInitialItems() end if end sub ' 'Check if options updated and any reloading required sub optionsClosed() if m.top.parentItem.collectionType = \"livetv\" and m.options.view &lt;&gt; m.view if m.options.view = \"tvGuide\" m.view = \"tvGuide\" set_user_setting(\"display.livetv.landing\", \"guide\") showTVGuide() return else m.view = \"livetv\" set_user_setting(\"display.livetv.landing\", \"channels\") if m.tvGuide &lt;&gt; invalid ' Try to hide the TV Guide m.top.removeChild(m.tvGuide) end if end if end if if m.top.parentItem.Type = \"CollectionFolder\" or m.top.parentItem.Type = \"Folder\" or m.top.parentItem.CollectionType = \"CollectionFolder\" ' Did the user just request \"Random\" on a PhotoAlbum? if m.options.view = \"singlephoto\" set_user_setting(\"photos.slideshow\", \"false\") set_user_setting(\"photos.random\", \"false\") else if m.options.view = \"slideshowphoto\" set_user_setting(\"photos.slideshow\", \"true\") set_user_setting(\"photos.random\", \"false\") else if m.options.view = \"randomphoto\" set_user_setting(\"photos.random\", \"true\") set_user_setting(\"photos.slideshow\", \"false\") end if end if reload = false if m.top.parentItem.collectionType = \"music\" if m.options.view &lt;&gt; m.view m.view = m.options.view set_user_setting(\"display.music.view\", m.view) reload = true end if else m.view = m.global.session.user.settings[\"display.\" + m.top.parentItem.Id + \".landing\"] if m.options.view &lt;&gt; m.view 'reload and store new view setting m.view = m.options.view set_user_setting(\"display.\" + m.top.parentItem.Id + \".landing\", m.view) reload = true end if end if if m.options.sortField &lt;&gt; m.sortField or m.options.sortAscending &lt;&gt; m.sortAscending m.sortField = m.options.sortField m.sortAscending = m.options.sortAscending reload = true 'Store sort settings if m.sortAscending = true sortAscendingStr = \"true\" else sortAscendingStr = \"false\" end if if m.top.parentItem.collectionType = \"livetv\" set_user_setting(\"display.livetv.sortField\", m.sortField) set_user_setting(\"display.livetv.sortAscending\", sortAscendingStr) else set_user_setting(\"display.\" + m.top.parentItem.Id + \".sortField\", m.sortField) set_user_setting(\"display.\" + m.top.parentItem.Id + \".sortAscending\", sortAscendingStr) end if end if if m.options.filter &lt;&gt; m.filter m.filter = m.options.filter updateTitle() reload = true 'Store filter setting if m.top.parentItem.collectionType = \"livetv\" set_user_setting(\"display.livetv.filter\", m.options.filter) else set_user_setting(\"display.\" + m.top.parentItem.Id + \".filter\", m.options.filter) end if end if if reload m.loadedRows = 0 m.loadedItems = 0 m.data = CreateObject(\"roSGNode\", \"ContentNode\") m.itemGrid.content = m.data loadInitialItems() end if m.itemGrid.setFocus(m.itemGrid.opacity = 1) m.genreList.setFocus(m.genreList.opacity = 1) if m.tvGuide &lt;&gt; invalid m.tvGuide.lastFocus.setFocus(true) end if end sub sub showTVGuide() if m.tvGuide = invalid m.tvGuide = createObject(\"roSGNode\", \"Schedule\") m.top.signalBeacon(\"EPGLaunchInitiate\") ' Required Roku Performance monitoring m.tvGuide.observeField(\"watchChannel\", \"onChannelSelected\") m.tvGuide.observeField(\"focusedChannel\", \"onChannelFocused\") end if m.tvGuide.filter = m.filter m.tvGuide.searchTerm = m.voiceBox.text m.top.appendChild(m.tvGuide) m.scheduleGrid = m.top.findNode(\"scheduleGrid\") m.tvGuide.lastFocus.setFocus(true) end sub sub onChannelSelected(msg) node = msg.getRoSGNode() m.top.lastFocus = lastFocusedChild(node) if node.watchChannel &lt;&gt; invalid ' Clone the node when it's reused/update in the TimeGrid it doesn't automatically start playing m.top.selectedItem = node.watchChannel.clone(false) end if end sub sub onChannelFocused(msg) node = msg.getRoSGNode() m.channelFocused = node.focusedChannel end sub 'Returns Focused Item function getItemFocused() if m.itemGrid.isinFocusChain() and isValid(m.itemGrid.itemFocused) return m.itemGrid.content.getChild(m.itemGrid.itemFocused) else if m.genreList.isinFocusChain() and isValid(m.genreList.rowItemFocused) return m.genreList.content.getChild(m.genreList.rowItemFocused[0]).getChild(m.genreList.rowItemFocused[1]) else if m.scheduleGrid.isinFocusChain() and isValid(m.scheduleGrid.itemFocused) return m.scheduleGrid.content.getChild(m.scheduleGrid.itemFocused) end if return invalid end function function onKeyEvent(key as string, press as boolean) as boolean if not press then return false if m.itemGrid.opacity = 1 topGrp = m.itemGrid else topGrp = m.genreList end if searchGrp = m.top.findNode(\"voiceBox\") if key = \"left\" and searchGrp.isinFocusChain() topGrp.setFocus(true) searchGrp.setFocus(false) end if if key = \"options\" if m.options.visible = true m.options.visible = false m.top.removeChild(m.options) optionsClosed() else channelSelected = m.channelFocused itemSelected = m.selectedFavoriteItem if itemSelected &lt;&gt; invalid m.options.selectedFavoriteItem = itemSelected end if if channelSelected &lt;&gt; invalid if channelSelected.type = \"TvChannel\" m.options.selectedFavoriteItem = channelSelected end if end if m.options.visible = true m.top.appendChild(m.options) m.options.setFocus(true) end if return true else if key = \"back\" if m.options.visible = true m.options.visible = false optionsClosed() return true else m.global.sceneManager.callfunc(\"popScene\") m.loadItemsTask.control = \"stop\" return true end if else if key = \"play\" markupGrid = m.top.findNode(\"itemGrid\") itemToPlay = getItemFocused() if itemToPlay &lt;&gt; invalid m.top.quickPlayNode = itemToPlay return true else if itemToPlay &lt;&gt; invalid and itemToPlay.type = \"Photo\" ' Spawn photo player task photoPlayer = CreateObject(\"roSgNode\", \"PhotoDetails\") photoPlayer.items = markupGrid photoPlayer.itemIndex = markupGrid.itemFocused m.global.sceneManager.callfunc(\"pushScene\", photoPlayer) return true end if else if key = \"left\" and topGrp.isinFocusChain() m.top.alphaActive = true topGrp.setFocus(false) alpha = m.alpha.getChild(0).findNode(\"Alphamenu\") alpha.setFocus(true) return true else if key = \"right\" and m.Alpha.isinFocusChain() m.top.alphaActive = false m.Alpha.setFocus(false) m.Alpha.visible = true topGrp.setFocus(true) return true else if key = \"replay\" and topGrp.isinFocusChain() if m.resetGrid = true m.itemGrid.animateToItem = 0 else m.itemGrid.jumpToItem = 0 end if end if if key = \"replay\" m.spinner.visible = true m.loadItemsTask.searchTerm = \"\" m.loadItemsTask.nameStartsWith = \"\" m.voiceBox.text = \"\" m.top.alphaSelected = \"\" m.loadItemsTask.filter = \"All\" m.filter = \"All\" m.data = CreateObject(\"roSGNode\", \"ContentNode\") m.itemGrid.content = m.data loadInitialItems() return true end if return false end function sub updateTitle() m.top.overhangTitle = m.top.parentItem.title if m.filter = \"Favorites\" m.top.overhangTitle = m.top.parentItem.title + \" \" + tr(\"(Favorites)\") end if if m.voiceBox.text &lt;&gt; \"\" m.top.overhangTitle = m.top.parentItem.title + tr(\" (Filtered by \") + m.loadItemsTask.searchTerm + \")\" end if if m.top.alphaSelected &lt;&gt; \"\" m.top.overhangTitle = m.top.parentItem.title + tr(\" (Filtered by \") + m.loadItemsTask.nameStartsWith + \")\" end if if m.view = \"music-artist\" m.top.overhangTitle = \"%s (%s)\".Format(m.top.parentItem.title, tr(\"Artists\")) else if m.view = \"music-album\" m.top.overhangTitle = \"%s (%s)\".Format(m.top.parentItem.title, tr(\"Albums\")) end if if m.options.view = \"Networks\" or m.view = \"Networks\" m.top.overhangTitle = \"%s (%s)\".Format(m.top.parentItem.title, tr(\"Networks\")) end if if m.options.view = \"Studios\" or m.view = \"Studios\" m.top.overhangTitle = \"%s (%s)\".Format(m.top.parentItem.title, tr(\"Studios\")) end if if m.options.view = \"Genres\" or m.view = \"Genres\" m.top.overhangTitle = \"%s (%s)\".Format(m.top.parentItem.title, tr(\"Genres\")) end if actInt = m.itemGrid.itemFocused + 1 if m.showItemCount and m.loadItemsTask.totalRecordCount &gt; 0 and m.options.view &lt;&gt; \"Genres\" and m.view &lt;&gt; \"Genres\" m.top.overhangTitle += \" (\" + tr(\"%1 of %2\").Replace(\"%1\", actInt.toStr()).Replace(\"%2\", m.loadItemsTask.totalRecordCount.toStr()) + \")\" end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_ItemGrid_ItemGridOptions.brs.html":{"id":"components_ItemGrid_ItemGridOptions.brs.html","title":"Source: components/ItemGrid/ItemGridOptions.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/ItemGrid/ItemGridOptions.brs import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/roku_modules/log/LogMixin.brs\" sub init() m.log = log.Logger(\"ItemGridOptions\") m.buttons = m.top.findNode(\"buttons\") m.buttons.buttons = [tr(\"View\"), tr(\"Sort\"), tr(\"Filter\")] m.buttons.selectedIndex = 1 m.buttons.setFocus(true) m.favoriteMenu = m.top.findNode(\"favoriteMenu\") m.selectedFavoriteItem = m.top.findNode(\"selectedFavoriteItem\") m.selectedSortIndex = 0 m.selectedItem = 1 m.menus = [] m.menus.push(m.top.findNode(\"viewMenu\")) m.menus.push(m.top.findNode(\"sortMenu\")) m.menus.push(m.top.findNode(\"filterMenu\")) m.filterOptions = m.top.findNode(\"filterOptions\") m.filterMenu = m.top.findNode(\"filterMenu\") m.filterMenu.observeField(\"itemFocused\", \"onFilterFocusChange\") m.viewNames = [] m.sortNames = [] m.filterNames = [] ' Animation m.fadeAnim = m.top.findNode(\"fadeAnim\") m.fadeOutAnimOpacity = m.top.findNode(\"outOpacity\") m.fadeInAnimOpacity = m.top.findNode(\"inOpacity\") m.showChecklistAnimation = m.top.findNode(\"showChecklistAnimation\") m.hideChecklistAnimation = m.top.findNode(\"hideChecklistAnimation\") m.buttons.observeField(\"focusedIndex\", \"buttonFocusChanged\") m.favoriteMenu.observeField(\"buttonSelected\", \"toggleFavorite\") end sub sub showChecklist() if m.filterOptions.opacity = 0 if m.showChecklistAnimation.state = \"stopped\" m.showChecklistAnimation.control = \"start\" end if end if end sub sub hideChecklist() if m.filterOptions.opacity = 1 if m.hideChecklistAnimation.state = \"stopped\" m.hideChecklistAnimation.control = \"start\" end if end if end sub sub onFilterFocusChange() if not isFilterMenuDataValid() hideChecklist() return end if if m.filterMenu.content.getChild(m.filterMenu.itemFocused).getChildCount() &gt; 0 showChecklist() else hideChecklist() end if m.filterOptions.content = m.filterMenu.content.getChild(m.filterMenu.itemFocused) if isValid(m.filterMenu.content.getChild(m.filterMenu.itemFocused).checkedState) m.filterOptions.checkedState = m.filterMenu.content.getChild(m.filterMenu.itemFocused).checkedState else m.filterOptions.checkedState = [] end if end sub ' Check if data for Filter Menu is valid function isFilterMenuDataValid() as boolean if not isValid(m.filterMenu) or not isValid(m.filterMenu.content) or not isValid(m.filterMenu.itemFocused) return false end if if not isValid(m.filterMenu.content.getChild(m.filterMenu.itemFocused)) return false end if return true end function sub optionsSet() ' Views Tab if m.top.options.views &lt;&gt; invalid viewContent = CreateObject(\"roSGNode\", \"ContentNode\") index = 0 selectedViewIndex = m.selectedViewIndex for each view in m.top.options.views entry = viewContent.CreateChild(\"ContentNode\") entry.title = view.Title m.viewNames.push(view.Name) if (view.selected &lt;&gt; invalid and view.selected = true) or viewContent.Name = m.top.view selectedViewIndex = index end if index = index + 1 end for m.menus[0].content = viewContent m.menus[0].checkedItem = selectedViewIndex end if ' Sort Tab if m.top.options.sort &lt;&gt; invalid sortContent = CreateObject(\"roSGNode\", \"ContentNode\") index = 0 m.selectedSortIndex = 0 for each sortItem in m.top.options.sort entry = sortContent.CreateChild(\"ContentNode\") entry.title = sortItem.Title m.sortNames.push(sortItem.Name) if sortItem.Selected &lt;&gt; invalid and sortItem.Selected = true m.selectedSortIndex = index if sortItem.Ascending &lt;&gt; invalid and sortItem.Ascending = false m.top.sortAscending = 0 else m.top.sortAscending = 1 end if end if index = index + 1 end for m.menus[1].content = sortContent m.menus[1].checkedItem = m.selectedSortIndex if m.top.sortAscending = 1 m.menus[1].focusedCheckedIconUri = m.global.constants.icons.ascending_black m.menus[1].checkedIconUri = m.global.constants.icons.ascending_white else m.menus[1].focusedCheckedIconUri = m.global.constants.icons.descending_black m.menus[1].checkedIconUri = m.global.constants.icons.descending_white end if end if ' Filter Tab if m.top.options.filter &lt;&gt; invalid filterContent = CreateObject(\"roSGNode\", \"ContentNode\") index = 0 m.selectedFilterIndex = 0 for each filterItem in m.top.options.filter entry = filterContent.CreateChild(\"OptionNode\") entry.title = filterItem.Title entry.name = filterItem.Name entry.delimiter = filterItem.Delimiter if isValid(filterItem.options) for each filterItemOption in filterItem.options entryOption = entry.CreateChild(\"ContentNode\") entryOption.title = toString(filterItemOption) end for entry.checkedState = filterItem.checkedState end if m.filterNames.push(filterItem.Name) if filterItem.selected &lt;&gt; invalid and filterItem.selected = true m.selectedFilterIndex = index end if index = index + 1 end for m.menus[2].content = filterContent m.menus[2].checkedItem = m.selectedFilterIndex else filterContent = CreateObject(\"roSGNode\", \"ContentNode\") entry = filterContent.CreateChild(\"ContentNode\") entry.title = \"All\" m.filterNames.push(\"All\") m.menus[2].content = filterContent m.menus[2].checkedItem = 0 end if end sub ' Switch menu shown when button focus changes sub buttonFocusChanged() if m.buttons.focusedIndex = m.selectedItem if m.buttons.hasFocus() m.buttons.setFocus(false) m.menus[m.selectedItem].setFocus(false) m.menus[m.selectedItem].visible = false m.favoriteMenu.setFocus(true) end if end if m.fadeOutAnimOpacity.fieldToInterp = m.menus[m.selectedItem].id + \".opacity\" m.fadeInAnimOpacity.fieldToInterp = m.menus[m.buttons.focusedIndex].id + \".opacity\" m.fadeAnim.control = \"start\" m.selectedItem = m.buttons.focusedIndex end sub sub toggleFavorite() m.favItemsTask = createObject(\"roSGNode\", \"FavoriteItemsTask\") if m.favoriteMenu.iconUri = \"pkg:/images/icons/favorite.png\" m.favoriteMenu.iconUri = \"pkg:/images/icons/favorite_selected.png\" m.favoriteMenu.focusedIconUri = \"pkg:/images/icons/favorite_selected.png\" ' Run the task to actually favorite it via API m.favItemsTask.favTask = \"Favorite\" m.favItemsTask.itemId = m.selectedFavoriteItem.id m.favItemsTask.control = \"RUN\" else m.favoriteMenu.iconUri = \"pkg:/images/icons/favorite.png\" m.favoriteMenu.focusedIconUri = \"pkg:/images/icons/favorite.png\" m.favItemsTask.favTask = \"Unfavorite\" m.favItemsTask.itemId = m.selectedFavoriteItem.id m.favItemsTask.control = \"RUN\" end if ' Make sure we set the Favorite Heart color for the appropriate child setHeartColor(\"#cc3333\") end sub sub setHeartColor(color as string) try for i = 0 to 6 node = m.favoriteMenu.getChild(i) if node &lt;&gt; invalid and node.uri &lt;&gt; invalid and node.uri = \"pkg:/images/icons/favorite_selected.png\" m.favoriteMenu.getChild(i).blendColor = color end if end for catch e m.log.error(\"setHeartColor()\", e.number, e.message) end try end sub sub saveFavoriteItemSelected(msg) data = msg.GetData() m.selectedFavoriteItem = data ' Favorite button if m.selectedFavoriteItem &lt;&gt; invalid if m.selectedFavoriteItem.favorite = true m.favoriteMenu.iconUri = \"pkg:/images/icons/favorite_selected.png\" m.favoriteMenu.focusedIconUri = \"pkg:/images/icons/favorite_selected.png\" ' Make sure we set the Favorite Heart color for the appropriate child setHeartColor(\"#cc3333\") else m.favoriteMenu.iconUri = \"pkg:/images/icons/favorite.png\" m.favoriteMenu.focusedIconUri = \"pkg:/images/icons/favorite.png\" ' Make sure we set the Favorite Heart color for the appropriate child setHeartColor(\"#cc3333\") end if end if end sub function onKeyEvent(key as string, press as boolean) as boolean if key = \"down\" or (key = \"OK\" and m.buttons.hasFocus()) m.buttons.setFocus(false) m.menus[m.selectedItem].setFocus(true) m.menus[m.selectedItem].drawFocusFeedback = true 'If user presses down from button menu, focus first item. If OK, focus checked item if key = \"down\" m.menus[m.selectedItem].jumpToItem = 0 else m.menus[m.selectedItem].jumpToItem = m.menus[m.selectedItem].itemSelected end if return true else if key = \"right\" if not isFilterMenuDataValid() then return false if m.menus[m.selectedItem].isInFocusChain() ' Handle Filter screen if m.selectedItem = 2 ' Selected filter has options, move cursor to it if m.filterMenu.content.getChild(m.filterMenu.itemFocused).getChildCount() &gt; 0 m.menus[m.selectedItem].setFocus(false) m.filterOptions.setFocus(true) return true end if end if end if else if key = \"left\" if m.favoriteMenu.hasFocus() m.favoriteMenu.setFocus(false) m.menus[m.selectedItem].visible = true m.buttons.setFocus(true) end if ' User wants to escape filter options if m.filterOptions.isInFocusChain() m.filterOptions.setFocus(false) m.menus[m.selectedItem].setFocus(true) return true end if else if key = \"OK\" if m.menus[m.selectedItem].isInFocusChain() ' Handle View Screen if m.selectedItem = 0 m.selectedViewIndex = m.menus[0].itemSelected m.top.view = m.viewNames[m.selectedViewIndex] end if ' Handle Sort screen if m.selectedItem = 1 if m.menus[1].itemSelected &lt;&gt; m.selectedSortIndex m.menus[1].focusedCheckedIconUri = m.global.constants.icons.ascending_black m.menus[1].checkedIconUri = m.global.constants.icons.ascending_white m.selectedSortIndex = m.menus[1].itemSelected m.top.sortAscending = true m.top.sortField = m.sortNames[m.selectedSortIndex] else if m.top.sortAscending = true m.top.sortAscending = false m.menus[1].focusedCheckedIconUri = m.global.constants.icons.descending_black m.menus[1].checkedIconUri = m.global.constants.icons.descending_white else m.top.sortAscending = true m.menus[1].focusedCheckedIconUri = m.global.constants.icons.ascending_black m.menus[1].checkedIconUri = m.global.constants.icons.ascending_white end if end if end if ' Handle Filter screen if m.selectedItem = 2 if not isFilterMenuDataValid() then return false ' If filter has no options, select it if m.filterMenu.content.getChild(m.filterMenu.itemFocused).getChildCount() = 0 m.menus[2].checkedItem = m.menus[2].itemSelected m.selectedFilterIndex = m.menus[2].itemSelected m.top.filter = m.filterNames[m.selectedFilterIndex] m.top.filterOptions = {} return true end if ' Selected filter has options, move cursor to it m.filterOptions.setFocus(true) m.menus[m.selectedItem].setFocus(false) return true end if end if ' User pressed OK from inside the filter's options if m.filterOptions.isInFocusChain() selectedOptions = [] for i = 0 to m.filterOptions.checkedState.count() - 1 if m.filterOptions.checkedState[i] selectedValue = toString(m.filterOptions.content.getChild(i).title) selectedOptions.push(selectedValue) end if end for if selectedOptions.Count() &gt; 0 m.menus[2].checkedItem = m.menus[2].itemFocused m.selectedFilterIndex = m.menus[2].itemFocused m.top.filter = m.filterMenu.content.getChild(m.filterMenu.itemFocused).Name newFilter = {} newFilter[m.top.filter] = selectedOptions.join(m.filterMenu.content.getChild(m.filterMenu.itemFocused).delimiter) m.top.filterOptions = newFilter else m.menus[2].checkedItem = 0 m.selectedFilterIndex = 0 m.top.filter = m.filterNames[0] m.top.filterOptions = {} end if m.filterMenu.content.getChild(m.filterMenu.itemFocused).checkedState = m.filterOptions.checkedState return true end if return true else if key = \"back\" or key = \"up\" if key = \"back\" then hideChecklist() m.menus[2].visible = true ' Show Filter contents in case hidden by favorite button if m.menus[m.selectedItem].isInFocusChain() m.buttons.setFocus(true) m.menus[m.selectedItem].drawFocusFeedback = false return true end if else if key = \"options\" hideChecklist() m.menus[2].visible = true ' Show Filter contents in case hidden by favorite button m.menus[m.selectedItem].drawFocusFeedback = false return false end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"source_api_Items.brs.html":{"id":"source_api_Items.brs.html","title":"Source: source/api/Items.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: source/api/Items.brs import \"pkg:/source/api/sdk.bs\" function ItemGetPlaybackInfo(id as string, startTimeTicks = 0 as longinteger) params = { \"UserId\": m.global.session.user.id, \"StartTimeTicks\": startTimeTicks, \"IsPlayback\": true, \"AutoOpenLiveStream\": true, \"MaxStreamingBitrate\": \"140000000\" } resp = APIRequest(Substitute(\"Items/{0}/PlaybackInfo\", id), params) return getJson(resp) end function function ItemPostPlaybackInfo(id as string, mediaSourceId = \"\" as string, audioTrackIndex = -1 as integer, subtitleTrackIndex = -1 as integer, startTimeTicks = 0 as longinteger) body = { \"DeviceProfile\": getDeviceProfile() } params = { \"UserId\": m.global.session.user.id, \"StartTimeTicks\": startTimeTicks, \"IsPlayback\": true, \"AutoOpenLiveStream\": true, \"MaxStreamingBitrate\": \"140000000\", \"MaxStaticBitrate\": \"140000000\", \"SubtitleStreamIndex\": subtitleTrackIndex } if mediaSourceId &lt;&gt; \"\" then params.MediaSourceId = mediaSourceId if audioTrackIndex &gt; -1 then params.AudioStreamIndex = audioTrackIndex req = APIRequest(Substitute(\"Items/{0}/PlaybackInfo\", id), params) req.SetRequest(\"POST\") return postJson(req, FormatJson(body)) end function ' Search across all libraries function searchMedia(query as string) if query &lt;&gt; \"\" data = api.users.GetItemsByQuery(m.global.session.user.id, { \"searchTerm\": query, \"IncludePeople\": true, \"IncludeMedia\": true, \"IncludeShows\": true, \"IncludeGenres\": true, \"IncludeStudios\": true, \"IncludeArtists\": true, \"IncludeItemTypes\": \"LiveTvChannel,Movie,BoxSet,Series,Episode,Video,Person,Audio,MusicAlbum,MusicArtist,Playlist\", \"EnableTotalRecordCount\": false, \"ImageTypeLimit\": 1, \"Recursive\": true, \"limit\": 100 }) results = [] for each item in data.Items tmp = CreateObject(\"roSGNode\", \"SearchData\") tmp.image = PosterImage(item.id) tmp.json = item results.push(tmp) end for data.Items = results return data end if return [] end function ' MetaData about an item function ItemMetaData(id as string) url = Substitute(\"Users/{0}/Items/{1}\", m.global.session.user.id, id) resp = APIRequest(url) data = getJson(resp) if data = invalid then return invalid imgParams = {} if data.type &lt;&gt; \"Audio\" if data.UserData &lt;&gt; invalid and data.UserData.PlayedPercentage &lt;&gt; invalid param = { \"PercentPlayed\": data.UserData.PlayedPercentage } imgParams.Append(param) end if end if if data.type = \"Movie\" or data.type = \"MusicVideo\" tmp = CreateObject(\"roSGNode\", \"MovieData\") tmp.image = PosterImage(data.id, imgParams) tmp.json = data return tmp else if data.type = \"Series\" tmp = CreateObject(\"roSGNode\", \"SeriesData\") tmp.image = PosterImage(data.id) tmp.json = data return tmp else if data.type = \"Episode\" ' param = { \"AddPlayedIndicator\": data.UserData.Played } ' imgParams.Append(param) tmp = CreateObject(\"roSGNode\", \"TVEpisodeData\") tmp.image = PosterImage(data.id, imgParams) tmp.json = data return tmp else if data.type = \"BoxSet\" or data.type = \"Playlist\" tmp = CreateObject(\"roSGNode\", \"CollectionData\") tmp.image = PosterImage(data.id, imgParams) tmp.json = data return tmp else if data.type = \"Season\" tmp = CreateObject(\"roSGNode\", \"TVSeasonData\") tmp.image = PosterImage(data.id) tmp.json = data return tmp else if data.type = \"Video\" tmp = CreateObject(\"roSGNode\", \"VideoData\") tmp.image = PosterImage(data.id) tmp.json = data return tmp else if data.type = \"Trailer\" tmp = CreateObject(\"roSGNode\", \"VideoData\") tmp.json = data return tmp else if data.type = \"TvChannel\" or data.type = \"Program\" tmp = CreateObject(\"roSGNode\", \"ChannelData\") tmp.image = PosterImage(data.id) tmp.isFavorite = data.UserData.isFavorite tmp.json = data return tmp else if data.type = \"Person\" tmp = CreateObject(\"roSGNode\", \"PersonData\") tmp.image = PosterImage(data.id, { \"MaxWidth\": 300, \"MaxHeight\": 450 }) tmp.json = data return tmp else if data.type = \"MusicArtist\" ' User clicked on an artist and wants to see the list of their albums tmp = CreateObject(\"roSGNode\", \"MusicArtistData\") tmp.image = PosterImage(data.id) tmp.json = data return tmp else if data.type = \"MusicAlbum\" ' User clicked on an album and wants to see the list of songs tmp = CreateObject(\"roSGNode\", \"MusicAlbumSongListData\") tmp.image = PosterImage(data.id) tmp.json = data return tmp else if data.type = \"Audio\" ' User clicked on a song and wants it to play tmp = CreateObject(\"roSGNode\", \"MusicSongData\") ' Try using song's parent for poster image tmp.image = PosterImage(data.ParentId, { \"MaxWidth\": 500, \"MaxHeight\": 500 }) ' Song's parent poster image is no good, try using the song's poster image if tmp.image = invalid tmp.image = PosterImage(data.id, { \"MaxWidth\": 500, \"MaxHeight\": 500 }) end if tmp.json = data return tmp else if data.type = \"Recording\" ' We know it's \"Recording\", but we don't do any special preprocessing ' for this data type at the moment, so just return the json. return data else print \"Items.brs::ItemMetaData processed unhandled type: \" data.type ' Return json if we don't know what it is return data end if end function ' Music Artist Data function ArtistOverview(name as string) req = createObject(\"roUrlTransfer\") url = Substitute(\"Artists/{0}\", req.escape(name)) resp = APIRequest(url) data = getJson(resp) if data = invalid then return invalid return data.overview end function ' Get list of albums belonging to an artist function MusicAlbumList(id as string) url = Substitute(\"Users/{0}/Items\", m.global.session.user.id) resp = APIRequest(url, { \"AlbumArtistIds\": id, \"includeitemtypes\": \"MusicAlbum\", \"sortBy\": \"SortName\", \"Recursive\": true }) data = getJson(resp) results = [] for each item in data.Items tmp = CreateObject(\"roSGNode\", \"MusicAlbumData\") tmp.image = PosterImage(item.id) tmp.json = item results.push(tmp) end for data.Items = results return data end function ' Get list of albums an artist appears on function AppearsOnList(id as string) url = Substitute(\"Users/{0}/Items\", m.global.session.user.id) resp = APIRequest(url, { \"ContributingArtistIds\": id, \"ExcludeItemIds\": id, \"includeitemtypes\": \"MusicAlbum\", \"sortBy\": \"PremiereDate,ProductionYear,SortName\", \"SortOrder\": \"Descending\", \"Recursive\": true }) data = getJson(resp) results = [] for each item in data.Items tmp = CreateObject(\"roSGNode\", \"MusicAlbumData\") tmp.image = PosterImage(item.id) tmp.json = item results.push(tmp) end for data.Items = results return data end function ' Get list of songs belonging to an artist function GetSongsByArtist(id as string, params = {} as object) url = Substitute(\"Users/{0}/Items\", m.global.session.user.id) paramArray = { \"AlbumArtistIds\": id, \"includeitemtypes\": \"Audio\", \"sortBy\": \"SortName\", \"Recursive\": true } ' overwrite defaults with the params provided for each param in params paramArray.AddReplace(param, params[param]) end for resp = APIRequest(url, paramArray) data = getJson(resp) results = [] if data = invalid then return invalid if data.Items = invalid then return invalid if data.Items.Count() = 0 then return invalid for each item in data.Items tmp = CreateObject(\"roSGNode\", \"MusicAlbumData\") tmp.image = PosterImage(item.id) tmp.json = item results.push(tmp) end for data.Items = results return data end function ' Get Items that are under the provided item function PlaylistItemList(id as string) url = Substitute(\"Playlists/{0}/Items\", id) resp = APIRequest(url, { \"UserId\": m.global.session.user.id }) results = [] data = getJson(resp) if data = invalid then return invalid if data.Items = invalid then return invalid if data.Items.Count() = 0 then return invalid for each item in data.Items tmp = CreateObject(\"roSGNode\", \"PlaylistData\") tmp.image = PosterImage(item.id) tmp.json = item results.push(tmp) end for data.Items = results return data end function ' Get Songs that are on an Album function MusicSongList(id as string) url = Substitute(\"Users/{0}/Items\", m.global.session.user.id, id) resp = APIRequest(url, { \"UserId\": m.global.session.user.id, \"parentId\": id, \"includeitemtypes\": \"Audio\", \"sortBy\": \"SortName\" }) results = [] data = getJson(resp) if data = invalid then return invalid if data.Items = invalid then return invalid if data.Items.Count() = 0 then return invalid for each item in data.Items tmp = CreateObject(\"roSGNode\", \"MusicSongData\") tmp.image = PosterImage(item.id) tmp.json = item results.push(tmp) end for data.Items = results return data end function ' Get Songs that are on an Album function AudioItem(id as string) url = Substitute(\"Users/{0}/Items/{1}\", m.global.session.user.id, id) resp = APIRequest(url, { \"UserId\": m.global.session.user.id, \"includeitemtypes\": \"Audio\", \"sortBy\": \"SortName\" }) return getJson(resp) end function ' Get Instant Mix based on item function CreateInstantMix(id as string) url = Substitute(\"/Items/{0}/InstantMix\", id) resp = APIRequest(url, { \"UserId\": m.global.session.user.id, \"Limit\": 201 }) return getJson(resp) end function ' Get Instant Mix based on item function CreateArtistMix(id as string) url = Substitute(\"Users/{0}/Items\", m.global.session.user.id) resp = APIRequest(url, { \"ArtistIds\": id, \"Recursive\": \"true\", \"MediaTypes\": \"Audio\", \"Filters\": \"IsNotFolder\", \"SortBy\": \"SortName\", \"Limit\": 300, \"Fields\": \"Chapters\", \"ExcludeLocationTypes\": \"Virtual\", \"EnableTotalRecordCount\": false, \"CollapseBoxSetItems\": false }) return getJson(resp) end function ' Get Intro Videos for an item function GetIntroVideos(id as string) url = Substitute(\"Users/{0}/Items/{1}/Intros\", m.global.session.user.id, id) resp = APIRequest(url, { \"UserId\": m.global.session.user.id }) return getJson(resp) end function function AudioStream(id as string) songData = AudioItem(id) if songData &lt;&gt; invalid content = createObject(\"RoSGNode\", \"ContentNode\") if songData.title &lt;&gt; invalid content.title = songData.title end if playbackInfo = ItemPostPlaybackInfo(songData.id, songData.mediaSources[0].id) if playbackInfo &lt;&gt; invalid content.id = playbackInfo.PlaySessionId if useTranscodeAudioStream(playbackInfo) ' Transcode the audio content.url = buildURL(playbackInfo.mediaSources[0].TranscodingURL) else ' Direct Stream the audio params = { \"Static\": \"true\", \"Container\": songData.mediaSources[0].container, \"MediaSourceId\": songData.mediaSources[0].id } content.streamformat = songData.mediaSources[0].container content.url = buildURL(Substitute(\"Audio/{0}/stream\", songData.id), params) end if else return invalid end if return content else return invalid end if end function function useTranscodeAudioStream(playbackInfo) return playbackInfo.mediaSources[0] &lt;&gt; invalid and playbackInfo.mediaSources[0].TranscodingURL &lt;&gt; invalid end function function BackdropImage(id as string) imgParams = { \"maxHeight\": \"720\", \"maxWidth\": \"1280\" } return ImageURL(id, \"Backdrop\", imgParams) end function ' Seasons for a TV Show function TVSeasons(id as string) as dynamic url = Substitute(\"Shows/{0}/Seasons\", id) resp = APIRequest(url, { \"UserId\": m.global.session.user.id }) data = getJson(resp) ' validate data if data = invalid or data.Items = invalid then return invalid results = [] for each item in data.Items imgParams = { \"AddPlayedIndicator\": item.UserData.Played } tmp = CreateObject(\"roSGNode\", \"TVSeasonData\") tmp.image = PosterImage(item.id, imgParams) tmp.json = item results.push(tmp) end for data.Items = results return data end function ' Returns a list of TV Shows for a given TV Show and season ' Accepts strings for the TV Show Id and the season Id function TVEpisodes(showId as string, seasonId as string) as dynamic ' Get and validate data data = api.shows.GetEpisodes(showId, { \"seasonId\": seasonId, \"UserId\": m.global.session.user.id, \"fields\": \"MediaStreams,MediaSources\" }) if data = invalid or data.Items = invalid then return invalid results = [] for each item in data.Items tmp = CreateObject(\"roSGNode\", \"TVEpisodeData\") tmp.image = PosterImage(item.id, { \"maxWidth\": 400, \"maxheight\": 250 }) if isValid(tmp.image) tmp.image.posterDisplayMode = \"scaleToZoom\" end if tmp.json = item tmpMetaData = ItemMetaData(item.id) ' validate meta data if isValid(tmpMetaData) and isValid(tmpMetaData.overview) tmp.overview = tmpMetaData.overview end if results.push(tmp) end for data.Items = results return data end function ' Returns a list of extra features for a TV Show season ' Accepts a string that is a TV Show season id function TVSeasonExtras(seasonId as string) as dynamic ' Get and validate TV extra features data data = api.users.GetSpecialFeatures(m.global.session.user.id, seasonId) if not isValid(data) then return invalid results = [] for each item in data tmp = CreateObject(\"roSGNode\", \"TVEpisodeData\") tmp.image = PosterImage(item.id, { \"maxWidth\": 400, \"maxheight\": 250 }) if isValid(tmp.image) tmp.image.posterDisplayMode = \"scaleToZoom\" end if tmp.json = item ' Force item type to Video so episode auto queue is not attempted tmp.type = \"Video\" tmpMetaData = ItemMetaData(item.id) ' Validate meta data if isValid(tmpMetaData) and isValid(tmpMetaData.overview) tmp.overview = tmpMetaData.overview end if results.push(tmp) end for ' Build that data format that the TVEpisodeRow expects return { Items: results } end function function TVEpisodeShuffleList(show_id as string) url = Substitute(\"Shows/{0}/Episodes\", show_id) resp = APIRequest(url, { \"UserId\": m.global.session.user.id, \"Limit\": 200, \"sortBy\": \"Random\" }) data = getJson(resp) results = [] for each item in data.Items tmp = CreateObject(\"roSGNode\", \"TVEpisodeData\") tmp.json = item results.push(tmp) end for data.Items = results return data end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_JFButton.brs.html":{"id":"components_JFButton.brs.html","title":"Source: components/JFButton.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/JFButton.brs sub init() m.top.observeFieldScoped(\"text\", \"onTextChanged\") m.top.iconUri = \"\" m.top.focusedIconUri = \"\" m.top.showFocusFootprint = true m.top.minWidth = 0 end sub ' ' Whenever the text changes, pad both sides with whitespace so we can center the button text ' sub onTextChanged() addSpaceAfter = true minChars = m.top.minChars if minChars = invalid then minChars = 50 while m.top.text.Len() &lt; minChars if addSpaceAfter m.top.text = m.top.text + Chr(160) else m.top.text = Chr(160) + m.top.text end if addSpaceAfter = addSpaceAfter = false end while end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_Buttons_JFButtons.brs.html":{"id":"components_Buttons_JFButtons.brs.html","title":"Source: components/Buttons/JFButtons.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/Buttons/JFButtons.brs sub init() m.top.focusable = true m.menubg = m.top.findNode(\"menubg\") m.focusRing = m.top.findNode(\"focus\") m.buttonGroup = m.top.findNode(\"buttonGroup\") m.focusAnim = m.top.findNode(\"moveFocusAnimation\") m.focusAnimTranslation = m.top.findNode(\"focusLocation\") m.focusAnimWidth = m.top.findNode(\"focusWidth\") m.focusAnimHeight = m.top.findNode(\"focusHeight\") ' Set button color to global m.focusRing.color = m.global.constants.colors.button m.buttonCount = 0 m.selectedFocusedIndex = 0 m.textSizeTask = createObject(\"roSGNode\", \"TextSizeTask\") m.top.observeField(\"focusedChild\", \"focusChanged\") m.top.enableRenderTracking = true m.top.observeField(\"renderTracking\", \"renderChanged\") end sub ' ' When Selected Index set, ensure it is the one Focused sub selectedIndexChanged() m.selectedFocusedIndex = m.top.selectedIndex end sub ' ' When options are fully displayed, set focus and selected option sub renderChanged() if m.top.renderTracking = \"full\" highlightSelected(m.selectedFocusedIndex, false) m.top.setfocus(true) end if end sub sub updateButtons() m.textSizeTask.fontsize = 40 m.textSizeTask.text = m.top.buttons m.textSizeTask.name = m.buttonCount m.textSizeTask.observeField(\"width\", \"showButtons\") m.textSizeTask.control = \"RUN\" end sub sub showButtons() totalWidth = 110 ' track for menu background width - start with side padding for i = 0 to m.top.buttons.count() - 1 m.buttonCount = m.buttonCount + 1 l = m.buttonGroup.createChild(\"Label\") l.text = m.top.buttons[i] l.font.size = 40 l.translation = [0, 10] l.height = m.textSizeTask.height l.width = m.textSizeTask.width[i] + 50 l.horizAlign = \"center\" l.vertAlign = \"center\" totalWidth = totalWidth + l.width + 45 end for m.menubg.width = totalWidth m.menubg.height = m.textSizeTask.height + 40 end sub ' Highlight selected menu option sub highlightSelected(index as integer, animate = true) val = m.buttonGroup.getChild(index) rect = val.ancestorBoundingRect(m.top) if animate = true m.focusAnimTranslation.keyValue = [m.focusRing.translation, [rect.x - 25, rect.y - 30]] m.focusAnimWidth.keyValue = [m.focusRing.width, val.width + 50] m.focusAnimHeight.keyValue = [m.focusRing.height, val.height + 60] m.focusAnim.control = \"start\" else m.focusRing.translation = [rect.x - 25, rect.y - 30] m.focusRing.width = val.width + 50 m.focusRing.height = val.height + 60 end if end sub ' Change opacity of the highlighted menu item based on focus sub focusChanged() if m.top.isInFocusChain() m.focusRing.opacity = 1 else m.focusRing.opacity = 0.6 end if end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false if key = \"left\" if m.selectedFocusedIndex &gt; 0 then m.selectedFocusedIndex = m.selectedFocusedIndex - 1 highlightSelected(m.selectedFocusedIndex) m.top.focusedIndex = m.selectedFocusedIndex return true else if key = \"right\" if m.selectedFocusedIndex &lt; m.buttonCount - 1 then m.selectedFocusedIndex = m.selectedFocusedIndex + 1 highlightSelected(m.selectedFocusedIndex) m.top.focusedIndex = m.selectedFocusedIndex return true else if key = \"OK\" m.top.selectedIndex = m.selectedFocusedIndex return true end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_JFGroup.brs.html":{"id":"components_JFGroup.brs.html","title":"Source: components/JFGroup.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/JFGroup.brs sub init() end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_JFMessageDialog.brs.html":{"id":"components_JFMessageDialog.brs.html","title":"Source: components/JFMessageDialog.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/JFMessageDialog.brs sub init() options = m.top.findNode(\"optionList\") options.focusBitmapBlendColor = \"0x0cb0e8\" options.color = \"0xffffff\" options.focusedColor = \"0xffffff\" options.setFocus(true) end sub function onKeyEvent(key as string, press as boolean) as boolean if key = \"back\" m.top.backPressed = true return true end if return false end function sub updateOptions() for each item in m.top.options row = CreateObject(\"roSGNode\", \"ContentNode\") row.title = item m.top.findNode(\"content\").appendChild(row) end for redraw() end sub sub updateMessage() message = m.top.findNode(\"messageText\") message.text = m.top.message redraw() end sub sub redraw() boxWidth = 900 border = 40 itemSpacing = 40 optionHeight = 60 maxRows = 9 bg = m.top.findNode(\"dialogBackground\") text = m.top.findNode(\"messageText\") options = m.top.findNode(\"optionList\") fontHeight = m.top.fontHeight fontWidth = m.top.fontWidth if text.text.len() &gt; 0 textWidth = boxWidth - (border * 2) text.width = textWidth text.numLines = int(fontWidth / textWidth) + 1 text.translation = [border, border] textHeight = (fontHeight * text.numLines) else textHeight = 0 itemSpacing = border end if options.translation = [border * 2, textHeight + itemSpacing] options.itemSize = [boxWidth - (border * 4), optionHeight] options.itemSpacing = \"[0,20]\" options.numRows = m.top.options.count() if options.numRows &gt; maxRows options.numRows = maxRows options.wrapDividerHeight = 0 options.vertFocusAnimationStyle = \"fixedFocusWrap\" end if boxHeight = options.translation[1] + (options.itemSize[1] * options.numRows) + (options.itemSpacing[1] * (options.NumRows - 1)) + border bg.width = boxWidth bg.height = boxHeight m.top.translation = [(1920 - boxWidth) / 2, (1080 - boxHeight) / 2] end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_JFOverhang.brs.html":{"id":"components_JFOverhang.brs.html","title":"Source: components/JFOverhang.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/JFOverhang.brs import \"pkg:/source/utils/config.brs\" sub init() m.top.id = \"overhang\" ' hide seperators till they're needed m.leftSeperator = m.top.findNode(\"overlayLeftSeperator\") m.leftSeperator.visible = \"false\" m.rightSeperator = m.top.findNode(\"overlayRightSeperator\") ' set font sizes m.optionText = m.top.findNode(\"overlayOptionsText\") m.optionText.font.size = 20 m.optionStar = m.top.findNode(\"overlayOptionsStar\") m.optionStar.font.size = 58 ' save node references m.title = m.top.findNode(\"overlayTitle\") m.overlayRightGroup = m.top.findNode(\"overlayRightGroup\") m.overlayTimeGroup = m.top.findNode(\"overlayTimeGroup\") m.slideDownAnimation = m.top.findNode(\"slideDown\") m.slideUpAnimation = m.top.findNode(\"slideUp\") ' show clock based on user setting m.hideClock = m.global.session.user.settings[\"ui.design.hideclock\"] if not m.hideClock ' save node references m.overlayHours = m.top.findNode(\"overlayHours\") m.overlayMinutes = m.top.findNode(\"overlayMinutes\") m.overlayMeridian = m.top.findNode(\"overlayMeridian\") m.overlayMeridian.font.size = 20 m.currentTimeTimer = m.top.findNode(\"currentTimeTimer\") ' display current time updateTime() ' start timer to update clock every minute m.currentTimeTimer.control = \"start\" m.currentTimeTimer.ObserveField(\"fire\", \"updateTime\") end if setClockVisibility() end sub sub onVisibleChange() if m.top.disableMoveAnimation m.top.translation = [0, 0] return end if if m.top.isVisible m.slideDownAnimation.control = \"start\" return end if m.slideUpAnimation.control = \"start\" end sub sub updateTitle() if m.top.title &lt;&gt; \"\" m.leftSeperator.visible = \"true\" else m.leftSeperator.visible = \"false\" end if m.title.text = m.top.title if not m.hideClock resetTime() end if end sub sub setClockVisibility() if m.hideClock m.overlayRightGroup.removeChild(m.overlayTimeGroup) end if end sub sub setRightSeperatorVisibility() if m.hideClock m.top.removeChild(m.rightSeperator) return end if if m.top.currentUser &lt;&gt; \"\" m.rightSeperator.visible = \"true\" else m.rightSeperator.visible = \"false\" end if end sub sub updateUser() setRightSeperatorVisibility() user = m.top.findNode(\"overlayCurrentUser\") user.text = m.top.currentUser end sub sub updateTime() currentTime = CreateObject(\"roDateTime\") currentTime.ToLocalTime() m.currentTimeTimer.duration = 60 - currentTime.GetSeconds() m.currentHours = currentTime.GetHours() m.currentMinutes = currentTime.GetMinutes() updateTimeDisplay() end sub sub resetTime() if m.hideClock then return m.currentTimeTimer.control = \"stop\" m.currentTimeTimer.control = \"start\" updateTime() end sub sub updateTimeDisplay() if m.global.device.clockFormat = \"24h\" m.overlayMeridian.text = \"\" if m.currentHours &lt; 10 m.overlayHours.text = \"0\" + StrI(m.currentHours).trim() else m.overlayHours.text = m.currentHours end if else if m.currentHours &lt; 12 m.overlayMeridian.text = \"AM\" if m.currentHours = 0 m.overlayHours.text = \"12\" else m.overlayHours.text = m.currentHours end if else m.overlayMeridian.text = \"PM\" if m.currentHours = 12 m.overlayHours.text = \"12\" else m.overlayHours.text = m.currentHours - 12 end if end if end if if m.currentMinutes &lt; 10 m.overlayMinutes.text = \"0\" + StrI(m.currentMinutes).trim() else m.overlayMinutes.text = m.currentMinutes end if end sub sub updateOptions() if m.top.showOptions = true m.optionText.visible = true m.optionStar.visible = true else m.optionText.visible = false m.optionStar.visible = false end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_JFScene.brs.html":{"id":"components_JFScene.brs.html","title":"Source: components/JFScene.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/JFScene.brs import \"pkg:/source/utils/misc.brs\" sub init() m.top.backgroundColor = \"#262626\" '\"#101010\" m.top.backgroundURI = \"\" end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false if key = \"back\" m.global.sceneManager.callFunc(\"popScene\") return true else if key = \"options\" group = m.global.sceneManager.callFunc(\"getActiveScene\") if isValid(group) and isValid(group.optionsAvailable) and group.optionsAvailable group.lastFocus = group.focusedChild panel = group.findNode(\"options\") panel.visible = true panel.findNode(\"panelList\").setFocus(true) end if return true end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_JFScreen.brs.html":{"id":"components_JFScreen.brs.html","title":"Source: components/JFScreen.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/JFScreen.brs import \"pkg:/source/roku_modules/log/LogMixin.brs\" sub init() ' initialize the log manager. second param sets log output: ' 1 error, 2 warn, 3 info, 4 verbose, 5 debug _rLog = log_initializeLogManager([\"log_PrintTransport\"], 5) 'bs:disable-line end sub ' Function called when the screen is displayed by the screen manager ' It is expected that screens override this function to handle focus ' managmenet and any other actions required on screen shown sub OnScreenShown() if m.top.lastFocus &lt;&gt; invalid m.top.lastFocus.setFocus(true) else m.top.setFocus(true) end if end sub ' Function called when the screen is hidden by the screen manager ' It is expected that screens override this function if required, ' to handle focus any actions required on the screen being hidden sub OnScreenHidden() end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_config_JFServer.brs.html":{"id":"components_config_JFServer.brs.html","title":"Source: components/config/JFServer.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/config/JFServer.brs sub init() as void m.poster = m.top.findNode(\"poster\") m.name = m.top.findNode(\"name\") m.baseUrl = m.top.findNode(\"baseUrl\") m.labels = m.top.findNode(\"labels\") setTextColor(0) end sub sub itemContentChanged() as void server = m.top.itemContent m.poster.uri = server.iconUrl m.name.text = server.name m.baseUrl.text = server.baseUrl end sub sub onFocusPercentChange(event) setTextColor(event.getData()) end sub sub setTextColor(percentFocused) white = \"0xffffffff\" black = \"0x00000099\" if percentFocused &gt; .4 color = black else color = white end if children = m.labels.getChildren(-1, 0) for each child in children child.color = color end for end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_JFVideo.brs.html":{"id":"components_JFVideo.brs.html","title":"Source: components/JFVideo.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/JFVideo.brs import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/utils/config.brs\" sub init() m.playbackTimer = m.top.findNode(\"playbackTimer\") m.bufferCheckTimer = m.top.findNode(\"bufferCheckTimer\") m.top.observeField(\"state\", \"onState\") m.top.observeField(\"content\", \"onContentChange\") m.playbackTimer.observeField(\"fire\", \"ReportPlayback\") m.bufferPercentage = 0 ' Track whether content is being loaded m.playReported = false m.top.transcodeReasons = [] m.bufferCheckTimer.duration = 30 if m.global.session.user.settings[\"ui.design.hideclock\"] = true clockNode = findNodeBySubtype(m.top, \"clock\") if clockNode[0] &lt;&gt; invalid then clockNode[0].parent.removeChild(clockNode[0].node) end if 'Play Next Episode button m.nextEpisodeButton = m.top.findNode(\"nextEpisode\") m.nextEpisodeButton.text = tr(\"Next Episode\") m.nextEpisodeButton.setFocus(false) m.nextupbuttonseconds = m.global.session.user.settings[\"playback.nextupbuttonseconds\"].ToInt() m.showNextEpisodeButtonAnimation = m.top.findNode(\"showNextEpisodeButton\") m.hideNextEpisodeButtonAnimation = m.top.findNode(\"hideNextEpisodeButton\") m.checkedForNextEpisode = false m.getNextEpisodeTask = createObject(\"roSGNode\", \"GetNextEpisodeTask\") m.getNextEpisodeTask.observeField(\"nextEpisodeData\", \"onNextEpisodeDataLoaded\") m.top.observeField(\"allowCaptions\", \"onAllowCaptionsChange\") end sub sub onAllowCaptionsChange() if not m.top.allowCaptions then return m.captionGroup = m.top.findNode(\"captionGroup\") m.captionGroup.createchildren(9, \"LayoutGroup\") m.captionTask = createObject(\"roSGNode\", \"captionTask\") m.captionTask.observeField(\"currentCaption\", \"updateCaption\") m.captionTask.observeField(\"useThis\", \"checkCaptionMode\") m.top.observeField(\"currentSubtitleTrack\", \"loadCaption\") m.top.observeField(\"globalCaptionMode\", \"toggleCaption\") if m.global.session.user.settings[\"playback.subs.custom\"] = false m.top.suppressCaptions = false else m.top.suppressCaptions = true toggleCaption() end if end sub sub loadCaption() if m.top.suppressCaptions m.captionTask.url = m.top.currentSubtitleTrack end if end sub sub toggleCaption() m.captionTask.playerState = m.top.state + m.top.globalCaptionMode if LCase(m.top.globalCaptionMode) = \"on\" m.captionTask.playerState = m.top.state + m.top.globalCaptionMode + \"w\" m.captionGroup.visible = true else m.captionGroup.visible = false end if end sub sub updateCaption () m.captionGroup.removeChildrenIndex(m.captionGroup.getChildCount(), 0) m.captionGroup.appendChildren(m.captionTask.currentCaption) end sub ' Event handler for when video content field changes sub onContentChange() if not isValid(m.top.content) then return m.top.observeField(\"position\", \"onPositionChanged\") end sub sub onNextEpisodeDataLoaded() m.checkedForNextEpisode = true m.top.observeField(\"position\", \"onPositionChanged\") end sub ' ' Runs Next Episode button animation and sets focus to button sub showNextEpisodeButton() if m.global.session.user.configuration.EnableNextEpisodeAutoPlay and not m.nextEpisodeButton.visible m.showNextEpisodeButtonAnimation.control = \"start\" m.nextEpisodeButton.setFocus(true) m.nextEpisodeButton.visible = true end if end sub ' 'Update count down text sub updateCount() nextEpisodeCountdown = Int(m.top.duration - m.top.position) if nextEpisodeCountdown &lt; 0 nextEpisodeCountdown = 0 end if m.nextEpisodeButton.text = tr(\"Next Episode\") + \" \" + nextEpisodeCountdown.toStr() end sub ' ' Runs hide Next Episode button animation and sets focus back to video sub hideNextEpisodeButton() m.hideNextEpisodeButtonAnimation.control = \"start\" m.nextEpisodeButton.setFocus(false) m.top.setFocus(true) end sub ' Checks if we need to display the Next Episode button sub checkTimeToDisplayNextEpisode() if m.top.content.contenttype &lt;&gt; 4 then return if m.nextupbuttonseconds = 0 then return if int(m.top.position) &gt;= (m.top.duration - m.nextupbuttonseconds) showNextEpisodeButton() updateCount() return end if if m.nextEpisodeButton.visible or m.nextEpisodeButton.hasFocus() m.nextEpisodeButton.visible = false m.nextEpisodeButton.setFocus(false) end if end sub ' When Video Player state changes sub onPositionChanged() if isValid(m.captionTask) m.captionTask.currentPos = Int(m.top.position * 1000) end if ' Check if dialog is open m.dialog = m.top.getScene().findNode(\"dialogBackground\") if not isValid(m.dialog) checkTimeToDisplayNextEpisode() end if end sub ' ' When Video Player state changes sub onState(msg) if isValid(m.captionTask) m.captionTask.playerState = m.top.state + m.top.globalCaptionMode end if ' When buffering, start timer to monitor buffering process if m.top.state = \"buffering\" and m.bufferCheckTimer &lt;&gt; invalid ' start timer m.bufferCheckTimer.control = \"start\" m.bufferCheckTimer.ObserveField(\"fire\", \"bufferCheck\") else if m.top.state = \"error\" if not m.playReported and m.top.transcodeAvailable m.top.retryWithTranscoding = true ' If playback was not reported, retry with transcoding else ' If an error was encountered, Display dialog dialog = createObject(\"roSGNode\", \"PlaybackDialog\") dialog.title = tr(\"Error During Playback\") dialog.buttons = [tr(\"OK\")] dialog.message = tr(\"An error was encountered while playing this item.\") m.top.getScene().dialog = dialog end if ' Stop playback and exit player m.top.control = \"stop\" m.top.backPressed = true else if m.top.state = \"playing\" ' Check if next episde is available if isValid(m.top.showID) if m.top.showID &lt;&gt; \"\" and not m.checkedForNextEpisode and m.top.content.contenttype = 4 m.getNextEpisodeTask.showID = m.top.showID m.getNextEpisodeTask.videoID = m.top.id m.getNextEpisodeTask.control = \"RUN\" end if end if if m.playReported = false ReportPlayback(\"start\") m.playReported = true else ReportPlayback() end if m.playbackTimer.control = \"start\" else if m.top.state = \"paused\" m.playbackTimer.control = \"stop\" ReportPlayback() else if m.top.state = \"stopped\" m.playbackTimer.control = \"stop\" ReportPlayback(\"stop\") m.playReported = false end if end sub ' ' Report playback to server sub ReportPlayback(state = \"update\" as string) if m.top.position = invalid then return params = { \"ItemId\": m.top.id, \"PlaySessionId\": m.top.PlaySessionId, \"PositionTicks\": int(m.top.position) * 10000000&amp;, 'Ensure a LongInteger is used \"IsPaused\": (m.top.state = \"paused\") } if m.top.content.live params.append({ \"MediaSourceId\": m.top.transcodeParams.MediaSourceId, \"LiveStreamId\": m.top.transcodeParams.LiveStreamId }) m.bufferCheckTimer.duration = 30 end if ' Report playstate via worker task playstateTask = m.global.playstateTask playstateTask.setFields({ status: state, params: params }) playstateTask.control = \"RUN\" end sub ' ' Check the the buffering has not hung sub bufferCheck(msg) if m.top.state &lt;&gt; \"buffering\" ' If video is not buffering, stop timer m.bufferCheckTimer.control = \"stop\" m.bufferCheckTimer.unobserveField(\"fire\") return end if if m.top.bufferingStatus &lt;&gt; invalid ' Check that the buffering percentage is increasing if m.top.bufferingStatus[\"percentage\"] &gt; m.bufferPercentage m.bufferPercentage = m.top.bufferingStatus[\"percentage\"] else if m.top.content.live = true m.top.callFunc(\"refresh\") else ' If buffering has stopped Display dialog dialog = createObject(\"roSGNode\", \"PlaybackDialog\") dialog.title = tr(\"Error Retrieving Content\") dialog.buttons = [tr(\"OK\")] dialog.message = tr(\"There was an error retrieving the data for this item from the server.\") m.top.getScene().dialog = dialog ' Stop playback and exit player m.top.control = \"stop\" m.top.backPressed = true end if end if end sub function onKeyEvent(key as string, press as boolean) as boolean if key = \"OK\" and m.nextEpisodeButton.hasfocus() and not m.top.trickPlayBar.visible m.top.state = \"finished\" hideNextEpisodeButton() return true else 'Hide Next Episode Button if m.nextEpisodeButton.visible or m.nextEpisodeButton.hasFocus() m.nextEpisodeButton.visible = false m.nextEpisodeButton.setFocus(false) m.top.setFocus(true) end if end if if not press then return false if key = \"down\" m.top.selectSubtitlePressed = true return true else if key = \"up\" m.top.selectPlaybackInfoPressed = true return true else if key = \"OK\" ' OK will play/pause depending on current state ' return false to allow selection during seeking if m.top.state = \"paused\" m.top.control = \"resume\" return false else if m.top.state = \"playing\" m.top.control = \"pause\" return false end if end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_ListPoster.brs.html":{"id":"components_ListPoster.brs.html","title":"Source: components/ListPoster.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/ListPoster.brs import \"pkg:/source/utils/config.brs\" import \"pkg:/source/utils/misc.brs\" sub init() m.title = m.top.findNode(\"title\") m.staticTitle = m.top.findNode(\"staticTitle\") m.series = m.top.findNode(\"Series\") m.poster = m.top.findNode(\"poster\") m.unplayedCount = m.top.findNode(\"unplayedCount\") m.unplayedEpisodeCount = m.top.findNode(\"unplayedEpisodeCount\") m.backdrop = m.top.findNode(\"backdrop\") ' Randmomise the background colors posterBackgrounds = m.global.constants.poster_bg_pallet m.backdrop.color = posterBackgrounds[rnd(posterBackgrounds.count()) - 1] updateSize() end sub sub updateSize() image = invalid if isValid(m.top.itemContent) and isValid(m.top.itemContent.image) image = m.top.itemContent.image end if if image = invalid m.backdrop.visible = true else m.backdrop.visible = false end if ' TODO - abstract this in case the parent doesnt have itemSize maxSize = m.top.getParent().itemSize ' Always reserve the bottom for the Poster Title m.title.maxWidth = maxSize[0] m.title.height = 40 m.title.translation = [0, int(maxSize[1]) - m.title.height + 5] m.staticTitle.width = maxSize[0] m.staticTitle.height = m.title.height m.staticTitle.translation = m.title.translation m.series.maxWidth = maxSize[0] m.poster.width = int(maxSize[0]) - 4 m.poster.height = int(maxSize[1]) - m.title.height 'Set poster height to available space m.backdrop.width = m.poster.width m.backdrop.height = m.poster.height end sub sub itemContentChanged() as void m.poster = m.top.findNode(\"poster\") itemData = m.top.itemContent m.title.text = itemData.title if m.global.session.user.settings[\"ui.tvshows.disableUnwatchedEpisodeCount\"] = false if isValid(itemData.json.UserData) and isValid(itemData.json.UserData.UnplayedItemCount) if itemData.json.UserData.UnplayedItemCount &gt; 0 m.unplayedCount.visible = true m.unplayedEpisodeCount.text = itemData.json.UserData.UnplayedItemCount end if end if end if if itemData.json.lookup(\"Type\") = \"Episode\" and isValid(itemData.json.IndexNumber) m.title.text = StrI(itemData.json.IndexNumber) + \". \" + m.title.text m.series.text = itemData.json.Series m.series.visible = true else if itemData.json.lookup(\"Type\") = \"MusicAlbum\" m.title.font = \"font:SmallestSystemFont\" m.staticTitle.font = \"font:SmallestSystemFont\" else m.series.visible = false end if m.staticTitle.text = m.title.text imageUrl = itemData.posterURL if m.global.session.user.settings[\"ui.tvshows.blurunwatched\"] = true if itemData.json.lookup(\"Type\") = \"Episode\" and isValid(itemData.json.userdata) if not itemData.json.userdata.played imageUrl = imageUrl + \"&amp;blur=15\" end if end if end if m.poster.uri = imageUrl updateSize() end sub ' ' Enable title scrolling based on item Focus sub focusChanged() if m.top.itemHasFocus = true m.title.repeatCount = -1 m.series.repeatCount = -1 m.staticTitle.visible = false m.title.visible = true ' text to speech for accessibility if m.global.device.isAudioGuideEnabled = true txt2Speech = CreateObject(\"roTextToSpeech\") txt2Speech.Flush() txt2Speech.Say(m.title.text) end if else m.title.repeatCount = 0 m.series.repeatCount = 0 m.staticTitle.visible = true m.title.visible = false end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_liveTv_LoadChannelsTask.brs.html":{"id":"components_liveTv_LoadChannelsTask.brs.html","title":"Source: components/liveTv/LoadChannelsTask.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/liveTv/LoadChannelsTask.brs import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" sub init() m.top.functionName = \"loadChannels\" end sub sub loadChannels() results = [] sort_field = m.top.sortField if m.top.sortAscending = true sort_order = \"Ascending\" else sort_order = \"Descending\" end if params = { includeItemTypes: \"LiveTvChannel\", SortBy: sort_field, SortOrder: sort_order, recursive: m.top.recursive, UserId: m.global.session.user.id } ' Handle special case when getting names starting with numeral if m.top.NameStartsWith &lt;&gt; \"\" if m.top.NameStartsWith = \"#\" params.searchterm = \"A\" else params.searchterm = m.top.nameStartsWith end if end if 'Append voice search when there is text if m.top.searchTerm &lt;&gt; \"\" params.searchTerm = m.top.searchTerm end if if m.top.filter = \"Favorites\" params.append({ isFavorite: true }) end if url = Substitute(\"Users/{0}/Items/\", m.global.session.user.id) resp = APIRequest(url, params) data = getJson(resp) if data.TotalRecordCount = invalid m.top.channels = results return end if for each item in data.Items channel = createObject(\"roSGNode\", \"ChannelData\") channel.json = item if item.UserData &lt;&gt; invalid and item.UserData.isFavorite &lt;&gt; invalid channel.favorite = item.UserData.isFavorite if channel.favorite = true results.Unshift(channel) else results.push(channel) end if else results.push(channel) end if end for m.top.channels = results end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_home_LoadItemsTask.brs.html":{"id":"components_home_LoadItemsTask.brs.html","title":"Source: components/home/LoadItemsTask.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/home/LoadItemsTask.brs import \"pkg:/source/api/Items.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/utils/deviceCapabilities.brs\" import \"pkg:/source/api/Image.brs\" import \"pkg:/source/api/sdk.bs\" sub init() m.top.functionName = \"loadItems\" end sub sub loadItems() results = [] ' Load Libraries if m.top.itemsToLoad = \"libraries\" url = Substitute(\"Users/{0}/Views/\", m.global.session.user.id) resp = APIRequest(url) data = getJson(resp) if isValid(data) and isValid(data.Items) for each item in data.Items ' Skip Books for now as we don't support it (issue #525) if item.CollectionType &lt;&gt; \"books\" tmp = CreateObject(\"roSGNode\", \"HomeData\") tmp.json = item results.push(tmp) end if end for end if ' Load Latest Additions to Libraries else if m.top.itemsToLoad = \"latest\" activeUser = m.global.session.user.id if isValid(activeUser) url = Substitute(\"Users/{0}/Items/Latest\", activeUser) params = {} params[\"Limit\"] = 16 params[\"ParentId\"] = m.top.itemId params[\"EnableImageTypes\"] = \"Primary,Backdrop,Thumb\" params[\"ImageTypeLimit\"] = 1 params[\"EnableTotalRecordCount\"] = false resp = APIRequest(url, params) data = getJson(resp) if isValid(data) for each item in data ' Skip Books for now as we don't support it (issue #525) if item.Type &lt;&gt; \"Book\" tmp = CreateObject(\"roSGNode\", \"HomeData\") tmp.json = item results.push(tmp) end if end for end if end if ' Load Next Up else if m.top.itemsToLoad = \"nextUp\" url = \"Shows/NextUp\" params = {} params[\"recursive\"] = true params[\"SortBy\"] = \"DatePlayed\" params[\"SortOrder\"] = \"Descending\" params[\"ImageTypeLimit\"] = 1 params[\"UserId\"] = m.global.session.user.id params[\"EnableRewatching\"] = false params[\"DisableFirstEpisode\"] = false params[\"limit\"] = 24 params[\"EnableTotalRecordCount\"] = false maxDaysInNextUp = m.global.session.user.settings[\"ui.details.maxdaysnextup\"].ToInt() if isValid(maxDaysInNextUp) if maxDaysInNextUp &gt; 0 dateToday = CreateObject(\"roDateTime\") dateCutoff = CreateObject(\"roDateTime\") dateCutoff.FromSeconds(dateToday.AsSeconds() - (maxDaysInNextUp * 86400)) params[\"NextUpDateCutoff\"] = dateCutoff.ToISOString() end if end if resp = APIRequest(url, params) data = getJson(resp) if isValid(data) and isValid(data.Items) for each item in data.Items tmp = CreateObject(\"roSGNode\", \"HomeData\") tmp.json = item results.push(tmp) end for end if ' Load Continue Watching else if m.top.itemsToLoad = \"continue\" activeUser = m.global.session.user.id if isValid(activeUser) url = Substitute(\"Users/{0}/Items/Resume\", activeUser) params = {} params[\"recursive\"] = true params[\"SortBy\"] = \"DatePlayed\" params[\"SortOrder\"] = \"Descending\" params[\"Filters\"] = \"IsResumable\" params[\"EnableTotalRecordCount\"] = false resp = APIRequest(url, params) data = getJson(resp) if isValid(data) and isValid(data.Items) for each item in data.Items ' Skip Books for now as we don't support it (issue #558) if item.Type &lt;&gt; \"Book\" tmp = CreateObject(\"roSGNode\", \"HomeData\") tmp.json = item results.push(tmp) end if end for end if end if else if m.top.itemsToLoad = \"favorites\" url = Substitute(\"Users/{0}/Items\", m.global.session.user.id) params = {} params[\"Filters\"] = \"IsFavorite\" params[\"Limit\"] = 20 params[\"recursive\"] = true params[\"sortby\"] = \"random\" params[\"EnableTotalRecordCount\"] = false resp = APIRequest(url, params) data = getJson(resp) if isValid(data) and isValid(data.Items) for each item in data.Items ' Skip Books for now as we don't support it (issue #558) ' also skip songs since there is limited space if not (item.Type = \"Book\" or item.Type = \"Audio\") tmp = CreateObject(\"roSGNode\", \"HomeData\") params = {} params[\"Tags\"] = item.PrimaryImageTag params[\"MaxWidth\"] = 234 params[\"MaxHeight\"] = 330 tmp.posterURL = ImageUrl(item.Id, \"Primary\", params) tmp.json = item results.push(tmp) end if end for end if else if m.top.itemsToLoad = \"onNow\" url = \"LiveTv/Programs/Recommended\" params = {} params[\"userId\"] = m.global.session.user.id params[\"isAiring\"] = true params[\"limit\"] = 16 ' 16 to be consistent with \"Latest In\" params[\"imageTypeLimit\"] = 1 params[\"enableImageTypes\"] = \"Primary,Thumb,Backdrop\" params[\"enableTotalRecordCount\"] = false params[\"fields\"] = \"ChannelInfo,PrimaryImageAspectRatio\" resp = APIRequest(url, params) data = getJson(resp) if isValid(data) and isValid(data.Items) for each item in data.Items tmp = CreateObject(\"roSGNode\", \"HomeData\") item.ImageURL = ImageURL(item.Id) tmp.json = item results.push(tmp) end for end if ' Extract array of persons from Views and download full metadata for each else if m.top.itemsToLoad = \"people\" for each person in m.top.peopleList tmp = CreateObject(\"roSGNode\", \"ExtrasData\") tmp.Id = person.Id tmp.labelText = person.Name params = {} params[\"Tags\"] = person.PrimaryImageTag params[\"MaxWidth\"] = 234 params[\"MaxHeight\"] = 330 tmp.posterURL = ImageUrl(person.Id, \"Primary\", params) tmp.json = person results.push(tmp) end for else if m.top.itemsToLoad = \"specialfeatures\" params = {} url = Substitute(\"Users/{0}/Items/{1}/SpecialFeatures\", m.global.session.user.id, m.top.itemId) resp = APIRequest(url, params) data = getJson(resp) if data &lt;&gt; invalid and data.count() &gt; 0 for each specfeat in data tmp = CreateObject(\"roSGNode\", \"ExtrasData\") results.push(tmp) params = {} params[\"Tags\"] = specfeat.ImageTags.Primary params[\"MaxWidth\"] = 450 params[\"MaxHeight\"] = 402 tmp.posterURL = ImageUrl(specfeat.Id, \"Primary\", params) tmp.json = specfeat end for end if else if m.top.itemsToLoad = \"additionalparts\" additionalParts = api.videos.GetAdditionalParts(m.top.itemId) if isValid(additionalParts) for each part in additionalParts.items tmp = CreateObject(\"roSGNode\", \"ExtrasData\") params = {} params[\"Tags\"] = part.ImageTags.Primary params[\"MaxWidth\"] = 450 params[\"MaxHeight\"] = 402 tmp.posterURL = ImageUrl(part.Id, \"Primary\", params) tmp.json = part results.push(tmp) end for end if else if m.top.itemsToLoad = \"likethis\" params = { \"userId\": m.global.session.user.id, \"limit\": 16 } url = Substitute(\"Items/{0}/Similar\", m.top.itemId) resp = APIRequest(url, params) data = getJson(resp) if isValid(data) and isValid(data.Items) for each item in data.items tmp = CreateObject(\"roSGNode\", \"ExtrasData\") tmp.posterURL = ImageUrl(item.Id, \"Primary\", { \"Tags\": item.PrimaryImageTag }) tmp.json = item results.push(tmp) end for end if else if m.top.itemsToLoad = \"personMovies\" getPersonVideos(\"Movie\", results, {}) else if m.top.itemsToLoad = \"personTVShows\" getPersonVideos(\"Episode\", results, { MaxWidth: 502, MaxHeight: 300 }) else if m.top.itemsToLoad = \"personSeries\" getPersonVideos(\"Series\", results, {}) else if m.top.itemsToLoad = \"metaData\" results.push(ItemMetaData(m.top.itemId)) else if m.top.itemsToLoad = \"audioStream\" results.push(AudioStream(m.top.itemId)) else if m.top.itemsToLoad = \"backdropImage\" results.push(BackdropImage(m.top.itemId)) end if m.top.content = results end sub sub getPersonVideos(videoType, dest, dimens) params = { personIds: m.top.itemId, recursive: true, includeItemTypes: videoType, Limit: 50, SortBy: \"Random\" } url = Substitute(\"Users/{0}/Items\", m.global.session.user.id) resp = APIRequest(url, params) data = getJson(resp) if data &lt;&gt; invalid and data.count() &gt; 0 for each item in data.items tmp = CreateObject(\"roSGNode\", \"ExtrasData\") imgParms = { \"Tags\": item.ImageTags.Primary } imgParms.append(dimens) tmp.posterURL = ImageUrl(item.Id, \"Primary\", imgParms) tmp.json = item dest.push(tmp) end for end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_ItemGrid_LoadItemsTask2.brs.html":{"id":"components_ItemGrid_LoadItemsTask2.brs.html","title":"Source: components/ItemGrid/LoadItemsTask2.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/ItemGrid/LoadItemsTask2.brs import \"pkg:/source/api/Items.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/api/Image.brs\" import \"pkg:/source/utils/deviceCapabilities.brs\" import \"pkg:/source/roku_modules/log/LogMixin.brs\" import \"pkg:/source/api/sdk.bs\" sub init() m.log = log.Logger(\"LoadItemsTask2\") m.top.functionName = \"loadItems\" m.top.limit = 60 usersettingLimit = m.global.session.user.settings[\"itemgrid.Limit\"] if usersettingLimit &lt;&gt; invalid m.top.limit = usersettingLimit end if end sub sub loadItems() results = [] sort_field = m.top.sortField if m.top.sortAscending = true sort_order = \"Ascending\" else sort_order = \"Descending\" end if if m.top.ItemType = \"LogoImage\" logoImageExists = api.items.HeadImageURLByName(m.top.itemId, \"logo\") if logoImageExists m.top.content = [api.items.GetImageURL(m.top.itemId, \"logo\", 0, { \"maxHeight\": 500, \"maxWidth\": 500, \"quality\": \"90\" })] else m.top.content = [] end if return end if params = { limit: m.top.limit, StartIndex: m.top.startIndex, parentid: m.top.itemId, SortBy: sort_field, SortOrder: sort_order, recursive: m.top.recursive, Fields: \"Overview\", StudioIds: m.top.studioIds, genreIds: m.top.genreIds } ' Handle special case when getting names starting with numeral if m.top.NameStartsWith &lt;&gt; \"\" if m.top.NameStartsWith = \"#\" if m.top.ItemType = \"LiveTV\" or m.top.ItemType = \"TvChannel\" params.searchterm = \"A\" params.append({ parentid: \" \" }) else params.NameLessThan = \"A\" end if else if m.top.ItemType = \"LiveTV\" or m.top.ItemType = \"TvChannel\" params.searchterm = m.top.nameStartsWith params.append({ parentid: \" \" }) else params.NameStartsWith = m.top.nameStartsWith end if end if end if 'reset data if LCase(m.top.searchTerm) = LCase(tr(\"all\")) params.searchTerm = \" \" else if m.top.searchTerm &lt;&gt; \"\" params.searchTerm = m.top.searchTerm end if filter = LCase(m.top.filter) if filter = \"all\" ' do nothing else if filter = \"favorites\" params.append({ Filters: \"IsFavorite\" }) params.append({ isFavorite: true }) else if filter = \"unplayed\" params.append({ Filters: \"IsUnplayed\" }) else if filter = \"played\" params.append({ Filters: \"IsPlayed\" }) else if filter = \"resumable\" params.append({ Filters: \"IsResumable\" }) end if if isValid(m.top.filterOptions) if m.top.filterOptions.count() &gt; 0 params.append(m.top.filterOptions) end if end if if m.top.ItemType &lt;&gt; \"\" params.append({ IncludeItemTypes: m.top.ItemType }) end if if m.top.ItemType = \"LiveTV\" url = \"LiveTv/Channels\" params.append({ UserId: m.global.session.user.id }) else if m.top.view = \"Networks\" url = \"Studios\" params.append({ UserId: m.global.session.user.id }) else if m.top.view = \"Genres\" url = \"Genres\" params.append({ UserId: m.global.session.user.id, includeItemTypes: m.top.itemType }) else if m.top.ItemType = \"MusicArtist\" url = \"Artists\" params.append({ UserId: m.global.session.user.id, Fields: \"Genres\" }) params.IncludeItemTypes = \"MusicAlbum,Audio\" else if m.top.ItemType = \"AlbumArtists\" url = \"Artists/AlbumArtists\" params.append({ UserId: m.global.session.user.id, Fields: \"Genres\" }) params.IncludeItemTypes = \"MusicAlbum,Audio\" else if m.top.ItemType = \"MusicAlbum\" url = Substitute(\"Users/{0}/Items/\", m.global.session.user.id) params.append({ ImageTypeLimit: 1 }) params.append({ EnableImageTypes: \"Primary,Backdrop,Banner,Thumb\" }) else url = Substitute(\"Users/{0}/Items/\", m.global.session.user.id) end if resp = APIRequest(url, params) data = getJson(resp) if data &lt;&gt; invalid if data.TotalRecordCount &lt;&gt; invalid then m.top.totalRecordCount = data.TotalRecordCount for each item in data.Items tmp = invalid if item.Type = \"Movie\" or item.Type = \"MusicVideo\" tmp = CreateObject(\"roSGNode\", \"MovieData\") else if item.Type = \"Series\" tmp = CreateObject(\"roSGNode\", \"SeriesData\") else if item.Type = \"BoxSet\" or item.Type = \"ManualPlaylistsFolder\" tmp = CreateObject(\"roSGNode\", \"CollectionData\") else if item.Type = \"TvChannel\" tmp = CreateObject(\"roSGNode\", \"ChannelData\") else if item.Type = \"Folder\" or item.Type = \"ChannelFolderItem\" or item.Type = \"CollectionFolder\" tmp = CreateObject(\"roSGNode\", \"FolderData\") else if item.Type = \"Video\" or item.Type = \"Recording\" tmp = CreateObject(\"roSGNode\", \"VideoData\") else if item.Type = \"Photo\" tmp = CreateObject(\"roSGNode\", \"PhotoData\") else if item.type = \"PhotoAlbum\" tmp = CreateObject(\"roSGNode\", \"FolderData\") else if item.type = \"Playlist\" tmp = CreateObject(\"roSGNode\", \"PlaylistData\") tmp.type = \"Playlist\" tmp.image = PosterImage(item.id, { \"maxHeight\": 425, \"maxWidth\": 290, \"quality\": \"90\" }) else if item.type = \"Episode\" tmp = CreateObject(\"roSGNode\", \"TVEpisode\") else if item.Type = \"Genre\" tmp = CreateObject(\"roSGNode\", \"ContentNode\") tmp.title = item.name genreData = api.users.GetItemsByQuery(m.global.session.user.id, { SortBy: \"Random\", SortOrder: \"Ascending\", IncludeItemTypes: m.top.itemType, Recursive: true, Fields: \"PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo\", ImageTypeLimit: 1, EnableImageTypes: \"Primary\", Limit: 6, GenreIds: item.id, EnableTotalRecordCount: false, ParentId: m.top.itemId }) if genreData.Items.Count() &gt; 5 ' Add View All item to the start of the row row = tmp.createChild(\"FolderData\") row.parentFolder = m.top.itemId row.title = tr(\"View All\") + \" \" + item.name item.name = tr(\"View All\") + \" \" + item.name row.json = item row.type = \"Folder\" if LCase(m.top.itemType) = \"movie\" genreItemImage = api.items.GetImageURL(item.id) else genreItemImage = invalid row.posterURL = invalid end if row.FHDPOSTERURL = genreItemImage row.HDPOSTERURL = genreItemImage row.SDPOSTERURL = genreItemImage end if for each genreItem in genreData.Items if LCase(m.top.itemType) = \"movie\" row = tmp.createChild(\"MovieData\") else row = tmp.createChild(\"SeriesData\") end if genreItemImage = api.items.GetImageURL(genreItem.id) row.title = genreItem.name row.FHDPOSTERURL = genreItemImage row.HDPOSTERURL = genreItemImage row.SDPOSTERURL = genreItemImage row.json = genreItem row.id = genreItem.id row.type = genreItem.type end for else if item.Type = \"Studio\" tmp = CreateObject(\"roSGNode\", \"FolderData\") else if item.Type = \"MusicAlbum\" tmp = CreateObject(\"roSGNode\", \"MusicAlbumData\") tmp.type = \"MusicAlbum\" if api.items.HeadImageURLByName(item.id, \"primary\") tmp.posterURL = ImageURL(item.id, \"Primary\") else tmp.posterURL = ImageURL(item.id, \"backdrop\") end if else if item.Type = \"MusicArtist\" tmp = CreateObject(\"roSGNode\", \"MusicArtistData\") else if item.Type = \"Audio\" tmp = CreateObject(\"roSGNode\", \"MusicSongData\") tmp.type = \"Audio\" tmp.image = api.items.GetImageURL(item.id, \"primary\", 0, { \"maxHeight\": 280, \"maxWidth\": 280, \"quality\": \"90\" }) else if item.Type = \"MusicGenre\" tmp = CreateObject(\"roSGNode\", \"FolderData\") tmp.title = item.name tmp.parentFolder = m.top.itemId tmp.json = item tmp.type = \"Folder\" tmp.posterUrl = api.items.GetImageURL(item.id, \"primary\", 0, { \"maxHeight\": 280, \"maxWidth\": 280, \"quality\": \"90\" }) else m.log.warn(\"Unknown Type\", item.Type) end if if tmp &lt;&gt; invalid if item.Type &lt;&gt; \"Genre\" and item.Type &lt;&gt; \"MusicGenre\" tmp.parentFolder = m.top.itemId tmp.json = item if item.UserData &lt;&gt; invalid and item.UserData.isFavorite &lt;&gt; invalid tmp.favorite = item.UserData.isFavorite end if end if results.push(tmp) end if end for end if m.top.content = results end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_photos_LoadPhotoTask.brs.html":{"id":"components_photos_LoadPhotoTask.brs.html","title":"Source: components/photos/LoadPhotoTask.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/photos/LoadPhotoTask.brs import \"pkg:/source/api/Image.brs\" import \"pkg:/source/utils/config.brs\" import \"pkg:/source/api/baserequest.brs\" sub init() m.top.functionName = \"loadItems\" end sub sub loadItems() item = m.top.itemContent if item &lt;&gt; invalid params = { maxHeight: 1080, maxWidth: 1920 } m.top.results = ImageURL(item.Id, \"Primary\", params) else m.top.results = invalid end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_liveTv_LoadProgramDetailsTask.brs.html":{"id":"components_liveTv_LoadProgramDetailsTask.brs.html","title":"Source: components/liveTv/LoadProgramDetailsTask.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/liveTv/LoadProgramDetailsTask.brs import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" sub init() m.top.functionName = \"loadProgramDetails\" end sub sub loadProgramDetails() channelIndex = m.top.ChannelIndex programIndex = m.top.ProgramIndex params = { UserId: m.global.session.user.id } url = Substitute(\"LiveTv/Programs/{0}\", m.top.programId) resp = APIRequest(url, params) data = getJson(resp) if data = invalid m.top.programDetails = {} return end if program = createObject(\"roSGNode\", \"ScheduleProgramData\") program.json = data program.channelIndex = channelIndex program.programIndex = programIndex program.fullyLoaded = true ' Are we currently recording this program? if program.json.TimerId &lt;&gt; invalid and program.json.TimerId &lt;&gt; \"\" ' This is needed here because the callee (onProgramDetailsLoaded) replaces the grid item with ' this newly created item from the server, without this, the red icon ' disappears when the user focuses on the program in question program.hdSmallIconUrl = \"pkg:/images/red.png\" else program.hdSmallIconUrl = invalid end if m.top.programDetails = program end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_music_LoadScreenSaverTimeoutTask.brs.html":{"id":"components_music_LoadScreenSaverTimeoutTask.brs.html","title":"Source: components/music/LoadScreenSaverTimeoutTask.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/music/LoadScreenSaverTimeoutTask.brs sub init() m.top.functionName = \"getScreensaverTimeout\" end sub sub getScreensaverTimeout() appinfo = CreateObject(\"roAppManager\") m.top.content = appinfo.GetScreensaverTimeout() * 60 end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_liveTv_LoadSheduleTask.brs.html":{"id":"components_liveTv_LoadSheduleTask.brs.html","title":"Source: components/liveTv/LoadSheduleTask.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/liveTv/LoadSheduleTask.brs import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" sub init() m.top.functionName = \"loadSchedule\" end sub sub loadSchedule() results = [] params = { UserId: m.global.session.user.id, SortBy: \"startDate\", EnableImages: false, EnableTotalRecordCount: false, EnableUserData: false, channelIds: m.top.channelIds, MaxStartDate: m.top.endTime, MinEndDate: m.top.startTime } url = \"LiveTv/Programs\" resp = APIRequest(url) data = postJson(resp, FormatJson(params)) if data = invalid m.top.schedule = results return end if results = [] for each item in data.Items program = createObject(\"roSGNode\", \"ScheduleProgramData\") program.json = item ' Are we currently recording this program? if program.json.TimerId &lt;&gt; invalid and program.json.TimerId &lt;&gt; \"\" program.hdSmallIconUrl = \"pkg:/images/red.png\" else program.hdSmallIconUrl = invalid end if results.push(program) end for m.top.schedule = results end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_ItemGrid_LoadVideoContentTask.brs.html":{"id":"components_ItemGrid_LoadVideoContentTask.brs.html","title":"Source: components/ItemGrid/LoadVideoContentTask.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/ItemGrid/LoadVideoContentTask.brs import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/api/Items.brs\" import \"pkg:/source/api/UserLibrary.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" import \"pkg:/source/api/Image.brs\" import \"pkg:/source/api/userauth.brs\" import \"pkg:/source/utils/deviceCapabilities.brs\" sub init() m.user = AboutMe() m.top.functionName = \"loadItems\" end sub sub loadItems() ' Reset intro tracker in case task gets reused m.top.isIntro = false ' Only show preroll once per queue if m.global.queueManager.callFunc(\"isPrerollActive\") ' Prerolls not allowed if we're resuming video if m.global.queueManager.callFunc(\"getCurrentItem\").startingPoint = 0 preRoll = GetIntroVideos(m.top.itemId) if isValid(preRoll) and preRoll.TotalRecordCount &gt; 0 and isValid(preRoll.items[0]) ' If an error is thrown in the Intros plugin, instead of passing the error they pass the entire rick roll music video. ' Bypass the music video and treat it as an error message if lcase(preRoll.items[0].name) &lt;&gt; \"rick roll'd\" m.global.queueManager.callFunc(\"push\", m.global.queueManager.callFunc(\"getCurrentItem\")) m.top.itemId = preRoll.items[0].id m.global.queueManager.callFunc(\"setPrerollStatus\", false) m.top.isIntro = true end if end if end if end if if m.top.selectedAudioStreamIndex = 0 currentItem = m.global.queueManager.callFunc(\"getCurrentItem\") if isValid(currentItem) and isValid(currentItem.json) m.top.selectedAudioStreamIndex = FindPreferredAudioStream(currentItem.json.MediaStreams) end if end if id = m.top.itemId mediaSourceId = invalid audio_stream_idx = m.top.selectedAudioStreamIndex subtitle_idx = m.top.selectedSubtitleIndex forceTranscoding = false m.top.content = [LoadItems_VideoPlayer(id, mediaSourceId, audio_stream_idx, subtitle_idx, forceTranscoding)] end sub function LoadItems_VideoPlayer(id as string, mediaSourceId = invalid as dynamic, audio_stream_idx = 1 as integer, subtitle_idx = -1 as integer, forceTranscoding = false as boolean) as dynamic video = {} video.id = id video.content = createObject(\"RoSGNode\", \"ContentNode\") LoadItems_AddVideoContent(video, mediaSourceId, audio_stream_idx, subtitle_idx, forceTranscoding) if video.content = invalid return invalid end if return video end function sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_stream_idx = 1 as integer, subtitle_idx = -1 as integer, forceTranscoding = false as boolean) meta = ItemMetaData(video.id) if not isValid(meta) video.errorMsg = \"Error loading metadata\" video.content = invalid return end if videotype = LCase(meta.type) if videotype = \"episode\" or videotype = \"series\" video.content.contenttype = \"episode\" end if video.content.title = meta.title video.showID = meta.showID user = AboutMe() if user.Configuration.EnableNextEpisodeAutoPlay if LCase(m.top.itemType) = \"episode\" addNextEpisodesToQueue(video.showID) end if end if playbackPosition = 0! currentItem = m.global.queueManager.callFunc(\"getCurrentItem\") if isValid(currentItem) and isValid(currentItem.startingPoint) playbackPosition = currentItem.startingPoint end if ' PlayStart requires the time to be in seconds video.content.PlayStart = int(playbackPosition / 10000000) if not isValid(mediaSourceId) then mediaSourceId = video.id if meta.live then mediaSourceId = \"\" m.playbackInfo = ItemPostPlaybackInfo(video.id, mediaSourceId, audio_stream_idx, subtitle_idx, playbackPosition) video.videoId = video.id video.mediaSourceId = mediaSourceId video.audioIndex = audio_stream_idx if not isValid(m.playbackInfo) video.errorMsg = \"Error loading playback info\" video.content = invalid return end if video.PlaySessionId = m.playbackInfo.PlaySessionId if meta.live video.content.live = true video.content.StreamFormat = \"hls\" end if video.container = getContainerType(meta) if not isValid(m.playbackInfo.MediaSources[0]) m.playbackInfo = meta.json end if addSubtitlesToVideo(video, meta) if meta.live video.transcodeParams = { \"MediaSourceId\": m.playbackInfo.MediaSources[0].Id, \"LiveStreamId\": m.playbackInfo.MediaSources[0].LiveStreamId, \"PlaySessionId\": video.PlaySessionId } end if ' 'TODO: allow user selection of subtitle track before playback initiated, for now set to no subtitles video.directPlaySupported = m.playbackInfo.MediaSources[0].SupportsDirectPlay fully_external = false ' For h264/hevc video, Roku spec states that it supports specfic encoding levels ' The device can decode content with a Higher Encoding level but may play it back with certain ' artifacts. If the user preference is set, and the only reason the server says we need to ' transcode is that the Encoding Level is not supported, then try to direct play but silently ' fall back to the transcode if that fails. if m.playbackInfo.MediaSources[0].MediaStreams.Count() &gt; 0 and meta.live = false tryDirectPlay = m.global.session.user.settings[\"playback.tryDirect.h264ProfileLevel\"] and m.playbackInfo.MediaSources[0].MediaStreams[0].codec = \"h264\" tryDirectPlay = tryDirectPlay or (m.global.session.user.settings[\"playback.tryDirect.hevcProfileLevel\"] and m.playbackInfo.MediaSources[0].MediaStreams[0].codec = \"hevc\") if tryDirectPlay and isValid(m.playbackInfo.MediaSources[0].TranscodingUrl) and forceTranscoding = false transcodingReasons = getTranscodeReasons(m.playbackInfo.MediaSources[0].TranscodingUrl) if transcodingReasons.Count() = 1 and transcodingReasons[0] = \"VideoLevelNotSupported\" video.directPlaySupported = true video.transcodeAvailable = true end if end if end if if video.directPlaySupported addVideoContentURL(video, mediaSourceId, audio_stream_idx, fully_external) video.isTranscoded = false else if m.playbackInfo.MediaSources[0].TranscodingUrl = invalid ' If server does not provide a transcode URL, display a message to the user m.global.sceneManager.callFunc(\"userMessage\", tr(\"Error Getting Playback Information\"), tr(\"An error was encountered while playing this item. Server did not provide required transcoding data.\")) video.errorMsg = \"Error getting playback information\" video.content = invalid return end if ' Get transcoding reason video.transcodeReasons = getTranscodeReasons(m.playbackInfo.MediaSources[0].TranscodingUrl) video.content.url = buildURL(m.playbackInfo.MediaSources[0].TranscodingUrl) video.isTranscoded = true end if setCertificateAuthority(video.content) video.audioTrack = (audio_stream_idx + 1).ToStr() ' Roku's track indexes count from 1. Our index is zero based video.SelectedSubtitle = subtitle_idx if not fully_external video.content = authRequest(video.content) end if end sub sub addVideoContentURL(video, mediaSourceId, audio_stream_idx, fully_external) protocol = LCase(m.playbackInfo.MediaSources[0].Protocol) if protocol &lt;&gt; \"file\" uri = parseUrl(m.playbackInfo.MediaSources[0].Path) if isLocalhost(uri[2]) ' if the domain of the URI is local to the server, ' create a new URI by appending the received path to the server URL ' later we will substitute the users provided URL for this case video.content.url = buildURL(uri[4]) else fully_external = true video.content.url = m.playbackInfo.MediaSources[0].Path end if else: params = {} params.append({ \"Static\": \"true\", \"Container\": video.container, \"PlaySessionId\": video.PlaySessionId, \"AudioStreamIndex\": audio_stream_idx }) if mediaSourceId &lt;&gt; \"\" params.MediaSourceId = mediaSourceId end if video.content.url = buildURL(Substitute(\"Videos/{0}/stream\", video.id), params) end if end sub sub addSubtitlesToVideo(video, meta) subtitles = sortSubtitles(meta.id, m.playbackInfo.MediaSources[0].MediaStreams) safesubs = subtitles[\"all\"] subtitleTracks = [] if m.global.session.user.settings[\"playback.subs.onlytext\"] = true safesubs = subtitles[\"text\"] end if for each subtitle in safesubs subtitleTracks.push(subtitle.track) end for video.content.SubtitleTracks = subtitleTracks video.fullSubtitleData = safesubs end sub ' ' Extract array of Transcode Reasons from the content URL ' @returns Array of Strings function getTranscodeReasons(url as string) as object regex = CreateObject(\"roRegex\", \"&amp;TranscodeReasons=([^&amp;]*)\", \"\") match = regex.Match(url) if match.count() &gt; 1 return match[1].Split(\",\") end if return [] end function function directPlaySupported(meta as object) as boolean devinfo = CreateObject(\"roDeviceInfo\") if isValid(meta.json.MediaSources[0]) and meta.json.MediaSources[0].SupportsDirectPlay = false return false end if if meta.json.MediaStreams[0] = invalid return false end if streamInfo = { Codec: meta.json.MediaStreams[0].codec } if isValid(meta.json.MediaStreams[0].Profile) and meta.json.MediaStreams[0].Profile.len() &gt; 0 streamInfo.Profile = LCase(meta.json.MediaStreams[0].Profile) end if if isValid(meta.json.MediaSources[0].container) and meta.json.MediaSources[0].container.len() &gt; 0 'CanDecodeVideo() requires the .container to be format: “mp4”, “hls”, “mkv”, “ism”, “dash”, “ts” if its to direct stream if meta.json.MediaSources[0].container = \"mov\" streamInfo.Container = \"mp4\" else streamInfo.Container = meta.json.MediaSources[0].container end if end if decodeResult = devinfo.CanDecodeVideo(streamInfo) return decodeResult &lt;&gt; invalid and decodeResult.result end function function getContainerType(meta as object) as string ' Determine the file type of the video file source if meta.json.mediaSources = invalid then return \"\" container = meta.json.mediaSources[0].container if container = invalid container = \"\" else if container = \"m4v\" or container = \"mov\" container = \"mp4\" end if return container end function ' Add next episodes to the playback queue sub addNextEpisodesToQueue(showID) ' Don't queue next episodes if we already have a playback queue maxQueueCount = 1 if m.top.isIntro maxQueueCount = 2 end if if m.global.queueManager.callFunc(\"getCount\") &gt; maxQueueCount then return videoID = m.top.itemId ' If first item is an intro video, use the next item in the queue if m.top.isIntro currentVideo = m.global.queueManager.callFunc(\"getItemByIndex\", 1) if isValid(currentVideo) and isValid(currentVideo.id) videoID = currentVideo.id ' Override showID value since it's for the intro video meta = ItemMetaData(videoID) if isValid(meta) showID = meta.showID end if end if end if url = Substitute(\"Shows/{0}/Episodes\", showID) urlParams = { \"UserId\": m.global.session.user.id } urlParams.Append({ \"StartItemId\": videoID }) urlParams.Append({ \"Limit\": 50 }) resp = APIRequest(url, urlParams) data = getJson(resp) if isValid(data) and data.Items.Count() &gt; 1 for i = 1 to data.Items.Count() - 1 m.global.queueManager.callFunc(\"push\", data.Items[i]) end for end if end sub 'Checks available subtitle tracks and puts subtitles in forced, default, and non-default/forced but preferred language at the top function sortSubtitles(id as string, MediaStreams) tracks = { \"forced\": [], \"default\": [], \"normal\": [], \"text\": [] } 'Too many args for using substitute prefered_lang = m.global.session.user.configuration.SubtitleLanguagePreference for each stream in MediaStreams if stream.type = \"Subtitle\" url = \"\" if isValid(stream.DeliveryUrl) url = buildURL(stream.DeliveryUrl) end if stream = { \"Track\": { \"Language\": stream.language, \"Description\": stream.displaytitle, \"TrackName\": url }, \"IsTextSubtitleStream\": stream.IsTextSubtitleStream, \"Index\": stream.index, \"IsDefault\": stream.IsDefault, \"IsForced\": stream.IsForced, \"IsExternal\": stream.IsExternal, \"IsEncoded\": stream.DeliveryMethod = \"Encode\" } if stream.isForced trackType = \"forced\" else if stream.IsDefault trackType = \"default\" else if stream.IsTextSubtitleStream trackType = \"text\" else trackType = \"normal\" end if if prefered_lang &lt;&gt; \"\" and prefered_lang = stream.Track.Language tracks[trackType].unshift(stream) else tracks[trackType].push(stream) end if end if end for tracks[\"default\"].append(tracks[\"normal\"]) tracks[\"forced\"].append(tracks[\"default\"]) tracks[\"forced\"].append(tracks[\"text\"]) return { \"all\": tracks[\"forced\"], \"text\": tracks[\"text\"] } end function function FindPreferredAudioStream(streams as dynamic) as integer preferredLanguage = m.user.Configuration.AudioLanguagePreference playDefault = m.user.Configuration.PlayDefaultAudioTrack if playDefault &lt;&gt; invalid and playDefault = true return 1 end if ' Do we already have the MediaStreams or not? if streams = invalid url = Substitute(\"Users/{0}/Items/{1}\", m.user.id, m.top.itemId) resp = APIRequest(url) jsonResponse = getJson(resp) if jsonResponse = invalid or jsonResponse.MediaStreams = invalid then return 1 streams = jsonResponse.MediaStreams end if if preferredLanguage &lt;&gt; invalid for i = 0 to streams.Count() - 1 if LCase(streams[i].Type) = \"audio\" if streams[i].Language &lt;&gt; invalid and LCase(streams[i].Language) = LCase(preferredLanguage) return i end if end if end for end if return 1 end function function getSubtitleLanguages() return { \"aar\": \"Afar\", \"abk\": \"Abkhazian\", \"ace\": \"Achinese\", \"ach\": \"Acoli\", \"ada\": \"Adangme\", \"ady\": \"Adyghe; Adygei\", \"afa\": \"Afro-Asiatic languages\", \"afh\": \"Afrihili\", \"afr\": \"Afrikaans\", \"ain\": \"Ainu\", \"aka\": \"Akan\", \"akk\": \"Akkadian\", \"alb\": \"Albanian\", \"ale\": \"Aleut\", \"alg\": \"Algonquian languages\", \"alt\": \"Southern Altai\", \"amh\": \"Amharic\", \"ang\": \"English, Old (ca.450-1100)\", \"anp\": \"Angika\", \"apa\": \"Apache languages\", \"ara\": \"Arabic\", \"arc\": \"Official Aramaic (700-300 BCE); Imperial Aramaic (700-300 BCE)\", \"arg\": \"Aragonese\", \"arm\": \"Armenian\", \"arn\": \"Mapudungun; Mapuche\", \"arp\": \"Arapaho\", \"art\": \"Artificial languages\", \"arw\": \"Arawak\", \"asm\": \"Assamese\", \"ast\": \"Asturian; Bable; Leonese; Asturleonese\", \"ath\": \"Athapascan languages\", \"aus\": \"Australian languages\", \"ava\": \"Avaric\", \"ave\": \"Avestan\", \"awa\": \"Awadhi\", \"aym\": \"Aymara\", \"aze\": \"Azerbaijani\", \"bad\": \"Banda languages\", \"bai\": \"Bamileke languages\", \"bak\": \"Bashkir\", \"bal\": \"Baluchi\", \"bam\": \"Bambara\", \"ban\": \"Balinese\", \"baq\": \"Basque\", \"bas\": \"Basa\", \"bat\": \"Baltic languages\", \"bej\": \"Beja; Bedawiyet\", \"bel\": \"Belarusian\", \"bem\": \"Bemba\", \"ben\": \"Bengali\", \"ber\": \"Berber languages\", \"bho\": \"Bhojpuri\", \"bih\": \"Bihari languages\", \"bik\": \"Bikol\", \"bin\": \"Bini; Edo\", \"bis\": \"Bislama\", \"bla\": \"Siksika\", \"bnt\": \"Bantu (Other)\", \"bos\": \"Bosnian\", \"bra\": \"Braj\", \"bre\": \"Breton\", \"btk\": \"Batak languages\", \"bua\": \"Buriat\", \"bug\": \"Buginese\", \"bul\": \"Bulgarian\", \"bur\": \"Burmese\", \"byn\": \"Blin; Bilin\", \"cad\": \"Caddo\", \"cai\": \"Central American Indian languages\", \"car\": \"Galibi Carib\", \"cat\": \"Catalan; Valencian\", \"cau\": \"Caucasian languages\", \"ceb\": \"Cebuano\", \"cel\": \"Celtic languages\", \"cha\": \"Chamorro\", \"chb\": \"Chibcha\", \"che\": \"Chechen\", \"chg\": \"Chagatai\", \"chi\": \"Chinese\", \"chk\": \"Chuukese\", \"chm\": \"Mari\", \"chn\": \"Chinook jargon\", \"cho\": \"Choctaw\", \"chp\": \"Chipewyan; Dene Suline\", \"chr\": \"Cherokee\", \"chu\": \"Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic\", \"chv\": \"Chuvash\", \"chy\": \"Cheyenne\", \"cmc\": \"Chamic languages\", \"cop\": \"Coptic\", \"cor\": \"Cornish\", \"cos\": \"Corsican\", \"cpe\": \"Creoles and pidgins, English based\", \"cpf\": \"Creoles and pidgins, French-based \", \"cpp\": \"Creoles and pidgins, Portuguese-based \", \"cre\": \"Cree\", \"crh\": \"Crimean Tatar; Crimean Turkish\", \"crp\": \"Creoles and pidgins \", \"csb\": \"Kashubian\", \"cus\": \"Cushitic languages\", \"cze\": \"Czech\", \"dak\": \"Dakota\", \"dan\": \"Danish\", \"dar\": \"Dargwa\", \"day\": \"Land Dayak languages\", \"del\": \"Delaware\", \"den\": \"Slave (Athapascan)\", \"dgr\": \"Dogrib\", \"din\": \"Dinka\", \"div\": \"Divehi; Dhivehi; Maldivian\", \"doi\": \"Dogri\", \"dra\": \"Dravidian languages\", \"dsb\": \"Lower Sorbian\", \"dua\": \"Duala\", \"dum\": \"Dutch, Middle (ca.1050-1350)\", \"dut\": \"Dutch; Flemish\", \"dyu\": \"Dyula\", \"dzo\": \"Dzongkha\", \"efi\": \"Efik\", \"egy\": \"Egyptian (Ancient)\", \"eka\": \"Ekajuk\", \"elx\": \"Elamite\", \"eng\": \"English\", \"enm\": \"English, Middle (1100-1500)\", \"epo\": \"Esperanto\", \"est\": \"Estonian\", \"ewe\": \"Ewe\", \"ewo\": \"Ewondo\", \"fan\": \"Fang\", \"fao\": \"Faroese\", \"fat\": \"Fanti\", \"fij\": \"Fijian\", \"fil\": \"Filipino; Pilipino\", \"fin\": \"Finnish\", \"fiu\": \"Finno-Ugrian languages\", \"fon\": \"Fon\", \"fre\": \"French\", \"frm\": \"French, Middle (ca.1400-1600)\", \"fro\": \"French, Old (842-ca.1400)\", \"frc\": \"French (Canada)\", \"frr\": \"Northern Frisian\", \"frs\": \"Eastern Frisian\", \"fry\": \"Western Frisian\", \"ful\": \"Fulah\", \"fur\": \"Friulian\", \"gaa\": \"Ga\", \"gay\": \"Gayo\", \"gba\": \"Gbaya\", \"gem\": \"Germanic languages\", \"geo\": \"Georgian\", \"ger\": \"German\", \"gez\": \"Geez\", \"gil\": \"Gilbertese\", \"gla\": \"Gaelic; Scottish Gaelic\", \"gle\": \"Irish\", \"glg\": \"Galician\", \"glv\": \"Manx\", \"gmh\": \"German, Middle High (ca.1050-1500)\", \"goh\": \"German, Old High (ca.750-1050)\", \"gon\": \"Gondi\", \"gor\": \"Gorontalo\", \"got\": \"Gothic\", \"grb\": \"Grebo\", \"grc\": \"Greek, Ancient (to 1453)\", \"gre\": \"Greek, Modern (1453-)\", \"grn\": \"Guarani\", \"gsw\": \"Swiss German; Alemannic; Alsatian\", \"guj\": \"Gujarati\", \"gwi\": \"Gwich'in\", \"hai\": \"Haida\", \"hat\": \"Haitian; Haitian Creole\", \"hau\": \"Hausa\", \"haw\": \"Hawaiian\", \"heb\": \"Hebrew\", \"her\": \"Herero\", \"hil\": \"Hiligaynon\", \"him\": \"Himachali languages; Western Pahari languages\", \"hin\": \"Hindi\", \"hit\": \"Hittite\", \"hmn\": \"Hmong; Mong\", \"hmo\": \"Hiri Motu\", \"hrv\": \"Croatian\", \"hsb\": \"Upper Sorbian\", \"hun\": \"Hungarian\", \"hup\": \"Hupa\", \"iba\": \"Iban\", \"ibo\": \"Igbo\", \"ice\": \"Icelandic\", \"ido\": \"Ido\", \"iii\": \"Sichuan Yi; Nuosu\", \"ijo\": \"Ijo languages\", \"iku\": \"Inuktitut\", \"ile\": \"Interlingue; Occidental\", \"ilo\": \"Iloko\", \"ina\": \"Interlingua (International Auxiliary Language Association)\", \"inc\": \"Indic languages\", \"ind\": \"Indonesian\", \"ine\": \"Indo-European languages\", \"inh\": \"Ingush\", \"ipk\": \"Inupiaq\", \"ira\": \"Iranian languages\", \"iro\": \"Iroquoian languages\", \"ita\": \"Italian\", \"jav\": \"Javanese\", \"jbo\": \"Lojban\", \"jpn\": \"Japanese\", \"jpr\": \"Judeo-Persian\", \"jrb\": \"Judeo-Arabic\", \"kaa\": \"Kara-Kalpak\", \"kab\": \"Kabyle\", \"kac\": \"Kachin; Jingpho\", \"kal\": \"Kalaallisut; Greenlandic\", \"kam\": \"Kamba\", \"kan\": \"Kannada\", \"kar\": \"Karen languages\", \"kas\": \"Kashmiri\", \"kau\": \"Kanuri\", \"kaw\": \"Kawi\", \"kaz\": \"Kazakh\", \"kbd\": \"Kabardian\", \"kha\": \"Khasi\", \"khi\": \"Khoisan languages\", \"khm\": \"Central Khmer\", \"kho\": \"Khotanese; Sakan\", \"kik\": \"Kikuyu; Gikuyu\", \"kin\": \"Kinyarwanda\", \"kir\": \"Kirghiz; Kyrgyz\", \"kmb\": \"Kimbundu\", \"kok\": \"Konkani\", \"kom\": \"Komi\", \"kon\": \"Kongo\", \"kor\": \"Korean\", \"kos\": \"Kosraean\", \"kpe\": \"Kpelle\", \"krc\": \"Karachay-Balkar\", \"krl\": \"Karelian\", \"kro\": \"Kru languages\", \"kru\": \"Kurukh\", \"kua\": \"Kuanyama; Kwanyama\", \"kum\": \"Kumyk\", \"kur\": \"Kurdish\", \"kut\": \"Kutenai\", \"lad\": \"Ladino\", \"lah\": \"Lahnda\", \"lam\": \"Lamba\", \"lao\": \"Lao\", \"lat\": \"Latin\", \"lav\": \"Latvian\", \"lez\": \"Lezghian\", \"lim\": \"Limburgan; Limburger; Limburgish\", \"lin\": \"Lingala\", \"lit\": \"Lithuanian\", \"lol\": \"Mongo\", \"loz\": \"Lozi\", \"ltz\": \"Luxembourgish; Letzeburgesch\", \"lua\": \"Luba-Lulua\", \"lub\": \"Luba-Katanga\", \"lug\": \"Ganda\", \"lui\": \"Luiseno\", \"lun\": \"Lunda\", \"luo\": \"Luo (Kenya and Tanzania)\", \"lus\": \"Lushai\", \"mac\": \"Macedonian\", \"mad\": \"Madurese\", \"mag\": \"Magahi\", \"mah\": \"Marshallese\", \"mai\": \"Maithili\", \"mak\": \"Makasar\", \"mal\": \"Malayalam\", \"man\": \"Mandingo\", \"mao\": \"Maori\", \"map\": \"Austronesian languages\", \"mar\": \"Marathi\", \"mas\": \"Masai\", \"may\": \"Malay\", \"mdf\": \"Moksha\", \"mdr\": \"Mandar\", \"men\": \"Mende\", \"mga\": \"Irish, Middle (900-1200)\", \"mic\": \"Mi'kmaq; Micmac\", \"min\": \"Minangkabau\", \"mis\": \"Uncoded languages\", \"mkh\": \"Mon-Khmer languages\", \"mlg\": \"Malagasy\", \"mlt\": \"Maltese\", \"mnc\": \"Manchu\", \"mni\": \"Manipuri\", \"mno\": \"Manobo languages\", \"moh\": \"Mohawk\", \"mon\": \"Mongolian\", \"mos\": \"Mossi\", \"mul\": \"Multiple languages\", \"mun\": \"Munda languages\", \"mus\": \"Creek\", \"mwl\": \"Mirandese\", \"mwr\": \"Marwari\", \"myn\": \"Mayan languages\", \"myv\": \"Erzya\", \"nah\": \"Nahuatl languages\", \"nai\": \"North American Indian languages\", \"nap\": \"Neapolitan\", \"nau\": \"Nauru\", \"nav\": \"Navajo; Navaho\", \"nbl\": \"Ndebele, South; South Ndebele\", \"nde\": \"Ndebele, North; North Ndebele\", \"ndo\": \"Ndonga\", \"nds\": \"Low German; Low Saxon; German, Low; Saxon, Low\", \"nep\": \"Nepali\", \"new\": \"Nepal Bhasa; Newari\", \"nia\": \"Nias\", \"nic\": \"Niger-Kordofanian languages\", \"niu\": \"Niuean\", \"nno\": \"Norwegian Nynorsk; Nynorsk, Norwegian\", \"nob\": \"Bokmål, Norwegian; Norwegian Bokmål\", \"nog\": \"Nogai\", \"non\": \"Norse, Old\", \"nor\": \"Norwegian\", \"nqo\": \"N'Ko\", \"nso\": \"Pedi; Sepedi; Northern Sotho\", \"nub\": \"Nubian languages\", \"nwc\": \"Classical Newari; Old Newari; Classical Nepal Bhasa\", \"nya\": \"Chichewa; Chewa; Nyanja\", \"nym\": \"Nyamwezi\", \"nyn\": \"Nyankole\", \"nyo\": \"Nyoro\", \"nzi\": \"Nzima\", \"oci\": \"Occitan (post 1500); Provençal\", \"oji\": \"Ojibwa\", \"ori\": \"Oriya\", \"orm\": \"Oromo\", \"osa\": \"Osage\", \"oss\": \"Ossetian; Ossetic\", \"ota\": \"Turkish, Ottoman (1500-1928)\", \"oto\": \"Otomian languages\", \"paa\": \"Papuan languages\", \"pag\": \"Pangasinan\", \"pal\": \"Pahlavi\", \"pam\": \"Pampanga; Kapampangan\", \"pan\": \"Panjabi; Punjabi\", \"pap\": \"Papiamento\", \"pau\": \"Palauan\", \"peo\": \"Persian, Old (ca.600-400 B.C.)\", \"per\": \"Persian\", \"phi\": \"Philippine languages\", \"phn\": \"Phoenician\", \"pli\": \"Pali\", \"pol\": \"Polish\", \"pon\": \"Pohnpeian\", \"por\": \"Portuguese\", \"pob\": \"Portuguese (Brazil)\", \"pra\": \"Prakrit languages\", \"pro\": \"Provençal, Old (to 1500)\", \"pus\": \"Pushto; Pashto\", \"qaa-qtz\": \"Reserved for local use\", \"que\": \"Quechua\", \"raj\": \"Rajasthani\", \"rap\": \"Rapanui\", \"rar\": \"Rarotongan; Cook Islands Maori\", \"roa\": \"Romance languages\", \"roh\": \"Romansh\", \"rom\": \"Romany\", \"rum\": \"Romanian; Moldavian; Moldovan\", \"run\": \"Rundi\", \"rup\": \"Aromanian; Arumanian; Macedo-Romanian\", \"rus\": \"Russian\", \"sad\": \"Sandawe\", \"sag\": \"Sango\", \"sah\": \"Yakut\", \"sai\": \"South American Indian (Other)\", \"sal\": \"Salishan languages\", \"sam\": \"Samaritan Aramaic\", \"san\": \"Sanskrit\", \"sas\": \"Sasak\", \"sat\": \"Santali\", \"scn\": \"Sicilian\", \"sco\": \"Scots\", \"sel\": \"Selkup\", \"sem\": \"Semitic languages\", \"sga\": \"Irish, Old (to 900)\", \"sgn\": \"Sign Languages\", \"shn\": \"Shan\", \"sid\": \"Sidamo\", \"sin\": \"Sinhala; Sinhalese\", \"sio\": \"Siouan languages\", \"sit\": \"Sino-Tibetan languages\", \"sla\": \"Slavic languages\", \"slo\": \"Slovak\", \"slv\": \"Slovenian\", \"sma\": \"Southern Sami\", \"sme\": \"Northern Sami\", \"smi\": \"Sami languages\", \"smj\": \"Lule Sami\", \"smn\": \"Inari Sami\", \"smo\": \"Samoan\", \"sms\": \"Skolt Sami\", \"sna\": \"Shona\", \"snd\": \"Sindhi\", \"snk\": \"Soninke\", \"sog\": \"Sogdian\", \"som\": \"Somali\", \"son\": \"Songhai languages\", \"sot\": \"Sotho, Southern\", \"spa\": \"Spanish; Latin\", \"spa\": \"Spanish; Castilian\", \"srd\": \"Sardinian\", \"srn\": \"Sranan Tongo\", \"srp\": \"Serbian\", \"srr\": \"Serer\", \"ssa\": \"Nilo-Saharan languages\", \"ssw\": \"Swati\", \"suk\": \"Sukuma\", \"sun\": \"Sundanese\", \"sus\": \"Susu\", \"sux\": \"Sumerian\", \"swa\": \"Swahili\", \"swe\": \"Swedish\", \"syc\": \"Classical Syriac\", \"syr\": \"Syriac\", \"tah\": \"Tahitian\", \"tai\": \"Tai languages\", \"tam\": \"Tamil\", \"tat\": \"Tatar\", \"tel\": \"Telugu\", \"tem\": \"Timne\", \"ter\": \"Tereno\", \"tet\": \"Tetum\", \"tgk\": \"Tajik\", \"tgl\": \"Tagalog\", \"tha\": \"Thai\", \"tib\": \"Tibetan\", \"tig\": \"Tigre\", \"tir\": \"Tigrinya\", \"tiv\": \"Tiv\", \"tkl\": \"Tokelau\", \"tlh\": \"Klingon; tlhIngan-Hol\", \"tli\": \"Tlingit\", \"tmh\": \"Tamashek\", \"tog\": \"Tonga (Nyasa)\", \"ton\": \"Tonga (Tonga Islands)\", \"tpi\": \"Tok Pisin\", \"tsi\": \"Tsimshian\", \"tsn\": \"Tswana\", \"tso\": \"Tsonga\", \"tuk\": \"Turkmen\", \"tum\": \"Tumbuka\", \"tup\": \"Tupi languages\", \"tur\": \"Turkish\", \"tut\": \"Altaic languages\", \"tvl\": \"Tuvalu\", \"twi\": \"Twi\", \"tyv\": \"Tuvinian\", \"udm\": \"Udmurt\", \"uga\": \"Ugaritic\", \"uig\": \"Uighur; Uyghur\", \"ukr\": \"Ukrainian\", \"umb\": \"Umbundu\", \"und\": \"Undetermined\", \"urd\": \"Urdu\", \"uzb\": \"Uzbek\", \"vai\": \"Vai\", \"ven\": \"Venda\", \"vie\": \"Vietnamese\", \"vol\": \"Volapük\", \"vot\": \"Votic\", \"wak\": \"Wakashan languages\", \"wal\": \"Walamo\", \"war\": \"Waray\", \"was\": \"Washo\", \"wel\": \"Welsh\", \"wen\": \"Sorbian languages\", \"wln\": \"Walloon\", \"wol\": \"Wolof\", \"xal\": \"Kalmyk; Oirat\", \"xho\": \"Xhosa\", \"yao\": \"Yao\", \"yap\": \"Yapese\", \"yid\": \"Yiddish\", \"yor\": \"Yoruba\", \"ypk\": \"Yupik languages\", \"zap\": \"Zapotec\", \"zbl\": \"Blissymbols; Blissymbolics; Bliss\", \"zen\": \"Zenaga\", \"zgh\": \"Standard Moroccan Tamazight\", \"zha\": \"Zhuang; Chuang\", \"znd\": \"Zande languages\", \"zul\": \"Zulu\", \"zun\": \"Zuni\", \"zxx\": \"No linguistic content; Not applicable\", \"zza\": \"Zaza; Dimili; Dimli; Kirdki; Kirmanjki; Zazaki\" } end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_config_LoginScene.brs.html":{"id":"components_config_LoginScene.brs.html","title":"Source: components/config/LoginScene.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/config/LoginScene.brs sub init() m.top.setFocus(true) m.top.optionsAvailable = false end sub function onKeyEvent(key as string, press as boolean) as boolean ' Returns true if user navigates to a new focusable element if not press then return false list = m.top.findNode(\"configOptions\") checkbox = m.top.findNode(\"onOff\") submit = m.top.findNode(\"submit\") quickConnect = m.top.findNode(\"quickConnect\") if key = \"back\" m.top.backPressed = true else if key = \"down\" and checkbox.focusedChild = invalid and submit.focusedChild = invalid limit = list.content.getChildren(-1, 0).count() - 1 if limit = list.itemFocused checkbox.setFocus(true) return true end if else if key = \"down\" and submit.focusedChild = invalid submit.setFocus(true) return true else if key = \"up\" and submit.focusedChild &lt;&gt; invalid checkbox.setFocus(true) return true else if key = \"up\" and quickConnect.focusedChild &lt;&gt; invalid checkbox.setFocus(true) return true else if key = \"up\" and checkbox.focusedChild &lt;&gt; invalid list.setFocus(true) return true else if key = \"right\" and checkbox.focusedChild &lt;&gt; invalid quickConnect.setFocus(true) return true else if key = \"right\" and submit.focusedChild &lt;&gt; invalid quickConnect.setFocus(true) return true else if key = \"left\" and quickConnect.focusedChild &lt;&gt; invalid submit.setFocus(true) return true end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"source_Main.brs.html":{"id":"source_Main.brs.html","title":"Source: source/Main.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: source/Main.brs sub Main (args as dynamic) as void ' The main function that runs when the application is launched. m.screen = CreateObject(\"roSGScreen\") ' Set global constants setConstants() ' Write screen tracker for screensaver WriteAsciiFile(\"tmp:/scene.temp\", \"\") MoveFile(\"tmp:/scene.temp\", \"tmp:/scene\") m.port = CreateObject(\"roMessagePort\") m.screen.setMessagePort(m.port) ' Set any initial Global Variables m.global = m.screen.getGlobalNode() SaveAppToGlobal() SaveDeviceToGlobal() session.Init() m.scene = m.screen.CreateScene(\"JFScene\") m.screen.show() ' vscode_rale_tracker_entry playstateTask = CreateObject(\"roSGNode\", \"PlaystateTask\") playstateTask.id = \"playstateTask\" sceneManager = CreateObject(\"roSGNode\", \"SceneManager\") sceneManager.observeField(\"dataReturned\", m.port) m.global.addFields({ app_loaded: false, playstateTask: playstateTask, sceneManager: sceneManager }) m.global.addFields({ queueManager: CreateObject(\"roSGNode\", \"QueueManager\") }) m.global.addFields({ audioPlayer: CreateObject(\"roSGNode\", \"AudioPlayer\") }) app_start: ' First thing to do is validate the ability to use the API if not LoginFlow() then return ' tell jellyfin server about device capabilities PostDeviceProfile() ' remove previous scenes from the stack sceneManager.callFunc(\"clearScenes\") ' load home page sceneManager.currentUser = m.global.session.user.name group = CreateHomeGroup() group.callFunc(\"loadLibraries\") sceneManager.callFunc(\"pushScene\", group) m.scene.observeField(\"exit\", m.port) ' Downloads and stores a fallback font to tmp:/ configEncoding = api.system.GetConfigurationByName(\"encoding\") if isValid(configEncoding) and isValid(configEncoding.EnableFallbackFont) if configEncoding.EnableFallbackFont re = CreateObject(\"roRegex\", \"Name.:.(.*?).,.Size\", \"s\") filename = APIRequest(\"FallbackFont/Fonts\").GetToString() if isValid(filename) filename = re.match(filename) if isValid(filename) and filename.count() &gt; 0 filename = filename[1] APIRequest(\"FallbackFont/Fonts/\" + filename).gettofile(\"tmp:/font\") end if end if end if end if ' Save the global last run version of the app if m.global.app.version &lt;&gt; m.global.app.lastRunVersion ' update global LastRunVersion set_setting(\"LastRunVersion\", m.global.app.version) ' Show the Whats New popup if m.global.session.user.settings[\"load.allowwhatsnew\"] = true dialog = createObject(\"roSGNode\", \"WhatsNewDialog\") m.scene.dialog = dialog m.scene.dialog.observeField(\"buttonSelected\", m.port) end if end if ' Save the user last run version of the app if m.global.session.user.lastRunVersion &lt;&gt; m.global.app.lastRunVersion ' update user LastRunVersion set_user_setting(\"LastRunVersion\", m.global.app.version) session.user.Update(\"lastRunVersion\", m.global.app.version) end if ' Handle input messages input = CreateObject(\"roInput\") input.SetMessagePort(m.port) device = CreateObject(\"roDeviceInfo\") device.setMessagePort(m.port) device.EnableScreensaverExitedEvent(true) device.EnableAppFocusEvent(true) device.EnableLowGeneralMemoryEvent(true) device.EnableLinkStatusEvent(true) device.EnableCodecCapChangedEvent(true) device.EnableAudioGuideChangedEvent(true) ' Check if we were sent content to play with the startup command (Deep Link) if isValidAndNotEmpty(args.mediaType) and isValidAndNotEmpty(args.contentId) deepLinkVideo = { id: args.contentId, type: \"video\" } m.global.queueManager.callFunc(\"push\", deepLinkVideo) m.global.queueManager.callFunc(\"playQueue\") end if ' This is the core logic loop. Mostly for transitioning between scenes ' This now only references m. fields so could be placed anywhere, in theory ' \"group\" is always \"whats on the screen\" ' m.scene's children is the \"previous view\" stack while true msg = wait(0, m.port) if type(msg) = \"roSGScreenEvent\" and msg.isScreenClosed() print \"CLOSING SCREEN\" return else if isNodeEvent(msg, \"exit\") return else if isNodeEvent(msg, \"closeSidePanel\") group = sceneManager.callFunc(\"getActiveScene\") if group.lastFocus &lt;&gt; invalid group.lastFocus.setFocus(true) else group.setFocus(true) end if else if isNodeEvent(msg, \"quickPlayNode\") ' measure processing time timeSpan = CreateObject(\"roTimespan\") startMediaLoadingSpinner() group = sceneManager.callFunc(\"getActiveScene\") reportingNode = msg.getRoSGNode() itemNode = invalid if isValid(reportingNode) itemNode = reportingNode.quickPlayNode reportingNodeType = reportingNode.subtype() print \"Quick Play reporting node type=\", reportingNodeType ' prevent double fire bug if isValid(reportingNodeType) and (reportingNodeType = \"Home\" or reportingNodeType = \"TVEpisodes\") reportingNode.quickPlayNode = invalid end if end if print \"Quick Play started. itemNode=\", itemNode ' if itemNode.json &lt;&gt; invalid ' print \"itemNode.json=\", itemNode.json ' end if if isValid(itemNode) and isValid(itemNode.id) and itemNode.id &lt;&gt; \"\" ' make sure there is a type and convert type to lowercase itemType = invalid if isValid(itemNode.type) and itemNode.type &lt;&gt; \"\" itemType = Lcase(itemNode.type) else ' grab type from json and convert to lowercase if isValid(itemNode.json) and isValid(itemNode.json.type) itemType = Lcase(itemNode.json.type) end if end if print \"Quick Play itemNode type=\", itemType ' can't play the item without knowing what type it is if isValid(itemType) m.global.queueManager.callFunc(\"clear\") ' empty queue/playlist m.global.queueManager.callFunc(\"resetShuffle\") ' turn shuffle off if itemType = \"episode\" or itemType = \"movie\" or itemType = \"video\" quickplay.video(itemNode) ' restore focus if LCase(group.subtype()) = \"tvepisodes\" if isValid(group.lastFocus) group.lastFocus.setFocus(true) end if end if else if itemType = \"audio\" quickplay.audio(itemNode) else if itemType = \"musicalbum\" quickplay.album(itemNode) else if itemType = \"musicartist\" quickplay.artist(itemNode) else if itemType = \"series\" quickplay.series(itemNode) else if itemType = \"season\" quickplay.season(itemNode) else if itemType = \"boxset\" quickplay.boxset(itemNode) else if itemType = \"collectionfolder\" quickplay.collectionFolder(itemNode) else if itemType = \"playlist\" quickplay.playlist(itemNode) else if itemType = \"userview\" quickplay.userView(itemNode) else if itemType = \"folder\" quickplay.folder(itemNode) else if itemType = \"musicvideo\" quickplay.musicVideo(itemNode) else if itemType = \"person\" quickplay.person(itemNode) else if itemType = \"tvchannel\" quickplay.tvChannel(itemNode) else if itemType = \"program\" quickplay.program(itemNode) end if m.global.queueManager.callFunc(\"playQueue\") end if end if stopLoadingSpinner() elapsed = timeSpan.TotalMilliseconds() / 1000 print \"Quick Play finished loading in \" + elapsed.toStr() + \" seconds.\" else if isNodeEvent(msg, \"selectedItem\") ' If you select a library from ANYWHERE, follow this flow selectedItem = msg.getData() if isValid(selectedItem) selectedItemType = selectedItem.type if selectedItemType = \"CollectionFolder\" if selectedItem.collectionType = \"movies\" group = CreateMovieLibraryView(selectedItem) else if selectedItem.collectionType = \"music\" group = CreateMusicLibraryView(selectedItem) else group = CreateItemGrid(selectedItem) end if sceneManager.callFunc(\"pushScene\", group) else if selectedItemType = \"Folder\" and selectedItem.json.type = \"Genre\" ' User clicked on a genre folder if selectedItem.json.MovieCount &gt; 0 group = CreateMovieLibraryView(selectedItem) else group = CreateItemGrid(selectedItem) end if sceneManager.callFunc(\"pushScene\", group) else if selectedItemType = \"Folder\" and selectedItem.json.type = \"MusicGenre\" group = CreateMusicLibraryView(selectedItem) sceneManager.callFunc(\"pushScene\", group) else if selectedItemType = \"UserView\" or selectedItemType = \"Folder\" or selectedItemType = \"Channel\" or selectedItemType = \"Boxset\" group = CreateItemGrid(selectedItem) sceneManager.callFunc(\"pushScene\", group) else if selectedItemType = \"Episode\" ' User has selected a TV episode they want us to play audio_stream_idx = 0 if isValid(selectedItem.selectedAudioStreamIndex) and selectedItem.selectedAudioStreamIndex &gt; 0 audio_stream_idx = selectedItem.selectedAudioStreamIndex end if selectedItem.selectedAudioStreamIndex = audio_stream_idx ' Display playback options dialog if selectedItem.json.userdata.PlaybackPositionTicks &gt; 0 m.global.queueManager.callFunc(\"hold\", selectedItem) playbackOptionDialog(selectedItem.json.userdata.PlaybackPositionTicks, selectedItem.json) else m.global.queueManager.callFunc(\"clear\") m.global.queueManager.callFunc(\"push\", selectedItem) m.global.queueManager.callFunc(\"playQueue\") end if else if selectedItemType = \"Series\" group = CreateSeriesDetailsGroup(selectedItem.json.id) else if selectedItemType = \"Season\" group = CreateSeasonDetailsGroupByID(selectedItem.json.SeriesId, selectedItem.id) else if selectedItemType = \"Movie\" ' open movie detail page group = CreateMovieDetailsGroup(selectedItem) else if selectedItemType = \"Person\" CreatePersonView(selectedItem) else if selectedItemType = \"TvChannel\" or selectedItemType = \"Video\" or selectedItemType = \"Program\" ' User selected a Live TV channel / program ' Show Channel Loading spinner dialog = createObject(\"roSGNode\", \"ProgressDialog\") dialog.title = tr(\"Loading Channel Data\") m.scene.dialog = dialog ' User selected a program. Play the channel the program is on if LCase(selectedItemType) = \"program\" selectedItem.id = selectedItem.json.ChannelId end if ' Display playback options dialog if selectedItem.json.userdata.PlaybackPositionTicks &gt; 0 dialog.close = true m.global.queueManager.callFunc(\"hold\", selectedItem) playbackOptionDialog(selectedItem.json.userdata.PlaybackPositionTicks, selectedItem.json) else m.global.queueManager.callFunc(\"clear\") m.global.queueManager.callFunc(\"push\", selectedItem) m.global.queueManager.callFunc(\"playQueue\") dialog.close = true end if else if selectedItemType = \"Photo\" ' Nothing to do here, handled in ItemGrid else if selectedItemType = \"MusicArtist\" group = CreateArtistView(selectedItem.json) if not isValid(group) message_dialog(tr(\"Unable to find any albums or songs belonging to this artist\")) end if else if selectedItemType = \"MusicAlbum\" group = CreateAlbumView(selectedItem.json) else if selectedItemType = \"MusicVideo\" group = CreateMovieDetailsGroup(selectedItem) else if selectedItemType = \"Playlist\" group = CreatePlaylistView(selectedItem.json) else if selectedItemType = \"Audio\" m.global.queueManager.callFunc(\"clear\") m.global.queueManager.callFunc(\"resetShuffle\") m.global.queueManager.callFunc(\"push\", selectedItem.json) m.global.queueManager.callFunc(\"playQueue\") else ' TODO - switch on more node types message_dialog(\"This type is not yet supported: \" + selectedItemType + \".\") end if end if else if isNodeEvent(msg, \"movieSelected\") ' If you select a movie from ANYWHERE, follow this flow node = getMsgPicker(msg, \"picker\") group = CreateMovieDetailsGroup(node) else if isNodeEvent(msg, \"seriesSelected\") ' If you select a TV Series from ANYWHERE, follow this flow node = getMsgPicker(msg, \"picker\") group = CreateSeriesDetailsGroup(node.id) else if isNodeEvent(msg, \"seasonSelected\") ' If you select a TV Season from ANYWHERE, follow this flow ptr = msg.getData() ' ptr is for [row, col] of selected item... but we only have 1 row series = msg.getRoSGNode() if isValid(ptr) and ptr.count() &gt;= 2 and isValid(ptr[1]) and isValid(series) and isValid(series.seasonData) and isValid(series.seasonData.items) node = series.seasonData.items[ptr[1]] group = CreateSeasonDetailsGroup(series.itemContent, node) end if else if isNodeEvent(msg, \"musicAlbumSelected\") ' If you select a Music Album from ANYWHERE, follow this flow ptr = msg.getData() albums = msg.getRoSGNode() node = albums.musicArtistAlbumData.items[ptr] group = CreateAlbumView(node) else if isNodeEvent(msg, \"appearsOnSelected\") ' If you select a Music Album from ANYWHERE, follow this flow ptr = msg.getData() albums = msg.getRoSGNode() node = albums.musicArtistAppearsOnData.items[ptr] group = CreateAlbumView(node) else if isNodeEvent(msg, \"playSong\") ' User has selected audio they want us to play selectedIndex = msg.getData() screenContent = msg.getRoSGNode() m.global.queueManager.callFunc(\"clear\") m.global.queueManager.callFunc(\"resetShuffle\") m.global.queueManager.callFunc(\"push\", screenContent.albumData.items[selectedIndex]) m.global.queueManager.callFunc(\"playQueue\") else if isNodeEvent(msg, \"playItem\") ' User has selected audio they want us to play selectedIndex = msg.getData() screenContent = msg.getRoSGNode() m.global.queueManager.callFunc(\"clear\") m.global.queueManager.callFunc(\"resetShuffle\") m.global.queueManager.callFunc(\"push\", screenContent.albumData.items[selectedIndex]) m.global.queueManager.callFunc(\"playQueue\") else if isNodeEvent(msg, \"playAllSelected\") ' User has selected playlist of of audio they want us to play screenContent = msg.getRoSGNode() m.spinner = screenContent.findNode(\"spinner\") m.spinner.visible = true m.global.queueManager.callFunc(\"clear\") m.global.queueManager.callFunc(\"resetShuffle\") m.global.queueManager.callFunc(\"set\", screenContent.albumData.items) m.global.queueManager.callFunc(\"playQueue\") else if isNodeEvent(msg, \"playArtistSelected\") ' User has selected playlist of of audio they want us to play screenContent = msg.getRoSGNode() m.global.queueManager.callFunc(\"clear\") m.global.queueManager.callFunc(\"resetShuffle\") m.global.queueManager.callFunc(\"set\", CreateArtistMix(screenContent.pageContent.id).Items) m.global.queueManager.callFunc(\"playQueue\") else if isNodeEvent(msg, \"instantMixSelected\") ' User has selected instant mix ' User has selected playlist of of audio they want us to play screenContent = msg.getRoSGNode() m.spinner = screenContent.findNode(\"spinner\") if isValid(m.spinner) m.spinner.visible = true end if viewHandled = false ' Create instant mix based on selected album if isValid(screenContent.albumData) if isValid(screenContent.albumData.items) if screenContent.albumData.items.count() &gt; 0 m.global.queueManager.callFunc(\"clear\") m.global.queueManager.callFunc(\"resetShuffle\") m.global.queueManager.callFunc(\"set\", CreateInstantMix(screenContent.albumData.items[0].id).Items) m.global.queueManager.callFunc(\"playQueue\") viewHandled = true end if end if end if if not viewHandled ' Create instant mix based on selected artist m.global.queueManager.callFunc(\"clear\") m.global.queueManager.callFunc(\"resetShuffle\") m.global.queueManager.callFunc(\"set\", CreateInstantMix(screenContent.pageContent.id).Items) m.global.queueManager.callFunc(\"playQueue\") end if else if isNodeEvent(msg, \"search_value\") query = msg.getRoSGNode().search_value group.findNode(\"SearchBox\").visible = false options = group.findNode(\"SearchSelect\") options.visible = true options.setFocus(true) dialog = createObject(\"roSGNode\", \"ProgressDialog\") dialog.title = tr(\"Loading Search Data\") m.scene.dialog = dialog results = SearchMedia(query) dialog.close = true options.itemData = results options.query = query else if isNodeEvent(msg, \"itemSelected\") ' Search item selected node = getMsgPicker(msg) ' TODO - swap this based on target.mediatype ' types: [ Series (Show), Episode, Movie, Audio, Person, Studio, MusicArtist ] if node.type = \"Series\" group = CreateSeriesDetailsGroup(node.id) else if node.type = \"Movie\" group = CreateMovieDetailsGroup(node) else if node.type = \"MusicArtist\" group = CreateArtistView(node.json) else if node.type = \"MusicAlbum\" group = CreateAlbumView(node.json) else if node.type = \"MusicVideo\" group = CreateMovieDetailsGroup(node) else if node.type = \"Audio\" m.global.queueManager.callFunc(\"clear\") m.global.queueManager.callFunc(\"resetShuffle\") m.global.queueManager.callFunc(\"push\", node.json) m.global.queueManager.callFunc(\"playQueue\") else if node.type = \"Person\" group = CreatePersonView(node) else if node.type = \"TvChannel\" group = CreateVideoPlayerGroup(node.id) sceneManager.callFunc(\"pushScene\", group) else if node.type = \"Episode\" group = CreateVideoPlayerGroup(node.id) sceneManager.callFunc(\"pushScene\", group) else if node.type = \"Audio\" selectedIndex = msg.getData() screenContent = msg.getRoSGNode() m.global.queueManager.callFunc(\"clear\") m.global.queueManager.callFunc(\"resetShuffle\") m.global.queueManager.callFunc(\"push\", screenContent.albumData.items[node.id]) m.global.queueManager.callFunc(\"playQueue\") else ' TODO - switch on more node types message_dialog(\"This type is not yet supported: \" + node.type + \".\") end if else if isNodeEvent(msg, \"buttonSelected\") ' If a button is selected, we have some determining to do btn = getButton(msg) group = sceneManager.callFunc(\"getActiveScene\") if isValid(btn) and btn.id = \"play-button\" ' User chose Play button from movie detail view ' Check if a specific Audio Stream was selected audio_stream_idx = 0 if isValid(group) and isValid(group.selectedAudioStreamIndex) audio_stream_idx = group.selectedAudioStreamIndex end if group.itemContent.selectedAudioStreamIndex = audio_stream_idx group.itemContent.id = group.selectedVideoStreamId ' Display playback options dialog if group.itemContent.json.userdata.PlaybackPositionTicks &gt; 0 m.global.queueManager.callFunc(\"hold\", group.itemContent) playbackOptionDialog(group.itemContent.json.userdata.PlaybackPositionTicks, group.itemContent.json) else m.global.queueManager.callFunc(\"clear\") m.global.queueManager.callFunc(\"push\", group.itemContent) m.global.queueManager.callFunc(\"playQueue\") end if if isValid(group) and isValid(group.lastFocus) and isValid(group.lastFocus.id) and group.lastFocus.id = \"main_group\" buttons = group.findNode(\"buttons\") if isValid(buttons) group.lastFocus = group.findNode(\"buttons\") end if end if if isValid(group) and isValid(group.lastFocus) group.lastFocus.setFocus(true) end if else if btn &lt;&gt; invalid and btn.id = \"trailer-button\" ' User chose to play a trailer from the movie detail view dialog = createObject(\"roSGNode\", \"ProgressDialog\") dialog.title = tr(\"Loading trailer\") m.scene.dialog = dialog trailerData = api.users.GetLocalTrailers(m.global.session.user.id, group.id) if isValid(trailerData) and isValid(trailerData[0]) and isValid(trailerData[0].id) m.global.queueManager.callFunc(\"clear\") m.global.queueManager.callFunc(\"set\", trailerData) m.global.queueManager.callFunc(\"playQueue\") dialog.close = true end if if isValid(group) and isValid(group.lastFocus) group.lastFocus.setFocus(true) end if else if btn &lt;&gt; invalid and btn.id = \"watched-button\" movie = group.itemContent if isValid(movie) and isValid(movie.watched) and isValid(movie.id) if movie.watched UnmarkItemWatched(movie.id) else MarkItemWatched(movie.id) end if movie.watched = not movie.watched end if else if btn &lt;&gt; invalid and btn.id = \"favorite-button\" movie = group.itemContent if movie.favorite UnmarkItemFavorite(movie.id) else MarkItemFavorite(movie.id) end if movie.favorite = not movie.favorite else ' If there are no other button matches, check if this is a simple \"OK\" Dialog &amp; Close if so dialog = msg.getRoSGNode() if dialog.id = \"OKDialog\" dialog.unobserveField(\"buttonSelected\") dialog.close = true end if end if else if isNodeEvent(msg, \"optionSelected\") button = msg.getRoSGNode() group = sceneManager.callFunc(\"getActiveScene\") if button.id = \"goto_search\" and isValid(group) ' Exit out of the side panel panel = group.findNode(\"options\") panel.visible = false if isValid(group.lastFocus) group.lastFocus.setFocus(true) else group.setFocus(true) end if group = CreateSearchPage() sceneManager.callFunc(\"pushScene\", group) group.findNode(\"SearchBox\").findNode(\"search_Key\").setFocus(true) group.findNode(\"SearchBox\").findNode(\"search_Key\").active = true else if button.id = \"change_server\" unset_setting(\"server\") session.server.Delete() SignOut(false) sceneManager.callFunc(\"clearScenes\") goto app_start else if button.id = \"change_user\" SignOut(false) sceneManager.callFunc(\"clearScenes\") goto app_start else if button.id = \"sign_out\" SignOut() sceneManager.callFunc(\"clearScenes\") goto app_start else if button.id = \"settings\" ' Exit out of the side panel panel = group.findNode(\"options\") panel.visible = false if isValid(group) and isValid(group.lastFocus) group.lastFocus.setFocus(true) else group.setFocus(true) end if sceneManager.callFunc(\"settings\") end if else if isNodeEvent(msg, \"selectSubtitlePressed\") node = m.scene.focusedChild if node.focusedChild &lt;&gt; invalid and node.focusedChild.isSubType(\"JFVideo\") trackSelected = selectSubtitleTrack(node.Subtitles, node.SelectedSubtitle) if trackSelected &lt;&gt; invalid and trackSelected &lt;&gt; -2 changeSubtitleDuringPlayback(trackSelected) end if end if else if isNodeEvent(msg, \"selectPlaybackInfoPressed\") node = m.scene.focusedChild if node.focusedChild &lt;&gt; invalid and node.focusedChild.isSubType(\"JFVideo\") info = GetPlaybackInfo() show_dialog(tr(\"Playback Information\"), info) end if else if isNodeEvent(msg, \"state\") node = msg.getRoSGNode() if isValid(node) and isValid(node.state) if node.selectedItemType = \"TvChannel\" and node.state = \"finished\" video = CreateVideoPlayerGroup(node.id) m.global.sceneManager.callFunc(\"pushScene\", video) m.global.sceneManager.callFunc(\"deleteSceneAtIndex\", 2) else if node.state = \"finished\" node.control = \"stop\" ' If node allows retrying using Transcode Url, give that shot if isValid(node.retryWithTranscoding) and node.retryWithTranscoding retryVideo = CreateVideoPlayerGroup(node.Id, invalid, node.audioIndex, true, false) m.global.sceneManager.callFunc(\"popScene\") if isValid(retryVideo) m.global.sceneManager.callFunc(\"pushScene\", retryVideo) end if else if not isValid(node.showID) sceneManager.callFunc(\"popScene\") else autoPlayNextEpisode(node.id, node.showID) end if end if end if else if type(msg) = \"roDeviceInfoEvent\" event = msg.GetInfo() if event.exitedScreensaver = true sceneManager.callFunc(\"resetTime\") group = sceneManager.callFunc(\"getActiveScene\") if isValid(group) and isValid(group.subtype()) ' refresh the current view if group.subtype() = \"Home\" currentTime = CreateObject(\"roDateTime\").AsSeconds() group.timeLastRefresh = currentTime group.callFunc(\"refresh\") end if ' todo: add other screens to be refreshed - movie detail, tv series, episode list etc. end if else if isValid(event.audioGuideEnabled) tmpGlobalDevice = m.global.device tmpGlobalDevice.AddReplace(\"isaudioguideenabled\", event.audioGuideEnabled) ' update global device array m.global.setFields({ device: tmpGlobalDevice }) else if isValid(event.Mode) ' Indicates the current global setting for the Caption Mode property, which may be one of the following values: ' \"On\" ' \"Off\" ' \"Instant replay\" ' \"When mute\" (Only returned for a TV; this option is not available on STBs). print \"event.Mode = \", event.Mode if isValid(event.Mute) print \"event.Mute = \", event.Mute end if else if isValid(event.linkStatus) ' True if the device currently seems to have an active network connection. print \"event.linkStatus = \", event.linkStatus else if isValid(event.generalMemoryLevel) ' This event will be sent first when the OS transitions from \"normal\" to \"low\" state and will continue to be sent while in \"low\" or \"critical\" states. ' - \"normal\" means that the general memory is within acceptable levels ' - \"low\" means that the general memory is below acceptable levels but not critical ' - \"critical\" means that general memory are at dangerously low level and that the OS may force terminate the application print \"event.generalMemoryLevel = \", event.generalMemoryLevel session.Update(\"memoreyLevel\", event.generalMemoryLevel) else if isValid(event.audioCodecCapabilityChanged) ' The audio codec capability has changed if true. print \"event.audioCodecCapabilityChanged = \", event.audioCodecCapabilityChanged PostDeviceProfile() else if isValid(event.videoCodecCapabilityChanged) ' The video codec capability has changed if true. print \"event.videoCodecCapabilityChanged = \", event.videoCodecCapabilityChanged PostDeviceProfile() else if isValid(event.appFocus) ' It is set to False when the System Overlay (such as the confirm partner button HUD or the caption control overlay) takes focus and True when the channel regains focus print \"event.appFocus = \", event.appFocus else print \"Unhandled roDeviceInfoEvent:\" print msg.GetInfo() end if else if type(msg) = \"roInputEvent\" if msg.IsInput() info = msg.GetInfo() if info.DoesExist(\"mediatype\") and info.DoesExist(\"contentid\") inputEventVideo = { id: info.contentId, type: \"video\" } m.global.queueManager.callFunc(\"clear\") m.global.queueManager.callFunc(\"push\", inputEventVideo) m.global.queueManager.callFunc(\"playQueue\") end if end if else if isNodeEvent(msg, \"dataReturned\") popupNode = msg.getRoSGNode() if isValid(popupNode) and isValid(popupNode.returnData) selectedItem = m.global.queueManager.callFunc(\"getHold\") m.global.queueManager.callFunc(\"clearHold\") if isValid(selectedItem) and selectedItem.count() &gt; 0 and isValid(selectedItem[0]) if popupNode.returnData.indexselected = 0 'Resume video from resume point startingPoint = 0 if isValid(selectedItem[0].json) and isValid(selectedItem[0].json.UserData) and isValid(selectedItem[0].json.UserData.PlaybackPositionTicks) if selectedItem[0].json.UserData.PlaybackPositionTicks &gt; 0 startingPoint = selectedItem[0].json.UserData.PlaybackPositionTicks end if end if selectedItem[0].startingPoint = startingPoint m.global.queueManager.callFunc(\"clear\") m.global.queueManager.callFunc(\"push\", selectedItem[0]) m.global.queueManager.callFunc(\"playQueue\") else if popupNode.returnData.indexselected = 1 'Start Over from beginning selected, set position to 0 selectedItem[0].startingPoint = 0 m.global.queueManager.callFunc(\"clear\") m.global.queueManager.callFunc(\"push\", selectedItem[0]) m.global.queueManager.callFunc(\"playQueue\") else if popupNode.returnData.indexselected = 2 ' User chose Go to series CreateSeriesDetailsGroup(selectedItem[0].json.SeriesId) else if popupNode.returnData.indexselected = 3 ' User chose Go to season CreateSeasonDetailsGroupByID(selectedItem[0].json.SeriesId, selectedItem[0].json.seasonID) else if popupNode.returnData.indexselected = 4 ' User chose Go to episode CreateMovieDetailsGroup(selectedItem[0]) end if end if end if else print \"Unhandled \" type(msg) print msg end if end while end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_MovieData.brs.html":{"id":"components_data_MovieData.brs.html","title":"Source: components/data/MovieData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/MovieData.brs import \"pkg:/source/api/Image.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" import \"pkg:/source/utils/misc.brs\" sub setFields() json = m.top.json m.top.id = json.id m.top.Title = json.name m.top.Description = json.overview m.top.favorite = json.UserData.isFavorite m.top.watched = json.UserData.played m.top.Type = \"Movie\" if isValid(json.MediaSourceCount) and json.MediaSourceCount &gt; 1 if isValid(json.MediaSources) m.top.mediaSources = [] for each source in json.MediaSources m.top.mediaSources.push(source) end for end if end if if json.ProductionYear &lt;&gt; invalid m.top.SubTitle = json.ProductionYear end if if json.OfficialRating &lt;&gt; invalid and json.OfficialRating &lt;&gt; \"\" m.top.Rating = json.OfficialRating if m.top.SubTitle &lt;&gt; \"\" m.top.SubTitle = m.top.SubTitle + \" - \" + m.top.Rating else m.top.SubTitle = m.top.Rating end if end if setPoster() setContainer() end sub sub setPoster() if m.top.image &lt;&gt; invalid m.top.posterURL = m.top.image.url else if isValid(m.top.json) if isValid(m.top.json.ImageTags) and isValid(m.top.json.ImageTags.Primary) imgParams = { \"maxHeight\": 440, \"maxWidth\": 295, \"Tag\": m.top.json.ImageTags.Primary } m.top.posterURL = ImageURL(m.top.json.id, \"Primary\", imgParams) else if isValid(m.top.json.BackdropImageTags) and isValid(m.top.json.BackdropImageTags[0]) imgParams = { \"maxHeight\": 440, \"Tag\": m.top.json.BackdropImageTags[0] } m.top.posterURL = ImageURL(m.top.json.id, \"Backdrop\", imgParams) else if isValid(m.top.json.ParentThumbImageTag) and isValid(m.top.json.ParentThumbItemId) imgParams = { \"maxHeight\": 440, \"maxWidth\": 295, \"Tag\": m.top.json.ParentThumbImageTag } m.top.posterURL = ImageURL(m.top.json.ParentThumbItemId, \"Thumb\", imgParams) end if ' Add Backdrop Image if isValid(m.top.json.BackdropImageTags) and isValid(m.top.json.BackdropImageTags[0]) imgParams = { \"maxHeight\": 720, \"maxWidth\": 1280, \"Tag\": m.top.json.BackdropImageTags[0] } m.top.backdropURL = ImageURL(m.top.json.id, \"Backdrop\", imgParams) end if end if end if end sub sub setContainer() json = m.top.json if json.mediaSources = invalid then return if json.mediaSources.count() = 0 then return m.top.container = json.mediaSources[0].container if m.top.container = invalid then m.top.container = \"\" if m.top.container = \"m4v\" or m.top.container = \"mov\" m.top.container = \"mp4\" end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_movies_MovieDetails.brs.html":{"id":"components_movies_MovieDetails.brs.html","title":"Source: components/movies/MovieDetails.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/movies/MovieDetails.brs import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/utils/config.brs\" sub init() m.extrasGrp = m.top.findnode(\"extrasGrp\") m.extrasGrid = m.top.findNode(\"extrasGrid\") m.top.optionsAvailable = false m.options = m.top.findNode(\"movieOptions\") m.infoGroup = m.top.findNode(\"infoGroup\") main = m.top.findNode(\"main_group\") main.translation = [96, 175] overview = m.top.findNode(\"overview\") overview.width = 1920 - 96 - 300 - 96 - 30 m.details = m.top.findNode(\"details\") m.tagline = m.top.findNode(\"tagline\") m.buttonGrp = m.top.findNode(\"buttons\") m.buttonGrp.setFocus(true) m.top.lastFocus = m.buttonGrp m.spinner = m.top.findNode(\"spinner\") m.top.observeField(\"itemContent\", \"itemContentChanged\") end sub sub OnScreenShown() ' set focus to button group if m.extrasGrp.opacity = 1 m.top.lastFocus.setFocus(true) else m.buttonGrp.setFocus(true) end if end sub sub trailerAvailableChanged() if m.top.trailerAvailable ' add trailor button to button group trailerButton = CreateObject(\"roSGNode\", \"Button\") trailerButton.id = \"trailer-button\" trailerButton.text = tr(\"Play Trailer\") trailerButton.iconUri = \"\" trailerButton.focusedIconUri = \"\" trailerButton.maxWidth = \"300\" trailerButton.minWidth = \"280\" m.buttonGrp.appendChild(trailerButton) else ' remove trailor button from button group m.buttonGrp.removeChild(m.top.findNode(\"trailer-button\")) end if end sub sub itemContentChanged() ' Updates video metadata item = m.top.itemContent itemData = item.json m.top.id = itemData.id m.top.findNode(\"moviePoster\").uri = m.top.itemContent.posterURL ' Set default video source if user hasn't selected one yet if m.top.selectedVideoStreamId = \"\" and isValid(itemData.MediaSources) m.top.selectedVideoStreamId = itemData.MediaSources[0].id end if ' Find first Audio Stream and set that as default SetDefaultAudioTrack(itemData) ' Handle all \"As Is\" fields m.top.overhangTitle = itemData.name setFieldText(\"releaseYear\", itemData.productionYear) setFieldText(\"overview\", itemData.overview) if itemData.officialRating &lt;&gt; invalid setFieldText(\"officialRating\", itemData.officialRating) else m.infoGroup.removeChild(m.top.findNode(\"officialRating\")) end if if itemData.communityRating &lt;&gt; invalid setFieldText(\"communityRating\", int(itemData.communityRating * 10) / 10) m.top.findNode(\"communityRatingGroup\").visible = \"true\" else ' hide the star icon m.infoGroup.removeChild(m.top.findNode(\"communityRatingGroup\")) end if if itemData.CriticRating &lt;&gt; invalid setFieldText(\"criticRatingLabel\", itemData.criticRating) if itemData.CriticRating &gt; 60 tomato = \"pkg:/images/fresh.png\" else tomato = \"pkg:/images/rotten.png\" end if m.top.findNode(\"criticRatingIcon\").uri = tomato else m.infoGroup.removeChild(m.top.findNode(\"criticRatingGroup\")) end if if type(itemData.RunTimeTicks) = \"LongInteger\" setFieldText(\"runtime\", stri(getRuntime()) + \" mins\") if m.global.session.user.settings[\"ui.design.hideclock\"] &lt;&gt; true setFieldText(\"ends-at\", tr(\"Ends at %1\").Replace(\"%1\", getEndTime())) end if end if if itemData.genres.count() &gt; 0 setFieldText(\"genres\", tr(\"Genres\") + \": \" + itemData.genres.join(\", \")) else m.top.findNode(\"details\").removeChild(m.top.findNode(\"genres\")) end if ' show tags if there are no genres to display if itemData.genres.count() = 0 and isValid(itemData.tags) and itemData.tags.count() &gt; 0 setFieldText(\"genres\", tr(\"Tags\") + \": \" + itemData.tags.join(\", \")) end if directors = [] for each person in itemData.people if person.type = \"Director\" directors.push(person.name) end if end for if directors.count() &gt; 0 setFieldText(\"director\", tr(\"Director\") + \": \" + directors.join(\", \")) else m.top.findNode(\"details\").removeChild(m.top.findNode(\"director\")) end if if m.global.session.user.settings[\"ui.details.hidetagline\"] = false if itemData.taglines.count() &gt; 0 setFieldText(\"tagline\", itemData.taglines[0]) end if else m.details.removeChild(m.tagline) end if 'set aired date if type is Episode if itemData.PremiereDate &lt;&gt; invalid and itemData.Type = \"Episode\" airDate = CreateObject(\"roDateTime\") airDate.FromISO8601String(itemData.PremiereDate) m.top.findNode(\"aired\").text = tr(\"Aired\") + \": \" + airDate.AsDateString(\"short-month-no-weekday\") 'remove movie release year label m.infoGroup.removeChild(m.top.findNode(\"releaseYear\")) end if setFavoriteColor() setWatchedColor() SetUpVideoOptions(itemData.mediaSources) SetUpAudioOptions(itemData.mediaStreams) m.buttonGrp.visible = true m.spinner.visible = false end sub sub SetUpVideoOptions(streams) videos = [] codecDetailsSet = false for i = 0 to streams.Count() - 1 if streams[i].VideoType = \"VideoFile\" codec = \"\" if streams[i].mediaStreams &lt;&gt; invalid and streams[i].mediaStreams.Count() &gt; 0 ' find the first (default) video track to get the codec for the details screen if codecDetailsSet = false for index = 0 to streams[i].mediaStreams.Count() - 1 if streams[i].mediaStreams[index].Type = \"Video\" setFieldText(\"video_codec\", tr(\"Video\") + \": \" + streams[i].mediaStreams[index].displayTitle) codecDetailsSet = true exit for end if end for end if codec = streams[i].mediaStreams[0].displayTitle end if ' Create options for user to switch between video tracks videos.push({ \"Title\": streams[i].Name, \"Description\": tr(\"Video\"), \"Selected\": m.top.selectedVideoStreamId = streams[i].id, \"StreamID\": streams[i].id, \"video_codec\": codec }) end if end for if streams.count() &gt; 1 m.top.findnode(\"video_codec_count\").text = \"+\" + stri(streams.Count() - 1).trim() end if options = {} options.videos = videos m.options.options = options end sub sub SetUpAudioOptions(streams) tracks = [] for i = 0 to streams.Count() - 1 if streams[i].Type = \"Audio\" tracks.push({ \"Title\": streams[i].displayTitle, \"Description\": streams[i].Title, \"Selected\": m.top.selectedAudioStreamIndex = i, \"StreamIndex\": i }) end if end for if tracks.count() &gt; 1 m.top.findnode(\"audio_codec_count\").text = \"+\" + stri(tracks.Count() - 1).trim() end if options = {} if m.options.options.videos &lt;&gt; invalid options.videos = m.options.options.videos end if options.audios = tracks m.options.options = options end sub sub SetDefaultAudioTrack(itemData) for i = 0 to itemData.mediaStreams.Count() - 1 if itemData.mediaStreams[i].Type = \"Audio\" m.top.selectedAudioStreamIndex = i setFieldText(\"audio_codec\", tr(\"Audio\") + \": \" + itemData.mediaStreams[i].displayTitle) exit for end if end for end sub sub setFieldText(field, value) node = m.top.findNode(field) if node = invalid or value = invalid then return ' Handle non strings... Which _shouldn't_ happen, but hey if type(value) = \"roInt\" or type(value) = \"Integer\" value = str(value) else if type(value) = \"roFloat\" or type(value) = \"Float\" value = str(value) else if type(value) &lt;&gt; \"roString\" and type(value) &lt;&gt; \"String\" value = \"\" end if node.text = value end sub function getRuntime() as integer itemData = m.top.itemContent.json ' A tick is .1ms, so 1/10,000,000 for ticks to seconds, ' then 1/60 for seconds to minutess... 1/600,000,000 return round(itemData.RunTimeTicks / 600000000.0) end function function getEndTime() as string itemData = m.top.itemContent.json date = CreateObject(\"roDateTime\") duration_s = int(itemData.RunTimeTicks / 10000000.0) date.fromSeconds(date.asSeconds() + duration_s) date.toLocalTime() return formatTime(date) end function sub setFavoriteColor() fave = m.top.itemContent.favorite fave_button = m.top.findNode(\"favorite-button\") if fave &lt;&gt; invalid and fave fave_button.textColor = \"#00ff00ff\" fave_button.focusedTextColor = \"#269926ff\" fave_button.text = tr(\"Favorite\") else fave_button.textColor = \"0xddddddff\" fave_button.focusedTextColor = \"#262626ff\" fave_button.text = tr(\"Set Favorite\") end if end sub sub setWatchedColor() watched = m.top.itemContent.watched watched_button = m.top.findNode(\"watched-button\") if watched watched_button.textColor = \"#ff0000ff\" watched_button.focusedTextColor = \"#992626ff\" watched_button.text = tr(\"Watched\") else watched_button.textColor = \"0xddddddff\" watched_button.focusedTextColor = \"#262626ff\" watched_button.text = tr(\"Set Watched\") end if end sub function round(f as float) as integer ' BrightScript only has a \"floor\" round ' This compares floor to floor + 1 to find which is closer m = int(f) n = m + 1 x = abs(f - m) y = abs(f - n) if y &gt; x return m else return n end if end function ' 'Check if options updated and any reloading required sub audioOptionsClosed() if m.options.audioStreamIndex &lt;&gt; m.top.selectedAudioStreamIndex m.top.selectedAudioStreamIndex = m.options.audioStreamIndex setFieldText(\"audio_codec\", tr(\"Audio\") + \": \" + m.top.itemContent.json.mediaStreams[m.top.selectedAudioStreamIndex].displayTitle) end if m.top.findNode(\"buttons\").setFocus(true) end sub ' ' Check if options were updated and if any reloding is needed... sub videoOptionsClosed() if m.options.videoStreamId &lt;&gt; m.top.selectedVideoStreamId m.top.selectedVideoStreamId = m.options.videoStreamId setFieldText(\"video_codec\", tr(\"Video\") + \": \" + m.options.video_codec) ' Because the video stream has changed (i.e. the actual video)... we need to reload the audio stream choices for that video m.top.unobservefield(\"itemContent\") itemData = m.top.itemContent.json for each mediaSource in itemData.mediaSources if mediaSource.id = m.top.selectedVideoStreamId itemData.mediaStreams = [] for i = 0 to mediaSource.mediaStreams.Count() - 1 itemData.mediaStreams.push(mediaSource.mediaStreams[i]) end for SetDefaultAudioTrack(itemData) SetUpAudioOptions(itemData.mediaStreams) exit for end if end for m.top.itemContent.json = itemData m.top.observeField(\"itemContent\", \"itemContentChanged\") end if m.top.findNode(\"buttons\").setFocus(true) end sub function onKeyEvent(key as string, press as boolean) as boolean ' Due to the way the button pressed event works, need to catch the release for the button as the press is being sent ' directly to the main loop. Will get this sorted in the layout update for Movie Details if key = \"OK\" and m.top.findNode(\"options-button\").isInFocusChain() m.options.visible = true m.options.setFocus(true) end if if key = \"down\" and m.buttonGrp.isInFocusChain() m.top.lastFocus = m.extrasGrid m.extrasGrid.setFocus(true) m.top.findNode(\"VertSlider\").reverse = false m.top.findNode(\"extrasFader\").reverse = false m.top.findNode(\"pplAnime\").control = \"start\" return true end if if key = \"up\" and m.top.findNode(\"extrasGrid\").isInFocusChain() if m.extrasGrid.itemFocused = 0 m.top.lastFocus = m.buttonGrp m.top.findNode(\"VertSlider\").reverse = true m.top.findNode(\"extrasFader\").reverse = true m.top.findNode(\"pplAnime\").control = \"start\" m.buttonGrp.setFocus(true) return true end if end if if not press then return false if key = \"back\" if m.options.visible = true m.options.visible = false videoOptionsClosed() audioOptionsClosed() return true end if else if key = \"play\" and m.extrasGrid.hasFocus() print \"Play was pressed from the movie details extras slider\" if m.extrasGrid.focusedItem &lt;&gt; invalid m.top.quickPlayNode = m.extrasGrid.focusedItem return true end if end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_ItemGrid_MovieLibraryView.brs.html":{"id":"components_ItemGrid_MovieLibraryView.brs.html","title":"Source: components/ItemGrid/MovieLibraryView.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/ItemGrid/MovieLibraryView.brs import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/utils/config.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/api/Image.brs\" import \"pkg:/source/utils/deviceCapabilities.brs\" sub setupNodes() m.options = m.top.findNode(\"options\") m.itemGrid = m.top.findNode(\"itemGrid\") m.voiceBox = m.top.findNode(\"voiceBox\") m.backdrop = m.top.findNode(\"backdrop\") m.newBackdrop = m.top.findNode(\"backdropTransition\") m.emptyText = m.top.findNode(\"emptyText\") m.selectedMovieName = m.top.findNode(\"selectedMovieName\") m.selectedMovieOverview = m.top.findNode(\"selectedMovieOverview\") m.selectedMovieProductionYear = m.top.findNode(\"selectedMovieProductionYear\") m.selectedMovieOfficialRating = m.top.findNode(\"selectedMovieOfficialRating\") m.movieLogo = m.top.findNode(\"movieLogo\") m.swapAnimation = m.top.findNode(\"backroundSwapAnimation\") m.spinner = m.top.findNode(\"spinner\") m.Alpha = m.top.findNode(\"AlphaMenu\") m.AlphaSelected = m.top.findNode(\"AlphaSelected\") m.micButton = m.top.findNode(\"micButton\") m.micButtonText = m.top.findNode(\"micButtonText\") m.communityRatingGroup = m.top.findNode(\"communityRatingGroup\") m.criticRatingIcon = m.top.findNode(\"criticRatingIcon\") m.criticRatingGroup = m.top.findNode(\"criticRatingGroup\") m.overhang = m.top.getScene().findNode(\"overhang\") m.genreList = m.top.findNode(\"genrelist\") m.infoGroup = m.top.findNode(\"infoGroup\") m.star = m.top.findNode(\"star\") end sub sub init() setupNodes() m.overhang.isVisible = false m.showItemCount = m.global.session.user.settings[\"itemgrid.showItemCount\"] m.swapAnimation.observeField(\"state\", \"swapDone\") m.loadedRows = 0 m.loadedItems = 0 m.data = CreateObject(\"roSGNode\", \"ContentNode\") m.itemGrid.content = m.data m.genreData = CreateObject(\"roSGNode\", \"ContentNode\") m.genreList.observeField(\"itemSelected\", \"onGenreItemSelected\") m.genreList.content = m.genreData m.itemGrid.observeField(\"itemFocused\", \"onItemFocused\") m.itemGrid.observeField(\"itemSelected\", \"onItemSelected\") m.itemGrid.observeField(\"alphaSelected\", \"onItemalphaSelected\") 'Voice filter setup m.voiceBox.voiceEnabled = true m.voiceBox.active = true m.voiceBox.observeField(\"text\", \"onvoiceFilter\") 'set voice help text m.voiceBox.hintText = tr(\"Use voice remote to search\") 'backdrop m.newBackdrop.observeField(\"loadStatus\", \"newBGLoaded\") 'Background Image Queued for loading m.queuedBGUri = \"\" 'Item sort - maybe load defaults from user prefs? m.sortField = \"SortName\" m.sortAscending = true m.filter = \"All\" m.filterOptions = {} m.favorite = \"Favorite\" m.loadItemsTask = createObject(\"roSGNode\", \"LoadItemsTask2\") m.loadLogoTask = createObject(\"roSGNode\", \"LoadItemsTask2\") m.getFiltersTask = createObject(\"roSGNode\", \"GetFiltersTask\") 'set inital counts for overhang before content is loaded. m.loadItemsTask.totalRecordCount = 0 m.spinner.visible = true 'Get reset folder setting m.resetGrid = m.global.session.user.settings[\"itemgrid.reset\"] 'Hide voice search if device does not have voice remote if m.global.device.hasVoiceRemote = false m.micButton.visible = false m.micButtonText.visible = false end if end sub sub OnScreenHidden() if not m.overhang.isVisible m.overhang.disableMoveAnimation = true m.overhang.isVisible = true m.overhang.disableMoveAnimation = false end if end sub sub OnScreenShown() m.overhang.isVisible = false if m.top.lastFocus &lt;&gt; invalid m.top.lastFocus.setFocus(true) else m.top.setFocus(true) end if end sub ' 'Load initial set of Data sub loadInitialItems() m.loadItemsTask.control = \"stop\" m.spinner.visible = true if m.top.parentItem.json.Type = \"CollectionFolder\" m.top.HomeLibraryItem = m.top.parentItem.Id end if if m.top.parentItem.backdropUrl &lt;&gt; invalid SetBackground(m.top.parentItem.backdropUrl) else SetBackground(\"\") end if m.sortField = m.global.session.user.settings[\"display.\" + m.top.parentItem.Id + \".sortField\"] m.filter = m.global.session.user.settings[\"display.\" + m.top.parentItem.Id + \".filter\"] m.filterOptions = m.global.session.user.settings[\"display.\" + m.top.parentItem.Id + \".filterOptions\"] m.view = m.global.session.user.settings[\"display.\" + m.top.parentItem.Id + \".landing\"] m.sortAscending = m.global.session.user.settings[\"display.\" + m.top.parentItem.Id + \".sortAscending\"] ' If user has not set a preferred view for this folder, check if they've set a default view if not isValid(m.view) m.view = m.global.session.user.settings[\"itemgrid.movieDefaultView\"] end if if not isValid(m.sortField) then m.sortField = \"SortName\" if not isValid(m.filter) then m.filter = \"All\" if not isValid(m.filterOptions) then m.filterOptions = \"{}\" if not isValid(m.view) then m.view = \"Movies\" if not isValid(m.sortAscending) then m.sortAscending = true m.filterOptions = ParseJson(m.filterOptions) if m.top.parentItem.json.type = \"Studio\" m.loadItemsTask.studioIds = m.top.parentItem.id m.loadItemsTask.itemId = m.top.parentItem.parentFolder m.loadItemsTask.genreIds = \"\" else if m.top.parentItem.json.type = \"Genre\" m.loadItemsTask.genreIds = m.top.parentItem.id m.loadItemsTask.itemId = m.top.parentItem.parentFolder m.loadItemsTask.studioIds = \"\" else if m.view = \"Movies\" or m.options.view = \"Movies\" m.loadItemsTask.studioIds = \"\" m.loadItemsTask.genreIds = \"\" else m.loadItemsTask.itemId = m.top.parentItem.Id end if m.loadItemsTask.nameStartsWith = m.top.alphaSelected m.loadItemsTask.searchTerm = m.voiceBox.text m.emptyText.visible = false m.loadItemsTask.sortField = m.sortField m.loadItemsTask.sortAscending = m.sortAscending m.loadItemsTask.filter = m.filter m.loadItemsTask.filterOptions = m.filterOptions m.loadItemsTask.startIndex = 0 ' Load Item Types if getCollectionType() = \"movies\" m.loadItemsTask.itemType = \"Movie\" m.loadItemsTask.itemId = m.top.parentItem.Id end if ' By default we load movies m.loadItemsTask.studioIds = \"\" m.loadItemsTask.view = \"Movies\" m.itemGrid.translation = \"[96, 650]\" m.itemGrid.itemSize = \"[230, 310]\" m.itemGrid.rowHeights = \"[310]\" m.itemGrid.numRows = \"2\" m.selectedMovieOverview.visible = true m.infoGroup.visible = true m.top.showItemTitles = \"hidealways\" if m.options.view = \"Studios\" or m.view = \"Studios\" m.itemGrid.translation = \"[96, 60]\" m.itemGrid.numRows = \"3\" m.loadItemsTask.view = \"Networks\" m.top.imageDisplayMode = \"scaleToFit\" m.selectedMovieOverview.visible = false m.infoGroup.visible = false else if LCase(m.options.view) = \"moviesgrid\" or LCase(m.view) = \"moviesgrid\" m.itemGrid.translation = \"[96, 60]\" m.itemGrid.numRows = \"3\" m.selectedMovieOverview.visible = false m.infoGroup.visible = false m.top.showItemTitles = m.global.session.user.settings[\"itemgrid.gridTitles\"] if LCase(m.top.showItemTitles) = \"hidealways\" m.itemGrid.itemSize = \"[230, 315]\" m.itemGrid.rowHeights = \"[315]\" else m.itemGrid.itemSize = \"[230, 350]\" m.itemGrid.rowHeights = \"[350]\" end if else if m.options.view = \"Genres\" or m.view = \"Genres\" m.loadItemsTask.StudioIds = m.top.parentItem.Id m.loadItemsTask.view = \"Genres\" m.movieLogo.visible = false m.selectedMovieName.visible = false m.selectedMovieOverview.visible = false m.infoGroup.visible = false end if m.loadItemsTask.observeField(\"content\", \"ItemDataLoaded\") m.spinner.visible = true m.loadItemsTask.control = \"RUN\" m.getFiltersTask.observeField(\"filters\", \"FilterDataLoaded\") m.getFiltersTask.params = { userid: m.global.session.user.id, parentid: m.top.parentItem.Id, includeitemtypes: \"Movie\" } m.getFiltersTask.control = \"RUN\" end sub ' Set Movies view, sort, and filter options sub setMoviesOptions(options) options.views = [ { \"Title\": tr(\"Movies (Presentation)\"), \"Name\": \"Movies\" }, { \"Title\": tr(\"Movies (Grid)\"), \"Name\": \"MoviesGrid\" }, { \"Title\": tr(\"Studios\"), \"Name\": \"Studios\" }, { \"Title\": tr(\"Genres\"), \"Name\": \"Genres\" } ] if m.top.parentItem.json.type = \"Genre\" options.views = [ { \"Title\": tr(\"Movies (Presentation)\"), \"Name\": \"Movies\" }, { \"Title\": tr(\"Movies (Grid)\"), \"Name\": \"MoviesGrid\" }, ] end if options.sort = [ { \"Title\": tr(\"TITLE\"), \"Name\": \"SortName\" }, { \"Title\": tr(\"IMDB_RATING\"), \"Name\": \"CommunityRating\" }, { \"Title\": tr(\"CRITIC_RATING\"), \"Name\": \"CriticRating\" }, { \"Title\": tr(\"DATE_ADDED\"), \"Name\": \"DateCreated\" }, { \"Title\": tr(\"DATE_PLAYED\"), \"Name\": \"DatePlayed\" }, { \"Title\": tr(\"OFFICIAL_RATING\"), \"Name\": \"OfficialRating\" }, { \"Title\": tr(\"PLAY_COUNT\"), \"Name\": \"PlayCount\" }, { \"Title\": tr(\"RELEASE_DATE\"), \"Name\": \"PremiereDate\" }, { \"Title\": tr(\"RUNTIME\"), \"Name\": \"Runtime\" } ] options.filter = [ { \"Title\": tr(\"All\"), \"Name\": \"All\" }, { \"Title\": tr(\"Favorites\"), \"Name\": \"Favorites\" }, { \"Title\": tr(\"Played\"), \"Name\": \"Played\" }, { \"Title\": tr(\"Unplayed\"), \"Name\": \"Unplayed\" }, { \"Title\": tr(\"Resumable\"), \"Name\": \"Resumable\" } ] if m.options.view = \"Genres\" or m.view = \"Genres\" options.sort = [{ \"Title\": tr(\"TITLE\"), \"Name\": \"SortName\" }] options.filter = [] end if if m.options.view = \"Studios\" or m.view = \"Studios\" options.sort = [ { \"Title\": tr(\"TITLE\"), \"Name\": \"SortName\" }, { \"Title\": tr(\"DATE_ADDED\"), \"Name\": \"DateCreated\" }, ] options.filter = [ { \"Title\": tr(\"All\"), \"Name\": \"All\" }, { \"Title\": tr(\"Favorites\"), \"Name\": \"Favorites\" } ] end if end sub ' Return parent collection type function getCollectionType() as string if m.top.parentItem.collectionType = invalid return m.top.parentItem.Type else return m.top.parentItem.CollectionType end if end function ' Search string array for search value. Return if it's found function inStringArray(array, searchValue) as boolean for each item in array if lcase(item) = lcase(searchValue) then return true end for return false end function ' Data to display when options button selected sub setSelectedOptions(options) ' Set selected view option for each o in options.views if o.Name = m.view o.Selected = true o.Ascending = m.sortAscending m.options.view = o.Name end if end for ' Set selected sort option for each o in options.sort if o.Name = m.sortField o.Selected = true o.Ascending = m.sortAscending m.options.sortField = o.Name end if end for ' Set selected filter for each o in options.filter if o.Name = m.filter o.Selected = true m.options.filter = o.Name end if ' Select selected filter options if isValid(o.options) and isValid(m.filterOptions) if o.options.Count() &gt; 0 and m.filterOptions.Count() &gt; 0 if LCase(o.Name) = LCase(m.filterOptions.keys()[0]) selectedFilterOptions = m.filterOptions[m.filterOptions.keys()[0]].split(o.delimiter) checkedState = [] for each availableFilterOption in o.options matchFound = false for each selectedFilterOption in selectedFilterOptions if LCase(toString(availableFilterOption).trim()) = LCase(selectedFilterOption.trim()) matchFound = true end if end for checkedState.push(matchFound) end for o.checkedState = checkedState end if end if end if end for m.options.options = options end sub ' ' Logo Image Loaded Event Handler sub FilterDataLoaded(msg) options = {} options.filter = [] options.favorite = [] setMoviesOptions(options) data = msg.GetData() m.getFiltersTask.unobserveField(\"filters\") if not isValid(data) then return ' Add Movie filters from the API data if LCase(m.loadItemsTask.view) = \"movies\" if isValid(data.genres) options.filter.push({ \"Title\": tr(\"Genres\"), \"Name\": \"Genres\", \"Options\": data.genres, \"Delimiter\": \"|\", \"CheckedState\": [] }) end if if isValid(data.OfficialRatings) options.filter.push({ \"Title\": tr(\"Parental Ratings\"), \"Name\": \"OfficialRatings\", \"Options\": data.OfficialRatings, \"Delimiter\": \"|\", \"CheckedState\": [] }) end if if isValid(data.Years) options.filter.push({ \"Title\": tr(\"Years\"), \"Name\": \"Years\", \"Options\": data.Years, \"Delimiter\": \",\", \"CheckedState\": [] }) end if end if setSelectedOptions(options) m.options.options = options end sub ' ' Logo Image Loaded Event Handler sub LogoImageLoaded(msg) data = msg.GetData() m.loadLogoTask.unobserveField(\"content\") m.loadLogoTask.content = [] if data.Count() &gt; 0 m.movieLogo.uri = data[0] m.movieLogo.visible = true else m.selectedMovieName.visible = true end if end sub ' 'Handle loaded data, and add to Grid sub ItemDataLoaded(msg) m.top.alphaActive = false itemData = msg.GetData() m.loadItemsTask.unobserveField(\"content\") m.loadItemsTask.content = [] if itemData = invalid m.Loading = false return end if if m.loadItemsTask.view = \"Genres\" ' Reset genre list data m.genreData.removeChildren(m.genreData.getChildren(-1, 0)) for each item in itemData m.genreData.appendChild(item) end for m.itemGrid.opacity = \"0\" m.genreList.opacity = \"1\" m.itemGrid.setFocus(false) m.genreList.setFocus(true) m.loading = false m.spinner.visible = false ' Return focus to options menu if it was opened while library was loading if m.options.visible m.options.setFocus(true) end if return end if m.itemGrid.opacity = \"1\" m.genreList.opacity = \"0\" m.itemGrid.setFocus(true) m.genreList.setFocus(false) if m.data.getChildCount() = 0 m.itemGrid.jumpToItem = 0 end if for each item in itemData m.data.appendChild(item) end for 'Update the stored counts m.loadedItems = m.itemGrid.content.getChildCount() m.loadedRows = m.loadedItems / m.itemGrid.numColumns m.Loading = false 'If there are no items to display, show message if m.loadedItems = 0 m.selectedMovieOverview.visible = false m.infoGroup.visible = false m.movieLogo.visible = false m.movieLogo.uri = \"\" m.selectedMovieName.visible = false SetName(\"\") SetOverview(\"\") SetOfficialRating(\"\") SetProductionYear(\"\") setFieldText(\"runtime\", \"\") setFieldText(\"communityRating\", \"\") setFieldText(\"criticRatingLabel\", \"\") m.criticRatingIcon.uri = \"\" m.star.uri = \"\" m.emptyText.text = tr(\"NO_ITEMS\").Replace(\"%1\", m.top.parentItem.Type) m.emptyText.visible = true end if m.spinner.visible = false ' Return focus to options menu if it was opened while library was loading if m.options.visible m.options.setFocus(true) end if end sub ' 'Set Selected Movie Name sub SetName(movieName as string) m.selectedMovieName.text = movieName end sub ' 'Set Selected Movie Overview sub SetOverview(movieOverview as string) m.selectedMovieOverview.text = movieOverview end sub ' 'Set Selected Movie OfficialRating sub SetOfficialRating(movieOfficialRating as string) m.selectedMovieOfficialRating.text = movieOfficialRating end sub ' 'Set Selected Movie ProductionYear sub SetProductionYear(movieProductionYear) m.selectedMovieProductionYear.text = movieProductionYear end sub ' 'Set Background Image sub SetBackground(backgroundUri as string) if backgroundUri = \"\" m.backdrop.opacity = 0 end if 'If a new image is being loaded, or transitioned to, store URL to load next if m.swapAnimation.state &lt;&gt; \"stopped\" or m.newBackdrop.loadStatus = \"loading\" m.queuedBGUri = backgroundUri return end if m.newBackdrop.uri = backgroundUri end sub ' 'Handle new item being focused sub onItemFocused() focusedRow = m.itemGrid.currFocusRow itemInt = m.itemGrid.itemFocused ' If no selected item, set background to parent backdrop if itemInt = -1 return end if m.movieLogo.visible = false m.selectedMovieName.visible = false ' Load more data if focus is within last 5 rows, and there are more items to load if focusedRow &gt;= m.loadedRows - 5 and m.loadeditems &lt; m.loadItemsTask.totalRecordCount loadMoreData() end if m.selectedFavoriteItem = getItemFocused() m.communityRatingGroup.visible = false m.criticRatingGroup.visible = false if not isValid(m.selectedFavoriteItem) return end if if LCase(m.options.view) = \"studios\" or LCase(m.view) = \"studios\" return else if LCase(m.options.view) = \"moviesgrid\" or LCase(m.view) = \"moviesgrid\" return end if itemData = m.selectedFavoriteItem.json m.star.uri = \"pkg:/images/sharp_star_white_18dp.png\" if isValid(itemData.communityRating) setFieldText(\"communityRating\", int(itemData.communityRating * 10) / 10) m.communityRatingGroup.visible = true end if if isValid(itemData.CriticRating) setFieldText(\"criticRatingLabel\", itemData.criticRating) tomato = \"pkg:/images/rotten.png\" if itemData.CriticRating &gt; 60 tomato = \"pkg:/images/fresh.png\" end if m.criticRatingIcon.uri = tomato m.criticRatingGroup.visible = true end if if isValid(itemData.Name) SetName(itemData.Name) else SetName(\"\") end if if isValid(itemData.Overview) SetOverview(itemData.Overview) else SetOverview(\"\") end if if isValid(itemData.ProductionYear) SetProductionYear(str(itemData.ProductionYear)) else SetProductionYear(\"\") end if if type(itemData.RunTimeTicks) = \"LongInteger\" setFieldText(\"runtime\", stri(getRuntime(itemData.RunTimeTicks)) + \" mins\") else setFieldText(\"runtime\", \"\") end if if isValid(itemData.OfficialRating) SetOfficialRating(itemData.OfficialRating) else SetOfficialRating(\"\") end if m.loadLogoTask.itemId = itemData.id m.loadLogoTask.itemType = \"LogoImage\" m.loadLogoTask.observeField(\"content\", \"LogoImageLoaded\") m.loadLogoTask.control = \"RUN\" ' Set Background to item backdrop SetBackground(m.selectedFavoriteItem.backdropUrl) end sub function getRuntime(runTimeTicks) as integer return round(runTimeTicks / 600000000.0) end function function round(f as float) as integer ' BrightScript only has a \"floor\" round ' This compares floor to floor + 1 to find which is closer m = int(f) n = m + 1 x = abs(f - m) y = abs(f - n) if y &gt; x return m else return n end if end function sub setFieldText(field, value) node = m.top.findNode(field) if node = invalid or value = invalid then return ' Handle non strings... Which _shouldn't_ happen, but hey if type(value) = \"roInt\" or type(value) = \"Integer\" value = str(value) else if type(value) = \"roFloat\" or type(value) = \"Float\" value = str(value) else if type(value) &lt;&gt; \"roString\" and type(value) &lt;&gt; \"String\" value = \"\" end if node.text = value end sub ' 'When Image Loading Status changes sub newBGLoaded() 'If image load was sucessful, start the fade swap if m.newBackdrop.loadStatus = \"ready\" m.swapAnimation.control = \"start\" end if end sub ' 'Swap Complete sub swapDone() if m.swapAnimation.state = \"stopped\" 'Set main BG node image and hide transitioning node m.backdrop.uri = m.newBackdrop.uri m.backdrop.opacity = 1 m.newBackdrop.opacity = 0 'If there is another one to load if m.newBackdrop.uri &lt;&gt; m.queuedBGUri and m.queuedBGUri &lt;&gt; \"\" SetBackground(m.queuedBGUri) m.queuedBGUri = \"\" end if end if end sub ' 'Load next set of items sub loadMoreData() m.spinner.visible = true if m.Loading = true then return m.Loading = true m.loadItemsTask.startIndex = m.loadedItems m.loadItemsTask.observeField(\"content\", \"ItemDataLoaded\") m.loadItemsTask.control = \"RUN\" end sub ' 'Item Selected sub onItemSelected() m.top.selectedItem = m.itemGrid.content.getChild(m.itemGrid.itemSelected) end sub ' 'Returns Focused Item function getItemFocused() if m.itemGrid.isinFocusChain() and isValid(m.itemGrid.itemFocused) return m.itemGrid.content.getChild(m.itemGrid.itemFocused) else if m.genreList.isinFocusChain() and isValid(m.genreList.rowItemFocused) return m.genreList.content.getChild(m.genreList.rowItemFocused[0]).getChild(m.genreList.rowItemFocused[1]) end if return invalid end function ' 'Genre Item Selected sub onGenreItemSelected() m.top.selectedItem = m.genreList.content.getChild(m.genreList.rowItemSelected[0]).getChild(m.genreList.rowItemSelected[1]) end sub sub onItemalphaSelected() if m.top.alphaSelected &lt;&gt; \"\" m.loadedRows = 0 m.loadedItems = 0 m.data = CreateObject(\"roSGNode\", \"ContentNode\") m.itemGrid.content = m.data m.genreData = CreateObject(\"roSGNode\", \"ContentNode\") m.genreList.content = m.genreData m.loadItemsTask.searchTerm = \"\" m.VoiceBox.text = \"\" m.loadItemsTask.nameStartsWith = m.alpha.itemAlphaSelected m.spinner.visible = true loadInitialItems() end if end sub sub onvoiceFilter() if m.VoiceBox.text &lt;&gt; \"\" m.loadedRows = 0 m.loadedItems = 0 m.data = CreateObject(\"roSGNode\", \"ContentNode\") m.itemGrid.content = m.data m.top.alphaSelected = \"\" m.loadItemsTask.NameStartsWith = \" \" m.loadItemsTask.searchTerm = m.voiceBox.text m.loadItemsTask.recursive = true m.spinner.visible = true loadInitialItems() end if end sub ' 'Check if options updated and any reloading required sub optionsClosed() reload = false if m.options.sortField &lt;&gt; m.sortField or m.options.sortAscending &lt;&gt; m.sortAscending m.sortField = m.options.sortField m.sortAscending = m.options.sortAscending reload = true sortAscendingStr = \"true\" 'Store sort settings if not m.sortAscending sortAscendingStr = \"false\" end if set_user_setting(\"display.\" + m.top.parentItem.Id + \".sortField\", m.sortField) set_user_setting(\"display.\" + m.top.parentItem.Id + \".sortAscending\", sortAscendingStr) end if if m.options.filter &lt;&gt; m.filter m.filter = m.options.filter reload = true set_user_setting(\"display.\" + m.top.parentItem.Id + \".filter\", m.options.filter) end if if not isValid(m.options.filterOptions) m.filterOptions = {} end if if not AssocArrayEqual(m.options.filterOptions, m.filterOptions) m.filterOptions = m.options.filterOptions reload = true set_user_setting(\"display.\" + m.top.parentItem.Id + \".filterOptions\", FormatJson(m.options.filterOptions)) end if m.view = m.global.session.user.settings[\"display.\" + m.top.parentItem.Id + \".landing\"] if m.options.view &lt;&gt; m.view m.view = m.options.view set_user_setting(\"display.\" + m.top.parentItem.Id + \".landing\", m.view) ' Reset any filtering or search terms m.top.alphaSelected = \"\" m.loadItemsTask.NameStartsWith = \" \" m.loadItemsTask.searchTerm = \"\" m.filter = \"All\" m.filterOptions = {} m.sortField = \"SortName\" m.sortAscending = true ' Reset view to defaults set_user_setting(\"display.\" + m.top.parentItem.Id + \".sortField\", m.sortField) set_user_setting(\"display.\" + m.top.parentItem.Id + \".sortAscending\", \"true\") set_user_setting(\"display.\" + m.top.parentItem.Id + \".filter\", m.filter) set_user_setting(\"display.\" + m.top.parentItem.Id + \".filterOptions\", FormatJson(m.filterOptions)) reload = true end if if reload m.loadedRows = 0 m.loadedItems = 0 m.data = CreateObject(\"roSGNode\", \"ContentNode\") m.itemGrid.content = m.data loadInitialItems() end if m.itemGrid.setFocus(m.itemGrid.opacity = 1) m.genreList.setFocus(m.genreList.opacity = 1) end sub sub onChannelSelected(msg) node = msg.getRoSGNode() m.top.lastFocus = lastFocusedChild(node) if node.watchChannel &lt;&gt; invalid ' Clone the node when it's reused/update in the TimeGrid it doesn't automatically start playing m.top.selectedItem = node.watchChannel.clone(false) end if end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false if key = \"left\" and m.voiceBox.isinFocusChain() m.itemGrid.setFocus(m.itemGrid.opacity = 1) m.genreList.setFocus(m.genreList.opacity = 1) m.voiceBox.setFocus(false) end if if key = \"options\" if m.options.visible = true m.options.visible = false m.top.removeChild(m.options) optionsClosed() else itemSelected = m.selectedFavoriteItem if itemSelected &lt;&gt; invalid m.options.selectedFavoriteItem = itemSelected end if m.options.visible = true m.top.appendChild(m.options) m.options.setFocus(true) end if return true else if key = \"back\" if m.options.visible = true m.options.visible = false optionsClosed() return true else m.global.sceneManager.callfunc(\"popScene\") m.loadItemsTask.control = \"stop\" return true end if else if key = \"play\" itemToPlay = getItemFocused() if itemToPlay &lt;&gt; invalid m.top.quickPlayNode = itemToPlay return true end if else if key = \"left\" if m.itemGrid.isinFocusChain() m.top.alphaActive = true m.itemGrid.setFocus(false) alpha = m.alpha.getChild(0).findNode(\"Alphamenu\") alpha.setFocus(true) return true else if m.genreList.isinFocusChain() m.top.alphaActive = true m.genreList.setFocus(false) alpha = m.alpha.getChild(0).findNode(\"Alphamenu\") alpha.setFocus(true) return true end if else if key = \"right\" and m.Alpha.isinFocusChain() m.top.alphaActive = false m.Alpha.setFocus(false) m.Alpha.visible = true m.itemGrid.setFocus(m.itemGrid.opacity = 1) m.genreList.setFocus(m.genreList.opacity = 1) return true else if key = \"replay\" and m.itemGrid.isinFocusChain() if m.resetGrid = true m.itemGrid.animateToItem = 0 else m.itemGrid.jumpToItem = 0 end if return true else if key = \"replay\" and m.genreList.isinFocusChain() if m.resetGrid = true m.genreList.animateToItem = 0 else m.genreList.jumpToItem = 0 end if return true end if if key = \"replay\" m.spinner.visible = true m.loadItemsTask.searchTerm = \"\" m.loadItemsTask.nameStartsWith = \"\" m.voiceBox.text = \"\" m.top.alphaSelected = \"\" m.loadItemsTask.filter = \"All\" m.filter = \"All\" m.filterOptions = {} m.data = CreateObject(\"roSGNode\", \"ContentNode\") m.itemGrid.content = m.data loadInitialItems() return true end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_movies_MovieOptions.brs.html":{"id":"components_movies_MovieOptions.brs.html","title":"Source: components/movies/MovieOptions.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/movies/MovieOptions.brs sub init() m.buttons = m.top.findNode(\"buttons\") m.buttons.buttons = [tr(\"Video\"), tr(\"Audio\")] m.buttons.selectedIndex = 0 m.buttons.setFocus(true) m.selectedItem = 0 m.selectedAudioIndex = 0 m.selectedVideoIndex = 0 m.menus = [m.top.findNode(\"videoMenu\"), m.top.findNode(\"audioMenu\")] m.videoNames = [] m.audioNames = [] ' Set button colors to global m.top.findNode(\"videoMenu\").focusBitmapBlendColor = m.global.constants.colors.button m.top.findNode(\"audioMenu\").focusBitmapBlendColor = m.global.constants.colors.button ' Animation m.fadeAnim = m.top.findNode(\"fadeAnim\") m.fadeOutAnimOpacity = m.top.findNode(\"outOpacity\") m.fadeInAnimOpacity = m.top.findNode(\"inOpacity\") m.buttons.observeField(\"focusedIndex\", \"buttonFocusChanged\") m.buttons.focusedIndex = m.selectedItem end sub sub optionsSet() ' Videos Tab if m.top.options.videos &lt;&gt; invalid viewContent = CreateObject(\"roSGNode\", \"ContentNode\") index = 0 selectedViewIndex = 0 for each view in m.top.options.videos entry = viewContent.CreateChild(\"VideoTrackListData\") entry.title = view.Title entry.description = view.Description entry.streamId = view.streamId entry.video_codec = view.video_codec m.videoNames.push(view.Name) if view.Selected &lt;&gt; invalid and view.Selected = true selectedViewIndex = index entry.selected = true m.top.videoStreamId = view.streamId end if index = index + 1 end for m.menus[0].content = viewContent m.menus[0].jumpToItem = selectedViewIndex m.menus[0].checkedItem = selectedViewIndex m.selectedVideoIndex = selectedViewIndex end if ' audio Tab if m.top.Options.audios &lt;&gt; invalid audioContent = CreateObject(\"roSGNode\", \"ContentNode\") index = 0 selectedAudioIndex = 0 for each audio in m.top.options.audios entry = audioContent.CreateChild(\"AudioTrackListData\") entry.title = audio.Title entry.description = audio.Description entry.streamIndex = audio.StreamIndex m.audioNames.push(audio.Name) if audio.Selected &lt;&gt; invalid and audio.Selected = true selectedAudioIndex = index entry.selected = true m.top.audioStreamIndex = audio.streamIndex end if index = index + 1 end for m.menus[1].content = audioContent m.menus[1].jumpToItem = selectedAudioIndex m.menus[1].checkedItem = selectedAudioIndex m.selectedAudioIndex = selectedAudioIndex end if end sub ' Switch menu shown when button focus changes sub buttonFocusChanged() if m.buttons.focusedIndex = m.selectedItem then return m.fadeOutAnimOpacity.fieldToInterp = m.menus[m.selectedItem].id + \".opacity\" m.fadeInAnimOpacity.fieldToInterp = m.menus[m.buttons.focusedIndex].id + \".opacity\" m.fadeAnim.control = \"start\" m.selectedItem = m.buttons.focusedIndex end sub function onKeyEvent(key as string, press as boolean) as boolean if key = \"down\" or (key = \"OK\" and m.top.findNode(\"buttons\").hasFocus()) m.top.findNode(\"buttons\").setFocus(false) m.menus[m.selectedItem].setFocus(true) m.menus[m.selectedItem].drawFocusFeedback = true 'If user presses down from button menu, focus first item. If OK, focus checked item if key = \"down\" m.menus[m.selectedItem].jumpToItem = 0 else m.menus[m.selectedItem].jumpToItem = m.menus[m.selectedItem].itemSelected end if return true else if key = \"OK\" if m.menus[m.selectedItem].isInFocusChain() selMenu = m.menus[m.selectedItem] selIndex = selMenu.itemSelected 'Handle Videos menu if m.selectedItem = 0 if m.selectedVideoIndex = selIndex else selMenu.content.GetChild(m.selectedVideoIndex).selected = false newSelection = selMenu.content.GetChild(selIndex) newSelection.selected = true m.selectedVideoIndex = selIndex m.top.videoStreamId = newSelection.streamId m.top.video_codec = newSelection.video_codec end if ' Then it is Audio options else if m.selectedItem = 1 if m.selectedAudioIndex = selIndex else selMenu.content.GetChild(m.selectedAudioIndex).selected = false newSelection = selMenu.content.GetChild(selIndex) newSelection.selected = true m.selectedAudioIndex = selIndex m.top.audioStreamIndex = newSelection.streamIndex end if end if end if return true else if key = \"back\" or key = \"up\" if m.menus[m.selectedItem].isInFocusChain() m.buttons.setFocus(true) m.menus[m.selectedItem].drawFocusFeedback = false return true end if else if key = \"options\" m.menus[m.selectedItem].drawFocusFeedback = false return false end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_MusicAlbumData.brs.html":{"id":"components_data_MusicAlbumData.brs.html","title":"Source: components/data/MusicAlbumData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/MusicAlbumData.brs sub setFields() datum = m.top.json m.top.id = datum.id m.top.title = datum.name m.top.overview = datum.overview end sub sub setPoster() if m.top.image &lt;&gt; invalid m.top.posterURL = m.top.image.url else m.top.posterURL = \"\" end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_MusicAlbumSongListData.brs.html":{"id":"components_data_MusicAlbumSongListData.brs.html","title":"Source: components/data/MusicAlbumSongListData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/MusicAlbumSongListData.brs import \"pkg:/source/api/Image.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" sub setFields() json = m.top.json m.top.id = json.id m.top.favorite = json.UserData.isFavorite m.top.Type = \"MusicAlbum\" setPoster() end sub sub setPoster() if m.top.image &lt;&gt; invalid m.top.posterURL = m.top.image.url else if m.top.json.ImageTags.Primary &lt;&gt; invalid imgParams = { \"maxHeight\": 440, \"maxWidth\": 295 } m.top.posterURL = ImageURL(m.top.json.id, \"Primary\", imgParams) else if m.top.json.BackdropImageTags[0] &lt;&gt; invalid imgParams = { \"maxHeight\": 440 } m.top.posterURL = ImageURL(m.top.json.id, \"Backdrop\", imgParams) else if m.top.json.ParentThumbImageTag &lt;&gt; invalid and m.top.json.ParentThumbItemId &lt;&gt; invalid imgParams = { \"maxHeight\": 440, \"maxWidth\": 295 } m.top.posterURL = ImageURL(m.top.json.ParentThumbItemId, \"Thumb\", imgParams) end if ' Add Backdrop Image if m.top.json.BackdropImageTags[0] &lt;&gt; invalid imgParams = { \"maxHeight\": 720, \"maxWidth\": 1280 } m.top.backdropURL = ImageURL(m.top.json.id, \"Backdrop\", imgParams) end if end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_MusicArtistData.brs.html":{"id":"components_data_MusicArtistData.brs.html","title":"Source: components/data/MusicArtistData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/MusicArtistData.brs import \"pkg:/source/api/Image.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" sub setFields() json = m.top.json m.top.id = json.id m.top.favorite = json.UserData.isFavorite m.top.Type = \"MusicArtist\" setPoster() m.top.title = json.name end sub sub setPoster() if m.top.image &lt;&gt; invalid m.top.posterURL = m.top.image.url else ' Add Artist Image if m.top.json.ImageTags.Primary &lt;&gt; invalid imgParams = { \"maxHeight\": 440, \"maxWidth\": 440 } m.top.posterURL = ImageURL(m.top.json.id, \"Primary\", imgParams) else if m.top.json.BackdropImageTags[0] &lt;&gt; invalid imgParams = { \"maxHeight\": 440 } m.top.posterURL = ImageURL(m.top.json.id, \"Backdrop\", imgParams) else if m.top.json.ParentThumbImageTag &lt;&gt; invalid and m.top.json.ParentThumbItemId &lt;&gt; invalid imgParams = { \"maxHeight\": 440, \"maxWidth\": 440 } m.top.posterURL = ImageURL(m.top.json.ParentThumbItemId, \"Thumb\", imgParams) end if ' Add Backdrop Image if m.top.json.BackdropImageTags[0] &lt;&gt; invalid imgParams = { \"maxHeight\": 720, \"maxWidth\": 1280 } m.top.backdropURL = ImageURL(m.top.json.id, \"Backdrop\", imgParams) end if end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_ItemGrid_MusicArtistGridItem.brs.html":{"id":"components_ItemGrid_MusicArtistGridItem.brs.html","title":"Source: components/ItemGrid/MusicArtistGridItem.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/ItemGrid/MusicArtistGridItem.brs import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/utils/config.brs\" sub init() m.itemPoster = m.top.findNode(\"itemPoster\") m.postTextBackground = m.top.findNode(\"postTextBackground\") m.posterText = m.top.findNode(\"posterText\") m.posterText.font.size = 30 m.backdrop = m.top.findNode(\"backdrop\") m.itemPoster.observeField(\"loadStatus\", \"onPosterLoadStatusChanged\") 'Parent is MarkupGrid and it's parent is the ItemGrid m.topParent = m.top.GetParent().GetParent() 'Get the imageDisplayMode for these grid items if m.topParent.imageDisplayMode &lt;&gt; invalid m.itemPoster.loadDisplayMode = m.topParent.imageDisplayMode end if m.gridTitles = m.global.session.user.settings[\"itemgrid.gridTitles\"] m.posterText.visible = false m.postTextBackground.visible = false end sub sub itemContentChanged() m.backdrop.blendColor = \"#101010\" m.posterText.visible = false m.postTextBackground.visible = false if isValid(m.topParent.showItemTitles) if LCase(m.topParent.showItemTitles) = \"showalways\" m.posterText.visible = true m.postTextBackground.visible = true end if end if itemData = m.top.itemContent if not isValid(itemData) then return if LCase(itemData.type) = \"musicalbum\" m.backdrop.uri = \"pkg:/images/icons/album.png\" else if LCase(itemData.type) = \"musicartist\" m.backdrop.uri = \"pkg:/images/missingArtist.png\" else if LCase(itemData.json.type) = \"musicgenre\" m.backdrop.uri = \"pkg:/images/icons/musicFolder.png\" end if m.itemPoster.uri = itemData.PosterUrl m.posterText.text = itemData.title 'If Poster not loaded, ensure \"blue box\" is shown until loaded if m.itemPoster.loadStatus &lt;&gt; \"ready\" m.backdrop.visible = true end if if m.top.itemHasFocus then focusChanged() end sub 'Display or hide title Visibility on focus change sub focusChanged() if m.top.itemHasFocus = true m.posterText.repeatCount = -1 else m.posterText.repeatCount = 0 end if if isValid(m.topParent.showItemTitles) if LCase(m.topParent.showItemTitles) = \"showonhover\" m.posterText.visible = m.top.itemHasFocus m.postTextBackground.visible = m.posterText.visible end if end if end sub 'Hide backdrop and text when poster loaded sub onPosterLoadStatusChanged() if m.itemPoster.loadStatus = \"ready\" m.backdrop.visible = false end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_ItemGrid_MusicLibraryView.brs.html":{"id":"components_ItemGrid_MusicLibraryView.brs.html","title":"Source: components/ItemGrid/MusicLibraryView.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/ItemGrid/MusicLibraryView.brs import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/utils/config.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/api/Image.brs\" import \"pkg:/source/utils/deviceCapabilities.brs\" sub setupNodes() m.options = m.top.findNode(\"options\") m.itemGrid = m.top.findNode(\"itemGrid\") m.voiceBox = m.top.findNode(\"voiceBox\") m.backdrop = m.top.findNode(\"backdrop\") m.newBackdrop = m.top.findNode(\"backdropTransition\") m.emptyText = m.top.findNode(\"emptyText\") m.selectedArtistName = m.top.findNode(\"selectedArtistName\") m.selectedArtistSongCount = m.top.findNode(\"selectedArtistSongCount\") m.selectedArtistAlbumCount = m.top.findNode(\"selectedArtistAlbumCount\") m.selectedArtistGenres = m.top.findNode(\"selectedArtistGenres\") m.artistLogo = m.top.findNode(\"artistLogo\") m.swapAnimation = m.top.findNode(\"backroundSwapAnimation\") m.spinner = m.top.findNode(\"spinner\") m.Alpha = m.top.findNode(\"AlphaMenu\") m.AlphaSelected = m.top.findNode(\"AlphaSelected\") m.micButton = m.top.findNode(\"micButton\") m.micButtonText = m.top.findNode(\"micButtonText\") m.overhang = m.top.getScene().findNode(\"overhang\") m.genreList = m.top.findNode(\"genrelist\") end sub sub init() setupNodes() m.overhang.isVisible = false m.showItemCount = m.global.session.user.settings[\"itemgrid.showItemCount\"] m.swapAnimation.observeField(\"state\", \"swapDone\") m.loadedRows = 0 m.loadedItems = 0 m.data = CreateObject(\"roSGNode\", \"ContentNode\") m.itemGrid.content = m.data m.genreData = CreateObject(\"roSGNode\", \"ContentNode\") m.genreList.observeField(\"itemSelected\", \"onGenreItemSelected\") m.genreList.observeField(\"itemFocused\", \"onGenreItemFocused\") m.genreList.content = m.genreData m.itemGrid.observeField(\"itemFocused\", \"onItemFocused\") m.itemGrid.observeField(\"itemSelected\", \"onItemSelected\") m.itemGrid.observeField(\"alphaSelected\", \"onItemalphaSelected\") 'Voice filter setup m.voiceBox.voiceEnabled = true m.voiceBox.active = true m.voiceBox.observeField(\"text\", \"onvoiceFilter\") 'set voice help text m.voiceBox.hintText = tr(\"Use voice remote to search\") 'backdrop m.newBackdrop.observeField(\"loadStatus\", \"newBGLoaded\") 'Background Image Queued for loading m.queuedBGUri = \"\" 'Item sort - maybe load defaults from user prefs? m.sortField = \"SortName\" m.sortAscending = true m.filter = \"All\" m.favorite = \"Favorite\" m.loadItemsTask = createObject(\"roSGNode\", \"LoadItemsTask2\") m.loadLogoTask = createObject(\"roSGNode\", \"LoadItemsTask2\") 'set inital counts for overhang before content is loaded. m.loadItemsTask.totalRecordCount = 0 m.spinner.visible = true 'Get reset folder setting m.resetGrid = m.global.session.user.settings[\"itemgrid.reset\"] 'Hide voice search if device does not have voice remote if m.global.device.hasVoiceRemote = false m.micButton.visible = false m.micButtonText.visible = false end if end sub sub OnScreenHidden() if not m.overhang.isVisible m.overhang.disableMoveAnimation = true m.overhang.isVisible = true m.overhang.disableMoveAnimation = false end if end sub sub OnScreenShown() m.overhang.isVisible = false if m.top.lastFocus &lt;&gt; invalid m.top.lastFocus.setFocus(true) else m.top.setFocus(true) end if end sub ' 'Load initial set of Data sub loadInitialItems() m.loadItemsTask.control = \"stop\" m.spinner.visible = true if LCase(m.top.parentItem.json.Type) = \"collectionfolder\" m.top.HomeLibraryItem = m.top.parentItem.Id end if if m.top.parentItem.backdropUrl &lt;&gt; invalid SetBackground(m.top.parentItem.backdropUrl) else SetBackground(\"\") end if m.sortField = m.global.session.user.settings[\"display.\" + m.top.parentItem.Id + \".sortField\"] m.sortAscending = m.global.session.user.settings[\"display.\" + m.top.parentItem.Id + \".sortAscending\"] m.filter = m.global.session.user.settings[\"display.\" + m.top.parentItem.Id + \".filter\"] m.view = m.global.session.user.settings[\"display.\" + m.top.parentItem.Id + \".landing\"] if not isValid(m.sortField) then m.sortField = \"SortName\" if not isValid(m.filter) then m.filter = \"All\" if not isValid(m.view) then m.view = \"ArtistsPresentation\" if not isValid(m.sortAscending) then m.sortAscending = true m.top.showItemTitles = m.global.session.user.settings[\"itemgrid.gridTitles\"] if LCase(m.top.parentItem.json.type) = \"musicgenre\" m.itemGrid.translation = \"[96, 60]\" m.loadItemsTask.itemType = \"MusicAlbum\" m.loadItemsTask.recursive = true m.loadItemsTask.genreIds = m.top.parentItem.id m.loadItemsTask.itemId = m.top.parentItem.parentFolder else if LCase(m.view) = \"artistspresentation\" or LCase(m.options.view) = \"artistspresentation\" m.loadItemsTask.genreIds = \"\" m.top.showItemTitles = \"hidealways\" else if LCase(m.view) = \"artistsgrid\" or LCase(m.options.view) = \"artistsgrid\" m.loadItemsTask.genreIds = \"\" else if LCase(m.view) = \"albumartistsgrid\" or LCase(m.options.view) = \"albumartistsgrid\" m.loadItemsTask.genreIds = \"\" else if LCase(m.view) = \"albumartistspresentation\" or LCase(m.options.view) = \"albumartistspresentation\" m.loadItemsTask.genreIds = \"\" m.top.showItemTitles = \"hidealways\" else m.loadItemsTask.itemId = m.top.parentItem.Id end if m.loadItemsTask.nameStartsWith = m.top.alphaSelected m.loadItemsTask.searchTerm = m.voiceBox.text m.emptyText.visible = false m.loadItemsTask.sortField = m.sortField m.loadItemsTask.sortAscending = m.sortAscending m.loadItemsTask.filter = m.filter m.loadItemsTask.startIndex = 0 ' Load Item Types if getCollectionType() = \"music\" m.loadItemsTask.itemType = \"MusicArtist\" m.loadItemsTask.itemId = m.top.parentItem.Id end if ' By default we load Artists m.loadItemsTask.view = \"Artists\" m.itemGrid.translation = \"[96, 420]\" m.itemGrid.numRows = \"3\" if LCase(m.options.view) = \"albums\" or LCase(m.view) = \"albums\" m.itemGrid.translation = \"[96, 60]\" m.itemGrid.numRows = \"4\" m.loadItemsTask.itemType = \"MusicAlbum\" m.top.imageDisplayMode = \"scaleToFit\" else if LCase(m.options.view) = \"artistsgrid\" or LCase(m.view) = \"artistsgrid\" m.itemGrid.translation = \"[96, 60]\" m.itemGrid.numRows = \"4\" else if LCase(m.options.view) = \"albumartistsgrid\" or LCase(m.view) = \"albumartistsgrid\" m.loadItemsTask.itemType = \"AlbumArtists\" m.itemGrid.translation = \"[96, 60]\" m.itemGrid.numRows = \"4\" else if LCase(m.options.view) = \"albumartistspresentation\" or LCase(m.view) = \"albumartistspresentation\" m.loadItemsTask.itemType = \"AlbumArtists\" else if LCase(m.options.view) = \"genres\" or LCase(m.view) = \"genres\" m.loadItemsTask.itemType = \"\" m.loadItemsTask.recursive = true m.loadItemsTask.view = \"Genres\" m.artistLogo.visible = false m.selectedArtistName.visible = false end if if LCase(m.top.parentItem.json.type) = \"musicgenre\" m.itemGrid.translation = \"[96, 60]\" m.itemGrid.numRows = \"4\" m.artistLogo.visible = false m.selectedArtistName.visible = false end if m.loadItemsTask.observeField(\"content\", \"ItemDataLoaded\") m.spinner.visible = true m.loadItemsTask.control = \"RUN\" SetUpOptions() end sub ' Set Music view, sort, and filter options sub setMusicOptions(options) options.views = [ { \"Title\": tr(\"Artists (Presentation)\"), \"Name\": \"ArtistsPresentation\" }, { \"Title\": tr(\"Artists (Grid)\"), \"Name\": \"ArtistsGrid\" }, { \"Title\": tr(\"Album Artists (Presentation)\"), \"Name\": \"AlbumArtistsPresentation\" }, { \"Title\": tr(\"Album Artists (Grid)\"), \"Name\": \"AlbumArtistsGrid\" }, { \"Title\": tr(\"Albums\"), \"Name\": \"Albums\" }, { \"Title\": tr(\"Genres\"), \"Name\": \"Genres\" } ] if LCase(m.top.parentItem.json.type) = \"musicgenre\" options.views = [ { \"Title\": tr(\"Albums\"), \"Name\": \"Albums\" } ] end if options.sort = [ { \"Title\": tr(\"TITLE\"), \"Name\": \"SortName\" }, { \"Title\": tr(\"DATE_ADDED\"), \"Name\": \"DateCreated\" }, { \"Title\": tr(\"DATE_PLAYED\"), \"Name\": \"DatePlayed\" }, { \"Title\": tr(\"RELEASE_DATE\"), \"Name\": \"PremiereDate\" }, ] options.filter = [ { \"Title\": tr(\"All\"), \"Name\": \"All\" }, { \"Title\": tr(\"Favorites\"), \"Name\": \"Favorites\" } ] if LCase(m.options.view) = \"genres\" or LCase(m.view) = \"genres\" options.sort = [ { \"Title\": tr(\"TITLE\"), \"Name\": \"SortName\" }, ] options.filter = [] end if if LCase(m.options.view) = \"albums\" or LCase(m.view) = \"albums\" options.sort = [ { \"Title\": tr(\"TITLE\"), \"Name\": \"SortName\" }, { \"Title\": tr(\"DATE_ADDED\"), \"Name\": \"DateCreated\" }, ] end if end sub ' Return parent collection type function getCollectionType() as string if m.top.parentItem.collectionType = invalid return LCase(m.top.parentItem.Type) else return LCase(m.top.parentItem.CollectionType) end if end function ' Search string array for search value. Return if it's found function inStringArray(array, searchValue) as boolean for each item in array if lcase(item) = lcase(searchValue) then return true end for return false end function ' Data to display when options button selected sub SetUpOptions() options = {} options.filter = [] options.favorite = [] setMusicOptions(options) ' Set selected view option for each o in options.views if LCase(o.Name) = LCase(m.view) o.Selected = true o.Ascending = m.sortAscending m.options.view = o.Name end if end for ' Set selected sort option for each o in options.sort if LCase(o.Name) = LCase(m.sortField) o.Selected = true o.Ascending = m.sortAscending m.options.sortField = o.Name end if end for ' Set selected filter option for each o in options.filter if LCase(o.Name) = LCase(m.filter) o.Selected = true m.options.filter = o.Name end if end for m.options.options = options end sub ' ' Logo Image Loaded Event Handler sub LogoImageLoaded(msg) data = msg.GetData() m.loadLogoTask.unobserveField(\"content\") m.loadLogoTask.content = [] if data.Count() &gt; 0 m.artistLogo.uri = data[0] m.artistLogo.visible = true else m.selectedArtistName.visible = true end if end sub ' 'Handle loaded data, and add to Grid sub ItemDataLoaded(msg) m.top.alphaActive = false itemData = msg.GetData() m.loadItemsTask.unobserveField(\"content\") m.loadItemsTask.content = [] if itemData = invalid m.Loading = false return end if if LCase(m.loadItemsTask.view) = \"genres\" for each item in itemData m.genreData.appendChild(item) end for m.itemGrid.opacity = \"0\" m.genreList.opacity = \"1\" m.itemGrid.setFocus(false) m.genreList.setFocus(true) m.loadedItems = m.genreList.content.getChildCount() m.loadedRows = m.loadedItems / m.genreList.numColumns m.loading = false m.spinner.visible = false return end if m.itemGrid.opacity = \"1\" m.genreList.opacity = \"0\" m.itemGrid.setFocus(true) m.genreList.setFocus(false) for each item in itemData m.data.appendChild(item) end for 'Update the stored counts m.loadedItems = m.itemGrid.content.getChildCount() m.loadedRows = m.loadedItems / m.itemGrid.numColumns m.Loading = false 'If there are no items to display, show message if m.loadedItems = 0 m.emptyText.text = tr(\"NO_ITEMS\").Replace(\"%1\", m.top.parentItem.Type) m.emptyText.visible = true end if m.spinner.visible = false end sub ' 'Set Selected Artist Name sub SetName(artistName as string) m.selectedArtistName.text = artistName end sub ' 'Set Selected Artist Song Count sub SetSongCount(totalCount) appendText = \" \" + tr(\"Songs\") if totalCount = 1 appendText = \" \" + tr(\"Song\") end if m.selectedArtistSongCount.text = totalCount.tostr() + appendText end sub ' 'Set Selected Artist Album Count sub SetAlbumCount(totalCount) appendText = \" \" + tr(\"Albums\") if totalCount = 1 appendText = \" \" + tr(\"Album\") end if m.selectedArtistAlbumCount.text = totalCount.tostr() + appendText end sub ' 'Set Selected Artist Genres sub SetGenres(artistGenres) m.selectedArtistGenres.text = artistGenres.join(\", \") end sub ' 'Set Background Image sub SetBackground(backgroundUri as string) if backgroundUri = \"\" m.backdrop.opacity = 0 end if 'If a new image is being loaded, or transitioned to, store URL to load next if LCase(m.swapAnimation.state) &lt;&gt; \"stopped\" or LCase(m.newBackdrop.loadStatus) = \"loading\" m.queuedBGUri = backgroundUri return end if m.newBackdrop.uri = backgroundUri end sub ' 'Handle new item being focused sub onItemFocused() focusedRow = m.itemGrid.currFocusRow itemInt = m.itemGrid.itemFocused ' If no selected item, set background to parent backdrop if itemInt = -1 return end if m.artistLogo.visible = false m.selectedArtistName.visible = false m.selectedArtistGenres.visible = false m.selectedArtistSongCount.visible = false m.selectedArtistAlbumCount.visible = false ' Load more data if focus is within last 5 rows, and there are more items to load if focusedRow &gt;= m.loadedRows - 5 and m.loadeditems &lt; m.loadItemsTask.totalRecordCount loadMoreData() end if m.selectedFavoriteItem = getItemFocused() if LCase(m.options.view) = \"albums\" or LCase(m.view) = \"albums\" or LCase(m.top.parentItem.json.type) = \"musicgenre\" return end if if LCase(m.options.view) = \"artistsgrid\" or LCase(m.view) = \"artistsgrid\" return end if if LCase(m.options.view) = \"albumartistsgrid\" or LCase(m.view) = \"albumartistsgrid\" return end if if not m.selectedArtistGenres.visible m.selectedArtistGenres.visible = true end if if not m.selectedArtistSongCount.visible m.selectedArtistSongCount.visible = true end if if not m.selectedArtistAlbumCount.visible m.selectedArtistAlbumCount.visible = true end if itemData = m.selectedFavoriteItem.json if isValid(itemData.SongCount) SetSongCount(itemData.SongCount) else SetSongCount(\"\") end if if isValid(itemData.AlbumCount) SetAlbumCount(itemData.AlbumCount) else SetAlbumCount(\"\") end if if isValid(itemData.Genres) SetGenres(itemData.Genres) else SetGenres([]) end if if isValid(itemData.Name) SetName(itemData.Name) else SetName(\"\") end if m.loadLogoTask.itemId = itemData.id m.loadLogoTask.itemType = \"LogoImage\" m.loadLogoTask.observeField(\"content\", \"LogoImageLoaded\") m.loadLogoTask.control = \"RUN\" ' Set Background to item backdrop SetBackground(m.selectedFavoriteItem.backdropUrl) end sub sub setFieldText(field, value) node = m.top.findNode(field) if node = invalid or value = invalid then return ' Handle non strings... Which _shouldn't_ happen, but hey if type(value) = \"roInt\" or type(value) = \"Integer\" value = str(value) else if type(value) = \"roFloat\" or type(value) = \"Float\" value = str(value) else if type(value) &lt;&gt; \"roString\" and type(value) &lt;&gt; \"String\" value = \"\" end if node.text = value end sub ' 'When Image Loading Status changes sub newBGLoaded() 'If image load was sucessful, start the fade swap if LCase(m.newBackdrop.loadStatus) = \"ready\" m.swapAnimation.control = \"start\" end if end sub ' 'Swap Complete sub swapDone() if LCase(m.swapAnimation.state) = \"stopped\" 'Set main BG node image and hide transitioning node m.backdrop.uri = m.newBackdrop.uri m.backdrop.opacity = 1 m.newBackdrop.opacity = 0 'If there is another one to load if m.newBackdrop.uri &lt;&gt; m.queuedBGUri and m.queuedBGUri &lt;&gt; \"\" SetBackground(m.queuedBGUri) m.queuedBGUri = \"\" end if end if end sub ' 'Load next set of items sub loadMoreData() m.spinner.visible = true if m.Loading = true then return m.Loading = true m.loadItemsTask.startIndex = m.loadedItems m.loadItemsTask.observeField(\"content\", \"ItemDataLoaded\") m.loadItemsTask.control = \"RUN\" end sub ' 'Item Selected sub onItemSelected() m.top.selectedItem = m.itemGrid.content.getChild(m.itemGrid.itemSelected) end sub ' 'Returns Focused Item function getItemFocused() if m.itemGrid.isinFocusChain() and isValid(m.itemGrid.itemFocused) return m.itemGrid.content.getChild(m.itemGrid.itemFocused) else if m.genreList.isinFocusChain() and isValid(m.genreList.itemFocused) return m.genreList.content.getChild(m.genreList.itemFocused) end if return invalid end function ' 'Genre Item Selected sub onGenreItemSelected() m.top.selectedItem = m.genreList.content.getChild(m.genreList.itemSelected) end sub ' 'Genre Item Focused sub onGenreItemFocused() focusedRow = m.genreList.currFocusRow ' Load more data if focus is within last 5 rows, and there are more items to load if focusedRow &gt;= m.loadedRows - 5 and m.loadeditems &lt; m.loadItemsTask.totalRecordCount loadMoreData() end if end sub sub onItemalphaSelected() if m.top.alphaSelected &lt;&gt; \"\" m.loadedRows = 0 m.loadedItems = 0 m.data = CreateObject(\"roSGNode\", \"ContentNode\") m.itemGrid.content = m.data m.genreData = CreateObject(\"roSGNode\", \"ContentNode\") m.genreList.content = m.genreData m.loadItemsTask.searchTerm = \"\" m.VoiceBox.text = \"\" m.loadItemsTask.nameStartsWith = m.alpha.itemAlphaSelected m.spinner.visible = true loadInitialItems() end if end sub sub onvoiceFilter() if m.VoiceBox.text &lt;&gt; \"\" m.loadedRows = 0 m.loadedItems = 0 m.data = CreateObject(\"roSGNode\", \"ContentNode\") m.itemGrid.content = m.data m.top.alphaSelected = \"\" m.loadItemsTask.NameStartsWith = \" \" m.loadItemsTask.searchTerm = m.voiceBox.text m.loadItemsTask.recursive = true m.spinner.visible = true loadInitialItems() end if end sub ' 'Check if options updated and any reloading required sub optionsClosed() reload = false if m.options.sortField &lt;&gt; m.sortField or m.options.sortAscending &lt;&gt; m.sortAscending m.sortField = m.options.sortField m.sortAscending = m.options.sortAscending reload = true sortAscendingStr = \"true\" 'Store sort settings if not m.sortAscending sortAscendingStr = \"false\" end if set_user_setting(\"display.\" + m.top.parentItem.Id + \".sortField\", m.sortField) set_user_setting(\"display.\" + m.top.parentItem.Id + \".sortAscending\", sortAscendingStr) end if if m.options.filter &lt;&gt; m.filter m.filter = m.options.filter reload = true set_user_setting(\"display.\" + m.top.parentItem.Id + \".filter\", m.options.filter) end if m.view = m.global.session.user.settings[\"display.\" + m.top.parentItem.Id + \".landing\"] if m.options.view &lt;&gt; m.view m.view = m.options.view m.top.view = m.view set_user_setting(\"display.\" + m.top.parentItem.Id + \".landing\", m.view) ' Reset any filtering or search terms m.top.alphaSelected = \"\" m.loadItemsTask.NameStartsWith = \" \" m.loadItemsTask.searchTerm = \"\" m.filter = \"All\" m.sortField = \"SortName\" m.sortAscending = true ' Reset view to defaults set_user_setting(\"display.\" + m.top.parentItem.Id + \".sortField\", m.sortField) set_user_setting(\"display.\" + m.top.parentItem.Id + \".sortAscending\", \"true\") set_user_setting(\"display.\" + m.top.parentItem.Id + \".filter\", m.filter) reload = true end if if reload m.loadedRows = 0 m.loadedItems = 0 m.data = CreateObject(\"roSGNode\", \"ContentNode\") m.genreData = CreateObject(\"roSGNode\", \"ContentNode\") m.itemGrid.content = m.data m.genreList.content = m.genreData loadInitialItems() end if m.itemGrid.setFocus(m.itemGrid.opacity = 1) m.genreList.setFocus(m.genreList.opacity = 1) end sub sub onChannelSelected(msg) node = msg.getRoSGNode() m.top.lastFocus = lastFocusedChild(node) if node.watchChannel &lt;&gt; invalid ' Clone the node when it's reused/update in the TimeGrid it doesn't automatically start playing m.top.selectedItem = node.watchChannel.clone(false) end if end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false if key = \"left\" and m.voiceBox.isinFocusChain() m.itemGrid.setFocus(m.itemGrid.opacity = 1) m.genreList.setFocus(m.genreList.opacity = 1) m.voiceBox.setFocus(false) end if if key = \"options\" if m.options.visible = true m.options.visible = false m.top.removeChild(m.options) optionsClosed() else itemSelected = m.selectedFavoriteItem if itemSelected &lt;&gt; invalid m.options.selectedFavoriteItem = itemSelected end if m.options.visible = true m.top.appendChild(m.options) m.options.setFocus(true) end if return true else if key = \"back\" if m.options.visible = true m.options.visible = false optionsClosed() return true else m.global.sceneManager.callfunc(\"popScene\") m.loadItemsTask.control = \"stop\" return true end if else if key = \"left\" if m.itemGrid.isinFocusChain() m.top.alphaActive = true m.itemGrid.setFocus(false) alpha = m.alpha.getChild(0).findNode(\"Alphamenu\") alpha.setFocus(true) return true else if m.genreList.isinFocusChain() m.top.alphaActive = true m.genreList.setFocus(false) alpha = m.alpha.getChild(0).findNode(\"Alphamenu\") alpha.setFocus(true) return true end if else if key = \"right\" and m.Alpha.isinFocusChain() m.top.alphaActive = false m.Alpha.setFocus(false) m.Alpha.visible = true m.itemGrid.setFocus(m.itemGrid.opacity = 1) m.genreList.setFocus(m.genreList.opacity = 1) return true else if key = \"replay\" and m.itemGrid.isinFocusChain() if m.resetGrid = true m.itemGrid.animateToItem = 0 else m.itemGrid.jumpToItem = 0 end if else if key = \"replay\" and m.genreList.isinFocusChain() if m.resetGrid = true m.genreList.animateToItem = 0 else m.genreList.jumpToItem = 0 end if return true else if key = \"play\" itemToPlay = getItemFocused() if itemToPlay &lt;&gt; invalid m.top.quickPlayNode = itemToPlay return true end if end if if key = \"replay\" m.spinner.visible = true m.loadItemsTask.searchTerm = \"\" m.loadItemsTask.nameStartsWith = \"\" m.voiceBox.text = \"\" m.top.alphaSelected = \"\" m.loadItemsTask.filter = \"All\" m.filter = \"All\" m.data = CreateObject(\"roSGNode\", \"ContentNode\") m.itemGrid.content = m.data loadInitialItems() return true end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_MusicSongData.brs.html":{"id":"components_data_MusicSongData.brs.html","title":"Source: components/data/MusicSongData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/MusicSongData.brs sub setFields() datum = m.top.json m.top.id = datum.id m.top.title = datum.name m.top.overview = datum.overview m.top.trackNumber = datum.IndexNumber m.top.length = datum.RunTimeTicks end sub sub setPoster() if m.top.image &lt;&gt; invalid m.top.posterURL = m.top.image.url else m.top.posterURL = \"\" end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_options_OptionNode.brs.html":{"id":"components_options_OptionNode.brs.html","title":"Source: components/options/OptionNode.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/options/OptionNode.brs sub init() end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_OptionsButton.brs.html":{"id":"components_data_OptionsButton.brs.html","title":"Source: components/data/OptionsButton.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/OptionsButton.brs import \"pkg:/source/utils/config.brs\" sub init() end sub sub press() end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_OptionsData.brs.html":{"id":"components_data_OptionsData.brs.html","title":"Source: components/data/OptionsData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/OptionsData.brs import \"pkg:/source/utils/config.brs\" sub init() m.top.value_index = 0 end sub sub update_title() if m.top.choices.count() = 0 m.top.title = m.top.base_title + \": &lt;none&gt;\" return end if for i = 0 to m.top.choices.count() - 1 if m.top.choices[i].value = m.top.value m.top.value_index = i exit for end if end for m.top.title = m.top.base_title + \": \" + m.top.choices[m.top.value_index].display end sub sub press() max_opt = m.top.choices.count() i = m.top.value_index + 1 while i &gt;= max_opt i = i - max_opt end while m.top.value_index = i m.top.value = m.top.choices[m.top.value_index].value if m.top.config_key = \"\" or m.top.config_key = invalid return end if if m.top.global_setting set_setting(m.top.config_key, m.top.value) else set_user_setting(m.top.config_key, m.top.value) end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_options_OptionsSlider.brs.html":{"id":"components_options_OptionsSlider.brs.html","title":"Source: components/options/OptionsSlider.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/options/OptionsSlider.brs sub init() m.top.visible = false panel = m.top.findNode(\"panel\") panel.panelSize = \"small\" panel.leftPosition = 96 panel.focusable = true panel.hasNextPanel = false panel.leftOnly = true list = m.top.findNode(\"panelList\") panel.list = list end sub sub setFields() options = m.top.options buttons = m.top.buttons row = m.top.findNode(\"fieldList\") row.clear() row.appendChildren(options) row.appendChildren(buttons) end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false if key = \"options\" or key = \"back\" m.top.visible = false m.top.closeSidePanel = true return true else if key = \"OK\" list = m.top.findNode(\"panelList\") data = list.content.getChild(list.itemFocused) data.optionSelected = true return true end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_OverviewDialog.bs.html":{"id":"components_OverviewDialog.bs.html","title":"Source: components/OverviewDialog.bs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/OverviewDialog.bs sub setTitle() m.top.findNode(\"titleArea\").primaryTitle = m.top.title end sub sub setOverview() m.top.findNode(\"description\").text = m.top.overview end sub function onKeyEvent(key as string, press as boolean) as boolean if press = false then return false if key = \"OK\" and m.top.findNode(\"contentArea\").isInFocusChain() m.top.close = true end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_PersonData.brs.html":{"id":"components_data_PersonData.brs.html","title":"Source: components/data/PersonData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/PersonData.brs import \"pkg:/source/api/Image.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" sub setFields() json = m.top.json m.top.id = json.id m.top.favorite = json.UserData.isFavorite m.top.Type = \"Person\" setPoster() end sub sub setPoster() if m.top.image &lt;&gt; invalid m.top.posterURL = m.top.image.url else if m.top.json.ImageTags.Primary &lt;&gt; invalid imgParams = { \"maxHeight\": 440, \"maxWidth\": 295, \"Tag\": m.top.json.ImageTags.Primary } m.top.posterURL = ImageURL(m.top.json.id, \"Primary\", imgParams) else if m.top.json.BackdropImageTags[0] &lt;&gt; invalid imgParams = { \"maxHeight\": 440, \"Tag\": m.top.json.BackdropImageTags[0] } m.top.posterURL = ImageURL(m.top.json.id, \"Backdrop\", imgParams) else if m.top.json.ParentThumbImageTag &lt;&gt; invalid and m.top.json.ParentThumbItemId &lt;&gt; invalid imgParams = { \"maxHeight\": 440, \"maxWidth\": 295, \"Tag\": m.top.json.ParentThumbImageTag } m.top.posterURL = ImageURL(m.top.json.ParentThumbItemId, \"Thumb\", imgParams) end if ' Add Backdrop Image if m.top.json.BackdropImageTags[0] &lt;&gt; invalid imgParams = { \"maxHeight\": 720, \"maxWidth\": 1280, \"Tag\": m.top.json.BackdropImageTags[0] } m.top.backdropURL = ImageURL(m.top.json.id, \"Backdrop\", imgParams) end if end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_PersonDetails.brs.html":{"id":"components_PersonDetails.brs.html","title":"Source: components/PersonDetails.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/PersonDetails.brs import \"pkg:/source/api/Image.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" sub init() m.dscr = m.top.findNode(\"description\") m.vidsList = m.top.findNode(\"extrasGrid\") m.btnGrp = m.top.findNode(\"buttons\") m.btnGrp.observeField(\"escape\", \"onButtonGroupEscaped\") m.favBtn = m.top.findNode(\"favorite-button\") m.extrasGrp = m.top.findNode(\"extrasGrp\") m.extrasGrp.opacity = 1.0 createDialogPallete() m.top.optionsAvailable = false end sub sub loadPerson() item = m.top.itemContent itemData = item.json m.top.Id = itemData.id name = m.top.findNode(\"Name\") name.Text = itemData.Name name.font.size = 70 if itemData.PremiereDate &lt;&gt; invalid and itemData.PremiereDate &lt;&gt; \"\" lifeStringLabel = createObject(\"rosgnode\", \"Label\") lifeStringLabel.id = \"premierDate\" lifeStringLabel.font = \"font:SmallestBoldSystemFont\" lifeStringLabel.height = \"100\" lifeStringLabel.vertAlign = \"bottom\" name.vertAlign = \"top\" name.font.size = 60 m.top.findNode(\"title_rectangle\").appendChild(lifeStringLabel) birthDate = CreateObject(\"roDateTime\") birthDate.FromISO8601String(itemData.PremiereDate) deathDate = CreateObject(\"roDatetime\") lifeString = tr(\"Born\") + \": \" + birthDate.AsDateString(\"short-month-no-weekday\") if itemData.EndDate &lt;&gt; invalid and itemData.EndDate &lt;&gt; \"\" deathDate.FromISO8601String(itemData.EndDate) lifeString = lifeString + \" * \" + tr(\"Died\") + \": \" + deathDate.AsDateString(\"short-month-no-weekday\") end if ' Calculate age age = deathDate.getYear() - birthDate.getYear() if deathDate.getMonth() &lt; birthDate.getMonth() age-- else if deathDate.getMonth() = birthDate.getMonth() if deathDate.getDayOfMonth() &lt; birthDate.getDayOfMonth() age-- end if end if lifeString = lifeString + \" * \" + tr(\"Age\") + \": \" + stri(age) lifeStringLabel.Text = lifeString end if if itemData.Overview &lt;&gt; invalid and itemData.Overview &lt;&gt; \"\" m.dscr.text = itemData.Overview else m.dscr.text = tr(\"Biographical information for this person is not currently available.\") m.dscr.horizAlign = \"center\" m.dscr.vertAlign = \"center\" end if if item.posterURL &lt;&gt; invalid and item.posterURL &lt;&gt; \"\" m.top.findnode(\"personImage\").uri = item.posterURL else m.top.findnode(\"personImage\").uri = \"pkg:/images/baseline_person_white_48dp.png\" end if m.vidsList.callFunc(\"loadPersonVideos\", m.top.Id) setFavoriteColor() if not m.favBtn.hasFocus() then dscrShowFocus() end sub sub dscrShowFocus() m.dscr.setFocus(true) m.dscr.opacity = 1.0 m.top.findNode(\"dscrBorder\").color = \"#d0d0d0ff\" end sub sub onButtonGroupEscaped() key = m.btnGrp.escape if key = \"down\" m.dscr.setFocus(true) m.dscr.opacity = 1.0 m.top.findNode(\"dscrBorder\").color = \"#d0d0d0ff\" end if end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false if key = \"OK\" if m.dscr.hasFocus() createFullDscrDlg() return true end if return false end if if key = \"back\" m.global.sceneManager.callfunc(\"popScene\") return true end if if key = \"down\" if m.dscr.hasFocus() m.dscr.opacity = 0.6 m.top.findNode(\"dscrBorder\").color = \"#data202020ff\" m.vidsList.setFocus(true) m.top.findNode(\"VertSlider\").reverse = false m.top.findNode(\"pplAnime\").control = \"start\" return true end if else if key = \"up\" if m.dscr.hasFocus() m.favBtn.setFocus(true) m.dscr.opacity = 0.6 m.top.findNode(\"dscrBorder\").color = \"#data202020ff\" return true else if m.vidsList.isInFocusChain() and m.vidsList.itemFocused = 0 m.top.findNode(\"VertSlider\").reverse = true m.top.findNode(\"pplAnime\").control = \"start\" dscrShowFocus() return true end if end if return false end function sub setFavoriteColor() fave = m.top.itemContent.favorite fave_button = m.top.findNode(\"favorite-button\") if fave &lt;&gt; invalid and fave fave_button.textColor = \"#00ff00ff\" fave_button.focusedTextColor = \"#269926ff\" fave_button.text = tr(\"Favorite\") else fave_button.textColor = \"0xddddddff\" fave_button.focusedTextColor = \"#262626ff\" fave_button.text = tr(\"Set Favorite\") end if end sub sub createFullDscrDlg() dlg = CreateObject(\"roSGNode\", \"OverviewDialog\") dlg.Title = m.top.itemContent.json.Name dlg.width = 1290 dlg.palette = m.dlgPalette dlg.overview = m.dscr.text m.fullDscrDlg = dlg m.top.getScene().dialog = dlg end sub sub createDialogPallete() m.dlgPalette = createObject(\"roSGNode\", \"RSGPalette\") m.dlgPalette.colors = { DialogBackgroundColor: \"0x262828FF\", DialogItemColor: \"0x00EF00FF\", DialogTextColor: \"0xb0b0b0FF\", DialogFocusColor: \"0xcececeFF\", DialogFocusItemColor: \"0x202020FF\", DialogSecondaryTextColor: \"0xf8f8f8ff\", DialogSecondaryItemColor: \"0xcc7ecc4D\", DialogInputFieldColor: \"0x80FF8080\", KeyboardDialogColor: \"0x80FF804D\", DialogFootprintColor: \"0x80FF804D\" } end sub function shortDate(isoDate) as string myDate = CreateObject(\"roDateTime\") myDate.FromISO8601String(isoDate) return myDate.AsDateString(\"short-month-no-weekday\") end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_PhotoData.brs.html":{"id":"components_data_PhotoData.brs.html","title":"Source: components/data/PhotoData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/PhotoData.brs import \"pkg:/source/api/Image.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" sub setFields() json = m.top.json m.top.id = json.id m.top.Title = json.name m.top.Type = \"Photo\" setPoster() end sub sub setPoster() if m.top.image &lt;&gt; invalid m.top.posterURL = m.top.image.url else if m.top.json.ImageTags.Primary &lt;&gt; invalid imgParams = { \"maxHeight\": 440, \"maxWidth\": 295, \"Tag\": m.top.json.ImageTags.Primary } m.top.posterURL = ImageURL(m.top.json.id, \"Primary\", imgParams) else if m.top.json.BackdropImageTags[0] &lt;&gt; invalid imgParams = { \"maxHeight\": 440, \"Tag\": m.top.json.BackdropImageTags[0] } m.top.posterURL = ImageURL(m.top.json.id, \"Backdrop\", imgParams) else if m.top.json.ParentThumbImageTag &lt;&gt; invalid and m.top.json.ParentThumbItemId &lt;&gt; invalid imgParams = { \"maxHeight\": 440, \"maxWidth\": 295, \"Tag\": m.top.json.ParentThumbImageTag } m.top.posterURL = ImageURL(m.top.json.ParentThumbItemId, \"Thumb\", imgParams) end if ' Add Backdrop Image if m.top.json.BackdropImageTags[0] &lt;&gt; invalid imgParams = { \"maxHeight\": 720, \"maxWidth\": 1280, \"Tag\": m.top.json.BackdropImageTags[0] } m.top.backdropURL = ImageURL(m.top.json.id, \"Backdrop\", imgParams) end if end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_photos_PhotoDetails.brs.html":{"id":"components_photos_PhotoDetails.brs.html","title":"Source: components/photos/PhotoDetails.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/photos/PhotoDetails.brs import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/utils/config.brs\" sub init() m.top.optionsAvailable = true m.top.overhangVisible = false m.slideshowTimer = m.top.findNode(\"slideshowTimer\") m.slideshowTimer.observeField(\"fire\", \"nextSlide\") m.status = m.top.findNode(\"status\") m.textBackground = m.top.findNode(\"background\") m.statusTimer = m.top.findNode(\"statusTimer\") m.statusTimer.observeField(\"fire\", \"statusUpdate\") m.slideshow = m.global.session.user.settings[\"photos.slideshow\"] m.random = m.global.session.user.settings[\"photos.random\"] m.showStatusAnimation = m.top.findNode(\"showStatusAnimation\") m.hideStatusAnimation = m.top.findNode(\"hideStatusAnimation\") itemContentChanged() end sub sub itemContentChanged() if isValidToContinue(m.top.itemIndex) m.LoadLibrariesTask = createObject(\"roSGNode\", \"LoadPhotoTask\") itemContent = m.top.items.content.getChild(m.top.itemIndex) m.LoadLibrariesTask.itemContent = itemContent m.LoadLibrariesTask.observeField(\"results\", \"onPhotoLoaded\") m.LoadLibrariesTask.control = \"RUN\" end if end sub sub onPhotoLoaded() if m.LoadLibrariesTask.results &lt;&gt; invalid photo = m.top.findNode(\"photo\") photo.uri = m.LoadLibrariesTask.results if m.slideshow = true or m.random = true ' user has requested either a slideshow or random... m.slideshowTimer.control = \"start\" end if else 'Show user error here (for example if it's not a supported image type) message_dialog(\"This image type is not supported.\") end if end sub sub nextSlide() m.slideshowTimer.control = \"stop\" if m.slideshow = true if isValidToContinue(m.top.itemIndex + 1) m.top.itemIndex++ m.slideshowTimer.control = \"start\" end if else if m.random = true index = rnd(m.top.items.content.getChildCount() - 1) if isValidToContinue(index) m.top.itemIndex = index m.slideshowTimer.control = \"start\" end if end if end sub sub statusUpdate() m.statusTimer.control = \"stop\" m.hideStatusAnimation.control = \"start\" end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false if key = \"right\" if isValidToContinue(m.top.itemIndex + 1) m.slideshowTimer.control = \"stop\" m.top.itemIndex++ end if return true end if if key = \"left\" if isValidToContinue(m.top.itemIndex - 1) m.slideshowTimer.control = \"stop\" m.top.itemIndex-- end if return true end if if key = \"play\" if m.slideshowTimer.control = \"start\" ' stop the slideshow if the user hits \"pause\" m.slideshowTimer.control = \"stop\" m.status.text = tr(\"Slideshow Paused\") if m.textBackground.opacity = 0 m.showStatusAnimation.control = \"start\" end if m.statusTimer.control = \"start\" else ' start the slideshow if the user hits \"play\" m.status.text = tr(\"Slideshow Resumed\") if m.textBackground.opacity = 0 m.showStatusAnimation.control = \"start\" end if m.slideshow = true m.statusTimer.control = \"start\" m.slideshowTimer.control = \"start\" end if return true end if if key = \"options\" ' Options (random etc) is done on itemGrid return true end if return false end function function isValidToContinue(index as integer) if isValid(m.top.items) and isValid(m.top.items.content) if index &gt;= 0 and index &lt; m.top.items.content.getChildCount() return true end if end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_PlaybackDialog.brs.html":{"id":"components_PlaybackDialog.brs.html","title":"Source: components/PlaybackDialog.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/PlaybackDialog.brs function onKeyEvent(key as string, press as boolean) as boolean if key = \"OK\" m.top.close = true return true end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_PlayedCheckmark.brs.html":{"id":"components_PlayedCheckmark.brs.html","title":"Source: components/PlayedCheckmark.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/PlayedCheckmark.brs sub init() checkmark = m.top.findNode(\"checkmark\") checkmark.font.size = 48 end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_PlaylistData.brs.html":{"id":"components_data_PlaylistData.brs.html","title":"Source: components/data/PlaylistData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/PlaylistData.brs sub setFields() datum = m.top.json m.top.id = datum.id m.top.title = datum.name m.top.overview = datum.overview end sub sub setPoster() if m.top.image &lt;&gt; invalid m.top.posterURL = m.top.image.url else m.top.posterURL = \"\" end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_music_PlaylistView.brs.html":{"id":"components_music_PlaylistView.brs.html","title":"Source: components/music/PlaylistView.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/music/PlaylistView.brs import \"pkg:/source/utils/misc.brs\" sub init() m.top.optionsAvailable = false setupMainNode() m.playAll = m.top.findNode(\"playAll\") m.albumCover = m.top.findNode(\"albumCover\") m.songList = m.top.findNode(\"songList\") m.infoGroup = m.top.FindNode(\"infoGroup\") m.songListRect = m.top.FindNode(\"songListRect\") m.songList.observeField(\"doneLoading\", \"onDoneLoading\") m.spinner = m.top.findNode(\"spinner\") m.spinner.visible = true m.dscr = m.top.findNode(\"overview\") createDialogPallete() end sub sub setupMainNode() main = m.top.findNode(\"toplevel\") main.translation = [96, 175] end sub ' Set values for displayed values on screen sub pageContentChanged() item = m.top.pageContent setPosterImage(item.posterURL) setScreenTitle(item.json) setOnScreenTextValues(item.json) ' Only 1 song shown, so hide Play Album button if item.json.ChildCount = 1 m.playAll.visible = false end if end sub ' Set poster image on screen sub setPosterImage(posterURL) if isValid(posterURL) m.albumCover.uri = posterURL end if end sub ' Set screen's title text sub setScreenTitle(json) newTitle = \"\" if isValid(json) if isValid(json.AlbumArtist) newTitle = json.AlbumArtist end if if isValid(json.AlbumArtist) and isValid(json.name) newTitle = newTitle + \" / \" end if if isValid(json.name) newTitle = newTitle + json.name end if end if m.top.overhangTitle = newTitle end sub ' Adjust scene by removing overview node and showing more songs sub adjustScreenForNoOverview() m.infoGroup.removeChild(m.dscr) m.songListRect.height = 800 m.songList.numRows = 12 end sub ' Populate on screen text variables sub setOnScreenTextValues(json) if isValid(json) if isValid(json.overview) and json.overview &lt;&gt; \"\" ' We have overview text setFieldTextValue(\"overview\", json.overview) else ' We don't have overview text adjustScreenForNoOverview() end if setFieldTextValue(\"numberofsongs\", stri(json.ChildCount) + \" Tracks\") if type(json.ProductionYear) = \"roInt\" setFieldTextValue(\"released\", \"Released \" + stri(json.ProductionYear)) end if if json.genres.count() &gt; 0 setFieldTextValue(\"genres\", json.genres.join(\", \")) end if if type(json.RunTimeTicks) = \"LongInteger\" setFieldTextValue(\"runtime\", stri(getMinutes(json.RunTimeTicks)) + \" mins\") end if end if end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false if m.spinner.visible then return false if key = \"options\" if m.dscr.isTextEllipsized createFullDscrDlg() return true end if return false end if if key = \"right\" if m.playAll.hasFocus() m.songList.setFocus(true) return true end if else if key = \"left\" and m.songList.hasFocus() if m.playAll.visible m.playAll.setFocus(true) else return false end if return true end if return false end function sub createFullDscrDlg() dlg = CreateObject(\"roSGNode\", \"OverviewDialog\") dlg.Title = tr(\"Press 'Back' to Close\") dlg.width = 1290 dlg.palette = m.dlgPalette dlg.overview = [m.dscr.text] m.fullDscrDlg = dlg m.top.getScene().dialog = dlg border = createObject(\"roSGNode\", \"Poster\") border.uri = \"pkg:/images/hd_focul_9.png\" border.blendColor = \"#c9c9c9ff\" border.width = dlg.width + 6 border.height = dlg.height + 6 border.translation = [dlg.translation[0] - 3, dlg.translation[1] - 3] border.visible = true end sub sub createDialogPallete() m.dlgPalette = createObject(\"roSGNode\", \"RSGPalette\") m.dlgPalette.colors = { DialogBackgroundColor: \"0x262828FF\", DialogItemColor: \"0x00EF00FF\", DialogTextColor: \"0xb0b0b0FF\", DialogFocusColor: \"0xcececeFF\", DialogFocusItemColor: \"0x202020FF\", DialogSecondaryTextColor: \"0xf8f8f8ff\", DialogSecondaryItemColor: \"0xcc7ecc4D\", DialogInputFieldColor: \"0x80FF8080\", DialogKeyboardColor: \"0x80FF804D\", DialogFootprintColor: \"0x80FF804D\" } end sub sub onDoneLoading() m.songList.unobservefield(\"doneLoading\") m.spinner.visible = false end sub sub OnScreenHidden() m.spinner.visible = false end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_PlaystateTask.brs.html":{"id":"components_PlaystateTask.brs.html","title":"Source: components/PlaystateTask.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/PlaystateTask.brs import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" sub init() m.top.functionName = \"PlaystateUpdate\" end sub sub PlaystateUpdate() if m.top.status = \"start\" url = \"Sessions/Playing\" else if m.top.status = \"stop\" url = \"Sessions/Playing/Stopped\" else if m.top.status = \"update\" url = \"Sessions/Playing/Progress\" else ' Unknown State return end if params = PlaystateDefaults(m.top.params) resp = APIRequest(url) postJson(resp, params) end sub function PlaystateDefaults(params = {} as object) new_params = { '\"CanSeek\": false '\"Item\": \"{}\", ' TODO! '\"NowPlayingQueue\": \"[]\", ' TODO! '\"PlaylistItemId\": \"\", '\"ItemId\": id, '\"SessionId\": \"\", ' TODO! '\"MediaSourceId\": id, '\"AudioStreamIndex\": 1, '\"SubtitleStreamIndex\": 0, \"IsPaused\": false, '\"IsMuted\": false, \"PositionTicks\": 0 '\"PlaybackStartTimeTicks\": 0, '\"VolumeLevel\": 100, '\"Brightness\": 100, '\"AspectRatio\": \"16x9\", '\"PlayMethod\": \"DirectStream\" '\"LiveStreamId\": \"\", '\"PlaySessionId\": \"\", '\"RepeatMode\": \"RepeatNone\" } paramsArray = params.items() for i = 0 to paramsArray.count() - 1 item = paramsArray[i] new_params[item.key] = item.value end for return FormatJson(new_params) end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_liveTv_ProgramDetails.brs.html":{"id":"components_liveTv_ProgramDetails.brs.html","title":"Source: components/liveTv/ProgramDetails.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/liveTv/ProgramDetails.brs import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/utils/config.brs\" sub init() ' Max \"Overview\" lines to show in Preview and Detail m.maxPreviewLines = 5 m.maxDetailLines = 14 m.detailsView = m.top.findNode(\"detailsView\") m.noInfoView = m.top.findNode(\"noInformation\") m.programName = m.top.findNode(\"programName\") m.episodeTitle = m.top.findNode(\"episodeTitle\") m.episodeNumber = m.top.findNode(\"episodeNumber\") m.overview = m.top.findNode(\"overview\") m.episodeDetailsGroup = m.top.findNode(\"episodeDetailsGroup\") m.isLiveGroup = m.top.findNode(\"isLive\") m.isRepeatGroup = m.top.findNode(\"isRepeat\") m.broadcastDetails = m.top.findNode(\"broadcastDetails\") m.duration = m.top.findNode(\"duration\") m.channelName = m.top.findNode(\"channelName\") m.image = m.top.findNode(\"image\") m.favorite = m.top.findNode(\"favorite\") m.viewChannelFocusAnimationOpacity = m.top.findNode(\"viewChannelFocusAnimationOpacity\") m.recordFocusAnimationOpacity = m.top.findNode(\"recordFocusAnimationOpacity\") m.recordSeriesFocusAnimationOpacity = m.top.findNode(\"recordSeriesFocusAnimationOpacity\") m.focusAnimation = m.top.findNode(\"focusAnimation\") m.viewChannelButton = m.top.findNode(\"viewChannelButton\") m.recordButton = m.top.findNode(\"recordButton\") m.recordSeriesButton = m.top.findNode(\"recordSeriesButton\") m.viewChannelOutline = m.top.findNode(\"viewChannelOutline\") m.recordOutline = m.top.findNode(\"recordOutline\") m.recordSeriesOutline = m.top.findNode(\"recordSeriesOutline\") m.viewChannelLabel = m.top.findNode(\"viewChannelButtonLabel\") m.recordLabel = m.top.findNode(\"recordButtonLabel\") m.recordSeriesLabel = m.top.findNode(\"recordSeriesButtonLabel\") m.viewChannelButtonBackground = m.top.findNode(\"viewChannelButtonBackground\") m.recordButtonBackground = m.top.findNode(\"recordButtonBackground\") m.recordSeriesButtonBackground = m.top.findNode(\"recordSeriesButtonBackground\") m.focusAnimation.observeField(\"state\", \"onAnimationComplete\") setupLabels() end sub ' Set up Live and Repeat label sizes sub setupLabels() boundingRect = m.top.findNode(\"isLiveText\").boundingRect() isLiveBackground = m.top.findNode(\"isLiveBackground\") isLiveBackground.width = boundingRect.width + 16 isLiveBackground.height = boundingRect.height + 8 m.episodeDetailsGroup.removeChildIndex(0) boundingRect = m.top.findNode(\"isRepeatText\").boundingRect() isRepeatBackground = m.top.findNode(\"isRepeatBackground\") isRepeatBackground.width = boundingRect.width + 16 isRepeatBackground.height = boundingRect.height + 8 m.episodeDetailsGroup.removeChildIndex(0) m.viewChannelLabel.text = tr(\"View Channel\") boundingRect = m.viewChannelButton.boundingRect() viewButtonBackground = m.top.findNode(\"viewChannelButtonBackground\") viewButtonBackground.width = boundingRect.width + 20 viewButtonBackground.height = boundingRect.height + 20 m.viewChannelOutline.width = viewButtonBackground.width m.viewChannelOutline.height = viewButtonBackground.height m.recordLabel.text = tr(\"Record\") boundingRect = m.recordButton.boundingRect() recordButtonBackground = m.top.findNode(\"recordButtonBackground\") recordButtonBackground.width = boundingRect.width + 20 recordButtonBackground.height = boundingRect.height + 20 m.recordOutline.width = recordButtonBackground.width m.recordOutline.height = recordButtonBackground.height m.recordSeriesLabel.text = tr(\"Record Series\") boundingRect = m.recordSeriesButton.boundingRect() recordSeriesButtonBackground = m.top.findNode(\"recordSeriesButtonBackground\") recordSeriesButtonBackground.width = boundingRect.width + 20 recordSeriesButtonBackground.height = boundingRect.height + 20 m.recordSeriesOutline.width = recordSeriesButtonBackground.width m.recordSeriesOutline.height = recordSeriesButtonBackground.height m.userCanRecord = m.global.session.user.settings[\"livetv.canrecord\"] if m.userCanRecord = false m.recordButton.visible = false m.recordSeriesButton.visible = false end if end sub sub updateLabels(recordText = \"Record\", recordSeriesText = \"Record Series\") m.recordLabel.text = tr(recordText) m.recordSeriesLabel.text = tr(recordSeriesText) boundingRect = m.recordButton.boundingRect() recordButtonBackground = m.top.findNode(\"recordButtonBackground\") recordButtonBackground.width = boundingRect.width recordButtonBackground.height = boundingRect.height m.recordOutline.width = recordButtonBackground.width m.recordOutline.height = recordButtonBackground.height boundingRect = m.recordSeriesButton.boundingRect() recordSeriesButtonBackground = m.top.findNode(\"recordSeriesButtonBackground\") recordSeriesButtonBackground.width = boundingRect.width recordSeriesButtonBackground.height = boundingRect.height m.recordSeriesOutline.width = recordSeriesButtonBackground.width m.recordSeriesOutline.height = recordSeriesButtonBackground.height end sub sub channelUpdated() if m.top.channel = invalid m.top.findNode(\"noInfoChannelName\").text = \"\" m.channelName.text = \"\" else m.top.findNode(\"noInfoChannelName\").text = m.top.channel.Title m.channelName.text = m.top.channel.Title if m.top.programDetails = invalid m.image.uri = m.top.channel.posterURL end if m.favorite.visible = m.top.channel.favorite end if end sub sub programUpdated() m.top.watchSelectedChannel = false m.top.recordSelectedChannel = false m.top.recordSeriesSelectedChannel = false m.overview.maxLines = m.maxDetailLines prog = m.top.programDetails ' If no program selected, hide details view if prog = invalid channelUpdated() m.detailsView.visible = \"false\" m.noInfoView.visible = \"true\" return end if m.programName.text = prog.Title m.overview.text = prog.description m.episodeDetailsGroup.removeChildrenIndex(m.episodeDetailsGroup.getChildCount(), 0) if prog.isLive m.episodeDetailsGroup.appendChild(m.isLiveGroup) else if prog.isRepeat m.episodeDetailsGroup.appendChild(m.isRepeatGroup) end if ' Episode Number if prog.seasonNumber &gt; 0 and prog.episodeNumber &gt; 0 m.episodeNumber.text = \"S\" + StrI(prog.seasonNumber).trim() + \":E\" + StrI(prog.episodeNumber).trim() if prog.episodeTitle &lt;&gt; \"\" then m.episodeNumber.text = m.episodeNumber.text + \" -\" ' Add a Dash if showing Episode Number and Title m.episodeDetailsGroup.appendChild(m.episodeNumber) end if if prog.episodeTitle &lt;&gt; invalid and prog.episodeTitle &lt;&gt; \"\" m.episodeTitle.text = prog.episodeTitle m.episodeTitle.visible = true m.episodeDetailsGroup.appendChild(m.episodeTitle) end if m.duration.text = getDurationStringFromSeconds(prog.PlayDuration) ' Calculate Broadcast Details now = createObject(\"roDateTime\") startDate = createObject(\"roDateTime\") endDate = createObject(\"roDateTime\") startDate.FromISO8601String(prog.StartDate) endDate.FromISO8601String(prog.EndDate) day = getRelativeDayName(startDate) ' Get Start Date in local timezone for display to user localStartDate = createObject(\"roDateTime\") localStartDate.FromISO8601String(prog.StartDate) localStartDate.ToLocalTime() if startDate.AsSeconds() &lt; now.AsSeconds() and endDate.AsSeconds() &gt; now.AsSeconds() if day = \"today\" m.broadcastDetails.text = tr(\"Started at\") + \" \" + formatTime(localStartDate) else m.broadcastDetails.text = tr(\"Started\") + \" \" + tr(day) + \", \" + formatTime(localStartDate) end if else if startDate.AsSeconds() &gt; now.AsSeconds() if day = \"today\" m.broadcastDetails.text = tr(\"Starts at\") + \" \" + formatTime(localStartDate) else m.broadcastDetails.text = tr(\"Starts\") + \" \" + tr(day) + \", \" + formatTime(localStartDate) end if else if day = \"today\" m.broadcastDetails.text = tr(\"Ended at\") + \" \" + formatTime(localStartDate) else m.broadcastDetails.text = tr(\"Ended\") + \" \" + tr(day) + \", \" + formatTime(localStartDate) end if end if m.image.uri = prog.PosterURL ' If currently being recorded, change button to \"Stop Recording\" if prog.json.TimerId &lt;&gt; invalid if prog.json.SeriesTimerId &lt;&gt; invalid updateLabels(\"Cancel Recording\", \"Cancel Series Recording\") else updateLabels(\"Cancel Recording\", \"Record Series\") end if else updateLabels() end if ' If not a series, hide Record Series button if prog.json.isSeries &lt;&gt; true ' could be invalid or false m.recordSeriesButton.visible = false else m.recordSeriesButton.visible = true end if m.detailsView.visible = \"true\" m.noInfoView.visible = \"false\" m.top.height = m.detailsView.boundingRect().height m.overview.maxLines = m.maxPreviewLines end sub ' ' Get relative date name for a date (yesterday, today, tomorrow, or otherwise weekday name ) function getRelativeDayName(date) as string now = createObject(\"roDateTime\") ' Check for Today if now.AsDateString(\"short-date-dashes\") = date.AsDateString(\"short-date-dashes\") return \"today\" end if ' Check for Yesterday todayMidnight = now.AsSeconds() - (now.AsSeconds() mod 86400) dateMidnight = date.AsSeconds() - (date.AsSeconds() mod 86400) if todayMidnight - dateMidnight = 86400 return \"yesterday\" end if if dateMidnight - todayMidnight = 86400 return \"tomorrow\" end if return date.GetWeekday() end function ' ' Get program duration string (e.g. 1h 20m) function getDurationStringFromSeconds(seconds) as string hours = 0 minutes = seconds / 60.0 if minutes &gt; 60 hours = (minutes - (minutes mod 60)) / 60 minutes = minutes mod 60 end if if hours &gt; 0 return \"%1h %2m\".Replace(\"%1\", StrI(hours).trim()).Replace(\"%2\", StrI(minutes).trim()) else return \"%1m\".Replace(\"%1\", StrI(minutes).trim()) end if end function ' ' Show view channel button when item has Focus sub focusChanged() if m.top.hasFocus = true m.overview.maxLines = m.maxDetailLines m.viewChannelFocusAnimationOpacity.keyValue = [0, 1] m.recordFocusAnimationOpacity.keyValue = [0, 1] m.recordSeriesFocusAnimationOpacity.keyValue = [0, 1] m.viewChannelButton.setFocus(true) m.viewChannelOutline.visible = true m.recordOutline.visible = false m.recordSeriesOutline.visible = false m.viewChannelButtonBackground.blendColor = \"#006fab\" m.recordButtonBackground.blendColor = \"#000000\" m.recordSeriesButtonBackground.blendColor = \"#000000\" else m.top.watchSelectedChannel = false m.top.recordSelectedChannel = false m.top.recordSeriesSelectedChannel = false m.viewChannelFocusAnimationOpacity.keyValue = [1, 0] m.recordFocusAnimationOpacity.keyValue = [1, 0] m.recordSeriesFocusAnimationOpacity.keyValue = [1, 0] end if m.focusAnimation.control = \"start\" end sub sub onAnimationComplete() if m.focusAnimation.state = \"stopped\" and m.top.hasFocus = false m.overview.maxLines = m.maxPreviewLines end if end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false if key = \"OK\" and m.viewChannelButton.hasFocus() m.top.watchSelectedChannel = true return true else if key = \"OK\" and m.recordButton.hasFocus() m.top.recordSelectedChannel = true return true else if key = \"OK\" and m.recordSeriesButton.hasFocus() m.top.recordSeriesSelectedChannel = true return true end if if m.userCanRecord = \"true\" if key = \"right\" and m.viewChannelButton.hasFocus() m.recordButton.setFocus(true) m.viewChannelOutline.visible = false m.recordOutline.visible = true m.viewChannelButtonBackground.blendColor = \"#000000\" m.recordButtonBackground.blendColor = \"#006fab\" m.recordSeriesButtonBackground.blendColor = \"#000000\" return true else if key = \"right\" and m.recordButton.hasFocus() m.recordSeriesButton.setFocus(true) m.recordOutline.visible = false m.recordSeriesOutline.visible = true m.viewChannelButtonBackground.blendColor = \"#000000\" m.recordButtonBackground.blendColor = \"#000000\" m.recordSeriesButtonBackground.blendColor = \"#006fab\" return true else if key = \"left\" and m.recordSeriesButton.hasFocus() m.recordButton.setFocus(true) m.recordOutline.visible = true m.recordSeriesOutline.visible = false m.viewChannelButtonBackground.blendColor = \"#000000\" m.recordButtonBackground.blendColor = \"#006fab\" m.recordSeriesButtonBackground.blendColor = \"#000000\" return true else if key = \"left\" and m.recordButton.hasFocus() m.viewChannelButton.setFocus(true) m.viewChannelOutline.visible = true m.recordOutline.visible = false m.viewChannelButtonBackground.blendColor = \"#006fab\" m.recordButtonBackground.blendColor = \"#000000\" m.recordSeriesButtonBackground.blendColor = \"#000000\" return true end if end if if key = \"up\" or key = \"down\" return true end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_PublicUserData.brs.html":{"id":"components_data_PublicUserData.brs.html","title":"Source: components/data/PublicUserData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/PublicUserData.brs sub init() end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_manager_QueueManager.brs.html":{"id":"components_manager_QueueManager.brs.html","title":"Source: components/manager/QueueManager.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/manager/QueueManager.brs import \"pkg:/source/utils/misc.brs\" import \"ViewCreator.brs\" import \"pkg:/source/api/Items.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" import \"pkg:/source/api/Image.brs\" import \"pkg:/source/utils/deviceCapabilities.brs\" sub init() m.hold = [] m.queue = [] m.originalQueue = [] m.queueTypes = [] m.isPlaying = false ' Preroll videos only play if user has cinema mode setting enabled m.isPrerollActive = m.global.session.user.settings[\"playback.cinemamode\"] m.position = 0 m.shuffleEnabled = false end sub ' Clear all content from play queue sub clear() m.isPlaying = false m.queue = [] m.queueTypes = [] m.isPrerollActive = m.global.session.user.settings[\"playback.cinemamode\"] setPosition(0) end sub ' Clear all hold content sub clearHold() m.hold = [] end sub ' Delete item from play queue at passed index sub deleteAtIndex(index) m.queue.Delete(index) m.queueTypes.Delete(index) end sub ' Return the number of items in the play queue function getCount() return m.queue.count() end function ' Return the item currently in focus from the play queue function getCurrentItem() return getItemByIndex(m.position) end function ' Return the items in the hold function getHold() return m.hold end function ' Return whether or not shuffle is enabled function getIsShuffled() return m.shuffleEnabled end function ' Return the item in the passed index from the play queue function getItemByIndex(index) return m.queue[index] end function ' Returns current playback position within the queue function getPosition() return m.position end function ' Hold an item sub hold(newItem) m.hold.push(newItem) end sub ' Move queue position back one sub moveBack() m.position-- end sub ' Move queue position ahead one sub moveForward() m.position++ end sub ' Return the current play queue function getQueue() return m.queue end function ' Return the types of items in current play queue function getQueueTypes() return m.queueTypes end function ' Return the unique types of items in current play queue function getQueueUniqueTypes() itemTypes = [] for each item in getQueueTypes() if not inArray(itemTypes, item) itemTypes.push(item) end if end for return itemTypes end function ' Return item at end of play queue without removing function peek() return m.queue.peek() end function ' Play items in queue sub playQueue() m.isPlaying = true nextItem = getCurrentItem() if not isValid(nextItem) then return nextItemMediaType = getItemType(nextItem) if nextItemMediaType = \"\" then return if nextItemMediaType = \"audio\" CreateAudioPlayerView() return end if if nextItemMediaType = \"musicvideo\" CreateVideoPlayerView() return end if if nextItemMediaType = \"video\" CreateVideoPlayerView() return end if if nextItemMediaType = \"movie\" CreateVideoPlayerView() return end if if nextItemMediaType = \"episode\" CreateVideoPlayerView() return end if if nextItemMediaType = \"trailer\" CreateVideoPlayerView() return end if end sub ' Remove item at end of play queue sub pop() m.queue.pop() m.queueTypes.pop() end sub ' Return isPrerollActive status function isPrerollActive() as boolean return m.isPrerollActive end function ' Set prerollActive status sub setPrerollStatus(newStatus as boolean) m.isPrerollActive = newStatus end sub ' Push new items to the play queue sub push(newItem) m.queue.push(newItem) m.queueTypes.push(getItemType(newItem)) end sub ' Set the queue position sub setPosition(newPosition) m.position = newPosition end sub ' Reset shuffle to off state sub resetShuffle() m.shuffleEnabled = false end sub ' Toggle shuffleEnabled state sub toggleShuffle() m.shuffleEnabled = not m.shuffleEnabled if m.shuffleEnabled shuffleQueueItems() return end if resetQueueItemOrder() end sub ' Reset queue items back to original, unshuffled order sub resetQueueItemOrder() set(m.originalQueue) end sub ' Return original, unshuffled queue function getUnshuffledQueue() return m.originalQueue end function ' Save a copy of the original queue and randomize order of queue items sub shuffleQueueItems() ' By calling getQueue 2 different ways, Roku avoids needing to do a deep copy m.originalQueue = m.global.queueManager.callFunc(\"getQueue\") itemIDArray = getQueue() temp = invalid if m.isPlaying ' Save the currently playing item temp = getCurrentItem() ' remove currently playing item from itemIDArray itemIDArray.Delete(m.position) end if ' shuffle all items itemIDArray = shuffleArray(itemIDArray) if m.isPlaying ' Put currently playing item in front of itemIDArray itemIDArray.Unshift(temp) end if set(itemIDArray) end sub ' Return the fitst item in the play queue function top() return getItemByIndex(0) end function ' Replace play queue with passed array sub set(items) clear() m.queue = items for each item in items m.queueTypes.push(getItemType(item)) end for end sub ' Set starting point for top item in the queue sub setTopStartingPoint(positionTicks) m.queue[0].startingPoint = positionTicks end sub function getItemType(item) as string if isValid(item) and isValid(item.json) and isValid(item.json.mediatype) and item.json.mediatype &lt;&gt; \"\" return LCase(item.json.mediatype) else if isValid(item) and isValid(item.type) and item.type &lt;&gt; \"\" return LCase(item.type) end if return \"\" end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_quickConnect_QuickConnect.brs.html":{"id":"components_quickConnect_QuickConnect.brs.html","title":"Source: components/quickConnect/QuickConnect.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/quickConnect/QuickConnect.brs import \"pkg:/source/api/userauth.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" sub init() m.top.functionName = \"monitorQuickConnect\" end sub sub monitorQuickConnect() authenticated = checkQuickConnect(m.top.secret) if authenticated = true m.top.authenticated = 1 else m.top.authenticated = -1 end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_quickConnect_QuickConnectDialog.brs.html":{"id":"components_quickConnect_QuickConnectDialog.brs.html","title":"Source: components/quickConnect/QuickConnectDialog.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/quickConnect/QuickConnectDialog.brs import \"pkg:/source/api/userauth.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" import \"pkg:/source/utils/session.bs\" sub init() m.quickConnectTimer = m.top.findNode(\"quickConnectTimer\") m.quickConnectTimer.observeField(\"fire\", \"quickConnectStatus\") m.quickConnectTimer.control = \"start\" m.top.observeFieldScoped(\"buttonSelected\", \"onButtonSelected\") end sub sub quickConnectStatus() m.quickConnectTimer.control = \"stop\" m.checkTask = CreateObject(\"roSGNode\", \"QuickConnect\") m.checkTask.secret = m.top.quickConnectJson.secret m.checkTask.observeField(\"authenticated\", \"OnAuthenticated\") m.checkTask.control = \"run\" end sub sub OnAuthenticated() m.checkTask.unobserveField(\"authenticated\") ' Did we get the A-OK to authenticate? authenticated = m.checkTask.authenticated if authenticated &lt; 0 ' Still waiting, check again in 3 seconds... authenticated = 0 m.checkTask.observeField(\"authenticated\", \"OnAuthenticated\") m.quickConnectTimer.control = \"start\" else if authenticated &gt; 0 ' We've been given the go ahead, try to authenticate via Quick Connect... authenticated = AuthenticateViaQuickConnect(m.top.quickConnectJson.secret) if authenticated &lt;&gt; invalid and authenticated = true currentUser = AboutMe() session.user.Login(currentUser) session.user.LoadUserPreferences() LoadUserAbilities() m.top.close = true m.top.authenticated = true else m.top.close = true m.top.authenticated = false end if end if end sub sub quickConnectClosed() m.quickConnectTimer.control = \"stop\" if m.checkTask &lt;&gt; invalid m.checkTask.unobserveField(\"authenticated\") end if m.top.close = true end sub sub onButtonSelected() ' only one button at the moment... quickConnectClosed() end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false ' Note that \"OK\" does not get sent here, hence onButtonSelected() above. if key = \"back\" quickConnectClosed() return true end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_RadioDialog.brs.html":{"id":"components_RadioDialog.brs.html","title":"Source: components/RadioDialog.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/RadioDialog.brs import \"pkg:/source/utils/misc.brs\" sub init() m.contentArea = m.top.findNode(\"contentArea\") m.radioOptions = m.top.findNode(\"radioOptions\") m.scrollBarColumn = [] m.top.observeField(\"contentData\", \"onContentDataChanged\") m.top.observeFieldScoped(\"buttonSelected\", \"onButtonSelected\") m.radioOptions.observeField(\"focusedChild\", \"onItemFocused\") m.top.id = \"OKDialog\" m.top.height = 900 end sub ' Event handler for when user selected a button sub onButtonSelected() if m.top.buttonSelected = 0 m.global.sceneManager.returnData = m.top.contentData.data[m.radioOptions.selectedIndex] end if end sub ' Event handler for when user's cursor highlights an option in the option list sub onItemFocused() focusedChild = m.radioOptions.focusedChild if not isValid(focusedChild) then return moveScrollBar() ' If the option list is scrollable, move the option list to the user's section if m.scrollBarColumn.count() &lt;&gt; 0 hightedButtonTranslation = m.radioOptions.focusedChild.translation m.radioOptions.translation = [m.radioOptions.translation[0], -1 * hightedButtonTranslation[1]] end if end sub ' Move the popup's scroll bar sub moveScrollBar() ' If we haven't found the scrollbar column node yet, try to find it now if m.scrollBarColumn.count() = 0 scrollBar = findNodeBySubtype(m.contentArea, \"StdDlgScrollbar\") if scrollBar.count() = 0 or not isValid(scrollBar[0]) or not isValid(scrollBar[0].node) return end if m.scrollBarColumn = findNodeBySubtype(scrollBar[0].node, \"Poster\") if m.scrollBarColumn.count() = 0 or not isValid(m.scrollBarColumn[0]) or not isValid(m.scrollBarColumn[0].node) return end if m.scrollBarThumb = findNodeBySubtype(m.scrollBarColumn[0].node, \"Poster\") if m.scrollBarThumb.count() = 0 or not isValid(m.scrollBarThumb[0]) or not isValid(m.scrollBarThumb[0].node) return end if m.scrollBarThumb[0].node.blendColor = \"#444444\" ' If the user presses left then right, it's possible for us to lose focus. Ensure focus stays on the option list. scrollBar[0].node.observeField(\"focusedChild\", \"onScrollBarFocus\") ' Hide the default scrollbar background m.scrollBarColumn[0].node.uri = \"\" ' Create a new scrollbar background so we can move the original nodes freely scrollbarBackground = createObject(\"roSGNode\", \"Rectangle\") scrollbarBackground.color = \"#101010\" scrollbarBackground.opacity = \"0.3\" scrollbarBackground.width = \"30\" scrollbarBackground.height = m.contentArea.clippingRect.height scrollbarBackground.translation = [0, 0] scrollBar[0].node.insertChild(scrollbarBackground, 0) ' Determine the proper scroll amount for the scrollbar m.scrollAmount = (m.contentArea.clippingRect.height - int(m.scrollBarThumb[0].node.height)) / m.radioOptions.getChildCount() m.scrollAmount += m.scrollAmount / m.radioOptions.getChildCount() end if if not isvalid(m.radioOptions.focusedChild.id) then return m.scrollBarColumn[0].node.translation = [0, val(m.radioOptions.focusedChild.id) * m.scrollAmount] end sub ' If somehow the scrollbar gains focus, set focus back to the option list sub onScrollBarFocus() m.radioOptions.setFocus(true) ' Ensure scrollbar styles remain in an unfocused state m.scrollBarThumb[0].node.blendColor = \"#353535\" end sub ' Once user selected an item, move cursor down to OK button sub onItemSelected() buttonArea = findNodeBySubtype(m.top, \"StdDlgButtonArea\") if buttonArea.count() &lt;&gt; 0 and isValid(buttonArea[0]) and isValid(buttonArea[0].node) buttonArea[0].node.setFocus(true) end if end sub sub onContentDataChanged() i = 0 for each item in m.top.contentData.data cardItem = m.radioOptions.CreateChild(\"StdDlgActionCardItem\") cardItem.iconType = \"radiobutton\" cardItem.id = i if isValid(item.selected) m.radioOptions.selectedIndex = i end if textLine = cardItem.CreateChild(\"SimpleLabel\") textLine.text = item.track.description cardItem.observeField(\"selected\", \"onItemSelected\") i++ end for end sub function onKeyEvent(key as string, press as boolean) as boolean if key = \"right\" ' By default RIGHT from the option list selects the OK button ' Instead, keep the user on the option list return true end if if not press then return false if key = \"up\" ' By default UP from the OK button is the scrollbar ' Instead, move the user to the option list if not m.radioOptions.isinFocusChain() m.radioOptions.setFocus(true) return true end if end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_liveTv_RecordProgramTask.brs.html":{"id":"components_liveTv_RecordProgramTask.brs.html","title":"Source: components/liveTv/RecordProgramTask.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/liveTv/RecordProgramTask.brs import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" import \"pkg:/source/roku_modules/log/LogMixin.brs\" sub init() m.log = log.Logger(\"RecordProgramTask\") m.top.functionName = \"RecordOrCancelProgram\" end sub sub RecordOrCancelProgram() if m.top.programDetails &lt;&gt; invalid ' Are we setting up a recording or canceling one? TimerId = invalid if m.top.programDetails.json.TimerId &lt;&gt; invalid and m.top.programDetails.json.TimerId &lt;&gt; \"\" TimerId = m.top.programDetails.json.TimerId end if if TimerId = invalid ' Setting up a recording... programId = m.top.programDetails.Id ' Get Live TV default params from server... url = \"LiveTv/Timers/Defaults\" params = { programId: programId } resp = APIRequest(url, params) data = getJson(resp) if data &lt;&gt; invalid ' Create recording timer... if m.top.recordSeries = true url = \"LiveTv/SeriesTimers\" else url = \"LiveTv/Timers\" end if resp = APIRequest(url) postJson(resp, FormatJson(data)) m.top.programDetails.hdSmallIconUrl = \"pkg:/images/red.png\" else ' Error msg to user? m.log.error(\"Could not retrieve live TV Defaults from Server\") end if else ' Cancelling a recording... if m.top.recordSeries = true TimerId = m.top.programDetails.json.SeriesTimerId url = Substitute(\"LiveTv/SeriesTimers/{0}\", TimerId) else url = Substitute(\"LiveTv/Timers/{0}\", TimerId) end if resp = APIRequest(url) deleteVoid(resp) m.top.programDetails.hdSmallIconUrl = invalid end if end if m.top.recordOperationDone = true end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_SceneManager.brs.html":{"id":"components_data_SceneManager.brs.html","title":"Source: components/data/SceneManager.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/SceneManager.brs import \"pkg:/source/roku_modules/log/LogMixin.brs\" sub init() m.log = log.Logger(\"SceneManager\") m.groups = [] m.scene = m.top.getScene() m.content = m.scene.findNode(\"content\") m.overhang = m.scene.findNode(\"overhang\") end sub ' ' Push a new group onto the stack, replacing the existing group on the screen sub pushScene(newGroup) currentGroup = m.groups.peek() if newGroup &lt;&gt; invalid if currentGroup &lt;&gt; invalid 'Search through group and store off last focused item if currentGroup.focusedChild &lt;&gt; invalid focused = currentGroup.focusedChild while focused.hasFocus() = false focused = focused.focusedChild end while currentGroup.lastFocus = focused currentGroup.setFocus(false) else currentGroup.setFocus(false) end if if currentGroup.isSubType(\"JFGroup\") unregisterOverhangData(currentGroup) end if currentGroup.visible = false if currentGroup.isSubType(\"JFScreen\") currentGroup.callFunc(\"OnScreenHidden\") end if end if m.groups.push(newGroup) if currentGroup &lt;&gt; invalid m.content.replaceChild(newGroup, 0) else m.content.appendChild(newGroup) end if if newGroup.isSubType(\"JFScreen\") newGroup.callFunc(\"OnScreenShown\") end if 'observe info about new group, set overhang title, etc. if newGroup.isSubType(\"JFGroup\") registerOverhangData(newGroup) ' Some groups set focus to a specific component within init(), so we don't want to ' change if that is the case. if newGroup.isInFocusChain() = false newGroup.setFocus(true) end if else if newGroup.isSubType(\"JFVideo\") newGroup.setFocus(true) newGroup.control = \"play\" m.overhang.visible = false end if else currentGroup.focusedChild.setFocus(true) end if end sub ' ' Remove the current group and load the last group from the stack sub popScene() group = m.groups.pop() if group &lt;&gt; invalid if group.isSubType(\"JFGroup\") unregisterOverhangData(group) else if group.isSubType(\"JFVideo\") ' Stop video to make sure app communicates stop playstate to server group.control = \"stop\" end if group.visible = false if group.isSubType(\"JFScreen\") group.callFunc(\"OnScreenHidden\") end if else ' Exit app if for some reason we don't have anything on the stack m.scene.exit = true end if group = m.groups.peek() if group &lt;&gt; invalid registerOverhangData(group) if group.subtype() = \"Home\" currentTime = CreateObject(\"roDateTime\").AsSeconds() if group.timeLastRefresh = invalid or (currentTime - group.timeLastRefresh) &gt; 20 group.timeLastRefresh = currentTime group.callFunc(\"refresh\") end if end if group.visible = true m.content.replaceChild(group, 0) if group.isSubType(\"JFScreen\") group.callFunc(\"OnScreenShown\") else ' Restore focus if group.lastFocus &lt;&gt; invalid group.lastFocus.setFocus(true) else if group.focusedChild &lt;&gt; invalid group.focusedChild.setFocus(true) else group.setFocus(true) end if end if end if else ' Exit app if the stack is empty after removing group m.scene.exit = true end if end sub ' ' Return group at top of stack without removing function getActiveScene() as object return m.groups.peek() end function ' ' Clear all content from group stack sub clearScenes() if m.content &lt;&gt; invalid then m.content.removeChildrenIndex(m.content.getChildCount(), 0) m.groups = [] end sub ' ' Clear previous scene from group stack sub clearPreviousScene() m.groups.pop() end sub ' ' Delete scene from group stack at passed index sub deleteSceneAtIndex(index = 1) m.groups.Delete(index) end sub ' ' Display user/device settings screen sub settings() settingsScreen = createObject(\"roSGNode\", \"Settings\") pushScene(settingsScreen) end sub ' ' Register observers for overhang data sub registerOverhangData(group) if group.isSubType(\"JFGroup\") if group.overhangTitle &lt;&gt; invalid then m.overhang.title = group.overhangTitle if group.optionsAvailable m.overhang.showOptions = true else m.overhang.showOptions = false end if group.observeField(\"optionsAvailable\", \"updateOptions\") group.observeField(\"overhangTitle\", \"updateOverhangTitle\") if group.overhangVisible m.overhang.visible = true else m.overhang.visible = false end if group.observeField(\"overhangVisible\", \"updateOverhangVisible\") else if group.isSubType(\"JFVideo\") m.overhang.visible = false else m.log.error(\"registerOverhangData(): Unexpected group type.\", group, group.subtype()) end if end sub ' ' Remove observers for overhang data sub unregisterOverhangData(group) group.unobserveField(\"overhangTitle\") end sub ' ' Update overhang title sub updateOverhangTitle(msg) m.overhang.title = msg.getData() end sub ' ' Update options availability sub updateOptions(msg) m.overhang.showOptions = msg.getData() end sub ' ' Update whether the overhang is visible or not sub updateOverhangVisible(msg) m.overhang.visible = msg.getData() end sub ' ' Update username in overhang sub updateUser() ' Passthrough to overhang if m.overhang &lt;&gt; invalid then m.overhang.currentUser = m.top.currentUser end sub ' ' Reset time sub resetTime() ' Passthrough to overhang m.overhang.callFunc(\"resetTime\") end sub ' ' Display dialog to user with an OK button sub userMessage(title as string, message as string) dialog = createObject(\"roSGNode\", \"StandardMessageDialog\") dialog.title = title dialog.message = message dialog.buttons = [tr(\"OK\")] dialog.observeField(\"buttonSelected\", \"dismissDialog\") m.scene.dialog = dialog end sub ' ' Display dialog to user with an OK button sub standardDialog(title, message) dialog = createObject(\"roSGNode\", \"StandardDialog\") dlgPalette = createObject(\"roSGNode\", \"RSGPalette\") dlgPalette.colors = { DialogBackgroundColor: \"0x262828FF\", DialogFocusColor: \"0xcececeFF\", DialogFocusItemColor: \"0x202020FF\", DialogSecondaryTextColor: \"0xf8f8f8ff\", DialogSecondaryItemColor: \"#00a4dcFF\", DialogTextColor: \"0xeeeeeeFF\" } dialog.palette = dlgPalette dialog.observeField(\"buttonSelected\", \"dismissDialog\") dialog.title = title dialog.contentData = message dialog.buttons = [tr(\"OK\")] m.scene.dialog = dialog end sub ' ' Display dialog to user with an OK button sub radioDialog(title, message) dialog = createObject(\"roSGNode\", \"RadioDialog\") dlgPalette = createObject(\"roSGNode\", \"RSGPalette\") dlgPalette.colors = { DialogBackgroundColor: \"0x262828FF\", DialogFocusColor: \"0xcececeFF\", DialogFocusItemColor: \"0x202020FF\", DialogSecondaryTextColor: \"0xf8f8f8ff\", DialogSecondaryItemColor: \"#00a4dcFF\", DialogTextColor: \"0xeeeeeeFF\" } dialog.palette = dlgPalette dialog.observeField(\"buttonSelected\", \"dismissDialog\") dialog.title = title dialog.contentData = message dialog.buttons = [tr(\"OK\")] m.scene.dialog = dialog end sub ' ' Display dialog to user with an OK button sub optionDialog(title, message, buttons) m.top.dataReturned = false m.top.returnData = invalid m.userselection = false dialog = createObject(\"roSGNode\", \"StandardMessageDialog\") dlgPalette = createObject(\"roSGNode\", \"RSGPalette\") dlgPalette.colors = { DialogBackgroundColor: \"0x262828FF\", DialogFocusColor: \"0xcececeFF\", DialogFocusItemColor: \"0x202020FF\", DialogSecondaryTextColor: \"0xf8f8f8ff\", DialogSecondaryItemColor: \"#00a4dcFF\", DialogTextColor: \"0xeeeeeeFF\" } dialog.palette = dlgPalette dialog.observeField(\"buttonSelected\", \"optionSelected\") dialog.observeField(\"wasClosed\", \"optionClosed\") dialog.title = title dialog.message = message dialog.buttons = buttons m.scene.dialog = dialog end sub ' ' Return button the user selected sub optionClosed() if m.userselection then return m.top.returnData = { indexSelected: -1, buttonSelected: \"\" } m.top.dataReturned = true end sub ' ' Return button the user selected sub optionSelected() m.userselection = true m.top.returnData = { indexSelected: m.scene.dialog.buttonSelected, buttonSelected: m.scene.dialog.buttons[m.scene.dialog.buttonSelected] } m.top.dataReturned = true dismissDialog() end sub ' ' Close currently displayed dialog sub dismissDialog() m.scene.dialog.close = true end sub ' ' Returns bool indicating if dialog is currently displayed function isDialogOpen() as boolean return m.scene.dialog &lt;&gt; invalid end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_ScheduleProgramData.brs.html":{"id":"components_data_ScheduleProgramData.brs.html","title":"Source: components/data/ScheduleProgramData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/ScheduleProgramData.brs import \"pkg:/source/api/Image.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" sub setFields() json = m.top.json startDate = createObject(\"roDateTime\") endDate = createObject(\"roDateTime\") startDate.FromISO8601String(json.StartDate) endDate.FromISO8601String(json.EndDate) m.top.Title = json.Name m.top.PlayStart = startDate.AsSeconds() m.top.PlayDuration = endDate.AsSeconds() - m.top.PlayStart m.top.Id = json.Id m.top.Description = json.overview m.top.EpisodeTitle = json.EpisodeTitle m.top.isLive = json.isLive m.top.isRepeat = json.isRepeat m.top.startDate = json.startDate m.top.endDate = json.endDate m.top.channelId = json.channelId if json.IsSeries &lt;&gt; invalid and json.IsSeries = true if json.IndexNumber &lt;&gt; invalid m.top.episodeNumber = json.IndexNumber end if if json.ParentIndexNumber &lt;&gt; invalid m.top.seasonNumber = json.ParentIndexNumber end if end if setPoster() end sub sub setPoster() if m.top.image &lt;&gt; invalid m.top.posterURL = m.top.image.url else if m.top.json.ImageTags &lt;&gt; invalid and m.top.json.ImageTags.Thumb &lt;&gt; invalid imgParams = { \"maxHeight\": 500, \"maxWidth\": 500, \"Tag\": m.top.json.ImageTags.Thumb } m.top.posterURL = ImageURL(m.top.json.id, \"Thumb\", imgParams) end if end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_SearchBox.brs.html":{"id":"components_SearchBox.brs.html","title":"Source: components/SearchBox.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/SearchBox.brs import \"pkg:/source/api/Items.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" import \"pkg:/source/api/Image.brs\" import \"pkg:/source/utils/deviceCapabilities.brs\" sub init() m.top.layoutDirection = \"vert\" m.top.horizAlignment = \"center\" m.top.vertAlignment = \"top\" m.top.visible = false m.searchText = m.top.findNode(\"search_Key\") m.searchText.textEditBox.hintText = tr(\"Search\") m.searchText.keyGrid.keyDefinitionUri = \"pkg:/components/data/CustomAddressKDF.json\" m.searchText.textEditBox.voiceEnabled = true m.searchText.textEditBox.active = true m.searchText.ObserveField(\"text\", \"searchMedias\") m.searchSelect = m.top.findNode(\"searchSelect\") 'set lable text m.label = m.top.findNode(\"text\") m.label.text = tr(\"Search now\") end sub sub searchMedias() m.top.search_values = m.searchText.text if m.top.search_values.len() &gt; 1 m.searchText.textEditBox.leadingEllipsis = true else m.searchText.textEditBox.leadingEllipsis = false end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_SearchData.brs.html":{"id":"components_data_SearchData.brs.html","title":"Source: components/data/SearchData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/SearchData.brs sub setFields() datum = m.top.json m.top.id = datum.id m.top.title = datum.name m.top.type = datum.Type end sub sub setPoster() if m.top.image &lt;&gt; invalid m.top.posterURL = m.top.image.url else m.top.posterURL = \"\" end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_search_SearchResults.brs.html":{"id":"components_search_SearchResults.brs.html","title":"Source: components/search/SearchResults.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/search/SearchResults.brs import \"pkg:/source/api/Items.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" import \"pkg:/source/api/Image.brs\" import \"pkg:/source/utils/deviceCapabilities.brs\" sub init() m.top.optionsAvailable = false m.searchSpinner = m.top.findnode(\"searchSpinner\") m.searchSelect = m.top.findnode(\"searchSelect\") m.searchTask = CreateObject(\"roSGNode\", \"SearchTask\") 'set label text m.searchHelpText = m.top.findNode(\"SearchHelpText\") m.searchHelpText.text = tr(\"You can search for Titles, People, Live TV Channels and more\") end sub sub searchMedias() query = m.top.searchAlpha 'if user deletes the search string hide the spinner if query.len() = 0 m.searchSpinner.visible = false end if 'if search task is running and user selectes another letter stop the search and load the next letter m.searchTask.control = \"stop\" if query &lt;&gt; invalid and query &lt;&gt; \"\" m.searchSpinner.visible = true end if m.searchTask.observeField(\"results\", \"loadResults\") m.searchTask.query = query m.top.overhangTitle = tr(\"Search\") + \": \" + query m.searchTask.control = \"RUN\" end sub sub loadResults() m.searchTask.unobserveField(\"results\") m.searchSpinner.visible = false m.searchSelect.itemdata = m.searchTask.results m.searchSelect.query = m.top.SearchAlpha m.searchHelpText.visible = false m.searchAlphabox = m.top.findnode(\"searchResults\") m.searchAlphabox.translation = \"[470, 85]\" end sub function onKeyEvent(key as string, press as boolean) as boolean m.searchAlphabox = m.top.findNode(\"search_Key\") if m.searchAlphabox.textEditBox.hasFocus() m.searchAlphabox.textEditBox.translation = \"[0, -150]\" else m.searchAlphabox.textEditBox.translation = \"[0, 0]\" end if if key = \"left\" and m.searchSelect.isinFocusChain() m.searchAlphabox.setFocus(true) return true else if key = \"right\" m.searchSelect.setFocus(true) return true end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_search_SearchRow.brs.html":{"id":"components_search_SearchRow.brs.html","title":"Source: components/search/SearchRow.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/search/SearchRow.brs import \"pkg:/source/api/Items.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" import \"pkg:/source/api/Image.brs\" import \"pkg:/source/utils/deviceCapabilities.brs\" sub init() m.top.itemComponentName = \"ListPoster\" m.top.content = getData() updateSize() m.top.showRowLabel = [true] m.top.rowLabelOffset = [0, 20] m.top.showRowCounter = [true] ' TODO - Define a failed to load image background ' m.top.failedBitmapURI end sub sub updateSize() ' In search results, rowSize only dictates how many are on screen at once m.top.rowSize = 3 dimensions = m.top.getScene().currentDesignResolution border = 50 m.top.translation = [border, border + 115] textHeight = 80 itemWidth = (dimensions[\"width\"] - border) / 6 itemHeight = itemWidth + (textHeight / 2.3) m.top.itemSize = [1350, itemHeight] ' this is used for setting the row size m.top.itemSpacing = [0, 105] m.top.rowItemSize = [itemWidth, itemHeight] m.top.rowItemSpacing = [0, 0] m.top.numRows = 2 m.top.translation = \"[12,18]\" end sub function getData() if m.top.itemData = invalid data = CreateObject(\"roSGNode\", \"ContentNode\") return data end if itemData = m.top.itemData ' todo - Or get the old data? I can't remember... data = CreateObject(\"roSGNode\", \"ContentNode\") ' Do this to keep the ordering, AssociateArrays have no order type_array = [\"Movie\", \"Series\", \"TvChannel\", \"Episode\", \"MusicArtist\", \"MusicAlbum\", \"Audio\", \"Person\", \"PlaylistsFolder\"] content_types = { \"TvChannel\": { \"label\": \"Channels\", \"count\": 0 }, \"Movie\": { \"label\": \"Movies\", \"count\": 0 }, \"Series\": { \"label\": \"Shows\", \"count\": 0 }, \"Episode\": { \"label\": \"Episodes\", \"count\": 0 }, \"MusicArtist\": { \"label\": \"Artists\", \"count\": 0 }, \"MusicAlbum\": { \"label\": \"Albums\", \"count\": 0 }, \"Audio\": { \"label\": \"Songs\", \"count\": 0 }, \"Person\": { \"label\": \"People\", \"count\": 0 }, \"PlaylistsFolder\": { \"label\": \"Playlist\", \"count\": 0 } } for each item in itemData.Items if content_types[item.type] &lt;&gt; invalid content_types[item.type].count += 1 end if end for for each ctype in type_array content_type = content_types[ctype] if content_type.count &gt; 0 addRow(data, content_type.label, ctype) end if end for m.top.content = data return data end function sub addRow(data, title, type_filter) itemData = m.top.itemData row = data.CreateChild(\"ContentNode\") row.title = title for each item in itemData.Items if item.type = type_filter row.appendChild(item) end if end for end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_search_SearchTask.brs.html":{"id":"components_search_SearchTask.brs.html","title":"Source: components/search/SearchTask.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/search/SearchTask.brs import \"pkg:/source/api/Items.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" import \"pkg:/source/api/Image.brs\" import \"pkg:/source/utils/deviceCapabilities.brs\" sub init() m.top.functionName = \"search\" end sub sub search() if m.top.query &lt;&gt; invalid and m.top.query &lt;&gt; \"\" m.top.results = searchMedia(m.top.query) end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_SeriesData.brs.html":{"id":"components_data_SeriesData.brs.html","title":"Source: components/data/SeriesData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/SeriesData.brs import \"pkg:/source/api/Image.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" sub setFields() json = m.top.json m.top.id = json.id m.top.Title = json.name m.top.Description = json.overview m.top.favorite = json.UserData.isFavorite m.top.watched = json.UserData.played m.top.Type = \"Series\" m.top.overview = json.overview if json.ProductionYear &lt;&gt; invalid m.top.SubTitle = json.ProductionYear end if if json.OfficialRating &lt;&gt; invalid and json.OfficialRating &lt;&gt; \"\" m.top.Rating = json.OfficialRating if m.top.SubTitle &lt;&gt; \"\" m.top.SubTitle = m.top.SubTitle + \" - \" + m.top.Rating else m.top.SubTitle = m.top.Rating end if end if setPoster() end sub sub setPoster() if m.top.image &lt;&gt; invalid m.top.posterURL = m.top.image.url else if m.top.json.ImageTags.Primary &lt;&gt; invalid imgParams = { \"maxHeight\": 440, \"maxWidth\": 295, \"Tag\": m.top.json.ImageTags.Primary } m.top.posterURL = ImageURL(m.top.json.id, \"Primary\", imgParams) else if m.top.json.BackdropImageTags &lt;&gt; invalid imgParams = { \"maxHeight\": 440, \"Tag\": m.top.json.BackdropImageTags[0] } m.top.posterURL = ImageURL(m.top.json.id, \"Backdrop\", imgParams) end if ' Add Backdrop Image if m.top.json.BackdropImageTags &lt;&gt; invalid imgParams = { \"maxHeight\": 720, \"maxWidth\": 1280, \"Tag\": m.top.json.BackdropImageTags[0] } m.top.backdropURL = ImageURL(m.top.json.id, \"Backdrop\", imgParams) end if end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_config_ServerDiscoveryTask.brs.html":{"id":"components_config_ServerDiscoveryTask.brs.html","title":"Source: components/config/ServerDiscoveryTask.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/config/ServerDiscoveryTask.brs import \"pkg:/source/roku_modules/log/LogMixin.brs\" ' ' Task used to discover jellyfin servers on the local network ' sub init() m.log = log.Logger(\"ServerDiscoveryTask\") m.top.functionName = \"execute\" end sub sub execute() m.servers = [] m.serverUrlMap = {} m.locationUrlMap = {} 'send both requests at the same time SendSSDPBroadcast() SendClientDiscoveryBroadcast() ts = CreateObject(\"roTimespan\") maxTimeMs = 2200 'monitor each port and collect messages while True elapsed = ts.TotalMilliseconds() if elapsed &gt;= maxTimeMs exit while end if msg = Wait(100, m.ssdp.port) if msg &lt;&gt; invalid ProcessSSDPResponse(msg) end if msg = Wait(100, m.clientDiscovery.port) if msg &lt;&gt; invalid ProcessClientDiscoveryResponse(msg) end if end while m.top.content = m.servers m.log.debug(\"Jellyfin servers found\", m.servers[0], m.servers[1], m.servers[2]) end sub sub AddServer(server) if m.serverUrlMap[server.baseUrl] = invalid m.serverUrlMap[server.baseUrl] = true m.servers.push(server) end if end sub sub SendClientDiscoveryBroadcast() m.clientDiscovery = { port: CreateObject(\"roMessagePort\"), address: CreateObject(\"roSocketAddress\"), socket: CreateObject(\"roDatagramSocket\"), urlTransfer: CreateObject(\"roUrlTransfer\") } m.clientDiscovery.address.SetAddress(\"255.255.255.255:7359\") m.clientDiscovery.urlTransfer.SetPort(m.clientDiscoveryPort) m.clientDiscovery.socket.SetMessagePort(m.clientDiscovery.port) m.clientDiscovery.socket.SetSendToAddress(m.clientDiscovery.address) m.clientDiscovery.socket.NotifyReadable(true) m.clientDiscovery.socket.SetBroadcast(true) m.clientDiscovery.socket.SendStr(\"Who is JellyfinServer?\") end sub sub ProcessClientDiscoveryResponse(message) if Type(message) = \"roSocketEvent\" and message.GetSocketId() = m.clientDiscovery.socket.GetId() and m.clientDiscovery.socket.IsReadable() try responseJson = m.clientDiscovery.socket.ReceiveStr(4096) server = ParseJson(responseJson) AddServer({ name: server.Name, baseUrl: server.Address, 'hardcoded icon since this service doesn't include them iconUrl: \"pkg:/images/logo-icon120.jpg\", iconWidth: 120, iconHeight: 120 }) m.log.info(\"Found Jellyfin server using client discovery\", server.Address) catch e m.log.error(\"Error scanning for jellyfin server\", message) end try end if end sub sub SendSSDPBroadcast() m.ssdp = { port: CreateObject(\"roMessagePort\"), address: CreateObject(\"roSocketAddress\"), socket: CreateObject(\"roDatagramSocket\"), urlTransfer: CreateObject(\"roUrlTransfer\") } m.ssdp.address.SetAddress(\"239.255.255.250:1900\") m.ssdp.socket.SetMessagePort(m.ssdp.port) m.ssdp.socket.SetSendToAddress(m.ssdp.address) m.ssdp.socket.NotifyReadable(true) m.ssdp.urlTransfer.SetPort(m.ssdp.port) 'brightscript can't escape characters in strings, so create a few vars here so we can use them in the strings below Q = Chr(34) CRLF = Chr(13) + Chr(10) ssdpStr = \"M-SEARCH * HTTP/1.1\" + CRLF ssdpStr += \"HOST: 239.255.255.250:1900\" + CRLF ssdpStr += \"MAN: \" + Q + \"ssdp:discover\" + Q + CRLF ssdpStr += \"ST:urn:schemas-upnp-org:device:MediaServer:1\" + CRLF ssdpStr += \"MX: 2\" + CRLF ssdpStr += CRLF m.ssdp.socket.SendStr(ssdpStr) end sub sub ProcessSSDPResponse(message) locationUrl = invalid if Type (message) = \"roSocketEvent\" and message.GetSocketId() = m.ssdp.socket.GetId() and m.ssdp.socket.IsReadable() recvStr = m.ssdp.socket.ReceiveStr(4096) match = CreateObject(\"roRegex\", \"\\r\\nLocation:\\s*(.*?)\\s*\\r\\n\", \"i\").Match(recvStr) if match.Count() = 2 locationUrl = match[1] end if end if if locationUrl = invalid return else if m.locationUrlMap[locationUrl] &lt;&gt; invalid m.log.warn(\"Already discovered this location\", locationUrl) return end if m.locationUrlMap[locationUrl] = true http = CreateObject(\"roUrlTransfer\") http.SetUrl(locationUrl) responseText = http.GetToString() xml = CreateObject(\"roXMLElement\") 'if we successfully parsed the response, process it if xml.Parse(responseText) deviceNode = xml.GetNamedElementsCi(\"device\")[0] manufacturer = deviceNode.GetNamedElementsCi(\"manufacturer\").GetText() 'only process jellyfin servers if lcase(manufacturer) = \"jellyfin\" 'find the largest icon width = 0 server = invalid icons = deviceNode.GetNamedElementsCi(\"iconList\")[0].GetNamedElementsCi(\"icon\") for each iconNode in icons iconUrl = iconNode.GetNamedElementsCi(\"url\").GetText() baseUrl = invalid match = CreateObject(\"roRegex\", \"(.*?)\\/dlna\\/\", \"i\").Match(iconUrl) if match.Count() = 2 baseUrl = match[1] end if loopResult = { name: deviceNode.GetNamedElementsCi(\"friendlyName\").GetText(), baseUrl: baseUrl, iconUrl: iconUrl, iconWidth: iconNode.GetNamedElementsCi(\"width\")[0].GetText().ToInt(), iconHeight: iconNode.GetNamedElementsCi(\"height\")[0].GetText().ToInt() } if baseUrl &lt;&gt; invalid and loopResult.iconWidth &gt; width width = loopResult.iconWidth server = loopResult end if end for AddServer(server) m.log.info(\"Found jellyfin server using SSDP and DLNA\", server.baseUrl) end if end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_config_SetServerScreen.brs.html":{"id":"components_config_SetServerScreen.brs.html","title":"Source: components/config/SetServerScreen.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/config/SetServerScreen.brs import \"pkg:/source/roku_modules/log/LogMixin.brs\" import \"pkg:/source/utils/config.brs\" sub init() m.log = log.Logger(\"SetServerScreen\") m.top.setFocus(true) m.spinner = m.top.findNode(\"spinner\") m.serverPicker = m.top.findNode(\"serverPicker\") m.serverUrlTextbox = m.top.findNode(\"serverUrlTextbox\") m.serverUrlContainer = m.top.findNode(\"serverUrlContainer\") m.serverUrlOutline = m.top.findNode(\"serverUrlOutline\") m.submit = m.top.findNode(\"submit\") m.top.observeField(\"serverUrl\", \"clearErrorMessage\") ScanForServers() end sub function onKeyEvent(key as string, press as boolean) as boolean m.log.debug(\"SetServerScreen onKeyEvent\", key, press) if not press then return true handled = true if key = \"OK\" and m.serverPicker.hasFocus() m.top.serverUrl = m.serverPicker.content.getChild(m.serverPicker.itemFocused).baseUrl m.submit.setFocus(true) 'if the user pressed the down key and we are already at the last child of server picker, then change focus to the url textbox else if key = \"down\" and m.serverPicker.hasFocus() and m.serverPicker.content.getChildCount() &gt; 0 and m.serverPicker.itemFocused = m.serverPicker.content.getChildCount() - 1 m.serverUrlContainer.setFocus(true) 'user navigating up to the server picker from the input box (it's only focusable if it has items) else if key = \"up\" and m.serverUrlContainer.hasFocus() and m.servers.Count() &gt; 0 m.serverPicker.setFocus(true) else if key = \"up\" and m.serverUrlContainer.hasFocus() and m.servers.Count() = 0 ScanForServers() else if key = \"back\" and m.serverUrlContainer.hasFocus() and m.servers.Count() &gt; 0 m.serverPicker.setFocus(true) else if key = \"OK\" and m.serverUrlContainer.hasFocus() ShowKeyboard() else if key = \"back\" and m.submit.hasFocus() and m.servers.Count() &gt; 0 m.serverPicker.setFocus(true) else if key = \"back\" and m.submit.hasFocus() and m.servers.Count() = 0 m.serverUrlContainer.setFocus(true) else if key = \"back\" and m.serverUrlContainer.hasFocus() and m.servers.Count() = 0 ScanForServers() else if key = \"back\" and m.serverPicker.hasFocus() and m.servers.Count() &gt; 0 ScanForServers() ' On \"back\" with or without available local servers, will rescan for servers else if key = \"up\" and m.submit.hasFocus() m.serverUrlContainer.setFocus(true) 'focus the submit button from serverUrl else if key = \"down\" and m.serverUrlContainer.hasFocus() m.submit.setFocus(true) else if key = \"options\" if m.serverPicker.itemFocused &gt;= 0 and m.serverPicker.itemFocused &lt; m.serverPicker.content.getChildCount() serverName = m.serverPicker.content.getChild(m.serverPicker.itemFocused).name if m.servers.Count() &gt; 0 and Instr(1, serverName, \"Saved\") &gt; 0 'Can only delete previously saved servers, not locally discovered ones 'So if we are on a \"Saved\" item, let the options dialog be shown (handled elsewhere) handled = false end if end if else handled = false end if 'show/hide input box outline m.serverUrlOutline.visible = m.serverUrlContainer.isInFocusChain() return handled end function sub ScanForServers() m.ssdpScanner = CreateObject(\"roSGNode\", \"ServerDiscoveryTask\") 'run the task m.ssdpScanner.observeField(\"content\", \"ScanForServersComplete\") m.ssdpScanner.control = \"RUN\" m.spinner.visible = true end sub sub ScanForServersComplete(event) m.servers = event.getData() items = CreateObject(\"roSGNode\", \"ContentNode\") for each server in m.servers server.subtype = \"ContentNode\" 'add new fields for every server property onto the ContentNode (rather than making a dedicated component just to hold data...) items.update([server], true) end for 'load any previously logged in to servers as well (if they aren't already discovered on the local network) saved = get_setting(\"saved_servers\") if saved &lt;&gt; invalid savedServers = ParseJson(saved) for each server in savedServers.serverList alreadyListed = false for each listed in m.servers if LCase(listed.baseUrl) = server.baseUrl 'saved server data is always lowercase alreadyListed = true exit for end if end for if alreadyListed = false items.update([server], true) m.servers.push(server) end if end for end if m.serverPicker.content = items m.spinner.visible = false 'if we have at least one server, focus on the server picker if m.servers.Count() &gt; 0 m.serverPicker.setFocus(true) 'no servers found...focus on the input textbox else m.serverUrlContainer.setFocus(true) 'show/hide input box outline m.serverUrlOutline.visible = true end if end sub sub ShowKeyboard() dialog = createObject(\"roSGNode\", \"StandardKeyboardDialog\") dialog.title = tr(\"Enter the server name or ip address\") dialog.buttons = [tr(\"OK\"), tr(\"Cancel\")] dialog.text = m.serverUrlTextbox.text greenPalette = createObject(\"roSGNode\", \"RSGPalette\") greenPalette.colors = { DialogBackgroundColor: \"#2A2B2A\" } dialog.palette = greenPalette m.top.getscene().dialog = dialog m.dialog = dialog dialog.observeField(\"buttonSelected\", \"onDialogButton\") end sub function onDialogButton() d = m.dialog button_text = d.buttons[d.buttonSelected] if button_text = tr(\"OK\") m.serverUrlTextbox.text = d.text m.dialog.close = true return true else if button_text = tr(\"Cancel\") m.dialog.close = true return true else return false end if end function sub clearErrorMessage() m.top.errorMessage = \"\" end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"source_ShowScenes.brs.html":{"id":"source_ShowScenes.brs.html","title":"Source: source/ShowScenes.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: source/ShowScenes.brs function LoginFlow() 'Collect Jellyfin server and user information start_login: serverUrl = get_setting(\"server\") if isValid(serverUrl) print \"Previous server connection saved to registry\" startOver = not session.server.UpdateURL(serverUrl) if startOver print \"Could not connect to previously saved server.\" end if else startOver = true print \"No previous server connection saved to registry\" end if invalidServer = true if not startOver ' Show Connecting to Server spinner dialog = createObject(\"roSGNode\", \"ProgressDialog\") dialog.title = tr(\"Connecting to Server\") m.scene.dialog = dialog invalidServer = ServerInfo().Error dialog.close = true end if m.serverSelection = \"Saved\" if startOver or invalidServer print \"Get server details\" SendPerformanceBeacon(\"AppDialogInitiate\") ' Roku Performance monitoring - Dialog Starting m.serverSelection = CreateServerGroup() SendPerformanceBeacon(\"AppDialogComplete\") ' Roku Performance monitoring - Dialog Closed if m.serverSelection = \"backPressed\" print \"backPressed\" m.global.sceneManager.callFunc(\"clearScenes\") return false end if SaveServerList() end if activeUser = get_setting(\"active_user\") if activeUser = invalid print \"No active user found in registry\" user_select: SendPerformanceBeacon(\"AppDialogInitiate\") ' Roku Performance monitoring - Dialog Starting publicUsers = GetPublicUsers() savedUsers = getSavedUsers() numPubUsers = publicUsers.count() numSavedUsers = savedUsers.count() if numPubUsers &gt; 0 or numSavedUsers &gt; 0 publicUsersNodes = [] publicUserIds = [] ' load public users if numPubUsers &gt; 0 for each item in publicUsers user = CreateObject(\"roSGNode\", \"PublicUserData\") user.id = item.Id user.name = item.Name if isValid(item.PrimaryImageTag) user.ImageURL = UserImageURL(user.id, { \"tag\": item.PrimaryImageTag }) end if publicUsersNodes.push(user) publicUserIds.push(user.id) end for end if ' load saved users for this server id if numSavedUsers &gt; 0 for each savedUser in savedUsers if isValid(savedUser.serverId) and savedUser.serverId = m.global.session.server.id ' only show unique userids on screen. if not arrayHasValue(publicUserIds, savedUser.Id) user = CreateObject(\"roSGNode\", \"PublicUserData\") user.id = savedUser.Id if isValid(savedUser.username) user.name = savedUser.username end if publicUsersNodes.push(user) end if end if end for end if ' push all users to the user select view userSelected = CreateUserSelectGroup(publicUsersNodes) SendPerformanceBeacon(\"AppDialogComplete\") ' Roku Performance monitoring - Dialog Closed if userSelected = \"backPressed\" session.server.Delete() unset_setting(\"server\") goto start_login else print \"A public user was selected with username=\" + userSelected session.user.Update(\"name\", userSelected) regex = CreateObject(\"roRegex\", \"[^a-zA-Z0-9\\ \\-\\_]\", \"\") session.user.Update(\"friendlyName\", regex.ReplaceAll(userSelected, \"\")) ' save userid to session for each user in publicUsersNodes if user.name = userSelected session.user.Update(\"id\", user.id) exit for end if end for ' try to login with token from registry myToken = get_user_setting(\"token\") if myToken &lt;&gt; invalid ' check if token is valid print \"Auth token found in registry for selected user\" session.user.Update(\"authToken\", myToken) print \"Attempting to use API with auth token\" currentUser = AboutMe() if currentUser = invalid print \"Auth token is no longer valid - deleting token\" unset_user_setting(\"token\") unset_user_setting(\"username\") else print \"Success! Auth token is still valid\" session.user.Login(currentUser, true) LoadUserAbilities() return true end if else print \"No auth token found in registry for selected user\" end if 'Try to login without password. If the token is valid, we're done print \"Attempting to login with no password\" userData = get_token(userSelected, \"\") if isValid(userData) print \"login success!\" session.user.Login(userData, true) LoadUserAbilities() return true else print \"Auth failed. Password required\" end if end if else userSelected = \"\" end if passwordEntry = CreateSigninGroup(userSelected) SendPerformanceBeacon(\"AppDialogComplete\") ' Roku Performance monitoring - Dialog Closed if passwordEntry = \"backPressed\" if numPubUsers &gt; 0 goto user_select else session.server.Delete() unset_setting(\"server\") goto start_login end if end if else print \"Active user found in registry\" session.user.Update(\"id\", activeUser) myUsername = get_user_setting(\"username\") myAuthToken = get_user_setting(\"token\") if isValid(myAuthToken) and isValid(myUsername) print \"Auth token found in registry\" session.user.Update(\"authToken\", myAuthToken) session.user.Update(\"name\", myUsername) regex = CreateObject(\"roRegex\", \"[^a-zA-Z0-9\\ \\-\\_]\", \"\") session.user.Update(\"friendlyName\", regex.ReplaceAll(myUsername, \"\")) print \"Attempting to use API with auth token\" currentUser = AboutMe() if currentUser = invalid print \"Auth token is no longer valid\" 'Try to login without password. If the token is valid, we're done print \"Attempting to login with no password\" userData = get_token(myUsername, \"\") if isValid(userData) print \"login success!\" session.user.Login(userData, true) LoadUserAbilities() return true else print \"Auth failed. Password required\" print \"delete token and restart login flow\" unset_user_setting(\"token\") unset_user_setting(\"username\") goto start_login end if else print \"Success! Auth token is still valid\" session.user.Login(currentUser, true) end if else print \"No auth token found in registry\" end if end if if m.global.session.user.id = invalid or m.global.session.user.authToken = invalid print \"Login failed, restart flow\" unset_setting(\"active_user\") session.user.Logout() goto start_login end if LoadUserAbilities() m.global.sceneManager.callFunc(\"clearScenes\") return true end function sub SaveServerList() 'Save off this server to our list of saved servers for easier navigation between servers server = m.global.session.server.url saved = get_setting(\"saved_servers\") if isValid(server) server = LCase(server)'Saved server data is always lowercase end if entryCount = 0 addNewEntry = true savedServers = { serverList: [] } if isValid(saved) savedServers = ParseJson(saved) entryCount = savedServers.serverList.Count() if isValid(savedServers.serverList) and entryCount &gt; 0 for each item in savedServers.serverList if item.baseUrl = server addNewEntry = false exit for end if end for end if end if if addNewEntry if entryCount = 0 set_setting(\"saved_servers\", FormatJson({ serverList: [{ name: m.serverSelection, baseUrl: server, iconUrl: \"pkg:/images/logo-icon120.jpg\", iconWidth: 120, iconHeight: 120 }] })) else savedServers.serverList.Push({ name: m.serverSelection, baseUrl: server, iconUrl: \"pkg:/images/logo-icon120.jpg\", iconWidth: 120, iconHeight: 120 }) set_setting(\"saved_servers\", FormatJson(savedServers)) end if end if end sub sub DeleteFromServerList(urlToDelete) saved = get_setting(\"saved_servers\") if isValid(urlToDelete) urlToDelete = LCase(urlToDelete) end if if isValid(saved) savedServers = ParseJson(saved) newServers = { serverList: [] } for each item in savedServers.serverList if item.baseUrl &lt;&gt; urlToDelete newServers.serverList.Push(item) end if end for set_setting(\"saved_servers\", FormatJson(newServers)) end if end sub ' Roku Performance monitoring sub SendPerformanceBeacon(signalName as string) if m.global.app_loaded = false m.scene.signalBeacon(signalName) end if end sub function CreateServerGroup() screen = CreateObject(\"roSGNode\", \"SetServerScreen\") screen.optionsAvailable = true m.global.sceneManager.callFunc(\"pushScene\", screen) port = CreateObject(\"roMessagePort\") m.colors = {} if isValid(m.global.session.server.url) screen.serverUrl = m.global.session.server.url end if m.viewModel = {} button = screen.findNode(\"submit\") button.observeField(\"buttonSelected\", port) 'create delete saved server option new_options = [] sidepanel = screen.findNode(\"options\") opt = CreateObject(\"roSGNode\", \"OptionsButton\") opt.title = tr(\"Delete Saved\") opt.id = \"delete_saved\" opt.observeField(\"optionSelected\", port) new_options.push(opt) sidepanel.options = new_options sidepanel.observeField(\"closeSidePanel\", port) screen.observeField(\"backPressed\", port) while true msg = wait(0, port) print type(msg), msg if type(msg) = \"roSGScreenEvent\" and msg.isScreenClosed() return \"false\" else if isNodeEvent(msg, \"backPressed\") return \"backPressed\" else if isNodeEvent(msg, \"closeSidePanel\") screen.setFocus(true) serverPicker = screen.findNode(\"serverPicker\") serverPicker.setFocus(true) else if type(msg) = \"roSGNodeEvent\" node = msg.getNode() if node = \"submit\" ' Show Connecting to Server spinner dialog = createObject(\"roSGNode\", \"ProgressDialog\") dialog.title = tr(\"Connecting to Server\") m.scene.dialog = dialog serverUrl = standardize_jellyfin_url(screen.serverUrl) isConnected = session.server.UpdateURL(serverUrl) serverInfoResult = invalid if isConnected set_setting(\"server\", serverUrl) serverInfoResult = ServerInfo() end if dialog.close = true if isConnected = false or serverInfoResult = invalid ' Maybe don't unset setting, but offer as a prompt ' Server not found, is it online? New values / Retry print \"Server not found, is it online? New values / Retry\" screen.errorMessage = tr(\"Server not found, is it online?\") SignOut(false) else if isValid(serverInfoResult.Error) and serverInfoResult.Error ' If server redirected received, update the URL if isValid(serverInfoResult.UpdatedUrl) serverUrl = serverInfoResult.UpdatedUrl isConnected = session.server.UpdateURL(serverUrl) if isConnected set_setting(\"server\", serverUrl) screen.visible = false return \"\" end if end if ' Display Error Message to user message = tr(\"Error: \") if isValid(serverInfoResult.ErrorCode) message = message + \"[\" + serverInfoResult.ErrorCode.toStr() + \"] \" end if screen.errorMessage = message + tr(serverInfoResult.ErrorMessage) SignOut(false) else screen.visible = false if isValid(serverInfoResult.serverName) return serverInfoResult.ServerName + \" (Saved)\" else return \"Saved\" end if end if end if else if node = \"delete_saved\" serverPicker = screen.findNode(\"serverPicker\") itemToDelete = serverPicker.content.getChild(serverPicker.itemFocused) urlToDelete = itemToDelete.baseUrl if isValid(urlToDelete) DeleteFromServerList(urlToDelete) serverPicker.content.removeChild(itemToDelete) sidepanel.visible = false serverPicker.setFocus(true) end if end if end if end while ' Just hide it when done, in case we need to come back screen.visible = false return \"\" end function function CreateUserSelectGroup(users = []) if users.count() = 0 return \"\" end if group = CreateObject(\"roSGNode\", \"UserSelect\") m.global.sceneManager.callFunc(\"pushScene\", group) port = CreateObject(\"roMessagePort\") group.itemContent = users group.findNode(\"userRow\").observeField(\"userSelected\", port) group.findNode(\"alternateOptions\").observeField(\"itemSelected\", port) group.observeField(\"backPressed\", port) while true msg = wait(0, port) if type(msg) = \"roSGScreenEvent\" and msg.isScreenClosed() group.visible = false return -1 else if isNodeEvent(msg, \"backPressed\") return \"backPressed\" else if type(msg) = \"roSGNodeEvent\" and msg.getField() = \"userSelected\" return msg.GetData() else if type(msg) = \"roSGNodeEvent\" and msg.getField() = \"itemSelected\" if msg.getData() = 0 return \"\" end if end if end while ' Just hide it when done, in case we need to come back group.visible = false return \"\" end function function CreateSigninGroup(user = \"\") ' Get and Save Jellyfin user login credentials group = CreateObject(\"roSGNode\", \"LoginScene\") m.global.sceneManager.callFunc(\"pushScene\", group) port = CreateObject(\"roMessagePort\") group.findNode(\"prompt\").text = tr(\"Sign In\") config = group.findNode(\"configOptions\") username_field = CreateObject(\"roSGNode\", \"ConfigData\") username_field.label = tr(\"Username\") username_field.field = \"username\" username_field.type = \"string\" if user = \"\" and get_setting(\"username\") &lt;&gt; invalid username_field.value = get_setting(\"username\") else username_field.value = user end if password_field = CreateObject(\"roSGNode\", \"ConfigData\") password_field.label = tr(\"Password\") password_field.field = \"password\" password_field.type = \"password\" registryPassword = get_setting(\"password\") if isValid(registryPassword) password_field.value = registryPassword end if ' Add checkbox for saving credentials checkbox = group.findNode(\"onOff\") items = CreateObject(\"roSGNode\", \"ContentNode\") items.role = \"content\" saveCheckBox = CreateObject(\"roSGNode\", \"ContentNode\") saveCheckBox.title = tr(\"Save Credentials?\") items.appendChild(saveCheckBox) checkbox.content = items checkbox.checkedState = [true] quickConnect = group.findNode(\"quickConnect\") ' Quick Connect only supported for server version 10.8+ right now... if versionChecker(m.global.session.server.version, \"10.8.0\") ' Add option for Quick Connect quickConnect.text = tr(\"Quick Connect\") quickConnect.observeField(\"buttonSelected\", port) else quickConnect.visible = false end if items = [username_field, password_field] config.configItems = items button = group.findNode(\"submit\") button.observeField(\"buttonSelected\", port) config = group.findNode(\"configOptions\") username = config.content.getChild(0) password = config.content.getChild(1) group.observeField(\"backPressed\", port) while true msg = wait(0, port) if type(msg) = \"roSGScreenEvent\" and msg.isScreenClosed() group.visible = false return \"false\" else if isNodeEvent(msg, \"backPressed\") group.unobserveField(\"backPressed\") group.backPressed = false return \"backPressed\" else if type(msg) = \"roSGNodeEvent\" node = msg.getNode() if node = \"submit\" ' Validate credentials activeUser = get_token(username.value, password.value) if isValid(activeUser) print \"activeUser=\", activeUser if checkbox.checkedState[0] = true ' save credentials session.user.Login(activeUser, true) set_user_setting(\"token\", activeUser.token) set_user_setting(\"username\", username.value) else session.user.Login(activeUser) end if return \"true\" end if print \"Login attempt failed...\" group.findNode(\"alert\").text = tr(\"Login attempt failed.\") else if node = \"quickConnect\" json = initQuickConnect() if json = invalid group.findNode(\"alert\").text = tr(\"Quick Connect not available.\") else ' Server user is talking to is at least 10.8 and has quick connect enabled... m.quickConnectDialog = createObject(\"roSGNode\", \"QuickConnectDialog\") m.quickConnectDialog.quickConnectJson = json m.quickConnectDialog.title = tr(\"Quick Connect\") m.quickConnectDialog.message = [tr(\"Here is your Quick Connect code: \") + json.Code, tr(\"(Dialog will close automatically)\")] m.quickConnectDialog.buttons = [tr(\"Cancel\")] m.quickConnectDialog.observeField(\"authenticated\", port) m.scene.dialog = m.quickConnectDialog end if else if msg.getField() = \"authenticated\" authenticated = msg.getData() if authenticated = true ' Quick connect authentication was successful... return \"true\" else dialog = createObject(\"roSGNode\", \"Dialog\") dialog.id = \"QuickConnectError\" dialog.title = tr(\"Quick Connect\") dialog.buttons = [tr(\"OK\")] dialog.message = tr(\"There was an error authenticating via Quick Connect.\") m.scene.dialog = dialog m.scene.dialog.observeField(\"buttonSelected\", port) end if else ' If there are no other button matches, check if this is a simple \"OK\" Dialog &amp; Close if so dialog = msg.getRoSGNode() if dialog.id = \"QuickConnectError\" dialog.unobserveField(\"buttonSelected\") dialog.close = true end if end if end if end while ' Just hide it when done, in case we need to come back group.visible = false return \"\" end function function CreateHomeGroup() ' Main screen after logging in. Shows the user's libraries group = CreateObject(\"roSGNode\", \"Home\") group.overhangTitle = tr(\"Home\") group.optionsAvailable = true group.observeField(\"selectedItem\", m.port) group.observeField(\"quickPlayNode\", m.port) sidepanel = group.findNode(\"options\") sidepanel.observeField(\"closeSidePanel\", m.port) new_options = [] options_buttons = [ { \"title\": \"Search\", \"id\": \"goto_search\" }, { \"title\": \"Change user\", \"id\": \"change_user\" }, { \"title\": \"Change server\", \"id\": \"change_server\" }, { \"title\": \"Sign out\", \"id\": \"sign_out\" } ] for each opt in options_buttons o = CreateObject(\"roSGNode\", \"OptionsButton\") o.title = tr(opt.title) o.id = opt.id o.observeField(\"optionSelected\", m.port) new_options.push(o) end for ' Add settings option to menu o = CreateObject(\"roSGNode\", \"OptionsButton\") o.title = \"Settings\" o.id = \"settings\" o.observeField(\"optionSelected\", m.port) new_options.push(o) ' And a profile button user_node = CreateObject(\"roSGNode\", \"OptionsData\") user_node.id = \"active_user\" user_node.title = tr(\"Profile\") user_node.base_title = tr(\"Profile\") user_options = [] for each user in AvailableUsers() user_options.push({ display: user.username + \"@\" + user.server, value: user.id }) end for user_node.choices = user_options user_node.value = m.global.session.user.id new_options.push(user_node) sidepanel.options = new_options return group end function function CreateMovieDetailsGroup(movie as object) as dynamic ' validate movie node if not isValid(movie) or not isValid(movie.id) then return invalid startLoadingSpinner() ' get movie meta data movieMetaData = ItemMetaData(movie.id) ' validate movie meta data if not isValid(movieMetaData) stopLoadingSpinner() return invalid end if ' start building MovieDetails view group = CreateObject(\"roSGNode\", \"MovieDetails\") group.observeField(\"quickPlayNode\", m.port) group.overhangTitle = movie.title group.optionsAvailable = false group.trailerAvailable = false ' push scene asap (to prevent extra button presses when retriving series/movie info) m.global.sceneManager.callFunc(\"pushScene\", group) group.itemContent = movieMetaData ' local trailers trailerData = api.users.GetLocalTrailers(m.global.session.user.id, movie.id) if isValid(trailerData) group.trailerAvailable = trailerData.Count() &gt; 0 end if ' watch for button presses buttons = group.findNode(\"buttons\") for each b in buttons.getChildren(-1, 0) b.observeField(\"buttonSelected\", m.port) end for ' setup and load movie extras extras = group.findNode(\"extrasGrid\") extras.observeField(\"selectedItem\", m.port) extras.callFunc(\"loadParts\", movieMetaData.json) ' done building MovieDetails view stopLoadingSpinner() return group end function function CreateSeriesDetailsGroup(seriesID as string) as dynamic ' validate series node if not isValid(seriesID) or seriesID = \"\" then return invalid startLoadingSpinner() ' get series meta data seriesMetaData = ItemMetaData(seriesID) ' validate series meta data if not isValid(seriesMetaData) stopLoadingSpinner() return invalid end if ' Get season data early in the function so we can check number of seasons. seasonData = TVSeasons(seriesID) ' Divert to season details if user setting goStraightToEpisodeListing is enabled and only one season exists. if m.global.session.user.settings[\"ui.tvshows.goStraightToEpisodeListing\"] = true and seasonData.Items.Count() = 1 stopLoadingSpinner() return CreateSeasonDetailsGroupByID(seriesID, seasonData.Items[0].id) end if ' start building SeriesDetails view group = CreateObject(\"roSGNode\", \"TVShowDetails\") group.optionsAvailable = false ' push scene asap (to prevent extra button presses when retriving series/movie info) m.global.sceneManager.callFunc(\"pushScene\", group) group.itemContent = seriesMetaData group.seasonData = seasonData ' watch for button presses group.observeField(\"seasonSelected\", m.port) group.observeField(\"quickPlayNode\", m.port) ' setup and load series extras extras = group.findNode(\"extrasGrid\") extras.observeField(\"selectedItem\", m.port) extras.callFunc(\"loadParts\", seriesMetaData.json) ' done building SeriesDetails view stopLoadingSpinner() return group end function ' Shows details on selected artist. Bio, image, and list of available albums function CreateArtistView(artist as object) as dynamic ' validate artist node if not isValid(artist) or not isValid(artist.id) then return invalid musicData = MusicAlbumList(artist.id) appearsOnData = AppearsOnList(artist.id) if (musicData = invalid or musicData.Items.Count() = 0) and (appearsOnData = invalid or appearsOnData.Items.Count() = 0) ' Just songs under artists... group = CreateObject(\"roSGNode\", \"AlbumView\") group.pageContent = ItemMetaData(artist.id) ' Lookup songs based on artist id songList = GetSongsByArtist(artist.id) if not isValid(songList) ' Lookup songs based on folder parent / child relationship songList = MusicSongList(artist.id) end if if not isValid(songList) return invalid end if group.albumData = songList group.observeField(\"playSong\", m.port) group.observeField(\"playAllSelected\", m.port) group.observeField(\"instantMixSelected\", m.port) else ' User has albums under artists group = CreateObject(\"roSGNode\", \"ArtistView\") group.pageContent = ItemMetaData(artist.id) group.musicArtistAlbumData = musicData group.musicArtistAppearsOnData = appearsOnData group.artistOverview = ArtistOverview(artist.name) group.observeField(\"musicAlbumSelected\", m.port) group.observeField(\"playArtistSelected\", m.port) group.observeField(\"instantMixSelected\", m.port) group.observeField(\"appearsOnSelected\", m.port) end if group.observeField(\"quickPlayNode\", m.port) m.global.sceneManager.callFunc(\"pushScene\", group) return group end function ' Shows details on selected album. Description text, image, and list of available songs function CreateAlbumView(album as object) as dynamic ' validate album node if not isValid(album) or not isValid(album.id) then return invalid group = CreateObject(\"roSGNode\", \"AlbumView\") m.global.sceneManager.callFunc(\"pushScene\", group) group.pageContent = ItemMetaData(album.id) group.albumData = MusicSongList(album.id) ' Watch for user clicking on a song group.observeField(\"playSong\", m.port) ' Watch for user click on Play button on album group.observeField(\"playAllSelected\", m.port) ' Watch for user click on Instant Mix button on album group.observeField(\"instantMixSelected\", m.port) return group end function ' Shows details on selected playlist. Description text, image, and list of available items function CreatePlaylistView(playlist as object) as dynamic ' validate playlist node if not isValid(playlist) or not isValid(playlist.id) then return invalid group = CreateObject(\"roSGNode\", \"PlaylistView\") m.global.sceneManager.callFunc(\"pushScene\", group) group.pageContent = ItemMetaData(playlist.id) group.albumData = PlaylistItemList(playlist.id) ' Watch for user clicking on an item group.observeField(\"playItem\", m.port) ' Watch for user click on Play button group.observeField(\"playAllSelected\", m.port) return group end function function CreateSeasonDetailsGroup(series as object, season as object) as dynamic ' validate series node if not isValid(series) or not isValid(series.id) then return invalid ' validate season node if not isValid(season) or not isValid(season.id) then return invalid startLoadingSpinner() ' get season meta data seasonMetaData = ItemMetaData(season.id) ' validate season meta data if not isValid(seasonMetaData) stopLoadingSpinner() return invalid end if ' start building SeasonDetails view group = CreateObject(\"roSGNode\", \"TVEpisodes\") group.optionsAvailable = false ' push scene asap (to prevent extra button presses when retriving series/movie info) m.global.sceneManager.callFunc(\"pushScene\", group) group.seasonData = seasonMetaData.json group.objects = TVEpisodes(series.id, season.id) group.episodeObjects = group.objects group.extrasObjects = TVSeasonExtras(season.id) ' watch for button presses group.observeField(\"episodeSelected\", m.port) group.observeField(\"quickPlayNode\", m.port) ' finished building SeasonDetails view stopLoadingSpinner() return group end function function CreateSeasonDetailsGroupByID(seriesID as string, seasonID as string) as dynamic ' validate parameters if seriesID = \"\" or seasonID = \"\" then return invalid startLoadingSpinner() ' get season meta data seasonMetaData = ItemMetaData(seasonID) ' validate season meta data if not isValid(seasonMetaData) stopLoadingSpinner() return invalid end if ' start building SeasonDetails view group = CreateObject(\"roSGNode\", \"TVEpisodes\") group.optionsAvailable = false ' push scene asap (to prevent extra button presses when retriving series/movie info) m.global.sceneManager.callFunc(\"pushScene\", group) group.seasonData = seasonMetaData.json group.objects = TVEpisodes(seriesID, seasonID) group.episodeObjects = group.objects group.extrasObjects = TVSeasonExtras(seasonID) ' watch for button presses group.observeField(\"episodeSelected\", m.port) group.observeField(\"quickPlayNode\", m.port) ' finished building SeasonDetails view stopLoadingSpinner() return group end function function CreateItemGrid(libraryItem as object) as dynamic ' validate libraryItem if not isValid(libraryItem) then return invalid group = CreateObject(\"roSGNode\", \"ItemGrid\") group.parentItem = libraryItem group.optionsAvailable = true group.observeField(\"selectedItem\", m.port) group.observeField(\"quickPlayNode\", m.port) return group end function function CreateMovieLibraryView(libraryItem as object) as dynamic ' validate libraryItem if not isValid(libraryItem) then return invalid group = CreateObject(\"roSGNode\", \"MovieLibraryView\") group.parentItem = libraryItem group.optionsAvailable = true group.observeField(\"selectedItem\", m.port) group.observeField(\"quickPlayNode\", m.port) return group end function function CreateMusicLibraryView(libraryItem as object) as dynamic ' validate libraryItem if not isValid(libraryItem) then return invalid group = CreateObject(\"roSGNode\", \"MusicLibraryView\") group.parentItem = libraryItem group.optionsAvailable = true group.observeField(\"selectedItem\", m.port) group.observeField(\"quickPlayNode\", m.port) return group end function function CreateSearchPage() ' Search + Results Page group = CreateObject(\"roSGNode\", \"searchResults\") options = group.findNode(\"searchSelect\") options.observeField(\"itemSelected\", m.port) return group end function function CreateVideoPlayerGroup(video_id as string, mediaSourceId = invalid as dynamic, audio_stream_idx = 1 as integer, forceTranscoding = false as boolean, showIntro = true as boolean, allowResumeDialog = true as boolean) ' validate video_id if not isValid(video_id) or video_id = \"\" then return invalid startMediaLoadingSpinner() ' Video is Playing video = VideoPlayer(video_id, mediaSourceId, audio_stream_idx, defaultSubtitleTrackFromVid(video_id), forceTranscoding, showIntro, allowResumeDialog) if video = invalid then return invalid video.allowCaptions = true if video.errorMsg = \"introaborted\" then return video video.observeField(\"selectSubtitlePressed\", m.port) video.observeField(\"selectPlaybackInfoPressed\", m.port) video.observeField(\"state\", m.port) stopLoadingSpinner() return video end function function CreatePersonView(personData as object) as dynamic ' validate personData node if not isValid(personData) or not isValid(personData.id) then return invalid startLoadingSpinner() ' get person meta data personMetaData = ItemMetaData(personData.id) ' validate season meta data if not isValid(personMetaData) stopLoadingSpinner() return invalid end if ' start building Person View person = CreateObject(\"roSGNode\", \"PersonDetails\") ' push scene asap (to prevent extra button presses when retriving series/movie info) m.global.SceneManager.callFunc(\"pushScene\", person) person.itemContent = personMetaData person.setFocus(true) ' watch for button presses person.observeField(\"selectedItem\", m.port) person.findNode(\"favorite-button\").observeField(\"buttonSelected\", m.port) ' finished building Person View stopLoadingSpinner() return person end function 'Opens dialog asking user if they want to resume video or start playback over only on the home screen sub playbackOptionDialog(time as longinteger, meta as object) resumeData = [ tr(\"Resume playing at \") + ticksToHuman(time) + \".\", tr(\"Start over from the beginning.\") ] group = m.global.sceneManager.callFunc(\"getActiveScene\") if LCase(group.subtype()) = \"home\" if LCase(meta.type) = \"episode\" resumeData.push(tr(\"Go to series\")) resumeData.push(tr(\"Go to season\")) resumeData.push(tr(\"Go to episode\")) end if end if m.global.sceneManager.callFunc(\"optionDialog\", tr(\"Playback Options\"), [], resumeData) end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_music_SongItem.brs.html":{"id":"components_music_SongItem.brs.html","title":"Source: components/music/SongItem.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/music/SongItem.brs import \"pkg:/source/utils/misc.brs\" sub init() m.itemText = m.top.findNode(\"itemText\") m.trackNumber = m.top.findNode(\"trackNumber\") m.tracklength = m.top.findNode(\"tracklength\") m.defaultTextColor = m.itemText.color end sub sub itemContentChanged() itemData = m.top.itemContent if itemData = invalid then return m.itemText.text = itemData.title if itemData.trackNumber &lt;&gt; 0 m.trackNumber.text = itemData.trackNumber end if m.tracklength.text = ticksToHuman(itemData.length) end sub sub focusChanged() if m.top.itemHasFocus color = \"#101010FF\" else color = m.defaultTextColor end if m.itemText.color = color m.trackNumber.color = color m.tracklength.color = color end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_Spinner.brs.html":{"id":"components_Spinner.brs.html","title":"Source: components/Spinner.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/Spinner.brs sub init() m.top.poster.uri = \"pkg:/images/spinner.png\" m.top.control = \"start\" m.top.clockwise = true m.top.spinInterval = 3 end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_StandardDialog.brs.html":{"id":"components_StandardDialog.brs.html","title":"Source: components/StandardDialog.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/StandardDialog.brs sub init() m.content = m.top.findNode(\"content\") m.top.observeField(\"contentData\", \"onContentDataChanged\") m.top.id = \"OKDialog\" m.top.height = 900 m.top.title = \"What's New?\" m.top.buttons = [tr(\"OK\")] m.dialogStyles = { \"default\": { \"fontSize\": 27, \"fontUri\": \"font:BoldSystemFontFile\", \"color\": \"#EFEFEFFF\" }, \"b\": { \"fontSize\": 27, \"fontUri\": \"font:SystemFontFile\", \"color\": \"#999999\" }, \"header\": { \"fontSize\": 35, \"fontUri\": \"font:SystemFontFile\", \"color\": \"#00a4dcFF\" } } end sub sub onContentDataChanged() for each item in m.top.contentData.data textLine = m.content.CreateChild(\"StdDlgMultiStyleTextItem\") textLine.drawingStyles = m.dialogStyles textLine.text = item end for end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"source_utils_Subtitles.brs.html":{"id":"source_utils_Subtitles.brs.html","title":"Source: source/utils/Subtitles.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: source/utils/Subtitles.brs ' Roku translates the info provided in subtitleTracks into availableSubtitleTracks ' Including ignoring tracks, if they are not understood, thus making indexing unpredictable. ' This function translates between our internel selected subtitle index ' and the corresponding index in availableSubtitleTracks. function availSubtitleTrackIdx(video, sub_idx) as integer url = video.Subtitles[sub_idx].Track.TrackName idx = 0 for each availTrack in video.availableSubtitleTracks ' The TrackName must contain the URL we supplied originally, though ' Roku mangles the name a bit, so we check if the URL is a substring, rather ' than strict equality if Instr(1, availTrack.TrackName, url) return idx end if idx = idx + 1 end for return -1 end function ' Identify the default subtitle track for a given video id ' returns the server-side track index for the appriate subtitle function defaultSubtitleTrackFromVid(video_id) as integer meta = ItemMetaData(video_id) if isValid(meta) and isValid(meta.json) and isValid(meta.json.mediaSources) subtitles = sortSubtitles(meta.id, meta.json.MediaSources[0].MediaStreams) default_text_subs = defaultSubtitleTrack(subtitles[\"all\"], true) ' Find correct subtitle track (forced text) if default_text_subs &lt;&gt; -1 return default_text_subs else if m.global.session.user.settings[\"playback.subs.onlytext\"] = false return defaultSubtitleTrack(subtitles[\"all\"]) ' if no appropriate text subs exist, allow non-text else return -1 end if end if end if ' No valid mediaSources (i.e. LiveTV) return -1 end function ' Identify the default subtitle track ' if \"requires_text\" is true, only return a track if it is textual ' This allows forcing text subs, since roku requires transcoding of non-text subs ' returns the server-side track index for the appriate subtitle function defaultSubtitleTrack(sorted_subtitles, require_text = false) as integer if m.global.session.user.configuration.SubtitleMode = \"None\" return -1 ' No subtitles desired: select none end if for each item in sorted_subtitles ' Only auto-select subtitle if language matches preference languageMatch = (m.global.session.user.configuration.SubtitleLanguagePreference = item.Track.Language) ' Ensure textuality of subtitle matches preferenced passed as arg matchTextReq = ((require_text and item.IsTextSubtitleStream) or not require_text) if languageMatch and matchTextReq if m.global.session.user.configuration.SubtitleMode = \"Default\" and (item.isForced or item.IsDefault or item.IsExternal) return item.Index ' Finds first forced, or default, or external subs in sorted list else if m.global.session.user.configuration.SubtitleMode = \"Always\" and not item.IsForced return item.Index ' Select the first non-forced subtitle option in the sorted list else if m.global.session.user.configuration.SubtitleMode = \"OnlyForced\" and item.IsForced return item.Index ' Select the first forced subtitle option in the sorted list else if m.global.session.user.configuration.SubtitlePlaybackMode = \"Smart\" and (item.isForced or item.IsDefault or item.IsExternal) ' Simplified \"Smart\" logic here mimics Default (as that is fallback behavior normally) ' Avoids detecting preferred audio language (as is utilized in main client) return item.Index end if end if end for return -1 ' Keep current default behavior of \"None\", if no correct subtitle is identified end function ' Given a set of subtitles, and a subtitle index (the index on the server, not in the list provided) ' this will set all relevant settings for roku (mainly closed captions) and return the index of the ' subtitle track specified, but indexed based on the provided list of subtitles function setupSubtitle(video, subtitles, subtitle_idx = -1) as integer if subtitle_idx = -1 ' If we are not using text-based subtitles, turn them off return -1 end if ' Translate the raw index to one relative to the provided list subtitleSelIdx = getSubtitleSelIdxFromSubIdx(subtitles, subtitle_idx) selectedSubtitle = subtitles[subtitleSelIdx] if isValid(selectedSubtitle) and isValid(selectedSubtitle.IsEncoded) if selectedSubtitle.IsEncoded ' With encoded subtitles, turn off captions video.globalCaptionMode = \"Off\" else ' If this is a text-based subtitle, set relevant settings for roku captions video.globalCaptionMode = \"On\" video.subtitleTrack = video.availableSubtitleTracks[availSubtitleTrackIdx(video, subtitleSelIdx)].TrackName end if end if return subtitleSelIdx end function ' The subtitle index on the server differs from the index we track locally ' This function converts the former into the latter function getSubtitleSelIdxFromSubIdx(subtitles, sub_idx) as integer selIdx = 0 if sub_idx = -1 then return -1 for each item in subtitles if item.Index = sub_idx return selIdx end if selIdx = selIdx + 1 end for return -1 end function function selectSubtitleTrack(tracks, current = -1) as integer video = m.scene.focusedChild.focusedChild trackSelected = selectSubtitleTrackDialog(video.Subtitles, video.SelectedSubtitle) if trackSelected = invalid or trackSelected = -1 ' back pressed in Dialog - no selection made return -2 else return trackSelected - 1 end if end function ' Present Dialog to user to select subtitle track function selectSubtitleTrackDialog(tracks, currentTrack = -1) iso6392 = getSubtitleLanguages() options = [\"None\"] for each item in tracks forced = \"\" default = \"\" if item.IsForced then forced = \" [Forced]\" if item.IsDefault then default = \" - Default\" if isValid(item.Track.Language) language = iso6392.lookup(item.Track.Language) if language = invalid then language = item.Track.Language else language = \"Undefined\" end if options.push(language + forced + default) end for return option_dialog(options, \"Select a subtitle track\", currentTrack + 1) end function sub changeSubtitleDuringPlayback(newid) ' If no subtitles set if newid = invalid or newid = -1 turnoffSubtitles() return end if video = m.scene.focusedChild.focusedChild ' If no change of subtitle track, return if newid = video.SelectedSubtitle then return currentSubtitles = video.Subtitles[video.SelectedSubtitle] newSubtitles = video.Subtitles[newid] if newSubtitles.IsEncoded or (isValid(currentSubtitles) and currentSubtitles.IsEncoded) ' With encoded subtitles we need to stop/start playback video.control = \"stop\" AddVideoContent(video, video.mediaSourceId, video.audioIndex, newSubtitles.Index, video.position * 10000000) video.control = \"play\" else ' Switching from text to text (or none to text) does not require stopping playback video.globalCaptionMode = \"On\" video.subtitleTrack = video.availableSubtitleTracks[availSubtitleTrackIdx(video, newid)].TrackName end if video.SelectedSubtitle = newid end sub sub turnoffSubtitles() video = m.scene.focusedChild.focusedChild current = video.SelectedSubtitle video.SelectedSubtitle = -1 video.globalCaptionMode = \"Off\" device = CreateObject(\"roDeviceInfo\") device.EnableAppFocusEvent(false) ' Check if Enoded subtitles are being displayed, and turn off if current &gt; -1 and video.Subtitles[current].IsEncoded video.control = \"stop\" AddVideoContent(video, video.mediaSourceId, video.audioIndex, -1, video.position * 10000000) video.control = \"play\" end if end sub 'Checks available subtitle tracks and puts subtitles in forced, default, and non-default/forced but preferred language at the top function sortSubtitles(id as string, MediaStreams) tracks = { \"forced\": [], \"default\": [], \"normal\": [] } 'Too many args for using substitute prefered_lang = m.global.session.user.configuration.SubtitleLanguagePreference for each stream in MediaStreams if stream.type = \"Subtitle\" url = \"\" if isValid(stream.DeliveryUrl) url = buildURL(stream.DeliveryUrl) end if stream = { \"Track\": { \"Language\": stream.language, \"Description\": stream.displaytitle, \"TrackName\": url }, \"IsTextSubtitleStream\": stream.IsTextSubtitleStream, \"Index\": stream.index, \"IsDefault\": stream.IsDefault, \"IsForced\": stream.IsForced, \"IsExternal\": stream.IsExternal, \"IsEncoded\": stream.DeliveryMethod = \"Encode\" } if stream.isForced trackType = \"forced\" else if stream.IsDefault trackType = \"default\" else trackType = \"normal\" end if if prefered_lang &lt;&gt; \"\" and prefered_lang = stream.Track.Language tracks[trackType].unshift(stream) else tracks[trackType].push(stream) end if end if end for tracks[\"default\"].append(tracks[\"normal\"]) tracks[\"forced\"].append(tracks[\"default\"]) textTracks = [] for i = 0 to tracks[\"forced\"].count() - 1 if tracks[\"forced\"][i].IsTextSubtitleStream textTracks.push(tracks[\"forced\"][i].Track) end if end for return { \"all\": tracks[\"forced\"], \"text\": textTracks } end function function getSubtitleLanguages() return { \"aar\": \"Afar\", \"abk\": \"Abkhazian\", \"ace\": \"Achinese\", \"ach\": \"Acoli\", \"ada\": \"Adangme\", \"ady\": \"Adyghe; Adygei\", \"afa\": \"Afro-Asiatic languages\", \"afh\": \"Afrihili\", \"afr\": \"Afrikaans\", \"ain\": \"Ainu\", \"aka\": \"Akan\", \"akk\": \"Akkadian\", \"alb\": \"Albanian\", \"ale\": \"Aleut\", \"alg\": \"Algonquian languages\", \"alt\": \"Southern Altai\", \"amh\": \"Amharic\", \"ang\": \"English, Old (ca.450-1100)\", \"anp\": \"Angika\", \"apa\": \"Apache languages\", \"ara\": \"Arabic\", \"arc\": \"Official Aramaic (700-300 BCE); Imperial Aramaic (700-300 BCE)\", \"arg\": \"Aragonese\", \"arm\": \"Armenian\", \"arn\": \"Mapudungun; Mapuche\", \"arp\": \"Arapaho\", \"art\": \"Artificial languages\", \"arw\": \"Arawak\", \"asm\": \"Assamese\", \"ast\": \"Asturian; Bable; Leonese; Asturleonese\", \"ath\": \"Athapascan languages\", \"aus\": \"Australian languages\", \"ava\": \"Avaric\", \"ave\": \"Avestan\", \"awa\": \"Awadhi\", \"aym\": \"Aymara\", \"aze\": \"Azerbaijani\", \"bad\": \"Banda languages\", \"bai\": \"Bamileke languages\", \"bak\": \"Bashkir\", \"bal\": \"Baluchi\", \"bam\": \"Bambara\", \"ban\": \"Balinese\", \"baq\": \"Basque\", \"bas\": \"Basa\", \"bat\": \"Baltic languages\", \"bej\": \"Beja; Bedawiyet\", \"bel\": \"Belarusian\", \"bem\": \"Bemba\", \"ben\": \"Bengali\", \"ber\": \"Berber languages\", \"bho\": \"Bhojpuri\", \"bih\": \"Bihari languages\", \"bik\": \"Bikol\", \"bin\": \"Bini; Edo\", \"bis\": \"Bislama\", \"bla\": \"Siksika\", \"bnt\": \"Bantu (Other)\", \"bos\": \"Bosnian\", \"bra\": \"Braj\", \"bre\": \"Breton\", \"btk\": \"Batak languages\", \"bua\": \"Buriat\", \"bug\": \"Buginese\", \"bul\": \"Bulgarian\", \"bur\": \"Burmese\", \"byn\": \"Blin; Bilin\", \"cad\": \"Caddo\", \"cai\": \"Central American Indian languages\", \"car\": \"Galibi Carib\", \"cat\": \"Catalan; Valencian\", \"cau\": \"Caucasian languages\", \"ceb\": \"Cebuano\", \"cel\": \"Celtic languages\", \"cha\": \"Chamorro\", \"chb\": \"Chibcha\", \"che\": \"Chechen\", \"chg\": \"Chagatai\", \"chi\": \"Chinese\", \"chk\": \"Chuukese\", \"chm\": \"Mari\", \"chn\": \"Chinook jargon\", \"cho\": \"Choctaw\", \"chp\": \"Chipewyan; Dene Suline\", \"chr\": \"Cherokee\", \"chu\": \"Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic\", \"chv\": \"Chuvash\", \"chy\": \"Cheyenne\", \"cmc\": \"Chamic languages\", \"cop\": \"Coptic\", \"cor\": \"Cornish\", \"cos\": \"Corsican\", \"cpe\": \"Creoles and pidgins, English based\", \"cpf\": \"Creoles and pidgins, French-based \", \"cpp\": \"Creoles and pidgins, Portuguese-based \", \"cre\": \"Cree\", \"crh\": \"Crimean Tatar; Crimean Turkish\", \"crp\": \"Creoles and pidgins \", \"csb\": \"Kashubian\", \"cus\": \"Cushitic languages\", \"cze\": \"Czech\", \"dak\": \"Dakota\", \"dan\": \"Danish\", \"dar\": \"Dargwa\", \"day\": \"Land Dayak languages\", \"del\": \"Delaware\", \"den\": \"Slave (Athapascan)\", \"dgr\": \"Dogrib\", \"din\": \"Dinka\", \"div\": \"Divehi; Dhivehi; Maldivian\", \"doi\": \"Dogri\", \"dra\": \"Dravidian languages\", \"dsb\": \"Lower Sorbian\", \"dua\": \"Duala\", \"dum\": \"Dutch, Middle (ca.1050-1350)\", \"dut\": \"Dutch; Flemish\", \"dyu\": \"Dyula\", \"dzo\": \"Dzongkha\", \"efi\": \"Efik\", \"egy\": \"Egyptian (Ancient)\", \"eka\": \"Ekajuk\", \"elx\": \"Elamite\", \"eng\": \"English\", \"enm\": \"English, Middle (1100-1500)\", \"epo\": \"Esperanto\", \"est\": \"Estonian\", \"ewe\": \"Ewe\", \"ewo\": \"Ewondo\", \"fan\": \"Fang\", \"fao\": \"Faroese\", \"fat\": \"Fanti\", \"fij\": \"Fijian\", \"fil\": \"Filipino; Pilipino\", \"fin\": \"Finnish\", \"fiu\": \"Finno-Ugrian languages\", \"fon\": \"Fon\", \"fre\": \"French\", \"frm\": \"French, Middle (ca.1400-1600)\", \"fro\": \"French, Old (842-ca.1400)\", \"frc\": \"French (Canada)\", \"frr\": \"Northern Frisian\", \"frs\": \"Eastern Frisian\", \"fry\": \"Western Frisian\", \"ful\": \"Fulah\", \"fur\": \"Friulian\", \"gaa\": \"Ga\", \"gay\": \"Gayo\", \"gba\": \"Gbaya\", \"gem\": \"Germanic languages\", \"geo\": \"Georgian\", \"ger\": \"German\", \"gez\": \"Geez\", \"gil\": \"Gilbertese\", \"gla\": \"Gaelic; Scottish Gaelic\", \"gle\": \"Irish\", \"glg\": \"Galician\", \"glv\": \"Manx\", \"gmh\": \"German, Middle High (ca.1050-1500)\", \"goh\": \"German, Old High (ca.750-1050)\", \"gon\": \"Gondi\", \"gor\": \"Gorontalo\", \"got\": \"Gothic\", \"grb\": \"Grebo\", \"grc\": \"Greek, Ancient (to 1453)\", \"gre\": \"Greek, Modern (1453-)\", \"grn\": \"Guarani\", \"gsw\": \"Swiss German; Alemannic; Alsatian\", \"guj\": \"Gujarati\", \"gwi\": \"Gwich'in\", \"hai\": \"Haida\", \"hat\": \"Haitian; Haitian Creole\", \"hau\": \"Hausa\", \"haw\": \"Hawaiian\", \"heb\": \"Hebrew\", \"her\": \"Herero\", \"hil\": \"Hiligaynon\", \"him\": \"Himachali languages; Western Pahari languages\", \"hin\": \"Hindi\", \"hit\": \"Hittite\", \"hmn\": \"Hmong; Mong\", \"hmo\": \"Hiri Motu\", \"hrv\": \"Croatian\", \"hsb\": \"Upper Sorbian\", \"hun\": \"Hungarian\", \"hup\": \"Hupa\", \"iba\": \"Iban\", \"ibo\": \"Igbo\", \"ice\": \"Icelandic\", \"ido\": \"Ido\", \"iii\": \"Sichuan Yi; Nuosu\", \"ijo\": \"Ijo languages\", \"iku\": \"Inuktitut\", \"ile\": \"Interlingue; Occidental\", \"ilo\": \"Iloko\", \"ina\": \"Interlingua (International Auxiliary Language Association)\", \"inc\": \"Indic languages\", \"ind\": \"Indonesian\", \"ine\": \"Indo-European languages\", \"inh\": \"Ingush\", \"ipk\": \"Inupiaq\", \"ira\": \"Iranian languages\", \"iro\": \"Iroquoian languages\", \"ita\": \"Italian\", \"jav\": \"Javanese\", \"jbo\": \"Lojban\", \"jpn\": \"Japanese\", \"jpr\": \"Judeo-Persian\", \"jrb\": \"Judeo-Arabic\", \"kaa\": \"Kara-Kalpak\", \"kab\": \"Kabyle\", \"kac\": \"Kachin; Jingpho\", \"kal\": \"Kalaallisut; Greenlandic\", \"kam\": \"Kamba\", \"kan\": \"Kannada\", \"kar\": \"Karen languages\", \"kas\": \"Kashmiri\", \"kau\": \"Kanuri\", \"kaw\": \"Kawi\", \"kaz\": \"Kazakh\", \"kbd\": \"Kabardian\", \"kha\": \"Khasi\", \"khi\": \"Khoisan languages\", \"khm\": \"Central Khmer\", \"kho\": \"Khotanese; Sakan\", \"kik\": \"Kikuyu; Gikuyu\", \"kin\": \"Kinyarwanda\", \"kir\": \"Kirghiz; Kyrgyz\", \"kmb\": \"Kimbundu\", \"kok\": \"Konkani\", \"kom\": \"Komi\", \"kon\": \"Kongo\", \"kor\": \"Korean\", \"kos\": \"Kosraean\", \"kpe\": \"Kpelle\", \"krc\": \"Karachay-Balkar\", \"krl\": \"Karelian\", \"kro\": \"Kru languages\", \"kru\": \"Kurukh\", \"kua\": \"Kuanyama; Kwanyama\", \"kum\": \"Kumyk\", \"kur\": \"Kurdish\", \"kut\": \"Kutenai\", \"lad\": \"Ladino\", \"lah\": \"Lahnda\", \"lam\": \"Lamba\", \"lao\": \"Lao\", \"lat\": \"Latin\", \"lav\": \"Latvian\", \"lez\": \"Lezghian\", \"lim\": \"Limburgan; Limburger; Limburgish\", \"lin\": \"Lingala\", \"lit\": \"Lithuanian\", \"lol\": \"Mongo\", \"loz\": \"Lozi\", \"ltz\": \"Luxembourgish; Letzeburgesch\", \"lua\": \"Luba-Lulua\", \"lub\": \"Luba-Katanga\", \"lug\": \"Ganda\", \"lui\": \"Luiseno\", \"lun\": \"Lunda\", \"luo\": \"Luo (Kenya and Tanzania)\", \"lus\": \"Lushai\", \"mac\": \"Macedonian\", \"mad\": \"Madurese\", \"mag\": \"Magahi\", \"mah\": \"Marshallese\", \"mai\": \"Maithili\", \"mak\": \"Makasar\", \"mal\": \"Malayalam\", \"man\": \"Mandingo\", \"mao\": \"Maori\", \"map\": \"Austronesian languages\", \"mar\": \"Marathi\", \"mas\": \"Masai\", \"may\": \"Malay\", \"mdf\": \"Moksha\", \"mdr\": \"Mandar\", \"men\": \"Mende\", \"mga\": \"Irish, Middle (900-1200)\", \"mic\": \"Mi'kmaq; Micmac\", \"min\": \"Minangkabau\", \"mis\": \"Uncoded languages\", \"mkh\": \"Mon-Khmer languages\", \"mlg\": \"Malagasy\", \"mlt\": \"Maltese\", \"mnc\": \"Manchu\", \"mni\": \"Manipuri\", \"mno\": \"Manobo languages\", \"moh\": \"Mohawk\", \"mon\": \"Mongolian\", \"mos\": \"Mossi\", \"mul\": \"Multiple languages\", \"mun\": \"Munda languages\", \"mus\": \"Creek\", \"mwl\": \"Mirandese\", \"mwr\": \"Marwari\", \"myn\": \"Mayan languages\", \"myv\": \"Erzya\", \"nah\": \"Nahuatl languages\", \"nai\": \"North American Indian languages\", \"nap\": \"Neapolitan\", \"nau\": \"Nauru\", \"nav\": \"Navajo; Navaho\", \"nbl\": \"Ndebele, South; South Ndebele\", \"nde\": \"Ndebele, North; North Ndebele\", \"ndo\": \"Ndonga\", \"nds\": \"Low German; Low Saxon; German, Low; Saxon, Low\", \"nep\": \"Nepali\", \"new\": \"Nepal Bhasa; Newari\", \"nia\": \"Nias\", \"nic\": \"Niger-Kordofanian languages\", \"niu\": \"Niuean\", \"nno\": \"Norwegian Nynorsk; Nynorsk, Norwegian\", \"nob\": \"Bokmål, Norwegian; Norwegian Bokmål\", \"nog\": \"Nogai\", \"non\": \"Norse, Old\", \"nor\": \"Norwegian\", \"nqo\": \"N'Ko\", \"nso\": \"Pedi; Sepedi; Northern Sotho\", \"nub\": \"Nubian languages\", \"nwc\": \"Classical Newari; Old Newari; Classical Nepal Bhasa\", \"nya\": \"Chichewa; Chewa; Nyanja\", \"nym\": \"Nyamwezi\", \"nyn\": \"Nyankole\", \"nyo\": \"Nyoro\", \"nzi\": \"Nzima\", \"oci\": \"Occitan (post 1500); Provençal\", \"oji\": \"Ojibwa\", \"ori\": \"Oriya\", \"orm\": \"Oromo\", \"osa\": \"Osage\", \"oss\": \"Ossetian; Ossetic\", \"ota\": \"Turkish, Ottoman (1500-1928)\", \"oto\": \"Otomian languages\", \"paa\": \"Papuan languages\", \"pag\": \"Pangasinan\", \"pal\": \"Pahlavi\", \"pam\": \"Pampanga; Kapampangan\", \"pan\": \"Panjabi; Punjabi\", \"pap\": \"Papiamento\", \"pau\": \"Palauan\", \"peo\": \"Persian, Old (ca.600-400 B.C.)\", \"per\": \"Persian\", \"phi\": \"Philippine languages\", \"phn\": \"Phoenician\", \"pli\": \"Pali\", \"pol\": \"Polish\", \"pon\": \"Pohnpeian\", \"por\": \"Portuguese\", \"pob\": \"Portuguese (Brazil)\", \"pra\": \"Prakrit languages\", \"pro\": \"Provençal, Old (to 1500)\", \"pus\": \"Pushto; Pashto\", \"qaa-qtz\": \"Reserved for local use\", \"que\": \"Quechua\", \"raj\": \"Rajasthani\", \"rap\": \"Rapanui\", \"rar\": \"Rarotongan; Cook Islands Maori\", \"roa\": \"Romance languages\", \"roh\": \"Romansh\", \"rom\": \"Romany\", \"rum\": \"Romanian; Moldavian; Moldovan\", \"run\": \"Rundi\", \"rup\": \"Aromanian; Arumanian; Macedo-Romanian\", \"rus\": \"Russian\", \"sad\": \"Sandawe\", \"sag\": \"Sango\", \"sah\": \"Yakut\", \"sai\": \"South American Indian (Other)\", \"sal\": \"Salishan languages\", \"sam\": \"Samaritan Aramaic\", \"san\": \"Sanskrit\", \"sas\": \"Sasak\", \"sat\": \"Santali\", \"scn\": \"Sicilian\", \"sco\": \"Scots\", \"sel\": \"Selkup\", \"sem\": \"Semitic languages\", \"sga\": \"Irish, Old (to 900)\", \"sgn\": \"Sign Languages\", \"shn\": \"Shan\", \"sid\": \"Sidamo\", \"sin\": \"Sinhala; Sinhalese\", \"sio\": \"Siouan languages\", \"sit\": \"Sino-Tibetan languages\", \"sla\": \"Slavic languages\", \"slo\": \"Slovak\", \"slv\": \"Slovenian\", \"sma\": \"Southern Sami\", \"sme\": \"Northern Sami\", \"smi\": \"Sami languages\", \"smj\": \"Lule Sami\", \"smn\": \"Inari Sami\", \"smo\": \"Samoan\", \"sms\": \"Skolt Sami\", \"sna\": \"Shona\", \"snd\": \"Sindhi\", \"snk\": \"Soninke\", \"sog\": \"Sogdian\", \"som\": \"Somali\", \"son\": \"Songhai languages\", \"sot\": \"Sotho, Southern\", \"spa\": \"Spanish; Latin\", \"spa\": \"Spanish; Castilian\", \"srd\": \"Sardinian\", \"srn\": \"Sranan Tongo\", \"srp\": \"Serbian\", \"srr\": \"Serer\", \"ssa\": \"Nilo-Saharan languages\", \"ssw\": \"Swati\", \"suk\": \"Sukuma\", \"sun\": \"Sundanese\", \"sus\": \"Susu\", \"sux\": \"Sumerian\", \"swa\": \"Swahili\", \"swe\": \"Swedish\", \"syc\": \"Classical Syriac\", \"syr\": \"Syriac\", \"tah\": \"Tahitian\", \"tai\": \"Tai languages\", \"tam\": \"Tamil\", \"tat\": \"Tatar\", \"tel\": \"Telugu\", \"tem\": \"Timne\", \"ter\": \"Tereno\", \"tet\": \"Tetum\", \"tgk\": \"Tajik\", \"tgl\": \"Tagalog\", \"tha\": \"Thai\", \"tib\": \"Tibetan\", \"tig\": \"Tigre\", \"tir\": \"Tigrinya\", \"tiv\": \"Tiv\", \"tkl\": \"Tokelau\", \"tlh\": \"Klingon; tlhIngan-Hol\", \"tli\": \"Tlingit\", \"tmh\": \"Tamashek\", \"tog\": \"Tonga (Nyasa)\", \"ton\": \"Tonga (Tonga Islands)\", \"tpi\": \"Tok Pisin\", \"tsi\": \"Tsimshian\", \"tsn\": \"Tswana\", \"tso\": \"Tsonga\", \"tuk\": \"Turkmen\", \"tum\": \"Tumbuka\", \"tup\": \"Tupi languages\", \"tur\": \"Turkish\", \"tut\": \"Altaic languages\", \"tvl\": \"Tuvalu\", \"twi\": \"Twi\", \"tyv\": \"Tuvinian\", \"udm\": \"Udmurt\", \"uga\": \"Ugaritic\", \"uig\": \"Uighur; Uyghur\", \"ukr\": \"Ukrainian\", \"umb\": \"Umbundu\", \"und\": \"Undetermined\", \"urd\": \"Urdu\", \"uzb\": \"Uzbek\", \"vai\": \"Vai\", \"ven\": \"Venda\", \"vie\": \"Vietnamese\", \"vol\": \"Volapük\", \"vot\": \"Votic\", \"wak\": \"Wakashan languages\", \"wal\": \"Walamo\", \"war\": \"Waray\", \"was\": \"Washo\", \"wel\": \"Welsh\", \"wen\": \"Sorbian languages\", \"wln\": \"Walloon\", \"wol\": \"Wolof\", \"xal\": \"Kalmyk; Oirat\", \"xho\": \"Xhosa\", \"yao\": \"Yao\", \"yap\": \"Yapese\", \"yid\": \"Yiddish\", \"yor\": \"Yoruba\", \"ypk\": \"Yupik languages\", \"zap\": \"Zapotec\", \"zbl\": \"Blissymbols; Blissymbolics; Bliss\", \"zen\": \"Zenaga\", \"zgh\": \"Standard Moroccan Tamazight\", \"zha\": \"Zhuang; Chuang\", \"znd\": \"Zande languages\", \"zul\": \"Zulu\", \"zun\": \"Zuni\", \"zxx\": \"No linguistic content; Not applicable\", \"zza\": \"Zaza; Dimili; Dimli; Kirdki; Kirmanjki; Zazaki\" } end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_TVEpisode.brs.html":{"id":"components_data_TVEpisode.brs.html","title":"Source: components/data/TVEpisode.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/TVEpisode.brs import \"pkg:/source/api/Image.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" sub setFields() json = m.top.json m.top.id = json.id m.top.Title = json.name m.top.Description = json.overview m.top.favorite = json.UserData.isFavorite m.top.watched = json.UserData.played m.top.Type = json.Type setPoster() end sub sub setPoster() if m.top.image &lt;&gt; invalid m.top.posterURL = m.top.image.url else if m.top.json.ImageTags.Primary &lt;&gt; invalid imgParams = { \"maxHeight\": 440, \"maxWidth\": 295 } m.top.posterURL = ImageURL(m.top.json.id, \"Primary\", imgParams) end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_TVEpisodeData.brs.html":{"id":"components_data_TVEpisodeData.brs.html","title":"Source: components/data/TVEpisodeData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/TVEpisodeData.brs sub setFields() datum = m.top.json m.top.id = datum.id m.top.title = datum.name m.top.showID = datum.SeriesID m.top.seasonID = datum.SeasonID m.top.overview = datum.overview m.top.favorite = datum.UserData.isFavorite end sub sub setPoster() if m.top.image &lt;&gt; invalid m.top.posterURL = m.top.image.url else m.top.posterURL = \"\" end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_tvshows_TVEpisodeRow.brs.html":{"id":"components_tvshows_TVEpisodeRow.brs.html","title":"Source: components/tvshows/TVEpisodeRow.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/tvshows/TVEpisodeRow.brs sub init() m.top.itemComponentName = \"TVListDetails\" m.top.content = setData() m.top.vertFocusAnimationStyle = \"fixedFocusWrap\" m.top.showRowLabel = [false] updateSize() m.top.setFocus(true) end sub sub updateSize() m.top.translation = [450, 180] itemWidth = 1360 itemHeight = 300 m.top.visible = true ' Size of the individual rows m.top.itemSize = [itemWidth, itemHeight] ' Spacing between Rows m.top.itemSpacing = [0, 40] ' Size of items in the row m.top.rowItemSize = [itemWidth, itemHeight] ' Spacing between items in the row m.top.rowItemSpacing = [20, 0] end sub sub setupRows() updateSize() objects = m.top.objects m.top.numRows = objects.items.count() m.top.content = setData() end sub function setData() data = CreateObject(\"roSGNode\", \"ContentNode\") if m.top.objects = invalid ' Return an empty node just to return something; we'll update once we have data return data end if for each item in m.top.objects.items row = data.CreateChild(\"ContentNode\") row.appendChild(item) end for m.top.doneLoading = true return data end function function onKeyEvent(key as string, press as boolean) as boolean if not press then return false return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_tvshows_TVEpisodeRowWithOptions.brs.html":{"id":"components_tvshows_TVEpisodeRowWithOptions.brs.html","title":"Source: components/tvshows/TVEpisodeRowWithOptions.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/tvshows/TVEpisodeRowWithOptions.brs import \"pkg:/source/utils/misc.brs\" sub init() m.rows = m.top.findNode(\"tvEpisodeRow\") m.tvListOptions = m.top.findNode(\"tvListOptions\") m.rows.observeField(\"doneLoading\", \"rowsDoneLoading\") end sub sub setupRows() objects = m.top.objects m.rows.objects = objects end sub sub rowsDoneLoading() m.top.doneLoading = true end sub ' List of video versions to choose from sub SetUpVideoOptions(streams as object) videos = [] for i = 0 to streams.Count() - 1 if LCase(streams[i].VideoType) = \"videofile\" ' Create options for user to switch between video tracks videos.push({ \"Title\": streams[i].Name, \"Description\": tr(\"Video\"), \"Selected\": m.top.objects.items[m.currentSelected].selectedVideoStreamId = streams[i].id, \"StreamID\": streams[i].id, \"video_codec\": streams[i].mediaStreams[0].displayTitle }) end if end for if videos.count() &gt;= 1 options = {} options.videos = videos m.tvListOptions.options = options end if end sub ' List of audio tracks to choose from sub SetUpAudioOptions(streams as object) tracks = [] for i = 0 to streams.Count() - 1 if streams[i].Type = \"Audio\" tracks.push({ \"Title\": streams[i].displayTitle, \"Description\": streams[i].Title, \"Selected\": m.top.objects.items[m.currentSelected].selectedAudioStreamIndex = i, \"StreamIndex\": i }) end if end for if tracks.count() &gt;= 1 options = {} if isValid(m.tvListOptions.options) and isValid(m.tvListOptions.options.videos) options.videos = m.tvListOptions.options.videos end if options.audios = tracks m.tvListOptions.options = options end if end sub sub audioOptionsClosed() if m.currentSelected &lt;&gt; invalid ' If the user opened the audio options, we report back even if they left the selection alone. ' Otherwise, the users' lang peference from the server will take over. ' To do this, we interpret anything other than \"0\" as the user opened the audio options. m.top.objects.items[m.currentSelected].selectedAudioStreamIndex = m.tvListOptions.audioStreamIndex = 0 ? 1 : m.tvListOptions.audioStreamIndex end if end sub sub videoOptionsClosed() if m.tvListOptions.videoStreamId &lt;&gt; m.top.objects.items[m.currentSelected].selectedVideoStreamId m.rows.objects.items[m.currentSelected].selectedVideoStreamId = m.tvListOptions.videoStreamId end if end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false if key = \"options\" and isValid(m.rows.focusedChild) and isValid(m.rows.focusedChild.rowItemFocused) m.currentSelected = m.rows.focusedChild.rowItemFocused[0] mediaStreams = m.rows.objects.items[m.currentSelected].json.MediaStreams mediaSources = m.rows.objects.items[m.currentSelected].json.MediaSources if m.rows.objects.items[m.currentSelected].selectedVideoStreamId &lt;&gt; \"\" for each source in mediaSources if source.id = m.rows.objects.items[m.currentSelected].selectedVideoStreamId mediaStreams = source.MediaStreams exit for end if end for end if if isValid(mediaSources) SetUpVideoOptions(mediaSources) end if if isValid(mediaStreams) SetUpAudioOptions(mediaStreams) end if if isValid(m.tvListOptions.options) m.tvListOptions.visible = true m.tvListOptions.setFocus(true) end if return true else if m.tvListOptions.visible = true and key = \"back\" or key = \"options\" m.tvListOptions.setFocus(false) m.tvListOptions.visible = false m.rows.setFocus(true) videoOptionsClosed() audioOptionsClosed() return true else if key = \"up\" and m.rows.hasFocus() = false m.rows.setFocus(true) else if key = \"down\" and m.rows.hasFocus() = false m.rows.setFocus(true) end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_tvshows_TVEpisodes.brs.html":{"id":"components_tvshows_TVEpisodes.brs.html","title":"Source: components/tvshows/TVEpisodes.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/tvshows/TVEpisodes.brs import \"pkg:/source/api/Image.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/api/sdk.bs\" sub init() m.top.optionsAvailable = false m.rows = m.top.findNode(\"picker\") m.poster = m.top.findNode(\"seasonPoster\") m.shuffle = m.top.findNode(\"shuffle\") m.extras = m.top.findNode(\"extras\") m.tvEpisodeRow = m.top.findNode(\"tvEpisodeRow\") m.unplayedCount = m.top.findNode(\"unplayedCount\") m.unplayedEpisodeCount = m.top.findNode(\"unplayedEpisodeCount\") m.rows.observeField(\"doneLoading\", \"updateSeason\") end sub sub setSeasonLoading() m.top.overhangTitle = tr(\"Loading...\") end sub ' Updates the visibility of the Extras button based on if this season has any extra features sub setExtraButtonVisibility() if isValid(m.top.extrasObjects) and isValidAndNotEmpty(m.top.extrasObjects.items) m.extras.visible = true end if end sub sub updateSeason() if m.global.session.user.settings[\"ui.tvshows.disableUnwatchedEpisodeCount\"] = false if isValid(m.top.seasonData) and isValid(m.top.seasonData.UserData) and isValid(m.top.seasonData.UserData.UnplayedItemCount) if m.top.seasonData.UserData.UnplayedItemCount &gt; 0 m.unplayedCount.visible = true m.unplayedEpisodeCount.text = m.top.seasonData.UserData.UnplayedItemCount end if end if end if imgParams = { \"maxHeight\": 450, \"maxWidth\": 300 } m.poster.uri = ImageURL(m.top.seasonData.Id, \"Primary\", imgParams) m.shuffle.visible = true m.top.overhangTitle = m.top.seasonData.SeriesName + \" - \" + m.top.seasonData.name end sub ' Handle navigation input from the remote and act on it function onKeyEvent(key as string, press as boolean) as boolean handled = false if key = \"left\" and m.tvEpisodeRow.hasFocus() m.shuffle.setFocus(true) return true end if if key = \"right\" and (m.shuffle.hasFocus() or m.extras.hasFocus()) m.tvEpisodeRow.setFocus(true) return true end if if m.extras.visible and key = \"up\" and m.extras.hasFocus() m.shuffle.setFocus(true) return true end if if m.extras.visible and key = \"down\" and m.shuffle.hasFocus() m.extras.setFocus(true) return true end if if key = \"OK\" or key = \"play\" if m.shuffle.hasFocus() episodeList = m.rows.getChild(0).objects.items for i = 0 to episodeList.count() - 1 j = Rnd(episodeList.count() - 1) temp = episodeList[i] episodeList[i] = episodeList[j] episodeList[j] = temp end for m.global.queueManager.callFunc(\"set\", episodeList) m.global.queueManager.callFunc(\"playQueue\") return true end if if m.extras.visible and m.extras.hasFocus() if LCase(m.extras.text.trim()) = LCase(tr(\"Extras\")) m.extras.text = tr(\"Episodes\") m.top.objects = m.top.extrasObjects else m.extras.text = tr(\"Extras\") m.top.objects = m.top.episodeObjects end if end if end if focusedChild = m.top.focusedChild.focusedChild if focusedChild.content = invalid then return handled ' OK needs to be handled on release... proceed = false if key = \"OK\" proceed = true end if if press and key = \"play\" or proceed = true m.top.lastFocus = focusedChild itemToPlay = focusedChild.content.getChild(focusedChild.rowItemFocused[0]).getChild(0) if isValid(itemToPlay) and isValid(itemToPlay.id) and itemToPlay.id &lt;&gt; \"\" m.top.quickPlayNode = itemToPlay end if handled = true end if return handled end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_tvshows_TVListDetails.brs.html":{"id":"components_tvshows_TVListDetails.brs.html","title":"Source: components/tvshows/TVListDetails.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/tvshows/TVListDetails.brs import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/utils/config.brs\" sub init() m.title = m.top.findNode(\"title\") m.title.text = tr(\"Loading...\") m.overview = m.top.findNode(\"overview\") m.poster = m.top.findNode(\"poster\") m.rating = m.top.findnode(\"rating\") m.infoBar = m.top.findnode(\"infoBar\") m.progressBackground = m.top.findNode(\"progressBackground\") m.progressBar = m.top.findnode(\"progressBar\") m.playedIndicator = m.top.findNode(\"playedIndicator\") m.checkmark = m.top.findNode(\"checkmark\") m.checkmark.font.size = 35 m.videoCodec = m.top.findNode(\"video_codec\") end sub sub itemContentChanged() item = m.top.itemContent itemData = item.json ' Set default video source if user hasn't selected one yet if item.selectedVideoStreamId = \"\" and isValid(itemData.MediaSources) item.selectedVideoStreamId = itemData.MediaSources[0].id end if if isValid(itemData.indexNumber) indexNumber = itemData.indexNumber.toStr() + \". \" else indexNumber = \"\" end if m.title.text = indexNumber + item.title m.overview.text = item.overview if isValid(itemData.PremiereDate) airDate = CreateObject(\"roDateTime\") airDate.FromISO8601String(itemData.PremiereDate) m.top.findNode(\"aired\").text = tr(\"Aired\") + \": \" + airDate.AsDateString(\"short-month-no-weekday\") end if imageUrl = item.posterURL if m.global.session.user.settings[\"ui.tvshows.blurunwatched\"] = true if itemData.lookup(\"Type\") = \"Episode\" if not itemData.userdata.played imageUrl = imageUrl + \"&amp;blur=15\" end if end if end if m.poster.uri = imageUrl if type(itemData.RunTimeTicks) = \"roInt\" or type(itemData.RunTimeTicks) = \"LongInteger\" runTime = getRuntime() if runTime &lt; 2 m.top.findNode(\"runtime\").text = \"1 min\" else m.top.findNode(\"runtime\").text = stri(runTime).trim() + \" mins\" end if if m.global.session.user.settings[\"ui.design.hideclock\"] &lt;&gt; true m.top.findNode(\"endtime\").text = tr(\"Ends at %1\").Replace(\"%1\", getEndTime()) end if end if if m.global.session.user.settings[\"ui.tvshows.disableCommunityRating\"] = false if isValid(itemData.communityRating) m.top.findNode(\"star\").visible = true m.top.findNode(\"communityRating\").text = str(int(itemData.communityRating * 10) / 10) else m.top.findNode(\"star\").visible = false end if else m.rating.visible = false m.infoBar.itemSpacings = [20, -25, 20, 20] end if ' Add checkmark in corner (if applicable) if isValid(itemData.UserData) and isValid(itemData.UserData.Played) and itemData.UserData.Played = true m.playedIndicator.visible = true end if ' Add progress bar on bottom (if applicable) if isValid(itemData.UserData) and isValid(itemData.UserData.PlayedPercentage) and itemData.UserData.PlayedPercentage &gt; 0 m.progressBackground.width = m.poster.width m.progressBackground.visible = true progressWidthInPixels = int(m.progressBackground.width * itemData.UserData.PlayedPercentage / 100) m.progressBar.width = progressWidthInPixels m.progressBar.visible = true end if ' Display current video_codec and check if there is more than one video to choose from... m.videoCodec.visible = false if isValid(itemData.MediaSources) for i = 0 to itemData.MediaSources.Count() - 1 if item.selectedVideoStreamId = itemData.MediaSources[i].id and isValid(itemData.MediaSources[i].MediaStreams[0]) m.videoCodec.text = tr(\"Video\") + \": \" + itemData.MediaSources[i].MediaStreams[0].DisplayTitle SetupAudioDisplay(itemData.MediaSources[i].MediaStreams, item.selectedAudioStreamIndex) exit for end if end for m.videoCodec.visible = true DisplayVideoAvailable(itemData.MediaSources) end if end sub ' Display current audio_codec and check if there is more than one audio track to choose from... sub SetupAudioDisplay(mediaStreams as object, selectedAudioStreamIndex as integer) audioIdx = invalid if isValid(mediaStreams) for i = 0 to mediaStreams.Count() - 1 if LCase(mediaStreams[i].Type) = \"audio\" and audioIdx = invalid if selectedAudioStreamIndex &gt; 0 and selectedAudioStreamIndex &lt; mediaStreams.Count() audioIdx = selectedAudioStreamIndex else audioIdx = i end if m.top.findNode(\"audio_codec\").text = tr(\"Audio\") + \": \" + mediaStreams[audioIdx].DisplayTitle end if if isValid(audioIdx) then exit for end for end if if isValid(audioIdx) m.top.findNode(\"audio_codec\").visible = true DisplayAudioAvailable(mediaStreams) else m.top.findNode(\"audio_codec\").visible = false end if end sub ' Adds \"+N\" (e.g. +1) if there is more than one video version to choose from sub DisplayVideoAvailable(streams as object) count = 0 for i = 0 to streams.Count() - 1 if LCase(streams[i].VideoType) = \"videofile\" count++ end if end for if count &gt; 1 m.top.findnode(\"video_codec_count\").text = \"+\" + stri(count - 1).trim() end if end sub ' Adds \"+N\" (e.g. +1) if there is more than one audio track to choose from sub DisplayAudioAvailable(streams as object) count = 0 for i = 0 to streams.Count() - 1 if streams[i].Type = \"Audio\" count++ end if end for if count &gt; 1 m.top.findnode(\"audio_codec_count\").text = \"+\" + stri(count - 1).trim() end if end sub function getRuntime() as integer itemData = m.top.itemContent.json ' A tick is .1ms, so 1/10,000,000 for ticks to seconds, ' then 1/60 for seconds to minutess... 1/600,000,000 return int(itemData.RunTimeTicks / 600000000.0) end function function getEndTime() as string itemData = m.top.itemContent.json date = CreateObject(\"roDateTime\") duration_s = int(itemData.RunTimeTicks / 10000000.0) date.fromSeconds(date.asSeconds() + duration_s) date.toLocalTime() return formatTime(date) end function sub focusChanged() if m.top.itemHasFocus = true ' text to speech for accessibility if m.global.device.isAudioGuideEnabled = true txt2Speech = CreateObject(\"roTextToSpeech\") txt2Speech.Flush() txt2Speech.Say(m.title.text) txt2Speech.Say(m.overview.text) end if end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_tvshows_TVListOptions.brs.html":{"id":"components_tvshows_TVListOptions.brs.html","title":"Source: components/tvshows/TVListOptions.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/tvshows/TVListOptions.brs import \"pkg:/source/utils/misc.brs\" sub init() m.buttons = m.top.findNode(\"buttons\") m.buttons.buttons = [tr(\"Video\"), tr(\"Audio\")] m.buttons.selectedIndex = 0 m.buttons.setFocus(true) m.selectedItem = 0 m.selectedAudioIndex = 0 m.selectedVideoIndex = 0 m.menus = [m.top.findNode(\"videoMenu\"), m.top.findNode(\"audioMenu\")] m.videoNames = [] m.audioNames = [] ' Set button colors to global m.top.findNode(\"videoMenu\").focusBitmapBlendColor = m.global.constants.colors.button m.top.findNode(\"audioMenu\").focusBitmapBlendColor = m.global.constants.colors.button ' Animation m.fadeAnim = m.top.findNode(\"fadeAnim\") m.fadeOutAnimOpacity = m.top.findNode(\"outOpacity\") m.fadeInAnimOpacity = m.top.findNode(\"inOpacity\") m.buttons.observeField(\"focusedIndex\", \"buttonFocusChanged\") m.buttons.focusedIndex = m.selectedItem end sub sub optionsSet() ' Videos Tab if isValid(m.top.options.videos) viewContent = CreateObject(\"roSGNode\", \"ContentNode\") index = 0 selectedViewIndex = 0 for each view in m.top.options.videos entry = viewContent.CreateChild(\"VideoTrackListData\") entry.title = view.Title entry.description = view.Description entry.streamId = view.streamId entry.video_codec = view.video_codec m.videoNames.push(view.Name) if isValid(view.Selected) and view.Selected selectedViewIndex = index entry.selected = true m.top.videoStreamId = view.streamId end if index = index + 1 end for m.menus[0].content = viewContent m.menus[0].jumpToItem = selectedViewIndex m.menus[0].checkedItem = selectedViewIndex m.selectedVideoIndex = selectedViewIndex end if ' audio Tab if isValid(m.top.options.audios) audioContent = CreateObject(\"roSGNode\", \"ContentNode\") index = 0 selectedAudioIndex = 0 for each audio in m.top.options.audios entry = audioContent.CreateChild(\"AudioTrackListData\") entry.title = audio.Title entry.description = audio.Description entry.streamIndex = audio.StreamIndex m.audioNames.push(audio.Name) if isValid(audio.Selected) and audio.Selected selectedAudioIndex = index entry.selected = true m.top.audioStreamIndex = audio.streamIndex end if index = index + 1 end for m.menus[1].content = audioContent m.menus[1].jumpToItem = selectedAudioIndex m.menus[1].checkedItem = selectedAudioIndex m.selectedAudioIndex = selectedAudioIndex end if end sub ' Switch menu shown when button focus changes sub buttonFocusChanged() if m.buttons.focusedIndex = m.selectedItem then return m.fadeOutAnimOpacity.fieldToInterp = m.menus[m.selectedItem].id + \".opacity\" m.fadeInAnimOpacity.fieldToInterp = m.menus[m.buttons.focusedIndex].id + \".opacity\" m.fadeAnim.control = \"start\" m.selectedItem = m.buttons.focusedIndex end sub function onKeyEvent(key as string, press as boolean) as boolean if key = \"down\" or (key = \"OK\" and m.top.findNode(\"buttons\").hasFocus()) m.top.findNode(\"buttons\").setFocus(false) m.menus[m.selectedItem].setFocus(true) m.menus[m.selectedItem].drawFocusFeedback = true 'If user presses down from button menu, focus first item. If OK, focus checked item if key = \"down\" m.menus[m.selectedItem].jumpToItem = 0 else m.menus[m.selectedItem].jumpToItem = m.menus[m.selectedItem].itemSelected end if return true else if key = \"OK\" if m.menus[m.selectedItem].isInFocusChain() selMenu = m.menus[m.selectedItem] selIndex = selMenu.itemSelected 'Handle Videos menu if m.selectedItem = 0 if m.selectedVideoIndex &lt;&gt; selIndex selMenu.content.GetChild(m.selectedVideoIndex).selected = false newSelection = selMenu.content.GetChild(selIndex) newSelection.selected = true m.selectedVideoIndex = selIndex m.top.videoStreamId = newSelection.streamId end if ' Then it is Audio options else if m.selectedItem = 1 if m.selectedAudioIndex &lt;&gt; selIndex selMenu.content.GetChild(m.selectedAudioIndex).selected = false newSelection = selMenu.content.GetChild(selIndex) newSelection.selected = true m.selectedAudioIndex = selIndex m.top.audioStreamIndex = newSelection.streamIndex end if end if end if return true else if key = \"back\" or key = \"up\" if m.menus[m.selectedItem].isInFocusChain() m.buttons.setFocus(true) m.menus[m.selectedItem].drawFocusFeedback = false return true end if else if key = \"options\" m.menus[m.selectedItem].drawFocusFeedback = false return false end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_TVSeasonData.brs.html":{"id":"components_data_TVSeasonData.brs.html","title":"Source: components/data/TVSeasonData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/TVSeasonData.brs sub setFields() datum = m.top.json m.top.id = datum.id m.top.title = datum.name m.top.overview = datum.overview setPoster() end sub sub setPoster() if m.top.image &lt;&gt; invalid m.top.posterURL = m.top.image.url else m.top.posterURL = \"\" end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_tvshows_TVSeasonRow.brs.html":{"id":"components_tvshows_TVSeasonRow.brs.html","title":"Source: components/tvshows/TVSeasonRow.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/tvshows/TVSeasonRow.brs sub init() m.top.itemComponentName = \"ListPoster\" m.top.content = getData() m.top.rowFocusAnimationStyle = \"fixedFocusWrap\" m.top.showRowLabel = [false] m.top.showRowCounter = [true] m.top.rowLabelOffset = [0, 0] updateSize() m.top.setfocus(true) end sub sub updateSize() itemWidth = 200 itemHeight = 320 ' width * 1.5 + text m.top.visible = true ' size of the whole row m.top.itemSize = [1680, (itemHeight + 40)] ' spacing between rows m.top.itemSpacing = [0, 0] ' size of the item in the row m.top.rowItemSize = [itemWidth, itemHeight] ' spacing between items in a row m.top.rowItemSpacing = [0, 0] end sub function getData() if m.top.TVSeasonData = invalid data = CreateObject(\"roSGNode\", \"ContentNode\") return data end if seasonData = m.top.TVSeasonData data = CreateObject(\"roSGNode\", \"ContentNode\") row = data.CreateChild(\"ContentNode\") row.title = \"Seasons\" for each item in seasonData.items row.appendChild(item) end for m.top.content = data return data end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_tvshows_TVShowDescription.brs.html":{"id":"components_tvshows_TVShowDescription.brs.html","title":"Source: components/tvshows/TVShowDescription.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/tvshows/TVShowDescription.brs import \"pkg:/source/utils/misc.brs\" sub init() buttons = m.top.findNode(\"buttons\") buttons.iconUri = \"\" for each button in buttons.getChildren(-1, 0) button.maxWidth = 350 button.minWidth = 350 end for end sub sub itemContentChanged() ' Updates video metadata ' TODO - make things use item rather than itemData item = m.top.itemContent itemData = item.json m.top.findNode(\"tvshowPoster\").uri = m.top.itemContent.posterURL ' Handle all \"As Is\" fields setFieldText(\"title\", itemData.name) setFieldText(\"releaseYear\", itemData.productionYear) setFieldText(\"officialRating\", itemData.officialRating) setFieldText(\"communityRating\", str(itemData.communityRating)) setFieldText(\"overview\", itemData.overview) if type(itemData.RunTimeTicks) = \"LongInteger\" setFieldText(\"runtime\", stri(getRuntime()) + \" mins\") end if setFieldText(\"history\", getHistory()) if itemData.genres.count() &gt; 0 setFieldText(\"genres\", itemData.genres.join(\", \")) end if for each person in itemData.people if person.type = \"Director\" exit for end if end for if itemData.taglines.count() &gt; 0 setFieldText(\"tagline\", itemData.taglines[0]) end if end sub sub setFieldText(field, value) node = m.top.findNode(field) if node = invalid or value = invalid then return ' Handle non strings... Which _shouldn't_ happen, but hey if type(value) = \"roInt\" or type(value) = \"Integer\" value = str(value) else if type(value) &lt;&gt; \"roString\" and type(value) &lt;&gt; \"String\" value = \"\" end if node.text = value end sub function getRuntime() as integer itemData = m.top.itemContent.json ' A tick is .1ms, so 1/10,000,000 for ticks to seconds, ' then 1/60 for seconds to minutess... 1/600,000,000 return round(itemData.RunTimeTicks / 600000000.0) end function function getEndTime() as string itemData = m.top.itemContent.json date = CreateObject(\"roDateTime\") duration_s = int(itemData.RunTimeTicks / 10000000.0) date.fromSeconds(date.asSeconds() + duration_s) date.toLocalTime() return formatTime(date) end function function getHistory() as string itemData = m.top.itemContent.json ' Aired Fridays at 9:30 PM on ABC (US) airwords = invalid studio = invalid if itemData.status = \"Ended\" verb = \"Aired\" else verb = \"Airs\" end if airdays = itemData.airdays airtime = itemData.airtime if airtime &lt;&gt; invalid and airdays.count() = 1 airwords = airdays[0] + \" at \" + airtime end if if itemData.studios.count() &gt; 0 studio = itemData.studios[0].name end if if studio = invalid and airwords = invalid return \"\" end if words = verb if airwords &lt;&gt; invalid words = words + \" \" + airwords end if if studio &lt;&gt; invalid words = words + \" on \" + studio end if return words end function function round(f as float) as integer ' BrightScript only has a \"floor\" round ' This compares floor to floor + 1 to find which is closer m = int(f) n = m + 1 x = abs(f - m) y = abs(f - n) if y &gt; x return m else return n end if end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_tvshows_TVShowDetails.brs.html":{"id":"components_tvshows_TVShowDetails.brs.html","title":"Source: components/tvshows/TVShowDetails.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/tvshows/TVShowDetails.brs import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/utils/config.brs\" sub init() m.top.optionsAvailable = false main = m.top.findNode(\"toplevel\") main.translation = [96, 175] m.extrasSlider = m.top.findNode(\"tvSeasonExtras\") m.unplayedCount = m.top.findNode(\"unplayedCount\") m.unplayedEpisodeCount = m.top.findNode(\"unplayedEpisodeCount\") m.getShuffleEpisodesTask = createObject(\"roSGNode\", \"getShuffleEpisodesTask\") m.Shuffle = m.top.findNode(\"Shuffle\") m.extrasSlider.visible = true m.seasons = m.top.findNode(\"seasons\") end sub sub itemContentChanged() ' Updates video metadata ' TODO - make things use item rather than itemData item = m.top.itemContent itemData = item.json if m.global.session.user.settings[\"ui.tvshows.disableUnwatchedEpisodeCount\"] = false if isValid(itemData.UserData) and isValid(itemData.UserData.UnplayedItemCount) if itemData.UserData.UnplayedItemCount &gt; 0 m.unplayedCount.visible = true m.unplayedEpisodeCount.text = itemData.UserData.UnplayedItemCount end if end if end if m.top.findNode(\"tvshowPoster\").uri = m.top.itemContent.posterURL ' Handle all \"As Is\" fields m.top.overhangTitle = itemData.name 'Check production year, if invalid remove label if isValid(itemData.productionYear) setFieldText(\"releaseYear\", itemData.productionYear) else m.top.findNode(\"main_group\").removeChild(m.top.findNode(\"releaseYear\")) end if 'Check officialRating, if invalid remove label if isValid(itemData.officialRating) setFieldText(\"officialRating\", itemData.officialRating) else m.top.findNode(\"main_group\").removeChild(m.top.findNode(\"officialRating\")) end if 'Check communityRating, if invalid remove label if isValid(itemData.communityRating) m.top.findNode(\"star\").visible = true setFieldText(\"communityRating\", int(itemData.communityRating * 10) / 10) else m.top.findNode(\"main_group\").removeChild(m.top.findNode(\"communityRating\")) m.top.findNode(\"main_group\").removeChild(m.top.findNode(\"star\")) m.top.findNode(\"star\").visible = false end if setFieldText(\"overview\", itemData.overview) m.Shuffle.visible = true if type(itemData.RunTimeTicks) = \"LongInteger\" setFieldText(\"runtime\", stri(getRuntime()) + \" mins\") end if 'History feild is set via the function getHistory() setFieldText(\"history\", getHistory()) 'Check genres, if invalid remove label if itemData.genres.count() &gt; 0 setFieldText(\"genres\", itemData.genres.join(\", \")) else m.top.findNode(\"main_group\").removeChild(m.top.findNode(\"genres\")) end if 'We don't display Directors in the show page. Might want to remove this. for each person in itemData.people if person.type = \"Director\" exit for end if end for if itemData.taglines.count() &gt; 0 setFieldText(\"tagline\", itemData.taglines[0]) else m.top.findNode(\"main_group\").removeChild(m.top.findNode(\"tagline\")) end if end sub sub setFieldText(field, value) node = m.top.findNode(field) if node = invalid or value = invalid then return ' Handle non strings... Which _shouldn't_ happen, but hey if type(value) = \"roInt\" or type(value) = \"Integer\" value = str(value).trim() else if type(value) = \"roFloat\" or type(value) = \"Float\" value = str(value).trim() else if type(value) &lt;&gt; \"roString\" and type(value) &lt;&gt; \"String\" value = \"\" end if node.text = value end sub function getRuntime() as integer itemData = m.top.itemContent.json ' A tick is .1ms, so 1/10,000,000 for ticks to seconds, ' then 1/60 for seconds to minutess... 1/600,000,000 return round(itemData.RunTimeTicks / 600000000.0) end function function getEndTime() as string itemData = m.top.itemContent.json date = CreateObject(\"roDateTime\") duration_s = int(itemData.RunTimeTicks / 10000000.0) date.fromSeconds(date.asSeconds() + duration_s) date.toLocalTime() return formatTime(date) end function function getHistory() as string itemData = m.top.itemContent.json ' Aired Fridays at 9:30 PM on ABC (US) airwords = invalid studio = invalid if itemData.status = \"Ended\" verb = \"Aired\" else verb = \"Airs\" end if airdays = itemData.airdays airtime = itemData.airtime if isValid(airtime) and airdays.count() = 1 airwords = airdays[0] + \" at \" + airtime end if if itemData.studios.count() &gt; 0 studio = itemData.studios[0].name end if if studio = invalid and airwords = invalid m.top.findNode(\"main_group\").removeChild(m.top.findNode(\"history\")) return \"\" end if words = verb if isValid(airwords) words = words + \" \" + airwords end if if isValid(studio) words = words + \" on \" + studio end if return words end function function round(f as float) as integer ' BrightScript only has a \"floor\" round ' This compares floor to floor + 1 to find which is closer m = int(f) n = m + 1 x = abs(f - m) y = abs(f - n) if y &gt; x return m else return n end if end function sub onShuffleEpisodeDataLoaded() m.getShuffleEpisodesTask.unobserveField(\"data\") m.global.queueManager.callFunc(\"set\", m.getShuffleEpisodesTask.data.items) m.global.queueManager.callFunc(\"playQueue\") end sub function onKeyEvent(key as string, press as boolean) as boolean if key = \"OK\" or key = \"play\" if m.Shuffle.hasFocus() m.getShuffleEpisodesTask.showID = m.top.itemContent.id m.getShuffleEpisodesTask.observeField(\"data\", \"onShuffleEpisodeDataLoaded\") m.getShuffleEpisodesTask.control = \"RUN\" return true end if end if if not press then return false overview = m.top.findNode(\"overview\") topGrp = m.top.findNode(\"seasons\") bottomGrp = m.top.findNode(\"extrasGrid\") if key = \"down\" and overview.hasFocus() m.Shuffle.setFocus(true) return true else if key = \"down\" and m.Shuffle.hasFocus() topGrp.setFocus(true) return true else if key = \"down\" and topGrp.hasFocus() bottomGrp.setFocus(true) m.top.findNode(\"VertSlider\").reverse = false m.top.findNode(\"extrasFader\").reverse = false m.top.findNode(\"pplAnime\").control = \"start\" return true else if key = \"up\" and bottomGrp.hasFocus() if bottomGrp.itemFocused = 0 m.top.findNode(\"VertSlider\").reverse = true m.top.findNode(\"extrasFader\").reverse = true m.top.findNode(\"pplAnime\").control = \"start\" topGrp.setFocus(true) return true end if else if key = \"up\" and topGrp.hasFocus() m.Shuffle.setFocus(true) return true else if key = \"up\" and m.Shuffle.hasFocus() overview.setFocus(true) return true else if key = \"play\" and m.seasons.hasFocus() print \"play was pressed from the seasons row\" if isValid(m.seasons.TVSeasonData) and isValid(m.seasons.TVSeasonData.Items) itemFocused = m.seasons.rowItemFocused m.top.quickPlayNode = m.seasons.TVSeasonData.Items[itemFocused[1]] return true end if else if key = \"play\" and m.extrasSlider.isInFocusChain() print \"play was pressed from the extras grid\" extrasGrid = m.top.findNode(\"extrasGrid\") if extrasGrid.focusedItem &lt;&gt; invalid m.top.quickPlayNode = extrasGrid.focusedItem return true end if end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_Buttons_TextSizeTask.brs.html":{"id":"components_Buttons_TextSizeTask.brs.html","title":"Source: components/Buttons/TextSizeTask.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/Buttons/TextSizeTask.brs sub init() m.top.functionName = \"getTextSize\" end sub sub getTextSize() reg = CreateObject(\"roFontRegistry\") font = reg.GetDefaultFont(m.top.fontsize, false, false) res = [] for each line in m.top.text res.push(font.GetOneLineWidth(line, m.top.maxWidth)) end for m.top.height = font.GetOneLineHeight() m.top.width = res end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_UserData.brs.html":{"id":"components_data_UserData.brs.html","title":"Source: components/data/UserData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/UserData.brs import \"pkg:/source/utils/config.brs\" sub setDataFromJSON() json = m.top.json loadFromJSON(json) end sub sub loadFromJSON(json) m.top.id = json.User.id m.top.username = json.User.name m.top.token = json.AccessToken end sub sub loadFromRegistry(id as string) m.top.id = id m.top.username = get_user_setting(\"username\") m.top.token = get_user_setting(\"token\") end sub sub saveToRegistry() users = parseJson(get_setting(\"available_users\", \"[]\")) this_user = invalid for each user in users if user.id = m.top.id then this_user = user end for if this_user = invalid users.push({ id: m.top.id, username: m.top.username, server: m.global.session.server.url }) set_setting(\"available_users\", formatJson(users)) end if end sub sub removeFromRegistry() new_users = [] users = parseJson(get_setting(\"available_users\", \"[]\")) for each user in users if m.top.id &lt;&gt; user.id then new_users.push(user) end for set_setting(\"available_users\", formatJson(new_users)) end sub function getPreference(key as string) return get_user_setting(\"pref-\" + key) end function function setPreference(key as string, value as string) return set_user_setting(\"pref-\" + key, value) end function sub setActive() if m.global.session.user.settings[\"global.rememberme\"] set_setting(\"active_user\", m.top.id) end if end sub sub setServer(hostname as string) m.top.server = hostname end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_login_UserItem.brs.html":{"id":"components_login_UserItem.brs.html","title":"Source: components/login/UserItem.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/login/UserItem.brs sub init() end sub sub itemContentChanged() itemData = m.top.itemContent if itemData = invalid then return profileImage = m.top.findNode(\"profileImage\") profileName = m.top.findNode(\"profileName\") if itemData.imageURL = \"\" profileImage.uri = \"pkg://images/baseline_person_white_48dp.png\" else profileImage.uri = itemData.imageURL end if profileName.text = itemData.name end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"source_api_UserLibrary.brs.html":{"id":"source_api_UserLibrary.brs.html","title":"Source: source/api/UserLibrary.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: source/api/UserLibrary.brs function MarkItemFavorite(id as string) url = Substitute(\"Users/{0}/FavoriteItems/{1}\", m.global.session.user.id, id) resp = APIRequest(url) return postJson(resp) end function function UnmarkItemFavorite(id as string) url = Substitute(\"Users/{0}/FavoriteItems/{1}\", m.global.session.user.id, id) resp = APIRequest(url) resp.setRequest(\"DELETE\") return getJson(resp) end function sub MarkItemWatched(id as string) date = CreateObject(\"roDateTime\") dateStr = date.ToISOString() url = Substitute(\"Users/{0}/PlayedItems/{1}\", m.global.session.user.id, id) req = APIRequest(url) postVoid(req, FormatJson({ \"DatePlayed\": dateStr })) end sub function UnmarkItemWatched(id as string) url = Substitute(\"Users/{0}/PlayedItems/{1}\", m.global.session.user.id, id) resp = APIRequest(url) resp.setRequest(\"DELETE\") return getJson(resp) end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_login_UserRow.brs.html":{"id":"components_login_UserRow.brs.html","title":"Source: components/login/UserRow.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/login/UserRow.brs sub init() m.top.itemComponentName = \"UserItem\" m.top.content = SetData() m.top.observeField(\"itemSelected\", \"SetUser\") m.top.showRowLabel = [false] updateSize() m.top.setFocus(true) end sub sub updateSize() itemWidth = 300 itemHeight = 364 m.top.visible = true ' Size of the individual rows m.top.itemSize = [1660, itemHeight] ' Spacing between Rows m.top.itemSpacing = [0, 40] ' Size of items in the row m.top.rowItemSize = [itemWidth, itemHeight] ' Spacing between items in the row m.top.rowItemSpacing = [40, 0] end sub function setData() if m.top.itemContent = invalid data = CreateObject(\"roSGNode\", \"ContentNode\") return data end if userData = m.top.itemContent data = CreateObject(\"roSGNode\", \"ContentNode\") row = data.CreateChild(\"ContentNode\") for each item in userData row.appendChild(item) end for m.top.content = data updateSize() return data end function sub setUser() m.top.userSelected = m.top.itemContent[m.top.rowItemFocused[1]].Name end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_login_UserSelect.brs.html":{"id":"components_login_UserSelect.brs.html","title":"Source: components/login/UserSelect.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/login/UserSelect.brs sub init() m.top.optionsAvailable = false end sub sub itemContentChanged() m.top.findNode(\"UserRow\").ItemContent = m.top.itemContent redraw() end sub sub redraw() userCount = m.top.itemContent.Count() topBorder = 360 leftBorder = 130 itemWidth = 300 itemSpacing = 40 if userCount &lt; 5 leftBorder = (1920 - ((userCount * itemWidth) + ((userCount - 1) * itemSpacing))) / 2 end if ' break() m.top.findNode(\"UserRow\").translation = [leftBorder, topBorder] end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false if key = \"back\" m.top.backPressed = true else if key = \"up\" if m.top.focusedChild.isSubType(\"LabelList\") m.top.findNode(\"UserRow\").setFocus(true) return true end if else if key = \"down\" if m.top.focusedChild.isSubType(\"UserRow\") m.top.findNode(\"alternateOptions\").setFocus(true) return true end if end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_data_VideoData.brs.html":{"id":"components_data_VideoData.brs.html","title":"Source: components/data/VideoData.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/data/VideoData.brs import \"pkg:/source/api/Image.brs\" import \"pkg:/source/api/baserequest.brs\" import \"pkg:/source/utils/config.brs\" sub setFields() json = m.top.json m.top.id = json.id m.top.Title = json.name m.top.Description = json.overview m.top.favorite = json.UserData.isFavorite m.top.watched = json.UserData.played m.top.Type = \"Video\" setPoster() end sub sub setPoster() if m.top.image &lt;&gt; invalid m.top.posterURL = m.top.image.url else if m.top.json.ImageTags.Primary &lt;&gt; invalid imgParams = { \"maxHeight\": 440, \"maxWidth\": 295, \"Tag\": m.top.json.ImageTags.Primary } m.top.posterURL = ImageURL(m.top.json.id, \"Primary\", imgParams) end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"source_VideoPlayer.brs.html":{"id":"source_VideoPlayer.brs.html","title":"Source: source/VideoPlayer.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: source/VideoPlayer.brs function VideoPlayer(id as string, mediaSourceId = invalid as dynamic, audio_stream_idx = 1 as integer, subtitle_idx = -1 as integer, forceTranscoding = false as boolean, showIntro = true as boolean, allowResumeDialog = true as boolean) as dynamic ' Get video controls and UI video = CreateObject(\"roSGNode\", \"JFVideo\") video.id = id AddVideoContent(video, mediaSourceId, audio_stream_idx, subtitle_idx, -1, forceTranscoding, showIntro, allowResumeDialog) if video.errorMsg = \"introaborted\" return video end if if video.content = invalid stopLoadingSpinner() return invalid end if jellyfin_blue = \"#00a4dcFF\" video.retrievingBar.filledBarBlendColor = jellyfin_blue video.bufferingBar.filledBarBlendColor = jellyfin_blue video.trickPlayBar.filledBarBlendColor = jellyfin_blue return video end function sub AddVideoContent(video as object, mediaSourceId as dynamic, audio_stream_idx = 1 as integer, subtitle_idx = -1 as integer, playbackPosition = -1 as integer, forceTranscoding = false as boolean, showIntro = true as boolean, allowResumeDialog = true as boolean) video.content = createObject(\"RoSGNode\", \"ContentNode\") meta = ItemMetaData(video.id) if meta = invalid video.content = invalid return end if m.videotype = meta.type ' Special handling for \"Programs\" or \"Vidoes\" launched from \"On Now\" or elsewhere on the home screen... ' basically anything that is a Live Channel. if isValid(meta.json) and isValid(meta.json.ChannelId) if isValid(meta.json.EpisodeTitle) meta.title = meta.json.EpisodeTitle else if isValid(meta.json.Name) meta.title = meta.json.Name end if meta.showID = meta.json.id meta.live = true if meta.json.type = \"Program\" video.id = meta.json.ChannelId else video.id = meta.json.id end if end if if m.videotype = \"Episode\" or m.videotype = \"Series\" video.content.contenttype = \"episode\" end if video.content.title = meta.title video.showID = meta.showID if playbackPosition = -1 and isValid(meta.json) playbackPosition = meta.json.UserData.PlaybackPositionTicks if allowResumeDialog if playbackPosition &gt; 0 stopLoadingSpinner() dialogResult = startPlayBackOver(playbackPosition) startMediaLoadingSpinner() 'Dialog returns -1 when back pressed, 0 for resume, and 1 for start over if dialogResult = -1 'User pressed back, return invalid and don't load video video.content = invalid return else if dialogResult = 1 'Start Over selected, change position to 0 playbackPosition = 0 else if dialogResult = 2 'Mark this item as watched, refresh the page, and return invalid so we don't load the video MarkItemWatched(video.id) video.content.watched = not video.content.watched group = m.scene.focusedChild group.timeLastRefresh = CreateObject(\"roDateTime\").AsSeconds() group.callFunc(\"refresh\") video.content = invalid return else if dialogResult = 3 'get series ID based off episiode ID params = { ids: video.Id } url = Substitute(\"Users/{0}/Items/\", m.global.session.user.id) resp = APIRequest(url, params) data = getJson(resp) for each item in data.Items m.series_id = item.SeriesId end for 'Get series json data params = { ids: m.series_id } url = Substitute(\"Users/{0}/Items/\", m.global.session.user.id) resp = APIRequest(url, params) data = getJson(resp) for each item in data.Items m.tmp = item end for stopLoadingSpinner() 'Create Series Scene CreateSeriesDetailsGroup(m.tmp) video.content = invalid return else if dialogResult = 4 'get Season/Series ID based off episiode ID params = { ids: video.Id } url = Substitute(\"Users/{0}/Items/\", m.global.session.user.id) resp = APIRequest(url, params) data = getJson(resp) for each item in data.Items m.season_id = item.SeasonId m.series_id = item.SeriesId end for 'Get Series json data params = { ids: m.season_id } url = Substitute(\"Users/{0}/Items/\", m.global.session.user.id) resp = APIRequest(url, params) data = getJson(resp) for each item in data.Items m.Season_tmp = item end for 'Get Season json data params = { ids: m.series_id } url = Substitute(\"Users/{0}/Items/\", m.global.session.user.id) resp = APIRequest(url, params) data = getJson(resp) for each item in data.Items m.Series_tmp = item end for stopLoadingSpinner() 'Create Season Scene CreateSeasonDetailsGroup(m.Series_tmp, m.Season_tmp) video.content = invalid return else if dialogResult = 5 'get episiode ID params = { ids: video.Id } url = Substitute(\"Users/{0}/Items/\", m.global.session.user.id) resp = APIRequest(url, params) data = getJson(resp) for each item in data.Items m.episode_id = item end for stopLoadingSpinner() 'Create Episode Scene CreateMovieDetailsGroup(m.episode_id) video.content = invalid return end if end if end if end if ' Don't attempt to play an intro for an intro video if showIntro ' Do not play intros when resuming playback if playbackPosition = 0 if not PlayIntroVideo(video.id, audio_stream_idx) video.errorMsg = \"introaborted\" return end if end if end if video.content.PlayStart = int(playbackPosition / 10000000) ' Call PlayInfo from server if mediaSourceId = invalid mediaSourceId = video.id end if ' Don't send mediaSourceId for Live Media ' Note: Recordings in progress will have meta.live = invalid, but we still don't want to send mediaSourceId if not isValid(meta.live) meta.live = false mediaSourceId = \"\" else if meta.live mediaSourceId = \"\" end if end if m.playbackInfo = ItemPostPlaybackInfo(video.id, mediaSourceId, audio_stream_idx, subtitle_idx, playbackPosition) video.videoId = video.id video.mediaSourceId = mediaSourceId video.audioIndex = audio_stream_idx if m.playbackInfo = invalid video.content = invalid return end if params = {} video.PlaySessionId = m.playbackInfo.PlaySessionId if meta.live video.content.live = true video.content.StreamFormat = \"hls\" end if video.container = getContainerType(meta) if not isValid(m.playbackInfo.MediaSources[0]) and isValid(meta.json) m.playbackInfo = meta.json end if subtitles = sortSubtitles(meta.id, m.playbackInfo.MediaSources[0].MediaStreams) if m.global.session.user.settings[\"playback.subs.onlytext\"] = true safesubs = [] for each subtitle in subtitles[\"all\"] if subtitle[\"IsTextSubtitleStream\"] safesubs.push(subtitle) end if end for video.Subtitles = safesubs else video.Subtitles = subtitles[\"all\"] end if if meta.live video.transcodeParams = { \"MediaSourceId\": m.playbackInfo.MediaSources[0].Id, \"LiveStreamId\": m.playbackInfo.MediaSources[0].LiveStreamId, \"PlaySessionId\": video.PlaySessionId } end if video.content.SubtitleTracks = subtitles[\"text\"] ' 'TODO: allow user selection of subtitle track before playback initiated, for now set to no subtitles video.directPlaySupported = m.playbackInfo.MediaSources[0].SupportsDirectPlay fully_external = false ' For h264/hevc video, Roku spec states that it supports specfic encoding levels ' The device can decode content with a Higher Encoding level but may play it back with certain ' artifacts. If the user preference is set, and the only reason the server says we need to ' transcode is that the Encoding Level is not supported, then try to direct play but silently ' fall back to the transcode if that fails. if m.playbackInfo.MediaSources[0].MediaStreams.Count() &gt; 0 and meta.live = false tryDirectPlay = m.global.session.user.settings[\"playback.tryDirect.h264ProfileLevel\"] = true and m.playbackInfo.MediaSources[0].MediaStreams[0].codec = \"h264\" tryDirectPlay = tryDirectPlay or (m.global.session.user.settings[\"playback.tryDirect.hevcProfileLevel\"] = true and m.playbackInfo.MediaSources[0].MediaStreams[0].codec = \"hevc\") if tryDirectPlay and isValid(m.playbackInfo.MediaSources[0].TranscodingUrl) and forceTranscoding = false transcodingReasons = getTranscodeReasons(m.playbackInfo.MediaSources[0].TranscodingUrl) if transcodingReasons.Count() = 1 and transcodingReasons[0] = \"VideoLevelNotSupported\" video.directPlaySupported = true video.transcodeAvailable = true end if end if end if if video.directPlaySupported protocol = LCase(m.playbackInfo.MediaSources[0].Protocol) if protocol &lt;&gt; \"file\" uri = parseUrl(m.playbackInfo.MediaSources[0].Path) if isLocalhost(uri[2]) ' the domain of the URI is local to the server. ' create a new URI by appending the received path to the server URL ' later we will substitute the users provided URL for this case video.content.url = buildURL(uri[4]) else fully_external = true video.content.url = m.playbackInfo.MediaSources[0].Path end if else: params.append({ \"Static\": \"true\", \"Container\": video.container, \"PlaySessionId\": video.PlaySessionId, \"AudioStreamIndex\": audio_stream_idx }) if mediaSourceId &lt;&gt; \"\" params.MediaSourceId = mediaSourceId end if video.content.url = buildURL(Substitute(\"Videos/{0}/stream\", video.id), params) end if video.isTranscoded = false else if m.playbackInfo.MediaSources[0].TranscodingUrl = invalid ' If server does not provide a transcode URL, display a message to the user m.global.sceneManager.callFunc(\"userMessage\", tr(\"Error Getting Playback Information\"), tr(\"An error was encountered while playing this item. Server did not provide required transcoding data.\")) video.content = invalid return end if ' Get transcoding reason video.transcodeReasons = getTranscodeReasons(m.playbackInfo.MediaSources[0].TranscodingUrl) video.content.url = buildURL(m.playbackInfo.MediaSources[0].TranscodingUrl) video.isTranscoded = true end if setCertificateAuthority(video.content) video.audioTrack = (audio_stream_idx + 1).ToStr() ' Roku's track indexes count from 1. Our index is zero based ' Perform relevant setup work for selected subtitle, and return the index of the subtitle ' is enabled/will be enabled, indexed on the provided list of subtitles video.SelectedSubtitle = setupSubtitle(video, video.Subtitles, subtitle_idx) if not fully_external video.content = authRequest(video.content) end if end sub function PlayIntroVideo(video_id, audio_stream_idx) as boolean ' Intro videos only play if user has cinema mode setting enabled if m.global.session.user.settings[\"playback.cinemamode\"] = true ' Check if server has intro videos setup and available introVideos = GetIntroVideos(video_id) if introVideos = invalid then return true if introVideos.TotalRecordCount &gt; 0 ' Bypass joke pre-roll if lcase(introVideos.items[0].name) = \"rick roll'd\" then return true introVideo = VideoPlayer(introVideos.items[0].id, introVideos.items[0].id, audio_stream_idx, defaultSubtitleTrackFromVid(video_id), false, false) if isValid(introVideo) introVideo.allowCaptions = false end if port = CreateObject(\"roMessagePort\") introVideo.observeField(\"state\", port) m.global.sceneManager.callFunc(\"pushScene\", introVideo) introPlaying = true stopLoadingSpinner() while introPlaying msg = wait(0, port) if type(msg) = \"roSGNodeEvent\" if msg.GetData() = \"finished\" m.global.sceneManager.callFunc(\"clearPreviousScene\") introPlaying = false else if msg.GetData() = \"stopped\" introPlaying = false return false end if end if end while end if end if return true end function ' ' Extract array of Transcode Reasons from the content URL ' @returns Array of Strings function getTranscodeReasons(url as string) as object regex = CreateObject(\"roRegex\", \"&amp;TranscodeReasons=([^&amp;]*)\", \"\") match = regex.Match(url) if match.count() &gt; 1 return match[1].Split(\",\") end if return [] end function 'Opens dialog asking user if they want to resume video or start playback over only on the home screen function startPlayBackOver(time as longinteger) as integer if m.scene.focusedChild.focusedChild.overhangTitle = tr(\"Home\") and (m.videotype = \"Episode\" or m.videotype = \"Series\") return option_dialog([tr(\"Resume playing at \") + ticksToHuman(time) + \".\", tr(\"Start over from the beginning.\"), tr(\"Watched\"), tr(\"Go to series\"), tr(\"Go to season\"), tr(\"Go to episode\")]) else return option_dialog([\"Resume playing at \" + ticksToHuman(time) + \".\", \"Start over from the beginning.\"]) end if end function function directPlaySupported(meta as object) as boolean devinfo = CreateObject(\"roDeviceInfo\") if isValid(meta.json.MediaSources[0]) and meta.json.MediaSources[0].SupportsDirectPlay = false return false end if if not isValid(meta.json.MediaSources[0]) return false end if streamInfo = { Codec: meta.json.MediaStreams[0].codec } if isValid(meta.json.MediaStreams[0].Profile) and meta.json.MediaStreams[0].Profile.len() &gt; 0 streamInfo.Profile = LCase(meta.json.MediaStreams[0].Profile) end if if isValid(meta.json.MediaSources[0].container) and meta.json.MediaSources[0].container.len() &gt; 0 'CanDecodeVideo() requires the .container to be format: “mp4”, “hls”, “mkv”, “ism”, “dash”, “ts” if its to direct stream if meta.json.MediaSources[0].container = \"mov\" streamInfo.Container = \"mp4\" else streamInfo.Container = meta.json.MediaSources[0].container end if end if decodeResult = devinfo.CanDecodeVideo(streamInfo) return isValid(decodeResult) and decodeResult.result end function function getContainerType(meta as object) as string ' Determine the file type of the video file source if not IsValid(meta.json) or not isValid(meta.json.mediaSources) then return \"\" container = meta.json.mediaSources[0].container if container = invalid container = \"\" else if container = \"m4v\" or container = \"mov\" container = \"mp4\" end if return container end function function getAudioFormat(meta as object) as string ' Determine the codec of the audio file source if meta.json.mediaSources = invalid then return \"\" audioInfo = getAudioInfo(meta) if audioInfo.count() = 0 or audioInfo[0].codec = invalid then return \"\" return audioInfo[0].codec end function function getAudioInfo(meta as object) as object ' Return audio metadata for a given stream results = [] for each source in meta.json.mediaSources[0].mediaStreams if source[\"type\"] = \"Audio\" results.push(source) end if end for return results end function sub autoPlayNextEpisode(videoID as string, showID as string) ' use web client setting if m.global.session.user.configuration.EnableNextEpisodeAutoPlay ' query API for next episode ID url = Substitute(\"Shows/{0}/Episodes\", showID) urlParams = { \"UserId\": m.global.session.user.id } urlParams.Append({ \"StartItemId\": videoID }) urlParams.Append({ \"Limit\": 2 }) resp = APIRequest(url, urlParams) data = getJson(resp) if isValid(data) and data.Items.Count() = 2 ' setup new video node nextVideo = CreateVideoPlayerGroup(data.Items[1].Id, invalid, 1, false, false) ' remove last videoplayer scene m.global.sceneManager.callFunc(\"clearPreviousScene\") if isValid(nextVideo) m.global.sceneManager.callFunc(\"pushScene\", nextVideo) else m.global.sceneManager.callFunc(\"popScene\") end if else ' can't play next episode m.global.sceneManager.callFunc(\"popScene\") end if else m.global.sceneManager.callFunc(\"popScene\") end if end sub ' Returns an array of playback info to be displayed during playback. ' In the future, with a custom playback info view, we can return an associated array. function GetPlaybackInfo() sessions = api.sessions.Get({ \"deviceId\": m.global.device.serverDeviceName }) if isValid(sessions) and sessions.Count() &gt; 0 return GetTranscodingStats(sessions[0]) end if errMsg = tr(\"Unable to get playback information\") return [errMsg] end function function GetTranscodingStats(deviceSession) sessionStats = [] if isValid(deviceSession.TranscodingInfo) and deviceSession.TranscodingInfo.Count() &gt; 0 transcodingReasons = deviceSession.TranscodingInfo.TranscodeReasons videoCodec = deviceSession.TranscodingInfo.VideoCodec audioCodec = deviceSession.TranscodingInfo.AudioCodec totalBitrate = deviceSession.TranscodingInfo.Bitrate audioChannels = deviceSession.TranscodingInfo.AudioChannels if isValid(transcodingReasons) and transcodingReasons.Count() &gt; 0 sessionStats.push(\"** \" + tr(\"Transcoding Information\") + \" **\") for each item in transcodingReasons sessionStats.push(tr(\"Reason\") + \": \" + item) end for end if if isValid(videoCodec) data = tr(\"Video Codec\") + \": \" + videoCodec if deviceSession.TranscodingInfo.IsVideoDirect data = data + \" (\" + tr(\"direct\") + \")\" end if sessionStats.push(data) end if if isValid(audioCodec) data = tr(\"Audio Codec\") + \": \" + audioCodec if deviceSession.TranscodingInfo.IsAudioDirect data = data + \" (\" + tr(\"direct\") + \")\" end if sessionStats.push(data) end if if isValid(totalBitrate) data = tr(\"Total Bitrate\") + \": \" + getDisplayBitrate(totalBitrate) sessionStats.push(data) end if if isValid(audioChannels) data = tr(\"Audio Channels\") + \": \" + Str(audioChannels) sessionStats.push(data) end if end if if havePlaybackInfo() stream = m.playbackInfo.mediaSources[0].MediaStreams[0] sessionStats.push(\"** \" + tr(\"Stream Information\") + \" **\") if isValid(stream.Container) data = tr(\"Container\") + \": \" + stream.Container sessionStats.push(data) end if if isValid(stream.Size) data = tr(\"Size\") + \": \" + stream.Size sessionStats.push(data) end if if isValid(stream.BitRate) data = tr(\"Bit Rate\") + \": \" + getDisplayBitrate(stream.BitRate) sessionStats.push(data) end if if isValid(stream.Codec) data = tr(\"Codec\") + \": \" + stream.Codec sessionStats.push(data) end if if isValid(stream.CodecTag) data = tr(\"Codec Tag\") + \": \" + stream.CodecTag sessionStats.push(data) end if if isValid(stream.VideoRangeType) data = tr(\"Video range type\") + \": \" + stream.VideoRangeType sessionStats.push(data) end if if isValid(stream.PixelFormat) data = tr(\"Pixel format\") + \": \" + stream.PixelFormat sessionStats.push(data) end if if isValid(stream.Width) and isValid(stream.Height) data = tr(\"WxH\") + \": \" + Str(stream.Width) + \" x \" + Str(stream.Height) sessionStats.push(data) end if if isValid(stream.Level) data = tr(\"Level\") + \": \" + Str(stream.Level) sessionStats.push(data) end if end if return sessionStats end function function havePlaybackInfo() if not isValid(m.playbackInfo) return false end if if not isValid(m.playbackInfo.mediaSources) return false end if if m.playbackInfo.mediaSources.Count() &lt;= 0 return false end if if not isValid(m.playbackInfo.mediaSources[0].MediaStreams) return false end if if m.playbackInfo.mediaSources[0].MediaStreams.Count() &lt;= 0 return false end if return true end function function getDisplayBitrate(bitrate) if bitrate &gt; 1000000 return Str(Fix(bitrate / 1000000)) + \" Mbps\" else return Str(Fix(bitrate / 1000)) + \" Kbps\" end if end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_video_VideoPlayerView.brs.html":{"id":"components_video_VideoPlayerView.brs.html","title":"Source: components/video/VideoPlayerView.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/video/VideoPlayerView.brs import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/utils/config.brs\" sub init() ' Hide the overhang on init to prevent showing 2 clocks m.top.getScene().findNode(\"overhang\").visible = false m.currentItem = m.global.queueManager.callFunc(\"getCurrentItem\") m.top.id = m.currentItem.id ' Load meta data m.LoadMetaDataTask = CreateObject(\"roSGNode\", \"LoadVideoContentTask\") m.LoadMetaDataTask.itemId = m.currentItem.id m.LoadMetaDataTask.itemType = m.currentItem.type m.LoadMetaDataTask.selectedAudioStreamIndex = m.currentItem.selectedAudioStreamIndex m.LoadMetaDataTask.observeField(\"content\", \"onVideoContentLoaded\") m.LoadMetaDataTask.control = \"RUN\" m.playbackTimer = m.top.findNode(\"playbackTimer\") m.bufferCheckTimer = m.top.findNode(\"bufferCheckTimer\") m.top.observeField(\"state\", \"onState\") m.top.observeField(\"content\", \"onContentChange\") m.top.observeField(\"selectedSubtitle\", \"onSubtitleChange\") ' Custom Caption Function m.top.observeField(\"allowCaptions\", \"onAllowCaptionsChange\") m.playbackTimer.observeField(\"fire\", \"ReportPlayback\") m.bufferPercentage = 0 ' Track whether content is being loaded m.playReported = false m.top.transcodeReasons = [] m.bufferCheckTimer.duration = 30 if m.global.session.user.settings[\"ui.design.hideclock\"] = true clockNode = findNodeBySubtype(m.top, \"clock\") if clockNode[0] &lt;&gt; invalid then clockNode[0].parent.removeChild(clockNode[0].node) end if 'Play Next Episode button m.nextEpisodeButton = m.top.findNode(\"nextEpisode\") m.nextEpisodeButton.text = tr(\"Next Episode\") m.nextEpisodeButton.setFocus(false) m.showNextEpisodeButtonAnimation = m.top.findNode(\"showNextEpisodeButton\") m.hideNextEpisodeButtonAnimation = m.top.findNode(\"hideNextEpisodeButton\") m.checkedForNextEpisode = false m.getNextEpisodeTask = createObject(\"roSGNode\", \"GetNextEpisodeTask\") m.getNextEpisodeTask.observeField(\"nextEpisodeData\", \"onNextEpisodeDataLoaded\") m.top.retrievingBar.filledBarBlendColor = m.global.constants.colors.blue m.top.bufferingBar.filledBarBlendColor = m.global.constants.colors.blue m.top.trickPlayBar.filledBarBlendColor = m.global.constants.colors.blue end sub ' Only setup captain items if captions are allowed sub onAllowCaptionsChange() if not m.top.allowCaptions then return m.captionGroup = m.top.findNode(\"captionGroup\") m.captionGroup.createchildren(9, \"LayoutGroup\") m.captionTask = createObject(\"roSGNode\", \"captionTask\") m.captionTask.observeField(\"currentCaption\", \"updateCaption\") m.captionTask.observeField(\"useThis\", \"checkCaptionMode\") m.top.observeField(\"subtitleTrack\", \"loadCaption\") m.top.observeField(\"globalCaptionMode\", \"toggleCaption\") if m.global.session.user.settings[\"playback.subs.custom\"] m.top.suppressCaptions = true toggleCaption() else m.top.suppressCaptions = false end if end sub ' Set caption url to server subtitle track sub loadCaption() if m.top.suppressCaptions m.captionTask.url = m.top.subtitleTrack end if end sub ' Toggles visibility of custom subtitles and sets captionTask's player state sub toggleCaption() m.captionTask.playerState = m.top.state + m.top.globalCaptionMode if LCase(m.top.globalCaptionMode) = \"on\" m.captionTask.playerState = m.top.state + m.top.globalCaptionMode + \"w\" m.captionGroup.visible = true else m.captionGroup.visible = false end if end sub ' Removes old subtitle lines and adds new subtitle lines sub updateCaption() m.captionGroup.removeChildrenIndex(m.captionGroup.getChildCount(), 0) m.captionGroup.appendChildren(m.captionTask.currentCaption) end sub ' Event handler for when selectedSubtitle changes sub onSubtitleChange() ' Save the current video position m.global.queueManager.callFunc(\"setTopStartingPoint\", int(m.top.position) * 10000000&amp;) m.top.control = \"stop\" m.LoadMetaDataTask.selectedSubtitleIndex = m.top.SelectedSubtitle m.LoadMetaDataTask.itemId = m.currentItem.id m.LoadMetaDataTask.observeField(\"content\", \"onVideoContentLoaded\") m.LoadMetaDataTask.control = \"RUN\" end sub sub onPlaybackErrorDialogClosed(msg) sourceNode = msg.getRoSGNode() sourceNode.unobserveField(\"buttonSelected\") sourceNode.unobserveField(\"wasClosed\") m.global.sceneManager.callFunc(\"popScene\") end sub sub onPlaybackErrorButtonSelected(msg) sourceNode = msg.getRoSGNode() sourceNode.close = true end sub sub showPlaybackErrorDialog(errorMessage as string) dialog = createObject(\"roSGNode\", \"Dialog\") dialog.title = tr(\"Error During Playback\") dialog.buttons = [tr(\"OK\")] dialog.message = errorMessage dialog.observeField(\"buttonSelected\", \"onPlaybackErrorButtonSelected\") dialog.observeField(\"wasClosed\", \"onPlaybackErrorDialogClosed\") m.top.getScene().dialog = dialog end sub sub onVideoContentLoaded() m.LoadMetaDataTask.unobserveField(\"content\") m.LoadMetaDataTask.control = \"STOP\" videoContent = m.LoadMetaDataTask.content m.LoadMetaDataTask.content = [] ' If we have nothing to play, return to previous screen if not isValid(videoContent) showPlaybackErrorDialog(tr(\"There was an error retrieving the data for this item from the server.\")) return end if if not isValid(videoContent[0]) showPlaybackErrorDialog(tr(\"There was an error retrieving the data for this item from the server.\")) return end if m.top.content = videoContent[0].content m.top.PlaySessionId = videoContent[0].PlaySessionId m.top.videoId = videoContent[0].id m.top.container = videoContent[0].container m.top.mediaSourceId = videoContent[0].mediaSourceId m.top.fullSubtitleData = videoContent[0].fullSubtitleData m.top.audioIndex = videoContent[0].audioIndex m.top.transcodeParams = videoContent[0].transcodeparams if m.LoadMetaDataTask.isIntro ' Disable trackplay bar for intro videos m.top.enableTrickPlay = false else ' Allow custom captions for non intro videos m.top.allowCaptions = true end if if isValid(m.top.audioIndex) m.top.audioTrack = (m.top.audioIndex + 1).toStr() else m.top.audioTrack = \"2\" end if m.top.setFocus(true) m.top.control = \"play\" end sub ' Event handler for when video content field changes sub onContentChange() if not isValid(m.top.content) then return m.top.observeField(\"position\", \"onPositionChanged\") end sub sub onNextEpisodeDataLoaded() m.checkedForNextEpisode = true m.top.observeField(\"position\", \"onPositionChanged\") end sub ' ' Runs Next Episode button animation and sets focus to button sub showNextEpisodeButton() if m.global.session.user.configuration.EnableNextEpisodeAutoPlay and not m.nextEpisodeButton.visible m.showNextEpisodeButtonAnimation.control = \"start\" m.nextEpisodeButton.setFocus(true) m.nextEpisodeButton.visible = true end if end sub ' 'Update count down text sub updateCount() m.nextEpisodeButton.text = tr(\"Next Episode\") + \" \" + Int(m.top.duration - m.top.position).toStr() end sub ' ' Runs hide Next Episode button animation and sets focus back to video sub hideNextEpisodeButton() m.hideNextEpisodeButtonAnimation.control = \"start\" m.nextEpisodeButton.setFocus(false) m.top.setFocus(true) end sub ' Checks if we need to display the Next Episode button sub checkTimeToDisplayNextEpisode() if int(m.top.position) &gt;= (m.top.duration - 30) showNextEpisodeButton() updateCount() return end if if m.nextEpisodeButton.visible or m.nextEpisodeButton.hasFocus() m.nextEpisodeButton.visible = false m.nextEpisodeButton.setFocus(false) end if end sub ' When Video Player state changes sub onPositionChanged() if isValid(m.captionTask) m.captionTask.currentPos = Int(m.top.position * 1000) end if ' Check if dialog is open m.dialog = m.top.getScene().findNode(\"dialogBackground\") if not isValid(m.dialog) ' Do not show Next Episode button for intro videos if not m.LoadMetaDataTask.isIntro checkTimeToDisplayNextEpisode() end if end if end sub ' ' When Video Player state changes sub onState(msg) if isValid(m.captionTask) m.captionTask.playerState = m.top.state + m.top.globalCaptionMode end if ' When buffering, start timer to monitor buffering process if m.top.state = \"buffering\" and m.bufferCheckTimer &lt;&gt; invalid ' start timer m.bufferCheckTimer.control = \"start\" m.bufferCheckTimer.ObserveField(\"fire\", \"bufferCheck\") else if m.top.state = \"error\" if not m.playReported and m.top.transcodeAvailable m.top.retryWithTranscoding = true ' If playback was not reported, retry with transcoding else ' If an error was encountered, Display dialog showPlaybackErrorDialog(tr(\"Error During Playback\")) end if ' Stop playback and exit player m.top.control = \"stop\" m.top.backPressed = true else if m.top.state = \"playing\" ' Check if next episde is available if isValid(m.top.showID) if m.top.showID &lt;&gt; \"\" and not m.checkedForNextEpisode and m.top.content.contenttype = 4 m.getNextEpisodeTask.showID = m.top.showID m.getNextEpisodeTask.videoID = m.top.id m.getNextEpisodeTask.control = \"RUN\" end if end if if m.playReported = false ReportPlayback(\"start\") m.playReported = true else ReportPlayback() end if m.playbackTimer.control = \"start\" else if m.top.state = \"paused\" m.playbackTimer.control = \"stop\" ReportPlayback() else if m.top.state = \"stopped\" m.playbackTimer.control = \"stop\" ReportPlayback(\"stop\") m.playReported = false end if end sub ' ' Report playback to server sub ReportPlayback(state = \"update\" as string) if m.top.position = invalid then return params = { \"ItemId\": m.top.id, \"PlaySessionId\": m.top.PlaySessionId, \"PositionTicks\": int(m.top.position) * 10000000&amp;, 'Ensure a LongInteger is used \"IsPaused\": (m.top.state = \"paused\") } if m.top.content.live params.append({ \"MediaSourceId\": m.top.transcodeParams.MediaSourceId, \"LiveStreamId\": m.top.transcodeParams.LiveStreamId }) m.bufferCheckTimer.duration = 30 end if ' Report playstate via worker task playstateTask = m.global.playstateTask playstateTask.setFields({ status: state, params: params }) playstateTask.control = \"RUN\" end sub ' ' Check the the buffering has not hung sub bufferCheck(msg) if m.top.state &lt;&gt; \"buffering\" ' If video is not buffering, stop timer m.bufferCheckTimer.control = \"stop\" m.bufferCheckTimer.unobserveField(\"fire\") return end if if m.top.bufferingStatus &lt;&gt; invalid ' Check that the buffering percentage is increasing if m.top.bufferingStatus[\"percentage\"] &gt; m.bufferPercentage m.bufferPercentage = m.top.bufferingStatus[\"percentage\"] else if m.top.content.live = true m.top.callFunc(\"refresh\") else ' If buffering has stopped Display dialog showPlaybackErrorDialog(tr(\"There was an error retrieving the data for this item from the server.\")) ' Stop playback and exit player m.top.control = \"stop\" m.top.backPressed = true end if end if end sub function onKeyEvent(key as string, press as boolean) as boolean if key = \"OK\" and m.nextEpisodeButton.hasfocus() and not m.top.trickPlayBar.visible m.top.control = \"stop\" m.top.state = \"finished\" hideNextEpisodeButton() return true else 'Hide Next Episode Button if m.nextEpisodeButton.visible or m.nextEpisodeButton.hasFocus() m.nextEpisodeButton.visible = false m.nextEpisodeButton.setFocus(false) m.top.setFocus(true) end if end if if not press then return false if key = \"down\" ' Do not show subtitle selection for intro videos if not m.LoadMetaDataTask.isIntro m.top.selectSubtitlePressed = true return true end if else if key = \"up\" ' Do not show playback info for intro videos if not m.LoadMetaDataTask.isIntro m.top.selectPlaybackInfoPressed = true return true end if else if key = \"OK\" ' OK will play/pause depending on current state ' return false to allow selection during seeking if m.top.state = \"paused\" m.top.control = \"resume\" return false else if m.top.state = \"playing\" m.top.control = \"pause\" return false end if end if if key = \"back\" m.top.control = \"stop\" end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_movies_VideoTrackListItem.brs.html":{"id":"components_movies_VideoTrackListItem.brs.html","title":"Source: components/movies/VideoTrackListItem.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/movies/VideoTrackListItem.brs sub init() m.title = m.top.findNode(\"title\") m.description = m.top.findNode(\"description\") m.selectedIcon = m.top.findNode(\"selectedIcon\") end sub sub itemContentChanged() m.title.text = m.top.itemContent.title m.description.text = m.top.itemContent.description if m.top.itemContent.description = \"\" m.title.translation = [50, 20] end if if m.top.itemContent.selected m.selectedIcon.uri = m.global.constants.icons.check_white else m.selectedIcon.uri = \"\" end if end sub ' 'Scroll description if focused sub focusChanged() if m.top.itemHasFocus = true m.description.repeatCount = -1 else m.description.repeatCount = 0 end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_manager_ViewCreator.brs.html":{"id":"components_manager_ViewCreator.brs.html","title":"Source: components/manager/ViewCreator.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/manager/ViewCreator.brs ' Play Audio sub CreateAudioPlayerView() m.view = CreateObject(\"roSGNode\", \"AudioPlayerView\") m.view.observeField(\"state\", \"onStateChange\") m.global.sceneManager.callFunc(\"pushScene\", m.view) end sub ' Play Video sub CreateVideoPlayerView() m.playbackData = {} m.selectedSubtitle = {} m.view = CreateObject(\"roSGNode\", \"VideoPlayerView\") m.view.observeField(\"state\", \"onStateChange\") m.view.observeField(\"selectPlaybackInfoPressed\", \"onSelectPlaybackInfoPressed\") m.view.observeField(\"selectSubtitlePressed\", \"onSelectSubtitlePressed\") mediaSourceId = m.global.queueManager.callFunc(\"getCurrentItem\").mediaSourceId if not isValid(mediaSourceId) or mediaSourceId = \"\" mediaSourceId = m.global.queueManager.callFunc(\"getCurrentItem\").id end if m.getPlaybackInfoTask = createObject(\"roSGNode\", \"GetPlaybackInfoTask\") m.getPlaybackInfoTask.videoID = mediaSourceId m.getPlaybackInfoTask.observeField(\"data\", \"onPlaybackInfoLoaded\") m.global.sceneManager.callFunc(\"pushScene\", m.view) end sub ' ----------------- ' Event Handlers ' ----------------- ' User requested subtitle selection popup sub onSelectSubtitlePressed() ' None is always first in the subtitle list subtitleData = { data: [{ \"Index\": -1, \"IsExternal\": false, \"Track\": { \"description\": \"None\" }, \"Type\": \"subtitleselection\" }] } for each item in m.view.fullSubtitleData item.type = \"subtitleselection\" if m.view.selectedSubtitle &lt;&gt; -1 ' Subtitle is a track within the file if item.index = m.view.selectedSubtitle item.selected = true end if else ' Subtitle is from an external source availableSubtitleTrackIndex = availSubtitleTrackIdx(item.track.TrackName) if availableSubtitleTrackIndex &lt;&gt; -1 ' Convert Jellyfin subtitle track name to Roku track name subtitleFullTrackName = m.view.availableSubtitleTracks[availableSubtitleTrackIndex].TrackName if subtitleFullTrackName = m.view.subtitleTrack item.selected = true end if end if end if subtitleData.data.push(item) end for m.global.sceneManager.callFunc(\"radioDialog\", tr(\"Select Subtitles\"), subtitleData) m.global.sceneManager.observeField(\"returnData\", \"onSelectionMade\") end sub ' User has selected something from the radioDialog popup sub onSelectionMade() m.global.sceneManager.unobserveField(\"returnData\") if not isValid(m.global.sceneManager.returnData) then return if not isValid(m.global.sceneManager.returnData.type) then return if LCase(m.global.sceneManager.returnData.type) = \"subtitleselection\" processSubtitleSelection() end if end sub sub processSubtitleSelection() m.selectedSubtitle = m.global.sceneManager.returnData ' The selected encoded subtitle did not change. if m.view.selectedSubtitle &lt;&gt; -1 or m.selectedSubtitle.index &lt;&gt; -1 if m.view.selectedSubtitle = m.selectedSubtitle.index then return end if ' The playbackData is now outdated and must be refreshed m.playbackData = invalid if LCase(m.selectedSubtitle.track.description) = \"none\" m.view.globalCaptionMode = \"Off\" m.view.subtitleTrack = \"\" if m.view.selectedSubtitle &lt;&gt; -1 m.view.selectedSubtitle = -1 end if return end if if m.selectedSubtitle.IsEncoded m.view.globalCaptionMode = \"Off\" else m.view.globalCaptionMode = \"On\" end if if m.selectedSubtitle.IsExternal availableSubtitleTrackIndex = availSubtitleTrackIdx(m.selectedSubtitle.Track.TrackName) if availableSubtitleTrackIndex = -1 then return m.view.subtitleTrack = m.view.availableSubtitleTracks[availableSubtitleTrackIndex].TrackName else m.view.selectedSubtitle = m.selectedSubtitle.Index end if end sub ' User requested playback info sub onSelectPlaybackInfoPressed() ' Check if we already have playback info and show it in a popup if isValid(m.playbackData) and isValid(m.playbackData.playbackinfo) m.global.sceneManager.callFunc(\"standardDialog\", tr(\"Playback Info\"), m.playbackData.playbackinfo) return end if m.getPlaybackInfoTask.control = \"RUN\" end sub ' The playback info task has returned data sub onPlaybackInfoLoaded() m.playbackData = m.getPlaybackInfoTask.data ' Check if we have playback info and show it in a popup if isValid(m.playbackData) and isValid(m.playbackData.playbackinfo) m.global.sceneManager.callFunc(\"standardDialog\", tr(\"Playback Info\"), m.playbackData.playbackinfo) end if end sub ' Playback state change event handlers sub onStateChange() if LCase(m.view.state) = \"finished\" ' Close any open dialogs if m.global.sceneManager.callFunc(\"isDialogOpen\") m.global.sceneManager.callFunc(\"dismissDialog\") end if ' If there is something next in the queue, play it if m.global.queueManager.callFunc(\"getPosition\") &lt; m.global.queueManager.callFunc(\"getCount\") - 1 m.global.sceneManager.callFunc(\"clearPreviousScene\") m.global.queueManager.callFunc(\"moveForward\") m.global.queueManager.callFunc(\"playQueue\") return end if ' Playback completed, return user to previous screen m.global.sceneManager.callFunc(\"popScene\") m.global.audioPlayer.loopMode = \"\" end if end sub ' Roku translates the info provided in subtitleTracks into availableSubtitleTracks ' Including ignoring tracks, if they are not understood, thus making indexing unpredictable. ' This function translates between our internel selected subtitle index ' and the corresponding index in availableSubtitleTracks. function availSubtitleTrackIdx(tracknameToFind as string) as integer idx = 0 for each availTrack in m.view.availableSubtitleTracks ' The TrackName must contain the URL we supplied originally, though ' Roku mangles the name a bit, so we check if the URL is a substring, rather ' than strict equality if Instr(1, availTrack.TrackName, tracknameToFind) return idx end if idx = idx + 1 end for return -1 end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_WhatsNewDialog.brs.html":{"id":"components_WhatsNewDialog.brs.html","title":"Source: components/WhatsNewDialog.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/WhatsNewDialog.brs sub init() m.content = m.top.findNode(\"content\") setPalette() m.top.id = \"OKDialog\" m.top.height = 900 m.top.title = \"What's New?\" m.top.buttons = [tr(\"OK\")] dialogStyles = { \"default\": { \"fontSize\": 27, \"fontUri\": \"font:SystemFontFile\", \"color\": \"#EFEFEFFF\" }, \"author\": { \"fontSize\": 27, \"fontUri\": \"font:SystemFontFile\", \"color\": \"#00a4dcFF\" } } whatsNewList = ParseJSON(ReadAsciiFile(\"pkg:/source/static/whatsNew.json\")) for each item in whatsNewList textLine = m.content.CreateChild(\"StdDlgMultiStyleTextItem\") textLine.drawingStyles = dialogStyles textLine.text = \"• \" + item.description + \" &lt;author&gt;\" + item.author + \"&lt;/author&gt;\" end for end sub sub setPalette() dlgPalette = createObject(\"roSGNode\", \"RSGPalette\") dlgPalette.colors = { DialogBackgroundColor: \"0x262828FF\", DialogFocusColor: \"0xcececeFF\", DialogFocusItemColor: \"0x202020FF\", DialogSecondaryTextColor: \"0xf8f8f8ff\", DialogSecondaryItemColor: \"#00a4dcFF\", DialogTextColor: \"0xeeeeeeFF\" } m.top.palette = dlgPalette end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"source_api_baserequest.brs.html":{"id":"source_api_baserequest.brs.html","title":"Source: source/api/baserequest.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: source/api/baserequest.brs ' Functions for making requests to the API function buildParams(params = {} as object) as string ' Take an object of parameters and construct the URL query param_array = [] for each field in params.items() item = \"\" if type(field.value) = \"String\" or type(field.value) = \"roString\" item = field.key + \"=\" + field.value.trim().EncodeUriComponent() else if type(field.value) = \"roInteger\" or type(field.value) = \"roInt\" item = field.key + \"=\" + stri(field.value).trim() 'item = field.key + \"=\" + str(field.value).trim() else if type(field.value) = \"roFloat\" item = field.key + \"=\" + stri(int(field.value)).trim() else if type(field.value) = \"LongInteger\" item = field.key + \"=\" + field.value.toStr().trim() else if type(field.value) = \"roArray\" ' TODO handle array params else if type(field.value) = \"roBoolean\" if field.value item = field.key + \"=true\" else item = field.key + \"=false\" end if else if field.value = invalid item = field.key + \"=null\" else if field &lt;&gt; invalid print \"Unhandled param type: \" + type(field.value) item = field.key + \"=\" + field.value.EncodeUriComponent() end if if item &lt;&gt; \"\" then param_array.push(item) end for return param_array.join(\"&amp;\") end function function buildURL(path as string, params = {} as object) as dynamic serverURL = get_url() if serverURL = invalid then return invalid ' Add intial '/' if path does not start with one if path.Left(1) = \"/\" full_url = serverURL + path else full_url = serverURL + \"/\" + path end if if params.count() &gt; 0 full_url = full_url + \"?\" + buildParams(params) end if return full_url end function function APIRequest(url as string, params = {} as object) as dynamic full_url = buildURL(url, params) if full_url = invalid then return invalid serverURL = m.global.session.server.url if serverURL = invalid then return invalid req = createObject(\"roUrlTransfer\") req.setUrl(full_url) req = authRequest(req) ' SSL cert if serverURL.left(8) = \"https://\" setCertificateAuthority(req) end if return req end function function getJson(req) 'req.retainBodyOnError(True) data = req.GetToString() if data = invalid or data = \"\" return invalid end if json = ParseJson(data) return json end function function postVoid(req, data = \"\" as string) as boolean req.setMessagePort(CreateObject(\"roMessagePort\")) req.AddHeader(\"Content-Type\", \"application/json\") req.AsyncPostFromString(data) resp = wait(30000, req.GetMessagePort()) if type(resp) &lt;&gt; \"roUrlEvent\" return false end if if resp.GetResponseCode() = 200 return true end if return false end function function headVoid(req) as boolean req.setMessagePort(CreateObject(\"roMessagePort\")) req.AddHeader(\"Content-Type\", \"application/json\") req.AsyncHead() resp = wait(30000, req.GetMessagePort()) if type(resp) &lt;&gt; \"roUrlEvent\" return false end if if resp.GetResponseCode() = 200 return true end if return false end function function getVoid(req) as boolean req.setMessagePort(CreateObject(\"roMessagePort\")) req.AddHeader(\"Content-Type\", \"application/json\") req.AsyncGetToString() resp = wait(30000, req.GetMessagePort()) if type(resp) &lt;&gt; \"roUrlEvent\" return false end if if resp.GetResponseCode() = 200 return true end if return false end function function postJson(req, data = \"\" as string) req.setMessagePort(CreateObject(\"roMessagePort\")) req.AddHeader(\"Content-Type\", \"application/json\") req.AsyncPostFromString(data) resp = wait(30000, req.GetMessagePort()) if type(resp) &lt;&gt; \"roUrlEvent\" return invalid end if if resp.getString() = \"\" return invalid end if json = ParseJson(resp.GetString()) return json end function function deleteVoid(req) req.setMessagePort(CreateObject(\"roMessagePort\")) req.AddHeader(\"Content-Type\", \"application/json\") req.SetRequest(\"DELETE\") req.GetToString() return true end function function get_url() serverURL = m.global.session.server.url if serverURL &lt;&gt; invalid if serverURL.right(1) = \"/\" serverURL = serverURL.left(serverURL.len() - 1) end if ' append http:// to the start if not specified if serverURL.left(7) &lt;&gt; \"http://\" and serverURL.left(8) &lt;&gt; \"https://\" serverURL = \"http://\" + serverURL end if end if return serverURL end function function getString(req) data = req.GetToString() return data end function function postString(req, data = \"\" as string) req.setMessagePort(CreateObject(\"roMessagePort\")) req.AddHeader(\"Content-Type\", \"application/json\") req.AsyncPostFromString(data) resp = wait(30000, req.GetMessagePort()) if type(resp) &lt;&gt; \"roUrlEvent\" return invalid end if return resp.getString() end function ' sets the certificate authority by file path on the passed node sub setCertificateAuthority(request as object) as void request.setCertificatesFile(\"common:/certs/ca-bundle.crt\") end sub ' Takes and returns a roUrlTransfer object after adding a Jellyfin \"Authorization\" header function authRequest(request as object) as object QUOTE = Chr(34) auth = \"MediaBrowser\" + \" Client=\" + QUOTE + \"Jellyfin Roku\" + QUOTE auth = auth + \", Device=\" + QUOTE + m.global.device.name + \" (\" + m.global.device.model + \")\" + QUOTE auth = auth + \", Version=\" + QUOTE + m.global.app.version + QUOTE if m.global.session.user.id &lt;&gt; invalid auth = auth + \", UserId=\" + QUOTE + m.global.session.user.id + QUOTE end if auth = auth + \", DeviceId=\" + QUOTE + m.global.device.serverDeviceName + QUOTE if m.global.session.user.authToken &lt;&gt; invalid auth = auth + \", Token=\" + QUOTE + m.global.session.user.authToken + QUOTE end if request.AddHeader(\"Authorization\", auth) return request end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_captionTask.brs.html":{"id":"components_captionTask.brs.html","title":"Source: components/captionTask.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/captionTask.brs import \"pkg:/source/utils/config.brs\" import \"pkg:/source/api/baserequest.brs\" sub init() m.top.observeField(\"url\", \"fetchCaption\") m.top.currentCaption = [] m.top.currentPos = 0 m.captionTimer = m.top.findNode(\"captionTimer\") m.captionTimer.ObserveField(\"fire\", \"updateCaption\") m.captionList = [] m.reader = createObject(\"roUrlTransfer\") m.font = CreateObject(\"roSGNode\", \"Font\") m.tags = CreateObject(\"roRegex\", \"{\\\\an\\d*}|&amp;lt;.*?&amp;gt;|&lt;.*?&gt;\", \"s\") ' Caption Style m.fontSizeDict = { \"Default\": 60, \"Large\": 60, \"Extra Large\": 70, \"Medium\": 50, \"Small\": 40 } m.percentageDict = { \"Default\": 1.0, \"100%\": 1.0, \"75%\": 0.75, \"50%\": 0.5, \"25%\": 0.25, \"Off\": 0 } m.textColorDict = { \"Default\": &amp;HFFFFFFFF, \"White\": &amp;HFFFFFFFF, \"Black\": &amp;H000000FF, \"Red\": &amp;HFF0000FF, \"Green\": &amp;H008000FF, \"Blue\": &amp;H0000FFFF, \"Yellow\": &amp;HFFFF00FF, \"Magenta\": &amp;HFF00FFFF, \"Cyan\": &amp;H00FFFFFF } m.bgColorDict = { \"Default\": &amp;H000000FF, \"White\": &amp;HFFFFFFFF, \"Black\": &amp;H000000FF, \"Red\": &amp;HFF0000FF, \"Green\": &amp;H008000FF, \"Blue\": &amp;H0000FFFF, \"Yellow\": &amp;HFFFF00FF, \"Magenta\": &amp;HFF00FFFF, \"Cyan\": &amp;H00FFFFFF } deviceInfo = CreateObject(\"roDeviceInfo\") m.fontSize = m.fontSizeDict[deviceInfo.GetCaptionsOption(\"Text/Size\")] m.textColor = m.textColorDict[deviceInfo.GetCaptionsOption(\"Text/Color\")] m.textOpac = m.percentageDict[deviceInfo.GetCaptionsOption(\"Text/Opacity\")] m.bgColor = m.bgColorDict[deviceInfo.GetCaptionsOption(\"Background/Color\")] m.bgOpac = m.percentageDict[deviceInfo.GetCaptionsOption(\"Background/Opacity\")] setFont() end sub sub setFont() fs = CreateObject(\"roFileSystem\") if fs.Exists(\"tmp:/font\") m.font.uri = \"tmp:/font\" m.font.size = m.fontSize else m.font = \"font:LargeSystemFont\" end if end sub sub fetchCaption() m.captionTimer.control = \"stop\" re = CreateObject(\"roRegex\", \"(http.*?\\.vtt)\", \"s\") url = re.match(m.top.url)[0] if url &lt;&gt; invalid m.reader.setUrl(url) text = m.reader.GetToString() m.captionList = parseVTT(text) m.captionTimer.control = \"start\" else m.captionTimer.control = \"stop\" end if end sub function newlabel(txt) label = CreateObject(\"roSGNode\", \"Label\") label.text = txt label.font = m.font label.font.size = m.fontSize label.color = m.textColor label.opacity = m.textOpac return label end function function newLayoutGroup(labels) newlg = CreateObject(\"roSGNode\", \"LayoutGroup\") newlg.appendchildren(labels) newlg.horizalignment = \"center\" newlg.vertalignment = \"bottom\" return newlg end function function newRect(lg) rectLG = CreateObject(\"roSGNode\", \"LayoutGroup\") rectxy = lg.BoundingRect() rect = CreateObject(\"roSGNode\", \"Rectangle\") rect.color = m.bgColor rect.opacity = m.bgOpac rect.width = rectxy.width + 50 rect.height = rectxy.height if lg.getchildCount() = 0 rect.width = 0 rect.height = 0 end if rectLG.translation = [0, -rect.height / 2] rectLG.horizalignment = \"center\" rectLG.vertalignment = \"center\" rectLG.appendchild(rect) return rectLG end function sub updateCaption() m.top.currentCaption = [] if LCase(m.top.playerState) = \"playingon\" m.top.currentPos = m.top.currentPos + 100 texts = [] for each entry in m.captionList if entry[\"start\"] &lt;= m.top.currentPos and m.top.currentPos &lt; entry[\"end\"] t = m.tags.replaceAll(entry[\"text\"], \"\") texts.push(t) end if end for labels = [] for each text in texts labels.push(newlabel (text)) end for lines = newLayoutGroup(labels) rect = newRect(lines) m.top.currentCaption = [rect, lines] else if LCase(m.top.playerState.right(1)) = \"w\" m.top.playerState = m.top.playerState.left(len (m.top.playerState) - 1) end if end sub function isTime(text) return text.right(1) = chr(31) end function function toMs(t) t = t.replace(\".\", \":\") t = t.left(12) timestamp = t.tokenize(\":\") return 3600000 * timestamp[0].toint() + 60000 * timestamp[1].toint() + 1000 * timestamp[2].toint() + timestamp[3].toint() end function function parseVTT(lines) lines = lines.replace(\" --&gt; \", chr(31) + chr(10)) lines = lines.split(chr(10)) curStart = -1 curEnd = -1 entries = [] for i = 0 to lines.count() - 1 if isTime(lines[i]) curStart = toMs (lines[i]) curEnd = toMs (lines[i + 1]) i += 1 else if curStart &lt;&gt; -1 trimmed = lines[i].trim() if trimmed &lt;&gt; chr(0) entry = { \"start\": curStart, \"end\": curEnd, \"text\": trimmed } entries.push(entry) end if end if end for return entries end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"source_utils_config.brs.html":{"id":"source_utils_config.brs.html","title":"Source: source/utils/config.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: source/utils/config.brs ' needed for set_user_setting() and unset_user_setting() import \"pkg:/source/utils/session.bs\" ' Read config tree from json config file and return function GetConfigTree() return ParseJSON(ReadAsciiFile(\"pkg:/settings/settings.json\")) end function ' Generic registry accessors function registry_read(key, section = invalid) if section = invalid then return invalid reg = CreateObject(\"roRegistrySection\", section) if reg.exists(key) then return reg.read(key) return invalid end function sub registry_write(key, value, section = invalid) if section = invalid then return reg = CreateObject(\"roRegistrySection\", section) reg.write(key, value) reg.flush() end sub sub registry_delete(key, section = invalid) if section = invalid then return reg = CreateObject(\"roRegistrySection\", section) reg.delete(key) reg.flush() end sub ' Return all data found inside a registry section function RegistryReadAll(section as string) as dynamic if section = \"\" then return invalid registry = CreateObject(\"roRegistrySection\", section) regKeyList = registry.GetKeyList() registryData = {} for each item in regKeyList ' ignore session related tokens if item &lt;&gt; \"token\" and item &lt;&gt; \"username\" and item &lt;&gt; \"password\" and LCase(item) &lt;&gt; \"lastrunversion\" if registry.Exists(item) registryData.AddReplace(item, registry.Read(item)) end if end if end for return registryData end function ' Return an array of all the registry section keys function getRegistrySections() as object registry = CreateObject(\"roRegistry\") return registry.GetSectionList() end function ' \"Jellyfin\" registry accessors for the default global settings function get_setting(key, defaultValue = invalid) value = registry_read(key, \"Jellyfin\") if value = invalid then return defaultValue return value end function sub set_setting(key, value) registry_write(key, value, \"Jellyfin\") end sub sub unset_setting(key) registry_delete(key, \"Jellyfin\") end sub ' User registry accessors for the currently active user function get_user_setting(key as string) as dynamic if key = \"\" or m.global.session.user.id = invalid then return invalid value = registry_read(key, m.global.session.user.id) return value end function sub set_user_setting(key as string, value as dynamic) if m.global.session.user.id = invalid then return session.user.settings.Save(key, value) registry_write(key, value, m.global.session.user.id) end sub sub unset_user_setting(key as string) if m.global.session.user.id = invalid then return session.user.settings.Delete(key) registry_delete(key, m.global.session.user.id) end sub ' Recursivly search the config tree for entry with settingname equal to key function findConfigTreeKey(key as string, tree) for each item in tree if item.settingName &lt;&gt; invalid and item.settingName = key then return item if item.children &lt;&gt; invalid and item.children.Count() &gt; 0 result = findConfigTreeKey(key, item.children) if result &lt;&gt; invalid then return result end if end for return invalid end function ' Returns an array of saved users from the registry ' that belong to the active server function getSavedUsers() as object registrySections = getRegistrySections() savedUsers = [] for each section in registrySections if LCase(section) &lt;&gt; \"jellyfin\" savedUsers.push(section) end if end for savedServerUsers = [] for each userId in savedUsers userArray = { id: userId } token = registry_read(\"token\", userId) username = registry_read(\"username\", userId) if username &lt;&gt; invalid userArray[\"username\"] = username end if serverId = registry_read(\"serverId\", userId) if serverId &lt;&gt; invalid userArray[\"serverId\"] = serverId end if if username &lt;&gt; invalid and token &lt;&gt; invalid and serverId &lt;&gt; invalid and serverId = m.global.session.server.id savedServerUsers.push(userArray) end if end for return savedServerUsers end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"source_utils_deviceCapabilities.brs.html":{"id":"source_utils_deviceCapabilities.brs.html","title":"Source: source/utils/deviceCapabilities.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: source/utils/deviceCapabilities.brs import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/api/baserequest.brs\" 'Device Capabilities for Roku. 'This will likely need further tweaking function getDeviceCapabilities() as object return { \"PlayableMediaTypes\": [ \"Audio\", \"Video\", \"Photo\" ], \"SupportedCommands\": [], \"SupportsPersistentIdentifier\": true, \"SupportsMediaControl\": false, \"SupportsContentUploading\": false, \"SupportsSync\": false, \"DeviceProfile\": getDeviceProfile(), \"AppStoreUrl\": \"https://channelstore.roku.com/details/cc5e559d08d9ec87c5f30dcebdeebc12/jellyfin\" } end function ' Send Device Profile information to server sub PostDeviceProfile() profile = getDeviceCapabilities() req = APIRequest(\"/Sessions/Capabilities/Full\") req.SetRequest(\"POST\") print \"profile =\", profile print \"profile.DeviceProfile =\", profile.DeviceProfile print \"profile.DeviceProfile.CodecProfiles =\" for each prof in profile.DeviceProfile.CodecProfiles print prof for each cond in prof.Conditions print cond end for end for print \"profile.DeviceProfile.ContainerProfiles =\", profile.DeviceProfile.ContainerProfiles print \"profile.DeviceProfile.DirectPlayProfiles =\" for each prof in profile.DeviceProfile.DirectPlayProfiles print prof end for print \"profile.DeviceProfile.SubtitleProfiles =\" for each prof in profile.DeviceProfile.SubtitleProfiles print prof end for print \"profile.DeviceProfile.TranscodingProfiles =\" for each prof in profile.DeviceProfile.TranscodingProfiles print prof if isValid(prof.Conditions) for each condition in prof.Conditions print condition end for end if end for print \"profile.PlayableMediaTypes =\", profile.PlayableMediaTypes print \"profile.SupportedCommands =\", profile.SupportedCommands postJson(req, FormatJson(profile)) end sub function getDeviceProfile() as object playMpeg2 = m.global.session.user.settings[\"playback.mpeg2\"] di = CreateObject(\"roDeviceInfo\") ' TRANSCODING ' use strings to preserve order mp4AudioCodecs = \"aac\" mp4VideoCodecs = \"h264\" tsAudioCodecs = \"aac\" tsVideoCodecs = \"h264\" ' profileSupport[\"mp4\"][\"hevc\"][\"profile name\"][\"profile level\"] profileSupport = { mp4: {}, ts: {} } ' does the users setup support surround sound? maxAudioChannels = \"2\" ' jellyfin expects this as a string ' in order of preference from left to right audioCodecs = [\"eac3\", \"ac3\", \"dts\", \"mp3\", \"vorbis\", \"opus\", \"flac\", \"alac\", \"ac4\", \"pcm\", \"wma\", \"wmapro\"] surroundSoundCodecs = [\"eac3\", \"ac3\", \"dts\"] if m.global.session.user.settings[\"playback.forceDTS\"] = true surroundSoundCodecs = [\"dts\", \"eac3\", \"ac3\"] end if preferredSurroundSoundCodec = invalid if di.GetAudioOutputChannel() = \"5.1 surround\" maxAudioChannels = \"6\" for each codec in surroundSoundCodecs if di.CanDecodeAudio({ Codec: codec, ChCnt: 6 }).Result preferredSurroundSoundCodec = codec if di.CanDecodeAudio({ Codec: codec, ChCnt: 8 }).Result maxAudioChannels = \"8\" end if exit for end if end for end if ' VIDEO CODECS ' ' AVC / h264 / MPEG4 AVC h264Profiles = [\"main\", \"high\"] h264Levels = [\"4.1\", \"4.2\"] for each container in profileSupport for each profile in h264Profiles for each level in h264Levels if di.CanDecodeVideo({ Codec: \"h264\", Container: container, Profile: profile, Level: level }).Result profileSupport[container] = updateProfileArray(profileSupport[container], \"h264\", profile, level) end if if di.CanDecodeVideo({ Codec: \"mpeg4 avc\", Container: container, Profile: profile, Level: level }).Result profileSupport[container] = updateProfileArray(profileSupport[container], \"mpeg4 avc\", profile, level) if container = \"mp4\" ' check for codec string before adding it if mp4VideoCodecs.Instr(0, \",mpeg4 avc\") = -1 mp4VideoCodecs = mp4VideoCodecs + \",mpeg4 avc\" end if else if container = \"ts\" ' check for codec string before adding it if tsVideoCodecs.Instr(0, \",mpeg4 avc\") = -1 tsVideoCodecs = tsVideoCodecs + \",mpeg4 avc\" end if end if end if end for end for end for addHevc = false if m.global.session.user.settings[\"playback.compatibility.disablehevc\"] = false ' HEVC / h265 hevcProfiles = [\"main\", \"main 10\"] hevcLevels = [\"4.1\", \"5.0\", \"5.1\"] for each container in profileSupport for each profile in hevcProfiles for each level in hevcLevels if di.CanDecodeVideo({ Codec: \"hevc\", Container: container, Profile: profile, Level: level }).Result addHevc = true profileSupport[container] = updateProfileArray(profileSupport[container], \"hevc\", profile, level) profileSupport[container] = updateProfileArray(profileSupport[container], \"h265\", profile, level) if container = \"mp4\" ' check for codec string before adding it if mp4VideoCodecs.Instr(0, \"h265,\") = -1 mp4VideoCodecs = \"h265,\" + mp4VideoCodecs end if if mp4VideoCodecs.Instr(0, \"hevc,\") = -1 mp4VideoCodecs = \"hevc,\" + mp4VideoCodecs end if else if container = \"ts\" ' check for codec string before adding it if tsVideoCodecs.Instr(0, \"h265,\") = -1 tsVideoCodecs = \"h265,\" + tsVideoCodecs end if if tsVideoCodecs.Instr(0, \"hevc,\") = -1 tsVideoCodecs = \"hevc,\" + tsVideoCodecs end if end if end if end for end for end for end if ' VP9 vp9Profiles = [\"profile 0\", \"profile 2\"] addVp9 = false for each container in profileSupport for each profile in vp9Profiles if di.CanDecodeAudio({ Codec: \"vp9\", Container: container, Profile: profile }).Result addVp9 = true profileSupport[container] = updateProfileArray(profileSupport[container], \"vp9\", profile) if container = \"mp4\" ' check for codec string before adding it if mp4VideoCodecs.Instr(0, \",vp9\") = -1 mp4VideoCodecs = mp4VideoCodecs + \",vp9\" end if else if container = \"ts\" ' check for codec string before adding it if tsVideoCodecs.Instr(0, \",vp9\") = -1 tsVideoCodecs = tsVideoCodecs + \",vp9\" end if end if end if end for end for ' MPEG2 ' mpeg2 uses levels with no profiles. see https://developer.roku.com/en-ca/docs/references/brightscript/interfaces/ifdeviceinfo.md#candecodevideovideo_format-as-object-as-object ' NOTE: the mpeg2 levels are being saved in the profileSupport array as if they were profiles mpeg2Levels = [\"main\", \"high\"] addMpeg2 = false if playMpeg2 for each container in profileSupport for each level in mpeg2Levels if di.CanDecodeVideo({ Codec: \"mpeg2\", Container: container, Level: level }).Result addMpeg2 = true profileSupport[container] = updateProfileArray(profileSupport[container], \"mpeg2\", level) if container = \"mp4\" ' check for codec string before adding it if mp4VideoCodecs.Instr(0, \",mpeg2video\") = -1 mp4VideoCodecs = mp4VideoCodecs + \",mpeg2video\" end if else if container = \"ts\" ' check for codec string before adding it if tsVideoCodecs.Instr(0, \",mpeg2video\") = -1 tsVideoCodecs = tsVideoCodecs + \",mpeg2video\" end if end if end if end for end for end if ' AV1 addAv1 = di.CanDecodeVideo({ Codec: \"av1\" }).Result av1Profiles = [\"main\", \"main 10\"] av1Levels = [\"4.1\", \"5.0\", \"5.1\"] if addAv1 for each container in profileSupport for each profile in av1Profiles for each level in av1Levels ' av1 doesn't support checking for container if di.CanDecodeVideo({ Codec: \"av1\", Profile: profile, Level: level }).Result profileSupport[container] = updateProfileArray(profileSupport[container], \"av1\", profile, level) if container = \"mp4\" ' check for codec string before adding it if mp4VideoCodecs.Instr(0, \",av1\") = -1 mp4VideoCodecs = mp4VideoCodecs + \",av1\" end if else if container = \"ts\" ' check for codec string before adding it if tsVideoCodecs.Instr(0, \",av1\") = -1 tsVideoCodecs = tsVideoCodecs + \",av1\" end if end if end if end for end for end for end if ' AUDIO CODECS for each container in profileSupport for each codec in audioCodecs if di.CanDecodeAudio({ Codec: codec, Container: container }).result if container = \"mp4\" mp4AudioCodecs = mp4AudioCodecs + \",\" + codec else if container = \"ts\" tsAudioCodecs = tsAudioCodecs + \",\" + codec end if end if end for end for ' HDR SUPPORT h264VideoRangeTypes = \"SDR\" hevcVideoRangeTypes = \"SDR\" vp9VideoRangeTypes = \"SDR\" av1VideoRangeTypes = \"SDR\" dp = di.GetDisplayProperties() if dp.Hdr10 hevcVideoRangeTypes = hevcVideoRangeTypes + \"|HDR10\" vp9VideoRangeTypes = vp9VideoRangeTypes + \"|HDR10\" av1VideoRangeTypes = av1VideoRangeTypes + \"|HDR10\" end if if dp.Hdr10Plus av1VideoRangeTypes = av1VideoRangeTypes + \"|HDR10+\" end if if dp.HLG hevcVideoRangeTypes = hevcVideoRangeTypes + \"|HLG\" vp9VideoRangeTypes = vp9VideoRangeTypes + \"|HLG\" av1VideoRangeTypes = av1VideoRangeTypes + \"|HLG\" end if if dp.DolbyVision h264VideoRangeTypes = h264VideoRangeTypes + \"|DOVI\" hevcVideoRangeTypes = hevcVideoRangeTypes + \"|DOVI\" 'vp9VideoRangeTypes = vp9VideoRangeTypes + \",DOVI\" no evidence that vp9 can hold DOVI av1VideoRangeTypes = av1VideoRangeTypes + \"|DOVI\" end if DirectPlayProfile = GetDirectPlayProfiles() deviceProfile = { \"Name\": \"Official Roku Client\", \"Id\": m.global.device.id, \"Identification\": { \"FriendlyName\": m.global.device.friendlyName, \"ModelNumber\": m.global.device.model, \"SerialNumber\": \"string\", \"ModelName\": m.global.device.name, \"ModelDescription\": \"Type: \" + m.global.device.modelType, \"Manufacturer\": m.global.device.modelDetails.VendorName }, \"FriendlyName\": m.global.device.friendlyName, \"Manufacturer\": m.global.device.modelDetails.VendorName, \"ModelName\": m.global.device.name, \"ModelDescription\": \"Type: \" + m.global.device.modelType, \"ModelNumber\": m.global.device.model, \"SerialNumber\": m.global.device.serial, \"MaxStreamingBitrate\": 120000000, \"MaxStaticBitrate\": 100000000, \"MusicStreamingTranscodingBitrate\": 192000, \"DirectPlayProfiles\": DirectPlayProfile, \"TranscodingProfiles\": [], \"ContainerProfiles\": [], \"CodecProfiles\": [ { \"Type\": \"VideoAudio\", \"Conditions\": [ { \"Condition\": \"LessThanEqual\", \"Property\": \"AudioChannels\", \"Value\": maxAudioChannels, \"IsRequired\": false } ] } ], \"SubtitleProfiles\": [ { \"Format\": \"vtt\", \"Method\": \"External\" }, { \"Format\": \"srt\", \"Method\": \"External\" }, { \"Format\": \"ttml\", \"Method\": \"External\" }, { \"Format\": \"sub\", \"Method\": \"External\" } ] } ' build TranscodingProfiles ' max resolution maxResSetting = m.global.session.user.settings[\"playback.resolution.max\"] maxResMode = m.global.session.user.settings[\"playback.resolution.mode\"] maxVideoHeight = maxResSetting maxVideoWidth = invalid if maxResSetting = \"auto\" maxVideoHeight = m.global.device.videoHeight maxVideoWidth = m.global.device.videoWidth else if maxResSetting &lt;&gt; \"off\" if maxResSetting = \"360\" maxVideoWidth = \"480\" else if maxResSetting = \"480\" maxVideoWidth = \"640\" else if maxResSetting = \"720\" maxVideoWidth = \"1280\" else if maxResSetting = \"1080\" maxVideoWidth = \"1920\" else if maxResSetting = \"2160\" maxVideoWidth = \"3840\" else if maxResSetting = \"4320\" maxVideoWidth = \"7680\" end if end if maxVideoHeightArray = { \"Condition\": \"LessThanEqual\", \"Property\": \"Width\", \"Value\": maxVideoWidth, \"IsRequired\": true } maxVideoWidthArray = { \"Condition\": \"LessThanEqual\", \"Property\": \"Height\", \"Value\": maxVideoHeight, \"IsRequired\": true } ' ' add mp3 to TranscodingProfile for music deviceProfile.TranscodingProfiles.push({ \"Container\": \"mp3\", \"Type\": \"Audio\", \"AudioCodec\": \"mp3\", \"Context\": \"Streaming\", \"Protocol\": \"http\", \"MaxAudioChannels\": maxAudioChannels }) deviceProfile.TranscodingProfiles.push({ \"Container\": \"mp3\", \"Type\": \"Audio\", \"AudioCodec\": \"mp3\", \"Context\": \"Static\", \"Protocol\": \"http\", \"MaxAudioChannels\": maxAudioChannels }) ' add aac to TranscodingProfile for stereo audio ' NOTE: multichannel aac is not supported. only decode to stereo on some devices deviceProfile.TranscodingProfiles.push({ \"Container\": \"ts\", \"Type\": \"Audio\", \"AudioCodec\": \"aac\", \"Context\": \"Streaming\", \"Protocol\": \"http\", \"MaxAudioChannels\": \"2\" }) deviceProfile.TranscodingProfiles.push({ \"Container\": \"ts\", \"Type\": \"Audio\", \"AudioCodec\": \"aac\", \"Context\": \"Static\", \"Protocol\": \"http\", \"MaxAudioChannels\": \"2\" }) tsArray = { \"Container\": \"ts\", \"Context\": \"Streaming\", \"Protocol\": \"hls\", \"Type\": \"Video\", \"AudioCodec\": tsAudioCodecs, \"VideoCodec\": tsVideoCodecs, \"MaxAudioChannels\": maxAudioChannels, \"MinSegments\": 1, \"BreakOnNonKeyFrames\": false } mp4Array = { \"Container\": \"mp4\", \"Context\": \"Streaming\", \"Protocol\": \"hls\", \"Type\": \"Video\", \"AudioCodec\": mp4AudioCodecs, \"VideoCodec\": mp4VideoCodecs, \"MaxAudioChannels\": maxAudioChannels, \"MinSegments\": 1, \"BreakOnNonKeyFrames\": false } ' apply max res to transcoding profile if maxResSetting &lt;&gt; \"off\" tsArray.Conditions = [maxVideoHeightArray, maxVideoWidthArray] mp4Array.Conditions = [maxVideoHeightArray, maxVideoWidthArray] end if ' surround sound if preferredSurroundSoundCodec &lt;&gt; invalid ' add preferred surround sound codec to TranscodingProfile deviceProfile.TranscodingProfiles.push({ \"Container\": preferredSurroundSoundCodec, \"Type\": \"Audio\", \"AudioCodec\": preferredSurroundSoundCodec, \"Context\": \"Streaming\", \"Protocol\": \"http\", \"MaxAudioChannels\": maxAudioChannels }) deviceProfile.TranscodingProfiles.push({ \"Container\": preferredSurroundSoundCodec, \"Type\": \"Audio\", \"AudioCodec\": preferredSurroundSoundCodec, \"Context\": \"Static\", \"Protocol\": \"http\", \"MaxAudioChannels\": maxAudioChannels }) ' move preferred codec to front of AudioCodec string tsArray.AudioCodec = setPreferredCodec(tsArray.AudioCodec, preferredSurroundSoundCodec) mp4Array.AudioCodec = setPreferredCodec(mp4Array.AudioCodec, preferredSurroundSoundCodec) end if deviceProfile.TranscodingProfiles.push(tsArray) deviceProfile.TranscodingProfiles.push(mp4Array) ' Build CodecProfiles ' H264 h264Mp4LevelSupported = 0.0 h264TsLevelSupported = 0.0 h264AssProfiles = {} h264LevelString = invalid for each container in profileSupport for each profile in profileSupport[container][\"h264\"] h264AssProfiles.AddReplace(profile, true) for each level in profileSupport[container][\"h264\"][profile] levelFloat = level.ToFloat() if container = \"mp4\" if levelFloat &gt; h264Mp4LevelSupported h264Mp4LevelSupported = levelFloat end if else if container = \"ts\" if levelFloat &gt; h264TsLevelSupported h264TsLevelSupported = levelFloat end if end if end for end for end for h264LevelString = h264Mp4LevelSupported if h264TsLevelSupported &gt; h264Mp4LevelSupported h264LevelString = h264TsLevelSupported end if ' convert to string h264LevelString = h264LevelString.ToStr() ' remove decimals h264LevelString = removeDecimals(h264LevelString) codecProfileArray = { \"Type\": \"Video\", \"Codec\": \"h264\", \"Conditions\": [ { \"Condition\": \"NotEquals\", \"Property\": \"IsAnamorphic\", \"Value\": \"true\", \"IsRequired\": false }, { \"Condition\": \"EqualsAny\", \"Property\": \"VideoProfile\", \"Value\": h264AssProfiles.Keys().join(\"|\"), \"IsRequired\": false }, { \"Condition\": \"EqualsAny\", \"Property\": \"VideoRangeType\", \"Value\": h264VideoRangeTypes, \"IsRequired\": false } ] } ' set max resolution if maxResMode = \"everything\" and maxResSetting &lt;&gt; \"off\" codecProfileArray.Conditions.push(maxVideoHeightArray) codecProfileArray.Conditions.push(maxVideoWidthArray) end if ' check user setting before adding video level restrictions if not m.global.session.user.settings[\"playback.tryDirect.h264ProfileLevel\"] codecProfileArray.Conditions.push({ \"Condition\": \"LessThanEqual\", \"Property\": \"VideoLevel\", \"Value\": h264LevelString, \"IsRequired\": false }) end if ' set bitrate restrictions based on user settings bitRateArray = GetBitRateLimit(\"h264\") if bitRateArray.count() &gt; 0 codecProfileArray.Conditions.push(bitRateArray) end if deviceProfile.CodecProfiles.push(codecProfileArray) ' MPEG2 ' NOTE: the mpeg2 levels are being saved in the profileSupport array as if they were profiles if addMpeg2 mpeg2Levels = [] for each container in profileSupport for each level in profileSupport[container][\"mpeg2\"] if not arrayHasValue(mpeg2Levels, level) mpeg2Levels.push(level) end if end for end for codecProfileArray = { \"Type\": \"Video\", \"Codec\": \"mpeg2\", \"Conditions\": [ { \"Condition\": \"EqualsAny\", \"Property\": \"VideoLevel\", \"Value\": mpeg2Levels.join(\"|\"), \"IsRequired\": false } ] } ' set max resolution if maxResMode = \"everything\" and maxResSetting &lt;&gt; \"off\" codecProfileArray.Conditions.push(maxVideoHeightArray) codecProfileArray.Conditions.push(maxVideoWidthArray) end if ' set bitrate restrictions based on user settings bitRateArray = GetBitRateLimit(\"mpeg2\") if bitRateArray.count() &gt; 0 codecProfileArray.Conditions.push(bitRateArray) end if deviceProfile.CodecProfiles.push(codecProfileArray) end if if addAv1 av1Mp4LevelSupported = 0.0 av1TsLevelSupported = 0.0 av1AssProfiles = {} av1HighestLevel = 0.0 for each container in profileSupport for each profile in profileSupport[container][\"av1\"] av1AssProfiles.AddReplace(profile, true) for each level in profileSupport[container][\"av1\"][profile] levelFloat = level.ToFloat() if container = \"mp4\" if levelFloat &gt; av1Mp4LevelSupported av1Mp4LevelSupported = levelFloat end if else if container = \"ts\" if levelFloat &gt; av1TsLevelSupported av1TsLevelSupported = levelFloat end if end if end for end for end for av1HighestLevel = av1Mp4LevelSupported if av1TsLevelSupported &gt; av1Mp4LevelSupported av1HighestLevel = av1TsLevelSupported end if codecProfileArray = { \"Type\": \"Video\", \"Codec\": \"av1\", \"Conditions\": [ { \"Condition\": \"EqualsAny\", \"Property\": \"VideoProfile\", \"Value\": av1AssProfiles.Keys().join(\"|\"), \"IsRequired\": false }, { \"Condition\": \"EqualsAny\", \"Property\": \"VideoRangeType\", \"Value\": av1VideoRangeTypes, \"IsRequired\": false }, { \"Condition\": \"LessThanEqual\", \"Property\": \"VideoLevel\", \"Value\": (120 * av1HighestLevel).ToStr(), \"IsRequired\": false } ] } ' set max resolution if maxResMode = \"everything\" and maxResSetting &lt;&gt; \"off\" codecProfileArray.Conditions.push(maxVideoHeightArray) codecProfileArray.Conditions.push(maxVideoWidthArray) end if ' set bitrate restrictions based on user settings bitRateArray = GetBitRateLimit(\"av1\") if bitRateArray.count() &gt; 0 codecProfileArray.Conditions.push(bitRateArray) end if deviceProfile.CodecProfiles.push(codecProfileArray) end if if addHevc hevcMp4LevelSupported = 0.0 hevcTsLevelSupported = 0.0 hevcAssProfiles = {} hevcHighestLevel = 0.0 for each container in profileSupport for each profile in profileSupport[container][\"hevc\"] hevcAssProfiles.AddReplace(profile, true) for each level in profileSupport[container][\"hevc\"][profile] levelFloat = level.ToFloat() if container = \"mp4\" if levelFloat &gt; hevcMp4LevelSupported hevcMp4LevelSupported = levelFloat end if else if container = \"ts\" if levelFloat &gt; hevcTsLevelSupported hevcTsLevelSupported = levelFloat end if end if end for end for end for hevcHighestLevel = hevcMp4LevelSupported if hevcTsLevelSupported &gt; hevcMp4LevelSupported hevcHighestLevel = hevcTsLevelSupported end if hevcLevelString = \"120\" if hevcHighestLevel = 5.1 hevcLevelString = \"153\" end if codecProfileArray = { \"Type\": \"Video\", \"Codec\": \"hevc\", \"Conditions\": [ { \"Condition\": \"NotEquals\", \"Property\": \"IsAnamorphic\", \"Value\": \"true\", \"IsRequired\": false }, { \"Condition\": \"EqualsAny\", \"Property\": \"VideoProfile\", \"Value\": profileSupport[\"ts\"][\"hevc\"].Keys().join(\"|\"), \"IsRequired\": false }, { \"Condition\": \"EqualsAny\", \"Property\": \"VideoRangeType\", \"Value\": hevcVideoRangeTypes, \"IsRequired\": false } ] } ' set max resolution if maxResMode = \"everything\" and maxResSetting &lt;&gt; \"off\" codecProfileArray.Conditions.push(maxVideoHeightArray) codecProfileArray.Conditions.push(maxVideoWidthArray) end if ' check user setting before adding VideoLevel restrictions if not m.global.session.user.settings[\"playback.tryDirect.hevcProfileLevel\"] codecProfileArray.Conditions.push({ \"Condition\": \"LessThanEqual\", \"Property\": \"VideoLevel\", \"Value\": hevcLevelString, \"IsRequired\": false }) end if ' set bitrate restrictions based on user settings bitRateArray = GetBitRateLimit(\"h265\") if bitRateArray.count() &gt; 0 codecProfileArray.Conditions.push(bitRateArray) end if deviceProfile.CodecProfiles.push(codecProfileArray) end if if addVp9 vp9Profiles = [] for each container in profileSupport for each profile in profileSupport[container][\"vp9\"] if vp9Profiles[profile] = invalid vp9Profiles.push(profile) end if end for end for codecProfileArray = { \"Type\": \"Video\", \"Codec\": \"vp9\", \"Conditions\": [ { \"Condition\": \"EqualsAny\", \"Property\": \"VideoLevel\", \"Value\": vp9Profiles.join(\"|\"), \"IsRequired\": false }, { \"Condition\": \"EqualsAny\", \"Property\": \"VideoRangeType\", \"Value\": vp9VideoRangeTypes, \"IsRequired\": false } ] } ' set max resolution if maxResMode = \"everything\" and maxResSetting &lt;&gt; \"off\" codecProfileArray.Conditions.push(maxVideoHeightArray) codecProfileArray.Conditions.push(maxVideoWidthArray) end if ' set bitrate restrictions based on user settings bitRateArray = GetBitRateLimit(\"vp9\") if bitRateArray.count() &gt; 0 codecProfileArray.Conditions.push(bitRateArray) end if deviceProfile.CodecProfiles.push(codecProfileArray) end if return deviceProfile end function function GetDirectPlayProfiles() as object di = CreateObject(\"roDeviceInfo\") ' all possible containers supportedCodecs = { mp4: { audio: [], video: [] }, hls: { audio: [], video: [] }, mkv: { audio: [], video: [] }, ism: { audio: [], video: [] }, dash: { audio: [], video: [] }, ts: { audio: [], video: [] } } ' all possible codecs (besides those restricted by user settings) videoCodecs = [\"h264\", \"mpeg4 avc\", \"vp8\", \"vp9\", \"h263\", \"mpeg1\"] audioCodecs = [\"mp3\", \"mp2\", \"pcm\", \"lpcm\", \"wav\", \"ac3\", \"ac4\", \"aiff\", \"wma\", \"flac\", \"alac\", \"aac\", \"opus\", \"dts\", \"wmapro\", \"vorbis\", \"eac3\", \"mpg123\"] ' check if hevc is disabled if m.global.session.user.settings[\"playback.compatibility.disablehevc\"] = false videoCodecs.push(\"hevc\") end if ' check video codecs for each container for each container in supportedCodecs for each videoCodec in videoCodecs if di.CanDecodeVideo({ Codec: videoCodec, Container: container }).Result if videoCodec = \"hevc\" supportedCodecs[container][\"video\"].push(\"hevc\") supportedCodecs[container][\"video\"].push(\"h265\") else ' device profile string matches codec string supportedCodecs[container][\"video\"].push(videoCodec) end if end if end for end for ' user setting overrides if m.global.session.user.settings[\"playback.mpeg4\"] for each container in supportedCodecs supportedCodecs[container][\"video\"].push(\"mpeg4\") end for end if if m.global.session.user.settings[\"playback.mpeg2\"] for each container in supportedCodecs supportedCodecs[container][\"video\"].push(\"mpeg2video\") end for end if ' video codec overrides ' these codecs play fine but are not correctly detected using CanDecodeVideo() if di.CanDecodeVideo({ Codec: \"av1\" }).Result ' codec must be checked by itself or the result will always be false for each container in supportedCodecs supportedCodecs[container][\"video\"].push(\"av1\") end for end if ' check audio codecs for each container for each container in supportedCodecs for each audioCodec in audioCodecs if di.CanDecodeAudio({ Codec: audioCodec, Container: container }).Result supportedCodecs[container][\"audio\"].push(audioCodec) end if end for end for ' check audio codecs with no container supportedAudio = [] for each audioCodec in audioCodecs if di.CanDecodeAudio({ Codec: audioCodec }).Result supportedAudio.push(audioCodec) end if end for ' build return array returnArray = [] for each container in supportedCodecs videoCodecString = supportedCodecs[container][\"video\"].Join(\",\") if videoCodecString &lt;&gt; \"\" containerString = container if container = \"mp4\" containerString = \"mp4,mov,m4v\" else if container = \"mkv\" containerString = \"mkv,webm\" end if returnArray.push({ \"Container\": containerString, \"Type\": \"Video\", \"VideoCodec\": videoCodecString, \"AudioCodec\": supportedCodecs[container][\"audio\"].Join(\",\") }) end if end for returnArray.push({ \"Container\": supportedAudio.Join(\",\"), \"Type\": \"Audio\" }) return returnArray end function function GetBitRateLimit(codec as string) as object if m.global.session.user.settings[\"playback.bitrate.maxlimited\"] = true userSetLimit = m.global.session.user.settings[\"playback.bitrate.limit\"].ToInt() if isValid(userSetLimit) and type(userSetLimit) = \"Integer\" and userSetLimit &gt; 0 userSetLimit *= 1000000 return { \"Condition\": \"LessThanEqual\", \"Property\": \"VideoBitrate\", \"Value\": userSetLimit.ToStr(), \"IsRequired\": true } else codec = Lcase(codec) ' Some repeated values (e.g. same \"40mbps\" for several codecs) ' but this makes it easy to update in the future if the bitrates start to deviate. if codec = \"h264\" ' Roku only supports h264 up to 10Mpbs return { \"Condition\": \"LessThanEqual\", \"Property\": \"VideoBitrate\", \"Value\": \"10000000\", \"IsRequired\": true } else if codec = \"av1\" ' Roku only supports AV1 up to 40Mpbs return { \"Condition\": \"LessThanEqual\", \"Property\": \"VideoBitrate\", \"Value\": \"40000000\", \"IsRequired\": true } else if codec = \"h265\" ' Roku only supports h265 up to 40Mpbs return { \"Condition\": \"LessThanEqual\", \"Property\": \"VideoBitrate\", \"Value\": \"40000000\", \"IsRequired\": true } else if codec = \"vp9\" ' Roku only supports VP9 up to 40Mpbs return { \"Condition\": \"LessThanEqual\", \"Property\": \"VideoBitrate\", \"Value\": \"40000000\", \"IsRequired\": true } end if end if end if return {} end function ' Recieves and returns an assArray of supported profiles and levels for each video codec function updateProfileArray(profileArray as object, videoCodec as string, videoProfile as string, profileLevel = \"\" as string) as object ' validate params if profileArray = invalid then return {} if videoCodec = \"\" or videoProfile = \"\" then return profileArray if profileArray[videoCodec] = invalid profileArray[videoCodec] = {} end if if profileArray[videoCodec][videoProfile] = invalid profileArray[videoCodec][videoProfile] = {} end if ' add profileLevel if a value was provided if profileLevel &lt;&gt; \"\" if profileArray[videoCodec][videoProfile][profileLevel] = invalid profileArray[videoCodec][videoProfile].AddReplace(profileLevel, true) end if end if ' profileSupport[container][codec][profile][level] return profileArray end function ' Remove all decimals from a string function removeDecimals(value as string) as string r = CreateObject(\"roRegex\", \"\\.\", \"\") value = r.ReplaceAll(value, \"\") return value end function ' Takes and returns a comma delimited string of codecs. ' Moves the preferred codec to the front of the string function setPreferredCodec(codecString as string, preferredCodec as string) as string if preferredCodec = \"\" then return \"\" if codecString = \"\" then return preferredCodec preferredCodecSize = Len(preferredCodec) ' is the codec already in front? if Left(codecString, preferredCodecSize) = preferredCodec return codecString else ' convert string to array codecArray = codecString.Split(\",\") ' remove preferred codec from array newArray = [] for each codec in codecArray if codec &lt;&gt; preferredCodec newArray.push(codec) end if end for ' convert newArray to string newCodecString = newArray.Join(\",\") ' add preferred codec to front of newCodecString newCodecString = preferredCodec + \",\" + newCodecString return newCodecString end if end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"source_utils_globals.brs.html":{"id":"source_utils_globals.brs.html","title":"Source: source/utils/globals.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: source/utils/globals.brs ' Set global constants sub setConstants() globals = m.screen.getGlobalNode() ' Set Global Constants globals.addFields({ constants: { poster_bg_pallet: [\"#00455c\", \"#44bae1\", \"#00a4db\", \"#1c4c5c\", \"#007ea8\"], colors: { button: \"#006fab\", blue: \"#00a4dcFF\" }, icons: { ascending_black: \"pkg:/images/icons/up_black.png\", ascending_white: \"pkg:/images/icons/up_white.png\", descending_black: \"pkg:/images/icons/down_black.png\", descending_white: \"pkg:/images/icons/down_white.png\", check_black: \"pkg:/images/icons/check_black.png\", check_white: \"pkg:/images/icons/check_white.png\" } } }) end sub ' Save information from roAppInfo to m.global.app sub SaveAppToGlobal() appInfo = CreateObject(\"roAppInfo\") lastRunVersion = get_setting(\"LastRunVersion\") m.global.addFields({ app: { id: appInfo.GetID(), isDev: appInfo.IsDev(), version: appInfo.GetVersion(), lastRunVersion: lastRunVersion } }) end sub ' Save information from roDeviceInfo to m.global.device sub SaveDeviceToGlobal() deviceInfo = CreateObject(\"roDeviceInfo\") ' remove special characters regex = CreateObject(\"roRegex\", \"[^a-zA-Z0-9\\ \\-\\_]\", \"\") filteredFriendly = regex.ReplaceAll(deviceInfo.getFriendlyName(), \"\") ' parse out serial displayName = deviceInfo.getModelDisplayName() deviceSerial = Mid(filteredFriendly, len(displayName) + 4) ' determine max playback resolution ' https://developer.roku.com/en-ca/docs/references/brightscript/interfaces/ifdeviceinfo.md#getvideomode-as-string videoMode = deviceInfo.GetVideoMode() iPos = Instr(1, videoMode, \"i\") pPos = Instr(1, videoMode, \"p\") videoHeight = invalid videoWidth = invalid refreshRate = \"0\" bitDepth = 8 extraData = invalid heightToWidth = { \"480\": \"720\", \"576\": \"720\", \"720\": \"1280\", \"1080\": \"1920\", \"2160\": \"3840\", \"4320\": \"7680\" } if iPos &gt; 0 and pPos = 0 ' videMode = 000i videoHeight = mid(videoMode, 1, iPos - 1) ' save refresh rate if Len(videoMode) &gt; iPos refreshRate = mid(videoMode, iPos + 1, 2) end if ' save whats left of string if Len(videoMode) &gt; iPos + 2 extraData = mid(videoMode, iPos + 3) end if else if iPos = 0 and pPos &gt; 0 ' videMode = 000p videoHeight = mid(videoMode, 1, pPos - 1) ' save refresh rate if Len(videoMode) &gt; pPos refreshRate = mid(videoMode, pPos + 1, 2) end if ' save whats left of string if Len(videoMode) &gt; pPos + 2 extraData = mid(videoMode, pPos + 3) end if else 'i and p not present in videoMode print \"ERROR parsing deviceInfo.GetVideoMode()\" end if videoWidth = heightToWidth[videoHeight] if videoHeight = \"2160\" and extraData = \"b10\" bitDepth = 10 else if videoHeight = \"4320\" bitDepth = 12 end if m.global.addFields({ device: { id: deviceInfo.getChannelClientID(), uuid: deviceInfo.GetRandomUUID(), name: displayName, friendlyName: filteredFriendly, serverDeviceName: deviceInfo.getChannelClientID(), model: deviceInfo.GetModel(), modelType: deviceInfo.GetModelType(), modelDetails: deviceInfo.GetModelDetails(), serial: deviceSerial, osVersion: deviceInfo.GetOSVersion(), locale: deviceInfo.GetCurrentLocale(), clockFormat: deviceInfo.GetClockFormat(), isAudioGuideEnabled: deviceInfo.IsAudioGuideEnabled(), hasVoiceRemote: deviceInfo.HasFeature(\"voice_remote\"), displayType: deviceInfo.GetDisplayType(), displayMode: deviceInfo.GetDisplayMode(), videoMode: videoMode, videoHeight: videoHeight, videoWidth: videoWidth, videoRefresh: StrToI(refreshRate), videoBitDepth: bitDepth } }) end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"source_migrations.bs.html":{"id":"source_migrations.bs.html","title":"Source: source/migrations.bs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: source/migrations.bs import \"pkg:/source/utils/misc.brs\" ' Functions that update the registry based on the last run version and the currently running version ' Run all necessary registry mirations on the \"global\" Jellyfin registry section sub runGlobalMigrations() ' Global registry migrations if isValid(m.global.app.lastRunVersion) and not versionChecker(m.global.app.lastRunVersion, \"1.7.0\") ' last app version used was less than 1.7.0 print \"Running 1.7.0 global registry migrations\" ' no longer saving raw password to registry ' auth token and username are now stored in user settings and not global settings savedUserId = get_setting(\"active_user\") if isValid(savedUserId) registry_write(\"serverId\", m.global.session.server.id, savedUserId) ' copy saved credentials to user block savedUsername = get_setting(\"username\") if isValid(savedUsername) registry_write(\"username\", savedUsername, savedUserId) end if savedToken = get_setting(\"token\") if isValid(savedToken) registry_write(\"token\", savedToken, savedUserId) end if end if unset_setting(\"port\") unset_setting(\"token\") unset_setting(\"username\") unset_setting(\"password\") ' remove saved credentials from saved_servers saved = get_setting(\"saved_servers\") if isValid(saved) savedServers = ParseJson(saved) if isValid(savedServers.serverList) and savedServers.serverList.Count() &gt; 0 newServers = { serverList: [] } for each item in savedServers.serverList item.Delete(\"username\") item.Delete(\"password\") newServers.serverList.Push(item) end for set_setting(\"saved_servers\", FormatJson(newServers)) end if end if end if if m.global.app.lastRunVersion &lt;&gt; invalid runRegistryUserMigrations(m.global.app.lastRunVersion) end if end sub sub runRegistryUserMigrations(version as string) regSections = getRegistrySections() for each section in regSections if LCase(section) &lt;&gt; \"jellyfin\" if version = \"1.7.0\" print \"Running User Registry Migration for 1.7.0\" ' now saving LastRunVersion globally and per user so that we can run user specific registry migrations ' duplicate LastRunVersion to all user settings in the registry so that we can run user specific migrations ' ' now saving LastRunVersion per user in addition to globally registry_write(\"LastRunVersion\", m.global.app.version, section) ' no longer saving password to registry registry_delete(\"password\", section) ' av1 playback no longer hidden behind user setting registry_delete(\"playback.av1\", section) end if end if end for end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"source_utils_misc.brs.html":{"id":"source_utils_misc.brs.html","title":"Source: source/utils/misc.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: source/utils/misc.brs function isNodeEvent(msg, field as string) as boolean return type(msg) = \"roSGNodeEvent\" and msg.getField() = field end function function getMsgPicker(msg, subnode = \"\" as string) as object node = msg.getRoSGNode() ' Subnode allows for handling alias messages if subnode &lt;&gt; \"\" node = node.findNode(subnode) end if coords = node.rowItemSelected target = node.content.getChild(coords[0]).getChild(coords[1]) return target end function function getButton(msg, subnode = \"buttons\" as string) as object buttons = msg.getRoSGNode().findNode(subnode) if buttons = invalid then return invalid active_button = buttons.focusedChild return active_button end function function leftPad(base as string, fill as string, length as integer) as string while len(base) &lt; length base = fill + base end while return base end function function ticksToHuman(ticks as longinteger) as string totalSeconds = int(ticks / 10000000) hours = stri(int(totalSeconds / 3600)).trim() minutes = stri(int((totalSeconds - (val(hours) * 3600)) / 60)).trim() seconds = stri(totalSeconds - (val(hours) * 3600) - (val(minutes) * 60)).trim() if val(hours) &gt; 0 and val(minutes) &lt; 10 then minutes = \"0\" + minutes if val(seconds) &lt; 10 then seconds = \"0\" + seconds r = \"\" if val(hours) &gt; 0 then r = hours + \":\" r = r + minutes + \":\" + seconds return r end function function secondsToHuman(totalSeconds as integer) as string hours = stri(int(totalSeconds / 3600)).trim() minutes = stri(int((totalSeconds - (val(hours) * 3600)) / 60)).trim() seconds = stri(totalSeconds - (val(hours) * 3600) - (val(minutes) * 60)).trim() if val(hours) &gt; 0 and val(minutes) &lt; 10 then minutes = \"0\" + minutes if val(seconds) &lt; 10 then seconds = \"0\" + seconds r = \"\" if val(hours) &gt; 0 then r = hours + \":\" r = r + minutes + \":\" + seconds return r end function ' Format time as 12 or 24 hour format based on system clock setting function formatTime(time) as string hours = time.getHours() minHourDigits = 1 if m.global.device.clockFormat = \"12h\" meridian = \"AM\" if hours = 0 hours = 12 meridian = \"AM\" else if hours = 12 hours = 12 meridian = \"PM\" else if hours &gt; 12 hours = hours - 12 meridian = \"PM\" end if else ' For 24hr Clock, no meridian and pad hours to 2 digits minHourDigits = 2 meridian = \"\" end if return Substitute(\"{0}:{1} {2}\", leftPad(stri(hours).trim(), \"0\", minHourDigits), leftPad(stri(time.getMinutes()).trim(), \"0\", 2), meridian) end function function div_ceiling(a as integer, b as integer) as integer if a &lt; b then return 1 if int(a / b) = a / b return a / b end if return a / b + 1 end function 'Returns the item selected or -1 on backpress or other unhandled closure of dialog. function get_dialog_result(dialog, port) while dialog &lt;&gt; invalid msg = wait(0, port) if isNodeEvent(msg, \"backPressed\") return -1 else if isNodeEvent(msg, \"itemSelected\") return dialog.findNode(\"optionList\").itemSelected end if end while 'Dialog has closed outside of this loop, return -1 for failure return -1 end function function lastFocusedChild(obj as object) as object if isValid(obj) if isValid(obj.focusedChild) and isValid(obj.focusedChild.focusedChild) and LCase(obj.focusedChild.focusedChild.subType()) = \"tvepisodes\" if isValid(obj.focusedChild.focusedChild.lastFocus) return obj.focusedChild.focusedChild.lastFocus end if end if child = obj for i = 0 to obj.getChildCount() if isValid(obj.focusedChild) child = child.focusedChild end if end for return child else return invalid end if end function function show_dialog(message as string, options = [], defaultSelection = 0) as integer lastFocus = lastFocusedChild(m.scene) dialog = createObject(\"roSGNode\", \"JFMessageDialog\") if options.count() then dialog.options = options if message.len() &gt; 0 reg = CreateObject(\"roFontRegistry\") font = reg.GetDefaultFont() dialog.fontHeight = font.GetOneLineHeight() dialog.fontWidth = font.GetOneLineWidth(message, 999999999) dialog.message = message end if if defaultSelection &gt; 0 dialog.findNode(\"optionList\").jumpToItem = defaultSelection end if dialog.visible = true m.scene.appendChild(dialog) dialog.setFocus(true) port = CreateObject(\"roMessagePort\") dialog.observeField(\"backPressed\", port) dialog.findNode(\"optionList\").observeField(\"itemSelected\", port) result = get_dialog_result(dialog, port) m.scene.removeChildIndex(m.scene.getChildCount() - 1) lastFocus.setFocus(true) return result end function function message_dialog(message = \"\" as string) return show_dialog(message, [\"OK\"]) end function function option_dialog(options, message = \"\", defaultSelection = 0) as integer return show_dialog(message, options, defaultSelection) end function ' ' Take a jellyfin hostname and ensure it's a full url. ' prepend http or https and append default ports, and remove excess slashes ' function standardize_jellyfin_url(url as string) 'Append default ports maxSlashes = 0 if left(url, 8) = \"https://\" or left(url, 7) = \"http://\" maxSlashes = 2 end if 'Check to make sure entry has no extra slashes before adding default ports. if Instr(0, url, \"/\") = maxSlashes if url.len() &gt; 5 and mid(url, url.len() - 4, 1) &lt;&gt; \":\" and mid(url, url.len() - 5, 1) &lt;&gt; \":\" if left(url, 5) = \"https\" url = url + \":8920\" else url = url + \":8096\" end if end if end if 'Append http:// to server if left(url, 4) &lt;&gt; \"http\" url = \"http://\" + url end if return url end function sub setFieldTextValue(field, value) node = m.top.findNode(field) if node = invalid or value = invalid then return ' Handle non strings... Which _shouldn't_ happen, but hey if type(value) = \"roInt\" or type(value) = \"Integer\" value = str(value).trim() else if type(value) = \"roFloat\" or type(value) = \"Float\" value = str(value).trim() else if type(value) &lt;&gt; \"roString\" and type(value) &lt;&gt; \"String\" value = \"\" end if node.text = value end sub ' Returns whether or not passed value is valid function isValid(input as dynamic) as boolean return input &lt;&gt; invalid end function ' Returns whether or not passed value is valid and not empty ' Accepts a string, or any countable type (arrays and lists) function isValidAndNotEmpty(input as dynamic) as boolean if not isValid(input) then return false ' Use roAssociativeArray instead of list so we get access to the doesExist() method countableTypes = { \"array\": 1, \"list\": 1, \"roarray\": 1, \"roassociativearray\": 1, \"rolist\": 1 } inputType = LCase(type(input)) if inputType = \"string\" or inputType = \"rostring\" trimmedInput = input.trim() return trimmedInput &lt;&gt; \"\" else if countableTypes.doesExist(inputType) return input.count() &gt; 0 else print \"Called isValidAndNotEmpty() with invalid type: \", inputType return false end if end function ' Returns an array from a url - [ url, proto, host, port, subdir/params ] ' If port or subdir are not found, an empty string will be added to the array ' Proto must be declared or array will be empty function parseUrl(url as string) as object rgx = CreateObject(\"roRegex\", \"^(.*:)//([A-Za-z0-9\\-\\.]+)(:[0-9]+)?(.*)$\", \"\") return rgx.Match(url) end function ' Returns true if the string is a loopback, such as 'localhost' or '127.0.0.1' function isLocalhost(url as string) as boolean ' https://stackoverflow.com/questions/8426171/what-regex-will-match-all-loopback-addresses rgx = CreateObject(\"roRegex\", \"^localhost$|^127(?:\\.[0-9]+){0,2}\\.[0-9]+$|^(?:0*\\:)*?:?0*1$\", \"i\") return rgx.isMatch(url) end function ' Rounds number to nearest integer function roundNumber(f as float) as integer ' BrightScript only has a \"floor\" round ' This compares floor to floor + 1 to find which is closer m = int(f) n = m + 1 x = abs(f - m) y = abs(f - n) if y &gt; x return m else return n end if end function ' Converts ticks to minutes function getMinutes(ticks) as integer ' A tick is .1ms, so 1/10,000,000 for ticks to seconds, ' then 1/60 for seconds to minutes... 1/600,000,000 return roundNumber(ticks / 600000000.0) end function ' ' Returns whether or not a version number (e.g. 10.7.7) is greater or equal ' to some minimum version allowed (e.g. 10.8.0) function versionChecker(versionToCheck as string, minVersionAccepted as string) leftHand = CreateObject(\"roLongInteger\") rightHand = CreateObject(\"roLongInteger\") regEx = CreateObject(\"roRegex\", \"\\.\", \"\") version = regEx.Split(versionToCheck) if version.Count() &lt; 3 for i = version.Count() to 3 step 1 version.AddTail(\"0\") end for end if minVersion = regEx.Split(minVersionAccepted) if minVersion.Count() &lt; 3 for i = minVersion.Count() to 3 step 1 minVersion.AddTail(\"0\") end for end if leftHand = (version[0].ToInt() * 10000) + (version[1].ToInt() * 100) + (version[2].ToInt() * 10) rightHand = (minVersion[0].ToInt() * 10000) + (minVersion[1].ToInt() * 100) + (minVersion[2].ToInt() * 10) return leftHand &gt;= rightHand end function function findNodeBySubtype(node, subtype) foundNodes = [] for each child in node.getChildren(-1, 0) if lcase(child.subtype()) = \"group\" return findNodeBySubtype(child, subtype) end if if lcase(child.subtype()) = lcase(subtype) foundNodes.push({ node: child, parent: node }) end if end for return foundNodes end function function AssocArrayEqual(Array1 as object, Array2 as object) as boolean if not isValid(Array1) or not isValid(Array2) return false end if if not Array1.Count() = Array2.Count() return false end if for each key in Array1 if not Array2.DoesExist(key) return false end if if Array1[key] &lt;&gt; Array2[key] return false end if end for return true end function ' Search string array for search value. Return if it's found function inArray(haystack, needle) as boolean valueToFind = needle if LCase(type(valueToFind)) &lt;&gt; \"rostring\" and LCase(type(valueToFind)) &lt;&gt; \"string\" valueToFind = str(needle) end if valueToFind = lcase(valueToFind) for each item in haystack if lcase(item) = valueToFind then return true end for return false end function function toString(input) as string if LCase(type(input)) = \"rostring\" or LCase(type(input)) = \"string\" return input end if return str(input) end function sub startLoadingSpinner() m.spinner = createObject(\"roSGNode\", \"Spinner\") m.spinner.translation = \"[900, 450]\" m.spinner.visible = true m.scene.appendChild(m.spinner) end sub sub startMediaLoadingSpinner() dialog = createObject(\"roSGNode\", \"ProgressDialog\") dialog.id = \"invisibiledialog\" dialog.visible = false m.scene.dialog = dialog startLoadingSpinner() end sub sub stopLoadingSpinner() if isValid(m.spinner) m.spinner.visible = false end if if isValid(m.scene) and isValid(m.scene.dialog) m.scene.dialog.close = true end if end sub ' Check if a specific value is inside of an array function arrayHasValue(arr as object, value as dynamic) as boolean for each entry in arr if entry = value return true end if end for return false end function ' Takes an array of data, shuffles the order, then returns the array ' uses the Fisher-Yates shuffling algorithm function shuffleArray(array as object) as object for i = array.count() - 1 to 1 step -1 j = Rnd(i + 1) - 1 t = array[i] : array[i] = array[j] : array[j] = t end for return array end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"source_utils_quickplay.bs.html":{"id":"source_utils_quickplay.bs.html","title":"Source: source/utils/quickplay.bs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: source/utils/quickplay.bs ' All of the Quick Play logic seperated by media type namespace quickplay ' Takes an array of items and adds to global queue. ' Also shuffles the playlist if asked sub pushToQueue(queueArray as object, shufflePlay = false as boolean) if isValidAndNotEmpty(queueArray) ' load everything for each item in queueArray m.global.queueManager.callFunc(\"push\", item) end for ' shuffle the playlist if asked if shufflePlay and m.global.queueManager.callFunc(\"getCount\") &gt; 1 m.global.queueManager.callFunc(\"toggleShuffle\") end if end if end sub ' A single video file. sub video(itemNode as object) if not isValid(itemNode) or not isValid(itemNode.id) or not isValid(itemNode.json) then return ' attempt to play video file. resume if possible if isValid(itemNode.selectedVideoStreamId) itemNode.id = itemNode.selectedVideoStreamId end if audio_stream_idx = 0 if isValid(itemNode.selectedAudioStreamIndex) and itemNode.selectedAudioStreamIndex &gt; 0 audio_stream_idx = itemNode.selectedAudioStreamIndex end if itemNode.selectedAudioStreamIndex = audio_stream_idx playbackPosition = 0 if isValid(itemNode.json.userdata) and isValid(itemNode.json.userdata.PlaybackPositionTicks) playbackPosition = itemNode.json.userdata.PlaybackPositionTicks end if itemNode.startingPoint = playbackPosition m.global.queueManager.callFunc(\"push\", itemNode) end sub ' A single audio file. sub audio(itemNode as object) if not isValid(itemNode) or not isValid(itemNode.id) then return m.global.queueManager.callFunc(\"push\", itemNode) end sub ' A single music video file. sub musicVideo(itemNode as object) if not isValid(itemNode) or not isValid(itemNode.id) or not isValid(itemNode.json) then return m.global.queueManager.callFunc(\"push\", itemNode) end sub ' A music album. ' Play the entire album starting with track 1. sub album(itemNode as object) if not isValid(itemNode) or not isValid(itemNode.id) then return ' grab list of songs in the album albumSongs = api.users.GetItemsByQuery(m.global.session.user.id, { \"parentId\": itemNode.id, \"imageTypeLimit\": 1, \"sortBy\": \"SortName\", \"limit\": 2000, \"enableUserData\": false, \"EnableTotalRecordCount\": false }) if isValid(albumSongs) and isValidAndNotEmpty(albumSongs.items) quickplay.pushToQueue(albumSongs.items) end if end sub ' A music artist. ' Shuffle play all songs by artist. sub artist(itemNode as object) if not isValid(itemNode) or not isValid(itemNode.id) then return ' get all songs by artist artistSongs = api.users.GetItemsByQuery(m.global.session.user.id, { \"artistIds\": itemNode.id, \"includeItemTypes\": \"Audio\", \"sortBy\": \"Album\", \"limit\": 2000, \"imageTypeLimit\": 1, \"Recursive\": true, \"enableUserData\": false, \"EnableTotalRecordCount\": false }) print \"artistSongs=\", artistSongs if isValid(artistSongs) and isValidAndNotEmpty(artistSongs.items) quickplay.pushToQueue(artistSongs.items, true) end if end sub ' A boxset. ' Play all items inside. sub boxset(itemNode as object) if not isValid(itemNode) or not isValid(itemNode.id) then return data = api.items.GetByQuery({ \"userid\": m.global.session.user.id, \"parentid\": itemNode.id, \"limit\": 2000, \"EnableTotalRecordCount\": false }) if isValid(data) and isValidAndNotEmpty(data.Items) quickplay.pushToQueue(data.items) end if end sub ' A TV Show Series. ' Play the first unwatched episode. ' If none, shuffle play the whole series. sub series(itemNode as object) if not isValid(itemNode) or not isValid(itemNode.id) then return data = api.shows.GetNextUp({ \"seriesId\": itemNode.id, \"recursive\": true, \"SortBy\": \"DatePlayed\", \"SortOrder\": \"Descending\", \"ImageTypeLimit\": 1, \"UserId\": m.global.session.user.id, \"EnableRewatching\": false, \"DisableFirstEpisode\": false, \"EnableTotalRecordCount\": false }) if isValid(data) and isValidAndNotEmpty(data.Items) ' there are unwatched episodes m.global.queueManager.callFunc(\"push\", data.Items[0]) else ' next up check was empty ' check for a resumable episode data = api.users.GetResumeItemsByQuery(m.global.session.user.id, { \"parentId\": itemNode.id, \"userid\": m.global.session.user.id, \"SortBy\": \"DatePlayed\", \"recursive\": true, \"SortOrder\": \"Descending\", \"Filters\": \"IsResumable\", \"EnableTotalRecordCount\": false }) print \"resumeitems data=\", data if isValid(data) and isValidAndNotEmpty(data.Items) ' play the resumable episode if isValid(data.Items[0].UserData) and isValid(data.Items[0].UserData.PlaybackPositionTicks) data.Items[0].startingPoint = data.Items[0].userdata.PlaybackPositionTicks end if m.global.queueManager.callFunc(\"push\", data.Items[0]) else ' shuffle all episodes data = api.shows.GetEpisodes(itemNode.id, { \"userid\": m.global.session.user.id, \"SortBy\": \"Random\", \"limit\": 2000, \"EnableTotalRecordCount\": false }) if isValid(data) and isValidAndNotEmpty(data.Items) ' add all episodes found to a playlist quickplay.pushToQueue(data.Items) end if end if end if end sub ' More than one TV Show Series. ' Shuffle play all watched episodes sub multipleSeries(itemNodes as object) if isValidAndNotEmpty(itemNodes) numTotal = 0 numLimit = 2000 for each tvshow in itemNodes ' grab all watched episodes for each series showData = api.shows.GetEpisodes(tvshow.id, { \"userId\": m.global.session.user.id, \"SortBy\": \"Random\", \"imageTypeLimit\": 0, \"EnableTotalRecordCount\": false, \"enableImages\": false }) if isValid(showData) and isValidAndNotEmpty(showData.items) playedEpisodes = [] ' add all played episodes to queue for each episode in showData.items if isValid(episode.userdata) and isValid(episode.userdata.Played) if episode.userdata.Played playedEpisodes.push(episode) end if end if end for quickplay.pushToQueue(playedEpisodes) ' keep track of how many items we've seen numTotal = numTotal + showData.items.count() if numTotal &gt;= numLimit ' stop grabbing more items if we hit our limit exit for end if end if end for if m.global.queueManager.callFunc(\"getCount\") &gt; 1 m.global.queueManager.callFunc(\"toggleShuffle\") end if end if end sub ' A TV Show Season. ' Play the first unwatched episode. ' If none, play the whole season starting with episode 1. sub season(itemNode as object) if not isValid(itemNode) or not isValid(itemNode.id) then return unwatchedData = api.shows.GetEpisodes(itemNode.json.SeriesId, { \"seasonId\": itemNode.id, \"userid\": m.global.session.user.id, \"limit\": 2000, \"EnableTotalRecordCount\": false }) if isValid(unwatchedData) and isValidAndNotEmpty(unwatchedData.Items) ' find the first unwatched episode firstUnwatchedEpisodeIndex = invalid for each item in unwatchedData.Items if isValid(item.UserData) if isValid(item.UserData.Played) and item.UserData.Played = false firstUnwatchedEpisodeIndex = item.IndexNumber - 1 if isValid(item.UserData.PlaybackPositionTicks) item.startingPoint = item.UserData.PlaybackPositionTicks end if exit for end if end if end for if isValid(firstUnwatchedEpisodeIndex) ' add the first unwatched episode and the rest of the season to a playlist for i = firstUnwatchedEpisodeIndex to unwatchedData.Items.count() - 1 m.global.queueManager.callFunc(\"push\", unwatchedData.Items[i]) end for else ' try to find a \"continue watching\" episode continueData = api.users.GetResumeItemsByQuery(m.global.session.user.id, { \"parentId\": itemNode.id, \"userid\": m.global.session.user.id, \"SortBy\": \"DatePlayed\", \"recursive\": true, \"SortOrder\": \"Descending\", \"Filters\": \"IsResumable\", \"EnableTotalRecordCount\": false }) if isValid(continueData) and isValidAndNotEmpty(continueData.Items) ' play the resumable episode for each item in continueData.Items if isValid(item.UserData) and isValid(item.UserData.PlaybackPositionTicks) item.startingPoint = item.userdata.PlaybackPositionTicks end if m.global.queueManager.callFunc(\"push\", item) end for else ' play the whole season in order if isValid(unwatchedData) and isValidAndNotEmpty(unwatchedData.Items) ' add all episodes found to a playlist pushToQueue(unwatchedData.Items) end if end if end if end if end sub ' Quick Play A Person. ' Shuffle play all videos found sub person(itemNode as object) if not isValid(itemNode) or not isValid(itemNode.id) then return ' get movies and videos by the person personMovies = api.users.GetItemsByQuery(m.global.session.user.id, { \"personIds\": itemNode.id, \"includeItemTypes\": \"Movie,Video\", \"excludeItemTypes\": \"Season,Series\", \"recursive\": true, \"limit\": 2000 }) print \"personMovies=\", personMovies if isValid(personMovies) and isValidAndNotEmpty(personMovies.Items) ' add each item to the queue quickplay.pushToQueue(personMovies.Items) end if ' get watched episodes by the person personEpisodes = api.users.GetItemsByQuery(m.global.session.user.id, { \"personIds\": itemNode.id, \"includeItemTypes\": \"Episode\", \"isPlayed\": true, \"excludeItemTypes\": \"Season,Series\", \"recursive\": true, \"limit\": 2000 }) print \"personEpisodes=\", personEpisodes if isValid(personEpisodes) and isValidAndNotEmpty(personEpisodes.Items) ' add each item to the queue quickplay.pushToQueue(personEpisodes.Items) end if if m.global.queueManager.callFunc(\"getCount\") &gt; 1 m.global.queueManager.callFunc(\"toggleShuffle\") end if end sub ' Quick Play A TVChannel sub tvChannel(itemNode as object) if not isValid(itemNode) or not isValid(itemNode.id) then return stopLoadingSpinner() group = CreateVideoPlayerGroup(itemNode.id) m.global.sceneManager.callFunc(\"pushScene\", group) end sub ' Quick Play A Live Program sub program(itemNode as object) if not isValid(itemNode) or not isValid(itemNode.json) or not isValid(itemNode.json.ChannelId) then return stopLoadingSpinner() group = CreateVideoPlayerGroup(itemNode.json.ChannelId) m.global.sceneManager.callFunc(\"pushScene\", group) end sub ' Quick Play A Playlist. ' Play the first unwatched episode. ' If none, play the whole season starting with episode 1. sub playlist(itemNode as object) if not isValid(itemNode) or not isValid(itemNode.id) then return ' get playlist items myPlaylist = api.playlists.GetItems(itemNode.id, { \"userId\": m.global.session.user.id, \"limit\": 2000 }) if isValid(myPlaylist) and isValidAndNotEmpty(myPlaylist.Items) ' add each item to the queue quickplay.pushToQueue(myPlaylist.Items) if m.global.queueManager.callFunc(\"getCount\") &gt; 1 m.global.queueManager.callFunc(\"toggleShuffle\") end if end if end sub ' Quick Play A folder. ' Shuffle play all items found sub folder(itemNode as object) if not isValid(itemNode) or not isValid(itemNode.id) then return paramArray = { \"includeItemTypes\": [\"Episode\", \"Movie\", \"Video\"], \"videoTypes\": \"VideoFile\", \"sortBy\": \"Random\", \"limit\": 2000, \"imageTypeLimit\": 1, \"Recursive\": true, \"enableUserData\": false, \"EnableTotalRecordCount\": false } ' modify api query based on folder type folderType = Lcase(itemNode.json.type) if folderType = \"studio\" paramArray[\"studioIds\"] = itemNode.id else if folderType = \"genre\" paramArray[\"genreIds\"] = itemNode.id if isValid(itemNode.json.MovieCount) and itemNode.json.MovieCount &gt; 0 paramArray[\"includeItemTypes\"] = \"Movie\" end if else if folderType = \"musicgenre\" paramArray[\"genreIds\"] = itemNode.id paramArray.delete(\"videoTypes\") paramArray[\"includeItemTypes\"] = \"Audio\" else paramArray[\"parentId\"] = itemNode.id end if ' look for tv series instead of video files if isValid(itemNode.json.SeriesCount) and itemNode.json.SeriesCount &gt; 0 paramArray[\"includeItemTypes\"] = \"Series\" paramArray.Delete(\"videoTypes\") end if ' get folder items folderData = api.users.GetItemsByQuery(m.global.session.user.id, paramArray) print \"folderData=\", folderData if isValid(folderData) and isValidAndNotEmpty(folderData.items) if isValid(itemNode.json.SeriesCount) and itemNode.json.SeriesCount &gt; 0 if itemNode.json.SeriesCount = 1 quickplay.series(folderData.items[0]) else quickplay.multipleSeries(folderData.items) end if else quickplay.pushToQueue(folderData.items, true) end if end if end sub ' Quick Play A CollectionFolder. ' Shuffle play the items inside ' with some differences based on collectionType. sub collectionFolder(itemNode as object) if not isValid(itemNode) or not isValid(itemNode.id) then return ' play depends on the kind of files inside the collectionfolder print \"attempting to quickplay a collection folder\" collectionType = LCase(itemNode.collectionType) print \"collectionType=\", collectionType if collectionType = \"movies\" ' get randomized list of movies inside data = api.users.GetItemsByQuery(m.global.session.user.id, { \"parentId\": itemNode.id, \"sortBy\": \"Random\", \"limit\": 2000 }) if isValid(data) and isValidAndNotEmpty(data.items) movieList = [] ' add each item to the queue for each item in data.Items ' only add movies we're not currently watching if isValid(item.userdata) and isValid(item.userdata.PlaybackPositionTicks) if item.userdata.PlaybackPositionTicks = 0 movieList.push(item) end if end if end for quickplay.pushToQueue(movieList) end if else if collectionType = \"music\" ' get audio files from under this collection ' sort songs by album then artist songsData = api.users.GetItemsByQuery(m.global.session.user.id, { \"parentId\": itemNode.id, \"includeItemTypes\": \"Audio\", \"sortBy\": \"Album\", \"Recursive\": true, \"limit\": 2000, \"imageTypeLimit\": 1, \"enableUserData\": false, \"EnableTotalRecordCount\": false }) print \"songsData=\", songsData if isValid(songsData) and isValidAndNotEmpty(songsData.items) quickplay.pushToQueue(songsData.Items, true) end if else if collectionType = \"boxsets\" ' get list of all boxsets inside boxsetData = api.users.GetItemsByQuery(m.global.session.user.id, { \"parentId\": itemNode.id, \"limit\": 2000, \"imageTypeLimit\": 0, \"enableUserData\": false, \"EnableTotalRecordCount\": false, \"enableImages\": false }) print \"boxsetData=\", boxsetData if isValid(boxsetData) and isValidAndNotEmpty(boxsetData.items) ' pick a random boxset arrayIndex = Rnd(boxsetData.items.count()) - 1 myBoxset = boxsetData.items[arrayIndex] ' grab list of items from boxset print \"myBoxset=\", myBoxset boxsetData = api.users.GetItemsByQuery(m.global.session.user.id, { \"parentId\": myBoxset.id, \"EnableTotalRecordCount\": false }) if isValid(boxsetData) and isValidAndNotEmpty(boxsetData.items) ' add all boxset items to queue quickplay.pushToQueue(boxsetData.Items) end if end if else if collectionType = \"tvshows\" or collectionType = \"collectionfolder\" ' get list of tv shows inside tvshowsData = api.users.GetItemsByQuery(m.global.session.user.id, { \"parentId\": itemNode.id, \"sortBy\": \"Random\", \"imageTypeLimit\": 0, \"enableUserData\": false, \"EnableTotalRecordCount\": false, \"enableImages\": false }) print \"tvshowsData=\", tvshowsData if isValid(tvshowsData) and isValidAndNotEmpty(tvshowsData.items) quickplay.multipleSeries(tvshowsData.items) end if else if collectionType = \"musicvideos\" ' get randomized list of videos inside data = api.users.GetItemsByQuery(m.global.session.user.id, { \"parentId\": itemNode.id, \"includeItemTypes\": \"MusicVideo\", \"sortBy\": \"Random\", \"Recursive\": true, \"limit\": 2000, \"imageTypeLimit\": 1, \"enableUserData\": false, \"EnableTotalRecordCount\": false }) print \"data=\", data if isValid(data) and isValidAndNotEmpty(data.items) quickplay.pushToQueue(data.Items) end if ' else if collectionType = \"homevideos\" ' also used for a \"Photo\" library else print \"Quick Play WARNING: Unknown collection type\" end if end sub ' Quick Play A UserView. ' Play logic depends on \"collectionType\". sub userView(itemNode as object) ' play depends on the kind of files inside the collectionfolder collectionType = LCase(itemNode.collectionType) print \"collectionType=\", collectionType if collectionType = \"playlists\" ' get list of all playlists inside playlistData = api.users.GetItemsByQuery(m.global.session.user.id, { \"parentId\": itemNode.id, \"imageTypeLimit\": 0, \"enableUserData\": false, \"EnableTotalRecordCount\": false, \"enableImages\": false }) print \"playlistData=\", playlistData if isValid(playlistData) and isValidAndNotEmpty(playlistData.items) ' pick a random playlist arrayIndex = Rnd(playlistData.items.count()) - 1 myPlaylist = playlistData.items[arrayIndex] ' grab list of items from playlist print \"myPlaylist=\", myPlaylist playlistItems = api.playlists.GetItems(myPlaylist.id, { \"userId\": m.global.session.user.id, \"EnableTotalRecordCount\": false, \"limit\": 2000 }) ' validate api results if isValid(playlistItems) and isValidAndNotEmpty(playlistItems.items) quickplay.pushToQueue(playlistItems.items, true) end if end if else if collectionType = \"livetv\" ' get list of all tv channels channelData = api.users.GetItemsByQuery(m.global.session.user.id, { \"includeItemTypes\": \"TVChannel\", \"sortBy\": \"Random\", \"Recursive\": true, \"imageTypeLimit\": 0, \"enableUserData\": false, \"EnableTotalRecordCount\": false, \"enableImages\": false }) print \"channelData=\", channelData if isValid(channelData) and isValidAndNotEmpty(channelData.items) ' pick a random channel arrayIndex = Rnd(channelData.items.count()) - 1 myChannel = channelData.items[arrayIndex] print \"myChannel=\", myChannel ' play channel quickplay.tvChannel(myChannel) end if else print \"Quick Play CollectionFolder WARNING: Unknown collection type\" end if end sub end namespace × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_liveTv_schedule.brs.html":{"id":"components_liveTv_schedule.brs.html","title":"Source: components/liveTv/schedule.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/liveTv/schedule.brs sub init() m.EPGLaunchCompleteSignaled = false m.scheduleGrid = m.top.findNode(\"scheduleGrid\") m.detailsPane = m.top.findNode(\"detailsPane\") m.detailsPane.observeField(\"watchSelectedChannel\", \"onWatchChannelSelected\") m.detailsPane.observeField(\"recordSelectedChannel\", \"onRecordChannelSelected\") m.detailsPane.observeField(\"recordSeriesSelectedChannel\", \"onRecordSeriesChannelSelected\") m.gridStartDate = CreateObject(\"roDateTime\") m.scheduleGrid.contentStartTime = m.gridStartDate.AsSeconds() - 1800 m.gridEndDate = createObject(\"roDateTime\") m.gridEndDate.FromSeconds(m.gridStartDate.AsSeconds() + (24 * 60 * 60)) m.scheduleGrid.observeField(\"programFocused\", \"onProgramFocused\") m.scheduleGrid.observeField(\"programSelected\", \"onProgramSelected\") m.scheduleGrid.observeField(\"leftEdgeTargetTime\", \"onGridScrolled\") m.scheduleGrid.channelInfoWidth = 350 m.gridMoveAnimation = m.top.findNode(\"gridMoveAnimation\") m.gridMoveAnimationPosition = m.top.findNode(\"gridMoveAnimationPosition\") m.LoadChannelsTask = createObject(\"roSGNode\", \"LoadChannelsTask\") m.LoadChannelsTask.observeField(\"channels\", \"onChannelsLoaded\") m.LoadChannelsTask.control = \"RUN\" m.top.lastFocus = m.scheduleGrid m.channelIndex = {} m.spinner = m.top.findNode(\"spinner\") end sub sub channelFilterSet() m.scheduleGrid.jumpToChannel = 0 if m.top.filter &lt;&gt; invalid and m.LoadChannelsTask.filter &lt;&gt; m.top.filter if m.LoadChannelsTask.state = \"run\" then m.LoadChannelsTask.control = \"stop\" m.LoadChannelsTask.filter = m.top.filter m.LoadChannelsTask.control = \"RUN\" end if end sub 'Voice Search set sub channelsearchTermSet() m.scheduleGrid.jumpToChannel = 0 'Reset filter if user says all if LCase(m.top.searchTerm) = LCase(tr(\"all\")) or m.LoadChannelsTask.searchTerm = LCase(tr(\"all\")) m.top.searchTerm = \" \" m.LoadChannelsTask.searchTerm = \" \" m.spinner.visible = true m.LoadChannelsTask.control = \"RUN\" 'filter if the searterm is not invalid else if m.top.searchTerm &lt;&gt; invalid and LCase(m.LoadChannelsTask.searchTerm) &lt;&gt; LCase(m.top.searchTerm) if m.LoadChannelsTask.state = \"run\" then m.LoadChannelsTask.control = \"stop\" m.LoadChannelsTask.searchTerm = m.top.searchTerm m.spinner.visible = true m.LoadChannelsTask.control = \"RUN\" end if end sub ' Initial list of channels loaded sub onChannelsLoaded() gridData = createObject(\"roSGNode\", \"ContentNode\") counter = 0 channelIdList = \"\" 'if search returns channels if m.LoadChannelsTask.channels.count() &gt; 0 for each item in m.LoadChannelsTask.channels gridData.appendChild(item) m.channelIndex[item.Id] = counter counter = counter + 1 channelIdList = channelIdList + item.Id + \",\" end for m.scheduleGrid.content = gridData m.LoadScheduleTask = createObject(\"roSGNode\", \"LoadScheduleTask\") m.LoadScheduleTask.observeField(\"schedule\", \"onScheduleLoaded\") m.LoadScheduleTask.startTime = m.gridStartDate.ToISOString() m.LoadScheduleTask.endTime = m.gridEndDate.ToISOString() m.LoadScheduleTask.channelIds = channelIdList m.LoadScheduleTask.control = \"RUN\" m.LoadProgramDetailsTask = createObject(\"roSGNode\", \"LoadProgramDetailsTask\") m.LoadProgramDetailsTask.observeField(\"programDetails\", \"onProgramDetailsLoaded\") m.scheduleGrid.setFocus(true) if m.EPGLaunchCompleteSignaled = false m.top.signalBeacon(\"EPGLaunchComplete\") ' Required Roku Performance monitoring m.EPGLaunchCompleteSignaled = true end if m.LoadChannelsTask.channels = [] end if end sub ' When LoadScheduleTask completes (initial or more data) and we have a schedule to display sub onScheduleLoaded() ' make sure we actually have a schedule (i.e. filter by favorites, but no channels have been favorited) if m.scheduleGrid.content.GetChildCount() &lt;= 0 return end if for each item in m.LoadScheduleTask.schedule channel = m.scheduleGrid.content.GetChild(m.channelIndex[item.ChannelId]) if channel.PosterUrl &lt;&gt; \"\" item.channelLogoUri = channel.PosterUrl end if if channel.Title &lt;&gt; \"\" item.channelName = channel.Title end if channel.appendChild(item) end for m.scheduleGrid.showLoadingDataFeedback = false m.scheduleGrid.setFocus(true) m.LoadScheduleTask.schedule = [] m.spinner.visible = false end sub sub onProgramFocused() m.top.watchChannel = invalid ' Make sure we have channels (i.e. filter set to favorite yet there are none) if m.scheduleGrid.content.getChildCount() &lt;= 0 channel = invalid else channel = m.scheduleGrid.content.GetChild(m.scheduleGrid.programFocusedDetails.focusChannelIndex) end if m.detailsPane.channel = channel m.top.focusedChannel = channel ' Exit if Channels not yet loaded if channel = invalid or channel.getChildCount() = 0 m.detailsPane.programDetails = invalid return end if prog = channel.GetChild(m.scheduleGrid.programFocusedDetails.focusIndex) if prog &lt;&gt; invalid and prog.fullyLoaded = false m.LoadProgramDetailsTask.programId = prog.Id m.LoadProgramDetailsTask.channelIndex = m.scheduleGrid.programFocusedDetails.focusChannelIndex m.LoadProgramDetailsTask.programIndex = m.scheduleGrid.programFocusedDetails.focusIndex m.LoadProgramDetailsTask.control = \"RUN\" end if m.detailsPane.programDetails = prog end sub ' Update the Program Details with full information sub onProgramDetailsLoaded() if m.LoadProgramDetailsTask.programDetails = invalid then return channel = m.scheduleGrid.content.GetChild(m.LoadProgramDetailsTask.programDetails.channelIndex) ' If TV Show does not have its own image, use the channel logo if m.LoadProgramDetailsTask.programDetails.PosterUrl = invalid or m.LoadProgramDetailsTask.programDetails.PosterUrl = \"\" m.LoadProgramDetailsTask.programDetails.PosterUrl = channel.PosterUrl end if channel.ReplaceChild(m.LoadProgramDetailsTask.programDetails, m.LoadProgramDetailsTask.programDetails.programIndex) m.LoadProgramDetailsTask.programDetails = invalid m.scheduleGrid.showLoadingDataFeedback = false end sub sub onProgramSelected() ' If there is no program data - view the channel if m.detailsPane.programDetails = invalid m.top.watchChannel = m.scheduleGrid.content.GetChild(m.scheduleGrid.programFocusedDetails.focusChannelIndex) return end if ' Move Grid Down focusProgramDetails(true) end sub ' Move the TV Guide Grid down or up depending whether details are selected sub focusProgramDetails(setFocused) h = m.detailsPane.height if h &lt; 400 then h = 400 h = h + 160 + 80 if setFocused = true m.gridMoveAnimationPosition.keyValue = [[0, 600], [0, h]] m.detailsPane.setFocus(true) m.detailsPane.hasFocus = true m.top.lastFocus = m.detailsPane else m.detailsPane.hasFocus = false m.gridMoveAnimationPosition.keyValue = [[0, h], [0, 600]] m.scheduleGrid.setFocus(true) m.top.lastFocus = m.scheduleGrid end if m.gridMoveAnimation.control = \"start\" end sub ' Handle user selecting \"Watch Channel\" from Program Details sub onWatchChannelSelected() if m.detailsPane.watchSelectedChannel = false then return ' Set focus back to grid before showing channel, to ensure grid has focus when we return focusProgramDetails(false) m.top.watchChannel = m.detailsPane.channel end sub ' As user scrolls grid, check if more data requries to be loaded sub onGridScrolled() ' If we're within 12 hours of end of grid, load next 24hrs of data if m.scheduleGrid.leftEdgeTargetTime + (12 * 60 * 60) &gt; m.gridEndDate.AsSeconds() ' Ensure the task is not already (still) running, if m.LoadScheduleTask.state &lt;&gt; \"run\" m.LoadScheduleTask.startTime = m.gridEndDate.ToISOString() m.gridEndDate.FromSeconds(m.gridEndDate.AsSeconds() + (24 * 60 * 60)) m.LoadScheduleTask.endTime = m.gridEndDate.ToISOString() m.LoadScheduleTask.control = \"RUN\" end if end if end sub ' Handle user selecting \"Record Channel\" from Program Details sub onRecordChannelSelected() if m.detailsPane.recordSelectedChannel = false then return ' Set focus back to grid before showing channel, to ensure grid has focus when we return focusProgramDetails(false) m.scheduleGrid.showLoadingDataFeedback = true m.RecordProgramTask = createObject(\"roSGNode\", \"RecordProgramTask\") m.RecordProgramTask.programDetails = m.detailsPane.programDetails m.RecordProgramTask.recordSeries = false m.RecordProgramTask.observeField(\"recordOperationDone\", \"onRecordOperationDone\") m.RecordProgramTask.control = \"RUN\" end sub ' Handle user selecting \"Record Series\" from Program Details sub onRecordSeriesChannelSelected() if m.detailsPane.recordSeriesSelectedChannel = false then return ' Set focus back to grid before showing channel, to ensure grid has focus when we return focusProgramDetails(false) m.scheduleGrid.showLoadingDataFeedback = true m.RecordProgramTask = createObject(\"roSGNode\", \"RecordProgramTask\") m.RecordProgramTask.programDetails = m.detailsPane.programDetails m.RecordProgramTask.recordSeries = true m.RecordProgramTask.observeField(\"recordOperationDone\", \"onRecordOperationDone\") m.RecordProgramTask.control = \"RUN\" end sub sub onRecordOperationDone() if m.RecordProgramTask.recordSeries = true and m.LoadScheduleTask.state &lt;&gt; \"run\" m.LoadScheduleTask.control = \"RUN\" else ' This reloads just the details for the currently selected program, so that we don't have to ' reload the entire grid... channel = m.scheduleGrid.content.GetChild(m.scheduleGrid.programFocusedDetails.focusChannelIndex) prog = channel.GetChild(m.scheduleGrid.programFocusedDetails.focusIndex) m.LoadProgramDetailsTask.programId = prog.Id m.LoadProgramDetailsTask.channelIndex = m.scheduleGrid.programFocusedDetails.focusChannelIndex m.LoadProgramDetailsTask.programIndex = m.scheduleGrid.programFocusedDetails.focusIndex m.LoadProgramDetailsTask.control = \"RUN\" end if end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false detailsGrp = m.top.findNode(\"detailsPane\") gridGrp = m.top.findNode(\"scheduleGrid\") if key = \"back\" and detailsGrp.isInFocusChain() focusProgramDetails(false) detailsGrp.setFocus(false) gridGrp.setFocus(true) return true else if key = \"back\" m.LoadChannelsTask.control = \"stop\" m.global.sceneManager.callFunc(\"popScene\") return true end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_section_section.brs.html":{"id":"components_section_section.brs.html","title":"Source: components/section/section.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/section/section.brs import \"pkg:/source/utils/misc.brs\" sub init() m.showFromBottomAnimation = m.top.findNode(\"showFromBottomAnimation\") m.showFromBottomPosition = m.top.findNode(\"showFromBottomPosition\") m.showFromBottomOpacity = m.top.findNode(\"showFromBottomOpacity\") m.showFromTopAnimation = m.top.findNode(\"showFromTopAnimation\") m.showFromTopPosition = m.top.findNode(\"showFromTopPosition\") m.showFromTopOpacity = m.top.findNode(\"showFromTopOpacity\") m.scrollOffTopAnimation = m.top.findNode(\"scrollOffTopAnimation\") m.scrollOffTopPosition = m.top.findNode(\"scrollOffTopPosition\") m.scrollOffTopOpacity = m.top.findNode(\"scrollOffTopOpacity\") m.scrollOffBottomAnimation = m.top.findNode(\"scrollOffBottomAnimation\") m.scrollOffBottomPosition = m.top.findNode(\"scrollOffBottomPosition\") m.scrollOffBottomOpacity = m.top.findNode(\"scrollOffBottomOpacity\") m.scrollUpToOnDeckAnimation = m.top.findNode(\"scrollUpToOnDeckAnimation\") m.scrollUpToOnDeckPosition = m.top.findNode(\"scrollUpToOnDeckPosition\") m.scrollDownToOnDeckAnimation = m.top.findNode(\"scrollDownToOnDeckAnimation\") m.scrollDownToOnDeckPosition = m.top.findNode(\"scrollDownToOnDeckPosition\") m.scrollOffOnDeckAnimation = m.top.findNode(\"scrollOffOnDeckAnimation\") m.scrollOffOnDeckPosition = m.top.findNode(\"scrollOffOnDeckPosition\") m.top.observeField(\"translation\", \"onTranslationChange\") m.top.observeField(\"id\", \"onIDChange\") m.top.observeField(\"focusedChild\", \"onFocusChange\") end sub sub onIDChange() m.showFromBottomPosition.fieldToInterp = m.top.id + \".translation\" m.showFromBottomOpacity.fieldToInterp = m.top.id + \".opacity\" m.showFromTopPosition.fieldToInterp = m.top.id + \".translation\" m.showFromTopOpacity.fieldToInterp = m.top.id + \".opacity\" m.scrollOffTopPosition.fieldToInterp = m.top.id + \".translation\" m.scrollOffTopOpacity.fieldToInterp = m.top.id + \".opacity\" m.scrollOffBottomPosition.fieldToInterp = m.top.id + \".translation\" m.scrollOffBottomOpacity.fieldToInterp = m.top.id + \".opacity\" m.scrollUpToOnDeckPosition.fieldToInterp = m.top.id + \".translation\" m.scrollDownToOnDeckPosition.fieldToInterp = m.top.id + \".translation\" m.scrollOffOnDeckPosition.fieldToInterp = m.top.id + \".translation\" end sub sub onTranslationChange() m.startingPosition = m.top.translation m.scrollOffBottomPosition.keyValue = \"[[0, 0], [\" + str(m.startingPosition[0]) + \", \" + str(m.startingPosition[1]) + \"]]\" m.top.unobserveField(\"translation\") end sub sub showFromTop() m.showFromTopAnimation.control = \"start\" end sub sub showFromBottom() m.showFromBottomAnimation.control = \"start\" end sub sub scrollOffBottom() m.scrollOffBottomAnimation.control = \"start\" end sub sub scrollOffTop() m.scrollOffTopAnimation.control = \"start\" end sub sub scrollUpToOnDeck() m.scrollUpToOnDeckAnimation.control = \"start\" end sub sub scrollDownToOnDeck() m.scrollDownToOnDeckAnimation.control = \"start\" end sub sub scrollOffOnDeck() m.scrollOffOnDeckAnimation.control = \"start\" end sub sub onFocusChange() defaultFocusElement = m.top.findNode(m.top.defaultFocusID) if isValid(defaultFocusElement) defaultFocusElement.setFocus(m.top.isInFocusChain()) if isValid(defaultFocusElement.focus) defaultFocusElement.focus = m.top.isInFocusChain() end if end if end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_section_sectionScroller.brs.html":{"id":"components_section_sectionScroller.brs.html","title":"Source: components/section/sectionScroller.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/section/sectionScroller.brs import \"pkg:/source/utils/misc.brs\" sub init() m.previouslyDisplayedSection = 0 end sub sub onFocusChange() if m.top.focus m.top.getChild(m.top.displayedIndex).setFocus(true) end if end sub sub displayedIndexChanged() if not m.top.affectsFocus then return if m.top.displayedIndex &lt; 0 return end if if m.top.displayedIndex &gt; (m.top.getChildCount() - 1) return end if m.top.getChild(m.previouslyDisplayedSection).setFocus(false) displayedSection = m.top.getChild(m.top.displayedIndex) displayedSection.setFocus(true) onDeckSection = invalid previouslyOnDeckSection = invalid if m.top.displayedIndex + 1 &lt;= (m.top.getChildCount() - 1) onDeckSection = m.top.getChild(m.top.displayedIndex + 1) end if if m.top.displayedIndex + 2 &lt;= (m.top.getChildCount() - 1) previouslyOnDeckSection = m.top.getChild(m.top.displayedIndex + 2) end if ' Move sections either up or down depending on what index we're moving to if m.top.displayedIndex &gt; m.previouslyDisplayedSection for i = m.previouslyDisplayedSection to m.top.displayedIndex - 1 m.top.getChild(i).callFunc(\"scrollOffTop\") end for displayedSection.callFunc(\"showFromBottom\") if isValid(onDeckSection) onDeckSection.callFunc(\"scrollUpToOnDeck\") end if else if m.top.displayedIndex &lt; m.previouslyDisplayedSection m.top.getChild(m.top.displayedIndex + 1).callFunc(\"scrollDownToOnDeck\") displayedSection.callFunc(\"showFromTop\") if isValid(previouslyOnDeckSection) previouslyOnDeckSection.callFunc(\"scrollOffOnDeck\") end if end if m.previouslyDisplayedSection = m.top.displayedIndex end sub × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"components_settings_settings.brs.html":{"id":"components_settings_settings.brs.html","title":"Source: components/settings/settings.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: components/settings/settings.brs import \"pkg:/source/utils/config.brs\" import \"pkg:/source/utils/misc.brs\" import \"pkg:/source/roku_modules/log/LogMixin.brs\" import \"pkg:/source/api/sdk.bs\" sub init() m.log = log.Logger(\"Settings\") m.top.optionsAvailable = false m.userLocation = [] m.settingsMenu = m.top.findNode(\"settingsMenu\") m.settingDetail = m.top.findNode(\"settingDetail\") m.settingDesc = m.top.findNode(\"settingDesc\") m.path = m.top.findNode(\"path\") m.boolSetting = m.top.findNode(\"boolSetting\") m.integerSetting = m.top.findNode(\"integerSetting\") m.radioSetting = m.top.findNode(\"radioSetting\") m.integerSetting.observeField(\"submit\", \"onKeyGridSubmit\") m.integerSetting.observeField(\"escape\", \"onKeyGridEscape\") m.settingsMenu.setFocus(true) m.settingsMenu.observeField(\"itemFocused\", \"settingFocused\") m.settingsMenu.observeField(\"itemSelected\", \"settingSelected\") m.boolSetting.observeField(\"checkedItem\", \"boolSettingChanged\") m.radioSetting.observeField(\"checkedItem\", \"radioSettingChanged\") ' Load Configuration Tree m.configTree = GetConfigTree() LoadMenu({ children: m.configTree }) end sub sub onKeyGridSubmit() selectedSetting = m.userLocation.peek().children[m.settingsMenu.itemFocused] set_user_setting(selectedSetting.settingName, m.integerSetting.text) m.settingsMenu.setFocus(true) end sub sub onKeyGridEscape() if m.integerSetting.escape = \"left\" or m.integerSetting.escape = \"back\" m.settingsMenu.setFocus(true) end if end sub sub LoadMenu(configSection) if configSection.children = invalid ' Load parent menu m.userLocation.pop() configSection = m.userLocation.peek() else if m.userLocation.Count() &gt; 0 then m.userLocation.peek().selectedIndex = m.settingsMenu.itemFocused m.userLocation.push(configSection) end if result = CreateObject(\"roSGNode\", \"ContentNode\") for each item in configSection.children listItem = result.CreateChild(\"ContentNode\") listItem.title = tr(item.title) listItem.Description = tr(item.description) listItem.id = item.id end for m.settingsMenu.content = result if configSection.selectedIndex &lt;&gt; invalid and configSection.selectedIndex &gt; -1 m.settingsMenu.jumpToItem = configSection.selectedIndex end if ' Set Path display m.path.text = tr(\"Settings\") for each level in m.userLocation if level.title &lt;&gt; invalid then m.path.text += \" / \" + tr(level.title) end for end sub sub settingFocused() selectedSetting = m.userLocation.peek().children[m.settingsMenu.itemFocused] m.settingDesc.text = tr(selectedSetting.Description) m.top.overhangTitle = tr(selectedSetting.Title) ' Hide Settings m.boolSetting.visible = false m.integerSetting.visible = false m.radioSetting.visible = false if selectedSetting.type = invalid return else if selectedSetting.type = \"bool\" m.boolSetting.visible = true if m.global.session.user.settings[selectedSetting.settingName] = true m.boolSetting.checkedItem = 1 else m.boolSetting.checkedItem = 0 end if else if selectedSetting.type = \"integer\" integerValue = m.global.session.user.settings[selectedSetting.settingName].ToStr() if isValid(integerValue) m.integerSetting.text = integerValue end if m.integerSetting.visible = true else if LCase(selectedSetting.type) = \"radio\" selectedValue = m.global.session.user.settings[selectedSetting.settingName] radioContent = CreateObject(\"roSGNode\", \"ContentNode\") itemIndex = 0 for each item in m.userLocation.peek().children[m.settingsMenu.itemFocused].options listItem = radioContent.CreateChild(\"ContentNode\") listItem.title = tr(item.title) listItem.id = item.id if selectedValue = item.id m.radioSetting.checkedItem = itemIndex end if itemIndex++ end for m.radioSetting.content = radioContent m.radioSetting.visible = true else m.log.warn(\"Unknown setting type\", selectedSetting.type) end if end sub sub settingSelected() selectedItem = m.userLocation.peek().children[m.settingsMenu.itemFocused] if selectedItem.type &lt;&gt; invalid ' Show setting if selectedItem.type = \"bool\" m.boolSetting.setFocus(true) end if if selectedItem.type = \"integer\" m.integerSetting.setFocus(true) end if if (selectedItem.type) = \"radio\" m.radioSetting.setFocus(true) end if else if selectedItem.children &lt;&gt; invalid and selectedItem.children.Count() &gt; 0 ' Show sub menu LoadMenu(selectedItem) m.settingsMenu.setFocus(true) else return end if m.settingDesc.text = m.settingsMenu.content.GetChild(m.settingsMenu.itemFocused).Description end sub sub boolSettingChanged() if m.boolSetting.focusedChild = invalid then return selectedSetting = m.userLocation.peek().children[m.settingsMenu.itemFocused] if m.boolSetting.checkedItem session.user.settings.Save(selectedSetting.settingName, \"true\") if Left(selectedSetting.settingName, 7) = \"global.\" ' global user setting ' save to main registry block set_setting(selectedSetting.settingName, \"true\") ' setting specific triggers if selectedSetting.settingName = \"global.rememberme\" print \"m.global.session.user.id=\", m.global.session.user.id set_setting(\"active_user\", m.global.session.user.id) end if else ' regular user setting ' save to user specific registry block set_user_setting(selectedSetting.settingName, \"true\") end if else session.user.settings.Save(selectedSetting.settingName, \"false\") if Left(selectedSetting.settingName, 7) = \"global.\" ' global user setting ' save to main registry block set_setting(selectedSetting.settingName, \"false\") ' setting specific triggers if selectedSetting.settingName = \"global.rememberme\" unset_setting(\"active_user\") end if else ' regular user setting ' save to user specific registry block set_user_setting(selectedSetting.settingName, \"false\") end if end if end sub sub radioSettingChanged() if m.radioSetting.focusedChild = invalid then return selectedSetting = m.userLocation.peek().children[m.settingsMenu.itemFocused] set_user_setting(selectedSetting.settingName, m.radioSetting.content.getChild(m.radioSetting.checkedItem).id) end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false if (key = \"back\" or key = \"left\") and m.settingsMenu.focusedChild &lt;&gt; invalid and m.userLocation.Count() &gt; 1 LoadMenu({}) return true else if (key = \"back\" or key = \"left\") and m.settingDetail.focusedChild &lt;&gt; invalid m.settingsMenu.setFocus(true) return true else if (key = \"back\" or key = \"left\") and m.radioSetting.hasFocus() m.settingsMenu.setFocus(true) return true end if if key = \"options\" m.global.sceneManager.callFunc(\"popScene\") return true end if if key = \"right\" settingSelected() end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"source_api_userauth.brs.html":{"id":"source_api_userauth.brs.html","title":"Source: source/api/userauth.brs","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Source: source/api/userauth.brs ' needed for SignOut() and ServerInfo() import \"pkg:/source/utils/session.bs\" import \"pkg:/source/utils/misc.brs\" function get_token(user as string, password as string) url = \"Users/AuthenticateByName?format=json\" req = APIRequest(url) json = postJson(req, FormatJson({ \"Username\": user, \"Pw\": password })) if json = invalid then return invalid userdata = CreateObject(\"roSGNode\", \"UserData\") userdata.json = json userdata.callFunc(\"setActive\") userdata.callFunc(\"saveToRegistry\") return userdata end function function AboutMe(id = \"\" as string) if id = \"\" if m.global.session.user.id &lt;&gt; invalid id = m.global.session.user.id else return invalid end if end if url = Substitute(\"Users/{0}\", id) resp = APIRequest(url) return getJson(resp) end function sub SignOut(deleteSavedEntry = true as boolean) if deleteSavedEntry unset_user_setting(\"token\") unset_user_setting(\"username\") end if unset_setting(\"active_user\") session.user.Logout() m.global.sceneManager.currentUser = \"\" group = m.global.sceneManager.callFunc(\"getActiveScene\") group.optionsAvailable = false end sub function AvailableUsers() users = parseJson(get_setting(\"available_users\", \"[]\")) return users end function function ServerInfo() url = \"System/Info/Public\" req = APIRequest(url) req.setMessagePort(CreateObject(\"roMessagePort\")) req.AsyncGetToString() ' wait 15 seconds for a server response resp = wait(35000, req.GetMessagePort()) ' handle unknown errors if type(resp) &lt;&gt; \"roUrlEvent\" return { \"Error\": true, \"ErrorMessage\": \"Unknown\" } end if ' check for a location redirect header in the response headers = resp.GetResponseHeaders() if headers &lt;&gt; invalid and headers.location &lt;&gt; invalid ' only follow redirect if it the API Endpoint path is the same (/System/Info/Public) ' set the server to new location and try again if right(headers.location, 19) = \"/System/Info/Public\" set_setting(\"server\", left(headers.location, len(headers.location) - 19)) isConnected = session.server.UpdateURL(left(headers.location, len(headers.location) - 19)) if isConnected info = ServerInfo() if info.Error info.UpdatedUrl = left(headers.location, len(headers.location) - 19) info.ErrorMessage = info.ErrorMessage + \" (Note: Server redirected us to \" + info.UpdatedUrl + \")\" end if return info end if end if end if ' handle any non 200 responses, returning the error code and message if resp.GetResponseCode() &lt;&gt; 200 return { \"Error\": true, \"ErrorCode\": resp.GetResponseCode(), \"ErrorMessage\": resp.GetFailureReason() } end if ' return the parsed response string responseString = resp.GetString() if responseString &lt;&gt; invalid and responseString &lt;&gt; \"\" result = ParseJson(responseString) if result &lt;&gt; invalid result.Error = false return result end if end if ' otherwise return error message return { \"Error\": true, \"ErrorMessage\": \"Does not appear to be a Jellyfin Server\" } end function function GetPublicUsers() url = \"Users/Public\" resp = APIRequest(url) return getJson(resp) end function sub LoadUserAbilities() if m.global.session.user.Policy.EnableLiveTvManagement = true set_user_setting(\"livetv.canrecord\", \"true\") else set_user_setting(\"livetv.canrecord\", \"false\") end if if m.global.session.user.Policy.EnableContentDeletion = true set_user_setting(\"content.candelete\", \"true\") else set_user_setting(\"content.candelete\", \"false\") end if end sub function initQuickConnect() resp = APIRequest(\"QuickConnect/Initiate\") jsonResponse = getJson(resp) if jsonResponse = invalid return invalid end if if jsonResponse.Secret = invalid return invalid end if return jsonResponse end function function checkQuickConnect(secret) url = Substitute(\"QuickConnect/Connect?secret={0}\", secret) resp = APIRequest(url) jsonResponse = getJson(resp) if jsonResponse = invalid return false end if if jsonResponse.Authenticated &lt;&gt; invalid and jsonResponse.Authenticated = true return true end if return false end function function AuthenticateViaQuickConnect(secret) params = { secret: secret } req = APIRequest(\"Users/AuthenticateWithQuickConnect\") jsonResponse = postJson(req, FormatJson(params)) if jsonResponse &lt;&gt; invalid and jsonResponse.AccessToken &lt;&gt; invalid and jsonResponse.User &lt;&gt; invalid userdata = CreateObject(\"roSGNode\", \"UserData\") userdata.json = jsonResponse session.user.Update(\"id\", jsonResponse.User.Id) session.user.Update(\"authToken\", jsonResponse.AccessToken) userdata.callFunc(\"setActive\") userdata.callFunc(\"saveToRegistry\") return true end if return false end function × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"modules.list.html":{"id":"modules.list.html","title":"Modules","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Modules × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"index.html":{"id":"index.html","title":"Index","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Welcome Use the Modules dropdown or the search feature to find files and functions to inspect Known Issues BrighterScript namespaces: Duplicate function names will prevent the entire file from being parsed by JSDoc i.e. having namespace.red.Delete() and namespace.blue.Delete() When viewing source files: The syntax highlighter doesn't support BrightScript and will treat all source files as JavaScript. The page scrolls to the correct line number but it does not highlight the selected line. × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-AlbumData.html":{"id":"module-AlbumData.html","title":"Module: AlbumData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: AlbumData Source: components/data/AlbumData.brs, line 1 Methods &lt;static&gt; setFields() Source: components/data/AlbumData.brs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-AlbumGrid.html":{"id":"module-AlbumGrid.html","title":"Module: AlbumGrid","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: AlbumGrid Source: components/music/AlbumGrid.brs, line 1 Methods &lt;static&gt; getData() Source: components/music/AlbumGrid.brs, line 14 Returns: Type dynamic &lt;static&gt; init() Source: components/music/AlbumGrid.brs, line 8 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/music/AlbumGrid.brs, line 22 Returns: Type boolean × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-AlbumTrackList.html":{"id":"module-AlbumTrackList.html","title":"Module: AlbumTrackList","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: AlbumTrackList Source: components/music/AlbumTrackList.brs, line 1 Methods &lt;static&gt; getData() Source: components/music/AlbumTrackList.brs, line 14 Returns: Type dynamic &lt;static&gt; init() Source: components/music/AlbumTrackList.brs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-AlbumView.html":{"id":"module-AlbumView.html","title":"Module: AlbumView","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: AlbumView Source: components/music/AlbumView.brs, line 1 Methods &lt;static&gt; OnScreenHidden() Source: components/music/AlbumView.brs, line 84 Returns: Type void &lt;static&gt; adjustScreenForNoOverview() Adjust scene by removing overview node and showing more songs Source: components/music/AlbumView.brs, line 44 Returns: Type void &lt;static&gt; createDialogPallete() Source: components/music/AlbumView.brs, line 72 Returns: Type void &lt;static&gt; createFullDscrDlg() Source: components/music/AlbumView.brs, line 66 Returns: Type void &lt;static&gt; init() Source: components/music/AlbumView.brs, line 8 Returns: Type void &lt;static&gt; onDoneLoading() Source: components/music/AlbumView.brs, line 78 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/music/AlbumView.brs, line 60 Returns: Type boolean &lt;static&gt; pageContentChanged() Set values for displayed values on screen Source: components/music/AlbumView.brs, line 21 Returns: Type void &lt;static&gt; setOnScreenTextValues(json) Populate on screen text variables Parameters: Name Type Description json dynamic Source: components/music/AlbumView.brs, line 52 Returns: Type void &lt;static&gt; setPosterImage(posterURL) Set poster image on screen Parameters: Name Type Description posterURL dynamic Source: components/music/AlbumView.brs, line 29 Returns: Type void &lt;static&gt; setScreenTitle(json) Set screen's title text Parameters: Name Type Description json dynamic Source: components/music/AlbumView.brs, line 37 Returns: Type void &lt;static&gt; setupMainNode() Source: components/music/AlbumView.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-Alpha.html":{"id":"module-Alpha.html","title":"Module: Alpha","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: Alpha Source: components/ItemGrid/Alpha.brs, line 1 Methods &lt;static&gt; init() Source: components/ItemGrid/Alpha.brs, line 8 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/ItemGrid/Alpha.brs, line 16 Returns: Type boolean × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-ArtistView.html":{"id":"module-ArtistView.html","title":"Module: ArtistView","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: ArtistView Source: components/music/ArtistView.brs, line 1 Methods &lt;static&gt; OnScreenHidden() Source: components/music/ArtistView.brs, line 38 Returns: Type void &lt;static&gt; OnScreenShown() Source: components/music/ArtistView.brs, line 32 Returns: Type void &lt;static&gt; artistOverviewChanged() Event fired when page data is loaded Source: components/music/ArtistView.brs, line 112 Returns: Type void &lt;static&gt; createDialogPallete() Source: components/music/ArtistView.brs, line 148 Returns: Type void &lt;static&gt; createFullDscrDlg() Source: components/music/ArtistView.brs, line 142 Returns: Type void &lt;static&gt; dscrShowFocus() Source: components/music/ArtistView.brs, line 136 Returns: Type void &lt;static&gt; init() Source: components/music/ArtistView.brs, line 8 Returns: Type void &lt;static&gt; onAlbumsData() Source: components/music/ArtistView.brs, line 14 Returns: Type void &lt;static&gt; onAlbumsEscape() Source: components/music/ArtistView.brs, line 44 Returns: Type void &lt;static&gt; onAppearsOnData() Source: components/music/ArtistView.brs, line 20 Returns: Type void &lt;static&gt; onAppearsOnEscape() Source: components/music/ArtistView.brs, line 50 Returns: Type void &lt;static&gt; onBackdropImageLoaded() Source: components/music/ArtistView.brs, line 97 Returns: Type void &lt;static&gt; onButtonSelectedChange() Event handler when user selected a different playback button Source: components/music/ArtistView.brs, line 64 Returns: Type void &lt;static&gt; onEllipsisChanged() Source: components/music/ArtistView.brs, line 118 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/music/ArtistView.brs, line 156 Returns: Type boolean &lt;static&gt; onSectionNavigationEscape() Source: components/music/ArtistView.brs, line 124 Returns: Type void &lt;static&gt; onSectionNavigationSelected() Source: components/music/ArtistView.brs, line 130 Returns: Type void &lt;static&gt; onSectionScrollerChange() Source: components/music/ArtistView.brs, line 26 Returns: Type void &lt;static&gt; pageContentChanged() Event fired when page data is loaded Source: components/music/ArtistView.brs, line 77 Returns: Type void &lt;static&gt; setBackdropImage(data) Add backdrop image to screen Parameters: Name Type Description data dynamic Source: components/music/ArtistView.brs, line 105 Returns: Type void &lt;static&gt; setPosterImage(posterURL) Parameters: Name Type Description posterURL dynamic Source: components/music/ArtistView.brs, line 91 Returns: Type void &lt;static&gt; setScreenTitle(json) Parameters: Name Type Description json dynamic Source: components/music/ArtistView.brs, line 84 Returns: Type void &lt;static&gt; setupButtons() Setup playback buttons, default to Play button selected Source: components/music/ArtistView.brs, line 57 Returns: Type void &lt;static&gt; setupMainNode() Source: components/music/ArtistView.brs, line 70 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-AudioPlayer.html":{"id":"module-AudioPlayer.html","title":"Module: AudioPlayer","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: AudioPlayer Source: components/mediaPlayers/AudioPlayer.brs, line 1 Methods &lt;static&gt; ReportPlayback(state) Report playback to server Parameters: Name Type Description state string Source: components/mediaPlayers/AudioPlayer.brs, line 23 Returns: Type void &lt;static&gt; audioStateChanged() State Change Event Handler Source: components/mediaPlayers/AudioPlayer.brs, line 15 Returns: Type void &lt;static&gt; init() Source: components/mediaPlayers/AudioPlayer.brs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-AudioPlayerView.html":{"id":"module-AudioPlayerView.html","title":"Module: AudioPlayerView","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: AudioPlayerView Source: components/music/AudioPlayerView.brs, line 1 Methods &lt;static&gt; LoadNextSong() Source: components/music/AudioPlayerView.brs, line 169 Returns: Type void &lt;static&gt; OnScreenHidden() Source: components/music/AudioPlayerView.brs, line 248 Returns: Type void &lt;static&gt; audioPositionChanged() Source: components/music/AudioPlayerView.brs, line 72 Returns: Type void &lt;static&gt; audioStateChanged() Source: components/music/AudioPlayerView.brs, line 96 Returns: Type void &lt;static&gt; bufferPositionChanged() Source: components/music/AudioPlayerView.brs, line 66 Returns: Type void &lt;static&gt; endScreenSaver() Source: components/music/AudioPlayerView.brs, line 90 Returns: Type void &lt;static&gt; findCurrentSongIndex(songList) Parameters: Name Type Description songList dynamic Source: components/music/AudioPlayerView.brs, line 145 Returns: Type integer &lt;static&gt; init() Source: components/music/AudioPlayerView.brs, line 8 Returns: Type void &lt;static&gt; loadButtons() If we have more and 1 song to play, fade in the next and previous controls Source: components/music/AudioPlayerView.brs, line 183 Returns: Type void &lt;static&gt; loopClicked() Source: components/music/AudioPlayerView.brs, line 120 Returns: Type boolean &lt;static&gt; nextClicked() Source: components/music/AudioPlayerView.brs, line 132 Returns: Type boolean &lt;static&gt; onAudioStreamLoaded() Source: components/music/AudioPlayerView.brs, line 189 Returns: Type void &lt;static&gt; onBackdropImageLoaded() Source: components/music/AudioPlayerView.brs, line 195 Returns: Type void &lt;static&gt; onButtonSelectedChange() Event handler when user selected a different playback button Source: components/music/AudioPlayerView.brs, line 54 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Process key press events Parameters: Name Type Description key string press boolean Source: components/music/AudioPlayerView.brs, line 242 Returns: Type boolean &lt;static&gt; onMetaDataLoaded() Source: components/music/AudioPlayerView.brs, line 201 Returns: Type void &lt;static&gt; onScreensaverTimeoutLoaded() Source: components/music/AudioPlayerView.brs, line 14 Returns: Type void &lt;static&gt; pageContentChanged() Update values on screen when page content changes Source: components/music/AudioPlayerView.brs, line 176 Returns: Type void &lt;static&gt; playAction() Source: components/music/AudioPlayerView.brs, line 102 Returns: Type boolean &lt;static&gt; previousClicked() Source: components/music/AudioPlayerView.brs, line 108 Returns: Type boolean &lt;static&gt; resetLoopModeToDefault() Source: components/music/AudioPlayerView.brs, line 114 Returns: Type void &lt;static&gt; screenSaverActive() Source: components/music/AudioPlayerView.brs, line 78 Returns: Type boolean &lt;static&gt; setBackdropImage(data) Add backdrop image to screen Parameters: Name Type Description data dynamic Source: components/music/AudioPlayerView.brs, line 233 Returns: Type void &lt;static&gt; setLoopButtonImage() Source: components/music/AudioPlayerView.brs, line 126 Returns: Type void &lt;static&gt; setOnScreenTextValues(json) Populate on screen text variables Parameters: Name Type Description json dynamic Source: components/music/AudioPlayerView.brs, line 225 Returns: Type void &lt;static&gt; setPosterImage(posterURL) Set poster image on screen Parameters: Name Type Description posterURL dynamic Source: components/music/AudioPlayerView.brs, line 209 Returns: Type void &lt;static&gt; setScreenTitle(json) Set screen's title text Parameters: Name Type Description json dynamic Source: components/music/AudioPlayerView.brs, line 217 Returns: Type void &lt;static&gt; setShuffleIconState() Source: components/music/AudioPlayerView.brs, line 157 Returns: Type void &lt;static&gt; setTrackNumberDisplay() Source: components/music/AudioPlayerView.brs, line 163 Returns: Type void &lt;static&gt; setupAnimationTasks() Source: components/music/AudioPlayerView.brs, line 26 Returns: Type void &lt;static&gt; setupAudioNode() Creates audio node used to play song(s) Source: components/music/AudioPlayerView.brs, line 40 Returns: Type void &lt;static&gt; setupButtons() Setup playback buttons, default to Play button selected Source: components/music/AudioPlayerView.brs, line 47 Returns: Type void &lt;static&gt; setupDataTasks() Creates tasks to gather data needed to render Scene and play song Source: components/music/AudioPlayerView.brs, line 33 Returns: Type void &lt;static&gt; setupInfoNodes() Source: components/music/AudioPlayerView.brs, line 60 Returns: Type void &lt;static&gt; setupScreenSaver() Source: components/music/AudioPlayerView.brs, line 20 Returns: Type void &lt;static&gt; shuffleClicked() Source: components/music/AudioPlayerView.brs, line 151 Returns: Type boolean &lt;static&gt; startScreenSaver() Source: components/music/AudioPlayerView.brs, line 84 Returns: Type void &lt;static&gt; toggleShuffleEnabled() Source: components/music/AudioPlayerView.brs, line 138 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-AudioTrackListItem.html":{"id":"module-AudioTrackListItem.html","title":"Module: AudioTrackListItem","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: AudioTrackListItem Source: components/movies/AudioTrackListItem.brs, line 1 Methods &lt;static&gt; focusChanged() Scroll description if focused Source: components/movies/AudioTrackListItem.brs, line 22 Returns: Type void &lt;static&gt; init() Source: components/movies/AudioTrackListItem.brs, line 8 Returns: Type void &lt;static&gt; itemContentChanged() Source: components/movies/AudioTrackListItem.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-ButtonGroupHoriz.html":{"id":"module-ButtonGroupHoriz.html","title":"Module: ButtonGroupHoriz","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: ButtonGroupHoriz Source: components/ButtonGroupHoriz.brs, line 1 Methods &lt;static&gt; init() Source: components/ButtonGroupHoriz.brs, line 8 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/ButtonGroupHoriz.brs, line 16 Returns: Type boolean × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-ChannelData.html":{"id":"module-ChannelData.html","title":"Module: ChannelData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: ChannelData Source: components/data/ChannelData.brs, line 1 Methods &lt;static&gt; setFields() Source: components/data/ChannelData.brs, line 8 Returns: Type void &lt;static&gt; setPoster() Source: components/data/ChannelData.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-CollectionData.html":{"id":"module-CollectionData.html","title":"Module: CollectionData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: CollectionData Source: components/data/CollectionData.brs, line 1 Methods &lt;static&gt; setFields() Source: components/data/CollectionData.brs, line 8 Returns: Type void &lt;static&gt; setPoster() Source: components/data/CollectionData.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-ConfigData.html":{"id":"module-ConfigData.html","title":"Module: ConfigData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: ConfigData Source: components/config/ConfigData.brs, line 1 Methods &lt;static&gt; init() Source: components/config/ConfigData.brs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-ConfigItem.html":{"id":"module-ConfigItem.html","title":"Module: ConfigItem","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: ConfigItem Source: components/config/ConfigItem.brs, line 1 Methods &lt;static&gt; init() Source: components/config/ConfigItem.brs, line 8 Returns: Type void &lt;static&gt; itemContentChanged() Source: components/config/ConfigItem.brs, line 14 Returns: Type void &lt;static&gt; setColors() Source: components/config/ConfigItem.brs, line 20 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-ConfigList.html":{"id":"module-ConfigList.html","title":"Module: ConfigList","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: ConfigList Source: components/config/ConfigList.brs, line 1 Methods &lt;static&gt; configListShowDialog(configField) Parameters: Name Type Description configField dynamic Source: components/config/ConfigList.brs, line 33 Returns: Type void &lt;static&gt; dismiss_dialog() Source: components/config/ConfigList.brs, line 39 Returns: Type void &lt;static&gt; init() Source: components/config/ConfigList.brs, line 8 Returns: Type void &lt;static&gt; onDialogButton() Source: components/config/ConfigList.brs, line 26 Returns: Type dynamic &lt;static&gt; onItemSelected() Source: components/config/ConfigList.brs, line 20 Returns: Type void &lt;static&gt; setData() Source: components/config/ConfigList.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-ExtrasItem.html":{"id":"module-ExtrasItem.html","title":"Module: ExtrasItem","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: ExtrasItem Source: components/extras/ExtrasItem.brs, line 1 Methods &lt;static&gt; focusChanged() Source: components/extras/ExtrasItem.brs, line 20 Returns: Type void &lt;static&gt; init() Source: components/extras/ExtrasItem.brs, line 8 Returns: Type void &lt;static&gt; showContent() Source: components/extras/ExtrasItem.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-ExtrasRowList.html":{"id":"module-ExtrasRowList.html","title":"Module: ExtrasRowList","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: ExtrasRowList Source: components/extras/ExtrasRowList.brs, line 1 Methods &lt;static&gt; addRowSize(newRow) Parameters: Name Type Description newRow dynamic Source: components/extras/ExtrasRowList.brs, line 86 Returns: Type void &lt;static&gt; buildRow(rowTitle, items [, imgWdth]) Parameters: Name Type Argument Default Description rowTitle string items dynamic imgWdth dynamic &lt;optional&gt; 0 Source: components/extras/ExtrasRowList.brs, line 79 Returns: Type dynamic &lt;static&gt; init() Source: components/extras/ExtrasRowList.brs, line 8 Returns: Type void &lt;static&gt; loadParts(data) Parameters: Name Type Description data object Source: components/extras/ExtrasRowList.brs, line 21 Returns: Type void &lt;static&gt; loadPersonVideos(personId) Parameters: Name Type Description personId dynamic Source: components/extras/ExtrasRowList.brs, line 28 Returns: Type void &lt;static&gt; onAdditionalPartsLoaded() Source: components/extras/ExtrasRowList.brs, line 34 Returns: Type void &lt;static&gt; onLikeThisLoaded() Source: components/extras/ExtrasRowList.brs, line 46 Returns: Type void &lt;static&gt; onMoviesLoaded() Source: components/extras/ExtrasRowList.brs, line 58 Returns: Type void &lt;static&gt; onPeopleLoaded() Source: components/extras/ExtrasRowList.brs, line 40 Returns: Type void &lt;static&gt; onRowItemFocused() Source: components/extras/ExtrasRowList.brs, line 98 Returns: Type void &lt;static&gt; onRowItemSelected() Source: components/extras/ExtrasRowList.brs, line 92 Returns: Type void &lt;static&gt; onSeriesLoaded() Source: components/extras/ExtrasRowList.brs, line 70 Returns: Type void &lt;static&gt; onShowsLoaded() Source: components/extras/ExtrasRowList.brs, line 64 Returns: Type void &lt;static&gt; onSpecialFeaturesLoaded() Source: components/extras/ExtrasRowList.brs, line 52 Returns: Type dynamic &lt;static&gt; updateSize() Source: components/extras/ExtrasRowList.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-FavoriteItemsTask.html":{"id":"module-FavoriteItemsTask.html","title":"Module: FavoriteItemsTask","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: FavoriteItemsTask Source: components/ItemGrid/FavoriteItemsTask.brs, line 1 Methods &lt;static&gt; init() Source: components/ItemGrid/FavoriteItemsTask.brs, line 8 Returns: Type void &lt;static&gt; setFavoriteStatus() Source: components/ItemGrid/FavoriteItemsTask.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-FolderData.html":{"id":"module-FolderData.html","title":"Module: FolderData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: FolderData Source: components/data/FolderData.brs, line 1 Methods &lt;static&gt; setFields() Source: components/data/FolderData.brs, line 8 Returns: Type void &lt;static&gt; setPoster() Source: components/data/FolderData.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-GetFiltersTask.html":{"id":"module-GetFiltersTask.html","title":"Module: GetFiltersTask","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: GetFiltersTask Source: components/data/GetFiltersTask.brs, line 1 Methods &lt;static&gt; getFiltersTask() Source: components/data/GetFiltersTask.brs, line 14 Returns: Type void &lt;static&gt; init() Source: components/data/GetFiltersTask.brs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-GetNextEpisodeTask.html":{"id":"module-GetNextEpisodeTask.html","title":"Module: GetNextEpisodeTask","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: GetNextEpisodeTask Source: components/GetNextEpisodeTask.brs, line 1 Methods &lt;static&gt; getNextEpisodeTask() Source: components/GetNextEpisodeTask.brs, line 14 Returns: Type void &lt;static&gt; init() Source: components/GetNextEpisodeTask.brs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-GetPlaybackInfoTask.html":{"id":"module-GetPlaybackInfoTask.html","title":"Module: GetPlaybackInfoTask","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: GetPlaybackInfoTask Source: components/GetPlaybackInfoTask.brs, line 1 Methods &lt;static&gt; GetTranscodingStats(deviceSession) Parameters: Name Type Description deviceSession dynamic Source: components/GetPlaybackInfoTask.brs, line 33 Returns: Type dynamic &lt;static&gt; ItemPostPlaybackInfo(id [, mediaSourceId] [, audioTrackIndex] [, startTimeTicks]) Parameters: Name Type Argument Default Description id string mediaSourceId string &lt;optional&gt; \"\" audioTrackIndex integer &lt;optional&gt; -1 startTimeTicks longinteger &lt;optional&gt; 0 Source: components/GetPlaybackInfoTask.brs, line 18 Returns: Type dynamic &lt;static&gt; getDisplayBitrate(bitrate) Parameters: Name Type Description bitrate dynamic Source: components/GetPlaybackInfoTask.brs, line 46 Returns: Type dynamic &lt;static&gt; getPlaybackInfoTask() Returns an array of playback info to be displayed during playback. In the future, with a custom playback info view, we can return an associated array. Source: components/GetPlaybackInfoTask.brs, line 26 Returns: Type void &lt;static&gt; havePlaybackInfo() Source: components/GetPlaybackInfoTask.brs, line 39 Returns: Type dynamic &lt;static&gt; init() Source: components/GetPlaybackInfoTask.brs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-GetShuffleEpisodesTask.html":{"id":"module-GetShuffleEpisodesTask.html","title":"Module: GetShuffleEpisodesTask","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: GetShuffleEpisodesTask Source: components/GetShuffleEpisodesTask.brs, line 1 Methods &lt;static&gt; getShuffleEpisodesTask() Source: components/GetShuffleEpisodesTask.brs, line 14 Returns: Type void &lt;static&gt; init() Source: components/GetShuffleEpisodesTask.brs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-GridItem.html":{"id":"module-GridItem.html","title":"Module: GridItem","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: GridItem Source: components/ItemGrid/GridItem.brs, line 1 Methods &lt;static&gt; focusChanged() Display or hide title Visibility on focus change Source: components/ItemGrid/GridItem.brs, line 30 Returns: Type void &lt;static&gt; focusChanging() Use FocusPercent to animate scaling of Poser Image Source: components/ItemGrid/GridItem.brs, line 22 Returns: Type void &lt;static&gt; init() Source: components/ItemGrid/GridItem.brs, line 8 Returns: Type void &lt;static&gt; itemContentChanged() Source: components/ItemGrid/GridItem.brs, line 14 Returns: Type void &lt;static&gt; onPosterLoadStatusChanged() Hide backdrop and text when poster loaded Source: components/ItemGrid/GridItem.brs, line 37 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-GridItemSmall.html":{"id":"module-GridItemSmall.html","title":"Module: GridItemSmall","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: GridItemSmall Source: components/ItemGrid/GridItemSmall.brs, line 1 Methods &lt;static&gt; focusChanged() Source: components/ItemGrid/GridItemSmall.brs, line 20 Returns: Type void &lt;static&gt; init() Source: components/ItemGrid/GridItemSmall.brs, line 8 Returns: Type void &lt;static&gt; itemContentChanged() Source: components/ItemGrid/GridItemSmall.brs, line 14 Returns: Type void &lt;static&gt; onPosterLoadStatusChanged() Hide backdrop and text when poster loaded Source: components/ItemGrid/GridItemSmall.brs, line 27 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-Home.html":{"id":"module-Home.html","title":"Module: Home","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: Home Source: components/home/Home.brs, line 1 Methods &lt;static&gt; init() Source: components/home/Home.brs, line 8 Returns: Type void &lt;static&gt; loadLibraries() Source: components/home/Home.brs, line 20 Returns: Type void &lt;static&gt; refresh() Source: components/home/Home.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-HomeData.html":{"id":"module-HomeData.html","title":"Module: HomeData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: HomeData Source: components/data/HomeData.brs, line 1 Methods &lt;static&gt; setData() Source: components/data/HomeData.brs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-HomeItem.html":{"id":"module-HomeItem.html","title":"Module: HomeItem","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: HomeItem Source: components/home/HomeItem.brs, line 1 Methods &lt;static&gt; drawProgressBar(itemData) Draws and animates item progress bar Parameters: Name Type Description itemData dynamic Source: components/home/HomeItem.brs, line 23 Returns: Type void &lt;static&gt; focusChanged() Enable title scrolling based on item Focus Source: components/home/HomeItem.brs, line 31 Returns: Type void &lt;static&gt; init() Source: components/home/HomeItem.brs, line 8 Returns: Type void &lt;static&gt; itemContentChanged() Source: components/home/HomeItem.brs, line 14 Returns: Type void &lt;static&gt; onPosterLoadStatusChanged() Hide backdrop and icon when poster loaded Source: components/home/HomeItem.brs, line 38 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-HomeRows.html":{"id":"module-HomeRows.html","title":"Module: HomeRows","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: HomeRows Source: components/home/HomeRows.brs, line 1 Methods &lt;static&gt; addHomeSection(content, sizeArray, sectionName) Adds a new home section to the home rows. Returns a boolean indicating whether the section was handled. Parameters: Name Type Description content dynamic sizeArray dynamic sectionName string Source: components/home/HomeRows.brs, line 45 Returns: Type boolean &lt;static&gt; createContinueWatchingRow(content, sizeArray) Create a row displaying items the user can continue watching Parameters: Name Type Description content dynamic sizeArray dynamic Source: components/home/HomeRows.brs, line 81 Returns: Type void &lt;static&gt; createFavoritesRow(content, sizeArray) Create a row displaying items from the user's favorites list Parameters: Name Type Description content dynamic sizeArray dynamic Source: components/home/HomeRows.brs, line 99 Returns: Type void &lt;static&gt; createLatestInRows(content, sizeArray) Create a row displaying latest items in each of the user's libraries Parameters: Name Type Description content dynamic sizeArray dynamic Source: components/home/HomeRows.brs, line 63 Returns: Type void &lt;static&gt; createLibraryRow(content, sizeArray) Create a row displaying the user's libraries Parameters: Name Type Description content dynamic sizeArray dynamic Source: components/home/HomeRows.brs, line 54 Returns: Type void &lt;static&gt; createLiveTVRow(content, sizeArray) Create a row displaying the live tv now on section Parameters: Name Type Description content dynamic sizeArray dynamic Source: components/home/HomeRows.brs, line 72 Returns: Type void &lt;static&gt; createNextUpRow(content, sizeArray) Create a row displaying next episodes up to watch Parameters: Name Type Description content dynamic sizeArray dynamic Source: components/home/HomeRows.brs, line 90 Returns: Type void &lt;static&gt; filterNodeArray(nodeArray, nodeKey, excludeArray) Parameters: Name Type Description nodeArray object nodeKey string excludeArray object Source: components/home/HomeRows.brs, line 176 Returns: Type object &lt;static&gt; init() Source: components/home/HomeRows.brs, line 8 Returns: Type void &lt;static&gt; itemSelected() Source: components/home/HomeRows.brs, line 159 Returns: Type void &lt;static&gt; loadLibraries() Source: components/home/HomeRows.brs, line 14 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/home/HomeRows.brs, line 167 Returns: Type boolean &lt;static&gt; onLibrariesLoaded() Source: components/home/HomeRows.brs, line 26 Returns: Type void &lt;static&gt; removeHomeSection(sectionType) Removes a home section from the home rows Parameters: Name Type Description sectionType string Source: components/home/HomeRows.brs, line 34 Returns: Type void &lt;static&gt; updateContinueWatchingItems() Source: components/home/HomeRows.brs, line 118 Returns: Type void &lt;static&gt; updateFavoritesItems() Source: components/home/HomeRows.brs, line 112 Returns: Type void &lt;static&gt; updateHomeRows() Update home row data Source: components/home/HomeRows.brs, line 106 Returns: Type void &lt;static&gt; updateLatestInRows() Iterate over user's libraries and update data for each Latest In section Source: components/home/HomeRows.brs, line 131 Returns: Type void &lt;static&gt; updateLatestItems(msg) Parameters: Name Type Description msg dynamic Source: components/home/HomeRows.brs, line 138 Returns: Type void &lt;static&gt; updateNextUpItems() Source: components/home/HomeRows.brs, line 124 Returns: Type void &lt;static&gt; updateOnNowItems() Source: components/home/HomeRows.brs, line 144 Returns: Type void &lt;static&gt; updateSize() Source: components/home/HomeRows.brs, line 20 Returns: Type void &lt;static&gt; updateSizeArray(rowItemSize [, rowIndex] [, action]) Parameters: Name Type Argument Default Description rowItemSize dynamic rowIndex dynamic &lt;optional&gt; invalid action dynamic &lt;optional&gt; \"insert\" Source: components/home/HomeRows.brs, line 153 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-IconButton.html":{"id":"module-IconButton.html","title":"Module: IconButton","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: IconButton Source: components/IconButton.brs, line 1 Methods &lt;static&gt; init() Source: components/IconButton.brs, line 8 Returns: Type void &lt;static&gt; onBackgroundChanged() Source: components/IconButton.brs, line 20 Returns: Type void &lt;static&gt; onFocusChanged() Source: components/IconButton.brs, line 14 Returns: Type void &lt;static&gt; onHeightChanged() Source: components/IconButton.brs, line 44 Returns: Type void &lt;static&gt; onIconChanged() Source: components/IconButton.brs, line 26 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/IconButton.brs, line 64 Returns: Type boolean &lt;static&gt; onPaddingChanged() Source: components/IconButton.brs, line 56 Returns: Type void &lt;static&gt; onTextChanged() Source: components/IconButton.brs, line 32 Returns: Type void &lt;static&gt; onWidthChanged() Source: components/IconButton.brs, line 50 Returns: Type void &lt;static&gt; setIconSize() Source: components/IconButton.brs, line 38 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-Image.html":{"id":"module-Image.html","title":"Module: Image","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: Image Source: source/api/Image.brs, line 1 Methods &lt;static&gt; ImageURL(id [, version] [, params]) Parameters: Name Type Argument Default Description id dynamic version dynamic &lt;optional&gt; \"Primary\" params dynamic &lt;optional&gt; {} Source: source/api/Image.brs, line 27 Returns: Type dynamic &lt;static&gt; ItemImages( [id] [, params]) Parameters: Name Type Argument Default Description id string &lt;optional&gt; \"\" params object &lt;optional&gt; {} Source: source/api/Image.brs, line 10 Returns: Type dynamic &lt;static&gt; PosterImage(id [, params]) Parameters: Name Type Argument Default Description id string params object &lt;optional&gt; {} Source: source/api/Image.brs, line 18 Returns: Type dynamic &lt;static&gt; UserImageURL(id [, params]) Parameters: Name Type Argument Default Description id dynamic params dynamic &lt;optional&gt; {} Source: source/api/Image.brs, line 35 Returns: Type dynamic × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-ImageData.html":{"id":"module-ImageData.html","title":"Module: ImageData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: ImageData Source: components/data/ImageData.brs, line 1 Methods &lt;static&gt; setFields() Source: components/data/ImageData.brs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-ItemGrid.html":{"id":"module-ItemGrid.html","title":"Module: ItemGrid","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: ItemGrid Source: components/ItemGrid/ItemGrid.brs, line 1 Methods &lt;static&gt; ItemDataLoaded(msg) Handle loaded data, and add to Grid Parameters: Name Type Description msg dynamic Source: components/ItemGrid/ItemGrid.brs, line 112 Returns: Type void &lt;static&gt; SetBackground(backgroundUri) Set Background Image Parameters: Name Type Description backgroundUri string Source: components/ItemGrid/ItemGrid.brs, line 121 Returns: Type void &lt;static&gt; SetUpOptions() Data to display when options button selected Source: components/ItemGrid/ItemGrid.brs, line 103 Returns: Type void &lt;static&gt; getCollectionType() Return parent collection type Source: components/ItemGrid/ItemGrid.brs, line 87 Returns: Type string &lt;static&gt; getItemFocused() Returns Focused Item Source: components/ItemGrid/ItemGrid.brs, line 208 Returns: Type dynamic &lt;static&gt; inStringArray(array, searchValue) Search string array for search value. Return if it's found Parameters: Name Type Description array dynamic searchValue dynamic Source: components/ItemGrid/ItemGrid.brs, line 96 Returns: Type boolean &lt;static&gt; init() Source: components/ItemGrid/ItemGrid.brs, line 8 Returns: Type void &lt;static&gt; loadInitialItems() Load initial set of Data Source: components/ItemGrid/ItemGrid.brs, line 24 Returns: Type void &lt;static&gt; loadMoreData() Load next set of items Source: components/ItemGrid/ItemGrid.brs, line 153 Returns: Type void &lt;static&gt; newBGLoaded() When Image Loading Status changes Source: components/ItemGrid/ItemGrid.brs, line 137 Returns: Type void &lt;static&gt; onChannelFocused(msg) Parameters: Name Type Description msg dynamic Source: components/ItemGrid/ItemGrid.brs, line 201 Returns: Type void &lt;static&gt; onChannelSelected(msg) Parameters: Name Type Description msg dynamic Source: components/ItemGrid/ItemGrid.brs, line 194 Returns: Type void &lt;static&gt; onGenreItemSelected() Genre Item Selected Source: components/ItemGrid/ItemGrid.brs, line 16 Returns: Type void &lt;static&gt; onItemFocused() Handle new item being focused Source: components/ItemGrid/ItemGrid.brs, line 129 Returns: Type void &lt;static&gt; onItemSelected() Item Selected Source: components/ItemGrid/ItemGrid.brs, line 161 Returns: Type void &lt;static&gt; onItemalphaSelected() Source: components/ItemGrid/ItemGrid.brs, line 167 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/ItemGrid/ItemGrid.brs, line 216 Returns: Type boolean &lt;static&gt; onvoiceFilter() Source: components/ItemGrid/ItemGrid.brs, line 173 Returns: Type void &lt;static&gt; optionsClosed() Check if options updated and any reloading required Source: components/ItemGrid/ItemGrid.brs, line 181 Returns: Type void &lt;static&gt; setBoxsetsOptions(options) Set Boxset view, sort, and filter options Parameters: Name Type Description options dynamic Source: components/ItemGrid/ItemGrid.brs, line 40 Returns: Type void &lt;static&gt; setDefaultOptions(options) Set Default view, sort, and filter options Parameters: Name Type Description options dynamic Source: components/ItemGrid/ItemGrid.brs, line 80 Returns: Type void &lt;static&gt; setLiveTvOptions(options) Set Live TV view, sort, and filter options Parameters: Name Type Description options dynamic Source: components/ItemGrid/ItemGrid.brs, line 56 Returns: Type void &lt;static&gt; setMoviesOptions(options) Set Movies view, sort, and filter options Parameters: Name Type Description options dynamic Source: components/ItemGrid/ItemGrid.brs, line 32 Returns: Type void &lt;static&gt; setMusicOptions(options) Set Music view, sort, and filter options Parameters: Name Type Description options dynamic Source: components/ItemGrid/ItemGrid.brs, line 64 Returns: Type void &lt;static&gt; setPhotoAlbumOptions(options) Set Photo Album view, sort, and filter options Parameters: Name Type Description options dynamic Source: components/ItemGrid/ItemGrid.brs, line 72 Returns: Type void &lt;static&gt; setTvShowsOptions(options) Set TV Show view, sort, and filter options Parameters: Name Type Description options dynamic Source: components/ItemGrid/ItemGrid.brs, line 48 Returns: Type void &lt;static&gt; showTVGuide() Source: components/ItemGrid/ItemGrid.brs, line 187 Returns: Type void &lt;static&gt; swapDone() Swap Complete Source: components/ItemGrid/ItemGrid.brs, line 145 Returns: Type void &lt;static&gt; updateTitle() Source: components/ItemGrid/ItemGrid.brs, line 222 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-ItemGridOptions.html":{"id":"module-ItemGridOptions.html","title":"Module: ItemGridOptions","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: ItemGridOptions Source: components/ItemGrid/ItemGridOptions.brs, line 1 Methods &lt;static&gt; buttonFocusChanged() Switch menu shown when button focus changes Source: components/ItemGrid/ItemGridOptions.brs, line 46 Returns: Type void &lt;static&gt; hideChecklist() Source: components/ItemGrid/ItemGridOptions.brs, line 20 Returns: Type void &lt;static&gt; init() Source: components/ItemGrid/ItemGridOptions.brs, line 8 Returns: Type void &lt;static&gt; isFilterMenuDataValid() Check if data for Filter Menu is valid Source: components/ItemGrid/ItemGridOptions.brs, line 33 Returns: Type boolean &lt;static&gt; onFilterFocusChange() Source: components/ItemGrid/ItemGridOptions.brs, line 26 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/ItemGrid/ItemGridOptions.brs, line 74 Returns: Type boolean &lt;static&gt; optionsSet() Source: components/ItemGrid/ItemGridOptions.brs, line 39 Returns: Type void &lt;static&gt; saveFavoriteItemSelected(msg) Parameters: Name Type Description msg dynamic Source: components/ItemGrid/ItemGridOptions.brs, line 66 Returns: Type void &lt;static&gt; setHeartColor(color) Parameters: Name Type Description color string Source: components/ItemGrid/ItemGridOptions.brs, line 59 Returns: Type void &lt;static&gt; showChecklist() Source: components/ItemGrid/ItemGridOptions.brs, line 14 Returns: Type void &lt;static&gt; toggleFavorite() Source: components/ItemGrid/ItemGridOptions.brs, line 52 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-Items.html":{"id":"module-Items.html","title":"Module: Items","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: Items Source: source/api/Items.brs, line 1 Methods &lt;static&gt; AppearsOnList(id) Get list of albums an artist appears on Parameters: Name Type Description id string Source: source/api/Items.brs, line 61 Returns: Type dynamic &lt;static&gt; ArtistOverview(name) Music Artist Data Parameters: Name Type Description name string Source: source/api/Items.brs, line 45 Returns: Type dynamic &lt;static&gt; AudioItem(id) Get Songs that are on an Album Parameters: Name Type Description id string Source: source/api/Items.brs, line 94 Returns: Type dynamic &lt;static&gt; AudioStream(id) Parameters: Name Type Description id string Source: source/api/Items.brs, line 125 Returns: Type dynamic &lt;static&gt; BackdropImage(id) Parameters: Name Type Description id string Source: source/api/Items.brs, line 139 Returns: Type dynamic &lt;static&gt; CreateArtistMix(id) Get Instant Mix based on item Parameters: Name Type Description id string Source: source/api/Items.brs, line 110 Returns: Type dynamic &lt;static&gt; CreateInstantMix(id) Get Instant Mix based on item Parameters: Name Type Description id string Source: source/api/Items.brs, line 102 Returns: Type dynamic &lt;static&gt; GetIntroVideos(id) Get Intro Videos for an item Parameters: Name Type Description id string Source: source/api/Items.brs, line 118 Returns: Type dynamic &lt;static&gt; GetSongsByArtist(id [, params]) Get list of songs belonging to an artist Parameters: Name Type Argument Default Description id string params object &lt;optional&gt; {} Source: source/api/Items.brs, line 70 Returns: Type dynamic &lt;static&gt; ItemGetPlaybackInfo(id [, startTimeTicks]) Parameters: Name Type Argument Default Description id string startTimeTicks longinteger &lt;optional&gt; 0 Source: source/api/Items.brs, line 10 Returns: Type dynamic &lt;static&gt; ItemMetaData(id) MetaData about an item Parameters: Name Type Description id string Source: source/api/Items.brs, line 37 Returns: Type dynamic &lt;static&gt; ItemPostPlaybackInfo(id [, mediaSourceId] [, audioTrackIndex] [, subtitleTrackIndex] [, startTimeTicks]) Parameters: Name Type Argument Default Description id string mediaSourceId string &lt;optional&gt; \"\" audioTrackIndex integer &lt;optional&gt; -1 subtitleTrackIndex integer &lt;optional&gt; -1 startTimeTicks longinteger &lt;optional&gt; 0 Source: source/api/Items.brs, line 21 Returns: Type dynamic &lt;static&gt; MusicAlbumList(id) Get list of albums belonging to an artist Parameters: Name Type Description id string Source: source/api/Items.brs, line 53 Returns: Type dynamic &lt;static&gt; MusicSongList(id) Get Songs that are on an Album Parameters: Name Type Description id string Source: source/api/Items.brs, line 86 Returns: Type dynamic &lt;static&gt; PlaylistItemList(id) Get Items that are under the provided item Parameters: Name Type Description id string Source: source/api/Items.brs, line 78 Returns: Type dynamic &lt;static&gt; TVEpisodeShuffleList(show_id) Parameters: Name Type Description show_id string Source: source/api/Items.brs, line 173 Returns: Type dynamic &lt;static&gt; TVEpisodes(showId, seasonId) Returns a list of TV Shows for a given TV Show and season Accepts strings for the TV Show Id and the season Id Parameters: Name Type Description showId string seasonId string Source: source/api/Items.brs, line 157 Returns: Type dynamic &lt;static&gt; TVSeasonExtras(seasonId) Returns a list of extra features for a TV Show season Accepts a string that is a TV Show season id Parameters: Name Type Description seasonId string Source: source/api/Items.brs, line 166 Returns: Type dynamic &lt;static&gt; TVSeasons(id) Seasons for a TV Show Parameters: Name Type Description id string Source: source/api/Items.brs, line 147 Returns: Type dynamic &lt;static&gt; searchMedia(query) Search across all libraries Parameters: Name Type Description query string Source: source/api/Items.brs, line 29 Returns: Type dynamic &lt;static&gt; useTranscodeAudioStream(playbackInfo) Parameters: Name Type Description playbackInfo dynamic Source: source/api/Items.brs, line 132 Returns: Type dynamic × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-JFButton.html":{"id":"module-JFButton.html","title":"Module: JFButton","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: JFButton Source: components/JFButton.brs, line 1 Methods &lt;static&gt; init() Source: components/JFButton.brs, line 8 Returns: Type void &lt;static&gt; onTextChanged() Whenever the text changes, pad both sides with whitespace so we can center the button text Source: components/JFButton.brs, line 17 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-JFButtons.html":{"id":"module-JFButtons.html","title":"Module: JFButtons","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: JFButtons Source: components/Buttons/JFButtons.brs, line 1 Methods &lt;static&gt; focusChanged() Change opacity of the highlighted menu item based on focus Source: components/Buttons/JFButtons.brs, line 52 Returns: Type void &lt;static&gt; highlightSelected(index [, animate]) Highlight selected menu option Parameters: Name Type Argument Default Description index integer animate dynamic &lt;optional&gt; true Source: components/Buttons/JFButtons.brs, line 45 Returns: Type void &lt;static&gt; init() Source: components/Buttons/JFButtons.brs, line 8 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/Buttons/JFButtons.brs, line 60 Returns: Type boolean &lt;static&gt; renderChanged() When options are fully displayed, set focus and selected option Source: components/Buttons/JFButtons.brs, line 24 Returns: Type void &lt;static&gt; selectedIndexChanged() When Selected Index set, ensure it is the one Focused Source: components/Buttons/JFButtons.brs, line 16 Returns: Type void &lt;static&gt; showButtons() Source: components/Buttons/JFButtons.brs, line 36 Returns: Type void &lt;static&gt; updateButtons() Source: components/Buttons/JFButtons.brs, line 30 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-JFGroup.html":{"id":"module-JFGroup.html","title":"Module: JFGroup","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: JFGroup Source: components/JFGroup.brs, line 1 Methods &lt;static&gt; init() Source: components/JFGroup.brs, line 8 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/JFGroup.brs, line 16 Returns: Type boolean × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-JFMessageDialog.html":{"id":"module-JFMessageDialog.html","title":"Module: JFMessageDialog","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: JFMessageDialog Source: components/JFMessageDialog.brs, line 1 Methods &lt;static&gt; init() Source: components/JFMessageDialog.brs, line 8 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/JFMessageDialog.brs, line 16 Returns: Type boolean &lt;static&gt; redraw() Source: components/JFMessageDialog.brs, line 34 Returns: Type void &lt;static&gt; updateMessage() Source: components/JFMessageDialog.brs, line 28 Returns: Type void &lt;static&gt; updateOptions() Source: components/JFMessageDialog.brs, line 22 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-JFOverhang.html":{"id":"module-JFOverhang.html","title":"Module: JFOverhang","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: JFOverhang Source: components/JFOverhang.brs, line 1 Methods &lt;static&gt; init() Source: components/JFOverhang.brs, line 8 Returns: Type void &lt;static&gt; onVisibleChange() Source: components/JFOverhang.brs, line 14 Returns: Type void &lt;static&gt; resetTime() Source: components/JFOverhang.brs, line 50 Returns: Type void &lt;static&gt; setClockVisibility() Source: components/JFOverhang.brs, line 26 Returns: Type void &lt;static&gt; setRightSeperatorVisibility() Source: components/JFOverhang.brs, line 32 Returns: Type void &lt;static&gt; updateOptions() Source: components/JFOverhang.brs, line 62 Returns: Type void &lt;static&gt; updateTime() Source: components/JFOverhang.brs, line 44 Returns: Type void &lt;static&gt; updateTimeDisplay() Source: components/JFOverhang.brs, line 56 Returns: Type void &lt;static&gt; updateTitle() Source: components/JFOverhang.brs, line 20 Returns: Type void &lt;static&gt; updateUser() Source: components/JFOverhang.brs, line 38 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-JFScene.html":{"id":"module-JFScene.html","title":"Module: JFScene","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: JFScene Source: components/JFScene.brs, line 1 Methods &lt;static&gt; init() Source: components/JFScene.brs, line 8 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/JFScene.brs, line 16 Returns: Type boolean × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-JFScreen.html":{"id":"module-JFScreen.html","title":"Module: JFScreen","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: JFScreen Source: components/JFScreen.brs, line 1 Methods &lt;static&gt; OnScreenHidden() Function called when the screen is hidden by the screen manager It is expected that screens override this function if required, to handle focus any actions required on the screen being hidden Source: components/JFScreen.brs, line 26 Returns: Type void &lt;static&gt; OnScreenShown() Function called when the screen is displayed by the screen manager It is expected that screens override this function to handle focus managmenet and any other actions required on screen shown Source: components/JFScreen.brs, line 17 Returns: Type void &lt;static&gt; init() Source: components/JFScreen.brs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-JFServer.html":{"id":"module-JFServer.html","title":"Module: JFServer","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: JFServer Source: components/config/JFServer.brs, line 1 Methods &lt;static&gt; init() Source: components/config/JFServer.brs, line 8 Returns: Type void &lt;static&gt; itemContentChanged() Source: components/config/JFServer.brs, line 14 Returns: Type void &lt;static&gt; onFocusPercentChange(event) Parameters: Name Type Description event dynamic Source: components/config/JFServer.brs, line 21 Returns: Type void &lt;static&gt; setTextColor(percentFocused) Parameters: Name Type Description percentFocused dynamic Source: components/config/JFServer.brs, line 28 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-JFVideo.html":{"id":"module-JFVideo.html","title":"Module: JFVideo","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: JFVideo Source: components/JFVideo.brs, line 1 Methods &lt;static&gt; ReportPlayback( [state]) Report playback to server Parameters: Name Type Argument Default Description state string &lt;optional&gt; \"update\" Source: components/JFVideo.brs, line 101 Returns: Type void &lt;static&gt; bufferCheck(msg) Check the the buffering has not hung Parameters: Name Type Description msg dynamic Source: components/JFVideo.brs, line 110 Returns: Type void &lt;static&gt; checkTimeToDisplayNextEpisode() Checks if we need to display the Next Episode button Source: components/JFVideo.brs, line 76 Returns: Type void &lt;static&gt; hideNextEpisodeButton() Runs hide Next Episode button animation and sets focus back to video Source: components/JFVideo.brs, line 69 Returns: Type void &lt;static&gt; init() Source: components/JFVideo.brs, line 8 Returns: Type void &lt;static&gt; loadCaption() Source: components/JFVideo.brs, line 20 Returns: Type void &lt;static&gt; onAllowCaptionsChange() Source: components/JFVideo.brs, line 14 Returns: Type void &lt;static&gt; onContentChange() Event handler for when video content field changes Source: components/JFVideo.brs, line 39 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/JFVideo.brs, line 118 Returns: Type boolean &lt;static&gt; onNextEpisodeDataLoaded() Source: components/JFVideo.brs, line 45 Returns: Type void &lt;static&gt; onPositionChanged() When Video Player state changes Source: components/JFVideo.brs, line 83 Returns: Type void &lt;static&gt; onState(msg) When Video Player state changes Parameters: Name Type Description msg dynamic Source: components/JFVideo.brs, line 92 Returns: Type void &lt;static&gt; showNextEpisodeButton() Runs Next Episode button animation and sets focus to button Source: components/JFVideo.brs, line 53 Returns: Type void &lt;static&gt; toggleCaption() Source: components/JFVideo.brs, line 26 Returns: Type void &lt;static&gt; updateCaption() Source: components/JFVideo.brs, line 32 Returns: Type void &lt;static&gt; updateCount() Update count down text Source: components/JFVideo.brs, line 61 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-ListPoster.html":{"id":"module-ListPoster.html","title":"Module: ListPoster","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: ListPoster Source: components/ListPoster.brs, line 1 Methods &lt;static&gt; focusChanged() Enable title scrolling based on item Focus Source: components/ListPoster.brs, line 28 Returns: Type void &lt;static&gt; init() Source: components/ListPoster.brs, line 8 Returns: Type void &lt;static&gt; itemContentChanged() Source: components/ListPoster.brs, line 20 Returns: Type void &lt;static&gt; updateSize() Source: components/ListPoster.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-LoadChannelsTask.html":{"id":"module-LoadChannelsTask.html","title":"Module: LoadChannelsTask","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: LoadChannelsTask Source: components/liveTv/LoadChannelsTask.brs, line 1 Methods &lt;static&gt; init() Source: components/liveTv/LoadChannelsTask.brs, line 8 Returns: Type void &lt;static&gt; loadChannels() Source: components/liveTv/LoadChannelsTask.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-LoadItemsTask.html":{"id":"module-LoadItemsTask.html","title":"Module: LoadItemsTask","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: LoadItemsTask Source: components/home/LoadItemsTask.brs, line 1 Methods &lt;static&gt; getPersonVideos(videoType, dest, dimens) Parameters: Name Type Description videoType dynamic dest dynamic dimens dynamic Source: components/home/LoadItemsTask.brs, line 23 Returns: Type void &lt;static&gt; init() Source: components/home/LoadItemsTask.brs, line 8 Returns: Type void &lt;static&gt; loadItems() Source: components/home/LoadItemsTask.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-LoadItemsTask2.html":{"id":"module-LoadItemsTask2.html","title":"Module: LoadItemsTask2","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: LoadItemsTask2 Source: components/ItemGrid/LoadItemsTask2.brs, line 1 Methods &lt;static&gt; init() Source: components/ItemGrid/LoadItemsTask2.brs, line 8 Returns: Type void &lt;static&gt; loadItems() Source: components/ItemGrid/LoadItemsTask2.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-LoadPhotoTask.html":{"id":"module-LoadPhotoTask.html","title":"Module: LoadPhotoTask","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: LoadPhotoTask Source: components/photos/LoadPhotoTask.brs, line 1 Methods &lt;static&gt; init() Source: components/photos/LoadPhotoTask.brs, line 8 Returns: Type void &lt;static&gt; loadItems() Source: components/photos/LoadPhotoTask.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-LoadProgramDetailsTask.html":{"id":"module-LoadProgramDetailsTask.html","title":"Module: LoadProgramDetailsTask","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: LoadProgramDetailsTask Source: components/liveTv/LoadProgramDetailsTask.brs, line 1 Methods &lt;static&gt; init() Source: components/liveTv/LoadProgramDetailsTask.brs, line 8 Returns: Type void &lt;static&gt; loadProgramDetails() Source: components/liveTv/LoadProgramDetailsTask.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-LoadScreenSaverTimeoutTask.html":{"id":"module-LoadScreenSaverTimeoutTask.html","title":"Module: LoadScreenSaverTimeoutTask","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: LoadScreenSaverTimeoutTask Source: components/music/LoadScreenSaverTimeoutTask.brs, line 1 Methods &lt;static&gt; getScreensaverTimeout() Source: components/music/LoadScreenSaverTimeoutTask.brs, line 14 Returns: Type void &lt;static&gt; init() Source: components/music/LoadScreenSaverTimeoutTask.brs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-LoadSheduleTask.html":{"id":"module-LoadSheduleTask.html","title":"Module: LoadSheduleTask","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: LoadSheduleTask Source: components/liveTv/LoadSheduleTask.brs, line 1 Methods &lt;static&gt; init() Source: components/liveTv/LoadSheduleTask.brs, line 8 Returns: Type void &lt;static&gt; loadSchedule() Source: components/liveTv/LoadSheduleTask.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-LoadVideoContentTask.html":{"id":"module-LoadVideoContentTask.html","title":"Module: LoadVideoContentTask","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: LoadVideoContentTask Source: components/ItemGrid/LoadVideoContentTask.brs, line 1 Methods &lt;static&gt; FindPreferredAudioStream(streams) Parameters: Name Type Description streams dynamic Source: components/ItemGrid/LoadVideoContentTask.brs, line 101 Returns: Type integer &lt;static&gt; LoadItems_AddVideoContent(video, mediaSourceId [, audio_stream_idx] [, subtitle_idx] [, forceTranscoding]) Parameters: Name Type Argument Default Description video object mediaSourceId dynamic audio_stream_idx integer &lt;optional&gt; 1 subtitle_idx integer &lt;optional&gt; -1 forceTranscoding boolean &lt;optional&gt; false Source: components/ItemGrid/LoadVideoContentTask.brs, line 36 Returns: Type void &lt;static&gt; LoadItems_VideoPlayer(id [, mediaSourceId] [, audio_stream_idx] [, subtitle_idx] [, forceTranscoding]) Parameters: Name Type Argument Default Description id string mediaSourceId dynamic &lt;optional&gt; invalid audio_stream_idx integer &lt;optional&gt; 1 subtitle_idx integer &lt;optional&gt; -1 forceTranscoding boolean &lt;optional&gt; false Source: components/ItemGrid/LoadVideoContentTask.brs, line 25 Returns: Type dynamic &lt;static&gt; addNextEpisodesToQueue(showID) Add next episodes to the playback queue Parameters: Name Type Description showID dynamic Source: components/ItemGrid/LoadVideoContentTask.brs, line 85 Returns: Type void &lt;static&gt; addSubtitlesToVideo(video, meta) Parameters: Name Type Description video dynamic meta dynamic Source: components/ItemGrid/LoadVideoContentTask.brs, line 54 Returns: Type void &lt;static&gt; addVideoContentURL(video, mediaSourceId, audio_stream_idx, fully_external) Parameters: Name Type Description video dynamic mediaSourceId dynamic audio_stream_idx dynamic fully_external dynamic Source: components/ItemGrid/LoadVideoContentTask.brs, line 46 Returns: Type void &lt;static&gt; directPlaySupported(meta) Parameters: Name Type Description meta object Source: components/ItemGrid/LoadVideoContentTask.brs, line 70 Returns: Type boolean &lt;static&gt; getContainerType(meta) Parameters: Name Type Description meta object Source: components/ItemGrid/LoadVideoContentTask.brs, line 77 Returns: Type string &lt;static&gt; getSubtitleLanguages() Source: components/ItemGrid/LoadVideoContentTask.brs, line 107 Returns: Type dynamic &lt;static&gt; getTranscodeReasons(url) Extract array of Transcode Reasons from the content URL Parameters: Name Type Description url string Source: components/ItemGrid/LoadVideoContentTask.brs, line 63 Returns: Array of Strings Type object &lt;static&gt; init() Source: components/ItemGrid/LoadVideoContentTask.brs, line 8 Returns: Type void &lt;static&gt; loadItems() Source: components/ItemGrid/LoadVideoContentTask.brs, line 14 Returns: Type void &lt;static&gt; sortSubtitles(id, MediaStreams) Checks available subtitle tracks and puts subtitles in forced, default, and non-default/forced but preferred language at the top Parameters: Name Type Description id string MediaStreams dynamic Source: components/ItemGrid/LoadVideoContentTask.brs, line 94 Returns: Type dynamic × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-LoginScene.html":{"id":"module-LoginScene.html","title":"Module: LoginScene","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: LoginScene Source: components/config/LoginScene.brs, line 1 Methods &lt;static&gt; init() Source: components/config/LoginScene.brs, line 8 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/config/LoginScene.brs, line 16 Returns: Type boolean × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-Main.html":{"id":"module-Main.html","title":"Module: Main","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: Main Source: source/Main.brs, line 1 Methods &lt;static&gt; Main(args) Parameters: Name Type Description args dynamic Source: source/Main.brs, line 9 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-MovieData.html":{"id":"module-MovieData.html","title":"Module: MovieData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: MovieData Source: components/data/MovieData.brs, line 1 Methods &lt;static&gt; setContainer() Source: components/data/MovieData.brs, line 20 Returns: Type void &lt;static&gt; setFields() Source: components/data/MovieData.brs, line 8 Returns: Type void &lt;static&gt; setPoster() Source: components/data/MovieData.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-MovieDetails.html":{"id":"module-MovieDetails.html","title":"Module: MovieDetails","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: MovieDetails Source: components/movies/MovieDetails.brs, line 1 Methods &lt;static&gt; OnScreenShown() Source: components/movies/MovieDetails.brs, line 14 Returns: Type void &lt;static&gt; SetDefaultAudioTrack(itemData) Parameters: Name Type Description itemData dynamic Source: components/movies/MovieDetails.brs, line 47 Returns: Type void &lt;static&gt; SetUpAudioOptions(streams) Parameters: Name Type Description streams dynamic Source: components/movies/MovieDetails.brs, line 40 Returns: Type void &lt;static&gt; SetUpVideoOptions(streams) Parameters: Name Type Description streams dynamic Source: components/movies/MovieDetails.brs, line 33 Returns: Type void &lt;static&gt; audioOptionsClosed() Check if options updated and any reloading required Source: components/movies/MovieDetails.brs, line 94 Returns: Type void &lt;static&gt; getEndTime() Source: components/movies/MovieDetails.brs, line 67 Returns: Type string &lt;static&gt; getRuntime() Source: components/movies/MovieDetails.brs, line 61 Returns: Type integer &lt;static&gt; init() Source: components/movies/MovieDetails.brs, line 8 Returns: Type void &lt;static&gt; itemContentChanged() Source: components/movies/MovieDetails.brs, line 26 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/movies/MovieDetails.brs, line 110 Returns: Type boolean &lt;static&gt; round(f) Parameters: Name Type Description f float Source: components/movies/MovieDetails.brs, line 86 Returns: Type integer &lt;static&gt; setFavoriteColor() Source: components/movies/MovieDetails.brs, line 73 Returns: Type void &lt;static&gt; setFieldText(field, value) Parameters: Name Type Description field dynamic value dynamic Source: components/movies/MovieDetails.brs, line 55 Returns: Type void &lt;static&gt; setWatchedColor() Source: components/movies/MovieDetails.brs, line 79 Returns: Type void &lt;static&gt; trailerAvailableChanged() Source: components/movies/MovieDetails.brs, line 20 Returns: Type void &lt;static&gt; videoOptionsClosed() Check if options were updated and if any reloding is needed... Source: components/movies/MovieDetails.brs, line 102 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-MovieLibraryView.html":{"id":"module-MovieLibraryView.html","title":"Module: MovieLibraryView","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: MovieLibraryView Source: components/ItemGrid/MovieLibraryView.brs, line 1 Methods &lt;static&gt; FilterDataLoaded(msg) Logo Image Loaded Event Handler Parameters: Name Type Description msg dynamic Source: components/ItemGrid/MovieLibraryView.brs, line 75 Returns: Type void &lt;static&gt; ItemDataLoaded(msg) Handle loaded data, and add to Grid Parameters: Name Type Description msg dynamic Source: components/ItemGrid/MovieLibraryView.brs, line 93 Returns: Type void &lt;static&gt; LogoImageLoaded(msg) Logo Image Loaded Event Handler Parameters: Name Type Description msg dynamic Source: components/ItemGrid/MovieLibraryView.brs, line 84 Returns: Type void &lt;static&gt; OnScreenHidden() Source: components/ItemGrid/MovieLibraryView.brs, line 20 Returns: Type void &lt;static&gt; OnScreenShown() Source: components/ItemGrid/MovieLibraryView.brs, line 26 Returns: Type void &lt;static&gt; SetBackground(backgroundUri) Set Background Image Parameters: Name Type Description backgroundUri string Source: components/ItemGrid/MovieLibraryView.brs, line 138 Returns: Type void &lt;static&gt; SetName(movieName) Set Selected Movie Name Parameters: Name Type Description movieName string Source: components/ItemGrid/MovieLibraryView.brs, line 102 Returns: Type void &lt;static&gt; SetOfficialRating(movieOfficialRating) Set Selected Movie OfficialRating Parameters: Name Type Description movieOfficialRating string Source: components/ItemGrid/MovieLibraryView.brs, line 120 Returns: Type void &lt;static&gt; SetOverview(movieOverview) Set Selected Movie Overview Parameters: Name Type Description movieOverview string Source: components/ItemGrid/MovieLibraryView.brs, line 111 Returns: Type void &lt;static&gt; SetProductionYear(movieProductionYear) Set Selected Movie ProductionYear Parameters: Name Type Description movieProductionYear dynamic Source: components/ItemGrid/MovieLibraryView.brs, line 129 Returns: Type void &lt;static&gt; getCollectionType() Return parent collection type Source: components/ItemGrid/MovieLibraryView.brs, line 49 Returns: Type string &lt;static&gt; getItemFocused() Returns Focused Item Source: components/ItemGrid/MovieLibraryView.brs, line 208 Returns: Type dynamic &lt;static&gt; getRuntime(runTimeTicks) Parameters: Name Type Description runTimeTicks dynamic Source: components/ItemGrid/MovieLibraryView.brs, line 153 Returns: Type integer &lt;static&gt; inStringArray(array, searchValue) Search string array for search value. Return if it's found Parameters: Name Type Description array dynamic searchValue dynamic Source: components/ItemGrid/MovieLibraryView.brs, line 58 Returns: Type boolean &lt;static&gt; init() Source: components/ItemGrid/MovieLibraryView.brs, line 14 Returns: Type void &lt;static&gt; loadInitialItems() Load initial set of Data Source: components/ItemGrid/MovieLibraryView.brs, line 34 Returns: Type void &lt;static&gt; loadMoreData() Load next set of items Source: components/ItemGrid/MovieLibraryView.brs, line 192 Returns: Type void &lt;static&gt; newBGLoaded() When Image Loading Status changes Source: components/ItemGrid/MovieLibraryView.brs, line 176 Returns: Type void &lt;static&gt; onChannelSelected(msg) Parameters: Name Type Description msg dynamic Source: components/ItemGrid/MovieLibraryView.brs, line 243 Returns: Type void &lt;static&gt; onGenreItemSelected() Genre Item Selected Source: components/ItemGrid/MovieLibraryView.brs, line 216 Returns: Type void &lt;static&gt; onItemFocused() Handle new item being focused Source: components/ItemGrid/MovieLibraryView.brs, line 146 Returns: Type void &lt;static&gt; onItemSelected() Item Selected Source: components/ItemGrid/MovieLibraryView.brs, line 200 Returns: Type void &lt;static&gt; onItemalphaSelected() Source: components/ItemGrid/MovieLibraryView.brs, line 222 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/ItemGrid/MovieLibraryView.brs, line 251 Returns: Type boolean &lt;static&gt; onvoiceFilter() Source: components/ItemGrid/MovieLibraryView.brs, line 228 Returns: Type void &lt;static&gt; optionsClosed() Check if options updated and any reloading required Source: components/ItemGrid/MovieLibraryView.brs, line 236 Returns: Type void &lt;static&gt; round(f) Parameters: Name Type Description f float Source: components/ItemGrid/MovieLibraryView.brs, line 160 Returns: Type integer &lt;static&gt; setFieldText(field, value) Parameters: Name Type Description field dynamic value dynamic Source: components/ItemGrid/MovieLibraryView.brs, line 168 Returns: Type void &lt;static&gt; setMoviesOptions(options) Set Movies view, sort, and filter options Parameters: Name Type Description options dynamic Source: components/ItemGrid/MovieLibraryView.brs, line 42 Returns: Type void &lt;static&gt; setSelectedOptions(options) Data to display when options button selected Parameters: Name Type Description options dynamic Source: components/ItemGrid/MovieLibraryView.brs, line 66 Returns: Type void &lt;static&gt; setupNodes() Source: components/ItemGrid/MovieLibraryView.brs, line 8 Returns: Type void &lt;static&gt; swapDone() Swap Complete Source: components/ItemGrid/MovieLibraryView.brs, line 184 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-MovieOptions.html":{"id":"module-MovieOptions.html","title":"Module: MovieOptions","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: MovieOptions Source: components/movies/MovieOptions.brs, line 1 Methods &lt;static&gt; buttonFocusChanged() Switch menu shown when button focus changes Source: components/movies/MovieOptions.brs, line 21 Returns: Type void &lt;static&gt; init() Source: components/movies/MovieOptions.brs, line 8 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/movies/MovieOptions.brs, line 29 Returns: Type boolean &lt;static&gt; optionsSet() Source: components/movies/MovieOptions.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-MusicAlbumData.html":{"id":"module-MusicAlbumData.html","title":"Module: MusicAlbumData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: MusicAlbumData Source: components/data/MusicAlbumData.brs, line 1 Methods &lt;static&gt; setFields() Source: components/data/MusicAlbumData.brs, line 8 Returns: Type void &lt;static&gt; setPoster() Source: components/data/MusicAlbumData.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-MusicAlbumSongListData.html":{"id":"module-MusicAlbumSongListData.html","title":"Module: MusicAlbumSongListData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: MusicAlbumSongListData Source: components/data/MusicAlbumSongListData.brs, line 1 Methods &lt;static&gt; setFields() Source: components/data/MusicAlbumSongListData.brs, line 8 Returns: Type void &lt;static&gt; setPoster() Source: components/data/MusicAlbumSongListData.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-MusicArtistData.html":{"id":"module-MusicArtistData.html","title":"Module: MusicArtistData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: MusicArtistData Source: components/data/MusicArtistData.brs, line 1 Methods &lt;static&gt; setFields() Source: components/data/MusicArtistData.brs, line 8 Returns: Type void &lt;static&gt; setPoster() Source: components/data/MusicArtistData.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-MusicArtistGridItem.html":{"id":"module-MusicArtistGridItem.html","title":"Module: MusicArtistGridItem","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: MusicArtistGridItem Source: components/ItemGrid/MusicArtistGridItem.brs, line 1 Methods &lt;static&gt; focusChanged() Display or hide title Visibility on focus change Source: components/ItemGrid/MusicArtistGridItem.brs, line 21 Returns: Type void &lt;static&gt; init() Source: components/ItemGrid/MusicArtistGridItem.brs, line 8 Returns: Type void &lt;static&gt; itemContentChanged() Source: components/ItemGrid/MusicArtistGridItem.brs, line 14 Returns: Type void &lt;static&gt; onPosterLoadStatusChanged() Hide backdrop and text when poster loaded Source: components/ItemGrid/MusicArtistGridItem.brs, line 28 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-MusicLibraryView.html":{"id":"module-MusicLibraryView.html","title":"Module: MusicLibraryView","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: MusicLibraryView Source: components/ItemGrid/MusicLibraryView.brs, line 1 Methods &lt;static&gt; ItemDataLoaded(msg) Handle loaded data, and add to Grid Parameters: Name Type Description msg dynamic Source: components/ItemGrid/MusicLibraryView.brs, line 83 Returns: Type void &lt;static&gt; LogoImageLoaded(msg) Logo Image Loaded Event Handler Parameters: Name Type Description msg dynamic Source: components/ItemGrid/MusicLibraryView.brs, line 74 Returns: Type void &lt;static&gt; OnScreenHidden() Source: components/ItemGrid/MusicLibraryView.brs, line 20 Returns: Type void &lt;static&gt; OnScreenShown() Source: components/ItemGrid/MusicLibraryView.brs, line 26 Returns: Type void &lt;static&gt; SetAlbumCount(totalCount) Set Selected Artist Album Count Parameters: Name Type Description totalCount dynamic Source: components/ItemGrid/MusicLibraryView.brs, line 110 Returns: Type void &lt;static&gt; SetBackground(backgroundUri) Set Background Image Parameters: Name Type Description backgroundUri string Source: components/ItemGrid/MusicLibraryView.brs, line 128 Returns: Type void &lt;static&gt; SetGenres(artistGenres) Set Selected Artist Genres Parameters: Name Type Description artistGenres dynamic Source: components/ItemGrid/MusicLibraryView.brs, line 119 Returns: Type void &lt;static&gt; SetName(artistName) Set Selected Artist Name Parameters: Name Type Description artistName string Source: components/ItemGrid/MusicLibraryView.brs, line 92 Returns: Type void &lt;static&gt; SetSongCount(totalCount) Set Selected Artist Song Count Parameters: Name Type Description totalCount dynamic Source: components/ItemGrid/MusicLibraryView.brs, line 101 Returns: Type void &lt;static&gt; SetUpOptions() Data to display when options button selected Source: components/ItemGrid/MusicLibraryView.brs, line 65 Returns: Type void &lt;static&gt; getCollectionType() Return parent collection type Source: components/ItemGrid/MusicLibraryView.brs, line 49 Returns: Type string &lt;static&gt; getItemFocused() Returns Focused Item Source: components/ItemGrid/MusicLibraryView.brs, line 184 Returns: Type dynamic &lt;static&gt; inStringArray(array, searchValue) Search string array for search value. Return if it's found Parameters: Name Type Description array dynamic searchValue dynamic Source: components/ItemGrid/MusicLibraryView.brs, line 58 Returns: Type boolean &lt;static&gt; init() Source: components/ItemGrid/MusicLibraryView.brs, line 14 Returns: Type void &lt;static&gt; loadInitialItems() Load initial set of Data Source: components/ItemGrid/MusicLibraryView.brs, line 34 Returns: Type void &lt;static&gt; loadMoreData() Load next set of items Source: components/ItemGrid/MusicLibraryView.brs, line 168 Returns: Type void &lt;static&gt; newBGLoaded() When Image Loading Status changes Source: components/ItemGrid/MusicLibraryView.brs, line 152 Returns: Type void &lt;static&gt; onChannelSelected(msg) Parameters: Name Type Description msg dynamic Source: components/ItemGrid/MusicLibraryView.brs, line 227 Returns: Type void &lt;static&gt; onGenreItemFocused() Genre Item Focused Source: components/ItemGrid/MusicLibraryView.brs, line 200 Returns: Type void &lt;static&gt; onGenreItemSelected() Genre Item Selected Source: components/ItemGrid/MusicLibraryView.brs, line 192 Returns: Type void &lt;static&gt; onItemFocused() Handle new item being focused Source: components/ItemGrid/MusicLibraryView.brs, line 136 Returns: Type void &lt;static&gt; onItemSelected() Item Selected Source: components/ItemGrid/MusicLibraryView.brs, line 176 Returns: Type void &lt;static&gt; onItemalphaSelected() Source: components/ItemGrid/MusicLibraryView.brs, line 206 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/ItemGrid/MusicLibraryView.brs, line 235 Returns: Type boolean &lt;static&gt; onvoiceFilter() Source: components/ItemGrid/MusicLibraryView.brs, line 212 Returns: Type void &lt;static&gt; optionsClosed() Check if options updated and any reloading required Source: components/ItemGrid/MusicLibraryView.brs, line 220 Returns: Type void &lt;static&gt; setFieldText(field, value) Parameters: Name Type Description field dynamic value dynamic Source: components/ItemGrid/MusicLibraryView.brs, line 144 Returns: Type void &lt;static&gt; setMusicOptions(options) Set Music view, sort, and filter options Parameters: Name Type Description options dynamic Source: components/ItemGrid/MusicLibraryView.brs, line 42 Returns: Type void &lt;static&gt; setupNodes() Source: components/ItemGrid/MusicLibraryView.brs, line 8 Returns: Type void &lt;static&gt; swapDone() Swap Complete Source: components/ItemGrid/MusicLibraryView.brs, line 160 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-MusicSongData.html":{"id":"module-MusicSongData.html","title":"Module: MusicSongData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: MusicSongData Source: components/data/MusicSongData.brs, line 1 Methods &lt;static&gt; setFields() Source: components/data/MusicSongData.brs, line 8 Returns: Type void &lt;static&gt; setPoster() Source: components/data/MusicSongData.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-OptionNode.html":{"id":"module-OptionNode.html","title":"Module: OptionNode","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: OptionNode Source: components/options/OptionNode.brs, line 1 Methods &lt;static&gt; init() Source: components/options/OptionNode.brs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-OptionsButton.html":{"id":"module-OptionsButton.html","title":"Module: OptionsButton","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: OptionsButton Source: components/data/OptionsButton.brs, line 1 Methods &lt;static&gt; init() Source: components/data/OptionsButton.brs, line 8 Returns: Type void &lt;static&gt; press() Source: components/data/OptionsButton.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-OptionsData.html":{"id":"module-OptionsData.html","title":"Module: OptionsData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: OptionsData Source: components/data/OptionsData.brs, line 1 Methods &lt;static&gt; init() Source: components/data/OptionsData.brs, line 8 Returns: Type void &lt;static&gt; press() Source: components/data/OptionsData.brs, line 20 Returns: Type void &lt;static&gt; update_title() Source: components/data/OptionsData.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-OptionsSlider.html":{"id":"module-OptionsSlider.html","title":"Module: OptionsSlider","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: OptionsSlider Source: components/options/OptionsSlider.brs, line 1 Methods &lt;static&gt; init() Source: components/options/OptionsSlider.brs, line 8 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/options/OptionsSlider.brs, line 22 Returns: Type boolean &lt;static&gt; setFields() Source: components/options/OptionsSlider.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-OverviewDialog.html":{"id":"module-OverviewDialog.html","title":"Module: OverviewDialog","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: OverviewDialog Source: components/OverviewDialog.bs, line 1 Methods &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/OverviewDialog.bs, line 22 Returns: Type boolean &lt;static&gt; setOverview() Source: components/OverviewDialog.bs, line 14 Returns: Type void &lt;static&gt; setTitle() Source: components/OverviewDialog.bs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-PersonData.html":{"id":"module-PersonData.html","title":"Module: PersonData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: PersonData Source: components/data/PersonData.brs, line 1 Methods &lt;static&gt; setFields() Source: components/data/PersonData.brs, line 8 Returns: Type void &lt;static&gt; setPoster() Source: components/data/PersonData.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-PersonDetails.html":{"id":"module-PersonDetails.html","title":"Module: PersonDetails","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: PersonDetails Source: components/PersonDetails.brs, line 1 Methods &lt;static&gt; createDialogPallete() Source: components/PersonDetails.brs, line 52 Returns: Type void &lt;static&gt; createFullDscrDlg() Source: components/PersonDetails.brs, line 46 Returns: Type void &lt;static&gt; dscrShowFocus() Source: components/PersonDetails.brs, line 20 Returns: Type void &lt;static&gt; init() Source: components/PersonDetails.brs, line 8 Returns: Type void &lt;static&gt; loadPerson() Source: components/PersonDetails.brs, line 14 Returns: Type void &lt;static&gt; onButtonGroupEscaped() Source: components/PersonDetails.brs, line 26 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/PersonDetails.brs, line 34 Returns: Type boolean &lt;static&gt; setFavoriteColor() Source: components/PersonDetails.brs, line 40 Returns: Type void &lt;static&gt; shortDate(isoDate) Parameters: Name Type Description isoDate dynamic Source: components/PersonDetails.brs, line 59 Returns: Type string × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-PhotoData.html":{"id":"module-PhotoData.html","title":"Module: PhotoData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: PhotoData Source: components/data/PhotoData.brs, line 1 Methods &lt;static&gt; setFields() Source: components/data/PhotoData.brs, line 8 Returns: Type void &lt;static&gt; setPoster() Source: components/data/PhotoData.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-PhotoDetails.html":{"id":"module-PhotoDetails.html","title":"Module: PhotoDetails","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: PhotoDetails Source: components/photos/PhotoDetails.brs, line 1 Methods &lt;static&gt; init() Source: components/photos/PhotoDetails.brs, line 8 Returns: Type void &lt;static&gt; isValidToContinue(index) Parameters: Name Type Description index integer Source: components/photos/PhotoDetails.brs, line 47 Returns: Type dynamic &lt;static&gt; itemContentChanged() Source: components/photos/PhotoDetails.brs, line 14 Returns: Type void &lt;static&gt; nextSlide() Source: components/photos/PhotoDetails.brs, line 26 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/photos/PhotoDetails.brs, line 40 Returns: Type boolean &lt;static&gt; onPhotoLoaded() Source: components/photos/PhotoDetails.brs, line 20 Returns: Type void &lt;static&gt; statusUpdate() Source: components/photos/PhotoDetails.brs, line 32 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-PlaybackDialog.html":{"id":"module-PlaybackDialog.html","title":"Module: PlaybackDialog","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: PlaybackDialog Source: components/PlaybackDialog.brs, line 1 Methods &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/PlaybackDialog.brs, line 10 Returns: Type boolean × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-PlayedCheckmark.html":{"id":"module-PlayedCheckmark.html","title":"Module: PlayedCheckmark","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: PlayedCheckmark Source: components/PlayedCheckmark.brs, line 1 Methods &lt;static&gt; init() Source: components/PlayedCheckmark.brs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-PlaylistData.html":{"id":"module-PlaylistData.html","title":"Module: PlaylistData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: PlaylistData Source: components/data/PlaylistData.brs, line 1 Methods &lt;static&gt; setFields() Source: components/data/PlaylistData.brs, line 8 Returns: Type void &lt;static&gt; setPoster() Source: components/data/PlaylistData.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-PlaylistView.html":{"id":"module-PlaylistView.html","title":"Module: PlaylistView","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: PlaylistView Source: components/music/PlaylistView.brs, line 1 Methods &lt;static&gt; OnScreenHidden() Source: components/music/PlaylistView.brs, line 84 Returns: Type void &lt;static&gt; adjustScreenForNoOverview() Adjust scene by removing overview node and showing more songs Source: components/music/PlaylistView.brs, line 44 Returns: Type void &lt;static&gt; createDialogPallete() Source: components/music/PlaylistView.brs, line 72 Returns: Type void &lt;static&gt; createFullDscrDlg() Source: components/music/PlaylistView.brs, line 66 Returns: Type void &lt;static&gt; init() Source: components/music/PlaylistView.brs, line 8 Returns: Type void &lt;static&gt; onDoneLoading() Source: components/music/PlaylistView.brs, line 78 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/music/PlaylistView.brs, line 60 Returns: Type boolean &lt;static&gt; pageContentChanged() Set values for displayed values on screen Source: components/music/PlaylistView.brs, line 21 Returns: Type void &lt;static&gt; setOnScreenTextValues(json) Populate on screen text variables Parameters: Name Type Description json dynamic Source: components/music/PlaylistView.brs, line 52 Returns: Type void &lt;static&gt; setPosterImage(posterURL) Set poster image on screen Parameters: Name Type Description posterURL dynamic Source: components/music/PlaylistView.brs, line 29 Returns: Type void &lt;static&gt; setScreenTitle(json) Set screen's title text Parameters: Name Type Description json dynamic Source: components/music/PlaylistView.brs, line 37 Returns: Type void &lt;static&gt; setupMainNode() Source: components/music/PlaylistView.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-PlaystateTask.html":{"id":"module-PlaystateTask.html","title":"Module: PlaystateTask","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: PlaystateTask Source: components/PlaystateTask.brs, line 1 Methods &lt;static&gt; PlaystateDefaults( [params]) Parameters: Name Type Argument Default Description params object &lt;optional&gt; {} Source: components/PlaystateTask.brs, line 21 Returns: Type dynamic &lt;static&gt; PlaystateUpdate() Source: components/PlaystateTask.brs, line 14 Returns: Type void &lt;static&gt; init() Source: components/PlaystateTask.brs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-ProgramDetails.html":{"id":"module-ProgramDetails.html","title":"Module: ProgramDetails","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: ProgramDetails Source: components/liveTv/ProgramDetails.brs, line 1 Methods &lt;static&gt; channelUpdated() Source: components/liveTv/ProgramDetails.brs, line 29 Returns: Type void &lt;static&gt; focusChanged() Show view channel button when item has Focus Source: components/liveTv/ProgramDetails.brs, line 61 Returns: Type void &lt;static&gt; getDurationStringFromSeconds(seconds) Get program duration string (e.g. 1h 20m) Parameters: Name Type Description seconds dynamic Source: components/liveTv/ProgramDetails.brs, line 53 Returns: Type string &lt;static&gt; getRelativeDayName(date) Get relative date name for a date (yesterday, today, tomorrow, or otherwise weekday name ) Parameters: Name Type Description date dynamic Source: components/liveTv/ProgramDetails.brs, line 44 Returns: Type string &lt;static&gt; init() Source: components/liveTv/ProgramDetails.brs, line 8 Returns: Type void &lt;static&gt; onAnimationComplete() Source: components/liveTv/ProgramDetails.brs, line 67 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/liveTv/ProgramDetails.brs, line 75 Returns: Type boolean &lt;static&gt; programUpdated() Source: components/liveTv/ProgramDetails.brs, line 35 Returns: Type void &lt;static&gt; setupLabels() Set up Live and Repeat label sizes Source: components/liveTv/ProgramDetails.brs, line 15 Returns: Type void &lt;static&gt; updateLabels( [recordText] [, recordSeriesText]) Parameters: Name Type Argument Default Description recordText dynamic &lt;optional&gt; \"Record\" recordSeriesText dynamic &lt;optional&gt; \"Record Series\" Source: components/liveTv/ProgramDetails.brs, line 23 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-PublicUserData.html":{"id":"module-PublicUserData.html","title":"Module: PublicUserData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: PublicUserData Source: components/data/PublicUserData.brs, line 1 Methods &lt;static&gt; init() Source: components/data/PublicUserData.brs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-QueueManager.html":{"id":"module-QueueManager.html","title":"Module: QueueManager","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: QueueManager Source: components/manager/QueueManager.brs, line 1 Methods &lt;static&gt; clear() Clear all content from play queue Source: components/manager/QueueManager.brs, line 15 Returns: Type void &lt;static&gt; clearHold() Clear all hold content Source: components/manager/QueueManager.brs, line 22 Returns: Type void &lt;static&gt; deleteAtIndex(index) Delete item from play queue at passed index Parameters: Name Type Description index dynamic Source: components/manager/QueueManager.brs, line 30 Returns: Type void &lt;static&gt; getCount() Return the number of items in the play queue Source: components/manager/QueueManager.brs, line 37 Returns: Type dynamic &lt;static&gt; getCurrentItem() Return the item currently in focus from the play queue Source: components/manager/QueueManager.brs, line 44 Returns: Type dynamic &lt;static&gt; getHold() Return the items in the hold Source: components/manager/QueueManager.brs, line 51 Returns: Type dynamic &lt;static&gt; getIsShuffled() Return whether or not shuffle is enabled Source: components/manager/QueueManager.brs, line 58 Returns: Type dynamic &lt;static&gt; getItemByIndex(index) Return the item in the passed index from the play queue Parameters: Name Type Description index dynamic Source: components/manager/QueueManager.brs, line 66 Returns: Type dynamic &lt;static&gt; getItemType(item) Parameters: Name Type Description item dynamic Source: components/manager/QueueManager.brs, line 233 Returns: Type string &lt;static&gt; getPosition() Returns current playback position within the queue Source: components/manager/QueueManager.brs, line 73 Returns: Type dynamic &lt;static&gt; getQueue() Return the current play queue Source: components/manager/QueueManager.brs, line 102 Returns: Type dynamic &lt;static&gt; getQueueTypes() Return the types of items in current play queue Source: components/manager/QueueManager.brs, line 109 Returns: Type dynamic &lt;static&gt; getQueueUniqueTypes() Return the unique types of items in current play queue Source: components/manager/QueueManager.brs, line 116 Returns: Type dynamic &lt;static&gt; getUnshuffledQueue() Return original, unshuffled queue Source: components/manager/QueueManager.brs, line 196 Returns: Type dynamic &lt;static&gt; hold(newItem) Hold an item Parameters: Name Type Description newItem dynamic Source: components/manager/QueueManager.brs, line 81 Returns: Type void &lt;static&gt; init() Source: components/manager/QueueManager.brs, line 8 Returns: Type void &lt;static&gt; isPrerollActive() Return isPrerollActive status Source: components/manager/QueueManager.brs, line 144 Returns: Type boolean &lt;static&gt; moveBack() Move queue position back one Source: components/manager/QueueManager.brs, line 88 Returns: Type void &lt;static&gt; moveForward() Move queue position ahead one Source: components/manager/QueueManager.brs, line 95 Returns: Type void &lt;static&gt; peek() Return item at end of play queue without removing Source: components/manager/QueueManager.brs, line 123 Returns: Type dynamic &lt;static&gt; playQueue() Play items in queue Source: components/manager/QueueManager.brs, line 130 Returns: Type void &lt;static&gt; pop() Remove item at end of play queue Source: components/manager/QueueManager.brs, line 137 Returns: Type void &lt;static&gt; push(newItem) Push new items to the play queue Parameters: Name Type Description newItem dynamic Source: components/manager/QueueManager.brs, line 160 Returns: Type void &lt;static&gt; resetQueueItemOrder() Reset queue items back to original, unshuffled order Source: components/manager/QueueManager.brs, line 189 Returns: Type void &lt;static&gt; resetShuffle() Reset shuffle to off state Source: components/manager/QueueManager.brs, line 175 Returns: Type void &lt;static&gt; set(items) Replace play queue with passed array Parameters: Name Type Description items dynamic Source: components/manager/QueueManager.brs, line 218 Returns: Type void &lt;static&gt; setPosition(newPosition) Set the queue position Parameters: Name Type Description newPosition dynamic Source: components/manager/QueueManager.brs, line 168 Returns: Type void &lt;static&gt; setPrerollStatus(newStatus) Set prerollActive status Parameters: Name Type Description newStatus boolean Source: components/manager/QueueManager.brs, line 152 Returns: Type void &lt;static&gt; setTopStartingPoint(positionTicks) Set starting point for top item in the queue Parameters: Name Type Description positionTicks dynamic Source: components/manager/QueueManager.brs, line 226 Returns: Type void &lt;static&gt; shuffleQueueItems() Save a copy of the original queue and randomize order of queue items Source: components/manager/QueueManager.brs, line 203 Returns: Type void &lt;static&gt; toggleShuffle() Toggle shuffleEnabled state Source: components/manager/QueueManager.brs, line 182 Returns: Type void &lt;static&gt; top() Return the fitst item in the play queue Source: components/manager/QueueManager.brs, line 210 Returns: Type dynamic × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-QuickConnect.html":{"id":"module-QuickConnect.html","title":"Module: QuickConnect","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: QuickConnect Source: components/quickConnect/QuickConnect.brs, line 1 Methods &lt;static&gt; init() Source: components/quickConnect/QuickConnect.brs, line 8 Returns: Type void &lt;static&gt; monitorQuickConnect() Source: components/quickConnect/QuickConnect.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-QuickConnectDialog.html":{"id":"module-QuickConnectDialog.html","title":"Module: QuickConnectDialog","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: QuickConnectDialog Source: components/quickConnect/QuickConnectDialog.brs, line 1 Methods &lt;static&gt; OnAuthenticated() Source: components/quickConnect/QuickConnectDialog.brs, line 20 Returns: Type void &lt;static&gt; init() Source: components/quickConnect/QuickConnectDialog.brs, line 8 Returns: Type void &lt;static&gt; onButtonSelected() Source: components/quickConnect/QuickConnectDialog.brs, line 32 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/quickConnect/QuickConnectDialog.brs, line 40 Returns: Type boolean &lt;static&gt; quickConnectClosed() Source: components/quickConnect/QuickConnectDialog.brs, line 26 Returns: Type void &lt;static&gt; quickConnectStatus() Source: components/quickConnect/QuickConnectDialog.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-RadioDialog.html":{"id":"module-RadioDialog.html","title":"Module: RadioDialog","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: RadioDialog Source: components/RadioDialog.brs, line 1 Methods &lt;static&gt; init() Source: components/RadioDialog.brs, line 8 Returns: Type void &lt;static&gt; moveScrollBar() Move the popup's scroll bar Source: components/RadioDialog.brs, line 29 Returns: Type void &lt;static&gt; onButtonSelected() Event handler for when user selected a button Source: components/RadioDialog.brs, line 15 Returns: Type void &lt;static&gt; onContentDataChanged() Source: components/RadioDialog.brs, line 49 Returns: Type void &lt;static&gt; onItemFocused() Event handler for when user's cursor highlights an option in the option list Source: components/RadioDialog.brs, line 22 Returns: Type void &lt;static&gt; onItemSelected() Once user selected an item, move cursor down to OK button Source: components/RadioDialog.brs, line 43 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/RadioDialog.brs, line 57 Returns: Type boolean &lt;static&gt; onScrollBarFocus() If somehow the scrollbar gains focus, set focus back to the option list Source: components/RadioDialog.brs, line 36 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-RecordProgramTask.html":{"id":"module-RecordProgramTask.html","title":"Module: RecordProgramTask","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: RecordProgramTask Source: components/liveTv/RecordProgramTask.brs, line 1 Methods &lt;static&gt; RecordOrCancelProgram() Source: components/liveTv/RecordProgramTask.brs, line 14 Returns: Type void &lt;static&gt; init() Source: components/liveTv/RecordProgramTask.brs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-SceneManager.html":{"id":"module-SceneManager.html","title":"Module: SceneManager","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: SceneManager Source: components/data/SceneManager.brs, line 1 Methods &lt;static&gt; clearPreviousScene() Clear previous scene from group stack Source: components/data/SceneManager.brs, line 49 Returns: Type void &lt;static&gt; clearScenes() Clear all content from group stack Source: components/data/SceneManager.brs, line 41 Returns: Type void &lt;static&gt; deleteSceneAtIndex( [index]) Delete scene from group stack at passed index Parameters: Name Type Argument Default Description index dynamic &lt;optional&gt; 1 Source: components/data/SceneManager.brs, line 58 Returns: Type void &lt;static&gt; dismissDialog() Close currently displayed dialog Source: components/data/SceneManager.brs, line 192 Returns: Type void &lt;static&gt; getActiveScene() Return group at top of stack without removing Source: components/data/SceneManager.brs, line 33 Returns: Type object &lt;static&gt; init() Source: components/data/SceneManager.brs, line 8 Returns: Type void &lt;static&gt; isDialogOpen() Returns bool indicating if dialog is currently displayed Source: components/data/SceneManager.brs, line 200 Returns: Type boolean &lt;static&gt; optionClosed() Return button the user selected Source: components/data/SceneManager.brs, line 176 Returns: Type void &lt;static&gt; optionDialog(title, message, buttons) Display dialog to user with an OK button Parameters: Name Type Description title dynamic message dynamic buttons dynamic Source: components/data/SceneManager.brs, line 168 Returns: Type void &lt;static&gt; optionSelected() Return button the user selected Source: components/data/SceneManager.brs, line 184 Returns: Type void &lt;static&gt; popScene() Remove the current group and load the last group from the stack Source: components/data/SceneManager.brs, line 25 Returns: Type void &lt;static&gt; pushScene(newGroup) Push a new group onto the stack, replacing the existing group on the screen Parameters: Name Type Description newGroup dynamic Source: components/data/SceneManager.brs, line 17 Returns: Type void &lt;static&gt; radioDialog(title, message) Display dialog to user with an OK button Parameters: Name Type Description title dynamic message dynamic Source: components/data/SceneManager.brs, line 157 Returns: Type void &lt;static&gt; registerOverhangData(group) Register observers for overhang data Parameters: Name Type Description group dynamic Source: components/data/SceneManager.brs, line 75 Returns: Type void &lt;static&gt; resetTime() Reset time Source: components/data/SceneManager.brs, line 127 Returns: Type void &lt;static&gt; settings() Display user/device settings screen Source: components/data/SceneManager.brs, line 66 Returns: Type void &lt;static&gt; standardDialog(title, message) Display dialog to user with an OK button Parameters: Name Type Description title dynamic message dynamic Source: components/data/SceneManager.brs, line 147 Returns: Type void &lt;static&gt; unregisterOverhangData(group) Remove observers for overhang data Parameters: Name Type Description group dynamic Source: components/data/SceneManager.brs, line 84 Returns: Type void &lt;static&gt; updateOptions(msg) Update options availability Parameters: Name Type Description msg dynamic Source: components/data/SceneManager.brs, line 102 Returns: Type void &lt;static&gt; updateOverhangTitle(msg) Update overhang title Parameters: Name Type Description msg dynamic Source: components/data/SceneManager.brs, line 93 Returns: Type void &lt;static&gt; updateOverhangVisible(msg) Update whether the overhang is visible or not Parameters: Name Type Description msg dynamic Source: components/data/SceneManager.brs, line 111 Returns: Type void &lt;static&gt; updateUser() Update username in overhang Source: components/data/SceneManager.brs, line 119 Returns: Type void &lt;static&gt; userMessage(title, message) Display dialog to user with an OK button Parameters: Name Type Description title string message string Source: components/data/SceneManager.brs, line 137 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-ScheduleProgramData.html":{"id":"module-ScheduleProgramData.html","title":"Module: ScheduleProgramData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: ScheduleProgramData Source: components/data/ScheduleProgramData.brs, line 1 Methods &lt;static&gt; setFields() Source: components/data/ScheduleProgramData.brs, line 8 Returns: Type void &lt;static&gt; setPoster() Source: components/data/ScheduleProgramData.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-SearchBox.html":{"id":"module-SearchBox.html","title":"Module: SearchBox","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: SearchBox Source: components/SearchBox.brs, line 1 Methods &lt;static&gt; init() Source: components/SearchBox.brs, line 8 Returns: Type void &lt;static&gt; searchMedias() Source: components/SearchBox.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-SearchData.html":{"id":"module-SearchData.html","title":"Module: SearchData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: SearchData Source: components/data/SearchData.brs, line 1 Methods &lt;static&gt; setFields() Source: components/data/SearchData.brs, line 8 Returns: Type void &lt;static&gt; setPoster() Source: components/data/SearchData.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-SearchResults.html":{"id":"module-SearchResults.html","title":"Module: SearchResults","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: SearchResults Source: components/search/SearchResults.brs, line 1 Methods &lt;static&gt; init() Source: components/search/SearchResults.brs, line 8 Returns: Type void &lt;static&gt; loadResults() Source: components/search/SearchResults.brs, line 20 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/search/SearchResults.brs, line 28 Returns: Type boolean &lt;static&gt; searchMedias() Source: components/search/SearchResults.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-SearchRow.html":{"id":"module-SearchRow.html","title":"Module: SearchRow","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: SearchRow Source: components/search/SearchRow.brs, line 1 Methods &lt;static&gt; addRow(data, title, type_filter) Parameters: Name Type Description data dynamic title dynamic type_filter dynamic Source: components/search/SearchRow.brs, line 29 Returns: Type void &lt;static&gt; getData() Source: components/search/SearchRow.brs, line 20 Returns: Type dynamic &lt;static&gt; init() Source: components/search/SearchRow.brs, line 8 Returns: Type void &lt;static&gt; updateSize() Source: components/search/SearchRow.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-SearchTask.html":{"id":"module-SearchTask.html","title":"Module: SearchTask","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: SearchTask Source: components/search/SearchTask.brs, line 1 Methods &lt;static&gt; init() Source: components/search/SearchTask.brs, line 8 Returns: Type void &lt;static&gt; search() Source: components/search/SearchTask.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-SeriesData.html":{"id":"module-SeriesData.html","title":"Module: SeriesData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: SeriesData Source: components/data/SeriesData.brs, line 1 Methods &lt;static&gt; setFields() Source: components/data/SeriesData.brs, line 8 Returns: Type void &lt;static&gt; setPoster() Source: components/data/SeriesData.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-ServerDiscoveryTask.html":{"id":"module-ServerDiscoveryTask.html","title":"Module: ServerDiscoveryTask","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: ServerDiscoveryTask Source: components/config/ServerDiscoveryTask.brs, line 1 Methods &lt;static&gt; AddServer(server) Parameters: Name Type Description server dynamic Source: components/config/ServerDiscoveryTask.brs, line 24 Returns: Type void &lt;static&gt; ProcessClientDiscoveryResponse(message) Parameters: Name Type Description message dynamic Source: components/config/ServerDiscoveryTask.brs, line 37 Returns: Type void &lt;static&gt; ProcessSSDPResponse(message) Parameters: Name Type Description message dynamic Source: components/config/ServerDiscoveryTask.brs, line 50 Returns: Type void &lt;static&gt; SendClientDiscoveryBroadcast() Source: components/config/ServerDiscoveryTask.brs, line 30 Returns: Type void &lt;static&gt; SendSSDPBroadcast() Source: components/config/ServerDiscoveryTask.brs, line 43 Returns: Type void &lt;static&gt; execute() Source: components/config/ServerDiscoveryTask.brs, line 17 Returns: Type void &lt;static&gt; init() Task used to discover jellyfin servers on the local network Source: components/config/ServerDiscoveryTask.brs, line 11 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-SetServerScreen.html":{"id":"module-SetServerScreen.html","title":"Module: SetServerScreen","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: SetServerScreen Source: components/config/SetServerScreen.brs, line 1 Methods &lt;static&gt; ScanForServers() Source: components/config/SetServerScreen.brs, line 22 Returns: Type void &lt;static&gt; ScanForServersComplete(event) Parameters: Name Type Description event dynamic Source: components/config/SetServerScreen.brs, line 29 Returns: Type void &lt;static&gt; ShowKeyboard() Source: components/config/SetServerScreen.brs, line 35 Returns: Type void &lt;static&gt; clearErrorMessage() Source: components/config/SetServerScreen.brs, line 47 Returns: Type void &lt;static&gt; init() Source: components/config/SetServerScreen.brs, line 8 Returns: Type void &lt;static&gt; onDialogButton() Source: components/config/SetServerScreen.brs, line 41 Returns: Type dynamic &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/config/SetServerScreen.brs, line 16 Returns: Type boolean × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-ShowScenes.html":{"id":"module-ShowScenes.html","title":"Module: ShowScenes","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: ShowScenes Source: source/ShowScenes.brs, line 1 Methods &lt;static&gt; CreateAlbumView(album) Shows details on selected album. Description text, image, and list of available songs Parameters: Name Type Description album object Source: source/ShowScenes.brs, line 85 Returns: Type dynamic &lt;static&gt; CreateArtistView(artist) Shows details on selected artist. Bio, image, and list of available albums Parameters: Name Type Description artist object Source: source/ShowScenes.brs, line 77 Returns: Type dynamic &lt;static&gt; CreateHomeGroup() Source: source/ShowScenes.brs, line 55 Returns: Type dynamic &lt;static&gt; CreateItemGrid(libraryItem) Parameters: Name Type Description libraryItem object Source: source/ShowScenes.brs, line 116 Returns: Type dynamic &lt;static&gt; CreateMovieDetailsGroup(movie) Parameters: Name Type Description movie object Source: source/ShowScenes.brs, line 62 Returns: Type dynamic &lt;static&gt; CreateMovieLibraryView(libraryItem) Parameters: Name Type Description libraryItem object Source: source/ShowScenes.brs, line 123 Returns: Type dynamic &lt;static&gt; CreateMusicLibraryView(libraryItem) Parameters: Name Type Description libraryItem object Source: source/ShowScenes.brs, line 130 Returns: Type dynamic &lt;static&gt; CreatePersonView(personData) Parameters: Name Type Description personData object Source: source/ShowScenes.brs, line 155 Returns: Type dynamic &lt;static&gt; CreatePlaylistView(playlist) Shows details on selected playlist. Description text, image, and list of available items Parameters: Name Type Description playlist object Source: source/ShowScenes.brs, line 93 Returns: Type dynamic &lt;static&gt; CreateSearchPage() Source: source/ShowScenes.brs, line 136 Returns: Type dynamic &lt;static&gt; CreateSeasonDetailsGroup(series, season) Parameters: Name Type Description series object season object Source: source/ShowScenes.brs, line 101 Returns: Type dynamic &lt;static&gt; CreateSeasonDetailsGroupByID(seriesID, seasonID) Parameters: Name Type Description seriesID string seasonID string Source: source/ShowScenes.brs, line 109 Returns: Type dynamic &lt;static&gt; CreateSeriesDetailsGroup(seriesID) Parameters: Name Type Description seriesID string Source: source/ShowScenes.brs, line 69 Returns: Type dynamic &lt;static&gt; CreateServerGroup() Source: source/ShowScenes.brs, line 35 Returns: Type dynamic &lt;static&gt; CreateSigninGroup( [user]) Parameters: Name Type Argument Default Description user dynamic &lt;optional&gt; \"\" Source: source/ShowScenes.brs, line 49 Returns: Type dynamic &lt;static&gt; CreateUserSelectGroup( [users]) Parameters: Name Type Argument Default Description users dynamic &lt;optional&gt; [] Source: source/ShowScenes.brs, line 42 Returns: Type dynamic &lt;static&gt; CreateVideoPlayerGroup(video_id [, mediaSourceId] [, audio_stream_idx] [, forceTranscoding] [, showIntro] [, allowResumeDialog]) Parameters: Name Type Argument Default Description video_id string mediaSourceId dynamic &lt;optional&gt; invalid audio_stream_idx integer &lt;optional&gt; 1 forceTranscoding boolean &lt;optional&gt; false showIntro boolean &lt;optional&gt; true allowResumeDialog boolean &lt;optional&gt; true Source: source/ShowScenes.brs, line 148 Returns: Type dynamic &lt;static&gt; DeleteFromServerList(urlToDelete) Parameters: Name Type Description urlToDelete dynamic Source: source/ShowScenes.brs, line 21 Returns: Type void &lt;static&gt; LoginFlow() Source: source/ShowScenes.brs, line 8 Returns: Type dynamic &lt;static&gt; SaveServerList() Source: source/ShowScenes.brs, line 14 Returns: Type void &lt;static&gt; SendPerformanceBeacon(signalName) Roku Performance monitoring Parameters: Name Type Description signalName string Source: source/ShowScenes.brs, line 29 Returns: Type void &lt;static&gt; playbackOptionDialog(time, meta) Opens dialog asking user if they want to resume video or start playback over only on the home screen Parameters: Name Type Description time longinteger meta object Source: source/ShowScenes.brs, line 164 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-SongItem.html":{"id":"module-SongItem.html","title":"Module: SongItem","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: SongItem Source: components/music/SongItem.brs, line 1 Methods &lt;static&gt; focusChanged() Source: components/music/SongItem.brs, line 20 Returns: Type void &lt;static&gt; init() Source: components/music/SongItem.brs, line 8 Returns: Type void &lt;static&gt; itemContentChanged() Source: components/music/SongItem.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-Spinner.html":{"id":"module-Spinner.html","title":"Module: Spinner","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: Spinner Source: components/Spinner.brs, line 1 Methods &lt;static&gt; init() Source: components/Spinner.brs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-StandardDialog.html":{"id":"module-StandardDialog.html","title":"Module: StandardDialog","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: StandardDialog Source: components/StandardDialog.brs, line 1 Methods &lt;static&gt; init() Source: components/StandardDialog.brs, line 8 Returns: Type void &lt;static&gt; onContentDataChanged() Source: components/StandardDialog.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-Subtitles.html":{"id":"module-Subtitles.html","title":"Module: Subtitles","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: Subtitles Source: source/utils/Subtitles.brs, line 1 Methods &lt;static&gt; availSubtitleTrackIdx(video, sub_idx) Roku translates the info provided in subtitleTracks into availableSubtitleTracks Including ignoring tracks, if they are not understood, thus making indexing unpredictable. This function translates between our internel selected subtitle index and the corresponding index in availableSubtitleTracks. Parameters: Name Type Description video dynamic sub_idx dynamic Source: source/utils/Subtitles.brs, line 14 Returns: Type integer &lt;static&gt; changeSubtitleDuringPlayback(newid) Parameters: Name Type Description newid dynamic Source: source/utils/Subtitles.brs, line 81 Returns: Type void &lt;static&gt; defaultSubtitleTrack(sorted_subtitles [, require_text]) Identify the default subtitle track if \"requires_text\" is true, only return a track if it is textual This allows forcing text subs, since roku requires transcoding of non-text subs returns the server-side track index for the appriate subtitle Parameters: Name Type Argument Default Description sorted_subtitles dynamic require_text dynamic &lt;optional&gt; false Source: source/utils/Subtitles.brs, line 35 Returns: Type integer &lt;static&gt; defaultSubtitleTrackFromVid(video_id) Identify the default subtitle track for a given video id returns the server-side track index for the appriate subtitle Parameters: Name Type Description video_id dynamic Source: source/utils/Subtitles.brs, line 23 Returns: Type integer &lt;static&gt; getSubtitleLanguages() Source: source/utils/Subtitles.brs, line 102 Returns: Type dynamic &lt;static&gt; getSubtitleSelIdxFromSubIdx(subtitles, sub_idx) The subtitle index on the server differs from the index we track locally This function converts the former into the latter Parameters: Name Type Description subtitles dynamic sub_idx dynamic Source: source/utils/Subtitles.brs, line 57 Returns: Type integer &lt;static&gt; selectSubtitleTrack(tracks [, current]) Parameters: Name Type Argument Default Description tracks dynamic current dynamic &lt;optional&gt; -1 Source: source/utils/Subtitles.brs, line 65 Returns: Type integer &lt;static&gt; selectSubtitleTrackDialog(tracks [, currentTrack]) Present Dialog to user to select subtitle track Parameters: Name Type Argument Default Description tracks dynamic currentTrack dynamic &lt;optional&gt; -1 Source: source/utils/Subtitles.brs, line 74 Returns: Type dynamic &lt;static&gt; setupSubtitle(video, subtitles [, subtitle_idx]) Given a set of subtitles, and a subtitle index (the index on the server, not in the list provided) this will set all relevant settings for roku (mainly closed captions) and return the index of the subtitle track specified, but indexed based on the provided list of subtitles Parameters: Name Type Argument Default Description video dynamic subtitles dynamic subtitle_idx dynamic &lt;optional&gt; -1 Source: source/utils/Subtitles.brs, line 47 Returns: Type integer &lt;static&gt; sortSubtitles(id, MediaStreams) Checks available subtitle tracks and puts subtitles in forced, default, and non-default/forced but preferred language at the top Parameters: Name Type Description id string MediaStreams dynamic Source: source/utils/Subtitles.brs, line 96 Returns: Type dynamic &lt;static&gt; turnoffSubtitles() Source: source/utils/Subtitles.brs, line 87 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-TVEpisode.html":{"id":"module-TVEpisode.html","title":"Module: TVEpisode","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: TVEpisode Source: components/data/TVEpisode.brs, line 1 Methods &lt;static&gt; setFields() Source: components/data/TVEpisode.brs, line 8 Returns: Type void &lt;static&gt; setPoster() Source: components/data/TVEpisode.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-TVEpisodeData.html":{"id":"module-TVEpisodeData.html","title":"Module: TVEpisodeData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: TVEpisodeData Source: components/data/TVEpisodeData.brs, line 1 Methods &lt;static&gt; setFields() Source: components/data/TVEpisodeData.brs, line 8 Returns: Type void &lt;static&gt; setPoster() Source: components/data/TVEpisodeData.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-TVEpisodeRow.html":{"id":"module-TVEpisodeRow.html","title":"Module: TVEpisodeRow","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: TVEpisodeRow Source: components/tvshows/TVEpisodeRow.brs, line 1 Methods &lt;static&gt; init() Source: components/tvshows/TVEpisodeRow.brs, line 8 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/tvshows/TVEpisodeRow.brs, line 34 Returns: Type boolean &lt;static&gt; setData() Source: components/tvshows/TVEpisodeRow.brs, line 26 Returns: Type dynamic &lt;static&gt; setupRows() Source: components/tvshows/TVEpisodeRow.brs, line 20 Returns: Type void &lt;static&gt; updateSize() Source: components/tvshows/TVEpisodeRow.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-TVEpisodeRowWithOptions.html":{"id":"module-TVEpisodeRowWithOptions.html","title":"Module: TVEpisodeRowWithOptions","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: TVEpisodeRowWithOptions Source: components/tvshows/TVEpisodeRowWithOptions.brs, line 1 Methods &lt;static&gt; SetUpAudioOptions(streams) List of audio tracks to choose from Parameters: Name Type Description streams object Source: components/tvshows/TVEpisodeRowWithOptions.brs, line 36 Returns: Type void &lt;static&gt; SetUpVideoOptions(streams) List of video versions to choose from Parameters: Name Type Description streams object Source: components/tvshows/TVEpisodeRowWithOptions.brs, line 28 Returns: Type void &lt;static&gt; audioOptionsClosed() Source: components/tvshows/TVEpisodeRowWithOptions.brs, line 42 Returns: Type void &lt;static&gt; init() Source: components/tvshows/TVEpisodeRowWithOptions.brs, line 8 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/tvshows/TVEpisodeRowWithOptions.brs, line 56 Returns: Type boolean &lt;static&gt; rowsDoneLoading() Source: components/tvshows/TVEpisodeRowWithOptions.brs, line 20 Returns: Type void &lt;static&gt; setupRows() Source: components/tvshows/TVEpisodeRowWithOptions.brs, line 14 Returns: Type void &lt;static&gt; videoOptionsClosed() Source: components/tvshows/TVEpisodeRowWithOptions.brs, line 48 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-TVEpisodes.html":{"id":"module-TVEpisodes.html","title":"Module: TVEpisodes","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: TVEpisodes Source: components/tvshows/TVEpisodes.brs, line 1 Methods &lt;static&gt; init() Source: components/tvshows/TVEpisodes.brs, line 8 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Handle navigation input from the remote and act on it Parameters: Name Type Description key string press boolean Source: components/tvshows/TVEpisodes.brs, line 36 Returns: Type boolean &lt;static&gt; setExtraButtonVisibility() Updates the visibility of the Extras button based on if this season has any extra features Source: components/tvshows/TVEpisodes.brs, line 21 Returns: Type void &lt;static&gt; setSeasonLoading() Source: components/tvshows/TVEpisodes.brs, line 14 Returns: Type void &lt;static&gt; updateSeason() Source: components/tvshows/TVEpisodes.brs, line 27 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-TVListDetails.html":{"id":"module-TVListDetails.html","title":"Module: TVListDetails","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: TVListDetails Source: components/tvshows/TVListDetails.brs, line 1 Methods &lt;static&gt; DisplayAudioAvailable(streams) Adds \"+N\" (e.g. +1) if there is more than one audio track to choose from Parameters: Name Type Description streams object Source: components/tvshows/TVListDetails.brs, line 39 Returns: Type void &lt;static&gt; DisplayVideoAvailable(streams) Adds \"+N\" (e.g. +1) if there is more than one video version to choose from Parameters: Name Type Description streams object Source: components/tvshows/TVListDetails.brs, line 31 Returns: Type void &lt;static&gt; SetupAudioDisplay(mediaStreams, selectedAudioStreamIndex) Display current audio_codec and check if there is more than one audio track to choose from... Parameters: Name Type Description mediaStreams object selectedAudioStreamIndex integer Source: components/tvshows/TVListDetails.brs, line 23 Returns: Type void &lt;static&gt; focusChanged() Source: components/tvshows/TVListDetails.brs, line 57 Returns: Type void &lt;static&gt; getEndTime() Source: components/tvshows/TVListDetails.brs, line 51 Returns: Type string &lt;static&gt; getRuntime() Source: components/tvshows/TVListDetails.brs, line 45 Returns: Type integer &lt;static&gt; init() Source: components/tvshows/TVListDetails.brs, line 8 Returns: Type void &lt;static&gt; itemContentChanged() Source: components/tvshows/TVListDetails.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-TVListOptions.html":{"id":"module-TVListOptions.html","title":"Module: TVListOptions","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: TVListOptions Source: components/tvshows/TVListOptions.brs, line 1 Methods &lt;static&gt; buttonFocusChanged() Switch menu shown when button focus changes Source: components/tvshows/TVListOptions.brs, line 21 Returns: Type void &lt;static&gt; init() Source: components/tvshows/TVListOptions.brs, line 8 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/tvshows/TVListOptions.brs, line 29 Returns: Type boolean &lt;static&gt; optionsSet() Source: components/tvshows/TVListOptions.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-TVSeasonData.html":{"id":"module-TVSeasonData.html","title":"Module: TVSeasonData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: TVSeasonData Source: components/data/TVSeasonData.brs, line 1 Methods &lt;static&gt; setFields() Source: components/data/TVSeasonData.brs, line 8 Returns: Type void &lt;static&gt; setPoster() Source: components/data/TVSeasonData.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-TVSeasonRow.html":{"id":"module-TVSeasonRow.html","title":"Module: TVSeasonRow","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: TVSeasonRow Source: components/tvshows/TVSeasonRow.brs, line 1 Methods &lt;static&gt; getData() Source: components/tvshows/TVSeasonRow.brs, line 20 Returns: Type dynamic &lt;static&gt; init() Source: components/tvshows/TVSeasonRow.brs, line 8 Returns: Type void &lt;static&gt; updateSize() Source: components/tvshows/TVSeasonRow.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-TVShowDescription.html":{"id":"module-TVShowDescription.html","title":"Module: TVShowDescription","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: TVShowDescription Source: components/tvshows/TVShowDescription.brs, line 1 Methods &lt;static&gt; getEndTime() Source: components/tvshows/TVShowDescription.brs, line 34 Returns: Type string &lt;static&gt; getHistory() Source: components/tvshows/TVShowDescription.brs, line 40 Returns: Type string &lt;static&gt; getRuntime() Source: components/tvshows/TVShowDescription.brs, line 28 Returns: Type integer &lt;static&gt; init() Source: components/tvshows/TVShowDescription.brs, line 8 Returns: Type void &lt;static&gt; itemContentChanged() Source: components/tvshows/TVShowDescription.brs, line 14 Returns: Type void &lt;static&gt; round(f) Parameters: Name Type Description f float Source: components/tvshows/TVShowDescription.brs, line 47 Returns: Type integer &lt;static&gt; setFieldText(field, value) Parameters: Name Type Description field dynamic value dynamic Source: components/tvshows/TVShowDescription.brs, line 22 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-TVShowDetails.html":{"id":"module-TVShowDetails.html","title":"Module: TVShowDetails","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: TVShowDetails Source: components/tvshows/TVShowDetails.brs, line 1 Methods &lt;static&gt; getEndTime() Source: components/tvshows/TVShowDetails.brs, line 34 Returns: Type string &lt;static&gt; getHistory() Source: components/tvshows/TVShowDetails.brs, line 40 Returns: Type string &lt;static&gt; getRuntime() Source: components/tvshows/TVShowDetails.brs, line 28 Returns: Type integer &lt;static&gt; init() Source: components/tvshows/TVShowDetails.brs, line 8 Returns: Type void &lt;static&gt; itemContentChanged() Source: components/tvshows/TVShowDetails.brs, line 14 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/tvshows/TVShowDetails.brs, line 61 Returns: Type boolean &lt;static&gt; onShuffleEpisodeDataLoaded() Source: components/tvshows/TVShowDetails.brs, line 53 Returns: Type void &lt;static&gt; round(f) Parameters: Name Type Description f float Source: components/tvshows/TVShowDetails.brs, line 47 Returns: Type integer &lt;static&gt; setFieldText(field, value) Parameters: Name Type Description field dynamic value dynamic Source: components/tvshows/TVShowDetails.brs, line 22 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-TextSizeTask.html":{"id":"module-TextSizeTask.html","title":"Module: TextSizeTask","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: TextSizeTask Source: components/Buttons/TextSizeTask.brs, line 1 Methods &lt;static&gt; getTextSize() Source: components/Buttons/TextSizeTask.brs, line 14 Returns: Type void &lt;static&gt; init() Source: components/Buttons/TextSizeTask.brs, line 8 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-UserData.html":{"id":"module-UserData.html","title":"Module: UserData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: UserData Source: components/data/UserData.brs, line 1 Methods &lt;static&gt; getPreference(key) Parameters: Name Type Description key string Source: components/data/UserData.brs, line 41 Returns: Type dynamic &lt;static&gt; loadFromJSON(json) Parameters: Name Type Description json dynamic Source: components/data/UserData.brs, line 15 Returns: Type void &lt;static&gt; loadFromRegistry(id) Parameters: Name Type Description id string Source: components/data/UserData.brs, line 22 Returns: Type void &lt;static&gt; removeFromRegistry() Source: components/data/UserData.brs, line 34 Returns: Type void &lt;static&gt; saveToRegistry() Source: components/data/UserData.brs, line 28 Returns: Type void &lt;static&gt; setActive() Source: components/data/UserData.brs, line 55 Returns: Type void &lt;static&gt; setDataFromJSON() Source: components/data/UserData.brs, line 8 Returns: Type void &lt;static&gt; setPreference(key, value) Parameters: Name Type Description key string value string Source: components/data/UserData.brs, line 49 Returns: Type dynamic &lt;static&gt; setServer(hostname) Parameters: Name Type Description hostname string Source: components/data/UserData.brs, line 62 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-UserItem.html":{"id":"module-UserItem.html","title":"Module: UserItem","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: UserItem Source: components/login/UserItem.brs, line 1 Methods &lt;static&gt; init() Source: components/login/UserItem.brs, line 8 Returns: Type void &lt;static&gt; itemContentChanged() Source: components/login/UserItem.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-UserLibrary.html":{"id":"module-UserLibrary.html","title":"Module: UserLibrary","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: UserLibrary Source: source/api/UserLibrary.brs, line 1 Methods &lt;static&gt; MarkItemFavorite(id) Parameters: Name Type Description id string Source: source/api/UserLibrary.brs, line 9 Returns: Type dynamic &lt;static&gt; MarkItemWatched(id) Parameters: Name Type Description id string Source: source/api/UserLibrary.brs, line 23 Returns: Type void &lt;static&gt; UnmarkItemFavorite(id) Parameters: Name Type Description id string Source: source/api/UserLibrary.brs, line 16 Returns: Type dynamic &lt;static&gt; UnmarkItemWatched(id) Parameters: Name Type Description id string Source: source/api/UserLibrary.brs, line 30 Returns: Type dynamic × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-UserRow.html":{"id":"module-UserRow.html","title":"Module: UserRow","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: UserRow Source: components/login/UserRow.brs, line 1 Methods &lt;static&gt; init() Source: components/login/UserRow.brs, line 8 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/login/UserRow.brs, line 34 Returns: Type boolean &lt;static&gt; setData() Source: components/login/UserRow.brs, line 20 Returns: Type dynamic &lt;static&gt; setUser() Source: components/login/UserRow.brs, line 26 Returns: Type void &lt;static&gt; updateSize() Source: components/login/UserRow.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-UserSelect.html":{"id":"module-UserSelect.html","title":"Module: UserSelect","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: UserSelect Source: components/login/UserSelect.brs, line 1 Methods &lt;static&gt; init() Source: components/login/UserSelect.brs, line 8 Returns: Type void &lt;static&gt; itemContentChanged() Source: components/login/UserSelect.brs, line 14 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/login/UserSelect.brs, line 28 Returns: Type boolean &lt;static&gt; redraw() Source: components/login/UserSelect.brs, line 20 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-VideoData.html":{"id":"module-VideoData.html","title":"Module: VideoData","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: VideoData Source: components/data/VideoData.brs, line 1 Methods &lt;static&gt; setFields() Source: components/data/VideoData.brs, line 8 Returns: Type void &lt;static&gt; setPoster() Source: components/data/VideoData.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-VideoPlayer.html":{"id":"module-VideoPlayer.html","title":"Module: VideoPlayer","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: VideoPlayer Source: source/VideoPlayer.brs, line 1 Methods &lt;static&gt; AddVideoContent(video, mediaSourceId [, audio_stream_idx] [, subtitle_idx] [, playbackPosition] [, forceTranscoding] [, showIntro] [, allowResumeDialog]) Parameters: Name Type Argument Default Description video object mediaSourceId dynamic audio_stream_idx integer &lt;optional&gt; 1 subtitle_idx integer &lt;optional&gt; -1 playbackPosition integer &lt;optional&gt; -1 forceTranscoding boolean &lt;optional&gt; false showIntro boolean &lt;optional&gt; true allowResumeDialog boolean &lt;optional&gt; true Source: source/VideoPlayer.brs, line 29 Returns: Type void &lt;static&gt; GetPlaybackInfo() Returns an array of playback info to be displayed during playback. In the future, with a custom playback info view, we can return an associated array. Source: source/VideoPlayer.brs, line 98 Returns: Type dynamic &lt;static&gt; GetTranscodingStats(deviceSession) Parameters: Name Type Description deviceSession dynamic Source: source/VideoPlayer.brs, line 105 Returns: Type dynamic &lt;static&gt; PlayIntroVideo(video_id, audio_stream_idx) Parameters: Name Type Description video_id dynamic audio_stream_idx dynamic Source: source/VideoPlayer.brs, line 37 Returns: Type boolean &lt;static&gt; VideoPlayer(id [, mediaSourceId] [, audio_stream_idx] [, subtitle_idx] [, forceTranscoding] [, showIntro] [, allowResumeDialog]) Parameters: Name Type Argument Default Description id string mediaSourceId dynamic &lt;optional&gt; invalid audio_stream_idx integer &lt;optional&gt; 1 subtitle_idx integer &lt;optional&gt; -1 forceTranscoding boolean &lt;optional&gt; false showIntro boolean &lt;optional&gt; true allowResumeDialog boolean &lt;optional&gt; true Source: source/VideoPlayer.brs, line 15 Returns: Type dynamic &lt;static&gt; autoPlayNextEpisode(videoID, showID) Parameters: Name Type Description videoID string showID string Source: source/VideoPlayer.brs, line 90 Returns: Type void &lt;static&gt; directPlaySupported(meta) Parameters: Name Type Description meta object Source: source/VideoPlayer.brs, line 61 Returns: Type boolean &lt;static&gt; getAudioFormat(meta) Parameters: Name Type Description meta object Source: source/VideoPlayer.brs, line 75 Returns: Type string &lt;static&gt; getAudioInfo(meta) Parameters: Name Type Description meta object Source: source/VideoPlayer.brs, line 82 Returns: Type object &lt;static&gt; getContainerType(meta) Parameters: Name Type Description meta object Source: source/VideoPlayer.brs, line 68 Returns: Type string &lt;static&gt; getDisplayBitrate(bitrate) Parameters: Name Type Description bitrate dynamic Source: source/VideoPlayer.brs, line 118 Returns: Type dynamic &lt;static&gt; getTranscodeReasons(url) Extract array of Transcode Reasons from the content URL Parameters: Name Type Description url string Source: source/VideoPlayer.brs, line 46 Returns: Array of Strings Type object &lt;static&gt; havePlaybackInfo() Source: source/VideoPlayer.brs, line 111 Returns: Type dynamic &lt;static&gt; startPlayBackOver(time) Opens dialog asking user if they want to resume video or start playback over only on the home screen Parameters: Name Type Description time longinteger Source: source/VideoPlayer.brs, line 54 Returns: Type integer × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-VideoPlayerView.html":{"id":"module-VideoPlayerView.html","title":"Module: VideoPlayerView","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: VideoPlayerView Source: components/video/VideoPlayerView.brs, line 1 Methods &lt;static&gt; ReportPlayback( [state]) Report playback to server Parameters: Name Type Argument Default Description state string &lt;optional&gt; \"update\" Source: components/video/VideoPlayerView.brs, line 139 Returns: Type void &lt;static&gt; bufferCheck(msg) Check the the buffering has not hung Parameters: Name Type Description msg dynamic Source: components/video/VideoPlayerView.brs, line 148 Returns: Type void &lt;static&gt; checkTimeToDisplayNextEpisode() Checks if we need to display the Next Episode button Source: components/video/VideoPlayerView.brs, line 114 Returns: Type void &lt;static&gt; hideNextEpisodeButton() Runs hide Next Episode button animation and sets focus back to video Source: components/video/VideoPlayerView.brs, line 107 Returns: Type void &lt;static&gt; init() Source: components/video/VideoPlayerView.brs, line 8 Returns: Type void &lt;static&gt; loadCaption() Set caption url to server subtitle track Source: components/video/VideoPlayerView.brs, line 22 Returns: Type void &lt;static&gt; onAllowCaptionsChange() Only setup captain items if captions are allowed Source: components/video/VideoPlayerView.brs, line 15 Returns: Type void &lt;static&gt; onContentChange() Event handler for when video content field changes Source: components/video/VideoPlayerView.brs, line 77 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/video/VideoPlayerView.brs, line 156 Returns: Type boolean &lt;static&gt; onNextEpisodeDataLoaded() Source: components/video/VideoPlayerView.brs, line 83 Returns: Type void &lt;static&gt; onPlaybackErrorButtonSelected(msg) Parameters: Name Type Description msg dynamic Source: components/video/VideoPlayerView.brs, line 57 Returns: Type void &lt;static&gt; onPlaybackErrorDialogClosed(msg) Parameters: Name Type Description msg dynamic Source: components/video/VideoPlayerView.brs, line 50 Returns: Type void &lt;static&gt; onPositionChanged() When Video Player state changes Source: components/video/VideoPlayerView.brs, line 121 Returns: Type void &lt;static&gt; onState(msg) When Video Player state changes Parameters: Name Type Description msg dynamic Source: components/video/VideoPlayerView.brs, line 130 Returns: Type void &lt;static&gt; onSubtitleChange() Event handler for when selectedSubtitle changes Source: components/video/VideoPlayerView.brs, line 43 Returns: Type void &lt;static&gt; onVideoContentLoaded() Source: components/video/VideoPlayerView.brs, line 70 Returns: Type void &lt;static&gt; showNextEpisodeButton() Runs Next Episode button animation and sets focus to button Source: components/video/VideoPlayerView.brs, line 91 Returns: Type void &lt;static&gt; showPlaybackErrorDialog(errorMessage) Parameters: Name Type Description errorMessage string Source: components/video/VideoPlayerView.brs, line 64 Returns: Type void &lt;static&gt; toggleCaption() Toggles visibility of custom subtitles and sets captionTask's player state Source: components/video/VideoPlayerView.brs, line 29 Returns: Type void &lt;static&gt; updateCaption() Removes old subtitle lines and adds new subtitle lines Source: components/video/VideoPlayerView.brs, line 36 Returns: Type void &lt;static&gt; updateCount() Update count down text Source: components/video/VideoPlayerView.brs, line 99 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-VideoTrackListItem.html":{"id":"module-VideoTrackListItem.html","title":"Module: VideoTrackListItem","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: VideoTrackListItem Source: components/movies/VideoTrackListItem.brs, line 1 Methods &lt;static&gt; focusChanged() Scroll description if focused Source: components/movies/VideoTrackListItem.brs, line 22 Returns: Type void &lt;static&gt; init() Source: components/movies/VideoTrackListItem.brs, line 8 Returns: Type void &lt;static&gt; itemContentChanged() Source: components/movies/VideoTrackListItem.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-ViewCreator.html":{"id":"module-ViewCreator.html","title":"Module: ViewCreator","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: ViewCreator Source: components/manager/ViewCreator.brs, line 1 Methods &lt;static&gt; CreateAudioPlayerView() Play Audio Source: components/manager/ViewCreator.brs, line 9 Returns: Type void &lt;static&gt; CreateVideoPlayerView() Play Video Source: components/manager/ViewCreator.brs, line 16 Returns: Type void &lt;static&gt; availSubtitleTrackIdx(tracknameToFind) Roku translates the info provided in subtitleTracks into availableSubtitleTracks Including ignoring tracks, if they are not understood, thus making indexing unpredictable. This function translates between our internel selected subtitle index and the corresponding index in availableSubtitleTracks. Parameters: Name Type Description tracknameToFind string Source: components/manager/ViewCreator.brs, line 68 Returns: Type integer &lt;static&gt; onPlaybackInfoLoaded() The playback info task has returned data Source: components/manager/ViewCreator.brs, line 50 Returns: Type void &lt;static&gt; onSelectPlaybackInfoPressed() User requested playback info Source: components/manager/ViewCreator.brs, line 43 Returns: Type void &lt;static&gt; onSelectSubtitlePressed() User requested subtitle selection popup Source: components/manager/ViewCreator.brs, line 23 Returns: Type void &lt;static&gt; onSelectionMade() User has selected something from the radioDialog popup Source: components/manager/ViewCreator.brs, line 30 Returns: Type void &lt;static&gt; onStateChange() Playback state change event handlers Source: components/manager/ViewCreator.brs, line 57 Returns: Type void &lt;static&gt; processSubtitleSelection() Source: components/manager/ViewCreator.brs, line 36 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-WhatsNewDialog.html":{"id":"module-WhatsNewDialog.html","title":"Module: WhatsNewDialog","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: WhatsNewDialog Source: components/WhatsNewDialog.brs, line 1 Methods &lt;static&gt; init() Source: components/WhatsNewDialog.brs, line 8 Returns: Type void &lt;static&gt; setPalette() Source: components/WhatsNewDialog.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-baserequest.html":{"id":"module-baserequest.html","title":"Module: baserequest","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: baserequest Source: source/api/baserequest.brs, line 1 Methods &lt;static&gt; APIRequest(url [, params]) Parameters: Name Type Argument Default Description url string params object &lt;optional&gt; {} Source: source/api/baserequest.brs, line 26 Returns: Type dynamic &lt;static&gt; authRequest(request) Takes and returns a roUrlTransfer object after adding a Jellyfin \"Authorization\" header Parameters: Name Type Description request object Source: source/api/baserequest.brs, line 107 Returns: Type object &lt;static&gt; buildParams( [params]) Functions for making requests to the API Parameters: Name Type Argument Default Description params object &lt;optional&gt; {} Source: source/api/baserequest.brs, line 10 Returns: Type string &lt;static&gt; buildURL(path [, params]) Parameters: Name Type Argument Default Description path string params object &lt;optional&gt; {} Source: source/api/baserequest.brs, line 18 Returns: Type dynamic &lt;static&gt; deleteVoid(req) Parameters: Name Type Description req dynamic Source: source/api/baserequest.brs, line 70 Returns: Type dynamic &lt;static&gt; getJson(req) Parameters: Name Type Description req dynamic Source: source/api/baserequest.brs, line 33 Returns: Type dynamic &lt;static&gt; getString(req) Parameters: Name Type Description req dynamic Source: source/api/baserequest.brs, line 83 Returns: Type dynamic &lt;static&gt; getVoid(req) Parameters: Name Type Description req dynamic Source: source/api/baserequest.brs, line 55 Returns: Type boolean &lt;static&gt; get_url() Source: source/api/baserequest.brs, line 76 Returns: Type dynamic &lt;static&gt; headVoid(req) Parameters: Name Type Description req dynamic Source: source/api/baserequest.brs, line 48 Returns: Type boolean &lt;static&gt; postJson(req [, data]) Parameters: Name Type Argument Default Description req dynamic data string &lt;optional&gt; \"\" Source: source/api/baserequest.brs, line 63 Returns: Type dynamic &lt;static&gt; postString(req [, data]) Parameters: Name Type Argument Default Description req dynamic data string &lt;optional&gt; \"\" Source: source/api/baserequest.brs, line 91 Returns: Type dynamic &lt;static&gt; postVoid(req [, data]) Parameters: Name Type Argument Default Description req dynamic data string &lt;optional&gt; \"\" Source: source/api/baserequest.brs, line 41 Returns: Type boolean &lt;static&gt; setCertificateAuthority(request) sets the certificate authority by file path on the passed node Parameters: Name Type Description request object Source: source/api/baserequest.brs, line 99 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-captionTask.html":{"id":"module-captionTask.html","title":"Module: captionTask","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: captionTask Source: components/captionTask.brs, line 1 Methods &lt;static&gt; fetchCaption() Source: components/captionTask.brs, line 20 Returns: Type void &lt;static&gt; init() Source: components/captionTask.brs, line 8 Returns: Type void &lt;static&gt; isTime(text) Parameters: Name Type Description text dynamic Source: components/captionTask.brs, line 54 Returns: Type dynamic &lt;static&gt; newLayoutGroup(labels) Parameters: Name Type Description labels dynamic Source: components/captionTask.brs, line 34 Returns: Type dynamic &lt;static&gt; newRect(lg) Parameters: Name Type Description lg dynamic Source: components/captionTask.brs, line 41 Returns: Type dynamic &lt;static&gt; newlabel(txt) Parameters: Name Type Description txt dynamic Source: components/captionTask.brs, line 27 Returns: Type dynamic &lt;static&gt; parseVTT(lines) Parameters: Name Type Description lines dynamic Source: components/captionTask.brs, line 68 Returns: Type dynamic &lt;static&gt; setFont() Source: components/captionTask.brs, line 14 Returns: Type void &lt;static&gt; toMs(t) Parameters: Name Type Description t dynamic Source: components/captionTask.brs, line 61 Returns: Type dynamic &lt;static&gt; updateCaption() Source: components/captionTask.brs, line 47 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-config.html":{"id":"module-config.html","title":"Module: config","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: config Source: source/utils/config.brs, line 1 Methods &lt;static&gt; GetConfigTree() Read config tree from json config file and return Source: source/utils/config.brs, line 9 Returns: Type dynamic &lt;static&gt; RegistryReadAll(section) Return all data found inside a registry section Parameters: Name Type Description section string Source: source/utils/config.brs, line 43 Returns: Type dynamic &lt;static&gt; findConfigTreeKey(key, tree) Recursivly search the config tree for entry with settingname equal to key Parameters: Name Type Description key string tree dynamic Source: source/utils/config.brs, line 106 Returns: Type dynamic &lt;static&gt; getRegistrySections() Return an array of all the registry section keys Source: source/utils/config.brs, line 50 Returns: Type object &lt;static&gt; getSavedUsers() Returns an array of saved users from the registry that belong to the active server Source: source/utils/config.brs, line 114 Returns: Type object &lt;static&gt; get_setting(key [, defaultValue]) \"Jellyfin\" registry accessors for the default global settings Parameters: Name Type Argument Default Description key dynamic defaultValue dynamic &lt;optional&gt; invalid Source: source/utils/config.brs, line 59 Returns: Type dynamic &lt;static&gt; get_user_setting(key) User registry accessors for the currently active user Parameters: Name Type Description key string Source: source/utils/config.brs, line 82 Returns: Type dynamic &lt;static&gt; registry_delete(key [, section]) Parameters: Name Type Argument Default Description key dynamic section dynamic &lt;optional&gt; invalid Source: source/utils/config.brs, line 35 Returns: Type void &lt;static&gt; registry_read(key [, section]) Generic registry accessors Parameters: Name Type Argument Default Description key dynamic section dynamic &lt;optional&gt; invalid Source: source/utils/config.brs, line 18 Returns: Type dynamic &lt;static&gt; registry_write(key, value [, section]) Parameters: Name Type Argument Default Description key dynamic value dynamic section dynamic &lt;optional&gt; invalid Source: source/utils/config.brs, line 27 Returns: Type void &lt;static&gt; set_setting(key, value) Parameters: Name Type Description key dynamic value dynamic Source: source/utils/config.brs, line 67 Returns: Type void &lt;static&gt; set_user_setting(key, value) Parameters: Name Type Description key string value dynamic Source: source/utils/config.brs, line 90 Returns: Type void &lt;static&gt; unset_setting(key) Parameters: Name Type Description key dynamic Source: source/utils/config.brs, line 74 Returns: Type void &lt;static&gt; unset_user_setting(key) Parameters: Name Type Description key string Source: source/utils/config.brs, line 97 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-deviceCapabilities.html":{"id":"module-deviceCapabilities.html","title":"Module: deviceCapabilities","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: deviceCapabilities Source: source/utils/deviceCapabilities.brs, line 1 Methods &lt;static&gt; GetBitRateLimit(codec) Parameters: Name Type Description codec string Source: source/utils/deviceCapabilities.brs, line 36 Returns: Type object &lt;static&gt; GetDirectPlayProfiles() Source: source/utils/deviceCapabilities.brs, line 29 Returns: Type object &lt;static&gt; PostDeviceProfile() Send Device Profile information to server Source: source/utils/deviceCapabilities.brs, line 17 Returns: Type void &lt;static&gt; getDeviceCapabilities() Device Capabilities for Roku. This will likely need further tweaking Source: source/utils/deviceCapabilities.brs, line 10 Returns: Type object &lt;static&gt; getDeviceProfile() Source: source/utils/deviceCapabilities.brs, line 23 Returns: Type object &lt;static&gt; removeDecimals(value) Remove all decimals from a string Parameters: Name Type Description value string Source: source/utils/deviceCapabilities.brs, line 55 Returns: Type string &lt;static&gt; setPreferredCodec(codecString, preferredCodec) Takes and returns a comma delimited string of codecs. Moves the preferred codec to the front of the string Parameters: Name Type Description codecString string preferredCodec string Source: source/utils/deviceCapabilities.brs, line 65 Returns: Type string &lt;static&gt; updateProfileArray(profileArray, videoCodec, videoProfile [, profileLevel]) Recieves and returns an assArray of supported profiles and levels for each video codec Parameters: Name Type Argument Default Description profileArray object videoCodec string videoProfile string profileLevel string &lt;optional&gt; \"\" Source: source/utils/deviceCapabilities.brs, line 47 Returns: Type object × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-globals.html":{"id":"module-globals.html","title":"Module: globals","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: globals Source: source/utils/globals.brs, line 1 Methods &lt;static&gt; SaveAppToGlobal() Save information from roAppInfo to m.global.app Source: source/utils/globals.brs, line 16 Returns: Type void &lt;static&gt; SaveDeviceToGlobal() Save information from roDeviceInfo to m.global.device Source: source/utils/globals.brs, line 23 Returns: Type void &lt;static&gt; setConstants() Set global constants Source: source/utils/globals.brs, line 9 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-migrations.html":{"id":"module-migrations.html","title":"Module: migrations","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: migrations Source: source/migrations.bs, line 1 Methods &lt;static&gt; runGlobalMigrations() Run all necessary registry mirations on the \"global\" Jellyfin registry section Source: source/migrations.bs, line 9 Returns: Type void &lt;static&gt; runRegistryUserMigrations(version) Parameters: Name Type Description version string Source: source/migrations.bs, line 16 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-misc.html":{"id":"module-misc.html","title":"Module: misc","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: misc Source: source/utils/misc.brs, line 1 Methods &lt;static&gt; AssocArrayEqual(Array1, Array2) Parameters: Name Type Description Array1 object Array2 object Source: source/utils/misc.brs, line 203 Returns: Type boolean &lt;static&gt; arrayHasValue(arr, value) Check if a specific value is inside of an array Parameters: Name Type Description arr object value dynamic Source: source/utils/misc.brs, line 246 Returns: Type boolean &lt;static&gt; div_ceiling(a, b) Parameters: Name Type Description a integer b integer Source: source/utils/misc.brs, line 65 Returns: Type integer &lt;static&gt; findNodeBySubtype(node, subtype) Parameters: Name Type Description node dynamic subtype dynamic Source: source/utils/misc.brs, line 195 Returns: Type dynamic &lt;static&gt; formatTime(time) Format time as 12 or 24 hour format based on system clock setting Parameters: Name Type Description time dynamic Source: source/utils/misc.brs, line 57 Returns: Type string &lt;static&gt; getButton(msg [, subnode]) Parameters: Name Type Argument Default Description msg dynamic subnode string &lt;optional&gt; \"buttons\" Source: source/utils/misc.brs, line 26 Returns: Type object &lt;static&gt; getMinutes(ticks) Converts ticks to minutes Parameters: Name Type Description ticks dynamic Source: source/utils/misc.brs, line 176 Returns: Type integer &lt;static&gt; getMsgPicker(msg [, subnode]) Parameters: Name Type Argument Default Description msg dynamic subnode string &lt;optional&gt; \"\" Source: source/utils/misc.brs, line 18 Returns: Type object &lt;static&gt; get_dialog_result(dialog, port) Returns the item selected or -1 on backpress or other unhandled closure of dialog. Parameters: Name Type Description dialog dynamic port dynamic Source: source/utils/misc.brs, line 74 Returns: Type dynamic &lt;static&gt; inArray(haystack, needle) Search string array for search value. Return if it's found Parameters: Name Type Description haystack dynamic needle dynamic Source: source/utils/misc.brs, line 212 Returns: Type boolean &lt;static&gt; isLocalhost(url) Returns true if the string is a loopback, such as 'localhost' or '127.0.0.1' Parameters: Name Type Description url string Source: source/utils/misc.brs, line 160 Returns: Type boolean &lt;static&gt; isNodeEvent(msg, field) Parameters: Name Type Description msg dynamic field string Source: source/utils/misc.brs, line 10 Returns: Type boolean &lt;static&gt; isValid(input) Returns whether or not passed value is valid Parameters: Name Type Description input dynamic Source: source/utils/misc.brs, line 133 Returns: Type boolean &lt;static&gt; isValidAndNotEmpty(input) Returns whether or not passed value is valid and not empty Accepts a string, or any countable type (arrays and lists) Parameters: Name Type Description input dynamic Source: source/utils/misc.brs, line 142 Returns: Type boolean &lt;static&gt; lastFocusedChild(obj) Parameters: Name Type Description obj object Source: source/utils/misc.brs, line 81 Returns: Type object &lt;static&gt; leftPad(base, fill, length) Parameters: Name Type Description base string fill string length integer Source: source/utils/misc.brs, line 35 Returns: Type string &lt;static&gt; message_dialog( [message]) Parameters: Name Type Argument Default Description message string &lt;optional&gt; \"\" Source: source/utils/misc.brs, line 97 Returns: Type dynamic &lt;static&gt; option_dialog(options [, message] [, defaultSelection]) Parameters: Name Type Argument Default Description options dynamic message dynamic &lt;optional&gt; \"\" defaultSelection dynamic &lt;optional&gt; 0 Source: source/utils/misc.brs, line 106 Returns: Type integer &lt;static&gt; parseUrl(url) Returns an array from a url - [ url, proto, host, port, subdir/params ] If port or subdir are not found, an empty string will be added to the array Proto must be declared or array will be empty Parameters: Name Type Description url string Source: source/utils/misc.brs, line 152 Returns: Type object &lt;static&gt; roundNumber(f) Rounds number to nearest integer Parameters: Name Type Description f float Source: source/utils/misc.brs, line 168 Returns: Type integer &lt;static&gt; secondsToHuman(totalSeconds) Parameters: Name Type Description totalSeconds integer Source: source/utils/misc.brs, line 49 Returns: Type string &lt;static&gt; setFieldTextValue(field, value) Parameters: Name Type Description field dynamic value dynamic Source: source/utils/misc.brs, line 125 Returns: Type void &lt;static&gt; show_dialog(message [, options] [, defaultSelection]) Parameters: Name Type Argument Default Description message string options dynamic &lt;optional&gt; [] defaultSelection dynamic &lt;optional&gt; 0 Source: source/utils/misc.brs, line 90 Returns: Type integer &lt;static&gt; shuffleArray(array) Takes an array of data, shuffles the order, then returns the array uses the Fisher-Yates shuffling algorithm Parameters: Name Type Description array object Source: source/utils/misc.brs, line 255 Returns: Type object &lt;static&gt; standardize_jellyfin_url(url) Take a jellyfin hostname and ensure it's a full url. prepend http or https and append default ports, and remove excess slashes Parameters: Name Type Description url string Source: source/utils/misc.brs, line 117 Returns: Type dynamic &lt;static&gt; startLoadingSpinner() Source: source/utils/misc.brs, line 225 Returns: Type void &lt;static&gt; startMediaLoadingSpinner() Source: source/utils/misc.brs, line 231 Returns: Type void &lt;static&gt; stopLoadingSpinner() Source: source/utils/misc.brs, line 237 Returns: Type void &lt;static&gt; ticksToHuman(ticks) Parameters: Name Type Description ticks longinteger Source: source/utils/misc.brs, line 42 Returns: Type string &lt;static&gt; toString(input) Parameters: Name Type Description input dynamic Source: source/utils/misc.brs, line 219 Returns: Type string &lt;static&gt; versionChecker(versionToCheck, minVersionAccepted) Returns whether or not a version number (e.g. 10.7.7) is greater or equal to some minimum version allowed (e.g. 10.8.0) Parameters: Name Type Description versionToCheck string minVersionAccepted string Source: source/utils/misc.brs, line 187 Returns: Type dynamic × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-quickplay.html":{"id":"module-quickplay.html","title":"Module: quickplay","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: quickplay Source: source/utils/quickplay.bs, line 1 Methods &lt;static&gt; album(itemNode) A music album. Play the entire album starting with track 1. Parameters: Name Type Description itemNode object Source: source/utils/quickplay.bs, line 53 Returns: Type void &lt;static&gt; artist(itemNode) A music artist. Shuffle play all songs by artist. Parameters: Name Type Description itemNode object Source: source/utils/quickplay.bs, line 63 Returns: Type void &lt;static&gt; audio(itemNode) A single audio file. Parameters: Name Type Description itemNode object Source: source/utils/quickplay.bs, line 34 Returns: Type void &lt;static&gt; boxset(itemNode) A boxset. Play all items inside. Parameters: Name Type Description itemNode object Source: source/utils/quickplay.bs, line 73 Returns: Type void &lt;static&gt; collectionFolder(itemNode) Quick Play A CollectionFolder. Shuffle play the items inside with some differences based on collectionType. Parameters: Name Type Description itemNode object Source: source/utils/quickplay.bs, line 165 Returns: Type void &lt;static&gt; folder(itemNode) Quick Play A folder. Shuffle play all items found Parameters: Name Type Description itemNode object Source: source/utils/quickplay.bs, line 154 Returns: Type void &lt;static&gt; multipleSeries(itemNodes) More than one TV Show Series. Shuffle play all watched episodes Parameters: Name Type Description itemNodes object Source: source/utils/quickplay.bs, line 94 Returns: Type void &lt;static&gt; musicVideo(itemNode) A single music video file. Parameters: Name Type Description itemNode object Source: source/utils/quickplay.bs, line 43 Returns: Type void &lt;static&gt; person(itemNode) Quick Play A Person. Shuffle play all videos found Parameters: Name Type Description itemNode object Source: source/utils/quickplay.bs, line 115 Returns: Type void &lt;static&gt; playlist(itemNode) Quick Play A Playlist. Play the first unwatched episode. If none, play the whole season starting with episode 1. Parameters: Name Type Description itemNode object Source: source/utils/quickplay.bs, line 144 Returns: Type void &lt;static&gt; program(itemNode) Quick Play A Live Program Parameters: Name Type Description itemNode object Source: source/utils/quickplay.bs, line 133 Returns: Type void &lt;static&gt; pushToQueue(queueArray [, shufflePlay]) Takes an array of items and adds to global queue. Also shuffles the playlist if asked Parameters: Name Type Argument Default Description queueArray object shufflePlay boolean &lt;optional&gt; false Source: source/utils/quickplay.bs, line 16 Returns: Type void &lt;static&gt; season(itemNode) A TV Show Season. Play the first unwatched episode. If none, play the whole season starting with episode 1. Parameters: Name Type Description itemNode object Source: source/utils/quickplay.bs, line 105 Returns: Type void &lt;static&gt; series(itemNode) A TV Show Series. Play the first unwatched episode. If none, shuffle play the whole series. Parameters: Name Type Description itemNode object Source: source/utils/quickplay.bs, line 84 Returns: Type void &lt;static&gt; tvChannel(itemNode) Quick Play A TVChannel Parameters: Name Type Description itemNode object Source: source/utils/quickplay.bs, line 124 Returns: Type void &lt;static&gt; userView(itemNode) Quick Play A UserView. Play logic depends on \"collectionType\". Parameters: Name Type Description itemNode object Source: source/utils/quickplay.bs, line 175 Returns: Type void &lt;static&gt; video(itemNode) A single video file. Parameters: Name Type Description itemNode object Source: source/utils/quickplay.bs, line 25 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-schedule.html":{"id":"module-schedule.html","title":"Module: schedule","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: schedule Source: components/liveTv/schedule.brs, line 1 Methods &lt;static&gt; channelFilterSet() Source: components/liveTv/schedule.brs, line 14 Returns: Type void &lt;static&gt; channelsearchTermSet() Voice Search set Source: components/liveTv/schedule.brs, line 21 Returns: Type void &lt;static&gt; focusProgramDetails(setFocused) Move the TV Guide Grid down or up depending whether details are selected Parameters: Name Type Description setFocused dynamic Source: components/liveTv/schedule.brs, line 62 Returns: Type void &lt;static&gt; init() Source: components/liveTv/schedule.brs, line 8 Returns: Type void &lt;static&gt; onChannelsLoaded() Initial list of channels loaded Source: components/liveTv/schedule.brs, line 28 Returns: Type void &lt;static&gt; onGridScrolled() As user scrolls grid, check if more data requries to be loaded Source: components/liveTv/schedule.brs, line 76 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/liveTv/schedule.brs, line 104 Returns: Type boolean &lt;static&gt; onProgramDetailsLoaded() Update the Program Details with full information Source: components/liveTv/schedule.brs, line 48 Returns: Type void &lt;static&gt; onProgramFocused() Source: components/liveTv/schedule.brs, line 41 Returns: Type void &lt;static&gt; onProgramSelected() Source: components/liveTv/schedule.brs, line 54 Returns: Type void &lt;static&gt; onRecordChannelSelected() Handle user selecting \"Record Channel\" from Program Details Source: components/liveTv/schedule.brs, line 83 Returns: Type void &lt;static&gt; onRecordOperationDone() Source: components/liveTv/schedule.brs, line 96 Returns: Type void &lt;static&gt; onRecordSeriesChannelSelected() Handle user selecting \"Record Series\" from Program Details Source: components/liveTv/schedule.brs, line 90 Returns: Type void &lt;static&gt; onScheduleLoaded() When LoadScheduleTask completes (initial or more data) and we have a schedule to display Source: components/liveTv/schedule.brs, line 35 Returns: Type void &lt;static&gt; onWatchChannelSelected() Handle user selecting \"Watch Channel\" from Program Details Source: components/liveTv/schedule.brs, line 69 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-section.html":{"id":"module-section.html","title":"Module: section","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: section Source: components/section/section.brs, line 1 Methods &lt;static&gt; init() Source: components/section/section.brs, line 8 Returns: Type void &lt;static&gt; onFocusChange() Source: components/section/section.brs, line 68 Returns: Type void &lt;static&gt; onIDChange() Source: components/section/section.brs, line 14 Returns: Type void &lt;static&gt; onTranslationChange() Source: components/section/section.brs, line 20 Returns: Type void &lt;static&gt; scrollDownToOnDeck() Source: components/section/section.brs, line 56 Returns: Type void &lt;static&gt; scrollOffBottom() Source: components/section/section.brs, line 38 Returns: Type void &lt;static&gt; scrollOffOnDeck() Source: components/section/section.brs, line 62 Returns: Type void &lt;static&gt; scrollOffTop() Source: components/section/section.brs, line 44 Returns: Type void &lt;static&gt; scrollUpToOnDeck() Source: components/section/section.brs, line 50 Returns: Type void &lt;static&gt; showFromBottom() Source: components/section/section.brs, line 32 Returns: Type void &lt;static&gt; showFromTop() Source: components/section/section.brs, line 26 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-sectionScroller.html":{"id":"module-sectionScroller.html","title":"Module: sectionScroller","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: sectionScroller Source: components/section/sectionScroller.brs, line 1 Methods &lt;static&gt; displayedIndexChanged() Source: components/section/sectionScroller.brs, line 20 Returns: Type void &lt;static&gt; init() Source: components/section/sectionScroller.brs, line 8 Returns: Type void &lt;static&gt; onFocusChange() Source: components/section/sectionScroller.brs, line 14 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-settings.html":{"id":"module-settings.html","title":"Module: settings","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: settings Source: components/settings/settings.brs, line 1 Methods &lt;static&gt; LoadMenu(configSection) Parameters: Name Type Description configSection dynamic Source: components/settings/settings.brs, line 27 Returns: Type void &lt;static&gt; boolSettingChanged() Source: components/settings/settings.brs, line 45 Returns: Type void &lt;static&gt; init() Source: components/settings/settings.brs, line 8 Returns: Type void &lt;static&gt; onKeyEvent(key, press) Parameters: Name Type Description key string press boolean Source: components/settings/settings.brs, line 59 Returns: Type boolean &lt;static&gt; onKeyGridEscape() Source: components/settings/settings.brs, line 20 Returns: Type void &lt;static&gt; onKeyGridSubmit() Source: components/settings/settings.brs, line 14 Returns: Type void &lt;static&gt; radioSettingChanged() Source: components/settings/settings.brs, line 51 Returns: Type void &lt;static&gt; settingFocused() Source: components/settings/settings.brs, line 33 Returns: Type void &lt;static&gt; settingSelected() Source: components/settings/settings.brs, line 39 Returns: Type void × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "},"module-userauth.html":{"id":"module-userauth.html","title":"Module: userauth","body":" jellyfin-roku api docs Modules AlbumDataAlbumGridAlbumTrackListAlbumViewAlphaArtistViewAudioPlayerAudioPlayerViewAudioTrackListItemButtonGroupHorizChannelDataCollectionDataConfigDataConfigItemConfigListExtrasItemExtrasRowListFavoriteItemsTaskFolderDataGetFiltersTaskGetNextEpisodeTaskGetPlaybackInfoTaskGetShuffleEpisodesTaskGridItemGridItemSmallHomeHomeDataHomeItemHomeRowsIconButtonImageImageDataItemGridItemGridOptionsItemsJFButtonJFButtonsJFGroupJFMessageDialogJFOverhangJFSceneJFScreenJFServerJFVideoListPosterLoadChannelsTaskLoadItemsTaskLoadItemsTask2LoadPhotoTaskLoadProgramDetailsTaskLoadScreenSaverTimeoutTaskLoadSheduleTaskLoadVideoContentTaskLoginSceneMainMovieDataMovieDetailsMovieLibraryViewMovieOptionsMusicAlbumDataMusicAlbumSongListDataMusicArtistDataMusicArtistGridItemMusicLibraryViewMusicSongDataOptionNodeOptionsButtonOptionsDataOptionsSliderOverviewDialogPersonDataPersonDetailsPhotoDataPhotoDetailsPlaybackDialogPlayedCheckmarkPlaylistDataPlaylistViewPlaystateTaskProgramDetailsPublicUserDataQueueManagerQuickConnectQuickConnectDialogRadioDialogRecordProgramTaskSceneManagerScheduleProgramDataSearchBoxSearchDataSearchResultsSearchRowSearchTaskSeriesDataServerDiscoveryTaskSetServerScreenShowScenesSongItemSpinnerStandardDialogSubtitlesTVEpisodeTVEpisodeDataTVEpisodeRowTVEpisodeRowWithOptionsTVEpisodesTVListDetailsTVListOptionsTVSeasonDataTVSeasonRowTVShowDescriptionTVShowDetailsTextSizeTaskUserDataUserItemUserLibraryUserRowUserSelectVideoDataVideoPlayerVideoPlayerViewVideoTrackListItemViewCreatorWhatsNewDialogbaserequestcaptionTaskconfigdeviceCapabilitiesglobalsmigrationsmiscquickplayschedulesectionsectionScrollersettingsuserauth Module: userauth Source: source/api/userauth.brs, line 1 Methods &lt;static&gt; AboutMe( [id]) Parameters: Name Type Argument Default Description id string &lt;optional&gt; \"\" Source: source/api/userauth.brs, line 17 Returns: Type dynamic &lt;static&gt; AuthenticateViaQuickConnect(secret) Parameters: Name Type Description secret dynamic Source: source/api/userauth.brs, line 68 Returns: Type dynamic &lt;static&gt; AvailableUsers() Source: source/api/userauth.brs, line 30 Returns: Type dynamic &lt;static&gt; GetPublicUsers() Source: source/api/userauth.brs, line 42 Returns: Type dynamic &lt;static&gt; LoadUserAbilities() Source: source/api/userauth.brs, line 48 Returns: Type void &lt;static&gt; ServerInfo() Source: source/api/userauth.brs, line 36 Returns: Type dynamic &lt;static&gt; SignOut( [deleteSavedEntry]) Parameters: Name Type Argument Default Description deleteSavedEntry boolean &lt;optional&gt; true Source: source/api/userauth.brs, line 24 Returns: Type void &lt;static&gt; checkQuickConnect(secret) Parameters: Name Type Description secret dynamic Source: source/api/userauth.brs, line 61 Returns: Type dynamic &lt;static&gt; get_token(user, password) Parameters: Name Type Description user string password string Source: source/api/userauth.brs, line 10 Returns: Type dynamic &lt;static&gt; initQuickConnect() Source: source/api/userauth.brs, line 54 Returns: Type dynamic × Search results Close Source code: https://github.com/jellyfin/jellyfin-rokuJellyfin Roku Development Forum: https://forum.jellyfin.org/f-roku-development Documentation generated by JSDoc 4.0.2 on Oct 29th 2023 using the DocStrap template. "}}
</script>
<script type="text/javascript">
$(document).ready(function() {
Searcher.init();
});
$(window).on("message", function(msg) {
var msgData = msg.originalEvent.data;
if (msgData.msgid != "docstrap.quicksearch.start") {
return;
}
var results = Searcher.search(msgData.searchTerms);
window.parent.postMessage({"results": results, "msgid": "docstrap.quicksearch.done"}, "*");
});
</script>
</body>
</html>