4 Commits

Author SHA1 Message Date
neoarz
a3efe4776c fix: interactive sounds wierd 😭 2025-11-22 14:42:21 -05:00
neoarz
3b2ca697e0 feat: finish cellos command 2025-11-22 14:40:48 -05:00
neoarz
50243773ec fix: image link 2025-11-22 14:25:21 -05:00
neoarz
6dec097a20 initial commit 2025-11-22 14:18:35 -05:00
66 changed files with 754 additions and 144 deletions

View File

@@ -33,7 +33,7 @@
| events | `baitbot` | | events | `baitbot` |
| miscellaneous | `keanu`, `labubu`, `piracy`, `tryitandsee`, `rickroll`, `dontasktoask`, `support`, `depart`, `docs` `sigma`, `duck`, `silly`, `color` | | miscellaneous | `keanu`, `labubu`, `piracy`, `tryitandsee`, `rickroll`, `dontasktoask`, `support`, `depart`, `docs` `sigma`, `duck`, `silly`, `color` |
| utilities | `translate`, `codepreview`, `dictionary` | | utilities | `translate`, `codepreview`, `dictionary` |
| media | `mcquote`, `img2gif`, `tweety`, `tts` | | media | `download`, `mcquote`, `img2gif`, `tweety`, `tts` |
## Download ## Download

2
bot.py
View File

@@ -282,4 +282,4 @@ if __name__ == "__main__":
except KeyboardInterrupt: except KeyboardInterrupt:
logger.info("Received keyboard interrupt") logger.info("Received keyboard interrupt")
except Exception as e: except Exception as e:
logger.critical(f"Fatal error during bot execution: {type(e).__name__}: {e}") logger.critical(f"Fatal error during bot execution: {type(e).__name__}: {e}")

View File

@@ -4,6 +4,7 @@ from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context from discord.ext.commands import Context
from datetime import datetime from datetime import datetime
import time
import pytz import pytz
from utils.contributors import generate_contributors_image from utils.contributors import generate_contributors_image

View File

@@ -35,3 +35,5 @@ class MentionListener(commands.Cog):
self.bot.logger.debug( self.bot.logger.debug(
f"Failed to react with fallback emoji: {fallback_error}" f"Failed to react with fallback emoji: {fallback_error}"
) )

View File

@@ -1,4 +1,5 @@
import random import random
from itertools import repeat
import discord import discord
from discord.ext import commands from discord.ext import commands
import asyncio import asyncio
@@ -61,21 +62,21 @@ class RowButton(discord.ui.Button):
def checkpos(count, rawpos, pos): def checkpos(count, rawpos, pos):
pos = view.GetBoardPos(rawpos) pos = view.GetBoardPos(rawpos)
if rawpos - 1 not in self.bombs or pos == 0: if not rawpos - 1 in self.bombs or pos == 0:
count.append(rawpos - 1) count.append(rawpos - 1)
if rawpos + 1 not in self.bombs or pos == 4: if not rawpos + 1 in self.bombs or pos == 4:
count.append(rawpos + 1) count.append(rawpos + 1)
if rawpos - 6 not in self.bombs or pos == 0: if not rawpos - 6 in self.bombs or pos == 0:
count.append(rawpos - 6) count.append(rawpos - 6)
if rawpos - 4 not in self.bombs or pos == 4: if not rawpos - 4 in self.bombs or pos == 4:
count.append(rawpos - 4) count.append(rawpos - 4)
if rawpos + 6 not in self.bombs or pos == 4: if not rawpos + 6 in self.bombs or pos == 4:
count.append(rawpos + 6) count.append(rawpos + 6)
if rawpos + 4 not in self.bombs or pos == 0: if not rawpos + 4 in self.bombs or pos == 0:
count.append(rawpos + 4) count.append(rawpos + 4)
if rawpos - 5 not in self.bombs: if not rawpos - 5 in self.bombs:
count.append(rawpos - 5) count.append(rawpos - 5)
if rawpos + 5 not in self.bombs: if not rawpos + 5 in self.bombs:
count.append(rawpos + 5) count.append(rawpos + 5)
return count return count

View File

@@ -1,3 +1,4 @@
import aiohttp
import discord import discord
from discord.ext import commands from discord.ext import commands

View File

@@ -1,8 +1,9 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
class FeedbackForm(discord.ui.Modal, title="Feedback"): class FeedbackForm(discord.ui.Modal, title="Feeedback"):
feedback = discord.ui.TextInput( feedback = discord.ui.TextInput(
label="What do you think about this bot?", label="What do you think about this bot?",
style=discord.TextStyle.long, style=discord.TextStyle.long,

View File

@@ -2,8 +2,10 @@ import discord
from discord.ext import commands from discord.ext import commands
from discord import app_commands from discord import app_commands
import aiohttp import aiohttp
import asyncio
from io import BytesIO from io import BytesIO
from PIL import Image from PIL import Image
import re
from datetime import datetime, timezone from datetime import datetime, timezone
ONE_MONTH = 2628000 ONE_MONTH = 2628000

View File

@@ -31,9 +31,7 @@ class Idevice(commands.GroupCog, name="idevice"):
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
@idevice_group.command(name="errorcodes") @idevice_group.command(name="errorcodes")
async def idevice_group_errorcodes( async def idevice_group_errorcodes(self, context: Context, *, error_code: str = None):
self, context: Context, *, error_code: str = None
):
await self._invoke_hybrid(context, "errorcodes", error_code=error_code) await self._invoke_hybrid(context, "errorcodes", error_code=error_code)
@idevice_group.command(name="developermode") @idevice_group.command(name="developermode")

View File

@@ -1,5 +1,8 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import time
def developermode_command(): def developermode_command():
@@ -21,7 +24,7 @@ def developermode_command():
embed.set_author( embed.set_author(
name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png" name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
) )
embed.set_footer(text="Last Edited by neoarz") embed.set_footer(text=f"Last Edited by neoarz")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()

BIN
cogs/idevice/files/DDI.zip Normal file

Binary file not shown.

View File

@@ -328,10 +328,5 @@
"name": "malformed_package_archive", "name": "malformed_package_archive",
"description": "malformed package archive", "description": "malformed package archive",
"code": -67 "code": -67
},
{
"name": "developer_mode_not_enabled",
"description": "Developer mode is not enabled",
"code": -68
} }
] ]

View File

@@ -1,5 +1,7 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import json import json
import os import os
import math import math

View File

