KiwiNail v2: The Automatic Thumbnail Add-on - The final solution to thumbnailing

  • 🐕 I am attempting to get the site runnning as fast as possible. If you are experiencing slow page load times, please report it.

Osama Bin Laden

Osama Bin ...
True & Honest Fan
kiwifarms.net
Joined
May 8, 2022
I think it should be obvious to anyone that I am not a programmer, but I do want to try to get into it as some sort of hobby. It's not something I want to devote my life but I like making little neat shit like this. i made a thread before about this, but I deleted it because I realized that after making the add-on, null uses xenforo 2.0, and not xenforo 1.0

cooltext480472099071503.gif

KiwiNail is the final solution to thumbnailing. KiwiNail takes images from your clipboard and automatically resizes them into thumbnail format. It was originally meant for only Null, but I am okay with everyone using it.

The issue I am having with the add-on is that, despite injecting the scripts into the message_box template and the create_thread template, and adding error logs. XenForo refuses to read clipboard data. I've tried just about narrowing everything down.

I've even tried writing a custom .js script specifically for this, but no dice.

JavaScript:
!function($, window, document, _undefined) {
    "use strict";

    XF.EditorPasteHandler = XF.Element.newHandler({
        options: {},

        init: function() {
            console.log('EditorPasteHandler initialized');
            this.$target.on('paste', XF.proxy(this, 'onPaste'));
        },

        onPaste: function(e) {
            console.log('Paste event fired at ' + new Date().toISOString());
            var clipboardData = e.originalEvent.clipboardData || window.clipboardData;
            if (!clipboardData || !clipboardData.items) {
                console.log('No clipboard data available');
                return;
            }

            var items = clipboardData.items;
            for (var i = 0; i < items.length; i++) {
                if (items[i].type.indexOf('image') === 0) {
                    var blob = items[i].getAsFile();
                    if (blob) {
                        console.log('Image detected, size: ' + blob.size + ' bytes');
                        this.uploadImage(blob);
                        e.preventDefault();
                        break;
                    }
                }
            }
        },

        uploadImage: function(blob) {
            var formData = new FormData();
            formData.append('upload', blob);

            XF.ajax('POST', XF.canonicalizeUrl('index.php?editor/paste'), formData,
                XF.proxy(this, 'uploadSuccess'),
                { contentType: false, processData: false }
            ).fail(function(xhr) {
                console.error('Upload failed: ' + (xhr.responseText || 'Unknown error'));
            });
        },

        uploadSuccess: function(data) {
            console.log('Upload success: ' + JSON.stringify(data));
            if (data.html) {
                console.log('Inserting BB code: ' + data.html);
                var editor = this.$target.data('xf-editor');
                if (editor) {
                    editor.insertContent(data.html);
                } else {
                    console.error('Editor instance not found');
                }
            }
        }
    });

    XF.Element.register('editor-paste-handler', 'XF.EditorPasteHandler');
}(jQuery, window, document);

Everything works as intended. HOWEVER, XenForo cannot detect the getPaste() function nor read any clipboard image data. I've tried using jQuery and Xenforo's own system, but I don't know what I'm missing. I've tried using AI as a way to help, but there's nothing there.


CODE:

Editor.php

PHP:
<?php

namespace KiwiNail\UploadImagePaste\XF\Pub\Controller;

use XF\Mvc\ParameterBag;

