Skip to content

Commit

Permalink
Workaround InputStream.Adaptive using incorrect path for downloaded subs
Browse files Browse the repository at this point in the history
- InputStream.Adaptive assumes absolute local paths are relative to manifest base url
- Disable adding subs to manifest if downloaded and fallback to using Kodi to load subs
- Disable downloading ttml subs as Kodi does not support this
- Use ttml subs based on ISA capability not Kodi version
- Also do not try to fetch subs for live streams as they are already included in the manifest
  • Loading branch information
MoojMidge committed Mar 12, 2024
1 parent 6f9aba4 commit 01bc20c
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ def use_inputstream_adaptive(self):
_ISA_CAPABILITIES = {
'live': loose_version('2.0.12'),
'drm': loose_version('2.2.12'),
'mpd_subs': loose_version('21.0.0'),
'ttml': loose_version('20.0.0'),
# audio codecs
'vorbis': loose_version('2.3.14'),
# unknown when Opus audio support was implemented
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ def video_playback_item(context, video_item, show_fanart=None):
'thumb': image,
})

if video_item.subtitles and manifest_type != 'mpd':
if video_item.subtitles:
list_item.setSubtitles(video_item.subtitles)

item_info = create_info_labels(video_item)
Expand Down
30 changes: 17 additions & 13 deletions resources/lib/youtube_plugin/youtube/helper/subtitles.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
)
from ...kodion.constants import TEMP_PATH
from ...kodion.network import BaseRequestsClass
from ...kodion.utils import make_dirs, current_system_version
from ...kodion.utils import make_dirs


class Subtitles(object):
Expand All @@ -34,7 +34,7 @@ class Subtitles(object):
BASE_PATH = make_dirs(TEMP_PATH)

FORMATS = {
'_default': 'ttml' if current_system_version.compatible(20) else 'vtt',
'_default': None,
'vtt': {
'mime_type': 'text/vtt',
'extension': 'vtt',
Expand All @@ -53,6 +53,13 @@ def __init__(self, context, video_id, captions, headers=None):
self.pre_download = settings.subtitle_download()
self.sub_selection = settings.get_subtitle_selection()

if (not self.pre_download
and settings.use_mpd_videos()
and context.inputstream_adaptive_capabilities('ttml')):
self.FORMATS['_default'] = 'ttml'
else:
self.FORMATS['_default'] = 'vtt'

sub_lang = context.get_subtitle_language()
ui_lang = settings.get_language()
if not sub_lang and ui_lang:
Expand All @@ -66,8 +73,7 @@ def __init__(self, context, video_id, captions, headers=None):
else:
self.preferred_lang = ('en',)

if not headers and 'headers' in captions:
headers = captions['headers']
if headers:
headers.pop('Authorization', None)
headers.pop('Content-Length', None)
headers.pop('Content-Type', None)
Expand Down Expand Up @@ -326,23 +332,21 @@ def _prompt(self):
.format(lang=lang))
return None

def _get_url(self, track, lang=None, download=None):
def _get_url(self, track, lang=None):
sub_format = self.FORMATS['_default']
tlang = None
base_lang = track.get('languageCode')
kind = track.get('kind')
if lang and lang != base_lang:
tlang = lang
lang = '_'.join((base_lang, tlang))
lang = '-'.join((base_lang, tlang))
elif kind == 'asr':
lang = '_'.join((base_lang, kind))
lang = '-'.join((base_lang, kind))
sub_format = 'vtt'
else:
lang = base_lang
mime_type = self.FORMATS[sub_format]['mime_type']

if download is None:
download = self.pre_download
download = self.pre_download
if download:
filename = '.'.join((
self.video_id,
Expand All @@ -359,7 +363,7 @@ def _get_url(self, track, lang=None, download=None):
self._context.log_debug('Subtitles._get_url'
' - use existing: |{lang}: {file}|'
.format(lang=lang, file=filepath))
return filepath, mime_type
return filepath, self.FORMATS[sub_format]['mime_type']

base_url = self._normalize_url(track.get('baseUrl'))
if not base_url:
Expand All @@ -378,7 +382,7 @@ def _get_url(self, track, lang=None, download=None):
.format(lang=lang, url=subtitle_url))

if not download:
return subtitle_url, mime_type
return subtitle_url, self.FORMATS[sub_format]['mime_type']

response = BaseRequestsClass().request(
subtitle_url,
Expand All @@ -401,7 +405,7 @@ def _get_url(self, track, lang=None, download=None):
' - write failed for: {file}'
.format(file=filepath))
if success:
return filepath, mime_type
return filepath, self.FORMATS[sub_format]['mime_type']
return None, None

def _get_track(self,
Expand Down
79 changes: 45 additions & 34 deletions resources/lib/youtube_plugin/youtube/helper/video_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -1210,37 +1210,6 @@ def _get_video_info(self):
is_live = video_details.get('isLiveContent', False)
thumb_suffix = '_live' if is_live else ''

if client.get('_query_subtitles'):
for client_name in ('smarttv_embedded', 'web', 'android'):
result = self.request(
video_info_url, 'POST',
error_msg=('Caption request failed to get player response for'
'video_id: {0}'.format(self.video_id)),
**self.build_client(client_name, client_data)
)
response = result and result.json() or {}
captions = response.get('captions')
if captions:
captions['headers'] = result.request.headers
break
else:
captions = response.get('captions')
if captions:
captions['headers'] = client['headers']
if captions:
captions = Subtitles(
self._context, self.video_id, captions
)
default_lang = captions.get_lang_details()
subs_data = captions.get_subtitles()
else:
default_lang = {
'default': 'und',
'original': 'und',
'is_asr': False,
}
subs_data = None

meta_info = {
'video': {
'id': video_details.get('videoId', self.video_id),
Expand Down Expand Up @@ -1271,9 +1240,7 @@ def _get_video_info(self):
'default': ('https://i.ytimg.com/vi/{0}/default{1}.jpg'
.format(self.video_id, thumb_suffix)),
},
'subtitles': [
subtitle['url'] for subtitle in subs_data.values()
] if subs_data else None,
'subtitles': None,
}

if _settings.use_remote_history():
Expand Down Expand Up @@ -1355,6 +1322,50 @@ def _get_video_info(self):
else:
live_type = None

if not live_type and client.get('_query_subtitles'):
for client_name in ('smarttv_embedded', 'web', 'android'):
caption_client = self.build_client(client_name, client_data)
result = self.request(
video_info_url,
'POST',
response_hook=self._response_hook_json,
error_title='Caption player request failed',
error_hook=self._error_hook,
error_hook_kwargs={
'video_id': self.video_id,
'client': client_name,
'auth': '_access_token' in client_data,
},
**caption_client
)
captions = result and result.get('captions')
if captions:
break
else:
captions = result.get('captions')
caption_client = client
if captions:
captions = Subtitles(
self._context,
self.video_id,
captions,
caption_client['headers']
)
default_lang = captions.get_lang_details()
subs_data = captions.get_subtitles()
if subs_data and (not use_mpd_vod or captions.pre_download):
meta_info['subtitles'] = [
subtitle['url'] for subtitle in subs_data.values()
]
subs_data = None
else:
default_lang = {
'default': 'und',
'original': 'und',
'is_asr': False,
}
subs_data = None

# extract adaptive streams and create MPEG-DASH manifest
if not live_type and not manifest_url and adaptive_fmts:
video_data, audio_data = self._process_stream_data(
Expand Down

0 comments on commit 01bc20c

Please sign in to comment.