source_utils_quickplay.bs

' All of the Quick Play logic seperated by media type
namespace quickplay

    ' Takes an array of items and adds to global queue.
    ' Also shuffles the playlist if asked
    sub pushToQueue(queueArray as object, shufflePlay = false as boolean)
        if isValidAndNotEmpty(queueArray)
            ' load everything
            for each item in queueArray
                m.global.queueManager.callFunc("push", item)
            end for
            ' shuffle the playlist if asked
            if shufflePlay and m.global.queueManager.callFunc("getCount") > 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 single photo.
    sub photo(itemNode as object)
        if not isValid(itemNode) or not isValid(itemNode.id) then return

        photoPlayer = CreateObject("roSgNode", "PhotoDetails")
        photoPlayer.itemsNode = itemNode
        photoPlayer.itemIndex = 0
        m.global.sceneManager.callfunc("pushScene", photoPlayer)
    end sub

    ' A photo album.
    sub photoAlbum(itemNode as object)
        if not isValid(itemNode) or not isValid(itemNode.id) then return

        ' grab all photos inside photo album
        photoAlbumData = api.users.GetItemsByQuery(m.global.session.user.id, {
            "parentId": itemNode.id,
            "includeItemTypes": "Photo",
            "sortBy": "Random",
            "Recursive": true
        })
        print "photoAlbumData=", photoAlbumData

        if isValid(photoAlbumData) and isValidAndNotEmpty(photoAlbumData.items)
            photoPlayer = CreateObject("roSgNode", "PhotoDetails")
            photoPlayer.isSlideshow = true
            photoPlayer.isRandom = false
            photoPlayer.itemsArray = photoAlbumData.items
            photoPlayer.itemIndex = 0
            m.global.sceneManager.callfunc("pushScene", photoPlayer)
        else
            stopLoadingSpinner()
        end if
    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)
        else
            stopLoadingSpinner()
        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)
        else
            stopLoadingSpinner()
        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)
        else
            stopLoadingSpinner()
        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": m.global.session.user.settings["ui.details.enablerewatchingnextup"],
            "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)
                else
                    stopLoadingSpinner()
                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")
            else
                stopLoadingSpinner()
            end if
        end if
    end sub

    ' A container with some kind of videos inside of it
    sub videoContainer(itemNode as object)
        print "itemNode=", itemNode
        collectionType = Lcase(itemNode.collectionType)
        if collectionType = "movies"
            ' get randomized list of videos inside
            data = api.users.GetItemsByQuery(m.global.session.user.id, {
                "parentId": itemNode.id,
                "sortBy": "Random",
                "recursive": true,
                "includeItemTypes": "Movie,Video",
                "limit": 2000
            })
            print "data=", data
            if isValid(data) and isValidAndNotEmpty(data.items)
                videoList = []
                ' add each item to the queue
                for each item in data.Items
                    print "data.Item=", item
                    ' only add videos we're not currently watching
                    if isValid(item.userdata) and isValid(item.userdata.PlaybackPositionTicks)
                        if item.userdata.PlaybackPositionTicks = 0
                            videoList.push(item)
                        end if
                    end if
                end for
                quickplay.pushToQueue(videoList)
            else
                stopLoadingSpinner()
            end if
            return
        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",
                "recursive": true,
                "excludeItemTypes": "Season",
                "imageTypeLimit": 0,
                "enableUserData": false,
                "EnableTotalRecordCount": false,
                "enableImages": false
            })

            print "tvshowsData=", tvshowsData

            if isValid(tvshowsData) and isValidAndNotEmpty(tvshowsData.items)
                ' the type of media returned from api may change.
                if tvshowsData.items[0].Type = "Series"
                    quickplay.multipleSeries(tvshowsData.items)
                else
                    ' if first item is not a series, then assume they are all videos and/or episodes
                    quickplay.pushToQueue(tvshowsData.items)
                end if
            else
                stopLoadingSpinner()
            end if
        else
            stopLoadingSpinner()
            print "Quick Play videoContainer WARNING: Unknown collection type"
        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 = isValid(item.IndexNumber) ? item.IndexNumber - 1 : 0
                        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
        else
            stopLoadingSpinner()
        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", "Recording"],
            "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")
        else
            stopLoadingSpinner()
        end if
    end sub

    ' Quick Play A TVChannel
    sub tvChannel(itemNode as object)
        if not isValid(itemNode) or not isValid(itemNode.id) then return

        group = CreateVideoPlayerGroup(itemNode.id)
        stopLoadingSpinner()
        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

        group = CreateVideoPlayerGroup(itemNode.json.ChannelId)
        stopLoadingSpinner()
        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
        else
            stopLoadingSpinner()
        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", "Recording", "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)
        print "folderType=", folderType
        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 if folderType = "photoalbum"
            paramArray["parentId"] = itemNode.id
            paramArray["includeItemTypes"] = "Photo"
            paramArray.delete("videoTypes")
            paramArray.delete("Recursive")
        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
                if folderType = "photoalbum"
                    photoPlayer = CreateObject("roSgNode", "PhotoDetails")
                    photoPlayer.isSlideshow = true
                    photoPlayer.isRandom = false
                    photoPlayer.itemsArray = folderData.items
                    photoPlayer.itemIndex = 0
                    m.global.sceneManager.callfunc("pushScene", photoPlayer)
                else
                    quickplay.pushToQueue(folderData.items, true)
                end if
            end if
        else
            stopLoadingSpinner()
        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"
            quickplay.videoContainer(itemNode)
        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)
            else
                stopLoadingSpinner()
            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)
                else
                    stopLoadingSpinner()
                end if
            end if
        else if collectionType = "tvshows" or collectionType = "collectionfolder"
            quickplay.videoContainer(itemNode)
        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)
            else
                stopLoadingSpinner()
            end if
        else if collectionType = "homevideos"
            ' Photo library - items can be type video, photo, or photoAlbum

            ' grab all photos inside library
            folderData = api.users.GetItemsByQuery(m.global.session.user.id, {
                "parentId": itemNode.id,
                "includeItemTypes": "Photo",
                "sortBy": "Random",
                "Recursive": true
            })
            print "folderData=", folderData

            if isValid(folderData) and isValidAndNotEmpty(folderData.items)
                photoPlayer = CreateObject("roSgNode", "PhotoDetails")
                photoPlayer.isSlideshow = true
                photoPlayer.isRandom = false
                photoPlayer.itemsArray = folderData.items
                photoPlayer.itemIndex = 0
                m.global.sceneManager.callfunc("pushScene", photoPlayer)
            else
                stopLoadingSpinner()
            end if
        else
            stopLoadingSpinner()
            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)
                else
                    stopLoadingSpinner()
                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)
            else
                stopLoadingSpinner()
            end if
        else if collectionType = "movies"
            quickplay.videoContainer(itemNode)
        else if collectionType = "tvshows"
            quickplay.videoContainer(itemNode)
        else
            stopLoadingSpinner()
            print "Quick Play CollectionFolder WARNING: Unknown collection type"
        end if
    end sub

end namespace