Esempio n. 1
0
def create_video_transcript(video_id,
                            language_code,
                            file_format,
                            content,
                            provider=TranscriptProviderType.CUSTOM):
    """
    Create a video transcript.

    Arguments:
        video_id(unicode): An Id identifying the Video data model object.
        language_code(unicode): A language code.
        file_format(unicode): Transcript file format.
        content(InMemoryUploadedFile): Transcript content.
        provider(unicode): Transcript provider (it will be 'custom' by default if not selected).
    """
    transcript_serializer = TranscriptSerializer(
        data=dict(provider=provider,
                  language_code=language_code,
                  file_format=file_format),
        context=dict(video_id=video_id),
    )
    if transcript_serializer.is_valid():
        transcript_serializer.save(content=content)
        return transcript_serializer.data

    raise ValCannotCreateError(transcript_serializer.errors)
Esempio n. 2
0
def create_profile(profile_name):
    """
    Used to create Profile objects in the database

    A profile needs to exists before an EncodedVideo object can be created.

    Args:
        profile_name (str): ID of the profile

    Raises:
        ValCannotCreateError: Raised if the profile name is invalid or exists
    """
    try:
        profile = Profile(profile_name=profile_name)
        profile.full_clean()
        profile.save()
    except ValidationError as err:
        raise ValCannotCreateError(err.message_dict)
Esempio n. 3
0
def create_video(video_data):
    """
    Called on to create Video objects in the database

    create_video is used to create Video objects whose children are EncodedVideo
    objects which are linked to Profile objects. This is an alternative to the HTTP
    requests so it can be used internally. The VideoSerializer is used to
    deserialize this object. If there are duplicate profile_names, the entire
    creation will be rejected. If the profile is not found in the database, the
    video will not be created.
    Args:
        video_data (dict):
         {
                url: api url to the video
                edx_video_id: ID of the video
                duration: Length of video in seconds
                client_video_id: client ID of video
                encoded_video: a list of EncodedVideo dicts
                    url: url of the video
                    file_size: size of the video in bytes
                    profile: ID of the profile
                courses: Courses associated with this video
                image: poster image file name for a particular course
         }

    Raises:
        Raises ValCannotCreateError if the video cannot be created.

    Returns the successfully created Video object
    """

    serializer = VideoSerializer(data=video_data)
    if serializer.is_valid():
        serializer.save()
        return video_data.get("edx_video_id")
    else:
        raise ValCannotCreateError(serializer.errors)
Esempio n. 4
0
def import_from_xml(xml, edx_video_id, course_id=None):
    """
    Imports data from a video_asset element about the given video_id.

    If the edx_video_id already exists, then no changes are made. If an unknown
    profile is referenced by an encoded video, that encoding will be ignored.

    Arguments:
        xml (Element): An lxml video_asset element containing import data
        edx_video_id (str): val video id
        course_id (str): The ID of a course to associate the video with

    Raises:
        ValCannotCreateError: if there is an error importing the video
    """
    if xml.tag != 'video_asset':
        raise ValCannotCreateError('Invalid XML')

    # if edx_video_id does not exist then create video transcripts only
    if not edx_video_id:
        return create_transcript_objects(xml)

    # If video with edx_video_id already exists, associate it with the given course_id.
    try:
        video = Video.objects.get(edx_video_id=edx_video_id)
        logger.info(
            "edx_video_id '%s' present in course '%s' not imported because it exists in VAL.",
            edx_video_id,
            course_id,
        )
        if course_id:
            course_video, __ = CourseVideo.get_or_create_with_validation(
                video=video, course_id=course_id)

            image_file_name = xml.get('image', '').strip()
            if image_file_name:
                VideoImage.create_or_update(course_video, image_file_name)

        # import transcripts
        create_transcript_objects(xml)

        return
    except ValidationError as err:
        logger.exception(err.message)
        raise ValCannotCreateError(err.message_dict)
    except Video.DoesNotExist:
        pass

    # Video with edx_video_id did not exist, so create one from xml data.
    data = {
        'edx_video_id': edx_video_id,
        'client_video_id': xml.get('client_video_id'),
        'duration': xml.get('duration'),
        'status': 'imported',
        'encoded_videos': [],
        'courses': [{
            course_id: xml.get('image')
        }] if course_id else [],
    }
    for encoded_video_el in xml.iterfind('encoded_video'):
        profile_name = encoded_video_el.get('profile')
        try:
            Profile.objects.get(profile_name=profile_name)
        except Profile.DoesNotExist:
            logger.info(
                "Imported edx_video_id '%s' contains unknown profile '%s'.",
                edx_video_id, profile_name)
            continue
        data['encoded_videos'].append({
            'profile':
            profile_name,
            'url':
            encoded_video_el.get('url'),
            'file_size':
            encoded_video_el.get('file_size'),
            'bitrate':
            encoded_video_el.get('bitrate'),
        })
    create_video(data)
    create_transcript_objects(xml)