@@ -1,9 +1,8 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import os import os
import aiohttp
import shutil
import tempfile
def mountddi_command(): def mountddi_command():
@commands.hybrid_command(name="mountddi", description="How to manually mount DDI") @commands.hybrid_command(name="mountddi", description="How to manually mount DDI")
@@ -13,27 +12,23 @@ def mountddi_command():
embed = discord.Embed( embed = discord.Embed(
color=0xFA8C4A, color=0xFA8C4A,
description=( description=(
"# How to Mount your DDI (Developer Disk Image):\n\n---\n\n" "# How to Manually Mount DDI\n\n---\n\n"
"1. Ensure you are connected to StikDebug's VPN and Wi-Fi.*\n"
"2. Force close StikDebug from the app switcher, then repon it.\n"
"## This should resolve your error! Remember, this must be done every time you restart your device.\n"
"If it doesn't work after a couple tries or you live in a country where github.com is blocked, try the steps below to manually mount the DDI:*\n"
"1. **Download the DDI.zip file attached above:**\n" "1. **Download the DDI.zip file attached above:**\n"
" - Save it to your device and extract the contents\n\n" " - Save it to your device and extract the contents\n\n"
"2. **Replace the DDI folder in StikDebug:**\n" "2. **Replace the DDI folder in StikDebug:**\n"
" - Navigate to the StikDebug default directory on your iPhone/iPad\n" " - Navigate to the StikDebug default directory on your iPhone/iPad\n"
" - Delete the existing DDI folder completely\n" " - Delete the existing DDI folder completely\n"
" - Replace it with the DDI folder from uncompressing the downloaded zip\n" " - Replace it with the DDI folder from the downloaded zip\n"
" - Make sure it's in StikDebug's default directory\n\n" " - Make sure it's in the StikDebug default directory\n\n"
"3. **Restart and retry:**\n" "3. **Restart and retry:**\n"
" - Completely restart StikDebug\n" " - Completely restart StikDebug\n"
" - If you still get the same error, ask the idevice server for more help\n\n" " - See if you get the same error again\n\n"
), ),
) )
embed.set_author( embed.set_author(
name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png" name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
) )
embed.set_footer(text="Last Edited by CelloSerenity") embed.set_footer(text="Last Edited by neoarz")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
@@ -46,43 +41,16 @@ def mountddi_command():
) )
) )
temp_dir = tempfile.mkdtemp() ddi_file_path = os.path.join(os.path.dirname(__file__), "files/DDI.zip")
try: file = (
ddi_dir = os.path.join(temp_dir, "DDI") discord.File(ddi_file_path, filename="DDI.zip")
os.makedirs(ddi_dir) if os.path.exists(ddi_file_path)
else None
base_url = "https://raw.githubusercontent.com/doronz88/DeveloperDiskImage/main/PersonalizedImages/Xcode_iOS_DDI_Personalized" )
files = ["BuildManifest.plist", "Image.dmg", "Image.dmg.trustcache"]
if file:
async with aiohttp.ClientSession() as session: await context.send(embed=embed, view=view, file=file)
for filename in files: else:
file_url = f"{base_url}/{filename}" await context.send(embed=embed, view=view)
async with session.get(file_url) as response:
if response.status != 200:
await context.send(f"Error: Failed to download {filename} (Status: {response.status})")
return
file_path = os.path.join(ddi_dir, filename)
with open(file_path, "wb") as f:
while True:
chunk = await response.content.read(8192)
if not chunk:
break
f.write(chunk)
zip_base_name = os.path.join(temp_dir, "DDI")
shutil.make_archive(zip_base_name, 'zip', root_dir=temp_dir, base_dir="DDI")
zip_file_path = zip_base_name + ".zip"
if os.path.exists(zip_file_path):
await context.send(embed=embed, view=view, file=discord.File(zip_file_path, filename="DDI.zip"))
else:
await context.send("Error: Failed to create zip file.", embed=embed, view=view)
except Exception as e:
await context.send(f"An error occurred: {e}")
finally:
shutil.rmtree(temp_dir)
return mountddi return mountddi

View File

@@ -1,5 +1,8 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import time
def noapps_command(): def noapps_command():
@@ -23,7 +26,7 @@ def noapps_command():
embed.set_author( embed.set_author(
name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png" name="idevice", icon_url="https://yes.nighty.works/raw/snLMuO.png"
) )
embed.set_footer(text="Last Edited by neoarz") embed.set_footer(text=f"Last Edited by neoarz")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()

View File

@@ -22,8 +22,7 @@ class Livecontainer(commands.GroupCog, name="livecontainer"):
color=0x0169FF, color=0x0169FF,
) )
embed.set_author( embed.set_author(
name="LiveContainer", name="LiveContainer", icon_url="https://raw.githubusercontent.com/LiveContainer/LiveContainer/main/screenshots/livecontainer_icon.png"
icon_url="https://raw.githubusercontent.com/LiveContainer/LiveContainer/main/screenshots/livecontainer_icon.png",
) )
view = LivecontainerView(self.bot) view = LivecontainerView(self.bot)
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
@@ -36,8 +35,7 @@ class Livecontainer(commands.GroupCog, name="livecontainer"):
color=0x0169FF, color=0x0169FF,
) )
embed.set_author( embed.set_author(
name="LiveContainer", name="LiveContainer", icon_url="https://raw.githubusercontent.com/LiveContainer/LiveContainer/main/screenshots/livecontainer_icon.png"
icon_url="https://raw.githubusercontent.com/LiveContainer/LiveContainer/main/screenshots/livecontainer_icon.png",
) )
view = LivecontainerView(self.bot) view = LivecontainerView(self.bot)
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
@@ -71,8 +69,7 @@ class Livecontainer(commands.GroupCog, name="livecontainer"):
color=0x0169FF, color=0x0169FF,
) )
embed.set_author( embed.set_author(
name="LiveContainer", name="LiveContainer", icon_url="https://raw.githubusercontent.com/LiveContainer/LiveContainer/main/screenshots/livecontainer_icon.png"
icon_url="https://raw.githubusercontent.com/LiveContainer/LiveContainer/main/screenshots/livecontainer_icon.png",
) )
view = LivecontainerView(self.bot) view = LivecontainerView(self.bot)
await interaction.response.send_message(embed=embed, view=view, ephemeral=True) await interaction.response.send_message(embed=embed, view=view, ephemeral=True)
@@ -91,3 +88,4 @@ async def setup(bot) -> None:
bot.logger.info("Loaded extension 'livecontainer.help'") bot.logger.info("Loaded extension 'livecontainer.help'")
bot.logger.info("Loaded extension 'livecontainer.26jit'") bot.logger.info("Loaded extension 'livecontainer.26jit'")

View File

