Create music artist view

This commit is contained in:
1hitsong 2022-05-13 22:35:50 -04:00
parent 047f884b35
commit 8f516926ef
12 changed files with 286 additions and 0 deletions

View File

@ -57,6 +57,9 @@ sub itemContentChanged()
else if itemData.type = "Photo"
m.itemPoster.uri = itemData.PosterUrl
m.itemText.text = itemData.Title
else if itemData.type = "MusicArtist"
m.itemPoster.uri = itemData.PosterUrl
m.itemText.text = itemData.Title
else
print "Unhandled Grid Item Type: " + itemData.type
end if

View File

@ -100,6 +100,8 @@ sub loadInitialItems()
m.loadItemsTask.itemType = "Movie"
else if m.top.parentItem.collectionType = "tvshows"
m.loadItemsTask.itemType = "Series"
else if m.top.parentItem.collectionType = "music"
m.loadItemsTask.itemType = "MusicArtist"
else if m.top.parentItem.collectionType = "livetv"
m.loadItemsTask.itemType = "LiveTV"
@ -208,6 +210,19 @@ sub SetUpOptions()
options.views = []
options.sort = []
options.filter = []
'Music
else if m.top.parentItem.collectionType = "music"
options.views = [{ "Title": tr("Music"), "Name": "music" }]
options.sort = [
{ "Title": tr("TITLE"), "Name": "SortName" },
{ "Title": tr("DATE_ADDED"), "Name": "DateCreated" },
{ "Title": tr("DATE_PLAYED"), "Name": "DatePlayed" },
{ "Title": tr("RELEASE_DATE"), "Name": "PremiereDate" },
]
options.filter = [
{ "Title": tr("All"), "Name": "All" },
{ "Title": tr("Favorites"), "Name": "Favorites" }
]
else
options.views = [
{ "Title": tr("Default"), "Name": "default" }

View File

@ -76,6 +76,8 @@ sub loadItems()
tmp = CreateObject("roSGNode", "PhotoData")
else if item.type = "PhotoAlbum"
tmp = CreateObject("roSGNode", "FolderData")
else if item.Type = "MusicArtist"
tmp = CreateObject("roSGNode", "MusicArtistData")
else
print "[LoadItems] Unknown Type: " item.Type
end if

View File

@ -0,0 +1,32 @@
sub setFields()
json = m.top.json
m.top.id = json.id
m.top.favorite = json.UserData.isFavorite
m.top.Type = "MusicArtist"
setPoster()
end sub
sub setPoster()
if m.top.image <> invalid
m.top.posterURL = m.top.image.url
else
if m.top.json.ImageTags.Primary <> invalid
imgParams = { "maxHeight": 440, "maxWidth": 295, "Tag": m.top.json.ImageTags.Primary }
m.top.posterURL = ImageURL(m.top.json.id, "Primary", imgParams)
else if m.top.json.BackdropImageTags[0] <> invalid
imgParams = { "maxHeight": 440, "Tag": m.top.json.BackdropImageTags[0] }
m.top.posterURL = ImageURL(m.top.json.id, "Backdrop", imgParams)
else if m.top.json.ParentThumbImageTag <> invalid and m.top.json.ParentThumbItemId <> invalid
imgParams = { "maxHeight": 440, "maxWidth": 295, "Tag": m.top.json.ParentThumbImageTag }
m.top.posterURL = ImageURL(m.top.json.ParentThumbItemId, "Thumb", imgParams)
end if
' Add Backdrop Image
if m.top.json.BackdropImageTags[0] <> invalid
imgParams = { "maxHeight": 720, "maxWidth": 1280, "Tag": m.top.json.BackdropImageTags[0] }
m.top.backdropURL = ImageURL(m.top.json.id, "Backdrop", imgParams)
end if
end if
end sub

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<component name="MusicArtistData" extends="JFContentItem">
<script type="text/brightscript" uri="MusicArtistData.brs" />
<script type="text/brightscript" uri="pkg:/source/api/Image.brs" />
<script type="text/brightscript" uri="pkg:/source/api/baserequest.brs" />
<script type="text/brightscript" uri="pkg:/source/utils/config.brs" />
</component>

View File

@ -0,0 +1,48 @@
sub init()
m.top.itemComponentName = "ListPoster"
m.top.content = getData()
m.top.rowFocusAnimationStyle = "fixedFocusWrap"
m.top.showRowLabel = [false]
m.top.showRowCounter = [true]
m.top.rowLabelOffset = [0, 0]
updateSize()
m.top.setfocus(true)
end sub
sub updateSize()
itemWidth = 200
itemHeight = 320 ' width * 1.5 + text
m.top.visible = true
' size of the whole row
m.top.itemSize = [1800, (itemHeight + 40)]
' spacing between rows
m.top.itemSpacing = [0, 0]
' size of the item in the row
m.top.rowItemSize = [itemWidth, itemHeight]
' spacing between items in a row
m.top.rowItemSpacing = [0, 0]
end sub
function getData()
if m.top.MusicArtistAlbumData = invalid
data = CreateObject("roSGNode", "ContentNode")
return data
end if
seasonData = m.top.MusicArtistAlbumData
data = CreateObject("roSGNode", "ContentNode")
row = data.CreateChild("ContentNode")
row.title = "Seasons"
for each item in seasonData.items
row.appendChild(item)
end for
m.top.content = data
return data
end function

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<component name="MusicArtistAlbumRow" extends="RowList">
<interface>
<field id="MusicArtistAlbumData" type="assocarray" onChange="getData" />
</interface>
<script type="text/brightscript" uri="MusicArtistAlbumRow.brs" />
</component>

View File

@ -0,0 +1,107 @@
sub init()
m.top.optionsAvailable = false
main = m.top.findNode("toplevel")
main.translation = [96, 175]
m.extrasSlider = m.top.findNode("tvSeasonExtras")
'm.extrasSlider.translation = [30,1014]
m.extrasSlider.visible = true
end sub
sub itemContentChanged()
' Updates video metadata
' TODO - make things use item rather than itemData
item = m.top.itemContent
itemData = item.json
m.top.findNode("musicartistPoster").uri = m.top.itemContent.posterURL
' Handle all "As Is" fields
m.top.overhangTitle = itemData.name
setFieldText("overview", itemData.overview)
if type(itemData.RunTimeTicks) = "LongInteger"
setFieldText("runtime", stri(getRuntime()) + " mins")
end if
end sub
sub setFieldText(field, value)
node = m.top.findNode(field)
if node = invalid or value = invalid then return
' Handle non strings... Which _shouldn't_ happen, but hey
if type(value) = "roInt" or type(value) = "Integer"
value = str(value).trim()
else if type(value) = "roFloat" or type(value) = "Float"
value = str(value).trim()
else if type(value) <> "roString" and type(value) <> "String"
value = ""
end if
node.text = value
end sub
function getRuntime() as integer
itemData = m.top.itemContent.json
' A tick is .1ms, so 1/10,000,000 for ticks to seconds,
' then 1/60 for seconds to minutess... 1/600,000,000
return round(itemData.RunTimeTicks / 600000000.0)
end function
function getEndTime() as string
itemData = m.top.itemContent.json
date = CreateObject("roDateTime")
duration_s = int(itemData.RunTimeTicks / 10000000.0)
date.fromSeconds(date.asSeconds() + duration_s)
date.toLocalTime()
return formatTime(date)
end function
function round(f as float) as integer
' BrightScript only has a "floor" round
' This compares floor to floor + 1 to find which is closer
m = int(f)
n = m + 1
x = abs(f - m)
y = abs(f - n)
if y > x
return m
else
return n
end if
end function
function onKeyEvent(key as string, press as boolean) as boolean
if not press then return false
overview = m.top.findNode("overview")
topGrp = m.top.findNode("seasons")
bottomGrp = m.top.findNode("extrasGrid")
if key = "down" and overview.hasFocus()
topGrp.setFocus(true)
return true
else if key = "down" and topGrp.hasFocus()
bottomGrp.setFocus(true)
m.top.findNode("VertSlider").reverse = false
m.top.findNode("extrasFader").reverse = false
m.top.findNode("pplAnime").control = "start"
return true
else if key = "up" and bottomGrp.hasFocus()
if bottomGrp.itemFocused = 0
m.top.findNode("VertSlider").reverse = true
m.top.findNode("extrasFader").reverse = true
m.top.findNode("pplAnime").control = "start"
topGrp.setFocus(true)
return true
end if
else if key = "up" and topGrp.hasFocus()
overview.setFocus(true)
return true
end if
return false
end function

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8" ?>
<component name="MusicArtistDetails" extends="JFGroup">
<children>
<LayoutGroup id="toplevel" layoutDirection="vert" itemSpacings="[-10]" >
<LayoutGroup id="main_group" layoutDirection="horiz" itemSpacings="[15]" >
<Poster id="musicartistPoster" width="450" height="450" />
<LayoutGroup layoutDirection="vert" itemSpacings="[15]">
<Label id="overview" wrap="true" width="1250" maxLines="8" />
</LayoutGroup>
</LayoutGroup>
<MusicArtistAlbumRow id="seasons" />
</LayoutGroup>
<ExtrasSlider id="tvSeasonExtras" />
</children>
<interface>
<field id="itemContent" type="node" onChange="itemContentChanged" />
<field id="musicArtistAlbumData" type="assocarray" alias="seasons.MusicArtistAlbumData" />
<field id="seasonSelected" alias="seasons.rowItemSelected" />
</interface>
<script type="text/brightscript" uri="pkg:/source/utils/misc.brs" />
<script type="text/brightscript" uri="MusicArtistDetails.brs" />
</component>

View File

@ -154,6 +154,8 @@ sub Main (args as dynamic) as void
end if
else if selectedItem.type = "Photo"
' Nothing to do here, handled in ItemGrid
else if selectedItem.type = "MusicArtist"
group = CreateMusicArtistDetailsGroup(selectedItem.json)
else
' TODO - switch on more node types
message_dialog("This type is not yet supported: " + selectedItem.type + ".")

View File

@ -321,6 +321,21 @@ function CreateSeriesDetailsGroup(series)
return group
end function
function CreateMusicArtistDetailsGroup(musicartist)
group = CreateObject("roSGNode", "MusicArtistDetails")
m.global.sceneManager.callFunc("pushScene", group)
group.itemContent = ItemMetaData(musicartist.id)
group.musicArtistAlbumData = MusicAlbums(musicartist.id)
group.observeField("seasonSelected", m.port)
extras = group.findNode("extrasGrid")
extras.observeField("selectedItem", m.port)
return group
end function
function CreateSeasonDetailsGroup(series, season)
group = CreateObject("roSGNode", "TVEpisodes")
group.optionsAvailable = false

View File

@ -118,6 +118,11 @@ function ItemMetaData(id as string)
tmp.image = PosterImage(data.id, { "MaxWidth": 300, "MaxHeight": 450 })
tmp.json = data
return tmp
else if data.type = "MusicArtist"
tmp = CreateObject("roSGNode", "MusicArtistData")
tmp.image = PosterImage(data.id)
tmp.json = data
return tmp
else
print "Items.brs::ItemMetaData processed unhandled type: " data.type
' Return json if we don't know what it is
@ -125,6 +130,27 @@ function ItemMetaData(id as string)
end if
end function
' Music Albums Belonging to an Artist
function MusicAlbums(id as string)
url = Substitute("Users/{0}/Items", get_setting("active_user"), id)
resp = APIRequest(url, {
"UserId": get_setting("active_user"),
"parentId": id,
"includeitemtypes": "MusicAlbum"
})
data = getJson(resp)
results = []
for each item in data.Items
tmp = CreateObject("roSGNode", "TVEpisodeData")
tmp.image = PosterImage(item.id)
tmp.json = item
results.push(tmp)
end for
data.Items = results
return data
end function
' Seasons for a TV Show
function TVSeasons(id as string)
url = Substitute("Shows/{0}/Seasons", id)