diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 21f0547..2664ef5 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -4,19 +4,12 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
@@ -78,7 +71,7 @@
-
+
@@ -88,7 +81,15 @@
1704234449168
-
+
+
+ 1704234565095
+
+
+
+ 1704234565095
+
+
@@ -97,6 +98,7 @@
-
+
+
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..9fe522b
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,16 @@
+FROM python:3.11-bookworm
+
+RUN DEBIAN_FRONTEND=noninteractive apt-get update
+RUN DEBIAN_FRONTEND=noninteractive apt-get install -y traceroute iputils-ping dnsutils net-tools git chromium chromium-driver chromium-sandbox chromium-shell
+
+RUN pip install --upgrade --break-system-packages pip wheel setuptools
+
+COPY requirements.txt /tmp/requirements.txt
+RUN pip install -Ur /tmp/requirements.txt --break-system-packages --no-input
+
+WORKDIR /app
+COPY main.py /app
+COPY cookies.txt /app
+COPY cogs/ /app/cogs/
+
+CMD ["python", "main.py"]
diff --git a/cogs/net.py b/cogs/net.py
index e63988b..2d0af08 100644
--- a/cogs/net.py
+++ b/cogs/net.py
@@ -1,15 +1,15 @@
+import asyncio
import io
import os
+import re
+import time
import typing
import discord
-from rich.console import Console
-import time
-import re
-from dns import asyncresolver
-from rich.tree import Tree
-import asyncio
from discord.ext import commands
+from dns import asyncresolver
+from rich.console import Console
+from rich.tree import Tree
class NetworkCog(commands.Cog):
diff --git a/cogs/screenshot.py b/cogs/screenshot.py
index 22d8abf..869e48e 100644
--- a/cogs/screenshot.py
+++ b/cogs/screenshot.py
@@ -1,21 +1,16 @@
+import asyncio
import datetime
import io
import logging
-import shutil
+import os
import tempfile
import time
-import zipfile
from urllib.parse import urlparse
-from PIL import Image
import discord
from discord.ext import commands
-import asyncio
-import aiohttp
-from pathlib import Path
-
+from PIL import Image
from selenium import webdriver
-from selenium.common.exceptions import WebDriverException
from selenium.webdriver.chrome.options import Options as ChromeOptions
from selenium.webdriver.chrome.service import Service as ChromeService
@@ -30,174 +25,22 @@ class ScreenshotCog(commands.Cog):
# self.chrome_options.add_argument("--disable-gpu")
self.chrome_options.add_argument("--disable-extensions")
self.chrome_options.add_argument("--incognito")
+ if os.getuid() == 0:
+ self.chrome_options.add_argument("--no-sandbox")
prefs = {
- # "download.open_pdf_in_system_reader": False,
+ "download.open_pdf_in_system_reader": False,
# "download.prompt_for_download": True,
# "download.default_directory": "/dev/null",
- # "plugins.always_open_pdf_externally": False,
+ "plugins.always_open_pdf_externally": False,
"download_restrictions": 3,
}
self.chrome_options.add_experimental_option(
"prefs", prefs
)
- self.dir = Path(__file__).parent.parent / "chrome"
- self.dir.mkdir(mode=0o775, exist_ok=True)
-
- self.chrome_dir = self.dir / "chrome-headless-shell-linux64"
- self.chrome_bin = self.chrome_dir / "chrome-headless-shell"
- self.chromedriver_dir = self.dir / "chromedriver-linux64"
- self.chromedriver_bin = self.chromedriver_dir / "chromedriver"
-
- self.chrome_options.binary_location = str(self.chrome_bin.resolve())
-
self.log = logging.getLogger("jimmy.cogs.screenshot")
- def clear_directories(self):
- shutil.rmtree(self.chrome_dir, ignore_errors=True)
- shutil.rmtree(self.chromedriver_dir, ignore_errors=True)
- self.chrome_dir.mkdir(mode=0o775, exist_ok=True)
- self.chromedriver_dir.mkdir(mode=0o775, exist_ok=True)
-
- async def download_latest_chrome(self, current: str = None, *, channel: str = "Stable"):
- async with aiohttp.ClientSession(raise_for_status=True) as session:
- async with session.get(
- "https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json",
- ) as response:
- versions = await response.json()
- self.log.debug("Got chrome versions: %r", versions)
- downloads = versions["channels"][channel]["downloads"]
- version = versions["channels"][channel]["version"]
- if version == current:
- self.log.debug(f"Chrome is up to date ({versions} == {current})")
- return
-
- self.log.debug("Downloading chrome...")
- chrome_zip_url = filter(lambda x: x["platform"] == "linux64", downloads["chrome-headless-shell"])
- if not chrome_zip_url:
- self.log.critical("No chrome zip url found for linux64 in %r.", downloads["chrome-headless-shell"])
- raise RuntimeError("No chrome zip url found for linux64.")
- chrome_zip_url = next(chrome_zip_url)["url"]
- self.log.debug("Chrome zip url: %s", chrome_zip_url)
-
- self.clear_directories()
-
- chrome_target = (self.chrome_dir.parent / f"chrome-download-{version}.zip")
- chromedriver_target = (self.chromedriver_dir.parent / f"chromedriver-download-{version}.zip")
- if chrome_target.exists():
- chrome_target.unlink()
- if chromedriver_target.exists():
- chromedriver_target.unlink()
- with chrome_target.open("wb+") as file:
- async with session.get(chrome_zip_url) as response:
- async for data in response.content.iter_any():
- self.log.debug("Read %d bytes from chrome zip.", len(data))
- file.write(data)
-
- self.log.debug("Extracting chrome...")
- with zipfile.ZipFile(chrome_target) as zip_file:
- await asyncio.get_event_loop().run_in_executor(
- None,
- zip_file.extractall,
- self.chrome_dir.parent
- )
- self.log.debug("Finished extracting chrome.")
-
- self.log.debug("Downloading chromedriver...")
- chromedriver_zip_url = filter(lambda x: x["platform"] == "linux64", downloads["chromedriver"])
- if not chromedriver_zip_url:
- self.log.critical("No chromedriver zip url found for linux64 in %r.", downloads["chromedriver"])
- raise RuntimeError("No chromedriver zip url found for linux64.")
- chromedriver_zip_url = next(chromedriver_zip_url)["url"]
- self.log.debug("Chromedriver zip url: %s", chromedriver_zip_url)
-
- with chromedriver_target.open("wb+") as file:
- async with session.get(chromedriver_zip_url) as response:
- async for data in response.content.iter_any():
- self.log.debug("Read %d bytes from chromedriver zip.", len(data))
- file.write(data)
-
- self.log.debug("Extracting chromedriver...")
- with zipfile.ZipFile(chromedriver_target) as zip_file:
- await asyncio.get_event_loop().run_in_executor(
- None,
- zip_file.extractall,
- self.chromedriver_dir.parent
- )
- self.log.debug("Finished extracting chromedriver.")
-
- self.log.debug("Making binaries executable.")
- await asyncio.get_event_loop().run_in_executor(
- None,
- self.chrome_bin.chmod,
- 0o775
- )
- await asyncio.get_event_loop().run_in_executor(
- None,
- self.chromedriver_bin.chmod,
- 0o775
- )
- self.log.debug("Finished making binaries executable.")
-
- async def get_version(self, full: bool = False) -> str:
- proc = await asyncio.create_subprocess_exec(
- str(self.chromedriver_bin),
- "--version",
- stdout=asyncio.subprocess.PIPE,
- stderr=asyncio.subprocess.PIPE
- )
- stdout, stderr = await proc.communicate()
- if proc.returncode != 0:
- raise RuntimeError(f"Error getting chromedriver version: {stderr.decode()}")
- if full:
- return stdout.decode().strip()
- return stdout.decode().strip().split(" ")[1]
-
- async def is_up_to_date(self, channel: str = "Stable"):
- try:
- current = await self.get_version(False)
- except (RuntimeError, FileNotFoundError):
- return False
- async with aiohttp.ClientSession(raise_for_status=True) as session:
- async with session.get(
- "https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions-with-downloads.json",
- ) as response:
- versions = await response.json()
- self.log.debug("Got chrome versions: %r", versions)
- version = versions["channels"][channel]["version"]
- if version == current:
- self.log.debug(f"Chrome is up to date ({versions} == {current})")
- return True
- return False
-
- @commands.command(name="update-chrome")
- async def update_chrome(self, ctx: commands.Context, channel: str = "Stable"):
- channel = channel.title()
- if await self.is_up_to_date(channel):
- await ctx.reply("Chrome is already up to date. Updating anyway.")
- async with ctx.channel.typing():
- try:
- await self.download_latest_chrome(channel)
- except RuntimeError as e:
- return await ctx.reply(f"\N{cross mark} Error downloading chrome: {e}")
-
- chrome_okay = self.chrome_bin.exists() and self.chrome_bin.is_file()
- chromedriver_okay = self.chromedriver_bin.exists() and self.chromedriver_bin.is_file()
-
- try:
- chromedriver_version = await self.get_version(True)
- except RuntimeError as e:
- chromedriver_version = str(e)
-
- return await ctx.reply(
- f"\N{white heavy check mark} Done.\n"
- f"CHANNEL: {channel}\n"
- f"CHROME OKAY: {chrome_okay}\n"
- f"CHROMEDRIVER OKAY: {chromedriver_okay}\n"
- f"CHROMEDRIVER VERSION: {chromedriver_version}"
- )
-
def compress_png(self, input_file: io.BytesIO) -> io.BytesIO:
img = Image.open(input_file)
img = img.convert("RGB")
@@ -220,6 +63,7 @@ class ScreenshotCog(commands.Cog):
raise RuntimeError("Couldn't compress image.")
return value
+ # noinspection PyTypeChecker
@commands.slash_command()
async def screenshot(
self,
@@ -242,17 +86,8 @@ class ScreenshotCog(commands.Cog):
parsed = urlparse(url)
await ctx.respond("Initialising...")
- if not all(map(lambda x: x.exists() and x.is_file(), (self.chrome_bin, self.chromedriver_bin))):
- await ctx.edit(content="Chrome is not installed, downloading. This may take a minute.")
- await self.download_latest_chrome()
- await ctx.edit(content="Initialising...")
- elif not await self.is_up_to_date():
- await ctx.edit(content="Updating chrome. This may take a minute.")
- await self.download_latest_chrome()
- await ctx.edit(content="Initialising...")
-
start_init = time.time()
- service = await asyncio.to_thread(ChromeService, str(self.chromedriver_bin))
+ service = await asyncio.to_thread(ChromeService)
driver: webdriver.Chrome = await asyncio.to_thread(
webdriver.Chrome,
service=service,
diff --git a/cogs/ytdl.py b/cogs/ytdl.py
index 1e9b796..28732ae 100644
--- a/cogs/ytdl.py
+++ b/cogs/ytdl.py
@@ -1,17 +1,16 @@
import asyncio
import functools
import logging
+import tempfile
import textwrap
import typing
+from pathlib import Path
+from urllib.parse import urlparse
import discord
import yt_dlp
-from urllib.parse import urlparse
-from pathlib import Path
-import tempfile
from discord.ext import commands
-
COOKIES_TXT = Path.cwd() / "cookies.txt"
diff --git a/config.example.toml b/config.example.toml
index 189353c..76ef8cb 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -1,2 +1,6 @@
[jimmy]
-token = "foo"
+token = "token"
+debug_guilds = [994710566612500550]
+
+[logging]
+level = "DEBUG"
\ No newline at end of file
diff --git a/main.py b/main.py
index 4b898ef..1852a61 100644
--- a/main.py
+++ b/main.py
@@ -1,14 +1,13 @@
import datetime
-import traceback
-
-import toml
-import discord
import logging
-from pathlib import Path
-from rich.logging import RichHandler
+import traceback
from logging import FileHandler
-from discord.ext import commands
+from pathlib import Path
+import discord
+import toml
+from discord.ext import commands
+from rich.logging import RichHandler
log = logging.getLogger("jimmy")
diff --git a/requirements.txt b/requirements.txt
index 85c37a1..ce1f46d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,9 +1,12 @@
wheel>=0.42
setuptools>=69
yt-dlp @ https://github.com/yt-dlp/yt-dlp/archive/master.tar.gz
-py-cord==2.4.1
+# py-cord==2.4.1
+py-cord @ git+https://github.com/Pycord-Development/pycord.git
httpx==0.26
psycopg==3.1.16
toml==0.10.2
pillow==10.2
selenium==4.16
+rich==13.7
+dnspython==2.4.2