Merge branch 'jellyfin:unstable' into searchFix

This commit is contained in:
matty-r 2023-10-29 09:53:02 +10:00 committed by GitHub
commit 503a063d8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
314 changed files with 7306 additions and 917 deletions

View File

@ -27,3 +27,8 @@ jobs:
uses: stefanzweifel/git-auto-commit-action@8756aa072ef5b4a080af5dc8fef36c5d586e521d # v5
with:
commit_message: Update API docs
# use jellyfin-bot to commit the changes instead of the default github-actions[bot]
commit_user_name: jellyfin-bot
commit_user_email: team@jellyfin.org
# use jellyfin-bot to author the changes instead of the default author of the merge commit
commit_author: jellyfin-bot <team@jellyfin.org>

View File

@ -2,9 +2,9 @@
name: deploy-api-docs
on:
# Runs on pushes targeting the default branch
push:
branches: ["unstable"]
paths: ["docs/**"] # only run if the docs are updated
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
@ -36,7 +36,7 @@ jobs:
uses: actions/upload-pages-artifact@a753861a5debcf57bf8b404356158c8e1e33150c # v2
with:
# Only upload the api docs folder
path: "docs/api/*"
path: "docs/api"
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@9dbe3824824f8a1377b8e298bafde1a50ede43e5 # v2

View File

@ -16,5 +16,6 @@
"**/.git": true,
"**/node_modules": true,
"docs/api/**": true
}
},
"brightscriptcomment.addExtraAtStartAndEnd": false
}

View File

@ -35,7 +35,7 @@ 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.sessions.Get()
sessions = api.sessions.Get({ "deviceId": m.global.device.serverDeviceName })
m.playbackInfo = ItemPostPlaybackInfo(m.top.videoID)

View File

@ -134,7 +134,15 @@ sub loadInitialItems()
m.view = m.global.session.user.settings["display." + m.top.parentItem.Id + ".landing"]
end if
if m.sortField = invalid then m.sortField = "SortName"
if m.sortField = invalid
' Set the default order for boxsets to the Release Date - API calls it PremiereDate
if LCase(m.top.parentItem.json.Type) = "boxset"
m.sortField = "PremiereDate"
else
m.sortField = "SortName"
end if
end if
if m.filter = invalid then m.filter = "All"
if sortAscendingStr = invalid or sortAscendingStr = true
@ -717,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
@ -734,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
@ -780,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"

View File

@ -144,6 +144,7 @@ sub loadInitialItems()
if not isValid(m.filter) then m.filter = "All"
if not isValid(m.filterOptions) then m.filterOptions = "{}"
if not isValid(m.view) then m.view = "Movies"
if not isValid(m.sortAscending) then m.sortAscending = true
m.filterOptions = ParseJson(m.filterOptions)
@ -707,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
'
@ -869,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

View File

@ -131,6 +131,7 @@ sub loadInitialItems()
if not isValid(m.sortField) then m.sortField = "SortName"
if not isValid(m.filter) then m.filter = "All"
if not isValid(m.view) then m.view = "ArtistsPresentation"
if not isValid(m.sortAscending) then m.sortAscending = true
m.top.showItemTitles = m.global.session.user.settings["itemgrid.gridTitles"]
@ -572,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
'
@ -750,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)
@ -760,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
@ -775,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"

View File

@ -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

View File

@ -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

View File

@ -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" />

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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 = {}

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -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" />

View File

@ -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

View File

@ -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>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More