Skip to content

Commit

Permalink
Merge pull request #1416 from JarodTAerts/developer/jarodtaerts/tvsho…
Browse files Browse the repository at this point in the history
…w-specialfeatures

Add support for TV show season level extra features
  • Loading branch information
1hitsong authored Oct 26, 2023
2 parents 6c38d1a + ec332f1 commit 4222882
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 21 deletions.
42 changes: 35 additions & 7 deletions components/tvshows/TVEpisodes.brs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import "pkg:/source/api/Image.brs"
import "pkg:/source/api/baserequest.brs"
import "pkg:/source/utils/config.brs"
import "pkg:/source/utils/misc.brs"
import "pkg:/source/api/sdk.bs"

sub init()
m.top.optionsAvailable = false

m.rows = m.top.findNode("picker")
m.poster = m.top.findNode("seasonPoster")
m.Shuffle = m.top.findNode("Shuffle")
m.shuffle = m.top.findNode("shuffle")
m.extras = m.top.findNode("extras")
m.tvEpisodeRow = m.top.findNode("tvEpisodeRow")

m.unplayedCount = m.top.findNode("unplayedCount")
Expand All @@ -21,6 +23,13 @@ sub setSeasonLoading()
m.top.overhangTitle = tr("Loading...")
end sub

' Updates the visibility of the Extras button based on if this season has any extra features
sub setExtraButtonVisibility()
if isValid(m.top.extrasObjects) and isValidAndNotEmpty(m.top.extrasObjects.items)
m.extras.visible = true
end if
end sub

sub updateSeason()
if m.global.session.user.settings["ui.tvshows.disableUnwatchedEpisodeCount"] = false
if isValid(m.top.seasonData) and isValid(m.top.seasonData.UserData) and isValid(m.top.seasonData.UserData.UnplayedItemCount)
Expand All @@ -33,26 +42,36 @@ sub updateSeason()

imgParams = { "maxHeight": 450, "maxWidth": 300 }
m.poster.uri = ImageURL(m.top.seasonData.Id, "Primary", imgParams)
m.Shuffle.visible = true
m.shuffle.visible = true
m.top.overhangTitle = m.top.seasonData.SeriesName + " - " + m.top.seasonData.name
end sub

' Handle navigation input from the remote and act on it
function onKeyEvent(key as string, press as boolean) as boolean
handled = false

if key = "left" and m.tvEpisodeRow.hasFocus()
m.Shuffle.setFocus(true)
m.shuffle.setFocus(true)
return true
end if

if key = "right" and (m.Shuffle.hasFocus())
if key = "right" and (m.shuffle.hasFocus() or m.extras.hasFocus())
m.tvEpisodeRow.setFocus(true)
return true
end if

if key = "OK" or key = "play"
if m.extras.visible and key = "up" and m.extras.hasFocus()
m.shuffle.setFocus(true)
return true
end if

if m.Shuffle.hasFocus()
if m.extras.visible and key = "down" and m.shuffle.hasFocus()
m.extras.setFocus(true)
return true
end if

if key = "OK" or key = "play"
if m.shuffle.hasFocus()
episodeList = m.rows.getChild(0).objects.items

for i = 0 to episodeList.count() - 1
Expand All @@ -66,6 +85,16 @@ function onKeyEvent(key as string, press as boolean) as boolean
m.global.queueManager.callFunc("playQueue")
return true
end if

if m.extras.visible and m.extras.hasFocus()
if LCase(m.extras.text.trim()) = LCase(tr("Extras"))
m.extras.text = tr("Episodes")
m.top.objects = m.top.extrasObjects
else
m.extras.text = tr("Extras")
m.top.objects = m.top.episodeObjects
end if
end if
end if

focusedChild = m.top.focusedChild.focusedChild
Expand All @@ -81,7 +110,6 @@ function onKeyEvent(key as string, press as boolean) as boolean
m.top.lastFocus = focusedChild
itemToPlay = focusedChild.content.getChild(focusedChild.rowItemFocused[0]).getChild(0)
if isValid(itemToPlay) and isValid(itemToPlay.id) and itemToPlay.id <> ""
itemToPlay.type = "Episode"
m.top.quickPlayNode = itemToPlay
end if
handled = true
Expand Down
5 changes: 4 additions & 1 deletion components/tvshows/TVEpisodes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
<Label id="unplayedEpisodeCount" width="90" height="60" font="font:SmallestBoldSystemFont" horizAlign="center" vertAlign="center" />
</Rectangle>
</Poster>
<JFButton id="Shuffle" minChars="10" text="Shuffle" translation="[90, 640]" visible="false"></JFButton>
<JFButton id="shuffle" minChars="10" text="Shuffle" translation="[90, 640]" visible="false"></JFButton>
<JFButton id="extras" minChars="10" text="Extras" translation="[90, 740]" visible="false"></JFButton>
<TVEpisodeRowWithOptions id="picker" visible="true" />
</children>
<interface>
<field id="episodeSelected" alias="picker.itemSelected" />
<field id="quickPlayNode" type="node" alwaysNotify="true" />
<field id="seasonData" type="assocarray" onChange="setSeasonLoading" />
<field id="objects" alias="picker.objects" />
<field id="episodeObjects" type="assocarray" />
<field id="extrasObjects" type="assocarray" onChange="setExtraButtonVisibility" />
</interface>
</component>
8 changes: 8 additions & 0 deletions locale/en_US/translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,14 @@
<source>Server</source>
<translation>Server</translation>
</message>
<message>
<source>Extras</source>
<translation>Extras</translation>
</message>
<message>
<source>Episodes</source>
<translation>Episodes</translation>
</message>
<message>
<source>Error Retrieving Content</source>
<translation>Error Retrieving Content</translation>
Expand Down
4 changes: 1 addition & 3 deletions settings/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
"type": "bool",
"default": "false"
}

]
},
{
Expand Down Expand Up @@ -126,7 +125,6 @@
]
}
]

},
{
"title": "Video Codec Support",
Expand Down Expand Up @@ -355,4 +353,4 @@
}
]
}
]
]
6 changes: 6 additions & 0 deletions source/ShowScenes.brs
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,9 @@ function CreateSeasonDetailsGroup(series as object, season as object) as dynamic
m.global.sceneManager.callFunc("pushScene", group)
group.seasonData = seasonMetaData.json
group.objects = TVEpisodes(series.id, season.id)
group.episodeObjects = group.objects
group.extrasObjects = TVSeasonExtras(season.id)

