UNPKG

kara-module-downloader

Version:

kara module download

225 lines (201 loc) 6.32 kB
/* eslint-disable */ import SparkMD5 from 'spark-md5' import EXIF from 'exif-js' import EE from 'event-emitter' import FileSaver from 'file-saver' if(!window.$emit){ window.$emitter = EE() } export default class FileAgent { CHUNK_SIZE = 1024*1024 UPDATE_INTERVAL = 1000 DB = {} token = '' apiRoot = '' constructor(){ window.$file = window.$file || this } _toast( msg = "", level = 'error', ){ window.$emitter.emit('TOAST', {msg, level}) } _naming(file, fileUploadId){ let hashName = '' if (fileUploadId) { hashName = fileUploadId.replace(/(-)/g, '').substring(0, 8); } if (file.name) { return encodeURIComponent(file.name); } else if (['jpeg', 'gif', 'png', 'jpg', 'bmp'].includes(file.type.split('/')[1])) { if (hashName) { return `${hashName}.png`; } return `${Date.now()}.png`; } if (hashName) { return `${hashName}`; } return `${Date.now()}`; } _hash(arrayBuffer){ let spark = new SparkMD5() let chars = new Uint8Array(arrayBuffer) const CHUNK_SIZE = 0x8000 let index = 0 let length = chars.length let result = '' let slice = null while (index < length) { slice = chars.subarray(index, Math.min(index + CHUNK_SIZE, length)) result += String.fromCodePoint.apply(null, slice) index += CHUNK_SIZE } spark.appendBinary(result) return spark.end() } _base64ArrayBuffer(arrayBuffer){ let base64 = ''; const encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; const bytes = new Uint8Array(arrayBuffer); const byteLength = bytes.byteLength; const byteRemainder = byteLength % 3; const mainLength = byteLength - byteRemainder; let a; let b; let c; let d; let chunk; // Main loop deals with bytes in chunks of 3 for (let i = 0; i < mainLength; i += 3) { // Combine the three bytes into a single integer chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]; // Use bitmasks to extract 6-bit segments from the triplet a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18 b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12 c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6 d = chunk & 63; // 63 = 2^6 - 1 // Convert the raw binary segments to the appropriate ASCII encoding base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]; } // Deal with the remaining bytes and padding if (byteRemainder === 1) { chunk = bytes[mainLength]; a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2 // Set the 4 least significant bits to zero b = (chunk & 3) << 4; // 3 = 2^2 - 1 base64 += `${encodings[a]}${encodings[b]}==`; } else if (byteRemainder === 2) { chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]; a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10 b = (chunk & 1008) >> 4; // 1008 = (2^6 - 1) << 4 // Set the 2 least significant bits to zero c = (chunk & 15) << 2; // 15 = 2^4 - 1 base64 += `${encodings[a]}${encodings[b]}${encodings[c]}=`; } return base64; } _dealWithImage( arrayBuffer, type, fileUploadId ){ if(!['jpeg', 'gif', 'png', 'jpg', 'bmp'].includes(type.split('/')[1])) return let data = this._base64ArrayBuffer(arrayBuffer) let img = new Image() img.onload = ()=>{ let imageStyle = { width: img.width>320 ? 320 : img.width, height: img.width>320 ? img.height*320/img.width : img.height } EXIF.getData(img, function(){ if(EXIF.getTag(this, 'Orientation') === 3){ imageStyle.transform = `rotate(180deg) translate(${imageStyle.width}, ${imageStyle.height})` }else if(EXIF.getTag(this, 'Orientation') === 6){ imageStyle.transform = `rotate(90deg) translate(${imageStyle.width}, ${imageStyle.height})` }else if(EXIF.getTag(this, 'Orientation') === 8){ imageStyle.transform = `rotate(-90deg) translate(${imageStyle.width}, ${imageStyle.height})` } }) this._update( { thumbnailUrl: `data:${type};base64,${data}`, imageStyle, progress: 'uploading', }, fileUploadId ) } img.src = `data:${type};base64,${data}` } download( fileId, channelId, ){ let prev = 0 let xhr = new XMLHttpRequest() xhr.open('GET', `${this.apiRoot}/v1.0.0/file/download/${fileId}/${channelId}`) xhr.setRequestHeader("Content-type", "application/json") xhr.setRequestHeader('Authorization', `bearer ${this.token}`) xhr.responseType = 'blob' xhr.addEventListener('loadstart', e=>{ window.$emitter.emit('DOWNLOAD_FILE',{ fileId, percent: 0, progress: 'start', }) }) xhr.addEventListener('progress', e=>{ let cur = Date.now() let isUpdate = true if(e.total > 10*1024*1024){ isUpdate = cur-prev > this.UPDATE_INTERVAL }else{ isUpdate = cur-prev > this.UPDATE_INTERVAL/2 } if(e.loaded!==e.total && !isUpdate){ return }else{ prev = cur } window.$emitter.emit('DOWNLOAD_FILE',{ fileId, percent: e.loaded/e.total, progress: 'downloading', cancel: ()=>{xhr.abort()} }) }) xhr.addEventListener('abort', e=>{ window.$emitter.emit('DOWNLOAD_FILE', { fileId, progress: 'cancel' }) }) xhr.addEventListener('error', e=>{ this._toast('文件下载失败') window.$emitter.emit('DOWNLOAD_FILE', { fileId, progress: 'failure' }) }) xhr.addEventListener('loadend', e=>{ prev = null if(xhr.status === 200){ window.$emitter.emit('DOWNLOAD_FILE',{ fileId, percent: e.loaded/e.total, progress: 'end', }) FileSaver.saveAs(xhr.response, decodeURIComponent(xhr.getResponseHeader('filename'))) }else if(xhr.status === 401){ this._toast('认证失败') window.$emitter.emit('DOWNLOAD_FILE', { fileId, progress: 'failure' }) } }) xhr.send() } }