Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew Schoen committed Apr 1, 2011
1 parent d152f70 commit 40e5cdf
Show file tree
Hide file tree
Showing 29 changed files with 2,113 additions and 0 deletions.
2 changes: 2 additions & 0 deletions AUTHORS
@@ -0,0 +1,2 @@
* Andrew Schoen <andrew.schoen@gmail.com>
* Mark Ransom <megamark16@gmail.com>
10 changes: 10 additions & 0 deletions LICENSE
@@ -0,0 +1,10 @@
Copyright (c) 2011, Salva O'Renick
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of the Salva O'Renick nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17 changes: 17 additions & 0 deletions README.rst
@@ -0,0 +1,17 @@
django-multimedia
=================
coming soon...

Dependancies
============

- django-celery
- django-filer
- paramiko
- pycrpto==2.0.1
- ffmpeg

Getting Started
=============

coming soon...
2 changes: 2 additions & 0 deletions multimedia/__init__.py
@@ -0,0 +1,2 @@
VERSION = (0,1,0)
__version__ = "0.1.0"
59 changes: 59 additions & 0 deletions multimedia/admin.py
@@ -0,0 +1,59 @@
from django.contrib import admin, messages
from models import Video, Audio
from forms import VideoAdminForm, AudioAdminForm

from celery.task.sets import subtask
from tasks import encode_media, generate_thumbnail, upload_media

class MediaAdmin(admin.ModelAdmin):
list_display = ('id','title','profile','encoding','encoded','uploaded','date_added','date_modified')
list_display_links = ('id','title',)
prepopulated_fields = {'slug': ('title',)}
exclude = ('user','file_type',)
readonly_fields = ('encoded','uploaded',)
list_filter = ('encoded','uploaded','encoding',)

def save_model(self, request, obj, form, change):
obj.user = request.user
obj.save()
if obj.encode and (not obj.encoded):
messages.success(request, "Your file is being encoded and uploaded. An email notification will be sent when complete.")

def encode_again(self, request, queryset):
rows_updated = 0
for media in queryset:
if media.encode:
rows_updated += 1
encode_media.delay(media.id, callback=subtask(upload_media))
media.encoded = False
media.uploaded = False
media.encoding = True
media.save()
if rows_updated == 1:
message_bit = "Your file is"
elif rows_updated > 1:
message_bit = "Your files are"

if rows_updated > 0:
messages.success(request, "%s being encoded and uploaded. An email notification will be sent when complete." % message_bit)

encode_again.short_description = "Re-encode and upload media"
actions = [encode_again,]

class VideoAdmin(MediaAdmin):
form = VideoAdminForm
readonly_fields = ('encoded','uploaded','generated_thumbnail',)
list_display = ('id','title','profile','encoding','encoded','uploaded','date_added','date_modified','admin_thumbnail',)

class Meta:
model = Video

class AudioAdmin(MediaAdmin):
form = AudioAdminForm

class Meta:
model = Audio

admin.site.register(Video, VideoAdmin)
admin.site.register(Audio, AudioAdmin)

Empty file added multimedia/conf/__init__.py
Empty file.
38 changes: 38 additions & 0 deletions multimedia/conf/multimedia_settings.py
@@ -0,0 +1,38 @@
from django.conf import settings


MEDIA_SERVER_HOST = getattr(settings.MEDIA_SERVER_HOST, "")
MEDIA_SERVER_USER = getattr(settings.MEDIA_SERVER_USER, "")
MEDIA_SERVER_PASSWORD = getattr(settings.MEDIA_SERVER_PASSWORD, "")
MEDIA_SERVER_PORT = getattr(settings.MEDIA_SERVER_PORT, 22)
MEDIA_SERVER_VIDEO_BUCKET = getattr(settings.MEDIA_SERVER_VIDEO_BUCKET, "")
MEDIA_SERVER_AUDIO_BUCKET = getattr(settings.MEDIA_SERVER_AUDIO_BUCKET, "")
MEDIA_SERVER_AUDIO_PATH = getattr(settings.MEDIA_SERVER_AUDIO_PATH, "")
MEDIA_SERVER_VIDEO_PATH = getattr(settings.MEDIA_SERVER_VIDEO_PATH, "")

MULTIMEDIA_NOTIFICATION_EMAIL = getattr(settings.MULTIMEDIA_NOTIFICATION_EMAIL, "")

DEFAULT_VIDEO_PROFILES = {
'f4v': {
'encode_cmd': 'ffmpeg -y -i "%(input)s" -f mp4 -acodec libfaac -ab 128k -vcodec libx264 -vpre slow -b 690k -ac 2 -crf 22 -s 620x350 -r 30 "%(output)s"',
'encode':True,
'name':'Flash Video',
'container':'f4v',
'thumbnail_cmd': 'ffmpeg -y -itsoffset -%(offset)s -i "%(input)s" -vcodec mjpeg -vframes 1 -an -f rawvideo -s 620x350 "%(output)s"'
},
}

