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

Merge v2.0.1 into master #1617

Merged
merged 26 commits into from
Jan 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
51452ab
Merge pull request #1585 from jellyfin/master
cewert Dec 16, 2023
20cdb6f
ensure lastRunVersion is valid
cewert Dec 13, 2023
0a97440
Merge pull request #1574 from cewert/fix-migration-crash
cewert Dec 16, 2023
7b5d553
Replace asTimeStringLoc() function with custom code
1hitsong Dec 23, 2023
c480610
Fix OK button not playing episode from episode list
1hitsong Dec 23, 2023
a90df38
Check for Live TV
jimdogx Dec 24, 2023
19c92f3
Copy / Paste error.
jimdogx Dec 24, 2023
b9e55e0
Merge pull request #1597 from 1hitsong/fixOKOnEpisodeList
1hitsong Dec 29, 2023
df6a04f
Make artist presentation views follow Item Titles setting
1hitsong Dec 29, 2023
a37c7d9
Fix subtitle selection
1hitsong Dec 31, 2023
f4a3c12
Merge pull request #1608 from 1hitsong/fixTextSubtitleChange
1hitsong Jan 2, 2024
37bc7dc
Merge pull request #1594 from 1hitsong/FixOSDClock
1hitsong Jan 2, 2024
5baa8f4
Bump version for release
cewert Jan 2, 2024
769c5f4
Merge pull request #1603 from 1hitsong/fixArtistNameDisplay
1hitsong Jan 2, 2024
0947dea
Merge pull request #1600 from jimdogx/fix/jf-live-tv-not-guide
cewert Jan 2, 2024
1c27486
Update What's New content
1hitsong Jan 2, 2024
abafbf5
Merge pull request #1610 from cewert/prep-v2.0.1
cewert Jan 2, 2024
945a6d3
Update source/static/whatsNew/2.0.1.json
1hitsong Jan 3, 2024
3a9987f
Fix default subtitle track selection
1hitsong Dec 30, 2023
286749c
Code cleanup
1hitsong Jan 3, 2024
7c8719c
Check var is valid before LCase()
1hitsong Jan 3, 2024
497615e
Fix variable styles
1hitsong Jan 5, 2024
8601adf
Improve default subtitle selection logic
1hitsong Jan 5, 2024
b5ad638
Update default subtitle logic to work with custom subtitle function
1hitsong Jan 5, 2024
2640369
Merge pull request #1604 from 1hitsong/fixDefaultSubtitleTrack
cewert Jan 6, 2024
ab8c590
Merge pull request #1612 from 1hitsong/updateWhatsNew
cewert Jan 6, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# If you want to get_images, you'll also need convert from ImageMagick
##########################################################################

VERSION := 2.0.0
VERSION := 2.0.1

## usage

Expand Down
78 changes: 72 additions & 6 deletions components/Clock.bs
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import "pkg:/source/utils/misc.bs"

' @fileoverview Clock component to display current time formatted based on user's chosen 12 or 24 hour setting

' Possible clock formats
enum ClockFormat
h12 = "12h"
h24 = "24h"
end enum

sub init()

' If hideclick setting is checked, exit without setting any variables
' If hideclick setting is enabled, exit without setting any variables
if m.global.session.user.settings["ui.design.hideclock"]
return
end if
Expand All @@ -16,11 +24,11 @@ sub init()
m.currentTimeTimer.control = "start"

' Default to 12 hour clock
m.format = "short-h12"
m.format = ClockFormat.h12

' If user has selected a 24 hour clock, update date display format
if LCase(m.global.device.clockFormat) = "24h"
m.format = "short-h24"
if LCase(m.global.device.clockFormat) = ClockFormat.h24
m.format = ClockFormat.h24
end if
end sub

Expand All @@ -34,6 +42,64 @@ sub onCurrentTimeTimerFire()
' Convert to local time zone
m.dateTimeObject.ToLocalTime()

' Format time as requested
m.clockTime.text = m.dateTimeObject.asTimeStringLoc(m.format)
' Format time for display - based on 12h/24h setting
formattedTime = formatTimeAsString()

' Display time
m.clockTime.text = formattedTime
end sub

' formatTimeAsString: Returns a string with the current time formatted for either a 12 or 24 hour clock
'
' @return {string} current time formatted for either a 12 hour or 24 hour clock
function formatTimeAsString() as string
return m.format = ClockFormat.h12 ? format12HourTime() : format24HourTime()
end function

