pixelfed/pixelfed

View on GitHub
app/Console/Commands/ImportEmojis.php

Summary

Maintainability
A
3 hrs
Test Coverage
<?php

namespace App\Console\Commands;

use App\Models\CustomEmoji;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Storage;

class ImportEmojis extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'import:emojis
                            {path : Path to a tar.gz archive with the emojis}
                            {--prefix : Define a prefix for the emjoi shortcode}
                            {--suffix : Define a suffix for the emjoi shortcode}
                            {--overwrite : Overwrite existing emojis}
                            {--disabled : Import all emojis as disabled}';


    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Import emojis to the database';

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $path = $this->argument('path');

        if (!file_exists($path) || !mime_content_type($path) == 'application/x-tar') {
            $this->error('Path does not exist or is not a tarfile');
            return Command::FAILURE;
        }

        $imported = 0;
        $skipped = 0;
        $failed = 0;

        $tar = new \PharData($path);
        $tar->decompress();

        foreach (new \RecursiveIteratorIterator($tar) as $entry) {
            $this->line("Processing {$entry->getFilename()}");
            if (!$entry->isFile() || !$this->isImage($entry) || !$this->isEmoji($entry->getPathname())) {
                $failed++;
                continue;
            }

            $filename = pathinfo($entry->getFilename(), PATHINFO_FILENAME);
            $extension = pathinfo($entry->getFilename(), PATHINFO_EXTENSION);

            // Skip macOS shadow files
            if (str_starts_with($filename, '._')) {
                continue;
            }

            $shortcode = implode('', [
                $this->option('prefix'),
                $filename,
                $this->option('suffix'),
            ]);

            $customEmoji = CustomEmoji::whereShortcode($shortcode)->first();

            if ($customEmoji && !$this->option('overwrite')) {
                $skipped++;
                continue;
            }

            $emoji = $customEmoji ?? new CustomEmoji();
            $emoji->shortcode = $shortcode;
            $emoji->domain = config('pixelfed.domain.app');
            $emoji->disabled = $this->option('disabled');
            $emoji->save();

            $fileName = $emoji->id . '.' . $extension;
            Storage::putFileAs('public/emoji', $entry->getPathname(), $fileName);
            $emoji->media_path = 'emoji/' . $fileName;
            $emoji->save();
            $imported++;
            Cache::forget('pf:custom_emoji');
        }

        $this->line("Imported: {$imported}");
        $this->line("Skipped: {$skipped}");
        $this->line("Failed: {$failed}");

        //delete file
        unlink(str_replace('.tar.gz', '.tar', $path));

        return Command::SUCCESS;
    }

    private function isImage($file)
    {
        $image = getimagesize($file->getPathname());
        return $image !== false;
    }

    private function isEmoji($filename)
    {
        $allowedMimeTypes = ['image/png', 'image/jpeg', 'image/webp'];
        $mimeType = mime_content_type($filename);

        return in_array($mimeType, $allowedMimeTypes);
    }
}