initial commit
This commit is contained in:
commit
a94f1bee77
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
__pycache__
|
||||||
|
*.pyc
|
||||||
|
venv/
|
||||||
|
.env
|
||||||
|
*.log
|
||||||
|
*.log.*
|
||||||
|
.vscode/
|
4
FEATURES.md
Normal file
4
FEATURES.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
- Web UI [ ]
|
||||||
|
- Filters [ ]
|
||||||
|
-
|
0
bot/__init__.py
Normal file
0
bot/__init__.py
Normal file
25
bot/bot.py
Normal file
25
bot/bot.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from discord import Intents
|
||||||
|
from discord.ext import commands
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class DiscordBot(commands.Bot):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__(
|
||||||
|
command_prefix="@",
|
||||||
|
intents=Intents.all()
|
||||||
|
)
|
||||||
|
|
||||||
|
async def on_ready(self):
|
||||||
|
await self.wait_until_ready()
|
||||||
|
await self.tree.sync()
|
||||||
|
log.info("Bot is synced and ready")
|
||||||
|
|
||||||
|
async def load_cogs(self, cog_path: str):
|
||||||
|
log.info("Loading cogs")
|
||||||
|
for path in cog_path.iterdir():
|
||||||
|
if path.suffix == ".py":
|
||||||
|
await self.load_extension(f"cogs.{path.stem}")
|
51
logs/config.json
Normal file
51
logs/config.json
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"disable_existing_loggers": false,
|
||||||
|
"formatters": {
|
||||||
|
"simple": {
|
||||||
|
"format": "%(levelname)s %(message)s"
|
||||||
|
},
|
||||||
|
"detail": {
|
||||||
|
"format": "[%(asctime)s] [%(levelname)s] [%(name)s]: %(message)s"
|
||||||
|
},
|
||||||
|
"complex": {
|
||||||
|
"format": "[%(levelname)s|%(module)s|L%(lineno)d] %(asctime)s %(message)s",
|
||||||
|
"datefmt": "%Y-%m-%dT%H:%M:%S%z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"handlers": {
|
||||||
|
"stdout": {
|
||||||
|
"class": "logging.StreamHandler",
|
||||||
|
"level": "DEBUG",
|
||||||
|
"formatter": "simple",
|
||||||
|
"stream": "ext://sys.stdout"
|
||||||
|
},
|
||||||
|
"file": {
|
||||||
|
"class": "logging.handlers.RotatingFileHandler",
|
||||||
|
"level": "DEBUG",
|
||||||
|
"formatter": "complex",
|
||||||
|
"filename": "logs/pyrss.log",
|
||||||
|
"maxBytes": 1048576,
|
||||||
|
"backupCount": 3
|
||||||
|
},
|
||||||
|
"queue_handler": {
|
||||||
|
"class": "logging.handlers.QueueHandler",
|
||||||
|
"handlers": [
|
||||||
|
"stdout",
|
||||||
|
"file"
|
||||||
|
],
|
||||||
|
"respect_handler_level": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"loggers": {
|
||||||
|
"root": {
|
||||||
|
"level": "DEBUG",
|
||||||
|
"handlers": [
|
||||||
|
"queue_handler"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"discord": {
|
||||||
|
"level": "INFO"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
53
main.py
Normal file
53
main.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import json
|
||||||
|
import atexit
|
||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
import logging.config
|
||||||
|
from os import getenv
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
load_dotenv(override=True)
|
||||||
|
|
||||||
|
from bot.bot import DiscordBot
|
||||||
|
from web.app import create_app
|
||||||
|
|
||||||
|
BASE_DIR = Path(__file__).parent
|
||||||
|
|
||||||
|
async def start_web():
|
||||||
|
app = create_app()
|
||||||
|
await app.run_task(host="0.0.0.0", port=5000)
|
||||||
|
|
||||||
|
async def start_bot(token: str):
|
||||||
|
async with DiscordBot() as bot:
|
||||||
|
await bot.load_cogs(BASE_DIR / "bot" / "cogs")
|
||||||
|
await bot.start(token, reconnect=True)
|
||||||
|
|
||||||
|
def setup_logging():
|
||||||
|
# load config from file
|
||||||
|
log_config_path = BASE_DIR / "logs" / "config.json"
|
||||||
|
if not log_config_path.exists():
|
||||||
|
raise FileNotFoundError("Logging config not found")
|
||||||
|
|
||||||
|
with open(log_config_path, "r") as file:
|
||||||
|
logging_config = json.load(file)
|
||||||
|
|
||||||
|
logging.config.dictConfig(logging_config)
|
||||||
|
|
||||||
|
# create queue handler for non-blocking logs
|
||||||
|
queue_handler = logging.getHandlerByName("queue_handler")
|
||||||
|
if queue_handler is not None:
|
||||||
|
queue_handler.listener.start()
|
||||||
|
atexit.register(queue_handler.listener.stop)
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
bot_token = getenv("BOT_TOKEN")
|
||||||
|
if not bot_token:
|
||||||
|
raise ValueError("'BOT_TOKEN' is missing")
|
||||||
|
|
||||||
|
setup_logging()
|
||||||
|
|
||||||
|
await asyncio.gather(start_web(), start_bot(bot_token))
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
27
requirements.txt
Normal file
27
requirements.txt
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
aiofiles==24.1.0
|
||||||
|
aiohappyeyeballs==2.4.4
|
||||||
|
aiohttp==3.11.11
|
||||||
|
aiosignal==1.3.2
|
||||||
|
attrs==24.3.0
|
||||||
|
blinker==1.9.0
|
||||||
|
click==8.1.8
|
||||||
|
discord.py==2.4.0
|
||||||
|
Flask==3.1.0
|
||||||
|
frozenlist==1.5.0
|
||||||
|
h11==0.14.0
|
||||||
|
h2==4.1.0
|
||||||
|
hpack==4.0.0
|
||||||
|
Hypercorn==0.17.3
|
||||||
|
hyperframe==6.0.1
|
||||||
|
idna==3.10
|
||||||
|
itsdangerous==2.2.0
|
||||||
|
Jinja2==3.1.5
|
||||||
|
MarkupSafe==3.0.2
|
||||||
|
multidict==6.1.0
|
||||||
|
priority==2.0.0
|
||||||
|
propcache==0.2.1
|
||||||
|
python-dotenv==1.0.1
|
||||||
|
Quart==0.20.0
|
||||||
|
Werkzeug==3.1.3
|
||||||
|
wsproto==1.2.0
|
||||||
|
yarl==1.18.3
|
0
web/__init__.py
Normal file
0
web/__init__.py
Normal file
12
web/app.py
Normal file
12
web/app.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from quart import Quart
|
||||||
|
from .routes.dashboard import dashboard
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def create_app():
|
||||||
|
log.info("Creating web app and registering blueprints")
|
||||||
|
app = Quart(__name__)
|
||||||
|
app.register_blueprint(dashboard, url_prefix="/dashboard")
|
||||||
|
return app
|
7
web/routes/dashboard.py
Normal file
7
web/routes/dashboard.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from quart import Blueprint
|
||||||
|
|
||||||
|
dashboard = Blueprint("dashboard", __name__)
|
||||||
|
|
||||||
|
@dashboard.route("/")
|
||||||
|
async def home():
|
||||||
|
return "Dashboard page"
|
Loading…
x
Reference in New Issue
Block a user