@@ -8,28 +8,17 @@ def jit26_command():
color=0x0169FF, color=0x0169FF,
description=( description=(
"# iOS 26 JIT & Sideloading Walkthrough\n\n---\n\n" "# iOS 26 JIT & Sideloading Walkthrough\n\n---\n\n"
"Click the [button below](https://github.com/CelloSerenity/iOS-26-Sideloading-and-JIT-Complete-Walkthrough) to set up sideloading and enabling JIT for LiveContainer on iOS 26." "Click the [button below](https://github.com/CelloSerenity/iOS-26-Sideloading-and-JIT-Complete-Walkthrough) to get started with iOS 26 JIT and sideloading."
), ),
) )
embed.set_author( embed.set_author(
name="LiveContainer", name="LiveContainer", icon_url="https://raw.githubusercontent.com/LiveContainer/LiveContainer/main/screenshots/livecontainer_icon.png"
icon_url="https://raw.githubusercontent.com/LiveContainer/LiveContainer/main/screenshots/livecontainer_icon.png",
) )
embed.set_footer( embed.set_footer(icon_url="https://yes.nighty.works/raw/2PPWd3.webp", text="Made By CelloSerenity")
icon_url="https://yes.nighty.works/raw/2PPWd3.webp",
text="Made By CelloSerenity",
)
view = discord.ui.View() view = discord.ui.View()
view.add_item( view.add_item(discord.ui.Button(label="Get Started", url="https://github.com/CelloSerenity/iOS-26-Sideloading-and-JIT-Complete-Walkthrough", style=discord.ButtonStyle.primary, emoji="<:githubicon:1417717356846776340>"))
discord.ui.Button(
label="Get Started",
url="https://github.com/CelloSerenity/iOS-26-Sideloading-and-JIT-Complete-Walkthrough",
style=discord.ButtonStyle.primary,
emoji="<:githubicon:1417717356846776340>",
)
)
if context.interaction: if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view) await context.interaction.response.send_message(embed=embed, view=view)
else: else:

View File

@@ -11,9 +11,7 @@ class LivecontainerSelect(discord.ui.Select):
description="Walkthrough for iOS 26 JIT and sideloading", description="Walkthrough for iOS 26 JIT and sideloading",
), ),
] ]
super().__init__( super().__init__(placeholder="Choose a LiveContainer command...", options=options)
placeholder="Choose a LiveContainer command...", options=options
)
async def callback(self, interaction: discord.Interaction): async def callback(self, interaction: discord.Interaction):
command_name = self.values[0] command_name = self.values[0]

View File

