#!/usr/bin/env python3 # -*- coding:utf-8 -*- from flexx import flx from ipfsdocs.common import ( URL, BootstrapDropdown, ) class DownloadManager(flx.JsComponent): # cid, filename, mimetype current_download = flx.TupleProp(settable=True) download_queue = flx.ListProp(settable=True) progress = flx.FloatProp(settable=True) history = flx.DictProp(settable=True) prevented = flx.DictProp(settable=True) pause = flx.BoolProp(settable=True) def init(self): global window, JSON self.set_history( JSON.parse( window.localStorage.getItem("history") or "{}" ) ) @flx.reaction("history") def update_local_storage(self): global window, JSON window.localStorage.setItem( "history", JSON.stringify(self.history) ) @flx.reaction("current_download") def trigger_download(self): if self.current_download != (): cid, filename, mimetype = self.current_download self._download(cid, filename, mimetype) @flx.reaction("download_queue", "current_download", "pause") def maybe_update_current_download(self, *events): if ( self.current_download == () and len(self.download_queue) > 0 and not self.pause ): cid, filename, mimetype = self.pop_download() self.set_current_download((cid, filename, mimetype)) def pop_download(self): self._pop_download() return self.download_queue[0] @flx.action def _pop_download(self): self._mutate_download_queue(1, "remove", 0) @flx.action def add_download(self, cid, filename, mimetype): if ( cid in self.history or cid in [elem[0] for elem in self.download_queue] or cid == self.current_download[0] ): self._mutate_prevented({cid: True}, "insert",) else: self._mutate_download_queue( [(cid, filename, mimetype)], "insert", len(self.download_queue) ) def onload(self, request, filename, mimetype): global download download( request.response, filename, mimetype, ) @flx.action def push_to_history(self, cid): self._mutate_history({cid: True}, "insert") def _download(self, cid, filename, mimetype): self.push_to_history(cid) url = f"{URL}{cid}?filename={filename}" global XMLHttpRequest request = XMLHttpRequest() request.open( "GET", url, True ) request.responseType = 'blob' request.onprogress = lambda event: self.set_progress(event.loaded / event.total) request.onload = lambda e: self.onload(request, filename, mimetype) request.onloadend = lambda: self.loadend() request.send() def loadend(self): # a download just finished, wait a bit to let the browser the time to # write on disk global window window.setTimeout(lambda: self.set_current_download(()), 5000) class DownloadHandler(BootstrapDropdown): def init(self): self.set_text("\uf0ed") self.update_disabled() self.set_the_items() @flx.reaction("root.state.downloadmanager.pause") def set_the_items(self): self.set_items( [ ("all", "\uf0ac"), ("selection", "\uf00c"), (None,), ("toggle_pause", ("\uf04b" if self.root.state.downloadmanager.pause else "\uf04c")), (None,), ("clean_queue", "\uf12d"), ("clean_history", "\uf0c7 \uf061 \uf12d"), ] ) self.set_button_style( "SECONDARY" if self.root.state.downloadmanager.pause else "PRIMARY" ) @flx.action def update_disabled(self): self._mutate_disabled_items( { "selection": not self.root.state.selection, "clean_history": not self.root.state.downloadmanager.history, "clean_queue": not self.root.state.downloadmanager.download_queue, }, "insert" ) @flx.reaction("root.state.downloadmanager.history", "root.state.selection", "root.state.downloadmanager.download_queue") def toggle_update_disabled(self): self.update_disabled() @flx.reaction("root.state.downloadmanager.prevented", "root.state.downloadmanager.download_queue") def update_on_prevented(self): text = '\uf0ed' if self.root.state.downloadmanager.download_queue: text += f" {len(self.root.state.downloadmanager.download_queue)}" if self.root.state.downloadmanager.prevented: text += f' ({len(self.root.state.downloadmanager.prevented.items())})' self.set_text(text) def download_url(self, url, filename, fast=False): global document a = document.createElement("a") a.download = filename if fast: base = URL else: base = "" url = base + url a.href = url a.target = "_blank" a.click() @flx.reaction("clicked") def on_clicked(self, *events): for event in events: if event.id == "all": for info_ in self.root.state.query_results: self.root.state.downloadmanager.add_download( info_["cid"], info_["filename"], info_["mimetype"] ) elif event.id == "selection": for info_ in [ self.root.state.get_info(cid) for cid in self.root.state.selection ]: self.root.state.downloadmanager.add_download( info_["cid"], info_["filename"], info_["mimetype"] ) elif event.id == "clean_history": self.root.state.downloadmanager.set_history({}) self.root.state.downloadmanager.set_prevented({}) elif event.id == "toggle_pause": self.root.state.downloadmanager.set_pause(not self.root.state.downloadmanager.pause) elif event.id == "clean_queue": self.root.state.downloadmanager.set_download_queue([])