Merge pull request #1376 from cewert/fix-quickplay
This commit is contained in:
commit
dd3972cff5
|
@ -725,6 +725,7 @@ sub showTVGuide()
|
|||
m.tvGuide.filter = m.filter
|
||||
m.tvGuide.searchTerm = m.voiceBox.text
|
||||
m.top.appendChild(m.tvGuide)
|
||||
m.scheduleGrid = m.top.findNode("scheduleGrid")
|
||||
m.tvGuide.lastFocus.setFocus(true)
|
||||
end sub
|
||||
|
||||
|
@ -742,6 +743,18 @@ sub onChannelFocused(msg)
|
|||
m.channelFocused = node.focusedChannel
|
||||
end sub
|
||||
|
||||
'Returns Focused Item
|
||||
function getItemFocused()
|
||||
if m.itemGrid.isinFocusChain() and isValid(m.itemGrid.itemFocused)
|
||||
return m.itemGrid.content.getChild(m.itemGrid.itemFocused)
|
||||
else if m.genreList.isinFocusChain() and isValid(m.genreList.rowItemFocused)
|
||||
return m.genreList.content.getChild(m.genreList.rowItemFocused[0]).getChild(m.genreList.rowItemFocused[1])
|
||||
else if m.scheduleGrid.isinFocusChain() and isValid(m.scheduleGrid.itemFocused)
|
||||
return m.scheduleGrid.content.getChild(m.scheduleGrid.itemFocused)
|
||||
end if
|
||||
return invalid
|
||||
end function
|
||||
|
||||
function onKeyEvent(key as string, press as boolean) as boolean
|
||||
if not press then return false
|
||||
|
||||
|
@ -788,11 +801,11 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
m.loadItemsTask.control = "stop"
|
||||
return true
|
||||
end if
|
||||
else if key = "play" or key = "OK"
|
||||
else if key = "play"
|
||||
markupGrid = m.top.findNode("itemGrid")
|
||||
itemToPlay = markupGrid.content.getChild(markupGrid.itemFocused)
|
||||
itemToPlay = getItemFocused()
|
||||
|
||||
if itemToPlay <> invalid and (itemToPlay.type = "Movie" or itemToPlay.type = "Episode")
|
||||
if itemToPlay <> invalid
|
||||
m.top.quickPlayNode = itemToPlay
|
||||
return true
|
||||
else if itemToPlay <> invalid and itemToPlay.type = "Photo"
|
||||
|
|
|
@ -708,7 +708,12 @@ end sub
|
|||
'
|
||||
'Returns Focused Item
|
||||
function getItemFocused()
|
||||
return m.itemGrid.content.getChild(m.itemGrid.itemFocused)
|
||||
if m.itemGrid.isinFocusChain() and isValid(m.itemGrid.itemFocused)
|
||||
return m.itemGrid.content.getChild(m.itemGrid.itemFocused)
|
||||
else if m.genreList.isinFocusChain() and isValid(m.genreList.rowItemFocused)
|
||||
return m.genreList.content.getChild(m.genreList.rowItemFocused[0]).getChild(m.genreList.rowItemFocused[1])
|
||||
end if
|
||||
return invalid
|
||||
end function
|
||||
|
||||
'
|
||||
|
@ -870,11 +875,10 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
m.loadItemsTask.control = "stop"
|
||||
return true
|
||||
end if
|
||||
else if key = "play" or key = "OK"
|
||||
|
||||
else if key = "play"
|
||||
itemToPlay = getItemFocused()
|
||||
|
||||
if itemToPlay <> invalid and (itemToPlay.type = "Movie" or itemToPlay.type = "Episode")
|
||||
if itemToPlay <> invalid
|
||||
m.top.quickPlayNode = itemToPlay
|
||||
return true
|
||||
end if
|
||||
|
|
|
@ -573,7 +573,12 @@ end sub
|
|||
'
|
||||
'Returns Focused Item
|
||||
function getItemFocused()
|
||||
return m.itemGrid.content.getChild(m.itemGrid.itemFocused)
|
||||
if m.itemGrid.isinFocusChain() and isValid(m.itemGrid.itemFocused)
|
||||
return m.itemGrid.content.getChild(m.itemGrid.itemFocused)
|
||||
else if m.genreList.isinFocusChain() and isValid(m.genreList.itemFocused)
|
||||
return m.genreList.content.getChild(m.genreList.itemFocused)
|
||||
end if
|
||||
return invalid
|
||||
end function
|
||||
|
||||
'
|
||||
|
@ -751,7 +756,6 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
alpha.setFocus(true)
|
||||
return true
|
||||
end if
|
||||
|
||||
else if key = "right" and m.Alpha.isinFocusChain()
|
||||
m.top.alphaActive = false
|
||||
m.Alpha.setFocus(false)
|
||||
|
@ -761,14 +765,12 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
m.genreList.setFocus(m.genreList.opacity = 1)
|
||||
|
||||
return true
|
||||
|
||||
else if key = "replay" and m.itemGrid.isinFocusChain()
|
||||
if m.resetGrid = true
|
||||
m.itemGrid.animateToItem = 0
|
||||
else
|
||||
m.itemGrid.jumpToItem = 0
|
||||
end if
|
||||
|
||||
else if key = "replay" and m.genreList.isinFocusChain()
|
||||
if m.resetGrid = true
|
||||
m.genreList.animateToItem = 0
|
||||
|
@ -776,6 +778,12 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
m.genreList.jumpToItem = 0
|
||||
end if
|
||||
return true
|
||||
else if key = "play"
|
||||
itemToPlay = getItemFocused()
|
||||
if itemToPlay <> invalid
|
||||
m.top.quickPlayNode = itemToPlay
|
||||
return true
|
||||
end if
|
||||
end if
|
||||
|
||||
if key = "replay"
|
||||
|
|
|
@ -31,7 +31,7 @@ sub setData()
|
|||
m.top.iconUrl = "pkg:/images/media_type_icons/folder_white.png"
|
||||
end if
|
||||
|
||||
else if datum.type = "Episode"
|
||||
else if datum.type = "Episode" or datum.type = "MusicVideo"
|
||||
m.top.isWatched = datum.UserData.Played
|
||||
|
||||
imgParams = {}
|
||||
|
@ -72,32 +72,7 @@ sub setData()
|
|||
m.top.widePosterUrl = ImageURL(datum.Id, "Backdrop", imgParams)
|
||||
end if
|
||||
|
||||
else if datum.type = "Movie"
|
||||
m.top.isWatched = datum.UserData.Played
|
||||
|
||||
imgParams = {}
|
||||
imgParams.Append({ "maxHeight": 261 })
|
||||
imgParams.Append({ "maxWidth": 175 })
|
||||
|
||||
if datum.ImageTags.Primary <> invalid
|
||||
param = { "Tag": datum.ImageTags.Primary }
|
||||
imgParams.Append(param)
|
||||
end if
|
||||
|
||||
m.top.posterURL = ImageURL(datum.id, "Primary", imgParams)
|
||||
|
||||
' For wide image, use backdrop
|
||||
imgParams["maxWidth"] = 464
|
||||
|
||||
if datum.ImageTags <> invalid and datum.imageTags.Thumb <> invalid
|
||||
imgParams["Tag"] = datum.imageTags.Thumb
|
||||
m.top.thumbnailUrl = ImageURL(datum.Id, "Thumb", imgParams)
|
||||
else if datum.BackdropImageTags[0] <> invalid
|
||||
imgParams["Tag"] = datum.BackdropImageTags[0]
|
||||
m.top.thumbnailUrl = ImageURL(datum.id, "Backdrop", imgParams)
|
||||
end if
|
||||
|
||||
else if datum.type = "Video"
|
||||
else if datum.type = "Movie" or datum.type = "Video"
|
||||
m.top.isWatched = datum.UserData.Played
|
||||
|
||||
imgParams = {}
|
||||
|
@ -126,12 +101,10 @@ sub setData()
|
|||
m.top.thumbnailURL = ImageURL(datum.id, "Primary", params)
|
||||
m.top.widePosterUrl = m.top.thumbnailURL
|
||||
m.top.posterUrl = m.top.thumbnailURL
|
||||
|
||||
else if datum.type = "TvChannel" or datum.type = "Channel"
|
||||
params = { "Tag": datum.ImageTags.Primary, "maxHeight": 261, "maxWidth": 464 }
|
||||
m.top.thumbnailURL = ImageURL(datum.id, "Primary", params)
|
||||
m.top.widePosterUrl = m.top.thumbnailURL
|
||||
m.top.iconUrl = "pkg:/images/media_type_icons/live_tv_white.png"
|
||||
end if
|
||||
|
||||
end sub
|
||||
|
|
|
@ -3,6 +3,7 @@ sub init()
|
|||
updateSize()
|
||||
m.top.rowFocusAnimationStyle = "fixedFocus"
|
||||
m.top.observeField("rowItemSelected", "onRowItemSelected")
|
||||
m.top.observeField("rowItemFocused", "onRowItemFocused")
|
||||
|
||||
' Set up all Tasks
|
||||
m.LoadPeopleTask = CreateObject("roSGNode", "LoadItemsTask")
|
||||
|
@ -207,3 +208,7 @@ end sub
|
|||
sub onRowItemSelected()
|
||||
m.top.selectedItem = m.top.content.getChild(m.top.rowItemSelected[0]).getChild(m.top.rowItemSelected[1])
|
||||
end sub
|
||||
|
||||
sub onRowItemFocused()
|
||||
m.top.focusedItem = m.top.content.getChild(m.top.rowItemFocused[0]).getChild(m.top.rowItemFocused[1])
|
||||
end sub
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<interface>
|
||||
<field id="type" type="string" />
|
||||
<field id="parentId" type="string" />
|
||||
<field id="focusedItem" type="node" alwaysNotify="true" />
|
||||
<field id="selectedItem" type="node" alwaysNotify="true" />
|
||||
<function name="loadParts" />
|
||||
<function name="loadPersonVideos" />
|
||||
|
|
|
@ -30,6 +30,7 @@ end sub
|
|||
sub itemContentChanged()
|
||||
itemData = m.top.itemContent
|
||||
if itemData = invalid then return
|
||||
|
||||
itemData.Title = itemData.name ' Temporarily required while we move from "HomeItem" to "JFContentItem"
|
||||
|
||||
m.itemPoster.width = itemData.imageWidth
|
||||
|
@ -135,7 +136,7 @@ sub itemContentChanged()
|
|||
return
|
||||
end if
|
||||
|
||||
if itemData.type = "Movie"
|
||||
if itemData.type = "Movie" or itemData.type = "MusicVideo"
|
||||
m.itemText.text = itemData.name
|
||||
|
||||
if itemData.PlayedPercentage > 0
|
||||
|
|
|
@ -522,21 +522,20 @@ sub itemSelected()
|
|||
end sub
|
||||
|
||||
function onKeyEvent(key as string, press as boolean) as boolean
|
||||
handled = false
|
||||
if press
|
||||
if key = "play"
|
||||
print "play was pressed from homerow"
|
||||
itemToPlay = m.top.content.getChild(m.top.rowItemFocused[0]).getChild(m.top.rowItemFocused[1])
|
||||
if isValid(itemToPlay) and (itemToPlay.type = "Movie" or itemToPlay.type = "Episode")
|
||||
if isValid(itemToPlay)
|
||||
m.top.quickPlayNode = itemToPlay
|
||||
end if
|
||||
handled = true
|
||||
end if
|
||||
|
||||
if key = "replay"
|
||||
return true
|
||||
else if key = "replay"
|
||||
m.top.jumpToRowItem = [m.top.rowItemFocused[0], 0]
|
||||
return true
|
||||
end if
|
||||
end if
|
||||
return handled
|
||||
return false
|
||||
end function
|
||||
|
||||
function filterNodeArray(nodeArray as object, nodeKey as string, excludeArray as object) as object
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<component name="HomeRows" extends="RowList">
|
||||
<interface>
|
||||
<field id="selectedItem" type="node" alwaysNotify="true" />
|
||||
<field id="quickPlayNode" type="node" alwaysNotify="true" />
|
||||
<field id="quickPlayNode" type="node" />
|
||||
<function name="updateHomeRows" />
|
||||
<function name="loadLibraries" />
|
||||
</interface>
|
||||
|
|
|
@ -137,7 +137,8 @@ sub loadItems()
|
|||
if isValid(data) and isValid(data.Items)
|
||||
for each item in data.Items
|
||||
' Skip Books for now as we don't support it (issue #558)
|
||||
if item.Type <> "Book"
|
||||
' also skip songs since there is limited space
|
||||
if not (item.Type = "Book" or item.Type = "Audio")
|
||||
tmp = CreateObject("roSGNode", "HomeData")
|
||||
|
||||
params = {}
|
||||
|
|
|
@ -11,6 +11,7 @@ sub init()
|
|||
m.queue = []
|
||||
m.originalQueue = []
|
||||
m.queueTypes = []
|
||||
m.isPlaying = false
|
||||
' Preroll videos only play if user has cinema mode setting enabled
|
||||
m.isPrerollActive = m.global.session.user.settings["playback.cinemamode"]
|
||||
m.position = 0
|
||||
|
@ -19,6 +20,7 @@ end sub
|
|||
|
||||
' Clear all content from play queue
|
||||
sub clear()
|
||||
m.isPlaying = false
|
||||
m.queue = []
|
||||
m.queueTypes = []
|
||||
m.isPrerollActive = m.global.session.user.settings["playback.cinemamode"]
|
||||
|
@ -111,6 +113,7 @@ end function
|
|||
|
||||
' Play items in queue
|
||||
sub playQueue()
|
||||
m.isPlaying = true
|
||||
nextItem = getCurrentItem()
|
||||
if not isValid(nextItem) then return
|
||||
|
||||
|
@ -122,11 +125,21 @@ sub playQueue()
|
|||
return
|
||||
end if
|
||||
|
||||
if nextItemMediaType = "musicvideo"
|
||||
CreateVideoPlayerView()
|
||||
return
|
||||
end if
|
||||
|
||||
if nextItemMediaType = "video"
|
||||
CreateVideoPlayerView()
|
||||
return
|
||||
end if
|
||||
|
||||
if nextItemMediaType = "movie"
|
||||
CreateVideoPlayerView()
|
||||
return
|
||||
end if
|
||||
|
||||
if nextItemMediaType = "episode"
|
||||
CreateVideoPlayerView()
|
||||
return
|
||||
|
@ -196,21 +209,25 @@ end function
|
|||
sub shuffleQueueItems()
|
||||
' By calling getQueue 2 different ways, Roku avoids needing to do a deep copy
|
||||
m.originalQueue = m.global.queueManager.callFunc("getQueue")
|
||||
songIDArray = getQueue()
|
||||
itemIDArray = getQueue()
|
||||
temp = invalid
|
||||
|
||||
' Move the currently playing song to the front of the queue
|
||||
temp = top()
|
||||
songIDArray[0] = getCurrentItem()
|
||||
songIDArray[getPosition()] = temp
|
||||
if m.isPlaying
|
||||
' Save the currently playing item
|
||||
temp = getCurrentItem()
|
||||
' remove currently playing item from itemIDArray
|
||||
itemIDArray.Delete(m.position)
|
||||
end if
|
||||
|
||||
for i = 1 to songIDArray.count() - 1
|
||||
j = Rnd(songIDArray.count() - 1)
|
||||
temp = songIDArray[i]
|
||||
songIDArray[i] = songIDArray[j]
|
||||
songIDArray[j] = temp
|
||||
end for
|
||||
' shuffle all items
|
||||
itemIDArray = shuffleArray(itemIDArray)
|
||||
|
||||
set(songIDArray)
|
||||
if m.isPlaying
|
||||
' Put currently playing item in front of itemIDArray
|
||||
itemIDArray.Unshift(temp)
|
||||
end if
|
||||
|
||||
set(itemIDArray)
|
||||
end sub
|
||||
|
||||
' Return the fitst item in the play queue
|
||||
|
|
|
@ -385,6 +385,12 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
audioOptionsClosed()
|
||||
return true
|
||||
end if
|
||||
else if key = "play" and m.extrasGrid.hasFocus()
|
||||
print "Play was pressed from the movie details extras slider"
|
||||
if m.extrasGrid.focusedItem <> invalid
|
||||
m.top.quickPlayNode = m.extrasGrid.focusedItem
|
||||
return true
|
||||
end if
|
||||
end if
|
||||
return false
|
||||
end function
|
||||
|
|
|
@ -50,5 +50,6 @@
|
|||
<field id="trailerAvailable" type="bool" onChange="trailerAvailableChanged" value="false" />
|
||||
<field id="selectedAudioStreamIndex" type="integer" />
|
||||
<field id="selectedVideoStreamId" type="string" />
|
||||
<field id="quickPlayNode" type="node" alwaysNotify="true" />
|
||||
</interface>
|
||||
</component>
|
|
@ -313,5 +313,21 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
end if
|
||||
end if
|
||||
|
||||
if key = "play"
|
||||
print "play button pressed from ArtistView"
|
||||
itemToPlay = invalid
|
||||
|
||||
if isValid(m.albums) and m.albums.isInFocusChain()
|
||||
itemToPlay = m.albums.MusicArtistAlbumData.items[m.albums.itemFocused]
|
||||
else if isValid(m.appearsOn) and m.appearsOn.isInFocusChain()
|
||||
itemToPlay = m.appearsOn.MusicArtistAlbumData.items[m.appearsOn.itemFocused]
|
||||
end if
|
||||
|
||||
if isValid(itemToPlay)
|
||||
m.top.quickPlayNode = itemToPlay
|
||||
return true
|
||||
end if
|
||||
end if
|
||||
|
||||
return false
|
||||
end function
|
||||
|
|
|
@ -54,5 +54,6 @@
|
|||
<field id="playArtistSelected" alias="play.selected" />
|
||||
<field id="instantMixSelected" alias="instantMix.selected" />
|
||||
<field id="selectedButtonIndex" type="integer" value="-1" />
|
||||
<field id="quickPlayNode" type="node" alwaysNotify="true" />
|
||||
</interface>
|
||||
</component>
|
|
@ -12,7 +12,7 @@
|
|||
</children>
|
||||
<interface>
|
||||
<field id="episodeSelected" alias="picker.itemSelected" />
|
||||
<field id="quickPlayNode" type="node" alwaysNotify="true" />
|
||||
<field id="quickPlayNode" type="node" />
|
||||
<field id="seasonData" type="assocarray" onChange="setSeasonLoading" />
|
||||
<field id="objects" alias="picker.objects" />
|
||||
<field id="episodeObjects" type="assocarray" />
|
||||
|
|
|
@ -11,6 +11,7 @@ sub init()
|
|||
m.getShuffleEpisodesTask = createObject("roSGNode", "getShuffleEpisodesTask")
|
||||
m.Shuffle = m.top.findNode("Shuffle")
|
||||
m.extrasSlider.visible = true
|
||||
m.seasons = m.top.findNode("seasons")
|
||||
end sub
|
||||
|
||||
sub itemContentChanged()
|
||||
|
@ -223,6 +224,20 @@ function onKeyEvent(key as string, press as boolean) as boolean
|
|||
else if key = "up" and m.Shuffle.hasFocus()
|
||||
overview.setFocus(true)
|
||||
return true
|
||||
else if key = "play" and m.seasons.hasFocus()
|
||||
print "play was pressed from the seasons row"
|
||||
if isValid(m.seasons.TVSeasonData) and isValid(m.seasons.TVSeasonData.Items)
|
||||
itemFocused = m.seasons.rowItemFocused
|
||||
m.top.quickPlayNode = m.seasons.TVSeasonData.Items[itemFocused[1]]
|
||||
return true
|
||||
end if
|
||||
else if key = "play" and m.extrasSlider.isInFocusChain()
|
||||
print "play was pressed from the extras grid"
|
||||
extrasGrid = m.top.findNode("extrasGrid")
|
||||
if extrasGrid.focusedItem <> invalid
|
||||
m.top.quickPlayNode = extrasGrid.focusedItem
|
||||
return true
|
||||
end if
|
||||
end if
|
||||
|
||||
return false
|
||||
|
|
|
@ -32,5 +32,6 @@
|
|||
<field id="itemContent" type="node" onChange="itemContentChanged" />
|
||||
<field id="seasonData" type="assocarray" alias="seasons.TVSeasonData" />
|
||||
<field id="seasonSelected" alias="seasons.rowItemSelected" alwaysNotify="true" />
|
||||
<field id="quickPlayNode" type="node" alwaysNotify="true" />
|
||||
</interface>
|
||||
</component>
|
120
source/Main.brs
120
source/Main.brs
|
@ -125,48 +125,89 @@ sub Main (args as dynamic) as void
|
|||
group.setFocus(true)
|
||||
end if
|
||||
else if isNodeEvent(msg, "quickPlayNode")
|
||||
' measure processing time
|
||||
timeSpan = CreateObject("roTimespan")
|
||||
|
||||
startMediaLoadingSpinner()
|
||||
|
||||
group = sceneManager.callFunc("getActiveScene")
|
||||
reportingNode = msg.getRoSGNode()
|
||||
itemNode = reportingNode.quickPlayNode
|
||||
if isValid(itemNode) and isValid(itemNode.id) and itemNode.id <> ""
|
||||
if itemNode.type = "Episode" or itemNode.type = "Movie" or itemNode.type = "Video"
|
||||
if isValid(itemNode.selectedVideoStreamId)
|
||||
itemNode.id = itemNode.selectedVideoStreamId
|
||||
end if
|
||||
|
||||
audio_stream_idx = 0
|
||||
if isValid(itemNode.selectedAudioStreamIndex) and itemNode.selectedAudioStreamIndex > 0
|
||||
audio_stream_idx = itemNode.selectedAudioStreamIndex
|
||||
end if
|
||||
|
||||
itemNode.selectedAudioStreamIndex = audio_stream_idx
|
||||
|
||||
playbackPosition = 0
|
||||
|
||||
' Display playback options dialog
|
||||
if isValid(itemNode.json) and isValid(itemNode.json.userdata) and isValid(itemNode.json.userdata.PlaybackPositionTicks)
|
||||
playbackPosition = itemNode.json.userdata.PlaybackPositionTicks
|
||||
end if
|
||||
|
||||
if playbackPosition > 0
|
||||
m.global.queueManager.callFunc("hold", itemNode)
|
||||
playbackOptionDialog(playbackPosition, itemNode.json)
|
||||
else
|
||||
m.global.queueManager.callFunc("clear")
|
||||
m.global.queueManager.callFunc("push", itemNode)
|
||||
m.global.queueManager.callFunc("playQueue")
|
||||
end if
|
||||
|
||||
' Prevent quick play node from double firing
|
||||
itemNode = invalid
|
||||
if isValid(reportingNode)
|
||||
itemNode = reportingNode.quickPlayNode
|
||||
reportingNodeType = reportingNode.subtype()
|
||||
print "Quick Play reporting node type=", reportingNodeType
|
||||
' prevent double fire bug
|
||||
if isValid(reportingNodeType) and (reportingNodeType = "Home" or reportingNodeType = "TVEpisodes")
|
||||
reportingNode.quickPlayNode = invalid
|
||||
|
||||
if LCase(group.subtype()) = "tvepisodes"
|
||||
if isValid(group.lastFocus)
|
||||
group.lastFocus.setFocus(true)
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
print "Quick Play started. itemNode=", itemNode
|
||||
' if itemNode.json <> invalid
|
||||
' print "itemNode.json=", itemNode.json
|
||||
' end if
|
||||
if isValid(itemNode) and isValid(itemNode.id) and itemNode.id <> ""
|
||||
' make sure there is a type and convert type to lowercase
|
||||
itemType = invalid
|
||||
if isValid(itemNode.type) and itemNode.type <> ""
|
||||
itemType = Lcase(itemNode.type)
|
||||
else
|
||||
' grab type from json and convert to lowercase
|
||||
if isValid(itemNode.json) and isValid(itemNode.json.type)
|
||||
itemType = Lcase(itemNode.json.type)
|
||||
end if
|
||||
end if
|
||||
print "Quick Play itemNode type=", itemType
|
||||
|
||||
' can't play the item without knowing what type it is
|
||||
if isValid(itemType)
|
||||
m.global.queueManager.callFunc("clear") ' empty queue/playlist
|
||||
m.global.queueManager.callFunc("resetShuffle") ' turn shuffle off
|
||||
|
||||
if itemType = "episode" or itemType = "movie" or itemType = "video"
|
||||
quickplay.video(itemNode)
|
||||
' restore focus
|
||||
if LCase(group.subtype()) = "tvepisodes"
|
||||
if isValid(group.lastFocus)
|
||||
group.lastFocus.setFocus(true)
|
||||
end if
|
||||
end if
|
||||
else if itemType = "audio"
|
||||
quickplay.audio(itemNode)
|
||||
else if itemType = "musicalbum"
|
||||
quickplay.album(itemNode)
|
||||
else if itemType = "musicartist"
|
||||
quickplay.artist(itemNode)
|
||||
else if itemType = "series"
|
||||
quickplay.series(itemNode)
|
||||
else if itemType = "season"
|
||||
quickplay.season(itemNode)
|
||||
else if itemType = "boxset"
|
||||
quickplay.boxset(itemNode)
|
||||
else if itemType = "collectionfolder"
|
||||
quickplay.collectionFolder(itemNode)
|
||||
else if itemType = "playlist"
|
||||
quickplay.playlist(itemNode)
|
||||
else if itemType = "userview"
|
||||
quickplay.userView(itemNode)
|
||||
else if itemType = "folder"
|
||||
quickplay.folder(itemNode)
|
||||
else if itemType = "musicvideo"
|
||||
quickplay.musicVideo(itemNode)
|
||||
else if itemType = "person"
|
||||
quickplay.person(itemNode)
|
||||
else if itemType = "tvchannel"
|
||||
quickplay.tvChannel(itemNode)
|
||||
else if itemType = "program"
|
||||
quickplay.program(itemNode)
|
||||
end if
|
||||
|
||||
m.global.queueManager.callFunc("playQueue")
|
||||
end if
|
||||
end if
|
||||
stopLoadingSpinner()
|
||||
elapsed = timeSpan.TotalMilliseconds() / 1000
|
||||
print "Quick Play finished loading in " + elapsed.toStr() + " seconds."
|
||||
else if isNodeEvent(msg, "selectedItem")
|
||||
' If you select a library from ANYWHERE, follow this flow
|
||||
selectedItem = msg.getData()
|
||||
|
@ -259,6 +300,8 @@ sub Main (args as dynamic) as void
|
|||
end if
|
||||
else if selectedItemType = "MusicAlbum"
|
||||
group = CreateAlbumView(selectedItem.json)
|
||||
else if selectedItemType = "MusicVideo"
|
||||
group = CreateMovieDetailsGroup(selectedItem)
|
||||
else if selectedItemType = "Playlist"
|
||||
group = CreatePlaylistView(selectedItem.json)
|
||||
else if selectedItemType = "Audio"
|
||||
|
@ -397,6 +440,8 @@ sub Main (args as dynamic) as void
|
|||
group = CreateArtistView(node.json)
|
||||
else if node.type = "MusicAlbum"
|
||||
group = CreateAlbumView(node.json)
|
||||
else if node.type = "MusicVideo"
|
||||
group = CreateMovieDetailsGroup(node)
|
||||
else if node.type = "Audio"
|
||||
m.global.queueManager.callFunc("clear")
|
||||
m.global.queueManager.callFunc("resetShuffle")
|
||||
|
@ -621,6 +666,7 @@ sub Main (args as dynamic) as void
|
|||
' - "low" means that the general memory is below acceptable levels but not critical
|
||||
' - "critical" means that general memory are at dangerously low level and that the OS may force terminate the application
|
||||
print "event.generalMemoryLevel = ", event.generalMemoryLevel
|
||||
session.Update("memoreyLevel", event.generalMemoryLevel)
|
||||
else if isValid(event.audioCodecCapabilityChanged)
|
||||
' The audio codec capability has changed if true.
|
||||
print "event.audioCodecCapabilityChanged = ", event.audioCodecCapabilityChanged
|
||||
|
|
|
@ -598,6 +598,7 @@ function CreateMovieDetailsGroup(movie as object) as dynamic
|
|||
end if
|
||||
' start building MovieDetails view
|
||||
group = CreateObject("roSGNode", "MovieDetails")
|
||||
group.observeField("quickPlayNode", m.port)
|
||||
group.overhangTitle = movie.title
|
||||
group.optionsAvailable = false
|
||||
group.trailerAvailable = false
|
||||
|
@ -651,6 +652,7 @@ function CreateSeriesDetailsGroup(seriesID as string) as dynamic
|
|||
group.seasonData = seasonData
|
||||
' watch for button presses
|
||||
group.observeField("seasonSelected", m.port)
|
||||
group.observeField("quickPlayNode", m.port)
|
||||
' setup and load series extras
|
||||
extras = group.findNode("extrasGrid")
|
||||
extras.observeField("selectedItem", m.port)
|
||||
|
@ -703,6 +705,7 @@ function CreateArtistView(artist as object) as dynamic
|
|||
group.observeField("appearsOnSelected", m.port)
|
||||
end if
|
||||
|
||||
group.observeField("quickPlayNode", m.port)
|
||||
m.global.sceneManager.callFunc("pushScene", group)
|
||||
|
||||
return group
|
||||
|
@ -821,6 +824,7 @@ function CreateItemGrid(libraryItem as object) as dynamic
|
|||
group.parentItem = libraryItem
|
||||
group.optionsAvailable = true
|
||||
group.observeField("selectedItem", m.port)
|
||||
group.observeField("quickPlayNode", m.port)
|
||||
return group
|
||||
end function
|
||||
|
||||
|
@ -832,6 +836,7 @@ function CreateMovieLibraryView(libraryItem as object) as dynamic
|
|||
group.parentItem = libraryItem
|
||||
group.optionsAvailable = true
|
||||
group.observeField("selectedItem", m.port)
|
||||
group.observeField("quickPlayNode", m.port)
|
||||
return group
|
||||
end function
|
||||
|
||||
|
@ -843,6 +848,7 @@ function CreateMusicLibraryView(libraryItem as object) as dynamic
|
|||
group.parentItem = libraryItem
|
||||
group.optionsAvailable = true
|
||||
group.observeField("selectedItem", m.port)
|
||||
group.observeField("quickPlayNode", m.port)
|
||||
return group
|
||||
end function
|
||||
|
||||
|
|
|
@ -225,15 +225,20 @@ function AppearsOnList(id as string)
|
|||
end function
|
||||
|
||||
' Get list of songs belonging to an artist
|
||||
function GetSongsByArtist(id as string)
|
||||
function GetSongsByArtist(id as string, params = {} as object)
|
||||
url = Substitute("Users/{0}/Items", m.global.session.user.id)
|
||||
resp = APIRequest(url, {
|
||||
paramArray = {
|
||||
"AlbumArtistIds": id,
|
||||
"includeitemtypes": "Audio",
|
||||
"sortBy": "SortName",
|
||||
"Recursive": true
|
||||
})
|
||||
}
|
||||
' overwrite defaults with the params provided
|
||||
for each param in params
|
||||
paramArray.AddReplace(param, params[param])
|
||||
end for
|
||||
|
||||
resp = APIRequest(url, paramArray)
|
||||
data = getJson(resp)
|
||||
results = []
|
||||
|
||||
|
@ -410,7 +415,7 @@ function TVSeasons(id as string) as dynamic
|
|||
results = []
|
||||
for each item in data.Items
|
||||
imgParams = { "AddPlayedIndicator": item.UserData.Played }
|
||||
tmp = CreateObject("roSGNode", "TVEpisodeData")
|
||||
tmp = CreateObject("roSGNode", "TVSeasonData")
|
||||
tmp.image = PosterImage(item.id, imgParams)
|
||||
tmp.json = item
|
||||
results.push(tmp)
|
||||
|
|
|
@ -1200,8 +1200,8 @@ namespace api
|
|||
end function
|
||||
|
||||
' Gets the original items of a playlist.
|
||||
function GetItems(id as string, params = {} as object)
|
||||
req = APIRequest(Substitute("/playlists/{0}/items", id), params)
|
||||
function GetItems(playlistID as string, params = {} as object)
|
||||
req = APIRequest(Substitute("/playlists/{0}/items", playlistID), params)
|
||||
return getJson(req)
|
||||
end function
|
||||
|
||||
|
|
|
@ -392,3 +392,13 @@ function arrayHasValue(arr as object, value as dynamic) as boolean
|
|||
end for
|
||||
return false
|
||||
end function
|
||||
|
||||
' Takes an array of data, shuffles the order, then returns the array
|
||||
' uses the Fisher-Yates shuffling algorithm
|
||||
function shuffleArray(array as object) as object
|
||||
for i = array.count() - 1 to 1 step -1
|
||||
j = Rnd(i + 1) - 1
|
||||
t = array[i] : array[i] = array[j] : array[j] = t
|
||||
end for
|
||||
return array
|
||||
end function
|
||||
|
|
585
source/utils/quickplay.bs
Normal file
585
source/utils/quickplay.bs
Normal file
|
@ -0,0 +1,585 @@
|
|||
' All of the Quick Play logic seperated by media type
|
||||
namespace quickplay
|
||||
|
||||
' Takes an array of items and adds to global queue.
|
||||
' Also shuffles the playlist if asked
|
||||
sub pushToQueue(queueArray as object, shufflePlay = false as boolean)
|
||||
if isValidAndNotEmpty(queueArray)
|
||||
' load everything
|
||||
for each item in queueArray
|
||||
m.global.queueManager.callFunc("push", item)
|
||||
end for
|
||||
' shuffle the playlist if asked
|
||||
if shufflePlay and m.global.queueManager.callFunc("getCount") > 1
|
||||
m.global.queueManager.callFunc("toggleShuffle")
|
||||
end if
|
||||
end if
|
||||
end sub
|
||||
|
||||
' A single video file.
|
||||
sub video(itemNode as object)
|
||||
if not isValid(itemNode) or not isValid(itemNode.id) or not isValid(itemNode.json) then return
|
||||
|
||||
' attempt to play video file. resume if possible
|
||||
if isValid(itemNode.selectedVideoStreamId)
|
||||
itemNode.id = itemNode.selectedVideoStreamId
|
||||
end if
|
||||
|
||||
audio_stream_idx = 0
|
||||
if isValid(itemNode.selectedAudioStreamIndex) and itemNode.selectedAudioStreamIndex > 0
|
||||
audio_stream_idx = itemNode.selectedAudioStreamIndex
|
||||
end if
|
||||
itemNode.selectedAudioStreamIndex = audio_stream_idx
|
||||
|
||||
playbackPosition = 0
|
||||
if isValid(itemNode.json.userdata) and isValid(itemNode.json.userdata.PlaybackPositionTicks)
|
||||
playbackPosition = itemNode.json.userdata.PlaybackPositionTicks
|
||||
end if
|
||||
itemNode.startingPoint = playbackPosition
|
||||
|
||||
m.global.queueManager.callFunc("push", itemNode)
|
||||
end sub
|
||||
|
||||
' A single audio file.
|
||||
sub audio(itemNode as object)
|
||||
if not isValid(itemNode) or not isValid(itemNode.id) then return
|
||||
|
||||
m.global.queueManager.callFunc("push", itemNode)
|
||||
end sub
|
||||
|
||||
' A single music video file.
|
||||
sub musicVideo(itemNode as object)
|
||||
if not isValid(itemNode) or not isValid(itemNode.id) or not isValid(itemNode.json) then return
|
||||
|
||||
m.global.queueManager.callFunc("push", itemNode)
|
||||
end sub
|
||||
|
||||
' A music album.
|
||||
' Play the entire album starting with track 1.
|
||||
sub album(itemNode as object)
|
||||
if not isValid(itemNode) or not isValid(itemNode.id) then return
|
||||
|
||||
' grab list of songs in the album
|
||||
albumSongs = api.users.GetItemsByQuery(m.global.session.user.id, {
|
||||
"parentId": itemNode.id,
|
||||
"imageTypeLimit": 1,
|
||||
"sortBy": "SortName",
|
||||
"limit": 2000,
|
||||
"enableUserData": false,
|
||||
"EnableTotalRecordCount": false
|
||||
})
|
||||
if isValid(albumSongs) and isValidAndNotEmpty(albumSongs.items)
|
||||
quickplay.pushToQueue(albumSongs.items)
|
||||
end if
|
||||
end sub
|
||||
|
||||
' A music artist.
|
||||
' Shuffle play all songs by artist.
|
||||
sub artist(itemNode as object)
|
||||
if not isValid(itemNode) or not isValid(itemNode.id) then return
|
||||
|
||||
' get all songs by artist
|
||||
artistSongs = api.users.GetItemsByQuery(m.global.session.user.id, {
|
||||
"artistIds": itemNode.id,
|
||||
"includeItemTypes": "Audio",
|
||||
"sortBy": "Album",
|
||||
"limit": 2000,
|
||||
"imageTypeLimit": 1,
|
||||
"Recursive": true,
|
||||
"enableUserData": false,
|
||||
"EnableTotalRecordCount": false
|
||||
})
|
||||
print "artistSongs=", artistSongs
|
||||
|
||||
if isValid(artistSongs) and isValidAndNotEmpty(artistSongs.items)
|
||||
quickplay.pushToQueue(artistSongs.items, true)
|
||||
end if
|
||||
end sub
|
||||
|
||||
' A boxset.
|
||||
' Play all items inside.
|
||||
sub boxset(itemNode as object)
|
||||
if not isValid(itemNode) or not isValid(itemNode.id) then return
|
||||
|
||||
data = api.items.GetByQuery({
|
||||
"userid": m.global.session.user.id,
|
||||
"parentid": itemNode.id,
|
||||
"limit": 2000,
|
||||
"EnableTotalRecordCount": false
|
||||
})
|
||||
if isValid(data) and isValidAndNotEmpty(data.Items)
|
||||
quickplay.pushToQueue(data.items)
|
||||
end if
|
||||
end sub
|
||||
|
||||
' A TV Show Series.
|
||||
' Play the first unwatched episode.
|
||||
' If none, shuffle play the whole series.
|
||||
sub series(itemNode as object)
|
||||
if not isValid(itemNode) or not isValid(itemNode.id) then return
|
||||
|
||||
data = api.shows.GetNextUp({
|
||||
"seriesId": itemNode.id,
|
||||
"recursive": true,
|
||||
"SortBy": "DatePlayed",
|
||||
"SortOrder": "Descending",
|
||||
"ImageTypeLimit": 1,
|
||||
"UserId": m.global.session.user.id,
|
||||
"EnableRewatching": false,
|
||||
"DisableFirstEpisode": false,
|
||||
"EnableTotalRecordCount": false
|
||||
})
|
||||
|
||||
if isValid(data) and isValidAndNotEmpty(data.Items)
|
||||
' there are unwatched episodes
|
||||
m.global.queueManager.callFunc("push", data.Items[0])
|
||||
else
|
||||
' next up check was empty
|
||||
' check for a resumable episode
|
||||
data = api.users.GetResumeItemsByQuery(m.global.session.user.id, {
|
||||
"parentId": itemNode.id,
|
||||
"userid": m.global.session.user.id,
|
||||
"SortBy": "DatePlayed",
|
||||
"recursive": true,
|
||||
"SortOrder": "Descending",
|
||||
"Filters": "IsResumable",
|
||||
"EnableTotalRecordCount": false
|
||||
})
|
||||
print "resumeitems data=", data
|
||||
if isValid(data) and isValidAndNotEmpty(data.Items)
|
||||
' play the resumable episode
|
||||
if isValid(data.Items[0].UserData) and isValid(data.Items[0].UserData.PlaybackPositionTicks)
|
||||
data.Items[0].startingPoint = data.Items[0].userdata.PlaybackPositionTicks
|
||||
end if
|
||||
m.global.queueManager.callFunc("push", data.Items[0])
|
||||
else
|
||||
' shuffle all episodes
|
||||
data = api.shows.GetEpisodes(itemNode.id, {
|
||||
"userid": m.global.session.user.id,
|
||||
"SortBy": "Random",
|
||||
"limit": 2000,
|
||||
"EnableTotalRecordCount": false
|
||||
})
|
||||
|
||||
if isValid(data) and isValidAndNotEmpty(data.Items)
|
||||
' add all episodes found to a playlist
|
||||
quickplay.pushToQueue(data.Items)
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
end sub
|
||||
|
||||
' More than one TV Show Series.
|
||||
' Shuffle play all watched episodes
|
||||
sub multipleSeries(itemNodes as object)
|
||||
if isValidAndNotEmpty(itemNodes)
|
||||
numTotal = 0
|
||||
numLimit = 2000
|
||||
for each tvshow in itemNodes
|
||||
' grab all watched episodes for each series
|
||||
showData = api.shows.GetEpisodes(tvshow.id, {
|
||||
"userId": m.global.session.user.id,
|
||||
"SortBy": "Random",
|
||||
"imageTypeLimit": 0,
|
||||
"EnableTotalRecordCount": false,
|
||||
"enableImages": false
|
||||
})
|
||||
|
||||
if isValid(showData) and isValidAndNotEmpty(showData.items)
|
||||
playedEpisodes = []
|
||||
' add all played episodes to queue
|
||||
for each episode in showData.items
|
||||
if isValid(episode.userdata) and isValid(episode.userdata.Played)
|
||||
if episode.userdata.Played
|
||||
playedEpisodes.push(episode)
|
||||
end if
|
||||
end if
|
||||
end for
|
||||
quickplay.pushToQueue(playedEpisodes)
|
||||
|
||||
' keep track of how many items we've seen
|
||||
numTotal = numTotal + showData.items.count()
|
||||
if numTotal >= numLimit
|
||||
' stop grabbing more items if we hit our limit
|
||||
exit for
|
||||
end if
|
||||
end if
|
||||
end for
|
||||
if m.global.queueManager.callFunc("getCount") > 1
|
||||
m.global.queueManager.callFunc("toggleShuffle")
|
||||
end if
|
||||
end if
|
||||
end sub
|
||||
|
||||
' A TV Show Season.
|
||||
' Play the first unwatched episode.
|
||||
' If none, play the whole season starting with episode 1.
|
||||
sub season(itemNode as object)
|
||||
if not isValid(itemNode) or not isValid(itemNode.id) then return
|
||||
|
||||
unwatchedData = api.shows.GetEpisodes(itemNode.json.SeriesId, {
|
||||
"seasonId": itemNode.id,
|
||||
"userid": m.global.session.user.id,
|
||||
"limit": 2000,
|
||||
"EnableTotalRecordCount": false
|
||||
})
|
||||
|
||||
if isValid(unwatchedData) and isValidAndNotEmpty(unwatchedData.Items)
|
||||
' find the first unwatched episode
|
||||
firstUnwatchedEpisodeIndex = invalid
|
||||
for each item in unwatchedData.Items
|
||||
if isValid(item.UserData)
|
||||
if isValid(item.UserData.Played) and item.UserData.Played = false
|
||||
firstUnwatchedEpisodeIndex = item.IndexNumber - 1
|
||||
if isValid(item.UserData.PlaybackPositionTicks)
|
||||
item.startingPoint = item.UserData.PlaybackPositionTicks
|
||||
end if
|
||||
exit for
|
||||
end if
|
||||
end if
|
||||
end for
|
||||
|
||||
if isValid(firstUnwatchedEpisodeIndex)
|
||||
' add the first unwatched episode and the rest of the season to a playlist
|
||||
for i = firstUnwatchedEpisodeIndex to unwatchedData.Items.count() - 1
|
||||
m.global.queueManager.callFunc("push", unwatchedData.Items[i])
|
||||
end for
|
||||
else
|
||||
' try to find a "continue watching" episode
|
||||
continueData = api.users.GetResumeItemsByQuery(m.global.session.user.id, {
|
||||
"parentId": itemNode.id,
|
||||
"userid": m.global.session.user.id,
|
||||
"SortBy": "DatePlayed",
|
||||
"recursive": true,
|
||||
"SortOrder": "Descending",
|
||||
"Filters": "IsResumable",
|
||||
"EnableTotalRecordCount": false
|
||||
})
|
||||
|
||||
if isValid(continueData) and isValidAndNotEmpty(continueData.Items)
|
||||
' play the resumable episode
|
||||
for each item in continueData.Items
|
||||
if isValid(item.UserData) and isValid(item.UserData.PlaybackPositionTicks)
|
||||
item.startingPoint = item.userdata.PlaybackPositionTicks
|
||||
end if
|
||||
m.global.queueManager.callFunc("push", item)
|
||||
end for
|
||||
else
|
||||
' play the whole season in order
|
||||
if isValid(unwatchedData) and isValidAndNotEmpty(unwatchedData.Items)
|
||||
' add all episodes found to a playlist
|
||||
pushToQueue(unwatchedData.Items)
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
end if
|
||||
end sub
|
||||
|
||||
' Quick Play A Person.
|
||||
' Shuffle play all videos found
|
||||
sub person(itemNode as object)
|
||||
if not isValid(itemNode) or not isValid(itemNode.id) then return
|
||||
' get movies and videos by the person
|
||||
personMovies = api.users.GetItemsByQuery(m.global.session.user.id, {
|
||||
"personIds": itemNode.id,
|
||||
"includeItemTypes": "Movie,Video",
|
||||
"excludeItemTypes": "Season,Series",
|
||||
"recursive": true,
|
||||
"limit": 2000
|
||||
})
|
||||
print "personMovies=", personMovies
|
||||
|
||||
if isValid(personMovies) and isValidAndNotEmpty(personMovies.Items)
|
||||
' add each item to the queue
|
||||
quickplay.pushToQueue(personMovies.Items)
|
||||
end if
|
||||
|
||||
' get watched episodes by the person
|
||||
personEpisodes = api.users.GetItemsByQuery(m.global.session.user.id, {
|
||||
"personIds": itemNode.id,
|
||||
"includeItemTypes": "Episode",
|
||||
"isPlayed": true,
|
||||
"excludeItemTypes": "Season,Series",
|
||||
"recursive": true,
|
||||
"limit": 2000
|
||||
})
|
||||
print "personEpisodes=", personEpisodes
|
||||
|
||||
if isValid(personEpisodes) and isValidAndNotEmpty(personEpisodes.Items)
|
||||
' add each item to the queue
|
||||
quickplay.pushToQueue(personEpisodes.Items)
|
||||
end if
|
||||
|
||||
if m.global.queueManager.callFunc("getCount") > 1
|
||||
m.global.queueManager.callFunc("toggleShuffle")
|
||||
end if
|
||||
end sub
|
||||
|
||||
' Quick Play A TVChannel
|
||||
sub tvChannel(itemNode as object)
|
||||
if not isValid(itemNode) or not isValid(itemNode.id) then return
|
||||
|
||||
stopLoadingSpinner()
|
||||
group = CreateVideoPlayerGroup(itemNode.id)
|
||||
m.global.sceneManager.callFunc("pushScene", group)
|
||||
end sub
|
||||
|
||||
' Quick Play A Live Program
|
||||
sub program(itemNode as object)
|
||||
if not isValid(itemNode) or not isValid(itemNode.json) or not isValid(itemNode.json.ChannelId) then return
|
||||
|
||||
stopLoadingSpinner()
|
||||
group = CreateVideoPlayerGroup(itemNode.json.ChannelId)
|
||||
m.global.sceneManager.callFunc("pushScene", group)
|
||||
end sub
|
||||
|
||||
' Quick Play A Playlist.
|
||||
' Play the first unwatched episode.
|
||||
' If none, play the whole season starting with episode 1.
|
||||
sub playlist(itemNode as object)
|
||||
if not isValid(itemNode) or not isValid(itemNode.id) then return
|
||||
' get playlist items
|
||||
myPlaylist = api.playlists.GetItems(itemNode.id, {
|
||||
"userId": m.global.session.user.id,
|
||||
"limit": 2000
|
||||
})
|
||||
|
||||
if isValid(myPlaylist) and isValidAndNotEmpty(myPlaylist.Items)
|
||||
' add each item to the queue
|
||||
quickplay.pushToQueue(myPlaylist.Items)
|
||||
if m.global.queueManager.callFunc("getCount") > 1
|
||||
m.global.queueManager.callFunc("toggleShuffle")
|
||||
end if
|
||||
end if
|
||||
end sub
|
||||
|
||||
' Quick Play A folder.
|
||||
' Shuffle play all items found
|
||||
sub folder(itemNode as object)
|
||||
if not isValid(itemNode) or not isValid(itemNode.id) then return
|
||||
|
||||
paramArray = {
|
||||
"includeItemTypes": ["Episode", "Movie", "Video"],
|
||||
"videoTypes": "VideoFile",
|
||||
"sortBy": "Random",
|
||||
"limit": 2000,
|
||||
"imageTypeLimit": 1,
|
||||
"Recursive": true,
|
||||
"enableUserData": false,
|
||||
"EnableTotalRecordCount": false
|
||||
}
|
||||
' modify api query based on folder type
|
||||
folderType = Lcase(itemNode.json.type)
|
||||
if folderType = "studio"
|
||||
paramArray["studioIds"] = itemNode.id
|
||||
else if folderType = "genre"
|
||||
paramArray["genreIds"] = itemNode.id
|
||||
if isValid(itemNode.json.MovieCount) and itemNode.json.MovieCount > 0
|
||||
paramArray["includeItemTypes"] = "Movie"
|
||||
end if
|
||||
else if folderType = "musicgenre"
|
||||
paramArray["genreIds"] = itemNode.id
|
||||
paramArray.delete("videoTypes")
|
||||
paramArray["includeItemTypes"] = "Audio"
|
||||
else
|
||||
paramArray["parentId"] = itemNode.id
|
||||
end if
|
||||
' look for tv series instead of video files
|
||||
if isValid(itemNode.json.SeriesCount) and itemNode.json.SeriesCount > 0
|
||||
paramArray["includeItemTypes"] = "Series"
|
||||
paramArray.Delete("videoTypes")
|
||||
end if
|
||||
' get folder items
|
||||
folderData = api.users.GetItemsByQuery(m.global.session.user.id, paramArray)
|
||||
print "folderData=", folderData
|
||||
|
||||
if isValid(folderData) and isValidAndNotEmpty(folderData.items)
|
||||
if isValid(itemNode.json.SeriesCount) and itemNode.json.SeriesCount > 0
|
||||
if itemNode.json.SeriesCount = 1
|
||||
quickplay.series(folderData.items[0])
|
||||
else
|
||||
quickplay.multipleSeries(folderData.items)
|
||||
end if
|
||||
else
|
||||
quickplay.pushToQueue(folderData.items, true)
|
||||
end if
|
||||
end if
|
||||
end sub
|
||||
|
||||
' Quick Play A CollectionFolder.
|
||||
' Shuffle play the items inside
|
||||
' with some differences based on collectionType.
|
||||
sub collectionFolder(itemNode as object)
|
||||
if not isValid(itemNode) or not isValid(itemNode.id) then return
|
||||
' play depends on the kind of files inside the collectionfolder
|
||||
print "attempting to quickplay a collection folder"
|
||||
collectionType = LCase(itemNode.collectionType)
|
||||
print "collectionType=", collectionType
|
||||
|
||||
if collectionType = "movies"
|
||||
' get randomized list of movies inside
|
||||
data = api.users.GetItemsByQuery(m.global.session.user.id, {
|
||||
"parentId": itemNode.id,
|
||||
"sortBy": "Random",
|
||||
"limit": 2000
|
||||
})
|
||||
|
||||
if isValid(data) and isValidAndNotEmpty(data.items)
|
||||
movieList = []
|
||||
' add each item to the queue
|
||||
for each item in data.Items
|
||||
' only add movies we're not currently watching
|
||||
if isValid(item.userdata) and isValid(item.userdata.PlaybackPositionTicks)
|
||||
if item.userdata.PlaybackPositionTicks = 0
|
||||
movieList.push(item)
|
||||
end if
|
||||
end if
|
||||
end for
|
||||
quickplay.pushToQueue(movieList)
|
||||
end if
|
||||
else if collectionType = "music"
|
||||
' get audio files from under this collection
|
||||
' sort songs by album then artist
|
||||
songsData = api.users.GetItemsByQuery(m.global.session.user.id, {
|
||||
"parentId": itemNode.id,
|
||||
"includeItemTypes": "Audio",
|
||||
"sortBy": "Album",
|
||||
"Recursive": true,
|
||||
"limit": 2000,
|
||||
"imageTypeLimit": 1,
|
||||
"enableUserData": false,
|
||||
"EnableTotalRecordCount": false
|
||||
})
|
||||
print "songsData=", songsData
|
||||
if isValid(songsData) and isValidAndNotEmpty(songsData.items)
|
||||
quickplay.pushToQueue(songsData.Items, true)
|
||||
end if
|
||||
else if collectionType = "boxsets"
|
||||
' get list of all boxsets inside
|
||||
boxsetData = api.users.GetItemsByQuery(m.global.session.user.id, {
|
||||
"parentId": itemNode.id,
|
||||
"limit": 2000,
|
||||
"imageTypeLimit": 0,
|
||||
"enableUserData": false,
|
||||
"EnableTotalRecordCount": false,
|
||||
"enableImages": false
|
||||
})
|
||||
|
||||
print "boxsetData=", boxsetData
|
||||
|
||||
if isValid(boxsetData) and isValidAndNotEmpty(boxsetData.items)
|
||||
' pick a random boxset
|
||||
arrayIndex = Rnd(boxsetData.items.count()) - 1
|
||||
myBoxset = boxsetData.items[arrayIndex]
|
||||
' grab list of items from boxset
|
||||
print "myBoxset=", myBoxset
|
||||
boxsetData = api.users.GetItemsByQuery(m.global.session.user.id, {
|
||||
"parentId": myBoxset.id,
|
||||
"EnableTotalRecordCount": false
|
||||
})
|
||||
|
||||
if isValid(boxsetData) and isValidAndNotEmpty(boxsetData.items)
|
||||
' add all boxset items to queue
|
||||
quickplay.pushToQueue(boxsetData.Items)
|
||||
end if
|
||||
end if
|
||||
else if collectionType = "tvshows" or collectionType = "collectionfolder"
|
||||
' get list of tv shows inside
|
||||
tvshowsData = api.users.GetItemsByQuery(m.global.session.user.id, {
|
||||
"parentId": itemNode.id,
|
||||
"sortBy": "Random",
|
||||
"imageTypeLimit": 0,
|
||||
"enableUserData": false,
|
||||
"EnableTotalRecordCount": false,
|
||||
"enableImages": false
|
||||
})
|
||||
|
||||
print "tvshowsData=", tvshowsData
|
||||
|
||||
if isValid(tvshowsData) and isValidAndNotEmpty(tvshowsData.items)
|
||||
quickplay.multipleSeries(tvshowsData.items)
|
||||
end if
|
||||
else if collectionType = "musicvideos"
|
||||
' get randomized list of videos inside
|
||||
data = api.users.GetItemsByQuery(m.global.session.user.id, {
|
||||
"parentId": itemNode.id,
|
||||
"includeItemTypes": "MusicVideo",
|
||||
"sortBy": "Random",
|
||||
"Recursive": true,
|
||||
"limit": 2000,
|
||||
"imageTypeLimit": 1,
|
||||
"enableUserData": false,
|
||||
"EnableTotalRecordCount": false
|
||||
})
|
||||
print "data=", data
|
||||
if isValid(data) and isValidAndNotEmpty(data.items)
|
||||
quickplay.pushToQueue(data.Items)
|
||||
end if
|
||||
' else if collectionType = "homevideos" ' also used for a "Photo" library
|
||||
else
|
||||
print "Quick Play WARNING: Unknown collection type"
|
||||
end if
|
||||
end sub
|
||||
|
||||
' Quick Play A UserView.
|
||||
' Play logic depends on "collectionType".
|
||||
sub userView(itemNode as object)
|
||||
' play depends on the kind of files inside the collectionfolder
|
||||
collectionType = LCase(itemNode.collectionType)
|
||||
print "collectionType=", collectionType
|
||||
|
||||
if collectionType = "playlists"
|
||||
' get list of all playlists inside
|
||||
playlistData = api.users.GetItemsByQuery(m.global.session.user.id, {
|
||||
"parentId": itemNode.id,
|
||||
"imageTypeLimit": 0,
|
||||
"enableUserData": false,
|
||||
"EnableTotalRecordCount": false,
|
||||
"enableImages": false
|
||||
})
|
||||
|
||||
print "playlistData=", playlistData
|
||||
|
||||
if isValid(playlistData) and isValidAndNotEmpty(playlistData.items)
|
||||
' pick a random playlist
|
||||
arrayIndex = Rnd(playlistData.items.count()) - 1
|
||||
myPlaylist = playlistData.items[arrayIndex]
|
||||
' grab list of items from playlist
|
||||
print "myPlaylist=", myPlaylist
|
||||
playlistItems = api.playlists.GetItems(myPlaylist.id, {
|
||||
"userId": m.global.session.user.id,
|
||||
"EnableTotalRecordCount": false,
|
||||
"limit": 2000
|
||||
})
|
||||
' validate api results
|
||||
if isValid(playlistItems) and isValidAndNotEmpty(playlistItems.items)
|
||||
quickplay.pushToQueue(playlistItems.items, true)
|
||||
end if
|
||||
end if
|
||||
else if collectionType = "livetv"
|
||||
' get list of all tv channels
|
||||
channelData = api.users.GetItemsByQuery(m.global.session.user.id, {
|
||||
"includeItemTypes": "TVChannel",
|
||||
"sortBy": "Random",
|
||||
"Recursive": true,
|
||||
"imageTypeLimit": 0,
|
||||
"enableUserData": false,
|
||||
"EnableTotalRecordCount": false,
|
||||
"enableImages": false
|
||||
})
|
||||
print "channelData=", channelData
|
||||
|
||||
if isValid(channelData) and isValidAndNotEmpty(channelData.items)
|
||||
' pick a random channel
|
||||
arrayIndex = Rnd(channelData.items.count()) - 1
|
||||
myChannel = channelData.items[arrayIndex]
|
||||
print "myChannel=", myChannel
|
||||
' play channel
|
||||
quickplay.tvChannel(myChannel)
|
||||
end if
|
||||
else
|
||||
print "Quick Play CollectionFolder WARNING: Unknown collection type"
|
||||
end if
|
||||
end sub
|
||||
|
||||
end namespace
|
|
@ -8,6 +8,7 @@ namespace session
|
|||
sub Init()
|
||||
m.global.addFields({
|
||||
session: {
|
||||
"memoryLevel": "normal",
|
||||
server: {},
|
||||
user: {
|
||||
Configuration: {},
|
||||
|
|
Loading…
Reference in New Issue
Block a user