Annotation export to self-contained zip

This commit is contained in:
Ruben van de Ven 2023-02-23 18:52:21 +01:00
parent 8be08ce9d6
commit 6fbe49473d
3 changed files with 80 additions and 0 deletions

View file

@ -2,7 +2,9 @@ import json
import logging import logging
import os import os
import shutil import shutil
import tempfile
from urllib.error import HTTPError from urllib.error import HTTPError
from zipfile import ZipFile
import tornado.ioloop import tornado.ioloop
import tornado.web import tornado.web
import tornado.websocket import tornado.websocket
@ -240,6 +242,73 @@ class AudioListingHandler(tornado.web.RequestHandler):
print(names) print(names)
self.write(json.dumps(names)) self.write(json.dumps(names))
class ExportHandler(tornado.web.RequestHandler):
"""
Export a player to a zip file
"""
def initialize(self, config, index: svganim.strokes.AnnotationIndex):
self.config = config
self.index = index
async def get(self, filename):
logger.info(f"file {filename=}")
if filename not in self.index.drawings:
raise tornado.web.HTTPError(404)
t_in = self.get_argument('t_in', None)
t_out = self.get_argument('t_out', None)
animation = self.index.drawings[filename].get_animation()
if t_in is not None and t_out is not None:
animation = animation.getSlice(float(t_in), float(t_out))
with tempfile.TemporaryDirectory() as tdir:
with ZipFile(tdir + '/annotation.zip', 'w') as archive:
logger.info('write svg')
svgstring = animation.get_as_svg()
archive.writestr('drawing.svg', svgstring)
logger.info('write png')
archive.writestr('drawing.png', cairosvg.svg2png(bytestring=svgstring))
logger.info('write mp3')
audio = await animation.audio.export(format="mp3")
archive.writestr('drawing.mp3', audio.read())
logger.info('write json')
data = animation.asDict()
data['audio']['file'] = 'drawing.mp3';
archive.writestr('annotation.json', json.dumps(data))
logger.info('write js')
with open('www/annotate.js', 'r') as fp:
archive.writestr('annotate.js', fp.read())
with open('www/assets/wNumb-1.2.0.min.js', 'r') as fp:
archive.writestr('wNumb-1.2.0.min.js', fp.read())
logger.info('write html')
html = """
<html>
<head>
<script src="wNumb-1.2.0.min.js"></script>
<script src="annotate.js"></script>
</head>
<body>
<annotation-player data-poster-url="drawing.svg" data-annotation-url="annotation.json">
</body>
</html>
"""
archive.writestr('drawing.html', html)
with open(tdir + '/annotation.zip', 'rb') as fp:
self.set_header("Content-Type", "application/zip")
self.write(fp.read())
logger.info('done')
class AnimationHandler(tornado.web.RequestHandler): class AnimationHandler(tornado.web.RequestHandler):
def initialize(self, config, index: svganim.strokes.AnnotationIndex): def initialize(self, config, index: svganim.strokes.AnnotationIndex):
@ -669,6 +738,7 @@ class Server:
}, },
), ),
(r"/files/(.*)", AnimationHandler, {"config": self.config, "index": self.index}), (r"/files/(.*)", AnimationHandler, {"config": self.config, "index": self.index}),
(r"/export/(.*)", ExportHandler, {"config": self.config, "index": self.index}),
( (
r"/audio/(.+)", r"/audio/(.+)",
tornado.web.StaticFileHandler, tornado.web.StaticFileHandler,

View file

@ -1669,6 +1669,10 @@ class AnnotationPlayer extends HTMLElement {
position: absolute; position: absolute;
background: rgba(255, 255, 255, 0.7); background: rgba(255, 255, 255, 0.7);
} }
details{
color: white;
}
summary{ summary{
list-style: none; list-style: none;

View file

@ -163,6 +163,12 @@ class AnnotationManager {
infoEl.classList.add('annotation-info'); infoEl.classList.add('annotation-info');
infoEl.innerText = `[${tag.get_name()}] ${annotation.comment}`; infoEl.innerText = `[${tag.get_name()}] ${annotation.comment}`;
const downloadEl = document.createElement('a');
downloadEl.href = annotation.url.replace('files', 'export');
downloadEl.innerHTML = '&darr;';
infoEl.appendChild(downloadEl);
liEl.appendChild(playerEl); liEl.appendChild(playerEl);
liEl.appendChild(selectEl); liEl.appendChild(selectEl);
liEl.appendChild(infoEl); liEl.appendChild(infoEl);