kara-module-downloader
Version:
kara module download
225 lines (201 loc) • 6.32 kB
JavaScript
/* 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()
}
}