diff --git a/cogs/ffmpeg_things.py b/cogs/ffmpeg_things.py new file mode 100644 index 0000000..feae126 --- /dev/null +++ b/cogs/ffmpeg_things.py @@ -0,0 +1,133 @@ +import os +import asyncio +import tempfile +import discord +from discord.ext import commands + +class FfmpegThings(commands.Cog): + def __init__(self, bot): + self.bot = bot + + #this command lists all the ffmpeg commands, not an actualy ffmpeg command## + @commands.command() + async def ffmpeg(self, ctx): + ffmpeg_commands = [f'!{cmd.name}' for cmd in self.get_commands()] + await ctx.reply('\n'.join(ffmpeg_commands)) + ###################################################################### + + async def _download_attachment(self, attachment): + suffix = os.path.splitext(attachment.filename)[1] or '.dat' + with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as tmp: + await attachment.save(tmp.name) + return tmp.name, attachment.filename + + async def _run_ffmpeg(self, args): + proc = await asyncio.create_subprocess_exec( + 'ffmpeg', + *args, + stdout=asyncio.subprocess.DEVNULL, + stderr=asyncio.subprocess.PIPE, + ) + _, stderr = await proc.communicate() + return proc.returncode, stderr.decode() + + async def _process_and_send(self, ctx, ffmpeg_args, temp_in, temp_out): + ret, err = await self._run_ffmpeg(ffmpeg_args) + if ret != 0: + await ctx.reply(f'ffmpeg failed:\n```\n{err}\n```') + if os.path.exists(temp_in): + os.remove(temp_in) + return + + if os.path.getsize(temp_out) > 8 * 1024 * 1024: + await ctx.reply('resulting gif is larger than 8mb.') + os.remove(temp_in) + os.remove(temp_out) + return + + await ctx.send(file=discord.File(temp_out)) + os.remove(temp_in) + os.remove(temp_out) + + @commands.command() + async def togif(self, ctx): + if not ctx.message.attachments: + return await ctx.reply('you need to attach a video file.') + + temp_in, _ = await self._download_attachment(ctx.message.attachments[0]) + temp_out = temp_in + '.gif' + + ffmpeg_args = [ + '-y', + '-i', temp_in, + '-filter_complex', + 'fps=15,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse', + '-loop', '0', + temp_out, + ] + await self._process_and_send(ctx, ffmpeg_args, temp_in, temp_out) + + @commands.command() + async def caption(self, ctx, *, text: str): + if not ctx.message.attachments: + return await ctx.reply('attach an image or gif to caption.') + + temp_in, _ = await self._download_attachment(ctx.message.attachments[0]) + temp_out = temp_in + '_cap.gif' + + drawtext = ( + f"drawtext=font=Impact:text='{text}':fontcolor=white:fontsize=48:" + "box=1:boxcolor=black@0.6:boxborderw=5:x=(w-text_w)/2:y=10" + ) + + ffmpeg_args = [ + '-y', + '-i', temp_in, + '-filter_complex', + f'{drawtext},fps=15,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse', + '-loop', '0', + temp_out, + ] + await self._process_and_send(ctx, ffmpeg_args, temp_in, temp_out) + + @commands.command() + async def reverse(self, ctx): + if not ctx.message.attachments: + return await ctx.reply('attach a gif or video to reverse.') + + temp_in, _ = await self._download_attachment(ctx.message.attachments[0]) + temp_out = temp_in + '_rev.gif' + + ffmpeg_args = [ + '-y', + '-i', temp_in, + '-filter_complex', + 'reverse,fps=15,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse', + '-loop', '0', + temp_out, + ] + await self._process_and_send(ctx, ffmpeg_args, temp_in, temp_out) + + @commands.command() + async def speed(self, ctx, multiplier: float): + if not ctx.message.attachments: + return await ctx.reply('attach a gif or video to adjust speed.') + + if multiplier <= 0: + return await ctx.reply('multiplier must be positive.') + + temp_in, _ = await self._download_attachment(ctx.message.attachments[0]) + temp_out = temp_in + '_spd.gif' + + ffmpeg_args = [ + '-y', + '-i', temp_in, + '-filter_complex', + f'setpts=PTS*{1/ multiplier},fps=15,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse', + '-loop', '0', + temp_out, + ] + await self._process_and_send(ctx, ffmpeg_args, temp_in, temp_out) + +async def setup(bot): + await bot.add_cog(FfmpegThings(bot)) diff --git a/main.py b/main.py index b98c4c6..9fc0bab 100644 --- a/main.py +++ b/main.py @@ -41,6 +41,7 @@ async def main(): await bot.load_extension('cogs.sysinfo') await bot.load_extension('music.music') await bot.load_extension('cogs.statchannel') + await bot.load_extension('cogs.ffmpeg_things') try: await bot.start(os.getenv('DISCORD_TOKEN'))