comparison libervia/web/pages/photos/album/_browser/__init__.py @ 1532:106945841fbc

_browser (album): moved code to upload file to a separate `file_uploader` module: this way, uploading logic can be re-used elsewhere.
author Goffi <goffi@goffi.org>
date Thu, 22 Jun 2023 16:36:01 +0200
parents d7c78722e4f8
children
comparison
equal deleted inserted replaced
1531:d7c78722e4f8 1532:106945841fbc
1 from browser import document, window, bind, html, DOMNode, aio 1 import alt_media_player
2 from bridge import AsyncBridge, Bridge
3 from browser import DOMNode, aio, bind, document, html, window
4 import dialog
5 from file_uploader import FileUploader
6 from invitation import InvitationManager
2 from javascript import JSON 7 from javascript import JSON
3 from bridge import Bridge, AsyncBridge 8 import loading
9 from slideshow import SlideShow
4 from template import Template 10 from template import Template
5 import dialog
6 from slideshow import SlideShow
7 from invitation import InvitationManager
8 import alt_media_player
9 # we use tmp_aio because `blob` is not handled in Brython's aio
10 import tmp_aio 11 import tmp_aio
11 import loading
12 12
13 13
14 cache_path = window.cache_path 14 cache_path = window.cache_path
15 files_service = window.files_service 15 files_service = window.files_service
16 files_path = window.files_path 16 files_path = window.files_path
26 photo_tpl = Template('photo/item.html') 26 photo_tpl = Template('photo/item.html')
27 player_tpl = Template('components/media_player.html') 27 player_tpl = Template('components/media_player.html')
28 28
29 # file upload 29 # file upload
30 30
31 def on_progress(ev, photo_elt): 31 file_uploader = FileUploader(files_service, "photo/item.html", files_path)
32 if ev.lengthComputable:
33 percent = int(ev.loaded/ev.total*100)
34 update_progress(photo_elt, percent)
35
36
37 def on_load(file_, photo_elt):
38 update_progress(photo_elt, 100)
39 photo_elt.classList.add("progress_finished")
40 photo_elt.classList.remove("progress_started")
41 photo_elt.select_one('.action_delete').bind("click", on_delete)
42 print(f"file {file_.name} uploaded correctly")
43
44
45 def on_error(failure, file_, photo_elt):
46 dialog.notification.show(
47 f"can't upload {file_.name}: {failure}",
48 level="error"
49 )
50
51
52 def update_progress(photo_elt, new_value):
53 progress_elt = photo_elt.select_one("progress")
54 progress_elt.value = new_value
55 progress_elt.text = f"{new_value}%"
56
57
58 def on_slot_cb(file_, upload_slot, photo_elt):
59 put_url, get_url, headers = upload_slot
60 xhr = window.XMLHttpRequest.new()
61 xhr.open("PUT", put_url, True)
62 xhr.upload.bind('progress', lambda ev: on_progress(ev, photo_elt))
63 xhr.upload.bind('load', lambda ev: on_load(file_, photo_elt))
64 xhr.upload.bind('error', lambda ev: on_error(xhr.response, file_, photo_elt))
65 xhr.setRequestHeader('Xmpp-File-Path', window.encodeURIComponent(files_path))
66 xhr.setRequestHeader('Xmpp-File-No-Http', "true")
67 xhr.send(file_)
68
69
70 def on_slot_eb(file_, failure, photo_elt):
71 dialog.notification.show(
72 f"Can't get upload slot: {failure['message']}",
73 level="error"
74 )
75 photo_elt.remove()
76
77
78 def upload_files(files):
79 print(f"uploading {len(files)} files")
80 album_items = document['album_items']
81 for file_ in files:
82 url = window.URL.createObjectURL(file_)
83 photo_elt = photo_tpl.get_elt({
84 "file": {
85 "name": file_.name,
86 # we don't want to open the file on click, it's not yet the
87 # uploaded URL
88 "url": url,
89 # we have no thumb yet, so we use the whole image
90 # TODO: reduce image for preview
91 "thumb_url": url,
92 },
93 "uploading": True,
94 })
95 photo_elt.classList.add("progress_started")
96 album_items <= photo_elt
97
98 bridge.file_http_upload_get_slot(
99 file_.name,
100 file_.size,
101 file_.type or '',
102 files_service,
103 callback=lambda upload_slot, file_=file_, photo_elt=photo_elt:
104 on_slot_cb(file_, upload_slot, photo_elt),
105 errback=lambda failure, file_=file_, photo_elt=photo_elt:
106 on_slot_eb(file_, failure, photo_elt),
107 )
108 32
109 33
110 @bind("#file_drop", "drop") 34 @bind("#file_drop", "drop")
111 def on_file_select(evt): 35 def on_file_select(evt):
112 evt.stopPropagation() 36 evt.stopPropagation()
113 evt.preventDefault() 37 evt.preventDefault()
114 files = evt.dataTransfer.files 38 files = evt.dataTransfer.files
115 upload_files(files) 39 file_uploader.upload_files(files, document["album_items"])
116 40
117 41
118 @bind("#file_drop", "dragover") 42 @bind("#file_drop", "dragover")
119 def on_drag_over(evt): 43 def on_drag_over(evt):
120 evt.stopPropagation() 44 evt.stopPropagation()
123 47
124 48
125 @bind("#file_input", "change") 49 @bind("#file_input", "change")
126 def on_file_input_change(evt): 50 def on_file_input_change(evt):
127 files = evt.currentTarget.files 51 files = evt.currentTarget.files
128 upload_files(files) 52 file_uploader.upload_files(files, document["album_items"])
129 53
130 # delete 54 # delete
131 55
132 def file_delete_cb(item_elt, item): 56 def file_delete_cb(item_elt, item):
133 item_elt.classList.add("state_deleted") 57 item_elt.classList.add("state_deleted")
170 ok_color="danger", 94 ok_color="danger",
171 ).show( 95 ).show(
172 ok_cb=lambda evt, notif_elt: delete_ok(evt, notif_elt, item_elt, item), 96 ok_cb=lambda evt, notif_elt: delete_ok(evt, notif_elt, item_elt, item),
173 cancel_cb=lambda evt, notif_elt: delete_cancel(evt, notif_elt, item_elt, item), 97 cancel_cb=lambda evt, notif_elt: delete_cancel(evt, notif_elt, item_elt, item),
174 ) 98 )
99
100 file_uploader.on_delete_cb = on_delete
175 101
176 # cover 102 # cover
177 103
178 async def cover_ok(evt, notif_elt, item_elt, item): 104 async def cover_ok(evt, notif_elt, item_elt, item):
179 # we first need to get a blob of the image 105 # we first need to get a blob of the image