such cleanup
This commit is contained in:
parent
d60828df07
commit
9d23438b13
@ -14,14 +14,14 @@ import regex
|
|||||||
from regex import Pattern
|
from regex import Pattern
|
||||||
from aiohttp import ClientSession, ClientTimeout
|
from aiohttp import ClientSession, ClientTimeout
|
||||||
from discord.ext import bridge, commands, tasks
|
from discord.ext import bridge, commands, tasks
|
||||||
|
from disc_havoc import Havoc
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Util:
|
class Util:
|
||||||
"""Karma Utility"""
|
"""Karma Utility"""
|
||||||
def __init__(self, bot):
|
def __init__(self, bot: Havoc):
|
||||||
self.bot = bot
|
self.bot: Havoc = bot
|
||||||
self.api_key: str = constants.PRV_API_KEY
|
self.api_key: str = constants.PRV_API_KEY
|
||||||
self.karma_endpoints_base_url: str = "https://api.codey.lol/karma/"
|
self.karma_endpoints_base_url: str = "https://api.codey.lol/karma/"
|
||||||
self.karma_retrieval_url: str = f"{self.karma_endpoints_base_url}get"
|
self.karma_retrieval_url: str = f"{self.karma_endpoints_base_url}get"
|
||||||
@ -146,9 +146,9 @@ class Util:
|
|||||||
|
|
||||||
class Karma(commands.Cog):
|
class Karma(commands.Cog):
|
||||||
"""Karma Cog for Havoc"""
|
"""Karma Cog for Havoc"""
|
||||||
def __init__(self, bot):
|
def __init__(self, bot: Havoc):
|
||||||
importlib.reload(constants)
|
importlib.reload(constants)
|
||||||
self.bot: discord.Bot = bot
|
self.bot: Havoc = bot
|
||||||
self.util = Util(self.bot)
|
self.util = Util(self.bot)
|
||||||
# self.karma_regex = regex.compile(r'(\w+)(\+\+|\-\-)')
|
# self.karma_regex = regex.compile(r'(\w+)(\+\+|\-\-)')
|
||||||
self.karma_regex: Pattern = regex.compile(r'(\b\w+(?:\s+\w+)*)(\+\+($|\s)|\-\-($|\s))')
|
self.karma_regex: Pattern = regex.compile(r'(\b\w+(?:\s+\w+)*)(\+\+($|\s)|\-\-($|\s))')
|
||||||
|
@ -10,12 +10,12 @@ import aiosqlite as sqlite3
|
|||||||
from discord.ext import bridge, commands
|
from discord.ext import bridge, commands
|
||||||
from util.lovehate_db import DB
|
from util.lovehate_db import DB
|
||||||
from constructors import LoveHateException
|
from constructors import LoveHateException
|
||||||
|
from disc_havoc import Havoc
|
||||||
|
|
||||||
class LoveHate(commands.Cog):
|
class LoveHate(commands.Cog):
|
||||||
"""LoveHate Cog for Havoc"""
|
"""LoveHate Cog for Havoc"""
|
||||||
def __init__(self, bot):
|
def __init__(self, bot: Havoc) -> None:
|
||||||
self.bot: discord.Bot = bot
|
self.bot: Havoc = bot
|
||||||
self.db = DB(self.bot)
|
self.db = DB(self.bot)
|
||||||
|
|
||||||
def join_with_and(self, items: list) -> str:
|
def join_with_and(self, items: list) -> str:
|
||||||
|
205
cogs/meme.py
205
cogs/meme.py
@ -6,12 +6,13 @@ import json
|
|||||||
import io
|
import io
|
||||||
import asyncio
|
import asyncio
|
||||||
import random
|
import random
|
||||||
from typing import LiteralString, Optional
|
from typing import LiteralString, Optional, Any
|
||||||
import logging
|
import logging
|
||||||
import textwrap
|
import textwrap
|
||||||
import regex
|
import regex
|
||||||
import requests
|
import requests
|
||||||
import discord
|
import discord
|
||||||
|
from disc_havoc import Havoc
|
||||||
from aiohttp import ClientSession
|
from aiohttp import ClientSession
|
||||||
from discord.ext import bridge, commands, tasks
|
from discord.ext import bridge, commands, tasks
|
||||||
from jesusmemes import JesusMemeGenerator
|
from jesusmemes import JesusMemeGenerator
|
||||||
@ -56,6 +57,8 @@ class MemeView(discord.ui.View):
|
|||||||
async def select_callback(self, select: discord.ui.Select,
|
async def select_callback(self, select: discord.ui.Select,
|
||||||
interaction: discord.Interaction) -> None:
|
interaction: discord.Interaction) -> None:
|
||||||
"""Meme Selection Callback"""
|
"""Meme Selection Callback"""
|
||||||
|
if not isinstance(select.values[0], str):
|
||||||
|
return
|
||||||
modal: discord.ui.Modal = MemeModal(meme=select.values[0], title="Meme Selected")
|
modal: discord.ui.Modal = MemeModal(meme=select.values[0], title="Meme Selected")
|
||||||
await interaction.response.send_modal(modal)
|
await interaction.response.send_modal(modal)
|
||||||
|
|
||||||
@ -63,7 +66,7 @@ class MemeModal(discord.ui.Modal):
|
|||||||
"""Meme Creation discord.ui.Modal"""
|
"""Meme Creation discord.ui.Modal"""
|
||||||
def __init__(self, *args, meme: Optional[str] = None, **kwargs) -> None:
|
def __init__(self, *args, meme: Optional[str] = None, **kwargs) -> None:
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.selected_meme: str = meme
|
self.selected_meme: Optional[str] = meme
|
||||||
self.meme_generator = JesusMemeGenerator()
|
self.meme_generator = JesusMemeGenerator()
|
||||||
self.TEXT_LIMIT: int = 80
|
self.TEXT_LIMIT: int = 80
|
||||||
|
|
||||||
@ -73,7 +76,14 @@ class MemeModal(discord.ui.Modal):
|
|||||||
style=discord.InputTextStyle.singleline))
|
style=discord.InputTextStyle.singleline))
|
||||||
|
|
||||||
async def callback(self, interaction: discord.Interaction) -> None:
|
async def callback(self, interaction: discord.Interaction) -> None:
|
||||||
|
if not self.selected_meme: # No meme selected
|
||||||
|
return
|
||||||
selected_meme: str = self.selected_meme
|
selected_meme: str = self.selected_meme
|
||||||
|
if not self.children or len(self.children) < 2: # Invalid request
|
||||||
|
return
|
||||||
|
if not isinstance(self.children[0].value, str)\
|
||||||
|
or not isinstance(self.children[1].value, str): # Invalid request
|
||||||
|
return
|
||||||
meme_top_line: str = self.children[0].value.strip()
|
meme_top_line: str = self.children[0].value.strip()
|
||||||
meme_bottom_line: str = self.children[1].value.strip()
|
meme_bottom_line: str = self.children[1].value.strip()
|
||||||
if len(meme_top_line) > self.TEXT_LIMIT or len(meme_bottom_line) > self.TEXT_LIMIT:
|
if len(meme_top_line) > self.TEXT_LIMIT or len(meme_bottom_line) > self.TEXT_LIMIT:
|
||||||
@ -85,18 +95,18 @@ class MemeModal(discord.ui.Modal):
|
|||||||
|
|
||||||
embed: discord.Embed = discord.Embed(title="Generated Meme")
|
embed: discord.Embed = discord.Embed(title="Generated Meme")
|
||||||
embed.set_image(url=meme_link)
|
embed.set_image(url=meme_link)
|
||||||
embed.add_field(name="Meme", value=self.selected_meme, inline=True)
|
embed.add_field(name="Meme", value=selected_meme, inline=True)
|
||||||
await interaction.response.send_message(embeds=[embed])
|
await interaction.response.send_message(embeds=[embed])
|
||||||
return
|
return
|
||||||
|
|
||||||
class Meme(commands.Cog):
|
class Meme(commands.Cog):
|
||||||
"""Meme Cog for Havoc"""
|
"""Meme Cog for Havoc"""
|
||||||
|
|
||||||
def __init__(self, bot) -> None:
|
def __init__(self, bot: Havoc) -> None:
|
||||||
self.bot: discord.Bot = bot
|
self.bot: Havoc = bot
|
||||||
self.meme_choices: list = []
|
self.meme_choices: list = []
|
||||||
self.meme_counter: int = 0
|
self.meme_counter: int = 0
|
||||||
self.THREADS: dict[dict[list]] = {
|
self.THREADS: dict[str, dict[int, list]] = {
|
||||||
# Format: Guild1: [ChanId : [Webhook, ThreadId], Guild2: [ChanId : [Webhook, ThreadId]
|
# Format: Guild1: [ChanId : [Webhook, ThreadId], Guild2: [ChanId : [Webhook, ThreadId]
|
||||||
'comic_explosm': {
|
'comic_explosm': {
|
||||||
1298729744216359055: [constants.EXPLOSM_WEBHOOK, 1299165855493390367],
|
1298729744216359055: [constants.EXPLOSM_WEBHOOK, 1299165855493390367],
|
||||||
@ -120,7 +130,7 @@ class Meme(commands.Cog):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.NO_THREAD_WEBHOOKS: dict[list] = {
|
self.NO_THREAD_WEBHOOKS: dict[str, list] = {
|
||||||
'theonion': [constants.ONION_WEBHOOK, constants.ONION_WEBHOOK2],
|
'theonion': [constants.ONION_WEBHOOK, constants.ONION_WEBHOOK2],
|
||||||
'thn': [constants.THN_WEBHOOK],
|
'thn': [constants.THN_WEBHOOK],
|
||||||
'memes': [constants.MEME_WEBHOOK1, constants.MEME_WEBHOOK2],
|
'memes': [constants.MEME_WEBHOOK1, constants.MEME_WEBHOOK2],
|
||||||
@ -132,7 +142,7 @@ class Meme(commands.Cog):
|
|||||||
self.meme_stream_loop.start()
|
self.meme_stream_loop.start()
|
||||||
self.explosm_loop.start()
|
self.explosm_loop.start()
|
||||||
|
|
||||||
def is_spamchan() -> bool: # pylint: disable=no-method-argument
|
def is_spamchan() -> bool: # type: ignore
|
||||||
"""Check if channel is spamchan"""
|
"""Check if channel is spamchan"""
|
||||||
def predicate(ctx):
|
def predicate(ctx):
|
||||||
try:
|
try:
|
||||||
@ -142,7 +152,7 @@ class Meme(commands.Cog):
|
|||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return False
|
return False
|
||||||
return commands.check(predicate)
|
return commands.check(predicate) # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -163,39 +173,43 @@ class Meme(commands.Cog):
|
|||||||
dino_grabber = dinog.DinosaurGrabber()
|
dino_grabber = dinog.DinosaurGrabber()
|
||||||
onion_grabber = oniong.OnionGrabber()
|
onion_grabber = oniong.OnionGrabber()
|
||||||
thn_grabber = thng.THNGrabber()
|
thn_grabber = thng.THNGrabber()
|
||||||
explosm_comics = xkcd_comics = smbc_comics = qc_comics = dino_comics\
|
explosm_comics: list[Optional[tuple]] = []
|
||||||
= onions = thns = []
|
xkcd_comics: list[Optional[tuple]] = []
|
||||||
memes: list[tuple] = await meme_grabber.get()
|
smbc_comics: list[Optional[tuple]] = []
|
||||||
|
dino_comics: list[Optional[tuple]] = []
|
||||||
|
onions: list[Optional[tuple]] = []
|
||||||
|
thns: list[Optional[tuple]] = []
|
||||||
|
memes: list[Optional[tuple]] = await meme_grabber.get()
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
explosm_comics: list[tuple] = await explosm_grabber.get()
|
explosm_comics = await explosm_grabber.get()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
xkcd_comics: list[tuple] = await xkcd_grabber.get()
|
xkcd_comics = await xkcd_grabber.get()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
smbc_comics: list[tuple] = await smbc_grabber.get()
|
smbc_comics = await smbc_grabber.get()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
qc_comics: list[tuple] = await qc_grabber.get()
|
qc_comics = await qc_grabber.get()
|
||||||
print(f"QC: {qc_comics}")
|
print(f"QC: {qc_comics}")
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
dino_comics: list[tuple] = await dino_grabber.get()
|
dino_comics = await dino_grabber.get()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.debug("Dino failed: %s", str(e))
|
logging.debug("Dino failed: %s", str(e))
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
onions: list[tuple] = await onion_grabber.get()
|
onions = await onion_grabber.get()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.debug("Onion failed: %s", str(e))
|
logging.debug("Onion failed: %s", str(e))
|
||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
thns: list[tuple] = await thn_grabber.get()
|
thns = await thn_grabber.get()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.debug("THNs failed: %s", str(e))
|
logging.debug("THNs failed: %s", str(e))
|
||||||
pass
|
pass
|
||||||
@ -208,12 +222,14 @@ class Meme(commands.Cog):
|
|||||||
if not only_comics:
|
if not only_comics:
|
||||||
try:
|
try:
|
||||||
for meme in memes:
|
for meme in memes:
|
||||||
|
if not meme:
|
||||||
|
continue
|
||||||
(meme_id, meme_title, meme_url) = meme # pylint: disable=unused-variable
|
(meme_id, meme_title, meme_url) = meme # pylint: disable=unused-variable
|
||||||
request = requests.get(meme_url, stream=True, timeout=(5, 30), headers=headers)
|
request = requests.get(meme_url, stream=True, timeout=(5, 30), headers=headers)
|
||||||
if not request.status_code == 200:
|
if not request.status_code == 200:
|
||||||
continue
|
continue
|
||||||
meme_content: bytes = request.raw.read()
|
meme_content: bytes = request.raw.read()
|
||||||
for meme_hook in self.NO_THREAD_WEBHOOKS.get('memes'):
|
for meme_hook in self.NO_THREAD_WEBHOOKS.get('memes', {}):
|
||||||
meme_image: io.BytesIO = io.BytesIO(meme_content)
|
meme_image: io.BytesIO = io.BytesIO(meme_content)
|
||||||
ext: str = meme_url.split(".")[-1]\
|
ext: str = meme_url.split(".")[-1]\
|
||||||
.split("?")[0].split("&")[0]
|
.split("?")[0].split("&")[0]
|
||||||
@ -227,24 +243,27 @@ class Meme(commands.Cog):
|
|||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
for comic in explosm_comics:
|
for comic in explosm_comics:
|
||||||
|
if not comic:
|
||||||
|
continue
|
||||||
(comic_title, comic_url) = comic
|
(comic_title, comic_url) = comic
|
||||||
comic_title: str = discord.utils.escape_markdown(comic_title)
|
comic_title = discord.utils.escape_markdown(comic_title)
|
||||||
comic_request = requests.get(comic_url, stream=True, timeout=(5, 20), headers=headers)
|
comic_request = requests.get(comic_url, stream=True, timeout=(5, 20), headers=headers)
|
||||||
comic_request.raise_for_status()
|
comic_request.raise_for_status()
|
||||||
comic_content: bytes = comic_request.raw.read()
|
comic_content: bytes = comic_request.raw.read()
|
||||||
ext: str = comic_url.split(".")[-1]\
|
ext = comic_url.split(".")[-1]\
|
||||||
.split("?")[0].split("&")[0]
|
.split("?")[0].split("&")[0]
|
||||||
|
|
||||||
async with ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
for chanid, _hook in self.THREADS.get('comic_explosm').items():
|
for chanid, _hook in self.THREADS.get('comic_explosm', {}).items():
|
||||||
comic_image: io.BytesIO = io.BytesIO(comic_content)
|
comic_image: io.BytesIO = io.BytesIO(comic_content)
|
||||||
channel: int = chanid
|
channel: int = chanid
|
||||||
hook_uri: str = _hook[0]
|
(hook_uri, thread_id) = _hook
|
||||||
thread_id: int = _hook[1]
|
webhook = discord.Webhook.from_url(hook_uri,
|
||||||
webhook: discord.Webhook = discord.Webhook.from_url(hook_uri,
|
|
||||||
session=session)
|
session=session)
|
||||||
thread: discord.Thread = self.bot.get_channel(channel)\
|
_channel: Any = self.bot.get_channel(channel)
|
||||||
.get_thread(thread_id)
|
if not _channel:
|
||||||
|
return
|
||||||
|
thread = _channel.get_thread(thread_id)
|
||||||
await webhook.send(f"**{comic_title}**", file=discord.File(comic_image, filename=f'img.{ext}'),
|
await webhook.send(f"**{comic_title}**", file=discord.File(comic_image, filename=f'img.{ext}'),
|
||||||
username="Cyanide & Happiness", thread=thread)
|
username="Cyanide & Happiness", thread=thread)
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
@ -252,25 +271,28 @@ class Meme(commands.Cog):
|
|||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
for comic in xkcd_comics:
|
for comic in xkcd_comics:
|
||||||
|
if not comic:
|
||||||
|
continue
|
||||||
(comic_title, comic_url) = comic
|
(comic_title, comic_url) = comic
|
||||||
comic_title: str = discord.utils.escape_markdown(comic_title)
|
comic_title = discord.utils.escape_markdown(comic_title)
|
||||||
comic_request = requests.get(comic_url, stream=True, timeout=(5, 20), headers=headers)
|
comic_request = requests.get(comic_url, stream=True, timeout=(5, 20), headers=headers)
|
||||||
comic_request.raise_for_status()
|
comic_request.raise_for_status()
|
||||||
comic_content: bytes = comic_request.raw.read()
|
comic_content = comic_request.raw.read()
|
||||||
comic_image: io.BytesIO = io.BytesIO(comic_request.raw.read())
|
comic_image = io.BytesIO(comic_request.raw.read())
|
||||||
ext: str = comic_url.split(".")[-1]\
|
ext = comic_url.split(".")[-1]\
|
||||||
.split("?")[0].split("&")[0]
|
.split("?")[0].split("&")[0]
|
||||||
|
|
||||||
async with ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
for chanid, _hook in self.THREADS.get('comic_xkcd').items():
|
for chanid, _hook in self.THREADS.get('comic_xkcd', {}).items():
|
||||||
comic_image: io.BytesIO = io.BytesIO(comic_content)
|
comic_image = io.BytesIO(comic_content)
|
||||||
channel: int = chanid
|
channel = chanid
|
||||||
hook_uri: str = _hook[0]
|
(hook_uri, thread_id) = _hook
|
||||||
thread_id: int = _hook[1]
|
webhook = discord.Webhook.from_url(hook_uri,
|
||||||
webhook: discord.Webhook = discord.Webhook.from_url(hook_uri,
|
|
||||||
session=session)
|
session=session)
|
||||||
thread: discord.Thread = self.bot.get_channel(channel)\
|
_channel = self.bot.get_channel(channel)
|
||||||
.get_thread(thread_id)
|
if not _channel:
|
||||||
|
return
|
||||||
|
thread = _channel.get_thread(thread_id)
|
||||||
await webhook.send(f"**{comic_title}**", file=discord.File(comic_image, filename=f'img.{ext}'),
|
await webhook.send(f"**{comic_title}**", file=discord.File(comic_image, filename=f'img.{ext}'),
|
||||||
username="xkcd", thread=thread)
|
username="xkcd", thread=thread)
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
@ -278,24 +300,27 @@ class Meme(commands.Cog):
|
|||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
for comic in smbc_comics:
|
for comic in smbc_comics:
|
||||||
|
if not comic:
|
||||||
|
continue
|
||||||
(comic_title, comic_url) = comic
|
(comic_title, comic_url) = comic
|
||||||
comic_title: str = discord.utils.escape_markdown(comic_title)
|
comic_title = discord.utils.escape_markdown(comic_title)
|
||||||
comic_request = requests.get(comic_url, stream=True, timeout=(5, 20), headers=headers)
|
comic_request = requests.get(comic_url, stream=True, timeout=(5, 20), headers=headers)
|
||||||
comic_request.raise_for_status()
|
comic_request.raise_for_status()
|
||||||
comic_content: bytes = comic_request.raw.read()
|
comic_content = comic_request.raw.read()
|
||||||
ext: str = comic_url.split(".")[-1]\
|
ext = comic_url.split(".")[-1]\
|
||||||
.split("?")[0].split("&")[0]
|
.split("?")[0].split("&")[0]
|
||||||
|
|
||||||
async with ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
for chanid, _hook in self.THREADS.get('comic_smbc').items():
|
for chanid, _hook in self.THREADS.get('comic_smbc', {}).items():
|
||||||
comic_image: io.BytesIO = io.BytesIO(comic_content)
|
comic_image = io.BytesIO(comic_content)
|
||||||
channel: int = chanid
|
channel = chanid
|
||||||
hook_uri: str = _hook[0]
|
(hook_uri, thread_id) = _hook
|
||||||
thread_id: int = _hook[1]
|
webhook = discord.Webhook.from_url(hook_uri,
|
||||||
webhook: discord.Webhook = discord.Webhook.from_url(hook_uri,
|
|
||||||
session=session)
|
session=session)
|
||||||
thread = self.bot.get_channel(channel)\
|
_channel = self.bot.get_channel(channel)
|
||||||
.get_thread(thread_id)
|
if not _channel:
|
||||||
|
return
|
||||||
|
thread = _channel.get_thread(thread_id)
|
||||||
await webhook.send(f"**{comic_title}**", file=discord.File(comic_image, filename=f'img.{ext}'),
|
await webhook.send(f"**{comic_title}**", file=discord.File(comic_image, filename=f'img.{ext}'),
|
||||||
username="SMBC", thread=thread)
|
username="SMBC", thread=thread)
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
@ -304,29 +329,32 @@ class Meme(commands.Cog):
|
|||||||
try:
|
try:
|
||||||
for comic in qc_comics:
|
for comic in qc_comics:
|
||||||
logging.debug("Trying QC...")
|
logging.debug("Trying QC...")
|
||||||
|
if not comic:
|
||||||
|
continue
|
||||||
(comic_title, comic_url) = comic
|
(comic_title, comic_url) = comic
|
||||||
comic_title: str = discord.utils.escape_markdown(comic_title)
|
comic_title = discord.utils.escape_markdown(comic_title)
|
||||||
comic_url: str = regex.sub(r'^http://ww\.', 'http://www.',
|
comic_url = regex.sub(r'^http://ww\.', 'http://www.',
|
||||||
comic_url)
|
comic_url)
|
||||||
comic_url: str = regex.sub(r'\.pmg$', '.png',
|
comic_url = regex.sub(r'\.pmg$', '.png',
|
||||||
comic_url)
|
comic_url)
|
||||||
comic_request = requests.get(comic_url, stream=True,
|
comic_request = requests.get(comic_url, stream=True,
|
||||||
timeout=(5, 20), headers=headers)
|
timeout=(5, 20), headers=headers)
|
||||||
comic_request.raise_for_status()
|
comic_request.raise_for_status()
|
||||||
comic_content: bytes = comic_request.raw.read()
|
comic_content = comic_request.raw.read()
|
||||||
ext: str = comic_url.split(".")[-1]\
|
ext = comic_url.split(".")[-1]\
|
||||||
.split("?")[0].split("&")[0]
|
.split("?")[0].split("&")[0]
|
||||||
|
|
||||||
async with ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
for chanid, _hook in self.THREADS.get('comic_qc').items():
|
for chanid, _hook in self.THREADS.get('comic_qc', {}).items():
|
||||||
comic_image: io.BytesIO = io.BytesIO(comic_content)
|
comic_image = io.BytesIO(comic_content)
|
||||||
channel: int = chanid
|
channel = chanid
|
||||||
hook_uri: str = _hook[0]
|
(hook_uri, thread_id) = _hook
|
||||||
thread_id: int = _hook[1]
|
webhook = discord.Webhook.from_url(hook_uri,
|
||||||
webhook: discord.Webhook = discord.Webhook.from_url(hook_uri,
|
|
||||||
session=session)
|
session=session)
|
||||||
thread: discord.Thread = self.bot.get_channel(channel)\
|
_channel = self.bot.get_channel(channel)
|
||||||
.get_thread(thread_id)
|
if not _channel:
|
||||||
|
return
|
||||||
|
thread = _channel.get_thread(thread_id)
|
||||||
await webhook.send(f"**{comic_title}**", file=discord.File(comic_image, filename=f'img.{ext}'),
|
await webhook.send(f"**{comic_title}**", file=discord.File(comic_image, filename=f'img.{ext}'),
|
||||||
username="Questionable Content", thread=thread)
|
username="Questionable Content", thread=thread)
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
@ -335,24 +363,27 @@ class Meme(commands.Cog):
|
|||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
for comic in dino_comics:
|
for comic in dino_comics:
|
||||||
|
if not comic:
|
||||||
|
continue
|
||||||
(comic_title, comic_url) = comic
|
(comic_title, comic_url) = comic
|
||||||
comic_title: str = discord.utils.escape_markdown(comic_title)
|
comic_title = discord.utils.escape_markdown(comic_title)
|
||||||
comic_request = requests.get(comic_url, stream=True, timeout=(5, 20), headers=headers)
|
comic_request = requests.get(comic_url, stream=True, timeout=(5, 20), headers=headers)
|
||||||
comic_request.raise_for_status()
|
comic_request.raise_for_status()
|
||||||
comic_content: bytes = comic_request.raw.read()
|
comic_content = comic_request.raw.read()
|
||||||
ext = comic_url.split(".")[-1]\
|
ext = comic_url.split(".")[-1]\
|
||||||
.split("?")[0].split("&")[0]
|
.split("?")[0].split("&")[0]
|
||||||
|
|
||||||
async with ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
for chanid, _hook in self.THREADS.get('comic_dino').items():
|
for chanid, _hook in self.THREADS.get('comic_dino', {}).items():
|
||||||
comic_image: io.BytesIO = io.BytesIO(comic_content)
|
comic_image = io.BytesIO(comic_content)
|
||||||
channel: int = chanid
|
channel = chanid
|
||||||
hook_uri: str = _hook[0]
|
(hook_uri, thread_id) = _hook
|
||||||
thread_id: int = _hook[1]
|
webhook = discord.Webhook.from_url(hook_uri,
|
||||||
webhook: discord.Webhook = discord.Webhook.from_url(hook_uri,
|
|
||||||
session=session)
|
session=session)
|
||||||
thread: discord.Thread = self.bot.get_channel(channel)\
|
_channel = self.bot.get_channel(channel)
|
||||||
.get_thread(thread_id)
|
if not _channel:
|
||||||
|
return
|
||||||
|
thread = _channel.get_thread(thread_id)
|
||||||
await webhook.send(f"**{comic_title}**", file=discord.File(comic_image, filename=f'img.{ext}'),
|
await webhook.send(f"**{comic_title}**", file=discord.File(comic_image, filename=f'img.{ext}'),
|
||||||
username="Dinosaur Comics", thread=thread)
|
username="Dinosaur Comics", thread=thread)
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
@ -360,15 +391,17 @@ class Meme(commands.Cog):
|
|||||||
pass
|
pass
|
||||||
try:
|
try:
|
||||||
for onion in onions:
|
for onion in onions:
|
||||||
|
if not onion:
|
||||||
|
continue
|
||||||
(onion_title, onion_description, onion_link, onion_video) = onion
|
(onion_title, onion_description, onion_link, onion_video) = onion
|
||||||
onion_description: list[str] = textwrap.wrap(text=onion_description,
|
onion_description = textwrap.wrap(text=onion_description,
|
||||||
width=860, max_lines=1)[0]
|
width=860, max_lines=1)[0]
|
||||||
embed: discord.Embed = discord.Embed(title=onion_title)
|
embed: discord.Embed = discord.Embed(title=onion_title)
|
||||||
embed.add_field(name="Content", value=f"{onion_description[0:960]}\n-# {onion_link}")
|
embed.add_field(name="Content", value=f"{onion_description[0:960]}\n-# {onion_link}")
|
||||||
async with ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
for hook in self.NO_THREAD_WEBHOOKS.get('theonion'):
|
for hook in self.NO_THREAD_WEBHOOKS.get('theonion', {}):
|
||||||
hook_uri: str = hook
|
hook_uri = hook
|
||||||
webhook: discord.Webhook = discord.Webhook.from_url(hook_uri,
|
webhook = discord.Webhook.from_url(hook_uri,
|
||||||
session=session)
|
session=session)
|
||||||
await webhook.send(embed=embed, username="The Onion")
|
await webhook.send(embed=embed, username="The Onion")
|
||||||
if onion_video:
|
if onion_video:
|
||||||
@ -379,16 +412,18 @@ class Meme(commands.Cog):
|
|||||||
try:
|
try:
|
||||||
for thn in thns:
|
for thn in thns:
|
||||||
logging.debug("Trying thn...")
|
logging.debug("Trying thn...")
|
||||||
|
if not thn:
|
||||||
|
continue
|
||||||
(thn_title, thn_description, thn_link, thn_pubdate, thn_video) = thn
|
(thn_title, thn_description, thn_link, thn_pubdate, thn_video) = thn
|
||||||
thn_description: list[str] = textwrap.wrap(text=thn_description,
|
thn_description = textwrap.wrap(text=thn_description,
|
||||||
width=860, max_lines=1)[0]
|
width=860, max_lines=1)[0]
|
||||||
embed: discord.Embed = discord.Embed(title=thn_title)
|
embed = discord.Embed(title=thn_title)
|
||||||
embed.add_field(name="Content", value=f"{thn_description[0:960]}\n-# {thn_link}")
|
embed.add_field(name="Content", value=f"{thn_description[0:960]}\n-# {thn_link}")
|
||||||
embed.add_field(name="Published", value=thn_pubdate, inline=False)
|
embed.add_field(name="Published", value=thn_pubdate, inline=False)
|
||||||
async with ClientSession() as session:
|
async with ClientSession() as session:
|
||||||
for hook in self.NO_THREAD_WEBHOOKS.get('thn'):
|
for hook in self.NO_THREAD_WEBHOOKS.get('thn', {}):
|
||||||
hook_uri: str = hook
|
hook_uri = hook
|
||||||
webhook: discord.Webhook = discord.Webhook.from_url(hook_uri,
|
webhook = discord.Webhook.from_url(hook_uri,
|
||||||
session=session)
|
session=session)
|
||||||
await webhook.send(embed=embed, username="The Hacker News")
|
await webhook.send(embed=embed, username="The Hacker News")
|
||||||
if thn_video:
|
if thn_video:
|
||||||
@ -422,8 +457,8 @@ class Meme(commands.Cog):
|
|||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
@bridge.bridge_command()
|
@bridge.bridge_command() # type: ignore
|
||||||
@is_spamchan() # pylint: disable=too-many-function-args
|
@is_spamchan()
|
||||||
async def meme(self, ctx) -> None:
|
async def meme(self, ctx) -> None:
|
||||||
"""Create Meme"""
|
"""Create Meme"""
|
||||||
await ctx.respond(view=MemeView())
|
await ctx.respond(view=MemeView())
|
||||||
|
@ -12,6 +12,7 @@ from .misc_util import Util
|
|||||||
import aiosqlite as sqlite3
|
import aiosqlite as sqlite3
|
||||||
from sh import cowsay as cow_say, fortune # pylint: disable=no-name-in-module
|
from sh import cowsay as cow_say, fortune # pylint: disable=no-name-in-module
|
||||||
from discord.ext import bridge, commands, tasks
|
from discord.ext import bridge, commands, tasks
|
||||||
|
from disc_havoc import Havoc
|
||||||
# pylint: disable=bare-except, broad-exception-caught, broad-exception-raised, global-statement
|
# pylint: disable=bare-except, broad-exception-caught, broad-exception-raised, global-statement
|
||||||
# pylint: disable=too-many-lines, invalid-name
|
# pylint: disable=too-many-lines, invalid-name
|
||||||
|
|
||||||
@ -25,8 +26,8 @@ BOT_CHANIDS = []
|
|||||||
|
|
||||||
class Misc(commands.Cog):
|
class Misc(commands.Cog):
|
||||||
"""Misc/Assorted Cog for Havoc"""
|
"""Misc/Assorted Cog for Havoc"""
|
||||||
def __init__(self, bot):
|
def __init__(self, bot: Havoc):
|
||||||
self.bot: discord.Bot = bot
|
self.bot: Havoc = bot
|
||||||
self.util = Util()
|
self.util = Util()
|
||||||
|
|
||||||
self.COWS: list[str] = os.listdir(os.path.join("/",
|
self.COWS: list[str] = os.listdir(os.path.join("/",
|
||||||
|
@ -9,13 +9,14 @@ from typing import Optional
|
|||||||
import discord
|
import discord
|
||||||
import requests
|
import requests
|
||||||
from discord.ext import bridge, commands
|
from discord.ext import bridge, commands
|
||||||
|
from disc_havoc import Havoc
|
||||||
import util
|
import util
|
||||||
|
|
||||||
class Owner(commands.Cog):
|
class Owner(commands.Cog):
|
||||||
"""Owner Cog for Havoc"""
|
"""Owner Cog for Havoc"""
|
||||||
def __init__(self, bot) -> None:
|
def __init__(self, bot: Havoc) -> None:
|
||||||
self.bot: discord.Bot = bot
|
self.bot: Havoc = bot
|
||||||
self.former_roles_store: dict = {}
|
self.former_roles_store: dict[int, list[discord.Role]] = {}
|
||||||
self._temperature: int = random.randrange(20, 30)
|
self._temperature: int = random.randrange(20, 30)
|
||||||
|
|
||||||
@bridge.bridge_command(guild_ids=[1145182936002482196])
|
@bridge.bridge_command(guild_ids=[1145182936002482196])
|
||||||
@ -41,7 +42,7 @@ class Owner(commands.Cog):
|
|||||||
return await ctx.respond("Too cold! (-15°C minimum)")
|
return await ctx.respond("Too cold! (-15°C minimum)")
|
||||||
elif _temperature > 35:
|
elif _temperature > 35:
|
||||||
return await ctx.respond("Too hot! (35°C maximum)")
|
return await ctx.respond("Too hot! (35°C maximum)")
|
||||||
self._temperature: int = _temperature
|
self._temperature = _temperature
|
||||||
return await ctx.respond(f"As per your request, I have adjusted the temperature to {_temperature} °C.")
|
return await ctx.respond(f"As per your request, I have adjusted the temperature to {_temperature} °C.")
|
||||||
|
|
||||||
@bridge.bridge_command()
|
@bridge.bridge_command()
|
||||||
@ -54,6 +55,7 @@ class Owner(commands.Cog):
|
|||||||
Returns:
|
Returns:
|
||||||
None
|
None
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.bot.load_exts(False)
|
self.bot.load_exts(False)
|
||||||
await ctx.respond("Reloaded!", ephemeral=True)
|
await ctx.respond("Reloaded!", ephemeral=True)
|
||||||
|
|
||||||
@ -70,20 +72,18 @@ class Owner(commands.Cog):
|
|||||||
Returns:
|
Returns:
|
||||||
None
|
None
|
||||||
"""
|
"""
|
||||||
parameters: list[str] = parameters.split(" ")
|
_parameters: list[str] = parameters.split(" ")
|
||||||
|
|
||||||
if not len(parameters) > 1:
|
if not len(_parameters) > 1:
|
||||||
return await ctx.respond("**Error**: Incorrect command usage; required: <chan> <msg>", ephemeral=True)
|
return await ctx.respond("**Error**: Incorrect command usage; required: <chan> <msg>", ephemeral=True)
|
||||||
|
|
||||||
channel: str = parameters[0]
|
channel: str = _parameters[0]
|
||||||
channel_mentions: list[str] = discord.utils.raw_channel_mentions(channel)
|
channel_mentions: list[int] = discord.utils.raw_channel_mentions(channel)
|
||||||
if channel_mentions:
|
if channel_mentions:
|
||||||
channel: str = str(channel_mentions[0])
|
channel = str(channel_mentions[0])
|
||||||
msg: str = " ".join(parameters[1:])
|
msg: str = " ".join(parameters[1:])
|
||||||
sent = await util.discord_helpers.send_message(self.bot, channel=channel,
|
await util.discord_helpers.send_message(self.bot, channel=channel,
|
||||||
message=msg)
|
message=msg)
|
||||||
if not sent:
|
|
||||||
return await ctx.respond("**Failed.**", ephemeral=True)
|
|
||||||
return await ctx.respond("**Done.**", ephemeral=True)
|
return await ctx.respond("**Done.**", ephemeral=True)
|
||||||
|
|
||||||
@bridge.bridge_command()
|
@bridge.bridge_command()
|
||||||
@ -144,6 +144,8 @@ class Owner(commands.Cog):
|
|||||||
None
|
None
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
if not isinstance(message.channel, discord.TextChannel):
|
||||||
|
return
|
||||||
memes_channel: discord.TextChannel = ctx.guild.get_channel(1147229098544988261)
|
memes_channel: discord.TextChannel = ctx.guild.get_channel(1147229098544988261)
|
||||||
message_content: str = message.content
|
message_content: str = message.content
|
||||||
message_author: str = message.author.display_name
|
message_author: str = message.author.display_name
|
||||||
@ -156,7 +158,9 @@ class Owner(commands.Cog):
|
|||||||
timeout=20).raw.read())
|
timeout=20).raw.read())
|
||||||
ext: str = item.url.split(".")[-1]\
|
ext: str = item.url.split(".")[-1]\
|
||||||
.split("?")[0].split("&")[0]
|
.split("?")[0].split("&")[0]
|
||||||
_file: discord.File = discord.File(image, filename=f'img.{ext}')
|
_file = discord.File(image, filename=f'img.{ext}')
|
||||||
|
if not _file:
|
||||||
|
return # No file to move
|
||||||
await memes_channel.send(f"*Performing bureaucratic duties (this didn't belong in #{message_channel})...*\n**{message_author}:** {message_content}", file=_file)
|
await memes_channel.send(f"*Performing bureaucratic duties (this didn't belong in #{message_channel})...*\n**{message_author}:** {message_content}", file=_file)
|
||||||
await message.delete()
|
await message.delete()
|
||||||
await ctx.respond("OK!", ephemeral=True)
|
await ctx.respond("OK!", ephemeral=True)
|
||||||
@ -176,6 +180,8 @@ class Owner(commands.Cog):
|
|||||||
None
|
None
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
if not isinstance(message.channel, discord.TextChannel):
|
||||||
|
return
|
||||||
drugs_channel: discord.TextChannel = ctx.guild.get_channel(1172247451047034910)
|
drugs_channel: discord.TextChannel = ctx.guild.get_channel(1172247451047034910)
|
||||||
message_content: str = message.content
|
message_content: str = message.content
|
||||||
message_author: str = message.author.display_name
|
message_author: str = message.author.display_name
|
||||||
@ -188,7 +194,9 @@ class Owner(commands.Cog):
|
|||||||
timeout=20).raw.read())
|
timeout=20).raw.read())
|
||||||
ext: str = item.url.split(".")[-1]\
|
ext: str = item.url.split(".")[-1]\
|
||||||
.split("?")[0].split("&")[0]
|
.split("?")[0].split("&")[0]
|
||||||
_file: discord.File = discord.File(image, filename=f'img.{ext}')
|
_file = discord.File(image, filename=f'img.{ext}')
|
||||||
|
if not _file:
|
||||||
|
return # No file to move
|
||||||
await drugs_channel.send(f"*Performing bureaucratic duties (this didn't belong in #{message_channel})...\
|
await drugs_channel.send(f"*Performing bureaucratic duties (this didn't belong in #{message_channel})...\
|
||||||
*\n**{message_author}:** {message_content}", file=_file)
|
*\n**{message_author}:** {message_content}", file=_file)
|
||||||
await message.delete()
|
await message.delete()
|
||||||
@ -209,6 +217,8 @@ class Owner(commands.Cog):
|
|||||||
None
|
None
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
if not isinstance(message.channel, discord.TextChannel):
|
||||||
|
return
|
||||||
funhouse_channel: discord.TextChannel = ctx.guild.get_channel(1213160512364478607)
|
funhouse_channel: discord.TextChannel = ctx.guild.get_channel(1213160512364478607)
|
||||||
message_content: str = message.content
|
message_content: str = message.content
|
||||||
message_author: str = message.author.display_name
|
message_author: str = message.author.display_name
|
||||||
@ -221,7 +231,7 @@ class Owner(commands.Cog):
|
|||||||
timeout=20).raw.read())
|
timeout=20).raw.read())
|
||||||
ext: str = item.url.split(".")[-1]\
|
ext: str = item.url.split(".")[-1]\
|
||||||
.split("?")[0].split("&")[0]
|
.split("?")[0].split("&")[0]
|
||||||
_file: discord.File = discord.File(image, filename=f'img.{ext}')
|
_file = discord.File(image, filename=f'img.{ext}')
|
||||||
await funhouse_channel.send(f"*Performing bureaucratic duties (this didn't belong in #{message_channel})\
|
await funhouse_channel.send(f"*Performing bureaucratic duties (this didn't belong in #{message_channel})\
|
||||||
...*\n**{message_author}:** {message_content}")
|
...*\n**{message_author}:** {message_content}")
|
||||||
await message.delete()
|
await message.delete()
|
||||||
@ -244,12 +254,14 @@ class Owner(commands.Cog):
|
|||||||
try:
|
try:
|
||||||
if not ctx.guild.id == 1145182936002482196:
|
if not ctx.guild.id == 1145182936002482196:
|
||||||
return # Not home server!
|
return # Not home server!
|
||||||
|
if not member.roles:
|
||||||
|
return # No roles
|
||||||
audit_reason: str = f"Einsperren von {ctx.user.display_name}"
|
audit_reason: str = f"Einsperren von {ctx.user.display_name}"
|
||||||
member: discord.Member = ctx.guild.get_member(member.id)
|
member = ctx.guild.get_member(member.id)
|
||||||
member_display: str = member.display_name
|
member_display: str = member.display_name
|
||||||
einsperren_role: discord.Role = ctx.guild.get_role(1235415059300093973) if ctx.guild.id != 1145182936002482196\
|
einsperren_role: discord.Role = ctx.guild.get_role(1235415059300093973) if ctx.guild.id != 1145182936002482196\
|
||||||
else ctx.guild.get_role(1235406301614309386)
|
else ctx.guild.get_role(1235406301614309386)
|
||||||
member_roles: list[discord.Role] = [role for role in member.roles if not role.name == "@everyone"]
|
member_roles: list = [role for role in member.roles if not role.name == "@everyone"]
|
||||||
member_role_names: list[str] = [str(role.name).lower() for role in member_roles]
|
member_role_names: list[str] = [str(role.name).lower() for role in member_roles]
|
||||||
opers_chan: discord.TextChannel = ctx.guild.get_channel(1181416083287187546)
|
opers_chan: discord.TextChannel = ctx.guild.get_channel(1181416083287187546)
|
||||||
if not "einsperren" in member_role_names:
|
if not "einsperren" in member_role_names:
|
||||||
@ -271,7 +283,7 @@ class Owner(commands.Cog):
|
|||||||
if not member.id in self.former_roles_store:
|
if not member.id in self.former_roles_store:
|
||||||
await member.edit(roles=[]) # No roles
|
await member.edit(roles=[]) # No roles
|
||||||
else:
|
else:
|
||||||
former_roles: list[discord.Role] = self.former_roles_store.get(member.id)
|
former_roles: list = self.former_roles_store.get(member.id, [0])
|
||||||
await member.edit(roles=former_roles, reason=f"De-{audit_reason}")
|
await member.edit(roles=former_roles, reason=f"De-{audit_reason}")
|
||||||
|
|
||||||
await ctx.respond(f"{member_display} wurde von der Einsperre befreit.", ephemeral=True)
|
await ctx.respond(f"{member_display} wurde von der Einsperre befreit.", ephemeral=True)
|
||||||
|
@ -13,11 +13,12 @@ import asyncio
|
|||||||
import discord
|
import discord
|
||||||
import aiosqlite as sqlite3
|
import aiosqlite as sqlite3
|
||||||
from discord.ext import bridge, commands
|
from discord.ext import bridge, commands
|
||||||
|
from disc_havoc import Havoc
|
||||||
|
|
||||||
class DB:
|
class DB:
|
||||||
"""DB Utility for Quote Cog"""
|
"""DB Utility for Quote Cog"""
|
||||||
def __init__(self, bot):
|
def __init__(self, bot: Havoc):
|
||||||
self.bot = bot
|
self.bot: Havoc = bot
|
||||||
self.db_path = os.path.join("/", "usr", "local", "share",
|
self.db_path = os.path.join("/", "usr", "local", "share",
|
||||||
"sqlite_dbs", "quotes.db")
|
"sqlite_dbs", "quotes.db")
|
||||||
self.hp_chanid = 1157529874936909934
|
self.hp_chanid = 1157529874936909934
|
||||||
@ -120,8 +121,8 @@ class DB:
|
|||||||
|
|
||||||
class Quote(commands.Cog):
|
class Quote(commands.Cog):
|
||||||
"""Quote Cog for Havoc"""
|
"""Quote Cog for Havoc"""
|
||||||
def __init__(self, bot):
|
def __init__(self, bot: Havoc):
|
||||||
self.bot = bot
|
self.bot: Havoc = bot
|
||||||
self.db = DB(self.bot)
|
self.db = DB(self.bot)
|
||||||
|
|
||||||
def is_homeserver(): # pylint: disable=no-method-argument
|
def is_homeserver(): # pylint: disable=no-method-argument
|
||||||
|
@ -7,12 +7,13 @@ from typing import Optional
|
|||||||
from discord.ext import bridge, commands, tasks
|
from discord.ext import bridge, commands, tasks
|
||||||
from util.radio_util import get_now_playing
|
from util.radio_util import get_now_playing
|
||||||
import discord
|
import discord
|
||||||
|
from disc_havoc import Havoc
|
||||||
|
|
||||||
class Radio(commands.Cog):
|
class Radio(commands.Cog):
|
||||||
"""Radio Cog for Havoc"""
|
"""Radio Cog for Havoc"""
|
||||||
def __init__(self, bot: discord.Bot) -> None:
|
def __init__(self, bot: Havoc) -> None:
|
||||||
self.bot: discord.Bot = bot
|
self.bot: Havoc = bot
|
||||||
self.channels: dict[tuple] = {
|
self.channels: dict[str, tuple] = {
|
||||||
'sfm': (1145182936002482196, 1221615558492029050), # Tuple: Guild Id, Chan Id
|
'sfm': (1145182936002482196, 1221615558492029050), # Tuple: Guild Id, Chan Id
|
||||||
}
|
}
|
||||||
self.STREAM_URL: str = "https://relay.sfm.codey.lol/aces.ogg"
|
self.STREAM_URL: str = "https://relay.sfm.codey.lol/aces.ogg"
|
||||||
|
94
cogs/sing.py
94
cogs/sing.py
@ -10,20 +10,22 @@ import discord
|
|||||||
import regex
|
import regex
|
||||||
from util.sing_util import Utility
|
from util.sing_util import Utility
|
||||||
from discord.ext import bridge, commands
|
from discord.ext import bridge, commands
|
||||||
|
from disc_havoc import Havoc
|
||||||
|
|
||||||
|
|
||||||
BOT_CHANIDS = []
|
BOT_CHANIDS = []
|
||||||
|
|
||||||
class Sing(commands.Cog):
|
class Sing(commands.Cog):
|
||||||
"""Sing Cog for Havoc"""
|
"""Sing Cog for Havoc"""
|
||||||
def __init__(self, bot):
|
def __init__(self, bot: Havoc) -> None:
|
||||||
self.bot: discord.Bot = bot
|
self.bot: Havoc = bot
|
||||||
self.utility = Utility()
|
self.utility = Utility()
|
||||||
global BOT_CHANIDS
|
global BOT_CHANIDS
|
||||||
BOT_CHANIDS = self.bot.BOT_CHANIDS # Inherit
|
BOT_CHANIDS = self.bot.BOT_CHANIDS # Inherit
|
||||||
self.control_strip_regex: Pattern = regex.compile(r"\x0f|\x1f|\035|\002|\u2064|\x02|(\x03([0-9]{1,2}))|(\x03|\003)(?:\d{1,2}(?:,\d{1,2})?)?",
|
self.control_strip_regex: Pattern = regex.compile(r"\x0f|\x1f|\035|\002|\u2064|\x02|(\x03([0-9]{1,2}))|(\x03|\003)(?:\d{1,2}(?:,\d{1,2})?)?",
|
||||||
regex.UNICODE)
|
regex.UNICODE)
|
||||||
|
|
||||||
def is_spamchan(): # pylint: disable=no-method-argument
|
def is_spamchan(): # type: ignore
|
||||||
"""Check if channel is spam chan"""
|
"""Check if channel is spam chan"""
|
||||||
def predicate(ctx):
|
def predicate(ctx):
|
||||||
try:
|
try:
|
||||||
@ -57,7 +59,7 @@ class Sing(commands.Cog):
|
|||||||
|
|
||||||
for _activity in ctx.author.activities:
|
for _activity in ctx.author.activities:
|
||||||
if _activity.type == discord.ActivityType.listening:
|
if _activity.type == discord.ActivityType.listening:
|
||||||
activity: discord.Activity = _activity
|
activity = _activity
|
||||||
|
|
||||||
if not activity:
|
if not activity:
|
||||||
return await ctx.respond("**Error**: No song specified, no activity found to read.")
|
return await ctx.respond("**Error**: No song specified, no activity found to read.")
|
||||||
@ -65,7 +67,9 @@ class Sing(commands.Cog):
|
|||||||
if interaction:
|
if interaction:
|
||||||
await ctx.respond("*Searching...*", ephemeral=True) # Must respond to interactions within 3 seconds, per Discord
|
await ctx.respond("*Searching...*", ephemeral=True) # Must respond to interactions within 3 seconds, per Discord
|
||||||
|
|
||||||
(search_artist, search_song, search_subsearch) = self.utility.parse_song_input(song, activity)
|
parsed = self.utility.parse_song_input(song, activity)
|
||||||
|
if isinstance(parsed, tuple):
|
||||||
|
(search_artist, search_song, search_subsearch) = parsed
|
||||||
|
|
||||||
# await ctx.respond(f"So, {search_song} by {search_artist}? Subsearch: {search_subsearch} I will try...") # Commented, useful for debugging
|
# await ctx.respond(f"So, {search_song} by {search_artist}? Subsearch: {search_subsearch} I will try...") # Commented, useful for debugging
|
||||||
search_result: list[str] = await self.utility.lyric_search(search_artist, search_song,
|
search_result: list[str] = await self.utility.lyric_search(search_artist, search_song,
|
||||||
@ -73,13 +77,16 @@ class Sing(commands.Cog):
|
|||||||
|
|
||||||
if len(search_result) == 1:
|
if len(search_result) == 1:
|
||||||
return await ctx.respond(search_result[0].strip())
|
return await ctx.respond(search_result[0].strip())
|
||||||
|
if not isinstance(search_result[0], tuple):
|
||||||
(search_result_artist, search_result_song, search_result_src,
|
return # Invalid data type
|
||||||
search_result_confidence, search_result_time_taken) = search_result[0] # First index is a tuple
|
(
|
||||||
|
search_result_artist, search_result_song, search_result_src,
|
||||||
|
search_result_confidence, search_result_time_taken
|
||||||
|
) = search_result[0] # First index is a tuple
|
||||||
search_result_wrapped: list[str] = search_result[1] # Second index is the wrapped lyrics
|
search_result_wrapped: list[str] = search_result[1] # Second index is the wrapped lyrics
|
||||||
search_result_wrapped_short: list[str] = search_result[2] # Third is short wrapped lyrics
|
search_result_wrapped_short: list[str] = search_result[2] # Third is short wrapped lyrics
|
||||||
if not ctx.channel.id in BOT_CHANIDS:
|
if not ctx.channel.id in BOT_CHANIDS:
|
||||||
search_result_wrapped: list[str] = search_result_wrapped_short # Replace with shortened lyrics for non spamchans
|
search_result_wrapped = search_result_wrapped_short # Replace with shortened lyrics for non spamchans
|
||||||
embeds: list[Optional[discord.Embed]] = []
|
embeds: list[Optional[discord.Embed]] = []
|
||||||
embed_url: str = f"[on codey.lol](https://codey.lol/#{urllib.parse.quote(search_artist)}/{urllib.parse.quote(search_song)})"
|
embed_url: str = f"[on codey.lol](https://codey.lol/#{urllib.parse.quote(search_artist)}/{urllib.parse.quote(search_song)})"
|
||||||
c: int = 0
|
c: int = 0
|
||||||
@ -87,8 +94,8 @@ class Sing(commands.Cog):
|
|||||||
for section in search_result_wrapped:
|
for section in search_result_wrapped:
|
||||||
c+=1
|
c+=1
|
||||||
if c == len(search_result_wrapped):
|
if c == len(search_result_wrapped):
|
||||||
footer: str = f"Found on: {search_result_src}"
|
footer = f"Found on: {search_result_src}"
|
||||||
section: str = self.control_strip_regex.sub('', section)
|
section = self.control_strip_regex.sub('', section)
|
||||||
# if ctx.guild.id == 1145182936002482196:
|
# if ctx.guild.id == 1145182936002482196:
|
||||||
# section = section.upper()
|
# section = section.upper()
|
||||||
embed: discord.Embed = discord.Embed(
|
embed: discord.Embed = discord.Embed(
|
||||||
@ -131,7 +138,7 @@ class Sing(commands.Cog):
|
|||||||
activity: Optional[discord.Activity] = None
|
activity: Optional[discord.Activity] = None
|
||||||
for _activity in ctx.interaction.guild.get_member(member_id).activities:
|
for _activity in ctx.interaction.guild.get_member(member_id).activities:
|
||||||
if _activity.type == discord.ActivityType.listening:
|
if _activity.type == discord.ActivityType.listening:
|
||||||
activity: discord.Activity = _activity
|
activity = _activity
|
||||||
parsed: tuple|bool = self.utility.parse_song_input(song=None,
|
parsed: tuple|bool = self.utility.parse_song_input(song=None,
|
||||||
activity=activity)
|
activity=activity)
|
||||||
if not parsed:
|
if not parsed:
|
||||||
@ -139,43 +146,44 @@ class Sing(commands.Cog):
|
|||||||
if IS_SPAMCHAN:
|
if IS_SPAMCHAN:
|
||||||
await ctx.respond(f"***Reading activity of {member_display}...***")
|
await ctx.respond(f"***Reading activity of {member_display}...***")
|
||||||
|
|
||||||
(search_artist, search_song, search_subsearch) = parsed
|
if isinstance(parsed, tuple):
|
||||||
await ctx.respond("*Searching...*", ephemeral=True) # Must respond to interactions within 3 seconds, per Discord
|
(search_artist, search_song, search_subsearch) = parsed
|
||||||
search_result: list = await self.utility.lyric_search(search_artist, search_song,
|
await ctx.respond("*Searching...*", ephemeral=True) # Must respond to interactions within 3 seconds, per Discord
|
||||||
|
search_result: list = await self.utility.lyric_search(search_artist, search_song,
|
||||||
search_subsearch)
|
search_subsearch)
|
||||||
|
|
||||||
if len(search_result) == 1:
|
if len(search_result) == 1:
|
||||||
return await ctx.send(search_result[0].strip())
|
return await ctx.send(search_result[0].strip())
|
||||||
|
|
||||||
(search_result_artist, search_result_song, search_result_src,
|
(search_result_artist, search_result_song, search_result_src,
|
||||||
search_result_confidence, search_result_time_taken) = search_result[0] # First index is a tuple
|
search_result_confidence, search_result_time_taken) = search_result[0] # First index is a tuple
|
||||||
search_result_wrapped: list[str] = search_result[1] # Second index is the wrapped lyrics
|
search_result_wrapped: list[str] = search_result[1] # Second index is the wrapped lyrics
|
||||||
search_result_wrapped_short: list[str] = search_result[2] # Third index is shortened lyrics
|
search_result_wrapped_short: list[str] = search_result[2] # Third index is shortened lyrics
|
||||||
|
|
||||||
if not IS_SPAMCHAN:
|
if not IS_SPAMCHAN:
|
||||||
search_result_wrapped: list[str] = search_result_wrapped_short # Swap for shortened lyrics if not spam chan
|
search_result_wrapped = search_result_wrapped_short # Swap for shortened lyrics if not spam chan
|
||||||
|
|
||||||
embeds: list[Optional[discord.Embed]] = []
|
embeds: list[Optional[discord.Embed]] = []
|
||||||
c: int = 0
|
c: int = 0
|
||||||
footer: str = "To be continued..." #Placeholder
|
footer: str = "To be continued..." #Placeholder
|
||||||
for section in search_result_wrapped:
|
for section in search_result_wrapped:
|
||||||
c+=1
|
c+=1
|
||||||
if c == len(search_result_wrapped):
|
if c == len(search_result_wrapped):
|
||||||
footer: str = f"Found on: {search_result_src}"
|
footer = f"Found on: {search_result_src}"
|
||||||
# if ctx.guild.id == 1145182936002482196:
|
# if ctx.guild.id == 1145182936002482196:
|
||||||
# section = section.upper()
|
# section = section.upper()
|
||||||
embed: discord.Embed = discord.Embed(
|
embed: discord.Embed = discord.Embed(
|
||||||
title=f"{search_result_song} by {search_result_artist}",
|
title=f"{search_result_song} by {search_result_artist}",
|
||||||
description=discord.utils.escape_markdown(section.replace("\n", "\n\n"))
|
description=discord.utils.escape_markdown(section.replace("\n", "\n\n"))
|
||||||
)
|
)
|
||||||
embed.add_field(name="Confidence", value=search_result_confidence, inline=True)
|
embed.add_field(name="Confidence", value=search_result_confidence, inline=True)
|
||||||
embed.add_field(name="Time Taken", value=search_result_time_taken, inline=True)
|
embed.add_field(name="Time Taken", value=search_result_time_taken, inline=True)
|
||||||
embed.add_field(name="Link", value=f"[on codey.lol](https://codey.lol/#{urllib.parse.quote(search_result_artist)}/{urllib.parse.quote(search_result_song)})")
|
embed.add_field(name="Link", value=f"[on codey.lol](https://codey.lol/#{urllib.parse.quote(search_result_artist)}/{urllib.parse.quote(search_result_song)})")
|
||||||
embed.set_footer(text=footer)
|
embed.set_footer(text=footer)
|
||||||
embeds.append(embed)
|
embeds.append(embed)
|
||||||
|
|
||||||
for embed in embeds:
|
for _embed in embeds:
|
||||||
await ctx.send(embed=embed)
|
await ctx.send(embed=_embed)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return await ctx.respond(f"ERR: {str(e)}")
|
return await ctx.respond(f"ERR: {str(e)}")
|
||||||
|
@ -10,6 +10,7 @@ import setproctitle
|
|||||||
import hypercorn
|
import hypercorn
|
||||||
import hypercorn.asyncio
|
import hypercorn.asyncio
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
from asyncio import Task
|
||||||
from discord.ext import bridge, commands
|
from discord.ext import bridge, commands
|
||||||
from termcolor import colored
|
from termcolor import colored
|
||||||
from constants import OWNERS, BOT_CHANIDS
|
from constants import OWNERS, BOT_CHANIDS
|
||||||
@ -38,50 +39,56 @@ load_dotenv()
|
|||||||
|
|
||||||
intents = discord.Intents.all()
|
intents = discord.Intents.all()
|
||||||
intents.message_content = True
|
intents.message_content = True
|
||||||
bot = bridge.Bot(command_prefix=".", intents=intents,
|
|
||||||
owner_ids=OWNERS, activity=bot_activity,
|
|
||||||
help_command=commands.MinimalHelpCommand())
|
|
||||||
|
|
||||||
@bot.event
|
class Havoc(bridge.Bot):
|
||||||
async def on_ready() -> None:
|
def __init__(self) -> None:
|
||||||
"""Run on Bot Ready"""
|
super().__init__(command_prefix=".", intents=intents,
|
||||||
logging.info("%s online!", bot.user)
|
owner_ids=OWNERS, activity=bot_activity,
|
||||||
|
help_command=commands.MinimalHelpCommand())
|
||||||
|
self.BOT_CHANIDS = BOT_CHANIDS
|
||||||
|
|
||||||
def load_exts(initialRun: Optional[bool] = True) -> None:
|
def load_exts(self, initialRun: Optional[bool] = True) -> None:
|
||||||
"""
|
"""
|
||||||
Load Cogs/Extensions
|
Load Cogs/Extensions
|
||||||
Args:
|
Args:
|
||||||
initialRun (Optional[bool]) default: True
|
initialRun (Optional[bool]) default: True
|
||||||
Returns:
|
Returns:
|
||||||
None"""
|
None"""
|
||||||
load_method = bot.load_extension if initialRun else bot.reload_extension
|
load_method = self.load_extension if initialRun\
|
||||||
|
else self.reload_extension
|
||||||
|
|
||||||
for cog in cogs_list:
|
for cog in cogs_list:
|
||||||
logging.info("Loading: %s", cog)
|
logging.info("Loading: %s", cog)
|
||||||
load_method(f'cogs.{cog}')
|
load_method(f'cogs.{cog}')
|
||||||
|
|
||||||
importlib.reload(api)
|
importlib.reload(api)
|
||||||
from api import API # pylint: disable=unused-import
|
from api import API # pylint: disable=unused-import
|
||||||
api_config = hypercorn.config.Config()
|
api_config = hypercorn.config.Config()
|
||||||
api_config.bind = "10.10.10.100:5992"
|
api_config.bind = ["10.10.10.100:5992"]
|
||||||
api_instance = api.API(bot)
|
api_instance = api.API(self)
|
||||||
try:
|
try:
|
||||||
bot.fapi_task.cancel()
|
self.fapi_task.cancel()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.debug("Failed to cancel fapi_task: %s",
|
logging.debug("Failed to cancel fapi_task: %s",
|
||||||
str(e))
|
str(e))
|
||||||
|
|
||||||
logging.info("Starting FAPI Task")
|
logging.info("Starting FAPI Task")
|
||||||
|
|
||||||
bot.fapi_task = bot.loop.create_task(hypercorn.asyncio.serve(api_instance.api_app,
|
self.fapi_task: Task = self.loop.create_task(hypercorn.asyncio.serve(api_instance.api_app,
|
||||||
api_config))
|
api_config))
|
||||||
|
|
||||||
|
|
||||||
|
@commands.Cog.listener()
|
||||||
|
async def on_ready(self) -> None:
|
||||||
|
"""Run on Bot Ready"""
|
||||||
|
logging.info("%s online!", self.user)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def __init__() -> None:
|
def __init__() -> None:
|
||||||
logging.info(colored(f"Log level: {logging.getLevelName(logging.root.level)}",
|
logging.info(colored(f"Log level: {logging.getLevelName(logging.root.level)}",
|
||||||
"red", attrs=['reverse']))
|
"red", attrs=['reverse']))
|
||||||
bot.BOT_CHANIDS = BOT_CHANIDS
|
bot = Havoc()
|
||||||
bot.load_exts = load_exts
|
|
||||||
bot.load_exts()
|
|
||||||
bot.run(os.getenv('TOKEN'))
|
bot.run(os.getenv('TOKEN'))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
50
jesusmemes.py
Normal file
50
jesusmemes.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/env python3.11
|
||||||
|
|
||||||
|
# Jesus Meme Generator (requires Catbox uploader)
|
||||||
|
|
||||||
|
import aiohttp # Not part of Python core
|
||||||
|
import asyncio # Part of Python core
|
||||||
|
import regex # Not part of Python core
|
||||||
|
import os # Part of Python core
|
||||||
|
import random # Part of Python core
|
||||||
|
import traceback
|
||||||
|
from urllib.parse import quote as urlquote
|
||||||
|
from catbox import Catbox # Not part of Python core
|
||||||
|
|
||||||
|
|
||||||
|
class JesusMemeGenerator():
|
||||||
|
def __init__(self):
|
||||||
|
self.MEMEAPIURL = "https://apimeme.com/meme?meme="
|
||||||
|
self.MEMESTORAGEDIR = os.path.join(os.path.expanduser("~"), "memes") # Save memes "temporarily" to the home directory-->'memes' subfolder; cleanup must be done externally
|
||||||
|
|
||||||
|
async def create_meme(self, top_line='', bottom_line='', meme="Jesus-Talking-To-Cool-Dude"):
|
||||||
|
try:
|
||||||
|
top_line = regex.sub('[^\p{Letter}\p{Number}\p{Punctuation}\p{Horiz_Space}\p{Currency_Symbol}]', '', top_line.strip())
|
||||||
|
bottom_line = regex.sub('[^\p{Letter}\p{Number}\p{Punctuation}\p{Horiz_Space}\p{Currency_Symbol}]', '', bottom_line.strip())
|
||||||
|
OUT_FNAME = ''
|
||||||
|
|
||||||
|
if len(top_line) < 1 or len(bottom_line) < 1:
|
||||||
|
return None
|
||||||
|
|
||||||
|
formed_url = f"{self.MEMEAPIURL}{meme}&top={top_line.strip()}&bottom={bottom_line.strip()}"
|
||||||
|
formed_url = regex.sub('\p{Horiz_Space}', '+', regex.sub('#', '%23', formed_url.strip()))
|
||||||
|
timeout = aiohttp.ClientTimeout(total=15)
|
||||||
|
async with aiohttp.ClientSession(timeout=timeout) as session:
|
||||||
|
async with session.get(formed_url) as response:
|
||||||
|
UUID = f"{random.getrandbits(8)}-{random.getrandbits(8)}"
|
||||||
|
OUT_FNAME = f"{UUID}.jpg"
|
||||||
|
with open(f"{self.MEMESTORAGEDIR}/{OUT_FNAME}", 'wb') as f:
|
||||||
|
f.write(await response.read())
|
||||||
|
|
||||||
|
if len (OUT_FNAME) > 0:
|
||||||
|
uploader = Catbox()
|
||||||
|
meme_link = uploader.upload(f"{self.MEMESTORAGEDIR}/{OUT_FNAME}")
|
||||||
|
return meme_link
|
||||||
|
except:
|
||||||
|
print(traceback.format_exc())
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
28
pyproject.toml
Normal file
28
pyproject.toml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
[project]
|
||||||
|
name = "havoc"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Add your description here"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.11"
|
||||||
|
dependencies = [
|
||||||
|
"aiosqlite>=0.20.0",
|
||||||
|
"beautifulsoup4>=4.12.3",
|
||||||
|
"bohancompliment>=0.2.0",
|
||||||
|
"fastapi>=0.115.7",
|
||||||
|
"feedparser>=6.0.11",
|
||||||
|
"hypercorn>=0.17.3",
|
||||||
|
"nvdlib>=0.7.9",
|
||||||
|
"openai>=1.60.0",
|
||||||
|
"py-cord[voice]>=2.6.1",
|
||||||
|
"pydantic>=2.10.6",
|
||||||
|
"python-dotenv>=1.0.1",
|
||||||
|
"pytz>=2024.2",
|
||||||
|
"regex>=2024.11.6",
|
||||||
|
"setproctitle>=1.3.4",
|
||||||
|
"sh>=2.2.1",
|
||||||
|
"termcolor>=2.5.0",
|
||||||
|
"websockets>=14.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.mypy]
|
||||||
|
disable_error_code = ["import-untyped"]
|
@ -18,16 +18,19 @@ async def get_channel_by_name(bot: discord.Bot, channel: str,
|
|||||||
Returns:
|
Returns:
|
||||||
Optional[Any]
|
Optional[Any]
|
||||||
"""
|
"""
|
||||||
channel: str = re.sub(r'^#', '', channel.strip())
|
channel = re.sub(r'^#', '', channel.strip())
|
||||||
if not guild:
|
if not guild:
|
||||||
return discord.utils.get(bot.get_all_channels(),
|
return discord.utils.get(bot.get_all_channels(),
|
||||||
name=channel)
|
name=channel)
|
||||||
else:
|
else:
|
||||||
channels: list = bot.get_guild(guild).channels
|
_guild: Optional[discord.Guild] = bot.get_guild(guild)
|
||||||
|
if not _guild:
|
||||||
|
return None
|
||||||
|
channels: list = _guild.channels
|
||||||
for _channel in channels:
|
for _channel in channels:
|
||||||
if _channel.name.lower() == channel.lower().strip():
|
if _channel.name.lower() == channel.lower().strip():
|
||||||
return _channel
|
return _channel
|
||||||
return
|
return None
|
||||||
|
|
||||||
async def send_message(bot: discord.Bot, channel: str,
|
async def send_message(bot: discord.Bot, channel: str,
|
||||||
message: str, guild: int | None = None) -> None:
|
message: str, guild: int | None = None) -> None:
|
||||||
@ -43,10 +46,12 @@ async def send_message(bot: discord.Bot, channel: str,
|
|||||||
None
|
None
|
||||||
"""
|
"""
|
||||||
if channel.isnumeric():
|
if channel.isnumeric():
|
||||||
channel: int = int(channel)
|
channel_int: int = int(channel)
|
||||||
_channel = bot.get_channel(channel)
|
_channel = bot.get_channel(channel_int)
|
||||||
else:
|
else:
|
||||||
channel: str = re.sub(r'^#', '', channel.strip())
|
channel = re.sub(r'^#', '', channel.strip())
|
||||||
_channel = await get_channel_by_name(bot=bot,
|
_channel = await get_channel_by_name(bot=bot,
|
||||||
channel=channel, guild=guild)
|
channel=channel, guild=guild)
|
||||||
|
if not isinstance(_channel, discord.TextChannel):
|
||||||
|
return None
|
||||||
await _channel.send(message)
|
await _channel.send(message)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user