' format12HourTime: Returns a string with the current time formatted for a 12 hour clock
'
' @return {string} current time formatted for a 12 hour clock
function format12HourTime() as string
currentHour = m.dateTimeObject.GetHours()
currentMinute = m.dateTimeObject.GetMinutes()

displayedHour = StrI(currentHour).trim()
displayedMinute = StrI(currentMinute).trim()
meridian = currentHour < 12 ? "am" : "pm"

if currentHour = 0
displayedHour = "12"
end if

if currentHour > 12
correctedHour = currentHour - 12
displayedHour = StrI(correctedHour).trim()
end if

if currentMinute < 10
displayedMinute = `0${displayedMinute}`
end if

return `${displayedHour}:${displayedMinute} ${meridian}`
end function

' format24HourTime: Returns a string with the current time formatted for a 24 hour clock
'
' @return {string} current time formatted for a 24 hour clock
function format24HourTime() as string
currentHour = m.dateTimeObject.GetHours()
currentMinute = m.dateTimeObject.GetMinutes()

displayedHour = StrI(currentHour).trim()
displayedMinute = StrI(currentMinute).trim()

if currentHour < 10
displayedHour = `0${displayedHour}`
end if

if currentMinute < 10
displayedMinute = `0${displayedMinute}`
end if

return `${displayedHour}:${displayedMinute}`
end function
162 changes: 149 additions & 13 deletions components/ItemGrid/LoadVideoContentTask.bs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import "pkg:/source/api/Image.bs"
import "pkg:/source/api/userauth.bs"
import "pkg:/source/utils/deviceCapabilities.bs"

enum SubtitleSelection
notset = -2
none = -1
end enum

sub init()
m.user = AboutMe()
m.top.functionName = "loadItems"
Expand Down Expand Up @@ -44,19 +49,18 @@ sub loadItems()
id = m.top.itemId
mediaSourceId = invalid
audio_stream_idx = m.top.selectedAudioStreamIndex
subtitle_idx = m.top.selectedSubtitleIndex
forceTranscoding = false

m.top.content = [LoadItems_VideoPlayer(id, mediaSourceId, audio_stream_idx, subtitle_idx, forceTranscoding)]
m.top.content = [LoadItems_VideoPlayer(id, mediaSourceId, audio_stream_idx, forceTranscoding)]
end sub

function LoadItems_VideoPlayer(id as string, mediaSourceId = invalid as dynamic, audio_stream_idx = 1 as integer, subtitle_idx = -1 as integer, forceTranscoding = false as boolean) as dynamic
function LoadItems_VideoPlayer(id as string, mediaSourceId = invalid as dynamic, audio_stream_idx = 1 as integer, forceTranscoding = false as boolean) as dynamic

video = {}
video.id = id
video.content = createObject("RoSGNode", "ContentNode")

LoadItems_AddVideoContent(video, mediaSourceId, audio_stream_idx, subtitle_idx, forceTranscoding)
LoadItems_AddVideoContent(video, mediaSourceId, audio_stream_idx, forceTranscoding)

if video.content = invalid
return invalid
Expand All @@ -65,9 +69,10 @@ function LoadItems_VideoPlayer(id as string, mediaSourceId = invalid as dynamic,
return video
end function

sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_stream_idx = 1 as integer, subtitle_idx = -1 as integer, forceTranscoding = false as boolean)
sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_stream_idx = 1 as integer, forceTranscoding = false as boolean)

meta = ItemMetaData(video.id)
subtitle_idx = m.top.selectedSubtitleIndex

if not isValid(meta)
video.errorMsg = "Error loading metadata"
Expand All @@ -77,6 +82,21 @@ sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_s

videotype = LCase(meta.type)

' Check for any Live TV streams coming from other places other than the TV Guide
if isValid(meta.json) and isValid(meta.json.ChannelId)
if isValid(meta.json.EpisodeTitle)
meta.title = meta.json.EpisodeTitle
else if isValid(meta.json.Name)
meta.title = meta.json.Name
end if
meta.live = true
if LCase(meta.json.type) = "program"
video.id = meta.json.ChannelId
else
video.id = meta.json.id
end if
end if

if videotype = "episode" or videotype = "series"
video.content.contenttype = "episode"
end if
Expand Down Expand Up @@ -107,16 +127,41 @@ sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_s
if meta.live then mediaSourceId = ""

m.playbackInfo = ItemPostPlaybackInfo(video.id, mediaSourceId, audio_stream_idx, subtitle_idx, playbackPosition)
video.videoId = video.id
video.mediaSourceId = mediaSourceId
video.audioIndex = audio_stream_idx