class Editor extends XFCP_Editor
{
    public function actionPaste(ParameterBag $params)
    {
        // Force logging to a specific file for testing
        $logFile = \XF::app()->get('config')['internalDataPath'] . '/paste_log.txt';
        file_put_contents($logFile, "actionPaste started at " . date('Y-m-d H:i:s') . "\n", FILE_APPEND);

        $upload = $this->request->getFile('upload');
        if (!$upload) {
            file_put_contents($logFile, "No file uploaded.\n", FILE_APPEND);
            return $this->error(\XF::phrase('no_file_uploaded_or_file_is_not_valid_image'));
        }

        file_put_contents($logFile, "Upload received: " . $upload->getFileName() . " (" . $upload->getFileSize() . " bytes)\n", FILE_APPEND);

        $handler = $this->getAttachmentHandler('post');
        $context = ['content_type' => 'post', 'content_id' => 0];
        $manipulator = $this->service('XF:Attachment\Manipulator', $handler, $context);

        $attachment = $manipulator->upload($upload);
        if (!$attachment) {
            file_put_contents($logFile, "Attachment upload failed.\n", FILE_APPEND);
            return $this->error(\XF::phrase('attachment_upload_failed'));
        }

        file_put_contents($logFile, "Attachment uploaded, ID: " . $attachment->attachment_id . "\n", FILE_APPEND);

        // Thumbnail generation
        $thumbW = 250;
        $thumbH = 250;
        $thumbnailDir = \XF::app()->get('config')['internalDataPath'] . '/attachments/thumbs/';
        $thumbnailPath = $thumbnailDir . $attachment->attachment_id . '.jpg';

        if (!file_exists($thumbnailDir)) {
            mkdir($thumbnailDir, 0777, true);
            file_put_contents($logFile, "Created thumbs directory: " . $thumbnailDir . "\n", FILE_APPEND);
        }

        $image = \XF::app()->imageManager()->imageFromFile($attachment->getData()['temp_file']);
        if ($image) {
            $image->resizeAndCrop($thumbW, $thumbH);
            $image->save($thumbnailPath, IMAGETYPE_JPEG);
            $attachment->fastUpdate([
                'thumbnail_width' => $thumbW,
                'thumbnail_height' => $thumbH,
                'thumbnail_date' => \XF::$time
            ]);
            file_put_contents($logFile, "Thumbnail generated at: " . $thumbnailPath . "\n", FILE_APPEND);
        } else {
            file_put_contents($logFile, "Thumbnail generation failed (GD/ImageMagick issue).\n", FILE_APPEND);
        }

        return $this->message([
            'attachment_id' => $attachment->attachment_id,
            'thumbnail' => true,
            'html' => '[ATTACH type="thumb"]' . $attachment->attachment_id . '[/ATTACH]'
        ]);
    }
}

editor.js
JavaScript:
!function($, window, document, _undefined) {
    "use strict";

    XF.EditorPasteHandler = XF.Element.newHandler({
        options: {},

        init: function() {
            console.log('EditorPasteHandler initialized at ' + new Date().toISOString());
            this.$target.on('paste', XF.proxy(this, 'onPaste'));
        },

        onPaste: function(e) {
            console.log('Paste event fired at ' + new Date().toISOString());
            var clipboardData = e.originalEvent.clipboardData || window.clipboardData;
            if (!clipboardData || !clipboardData.items) {
                console.log('No clipboard data available');
                return;
            }

            var items = clipboardData.items;
            for (var i = 0; i < items.length; i++) {
                if (items[i].type.indexOf('image') === 0) {
                    var blob = items[i].getAsFile();
                    if (blob) {
                        console.log('Image detected, size: ' + blob.size + ' bytes');
                        this.uploadImage(blob);
                        e.preventDefault();
                        break;
                    }
                }
            }
        },

        uploadImage: function(blob) {
            var formData = new FormData();
            formData.append('upload', blob);

            XF.ajax('POST', XF.canonicalizeUrl('index.php?editor/paste'), formData,
                XF.proxy(this, 'uploadSuccess'),
                { contentType: false, processData: false }
            ).fail(function(xhr) {
                console.error('Upload failed: ' + (xhr.responseText || 'Unknown error'));
            });
        },

        uploadSuccess: function(data) {
            console.log('Upload success: ' + JSON.stringify(data));
            if (data.html) {
                console.log('Inserting BB code: ' + data.html);
                var editor = this.$target.data('xf-editor');
                if (editor) {
                    editor.insertContent(data.html);
                } else {
                    console.error('Editor instance not found');
                }
            } else {
                console.error('No HTML in response');
            }
        }
    });

    XF.Element.register('editor-paste-handler', 'XF.EditorPasteHandler');
}(jQuery, window, document);