@@ -4,6 +4,7 @@ from discord.ext import commands
from discord.ext.commands import Context from discord.ext.commands import Context
from typing import Optional from typing import Optional
from .download import download_command
from .mcquote import mcquote_command from .mcquote import mcquote_command
from .img2gif import img2gif_command from .img2gif import img2gif_command
from .tweety import tweety_command from .tweety import tweety_command
@@ -62,12 +63,15 @@ class Media(commands.GroupCog, name="media"):
) )
embed.add_field( embed.add_field(
name="Available", name="Available",
value="mcquote, img2gif, tweety, tts", value="download, mcquote, img2gif, tweety, tts",
inline=False, inline=False,
) )
await context.send(embed=embed) await context.send(embed=embed)
async def _invoke_hybrid(self, context: Context, name: str, *args, **kwargs): async def _invoke_hybrid(self, context: Context, name: str, *args, **kwargs):
if name == "download":
await self.download(context, url=kwargs.get("url", ""))
return
if name == "mcquote": if name == "mcquote":
await self.mcquote(context, text=kwargs.get("text", "")) await self.mcquote(context, text=kwargs.get("text", ""))
return return
@@ -82,6 +86,10 @@ class Media(commands.GroupCog, name="media"):
return return
await context.send(f"Unknown media command: {name}") await context.send(f"Unknown media command: {name}")
@media_group.command(name="download")
async def media_group_download(self, context: Context, *, url: str):
await self._invoke_hybrid(context, "download", url=url)
@media_group.command(name="mcquote") @media_group.command(name="mcquote")
async def media_group_mcquote(self, context: Context, *, text: str): async def media_group_mcquote(self, context: Context, *, text: str):
await self._invoke_hybrid(context, "mcquote", text=text) await self._invoke_hybrid(context, "mcquote", text=text)
@@ -100,6 +108,14 @@ class Media(commands.GroupCog, name="media"):
async def media_group_tts(self, context: Context, *, text: str = None): async def media_group_tts(self, context: Context, *, text: str = None):
await self._invoke_hybrid(context, "tts", text=text) await self._invoke_hybrid(context, "tts", text=text)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="download",
description="Download a video from a URL using yt-dlp.",
)
async def download(self, context, *, url: str):
return await download_command()(self, context, url=url)
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@commands.hybrid_command( @commands.hybrid_command(
name="mcquote", name="mcquote",
@@ -137,6 +153,7 @@ async def setup(bot) -> None:
cog = Media(bot) cog = Media(bot)
await bot.add_cog(cog) await bot.add_cog(cog)
bot.logger.info("Loaded extension 'media.download'")
bot.logger.info("Loaded extension 'media.mcquote'") bot.logger.info("Loaded extension 'media.mcquote'")
bot.logger.info("Loaded extension 'media.img2gif'") bot.logger.info("Loaded extension 'media.img2gif'")
bot.logger.info("Loaded extension 'media.tweety'") bot.logger.info("Loaded extension 'media.tweety'")

531
cogs/media/download.py Normal file
View File

@@ -0,0 +1,531 @@
import asyncio
import os
import tempfile
import discord
from discord.ext import commands
import yt_dlp
from urllib.parse import urlparse
import aiohttp
import logging
logger = logging.getLogger("discord_bot")
def download_command():
@commands.hybrid_command(
name="download",
description="Download a video from a URL using yt-dlp.",
)
@commands.cooldown(1, 30, commands.BucketType.user)
async def download(self, context, *, url: str):
if isinstance(context.channel, discord.DMChannel):
embed = discord.Embed(
title="Error",
description="This command can only be used in servers.",
color=0xE02B2B,
)
embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None)
if interaction is not None:
if not interaction.response.is_done():
await interaction.response.send_message(embed=embed, ephemeral=True)
else:
await interaction.followup.send(embed=embed, ephemeral=True)
else:
await context.send(embed=embed, ephemeral=True)
return
if isinstance(context.channel, discord.PartialMessageable):
embed = discord.Embed(
title="Error",
description="The bot needs the `send messages` permission in this channel.",
color=0xE02B2B,
)
embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None)
if interaction is not None:
if not interaction.response.is_done():
await interaction.response.send_message(embed=embed, ephemeral=True)
else:
await interaction.followup.send(embed=embed, ephemeral=True)
else:
await context.send(embed=embed, ephemeral=True)
return
if not url:
embed = discord.Embed(
title="Error",
description="Please provide a valid URL to download.",
color=0xE02B2B,
)
embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None)
if interaction is not None:
if not interaction.response.is_done():
await interaction.response.send_message(embed=embed, ephemeral=True)
else:
await interaction.followup.send(embed=embed, ephemeral=True)
else:
await context.send(embed=embed, ephemeral=True)
return
# Check if bot has send messages permission before starting download
try:
test_embed = discord.Embed(title="Testing permissions...", color=0x7289DA)
test_embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
await context.channel.send(embed=test_embed, delete_after=0.1)
except discord.Forbidden:
embed = discord.Embed(
title="Permission Error",
description="The bot needs the `send messages` permission to execute this command.",
color=0xE02B2B,
)
embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None)
if interaction is not None:
if not interaction.response.is_done():
await interaction.response.send_message(embed=embed, ephemeral=True)
else:
await interaction.followup.send(embed=embed, ephemeral=True)
else:
await context.send(embed=embed, ephemeral=True)
return
try:
parsed_url = urlparse(url)
if not parsed_url.scheme or not parsed_url.netloc:
embed = discord.Embed(
title="Error",
description="Please provide a valid URL.",
color=0xE02B2B,
)
embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None)
if interaction is not None:
if not interaction.response.is_done():
await interaction.response.send_message(
embed=embed, ephemeral=True
)
else:
await interaction.followup.send(embed=embed, ephemeral=True)
else:
await context.send(embed=embed, ephemeral=True)
return
except Exception:
embed = discord.Embed(
title="Error",
description="Please provide a valid URL.",
color=0xE02B2B,
)
embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None)
if interaction is not None:
if not interaction.response.is_done():
await interaction.response.send_message(embed=embed, ephemeral=True)
else:
await interaction.followup.send(embed=embed, ephemeral=True)
else:
await context.send(embed=embed, ephemeral=True)
return
processing_embed = discord.Embed(
title="Download (Processing)",
description="<a:mariospin:1423677027013103709> Downloading video... This may take a moment.",
color=0x7289DA,
)
processing_embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
interaction = getattr(context, "interaction", None)
if interaction is not None:
if not interaction.response.is_done():
await interaction.response.send_message(
embed=processing_embed, ephemeral=True
)
else:
await interaction.followup.send(embed=processing_embed, ephemeral=True)
else:
processing_msg = await context.send(embed=processing_embed)
temp_dir = tempfile.mkdtemp()
# Try Docker path first, fallback to local path for development
cookie_path = "/bot/cogs/media/files/cookies.txt"
if not os.path.exists(cookie_path):
cookie_path = os.path.join(
os.path.dirname(__file__), "files", "cookies.txt"
)
ydl_opts = {
"format": "bestvideo[filesize<200M]+bestaudio[filesize<200M]/best[filesize<200M]/bestvideo+bestaudio/best",
"outtmpl": os.path.join(temp_dir, "%(title)s.%(ext)s"),
"noplaylist": True,
"extract_flat": False,
"writesubtitles": False,
"writeautomaticsub": False,
"writethumbnail": False,
"ignoreerrors": False,
"merge_output_format": "mp4",
"cookiefile": cookie_path,
}
try:
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = await asyncio.get_event_loop().run_in_executor(
None, lambda: ydl.extract_info(url, download=True)
)
if not info:
raise Exception("Could not extract video information")
video_title = info.get("title", "Unknown Title")
video_duration_seconds = int(info.get("duration") or 0)
video_uploader = info.get("uploader", "Unknown")
video_url = info.get("webpage_url") or info.get("original_url") or url
platform = (
info.get("extractor") or info.get("extractor_key") or "Unknown"
)
view_count = info.get("view_count")
files = [
f
for f in os.listdir(temp_dir)
if os.path.isfile(os.path.join(temp_dir, f))
]
if not files:
raise Exception("No video file was downloaded")
video_file = os.path.join(temp_dir, files[0])
file_size = os.path.getsize(video_file)
logger.info(
f"File size: {file_size} bytes ({file_size / (1024 * 1024):.2f} MB)"
)
if file_size > 24 * 1024 * 1024: # 24MB limit
logger.info("File is over 24MB, uploading to Catbox")
async def upload_to_catbox(path: str) -> str:
try:
file_size_bytes = os.path.getsize(path)
except Exception:
file_size_bytes = -1
logger.info(
f"Catbox upload start: name={os.path.basename(path)} size={file_size_bytes}"
)
form = aiohttp.FormData()
form.add_field("reqtype", "fileupload")
form.add_field(
"fileToUpload",
open(path, "rb"),
filename=os.path.basename(path),
)
timeout = aiohttp.ClientTimeout(total=600)
async with aiohttp.ClientSession(timeout=timeout) as session:
async with session.post(
"https://catbox.moe/user/api.php", data=form
) as resp:
text = await resp.text()
logger.info(
f"Catbox response: status={resp.status} body_len={len(text)}"
)
if resp.status == 200 and text.startswith("https://"):
url_text = text.strip()
logger.info(
f"Catbox upload success: url={url_text}"
)
return url_text
logger.error(
f"Catbox upload failed: status={resp.status} body={text.strip()[:500]}"
)
raise RuntimeError(f"Upload failed: {text.strip()}")
try:
link = await upload_to_catbox(video_file)
minutes, seconds = divmod(video_duration_seconds, 60)
duration_str = f"{minutes}:{seconds:02d}"
description_text = (
f"### **[{video_title}]({video_url})**"
if video_url
else f"### **{video_title}**"
)
embed = discord.Embed(
title="Download",
description=description_text,
color=0x7289DA,
)
embed.set_author(
name="Media",
icon_url="https://yes.nighty.works/raw/y5SEZ9.webp",
)
embed.add_field(
name="Uploader",
value=video_uploader or "Unknown",
inline=True,
)
embed.add_field(
name="Duration", value=duration_str, inline=True
)
embed.add_field(name="Platform", value=platform, inline=True)
embed.set_footer(
text=f"Requested by {context.author.name}",
icon_url=context.author.display_avatar.url,
)
if interaction is not None:
await context.channel.send(embed=embed)
await context.channel.send(link)
try:
await interaction.delete_original_response()
except:
pass
else:
await processing_msg.delete()
await context.channel.send(embed=embed)
await context.channel.send(link)
return
except Exception as upload_error:
logger.exception(f"Catbox upload exception: {upload_error}")
error_msg = str(upload_error)
if "greater than 200mb" in error_msg.lower():
description = "The video is too large to upload. The file exceeds 200MB (Catbox limit) and cannot be sent via Discord (25MB limit)."
else:
description = f"The video is over 25MB and upload to hosting failed: {upload_error}"
embed = discord.Embed(
title="Error",
description=description,
color=0xE02B2B,
)
embed.set_author(
name="Media",
icon_url="https://yes.nighty.works/raw/y5SEZ9.webp",
)
if interaction is not None:
try:
await interaction.delete_original_response()
except:
pass
await interaction.followup.send(embed=embed, ephemeral=True)
else:
await processing_msg.delete()
await context.send(embed=embed, ephemeral=True)
return
else:
logger.info("File is under 24MB, sending directly to Discord")
minutes, seconds = divmod(video_duration_seconds, 60)
duration_str = f"{minutes}:{seconds:02d}"
description_text = (
f"### **[{video_title}]({video_url})**"
if video_url
else f"### **{video_title}**"
)
embed = discord.Embed(
title="Download",
description=description_text,
color=0x7289DA,
)
embed.set_author(
name="Media",
icon_url="https://yes.nighty.works/raw/y5SEZ9.webp",
)
embed.add_field(
name="Uploader", value=video_uploader or "Unknown", inline=True
)
embed.add_field(name="Duration", value=duration_str, inline=True)
embed.add_field(name="Platform", value=platform, inline=True)
embed.set_footer(
text=f"Requested by {context.author.name}",
icon_url=context.author.display_avatar.url,
)
try:
with open(video_file, "rb") as f:
file = discord.File(f, filename=files[0])
if interaction is not None:
await context.channel.send(embed=embed)
await context.channel.send(file=file)
try:
await interaction.delete_original_response()
except:
pass
else:
await processing_msg.delete()
await context.channel.send(embed=embed)
await context.channel.send(file=file)
except discord.HTTPException as e:
if e.status == 413:
logger.info(
"Discord rejected file (413), falling back to Catbox upload"
)
async def upload_to_catbox(path: str) -> str:
try:
file_size_bytes = os.path.getsize(path)
except Exception:
file_size_bytes = -1
logger.info(
f"Catbox upload start: name={os.path.basename(path)} size={file_size_bytes}"
)
form = aiohttp.FormData()
form.add_field("reqtype", "fileupload")
form.add_field(
"fileToUpload",
open(path, "rb"),
filename=os.path.basename(path),
)
timeout = aiohttp.ClientTimeout(total=600)
async with aiohttp.ClientSession(
timeout=timeout
) as session:
async with session.post(
"https://catbox.moe/user/api.php", data=form
) as resp:
text = await resp.text()
logger.info(
f"Catbox response: status={resp.status} body_len={len(text)}"
)
if resp.status == 200 and text.startswith(
"https://"
):
url_text = text.strip()
logger.info(
f"Catbox upload success: url={url_text}"
)
return url_text
logger.error(
f"Catbox upload failed: status={resp.status} body={text.strip()[:500]}"
)
raise RuntimeError(
f"Upload failed: {text.strip()}"
)
try:
link = await upload_to_catbox(video_file)
description_text_with_link = (
f"### **[{video_title}]({video_url})**\n\n{link}"
if video_url
else f"### **{video_title}**\n\n{link}"
)
embed = discord.Embed(
title="Download",
description=description_text,
color=0x7289DA,
)
embed.set_author(
name="Media",
icon_url="https://yes.nighty.works/raw/y5SEZ9.webp",
)
embed.add_field(
name="Uploader",
value=video_uploader or "Unknown",
inline=True,
)
embed.add_field(
name="Duration", value=duration_str, inline=True
)
embed.add_field(
name="Platform", value=platform, inline=True
)
embed.set_footer(
text=f"Requested by {context.author.name}",
icon_url=context.author.display_avatar.url,
)
if interaction is not None:
await context.channel.send(embed=embed)
await context.channel.send(link)
try:
await interaction.delete_original_response()
except:
pass
else:
await processing_msg.delete()
await context.channel.send(embed=embed)
await context.channel.send(link)
except Exception as upload_error:
logger.exception(
f"Catbox upload exception: {upload_error}"
)
embed = discord.Embed(
title="Error",
description=f"Discord rejected the file and Catbox upload failed: {upload_error}",
color=0xE02B2B,
)
embed.set_author(
name="Media",
icon_url="https://yes.nighty.works/raw/y5SEZ9.webp",
)
if interaction is not None:
try:
await interaction.delete_original_response()
except:
pass
await interaction.followup.send(
embed=embed, ephemeral=True
)
else:
await processing_msg.delete()
await context.send(embed=embed, ephemeral=True)
else:
raise e
except Exception as e:
embed = discord.Embed(
title="Error",
description=f"Failed to download video: {str(e)}",
color=0xE02B2B,
)
embed.set_author(
name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp"
)
if interaction is not None:
try:
await interaction.delete_original_response()
except:
pass
await interaction.followup.send(embed=embed, ephemeral=True)
else:
try:
await processing_msg.delete()
except:
pass
await context.send(embed=embed, ephemeral=True)
finally:
for file in os.listdir(temp_dir):
try:
os.remove(os.path.join(temp_dir, file))
except:
pass
try:
os.rmdir(temp_dir)
except:
pass
return download

