555 lines
28 KiB
Python
555 lines
28 KiB
Python
import discord
|
|
from discord.ext import commands
|
|
from discord import app_commands
|
|
import os
|
|
import asyncio
|
|
import json
|
|
import tempfile
|
|
import glob
|
|
import sys
|
|
import importlib.util
|
|
|
|
class JSON:
|
|
def read(file):
|
|
with open(f"{file}.json", "r", encoding="utf8") as file:
|
|
data = json.load(file, strict=False)
|
|
return data
|
|
|
|
def dump(file, data):
|
|
with open(f"{file}.json", "w", encoding="utf8") as file:
|
|
json.dump(data, file, indent=4)
|
|
|
|
class WebdriverTorsoCog(commands.Cog):
|
|
def __init__(self, bot):
|
|
self.bot = bot
|
|
self.is_processing = False
|
|
|
|
# Default configuration values
|
|
self.DEFAULT_CONFIG = {
|
|
"WIDTH": 640,
|
|
"HEIGHT": 480,
|
|
"MAX_WIDTH": 200,
|
|
"MAX_HEIGHT": 200,
|
|
"MIN_WIDTH": 20,
|
|
"MIN_HEIGHT": 20,
|
|
"SLIDES": 10,
|
|
"VIDEOS": 1,
|
|
"MIN_SHAPES": 5,
|
|
"MAX_SHAPES": 15,
|
|
"SOUND_QUALITY": 44100,
|
|
"TTS_ENABLED": False,
|
|
"TTS_TEXT": "This is a Webdriver Torso style test video created by the bot.",
|
|
"TTS_PROVIDER": "gtts",
|
|
"AUDIO_WAVE_TYPE": "sawtooth",
|
|
"SLIDE_DURATION": 1000,
|
|
"DEFORM_LEVEL": "medium",
|
|
"COLOR_MODE": "random",
|
|
"COLOR_SCHEME": "default",
|
|
"SOLID_COLOR": "#FFFFFF",
|
|
"ALLOWED_SHAPES": ["rectangle", "ellipse", "polygon", "triangle", "circle"],
|
|
"WAVE_VIBE": "random",
|
|
"TOP_LEFT_TEXT_ENABLED": True,
|
|
"TOP_LEFT_TEXT_MODE": "random",
|
|
"WORDS_TOPIC": "random",
|
|
"TEXT_COLOR": "#000000",
|
|
"TEXT_SIZE": 0,
|
|
"TEXT_POSITION": "top-left",
|
|
"COLOR_SCHEMES": {
|
|
"pastel": [[255, 182, 193], [176, 224, 230], [240, 230, 140], [221, 160, 221], [152, 251, 152]],
|
|
"dark_gritty": [[47, 79, 79], [105, 105, 105], [0, 0, 0], [85, 107, 47], [139, 69, 19]],
|
|
"nature": [[34, 139, 34], [107, 142, 35], [46, 139, 87], [32, 178, 170], [154, 205, 50]],
|
|
"vibrant": [[255, 0, 0], [0, 255, 0], [0, 0, 255], [255, 255, 0], [255, 0, 255]],
|
|
"ocean": [[0, 105, 148], [72, 209, 204], [70, 130, 180], [135, 206, 250], [176, 224, 230]],
|
|
"neon": [[255, 0, 102], [0, 255, 255], [255, 255, 0], [0, 255, 0], [255, 0, 255]],
|
|
"monochrome": [[0, 0, 0], [50, 50, 50], [100, 100, 100], [150, 150, 150], [200, 200, 200]],
|
|
"autumn": [[165, 42, 42], [210, 105, 30], [139, 69, 19], [160, 82, 45], [205, 133, 63]],
|
|
"cyberpunk": [[255, 0, 128], [0, 255, 255], [128, 0, 255], [255, 255, 0], [0, 255, 128]],
|
|
"retro": [[255, 204, 0], [255, 102, 0], [204, 0, 0], [0, 102, 204], [0, 204, 102]]
|
|
},
|
|
"WAVE_VIBES": {
|
|
"calm": {"frequency": 200, "amplitude": 0.3, "modulation": 0.1},
|
|
"eerie": {"frequency": 600, "amplitude": 0.5, "modulation": 0.7},
|
|
"random": {},
|
|
"energetic": {"frequency": 800, "amplitude": 0.7, "modulation": 0.2},
|
|
"dreamy": {"frequency": 400, "amplitude": 0.4, "modulation": 0.5},
|
|
"chaotic": {"frequency": 1000, "amplitude": 1.0, "modulation": 1.0},
|
|
"glitchy": {"frequency": 1200, "amplitude": 0.8, "modulation": 0.9},
|
|
"underwater": {"frequency": 300, "amplitude": 0.6, "modulation": 0.3},
|
|
"mechanical": {"frequency": 500, "amplitude": 0.5, "modulation": 0.1},
|
|
"ethereal": {"frequency": 700, "amplitude": 0.4, "modulation": 0.8},
|
|
"pulsating": {"frequency": 900, "amplitude": 0.7, "modulation": 0.6}
|
|
},
|
|
"WORD_TOPICS": {
|
|
"introspective": ["reflection", "thought", "solitude", "ponder", "meditation", "introspection", "awareness", "contemplation", "silence", "stillness"],
|
|
"action": ["run", "jump", "climb", "race", "fight", "explore", "build", "create", "overcome", "achieve"],
|
|
"nature": ["tree", "mountain", "river", "ocean", "flower", "forest", "animal", "sky", "valley", "meadow"],
|
|
"technology": ["computer", "robot", "network", "data", "algorithm", "innovation", "digital", "machine", "software", "hardware"],
|
|
"space": ["star", "planet", "galaxy", "cosmos", "orbit", "nebula", "asteroid", "comet", "universe", "void"],
|
|
"ocean": ["wave", "coral", "fish", "shark", "seaweed", "tide", "reef", "abyss", "current", "marine"],
|
|
"fantasy": ["dragon", "wizard", "magic", "quest", "sword", "spell", "kingdom", "myth", "legend", "fairy"],
|
|
"science": ["experiment", "theory", "hypothesis", "research", "discovery", "laboratory", "element", "molecule", "atom", "energy"],
|
|
"art": ["canvas", "paint", "sculpture", "gallery", "artist", "creativity", "expression", "masterpiece", "composition", "design"],
|
|
"music": ["melody", "rhythm", "harmony", "song", "instrument", "concert", "symphony", "chord", "note", "beat"],
|
|
"food": ["cuisine", "flavor", "recipe", "ingredient", "taste", "dish", "spice", "dessert", "meal", "delicacy"],
|
|
"emotions": ["joy", "sorrow", "anger", "fear", "love", "hate", "surprise", "disgust", "anticipation", "trust"],
|
|
"colors": ["red", "blue", "green", "yellow", "purple", "orange", "black", "white", "pink", "teal"],
|
|
"abstract": ["concept", "idea", "thought", "theory", "philosophy", "abstraction", "notion", "principle", "essence", "paradigm"]
|
|
}
|
|
}
|
|
|
|
# Create directories if they don't exist
|
|
for directory in ["IMG", "SOUND", "OUTPUT", "FONT"]:
|
|
os.makedirs(directory, exist_ok=True)
|
|
|
|
async def _generate_video_logic(self, ctx_or_interaction, width=None, height=None, max_width=None, max_height=None,
|
|
min_width=None, min_height=None, slides=None, videos=None, min_shapes=None, max_shapes=None,
|
|
sound_quality=None, tts_enabled=None, tts_text=None, tts_provider=None, audio_wave_type=None, slide_duration=None,
|
|
deform_level=None, color_mode=None, color_scheme=None, solid_color=None, allowed_shapes=None,
|
|
wave_vibe=None, top_left_text_enabled=None, top_left_text_mode=None, words_topic=None,
|
|
text_color=None, text_size=None, text_position=None, already_deferred=False):
|
|
"""Core logic for the webdrivertorso command."""
|
|
# Check if already processing a video
|
|
if self.is_processing:
|
|
return "⚠️ Already processing a video. Please wait for the current process to complete."
|
|
|
|
self.is_processing = True
|
|
|
|
try:
|
|
# Start with default config
|
|
config_data = self.DEFAULT_CONFIG.copy()
|
|
|
|
# Override config with parameters if provided
|
|
if width is not None:
|
|
config_data["WIDTH"] = width
|
|
if height is not None:
|
|
config_data["HEIGHT"] = height
|
|
if max_width is not None:
|
|
config_data["MAX_WIDTH"] = max_width
|
|
if max_height is not None:
|
|
config_data["MAX_HEIGHT"] = max_height
|
|
if min_width is not None:
|
|
config_data["MIN_WIDTH"] = min_width
|
|
if min_height is not None:
|
|
config_data["MIN_HEIGHT"] = min_height
|
|
if slides is not None:
|
|
config_data["SLIDES"] = slides
|
|
if videos is not None:
|
|
config_data["VIDEOS"] = videos
|
|
if min_shapes is not None:
|
|
config_data["MIN_SHAPES"] = min_shapes
|
|
if max_shapes is not None:
|
|
config_data["MAX_SHAPES"] = max_shapes
|
|
if sound_quality is not None:
|
|
config_data["SOUND_QUALITY"] = sound_quality
|
|
if tts_enabled is not None:
|
|
config_data["TTS_ENABLED"] = tts_enabled
|
|
if tts_text is not None:
|
|
config_data["TTS_TEXT"] = tts_text
|
|
if tts_enabled is None: # Only set to True if not explicitly set to False
|
|
config_data["TTS_ENABLED"] = True
|
|
if tts_provider is not None:
|
|
config_data["TTS_PROVIDER"] = tts_provider
|
|
if audio_wave_type is not None:
|
|
config_data["AUDIO_WAVE_TYPE"] = audio_wave_type
|
|
if slide_duration is not None:
|
|
config_data["SLIDE_DURATION"] = slide_duration
|
|
if deform_level is not None:
|
|
config_data["DEFORM_LEVEL"] = deform_level
|
|
if color_mode is not None:
|
|
config_data["COLOR_MODE"] = color_mode
|
|
if color_scheme is not None:
|
|
config_data["COLOR_SCHEME"] = color_scheme
|
|
if solid_color is not None:
|
|
config_data["SOLID_COLOR"] = solid_color
|
|
if allowed_shapes is not None:
|
|
config_data["ALLOWED_SHAPES"] = allowed_shapes
|
|
if wave_vibe is not None:
|
|
config_data["WAVE_VIBE"] = wave_vibe
|
|
if top_left_text_enabled is not None:
|
|
config_data["TOP_LEFT_TEXT_ENABLED"] = top_left_text_enabled
|
|
if top_left_text_mode is not None:
|
|
config_data["TOP_LEFT_TEXT_MODE"] = top_left_text_mode
|
|
if words_topic is not None:
|
|
config_data["WORDS_TOPIC"] = words_topic
|
|
if text_color is not None:
|
|
config_data["TEXT_COLOR"] = text_color
|
|
if text_size is not None:
|
|
config_data["TEXT_SIZE"] = text_size
|
|
if text_position is not None:
|
|
config_data["TEXT_POSITION"] = text_position
|
|
|
|
# Clean directories
|
|
for directory in ["IMG", "SOUND"]:
|
|
for file in glob.glob(f'./{directory}/*'):
|
|
try:
|
|
os.remove(file)
|
|
except Exception as e:
|
|
print(f"Error removing file {file}: {e}")
|
|
|
|
# Create a temporary script file
|
|
script_path = os.path.join(tempfile.gettempdir(), "webdrivertorso_temp.py")
|
|
|
|
# Use our enhanced template instead of EXAMPLE.py
|
|
if os.path.exists("webdrivertorso_template.py"):
|
|
with open("webdrivertorso_template.py", "r", encoding="utf8") as f:
|
|
script_content = f.read()
|
|
else:
|
|
with open("EXAMPLE.py", "r", encoding="utf8") as f:
|
|
script_content = f.read()
|
|
|
|
# Create a temporary config file for this run only
|
|
temp_config_path = os.path.join(tempfile.gettempdir(), "webdrivertorso_temp_config.json")
|
|
with open(temp_config_path, "w", encoding="utf8") as f:
|
|
json.dump(config_data, f, indent=4)
|
|
|
|
# Replace the config file path in the script content
|
|
script_content = script_content.replace('config_data = JSON.read("config")', f'config_data = JSON.read("{os.path.splitext(temp_config_path)[0]}")')
|
|
|
|
with open(script_path, "w", encoding="utf8") as f:
|
|
f.write(script_content)
|
|
|
|
# Send initial message
|
|
if isinstance(ctx_or_interaction, commands.Context):
|
|
await ctx_or_interaction.reply("🎬 Generating Webdriver Torso style video... This may take a minute.")
|
|
elif not already_deferred: # It's an Interaction and not deferred yet
|
|
await ctx_or_interaction.response.defer(thinking=True)
|
|
|
|
# Run the script as a subprocess
|
|
process = await asyncio.create_subprocess_exec(
|
|
sys.executable, script_path,
|
|
stdout=asyncio.subprocess.PIPE,
|
|
stderr=asyncio.subprocess.PIPE
|
|
)
|
|
|
|
# Wait for the process to complete
|
|
_, stderr = await process.communicate()
|
|
|
|
# Check if the process was successful
|
|
if process.returncode != 0:
|
|
error_msg = stderr.decode() if stderr else "Unknown error"
|
|
return f"❌ Error generating video: {error_msg}"
|
|
|
|
# Find the generated video file
|
|
video_files = glob.glob('./OUTPUT/*.mp4')
|
|
if not video_files:
|
|
return "❌ No video files were generated."
|
|
|
|
# Get the most recent video file
|
|
video_file = max(video_files, key=os.path.getctime)
|
|
|
|
# Send the video file
|
|
if isinstance(ctx_or_interaction, commands.Context):
|
|
await ctx_or_interaction.reply(file=discord.File(video_file))
|
|
else: # It's an Interaction
|
|
await ctx_or_interaction.followup.send(file=discord.File(video_file))
|
|
|
|
return f"✅ Video generated successfully: {os.path.basename(video_file)}"
|
|
|
|
except Exception as e:
|
|
return f"❌ An error occurred: {str(e)}"
|
|
finally:
|
|
self.is_processing = False
|
|
|
|
# --- Prefix Command ---
|
|
@commands.command(name="webdrivertorso")
|
|
async def webdrivertorso(self, ctx, *, options: str = ""):
|
|
"""Generate a Webdriver Torso style test video.
|
|
|
|
Usage: !webdrivertorso [option1=value1] [option2=value2] ...
|
|
|
|
Available options:
|
|
# Individual parameters (original method):
|
|
- width: Video width in pixels (default: 640)
|
|
- height: Video height in pixels (default: 480)
|
|
- max_width: Maximum shape width (default: 200)
|
|
- max_height: Maximum shape height (default: 200)
|
|
- min_width: Minimum shape width (default: 20)
|
|
- min_height: Minimum shape height (default: 20)
|
|
- min_shapes: Minimum number of shapes per slide (default: 5)
|
|
- max_shapes: Maximum number of shapes per slide (default: 15)
|
|
|
|
# Combined parameters (alternative method):
|
|
- dimensions: Video dimensions in format 'width,height' (e.g., '640,480')
|
|
- shape_size_limits: Shape size limits in format 'min_width,min_height,max_width,max_height' (e.g., '20,20,200,200')
|
|
- shapes_count: Number of shapes per slide in format 'min,max' (e.g., '5,15')
|
|
|
|
# Other parameters:
|
|
- slides: Number of slides in the video (default: 10)
|
|
- videos: Number of videos to generate (default: 1)
|
|
- sound_quality: Audio sample rate (default: 44100)
|
|
- tts_enabled: Enable text-to-speech (true/false)
|
|
- tts_provider: TTS provider to use (gtts, pyttsx3, coqui)
|
|
- tts_text: Text to be spoken in the video
|
|
- audio_wave_type: Type of audio wave (sawtooth, sine, square, triangle, noise, pulse, harmonic)
|
|
- slide_duration: Duration of each slide in milliseconds (default: 1000)
|
|
- deform_level: Level of shape deformation (none, low, medium, high)
|
|
- color_mode: Color mode for shapes (random, scheme, solid)
|
|
- color_scheme: Color scheme to use (pastel, dark_gritty, nature, vibrant, ocean, neon, monochrome, autumn, cyberpunk, retro)
|
|
- solid_color: Hex color code for solid color mode (#RRGGBB)
|
|
- wave_vibe: Audio wave vibe (calm, eerie, random, energetic, dreamy, chaotic, glitchy, underwater, mechanical, ethereal, pulsating)
|
|
- top_left_text_enabled: Show text in top-left corner (true/false)
|
|
- top_left_text_mode: Mode for top-left text (random, word)
|
|
- words_topic: Topic for word generation (random, introspective, action, nature, technology, space, ocean, fantasy, science, art, music, food, emotions, colors, abstract)
|
|
- text_color: Color of text (hex code or name)
|
|
- text_size: Size of text (default: auto-scaled)
|
|
- text_position: Position of text (top-left, top-right, bottom-left, bottom-right, center, random)
|
|
"""
|
|
# Parse options from the string
|
|
params = {}
|
|
if options:
|
|
option_pairs = options.split()
|
|
for pair in option_pairs:
|
|
if '=' in pair:
|
|
key, value = pair.split('=', 1)
|
|
# Convert string values to appropriate types
|
|
if value.lower() == 'true':
|
|
params[key] = True
|
|
elif value.lower() == 'false':
|
|
params[key] = False
|
|
elif value.isdigit():
|
|
params[key] = int(value)
|
|
elif key == 'allowed_shapes' and value.startswith('[') and value.endswith(']'):
|
|
# Parse list of shapes
|
|
shapes_list = value[1:-1].split(',')
|
|
params[key] = [shape.strip() for shape in shapes_list]
|
|
# Handle combined parameters
|
|
elif key == 'dimensions' and ',' in value:
|
|
width, height = value.split(',', 1)
|
|
if width.strip().isdigit():
|
|
params['width'] = int(width.strip())
|
|
if height.strip().isdigit():
|
|
params['height'] = int(height.strip())
|
|
elif key == 'shape_size_limits' and ',' in value:
|
|
parts = value.split(',')
|
|
if len(parts) >= 1 and parts[0].strip().isdigit():
|
|
params['min_width'] = int(parts[0].strip())
|
|
if len(parts) >= 2 and parts[1].strip().isdigit():
|
|
params['min_height'] = int(parts[1].strip())
|
|
if len(parts) >= 3 and parts[2].strip().isdigit():
|
|
params['max_width'] = int(parts[2].strip())
|
|
if len(parts) >= 4 and parts[3].strip().isdigit():
|
|
params['max_height'] = int(parts[3].strip())
|
|
elif key == 'shapes_count' and ',' in value:
|
|
min_shapes, max_shapes = value.split(',', 1)
|
|
if min_shapes.strip().isdigit():
|
|
params['min_shapes'] = int(min_shapes.strip())
|
|
if max_shapes.strip().isdigit():
|
|
params['max_shapes'] = int(max_shapes.strip())
|
|
else:
|
|
params[key] = value
|
|
|
|
async with ctx.typing():
|
|
result = await self._generate_video_logic(ctx, **params)
|
|
|
|
if isinstance(result, str):
|
|
await ctx.reply(result)
|
|
|
|
# --- Slash Command ---
|
|
@app_commands.command(name="webdrivertorso", description="Generate a Webdriver Torso style test video")
|
|
@app_commands.describe(
|
|
# Video structure
|
|
slides="Number of slides in the video (default: 10)",
|
|
videos="Number of videos to generate (default: 1)",
|
|
slide_duration="Duration of each slide in milliseconds (default: 1000)",
|
|
|
|
# Video dimensions
|
|
dimensions="Video dimensions in format 'width,height' (default: '640,480')",
|
|
shape_size_limits="Shape size limits in format 'min_width,min_height,max_width,max_height' (default: '20,20,200,200')",
|
|
|
|
# Shapes
|
|
shapes_count="Number of shapes per slide in format 'min,max' (default: '5,15')",
|
|
deform_level="Level of shape deformation (none, low, medium, high)",
|
|
shape_types="Types of shapes to include (comma-separated list)",
|
|
|
|
# Colors
|
|
color_mode="Color mode for shapes (random, scheme, solid)",
|
|
color_scheme="Color scheme to use (pastel, dark_gritty, nature, vibrant, ocean)",
|
|
solid_color="Hex color code for solid color mode (#RRGGBB)",
|
|
|
|
# Audio
|
|
sound_quality="Audio sample rate (default: 44100)",
|
|
audio_wave_type="Type of audio wave (sawtooth, sine, square)",
|
|
wave_vibe="Audio wave vibe (calm, eerie, random, energetic, dreamy, chaotic)",
|
|
tts_enabled="Enable text-to-speech (default: false)",
|
|
tts_provider="TTS provider to use (gtts, pyttsx3, coqui)",
|
|
tts_text="Text to be spoken in the video",
|
|
|
|
# Text
|
|
top_left_text_enabled="Show text in top-left corner (default: true)",
|
|
top_left_text_mode="Mode for top-left text (random, word)",
|
|
words_topic="Topic for word generation (random, introspective, action, nature, technology, etc.)",
|
|
text_color="Color of text (hex code or name)",
|
|
text_size="Size of text (default: auto-scaled)",
|
|
text_position="Position of text (top-left, top-right, bottom-left, bottom-right, center)"
|
|
)
|
|
@app_commands.choices(deform_level=[
|
|
app_commands.Choice(name="None", value="none"),
|
|
app_commands.Choice(name="Low", value="low"),
|
|
app_commands.Choice(name="Medium", value="medium"),
|
|
app_commands.Choice(name="High", value="high")
|
|
])
|
|
@app_commands.choices(color_mode=[
|
|
app_commands.Choice(name="Random", value="random"),
|
|
app_commands.Choice(name="Color Scheme", value="scheme"),
|
|
app_commands.Choice(name="Solid Color", value="solid")
|
|
])
|
|
@app_commands.choices(color_scheme=[
|
|
app_commands.Choice(name="Pastel", value="pastel"),
|
|
app_commands.Choice(name="Dark Gritty", value="dark_gritty"),
|
|
app_commands.Choice(name="Nature", value="nature"),
|
|
app_commands.Choice(name="Vibrant", value="vibrant"),
|
|
app_commands.Choice(name="Ocean", value="ocean"),
|
|
# Additional color schemes
|
|
app_commands.Choice(name="Neon", value="neon"),
|
|
app_commands.Choice(name="Monochrome", value="monochrome"),
|
|
app_commands.Choice(name="Autumn", value="autumn"),
|
|
app_commands.Choice(name="Cyberpunk", value="cyberpunk"),
|
|
app_commands.Choice(name="Retro", value="retro")
|
|
])
|
|
@app_commands.choices(audio_wave_type=[
|
|
app_commands.Choice(name="Sawtooth", value="sawtooth"),
|
|
app_commands.Choice(name="Sine", value="sine"),
|
|
app_commands.Choice(name="Square", value="square"),
|
|
# Additional wave types
|
|
app_commands.Choice(name="Triangle", value="triangle"),
|
|
app_commands.Choice(name="Noise", value="noise"),
|
|
app_commands.Choice(name="Pulse", value="pulse"),
|
|
app_commands.Choice(name="Harmonic", value="harmonic")
|
|
])
|
|
@app_commands.choices(tts_provider=[
|
|
app_commands.Choice(name="Google TTS", value="gtts"),
|
|
app_commands.Choice(name="pyttsx3 (Offline TTS)", value="pyttsx3"),
|
|
app_commands.Choice(name="Coqui TTS (AI Voice)", value="coqui")
|
|
])
|
|
@app_commands.choices(wave_vibe=[
|
|
app_commands.Choice(name="Calm", value="calm"),
|
|
app_commands.Choice(name="Eerie", value="eerie"),
|
|
app_commands.Choice(name="Random", value="random"),
|
|
app_commands.Choice(name="Energetic", value="energetic"),
|
|
app_commands.Choice(name="Dreamy", value="dreamy"),
|
|
app_commands.Choice(name="Chaotic", value="chaotic"),
|
|
# Additional wave vibes
|
|
app_commands.Choice(name="Glitchy", value="glitchy"),
|
|
app_commands.Choice(name="Underwater", value="underwater"),
|
|
app_commands.Choice(name="Mechanical", value="mechanical"),
|
|
app_commands.Choice(name="Ethereal", value="ethereal"),
|
|
app_commands.Choice(name="Pulsating", value="pulsating")
|
|
])
|
|
@app_commands.choices(top_left_text_mode=[
|
|
app_commands.Choice(name="Random", value="random"),
|
|
app_commands.Choice(name="Word", value="word")
|
|
])
|
|
@app_commands.choices(words_topic=[
|
|
app_commands.Choice(name="Random", value="random"),
|
|
app_commands.Choice(name="Introspective", value="introspective"),
|
|
app_commands.Choice(name="Action", value="action"),
|
|
app_commands.Choice(name="Nature", value="nature"),
|
|
app_commands.Choice(name="Technology", value="technology"),
|
|
# Additional word topics
|
|
app_commands.Choice(name="Space", value="space"),
|
|
app_commands.Choice(name="Ocean", value="ocean"),
|
|
app_commands.Choice(name="Fantasy", value="fantasy"),
|
|
app_commands.Choice(name="Science", value="science"),
|
|
app_commands.Choice(name="Art", value="art"),
|
|
app_commands.Choice(name="Music", value="music"),
|
|
app_commands.Choice(name="Food", value="food"),
|
|
app_commands.Choice(name="Emotions", value="emotions"),
|
|
app_commands.Choice(name="Colors", value="colors"),
|
|
app_commands.Choice(name="Abstract", value="abstract")
|
|
])
|
|
@app_commands.choices(text_position=[
|
|
app_commands.Choice(name="Top Left", value="top-left"),
|
|
app_commands.Choice(name="Top Right", value="top-right"),
|
|
app_commands.Choice(name="Bottom Left", value="bottom-left"),
|
|
app_commands.Choice(name="Bottom Right", value="bottom-right"),
|
|
app_commands.Choice(name="Center", value="center"),
|
|
app_commands.Choice(name="Random", value="random")
|
|
])
|
|
async def webdrivertorso_slash(self, interaction: discord.Interaction,
|
|
# Video structure
|
|
slides: int = None,
|
|
videos: int = None,
|
|
slide_duration: int = None,
|
|
|
|
# Video dimensions
|
|
dimensions: str = None,
|
|
shape_size_limits: str = None,
|
|
|
|
# Shapes
|
|
shapes_count: str = None,
|
|
deform_level: str = None,
|
|
shape_types: str = None,
|
|
|
|
# Colors
|
|
color_mode: str = None,
|
|
color_scheme: str = None,
|
|
solid_color: str = None,
|
|
|
|
# Audio
|
|
sound_quality: int = None,
|
|
audio_wave_type: str = None,
|
|
wave_vibe: str = None,
|
|
tts_enabled: bool = None,
|
|
tts_provider: str = None,
|
|
tts_text: str = None,
|
|
|
|
# Text
|
|
top_left_text_enabled: bool = None,
|
|
top_left_text_mode: str = None,
|
|
words_topic: str = None,
|
|
text_color: str = None,
|
|
text_size: int = None,
|
|
text_position: str = None):
|
|
"""Slash command version of webdrivertorso."""
|
|
await interaction.response.defer(thinking=True)
|
|
result = await self._generate_video_logic(
|
|
interaction,
|
|
# Video structure
|
|
slides=slides,
|
|
videos=videos,
|
|
slide_duration=slide_duration,
|
|
|
|
# Video dimensions
|
|
width=int(dimensions.split(',')[0]) if dimensions else None,
|
|
height=int(dimensions.split(',')[1]) if dimensions and ',' in dimensions else None,
|
|
min_width=int(shape_size_limits.split(',')[0]) if shape_size_limits else None,
|
|
min_height=int(shape_size_limits.split(',')[1]) if shape_size_limits and len(shape_size_limits.split(',')) > 1 else None,
|
|
max_width=int(shape_size_limits.split(',')[2]) if shape_size_limits and len(shape_size_limits.split(',')) > 2 else None,
|
|
max_height=int(shape_size_limits.split(',')[3]) if shape_size_limits and len(shape_size_limits.split(',')) > 3 else None,
|
|
|
|
# Shapes
|
|
min_shapes=int(shapes_count.split(',')[0]) if shapes_count else None,
|
|
max_shapes=int(shapes_count.split(',')[1]) if shapes_count and ',' in shapes_count else None,
|
|
deform_level=deform_level,
|
|
allowed_shapes=shape_types.split(',') if shape_types else None,
|
|
|
|
# Colors
|
|
color_mode=color_mode,
|
|
color_scheme=color_scheme,
|
|
solid_color=solid_color,
|
|
|
|
# Audio
|
|
sound_quality=sound_quality,
|
|
audio_wave_type=audio_wave_type,
|
|
wave_vibe=wave_vibe,
|
|
tts_enabled=tts_enabled,
|
|
tts_provider=tts_provider,
|
|
tts_text=tts_text,
|
|
|
|
# Text
|
|
top_left_text_enabled=top_left_text_enabled,
|
|
top_left_text_mode=top_left_text_mode,
|
|
words_topic=words_topic,
|
|
text_color=text_color,
|
|
text_size=text_size,
|
|
text_position=text_position,
|
|
|
|
already_deferred=True
|
|
)
|
|
|
|
if isinstance(result, str):
|
|
await interaction.followup.send(result)
|
|
|
|
async def setup(bot: commands.Bot):
|
|
await bot.add_cog(WebdriverTorsoCog(bot))
|