Доброго времени суток!
Итак начнём. В статье я опишу краткий проект на 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/, буду рад всем кто поможет довести его до ума!