if not isValid(m.playbackInfo)
video.errorMsg = "Error loading playback info"
video.content = invalid
return
end if

addSubtitlesToVideo(video, meta)

' Enable default subtitle track
if subtitle_idx = SubtitleSelection.notset
defaultSubtitleIndex = defaultSubtitleTrackFromVid(video.id)

if defaultSubtitleIndex <> SubtitleSelection.none
video.SelectedSubtitle = defaultSubtitleIndex
subtitle_idx = defaultSubtitleIndex

m.playbackInfo = ItemPostPlaybackInfo(video.id, mediaSourceId, audio_stream_idx, subtitle_idx, playbackPosition)
if not isValid(m.playbackInfo)
video.errorMsg = "Error loading playback info"
video.content = invalid
return
end if

addSubtitlesToVideo(video, meta)
else
video.SelectedSubtitle = subtitle_idx
end if
else
video.SelectedSubtitle = subtitle_idx
end if

video.videoId = video.id
video.mediaSourceId = mediaSourceId
video.audioIndex = audio_stream_idx

video.PlaySessionId = m.playbackInfo.PlaySessionId

if meta.live
Expand All @@ -130,8 +175,6 @@ sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_s
m.playbackInfo = meta.json
end if

addSubtitlesToVideo(video, meta)

