Logo Cinquin Andy Signature

Midjourney Video to Seamless Loop using FFmpeg - Complete Automation Script

Développeur Freelance - Logo

The sites and the associated resources.

Midjourney Video to Seamless Loop using FFmpeg - Complete Automation Script

Posted on  - June 18, 2025 by Andy Cinquin

MidjourneyFFmpegSeamless LoopAI VideoWebP AnimationVideo ProcessingAutomationBash Script

An automatic Bash script to convert videos to seamlessly looping animated WebP files on Fedora, integrated into Nautilus context menu.

✨ Features

  • Automatic conversion: Converts any video to animated WebP
  • Seamless looping: Creates fade effect between end and beginning for perfect loops
  • Context menu: Accessible directly via right-click on video files
  • Notifications: Shows progress and results via system notifications
  • Auto cleanup: Automatically removes temporary files
  • Quality optimization: Balanced settings between quality and file size

🎯 Supported Formats

Input: MP4, AVI, MKV, MOV, WMV, FLV, WebM, 3GP, M4V Output: Animated WebP (30fps, infinite loop)

📋 Requirements

  • Fedora Linux (tested on Fedora 38+)
  • GNOME Desktop Environment with Nautilus
  • Sudo access for installation

🚀 Quick Installation

  1. Create the files below in a folder:
    mkdir video-to-webp-converter
    cd video-to-webp-converter
    
  2. Copy the content of each script (see sections below)
  3. Make the installation script executable:
    chmod +x install.sh
    
  4. Run the installation:
    ./install.sh
    

🎬 Usage

Via context menu (recommended)

  1. Open Nautilus (Files)
  2. Navigate to a folder containing videos
  3. Right-click on any video file
  4. Select "Convert to Animated WebP"
  5. Wait for conversion to complete (notifications shown)
  6. WebP file will be created with _loop.webp suffix

Via command line

video-to-webp.sh "path/to/your/video.mp4"

📁 COMPLETE SCRIPTS TO CREATE

1. 📝 File: video-to-webp.sh

#!/bin/bash

# Script to convert video to looping animated WebP
# Author: Assistant
# Usage: video-to-webp.sh "input_video.mp4"

set -euo pipefail

# Configuration
FPS_INTERMEDIATE=24
FPS_OUTPUT=30
CRF=18
PRESET="veryfast"
FADE_DURATION=0.5
FADE_OFFSET=3.5

# Function to show notifications
notify_user() {
    local message="$1"
    local urgency="${2:-normal}"
    
    if command -v notify-send &> /dev/null; then
        notify-send -u "$urgency" "Video to WebP" "$message"
    fi
    echo "$message"
}

# Function to cleanup temporary files
cleanup() {
    local temp_file="$1"
    if [[ -f "$temp_file" ]]; then
        rm -f "$temp_file"
    fi
}

# Function to get video duration
get_video_duration() {
    local input_file="$1"
    ffprobe -v quiet -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$input_file" 2>/dev/null || echo "0"
}

