From a8e85cf28dd0293c9dd5456fbdd733e648da8f13 Mon Sep 17 00:00:00 2001 From: trendschau Date: Sun, 27 Oct 2024 21:41:50 +0100 Subject: [PATCH] V2.11.0 native audio uploads --- system/typemill/Extensions/MediaExtension.php | 63 ++++ .../typemill/author/js/vue-blox-components.js | 293 ++++++++++++++++++ system/typemill/author/js/vue-blox-config.js | 8 + system/typemill/author/partials/symbols.twig | 4 + system/typemill/settings/defaults.yaml | 1 + system/typemill/settings/system.yaml | 1 + 6 files changed, 370 insertions(+) diff --git a/system/typemill/Extensions/MediaExtension.php b/system/typemill/Extensions/MediaExtension.php index 1f1f6f1..2e4a877 100644 --- a/system/typemill/Extensions/MediaExtension.php +++ b/system/typemill/Extensions/MediaExtension.php @@ -110,5 +110,68 @@ class MediaExtension implements EventSubscriberInterface $shortcode->setData($html); } + + if(is_array($shortcodeArray) && $shortcodeArray['name'] == 'audio' && isset($shortcodeArray['params']['path'])) + { + $relUrl = $shortcodeArray['params']['path']; + $relUrl = '/' . trim($relUrl, '/'); + + # Convert the relative URL to an absolute file path + $filePath = $this->rootpath . $relUrl; + + # check file exists + if(!file_exists($filePath)) + { + $html = '

File not found

'; + } + else + { + # Get file extension using pathinfo() + $fileInfo = pathinfo($filePath); + $extension = strtolower($fileInfo['extension']); // Get file extension and convert to lowercase + $absUrl = $this->baseurl . $relUrl; + + # Determine the correct file type for the video tag + $type = ''; + switch ($extension) { + case 'mp3': + $type = 'mp3'; + break; + case 'ogg': + $type = 'ogg'; + break; + default: + $html = '

Unsupported file type

'; + return; // Exit if file type is not supported + } + + $preload = 'none'; + if(isset($shortcodeArray['params']['preload']) && ($shortcodeArray['params']['preload'] == 'auto' or $shortcodeArray['params']['preload'] == 'metadata')) + { + $preload = $shortcodeArray['params']['preload']; + } + + $width = $shortcodeArray['params']['width'] ?? '500'; + if (!preg_match('/^(\d+)(px|%)?$/', $width)) + { + $width = '500'; + } + + $html = ''; + } + + $shortcode->setData($html); + } } + } \ No newline at end of file diff --git a/system/typemill/author/js/vue-blox-components.js b/system/typemill/author/js/vue-blox-components.js index 68c70f0..86df4df 100644 --- a/system/typemill/author/js/vue-blox-components.js +++ b/system/typemill/author/js/vue-blox-components.js @@ -2640,6 +2640,299 @@ bloxeditor.component('video-component', { } }) +bloxeditor.component('audio-component', { + props: ['markdown', 'disabled', 'index'], + components: { + medialib: medialib + }, + template: `
+ +
+
+ +

+ + + + {{ $filters.translate('upload audio') }} +

+
+ +
+ + +
+ + +
+
+ +
+ + + +
+
+
+ +
+ + +
+
+ + +
+
+ + +
+
+
`, + data: function(){ + return { + maxsize: 100, // megabyte + showmedialib: false, + load: false, + filemeta: false, + fileextension: '', + allowedExtensions: ['mp3', 'ogg'], + fileurl: '', + width: '500px', + fileid: '', + savefile: false, + preload: 'none', + } + }, + mounted: function() { + eventBus.$on('beforeSave', this.beforeSave); + + this.$refs.markdown.focus(); + + if (this.markdown) + { + this.filemeta = true; + + var fileurl = this.markdown.match(/path="(.*?)"/); + if (fileurl && fileurl[1]) + { + this.fileurl = fileurl[1]; + } + + var width = this.markdown.match(/width="(.*?)"/); + if (width && width[1]) + { + this.width = width[1]; + } + + var preload = this.markdown.match(/preload="(.*?)"/); + if (preload && preload[1]) + { + this.preload = preload[1]; + } + } + }, + methods: { + addFromMedialibFunction(file) + { + this.showmedialib = false; + this.savefile = false; + this.filemeta = true; + + if (this.allowedExtensions.includes(file.info.extension.toLowerCase())) + { + this.filetitle = file.name; + this.fileextension = file.info.extension.toLowerCase(); + this.fileurl = file.url; + } + else + { + let message = "Unsupported file type. Please select a valid audio file (mp3, ogg)."; + eventBus.$emit('publishermessage', message); + return; + } + + this.createmarkdown(); + }, + openmedialib() + { + this.showmedialib = true; + }, + isChecked(classname) + { + if(this.fileclass == classname) + { + return ' checked'; + } + }, + updatemarkdown(event, url) + { + this.$emit('updateMarkdownEvent', event.target.value); + }, + createmarkdown() + { + var errors = false; + var filemarkdown = false; + + if (this.fileurl !== '') + { + if (this.fileurl.length < 101) + { + var width = this.width ? ' width="' + this.width + '"' : ''; + var preload = this.preload ? ' preload="' + this.preload + '"' : ' preload="none"'; + + filemarkdown = '[:audio path="' + this.fileurl + '"' + width + preload + ' :]'; + } + else + { + errors = this.$filters.translate('Maximum size of file link is 100 characters'); + } + } + + if (errors) + { + eventBus.$emit('publishermessage', this.$filters.translate(errors)); + } + else if (filemarkdown) + { + this.$emit('updateMarkdownEvent', filemarkdown); + this.compmarkdown = filemarkdown; + } + }, + onFileChange( e ) + { + if(e.target.files.length > 0) + { + let uploadedFile = e.target.files[0]; + + let allowedAudioTypes = ['audio/mpeg', 'audio/ogg']; + if (!allowedAudioTypes.includes(uploadedFile.type)) { + let message = "Unsupported file type. Please select an audio file (mp3, ogg)."; + eventBus.$emit('publishermessage', message); + return; + } + + let size = uploadedFile.size / 1024 / 1024; + + if (size > this.maxsize) + { + let message = "The maximal size of a file is " + this.maxsize + " MB"; + eventBus.$emit('publishermessage', message); + return; + } + else + { + self = this; + + self.load = true; + + let reader = new FileReader(); + reader.readAsDataURL(uploadedFile); + reader.onload = function(e) { + + tmaxios.post('/api/v1/file',{ + 'url': data.urlinfo.route, + 'file': e.target.result, + 'name': uploadedFile.name, + }) + .then(function (response) { + + self.load = false; + + self.filemeta = true; + self.savefile = true; + self.filetitle = response.data.fileinfo.title; + self.fileextension = response.data.fileinfo.extension; + self.fileurl = response.data.filepath; + self.selectedrole = ''; + + self.createmarkdown(); + }) + .catch(function (error) + { + self.load = false; + if(error.response) + { + let message = self.$filters.translate(error.response.data.message); + eventBus.$emit('publishermessage', message); + } + }); + } + } + } + }, + beforeSave() + { + /* publish file before you save markdown */ + + if(!this.fileurl) + { + let message = this.$filters.translate('file is missing.'); + eventBus.$emit('publishermessage', message); + + return; + } + + const fileExtension = this.fileurl.split('.').pop().toLowerCase(); + + if (!this.allowedExtensions.includes(fileExtension)) + { + let message = this.$filters.translate('Unsupported file format. Only MP3, and OGG files are allowed.'); + eventBus.$emit('publishermessage', message); + + return; + } + + if(!this.savefile) + { + this.createmarkdown(); + this.$emit('saveBlockEvent'); + } + else + { + var self = this; + + tmaxios.put('/api/v1/file',{ + 'url': data.urlinfo.route, + 'file': this.fileurl, + }) + .then(function (response) + { + self.fileurl = response.data.path; + + self.createmarkdown(); + + self.$emit('saveBlockEvent'); + }) + .catch(function (error) + { + if(error.response) + { + let message = self.$filters.translate(error.response.data.message); + eventBus.$emit('publishermessage', message); + } + }); + } + }, + } +}) + bloxeditor.component('shortcode-component', { props: ['markdown', 'disabled', 'index'], data: function(){ diff --git a/system/typemill/author/js/vue-blox-config.js b/system/typemill/author/js/vue-blox-config.js index 6f8f211..684936b 100644 --- a/system/typemill/author/js/vue-blox-config.js +++ b/system/typemill/author/js/vue-blox-config.js @@ -74,6 +74,13 @@ const determiner = { } return false; }, + audio: function(block,lines,firstChar,secondChar,thirdChar){ + if (lines[0].startsWith('[:audio')) + { + return "audio-component"; + } + return false; + }, code: function(block,lines,firstChar,secondChar,thirdChar){ if( firstChar == '`' && secondChar == '`' && thirdChar == '`') { @@ -114,6 +121,7 @@ const bloxFormats = { notice: { label: '', title: 'Notice', component: 'notice-component' }, image: { label: '', title: 'Image', component: 'image-component' }, video: { label: '', title: 'Video', component: 'video-component' }, + audio: { label: '', title: 'Audio', component: 'audio-component' }, file: { label: '', title: 'File', component: 'file-component' }, toc: { label: '', title: 'Table of Contents', component: 'toc-component' }, hr: { label: '', title: 'Horizontal Line', component: 'hr-component' }, diff --git a/system/typemill/author/partials/symbols.twig b/system/typemill/author/partials/symbols.twig index 317d941..39f410f 100644 --- a/system/typemill/author/partials/symbols.twig +++ b/system/typemill/author/partials/symbols.twig @@ -46,6 +46,10 @@ {{ translate('VIDEO') }} + + {{ translate('AUDIO') }} + + {{ translate('QUOTES') }} diff --git a/system/typemill/settings/defaults.yaml b/system/typemill/settings/defaults.yaml index 2a1beae..47dde9d 100644 --- a/system/typemill/settings/defaults.yaml +++ b/system/typemill/settings/defaults.yaml @@ -16,6 +16,7 @@ formats: - 'notice' - 'image' - 'video' + - 'audio' - 'file' - 'toc' - 'hr' diff --git a/system/typemill/settings/system.yaml b/system/typemill/settings/system.yaml index ed05967..21816b0 100644 --- a/system/typemill/settings/system.yaml +++ b/system/typemill/settings/system.yaml @@ -126,6 +126,7 @@ fieldsetwriting: 'notice': 'notice' 'image': 'image' 'video': 'video' + 'audio': 'audio' 'file': 'file' 'toc': 'table of contents' 'hr': 'horizontal line'