Доброго времени суток!
Итак начнём. В статье я опишу краткий проект на django, который конвертирует/загружает видео-ролики на Ваш канал YouTube.
Пару слов об истории проблемы… Я работаю в небольшой региональной телевизионной компании, которой в один чудесный день захотелось, чтобы их контент люди могли наблюдать, не только сидя у голубых экранов, но и в YouTube. Т.к. у нас стоит вещательный сервер от Omneon, все материалы у нас готовятся в формате mov, а средний вес 15 минутной программы = 3,5Гб. Заливать файл такого размера утомительно и глупо, гораздо правильнее будет конвертировать ролики в mp4 (например) и выкладывать уже лёгкими на YouTube (благо качество от этого теряем мы не так много). Для примера: 3,5Гб сжимаются где-то в 100Мб приемлемого качества.
Статья не претендует на звание «открытие» и «прорыв года», она просто упорядочивает известные факты в удобную инструкцию.
Для себя я руководствовался следующей последовательностью действий:
Также мне захотелось добавить некое логирование, аля «кто / когда / что закачал».
Надеюсь django у Вас установлено, иначе дальше читать бессмысленно. Также потребуются следующие пакеты:
Сам люблю когда на рассказываемое хоть краем глаза можно посмотреть, потому вот финальный скриншот:

Буду рассказывать по пунктам с самого старта.
Первым делом стартуем новый проект: django-admin.py startproject YTupload
В новом проекте сразу правим settings.py под свои нужды и добавляем следующие поля:
Выше я «заикался» о логировании действий. Вот для этого нам нужна следующая моделька.
создаём приложение django-admin.py startapp control
открываем models.py
переходим к views.py
Код не сложный (если нужно будет, готов по подробнее рассказать), функция index выдаёт 2 списка: первый — какие файлы есть в папке, второй — какие файлы уже записаны в лог. Вывод этой функции виден на скриншоте выше… enter и exit — самая простая аутентификация.
Идём дальше: urls.py
Здесь всё просто. Зашёл, авторизовался, закачал!
Финальный аккорд — это converting.py, который и делает всю работу.
Этот скрипт у меня запускается через crontab. Смысл прост: берём первый попавшийся файл со статусом «in query» (в очереди), конвертируем (меняем статус на converting), загружаем (меняем статус на uploading), загрузили (статус = uploaded).
crontab:
Ну и собственно дарю html-код шаблона:
enter.html
index.html
Надеюсь кому-то это поможет / сэкономит время / или просто повеселит. Представленный мной вариант можно доработать (может выложить на github?), слава богу кучу всего ещё можно поправить, например какие я вижу варианты развития:
Спасибо за внимание!
P.S. код далёк от совершенства, будет «шлифоваться». Спасибо Evgeny Bespaly за советы по оптимизации, обязательно воспользуюсь.
UPD: проект на github = https://github.com/1vank1n/YTupload/, буду рад всем кто поможет довести его до ума!
Итак начнём. В статье я опишу краткий проект на django, который конвертирует/загружает видео-ролики на Ваш канал YouTube.
Пару слов об истории проблемы… Я работаю в небольшой региональной телевизионной компании, которой в один чудесный день захотелось, чтобы их контент люди могли наблюдать, не только сидя у голубых экранов, но и в YouTube. Т.к. у нас стоит вещательный сервер от Omneon, все материалы у нас готовятся в формате mov, а средний вес 15 минутной программы = 3,5Гб. Заливать файл такого размера утомительно и глупо, гораздо правильнее будет конвертировать ролики в mp4 (например) и выкладывать уже лёгкими на YouTube (благо качество от этого теряем мы не так много). Для примера: 3,5Гб сжимаются где-то в 100Мб приемлемого качества.
Статья не претендует на звание «открытие» и «прорыв года», она просто упорядочивает известные факты в удобную инструкцию.
1. Алгоритм
Для себя я руководствовался следующей последовательностью действий:
- Смотрим в папку, где живут видео-ролики
- Выбираем нужный
- Вводим информацию для YT (название, описание, ключевые слова)
- Ставим файл в очередь
- В очереди последовательно идёт конвертирование роликов, потом загрузка их на YT
- Как ролик загрузился, у меня высветился статус «uploaded»
Также мне захотелось добавить некое логирование, аля «кто / когда / что закачал».
2. Что необходимо?
Надеюсь django у Вас установлено, иначе дальше читать бессмысленно. Также потребуются следующие пакеты:
- youtube-upload (за собой тянет он ещё и python-gdata)
- ffmpeg (на ubuntu проставляется простой комбинацией apt-get install ffmpeg)
3. Собираем всё вместе
Сам люблю когда на рассказываемое хоть краем глаза можно посмотреть, потому вот финальный скриншот:

