Skip to content

Commit

Permalink
Initialized django project for VAL
Browse files Browse the repository at this point in the history
Created models for Video, EncodedVideo, and Profile. Added
function to return a serialized video object, with it's
associated EncodedVideo objects.

Other Notes:
-Added djangorestframework==2.3.5
-Added Travis
-Added mock==1.0.1
-Added django-nose==1.2
-Added coverage==3.7.1
  • Loading branch information
christopher lee committed Aug 4, 2014
1 parent 15736e0 commit 2bb8cd0
Show file tree
Hide file tree
Showing 17 changed files with 725 additions and 0 deletions.
66 changes: 66 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
*.py[cod]

*.db

# C extensions
*.so

# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
lib64
__pycache__

# Various common editor backups
*.orig
.*.swp

# Installer logs
pip-log.txt

# Unit test / coverage reports
.coverage
.tox
nosetests.xml
htmlcov
coverage.xml

# Mr Developer
.mr.developer.cfg
.project
.pydevproject

# Sass/Codekit
.sass-cache/
config.codekit

# some mac thing
.DS_Store

# PyCharm
.idea

# node
node_modules
npm-debug.log
coverage

# tim-specific
ora2db
storage/*
openassessment/xblock/static/js/fixtures/*.html

# logging
logs/*/*.log*

# Vagrant
.vagrant
Empty file added edxval/__init__.py
Empty file.
7 changes: 7 additions & 0 deletions edxval/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.contrib import admin
from .models import Video, Profile, EncodedVideo

admin.site.register(Video)
admin.site.register(Profile)
admin.site.register(EncodedVideo)

111 changes: 111 additions & 0 deletions edxval/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# -*- coding: utf-8 -*-
"""
The internal API for VAL
"""
import logging

from edxval.models import Video
from edxval.serializers import EncodedVideoSetSerializer

logger = logging.getLogger(__name__)


class ValError(Exception):
"""
An error that occurs during VAL actions.
This error is raised when the VAL API cannot perform a requested
action.
"""
pass


class ValInternalError(ValError):
"""
An error internal to the VAL API has occurred.
This error is raised when an error occurs that is not caused by incorrect
use of the API, but rather internal implementation of the underlying
services.
"""
pass


class ValVideoNotFoundError(ValError):
"""
This error is raised when a video is not found
If a state is specified in a call to the API that results in no matching
entry in database, this error may be raised.
"""
pass


def get_video_info(edx_video_id, location=None):
"""
Retrieves all encoded videos of a video found with given video edx_video_id
Args:
location (str): geographic locations used determine CDN
edx_video_id (str): id for video content.
Returns:
result (dict): Deserialized Video Object with related field EncodedVideo
Returns all the Video object fields, and it's related EncodedVideo
objects in a list.
{
edx_video_id: ID of the video
duration: Length of video in seconds
client_title: human readable ID
encoded_video: a list of EncodedVideo dicts
url: url of the video
file_size: size of the video in bytes
profile: a dict of encoding details
profile_name: ID of the profile
extension: 3 letter extension of video
width: horizontal pixel resolution
height: vertical pixel resolution
}
Raises:
ValVideoNotFoundError: Raised if video doesn't exist
ValInternalError: Raised for unknown errors
Example:
Given one EncodedVideo with edx_video_id "thisis12char-thisis7"
>>>
>>> get_video_info("thisis12char-thisis7",location)
Returns (dict):
>>>{
>>> 'edx_video_id': u'thisis12char-thisis7',
>>> 'duration': 111.0,
>>> 'client_title': u'Thunder Cats S01E01',
>>> 'encoded_video': [
>>> {
>>> 'url': u'http://www.meowmix.com',
>>> 'file_size': 25556,
>>> 'bitrate': 9600,
>>> 'profile': {
>>> 'profile_name': u'mobile',
>>> 'extension': u'avi',
>>> 'width': 100,
>>> 'height': 101
>>> }
>>> },
>>> ]
>>>}
"""
try:
v = Video.objects.get(edx_video_id=edx_video_id)
result = EncodedVideoSetSerializer(v)
except Video.DoesNotExist:
error_message = u"Video not found for edx_video_id: {0}".format(edx_video_id)
raise ValVideoNotFoundError(error_message)
except Exception:
error_message = u"Could not get edx_video_id: {0}".format(edx_video_id)
logger.exception(error_message)
raise ValInternalError(error_message)
return result.data
80 changes: 80 additions & 0 deletions edxval/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
"""
Django models for videos for Video Abstraction Layer (VAL)
"""

from django.db import models


class Profile(models.Model):
"""
Details for pre-defined encoding format
"""
profile_name = models.CharField(max_length=50, unique=True)
extension = models.CharField(max_length=10)
width = models.PositiveIntegerField()
height = models.PositiveIntegerField()

def __repr__(self):
return (
u"Profile(profile_name={0.profile_name})"
).format(self)

def __unicode__(self):
return repr(self)


class Video(models.Model):
"""
Model for a Video group with the same content.
A video can have multiple formats. This model is the collection of those
videos with fields that do not change across formats.
"""
edx_video_id = models.CharField(max_length=50, unique=True)
client_title = models.CharField(max_length=255, db_index=True)
duration = models.FloatField()

def __repr__(self):
return (
u"Video(client_title={0.client_title}, duration={0.duration})"
).format(self)

def __unicode__(self):
return repr(self)


class CourseVideos(models.Model):
"""
Model for the course_id associated with the video content.
Every course-semester has a unique course_id. A video can be paired with multiple
course_id's but each pair is unique together.
"""
course_id = models.CharField(max_length=255)
video = models.ForeignKey(Video)

class Meta:
unique_together = ("course_id", "video")


class EncodedVideo(models.Model):
"""
Video/encoding pair
"""
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
url = models.URLField(max_length=200)
file_size = models.PositiveIntegerField()
bitrate = models.PositiveIntegerField()

profile = models.ForeignKey(Profile, related_name="+")
video = models.ForeignKey(Video, related_name="encoded_videos")

def __repr__(self):
return (
u"EncodedVideo(video={0.video.client_title}, "
u"profile={0.profile.profile_name})"
).format(self)

def __unicode__(self):
return repr(self)
44 changes: 44 additions & 0 deletions edxval/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""
Serializers for Video Abstraction Layer
"""
from rest_framework import serializers
from django.core.validators import MinValueValidator

from edxval.models import Profile


class VideoSerializer(serializers.Serializer):
edx_video_id = serializers.CharField(required=True, max_length=50)
duration = serializers.FloatField()
client_title = serializers.CharField(max_length=255)


class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = (
"profile_name",
"extension",
"width",
"height"
)


class OnlyEncodedVideoSerializer(serializers.Serializer):
"""
Used to serialize the EncodedVideo fir the EncodedVideoSetSerializer
"""
url = serializers.URLField(max_length=200)
file_size = serializers.IntegerField(validators=[MinValueValidator(1)])
bitrate = serializers.IntegerField(validators=[MinValueValidator(1)])
profile = ProfileSerializer()


class EncodedVideoSetSerializer(serializers.Serializer):
"""
Used to serialize a list of EncodedVideo objects it's foreign key Video Object.
"""
edx_video_id = serializers.CharField(max_length=50)
client_title = serializers.CharField(max_length=255)
duration = serializers.FloatField(validators=[MinValueValidator(1)])
encoded_videos = OnlyEncodedVideoSerializer()
Loading

0 comments on commit 2bb8cd0

Please sign in to comment.