Merge pull request #1604 from 1hitsong/fixDefaultSubtitleTrack
This commit is contained in:
commit
2640369753
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -122,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
|
||||
|
@ -145,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,
|
||||
|
@ -198,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"
|
||||
|
|
|
@ -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="" />
|
||||
|
|
|
@ -335,6 +335,29 @@ sub onVideoContentLoaded()
|
|||
m.top.allowCaptions = true
|
||||
end if
|
||||
|
||||
' Allow default subtitles
|
||||
m.top.unobserveField("selectedSubtitle")
|
||||
|
||||
' Set subtitleTrack property is subs are natively supported by Roku
|
||||
selectedSubtitle = invalid
|
||||
for each subtitle in m.top.fullSubtitleData
|
||||
if subtitle.Index = videoContent[0].selectedSubtitle
|
||||
selectedSubtitle = subtitle
|
||||
exit for
|
||||
end if
|
||||
end for
|
||||
|
||||
if isValid(selectedSubtitle)
|
||||
availableSubtitleTrackIndex = availSubtitleTrackIdx(selectedSubtitle.Track.TrackName)
|
||||
if availableSubtitleTrackIndex <> -1
|
||||
m.top.subtitleTrack = m.top.availableSubtitleTracks[availableSubtitleTrackIndex].TrackName
|
||||
end if
|
||||
end if
|
||||
|
||||
m.top.selectedSubtitle = videoContent[0].selectedSubtitle
|
||||
|
||||
m.top.observeField("selectedSubtitle", "onSubtitleChange")
|
||||
|
||||
if isValid(m.top.audioIndex)
|
||||
m.top.audioTrack = (m.top.audioIndex + 1).toStr()
|
||||
else
|
||||
|
@ -582,6 +605,25 @@ function stateAllowsOSD() as boolean
|
|||
return inArray(validStates, m.top.state)
|
||||
end function
|
||||
|
||||
|
||||
' availSubtitleTrackIdx: Returns Roku's index for requested subtitle track
|
||||
'
|
||||
' @param {string} tracknameToFind - TrackName for subtitle we're looking to match
|
||||
' @return {integer} indicating Roku's index for requested subtitle track. Returns -1 if not found
|
||||
function availSubtitleTrackIdx(tracknameToFind as string) as integer
|
||||
idx = 0
|
||||
for each availTrack in m.top.availableSubtitleTracks
|
||||
' The TrackName must contain the URL we supplied originally, though
|
||||
' Roku mangles the name a bit, so we check if the URL is a substring, rather
|
||||
' than strict equality
|
||||
if Instr(1, availTrack.TrackName, tracknameToFind)
|
||||
return idx
|
||||
end if
|
||||
idx = idx + 1
|
||||
end for
|
||||
return -1
|
||||
end function
|
||||
|
||||
function onKeyEvent(key as string, press as boolean) as boolean
|
||||
|
||||
' Keypress handler while user is inside the chapter menu
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<field id="selectPlaybackInfoPressed" type="boolean" alwaysNotify="true" />
|
||||
<field id="PlaySessionId" type="string" />
|
||||
<field id="Subtitles" type="array" />
|
||||
<field id="SelectedSubtitle" type="integer" value="-1" alwaysNotify="true" />
|
||||
<field id="SelectedSubtitle" type="integer" value="-2" alwaysNotify="true" />
|
||||
<field id="container" type="string" />
|
||||
<field id="directPlaySupported" type="boolean" />
|
||||
<field id="systemOverlay" type="boolean" value="false" />
|
||||
|
|
Loading…
Reference in New Issue
Block a user