Unverified Commit e0b308bf by M. Rehan Committed by GitHub

Merge pull request #114 from edx/mrehan/download-transcripts-on-upload-page

Feature: Create/edit/delete transcript via Video Upload Page
parents cd3d5f30 83d2c3e5
......@@ -71,3 +71,6 @@ venvs/
src/
video-images/
video-transcripts/
### VisualStudioCode ###
.vscode/*
......@@ -6,8 +6,7 @@ env:
- TOXENV=django110
- TOXENV=django111
install:
- pip install -r requirements.txt
- pip install -r test-requirements.txt
- pip install tox
- pip install coveralls
script:
- tox
......
......@@ -247,7 +247,7 @@ def get_video_transcript_data(video_ids, language_code):
try:
video_transcript = VideoTranscript.objects.get(video_id=video_id, language_code=language_code)
transcript_data = dict(
file_name=video_transcript.transcript.name,
file_name=video_transcript.filename,
content=video_transcript.transcript.file.read()
)
break
......@@ -296,46 +296,57 @@ def get_video_transcript_url(video_id, language_code):
return video_transcript.url()
def create_or_update_video_transcript(
video_id,
language_code,
file_name,
file_format,
provider,
file_data=None,
):
def create_or_update_video_transcript(video_id, language_code, metadata, file_data=None):
"""
Create or Update video transcript for an existing video.
Arguments:
video_id: it can be an edx_video_id or an external_id extracted from external sources in a video component.
language_code: language code of a video transcript
file_name: file name of a video transcript
metadata (dict): A dict containing (to be overwritten) properties
file_data (InMemoryUploadedFile): Transcript data to be saved for a course video.
file_format: format of the transcript
provider: transcript provider
Returns:
video transcript url
"""
if file_format not in dict(TranscriptFormat.CHOICES).keys():
# Filter wanted properties
metadata = {
prop: value
for prop, value in metadata.iteritems()
if prop in ['provider', 'language_code', 'file_name', 'file_format'] and value
}
file_format = metadata.get('file_format')
if file_format and file_format not in dict(TranscriptFormat.CHOICES).keys():
raise InvalidTranscriptFormat('{} transcript format is not supported'.format(file_format))
if provider not in dict(TranscriptProviderType.CHOICES).keys():
provider = metadata.get('provider')
if provider and provider not in dict(TranscriptProviderType.CHOICES).keys():
raise InvalidTranscriptProvider('{} transcript provider is not supported'.format(provider))
video_transcript, __ = VideoTranscript.create_or_update(
video_id,
language_code,
file_name,
file_format,
provider,
file_data,
)
video_transcript, __ = VideoTranscript.create_or_update(video_id, language_code, metadata, file_data)
return video_transcript.url()
def delete_video_transcript(video_id, language_code):
"""
Delete transcript for an existing video.
Arguments:
video_id: id of the video with which transcript is associated
language_code: language code of a video transcript
"""
try:
video_transcript = VideoTranscript.objects.get(video_id=video_id, language_code=language_code)
# delete the actual transcript file from storage
video_transcript.transcript.delete()
# delete the record from db
video_transcript.delete()
except VideoTranscript.DoesNotExist:
pass
def get_3rd_party_transcription_plans():
"""
Retrieves 3rd party transcription plans.
......@@ -926,9 +937,11 @@ def create_transcript_objects(xml):
VideoTranscript.create_or_update(
transcript.attrib['video_id'],
transcript.attrib['language_code'],
transcript.attrib['file_name'],
transcript.attrib['file_format'],
transcript.attrib['provider'],
metadata=dict(
provider=transcript.attrib['provider'],
file_name=transcript.attrib['file_name'],
file_format=transcript.attrib['file_format'],
)
)
except KeyError:
logger.warn("VAL: Required attributes are missing from xml, xml=[%s]", etree.tostring(transcript).strip())
......@@ -417,6 +417,28 @@ class VideoTranscript(TimeStampedModel):
class Meta:
unique_together = ('video_id', 'language_code')
@property
def filename(self):
"""
Returns readable filename for a transcript
"""
try:
video = Video.objects.get(edx_video_id=self.video_id)
client_id, __ = os.path.splitext(video.client_video_id)
file_name = u'{name}-{language}.{format}'.format(
name=client_id,
language=self.language_code,
format=self.file_format
)
except Video.DoesNotExist:
file_name = u'{name}-{language}.{format}'.format(
name=self.video_id,
language=self.language_code,
format=self.file_format
)
return file_name
@classmethod
def get_or_none(cls, video_id, language_code):
"""
......@@ -434,16 +456,14 @@ class VideoTranscript(TimeStampedModel):
return transcript
@classmethod
def create_or_update(cls, video_id, language_code, file_name, file_format, provider, file_data=None):
def create_or_update(cls, video_id, language_code, metadata, file_data=None):
"""
Create or update Transcript object.
Arguments:
video_id (str): unique id for a video
language_code (str): language code
file_name (str): File name of the image
file_format (str): Format of transcript
provider (str): Transcript provider
language_code (str): language code for (to be created/updated) transcript
metadata (dict): A dict containing (to be overwritten) properties
file_data (InMemoryUploadedFile): File data to be saved
Returns:
......@@ -451,20 +471,24 @@ class VideoTranscript(TimeStampedModel):
"""
video_transcript, created = cls.objects.get_or_create(video_id=video_id, language_code=language_code)
# delete the existing transcript file
if not created and file_data:
video_transcript.transcript.delete()
for prop, value in metadata.iteritems():
if prop in ['language_code', 'file_format', 'provider']:
setattr(video_transcript, prop, value)
video_transcript.transcript.name = file_name
video_transcript.file_format = file_format
video_transcript.provider = provider
transcript_name = metadata.get('file_name')
if transcript_name:
video_transcript.transcript.name = transcript_name
elif file_data:
# Delete the existing transcript file and
# recreate with the new content
if not created:
video_transcript.transcript.delete()
if file_data:
with closing(file_data) as transcript_file_data:
file_name = '{uuid}{ext}'.format(uuid=uuid4().hex, ext=os.path.splitext(file_name)[1])
file_name = '{uuid}.{ext}'.format(uuid=uuid4().hex, ext=video_transcript.file_format)
try:
video_transcript.transcript.save(file_name, transcript_file_data)
except Exception: # pylint: disable=broad-except
except Exception:
logger.exception('VAL: Transcript save failed to storage for video_id [%s]', video_id)
raise
......
......@@ -373,7 +373,7 @@ VIDEO_TRANSCRIPT_CIELO24 = dict(
VIDEO_TRANSCRIPT_3PLAY = dict(
video_id='super-soaker',
language_code='de',
transcript='wow.sjson',
transcript='edxval/tests/data/wow.sjson',
provider=TranscriptProviderType.THREE_PLAY_MEDIA,
file_format=TranscriptFormat.SJSON,
)
......
{
"start": [10],
"end": [100],
"text": ["Hi, welcome to edxval."],
}
\ No newline at end of file
......@@ -4,9 +4,7 @@ Views file for django app edxval.
import logging
from django.core.exceptions import ValidationError
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.views.decorators.http import last_modified
from rest_framework import generics, status
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import DjangoModelPermissions
......@@ -14,12 +12,16 @@ from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_oauth.authentication import OAuth2Authentication
from edxval.api import (create_or_update_video_transcript,
get_video_transcript, update_video_status)
from edxval.models import (CourseVideo, Profile, TranscriptFormat,
TranscriptProviderType, Video, VideoImage,
VideoTranscript)
from edxval.serializers import TranscriptSerializer, VideoSerializer
from edxval.api import create_or_update_video_transcript
from edxval.models import (
CourseVideo,
TranscriptFormat,
TranscriptProviderType,
Video,
VideoImage,
VideoTranscript
)
from edxval.serializers import VideoSerializer
LOGGER = logging.getLogger(__name__) # pylint: disable=C0103
......@@ -148,13 +150,11 @@ class VideoTranscriptView(APIView):
transcript = VideoTranscript.get_or_none(video_id, language_code)
if transcript is None:
create_or_update_video_transcript(
video_id,
language_code,
transcript_name,
file_format,
provider,
)
create_or_update_video_transcript(video_id, language_code, metadata={
'provider': provider,
'file_name': transcript_name,
'file_format': file_format
})
response = Response(status=status.HTTP_200_OK)
else:
message = (
......
......@@ -3,4 +3,3 @@ ddt==0.8.0
django-nose==1.4.4
mock==1.0.1
pylint==1.3.0
tox==2.7.0
......@@ -3,10 +3,10 @@ envlist = django{18,110,111}
[testenv]
deps =
-r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
django18: Django>=1.8,<1.9
django110: Django>=1.10,<1.11
django111: Django>=1.11,<2
-r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
commands =
python manage.py test {posargs}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment