Annotation zip uses unique filenames so they can be extracted into a single folder

This commit is contained in:
Ruben van de Ven 2023-02-24 14:12:06 +01:00
parent c4c22848e8
commit 4d08b0b4ad
2 changed files with 23 additions and 10 deletions

View File

@ -5,6 +5,8 @@ from ctypes.wintypes import tagMSG
import json import json
from os import X_OK, PathLike from os import X_OK, PathLike
import os import os
import random
import string
import subprocess import subprocess
from typing import Optional, Union from typing import Optional, Union
import shelve import shelve
@ -202,6 +204,14 @@ class AnimationSlice:
return self.id[0] return self.id[0]
return self.id[0] + f"{extension}?t_in={self.t_in}&t_out={self.t_out}" return self.id[0] + f"{extension}?t_in={self.t_in}&t_out={self.t_out}"
def getHash(self):
'''
A repeatable way to create a relatively unique hash for the slice
Used e.g. to export the slice.
'''
random.seed('-'.join([str(b) if b is not None else "" for b in self.id]))
return ''.join(random.choices(string.ascii_uppercase + string.digits, k=8))
def get_bounding_box(self, stroke_thickness: float = 3.5) -> Viewbox: def get_bounding_box(self, stroke_thickness: float = 3.5) -> Viewbox:
"""Stroke_thickness 3.5 == 1mm. If it should not be considered, just set it to 0. """Stroke_thickness 3.5 == 1mm. If it should not be considered, just set it to 0.

View File

@ -263,24 +263,26 @@ class ExportHandler(tornado.web.RequestHandler):
if t_in is not None and t_out is not None: if t_in is not None and t_out is not None:
animation = animation.getSlice(float(t_in), float(t_out)) animation = animation.getSlice(float(t_in), float(t_out))
identifier = animation.getHash()
with tempfile.TemporaryDirectory() as tdir: with tempfile.TemporaryDirectory() as tdir:
with ZipFile(tdir + '/annotation.zip', 'w') as archive: with ZipFile(tdir + f'/annotation-{identifier}.zip', 'w') as archive:
logger.info('write svg') logger.info('write svg')
svgstring = animation.get_as_svg() svgstring = animation.get_as_svg()
archive.writestr('drawing.svg', svgstring) archive.writestr(f'annotation-{identifier}.svg', svgstring)
logger.info('write png') logger.info('write png')
archive.writestr('drawing.png', cairosvg.svg2png(bytestring=svgstring)) archive.writestr(f'annotation-{identifier}.png', cairosvg.svg2png(bytestring=svgstring))
logger.info('write mp3') logger.info('write mp3')
audio = await animation.audio.export(format="mp3") audio = await animation.audio.export(format="mp3")
archive.writestr('drawing.mp3', audio.read()) archive.writestr(f'annotation-{identifier}.mp3', audio.read())
logger.info('write json') logger.info('write json')
data = animation.asDict() data = animation.asDict()
data['audio']['file'] = 'drawing.mp3'; data['audio']['file'] = f'annotation-{identifier}.mp3';
archive.writestr('annotation.json', json.dumps(data)) archive.writestr(f'annotation-{identifier}.json', json.dumps(data))
logger.info('write js') logger.info('write js')
@ -290,21 +292,22 @@ class ExportHandler(tornado.web.RequestHandler):
archive.writestr('wNumb-1.2.0.min.js', fp.read()) archive.writestr('wNumb-1.2.0.min.js', fp.read())
logger.info('write html') logger.info('write html')
html = """ html = f"""
<html> <html>
<head> <head>
<script src="wNumb-1.2.0.min.js"></script> <script src="wNumb-1.2.0.min.js"></script>
<script src="annotate.js"></script> <script src="annotate.js"></script>
</head> </head>
<body> <body>
<annotation-player data-poster-url="drawing.svg" data-annotation-url="annotation.json"> <annotation-player data-poster-url="annotation-{identifier}.svg" data-annotation-url="annotation-{identifier}.json">
</body> </body>
</html> </html>
""" """
archive.writestr('drawing.html', html) archive.writestr(f'annotation-{identifier}.html', html)
with open(tdir + '/annotation.zip', 'rb') as fp: with open(tdir + f'/annotation-{identifier}.zip', 'rb') as fp:
self.set_header("Content-Type", "application/zip") self.set_header("Content-Type", "application/zip")
self.set_header("Content-Disposition", f"attachment;filename=annotation-{identifier}.zip")
self.write(fp.read()) self.write(fp.read())
logger.info('done') logger.info('done')