Implement Version selection for Movies

This commit is contained in:
Jimi 2022-03-12 17:36:11 -07:00
parent 0e2e2052e1
commit ecde74cd3e
14 changed files with 286 additions and 35 deletions

BIN
components/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -8,6 +8,13 @@ sub setFields()
m.top.watched = json.UserData.played
m.top.Type = "Movie"
if json.MediaSourceCount <> invalid and json.MediaSourceCount > 1
m.top.mediaSources = []
for each source in json.MediaSources
m.top.mediaSources.push(source)
end for
end if
if json.ProductionYear <> invalid
m.top.SubTitle = json.ProductionYear
end if

View File

@ -5,6 +5,8 @@
<field id="movieID" type="string" />
<field id="seasons" type="assocarray" />
<field id="container" type="string" />
<field id="mediaSourceCount" type="integer" />
<field id="mediaSources" type="array" />
</interface>
<script type="text/brightscript" uri="MovieData.brs" />
<script type="text/brightscript" uri="pkg:/source/api/Image.brs" />

View File

@ -41,7 +41,7 @@ sub optionsSet()
if view.Selected <> invalid and view.Selected = true
selectedViewIndex = index
entry.selected = true
m.top.audioSteamIndex = view.streamIndex
m.top.audioStreamIndex = view.streamIndex
end if
index = index + 1
end for
@ -90,7 +90,7 @@ function onKeyEvent(key as string, press as boolean) as boolean
newSelection = selMenu.content.GetChild(selIndex)
newSelection.selected = true
m.selectedAudioIndex = selIndex
m.top.audioSteamIndex = newSelection.streamIndex
m.top.audioStreamIndex = newSelection.streamIndex
end if
end if
return true

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?>
<component name="MovieOptions" extends="Group">
<component name="MovieAudioOptions" extends="Group">
<children>
<Rectangle width="1920" height="1080" color="#000000" opacity="0.75" />
<Group translation="[100,100]">
@ -31,7 +31,7 @@
<interface>
<field id="buttons" type="nodearray" />
<field id="options" type="assocarray" onChange="optionsSet" />
<field id="audioSteamIndex" type="integer" />
<field id="audioStreamIndex" type="integer" />
</interface>
<script type="text/brightscript" uri="MovieOptions.brs" />
<script type="text/brightscript" uri="MovieAudioOptions.brs" />
</component>

View File

@ -1,6 +1,7 @@
sub init()
m.top.optionsAvailable = false
m.options = m.top.findNode("options")
m.audioOptions = m.top.findNode("audioOptions")
m.videoOptions = m.top.findNode("videoOptions")
main = m.top.findNode("main_group")
main.translation = [96, 175]
@ -18,6 +19,9 @@ sub itemContentChanged()
m.top.id = itemData.id
m.top.findNode("moviePoster").uri = m.top.itemContent.posterURL
' Set default video source
m.top.selectedVideoStreamId = itemData.MediaSources[0].id
' Find first Audio Stream and set that as default
for i = 0 to itemData.mediaStreams.Count() - 1
if itemData.mediaStreams[i].Type = "Audio"
@ -87,11 +91,29 @@ sub itemContentChanged()
end if
setFavoriteColor()
setWatchedColor()
SetUpOptions(itemData.mediaStreams)
SetUpVideoOptions(itemData.mediaSources)
SetUpAudioOptions(itemData.mediaStreams)
end sub
sub SetUpOptions(streams)
sub SetUpVideoOptions(streams)
videos = []
for i = 0 to streams.Count() - 1
if streams[i].VideoType = "VideoFile"
videos.push({ "Title": streams[i].Name, "Description": tr("Video"), "Selected": m.top.selectedVideoStreamId = streams[i].id, "StreamID": streams[i].id, "video_codec": streams[i].mediaStreams[0].displayTitle })
end if
end for
options = {}
options.views = videos
m.videoOptions.options = options
end sub
sub SetUpAudioOptions(streams)
tracks = []
@ -103,7 +125,7 @@ sub SetUpOptions(streams)
options = {}
options.views = tracks
m.options.options = options
m.audioOptions.options = options
end sub
@ -183,39 +205,44 @@ end function
'
'Check if options updated and any reloading required
sub optionsClosed()
if m.options.audioSteamIndex <> m.top.selectedAudioStreamIndex
m.top.selectedAudioStreamIndex = m.options.audioSteamIndex
sub audioOptionsClosed()
if m.audioOptions.audioStreamIndex <> m.top.selectedAudioStreamIndex
m.top.selectedAudioStreamIndex = m.audioOptions.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
sub videoOptionsClosed()
if m.videoOptions.videoStreamId <> m.top.selectedVideoStreamId
m.top.selectedVideoStreamId = m.videoOptions.videoStreamId
setFieldText("video_codec", tr("Video") + ": " + m.videoOptions.video_codec)
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("audio-button").isInFocusChain()
m.options.visible = true
m.options.setFocus(true)
if key = "OK" and m.top.findNode("video-button").isInFocusChain()
m.videoOptions.visible = true
m.videoOptions.setFocus(true)
else if key = "OK" and m.top.findNode("audio-button").isInFocusChain()
m.audioOptions.visible = true
m.audioOptions.setFocus(true)
end if
if not press then return false
if key = "options"
if m.options.visible = true
m.options.visible = false
optionsClosed()
else
m.options.visible = true
m.options.setFocus(true)
end if
return true
else if key = "back"
if m.options.visible = true
m.options.visible = false
optionsClosed()
if key = "back"
if m.audioOptions.visible = true
m.audioOptions.visible = false
audioOptionsClosed()
return true
else if m.videoOptions.visible = true
m.videoOptions.visible = false
videoOptionsClosed()
return true
end if
end if