View File

@@ -1,3 +1,4 @@
import asyncio
import os import os
import tempfile import tempfile
import discord import discord

View File

@@ -1,5 +1,6 @@
import asyncio import asyncio
import io import io
import tempfile
from typing import Optional from typing import Optional
import discord import discord

View File

@@ -267,7 +267,7 @@ class TweetyView(discord.ui.View):
os.remove(temp_file_path) os.remove(temp_file_path)
except Exception: except Exception as e:
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description="Error regenerating tweet image", description="Error regenerating tweet image",
@@ -462,7 +462,7 @@ def tweety_command():
) )
embed = discord.Embed( embed = discord.Embed(
title="Tweet Generated", title="Tweet Generated",
description="<:error:1424007141768822824> Tweet sometimes may look a bit broken, im gonna rewrite the API another time... (it wasnt made for Syntrel in the first place)", description=f"<:error:1424007141768822824> Tweet sometimes may look a bit broken, im gonna rewrite the API another time... (it wasnt made for Syntrel in the first place)",
color=0x7289DA, color=0x7289DA,
) )
embed.set_author( embed.set_author(
@@ -491,7 +491,7 @@ def tweety_command():
await processing_msg.delete() await processing_msg.delete()
embed = discord.Embed( embed = discord.Embed(
title="Error", title="Error",
description="Connection error: Could not reach tweet API", description=f"Connection error: Could not reach tweet API",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author( embed.set_author(

View File

@@ -1,5 +1,8 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import time
def error_command(): def error_command():
@@ -20,7 +23,7 @@ def error_command():
embed.set_author( embed.set_author(
name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png" name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
) )
embed.set_footer(text="Last Edited by Meshal :D") embed.set_footer(text=f"Last Edited by Meshal :D")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()

View File

@@ -1,5 +1,8 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import time
def crash_command(): def crash_command():
@@ -23,7 +26,7 @@ def crash_command():
embed.set_author( embed.set_author(
name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png" name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
) )
embed.set_footer(text="Last Edited by Meshal :D") embed.set_footer(text=f"Last Edited by Meshal :D")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()

View File

@@ -1,5 +1,8 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import time
def ios26_command(): def ios26_command():
@@ -23,7 +26,7 @@ def ios26_command():
embed.set_author( embed.set_author(
name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png" name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
) )
embed.set_footer(text="Last Edited by Meshal :D") embed.set_footer(text=f"Last Edited by Meshal :D")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()

View File

@@ -1,5 +1,8 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import time
def legal_command(): def legal_command():
@@ -35,7 +38,7 @@ def legal_command():
embed.set_author( embed.set_author(
name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png" name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
) )
embed.set_footer(text="Last Edited by stossy11") embed.set_footer(text=f"Last Edited by stossy11")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()

View File

@@ -1,5 +1,8 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import time
def mods_command(): def mods_command():
@@ -26,7 +29,7 @@ def mods_command():
embed.set_author( embed.set_author(
name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png" name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
) )
embed.set_footer(text="Last Edited by Meshal :D") embed.set_footer(text=f"Last Edited by Meshal :D")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()

View File

@@ -1,5 +1,8 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import time
def requirements_command(): def requirements_command():
@@ -21,7 +24,7 @@ def requirements_command():
embed.set_author( embed.set_author(
name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png" name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
) )
embed.set_footer(text="Last Edited by Meshal :D") embed.set_footer(text=f"Last Edited by Meshal :D")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()

View File

@@ -1,5 +1,8 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import time
def transfer_command(): def transfer_command():
@@ -32,7 +35,7 @@ def transfer_command():
embed.set_author( embed.set_author(
name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png" name="MeloNX", icon_url="https://yes.nighty.works/raw/TLGaVa.png"
) )
embed.set_footer(text="Last Edited by Meshal :D") embed.set_footer(text=f"Last Edited by Meshal :D")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()

View File

@@ -57,3 +57,4 @@ def upgrade_command():
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return upgrade return upgrade

View File

@@ -1,5 +1,6 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import aiohttp import aiohttp
import io import io

View File

@@ -1,5 +1,6 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import aiohttp import aiohttp
import io import io

View File

@@ -1,5 +1,6 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import aiohttp import aiohttp
import io import io

View File

@@ -1,4 +1,6 @@
import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
def duck_command(): def duck_command():

View File

@@ -1,5 +1,6 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import random import random

View File

@@ -1,5 +1,6 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
def labubu_command(): def labubu_command():
@@ -51,7 +52,7 @@ def labubu_command():
embed.set_author( embed.set_author(
name="Labubu", icon_url="https://yes.nighty.works/raw/YxMC0r.png" name="Labubu", icon_url="https://yes.nighty.works/raw/YxMC0r.png"
) )
embed.set_footer(text="May look broken on mobile") embed.set_footer(text=f"May look broken on mobile")
if getattr(context, "interaction", None): if getattr(context, "interaction", None):
inter = context.interaction inter = context.interaction

View File

@@ -1,5 +1,6 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import aiohttp import aiohttp
import io import io

View File

@@ -1,5 +1,6 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import aiohttp import aiohttp
import io import io

View File

@@ -1,5 +1,6 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import aiohttp import aiohttp
import io import io

View File

@@ -1,4 +1,6 @@
import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
def silly_command(): def silly_command():

View File

@@ -1,5 +1,6 @@
import discord import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import aiohttp import aiohttp
import io import io

View File

@@ -1,4 +1,6 @@
import discord
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
def tryitandsee_command(): def tryitandsee_command():

View File

@@ -3,6 +3,7 @@ from datetime import datetime
import discord import discord
from discord import app_commands from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
def archive_command(): def archive_command():

View File

@@ -1,6 +1,7 @@
import discord import discord
from discord import app_commands from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
def ban_command(): def ban_command():
@@ -221,7 +222,7 @@ def ban_command():
) )
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
except Exception: except Exception as e:
embed = discord.Embed( embed = discord.Embed(
title="Error!", title="Error!",
description="An unexpected error occurred.", description="An unexpected error occurred.",

View File

@@ -1,6 +1,7 @@
import discord import discord
from discord import app_commands from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
def hackban_command(): def hackban_command():

View File

@@ -1,6 +1,7 @@
import discord import discord
from discord import app_commands from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
def kick_command(): def kick_command():
@@ -141,7 +142,7 @@ def kick_command():
) )
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
except Exception: except Exception as e:
embed = discord.Embed( embed = discord.Embed(
title="Error!", title="Error!",
description="An unexpected error occurred.", description="An unexpected error occurred.",

View File

@@ -1,6 +1,7 @@
import discord import discord
from discord import app_commands from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
def nick_command(): def nick_command():

View File

@@ -1,6 +1,7 @@
import discord import discord
from discord import app_commands from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
def purge_command(): def purge_command():

View File

@@ -92,7 +92,7 @@ class Logs(commands.Cog, name="logs"):
selected_lines = all_lines[-lines:] if len(all_lines) > lines else all_lines selected_lines = all_lines[-lines:] if len(all_lines) > lines else all_lines
log_content = "".join(selected_lines) log_content = "".join(selected_lines)
log_file = "logs.txt" log_file = f"logs.txt"
with open(log_file, "w", encoding="utf-8") as f: with open(log_file, "w", encoding="utf-8") as f:
f.write( f.write(
f"Bot logs extracted at {discord.utils.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC\n" f"Bot logs extracted at {discord.utils.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC\n"

View File

@@ -1,5 +1,8 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import time
def afc_command(): def afc_command():
@@ -12,15 +15,15 @@ def afc_command():
description=( description=(
"# AFC Connection Failure\n\n---\n\n" "# AFC Connection Failure\n\n---\n\n"
+ "1. Make sure Wi-Fi is connected to a stable network\n" + "1. Make sure Wi-Fi is connected to a stable network\n"
+ "2. Make sure LocalDevVPN is connected and updated\n" + "2. Make sure StosVPN is connected and updated\n"
+ "3. If issue still persists, replace pairing file using `iloader`. See [Pairing File instructions](https://docs.sidestore.io/docs/advanced/pairing-file) for details" + "3. If issue still persists, create and import a new pairing file using `idevice_pair`. See [Pairing File instructions](https://docs.sidestore.io/docs/installation/pairing-file) for details"
), ),
) )
embed.set_author( embed.set_author(
name="SideStore", name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
) )
embed.set_footer(text="Last Edited by CelloSerenity") embed.set_footer(text=f"Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
@@ -36,7 +39,7 @@ def afc_command():
discord.ui.Button( discord.ui.Button(
label="Documentation", label="Documentation",
style=discord.ButtonStyle.primary, style=discord.ButtonStyle.primary,
url="https://docs.sidestore.io/docs/troubleshooting/common-issues/#afc-connection-failure--no-wi-fi-or-vpn-connection", url="https://docs.sidestore.io/docs/troubleshooting/common-issues#afc-connection-failure",
emoji="<:sidestorepride:1417717648795631787>", emoji="<:sidestorepride:1417717648795631787>",
) )
) )

View File

@@ -1,5 +1,8 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import time
def code_command(): def code_command():
@@ -31,7 +34,7 @@ def code_command():
name="SideStore", name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
) )
embed.set_footer(text="Last Edited by CelloSerenity") embed.set_footer(text=f"Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()

View File

@@ -1,5 +1,8 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import time
def crash_command(): def crash_command():
@@ -12,12 +15,12 @@ def crash_command():
description=( description=(
"# SideStore Crashing After Refresh\n\n---\n\n" "# SideStore Crashing After Refresh\n\n---\n\n"
+ "First, to try and save your data:\n" + "First, to try and save your data:\n"
+ "1. DON'T DELETE SIDESTORE, reinstall using iloader's Install `SideStore (Stable)` button.\n" + "1. DON'T DELETE SIDESTORE, reinstall with AltServer's `Sideload .ipa`.\n"
+ "If that doesn't work:\n" + "If that doesn't work:\n"
+ "1. Delete your current SideStore. Reinstall with iloader.\n" + "1. Delete your current SideStore. Reinstall with AltServer.\n"
+ "2. Import your pairing file and sign into SideStore.\n" + "2. Import your pairing file and sign into SideStore.\n"
+ "3. Download the SideStore .ipa file, and save it to your Files app.\n" + "3. Download the SideStore .ipa file, and save it to your Files app.\n"
+ '4. Import the "SideStore.ipa" file into SideStore, just like how you import any other IPA.\n\n' + '4. Import the "Sidestore.ipa" file into SideStore, just like how you import any other IPA.\n\n'
+ "This process ensures SideStore is refreshed without issues." + "This process ensures SideStore is refreshed without issues."
), ),
) )
@@ -25,7 +28,7 @@ def crash_command():
name="SideStore", name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
) )
embed.set_footer(text="Last Edited by CelloSerenity") embed.set_footer(text=f"Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()

View File

@@ -1,5 +1,8 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import time
def half_command(): def half_command():
@@ -18,7 +21,7 @@ def half_command():
+ "- Change Anisette Server\n" + "- Change Anisette Server\n"
+ "- Reset adi.pb\n" + "- Reset adi.pb\n"
+ "- Sign out from SideStore and sign back in\n" + "- Sign out from SideStore and sign back in\n"
+ "- Replace pairing file\n" + "- Recreate pairing file\n"
+ "- Reinstall SideStore\n\n" + "- Reinstall SideStore\n\n"
), ),
) )
@@ -26,7 +29,7 @@ def half_command():
name="SideStore", name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
) )
embed.set_footer(text="Last Edited by CelloSerenity") embed.set_footer(text=f"Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
@@ -42,7 +45,7 @@ def half_command():
discord.ui.Button( discord.ui.Button(
label="Documentation", label="Documentation",
style=discord.ButtonStyle.primary, style=discord.ButtonStyle.primary,
url="https://docs.sidestore.io/docs/troubleshooting/common-issues/#sidestore-hangs-partway-through-installation", url="https://docs.sidestore.io/docs/troubleshooting/common-issues#sidestore-hangs-halfway-through-installation",
emoji="<:sidestorepride:1417717648795631787>", emoji="<:sidestorepride:1417717648795631787>",
) )
) )

