diff --git a/Makefile b/Makefile index bd07230e7..b22a6d4da 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # If you want to get_images, you'll also need convert from ImageMagick ########################################################################## -VERSION := 2.1.4 +VERSION := 2.1.5 ## usage diff --git a/components/ItemGrid/GridItem.bs b/components/ItemGrid/GridItem.bs index b98ddcc64..9f7a62ae1 100644 --- a/components/ItemGrid/GridItem.bs +++ b/components/ItemGrid/GridItem.bs @@ -20,9 +20,6 @@ sub init() m.checkmark.width = 90 m.checkmark.height = 60 - m.itemText.translation = [0, m.itemPoster.height + 7] - m.itemText.visible = m.gridTitles = "showalways" - ' Add some padding space when Item Titles are always showing if m.itemText.visible then m.itemText.maxWidth = 250 @@ -38,6 +35,9 @@ sub init() end if end if + m.itemText.translation = [0, m.itemPoster.height + 7] + m.itemText.visible = m.gridTitles = "showalways" + end sub sub itemContentChanged() diff --git a/components/ItemGrid/ItemGrid.bs b/components/ItemGrid/ItemGrid.bs index 21789b45e..759bacd7e 100644 --- a/components/ItemGrid/ItemGrid.bs +++ b/components/ItemGrid/ItemGrid.bs @@ -6,6 +6,7 @@ import "pkg:/source/roku_modules/log/LogMixin.brs" sub init() m.log = log.Logger("ItemGrid") + m.log.debug("start init()") m.options = m.top.findNode("options") m.showItemCount = m.global.session.user.settings["itemgrid.showItemCount"] @@ -70,6 +71,7 @@ sub init() m.resetGrid = m.global.session.user.settings["itemgrid.reset"] m.top.gridTitles = m.global.session.user.settings["itemgrid.gridTitles"] + m.log.debug("end init()") end sub 'Genre Item Selected @@ -79,6 +81,7 @@ end sub 'Load initial set of Data sub loadInitialItems() + m.log.debug("start loadInitialItems()") m.loadItemsTask.control = "stop" startLoadingSpinner() @@ -235,6 +238,7 @@ sub loadInitialItems() startLoadingSpinner(false) m.loadItemsTask.control = "RUN" SetUpOptions() + m.log.debug("end loadInitialItems()") end sub ' Set Movies view, sort, and filter options @@ -445,6 +449,7 @@ end sub 'Handle loaded data, and add to Grid sub ItemDataLoaded(msg) + m.log.debug("start ItemDataLoaded()") itemData = msg.GetData() m.loadItemsTask.unobserveField("content") m.loadItemsTask.content = [] @@ -501,22 +506,28 @@ sub ItemDataLoaded(msg) end if stopLoadingSpinner() + m.log.debug("end ItemDataLoaded()") end sub 'Set Background Image sub SetBackground(backgroundUri as string) - + m.log.debug("start SetBackground()", backgroundUri, m.swapAnimation.state, m.newBackdrop.loadStatus) 'If a new image is being loaded, or transitioned to, store URL to load next - if m.swapAnimation.state <> "stopped" or m.newBackdrop.loadStatus = "loading" - m.queuedBGUri = backgroundUri - return + if not m.top.alphaActive + if m.swapAnimation.state <> "stopped" or m.newBackdrop.loadStatus = "loading" + m.log.debug("caching new background URI") + m.queuedBGUri = backgroundUri + return + end if end if m.newBackdrop.uri = backgroundUri + m.log.debug("end SetBackground()") end sub 'Handle new item being focused sub onItemFocused() + m.log.debug("start onItemFocused()", m.itemGrid.currFocusRow, m.itemGrid.itemFocused) focusedRow = m.itemGrid.currFocusRow @@ -525,7 +536,7 @@ sub onItemFocused() updateTitle() ' If no selected item, set background to parent backdrop - if itemInt = -1 + if itemInt = -1 or focusedRow = -1 return end if @@ -538,6 +549,7 @@ sub onItemFocused() if focusedRow >= m.loadedRows - 5 and m.loadeditems < m.loadItemsTask.totalRecordCount loadMoreData() end if + m.log.debug("end onItemFocused()") end sub 'When Image Loading Status changes @@ -558,6 +570,7 @@ sub swapDone() 'If there is another one to load if m.newBackdrop.uri <> m.queuedBGUri and m.queuedBGUri <> "" + m.log.debug("Loading queued backdrop image", m.queuedBGUri) SetBackground(m.queuedBGUri) m.queuedBGUri = "" end if @@ -566,6 +579,7 @@ end sub 'Load next set of items sub loadMoreData() + m.log.debug("start loadMoreData()") if m.Loading = true then return startLoadingSpinner(false) @@ -573,6 +587,7 @@ sub loadMoreData() m.loadItemsTask.startIndex = m.loadedItems m.loadItemsTask.observeField("content", "ItemDataLoaded") m.loadItemsTask.control = "RUN" + m.log.debug("end loadMoreData()") end sub 'Item Selected @@ -767,6 +782,20 @@ function getItemFocused() return invalid end function +sub alphaActiveChanged() + m.log.debug("start alphaActiveChanged()", m.top.alphaActive) + + if m.top.alphaActive + ' fade into an empty backdrop + m.swapAnimation.state = "stop" + m.queuedBGUri = "" + ' use a 1px image because we can't use the animation to fade into a blank uri string + SetBackground("pkg:/images/1px-262626.png") + end if + + m.log.debug("end alphaActiveChanged()") +end sub + function onKeyEvent(key as string, press as boolean) as boolean if not press then return false @@ -833,11 +862,14 @@ function onKeyEvent(key as string, press as boolean) as boolean return true end if else if key = "left" and topGrp.isinFocusChain() and m.alpha.visible + m.log.debug("Now entering alpha menu") m.top.alphaActive = true topGrp.setFocus(false) m.alphaMenu.setFocus(true) + return true else if key = "right" and m.alpha.isinFocusChain() + m.log.debug("Now leaving alpha menu") m.top.alphaActive = false m.alphaMenu.setFocus(false) topGrp.setFocus(true) diff --git a/components/ItemGrid/ItemGrid.xml b/components/ItemGrid/ItemGrid.xml index bea6a14a6..74b8665c6 100644 --- a/components/ItemGrid/ItemGrid.xml +++ b/components/ItemGrid/ItemGrid.xml @@ -33,7 +33,7 @@ - + diff --git a/components/PlaystateTask.bs b/components/PlaystateTask.bs index fc06ae3e1..556ab52f2 100644 --- a/components/PlaystateTask.bs +++ b/components/PlaystateTask.bs @@ -8,7 +8,7 @@ end sub sub PlaystateUpdate() if m.top.status = "start" url = "Sessions/Playing" - else if m.top.status = "stop" + else if m.top.status = "stop" or m.top.status = "finished" url = "Sessions/Playing/Stopped" else if m.top.status = "update" url = "Sessions/Playing/Progress" diff --git a/components/data/ChannelData.xml b/components/data/ChannelData.xml index b7a2feb51..2d0667b58 100644 --- a/components/data/ChannelData.xml +++ b/components/data/ChannelData.xml @@ -1,6 +1,7 @@ + diff --git a/components/video/VideoPlayerView.bs b/components/video/VideoPlayerView.bs index be0d32be2..b662cfcf9 100644 --- a/components/video/VideoPlayerView.bs +++ b/components/video/VideoPlayerView.bs @@ -1,7 +1,9 @@ import "pkg:/source/utils/misc.bs" import "pkg:/source/utils/config.bs" +import "pkg:/source/roku_modules/log/LogMixin.brs" sub init() + m.log = log.Logger("VideoPlayerView") ' Hide the overhang on init to prevent showing 2 clocks m.top.getScene().findNode("overhang").visible = false m.currentItem = m.global.queueManager.callFunc("getCurrentItem") @@ -602,6 +604,7 @@ end sub ' ' When Video Player state changes sub onState(msg) + m.log.debug("start onState()", m.top.state) if isValid(m.captionTask) m.captionTask.playerState = m.top.state + m.top.globalCaptionMode end if @@ -610,12 +613,23 @@ sub onState(msg) m.osd.playbackState = m.top.state ' When buffering, start timer to monitor buffering process - if m.top.state = "buffering" and m.bufferCheckTimer <> invalid + if m.top.state = "buffering" + ' start buffer timer + if isValid(m.bufferCheckTimer) + m.bufferCheckTimer.control = "start" + m.bufferCheckTimer.ObserveField("fire", "bufferCheck") + end if - ' start timer - m.bufferCheckTimer.control = "start" - m.bufferCheckTimer.ObserveField("fire", "bufferCheck") + ' update server if needed + if not m.playReported + m.playReported = true + ReportPlayback("start") + end if else if m.top.state = "error" + m.log.error(m.top.errorCode, m.top.errorMsg, m.top.errorStr, m.top.errorCode) + + print m.top.errorInfo + if not m.playReported and m.top.transcodeAvailable m.top.retryWithTranscoding = true ' If playback was not reported, retry with transcoding else @@ -625,7 +639,6 @@ sub onState(msg) ' Stop playback and exit player m.top.control = "stop" - m.top.backPressed = true else if m.top.state = "playing" ' Check if next episode is available @@ -651,16 +664,22 @@ sub onState(msg) m.playbackTimer.control = "stop" ReportPlayback("stop") m.playReported = false + else if m.top.state = "finished" + m.playbackTimer.control = "stop" + ReportPlayback("finished") + else + m.log.warning("Unhandled state", m.top.state, m.playReported, m.playFinished) end if - + m.log.debug("end onState()", m.top.state) end sub ' ' Report playback to server sub ReportPlayback(state = "update" as string) - if m.top.position = invalid then return + m.log.debug("start ReportPlayback()", state, int(m.top.position)) + params = { "ItemId": m.top.id, "PlaySessionId": m.top.PlaySessionId, @@ -679,6 +698,8 @@ sub ReportPlayback(state = "update" as string) playstateTask = m.global.playstateTask playstateTask.setFields({ status: state, params: params }) playstateTask.control = "RUN" + + m.log.debug("end ReportPlayback()", state, int(m.top.position)) end sub ' @@ -704,7 +725,6 @@ sub bufferCheck(msg) ' Stop playback and exit player m.top.control = "stop" - m.top.backPressed = true end if end if diff --git a/images/1px-262626.png b/images/1px-262626.png new file mode 100644 index 000000000..5122799ac Binary files /dev/null and b/images/1px-262626.png differ diff --git a/manifest b/manifest index 6dac4b714..47de6e805 100644 --- a/manifest +++ b/manifest @@ -3,7 +3,7 @@ title=Jellyfin major_version=2 minor_version=1 -build_version=4 +build_version=5 ### Main Menu Icons / Channel Poster Artwork diff --git a/package-lock.json b/package-lock.json index 2490ceb8b..99083eb06 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "jellyfin-roku", - "version": "2.1.4", + "version": "2.1.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "jellyfin-roku", - "version": "2.1.4", + "version": "2.1.5", "hasInstallScript": true, "license": "GPL-2.0", "dependencies": { diff --git a/package.json b/package.json index bf2b648d4..f4c7abe4a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "jellyfin-roku", "type": "module", - "version": "2.1.4", + "version": "2.1.5", "description": "Roku app for Jellyfin media server", "dependencies": { "@rokucommunity/bslib": "0.1.1", diff --git a/source/api/Items.bs b/source/api/Items.bs index 6b5db4ead..f4262dc29 100644 --- a/source/api/Items.bs +++ b/source/api/Items.bs @@ -26,7 +26,17 @@ function ItemPostPlaybackInfo(id as string, mediaSourceId = "" as string, audioT "SubtitleStreamIndex": subtitleTrackIndex } - if mediaSourceId <> "" then params.MediaSourceId = mediaSourceId + ' Note: Jellyfin v10.9+ now remuxs LiveTV and does not allow DirectPlay anymore. + ' Because of this, we need to tell the server "EnableDirectPlay = false" so that we receive the + ' transcoding URL (which is just a remux and not a transcode; unless it is) + ' The web handles this by disabling EnableDirectPlay on a Retry, but we don't currently Retry a Live + ' TV stream, thus we just turn it off on the first try here. + if mediaSourceId <> "" + params.MediaSourceId = mediaSourceId + else + ' No mediaSourceId? Must be LiveTV... + params.EnableDirectPlay = false + end if if audioTrackIndex > -1 then params.AudioStreamIndex = audioTrackIndex diff --git a/source/utils/deviceCapabilities.bs b/source/utils/deviceCapabilities.bs index 3dd234dce..05bec80b5 100644 --- a/source/utils/deviceCapabilities.bs +++ b/source/utils/deviceCapabilities.bs @@ -440,7 +440,26 @@ function getCodecProfiles() as object if di.CanDecodeAudio({ Codec: audioCodec, ChCnt: audioChannel }).Result channelSupportFound = true for each codecType in ["VideoAudio", "Audio"] - if audioCodec = "opus" and codecType = "Audio" + if audioCodec = "aac" + codecProfiles.push({ + "Type": codecType, + "Codec": audioCodec, + "Conditions": [ + { + "Condition": "NotEquals", + "Property": "AudioProfile", + "Value": "Main", + "IsRequired": true + }, + { + "Condition": "LessThanEqual", + "Property": "AudioChannels", + "Value": audioChannel, + "IsRequired": true + } + ] + }) + else if audioCodec = "opus" and codecType = "Audio" ' opus audio files not supported by roku else codecProfiles.push({