Commit dd811f85 by Dave St.Germain

Added subtitle model and API

parent df4728fc
......@@ -3,9 +3,9 @@ Admin file for django app edxval.
"""
from django.contrib import admin
from .models import Video, Profile, EncodedVideo
from .models import Video, Profile, EncodedVideo, Subtitle
admin.site.register(Video)
admin.site.register(Profile)
admin.site.register(EncodedVideo)
admin.site.register(Subtitle)
......@@ -139,6 +139,11 @@ def get_video_info(edx_video_id, location=None): # pylint: disable=W0613
extension: 3 letter extension of video
width: horizontal pixel resolution
height: vertical pixel resolution
subtitles: a list of Subtitle dicts
fmt: file format (SRT or SJSON)
language: language code
content_url: url of file
url: api url to subtitle
}
Raises:
......
......@@ -29,6 +29,7 @@ invalid profile_name will be returned.
from django.db import models
from django.core.validators import MinValueValidator, RegexValidator
from django.core.urlresolvers import reverse
url_regex = r'^[a-zA-Z0-9\-]*$'
......@@ -78,6 +79,9 @@ class Video(models.Model):
client_video_id = models.CharField(max_length=255, db_index=True)
duration = models.FloatField(validators=[MinValueValidator(0)])
def __str__(self):
return self.edx_video_id
class CourseVideos(models.Model):
"""
......@@ -89,7 +93,7 @@ class CourseVideos(models.Model):
course_id = models.CharField(max_length=255)
video = models.ForeignKey(Video)
class Meta:
class Meta: # pylint: disable=C1001
"""
course_id is listed first in this composite index
"""
......@@ -108,3 +112,34 @@ class EncodedVideo(models.Model):
profile = models.ForeignKey(Profile, related_name="+")
video = models.ForeignKey(Video, related_name="encoded_videos")
SUBTITLE_FORMATS = (
('srt', 'SubRip'),
('sjson', 'SRT JSON')
)
class Subtitle(models.Model):
"""
Subtitle for video
"""
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
video = models.ForeignKey(Video, related_name="subtitles")
fmt = models.CharField(max_length=20, db_index=True, choices=SUBTITLE_FORMATS)
language = models.CharField(max_length=8, db_index=True)
content = models.TextField()
def __str__(self):
return '%s Subtitle for %s' % (self.language, self.video)
def get_absolute_url(self):
return reverse('subtitle-content', args=[str(self.id)])
@property
def content_type(self):
if self.fmt == 'sjson':
return 'application/json'
else:
return 'text/plain'
......@@ -7,7 +7,7 @@ EncodedVideoSerializer which uses the profile_name as it's profile field.
from rest_framework import serializers
from django.core.exceptions import ValidationError
from edxval.models import Profile, Video, EncodedVideo
from edxval.models import Profile, Video, EncodedVideo, Subtitle
class ProfileSerializer(serializers.ModelSerializer):
......@@ -51,6 +51,41 @@ class EncodedVideoSerializer(serializers.ModelSerializer):
return data.get('profile', None)
class SubtitleSerializer(serializers.HyperlinkedModelSerializer):
"""
Serializer for Subtitle objects
"""
content_url = serializers.CharField(source='get_absolute_url', read_only=True)
content = serializers.CharField(write_only=True)
def validate_content(self, attrs, source):
"""
Validate that the subtitle is in the correct format
"""
value = attrs[source]
if attrs.get('fmt') == 'sjson':
import json
try:
loaded = json.loads(value)
except ValueError:
raise serializers.ValidationError("Not in JSON format")
else:
attrs[source] = json.dumps(loaded)
return attrs
class Meta: # pylint: disable=C1001, C0111
model = Subtitle
lookup_field = "id"
fields = (
"fmt",
"language",
"id",
"content_url",
"url",
"content"
)
class VideoSerializer(serializers.HyperlinkedModelSerializer):
"""
Serializer for Video object
......@@ -58,6 +93,7 @@ class VideoSerializer(serializers.HyperlinkedModelSerializer):
encoded_videos takes a list of dicts EncodedVideo data.
"""
encoded_videos = EncodedVideoSerializer(many=True, allow_add_remove=True)
subtitles = SubtitleSerializer(many=True, allow_add_remove=True)
class Meta: # pylint: disable=C0111
model = Video
......
......@@ -18,4 +18,13 @@ urlpatterns = patterns(
views.VideoDetail.as_view(),
name="video-detail"
),
url(
r'^edxval/subtitle/(?P<id>[\d]+)$',
views.SubtitleDetail.as_view(),
name="subtitle-detail"
),
url(r'^edxval/subtitle/(?P<subtitle_id>[\d]+)/content$',
views.get_subtitle,
name="subtitle-content"
),
)
......@@ -3,11 +3,14 @@ Views file for django app edxval.
"""
from rest_framework import generics
from django.http import HttpResponse
from django.views.decorators.http import last_modified
from edxval.models import Video, Profile
from edxval.models import Video, Profile, Subtitle
from edxval.serializers import (
VideoSerializer,
ProfileSerializer
ProfileSerializer,
SubtitleSerializer
)
......@@ -36,3 +39,22 @@ class VideoDetail(generics.RetrieveUpdateDestroyAPIView):
lookup_field = "edx_video_id"
queryset = Video.objects.all()
serializer_class = VideoSerializer
class SubtitleDetail(generics.RetrieveUpdateDestroyAPIView):
"""
Gets a subtitle instance given its id
"""
lookup_field = "id"
queryset = Subtitle.objects.all()
serializer_class = SubtitleSerializer
@last_modified(last_modified_func=lambda request, subtitle_id: Subtitle.objects.get(pk=subtitle_id).modified)
def get_subtitle(request, subtitle_id):
"""
Return content of subtitle by id
"""
sub = Subtitle.objects.get(pk=subtitle_id)
response = HttpResponse(sub.content, content_type=sub.content_type)
return response
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