785 lines
62 KiB
HTML
785 lines
62 KiB
HTML
<!DOCTYPE html><html lang="en" style="font-size:16px"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Source: components/music/AudioPlayerView.bs</title><!--[if lt IE 9]>
|
|
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
|
<![endif]--><script src="scripts/third-party/hljs.js" defer="defer"></script><script src="scripts/third-party/hljs-line-num.js" defer="defer"></script><script src="scripts/third-party/popper.js" defer="defer"></script><script src="scripts/third-party/tippy.js" defer="defer"></script><script src="scripts/third-party/tocbot.min.js"></script><script>var baseURL="/",locationPathname="";baseURL=(baseURL=(baseURL="https://jellyfin.github.io/jellyfin-roku/").replace(/https?:\/\//i,"")).substr(baseURL.indexOf("/"))</script><link rel="stylesheet" href="styles/clean-jsdoc-theme.min.css"><svg aria-hidden="true" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:none"><defs><symbol id="copy-icon" viewbox="0 0 488.3 488.3"><g><path d="M314.25,85.4h-227c-21.3,0-38.6,17.3-38.6,38.6v325.7c0,21.3,17.3,38.6,38.6,38.6h227c21.3,0,38.6-17.3,38.6-38.6V124 C352.75,102.7,335.45,85.4,314.25,85.4z M325.75,449.6c0,6.4-5.2,11.6-11.6,11.6h-227c-6.4,0-11.6-5.2-11.6-11.6V124 c0-6.4,5.2-11.6,11.6-11.6h227c6.4,0,11.6,5.2,11.6,11.6V449.6z"/><path d="M401.05,0h-227c-21.3,0-38.6,17.3-38.6,38.6c0,7.5,6,13.5,13.5,13.5s13.5-6,13.5-13.5c0-6.4,5.2-11.6,11.6-11.6h227 c6.4,0,11.6,5.2,11.6,11.6v325.7c0,6.4-5.2,11.6-11.6,11.6c-7.5,0-13.5,6-13.5,13.5s6,13.5,13.5,13.5c21.3,0,38.6-17.3,38.6-38.6 V38.6C439.65,17.3,422.35,0,401.05,0z"/></g></symbol><symbol id="search-icon" viewBox="0 0 512 512"><g><g><path d="M225.474,0C101.151,0,0,101.151,0,225.474c0,124.33,101.151,225.474,225.474,225.474 c124.33,0,225.474-101.144,225.474-225.474C450.948,101.151,349.804,0,225.474,0z M225.474,409.323 c-101.373,0-183.848-82.475-183.848-183.848S124.101,41.626,225.474,41.626s183.848,82.475,183.848,183.848 S326.847,409.323,225.474,409.323z"/></g></g><g><g><path d="M505.902,476.472L386.574,357.144c-8.131-8.131-21.299-8.131-29.43,0c-8.131,8.124-8.131,21.306,0,29.43l119.328,119.328 c4.065,4.065,9.387,6.098,14.715,6.098c5.321,0,10.649-2.033,14.715-6.098C514.033,497.778,514.033,484.596,505.902,476.472z"/></g></g></symbol><symbol id="font-size-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11.246 15H4.754l-2 5H.6L7 4h2l6.4 16h-2.154l-2-5zm-.8-2L8 6.885 5.554 13h4.892zM21 12.535V12h2v8h-2v-.535a4 4 0 1 1 0-6.93zM19 18a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"/></symbol><symbol id="add-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M11 11V5h2v6h6v2h-6v6h-2v-6H5v-2z"/></symbol><symbol id="minus-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M5 11h14v2H5z"/></symbol><symbol id="dark-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2h.1A6.979 6.979 0 0 0 10 7zm-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938 7.999 7.999 0 0 0 4 12z"/></symbol><symbol id="light-theme-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></symbol><symbol id="reset-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M18.537 19.567A9.961 9.961 0 0 1 12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10c0 2.136-.67 4.116-1.81 5.74L17 12h3a8 8 0 1 0-2.46 5.772l.997 1.795z"/></symbol><symbol id="down-icon" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.7803 6.21967C13.0732 6.51256 13.0732 6.98744 12.7803 7.28033L8.53033 11.5303C8.23744 11.8232 7.76256 11.8232 7.46967 11.5303L3.21967 7.28033C2.92678 6.98744 2.92678 6.51256 3.21967 6.21967C3.51256 5.92678 3.98744 5.92678 4.28033 6.21967L8 9.93934L11.7197 6.21967C12.0126 5.92678 12.4874 5.92678 12.7803 6.21967Z"></path></symbol><symbol id="codepen-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M16.5 13.202L13 15.535v3.596L19.197 15 16.5 13.202zM14.697 12L12 10.202 9.303 12 12 13.798 14.697 12zM20 10.869L18.303 12 20 13.131V10.87zM19.197 9L13 4.869v3.596l3.5 2.333L19.197 9zM7.5 10.798L11 8.465V4.869L4.803 9 7.5 10.798zM4.803 15L11 19.131v-3.596l-3.5-2.333L4.803 15zM4 13.131L5.697 12 4 10.869v2.262zM2 9a1 1 0 0 1 .445-.832l9-6a1 1 0 0 1 1.11 0l9 6A1 1 0 0 1 22 9v6a1 1 0 0 1-.445.832l-9 6a1 1 0 0 1-1.11 0l-9-6A1 1 0 0 1 2 15V9z"/></symbol><symbol id="close-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z"/></symbol><symbol id="menu-icon" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M3 4h18v2H3V4zm0 7h18v2H3v-2zm0 7h18v2H3v-2z"/></symbol></defs></svg></head><body data-theme="fallback-dark"><div class="sidebar-container"><div class="sidebar" id="sidebar"><a href="/" class="sidebar-title sidebar-title-anchor">jellyfin-roku Code Documentation</a><div class="sidebar-items-container"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-modules"><div>Modules</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="module-AlbumData.html">AlbumData</a></div><div class="sidebar-section-children"><a href="module-AlbumGrid.html">AlbumGrid</a></div><div class="sidebar-section-children"><a href="module-AlbumTrackList.html">AlbumTrackList</a></div><div class="sidebar-section-children"><a href="module-AlbumView.html">AlbumView</a></div><div class="sidebar-section-children"><a href="module-Alpha.html">Alpha</a></div><div class="sidebar-section-children"><a href="module-ArtistView.html">ArtistView</a></div><div class="sidebar-section-children"><a href="module-AudioPlayer.html">AudioPlayer</a></div><div class="sidebar-section-children"><a href="module-AudioPlayerView.html">AudioPlayerView</a></div><div class="sidebar-section-children"><a href="module-AudioTrackListItem.html">AudioTrackListItem</a></div><div class="sidebar-section-children"><a href="module-ButtonGroupHoriz.html">ButtonGroupHoriz</a></div><div class="sidebar-section-children"><a href="module-ButtonGroupVert.html">ButtonGroupVert</a></div><div class="sidebar-section-children"><a href="module-ChannelData.html">ChannelData</a></div><div class="sidebar-section-children"><a href="module-Clock.html">Clock</a></div><div class="sidebar-section-children"><a href="module-CollectionData.html">CollectionData</a></div><div class="sidebar-section-children"><a href="module-ConfigData.html">ConfigData</a></div><div class="sidebar-section-children"><a href="module-ConfigItem.html">ConfigItem</a></div><div class="sidebar-section-children"><a href="module-ConfigList.html">ConfigList</a></div><div class="sidebar-section-children"><a href="module-ExtrasItem.html">ExtrasItem</a></div><div class="sidebar-section-children"><a href="module-ExtrasRowList.html">ExtrasRowList</a></div><div class="sidebar-section-children"><a href="module-FavoriteItemsTask.html">FavoriteItemsTask</a></div><div class="sidebar-section-children"><a href="module-FolderData.html">FolderData</a></div><div class="sidebar-section-children"><a href="module-GetFiltersTask.html">GetFiltersTask</a></div><div class="sidebar-section-children"><a href="module-GetNextEpisodeTask.html">GetNextEpisodeTask</a></div><div class="sidebar-section-children"><a href="module-GetPlaybackInfoTask.html">GetPlaybackInfoTask</a></div><div class="sidebar-section-children"><a href="module-GetShuffleEpisodesTask.html">GetShuffleEpisodesTask</a></div><div class="sidebar-section-children"><a href="module-GridItem.html">GridItem</a></div><div class="sidebar-section-children"><a href="module-GridItemSmall.html">GridItemSmall</a></div><div class="sidebar-section-children"><a href="module-Home.html">Home</a></div><div class="sidebar-section-children"><a href="module-HomeData.html">HomeData</a></div><div class="sidebar-section-children"><a href="module-HomeItem.html">HomeItem</a></div><div class="sidebar-section-children"><a href="module-HomeRowItemSizes.html">HomeRowItemSizes</a></div><div class="sidebar-section-children"><a href="module-HomeRows.html">HomeRows</a></div><div class="sidebar-section-children"><a href="module-IconButton.html">IconButton</a></div><div class="sidebar-section-children"><a href="module-Image.html">Image</a></div><div class="sidebar-section-children"><a href="module-ImageData.html">ImageData</a></div><div class="sidebar-section-children"><a href="module-IntegerKeyboard.html">IntegerKeyboard</a></div><div class="sidebar-section-children"><a href="module-ItemGrid.html">ItemGrid</a></div><div class="sidebar-section-children"><a href="module-ItemGridOptions.html">ItemGridOptions</a></div><div class="sidebar-section-children"><a href="module-Items.html">Items</a></div><div class="sidebar-section-children"><a href="module-JFButton.html">JFButton</a></div><div class="sidebar-section-children"><a href="module-JFButtons.html">JFButtons</a></div><div class="sidebar-section-children"><a href="module-JFGroup.html">JFGroup</a></div><div class="sidebar-section-children"><a href="module-JFMessageDialog.html">JFMessageDialog</a></div><div class="sidebar-section-children"><a href="module-JFOverhang.html">JFOverhang</a></div><div class="sidebar-section-children"><a href="module-JFScene.html">JFScene</a></div><div class="sidebar-section-children"><a href="module-JFScreen.html">JFScreen</a></div><div class="sidebar-section-children"><a href="module-JFServer.html">JFServer</a></div><div class="sidebar-section-children"><a href="module-JFVideo.html">JFVideo</a></div><div class="sidebar-section-children"><a href="module-ListPoster.html">ListPoster</a></div><div class="sidebar-section-children"><a href="module-LoadChannelsTask.html">LoadChannelsTask</a></div><div class="sidebar-section-children"><a href="module-LoadItemsTask.html">LoadItemsTask</a></div><div class="sidebar-section-children"><a href="module-LoadItemsTask2.html">LoadItemsTask2</a></div><div class="sidebar-section-children"><a href="module-LoadPhotoTask.html">LoadPhotoTask</a></div><div class="sidebar-section-children"><a href="module-LoadProgramDetailsTask.html">LoadProgramDetailsTask</a></div><div class="sidebar-section-children"><a href="module-LoadScreenSaverTimeoutTask.html">LoadScreenSaverTimeoutTask</a></div><div class="sidebar-section-children"><a href="module-LoadSheduleTask.html">LoadSheduleTask</a></div><div class="sidebar-section-children"><a href="module-LoadVideoContentTask.html">LoadVideoContentTask</a></div><div class="sidebar-section-children"><a href="module-LoginScene.html">LoginScene</a></div><div class="sidebar-section-children"><a href="module-Main.html">Main</a></div><div class="sidebar-section-children"><a href="module-MovieData.html">MovieData</a></div><div class="sidebar-section-children"><a href="module-MovieDetails.html">MovieDetails</a></div><div class="sidebar-section-children"><a href="module-MovieLibraryView.html">MovieLibraryView</a></div><div class="sidebar-section-children"><a href="module-MovieOptions.html">MovieOptions</a></div><div class="sidebar-section-children"><a href="module-MusicAlbumData.html">MusicAlbumData</a></div><div class="sidebar-section-children"><a href="module-MusicAlbumSongListData.html">MusicAlbumSongListData</a></div><div class="sidebar-section-children"><a href="module-MusicArtistData.html">MusicArtistData</a></div><div class="sidebar-section-children"><a href="module-MusicArtistGridItem.html">MusicArtistGridItem</a></div><div class="sidebar-section-children"><a href="module-MusicLibraryView.html">MusicLibraryView</a></div><div class="sidebar-section-children"><a href="module-MusicSongData.html">MusicSongData</a></div><div class="sidebar-section-children"><a href="module-OSD.html">OSD</a></div><div class="sidebar-section-children"><a href="module-OptionNode.html">OptionNode</a></div><div class="sidebar-section-children"><a href="module-OptionsButton.html">OptionsButton</a></div><div class="sidebar-section-children"><a href="module-OptionsData.html">OptionsData</a></div><div class="sidebar-section-children"><a href="module-OptionsSlider.html">OptionsSlider</a></div><div class="sidebar-section-children"><a href="module-OverviewDialog.html">OverviewDialog</a></div><div class="sidebar-section-children"><a href="module-PersonData.html">PersonData</a></div><div class="sidebar-section-children"><a href="module-PersonDetails.html">PersonDetails</a></div><div class="sidebar-section-children"><a href="module-PhotoData.html">PhotoData</a></div><div class="sidebar-section-children"><a href="module-PhotoDetails.html">PhotoDetails</a></div><div class="sidebar-section-children"><a href="module-PlaybackDialog.html">PlaybackDialog</a></div><div class="sidebar-section-children"><a href="module-PlayedCheckmark.html">PlayedCheckmark</a></div><div class="sidebar-section-children"><a href="module-PlaylistData.html">PlaylistData</a></div><div class="sidebar-section-children"><a href="module-PlaylistView.html">PlaylistView</a></div><div class="sidebar-section-children"><a href="module-PlaystateTask.html">PlaystateTask</a></div><div class="sidebar-section-children"><a href="module-PostTask.html">PostTask</a></div><div class="sidebar-section-children"><a href="module-ProgramDetails.html">ProgramDetails</a></div><div class="sidebar-section-children"><a href="module-PublicUserData.html">PublicUserData</a></div><div class="sidebar-section-children"><a href="module-QueueManager.html">QueueManager</a></div><div class="sidebar-section-children"><a href="module-QuickConnect.html">QuickConnect</a></div><div class="sidebar-section-children"><a href="module-QuickConnectDialog.html">QuickConnectDialog</a></div><div class="sidebar-section-children"><a href="module-RadioDialog.html">RadioDialog</a></div><div class="sidebar-section-children"><a href="module-RecordProgramTask.html">RecordProgramTask</a></div><div class="sidebar-section-children"><a href="module-SceneManager.html">SceneManager</a></div><div class="sidebar-section-children"><a href="module-ScheduleProgramData.html">ScheduleProgramData</a></div><div class="sidebar-section-children"><a href="module-SearchBox.html">SearchBox</a></div><div class="sidebar-section-children"><a href="module-SearchData.html">SearchData</a></div><div class="sidebar-section-children"><a href="module-SearchResults.html">SearchResults</a></div><div class="sidebar-section-children"><a href="module-SearchRow.html">SearchRow</a></div><div class="sidebar-section-children"><a href="module-SearchTask.html">SearchTask</a></div><div class="sidebar-section-children"><a href="module-SeriesData.html">SeriesData</a></div><div class="sidebar-section-children"><a href="module-ServerDiscoveryTask.html">ServerDiscoveryTask</a></div><div class="sidebar-section-children"><a href="module-SetServerScreen.html">SetServerScreen</a></div><div class="sidebar-section-children"><a href="module-ShowScenes.html">ShowScenes</a></div><div class="sidebar-section-children"><a href="module-SlideOutButton.html">SlideOutButton</a></div><div class="sidebar-section-children"><a href="module-SongItem.html">SongItem</a></div><div class="sidebar-section-children"><a href="module-Spinner.html">Spinner</a></div><div class="sidebar-section-children"><a href="module-StandardDialog.html">StandardDialog</a></div><div class="sidebar-section-children"><a href="module-Subtitles.html">Subtitles</a></div><div class="sidebar-section-children"><a href="module-TVEpisode.html">TVEpisode</a></div><div class="sidebar-section-children"><a href="module-TVEpisodeData.html">TVEpisodeData</a></div><div class="sidebar-section-children"><a href="module-TVEpisodeRow.html">TVEpisodeRow</a></div><div class="sidebar-section-children"><a href="module-TVEpisodeRowWithOptions.html">TVEpisodeRowWithOptions</a></div><div class="sidebar-section-children"><a href="module-TVEpisodes.html">TVEpisodes</a></div><div class="sidebar-section-children"><a href="module-TVListDetails.html">TVListDetails</a></div><div class="sidebar-section-children"><a href="module-TVListOptions.html">TVListOptions</a></div><div class="sidebar-section-children"><a href="module-TVSeasonData.html">TVSeasonData</a></div><div class="sidebar-section-children"><a href="module-TVSeasonRow.html">TVSeasonRow</a></div><div class="sidebar-section-children"><a href="module-TVShowDescription.html">TVShowDescription</a></div><div class="sidebar-section-children"><a href="module-TVShowDetails.html">TVShowDetails</a></div><div class="sidebar-section-children"><a href="module-TextSizeTask.html">TextSizeTask</a></div><div class="sidebar-section-children"><a href="module-UserData.html">UserData</a></div><div class="sidebar-section-children"><a href="module-UserItem.html">UserItem</a></div><div class="sidebar-section-children"><a href="module-UserLibrary.html">UserLibrary</a></div><div class="sidebar-section-children"><a href="module-UserRow.html">UserRow</a></div><div class="sidebar-section-children"><a href="module-UserSelect.html">UserSelect</a></div><div class="sidebar-section-children"><a href="module-VideoData.html">VideoData</a></div><div class="sidebar-section-children"><a href="module-VideoPlayer.html">VideoPlayer</a></div><div class="sidebar-section-children"><a href="module-VideoPlayerView.html">VideoPlayerView</a></div><div class="sidebar-section-children"><a href="module-VideoTrackListItem.html">VideoTrackListItem</a></div><div class="sidebar-section-children"><a href="module-ViewCreator.html">ViewCreator</a></div><div class="sidebar-section-children"><a href="module-WhatsNewDialog.html">WhatsNewDialog</a></div><div class="sidebar-section-children"><a href="module-baserequest.html">baserequest</a></div><div class="sidebar-section-children"><a href="module-captionTask.html">captionTask</a></div><div class="sidebar-section-children"><a href="module-conditional.html">conditional</a></div><div class="sidebar-section-children"><a href="module-config.html">config</a></div><div class="sidebar-section-children"><a href="module-deviceCapabilities.html">deviceCapabilities</a></div><div class="sidebar-section-children"><a href="module-globals.html">globals</a></div><div class="sidebar-section-children"><a href="module-homeRowItemSizes_.html">homeRowItemSizes</a></div><div class="sidebar-section-children"><a href="module-migrations.html">migrations</a></div><div class="sidebar-section-children"><a href="module-misc.html">misc</a></div><div class="sidebar-section-children"><a href="module-quickplay.html">quickplay</a></div><div class="sidebar-section-children"><a href="module-schedule.html">schedule</a></div><div class="sidebar-section-children"><a href="module-section.html">section</a></div><div class="sidebar-section-children"><a href="module-sectionScroller.html">sectionScroller</a></div><div class="sidebar-section-children"><a href="module-settings.html">settings</a></div><div class="sidebar-section-children"><a href="module-userauth.html">userauth</a></div></div></div></div></div><div class="navbar-container" id="VuAckcnZhf"><nav class="navbar"><div class="navbar-left-items"><div class="external-link navbar-item"><a id="jellyfin-link" href="https://jellyfin.org/" target="_blank">Jellyfin</a></div><div class="external-link navbar-item"><a id="github-link" href="https://github.com/jellyfin/jellyfin-roku" target="_blank">GitHub</a></div><div class="external-link navbar-item"><a id="forum-link" href="https://forum.jellyfin.org/f-roku-development" target="_blank">Forum</a></div><div class="external-link navbar-item"><a id="matrix-link" href="https://matrix.to/#/#jellyfin-dev-roku:matrix.org" target="_blank">Matrix</a></div></div><div class="navbar-right-items"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#dark-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div><nav></nav></nav></div><div class="toc-container"><div class="toc-content"><span class="bold">On this page</span><div id="eed4d2a0bfd64539bb9df78095dec881"></div></div></div><div class="body-wrapper"><div class="main-content"><div class="main-wrapper"><section id="source-page" class="source-page"><header><h1 id="title" class="has-anchor">components_music_AudioPlayerView.bs</h1></header><article><pre class="prettyprint source lang-js"><code>import "pkg:/source/utils/misc.bs"
|
|
import "pkg:/source/api/Image.bs"
|
|
import "pkg:/source/api/baserequest.bs"
|
|
import "pkg:/source/utils/config.bs"
|
|
|
|
sub init()
|
|
m.top.optionsAvailable = false
|
|
m.inScrubMode = false
|
|
m.lastRecordedPositionTimestamp = 0
|
|
m.scrubTimestamp = -1
|
|
|
|
setupAudioNode()
|
|
setupAnimationTasks()
|
|
setupButtons()
|
|
setupInfoNodes()
|
|
setupDataTasks()
|
|
setupScreenSaver()
|
|
|
|
m.playlistTypeCount = m.global.queueManager.callFunc("getQueueUniqueTypes").count()
|
|
|
|
m.buttonCount = m.buttons.getChildCount()
|
|
m.seekPosition.translation = [720 - (m.seekPosition.width / 2), m.seekPosition.translation[1]]
|
|
|
|
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()
|
|
|
|
m.buttons.setFocus(true)
|
|
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.thumb = m.top.findNode("thumb")
|
|
m.shuffleIndicator = m.top.findNode("shuffleIndicator")
|
|
m.loopIndicator = m.top.findNode("loopIndicator")
|
|
m.positionTimestamp = m.top.findNode("positionTimestamp")
|
|
m.seekPosition = m.top.findNode("seekPosition")
|
|
m.seekTimestamp = m.top.findNode("seekTimestamp")
|
|
m.totalLengthTimestamp = m.top.findNode("totalLengthTimestamp")
|
|
end sub
|
|
|
|
sub bufferPositionChanged()
|
|
if m.inScrubMode then return
|
|
|
|
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 > 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()
|
|
stopLoadingSpinner()
|
|
|
|
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 > m.seekBar.width
|
|
playPositionBarWidth = m.seekBar.width
|
|
end if
|
|
|
|
if not m.inScrubMode
|
|
moveSeekbarThumb(playPositionBarWidth)
|
|
' Change the seek position timestamp
|
|
m.seekTimestamp.text = secondsToHuman(m.global.audioPlayer.position, false)
|
|
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.lastRecordedPositionTimestamp = m.global.audioPlayer.position
|
|
m.positionTimestamp.text = secondsToHuman(m.global.audioPlayer.position, false)
|
|
else
|
|
m.lastRecordedPositionTimestamp = 0
|
|
m.positionTimestamp.text = "0:00"
|
|
end if
|
|
|
|
' Only fall into screensaver logic if the user has screensaver enabled in Roku settings
|
|
if m.screenSaverTimeout > 0
|
|
if m.di.TimeSinceLastKeypress() >= 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 > 0 or m.PosterOne.opacity > 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"
|
|
m.scrubTimestamp = -1
|
|
playAction()
|
|
exitScrubMode()
|
|
return
|
|
end if
|
|
|
|
if m.global.queueManager.callFunc("getPosition") < 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 > 1 then return false
|
|
if m.global.queueManager.callFunc("getPosition") = 0 then return false
|
|
|
|
exitScrubMode()
|
|
|
|
m.lastRecordedPositionTimestamp = 0
|
|
m.positionTimestamp.text = "0:00"
|
|
|
|
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 > 1 then return false
|
|
|
|
exitScrubMode()
|
|
|
|
m.lastRecordedPositionTimestamp = 0
|
|
m.positionTimestamp.text = "0:00"
|
|
|
|
' Reset loop mode due to manual user interaction
|
|
if m.global.audioPlayer.loopMode = "one"
|
|
resetLoopModeToDefault()
|
|
end if
|
|
|
|
if m.global.queueManager.callFunc("getPosition") < 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
|
|
|
|
exitScrubMode()
|
|
|
|
' 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()
|
|
|
|
m.LoadAudioStreamTask.control = "STOP"
|
|
|
|
currentItem = m.global.queueManager.callFunc("getCurrentItem")
|
|
|
|
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 > 1 then return
|
|
|
|
if m.global.queueManager.callFunc("getCount") > 1
|
|
m.shuffleIndicator.opacity = ".4"
|
|
m.loopIndicator.opacity = ".4"
|
|
m.displayButtonsAnimation.control = "start"
|
|
setLoopButtonImage()
|
|
end if
|
|
end sub
|
|
|
|
sub onAudioStreamLoaded()
|
|
stopLoadingSpinner()
|
|
data = m.LoadAudioStreamTask.content[0]
|
|
m.LoadAudioStreamTask.unobserveField("content")
|
|
if data <> invalid and data.count() > 0
|
|
' 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.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 <> ""
|
|
setBackdropImage(data)
|
|
end if
|
|
end sub
|
|
|
|
sub onMetaDataLoaded()
|
|
data = m.LoadMetaDataTask.content[0]
|
|
m.LoadMetaDataTask.unobserveField("content")
|
|
if isValid(data) and data.count() > 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 <> 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 <> 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 <> data
|
|
m.backDrop.uri = data
|
|
end if
|
|
end if
|
|
end sub
|
|
|
|
' setSelectedButtonState: Changes the icon state url for the currently selected button
|
|
'
|
|
' @param {string} oldState - current state to replace in icon url
|
|
' @param {string} newState - state to replace {oldState} with in icon url
|
|
sub setSelectedButtonState(oldState as string, newState as string)
|
|
selectedButton = m.buttons.getChild(m.top.selectedButtonIndex)
|
|
selectedButton.uri = selectedButton.uri.Replace(oldState, newState)
|
|
end sub
|
|
|
|
' processScrubAction: Handles +/- seeking for the audio trickplay bar
|
|
'
|
|
' @param {integer} seekStep - seconds to move the trickplay position (negative values allowed)
|
|
sub processScrubAction(seekStep as integer)
|
|
' Prepare starting playStart property value
|
|
if m.scrubTimestamp = -1
|
|
m.scrubTimestamp = m.lastRecordedPositionTimestamp
|
|
end if
|
|
|
|
' Don't let seek to go past the end of the song
|
|
if m.scrubTimestamp + seekStep > m.songDuration - 5
|
|
return
|
|
end if
|
|
|
|
if seekStep > 0
|
|
' Move seek forward
|
|
m.scrubTimestamp += seekStep
|
|
else if m.scrubTimestamp >= Abs(seekStep)
|
|
' If back seek won't go below 0, move seek back
|
|
m.scrubTimestamp += seekStep
|
|
else
|
|
' Back seek would go below 0, set to 0 directly
|
|
m.scrubTimestamp = 0
|
|
end if
|
|
|
|
' Move the seedbar thumb forward
|
|
songPercentComplete = m.scrubTimestamp / m.songDuration
|
|
playPositionBarWidth = m.seekBar.width * songPercentComplete
|
|
|
|
moveSeekbarThumb(playPositionBarWidth)
|
|
|
|
' Change the displayed position timestamp
|
|
m.seekTimestamp.text = secondsToHuman(m.scrubTimestamp, false)
|
|
end sub
|
|
|
|
' resetSeekbarThumb: Resets the thumb to the playing position
|
|
'
|
|
sub resetSeekbarThumb()
|
|
m.scrubTimestamp = -1
|
|
moveSeekbarThumb(m.playPosition.width)
|
|
end sub
|
|
|
|
' moveSeekbarThumb: Positions the thumb on the seekbar
|
|
'
|
|
' @param {float} playPositionBarWidth - width of the play position bar
|
|
sub moveSeekbarThumb(playPositionBarWidth as float)
|
|
' Center the thumb on the play position bar
|
|
thumbPostionLeft = playPositionBarWidth - 10
|
|
|
|
' Don't let thumb go below 0
|
|
if thumbPostionLeft < 0 then thumbPostionLeft = 0
|
|
|
|
' Don't let thumb go past end of seekbar
|
|
if thumbPostionLeft > m.seekBar.width - 25
|
|
thumbPostionLeft = m.seekBar.width - 25
|
|
end if
|
|
|
|
' Move the thumb
|
|
m.thumb.translation = [thumbPostionLeft, m.thumb.translation[1]]
|
|
|
|
' Move the seek position element so it follows the thumb
|
|
m.seekPosition.translation = [720 + thumbPostionLeft - (m.seekPosition.width / 2), m.seekPosition.translation[1]]
|
|
end sub
|
|
|
|
' exitScrubMode: Moves player out of scrub mode state, resets back to standard play mode
|
|
'
|
|
sub exitScrubMode()
|
|
m.buttons.setFocus(true)
|
|
m.thumb.setFocus(false)
|
|
|
|
if m.seekPosition.visible
|
|
m.seekPosition.visible = false
|
|
end if
|
|
|
|
resetSeekbarThumb()
|
|
|
|
m.inScrubMode = false
|
|
m.thumb.visible = false
|
|
setSelectedButtonState("-default", "-selected")
|
|
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
|
|
|
|
' Key Event handler when m.thumb is in focus
|
|
if m.thumb.hasFocus()
|
|
if key = "right"
|
|
m.inScrubMode = true
|
|
processScrubAction(10)
|
|
return true
|
|
end if
|
|
|
|
if key = "left"
|
|
m.inScrubMode = true
|
|
processScrubAction(-10)
|
|
return true
|
|
end if
|
|
|
|
if key = "OK" or key = "play"
|
|
if m.inScrubMode
|
|
startLoadingSpinner()
|
|
m.inScrubMode = false
|
|
m.global.audioPlayer.seek = m.scrubTimestamp
|
|
return true
|
|
end if
|
|
|
|
return playAction()
|
|
end if
|
|
end if
|
|
|
|
if key = "play"
|
|
return playAction()
|
|
end if
|
|
|
|
if key = "up"
|
|
if not m.thumb.visible
|
|
m.thumb.visible = true
|
|
setSelectedButtonState("-selected", "-default")
|
|
end if
|
|
if not m.seekPosition.visible
|
|
m.seekPosition.visible = true
|
|
end if
|
|
|
|
m.thumb.setFocus(true)
|
|
m.buttons.setFocus(false)
|
|
return true
|
|
end if
|
|
|
|
if key = "down"
|
|
if m.thumb.visible
|
|
exitScrubMode()
|
|
end if
|
|
return true
|
|
end if
|
|
|
|
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.buttons.hasFocus()
|
|
if m.global.queueManager.callFunc("getCount") = 1 then return false
|
|
|
|
if m.top.selectedButtonIndex > 0
|
|
m.previouslySelectedButtonIndex = m.top.selectedButtonIndex
|
|
m.top.selectedButtonIndex = m.top.selectedButtonIndex - 1
|
|
end if
|
|
return true
|
|
end if
|
|
else if key = "right"
|
|
if m.buttons.hasFocus()
|
|
if m.global.queueManager.callFunc("getCount") = 1 then return false
|
|
|
|
m.previouslySelectedButtonIndex = m.top.selectedButtonIndex
|
|
if m.top.selectedButtonIndex < m.buttonCount - 1 then m.top.selectedButtonIndex = m.top.selectedButtonIndex + 1
|
|
return true
|
|
end if
|
|
else if key = "OK"
|
|
if m.buttons.hasFocus()
|
|
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
|
|
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
|
|
</code></pre></article></section><footer class="footer" id="PeOAagUepe"><div class="wrapper"><span class="jsdoc-message">Automatically generated using <a href="https://github.com/jsdoc/jsdoc" target="_blank">JSDoc</a> and the <a href="https://github.com/ankitskvmdam/clean-jsdoc-theme" target="_blank">clean-jsdoc-theme</a>.</span></div></footer></div></div></div><div class="search-container" id="PkfLWpAbet" style="display:none"><div class="wrapper" id="iCxFxjkHbP"><button class="icon-button search-close-button" id="VjLlGakifb" aria-label="close search"><svg><use xlink:href="#close-icon"></use></svg></button><div class="search-box-c"><svg><use xlink:href="#search-icon"></use></svg> <input type="text" id="vpcKVYIppa" class="search-input" placeholder="Search..." autofocus></div><div class="search-result-c" id="fWwVHRuDuN"><span class="search-result-c-text">Type anything to view search result</span></div></div></div><div class="mobile-menu-icon-container"><button class="icon-button" id="mobile-menu" data-isopen="false" aria-label="menu"><svg><use xlink:href="#menu-icon"></use></svg></button></div><div id="mobile-sidebar" class="mobile-sidebar-container"><div class="mobile-sidebar-wrapper"><a href="/" class="sidebar-title sidebar-title-anchor">jellyfin-roku Code Documentation</a><div class="mobile-nav-links"><div class="external-link navbar-item"><a id="jellyfin-link-mobile" href="https://jellyfin.org/" target="_blank">Jellyfin</a></div><div class="external-link navbar-item"><a id="github-link-mobile" href="https://github.com/jellyfin/jellyfin-roku" target="_blank">GitHub</a></div><div class="external-link navbar-item"><a id="forum-link-mobile" href="https://forum.jellyfin.org/f-roku-development" target="_blank">Forum</a></div><div class="external-link navbar-item"><a id="matrix-link-mobile" href="https://matrix.to/#/#jellyfin-dev-roku:matrix.org" target="_blank">Matrix</a></div></div><div class="mobile-sidebar-items-c"><div class="sidebar-section-title with-arrow" data-isopen="false" id="sidebar-modules"><div>Modules</div><svg><use xlink:href="#down-icon"></use></svg></div><div class="sidebar-section-children-container"><div class="sidebar-section-children"><a href="module-AlbumData.html">AlbumData</a></div><div class="sidebar-section-children"><a href="module-AlbumGrid.html">AlbumGrid</a></div><div class="sidebar-section-children"><a href="module-AlbumTrackList.html">AlbumTrackList</a></div><div class="sidebar-section-children"><a href="module-AlbumView.html">AlbumView</a></div><div class="sidebar-section-children"><a href="module-Alpha.html">Alpha</a></div><div class="sidebar-section-children"><a href="module-ArtistView.html">ArtistView</a></div><div class="sidebar-section-children"><a href="module-AudioPlayer.html">AudioPlayer</a></div><div class="sidebar-section-children"><a href="module-AudioPlayerView.html">AudioPlayerView</a></div><div class="sidebar-section-children"><a href="module-AudioTrackListItem.html">AudioTrackListItem</a></div><div class="sidebar-section-children"><a href="module-ButtonGroupHoriz.html">ButtonGroupHoriz</a></div><div class="sidebar-section-children"><a href="module-ButtonGroupVert.html">ButtonGroupVert</a></div><div class="sidebar-section-children"><a href="module-ChannelData.html">ChannelData</a></div><div class="sidebar-section-children"><a href="module-Clock.html">Clock</a></div><div class="sidebar-section-children"><a href="module-CollectionData.html">CollectionData</a></div><div class="sidebar-section-children"><a href="module-ConfigData.html">ConfigData</a></div><div class="sidebar-section-children"><a href="module-ConfigItem.html">ConfigItem</a></div><div class="sidebar-section-children"><a href="module-ConfigList.html">ConfigList</a></div><div class="sidebar-section-children"><a href="module-ExtrasItem.html">ExtrasItem</a></div><div class="sidebar-section-children"><a href="module-ExtrasRowList.html">ExtrasRowList</a></div><div class="sidebar-section-children"><a href="module-FavoriteItemsTask.html">FavoriteItemsTask</a></div><div class="sidebar-section-children"><a href="module-FolderData.html">FolderData</a></div><div class="sidebar-section-children"><a href="module-GetFiltersTask.html">GetFiltersTask</a></div><div class="sidebar-section-children"><a href="module-GetNextEpisodeTask.html">GetNextEpisodeTask</a></div><div class="sidebar-section-children"><a href="module-GetPlaybackInfoTask.html">GetPlaybackInfoTask</a></div><div class="sidebar-section-children"><a href="module-GetShuffleEpisodesTask.html">GetShuffleEpisodesTask</a></div><div class="sidebar-section-children"><a href="module-GridItem.html">GridItem</a></div><div class="sidebar-section-children"><a href="module-GridItemSmall.html">GridItemSmall</a></div><div class="sidebar-section-children"><a href="module-Home.html">Home</a></div><div class="sidebar-section-children"><a href="module-HomeData.html">HomeData</a></div><div class="sidebar-section-children"><a href="module-HomeItem.html">HomeItem</a></div><div class="sidebar-section-children"><a href="module-HomeRowItemSizes.html">HomeRowItemSizes</a></div><div class="sidebar-section-children"><a href="module-HomeRows.html">HomeRows</a></div><div class="sidebar-section-children"><a href="module-IconButton.html">IconButton</a></div><div class="sidebar-section-children"><a href="module-Image.html">Image</a></div><div class="sidebar-section-children"><a href="module-ImageData.html">ImageData</a></div><div class="sidebar-section-children"><a href="module-IntegerKeyboard.html">IntegerKeyboard</a></div><div class="sidebar-section-children"><a href="module-ItemGrid.html">ItemGrid</a></div><div class="sidebar-section-children"><a href="module-ItemGridOptions.html">ItemGridOptions</a></div><div class="sidebar-section-children"><a href="module-Items.html">Items</a></div><div class="sidebar-section-children"><a href="module-JFButton.html">JFButton</a></div><div class="sidebar-section-children"><a href="module-JFButtons.html">JFButtons</a></div><div class="sidebar-section-children"><a href="module-JFGroup.html">JFGroup</a></div><div class="sidebar-section-children"><a href="module-JFMessageDialog.html">JFMessageDialog</a></div><div class="sidebar-section-children"><a href="module-JFOverhang.html">JFOverhang</a></div><div class="sidebar-section-children"><a href="module-JFScene.html">JFScene</a></div><div class="sidebar-section-children"><a href="module-JFScreen.html">JFScreen</a></div><div class="sidebar-section-children"><a href="module-JFServer.html">JFServer</a></div><div class="sidebar-section-children"><a href="module-JFVideo.html">JFVideo</a></div><div class="sidebar-section-children"><a href="module-ListPoster.html">ListPoster</a></div><div class="sidebar-section-children"><a href="module-LoadChannelsTask.html">LoadChannelsTask</a></div><div class="sidebar-section-children"><a href="module-LoadItemsTask.html">LoadItemsTask</a></div><div class="sidebar-section-children"><a href="module-LoadItemsTask2.html">LoadItemsTask2</a></div><div class="sidebar-section-children"><a href="module-LoadPhotoTask.html">LoadPhotoTask</a></div><div class="sidebar-section-children"><a href="module-LoadProgramDetailsTask.html">LoadProgramDetailsTask</a></div><div class="sidebar-section-children"><a href="module-LoadScreenSaverTimeoutTask.html">LoadScreenSaverTimeoutTask</a></div><div class="sidebar-section-children"><a href="module-LoadSheduleTask.html">LoadSheduleTask</a></div><div class="sidebar-section-children"><a href="module-LoadVideoContentTask.html">LoadVideoContentTask</a></div><div class="sidebar-section-children"><a href="module-LoginScene.html">LoginScene</a></div><div class="sidebar-section-children"><a href="module-Main.html">Main</a></div><div class="sidebar-section-children"><a href="module-MovieData.html">MovieData</a></div><div class="sidebar-section-children"><a href="module-MovieDetails.html">MovieDetails</a></div><div class="sidebar-section-children"><a href="module-MovieLibraryView.html">MovieLibraryView</a></div><div class="sidebar-section-children"><a href="module-MovieOptions.html">MovieOptions</a></div><div class="sidebar-section-children"><a href="module-MusicAlbumData.html">MusicAlbumData</a></div><div class="sidebar-section-children"><a href="module-MusicAlbumSongListData.html">MusicAlbumSongListData</a></div><div class="sidebar-section-children"><a href="module-MusicArtistData.html">MusicArtistData</a></div><div class="sidebar-section-children"><a href="module-MusicArtistGridItem.html">MusicArtistGridItem</a></div><div class="sidebar-section-children"><a href="module-MusicLibraryView.html">MusicLibraryView</a></div><div class="sidebar-section-children"><a href="module-MusicSongData.html">MusicSongData</a></div><div class="sidebar-section-children"><a href="module-OSD.html">OSD</a></div><div class="sidebar-section-children"><a href="module-OptionNode.html">OptionNode</a></div><div class="sidebar-section-children"><a href="module-OptionsButton.html">OptionsButton</a></div><div class="sidebar-section-children"><a href="module-OptionsData.html">OptionsData</a></div><div class="sidebar-section-children"><a href="module-OptionsSlider.html">OptionsSlider</a></div><div class="sidebar-section-children"><a href="module-OverviewDialog.html">OverviewDialog</a></div><div class="sidebar-section-children"><a href="module-PersonData.html">PersonData</a></div><div class="sidebar-section-children"><a href="module-PersonDetails.html">PersonDetails</a></div><div class="sidebar-section-children"><a href="module-PhotoData.html">PhotoData</a></div><div class="sidebar-section-children"><a href="module-PhotoDetails.html">PhotoDetails</a></div><div class="sidebar-section-children"><a href="module-PlaybackDialog.html">PlaybackDialog</a></div><div class="sidebar-section-children"><a href="module-PlayedCheckmark.html">PlayedCheckmark</a></div><div class="sidebar-section-children"><a href="module-PlaylistData.html">PlaylistData</a></div><div class="sidebar-section-children"><a href="module-PlaylistView.html">PlaylistView</a></div><div class="sidebar-section-children"><a href="module-PlaystateTask.html">PlaystateTask</a></div><div class="sidebar-section-children"><a href="module-PostTask.html">PostTask</a></div><div class="sidebar-section-children"><a href="module-ProgramDetails.html">ProgramDetails</a></div><div class="sidebar-section-children"><a href="module-PublicUserData.html">PublicUserData</a></div><div class="sidebar-section-children"><a href="module-QueueManager.html">QueueManager</a></div><div class="sidebar-section-children"><a href="module-QuickConnect.html">QuickConnect</a></div><div class="sidebar-section-children"><a href="module-QuickConnectDialog.html">QuickConnectDialog</a></div><div class="sidebar-section-children"><a href="module-RadioDialog.html">RadioDialog</a></div><div class="sidebar-section-children"><a href="module-RecordProgramTask.html">RecordProgramTask</a></div><div class="sidebar-section-children"><a href="module-SceneManager.html">SceneManager</a></div><div class="sidebar-section-children"><a href="module-ScheduleProgramData.html">ScheduleProgramData</a></div><div class="sidebar-section-children"><a href="module-SearchBox.html">SearchBox</a></div><div class="sidebar-section-children"><a href="module-SearchData.html">SearchData</a></div><div class="sidebar-section-children"><a href="module-SearchResults.html">SearchResults</a></div><div class="sidebar-section-children"><a href="module-SearchRow.html">SearchRow</a></div><div class="sidebar-section-children"><a href="module-SearchTask.html">SearchTask</a></div><div class="sidebar-section-children"><a href="module-SeriesData.html">SeriesData</a></div><div class="sidebar-section-children"><a href="module-ServerDiscoveryTask.html">ServerDiscoveryTask</a></div><div class="sidebar-section-children"><a href="module-SetServerScreen.html">SetServerScreen</a></div><div class="sidebar-section-children"><a href="module-ShowScenes.html">ShowScenes</a></div><div class="sidebar-section-children"><a href="module-SlideOutButton.html">SlideOutButton</a></div><div class="sidebar-section-children"><a href="module-SongItem.html">SongItem</a></div><div class="sidebar-section-children"><a href="module-Spinner.html">Spinner</a></div><div class="sidebar-section-children"><a href="module-StandardDialog.html">StandardDialog</a></div><div class="sidebar-section-children"><a href="module-Subtitles.html">Subtitles</a></div><div class="sidebar-section-children"><a href="module-TVEpisode.html">TVEpisode</a></div><div class="sidebar-section-children"><a href="module-TVEpisodeData.html">TVEpisodeData</a></div><div class="sidebar-section-children"><a href="module-TVEpisodeRow.html">TVEpisodeRow</a></div><div class="sidebar-section-children"><a href="module-TVEpisodeRowWithOptions.html">TVEpisodeRowWithOptions</a></div><div class="sidebar-section-children"><a href="module-TVEpisodes.html">TVEpisodes</a></div><div class="sidebar-section-children"><a href="module-TVListDetails.html">TVListDetails</a></div><div class="sidebar-section-children"><a href="module-TVListOptions.html">TVListOptions</a></div><div class="sidebar-section-children"><a href="module-TVSeasonData.html">TVSeasonData</a></div><div class="sidebar-section-children"><a href="module-TVSeasonRow.html">TVSeasonRow</a></div><div class="sidebar-section-children"><a href="module-TVShowDescription.html">TVShowDescription</a></div><div class="sidebar-section-children"><a href="module-TVShowDetails.html">TVShowDetails</a></div><div class="sidebar-section-children"><a href="module-TextSizeTask.html">TextSizeTask</a></div><div class="sidebar-section-children"><a href="module-UserData.html">UserData</a></div><div class="sidebar-section-children"><a href="module-UserItem.html">UserItem</a></div><div class="sidebar-section-children"><a href="module-UserLibrary.html">UserLibrary</a></div><div class="sidebar-section-children"><a href="module-UserRow.html">UserRow</a></div><div class="sidebar-section-children"><a href="module-UserSelect.html">UserSelect</a></div><div class="sidebar-section-children"><a href="module-VideoData.html">VideoData</a></div><div class="sidebar-section-children"><a href="module-VideoPlayer.html">VideoPlayer</a></div><div class="sidebar-section-children"><a href="module-VideoPlayerView.html">VideoPlayerView</a></div><div class="sidebar-section-children"><a href="module-VideoTrackListItem.html">VideoTrackListItem</a></div><div class="sidebar-section-children"><a href="module-ViewCreator.html">ViewCreator</a></div><div class="sidebar-section-children"><a href="module-WhatsNewDialog.html">WhatsNewDialog</a></div><div class="sidebar-section-children"><a href="module-baserequest.html">baserequest</a></div><div class="sidebar-section-children"><a href="module-captionTask.html">captionTask</a></div><div class="sidebar-section-children"><a href="module-conditional.html">conditional</a></div><div class="sidebar-section-children"><a href="module-config.html">config</a></div><div class="sidebar-section-children"><a href="module-deviceCapabilities.html">deviceCapabilities</a></div><div class="sidebar-section-children"><a href="module-globals.html">globals</a></div><div class="sidebar-section-children"><a href="module-homeRowItemSizes_.html">homeRowItemSizes</a></div><div class="sidebar-section-children"><a href="module-migrations.html">migrations</a></div><div class="sidebar-section-children"><a href="module-misc.html">misc</a></div><div class="sidebar-section-children"><a href="module-quickplay.html">quickplay</a></div><div class="sidebar-section-children"><a href="module-schedule.html">schedule</a></div><div class="sidebar-section-children"><a href="module-section.html">section</a></div><div class="sidebar-section-children"><a href="module-sectionScroller.html">sectionScroller</a></div><div class="sidebar-section-children"><a href="module-settings.html">settings</a></div><div class="sidebar-section-children"><a href="module-userauth.html">userauth</a></div></div></div><div class="mobile-navbar-actions"><div class="navbar-right-item"><button class="icon-button search-button" aria-label="open-search"><svg><use xlink:href="#search-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button theme-toggle" aria-label="toggle-theme"><svg><use class="theme-svg-use" xlink:href="#dark-theme-icon"></use></svg></button></div><div class="navbar-right-item"><button class="icon-button font-size" aria-label="change-font-size"><svg><use xlink:href="#font-size-icon"></use></svg></button></div></div></div></div><script type="text/javascript" src="scripts/core.min.js"></script><script src="scripts/search.min.js" defer="defer"></script><script src="scripts/third-party/fuse.js" defer="defer"></script><script type="text/javascript">var tocbotInstance=tocbot.init({tocSelector:"#eed4d2a0bfd64539bb9df78095dec881",contentSelector:".main-content",headingSelector:"h1, h2, h3",hasInnerContainers:!0,scrollContainer:".main-content",headingsOffset:130,onClick:bringLinkToView})</script></body></html> |