Flash置場が欲しかったので、Google App Engineのデータベース(datastore)を使ったFlashコンテンツのアップローダを作ってみた。BlobProperty()を使うことでデータベースには一応入ったが、サイズが大きいFlashでは例の時間制限に引っ掛かってアップロード途中でエラーを吐いてしまった。この制限、どうにかならないかなぁ。
取り敢えず、ソースを以下に示しておく。
flash_uploader.py
#!/usr/bin/env python # -*- coding: utf-8 -*- import cgi, re, urllib, datetime import wsgiref.handlers from google.appengine.api import users from google.appengine.ext import webapp from google.appengine.ext import db # Flash SWFデータ class FlashData(db.Model): author = db.UserProperty() username = db.StringProperty(multiline=False) date = db.DateTimeProperty(auto_now_add=True) title = db.StringProperty(multiline=False) summary = db.TextProperty() width = db.IntegerProperty() height = db.IntegerProperty() content = db.BlobProperty() class Flash(webapp.RequestHandler): def get(self): user = users.get_current_user() self.response.out.write("""<title>Flashコンテンツ - アップローダ</title> <h1>Flashコンテンツ - アップローダ</h1> """) if not user: url = users.create_login_url(self.request.uri) url_linktext = "Login" self.response.out.write("""<p>アップロードを行う場合は、<a href="https://www.google.com/accounts/">Googleアカウント</a>でログインしてください。[<a href="%s">%s</a>]</p> """ % (url, url_linktext)) else: H = (datetime.datetime.utcnow() + datetime.timedelta(hours=9)).hour if H >= 3 and H < 9: greeting = u"おはようございます" elif H >= 9 and H < 18: greeting = u"こんにちは" elif H >= 18 or H < 3: greeting = u"こんばんは" else: greeting = u"こんにちは" url = users.create_logout_url(self.request.uri) url_linktext = "Logout" self.response.out.write("""<p>%s。[<a href="%s">%s</a>]</p> """ % (greeting.encode("utf-8"), url, url_linktext)) self.response.out.write("""<form action="/flash/upload" enctype="multipart/form-data" method="post"> <div><label>タイトル:</label> <input type="text" name="title" size="31" maxlength="255"></input> <label>名前:</label> <input type="text" name="username" size="12" maxlength="50"></input></div> <div><label>概要:</label></div> <div><textarea name="summary" rows="5" cols="60"></textarea></div> <div><label>ファイル:</label> <input type="file" name="flash" /> <label>幅:</label> <input type=text" name="width" size="4" value="300"></input> <label>高さ:</label> <input type=text" name="height" size="4" value="300"></input></div> <div><input type="submit" value="アップロード"></div> </form> """) items = FlashData.all().order("-date").fetch(limit=20) for item in items: self.response.out.write("<div style=\"line-height:140%;\"><ul>") if len(item.title.strip()) == 0: item.title = u"(無題)" self.response.out.write("<dt><strong><a href=\"/flash/play?title=%s&w=%d&h=%d&id=%s\">%s</a></strong> <span style=\"color:gray;font-size:x-small;\">by %s, %s年%s月%s日%s時%s分%s秒</span></dt>" % (urllib.quote_plus(item.title.encode("utf-8")), item.width, item.height, item.key(), cgi.escape(item.title.encode("utf-8")), cgi.escape(item.username.encode("utf-8")), item.date.year, item.date.month, item.date.day, item.date.hour, item.date.minute, item.date.second)) if len(item.summary.strip()) == 0: item.summary = " " self.response.out.write("<dd>%s</dd>" % item.summary.encode("utf-8")) self.response.out.write("</ul></div>") class FlashPlay(webapp.RequestHandler): def get(self): title = urllib.unquote_plus(self.request.get("title")) w = self.request.get("w") h = self.request.get("h") id = self.request.get("id") self.response.out.write("<title>%s</title>" % title) self.response.out.write("<h1>%s</h1>" % title) self.response.out.write("""<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width=%s height=%s> <param name="movie" value="/flash/data/%s" /> <param name="quality" value="high" /> <!-- <param name="bgcolor" value="#ffffff" /> --> <embed src="/flash/data/%s" width=%s height=%s quality="high" bgcolor="#ffffff" align="middle" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" /> </object> """ % (w, h, id, w, h, id)) self.response.out.write("<div><a href=\"/flash\">%s</a></div>" % u"戻る") class FlashUpload(webapp.RequestHandler): def post(self): data = FlashData() data.author = users.get_current_user() data.username = self.request.get("username").strip() if not data.username: data.username = data.author.nickname() data.title = self.request.get("title") data.summary = cgi.escape(self.request.get("summary").strip()) width = self.request.get("width") height = self.request.get("height") data.width = int(width) if width.isdigit() else 300 data.height = int(height) if height.isdigit() else 300 flash = self.request.get("flash") data.content = db.Blob(flash) data.date = data.date + datetime.timedelta(hours=9) data.put() self.redirect("/flash") class FlashSWF(webapp.RequestHandler): def get(self, flash_id): content = FlashData.get(flash_id).content self.response.headers["Content-Type"] = "application/x-shockwave-flash" self.response.out.write(content) def main(): application = webapp.WSGIApplication([("/flash", Flash), ("/flash/play", FlashPlay), ("/flash/upload", FlashUpload), ("/flash/data/([^/]+)", FlashSWF)], debug=False) wsgiref.handlers.CGIHandler().run(application) if __name__ == "__main__": main()
追記(2008/7/4): 説明文の表示がずれるバグを修正。
取り敢えず、ソースを以下に示しておく。
flash_uploader.py
#!/usr/bin/env python # -*- coding: utf-8 -*- import cgi, re, urllib, datetime import wsgiref.handlers from google.appengine.api import users from google.appengine.ext import webapp from google.appengine.ext import db # Flash SWFデータ class FlashData(db.Model): author = db.UserProperty() username = db.StringProperty(multiline=False) date = db.DateTimeProperty(auto_now_add=True) title = db.StringProperty(multiline=False) summary = db.TextProperty() width = db.IntegerProperty() height = db.IntegerProperty() content = db.BlobProperty() class Flash(webapp.RequestHandler): def get(self): user = users.get_current_user() self.response.out.write("""<title>Flashコンテンツ - アップローダ</title> <h1>Flashコンテンツ - アップローダ</h1> """) if not user: url = users.create_login_url(self.request.uri) url_linktext = "Login" self.response.out.write("""<p>アップロードを行う場合は、<a href="https://www.google.com/accounts/">Googleアカウント</a>でログインしてください。[<a href="%s">%s</a>]</p> """ % (url, url_linktext)) else: H = (datetime.datetime.utcnow() + datetime.timedelta(hours=9)).hour if H >= 3 and H < 9: greeting = u"おはようございます" elif H >= 9 and H < 18: greeting = u"こんにちは" elif H >= 18 or H < 3: greeting = u"こんばんは" else: greeting = u"こんにちは" url = users.create_logout_url(self.request.uri) url_linktext = "Logout" self.response.out.write("""<p>%s。[<a href="%s">%s</a>]</p> """ % (greeting.encode("utf-8"), url, url_linktext)) self.response.out.write("""<form action="/flash/upload" enctype="multipart/form-data" method="post"> <div><label>タイトル:</label> <input type="text" name="title" size="31" maxlength="255"></input> <label>名前:</label> <input type="text" name="username" size="12" maxlength="50"></input></div> <div><label>概要:</label></div> <div><textarea name="summary" rows="5" cols="60"></textarea></div> <div><label>ファイル:</label> <input type="file" name="flash" /> <label>幅:</label> <input type=text" name="width" size="4" value="300"></input> <label>高さ:</label> <input type=text" name="height" size="4" value="300"></input></div> <div><input type="submit" value="アップロード"></div> </form> """) items = FlashData.all().order("-date").fetch(limit=20) for item in items: self.response.out.write("<div style=\"line-height:140%;\"><ul>") if len(item.title.strip()) == 0: item.title = u"(無題)" self.response.out.write("<dt><strong><a href=\"/flash/play?title=%s&w=%d&h=%d&id=%s\">%s</a></strong> <span style=\"color:gray;font-size:x-small;\">by %s, %s年%s月%s日%s時%s分%s秒</span></dt>" % (urllib.quote_plus(item.title.encode("utf-8")), item.width, item.height, item.key(), cgi.escape(item.title.encode("utf-8")), cgi.escape(item.username.encode("utf-8")), item.date.year, item.date.month, item.date.day, item.date.hour, item.date.minute, item.date.second)) if len(item.summary.strip()) == 0: item.summary = " " self.response.out.write("<dd>%s</dd>" % item.summary.encode("utf-8")) self.response.out.write("</ul></div>") class FlashPlay(webapp.RequestHandler): def get(self): title = urllib.unquote_plus(self.request.get("title")) w = self.request.get("w") h = self.request.get("h") id = self.request.get("id") self.response.out.write("<title>%s</title>" % title) self.response.out.write("<h1>%s</h1>" % title) self.response.out.write("""<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width=%s height=%s> <param name="movie" value="/flash/data/%s" /> <param name="quality" value="high" /> <!-- <param name="bgcolor" value="#ffffff" /> --> <embed src="/flash/data/%s" width=%s height=%s quality="high" bgcolor="#ffffff" align="middle" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" /> </object> """ % (w, h, id, w, h, id)) self.response.out.write("<div><a href=\"/flash\">%s</a></div>" % u"戻る") class FlashUpload(webapp.RequestHandler): def post(self): data = FlashData() data.author = users.get_current_user() data.username = self.request.get("username").strip() if not data.username: data.username = data.author.nickname() data.title = self.request.get("title") data.summary = cgi.escape(self.request.get("summary").strip()) width = self.request.get("width") height = self.request.get("height") data.width = int(width) if width.isdigit() else 300 data.height = int(height) if height.isdigit() else 300 flash = self.request.get("flash") data.content = db.Blob(flash) data.date = data.date + datetime.timedelta(hours=9) data.put() self.redirect("/flash") class FlashSWF(webapp.RequestHandler): def get(self, flash_id): content = FlashData.get(flash_id).content self.response.headers["Content-Type"] = "application/x-shockwave-flash" self.response.out.write(content) def main(): application = webapp.WSGIApplication([("/flash", Flash), ("/flash/play", FlashPlay), ("/flash/upload", FlashUpload), ("/flash/data/([^/]+)", FlashSWF)], debug=False) wsgiref.handlers.CGIHandler().run(application) if __name__ == "__main__": main()
追記(2008/7/4): 説明文の表示がずれるバグを修正。
コメント