それでは始めましょう。 この記事では、動画をYouTubeチャンネルに変換/アップロードする短いdjangoプロジェクトについて説明します。
問題の歴史について一言...私はある小さな地域のテレビ会社で働いています。ある素晴らしい日は、ブルースクリーンだけでなくYouTubeでもコンテンツを視聴してほしいと思っていました 。 なぜなら Omneonのブロードキャストサーバーがあり、すべての素材がmov形式で準備されており、15分の番組の平均重量= 3.5 GBです。 このサイズのファイルをアップロードするのは退屈で愚かです。たとえば、クリップをmp4に変換し、YouTubeに軽くアップロードする方がはるかに正確です(これによりあまり品質が低下しないため)。 たとえば、3.5GBは100MBの許容品質でどこかに圧縮されます。
この記事は、「発見」や「突破」のタイトルを装うものではなく、単に既知の事実を便利な指示にまとめたものです。
1.アルゴリズム
私自身は、次の一連のアクションに導かれました。
- 私たちは、ビデオが住んでいるフォルダを見ます
- 適切なものを選択してください
- YTの情報(名前、説明、キーワード)を入力します
- ファイルをキューに入れる
- キューはクリップを順番に変換し、YTにアップロードしています
- ビデオがロードされると、ステータスが「アップロード済み」になりました
また、「アップロードした誰/いつ/何を」という何らかのロギングを追加したかった。
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
上記で、アクションのロギングについて「st音」を立てました。 ここでは、次のモデルが必要です。
django-admin.py startappコントロールアプリケーションを作成する
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})
コードは複雑ではありません(必要に応じて、詳細を説明します)。 インデックス関数は 2つのリストを返します。1つ目はフォルダー内にあり、2つ目は既にログに書き込まれているファイルです。 この関数の出力は、上のスクリーンショットに表示されています... 入力と終了が最も簡単な認証です。
どうぞ : 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を介して起動されます。 意味は簡単です。ステータスが「クエリ内」(キュー内)の最初のファイルを取得し、変換(ステータスを変換中に変更)、アップロード(ステータスをアップロード中に変更)、アップロード(ステータス=アップロード)します。
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に投稿できますか?)、神に感謝します。たとえば、私の開発オプションは何ですか?
- ロードするプレイリストに選択肢を追加します
- プログレスバーのダウンロード
- ダウンロード通知
- ビデオをアップロードするチャンネルを選択する機能
- 品質を選択する機能(ビットレート変換)
- そしておそらく他の何か...
ご清聴ありがとうございました!
PSコードは完璧とはほど遠い、「洗練された」ものになります。 最適化のヒントを提供してくれたEvgeny Bespalyに感謝します。
UPD: github のプロジェクト= https://github.com/1vank1n/YTupload/ 、それを思い起こさせる手助けをしてくれるすべての人に嬉しいです!