Audio playback speedup
This commit is contained in:
parent
86edf371d3
commit
071b814568
|
@ -152,6 +152,12 @@ sub loadItems()
|
|||
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
|
||||
|
|
|
@ -1,29 +1,41 @@
|
|||
sub init()
|
||||
m.top.optionsAvailable = false
|
||||
|
||||
setupMainNode()
|
||||
setupAudioNode()
|
||||
setupButtons()
|
||||
setupInfoNodes()
|
||||
end sub
|
||||
|
||||
sub setupMainNode()
|
||||
main = m.top.findNode("toplevel")
|
||||
main.translation = [96, 175]
|
||||
m.LoadMetaDataTask = CreateObject("roSGNode", "LoadItemsTask")
|
||||
m.LoadMetaDataTask.itemsToLoad = "metaData"
|
||||
|
||||
m.LoadBackdropImageTask = CreateObject("roSGNode", "LoadItemsTask")
|
||||
m.LoadBackdropImageTask.itemsToLoad = "backdropImage"
|
||||
|
||||
m.LoadAudioStreamTask = CreateObject("roSGNode", "LoadItemsTask")
|
||||
m.LoadAudioStreamTask.itemsToLoad = "audioStream"
|
||||
|
||||
m.currentSongIndex = 0
|
||||
m.buttonsNeedToBeLoaded = true
|
||||
end sub
|
||||
|
||||
sub setupAudioNode()
|
||||
m.top.audio = createObject("RoSGNode", "Audio")
|
||||
m.top.audio.observeField("contentIndex", "audioIndexChanged")
|
||||
m.top.audio.observeField("state", "audioStateChanged")
|
||||
end sub
|
||||
|
||||
sub setupButtons()
|
||||
m.buttons = m.top.findNode("buttons")
|
||||
m.buttons.buttons = [tr("Previous"), tr("Play/Pause"), tr("Next")]
|
||||
m.top.observeField("selectedButtonIndex", "selectedButtonChanged")
|
||||
m.previouslySelectedButtonIndex = 1
|
||||
m.top.selectedButtonIndex = 1
|
||||
end sub
|
||||
|
||||
m.buttons.selectedIndex = 1
|
||||
m.buttons.focusedIndex = 1
|
||||
m.buttons.setFocus(true)
|
||||
sub selectedButtonChanged()
|
||||
selectedButton = m.buttons.getChild(m.previouslySelectedButtonIndex)
|
||||
selectedButton.uri = selectedButton.uri.Replace("-selected", "-default")
|
||||
|
||||
selectedButton = m.buttons.getChild(m.top.selectedButtonIndex)
|
||||
selectedButton.uri = selectedButton.uri.Replace("-default", "-selected")
|
||||
end sub
|
||||
|
||||
sub setupInfoNodes()
|
||||
|
@ -31,8 +43,16 @@ sub setupInfoNodes()
|
|||
m.backDrop = m.top.findNode("backdrop")
|
||||
end sub
|
||||
|
||||
sub audioIndexChanged()
|
||||
pageContentChanged()
|
||||
sub audioStateChanged()
|
||||
' Song Finished, attempt to move to next song
|
||||
if m.top.audio.state = "finished"
|
||||
if m.currentSongIndex < m.top.pageContent.count() - 1
|
||||
LoadNextSong()
|
||||
else
|
||||
' Return to previous screen
|
||||
m.top.state = "finished"
|
||||
end if
|
||||
end if
|
||||
end sub
|
||||
|
||||
function playAction() as boolean
|
||||
|
@ -46,33 +66,80 @@ function playAction() as boolean
|
|||
end function
|
||||
|
||||
function previousClicked() as boolean
|
||||
if m.top.audio.contentIndex > 0
|
||||
m.top.audio.nextContentIndex = m.top.audio.contentIndex - 1
|
||||
m.top.audio.control = "skipcontent"
|
||||
if m.currentSongIndex > 0
|
||||
m.currentSongIndex--
|
||||
pageContentChanged()
|
||||
end if
|
||||
|
||||
return true
|
||||
end function
|
||||
|
||||
function nextClicked() as boolean
|
||||
if m.top.audio.contentIsPlaylist
|
||||
m.top.audio.control = "skipcontent"
|
||||
if m.currentSongIndex < m.top.pageContent.count() - 1
|
||||
LoadNextSong()
|
||||
end if
|
||||
|
||||
return true
|
||||
end function
|
||||
|
||||
sub LoadNextSong()
|
||||
m.currentSongIndex++
|
||||
pageContentChanged()
|
||||
end sub
|
||||
|
||||
' Update values on screen when page content changes
|
||||
sub pageContentChanged()
|
||||
' If audio isn't playing yet, skip because we have nothing to update
|
||||
if m.top.audio.contentIndex = -1 then return
|
||||
m.LoadMetaDataTask.itemId = m.top.pageContent[m.currentSongIndex]
|
||||
m.LoadMetaDataTask.observeField("content", "onMetaDataLoaded")
|
||||
m.LoadMetaDataTask.control = "RUN"
|
||||
|
||||
item = m.top.pageContent[m.top.audio.contentIndex]
|
||||
m.LoadAudioStreamTask.itemId = m.top.pageContent[m.currentSongIndex]
|
||||
m.LoadAudioStreamTask.observeField("content", "onAudioStreamLoaded")
|
||||
m.LoadAudioStreamTask.control = "RUN"
|
||||
end sub
|
||||
|
||||
setPosterImage(item.posterURL)
|
||||
setScreenTitle(item.json)
|
||||
setOnScreenTextValues(item.json)
|
||||
setBackdropImage()
|
||||
sub onAudioStreamLoaded()
|
||||
data = m.LoadAudioStreamTask.content[0]
|
||||
m.LoadAudioStreamTask.unobserveField("content")
|
||||
if data <> invalid and data.count() > 0
|
||||
m.top.audio.content = data
|
||||
m.top.audio.control = "stop"
|
||||
m.top.audio.control = "none"
|
||||
m.top.audio.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 data <> invalid and data.count() > 0
|
||||
|
||||
' Use metadata to load backdrop image
|
||||
m.LoadBackdropImageTask.itemId = data.json.ArtistItems[0].id
|
||||
m.LoadBackdropImageTask.observeField("content", "onBackdropImageLoaded")
|
||||
m.LoadBackdropImageTask.control = "RUN"
|
||||
|
||||
setPosterImage(data.posterURL)
|
||||
setScreenTitle(data.json)
|
||||
setOnScreenTextValues(data.json)
|
||||
|
||||
' If we have more and 1 song to play, fade in the next and previous controls
|
||||
if m.buttonsNeedToBeLoaded
|
||||
if m.top.pageContent.count() > 1
|
||||
m.floatanimation = m.top.FindNode("displayButtonsAnimation")
|
||||
m.floatanimation.control = "start"
|
||||
end if
|
||||
m.buttonsNeedToBeLoaded = false
|
||||
end if
|
||||
end if
|
||||
end sub
|
||||
|
||||
' Set poster image on screen
|
||||
|
@ -107,18 +174,17 @@ end sub
|
|||
' Populate on screen text variables
|
||||
sub setOnScreenTextValues(json)
|
||||
if isValid(json)
|
||||
setFieldTextValue("numberofsongs", "Track " + stri(m.top.audio.contentIndex + 1) + "/" + stri(m.top.pageContent.count()))
|
||||
setFieldTextValue("numberofsongs", "Track " + stri(m.currentSongIndex + 1) + "/" + stri(m.top.pageContent.count()))
|
||||
setFieldTextValue("artist", json.Artists[0])
|
||||
setFieldTextValue("album", json.album)
|
||||
setFieldTextValue("song", json.name)
|
||||
end if
|
||||
end sub
|
||||
|
||||
' Add backdrop image to screen
|
||||
sub setBackdropImage()
|
||||
if isValid(m.top.backgroundContent[m.top.audio.contentIndex])
|
||||
if m.backDrop.uri <> m.top.backgroundContent[m.top.audio.contentIndex]
|
||||
m.backDrop.uri = m.top.backgroundContent[m.top.audio.contentIndex]
|
||||
sub setBackdropImage(data)
|
||||
if isValid(data)
|
||||
if m.backDrop.uri <> data
|
||||
m.backDrop.uri = data
|
||||
end if
|
||||
end if
|
||||
end sub
|
||||
|
@ -136,19 +202,26 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
return previousClicked()
|
||||
else if key = "fastforward"
|
||||
return nextClicked()
|
||||
end if
|
||||
else if key = "left"
|
||||
if m.top.pageContent.count() = 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
|
||||
else if key = "right"
|
||||
if m.top.pageContent.count() = 1 then return false
|
||||
|
||||
return false
|
||||
end if
|
||||
|
||||
' Key bindings for button group
|
||||
if m.buttons.hasFocus()
|
||||
if key = "OK"
|
||||
if m.buttons.buttons[m.buttons.focusedIndex] = tr("Play/Pause")
|
||||
m.previouslySelectedButtonIndex = m.top.selectedButtonIndex
|
||||
if m.top.selectedButtonIndex < 2 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.buttons[m.buttons.focusedIndex] = tr("Previous")
|
||||
else if m.buttons.getChild(m.top.selectedButtonIndex).id = "previous"
|
||||
return previousClicked()
|
||||
else if m.buttons.buttons[m.buttons.focusedIndex] = tr("Next")
|
||||
else if m.buttons.getChild(m.top.selectedButtonIndex).id = "next"
|
||||
return nextClicked()
|
||||
end if
|
||||
end if
|
||||
|
|
|
@ -1,28 +1,34 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<component name="NowPlaying" extends="JFGroup">
|
||||
<children>
|
||||
<Poster id="backdrop" opacity=".5" loadDisplayMode="scaleToZoom" width="2000" height="1200" blendColor="#3f3f3f" />
|
||||
<LayoutGroup id="toplevel" layoutDirection="vert" itemSpacings="[-10]" >
|
||||
<LayoutGroup id="main_group" layoutDirection="horiz" itemSpacings="[15]" >
|
||||
<LayoutGroup layoutDirection="vert" itemSpacings="[15]">
|
||||
<Poster id="albumCover" width="450" height="450" />
|
||||
<Label id="numberofsongs" width="450" height="25" horizAlign="left" />
|
||||
</LayoutGroup>
|
||||
<LayoutGroup layoutDirection="vert" horizAlignment="left" itemSpacings="[15]">
|
||||
<Label id="artist" width="450" height="25" horizAlign="left" />
|
||||
<Label id="song" width="450" height="25" horizAlign="left" />
|
||||
<Label id="album" width="450" height="25" horizAlign="left" />
|
||||
<LayoutGroup id="controlButtons" layoutDirection="horiz" itemSpacings="[15]">
|
||||
<JFButtons id="buttons" />
|
||||
</LayoutGroup>
|
||||
</LayoutGroup>
|
||||
<Poster id="backdrop" opacity=".5" loadDisplayMode="scaleToZoom" width="1920" height="1200" blendColor="#3f3f3f" />
|
||||
<LayoutGroup id="toplevel" layoutDirection="vert" horizAlignment="center" translation="[900,175]" itemSpacings="[40]">
|
||||
<LayoutGroup id="main_group" layoutDirection="vert" horizAlignment="center" itemSpacings="[15]">
|
||||
<Poster id="albumCover" width="500" height="500" />
|
||||
<Label id="artist" width="900" height="25" horizAlign="center" />
|
||||
<Label id="song" width="900" height="25" horizAlign="center" />
|
||||
<Label id="numberofsongs" width="500" height="25" horizAlign="center" font="font:SmallestSystemFont" color="#999999" />
|
||||
</LayoutGroup>
|
||||
<LayoutGroup id="buttons" layoutDirection="horiz" horizAlignment="center" itemSpacings="[45]">
|
||||
<Poster id="previous" width="64" height="64" uri="pkg:/images/icons/previous-default.png" opacity="0" />
|
||||
<Poster id="play" width="64" height="64" uri="pkg:/images/icons/play-default.png" />
|
||||
<Poster id="next" width="64" height="64" uri="pkg:/images/icons/next-default.png" opacity="0" />
|
||||
</LayoutGroup>
|
||||
<Animation id="displayButtonsAnimation" duration="1" repeat="false" easeFunction="linear">
|
||||
<FloatFieldInterpolator key="[0.0, 1.0]" keyValue="[0.0, 1.0]" fieldToInterp="previous.opacity" />
|
||||
<FloatFieldInterpolator key="[0.0, 1.0]" keyValue="[0.0, 1.0]" fieldToInterp="next.opacity" />
|
||||
</Animation>
|
||||
</LayoutGroup>
|
||||
<!-- Preload selected icons to prevent flicker -->
|
||||
<Poster width="0" height="0" uri="pkg:/images/icons/previous-selected.png" visible="false" />
|
||||
<Poster width="0" height="0" uri="pkg:/images/icons/play-selected.png" visible="false" />
|
||||
<Poster width="0" height="0" uri="pkg:/images/icons/next-selected.png" visible="false" />
|
||||
</children>
|
||||
<interface>
|
||||
<field id="backgroundContent" type="array" />
|
||||
<field id="pageContent" type="nodearray" onChange="pageContentChanged" />
|
||||
<field id="pageContent" type="array" onChange="pageContentChanged" />
|
||||
<field id="audio" type="node" />
|
||||
<field id="state" type="string" />
|
||||
<field id="selectedButtonIndex" type="integer" />
|
||||
</interface>
|
||||
<script type="text/brightscript" uri="pkg:/source/utils/misc.brs" />
|
||||
<script type="text/brightscript" uri="NowPlaying.brs" />
|
||||
|
|
BIN
images/icons/next-default.png
Executable file
BIN
images/icons/next-default.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
images/icons/next-selected.png
Executable file
BIN
images/icons/next-selected.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
images/icons/play-default.png
Executable file
BIN
images/icons/play-default.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
images/icons/play-selected.png
Executable file
BIN
images/icons/play-selected.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
images/icons/previous-default.png
Executable file
BIN
images/icons/previous-default.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
images/icons/previous-selected.png
Executable file
BIN
images/icons/previous-selected.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
|
@ -159,7 +159,7 @@ sub Main (args as dynamic) as void
|
|||
else if selectedItem.type = "MusicAlbum"
|
||||
group = CreateMusicAlbumDetailsGroup(selectedItem.json)
|
||||
else if selectedItem.type = "Audio"
|
||||
group = CreateAudioPlayerGroup(selectedItem.json)
|
||||
group = CreateAudioPlayerGroup([selectedItem.json])
|
||||
else
|
||||
' TODO - switch on more node types
|
||||
message_dialog("This type is not yet supported: " + selectedItem.type + ".")
|
||||
|
@ -190,7 +190,7 @@ sub Main (args as dynamic) as void
|
|||
' User has selected audio they want us to play
|
||||
selectedIndex = msg.getData()
|
||||
screenContent = msg.getRoSGNode()
|
||||
group = CreateAudioPlayerGroup(screenContent.albumData.items[selectedIndex])
|
||||
group = CreateAudioPlayerGroup([screenContent.albumData.items[selectedIndex]])
|
||||
else if isNodeEvent(msg, "playAllSelected")
|
||||
' User has selected playlist of of audio they want us to play
|
||||
screenContent = msg.getRoSGNode()
|
||||
|
|
|
@ -418,82 +418,16 @@ end function
|
|||
function CreateAudioPlayerGroup(audiodata)
|
||||
|
||||
group = CreateObject("roSGNode", "NowPlaying")
|
||||
songMetaDataArray = CreateObject("roArray", 0, true)
|
||||
songBackdropArray = CreateObject("roArray", 0, true)
|
||||
content = createObject("RoSGNode", "ContentNode")
|
||||
group.observeField("state", m.port)
|
||||
songIDArray = CreateObject("roArray", 0, true)
|
||||
|
||||
if type(audiodata) = "roArray"
|
||||
' Passed data is an array of audio, setup playback as a playlist
|
||||
|
||||
group.audio.contentIsPlaylist = true
|
||||
|
||||
audioPlaylistContent = createObject("RoSGNode", "ContentNode")
|
||||
|
||||
for each song in audiodata
|
||||
songContent = audioPlaylistContent.CreateChild("ContentNode")
|
||||
songData = AudioItem(song.id)
|
||||
|
||||
songMetaDataArray.push(ItemMetaData(song.id))
|
||||
imgParams = { "maxHeight": "720", "maxWidth": "1280" }
|
||||
|
||||
if isValid(song.json.ArtistItems[0])
|
||||
songBackdropArray.push(ImageURL(song.json.ArtistItems[0].id, "Backdrop", imgParams))
|
||||
end if
|
||||
|
||||
params = {}
|
||||
|
||||
params.append({
|
||||
"Static": "true",
|
||||
"Container": songData.mediaSources[0].container,
|
||||
})
|
||||
|
||||
params.MediaSourceId = songData.mediaSources[0].id
|
||||
|
||||
songContent.url = buildURL(Substitute("Audio/{0}/stream", song.id), params)
|
||||
songContent.title = song.title
|
||||
songContent.streamformat = songData.mediaSources[0].container
|
||||
end for
|
||||
|
||||
content = audioPlaylistContent
|
||||
|
||||
else if type(audiodata) = "roSGNode"
|
||||
' Passed data is a single node
|
||||
|
||||
if audiodata.subtype() = "MusicSongData"
|
||||
' Passed data is data for a single song, setup playback as a single song
|
||||
|
||||
songData = AudioItem(audiodata.id)
|
||||
|
||||
songMetaDataArray.push(ItemMetaData(audiodata.id))
|
||||
imgParams = { "maxHeight": "720", "maxWidth": "1280" }
|
||||
|
||||
if isValid(audiodata.json.ArtistItems[0])
|
||||
songBackdropArray.push(ImageURL(audiodata.json.ArtistItems[0].id, "Backdrop", imgParams))
|
||||
end if
|
||||
|
||||
params = {}
|
||||
|
||||
params.append({
|
||||
"Static": "true",
|
||||
"Container": songData.mediaSources[0].container,
|
||||
})
|
||||
|
||||
params.MediaSourceId = songData.mediaSources[0].id
|
||||
|
||||
content.url = buildURL(Substitute("Audio/{0}/stream", audiodata.id), params)
|
||||
content.title = audiodata.title
|
||||
content.streamformat = songData.mediaSources[0].container
|
||||
end if
|
||||
end if
|
||||
|
||||
group.backgroundContent = songBackdropArray
|
||||
group.pageContent = songMetaDataArray
|
||||
' All we need is an array of Song IDs the user selected to play.
|
||||
for each song in audiodata
|
||||
songIDArray.push(song.id)
|
||||
end for
|
||||
|
||||
group.pageContent = songIDArray
|
||||
group.musicArtistAlbumData = audiodata
|
||||
group.audio.content = content
|
||||
group.audio.control = "stop"
|
||||
group.audio.control = "none"
|
||||
group.audio.control = "play"
|
||||
|
||||
m.global.sceneManager.callFunc("pushScene", group)
|
||||
|
||||
|
|
|
@ -204,24 +204,33 @@ function AudioItem(id as string)
|
|||
"sortBy": "SortName"
|
||||
})
|
||||
|
||||
data = getJson(resp)
|
||||
results = []
|
||||
if data.Items <> invalid
|
||||
for each item in data.Items
|
||||
tmp = CreateObject("roSGNode", "MusicSongData")
|
||||
tmp.image = PosterImage(item.id)
|
||||
tmp.json = item
|
||||
results.push(tmp)
|
||||
end for
|
||||
else
|
||||
tmp = CreateObject("roSGNode", "MusicSongData")
|
||||
tmp.image = PosterImage(data.id)
|
||||
tmp.json = data
|
||||
results.push(tmp)
|
||||
end if
|
||||
return getJson(resp)
|
||||
end function
|
||||
|
||||
data.Items = results
|
||||
return data
|
||||
function AudioStream(id as string)
|
||||
songData = AudioItem(id)
|
||||
|
||||
content = createObject("RoSGNode", "ContentNode")
|
||||
|
||||
params = {}
|
||||
|
||||
params.append({
|
||||
"Static": "true",
|
||||
"Container": songData.mediaSources[0].container,
|
||||
})
|
||||
|
||||
params.MediaSourceId = songData.mediaSources[0].id
|
||||
|
||||
content.url = buildURL(Substitute("Audio/{0}/stream", songData.id), params)
|
||||
content.title = songData.title
|
||||
content.streamformat = songData.mediaSources[0].container
|
||||
|
||||
return content
|
||||
end function
|
||||
|
||||
function BackdropImage(id as string)
|
||||
imgParams = { "maxHeight": "720", "maxWidth": "1280" }
|
||||
return ImageURL(id, "Backdrop", imgParams)
|
||||
end function
|
||||
|
||||
' Seasons for a TV Show
|
||||
|
|
Loading…
Reference in New Issue
Block a user