/* eslint-env browser */ import statusPosterService from '../../services/status_poster/status_poster.service.js' import fileSizeFormatService from '../../services/file_size_format/file_size_format.js' import { library } from '@fortawesome/fontawesome-svg-core' import { faUpload, faCircleNotch } from '@fortawesome/free-solid-svg-icons' library.add( faUpload, faCircleNotch ) const mediaUpload = { data () { return { uploadCount: 0, uploadReady: true } }, computed: { uploading () { return this.uploadCount > 0 } }, methods: { onClick () { if (this.uploadReady) { this.$refs.input.click() } }, async resizeImage (file) { // Skip if not an image or if it's a GIF if (!file.type.startsWith('image/') || file.type === 'image/gif') { return file } // Skip if image compression is disabled if (!this.$store.getters.mergedConfig.imageCompression) { return file } // For PNGs, check if animated if (file.type === 'image/png') { const isAnimated = await this.isAnimatedPng(file) if (isAnimated) { return file } } return new Promise((resolve) => { const img = new Image() img.onload = () => { // Calculate new dimensions let width = img.width let height = img.height const maxSize = 2048 if (width > maxSize || height > maxSize) { if (width > height) { height = Math.round((height * maxSize) / width) width = maxSize } else { width = Math.round((width * maxSize) / height) height = maxSize } } // Create canvas and resize const canvas = document.createElement('canvas') canvas.width = width canvas.height = height const ctx = canvas.getContext('2d') ctx.drawImage(img, 0, 0, width, height) // Check WebP support by trying to create a WebP canvas const testCanvas = document.createElement('canvas') const supportsWebP = testCanvas.toDataURL('image/webp').startsWith('data:image/webp') // Convert to WebP if supported and alwaysUseJpeg is false, otherwise JPEG const type = (!this.$store.getters.mergedConfig.alwaysUseJpeg && supportsWebP) ? 'image/webp' : 'image/jpeg' const extension = type === 'image/webp' ? '.webp' : '.jpg' // Remove the original extension and add new one const newFileName = file.name.replace(/\.[^/.]+$/, '') + extension canvas.toBlob((blob) => { resolve(new File([blob], newFileName, { type, lastModified: Date.now() })) }, type, 0.85) } img.src = URL.createObjectURL(file) }) }, async isAnimatedPng (file) { const buffer = await file.arrayBuffer() const view = new Uint8Array(buffer) // Look for animated PNG chunks (acTL) for (let i = 0; i < view.length - 8; i++) { if (view[i] === 0x61 && // a view[i + 1] === 0x63 && // c view[i + 2] === 0x54 && // T view[i + 3] === 0x4C) { // L return true } } return false }, async uploadFile (file) { const self = this const store = this.$store if (file.size > store.state.instance.uploadlimit) { const filesize = fileSizeFormatService.fileSizeFormat(file.size) const allowedsize = fileSizeFormatService.fileSizeFormat(store.state.instance.uploadlimit) self.$emit('upload-failed', 'file_too_big', { filesize: filesize.num, filesizeunit: filesize.unit, allowedsize: allowedsize.num, allowedsizeunit: allowedsize.unit }) return } // Resize image if needed const processedFile = await this.resizeImage(file) const formData = new FormData() formData.append('file', processedFile) self.$emit('uploading') self.uploadCount++ statusPosterService.uploadMedia({ store, formData }) .then((fileData) => { self.$emit('uploaded', fileData) self.decreaseUploadCount() }, (error) => { console.error('Error uploading file', error) self.$emit('upload-failed', 'default') self.decreaseUploadCount() }) }, decreaseUploadCount () { this.uploadCount-- if (this.uploadCount === 0) { this.$emit('all-uploaded') } }, clearFile () { this.uploadReady = false this.$nextTick(() => { this.uploadReady = true }) }, multiUpload (files) { for (const file of files) { this.uploadFile(file) } }, change ({ target }) { this.multiUpload(target.files) } }, props: { dropFiles: Object, disabled: Boolean, normalButton: Boolean, acceptTypes: { type: String, default: '*/*' } }, watch: { dropFiles: function (fileInfos) { if (!this.uploading) { this.multiUpload(fileInfos) } } } } export default mediaUpload