feat: port Hatena server to Python 3
* Update server-side database and dynamic resource code for Python 3 * Preserve existing Flipnote, UGO, NTFT, CSS, localization, and Hatena assets * Port Flipnote upload and movie endpoints * Update front page UGO menu generators * Preserve existing database and sample Flipnote data * Add regression tests for database operations and binary formats * Add server resource loading tests * Maintain compatibility with the original DSi Flipnote Studio protocol
This commit is contained in:
1 parent
687a2bcb43
commit
e4bb0b00ba
48 files changed
+3463
No files matched your search
@@ -0,0 +1,73 @@
|
||||
from twisted.web import resource
|
||||
from twisted.internet import reactor
|
||||
import time
|
||||
|
||||
from hatena import Log, NotFound, request_args, request_path
|
||||
from DB import Database
|
||||
from Hatenatools import UGO
|
||||
|
||||
|
||||
class PyResource(resource.Resource):
|
||||
isLeaf = True
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.pages = []
|
||||
self.newestflip = None
|
||||
self.newestview = None
|
||||
self.Update()
|
||||
|
||||
def render(self, request):
|
||||
try:
|
||||
page = int(request_args(request).get("page", ["1"])[0])
|
||||
except ValueError:
|
||||
page = 1
|
||||
if 1 <= page <= len(self.pages):
|
||||
path = "/".join(request_path(request).split("/")[3:])
|
||||
Log(request, "%s page %i" % (path, page))
|
||||
request.setHeader(b"content-type", b"text/plain")
|
||||
return self.pages[page - 1]
|
||||
return NotFound.render(request)
|
||||
|
||||
def Update(self):
|
||||
reactor.callLater(600, self.Update)
|
||||
current = Database.Newest[0] if Database.Newest else None
|
||||
if current != self.newestflip or self.newestview != Database.Views:
|
||||
self.newestflip = current
|
||||
self.newestview = Database.Views
|
||||
reactor.callInThread(self.UpdateThreaded, list(Database.Newest))
|
||||
|
||||
def UpdateThreaded(self, flipnotes):
|
||||
def score(item):
|
||||
i, (creator_id, flip) = item
|
||||
views, stars = Database.GetFlipnote(creator_id, flip)[1:3]
|
||||
return int(views) * 60 + int(stars) // 4 - i
|
||||
flipnotes = [x[1] for x in sorted(enumerate(flipnotes), key=score, reverse=True)[:500]]
|
||||
pages = []
|
||||
pagecount = (len(flipnotes) + 49) // 50
|
||||
pagecount = min(pagecount, 10)
|
||||
flipcount = min(len(flipnotes), 500)
|
||||
for i in range(pagecount):
|
||||
pages.append(self.MakePage(flipnotes[i * 50 : i * 50 + 50], i + 1, i < pagecount - 1, flipcount))
|
||||
if self.pages:
|
||||
print(time.strftime("[%H:%M:%S] Updated hotmovies.ugo"))
|
||||
self.pages = pages
|
||||
|
||||
def MakePage(self, flipnotes, page, has_next, count):
|
||||
ugo = UGO()
|
||||
ugo.Loaded = True
|
||||
ugo.Items = []
|
||||
ugo.Items.append(("layout", (2, 1)))
|
||||
ugo.Items.append(("topscreen text", ["Popular Flipnotes", "Flipnotes", str(count), "", "The most popular new Flipnotes."], 0))
|
||||
ugo.Items.append(("category", "http://flipnote.hatena.com/ds/v2-xx/frontpage/hotmovies.uls", "Most Popular", True))
|
||||
ugo.Items.append(("category", "http://flipnote.hatena.com/ds/v2-xx/frontpage/likedmovies.uls", "Most Liked", False))
|
||||
ugo.Items.append(("category", "http://flipnote.hatena.com/ds/v2-xx/frontpage/newmovies.uls", "New Flipnotes", False))
|
||||
ugo.Items.append(("unknown", ("3", "http://flipnote.hatena.com/ds/v2-xx/help/post_howto.htm", "UABvAHMAdAAgAEYAbABpAHAAbgBvAHQAZQA=")))
|
||||
if page > 1:
|
||||
ugo.Items.append(("button", 115, "Previous", "http://flipnote.hatena.com/ds/v2-xx/frontpage/hotmovies.uls?page=%i" % (page - 1), ("", ""), None))
|
||||
for creatorid, filename in flipnotes:
|
||||
stars = str(Database.GetFlipnote(creatorid, filename)[2])
|
||||
ugo.Items.append(("button", 3, "", "http://flipnote.hatena.com/ds/v2-xx/movie/%s/%s.ppm" % (creatorid, filename), (stars, "765", "573", "0"), (filename + ".ppm", Database.GetFlipnoteTMB(creatorid, filename))))
|
||||
if has_next:
|
||||
ugo.Items.append(("button", 115, "Next", "http://flipnote.hatena.com/ds/v2-xx/frontpage/hotmovies.uls?page=%i" % (page + 1), ("", ""), None))
|
||||
return ugo.Pack()
|
||||
Reference in new issue
Block a user