# Function to convert video to WebP
convert_video_to_webp() {
    local input_file="$1"
    local base_name="${input_file%.*}"
    local output_file="${base_name}_loop.webp"
    local temp_cfr="${base_name}_tmp_cfr.mp4"
    local temp_loop="${base_name}_tmp_loop.mp4"
    
    # Validate input file
    if [[ ! -f "$input_file" ]]; then
        notify_user "Error: Input file '$input_file' not found" "critical"
        return 1
    fi
    
    # Check if ffmpeg is available
    if ! command -v ffmpeg &> /dev/null; then
        notify_user "Error: ffmpeg is not installed. Install it with: sudo dnf install ffmpeg" "critical"
        return 1
    fi
    
    # Get video duration
    local duration
    duration=$(get_video_duration "$input_file")
    
    if (( $(echo "$duration < 1" | bc -l) )); then
        notify_user "Error: Unable to determine video duration or video too short" "critical"
        return 1
    fi
    
    notify_user "Starting conversion of '$input_file' to WebP..."
    
    # Step 1: Convert to constant frame rate
    notify_user "Step 1/3: Converting to constant frame rate..."
    if ! ffmpeg -y -i "$input_file" \
        -r "$FPS_INTERMEDIATE" \
        -c:v libx264 \
        -crf "$CRF" \
        -preset "$PRESET" \
        -an \
        "$temp_cfr" 2>/dev/null; then
        notify_user "Error: Failed to convert to CFR" "critical"
        cleanup "$temp_cfr"
        return 1
    fi
    
    # Step 2: Create seamless loop with crossfade
    notify_user "Step 2/3: Creating seamless loop..."
    if ! ffmpeg -y -i "$temp_cfr" \
        -filter_complex \
        "[0:v]split=2[main1][main2]; \
         [main1]trim=end=1,setpts=PTS-STARTPTS,fps=$FPS_INTERMEDIATE[begin]; \
         [main2]trim=start=1,setpts=PTS-STARTPTS,fps=$FPS_INTERMEDIATE[end]; \
         [end][begin]xfade=transition=fade:duration=$FADE_DURATION:offset=$FADE_OFFSET,format=yuv420p[v]" \
        -map "[v]" \
        -c:v libx264 \
        -crf "$CRF" \
        -preset "$PRESET" \
        "$temp_loop" 2>/dev/null; then
        notify_user "Error: Failed to create loop" "critical"
        cleanup "$temp_cfr"
        cleanup "$temp_loop"
        return 1
    fi
    
    # Step 3: Convert to WebP
    notify_user "Step 3/3: Converting to animated WebP..."
    if ! ffmpeg -y -i "$temp_loop" \
        -vf "fps=$FPS_OUTPUT" \
        -loop 0 \
        -quality 80 \
        -method 6 \
        -lossless 0 \
        "$output_file" 2>/dev/null; then
        notify_user "Error: Failed to convert to WebP" "critical"
        cleanup "$temp_cfr"
        cleanup "$temp_loop"
        return 1
    fi
    
    # Cleanup temporary files
    cleanup "$temp_cfr"
    cleanup "$temp_loop"
    
    # Get file sizes for comparison
    local input_size output_size
    input_size=$(du -h "$input_file" | cut -f1)
    output_size=$(du -h "$output_file" | cut -f1)
    
    notify_user "✅ Conversion completed successfully!
Input: $input_size → Output: $output_size
Saved as: $(basename "$output_file")"
    
    # Open file manager to show the result
    if command -v nautilus &> /dev/null; then
        nautilus "$(dirname "$output_file")" &
    fi
}