View File

@@ -1,22 +1,40 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import time
def pairing_command(): def pairing_command():
@commands.hybrid_command(name="pairing", description="Link to the pairing guide") @commands.hybrid_command(
name="pairing", description="Help with pairing file issues"
)
async def pairing(self, context): async def pairing(self, context):
embed = discord.Embed( embed = discord.Embed(
color=0x8E82F9, color=0x8E82F9,
description=( description=(
"# How to obtain your pairing file:\n\n---\n\n" "# Cannot Choose Pairing File\n\n---\n\n"
+ "[Click here](https://docs.sidestore.io/advanced/pairing-file) to read the SideStore documentation on replacing your pairing file.\n" + "1. **Check File Extension:**\n"
+ " Make sure your pairing file's extension ends with `.mobiledevicepairing` or `.plist`\n"
+ " - If it doesn't, double-check to see if you had zipped your pairing file before sending it to your phone. Failing to do so may lead to the file being corrupted during transport\n\n"
+ "2. **Move Pairing File:**\n"
+ " If you are unable to select the pairing file from within the app:\n"
+ " - Rename the file to `ALTPairingFile.mobiledevicepairing`\n"
+ ' - Try moving the pairing file to the root directory of the SideStore folder in the Files app under "On My iPhone/iPad"\n\n'
+ "3. **Certificate Signing:**\n"
+ " When signing SideStore with certain certificates, you won't be able to select the pairing file from within the app\n"
+ " - Try the fix mentioned above\n"
+ " - If you do not see the SideStore folder in the Files app:\n"
+ " • Connect your phone to your computer\n"
+ " • Drag and drop the pairing file into the SideStore app's files section\n"
+ " • Ensure the file is renamed to `ALTPairingFile.mobiledevicepairing`\n"
), ),
) )
embed.set_author( embed.set_author(
name="SideStore", name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
) )
embed.set_footer(text="Last Edited by CelloSerenity") embed.set_footer(text=f"Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
@@ -32,7 +50,7 @@ def pairing_command():
discord.ui.Button( discord.ui.Button(
label="Documentation", label="Documentation",
style=discord.ButtonStyle.primary, style=discord.ButtonStyle.primary,
url="https://docs.sidestore.io/docs/advanced/pairing-file", url="https://docs.sidestore.io/docs/troubleshooting/#cannot-choose-pairing-file",
emoji="<:sidestorepride:1417717648795631787>", emoji="<:sidestorepride:1417717648795631787>",
) )
) )

