Commit 28993bd5 by Nimisha Asthagiri

Support for studio-based Video Pipeline.

Allow "colon" in edx-video_ids.
Added get_videos_for_ids method.
Added status and created fields.
parent e39fcbc8
...@@ -2,7 +2,7 @@ edx-val ...@@ -2,7 +2,7 @@ edx-val
======= =======
Note: Note:
The naming convetion for the `profile_name` in `Profile` objects will be the The naming convention for the `profile_name` in `Profile` objects will be the
medium of the profile (a-z), an underscore, and then the quality (a-z). medium of the profile (a-z), an underscore, and then the quality (a-z).
Examples: Examples:
......
...@@ -129,6 +129,7 @@ def get_video_info(edx_video_id, location=None): # pylint: disable=W0613 ...@@ -129,6 +129,7 @@ def get_video_info(edx_video_id, location=None): # pylint: disable=W0613
{ {
url: api url to the video url: api url to the video
edx_video_id: ID of the video edx_video_id: ID of the video
status: Status of the video as a string
duration: Length of video in seconds duration: Length of video in seconds
client_video_id: client ID of video client_video_id: client ID of video
encoded_video: a list of EncodedVideo dicts encoded_video: a list of EncodedVideo dicts
...@@ -211,6 +212,13 @@ def get_videos_for_course(course_id): ...@@ -211,6 +212,13 @@ def get_videos_for_course(course_id):
videos = Video.objects.filter(courses__course_id=unicode(course_id)) videos = Video.objects.filter(courses__course_id=unicode(course_id))
return (VideoSerializer(video).data for video in videos) return (VideoSerializer(video).data for video in videos)
def get_videos_for_ids(edx_video_ids):
"""
Returns an iterator of videos that match the given list of ids
"""
videos = Video.objects.filter(edx_video_id__in=edx_video_ids)
return (VideoSerializer(video).data for video in videos)
def get_video_info_for_course_and_profile(course_id, profile_name): def get_video_info_for_course_and_profile(course_id, profile_name):
"""Returns a dict mapping profiles to URLs. """Returns a dict mapping profiles to URLs.
......
...@@ -85,7 +85,7 @@ class Migration(SchemaMigration): ...@@ -85,7 +85,7 @@ class Migration(SchemaMigration):
models = { models = {
'edxval.coursevideos': { 'edxval.coursevideo': {
'Meta': {'unique_together': "(('course_id', 'video'),)", 'object_name': 'CourseVideo'}, 'Meta': {'unique_together': "(('course_id', 'video'),)", 'object_name': 'CourseVideo'},
'course_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), 'course_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
......
...@@ -24,7 +24,7 @@ class Migration(DataMigration): ...@@ -24,7 +24,7 @@ class Migration(DataMigration):
).delete() ).delete()
models = { models = {
'edxval.coursevideos': { 'edxval.coursevideo': {
'Meta': {'unique_together': "(('course_id', 'video'),)", 'object_name': 'CourseVideo'}, 'Meta': {'unique_together': "(('course_id', 'video'),)", 'object_name': 'CourseVideo'},
'course_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}), 'course_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
......
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'Video.created'
db.add_column('edxval_video', 'created',
self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, default=datetime.datetime(2014, 11, 17, 0, 0), blank=True),
keep_default=False)
# Adding field 'Video.status'
db.add_column('edxval_video', 'status',
self.gf('django.db.models.fields.CharField')(default='File Complete', max_length=255, db_index=True),
keep_default=False)
# Changing field 'Video.edx_video_id'
db.alter_column('edxval_video', 'edx_video_id', self.gf('django.db.models.fields.CharField')(unique=True, max_length=100))
# Changing field 'EncodedVideo.url'
db.alter_column('edxval_encodedvideo', 'url', self.gf('django.db.models.fields.CharField')(max_length=200))
def backwards(self, orm):
# Deleting field 'Video.created'
db.delete_column('edxval_video', 'created')
# Deleting field 'Video.status'
db.delete_column('edxval_video', 'status')
# Changing field 'Video.edx_video_id'
db.alter_column('edxval_video', 'edx_video_id', self.gf('django.db.models.fields.CharField')(max_length=50, unique=True))
# Changing field 'EncodedVideo.url'
db.alter_column('edxval_encodedvideo', 'url', self.gf('django.db.models.fields.URLField')(max_length=200))
models = {
'edxval.coursevideo': {
'Meta': {'unique_together': "(('course_id', 'video'),)", 'object_name': 'CourseVideo'},
'course_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'video': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'courses'", 'to': "orm['edxval.Video']"})
},
'edxval.encodedvideo': {
'Meta': {'object_name': 'EncodedVideo'},
'bitrate': ('django.db.models.fields.PositiveIntegerField', [], {}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'file_size': ('django.db.models.fields.PositiveIntegerField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'profile': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'+'", 'to': "orm['edxval.Profile']"}),
'url': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
'video': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'encoded_videos'", 'to': "orm['edxval.Video']"})
},
'edxval.profile': {
'Meta': {'object_name': 'Profile'},
'extension': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
'height': ('django.db.models.fields.PositiveIntegerField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'profile_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50'}),
'width': ('django.db.models.fields.PositiveIntegerField', [], {})
},
'edxval.subtitle': {
'Meta': {'object_name': 'Subtitle'},
'content': ('django.db.models.fields.TextField', [], {'default': "''"}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'fmt': ('django.db.models.fields.CharField', [], {'max_length': '20', 'db_index': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'max_length': '8', 'db_index': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'video': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'subtitles'", 'to': "orm['edxval.Video']"})
},
'edxval.video': {
'Meta': {'object_name': 'Video'},
'client_video_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'duration': ('django.db.models.fields.FloatField', [], {}),
'edx_video_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'status': ('django.db.models.fields.CharField', [], {'max_length': '255', 'db_index': 'True'})
}
}
complete_apps = ['edxval']
\ No newline at end of file
...@@ -32,7 +32,7 @@ from django.core.validators import MinValueValidator, RegexValidator ...@@ -32,7 +32,7 @@ from django.core.validators import MinValueValidator, RegexValidator
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
URL_REGEX = r'^[a-zA-Z0-9\-_]*$' URL_REGEX = r'^[a-zA-Z0-9\-_\:]*$'
class Profile(models.Model): class Profile(models.Model):
...@@ -68,8 +68,9 @@ class Video(models.Model): ...@@ -68,8 +68,9 @@ class Video(models.Model):
A video can have multiple formats. This model are the fields that represent A video can have multiple formats. This model are the fields that represent
the collection of those videos that do not change across formats. the collection of those videos that do not change across formats.
""" """
created = models.DateTimeField(auto_now_add=True)
edx_video_id = models.CharField( edx_video_id = models.CharField(
max_length=50, max_length=100,
unique=True, unique=True,
validators=[ validators=[
RegexValidator( RegexValidator(
...@@ -81,6 +82,7 @@ class Video(models.Model): ...@@ -81,6 +82,7 @@ class Video(models.Model):
) )
client_video_id = models.CharField(max_length=255, db_index=True, blank=True) client_video_id = models.CharField(max_length=255, db_index=True, blank=True)
duration = models.FloatField(validators=[MinValueValidator(0)]) duration = models.FloatField(validators=[MinValueValidator(0)])
status = models.CharField(max_length=255, db_index=True)
def get_absolute_url(self): def get_absolute_url(self):
""" """
......
...@@ -45,6 +45,7 @@ VIDEO_DICT_NEGATIVE_DURATION = dict( ...@@ -45,6 +45,7 @@ VIDEO_DICT_NEGATIVE_DURATION = dict(
client_video_id="Thunder Cats S01E01", client_video_id="Thunder Cats S01E01",
duration=-111, duration=-111,
edx_video_id="thisis12char-thisis7", edx_video_id="thisis12char-thisis7",
status="test",
encoded_videos=[], encoded_videos=[],
subtitles=[] subtitles=[]
) )
...@@ -52,11 +53,13 @@ VIDEO_DICT_BEE_INVALID = dict( ...@@ -52,11 +53,13 @@ VIDEO_DICT_BEE_INVALID = dict(
client_video_id="Barking Bee", client_video_id="Barking Bee",
duration=111.00, duration=111.00,
edx_video_id="wa/sps", edx_video_id="wa/sps",
status="test",
) )
VIDEO_DICT_INVALID_ID = dict( VIDEO_DICT_INVALID_ID = dict(
client_video_id="SuperSloth", client_video_id="SuperSloth",
duration=42, duration=42,
edx_video_id="sloppy/sloth!!", edx_video_id="sloppy/sloth!!",
status="test",
encoded_videos=[], encoded_videos=[],
subtitles=[] subtitles=[]
) )
...@@ -77,6 +80,7 @@ VIDEO_DICT_NON_LATIN_TITLE = dict( ...@@ -77,6 +80,7 @@ VIDEO_DICT_NON_LATIN_TITLE = dict(
client_video_id=u"배고픈 햄스터", client_video_id=u"배고픈 햄스터",
duration=42, duration=42,
edx_video_id="ID", edx_video_id="ID",
status="test",
encoded_videos=[], encoded_videos=[],
subtitles=[] subtitles=[]
) )
...@@ -84,6 +88,7 @@ VIDEO_DICT_NON_LATIN_ID = dict( ...@@ -84,6 +88,7 @@ VIDEO_DICT_NON_LATIN_ID = dict(
client_video_id="Hungry Hamster", client_video_id="Hungry Hamster",
duration=42, duration=42,
edx_video_id="밥줘", edx_video_id="밥줘",
status="test",
encoded_videos=[], encoded_videos=[],
subtitles=[] subtitles=[]
) )
...@@ -140,12 +145,14 @@ Fish ...@@ -140,12 +145,14 @@ Fish
VIDEO_DICT_FISH = dict( VIDEO_DICT_FISH = dict(
client_video_id="Shallow Swordfish", client_video_id="Shallow Swordfish",
duration=122.00, duration=122.00,
edx_video_id="super-soaker" edx_video_id="super-soaker",
status="test",
) )
VIDEO_DICT_DIFFERENT_ID_FISH = dict( VIDEO_DICT_DIFFERENT_ID_FISH = dict(
client_video_id="Shallow Swordfish", client_video_id="Shallow Swordfish",
duration=122.00, duration=122.00,
edx_video_id="medium-soaker" edx_video_id="medium-soaker",
status="test",
) )
ENCODED_VIDEO_DICT_FISH_MOBILE = dict( ENCODED_VIDEO_DICT_FISH_MOBILE = dict(
url="https://www.swordsingers.com", url="https://www.swordsingers.com",
...@@ -242,6 +249,7 @@ COMPLETE_SET_INVALID_VIDEO_FISH = dict( ...@@ -242,6 +249,7 @@ COMPLETE_SET_INVALID_VIDEO_FISH = dict(
client_video_id="Shallow Swordfish", client_video_id="Shallow Swordfish",
duration=122.00, duration=122.00,
edx_video_id="super/soaker", edx_video_id="super/soaker",
status="test",
encoded_videos=[ encoded_videos=[
ENCODED_VIDEO_DICT_FISH_MOBILE, ENCODED_VIDEO_DICT_FISH_MOBILE,
ENCODED_VIDEO_DICT_FISH_DESKTOP ENCODED_VIDEO_DICT_FISH_DESKTOP
...@@ -259,7 +267,8 @@ Star ...@@ -259,7 +267,8 @@ Star
VIDEO_DICT_STAR = dict( VIDEO_DICT_STAR = dict(
client_video_id="TWINKLE TWINKLE", client_video_id="TWINKLE TWINKLE",
duration=122.00, duration=122.00,
edx_video_id="little-star" edx_video_id="little-star",
status="test",
) )
ENCODED_VIDEO_DICT_STAR = dict( ENCODED_VIDEO_DICT_STAR = dict(
url="https://www.howIwonder.com", url="https://www.howIwonder.com",
...@@ -317,6 +326,7 @@ VIDEO_DICT_ZEBRA = dict( ...@@ -317,6 +326,7 @@ VIDEO_DICT_ZEBRA = dict(
client_video_id="Zesty Zebra", client_video_id="Zesty Zebra",
duration=111.00, duration=111.00,
edx_video_id="zestttt", edx_video_id="zestttt",
status="test",
encoded_videos=[], encoded_videos=[],
subtitles=[] subtitles=[]
) )
...@@ -324,6 +334,7 @@ VIDEO_DICT_ANIMAL = dict( ...@@ -324,6 +334,7 @@ VIDEO_DICT_ANIMAL = dict(
client_video_id="Average Animal", client_video_id="Average Animal",
duration=111.00, duration=111.00,
edx_video_id="mediocrity", edx_video_id="mediocrity",
status="test",
encoded_videos=[], encoded_videos=[],
subtitles=[] subtitles=[]
) )
...@@ -331,6 +342,7 @@ VIDEO_DICT_UPDATE_ANIMAL = dict( ...@@ -331,6 +342,7 @@ VIDEO_DICT_UPDATE_ANIMAL = dict(
client_video_id="Above Average Animal", client_video_id="Above Average Animal",
duration=999.00, duration=999.00,
edx_video_id="mediocrity", edx_video_id="mediocrity",
status="test",
encoded_videos=[], encoded_videos=[],
subtitles=[] subtitles=[]
) )
...@@ -161,6 +161,17 @@ class GetVideoInfoTest(TestCase): ...@@ -161,6 +161,17 @@ class GetVideoInfoTest(TestCase):
videos = list(api.get_videos_for_course('unknown')) videos = list(api.get_videos_for_course('unknown'))
self.assertEqual(len(videos), 0) self.assertEqual(len(videos), 0)
def test_get_videos_for_ids(self):
"""
Tests retrieving videos for ids
"""
edx_video_id = constants.VIDEO_DICT_FISH['edx_video_id']
videos = list(api.get_videos_for_ids([edx_video_id]))
self.assertEqual(len(videos), 1)
self.assertEqual(videos[0]['edx_video_id'], edx_video_id)
videos = list(api.get_videos_for_ids(['unknown']))
self.assertEqual(len(videos), 0)
def test_no_such_video(self): def test_no_such_video(self):
""" """
Tests searching for a video that does not exist Tests searching for a video that does not exist
......
...@@ -513,6 +513,7 @@ class VideoListTest(APIAuthTestCase): ...@@ -513,6 +513,7 @@ class VideoListTest(APIAuthTestCase):
""" """
video = { video = {
'edx_video_id': 'testing-youtube', 'edx_video_id': 'testing-youtube',
'status': 'test',
'encoded_videos': [ 'encoded_videos': [
{ {
'profile': 'youtube', 'profile': 'youtube',
......
...@@ -14,17 +14,17 @@ urlpatterns = patterns( ...@@ -14,17 +14,17 @@ urlpatterns = patterns(
name="video-list" name="video-list"
), ),
url( url(
r'^videos/(?P<edx_video_id>[-\w]+)$', r'^videos/(?P<edx_video_id>[-\:\w]+)$',
views.VideoDetail.as_view(), views.VideoDetail.as_view(),
name="video-detail" name="video-detail"
), ),
url( url(
r'^videos/(?P<video__edx_video_id>[-\w]+)/(?P<language>[-_\w]+)$', r'^videos/(?P<video__edx_video_id>[-\:\w]+)/(?P<language>[-_\w]+)$',
views.SubtitleDetail.as_view(), views.SubtitleDetail.as_view(),
name="subtitle-detail" name="subtitle-detail"
), ),
url( url(
r'^videos/(?P<edx_video_id>[-\w]+)/(?P<language>[-_\w]+)/subtitle$', r'^videos/(?P<edx_video_id>[-\:\w]+)/(?P<language>[-_\w]+)/subtitle$',
views.get_subtitle, views.get_subtitle,
name="subtitle-content" name="subtitle-content"
), ),
......
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