if meta.live
video.transcodeParams = {
"MediaSourceId": m.playbackInfo.MediaSources[0].Id,
Expand Down Expand Up @@ -183,13 +226,106 @@ sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_s
setCertificateAuthority(video.content)
video.audioTrack = (audio_stream_idx + 1).ToStr() ' Roku's track indexes count from 1. Our index is zero based

video.SelectedSubtitle = subtitle_idx

if not fully_external
video.content = authRequest(video.content)
end if
end sub

' defaultSubtitleTrackFromVid: Identifies the default subtitle track given video id
'
' @param {dynamic} videoID - id of video user is playing
' @return {integer} indicating the default track's server-side index. Defaults to {SubtitleSelection.none} is one is not found
function defaultSubtitleTrackFromVid(videoID) as integer
if m.global.session.user.configuration.SubtitleMode = "None"
return SubtitleSelection.none ' No subtitles desired: return none
end if

meta = ItemMetaData(videoID)

if not isValid(meta) then return SubtitleSelection.none
if not isValid(meta.json) then return SubtitleSelection.none
if not isValidAndNotEmpty(meta.json.mediaSources) then return SubtitleSelection.none
if not isValidAndNotEmpty(meta.json.MediaSources[0].MediaStreams) then return SubtitleSelection.none

subtitles = sortSubtitles(meta.id, meta.json.MediaSources[0].MediaStreams)
selectedAudioLanguage = meta.json.MediaSources[0].MediaStreams[m.top.selectedAudioStreamIndex].Language ?? ""

defaultTextSubs = defaultSubtitleTrack(subtitles["all"], selectedAudioLanguage, true) ' Find correct subtitle track (forced text)
if defaultTextSubs <> SubtitleSelection.none
return defaultTextSubs
end if

if not m.global.session.user.settings["playback.subs.onlytext"]
return defaultSubtitleTrack(subtitles["all"], selectedAudioLanguage) ' if no appropriate text subs exist, allow non-text
end if

return SubtitleSelection.none
end function

' defaultSubtitleTrack:
'
' @param {dynamic} sortedSubtitles - array of subtitles sorted by type and language
' @param {string} selectedAudioLanguage - language for selected audio track
' @param {boolean} [requireText=false] - indicates if only text subtitles should be considered
' @return {integer} indicating the default track's server-side index. Defaults to {SubtitleSelection.none} is one is not found
function defaultSubtitleTrack(sortedSubtitles, selectedAudioLanguage as string, requireText = false as boolean) as integer
userConfig = m.global.session.user.configuration

subtitleMode = isValid(userConfig.SubtitleMode) ? LCase(userConfig.SubtitleMode) : ""

allowSmartMode = false

' Only evaluate selected audio language if we have a value
if selectedAudioLanguage <> ""
allowSmartMode = selectedAudioLanguage <> userConfig.SubtitleLanguagePreference
end if

for each item in sortedSubtitles
' Only auto-select subtitle if language matches SubtitleLanguagePreference
languageMatch = true
if userConfig.SubtitleLanguagePreference <> ""
languageMatch = (userConfig.SubtitleLanguagePreference = item.Track.Language)
end if

' Ensure textuality of subtitle matches preferenced passed as arg
matchTextReq = ((requireText and item.IsTextSubtitleStream) or not requireText)

if languageMatch and matchTextReq
if subtitleMode = "default" and (item.isForced or item.IsDefault)
' Return first forced or default subtitle track
return item.Index
else if subtitleMode = "always"
' Return the first found subtitle track
return item.Index
else if subtitleMode = "onlyforced" and item.IsForced
' Return first forced subtitle track
return item.Index
else if subtitleMode = "smart" and allowSmartMode
' Return the first found subtitle track
return item.Index
end if
end if
end for

' User has chosed smart subtitle mode
' We already attempted to load subtitles in preferred language, but none were found.
' Fall back to default behaviour while ignoring preferredlanguage
if subtitleMode = "smart" and allowSmartMode
for each item in sortedSubtitles
' Ensure textuality of subtitle matches preferenced passed as arg
matchTextReq = ((requireText and item.IsTextSubtitleStream) or not requireText)
if matchTextReq
if item.isForced or item.IsDefault
' Return first forced or default subtitle track
return item.Index
end if
end if
end for
end if

return SubtitleSelection.none ' Keep current default behavior of "None", if no correct subtitle is identified
end function

sub addVideoContentURL(video, mediaSourceId, audio_stream_idx, fully_external)
protocol = LCase(m.playbackInfo.MediaSources[0].Protocol)
if protocol <> "file"
Expand Down
2 changes: 1 addition & 1 deletion components/ItemGrid/LoadVideoContentTask.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<interface>
<field id="itemId" type="string" />
<field id="selectedAudioStreamIndex" type="integer" value="0" />
<field id="selectedSubtitleIndex" type="integer" value="-1" />
<field id="selectedSubtitleIndex" type="integer" value="-2" />
<field id="isIntro" type="boolean" />
<field id="startIndex" type="integer" value="0" />
<field id="itemType" type="string" value="" />
Expand Down
2 changes: 0 additions & 2 deletions components/ItemGrid/MusicLibraryView.bs
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,12 @@ sub loadInitialItems()
m.loadItemsTask.itemId = m.top.parentItem.parentFolder
else if LCase(m.view) = "artistspresentation" or LCase(m.options.view) = "artistspresentation"
m.loadItemsTask.genreIds = ""
m.top.showItemTitles = "hidealways"
else if LCase(m.view) = "artistsgrid" or LCase(m.options.view) = "artistsgrid"
m.loadItemsTask.genreIds = ""
else if LCase(m.view) = "albumartistsgrid" or LCase(m.options.view) = "albumartistsgrid"
m.loadItemsTask.genreIds = ""
else if LCase(m.view) = "albumartistspresentation" or LCase(m.options.view) = "albumartistspresentation"
m.loadItemsTask.genreIds = ""
m.top.showItemTitles = "hidealways"
else
m.loadItemsTask.itemId = m.top.parentItem.Id
end if
Expand Down
9 changes: 5 additions & 4 deletions components/manager/ViewCreator.bs
Original file line number Diff line number Diff line change
Expand Up @@ -111,19 +111,20 @@ sub processSubtitleSelection()
end if

if m.selectedSubtitle.IsEncoded
' Roku can not natively display these subtitles, so turn off the caption mode on the device
m.view.globalCaptionMode = "Off"
else
' Roku can natively display these subtitles, ensure the caption mode on the device is on
m.view.globalCaptionMode = "On"
end if

if m.selectedSubtitle.IsExternal
' Roku may rearrange subtitle tracks. Look up track based on name to ensure we get the correct index
availableSubtitleTrackIndex = availSubtitleTrackIdx(m.selectedSubtitle.Track.TrackName)
if availableSubtitleTrackIndex = -1 then return

m.view.subtitleTrack = m.view.availableSubtitleTracks[availableSubtitleTrackIndex].TrackName
else
m.view.selectedSubtitle = m.selectedSubtitle.Index
end if

m.view.selectedSubtitle = m.selectedSubtitle.Index
end sub

' User requested playback info
Expand Down
2 changes: 2 additions & 0 deletions components/tvshows/TVEpisodes.bs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ function onKeyEvent(key as string, press as boolean) as boolean
focusedItem = getFocusedItem()
if isValid(focusedItem)
m.top.selectedItem = focusedItem
'Prevent the selected item event from double firing
m.top.selectedItem = invalid
end if
return true
end if
Expand Down
Loading