View File

@@ -1,5 +1,8 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import time
def refresh_command(): def refresh_command():
@@ -12,16 +15,16 @@ def refresh_command():
description=( description=(
"# Can't Refresh or Install Apps\n\n---\n\n" "# Can't Refresh or Install Apps\n\n---\n\n"
+ "1. Make sure your device is connected to a stable Wi-Fi network and not using cellular data.\n" + "1. Make sure your device is connected to a stable Wi-Fi network and not using cellular data.\n"
+ "2. Verify VPN is connected in the LocalDevVPN app.\n" + "2. Verify VPN is connected in the StosVPN app.\n"
+ "3. **Replace your pairing file.**\n" + "3. **Create a brand new pairing file.**\n"
+ " - If none of the above worked, it is very likely that the pairing file is corrupted. You can reference the documentation on how to replace your pairing file [here](https://docs.sidestore.io/docs/advanced/pairing-file).\n" + " - If none of the above worked, it is very likely that the pairing file is corrupted. You can reference the documentation on how to create a new pairing file [here](https://docs.sidestore.io/docs/installation/pairing-file).\n"
), ),
) )
embed.set_author( embed.set_author(
name="SideStore", name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
) )
embed.set_footer(text="Last Edited by CelloSerenity") embed.set_footer(text=f"Last Edited by neoarz")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
@@ -37,7 +40,7 @@ def refresh_command():
discord.ui.Button( discord.ui.Button(
label="Documentation", label="Documentation",
style=discord.ButtonStyle.primary, style=discord.ButtonStyle.primary,
url="https://docs.sidestore.io/docs/advanced/pairing-file", url="https://docs.sidestore.io/docs/installation/pairing-file",
emoji="<:sidestorepride:1417717648795631787>", emoji="<:sidestorepride:1417717648795631787>",
) )
) )

