Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Playlist support & TV Shuffle #986

Merged
merged 15 commits into from
Feb 25, 2023
Merged
161 changes: 161 additions & 0 deletions components/GetPlaybackInfoTask.brs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
sub init()
m.top.functionName = "getPlaybackInfoTask"
end sub

function ItemPostPlaybackInfo(id as string, mediaSourceId = "" as string, audioTrackIndex = -1 as integer, subtitleTrackIndex = -1 as integer, startTimeTicks = 0 as longinteger)
body = {
"DeviceProfile": getDeviceProfile()
}
params = {
"UserId": get_setting("active_user"),
"StartTimeTicks": startTimeTicks,
"IsPlayback": true,
"AutoOpenLiveStream": true,
"MaxStreamingBitrate": "140000000",
"MaxStaticBitrate": "140000000",
"SubtitleStreamIndex": subtitleTrackIndex
}

mediaSourceId = id
if mediaSourceId <> "" then params.MediaSourceId = mediaSourceId

if audioTrackIndex > -1 then params.AudioStreamIndex = audioTrackIndex

req = APIRequest(Substitute("Items/{0}/PlaybackInfo", id), params)
req.SetRequest("POST")
return postJson(req, FormatJson(body))
end function

' Returns an array of playback info to be displayed during playback.
' In the future, with a custom playback info view, we can return an associated array.
sub getPlaybackInfoTask()
sessions = api_API().sessions.get()

m.playbackInfo = ItemPostPlaybackInfo(m.top.videoID)

if isValid(sessions) and sessions.Count() > 0
m.top.data = { playbackInfo: GetTranscodingStats(sessions[0]) }
else
m.top.data = { playbackInfo: [tr("Unable to get playback information")] }
end if
end sub

function GetTranscodingStats(session)
sessionStats = { data: [] }

if isValid(session.TranscodingInfo) and session.TranscodingInfo.Count() > 0
transcodingReasons = session.TranscodingInfo.TranscodeReasons
videoCodec = session.TranscodingInfo.VideoCodec
audioCodec = session.TranscodingInfo.AudioCodec
totalBitrate = session.TranscodingInfo.Bitrate
audioChannels = session.TranscodingInfo.AudioChannels

if isValid(transcodingReasons) and transcodingReasons.Count() > 0
sessionStats.data.push("<header>" + tr("Transcoding Information") + "</header>")
for each item in transcodingReasons
sessionStats.data.push("<b>• " + tr("Reason") + ":</b> " + item)
end for
end if

if isValid(videoCodec)
data = "<b>• " + tr("Video Codec") + ":</b> " + videoCodec
if session.TranscodingInfo.IsVideoDirect
data = data + " (" + tr("direct") + ")"
end if
sessionStats.data.push(data)
end if

if isValid(audioCodec)
data = "<b>• " + tr("Audio Codec") + ":</b> " + audioCodec
if session.TranscodingInfo.IsAudioDirect
data = data + " (" + tr("direct") + ")"
end if
sessionStats.data.push(data)
end if

if isValid(totalBitrate)
data = "<b>• " + tr("Total Bitrate") + ":</b> " + getDisplayBitrate(totalBitrate)
sessionStats.data.push(data)
end if

if isValid(audioChannels)
data = "<b>• " + tr("Audio Channels") + ":</b> " + Str(audioChannels)
sessionStats.data.push(data)
end if
end if

if havePlaybackInfo()
stream = m.playbackInfo.mediaSources[0].MediaStreams[0]
sessionStats.data.push("<header>" + tr("Stream Information") + "</header>")
if isValid(stream.Container)
data = "<b>• " + tr("Container") + ":</b> " + stream.Container
sessionStats.data.push(data)
end if
if isValid(stream.Size)
data = "<b>• " + tr("Size") + ":</b> " + stream.Size
sessionStats.data.push(data)
end if
if isValid(stream.BitRate)
data = "<b>• " + tr("Bit Rate") + ":</b> " + getDisplayBitrate(stream.BitRate)
sessionStats.data.push(data)
end if
if isValid(stream.Codec)
data = "<b>• " + tr("Codec") + ":</b> " + stream.Codec
sessionStats.data.push(data)
end if
if isValid(stream.CodecTag)
data = "<b>• " + tr("Codec Tag") + ":</b> " + stream.CodecTag
sessionStats.data.push(data)
end if
if isValid(stream.VideoRangeType)
data = "<b>• " + tr("Video range type") + ":</b> " + stream.VideoRangeType
sessionStats.data.push(data)
end if
if isValid(stream.PixelFormat)
data = "<b>• " + tr("Pixel format") + ":</b> " + stream.PixelFormat
sessionStats.data.push(data)
end if
if isValid(stream.Width) and isValid(stream.Height)
data = "<b>• " + tr("WxH") + ":</b> " + Str(stream.Width) + " x " + Str(stream.Height)
sessionStats.data.push(data)
end if
if isValid(stream.Level)
data = "<b>• " + tr("Level") + ":</b> " + Str(stream.Level)
sessionStats.data.push(data)
end if
end if