# Main execution
main() {
    if [[ $# -eq 0 ]]; then
        echo "Usage: $0 <input_video_file>"
        echo "Example: $0 'my_video.mp4'"
        exit 1
    fi
    
    local input_file="$1"
    
    # Convert to absolute path
    input_file=$(realpath "$input_file")
    
    # Start conversion
    convert_video_to_webp "$input_file"
}

# Trap cleanup on exit
trap 'cleanup "${base_name}_tmp_cfr.mp4" 2>/dev/null || true; cleanup "${base_name}_tmp_loop.mp4" 2>/dev/null || true' EXIT

# Run main function
main "$@"

2. 🗂️ File: video-to-webp.desktop

[Desktop Entry]
Type=Action
Icon=video-x-generic
Name[en]=Convert to Animated WebP
Name[fr]=Convertir en WebP animé
Tooltip[en]=Convert video to looping animated WebP
Tooltip[fr]=Convertir la vidéo en WebP animé en boucle
MimeType=video/mp4;video/avi;video/mkv;video/mov;video/wmv;video/flv;video/webm;video/3gp;video/m4v;video/x-msvideo;video/quicktime;
Profiles=profile-zero;

[X-Action-Profile profile-zero]
Exec=/usr/local/bin/video-to-webp.sh %f
Name[en]=Convert to Animated WebP Loop
Name[fr]=Convertir en WebP animé en boucle
Icon=video-x-generic
Description[en]=Convert selected video to an animated WebP with seamless loop
Description[fr]=Convertir la vidéo sélectionnée en WebP animé avec boucle fluide
MimeTypes=video/mp4;video/avi;video/mkv;video/mov;video/wmv;video/flv;video/webm;video/3gp;video/m4v;video/x-msvideo;video/quicktime;
SelectionCount==1

3. 🚀 File: install.sh

#!/bin/bash

# Installation script for Video to WebP converter
# For Fedora Linux with Nautilus file manager

set -euo pipefail

SCRIPT_NAME="video-to-webp.sh"
DESKTOP_FILE="video-to-webp.desktop"
INSTALL_DIR="/usr/local/bin"
NAUTILUS_ACTIONS_DIR="$HOME/.local/share/file-manager/actions"

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Function to print colored output
print_status() {
    local color=$1
    local message=$2
    echo -e "${color}${message}${NC}"
}

# Function to check if command exists
command_exists() {
    command -v "$1" >/dev/null 2>&1
}

# Function to install dependencies
install_dependencies() {
    print_status "$BLUE" "🔍 Checking dependencies..."
    
    local missing_packages=()
    
    # Check for ffmpeg
    if ! command_exists ffmpeg; then
        missing_packages+=("ffmpeg")
    fi
    
    # Check for bc (for float calculations)
    if ! command_exists bc; then
        missing_packages+=("bc")
    fi
    
    # Check for notify-send
    if ! command_exists notify-send; then
        missing_packages+=("libnotify")
    fi
    
    if [[ ${#missing_packages[@]} -gt 0 ]]; then
        print_status "$YELLOW" "📦 Installing missing packages: ${missing_packages[*]}"
        
        # Enable RPM Fusion repositories if ffmpeg is missing
        if [[ " ${missing_packages[*]} " =~ " ffmpeg " ]]; then
            print_status "$BLUE" "🔧 Enabling RPM Fusion repositories for ffmpeg..."
            sudo dnf install -y \
                https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm \
                https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm 2>/dev/null || true
        fi
        
        sudo dnf install -y "${missing_packages[@]}"
        print_status "$GREEN" "✅ Dependencies installed successfully"
    else
        print_status "$GREEN" "✅ All dependencies are already installed"
    fi
}

# Function to install the main script
install_script() {
    print_status "$BLUE" "📝 Installing video conversion script..."
    
    if [[ ! -f "$SCRIPT_NAME" ]]; then
        print_status "$RED" "❌ Error: $SCRIPT_NAME not found in current directory"
        exit 1
    fi
    
    # Copy script to system directory
    sudo cp "$SCRIPT_NAME" "$INSTALL_DIR/"
    sudo chmod +x "$INSTALL_DIR/$SCRIPT_NAME"
    
    print_status "$GREEN" "✅ Script installed to $INSTALL_DIR/$SCRIPT_NAME"
}

# Function to install Nautilus action
install_nautilus_action() {
    print_status "$BLUE" "🗂️  Installing Nautilus context menu action..."
    
    if [[ ! -f "$DESKTOP_FILE" ]]; then
        print_status "$RED" "❌ Error: $DESKTOP_FILE not found in current directory"
        exit 1
    fi
    
    # Create actions directory if it doesn't exist
    mkdir -p "$NAUTILUS_ACTIONS_DIR"
    
    # Copy desktop file
    cp "$DESKTOP_FILE" "$NAUTILUS_ACTIONS_DIR/"
    
    print_status "$GREEN" "✅ Nautilus action installed to $NAUTILUS_ACTIONS_DIR/$DESKTOP_FILE"
}

# Function to restart Nautilus
restart_nautilus() {
    print_status "$BLUE" "🔄 Restarting Nautilus to apply changes..."
    
    # Kill all nautilus processes
    pkill -f nautilus 2>/dev/null || true
    
    # Wait a moment
    sleep 2
    
    # Start nautilus in background
    nautilus &>/dev/null &
    
    print_status "$GREEN" "✅ Nautilus restarted"
}

# Function to create test video
create_test_video() {
    local test_file="test_animation.mp4"
    
    if [[ ! -f "$test_file" ]]; then
        print_status "$BLUE" "🎬 Creating test video for demonstration..."
        
        # Create a simple test animation using ffmpeg
        ffmpeg -f lavfi -i "testsrc=duration=3:size=320x240:rate=30" \
               -f lavfi -i "sine=frequency=1000:duration=3" \
               -c:v libx264 -crf 23 -c:a aac \
               "$test_file" 2>/dev/null
        
        if [[ -f "$test_file" ]]; then
            print_status "$GREEN" "✅ Test video created: $test_file"
        fi
    fi
}

# Function to display usage instructions
show_usage_instructions() {
    print_status "$GREEN" "🎉 Installation completed successfully!"
    echo
    print_status "$BLUE" "📋 How to use:"
    echo "1. Open Nautilus (Files) file manager"
    echo "2. Navigate to a folder containing video files"
    echo "3. Right-click on any video file (.mp4, .avi, .mkv, etc.)"
    echo "4. Select 'Convert to Animated WebP' from the context menu"
    echo "5. Wait for the conversion to complete"
    echo "6. The WebP file will be created in the same directory"
    echo
    print_status "$YELLOW" "💡 Tips:"
    echo "• The script creates seamless looping animations"
    echo "• Output files are named with '_loop.webp' suffix"
    echo "• You'll get notifications during the conversion process"
    echo "• The file manager will open automatically when done"
    echo
    print_status "$BLUE" "🔧 Manual usage:"
    echo "You can also run the script manually from terminal:"
    echo "video-to-webp.sh 'path/to/your/video.mp4'"
}

# Main installation process
main() {
    print_status "$GREEN" "🚀 Starting Video to WebP Converter installation on Fedora"
    echo
    
    # Check if running as root (we don't want that for the full script)
    if [[ $EUID -eq 0 ]]; then
        print_status "$RED" "❌ Please don't run this script as root. It will ask for sudo when needed."
        exit 1
    fi
    
    # Check if we're on Fedora
    if [[ ! -f /etc/fedora-release ]]; then
        print_status "$YELLOW" "⚠️  Warning: This script is designed for Fedora. It may work on other RPM-based distributions."
        read -p "Continue anyway? (y/N): " -n 1 -r
        echo
        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
            exit 0
        fi
    fi
    
    # Check if Nautilus is available
    if ! command_exists nautilus; then
        print_status "$RED" "❌ Error: Nautilus file manager not found. This script requires GNOME desktop environment."
        exit 1
    fi
    
    # Run installation steps
    install_dependencies
    install_script
    install_nautilus_action
    restart_nautilus
    create_test_video
    show_usage_instructions
    
    print_status "$GREEN" "✨ Installation completed! You can now right-click on video files to convert them to WebP!"
}

# Run main function
main "$@"

4. 🧪 File: test.sh

#!/bin/bash

# Test script for Video to WebP converter
# Creates a test video and converts it to verify installation

set -euo pipefail

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

print_status() {
    local color=$1
    local message=$2
    echo -e "${color}${message}${NC}"
}

# Function to create test video
create_test_video() {
    local test_file="test_sample.mp4"
    
    print_status "$BLUE" "🎬 Creating test video..."
    
    # Create a colorful test pattern with text overlay
    ffmpeg -y \
        -f lavfi -i "testsrc2=duration=5:size=640x480:rate=30" \
        -f lavfi -i "sine=frequency=440:duration=5" \
        -vf "drawtext=text='Test Animation':x=(w-text_w)/2:y=(h-text_h)/2:fontsize=48:fontcolor=white:box=1:boxcolor=black@0.5" \
        -c:v libx264 -crf 23 -preset fast \
        -c:a aac -b:a 128k \
        "$test_file" 2>/dev/null
    
    if [[ -f "$test_file" ]]; then
        print_status "$GREEN" "✅ Test video created: $test_file"
        return 0
    else
        print_status "$RED" "❌ Failed to create test video"
        return 1
    fi
}

# Function to test the converter
test_converter() {
    local test_file="test_sample.mp4"
    local expected_output="test_sample_loop.webp"
    
    print_status "$BLUE" "🔄 Testing video converter..."
    
    if [[ ! -f "$test_file" ]]; then
        print_status "$RED" "❌ Test video not found"
        return 1
    fi
    
    # Test the converter script
    if command -v video-to-webp.sh &>/dev/null; then
        print_status "$BLUE" "📝 Running conversion test..."
        
        if video-to-webp.sh "$test_file"; then
            if [[ -f "$expected_output" ]]; then
                local input_size output_size
                input_size=$(du -h "$test_file" | cut -f1)
                output_size=$(du -h "$expected_output" | cut -f1)
                
                print_status "$GREEN" "✅ Conversion test successful!"
                print_status "$GREEN" "   Input: $input_size → Output: $output_size"
                return 0
            else
                print_status "$RED" "❌ Output file not created"
                return 1
            fi
        else
            print_status "$RED" "❌ Conversion failed"
            return 1
        fi
    else
        print_status "$RED" "❌ video-to-webp.sh script not found in PATH"
        print_status "$YELLOW" "   Run the installer first: ./install.sh"
        return 1
    fi
}

# Function to check Nautilus integration
check_nautilus_integration() {
    local action_file="$HOME/.local/share/file-manager/actions/video-to-webp.desktop"
    
    print_status "$BLUE" "🗂️  Checking Nautilus integration..."
    
    if [[ -f "$action_file" ]]; then
        print_status "$GREEN" "✅ Nautilus action file found"
        
        # Check if the action file is valid
        if grep -q "video-to-webp.sh" "$action_file"; then
            print_status "$GREEN" "✅ Action file points to correct script"
        else
            print_status "$YELLOW" "⚠️  Action file may have incorrect path"
        fi
        
        return 0
    else
        print_status "$RED" "❌ Nautilus action file not found"
        print_status "$YELLOW" "   Expected: $action_file"
        return 1
    fi
}

# Function to check dependencies
check_dependencies() {
    print_status "$BLUE" "🔍 Checking dependencies..."
    
    local deps=("ffmpeg" "ffprobe" "bc" "notify-send")
    local missing=()
    
    for dep in "${deps[@]}"; do
        if command -v "$dep" &>/dev/null; then
            print_status "$GREEN" "✅ $dep found"
        else
            print_status "$RED" "❌ $dep missing"
            missing+=("$dep")
        fi
    done
    
    if [[ ${#missing[@]} -eq 0 ]]; then
        print_status "$GREEN" "✅ All dependencies satisfied"
        return 0
    else
        print_status "$RED" "❌ Missing dependencies: ${missing[*]}"
        return 1
    fi
}

# Function to cleanup test files
cleanup_test_files() {
    local files=("test_sample.mp4" "test_sample_loop.webp" "test_sample_tmp_cfr.mp4" "test_sample_tmp_loop.mp4")
    
    print_status "$BLUE" "🧹 Cleaning up test files..."
    
    for file in "${files[@]}"; do
        if [[ -f "$file" ]]; then
            rm -f "$file"
            print_status "$GREEN" "   Removed: $file"
        fi
    done
}

# Function to show test results
show_test_results() {
    echo
    print_status "$BLUE" "📋 Test Summary:"
    echo "==================="
    
    if check_dependencies; then
        echo "✅ Dependencies: OK"
    else
        echo "❌ Dependencies: MISSING"
    fi
    
    if check_nautilus_integration; then
        echo "✅ Nautilus Integration: OK"
    else
        echo "❌ Nautilus Integration: MISSING"
    fi
    
    if command -v video-to-webp.sh &>/dev/null; then
        echo "✅ Script Installation: OK"
    else
        echo "❌ Script Installation: MISSING"
    fi
    
    echo "==================="
}

# Main test function
main() {
    print_status "$GREEN" "🧪 Starting Video to WebP Converter Test Suite"
    echo
    
    # Check if we should cleanup first
    if [[ "${1:-}" == "--cleanup" ]]; then
        cleanup_test_files
        exit 0
    fi
    
    # Run checks
    local overall_success=true
    
    if ! check_dependencies; then
        overall_success=false
    fi
    
    if ! check_nautilus_integration; then
        overall_success=false
    fi
    
    # Only run conversion test if basic checks pass
    if [[ "$overall_success" == true ]]; then
        if create_test_video && test_converter; then
            print_status "$GREEN" "🎉 All tests passed! The converter is working properly."
        else
            overall_success=false
        fi
    fi
    
    show_test_results
    
    # Cleanup option
    echo
    read -p "Clean up test files? (Y/n): " -n 1 -r
    echo
    if [[ $REPLY =~ ^[Yy]$|^$ ]]; then
        cleanup_test_files
    fi
    
    if [[ "$overall_success" == true ]]; then
        print_status "$GREEN" "✨ Installation verified! You can now use the converter."
        echo
        print_status "$BLUE" "💡 How to use:"
        echo "1. Open Nautilus file manager"
        echo "2. Right-click on any video file"
        echo "3. Select 'Convert to Animated WebP'"
        exit 0
    else
        print_status "$RED" "❌ Some tests failed. Please check the installation."
        echo
        print_status "$YELLOW" "💡 Try running the installer again:"
        echo "./install.sh"
        exit 1
    fi
}

# Show usage if needed
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
    echo "Video to WebP Converter Test Suite"
    echo "Usage: $0 [--cleanup|--help]"
    echo
    echo "Options:"
    echo "  --cleanup   Remove test files and exit"
    echo "  --help      Show this help message"
    echo
    echo "This script tests the installation of the video-to-webp converter."
    exit 0
fi

# Run main function
main "$@"

📋 INSTALLATION INSTRUCTIONS

🚀 One-Time Installation:

# 1. Create folder and all files
mkdir video-to-webp-converter
cd video-to-webp-converter

# 2. Create each file with its content (copy-paste from this README)
nano video-to-webp.sh          # Paste main script content
nano video-to-webp.desktop     # Paste desktop file content
nano install.sh                # Paste installation script content
nano test.sh                   # Paste test script content

# 3. Make scripts executable
chmod +x *.sh

# 4. Run installation
./install.sh

# 5. (Optional) Test installation
./test.sh
you can also, copy the script into your folder share nautilus. for me it's "/home/andycinquin/.local/share/nautilus/scripts"
Pasted image 20250619004116.png

⚙️ Advanced Configuration

Modify settings in video-to-webp.sh:
FPS_INTERMEDIATE=24    # Intermediate FPS for processing
FPS_OUTPUT=30         # Final WebP FPS
CRF=18               # Video quality (lower = better quality)
PRESET="veryfast"    # Encoding speed
FADE_DURATION=0.5    # Fade duration for loop
FADE_OFFSET=3.5      # Fade offset

🔧 Conversion Process

The script automatically performs 3 steps:
  1. Normalization: Convert to constant framerate (24fps)
  2. Seamless loop: Create fade between end and beginning
  3. WebP export: Final conversion to animated WebP (30fps)

🐛 Troubleshooting

Context menu doesn't appear

pkill nautilus && nautilus &

FFmpeg not found

sudo dnf install ffmpeg

Permission errors

# Check script permissions
ls -la /usr/local/bin/video-to-webp.sh
# Should show: -rwxr-xr-x

Complete reinstallation

sudo rm -f /usr/local/bin/video-to-webp.sh
rm -f ~/.local/share/file-manager/actions/video-to-webp.desktop
./install.sh

📊 Example Results

  • 10MB MP4 video~2-3MB WebP
  • Visual quality: Excellent for short animations
  • Conversion time: ~30 seconds for 10 seconds of video
  • Compatibility: Works in all modern browsers

🎯 Ideal Use Cases

  • GIF replacement: Reduced size, superior quality
  • Web animations: Optimized performance
  • Social media: Modern and efficient format
  • Presentations: Smooth and lightweight animations

🛠️ Uninstallation

To completely remove the system:
# Remove main script
sudo rm -f /usr/local/bin/video-to-webp.sh

# Remove Nautilus action
rm -f ~/.local/share/file-manager/actions/video-to-webp.desktop

# Restart Nautilus
pkill nautilus && nautilus &

📁 File Structure

video-to-webp-converter/
├── video-to-webp.sh          # Main conversion script
├── video-to-webp.desktop     # Nautilus action file
├── install.sh                # Automatic installation script
└── test.sh                   # Test and verification script

📝 Technical Notes

  • Seamless loop: Uses FFmpeg's xfade for imperceptible fade
  • Optimization: CRF 18 to balance quality/size
  • Cleanup: Automatic removal of temporary files
  • Security: Input validation and robust error handling

🤝 Contributing

Feel free to report bugs or suggest improvements!

Author: Assistant
License: MIT
Version: 1.0.0
Complete portable kit! Copy each script, install and enjoy one-click animated WebP conversion!



🚀 Thanks for reading!
If you enjoyed this article, feel free to share it around.

💡 Got an idea? Let's talk !

DEVELOP YOUR PROJECTS TOGETHER

An idea, a project? I'm here to answer your questions and help you.
I'd be delighted to discuss your project with you!