View File

@@ -1,5 +1,8 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import time
def server_command(): def server_command():
@@ -25,7 +28,7 @@ def server_command():
name="SideStore", name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
) )
embed.set_footer(text="Last Edited by CelloSerenity") embed.set_footer(text=f"Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()

View File

@@ -1,5 +1,8 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import time
class SidestoreSelect(discord.ui.Select): class SidestoreSelect(discord.ui.Select):

View File

@@ -1,5 +1,8 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import time
def sparse_command(): def sparse_command():
@@ -20,7 +23,7 @@ def sparse_command():
name="SideStore", name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
) )
embed.set_footer(text="Last Edited by neoarz") embed.set_footer(text=f"Last Edited by neoarz")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
@@ -36,7 +39,7 @@ def sparse_command():
discord.ui.Button( discord.ui.Button(
label="Documentation", label="Documentation",
style=discord.ButtonStyle.primary, style=discord.ButtonStyle.primary,
url="https://docs.sidestore.io/docs/advanced/alternative#sparserestore-3-app-limit", url="https://docs.sidestore.io/docs/advanced/sparserestore",
emoji="<:sidestorepride:1417717648795631787>", emoji="<:sidestorepride:1417717648795631787>",
) )
) )

View File

@@ -1,5 +1,8 @@
import discord import discord
from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import time
def udid_command(): def udid_command():
@@ -11,15 +14,15 @@ def udid_command():
color=0x8E82F9, color=0x8E82F9,
description=( description=(
"# SideStore Could Not Determine Device UDID\n\n---\n\n" "# SideStore Could Not Determine Device UDID\n\n---\n\n"
+ "This error usually occurs when the pairing file is corrupted. Please replace your pairing file using `iloader` and try again.\n\n" + "This error usually occurs when the pairing file is corrupted. Please create a new pairing file using `idevice_pair` and try again.\n\n"
+ "If you forgot how to replace your pairing file, you can refer to the documentation below." + "If you forgot how to create a new pairing file, you can refer to the documentation below."
), ),
) )
embed.set_author( embed.set_author(
name="SideStore", name="SideStore",
icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true", icon_url="https://github.com/SideStore/assets/blob/main/icons/classic/Default.png?raw=true",
) )
embed.set_footer(text="Last Edited by CelloSerenity") embed.set_footer(text=f"Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
@@ -35,7 +38,7 @@ def udid_command():
discord.ui.Button( discord.ui.Button(
label="Documentation", label="Documentation",
style=discord.ButtonStyle.secondary, style=discord.ButtonStyle.secondary,
url="https://docs.sidestore.io/docs/advanced/pairing-file/", url="https://docs.sidestore.io/docs/installation/pairing-file/",
emoji="<:sidestorepride:1417717648795631787>", emoji="<:sidestorepride:1417717648795631787>",
) )
) )

View File

@@ -1,8 +1,10 @@
import discord import discord
from discord import app_commands from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import aiohttp import aiohttp
import re import re
import json
def codepreview_command(): def codepreview_command():

View File

@@ -1,6 +1,7 @@
import discord import discord
from discord import app_commands from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import aiohttp import aiohttp
@@ -37,7 +38,7 @@ def dictionary_command():
} }
except aiohttp.ClientError: except aiohttp.ClientError:
return {"success": False, "error": "Network error occurred"} return {"success": False, "error": "Network error occurred"}
except Exception: except Exception as e:
return {"success": False, "error": "An unexpected error occurred"} return {"success": False, "error": "An unexpected error occurred"}
@commands.hybrid_command( @commands.hybrid_command(
@@ -123,7 +124,7 @@ def dictionary_command():
meanings = entry.get("meanings", []) meanings = entry.get("meanings", [])
embed = discord.Embed( embed = discord.Embed(
title="Dictionary", title=f"Dictionary",
description=f"**```{word_title}```**", description=f"**```{word_title}```**",
color=0x7289DA, color=0x7289DA,
) )

View File

@@ -1,9 +1,12 @@
import discord import discord
from discord import app_commands from discord import app_commands
from discord.ext import commands from discord.ext import commands
from discord.ext.commands import Context
import aiohttp import aiohttp
import asyncio
import re import re
import json import json
import urllib.parse
languages = { languages = {

View File

@@ -7,6 +7,7 @@ services:
volumes: volumes:
- ./database:/bot/database - ./database:/bot/database
- ./discord.log:/bot/discord.log - ./discord.log:/bot/discord.log
- ./cogs/media/files:/bot/cogs/media/files
# Alternatively you can set the environment variables as such: # Alternatively you can set the environment variables as such:
# /!\ The token shouldn't be written here, as this file is not ignored from Git /!\ # /!\ The token shouldn't be written here, as this file is not ignored from Git /!\

View File

@@ -2,6 +2,7 @@ aiohttp
aiosqlite aiosqlite
discord.py discord.py
python-dotenv python-dotenv
yt-dlp
Pillow Pillow
pillow-heif pillow-heif
pytz pytz

View File

@@ -1,6 +1,8 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# From https://github.com/neoarz/Velora/blob/main/Velora/ui/ascii.py # From https://github.com/neoarz/Velora/blob/main/Velora/ui/ascii.py
import math
def gradient_text(text, start_color, end_color): def gradient_text(text, start_color, end_color):
def rgb_interp(start, end, t): def rgb_interp(start, end, t):