Esempio n. 5
0
def import_from_xml(xml, edx_video_id, resource_fs, static_dir, external_transcripts=None, course_id=None):
    """
    Imports data from a video_asset element about the given video_id.
    If the edx_video_id already exists, then no changes are made. If an unknown
    profile is referenced by an encoded video, that encoding will be ignored.

    Arguments:
        xml (Element): An lxml video_asset element containing import data
        edx_video_id (str): val video id
        resource_fs (OSFS): Import file system.
        static_dir (str): The Directory to retrieve transcript file.
        external_transcripts : A dict containing the list of names of the external transcripts.
        course_id: course id
            Example:
            {
                'en': ['The_Flash.srt', 'Harry_Potter.srt'],
                'es': ['Green_Arrow.srt']
            }
        course_id (str): The ID of a course to associate the video with

    Raises:
        ValCannotCreateError: if there is an error importing the video

    Returns:
        edx_video_id (str): val video id.
    """
    if external_transcripts is None:
        external_transcripts = {}

    if xml.tag != 'video_asset':
        raise ValCannotCreateError('Invalid XML')

    # If video with edx_video_id already exists, associate it with the given course_id.
    try:
        if not edx_video_id:
            raise Video.DoesNotExist

        video = Video.objects.get(edx_video_id=edx_video_id)
        logger.info(
            "edx_video_id '%s' present in course '%s' not imported because it exists in VAL.",
            edx_video_id,
            course_id,
        )

        # We don't want to link an existing video to course if its an external video.
        # External videos do not have any playback profiles associated, these are just to track video
        # transcripts for those video components who do not use edx hosted videos for playback.
        if course_id and video.status != EXTERNAL_VIDEO_STATUS:
            course_video, __ = CourseVideo.get_or_create_with_validation(video=video, course_id=course_id)

            image_file_name = xml.get('image', '').strip()
            if image_file_name:
                VideoImage.create_or_update(course_video, image_file_name)

        # Make sure transcripts are imported when video exists
        create_transcript_objects(
            xml,
            edx_video_id,
            resource_fs,
            static_dir,
            external_transcripts
        )

        return edx_video_id
    except ValidationError as err:
        logger.exception(xml)
        raise ValCannotCreateError(err.message_dict) from err
    except Video.DoesNotExist:
        pass

    if edx_video_id:
        # Video with edx_video_id did not exist, so create one from xml data.
        data = {
            'edx_video_id': edx_video_id,
            'client_video_id': xml.get('client_video_id'),
            'duration': xml.get('duration'),
            'status': 'imported',
            'encoded_videos': [],
            'courses': [{course_id: xml.get('image')}] if course_id else [],
        }
        for encoded_video_el in xml.iterfind('encoded_video'):
            profile_name = encoded_video_el.get('profile')
            try:
                Profile.objects.get(profile_name=profile_name)
            except Profile.DoesNotExist:
                logger.info(
                    "Imported edx_video_id '%s' contains unknown profile '%s'.",
                    edx_video_id,
                    profile_name
                )
                continue
            data['encoded_videos'].append({
                'profile': profile_name,
                'url': encoded_video_el.get('url'),
                'file_size': encoded_video_el.get('file_size'),
                'bitrate': encoded_video_el.get('bitrate'),
            })

        if not data['encoded_videos']:
            # Video's status does not get included in video xml at the time of export. So, at this point,
            # we cannot tell from xml that whether a video had an external status. But if encoded videos
            # are not set, the chances are, the video was an external one, in which case, we will not link
            # it to the course(s). Even if the video wasn't an external one and it is having 0 encodes in
            # xml, it does not have a side effect if not linked to a course, since the video was already
            # non-playable.
            data['status'] = EXTERNAL_VIDEO_STATUS
            data['courses'] = []

        # Create external video if no edx_video_id.
        edx_video_id = create_video(data)
    else:
        edx_video_id = create_external_video('External Video')

    create_transcript_objects(xml, edx_video_id, resource_fs, static_dir, external_transcripts)
    return edx_video_id