274 lines
13 KiB
Python
274 lines
13 KiB
Python
# ╔══════════════════════════════════════════════════════════════════╗
|
|
# ║ ║
|
|
# ║ +-+-+-+-+-+-+-+-+ ║
|
|
# ║ |H|e|x|a|H|o|s|t| ║
|
|
# ║ +-+-+-+-+-+-+-+-+ ║
|
|
# ║ ║
|
|
# ║ © 2026 HexaHost — All Rights Reserved ║
|
|
# ║ ║
|
|
# ║ discord ── https://discord.gg/hexahost ║
|
|
# ║ github ── https://github.com/theoneandonlymace ║
|
|
# ║ ║
|
|
# ╚══════════════════════════════════════════════════════════════════╝
|
|
|
|
import discord
|
|
from utils.emoji import DELETE
|
|
from discord.ext import commands
|
|
from discord import ui, ButtonStyle, SelectOption
|
|
from discord.ui import LayoutView, TextDisplay, Separator, ActionRow, MediaGallery
|
|
import requests
|
|
import asyncio
|
|
from utils.Tools import *
|
|
from utils.cv2 import CV2, build_container
|
|
from utils.config import *
|
|
class MapView(LayoutView):
|
|
def __init__(self, bot, location, ctx):
|
|
super().__init__(timeout=None)
|
|
self.bot = bot
|
|
self.location = location
|
|
self.ctx = ctx
|
|
self.zoom_level = 14
|
|
self.map_style = 'map'
|
|
self.map_size = '1200,900'
|
|
self.coordinates = self.get_coordinates(location)
|
|
self.latitude, self.longitude = None, None
|
|
if self.coordinates != (None, None):
|
|
self.latitude, self.longitude = float(self.coordinates[0]), float(self.coordinates[1])
|
|
|
|
self.update_map()
|
|
|
|
b_left = ui.Button(label="", emoji="⬅️", style=ButtonStyle.secondary)
|
|
b_left.callback = self.move_left
|
|
b_up = ui.Button(label="", emoji="⬆️", style=ButtonStyle.secondary)
|
|
b_up.callback = self.move_up
|
|
b_delete = ui.Button(label="", emoji=DELETE, style=ButtonStyle.danger)
|
|
b_delete.callback = self.delete_embed
|
|
b_down = ui.Button(label="", emoji="⬇️", style=ButtonStyle.secondary)
|
|
b_down.callback = self.move_down
|
|
b_right = ui.Button(label="", emoji="➡️", style=ButtonStyle.secondary)
|
|
b_right.callback = self.move_right
|
|
|
|
self.add_item(ActionRow(b_left, b_up, b_delete, b_down, b_right))
|
|
|
|
b_zin = ui.Button(label="Zoom In", style=ButtonStyle.primary)
|
|
b_zin.callback = self.zoom_in
|
|
b_zout = ui.Button(label="Zoom Out", style=ButtonStyle.primary)
|
|
b_zout.callback = self.zoom_out
|
|
b_coords = ui.Button(label="Enter Coordinates", style=ButtonStyle.primary)
|
|
b_coords.callback = self.enter_coordinates
|
|
b_addr = ui.Button(label="Enter Address", style=ButtonStyle.success)
|
|
b_addr.callback = self.enter_address
|
|
|
|
self.add_item(ActionRow(b_zin, b_zout, b_coords, b_addr))
|
|
|
|
self.add_item(ActionRow(MapStyleSelect(self)))
|
|
self.add_item(ActionRow(MapSizeSelect(self)))
|
|
|
|
self.build_ui()
|
|
|
|
def build_ui(self):
|
|
|
|
container = build_container(
|
|
TextDisplay(f"**Map of {self.location}**"),
|
|
Separator(visible=True),
|
|
TextDisplay(
|
|
f"🌐 **[Open in Webpage](https://www.openstreetmap.org/?mlat={self.latitude}&mlon={self.longitude}&zoom={self.zoom_level})**\n"
|
|
f"🔍 **Current Zoom Level:** {str(self.zoom_level)}\n"
|
|
f"🗺️ **Map Style:** {self.map_style}\n"
|
|
f"📏 **Map Size:** {self.map_size}\n"
|
|
f"📍 **Current Coordinates:** {self.latitude}, {self.longitude}"
|
|
)
|
|
)
|
|
|
|
gallery = MediaGallery()
|
|
gallery.add_item(media=self.map_url)
|
|
container.add_item(gallery)
|
|
|
|
|
|
self.children = [c for c in self.children if not isinstance(c, type(container))]
|
|
self.add_item(container)
|
|
|
|
|
|
def get_coordinates(self, location):
|
|
try:
|
|
headers = {'User-Agent': f'{BRAND_NAME} Bot (https://hexahost.dev)'}
|
|
response = requests.get(f'https://nominatim.openstreetmap.org/search?q={location}&format=json', headers=headers)
|
|
response.raise_for_status()
|
|
data = response.json()[0]
|
|
return data['lat'], data['lon']
|
|
except (requests.RequestException, IndexError) as e:
|
|
print(f"Failed to get coordinates: {e}")
|
|
return None, None
|
|
|
|
def update_map(self):
|
|
if self.latitude is None or self.longitude is None:
|
|
return
|
|
self.map_url = f'https://www.mapquestapi.com/staticmap/v5/map?key=E2SaL3qiTpXQ43nxZFBp0wzEnBI6pqbG¢er={self.latitude},{self.longitude}&zoom={self.zoom_level}&size={self.map_size}&type={self.map_style}'
|
|
self.build_ui()
|
|
|
|
async def update_embed(self, interaction: discord.Interaction):
|
|
if self.latitude is None or self.longitude is None:
|
|
await interaction.response.send_message("Failed to retrieve map data. Please try again.", ephemeral=True)
|
|
return
|
|
|
|
try:
|
|
await interaction.message.edit(view=self)
|
|
except Exception as e:
|
|
await interaction.response.send_message(f"Error updating message: {e}", ephemeral=True)
|
|
|
|
|
|
async def interaction_check(self, interaction: discord.Interaction) -> bool:
|
|
if interaction.user != self.ctx.author:
|
|
await interaction.response.send_message(
|
|
view=CV2("⚠️ Access Denied", "Sorry only the requested author can control this"),
|
|
ephemeral=True
|
|
)
|
|
return False
|
|
return True
|
|
|
|
async def move_left(self, interaction: discord.Interaction):
|
|
if self.longitude is not None:
|
|
self.longitude -= 0.01
|
|
self.update_map()
|
|
await self.update_embed(interaction)
|
|
await interaction.response.send_message(view=CV2("✅ Map Updated", "Moved left."), ephemeral=True)
|
|
|
|
async def move_up(self, interaction: discord.Interaction):
|
|
if self.latitude is not None:
|
|
self.latitude += 0.01
|
|
self.update_map()
|
|
await self.update_embed(interaction)
|
|
await interaction.response.send_message(view=CV2("✅ Map Updated", "Moved up."), ephemeral=True)
|
|
|
|
async def delete_embed(self, interaction: discord.Interaction):
|
|
try:
|
|
await interaction.message.delete()
|
|
except Exception as e:
|
|
await interaction.response.send_message(f"Error deleting message: {e}", ephemeral=True)
|
|
|
|
async def move_down(self, interaction: discord.Interaction):
|
|
if self.latitude is not None:
|
|
self.latitude -= 0.01
|
|
self.update_map()
|
|
await self.update_embed(interaction)
|
|
await interaction.response.send_message(view=CV2("✅ Map Updated", "Moved down."), ephemeral=True)
|
|
|
|
async def move_right(self, interaction: discord.Interaction):
|
|
if self.longitude is not None:
|
|
self.longitude += 0.01
|
|
self.update_map()
|
|
await self.update_embed(interaction)
|
|
await interaction.response.send_message(view=CV2("✅ Map Updated", "Moved right."), ephemeral=True)
|
|
|
|
async def zoom_in(self, interaction: discord.Interaction):
|
|
print("Zooming in")
|
|
self.zoom_level = min(self.zoom_level + 1, 18)
|
|
self.update_map()
|
|
await self.update_embed(interaction)
|
|
await interaction.response.send_message(view=CV2("✅ Map Updated", "Zoomed in."), ephemeral=True)
|
|
|
|
async def zoom_out(self, interaction: discord.Interaction):
|
|
print("Zooming out")
|
|
self.zoom_level = max(self.zoom_level - 1, 0)
|
|
self.update_map()
|
|
await self.update_embed(interaction)
|
|
await interaction.response.send_message(view=CV2("✅ Map Updated", "Zoomed Out."), ephemeral=True)
|
|
|
|
async def enter_coordinates(self, interaction: discord.Interaction):
|
|
await interaction.response.send_message("Please enter the coordinates (latitude, longitude):", ephemeral=True)
|
|
|
|
def check(message):
|
|
return message.author == interaction.user and message.channel == interaction.channel
|
|
|
|
try:
|
|
coords_msg = await self.bot.wait_for('message', check=check, timeout=60)
|
|
coords = coords_msg.content.split(',')
|
|
if len(coords) == 2:
|
|
self.latitude, self.longitude = float(coords[0].strip()), float(coords[1].strip())
|
|
self.update_map()
|
|
await self.update_embed(interaction)
|
|
await interaction.followup.send(view=CV2("✅ Map Updated", "Coordinates updated."), ephemeral=True)
|
|
else:
|
|
await interaction.followup.send("Invalid coordinates format. Please enter in the format 'latitude, longitude'.", ephemeral=True)
|
|
except asyncio.TimeoutError:
|
|
await interaction.followup.send("You took too long to respond. Please try again.", ephemeral=True)
|
|
|
|
async def enter_address(self, interaction: discord.Interaction):
|
|
await interaction.response.send_message("Please enter the address:", ephemeral=True)
|
|
|
|
def check(message):
|
|
return message.author == interaction.user and message.channel == interaction.channel
|
|
|
|
try:
|
|
address_msg = await self.bot.wait_for('message', check=check, timeout=60)
|
|
address = address_msg.content
|
|
self.coordinates = self.get_coordinates(address)
|
|
if self.coordinates == (None, None):
|
|
await interaction.followup.send("Failed to retrieve coordinates for the address. Please try again.", ephemeral=True)
|
|
else:
|
|
self.latitude, self.longitude = float(self.coordinates[0]), float(self.coordinates[1])
|
|
self.location = address
|
|
self.update_map()
|
|
await self.update_embed(interaction)
|
|
await interaction.followup.send(view=CV2("✅ Map Updated", "Address updated."), ephemeral=True)
|
|
except asyncio.TimeoutError:
|
|
await interaction.followup.send("You took too long to respond. Please try again.", ephemeral=True)
|
|
|
|
|
|
class MapStyleSelect(ui.Select):
|
|
def __init__(self, map_view):
|
|
super().__init__(placeholder='Select Map Style')
|
|
self.map_view = map_view
|
|
options = [
|
|
SelectOption(label='Map', value='map'),
|
|
SelectOption(label='Satellite', value='sat'),
|
|
SelectOption(label='Hybrid', value='hyb'),
|
|
SelectOption(label='Light', value='light'),
|
|
SelectOption(label='Dark', value='dark'),
|
|
]
|
|
self.options = options
|
|
|
|
async def callback(self, interaction: discord.Interaction):
|
|
print(f"Changing map style to {self.values[0]}")
|
|
self.map_view.map_style = self.values[0]
|
|
self.map_view.update_map()
|
|
await self.map_view.update_embed(interaction)
|
|
await interaction.response.send_message(view=CV2("✅ Map Updated", "Map style updated successfully."), ephemeral=True)
|
|
|
|
class MapSizeSelect(ui.Select):
|
|
def __init__(self, map_view):
|
|
super().__init__(placeholder='Select Map Size')
|
|
self.map_view = map_view
|
|
options = [
|
|
SelectOption(label='400x300', value='400,300'),
|
|
SelectOption(label='800x600', value='800,600'),
|
|
SelectOption(label='1200x900', value='1200,900')
|
|
]
|
|
self.options = options
|
|
|
|
async def callback(self, interaction: discord.Interaction):
|
|
print(f"Changing map size to {self.values[0]}")
|
|
self.map_view.map_size = self.values[0]
|
|
self.map_view.update_map()
|
|
await self.map_view.update_embed(interaction)
|
|
await interaction.response.send_message(view=CV2("✅ Map Updated", "Map size updated successfully."), ephemeral=True)
|
|
|
|
|
|
class Map(commands.Cog):
|
|
def __init__(self, bot):
|
|
self.bot = bot
|
|
|
|
@commands.hybrid_command(name="map", help="Shows a map of a location", usage="<location>", description="Shows a map of a location")
|
|
@blacklist_check()
|
|
@ignore_check()
|
|
@commands.cooldown(1, 5, commands.BucketType.user)
|
|
async def map(self, ctx, *, location: str):
|
|
view = MapView(self.bot, location, ctx)
|
|
if view.coordinates == (None, None):
|
|
await ctx.send(view=CV2("❌ Error", "Failed to retrieve coordinates for the location. Please try again."))
|
|
return
|
|
await ctx.send(view=view)
|
|
|
|
async def setup(bot):
|
|
await bot.add_cog(Map(bot))
|