View File

@ -25,21 +25,24 @@
<Label id="video_codec" />
<Label id="audio_codec" />
<ButtonGroupHoriz id="buttons" itemSpacings="[10]">
<Button text="Play" id="play-button" iconUri="" focusedIconUri="" maxWidth="320" minWidth="320" />
<Button text="Audio" id="audio-button" iconUri="" focusedIconUri="" maxWidth="320" minWidth="320" />
<Button text="Watched" id="watched-button" iconUri="" focusedIconUri="" maxWidth="320" minWidth="320" />
<Button text="Favorite" id="favorite-button" iconUri="" focusedIconUri="" maxWidth="320" minWidth="320" />
<Button text="Play" id="play-button" iconUri="" focusedIconUri="" maxWidth="300" minWidth="300" />
<Button text="Version" id="video-button" iconUri="" focusedIconUri="" maxWidth="300" minWidth="300" />
<Button text="Audio" id="audio-button" iconUri="" focusedIconUri="" maxWidth="300" minWidth="300" />
<Button text="Watched" id="watched-button" iconUri="" focusedIconUri="" maxWidth="300" minWidth="300" />
<Button text="Favorite" id="favorite-button" iconUri="" focusedIconUri="" maxWidth="300" minWidth="300" />
</ButtonGroupHoriz>
<Label id="tagline" />
<Label id="overview" wrap="true" maxLines="8" />
</LayoutGroup>
</LayoutGroup>
<MovieOptions id="options" visible="false" />
<MovieVideoOptions id="videoOptions" visible="false" />
<MovieAudioOptions id="audioOptions" visible="false" />
</children>
<interface>
<field id="itemContent" type="node" onChange="itemContentChanged" />
<field id="selectedAudioStreamIndex" type="integer" />
<field id="selectedVideoStreamId" type="string" />
</interface>
<script type="text/brightscript" uri="pkg:/source/utils/misc.brs" />
<script type="text/brightscript" uri="MovieDetails.brs" />

View File

