feat: Video editor supports transcripts [FC-0076] (#36058)

* Add error handler on save video to avoid creating sjson
* Support transcripts without edx_video_id in definition_to_xml
* When copying a video from a library to a course: Create a new edx_video_id
* Save transcripts as static assets in a video in a library when adding a new transcript.
* Delete transcripts as static assets in a video in a library when deleting transcripts.
* Support download transcript in a video in a library.
* Support replace transcript in a video in a library.
* Support updating transcripts in video in a library.
* Refactor the code of downloading YouTube transcripts to enable this feature in libraries.
* Support copy from a library to a course and a course to a library.
This commit is contained in:
Chris Chávez
2025-02-21 13:33:13 -05:00
committed by GitHub
parent 6c6fd84e53
commit b6489e718c
12 changed files with 573 additions and 183 deletions

View File

@@ -20,6 +20,7 @@ from lxml import etree
from opaque_keys.edx.keys import UsageKeyV2
from pysrt import SubRipFile, SubRipItem, SubRipTime
from pysrt.srtexc import Error
from opaque_keys.edx.locator import LibraryLocatorV2
from openedx.core.djangoapps.xblock.api import get_component_from_usage_key
from xmodule.contentstore.content import StaticContent
@@ -498,16 +499,17 @@ def manage_video_subtitles_save(item, user, old_metadata=None, generate_translat
remove_subs_from_store(video_id, item, lang)
reraised_message = ''
for lang in new_langs: # 3b
try:
generate_sjson_for_all_speeds(
item,
item.transcripts[lang],
{speed: subs_id for subs_id, speed in youtube_speed_dict(item).items()},
lang,
)
except TranscriptException:
pass
if not isinstance(item.usage_key.context_key, LibraryLocatorV2):
for lang in new_langs: # 3b
try:
generate_sjson_for_all_speeds(
item,
item.transcripts[lang],
{speed: subs_id for subs_id, speed in youtube_speed_dict(item).items()},
lang,
)
except TranscriptException:
pass
if reraised_message:
item.save_with_metadata(user)
raise TranscriptException(reraised_message)
@@ -684,6 +686,18 @@ def convert_video_transcript(file_name, content, output_format):
return dict(filename=filename, content=converted_transcript)
def clear_transcripts(block):
"""
Deletes all transcripts of a video block from VAL
"""
for language_code in block.transcripts.keys():
edxval_api.delete_video_transcript(
video_id=block.edx_video_id,
language_code=language_code,
)
block.transcripts = {}
class Transcript:
"""
Container for transcript methods.
@@ -1040,6 +1054,13 @@ def get_transcript_from_contentstore(video, language, output_format, transcripts
return transcript_content, transcript_name, Transcript.mime_types[output_format]
def build_components_import_path(usage_key, file_path):
"""
Build components import path
"""
return f"components/{usage_key.block_type}/{usage_key.block_id}/{file_path}"
def get_transcript_from_learning_core(video_block, language, output_format, transcripts_info):
"""
Get video transcript from Learning Core (used for Content Libraries)