' watch for button presses
group.observeField("episodeSelected", m.port)
group.observeField("quickPlayNode", m.port)
Expand Down Expand Up @@ -770,6 +773,9 @@ function CreateSeasonDetailsGroupByID(seriesID as string, seasonID as string) as
m.global.sceneManager.callFunc("pushScene", group)
group.seasonData = seasonMetaData.json
group.objects = TVEpisodes(seriesID, seasonID)
group.episodeObjects = group.objects
group.extrasObjects = TVSeasonExtras(seasonID)

' watch for button presses
group.observeField("episodeSelected", m.port)
group.observeField("quickPlayNode", m.port)
Expand Down
52 changes: 42 additions & 10 deletions source/api/Items.brs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import "pkg:/source/api/sdk.bs"

function ItemGetPlaybackInfo(id as string, startTimeTicks = 0 as longinteger)
params = {
"UserId": m.global.session.user.id,
Expand Down Expand Up @@ -417,26 +419,25 @@ function TVSeasons(id as string) as dynamic
return data
end function

function TVEpisodes(show_id as string, season_id as string) as dynamic
url = Substitute("Shows/{0}/Episodes", show_id)
resp = APIRequest(url, { "seasonId": season_id, "UserId": m.global.session.user.id, "fields": "MediaStreams,MediaSources" })

data = getJson(resp)
' validate data
' Returns a list of TV Shows for a given TV Show and season
' Accepts strings for the TV Show Id and the season Id
function TVEpisodes(showId as string, seasonId as string) as dynamic
' Get and validate data
data = api.shows.GetEpisodes(showId, { "seasonId": seasonId, "UserId": m.global.session.user.id, "fields": "MediaStreams,MediaSources" })
if data = invalid or data.Items = invalid then return invalid

results = []
for each item in data.Items
imgParams = { "maxWidth": 400, "maxheight": 250 }
tmp = CreateObject("roSGNode", "TVEpisodeData")
tmp.image = PosterImage(item.id, imgParams)
if tmp.image <> invalid
tmp.image = PosterImage(item.id, { "maxWidth": 400, "maxheight": 250 })
if isValid(tmp.image)
tmp.image.posterDisplayMode = "scaleToZoom"
end if
tmp.json = item
tmpMetaData = ItemMetaData(item.id)

' validate meta data
if tmpMetaData <> invalid and tmpMetaData.overview <> invalid
if isValid(tmpMetaData) and isValid(tmpMetaData.overview)
tmp.overview = tmpMetaData.overview
end if
results.push(tmp)
Expand All @@ -445,6 +446,37 @@ function TVEpisodes(show_id as string, season_id as string) as dynamic
return data
end function

' Returns a list of extra features for a TV Show season
' Accepts a string that is a TV Show season id
function TVSeasonExtras(seasonId as string) as dynamic
' Get and validate TV extra features data
data = api.users.GetSpecialFeatures(m.global.session.user.id, seasonId)
if not isValid(data) then return invalid

results = []
for each item in data
tmp = CreateObject("roSGNode", "TVEpisodeData")
tmp.image = PosterImage(item.id, { "maxWidth": 400, "maxheight": 250 })
if isValid(tmp.image)
tmp.image.posterDisplayMode = "scaleToZoom"
end if
tmp.json = item

' Force item type to Video so episode auto queue is not attempted
tmp.type = "Video"
tmpMetaData = ItemMetaData(item.id)

' Validate meta data
if isValid(tmpMetaData) and isValid(tmpMetaData.overview)
tmp.overview = tmpMetaData.overview
end if
results.push(tmp)
end for

' Build that data format that the TVEpisodeRow expects
return { Items: results }
end function

function TVEpisodeShuffleList(show_id as string)
url = Substitute("Shows/{0}/Episodes", show_id)
resp = APIRequest(url, {
Expand Down

0 comments on commit 4222882

Please sign in to comment.