@ -0,0 +1,112 @@
sub init()
m.buttons = m.top.findNode("buttons")
m.buttons.buttons = [tr("Version")]
m.buttons.setFocus(true)
m.selectedItem = 0
m.selectedVideoIndex = 0
m.menus = []
m.menus.push(m.top.findNode("videoMenu"))
m.viewNames = []
' Set button color to global
m.top.findNode("videoMenu").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")
end sub
sub optionsSet()
' Views Tab
if m.top.options.views <> invalid
viewContent = CreateObject("roSGNode", "ContentNode")
index = 0
selectedViewIndex = 0
for each view in m.top.options.views
entry = viewContent.CreateChild("VideoTrackListData")
entry.title = view.Title
entry.description = view.Description
entry.streamId = view.streamId
entry.video_codec = view.video_codec
m.viewNames.push(view.Name)
if view.Selected <> 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.selectedVideoIndex = selectedViewIndex
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
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
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

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8" ?>
<component name="MovieVideoOptions" extends="Group">
<children>
<Rectangle width="1920" height="1080" color="#000000" opacity="0.75" />
<Group translation="[100,100]">
<Poster width="1720" height="880" uri="pkg:/images/dialog.9.png" />
<LayoutGroup horizAlignment="center" translation="[860,50]" itemSpacings="[50]">
<JFButtons id="buttons" />
<Group>
<MarkupList
id="videoMenu"
itemComponentName="VideoTrackListItem"
itemSize="[600, 70]"
itemSpacing="[20,20]"
numrows = "8"
vertFocusAnimationStyle="floatingFocus"
focusFootprintBlendColor="#00000000"
/>
</Group>
</LayoutGroup>
</Group>
<Animation id="fadeAnim" duration="0.5" repeat="false">
<FloatFieldInterpolator id="outOpacity" key="[0.0, 0.5, 1.0]" keyValue="[ 1, 0, 0 ]" fieldToInterp="focus.opacity" />
<FloatFieldInterpolator id="inOpacity" key="[0.0, 0.5, 1.0]" keyValue="[ 0, 0, 1 ]" fieldToInterp="focus.opacity" />
</Animation>
</children>
<interface>
<field id="buttons" type="nodearray" />
<field id="options" type="assocarray" onChange="optionsSet" />
<field id="videoStreamId" type="string" />
<field id="video_codec" type="string" />
</interface>
<script type="text/brightscript" uri="MovieVideoOptions.brs" />
</component>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<component name="VideoTrackListData" extends="ContentNode">
<interface>
<field id="selected" type="boolean" value="false" />
<field id="streamId" type="string" />
<field id="video_codec" type="string" />
</interface>
</component>

View File

@ -0,0 +1,33 @@
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

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8" ?>
<component name="VideoTrackListItem" extends="Group">
<children>
<Poster width="32" height="32" id="selectedIcon" translation="[5,19]" uri="" />
<Label id="title" font="font:MediumSystemFont" color="0xffffffff" translation="[50,3]" />
<ScrollingLabel id="description" font="font:SmallestSystemFont" color="0xabababff" maxWidth="800" repeatCount="0" translation="[50,45]" />
</children>
<interface>
<field id="itemContent" type="node" onChange="itemContentChanged"/>
<field id="itemHasFocus" type="boolean" onChange="focusChanged" />
</interface>
<script type="text/brightscript" uri="VideoTrackListItem.brs" />
</component>

View File

@ -421,5 +421,9 @@
<translation>An error was encountered while playing this item. Server did not provide required transcoding data.</translation>
<extracomment>Content of message box when trying to play an item which requires transcoding, and the server did not provide transcode url</extracomment>
</message>
<message>
<source>Version</source>
<translation>Version</translation>
</message>
</context>
</TS>

View File

@ -193,13 +193,19 @@ sub Main (args as dynamic) as void
btn = getButton(msg)
group = sceneManager.callFunc("getActiveScene")
if btn <> invalid and btn.id = "play-button"
' Check is a specific Audio Stream was selected
' Check if a specific Audio Stream was selected
audio_stream_idx = 1
if group.selectedAudioStreamIndex <> invalid
audio_stream_idx = group.selectedAudioStreamIndex
end if
video_id = group.id
' Check to see if a specific video "version" was selected
if group.selectedVideoStreamId <> invalid
video_id = group.selectedVideoStreamId
else
video_id = group.id
end if
video = CreateVideoPlayerGroup(video_id, audio_stream_idx)
if video <> invalid
sceneManager.callFunc("pushScene", video)