Twistedで作るローカルYoutubeサーバ その5
まとめ。
まとめで全ソース。
server.tac
from twisted.application.internet import TimerService from twisted.application import service, strports from nevow import static from nevow import appserver import setting import downloader import web import shell application = service.Application('youtube') page = web.ListPage() page.putChild('flvplayer.swf', static.File('./flvplayer.swf')) page.putChild('video', static.File(setting.repo)) site = appserver.NevowSite(page) strports.service("8081", site).setServiceParent(application) strports.service("2222", shell.getManholeFactory(globals(), admin='admin')).setServiceParent(application) timer = TimerService(60, downloader.downloadAll) timer.setServiceParent(application)
web.py
from nevow import rend from nevow import loaders from nevow import accessors from nevow import inevow from twisted.python import util from twisted.python.components import registerAdapter items = [] class VideoItem(object): pass class ListPage(rend.Page): docFactory=loaders.xmlfile(util.sibpath(__file__, 'list.html')) def childFactory(self, ctx, segments): return DetailPage(segments) def data_list(self, ctx, data): return items class DetailPage(rend.Page): addSlash = True docFactory=loaders.xmlfile(util.sibpath(__file__, 'detail.html')) def __init__(self, id): self.id = id def data_id(self, ctx, data): return '/flvplayer.swf?file=/video/%s.flv' % self.id registerAdapter(accessors.ObjectContainer, VideoItem, inevow.IContainer)
list.html
<html xmlns:n="http://nevow.com/ns/nevow/0.1"> <head>YouTube</head> <body> <ul n:render="sequence" n:data="list"> <li n:pattern="item"> <a><n:attr name="href">/<n:invisible n:data="id" n:render="data" />/</n:attr><n:invisible n:data="title" n:render="string" /></a> </li> </ul> </body> </html>
detail.html
<html xmlns:n="http://nevow.com/ns/nevow/0.1"> <head>Detail</head> <body> <object type="application/x-shockwave-flash" data="/flvplayer.swf?file=/video/4-uxh1iQX0E.flv" width="560" height="380" wmode="transparent"><n:attr name="data" n:data="id" n:render="string" /> <param name="movie"><n:attr name="value" n:data="id" n:render="string" /></param> <param name="wmode" value="transparent" /> </object> </body> </html>
downloder.py
from twisted.web import client from twisted.web import error from twisted.internet import reactor import os.path import re import web const_video_url_params_re = re.compile(r'player2\.swf\?([^"]+)"', re.M) const_video_url_real_str = 'http://www.youtube.com/get_video?%s' const_video_url_re = re.compile(r'^((?:http://)?(?:\w+\.)?youtube\.com/(?:v/|(?:watch(?:\.php)?)?\?(?:.+&)?v=))?([0-9A-Za-z_-]+)(?(1)[&/].*)?$') const_video_title_re = re.compile(r'<title>YouTube - ([^<]*)</title>', re.M | re.I) def _finish(data, id, title, file): print 'finish %s %s %s' % (title, id, file) v = web.VideoItem() v.title = title v.id = id v.file = file web.items.append(v) def _err(error): print error def downloadFlv(url, file): def _parseFlvUrl(data): match = const_video_url_params_re.search(data) param = match.group(1) url = const_video_url_real_str % param match_title = const_video_title_re.search(data) title = match_title.group(1) return (url, title) def _download(file, id): if os.path.isdir(file): file = os.path.join(file, '%s.flv' % id) def _downloadPage(data): url, title = data client.downloadPage(url, file).addCallback(_finish, id, title, file).addErrback(_err) return _downloadPage match = const_video_url_re.search(url) id = match.group(2) return client.getPage(url).addCallback(_parseFlvUrl).addCallback(_download(file, id)).addErrback(_err) def downloadAll(): print 'start' import setting while setting.video: url = setting.video.pop() downloadFlv(url, setting.repo)
shell.py
from twisted.cred import portal, checkers from twisted.conch import manhole, manhole_ssh def getManholeFactory(namespace, **passwords): realm = manhole_ssh.TerminalRealm() def getManhole(_): return manhole.Manhole(namespace) realm.chainedProtocolFactory.protocolFactory = getManhole p = portal.Portal(realm) p.registerChecker(checkers.InMemoryUsernamePasswordDatabaseDontUse(**passwords)) f = manhole_ssh.ConchFactory(p) return f