Буду рассказывать по пунктам с самого старта.
Первым делом стартуем новый проект: django-admin.py startproject YTupload
В новом проекте сразу правим settings.py под свои нужды и добавляем следующие поля:
ENCODE_DIR_FROM = '/путь_до_директории_в_которую_складываются_ролики_для_закачки_на_YT/'
ENCODE_DIR_TO = os.path.join(ROOT,'file_out') #временная папка куда будут складываться отконвертированные... у меня как видите это просто подпапка file_out в самом проекте
YT_LOGIN = 'login@gmail.com' #ваш логин от YT
YT_PASSWORD = 'password' #ваш пароль от YT
Выше я «заикался» о логировании действий. Вот для этого нам нужна следующая моделька.
создаём приложение django-admin.py startapp control
открываем models.py
# -*- coding: utf-8 -*-
from django.db import models
from django.contrib.auth.models import User
class Log(models.Model):
filename = models.CharField(max_length=300)
filesize = models.CharField(max_length=300)
user = models.ForeignKey(User)
created = models.DateTimeField()
uploaded = models.DateTimeField(null=True, blank=True)
link = models.CharField(max_length=300, blank=True)
#youtube properties
title = models.CharField(max_length=300)
description = models.TextField()
keywords = models.CharField(max_length=300)
status = models.CharField(max_length=300, blank=True)
class People(models.Model):
login = models.OneToOneField(User, primary_key=True)
name = models.CharField(max_length=200)
переходим к views.py
# -*- coding: utf-8 -*-
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect, HttpResponse, Http404
from django.template import RequestContext
from django.shortcuts import get_object_or_404, get_list_or_404
from django.contrib.auth import login, logout
from django.contrib.auth.forms import AuthenticationForm
from control.models import *
import os, datetime, settings
# функция вывода статуса
def LogStatus(l):
try: return Log.objects.filter(filename=l)[0].status
except: return None
def index(request, template):
if not request.user.is_authenticated():
return HttpResponseRedirect('/enter/')
loglist = Log.objects.order_by('-id')[:10]
# смотрим в директорию
listdir = os.listdir(settings.ENCODE_DIR_FROM)
dictdir = [{'filename':None,'filesize':None, 'status':None} for i in range(len(listdir))]
n = 0
for l in listdir:
dictdir[n]['filename'] = l
dictdir[n]['filesize'] = os.path.getsize(os.path.join(settings.ENCODE_DIR_FROM,l))
dictdir[n]['status'] = LogStatus(l)
n+=1
# действие по нажатию кнопки
if request.method == 'POST':
filename = request.POST['filename']
filesize = request.POST['filesize']
title = request.POST['title']
description = request.POST['description']
keywords = request.POST['keywords']
# проверить не конвертируется ли ещё?
if Log.objects.filter(filename=filename):
return HttpResponse('already in query')
else:
# записать в Log, поставить статус "конвертируется"
l = Log(filename=filename, filesize=filesize, user=User.objects.filter(id=int(request.user.id))[0], created=datetime.datetime.now(), title=title, description=description, keywords=keywords, status='in query')
l.save()
return HttpResponseRedirect('/')
return render_to_response(template, {'dictdir':dictdir,
'loglist':loglist,})
def exit(request):
logout(request)
return HttpResponseRedirect('/enter/')
def enter(request, template):
authform = AuthenticationForm()
if request.user.is_authenticated():
return HttpResponseRedirect('/')
if request.method == 'POST':
authform = AuthenticationForm(data=request.POST)
if authform.is_valid():
login(request, authform.get_user())
return HttpResponseRedirect('/')
return render_to_response(template, {'authform': authform})
Код не сложный (если нужно будет, готов по подробнее рассказать), функция index выдаёт 2 списка: первый — какие файлы есть в папке, второй — какие файлы уже записаны в лог. Вывод этой функции виден на скриншоте выше… enter и exit — самая простая аутентификация.
Идём дальше: urls.py
from django.conf.urls.defaults import *
from django.contrib import admin
admin.autodiscover()
import views, settings
urlpatterns = patterns('',
(r'^admin/', include(admin.site.urls)),
(r'^$', views.index, {'template': 'index.html'}),
(r'^enter/$', views.enter, {'template': 'enter.html'}),
(r'^exit/$', views.exit),
(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}),
)
Здесь всё просто. Зашёл, авторизовался, закачал!
Финальный аккорд — это converting.py, который и делает всю работу.
# -*- coding: utf-8 -*-
import settings, os, datetime
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
from control.models import *
if Log.objects.filter(status='converting'):
quit()
else:
try:
file = Log.objects.filter(status='in query')[0]
except:
quit()
file.status = 'converting'
file.save()
# новое имя файла
basename, extension = os.path.splitext(file.filename)
newfilename = basename + '.flv'
os.system('ffmpeg -i ' + os.path.join(settings.ENCODE_DIR_FROM, file.filename) + ' -ar 22050 -vb 1500kbits/s ' + os.path.join(settings.ENCODE_DIR_TO, newfilename))
file.status = 'uploading'
file.save()
os.system('youtube-upload --email=' + settings.YT_LOGIN + ' --password=' + settings.YT_PASSWORD + ' --title="' + file.title.encode('utf-8') + '" --description="' + file.description.encode('utf-8') + '" --category="News" --keywords="' + file.keywords.encode('utf-8') + '" ' + os.path.join(settings.ENCODE_DIR_TO, newfilename).encode("utf-8"))
file.status = 'uploaded'
file.uploaded = datetime.datetime.now()
file.save()
Этот скрипт у меня запускается через crontab. Смысл прост: берём первый попавшийся файл со статусом «in query» (в очереди), конвертируем (меняем статус на converting), загружаем (меняем статус на uploading), загрузили (статус = uploaded).
crontab:
*/1 * * * * python /var/www/YTupload/converting.py &> /dev/null
Ну и собственно дарю html-код шаблона:
enter.html
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>Вход | YTUpload | 1vank1n.habrahabr.ru</title>
<style type="text/css">
html, body {
font-size: 14px;
font-family: Georgia, "Times New Roman", Times, serif;
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
#table-center {
height: 100%;
width: 100%;
}
#form-auth {
margin-bottom: 0px;
margin-top: 0px;
margin-right: auto;
margin-left: auto;
height: 100px;
width: 330px;
}
#form-auth table td {
padding: 5px;
}
#form-auth input {
background-color: white;
border-color: #cccccc;
border-style: solid;
border-width: 1px;
padding: 5px;
display: block;
margin: 0 auto;
}
</style>
</head>
<body>
<table id="table-center">
<tr><td>
<form id="form-auth" action="" method="POST">{% csrf_token %}
<table >
{{ authform.as_table }}
<input type="hidden" name="formname" value="auth">
</table>
<input type="submit" value="Вход">
</form>
</td></tr>
</table>
</body>
</html>
index.html
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>YTUpload | 1vank1n.habrahabr.ru</title>
<script type="text/javascript" src="/media/jquery-1.6.1.min.js"></script>
<script type="text/javascript">
$(function(){
$('#choose_file a').click(function(){
$('#file_properties').fadeIn();
$('input[name="filename"]').attr('value', $(this).text());
$('input[name="filesize"]').attr('value', $(this).next('span').text());
});
});
</script>
<style type="text/css">
body {width:1000px;margin:0 auto;position: relative;font-size:11pt;}
#file_properties {display: none;}
#choose_file {width: 490px; float: left; height: 500px; overflow-y: auto;}
#loglist, #loglist table {width: 500px; float:right;}
#loglist td {border: 1px solid #555;margin: 0;padding: 5px;}
#exit {display: block; position: absolute; top:0; right:0; padding: 10px; background: #ddf; color: #000; text-decoration: none;}
input, textarea, button {border: 1px solid #ccc; padding:5px;}
</style>
</head>
<body>
<a id="exit" href="/exit/">Выход</a>
<div id="loglist">
<h1>Отчёт</h1>
<table cellpadding="0" cellspacing="0">
<tr>
<td>Имя файла</td>
<td>Размер</td>
<td>Статус</td>
</tr>
{% for l in loglist %}
<tr>
<td>{{ l.filename }}</td>
<td>{{ l.filesize }}</td>
<td>{{ l.status }}</td>
</tr>
{% endfor %}
</table>
</div>
<div id="choose_file">
<h1>1. Выберите файл:</h1>
<p>Используйте в имени файла только латинские буквы, без пробелов и всяких там символов (+,-,%,',",^,&)!!!</p>
{% for d in dictdir %}
<li>{% if not d.status %}<a value="{{ d.filename }}" href="#">{% endif %}{{ d.filename }}</a> | <span>{{ d.filesize|filesizeformat }}</span></li>
{% endfor %}
</div>
<div style="height:10px;width:100%;clear:both;"></div>
<div id="file_properties">
<h1>2. Описание файла:</h1>
<table>
<form method="post" name="uploadform">
<tr><td>Файл:</td><td><input type="text" name="filename" readonly /> <input type="text" name="filesize" hidden></td></tr>
<tr><td>Название:</td><td><input type="text" name="title" /></td></tr>
<tr><td>Описание:</td><td><textarea name="description"></textarea></td></tr>
<!-- <tr><td>Категория:</td><td><select></select></td></tr> -->
<tr><td>Ключевые слова:</td><td><input type="text" name="keywords" /></td></tr>
<tr><td></td><td><input type="submit" value="3. Загрузить на YouTube" /></td></tr>
</table>
</form>
</div>
</body>
</html>
4. Вместо финала
Надеюсь кому-то это поможет / сэкономит время / или просто повеселит. Представленный мной вариант можно доработать (может выложить на github?), слава богу кучу всего ещё можно поправить, например какие я вижу варианты развития:
- добавить выбор в какой playlist грузить
- прогрессбар загрузки
- уведомления о загрузке
- возможность выбора в какой канал видео загружать
- возможность выбора качества (битрейт конвертации)
- и наверняка ещё что-то...
Спасибо за внимание!
P.S. код далёк от совершенства, будет «шлифоваться». Спасибо Evgeny Bespaly за советы по оптимизации, обязательно воспользуюсь.
UPD: проект на github = https://github.com/1vank1n/YTupload/, буду рад всем кто поможет довести его до ума!