8 Commits

Author SHA1 Message Date
neoarz
e086dd4351 chore: bleh 2025-12-29 19:40:52 -05:00
neoarz
63e26bac74 fix: sidestore message and preview 2025-12-29 18:17:10 -05:00
neo
bc2cfb57d1 feat: sticky message (#29) 2025-12-29 17:56:33 -05:00
neoarz
6d61482216 chore: rm download 2025-12-10 13:19:43 -05:00
CelloSerenity
b7d010e44c feat: Update mountddi, replace the pairing commands, switch to localdevvpn
* Update mountddi.py

* Update pairing command description and embed content

* Update crash.py

* Update afc.py

* Update VPN app reference in error message

* Update footer text in embed message

* feat: update mount ddi to be downloaded on the fly

also fix some small errors and update errorcodes.json

---------

Co-authored-by: neoarz <email@neoarz.dev>
2025-12-07 18:08:09 -05:00
CelloSerenity
0d3fcb8146 fix: Update to iloader and fix broken links (#26)
* Update afc.py

* Update afc.py

* Update error message and documentation link for UDID

* Update pairing file instructions and documentation URL

* Update pairing file instructions in refresh.py

* Update sparse.py

* NOTE TO SELF: This can probably be removed altogether or modified drastically because we don’t use jitterbug anymore

* Update jit26.py
2025-11-27 14:14:49 -05:00
neoarz
23790c46b4 chore: ruff fix 2025-11-22 19:51:46 -05:00
neo
4a9b6b1f06 feat: livecontainer command group (#25)
* initial commit

* fix: image link

* feat: finish cellos command

* fix: interactive sounds wierd 😭
2025-11-22 14:43:31 -05:00
69 changed files with 683 additions and 743 deletions

View File

@@ -30,10 +30,10 @@
| sidestore | `help`, `refresh`, `code`, `crash`, `pairing`, `server`, `half`, `sparse`, `afc`, `udid` | | sidestore | `help`, `refresh`, `code`, `crash`, `pairing`, `server`, `half`, `sparse`, `afc`, `udid` |
| idevice | `help`, `noapps`, `errorcode`, `developermode`, `mountddi` | | idevice | `help`, `noapps`, `errorcode`, `developermode`, `mountddi` |
| melonx | `help`, `transfer`, `mods`, `gamecrash`, `requirements`, `error`, `26`, `legal` | | melonx | `help`, `transfer`, `mods`, `gamecrash`, `requirements`, `error`, `26`, `legal` |
| events | `baitbot` | | events | `baitbot`, `stickybot` |
| 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 | `download`, `mcquote`, `img2gif`, `tweety`, `tts` | | media | `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,7 +4,6 @@ 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

@@ -5,6 +5,11 @@ from discord.ext.commands import Context
from .baitbot import baitbot_command, BaitBotListener, has_protected_role from .baitbot import baitbot_command, BaitBotListener, has_protected_role
from .mention import MentionListener from .mention import MentionListener
from .stickybot import (
stickybot_command,
StickyBotListener,
has_allowed_role as has_sticky_role,
)
def _require_group_prefix(context: Context) -> bool: def _require_group_prefix(context: Context) -> bool:
@@ -35,7 +40,7 @@ class Events(commands.GroupCog, name="events"):
embed.set_author( embed.set_author(
name="Events", icon_url="https://yes.nighty.works/raw/eW5lLm.webp" name="Events", icon_url="https://yes.nighty.works/raw/eW5lLm.webp"
) )
embed.add_field(name="Available", value="baitbot", inline=False) embed.add_field(name="Available", value="baitbot, stickybot", inline=False)
await context.send(embed=embed) await context.send(embed=embed)
async def _invoke_hybrid(self, context: Context, name: str, **kwargs): async def _invoke_hybrid(self, context: Context, name: str, **kwargs):
@@ -50,6 +55,11 @@ class Events(commands.GroupCog, name="events"):
async def events_group_baitbot(self, context: Context): async def events_group_baitbot(self, context: Context):
await self._invoke_hybrid(context, "baitbot") await self._invoke_hybrid(context, "baitbot")
@events_group.command(name="stickybot")
@has_sticky_role()
async def events_group_stickybot(self, context: Context):
await self._invoke_hybrid(context, "stickybot")
@commands.check(_require_group_prefix) @commands.check(_require_group_prefix)
@has_protected_role() @has_protected_role()
@commands.hybrid_command( @commands.hybrid_command(
@@ -58,6 +68,14 @@ class Events(commands.GroupCog, name="events"):
async def baitbot(self, context): async def baitbot(self, context):
return await baitbot_command()(self, context) return await baitbot_command()(self, context)
@commands.check(_require_group_prefix)
@has_sticky_role()
@commands.hybrid_command(
name="stickybot", description="View sticky bot configuration and status."
)
async def stickybot(self, context):
return await stickybot_command()(self, context)
async def setup(bot) -> None: async def setup(bot) -> None:
cog = Events(bot) cog = Events(bot)
@@ -69,5 +87,9 @@ async def setup(bot) -> None:
mention_listener = MentionListener(bot) mention_listener = MentionListener(bot)
await bot.add_cog(mention_listener) await bot.add_cog(mention_listener)
sticky_bot = StickyBotListener(bot)
await bot.add_cog(sticky_bot)
bot.logger.info("Loaded extension 'events.baitbot'") bot.logger.info("Loaded extension 'events.baitbot'")
bot.logger.info("Loaded extension 'events.mention'") bot.logger.info("Loaded extension 'events.mention'")
bot.logger.info("Loaded extension 'events.stickybot'")

View File

@@ -35,5 +35,3 @@ 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}"
) )

310
cogs/events/stickybot.py Normal file
View File

@@ -0,0 +1,310 @@
import discord
from discord.ext import commands
from discord.ext.commands import Context
import asyncio
# Make a pr to add your own server config here, you shouldn't need to touch the rest of the file, please fill in all the values for your own server
STICKY_CONFIGS = {
"neotest": {
"guild_id": 1069946178659160076,
"channel_ids": [
1455338488546459789,
],
"allowed_role_id": 1432165329483857940,
"message": "# Example sticky message", # You can add your own markdown here
"footer": "This is an automated sticky message.", # This will be appended to the message and uses "-#" to format the footer
"delay": 5, # in seconds
},
"SideStore": {
"guild_id": 949183273383395328,
"channel_ids": [
1279548738586673202,
],
"allowed_role_id": 949207813815697479,
"message": "## Please read the README in https://discord.com/channels/949183273383395328/1155736594679083089 and the documentation at <https://docs.sidestore.io> before asking your question.",
"footer": "This is an automated sticky message.",
"delay": 5,
},
}
def has_allowed_role():
async def predicate(context: Context):
if not context.guild:
context.bot.logger.warning(
f"[STICKYBOT] Unauthorized stickybot command attempt by {context.author} ({context.author.id}) in DMs"
)
embed = discord.Embed(
title="Permission Denied",
description="You don't have permission to use this command.",
color=0xE02B2B,
)
embed.set_author(
name="Events", icon_url="https://yes.nighty.works/raw/C8Hh6o.png"
)
await context.send(embed=embed, ephemeral=True)
return False
if not hasattr(context.author, "roles"):
context.bot.logger.warning(
f"[STICKYBOT] Unauthorized stickybot command attempt by {context.author} ({context.author.id}) in {context.guild.name} - no roles"
)
embed = discord.Embed(
title="Permission Denied",
description="You don't have permission to use this command.",
color=0xE02B2B,
)
embed.set_author(
name="Events", icon_url="https://yes.nighty.works/raw/C8Hh6o.png"
)
await context.send(embed=embed, ephemeral=True)
return False
for config in STICKY_CONFIGS.values():
if context.guild.id != config.get("guild_id"):
continue
allowed_role_id = config.get("allowed_role_id")
if allowed_role_id:
allowed_role = context.guild.get_role(allowed_role_id)
if allowed_role:
for role in context.author.roles:
if (
role.position >= allowed_role.position
and role.id != context.guild.default_role.id
):
return True
context.bot.logger.warning(
f"[STICKYBOT] Unauthorized stickybot command attempt by {context.author} ({context.author.id}) in {context.guild.name} - insufficient role permissions"
)
embed = discord.Embed(
title="Permission Denied",
description="You don't have permission to use this command.",
color=0xE02B2B,
)
embed.set_author(
name="Events", icon_url="https://yes.nighty.works/raw/C8Hh6o.png"
)
await context.send(embed=embed, ephemeral=True)
return False
return commands.check(predicate)
def stickybot_command():
async def wrapper(self, context: Context):
embed = discord.Embed(
title="Sticky Bot",
description="Sends sticky messages in configured channels.",
color=0x7289DA,
)
embed.set_author(
name="Events", icon_url="https://yes.nighty.works/raw/C8Hh6o.png"
)
found_config = False
if STICKY_CONFIGS:
for name, config in STICKY_CONFIGS.items():
guild_id = config.get("guild_id")
if context.guild and guild_id == context.guild.id:
channel_ids = config.get("channel_ids", [])
channel_displays = []
for channel_id in channel_ids:
channel = context.guild.get_channel(channel_id)
channel_display = (
f"<#{channel_id}> (`{channel_id}`)"
if channel
else f"`{channel_id}`"
)
channel_displays.append(channel_display)
channels_text = (
"\n".join(channel_displays) if channel_displays else "Not set"
)
allowed_role_id = config.get("allowed_role_id", "Not set")
role = context.guild.get_role(allowed_role_id)
role_display = (
f"<@&{allowed_role_id}> (`{allowed_role_id}`)"
if role
else f"`{allowed_role_id}`"
)
message_content = config.get("message", "*No message set*")
footer_text = config.get("footer", "This is an automated sticky message.")
full_content = f"{message_content}\n-# {footer_text}"
embed.add_field(
name="\u200b",
value=f"**Channels:**\n{channels_text}\n\n**Allowed Role:**\n{role_display}\n\n**Message Preview:**\n```\n{full_content}\n```",
inline=False,
)
found_config = True
if not found_config:
embed.add_field(
name="No Configurations",
value="No sticky configurations found for this server",
inline=False,
)
if context.guild and context.guild.icon:
embed.set_thumbnail(url=context.guild.icon.url)
await context.send(embed=embed)
return wrapper
class StickyBotListener(commands.Cog):
def __init__(self, bot):
self.bot = bot
self.last_sticky_messages = {}
self.debounce_tasks = {}
async def delete_last_sticky(self, channel):
try:
active_config = None
for config in STICKY_CONFIGS.values():
if channel.guild.id == config.get(
"guild_id"
) and channel.id in config.get("channel_ids", []):
active_config = config
break
if not active_config:
return
target_footer = active_config.get(
"footer", "This is an automated sticky message."
)
async for message in channel.history(limit=20):
if (
message.author.id == self.bot.user.id
and target_footer in message.content
):
await message.delete()
except Exception as e:
self.bot.logger.warning(
f"[STICKYBOT] Error cleaning up sticky in #{channel.name}: {e}"
)
async def send_sticky_message(self, channel, config):
if not channel:
return
last_msg_id = self.last_sticky_messages.get(channel.id)
deleted = False
if last_msg_id:
try:
old_msg = await channel.fetch_message(last_msg_id)
await old_msg.delete()
deleted = True
except discord.NotFound:
deleted = True
except discord.Forbidden:
self.bot.logger.warning(
f"[STICKYBOT] Missing delete permissions in #{channel.name}"
)
except Exception as e:
self.bot.logger.warning(
f"[STICKYBOT] Error deleting info in #{channel.name}: {e}"
)
if not deleted:
await self.delete_last_sticky(channel)
message_content = config.get("message")
if not message_content:
return
footer_text = config.get("footer", "This is an automated sticky message.")
footer = f"\n-# {footer_text}"
full_content = f"{message_content}{footer}"
try:
new_msg = await channel.send(
full_content, allowed_mentions=discord.AllowedMentions.none()
)
self.last_sticky_messages[channel.id] = new_msg.id
except discord.Forbidden:
self.bot.logger.warning(
f"[STICKYBOT] Missing send permissions in #{channel.name}"
)
except Exception as e:
self.bot.logger.error(
f"[STICKYBOT] Error sending sticky in #{channel.name}: {e}"
)
@commands.Cog.listener()
async def on_ready(self):
await self.bot.wait_until_ready()
await self.initialize_stickies()
async def initialize_stickies(self):
for name, config in STICKY_CONFIGS.items():
guild_id = config.get("guild_id")
guild = self.bot.get_guild(guild_id)
if not guild:
continue
channel_ids = config.get("channel_ids", [])
for channel_id in channel_ids:
channel = guild.get_channel(channel_id)
if channel:
await self.send_sticky_message(channel, config)
async def trigger_sticky(self, channel, guild):
if not guild or not channel:
return
active_config = None
for config in STICKY_CONFIGS.values():
if guild.id == config.get("guild_id"):
if channel.id in config.get("channel_ids", []):
active_config = config
break
if not active_config:
return
channel_id = channel.id
if channel_id in self.debounce_tasks:
self.debounce_tasks[channel_id].cancel()
async def debounce_wrapper():
try:
delay = active_config.get("delay", 5)
await asyncio.sleep(delay)
await self.send_sticky_message(channel, active_config)
except asyncio.CancelledError:
pass
except Exception as e:
self.bot.logger.error(f"[STICKYBOT] Error in debounce task: {e}")
finally:
if self.debounce_tasks.get(channel_id) == asyncio.current_task():
del self.debounce_tasks[channel_id]
self.debounce_tasks[channel_id] = self.bot.loop.create_task(debounce_wrapper())
@commands.Cog.listener()
async def on_message(self, message: discord.Message):
if message.guild is None or message.author.bot:
return
if message.id == self.last_sticky_messages.get(message.channel.id):
return
await self.trigger_sticky(message.channel, message.guild)
@commands.Cog.listener()
async def on_interaction(self, interaction: discord.Interaction):
if interaction.guild is None or interaction.user.bot:
return
if interaction.type == discord.InteractionType.application_command:
await self.trigger_sticky(interaction.channel, interaction.guild)

View File

@@ -1,5 +1,4 @@
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
@@ -62,21 +61,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 not rawpos - 1 in self.bombs or pos == 0: if rawpos - 1 not in self.bombs or pos == 0:
count.append(rawpos - 1) count.append(rawpos - 1)
if not rawpos + 1 in self.bombs or pos == 4: if rawpos + 1 not in self.bombs or pos == 4:
count.append(rawpos + 1) count.append(rawpos + 1)
if not rawpos - 6 in self.bombs or pos == 0: if rawpos - 6 not in self.bombs or pos == 0:
count.append(rawpos - 6) count.append(rawpos - 6)
if not rawpos - 4 in self.bombs or pos == 4: if rawpos - 4 not in self.bombs or pos == 4:
count.append(rawpos - 4) count.append(rawpos - 4)
if not rawpos + 6 in self.bombs or pos == 4: if rawpos + 6 not in self.bombs or pos == 4:
count.append(rawpos + 6) count.append(rawpos + 6)
if not rawpos + 4 in self.bombs or pos == 0: if rawpos + 4 not in self.bombs or pos == 0:
count.append(rawpos + 4) count.append(rawpos + 4)
if not rawpos - 5 in self.bombs: if rawpos - 5 not in self.bombs:
count.append(rawpos - 5) count.append(rawpos - 5)
if not rawpos + 5 in self.bombs: if rawpos + 5 not in self.bombs:
count.append(rawpos + 5) count.append(rawpos + 5)
return count return count

View File

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

View File

@@ -1,9 +1,8 @@
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="Feeedback"): class FeedbackForm(discord.ui.Modal, title="Feedback"):
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,10 +2,8 @@ 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

@@ -21,6 +21,7 @@ class Help(commands.Cog, name="help"):
"sidestore", "sidestore",
"idevice", "idevice",
"melonx", "melonx",
"livecontainer",
"media", "media",
"miscellaneous", "miscellaneous",
"utilities", "utilities",
@@ -51,6 +52,7 @@ class Help(commands.Cog, name="help"):
"fun": "fun", "fun": "fun",
"idevice": "idevice", "idevice": "idevice",
"melonx": "melonx", "melonx": "melonx",
"livecontainer": "livecontainer",
"media": "media", "media": "media",
"misc": "miscellaneous", "misc": "miscellaneous",
"miscellaneous": "miscellaneous", "miscellaneous": "miscellaneous",
@@ -77,6 +79,7 @@ class Help(commands.Cog, name="help"):
"sidestore": "SideStore troubleshooting commands", "sidestore": "SideStore troubleshooting commands",
"idevice": "idevice troubleshooting commands", "idevice": "idevice troubleshooting commands",
"melonx": "MeloNX troubleshooting commands", "melonx": "MeloNX troubleshooting commands",
"livecontainer": "LiveContainer troubleshooting commands",
"media": "Media commands", "media": "Media commands",
"utilities": "Utility commands", "utilities": "Utility commands",
"miscellaneous": "Miscellaneous commands", "miscellaneous": "Miscellaneous commands",

View File

@@ -31,7 +31,9 @@ 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(self, context: Context, *, error_code: str = None): async def idevice_group_errorcodes(
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,8 +1,5 @@
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():
@@ -24,7 +21,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=f"Last Edited by neoarz") 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()

Binary file not shown.

View File

@@ -328,5 +328,10 @@
"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,7 +1,5 @@
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,7 +1,9 @@
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():
@@ -12,23 +14,27 @@ def mountddi_command():
embed = discord.Embed( embed = discord.Embed(
color=0xFA8C4A, color=0xFA8C4A,
description=( description=(
"# How to Manually Mount DDI\n\n---\n\n" "# How to Mount your DDI (Developer Disk Image):\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 the downloaded zip\n" " - Replace it with the DDI folder from uncompressing the downloaded zip\n"
" - Make sure it's in the StikDebug default directory\n\n" " - Make sure it's in StikDebug's default directory\n\n"
"3. **Restart and retry:**\n" "3. **Restart and retry:**\n"
" - Completely restart StikDebug\n" " - Completely restart StikDebug\n"
" - See if you get the same error again\n\n" " - If you still get the same error, ask the idevice server for more help\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 neoarz") embed.set_footer(text="Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
@@ -41,16 +47,51 @@ def mountddi_command():
) )
) )
ddi_file_path = os.path.join(os.path.dirname(__file__), "files/DDI.zip") temp_dir = tempfile.mkdtemp()
file = ( try:
discord.File(ddi_file_path, filename="DDI.zip") ddi_dir = os.path.join(temp_dir, "DDI")
if os.path.exists(ddi_file_path) os.makedirs(ddi_dir)
else None
)
if file: base_url = "https://raw.githubusercontent.com/doronz88/DeveloperDiskImage/main/PersonalizedImages/Xcode_iOS_DDI_Personalized"
await context.send(embed=embed, view=view, file=file) files = ["BuildManifest.plist", "Image.dmg", "Image.dmg.trustcache"]
else:
await context.send(embed=embed, view=view) async with aiohttp.ClientSession() as session:
for filename in files:
file_url = f"{base_url}/{filename}"
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,8 +1,5 @@
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():
@@ -26,7 +23,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=f"Last Edited by neoarz") 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()

View File

@@ -0,0 +1,93 @@
import discord
from discord import app_commands
from discord.ext import commands
from discord.ext.commands import Context
from .livecontainer import LivecontainerView
from .jit26 import jit26_command
@app_commands.allowed_contexts(guilds=True, dms=True, private_channels=True)
@app_commands.allowed_installs(guilds=True, users=True)
class Livecontainer(commands.GroupCog, name="livecontainer"):
def __init__(self, bot) -> None:
self.bot = bot
super().__init__()
@commands.group(name="livecontainer", invoke_without_command=True)
async def livecontainer_group(self, context: Context):
embed = discord.Embed(
title="LiveContainer Commands",
description="Choose a command from the dropdown below to get help with specific issues:",
color=0x0169FF,
)
embed.set_author(
name="LiveContainer",
icon_url="https://raw.githubusercontent.com/LiveContainer/LiveContainer/main/screenshots/livecontainer_icon.png",
)
view = LivecontainerView(self.bot)
await context.send(embed=embed, view=view)
@livecontainer_group.command(name="help")
async def livecontainer_group_help(self, context: Context):
embed = discord.Embed(
title="LiveContainer Commands",
description="Choose a command from the dropdown below to get help with specific issues:",
color=0x0169FF,
)
embed.set_author(
name="LiveContainer",
icon_url="https://raw.githubusercontent.com/LiveContainer/LiveContainer/main/screenshots/livecontainer_icon.png",
)
view = LivecontainerView(self.bot)
await context.send(embed=embed, view=view)
@livecontainer_group.command(name="26jit")
async def livecontainer_group_26jit(self, context: Context):
await self._invoke_hybrid(context, "26jit")
async def _invoke_hybrid(self, context: Context, name: str):
command = self.bot.get_command(name)
if command is not None:
await context.invoke(command)
else:
await context.send(f"Unknown LiveContainer command: {name}")
def _require_group_prefix(context: Context) -> bool:
if getattr(context, "interaction", None):
return True
group = getattr(getattr(context, "cog", None), "qualified_name", "").lower()
if not group:
return True
prefix = context.prefix or ""
content = context.message.content.strip().lower()
return content.startswith(f"{prefix}{group} ")
@app_commands.command(name="help", description="LiveContainer troubleshooting help")
async def help(self, interaction: discord.Interaction):
embed = discord.Embed(
title="LiveContainer Commands",
description="Choose a command from the dropdown below to get help with specific issues:",
color=0x0169FF,
)
embed.set_author(
name="LiveContainer",
icon_url="https://raw.githubusercontent.com/LiveContainer/LiveContainer/main/screenshots/livecontainer_icon.png",
)
view = LivecontainerView(self.bot)
await interaction.response.send_message(embed=embed, view=view, ephemeral=True)
@commands.check(_require_group_prefix)
@commands.hybrid_command(
name="26jit", description="Walkthrough for iOS 26 JIT and sideloading"
)
async def jit26(self, context):
return await jit26_command()(self, context)
async def setup(bot) -> None:
cog = Livecontainer(bot)
await bot.add_cog(cog)
bot.logger.info("Loaded extension 'livecontainer.help'")
bot.logger.info("Loaded extension 'livecontainer.26jit'")

View File

@@ -0,0 +1,38 @@
import discord
from discord.ext.commands import Context
def jit26_command():
async def command(self, context: Context):
embed = discord.Embed(
color=0x0169FF,
description=(
"# 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."
),
)
embed.set_author(
name="LiveContainer",
icon_url="https://raw.githubusercontent.com/LiveContainer/LiveContainer/main/screenshots/livecontainer_icon.png",
)
embed.set_footer(
icon_url="https://yes.nighty.works/raw/2PPWd3.webp",
text="Made By CelloSerenity",
)
view = discord.ui.View()
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>",
)
)
if context.interaction:
await context.interaction.response.send_message(embed=embed, view=view)
else:
await context.send(embed=embed, view=view)
return command

View File

@@ -0,0 +1,90 @@
import discord
class LivecontainerSelect(discord.ui.Select):
def __init__(self, bot):
self.bot = bot
options = [
discord.SelectOption(
label="iOS 26 JIT & Sideloading",
value="26jit",
description="Walkthrough for iOS 26 JIT and sideloading",
),
]
super().__init__(
placeholder="Choose a LiveContainer command...", options=options
)
async def callback(self, interaction: discord.Interaction):
command_name = self.values[0]
command = self.bot.get_command(command_name)
if command:
try:
ctx = await self.bot.get_context(interaction.message)
if ctx:
await ctx.invoke(command)
embed = discord.Embed(
title="Command Executed",
description=f"Successfully executed `/{command_name}`",
color=0x00FF00,
)
embed.set_author(
name="LiveContainer",
icon_url="https://raw.githubusercontent.com/LiveContainer/LiveContainer/main/screenshots/livecontainer_icon.png",
)
await interaction.response.edit_message(embed=embed, view=None)
except discord.Forbidden:
guild_info = (
f"server {interaction.guild.name} (ID: {interaction.guild.id})"
if interaction.guild
else "DM or private channel"
)
self.bot.logger.warning(
f"Bot missing permissions in {guild_info} - cannot execute {command_name} command"
)
if interaction.guild is None:
embed = discord.Embed(
title="Error",
description="This command cannot be executed in DMs.",
color=0xFF0000,
)
else:
embed = discord.Embed(
title="Permission Error",
description="The bot needs the `send messages` permission to execute this command.",
color=0xFF0000,
)
embed.set_author(
name="LiveContainer",
icon_url="https://raw.githubusercontent.com/LiveContainer/LiveContainer/main/screenshots/livecontainer_icon.png",
)
await interaction.response.edit_message(embed=embed, view=None)
except Exception as e:
self.bot.logger.error(f"Error executing {command_name} command: {e}")
embed = discord.Embed(
title="Error",
description="An error occurred while executing the command.",
color=0xFF0000,
)
embed.set_author(
name="LiveContainer",
icon_url="https://raw.githubusercontent.com/LiveContainer/LiveContainer/main/screenshots/livecontainer_icon.png",
)
await interaction.response.edit_message(embed=embed, view=None)
else:
embed = discord.Embed(
title="Error", description="Command not found!", color=0xFF0000
)
embed.set_author(
name="LiveContainer",
icon_url="https://raw.githubusercontent.com/LiveContainer/LiveContainer/main/screenshots/livecontainer_icon.png",
)
await interaction.response.edit_message(embed=embed, view=None)
class LivecontainerView(discord.ui.View):
def __init__(self, bot):
super().__init__()
self.add_item(LivecontainerSelect(bot))

View File

@@ -4,7 +4,6 @@ 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
@@ -63,15 +62,12 @@ class Media(commands.GroupCog, name="media"):
) )
embed.add_field( embed.add_field(
name="Available", name="Available",
value="download, mcquote, img2gif, tweety, tts", value="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
@@ -86,10 +82,6 @@ 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)
@@ -108,14 +100,6 @@ 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",
@@ -153,7 +137,6 @@ 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'")

View File

@@ -1,531 +0,0 @@
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,4 +1,3 @@
import asyncio
import os import os
import tempfile import tempfile
import discord import discord

View File

@@ -1,6 +1,5 @@
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 as e: except Exception:
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=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)", 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)",
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=f"Connection error: Could not reach tweet API", description="Connection error: Could not reach tweet API",
color=0xE02B2B, color=0xE02B2B,
) )
embed.set_author( embed.set_author(

View File

@@ -1,8 +1,5 @@
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():
@@ -23,7 +20,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=f"Last Edited by Meshal :D") embed.set_footer(text="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,8 +1,5 @@
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():
@@ -26,7 +23,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=f"Last Edited by Meshal :D") embed.set_footer(text="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,8 +1,5 @@
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():
@@ -26,7 +23,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=f"Last Edited by Meshal :D") embed.set_footer(text="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,8 +1,5 @@
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():
@@ -38,7 +35,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=f"Last Edited by stossy11") embed.set_footer(text="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,8 +1,5 @@
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():
@@ -29,7 +26,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=f"Last Edited by Meshal :D") embed.set_footer(text="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,8 +1,5 @@
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():
@@ -24,7 +21,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=f"Last Edited by Meshal :D") embed.set_footer(text="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,8 +1,5 @@
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():
@@ -35,7 +32,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=f"Last Edited by Meshal :D") embed.set_footer(text="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,4 +57,3 @@ def upgrade_command():
await context.send(embed=embed, view=view) await context.send(embed=embed, view=view)
return upgrade return upgrade

View File

@@ -1,6 +1,5 @@
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,6 +1,5 @@
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,6 +1,5 @@
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,6 +1,4 @@
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,6 +1,5 @@
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,6 +1,5 @@
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():
@@ -52,7 +51,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=f"May look broken on mobile") embed.set_footer(text="May look broken on mobile")
if getattr(context, "interaction", None): if getattr(context, "interaction", None):
inter = context.interaction inter = context.interaction

View File

@@ -1,6 +1,5 @@
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,6 +1,5 @@
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,6 +1,5 @@
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,6 +1,4 @@
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,6 +1,5 @@
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,6 +1,4 @@
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,7 +3,6 @@ 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,7 +1,6 @@
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():
@@ -222,7 +221,7 @@ def ban_command():
) )
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
except Exception as e: except Exception:
embed = discord.Embed( embed = discord.Embed(
title="Error!", title="Error!",
description="An unexpected error occurred.", description="An unexpected error occurred.",

View File

@@ -1,7 +1,6 @@
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,7 +1,6 @@
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():
@@ -142,7 +141,7 @@ def kick_command():
) )
await context.send(embed=embed, ephemeral=True) await context.send(embed=embed, ephemeral=True)
except Exception as e: except Exception:
embed = discord.Embed( embed = discord.Embed(
title="Error!", title="Error!",
description="An unexpected error occurred.", description="An unexpected error occurred.",

View File

@@ -1,7 +1,6 @@
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,7 +1,6 @@
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 = f"logs.txt" log_file = "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,8 +1,5 @@
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():
@@ -15,15 +12,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 StosVPN is connected and updated\n" + "2. Make sure LocalDevVPN is connected and updated\n"
+ "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" + "3. If issue still persists, replace pairing file using `iloader`. See [Pairing File instructions](https://docs.sidestore.io/docs/advanced/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=f"Last Edited by CelloSerenity") embed.set_footer(text="Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
@@ -39,7 +36,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", url="https://docs.sidestore.io/docs/troubleshooting/common-issues/#afc-connection-failure--no-wi-fi-or-vpn-connection",
emoji="<:sidestorepride:1417717648795631787>", emoji="<:sidestorepride:1417717648795631787>",
) )
) )

View File

@@ -1,8 +1,5 @@
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():
@@ -34,7 +31,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=f"Last Edited by CelloSerenity") embed.set_footer(text="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,8 +1,5 @@
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():
@@ -15,12 +12,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 with AltServer's `Sideload .ipa`.\n" + "1. DON'T DELETE SIDESTORE, reinstall using iloader's Install `SideStore (Stable)` button.\n"
+ "If that doesn't work:\n" + "If that doesn't work:\n"
+ "1. Delete your current SideStore. Reinstall with AltServer.\n" + "1. Delete your current SideStore. Reinstall with iloader.\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."
), ),
) )
@@ -28,7 +25,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=f"Last Edited by CelloSerenity") embed.set_footer(text="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,8 +1,5 @@
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():
@@ -21,7 +18,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"
+ "- Recreate pairing file\n" + "- Replace pairing file\n"
+ "- Reinstall SideStore\n\n" + "- Reinstall SideStore\n\n"
), ),
) )
@@ -29,7 +26,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=f"Last Edited by CelloSerenity") embed.set_footer(text="Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
@@ -45,7 +42,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-halfway-through-installation", url="https://docs.sidestore.io/docs/troubleshooting/common-issues/#sidestore-hangs-partway-through-installation",
emoji="<:sidestorepride:1417717648795631787>", emoji="<:sidestorepride:1417717648795631787>",
) )
) )

View File

@@ -1,40 +1,22 @@
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( @commands.hybrid_command(name="pairing", description="Link to the pairing guide")
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=(
"# Cannot Choose Pairing File\n\n---\n\n" "# How to obtain your pairing file:\n\n---\n\n"
+ "1. **Check File Extension:**\n" + "[Click here](https://docs.sidestore.io/advanced/pairing-file) to read the SideStore documentation on replacing your pairing file.\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=f"Last Edited by CelloSerenity") embed.set_footer(text="Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
@@ -50,7 +32,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/troubleshooting/#cannot-choose-pairing-file", url="https://docs.sidestore.io/docs/advanced/pairing-file",
emoji="<:sidestorepride:1417717648795631787>", emoji="<:sidestorepride:1417717648795631787>",
) )
) )

View File

@@ -1,8 +1,5 @@
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():
@@ -15,16 +12,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 StosVPN app.\n" + "2. Verify VPN is connected in the LocalDevVPN app.\n"
+ "3. **Create a brand new pairing file.**\n" + "3. **Replace your 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" + " - 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"
), ),
) )
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=f"Last Edited by neoarz") embed.set_footer(text="Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
@@ -40,7 +37,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/installation/pairing-file", url="https://docs.sidestore.io/docs/advanced/pairing-file",
emoji="<:sidestorepride:1417717648795631787>", emoji="<:sidestorepride:1417717648795631787>",
) )
) )

View File

@@ -1,8 +1,5 @@
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():
@@ -28,7 +25,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=f"Last Edited by CelloSerenity") embed.set_footer(text="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,8 +1,5 @@
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,8 +1,5 @@
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():
@@ -23,7 +20,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=f"Last Edited by neoarz") 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()
@@ -39,7 +36,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/sparserestore", url="https://docs.sidestore.io/docs/advanced/alternative#sparserestore-3-app-limit",
emoji="<:sidestorepride:1417717648795631787>", emoji="<:sidestorepride:1417717648795631787>",
) )
) )

View File

@@ -1,8 +1,5 @@
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():
@@ -14,15 +11,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 create a new pairing file using `idevice_pair` and try again.\n\n" + "This error usually occurs when the pairing file is corrupted. Please replace your pairing file using `iloader` and try again.\n\n"
+ "If you forgot how to create a new pairing file, you can refer to the documentation below." + "If you forgot how to replace your 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=f"Last Edited by CelloSerenity") embed.set_footer(text="Last Edited by CelloSerenity")
embed.timestamp = discord.utils.utcnow() embed.timestamp = discord.utils.utcnow()
view = discord.ui.View() view = discord.ui.View()
@@ -38,7 +35,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/installation/pairing-file/", url="https://docs.sidestore.io/docs/advanced/pairing-file/",
emoji="<:sidestorepride:1417717648795631787>", emoji="<:sidestorepride:1417717648795631787>",
) )
) )

View File

@@ -1,10 +1,8 @@
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,7 +1,6 @@
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
@@ -38,7 +37,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 as e: except Exception:
return {"success": False, "error": "An unexpected error occurred"} return {"success": False, "error": "An unexpected error occurred"}
@commands.hybrid_command( @commands.hybrid_command(
@@ -124,7 +123,7 @@ def dictionary_command():
meanings = entry.get("meanings", []) meanings = entry.get("meanings", [])
embed = discord.Embed( embed = discord.Embed(
title=f"Dictionary", title="Dictionary",
description=f"**```{word_title}```**", description=f"**```{word_title}```**",
color=0x7289DA, color=0x7289DA,
) )

View File

@@ -1,12 +1,9 @@
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,7 +7,6 @@ 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,7 +2,6 @@ aiohttp
aiosqlite aiosqlite
discord.py discord.py
python-dotenv python-dotenv
yt-dlp
Pillow Pillow
pillow-heif pillow-heif
pytz pytz

View File

@@ -1,8 +1,6 @@
#!/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):