return sessionStats
end function

function havePlaybackInfo()
if not isValid(m.playbackInfo)
return false
end if

if not isValid(m.playbackInfo.mediaSources)
return false
end if

if m.playbackInfo.mediaSources.Count() <= 0
return false
end if

if not isValid(m.playbackInfo.mediaSources[0].MediaStreams)
return false
end if

if m.playbackInfo.mediaSources[0].MediaStreams.Count() <= 0
return false
end if

return true
end function

function getDisplayBitrate(bitrate)
if bitrate > 1000000
return Str(Fix(bitrate / 1000000)) + " Mbps"
else
return Str(Fix(bitrate / 1000)) + " Kbps"
end if
end function
14 changes: 14 additions & 0 deletions components/GetPlaybackInfoTask.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>

<component name="GetPlaybackInfoTask" extends="Task">
<interface>
<field id="videoID" type="string" />
<field id="data" type="assocarray" />
</interface>
<script type="text/brightscript" uri="GetPlaybackInfoTask.brs" />
<script type="text/brightscript" uri="pkg:/source/utils/config.brs" />
<script type="text/brightscript" uri="pkg:/source/utils/misc.brs" />
<script type="text/brightscript" uri="pkg:/source/utils/deviceCapabilities.brs" />
<script type="text/brightscript" uri="pkg:/source/api/baserequest.brs" />
<script type="text/brightscript" uri="pkg:/source/roku_modules/api/api.brs" />
</component>
13 changes: 13 additions & 0 deletions components/GetShuffleEpisodesTask.brs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
sub init()
m.top.functionName = "getShuffleEpisodesTask"
end sub

sub getShuffleEpisodesTask()
data = api_API().shows.getepisodes(m.top.showID, {
UserId: get_setting("active_user"),
SortBy: "Random",
Limit: 200
})

m.top.data = data
end sub
11 changes: 11 additions & 0 deletions components/GetShuffleEpisodesTask.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8" ?>

<component name="GetShuffleEpisodesTask" extends="Task">
<interface>
<field id="showID" type="string" />
<field id="data" type="assocarray" />
</interface>
<script type="text/brightscript" uri="GetShuffleEpisodesTask.brs" />
<script type="text/brightscript" uri="pkg:/source/utils/config.brs" />
<script type="text/brightscript" uri="pkg:/source/roku_modules/api/api.brs" />
</component>
4 changes: 4 additions & 0 deletions components/ItemGrid/GridItem.brs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ sub itemContentChanged()
m.itemPoster.uri = itemData.PosterUrl
m.itemIcon.uri = itemData.iconUrl
m.itemText.text = itemData.Title
else if itemData.type = "Playlist"
m.itemPoster.uri = itemData.PosterUrl
m.itemIcon.uri = itemData.iconUrl
m.itemText.text = itemData.Title
else if itemData.type = "Photo"
m.itemPoster.uri = itemData.PosterUrl
m.itemIcon.uri = itemData.iconUrl
Expand Down
6 changes: 6 additions & 0 deletions components/ItemGrid/LoadItemsTask2.brs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ sub loadItems()
tmp = CreateObject("roSGNode", "PhotoData")
else if item.type = "PhotoAlbum"
tmp = CreateObject("roSGNode", "FolderData")
else if item.type = "Playlist"
tmp = CreateObject("roSGNode", "PlaylistData")
tmp.type = "Playlist"
tmp.image = PosterImage(item.id, { "maxHeight": 425, "maxWidth": 290, "quality": "90" })
else if item.type = "Episode"
tmp = CreateObject("roSGNode", "TVEpisode")
else if item.Type = "Genre"
Expand Down Expand Up @@ -207,6 +211,8 @@ sub loadItems()
tmp = CreateObject("roSGNode", "MusicArtistData")
else if item.Type = "Audio"
tmp = CreateObject("roSGNode", "MusicSongData")
tmp.type = "Audio"
tmp.image = api_API().items.getimageurl(item.id, "primary", 0, { "maxHeight": 280, "maxWidth": 280, "quality": "90" })
else if item.Type = "MusicGenre"
tmp = CreateObject("roSGNode", "FolderData")
tmp.title = item.name
Expand Down
Loading