MULTIMEDIA_VIDEO_PROFILES = getattr(settings.MULTIMEDIA_VIDEO_PROFILES, DEFAULT_VIDEO_PROFILES)

DEFAULT_AUDIO_PROFILES = {
'audio': {
'encode_cmd': 'ffmpeg -y -i "%(input)s" "%(output)s"',
'encode':True,
'name':'MP3 Audio',
'container':'mp3',
},
}

MULTIMEDIA_AUDIO_PROFILES = getattr(settings.MULTIMEDIA_AUDIO_PROFILES, DEFAULT_AUDIO_PROFILES)

MULTIMEDIA_APP_LABLEL = getattr(settings.MULTIMEDIA_APP_LABEL, "Multimedia")
14 changes: 14 additions & 0 deletions multimedia/forms.py
@@ -0,0 +1,14 @@
from django import forms
from models import Video, Audio, VIDEO_PROFILES, AUDIO_PROFILES

class VideoAdminForm(forms.ModelForm):
profile = forms.ChoiceField(choices=VIDEO_PROFILES)

class Meta:
model = Video

class AudioAdminForm(forms.ModelForm):
profile = forms.ChoiceField(choices=AUDIO_PROFILES)

class Meta:
model = Audio
Empty file.
Empty file.
48 changes: 48 additions & 0 deletions multimedia/management/commands/encode_video.py
@@ -0,0 +1,48 @@
"""
A management command which pulls rss feeds for each feed setup in the feedreader.Feed.
"""
import os
import shutil
from dateutil import parser
from subprocess import Popen, PIPE
from django.core.management.base import NoArgsCommand
from django.utils.html import strip_tags
from django.conf import settings
from multimedia.models import Video
from multimedia.utils import upload_file, check_encoded_video_length

class Command(NoArgsCommand):
help = "Pull all new entries from all Feed records"

def handle_noargs(self, **options):
videos = Video.objects.filter(uploaded=False)
for video in videos:
print "Encoding and Uploading %s" % video
video_path = os.path.join(settings.MEDIA_ROOT, video.file.name)
if os.path.exists(video_path):
need_to_encode = True
encoded_video_path = os.path.join(settings.MEDIA_ROOT, "%s_encoded.f4v" % video.file.name)
if os.path.exists(encoded_video_path):
if check_encoded_video_length(video):
print "No need to encode"
need_to_encode = False
else:
print "Existing encoded version is bad, deleting and starting again"
os.remove(encoded_video_path)

if need_to_encode:
temp_video_path = "%s.encoding" % video_path
shutil.move(video_path, temp_video_path)
command = '/usr/local/bin/ffmpeg -i %s -f mp4 -acodec libfaac -ab 128k -vcodec libx264 -vpre slow -b 690k -ac 2 -crf 22 -s 496x278 %s' % (temp_video_path, encoded_video_path)
process = Popen(command.split(' '))
process.wait()
#log_file = open('/tmp/video_encode_log_%s.txt' % video.id, 'w')
#log_file.write(process.communicate()[0])
#log_file.close()
shutil.move(temp_video_path, video_path)

# We only want to do this for the first video file that isn't already being encoded, that
# way we won't ever have multiple encoding processes trying to encode the same videos.
upload_file(video)
return

81 changes: 81 additions & 0 deletions multimedia/migrations/0001_initial.py
@@ -0,0 +1,81 @@
# encoding: 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 model 'Media'
db.create_table('multimedia_media', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('title', self.gf('django.db.models.fields.CharField')(max_length=255)),
('date_added', self.gf('django.db.models.fields.DateField')(auto_now_add=True, blank=True)),
('description', self.gf('django.db.models.fields.TextField')(blank=True)),
('file', self.gf('django.db.models.fields.files.FileField')(max_length=100)),
('uploaded', self.gf('django.db.models.fields.BooleanField')(default=False)),
('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True)),
('media_type', self.gf('django.db.models.fields.CharField')(max_length=255)),
))
db.send_create_signal('multimedia', ['Media'])


def backwards(self, orm):

# Deleting model 'Media'
db.delete_table('multimedia_media')


models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'multimedia.media': {
'Meta': {'ordering': "('-date_added',)", 'object_name': 'Media'},
'date_added': ('django.db.models.fields.DateField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'file': ('django.db.models.fields.files.FileField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'media_type': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'uploaded': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'})
}
}

complete_apps = ['multimedia']

0 comments on commit 40e5cdf

Please sign in to comment.