media_upload.js (5113B)
- /* 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, otherwise JPEG
- const type = supportsWebP ? 'image/webp' : 'image/jpeg'
- const extension = supportsWebP ? '.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