Attachment.php
PHP:
namespace KiwiNail\Listener;

use XF\Attachment\Manipulator;
use XF\Entity\Attachment;
use XF\Pub\Controller\Attachment as AttachmentController;

class Attachment
{
    public static function postUpload(Manipulator $manipulator, Attachment $attachment, $context)
    {
        if (strpos($attachment->getFile()->getType(), 'image/') === 0) {
            $thumbW = 250;
            $thumbH = 250;

            if (!$attachment->hasThumbnail()) {
                $image = \XF::app()->imageManager()->imageFromFile($attachment->getFile()->getPath());
                if ($image) {
                    $image->resizeAndCrop($thumbW, $thumbH);
                    $image->save($attachment->getThumbnailPath());
                    $attachment->set('thumbnail_width', $thumbW);
                    $attachment->set('thumbnail_height', $thumbH);
                    $attachment->save();
                }
            }
        }
    }

    public static function preInsert(AttachmentController $controller, &$output, &$insertFull)
    {
        $insertFull = false;
    }
}

Addon.json
JSON:
{
    "legacy_addon_id": "",
    "addon_id": "KiwiNail/UploadImagePaste",
    "title": "KiwiNail - Auto Thumbnail Generator",
    "description": "Automatically generates thumbnails for images in posts, whether uploaded or pasted from the clipboard.",
    "version_id": 1000010,
    "version_string": "1.0.0",
    "dev": "Osama Bin Laden",
    "dev_url": "https://kiwifarms.st",
    "faq_url": "",
    "support_url": "",
    "extra_urls": [],
    "require": {
        "XF": "2.3.3"
    },
    "icon": "",
    "listeners": {
        "XF\\Attachment\\Manipulator::postUpload": "KiwiNail\\Listener\\Attachment::postUpload",
        "XF\\Pub\\Controller\\Attachment::preInsert": "KiwiNail\\Listener\\Attachment::preInsert"
    },
    "additional_files": [
        "js/kiwinail/editor.js"
    ]
}
 

Attachments

Last edited:
I looked through the code and I don't see any viruses (yet)
Can't help with the clipboard problem though.
 
or just do it the white man's way...
paste -> backspace -> click insert -> click thumbnail
No one wants to do extra work for such a trivial task. Do you go out and pick cotton to make the clothes you wear? No, that shit's for the slaves to do, and basically you're an autistic nigger if you think you're better at working harder instead of smarter like what OP is doing.
 
i've spent many autistic hours into this. however, I do have some good news.

I finally managed to get jQuery working, and now everything is working as it should be. However, FOR SOME FUCKING REASON, Xenforo refuses to still thumbnail my images

It's the jews fault.
 

Attachments

  • Informative
Reactions: Vecr
No one wants to do extra work for such a trivial task. Do you go out and pick cotton to make the clothes you wear? No, that shit's for the slaves to do, and basically you're an autistic nigger if you think you're better at working harder instead of smarter like what OP is doing.
yeah but you aren't letting your nigger-slave cut your food or put on the clothes for you
 
im still working on it

JSON:
jquery-3.5.1.min.js?_v=1f8525f2:2  POST http://localhost/index.php?attachments/upload 403 (Forbidden)
editor.js?_v=2030370:179 [KiwiNail] Upload failed: error Forbidden 
[LIST=1]
[*]{status: 'error', errors: Array(1), errorHtml: {…}, visitor: {…}, debug: {…}}
[LIST=1]
[*]debug: {time: 0.1904, queries: 4, memory: 2}
[*]errorHtml: {content: '\n\n<div data-template-name="public:error" class="bl…o view this page or perform this action.\n\t\n</div>', title: 'Oops! We ran into some problems.'}
[*]errors: ['You do not have permission to view this page or perform this action.']
[*]status: "error"
[*]visitor: {conversations_unread: '0', alerts_unviewed: '0', total_unread: '0'}
[*][[Prototype]]: Object
[/LIST]
[/LIST]
 
Back