77"""
88
99import logging
10+ from typing import Any
1011
12+ from django .conf import settings
1113from opaque_keys .edx .keys import CourseKey , UsageKey
1214from opaque_keys .edx .locator import LibraryLocatorV2
1315from xblocks_contrib .video .exceptions import TranscriptNotFoundError
3436 remove_subs_from_store ,
3537)
3638
39+ from xmodule .exceptions import NotFoundError
40+
41+
3742log = logging .getLogger (__name__ )
3843
3944
@@ -129,7 +134,6 @@ def get_transcript(
129134 """
130135 # Import here to avoid circular dependency
131136 from openedx .core .djangoapps .video_config .transcripts_utils import get_transcript
132- from xmodule .exceptions import NotFoundError
133137
134138 try :
135139 return get_transcript (video_block , lang , output_format , youtube_id )
@@ -138,6 +142,68 @@ def get_transcript(
138142 f"Failed to get transcript: { exc } "
139143 ) from exc
140144
145+ def available_translations (
146+ self ,
147+ video_block ,
148+ transcripts : dict [str , Any ],
149+ verify_assets : bool | None = None ,
150+ is_bumper : bool = False ,
151+ ) -> list [str ]:
152+ """
153+ Return a list of language codes for which we have transcripts.
154+
155+ Arguments:
156+ video_block: The video XBlock instance
157+ transcripts (dict): A dict with all transcripts and a sub.
158+ verify_assets (boolean): If True, checks to ensure that the transcripts
159+ really exist in the contentstore. If False, we just look at the
160+ VideoBlock fields and do not query the contentstore. One reason
161+ we might do this is to avoid slamming contentstore() with queries
162+ when trying to make a listing of videos and their languages.
163+
164+ Defaults to `not FALLBACK_TO_ENGLISH_TRANSCRIPTS`.
165+
166+ is_bumper (boolean): If True, indicates this is a bumper video.
167+
168+ Returns:
169+ list[str]: List of language codes for available transcripts.
170+ """
171+ from openedx .core .djangoapps .video_config .transcripts_utils import (
172+ get_transcript_for_video ,
173+ get_transcript ,
174+ )
175+
176+ translations = []
177+ if verify_assets is None :
178+ verify_assets = not settings .FEATURES .get ('FALLBACK_TO_ENGLISH_TRANSCRIPTS' )
179+
180+ sub , other_langs = transcripts ["sub" ], transcripts ["transcripts" ]
181+
182+ if verify_assets :
183+ all_langs = dict (** other_langs )
184+ if sub :
185+ all_langs .update ({'en' : sub })
186+
187+ for language , filename in all_langs .items ():
188+ try :
189+ # for bumper videos, transcripts are stored in content store only
190+ if is_bumper :
191+ get_transcript_for_video (video_block .location , filename , filename , language )
192+ else :
193+ get_transcript (video_block , language )
194+ except NotFoundError :
195+ continue
196+
197+ translations .append (language )
198+ else :
199+ # If we're not verifying the assets, we just trust our field values
200+ translations = list (other_langs )
201+ if not translations or sub :
202+ translations += ['en' ]
203+
204+ # to clean redundant language codes.
205+ return list (set (translations ))
206+
141207 def upload_transcript (
142208 self ,
143209 * ,
0 commit comments