Compare commits

...

60 Commits

Author SHA1 Message Date
forust ace23ad1f9 fix: remove www.xdfnx.cfd from ingress, add Gitea access log config
ci / lint-prettier (push) Successful in 13s
ci / lint-ruff (push) Successful in 7s
ci / lint-yaml (push) Successful in 17s
ci / lint-dockerfiles (push) Successful in 14s
ci / validate (push) Successful in 15s
ci / build (push) Successful in 26s
2026-07-20 11:40:41 +02:00
forust 92aa731e44 deleted crowdsec stack from the repo. will figure something else
ci / lint-prettier (push) Successful in 18s
ci / lint-ruff (push) Successful in 6s
ci / lint-yaml (push) Successful in 6s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 6s
ci / build (push) Successful in 43s
Signed-off-by: mr-forust <vzlomdsisma@gmail.com>
2026-07-19 23:16:14 +02:00
forust 87ca3fd40c chore: updatet chernuha's pfp, added projects sections for forust.xyz
ci / lint-prettier (push) Successful in 8s
ci / lint-ruff (push) Successful in 3s
ci / lint-yaml (push) Successful in 7s
ci / lint-dockerfiles (push) Successful in 6s
ci / validate (push) Successful in 7s
ci / build (push) Successful in 18s
2026-07-05 02:59:31 +02:00
forust 82bcd30ed8 updated xdfnx's page
ci / lint-prettier (push) Successful in 8s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 6s
ci / lint-dockerfiles (push) Successful in 4s
ci / validate (push) Successful in 11s
ci / build (push) Successful in 19s
2026-07-04 01:01:05 +02:00
forust 620262d98c ci: fetch full history for change detection after rebase
ci / lint-prettier (push) Successful in 9s
ci / lint-ruff (push) Successful in 6s
ci / lint-yaml (push) Successful in 9s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 5s
ci / build (push) Successful in 3s
2026-07-04 00:55:46 +02:00
forust 831f3a46b0 updated xdfnx's page
ci / lint-prettier (push) Successful in 8s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 6s
ci / lint-dockerfiles (push) Successful in 5s
ci / validate (push) Successful in 5s
ci / build (push) Successful in 3s
2026-07-04 00:46:13 +02:00
forust f7902e74e8 ci: require lint and validate before build
ci / lint-prettier (push) Successful in 7s
ci / lint-ruff (push) Successful in 4s
ci / lint-yaml (push) Successful in 6s
ci / lint-dockerfiles (push) Successful in 3s
ci / validate (push) Successful in 5s
ci / build (push) Successful in 2s
2026-06-30 01:23:53 +02:00
forust eb8d1b361e ci: add branch tags to docker builds
ci / lint (push) Successful in 15s
ci / validate (push) Successful in 8s
ci / build (push) Successful in 3s
2026-06-30 01:20:51 +02:00
forust 6e2cafb206 ci: merge lint validate and docker builds
ci / lint (push) Successful in 14s
ci / validate (push) Successful in 19s
ci / build (push) Successful in 2s
2026-06-30 01:17:31 +02:00
forust 67b0c0824f ci: restore docker-based lint and validate jobs
lint / prettier (push) Successful in 7s
lint / ruff (push) Successful in 3s
lint / yamllint (push) Successful in 5s
lint / hadolint (push) Successful in 4s
validate / yaml (push) Successful in 6s
validate / k8s (push) Successful in 4s
2026-06-30 01:12:23 +02:00
forust 8e72e0a920 ci: run lint and validate tools locally
lint / prettier (push) Failing after 2s
lint / ruff (push) Successful in 2s
lint / yamllint (push) Successful in 3s
lint / hadolint (push) Failing after 2s
validate / yaml (push) Successful in 2s
validate / k8s (push) Failing after 1s
2026-06-30 00:14:14 +02:00
forust 73a1132beb Align Traefik Helm log values with chart v41
lint / prettier (push) Successful in 1m59s
lint / ruff (push) Successful in 4s
lint / yamllint (push) Successful in 5s
lint / hadolint (push) Successful in 4s
validate / yaml (push) Successful in 6s
validate / k8s (push) Successful in 3s
2026-06-29 23:02:26 +02:00
forust a128523c24 Fix CrowdSec middleware references in Traefik ingresses 2026-06-29 22:47:21 +02:00
forust ee881acd0e refactor: update xdfnx homepage index.html
lint / prettier (push) Successful in 14s
lint / ruff (push) Successful in 5s
lint / yamllint (push) Successful in 9s
lint / hadolint (push) Successful in 17s
validate / yaml (push) Successful in 8s
validate / k8s (push) Successful in 7s
2026-06-28 11:59:57 +02:00
forust bacb2f4b9f fix: correct Traefik rule syntax for local IngressRoutes
Move parentheses outside Host() calls so that || and && operators
are properly grouped in Traefik rule expressions.
2026-06-28 11:59:52 +02:00
forust 91211e7b78 fix: resolve CrowdSec Helm upgrade failure - remove duplicate DISABLE_ONLINE_API env and add metrics config 2026-06-28 11:59:46 +02:00
forust 9b3a7aadb4 fix: resolve pyrogram imports by adding venv and pyright config
lint / prettier (push) Successful in 7s
lint / ruff (push) Successful in 4s
lint / yamllint (push) Successful in 6s
lint / hadolint (push) Successful in 4s
validate / yaml (push) Successful in 5s
validate / k8s (push) Successful in 5s
- Create .venv with pyrofork and all dependencies installed
- Add pyrightconfig.json at workspace root and in userbot/
- Enable pyright as language server for Python in Zed settings
- Update uv.lock with resolved dependency tree
2026-06-21 22:33:04 +02:00
forust b123621ead chore: remove github obsolete prod deploy workflow
lint / prettier (push) Successful in 7s
lint / ruff (push) Successful in 4s
lint / yamllint (push) Successful in 6s
lint / hadolint (push) Successful in 4s
validate / yaml (push) Successful in 6s
validate / k8s (push) Successful in 4s
2026-06-21 22:24:30 +02:00
forust a2df8504f5 Fix DL3013: pin pip version in webinar-checker Dockerfile
lint / prettier (push) Successful in 8s
lint / ruff (push) Successful in 4s
lint / yamllint (push) Successful in 6s
lint / hadolint (push) Successful in 4s
validate / yaml (push) Successful in 6s
validate / k8s (push) Successful in 4s
2026-06-21 22:07:44 +02:00
forust fb43306571 Fix all lint issues: Dockerfiles (DL3015/DL3013/DL4006) + Ruff (173→0 errors)
lint / prettier (push) Successful in 8s
lint / ruff (push) Successful in 5s
lint / yamllint (push) Successful in 7s
lint / hadolint (push) Failing after 4s
validate / yaml (push) Successful in 5s
validate / k8s (push) Successful in 5s
Dockerfile fixes:
- edu_master/phpsessid-bot: add --no-install-recommends, pin pip versions
- edu_master/webinar-checker: pin pip versions with --no-cache-dir
- userbot: add SHELL with pipefail for pipe operations

Ruff fixes (173 → 0):
- W293/W291/W292: whitespace clean via ruff format
- N806: camelCase → snake_case (anilist, safone, hearts, flux, etc.)
- ARG001/ARG002: prefix unused params with _
- SIM115: use context managers for file I/O
- SIM117: combine nested with statements
- S608: noqa on SQL f-strings (module name is validated)
- E402/N812/N817: import fixes
- B023: pass loop variable as argument
- I001: auto-sorted imports
- syntax: fixed = vs == in dtek_notif/main.py
2026-06-21 22:01:51 +02:00
forust f424d91405 Tighten lint workflow scope
lint / prettier (push) Successful in 8s
lint / ruff (push) Failing after 5s
lint / yamllint (push) Successful in 6s
lint / hadolint (push) Failing after 4s
validate / yaml (push) Successful in 6s
validate / k8s (push) Successful in 4s
2026-06-21 21:51:20 +02:00
forust 88a8f2987f Unify workflow job naming
lint / prettier (push) Failing after 9s
lint / ruff (push) Failing after 5s
lint / yamllint (push) Successful in 7s
lint / hadolint (push) Failing after 13s
validate / yaml (push) Successful in 6s
validate / k8s (push) Successful in 5s
2026-06-21 21:46:22 +02:00
forust 17027b232b Rename workflows to yaml 2026-06-21 21:45:16 +02:00
forust 6ecbbb39b4 Fix yamllint workflow invocation
validate / yaml (push) Successful in 7s
validate / k8s (push) Successful in 5s
2026-06-21 21:40:11 +02:00
forust 175cbc8860 Fix validation workflows for self-hosted runner
validate / yaml (push) Failing after 15s
validate / k8s (push) Successful in 9s
2026-06-21 21:37:30 +02:00
forust 6363d050b0 Add YAML validation workflows 2026-06-21 21:27:31 +02:00
forust c855764bc6 feat: add vaultwarden deployment config (compose + k8s)
Deploy to Server / deploy (push) Failing after 1s
2026-06-21 01:02:09 +02:00
forust 7d92b85e21 Merge commit '4355f451d4b4288d43468e08cad1f377e511f98a'
Deploy to Server / deploy (push) Has been cancelled
2026-06-19 23:23:28 +02:00
forust 9364392bc0 Merge commit '3eaef5dc90b716cc0fa391cbe2394be56d5f6041' as 'userbot'
Deploy to Server / deploy (push) Has been cancelled
2026-06-19 23:20:23 +02:00
forust 4355f451d4 Merge commit '3eaef5dc90b716cc0fa391cbe2394be56d5f6041' as 'userbot' 2026-06-19 23:20:23 +02:00
forust 3eaef5dc90 Squashed 'userbot/' content from commit 7fb0a0e
git-subtree-dir: userbot
git-subtree-split: 7fb0a0e179
2026-06-19 23:20:23 +02:00
forust 69ffd3682e refactor: userbot to subtree 2026-06-19 23:20:13 +02:00
forust 1930600c40 Revert "refactor: extract userbot to standalone repo, add as git submodule"
This reverts commit 3c383db9a7.
2026-06-19 23:11:27 +02:00
forust d74a705d53 chore(k8s): rewritten ingressroute to include headplane AND headscale-admin ui
Deploy to Server / deploy (push) Has been cancelled
new routes groupping style
2026-06-19 23:02:22 +02:00
forust 3c383db9a7 refactor: extract userbot to standalone repo, add as git submodule
Deploy to Server / deploy (push) Has been cancelled
userbot now lives at ssh://git@gitssh.forust.xyz:2221/forust/userbot.git
and is included in homelab as a submodule at userbot/
2026-06-19 15:39:00 +02:00
forust 7fb0a0e179 chore: batch lint fixes across userbot and edu_master
- S113: Add timeout=10 to all requests calls (74 fixes)
- E722: Replace bare except: with except Exception:
- B904: Replace redundant re-raise with bare raise
- E402: Add noqa for intentional late imports after import_library()
- S102/S307/S310/S311/S603/S605/S606/S607/S108: Add noqa for intentional usage
- F601: Fix duplicate dict key in unsplash.py
- N802: Rename ReplyCheck -> reply_check with backward compat alias
- N813: Rename bs -> BS in icons.py
- B007/B020: Rename loop var _j in animations.py
- SIM102: Collapse nested if in autofwd.py
- SIM113: Use enumerate() in calculator.py
- A002: Add noqa for builtin shadowing in admlist.py
- F811: Add noqa for cohere redefinition
- edu_master: Fix ARG001, S108, S110, SIM117, apply --unsafe-fixes
- Add modules_list.txt with full module inventory
2026-06-19 15:36:25 +02:00
forust 227e5fda27 chore: batch lint fixes across userbot and edu_master
- S113: Add timeout=10 to all requests calls (74 fixes)
- E722: Replace bare except: with except Exception:
- B904: Replace redundant re-raise with bare raise
- E402: Add noqa for intentional late imports after import_library()
- S102/S307/S310/S311/S603/S605/S606/S607/S108: Add noqa for intentional usage
- F601: Fix duplicate dict key in unsplash.py
- N802: Rename ReplyCheck -> reply_check with backward compat alias
- N813: Rename bs -> BS in icons.py
- B007/B020: Rename loop var _j in animations.py
- SIM102: Collapse nested if in autofwd.py
- SIM113: Use enumerate() in calculator.py
- A002: Add noqa for builtin shadowing in admlist.py
- F811: Add noqa for cohere redefinition
- edu_master: Fix ARG001, S108, S110, SIM117, apply --unsafe-fixes
- Add modules_list.txt with full module inventory
2026-06-19 15:36:25 +02:00
forust 20bce5b31c fix(userbot): add missing safone.py imports, apply ruff --unsafe-fixes
- Add missing aiohttp, PIL, BytesIO imports to safone.py (F821 runtime bugs)
- Apply ruff --unsafe-fixes (27 fixes): ternary operators, .get() patterns,
  contextlib.suppress, enumerate(), collapsible if/else, remove .keys()
2026-06-19 15:27:12 +02:00
forust 70d7855f06 fix(userbot): add missing safone.py imports, apply ruff --unsafe-fixes
- Add missing aiohttp, PIL, BytesIO imports to safone.py (F821 runtime bugs)
- Apply ruff --unsafe-fixes (27 fixes): ternary operators, .get() patterns,
  contextlib.suppress, enumerate(), collapsible if/else, remove .keys()
2026-06-19 15:27:12 +02:00
forust c905bbd039 chore(userbot): optimize Dockerfile with multi-stage build and static ffmpeg
- Multi-stage build: pip deps built in separate stage
- Static ffmpeg binary instead of apt package (avoid 200+ deps)
- Keep only git, mediainfo, wget via apt
2026-06-19 14:56:37 +02:00
forust 7ba6bc44f2 chore(userbot): apply ruff check --fix and ruff format
- ruff check --fix: 210 auto-fixed errors (import sorting, trailing
  whitespace, unused imports, f-string fixups, deprecated annotations)
- ruff format: 104 files reformatted to consistent style
- 268 non-auto-fixable issues remain (S113 requests timeout, etc.)
2026-06-19 12:19:01 +02:00
forust 95cec59263 chore(userbot): apply prettier formatting across manifests 2026-06-19 12:03:13 +02:00
forust 20b8c93275 chore(k8s): make dockmon statefulset
+ adjusted userbot sys reqs
2026-06-10 19:40:45 +02:00
forust bb821e138a chore(k8): adjusted system resources requests and limits based on manual monitoring 2026-06-10 19:37:16 +02:00
forust b7854447af lint: yaml spaces and tabs 2026-06-09 12:59:36 +02:00
forust 444bb97f8e feat: add userbot k8s deployment method
- Kustomize: base + overlays/dev + overlays/prod
2026-06-07 19:41:28 +02:00
forust 4f01cdac31 fix: removed git checkout (was destructive)
- Remove git init/fetch/checkout from utils/misc.py
- Hardcode userbot_version to 2.5.0
2026-06-07 19:40:52 +02:00
forust cb40b10ecf chore: add gitea container registry compose support for localy builded apps 2026-06-07 14:37:57 +02:00
forust bed58c84ef refactor: update .dockerignore
pull_policy never to use local images
2026-05-25 01:43:46 +02:00
forust 56e5d79e3e refactor: improved error handling, timeouts and use temp files 2026-05-21 22:14:29 +02:00
forust cd0ce06246 refactor: imporved layer caching for dockerfile
using existing built image for account 2
2026-05-21 22:12:33 +02:00
forust a699ceb935 refactor: userbots' compose-files cleanup 2025-12-09 21:45:24 +01:00
forust ce66a546f1 chore: update gitignore, add translations 2025-11-27 18:58:17 +01:00
forust a30bda4940 Renamed userbot's dockercompose for easy access 2025-11-13 04:00:23 +01:00
forust b722467991 Remove unnecessary network and development configurations from userbot Docker Compose file 2025-11-13 03:48:50 +01:00
forust 5f8fd05266 Add userbot Docker Compose configuration for userbot_forust and userbot_anna services 2025-11-13 00:17:26 +01:00
forust 1c7afe5bb3 Move userbot Docker Compose configuration for forust and anna services 2025-11-11 01:57:44 +01:00
forust 4ff80c07b0 deleting that install shit 2025-11-11 01:41:24 +01:00
forust 3a5652daa7 userbot/install.sh, start 2025-11-11 01:39:53 +01:00
forust 4e18cd0eb3 init, .gitignore 2025-11-11 00:02:49 +01:00
122 changed files with 3586 additions and 2800 deletions
+191
View File
@@ -0,0 +1,191 @@
# Инструкция: Анализ хранилища Kubernetes и настройка NFS
## Цель
Проанализировать текущую конфигурацию хранилища Kubernetes и подготовить план внедрения NFS StorageClass для сохранения данных при удалении namespace.
## 1. Собрать информацию о кластере
### 1.1. Версия Kubernetes и тип дистрибутива
```bash
kubectl version --short
# или
kubectl version
```
Определить, используется ли k3s, k8s, microk8s и т.д.:
```bash
# Проверить наличие k3s
which k3s
# Проверить процесс
ps aux | grep -E 'kube|k3s'
```
### 1.2. StorageClass
```bash
kubectl get storageclass -o wide
```
Запомнить:
- `PROVISIONER` — какой драйвер используется
- `RECLAIMPOLICY` — Delete или Retain
- Какой StorageClass помечен как `(default)`
### 1.3. Существующие PV и PVC
```bash
kubectl get pv -o wide
kubectl get pvc --all-namespaces
```
Посмотреть, какие PVC привязаны к каким PV, и какой reclaimPolicy у PV.
### 1.4. Нода и диски
```bash
# Список нод
kubectl get nodes -o wide
# На каждой ноде (через ssh или локально):
lsblk
df -h
cat /etc/fstab
```
Определить:
- Есть ли отдельный раздел/диск для данных
- Куда смонтированы разделы
- Сколько свободного места
- Есть ли монтирование NTFS-разделов (как `/media/forust/Programs`)
### 1.5. Где local-path хранит данные (для k3s)
```bash
ls -la /var/lib/rancher/k3s/storage/ 2>/dev/null
# или для microk8s
ls -la /var/snap/microk8s/common/ 2>/dev/null
```
## 2. Анализ: сохраняются ли данные при удалении namespace?
| Сценарий | Результат |
|---|---|
| `kubectl delete ns <ns>` | Все PVC в namespace удаляются |
| PVC → PV c `reclaimPolicy: Delete` | PV и данные удалены |
| PVC → PV c `reclaimPolicy: Retain` | PV остаётся (статус Released), данные целы |
**Вывод:** Если reclaimPolicy в StorageClass = `Delete`, то данные **пропадут**. Если `Retain` — сохранятся.
## 3. План внедрения NFS
### 3.1. Проверить, установлен ли NFS
```bash
which nfsstat exportfs mount.nfs
systemctl status nfs-server 2>/dev/null || systemctl status nfs-kernel-server 2>/dev/null
```
### 3.2. Выбрать директорию для NFS-экспорта
Варианты (выбрать подходящий):
- `/var/lib/k8s-nfs/` — на корневом разделе
- `<путь к отдельному разделу>/k8s-nfs/` — если есть отдельный диск/раздел
- Не рекомендуется использовать NTFS-раздел (проблемы с правами и производительностью)
Требования:
- Файловая система: ext4 или xfs (не ntfs!)
- Достаточно свободного места
- Права: `755`, владелец root
### 3.3. Установить NFS-сервер
```bash
# Debian/Ubuntu
apt update && apt install -y nfs-kernel-server
# RHEL/Fedora
dnf install -y nfs-utils
```
### 3.4. Настроить экспорт
Создать директорию:
```bash
mkdir -p /var/lib/k8s-nfs
chmod 755 /var/lib/k8s-nfs
```
Добавить в `/etc/exports`:
```
/var/lib/k8s-nfs *(rw,sync,no_subtree_check,no_root_squash)
```
Применить:
```bash
exportfs -rav
```
Проверить:
```bash
showmount -e localhost
```
### 3.5. Выбрать способ интеграции с Kubernetes
#### Вариант A: nfs-subdir-external-provisioner (проще)
```bash
helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
helm install nfs-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
--namespace kube-system \
--set nfs.server=127.0.0.1 \
--set nfs.path=/var/lib/k8s-nfs \
--set storageClass.name=nfs \
--set storageClass.defaultClass=false \
--set storageClass.reclaimPolicy=Retain
```
#### Вариант B: NFS CSI Driver
```bash
helm repo add csi-driver-nfs https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/charts
helm install csi-driver-nfs csi-driver-nfs/csi-driver-nfs --namespace kube-system
```
После установки CSI драйвера создать StorageClass:
```yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs
provisioner: nfs.csi.k8s.io
parameters:
server: 127.0.0.1
share: /var/lib/k8s-nfs
reclaimPolicy: Retain
volumeBindingMode: Immediate
```
### 3.6. Проверить результат
```bash
kubectl get storageclass
kubectl get pods -n kube-system | grep -E 'nfs|provisioner'
```
## 4. Итоговая конфигурация
После внедрения в кластере будет два StorageClass:
| Имя | Provisioner | ReclaimPolicy | Назначение |
|---|---|---|---|
| `local-path` (default) | rancher.io/local-path | Delete | Временные данные, stateless |
| `nfs` | nfs-subdir-external-provisioner или nfs.csi.k8s.io | Retain | Данные, которые нужно сохранять |
**Главное преимущество:** PVC c `storageClassName: nfs` при удалении namespace сохраняют данные на диске, так как NFS-провизор использует `reclaimPolicy: Retain` или файлы физически остаются в NFS-экспорте.
## 5. Ответы на частые вопросы
**В:** Не упадёт ли local-path при установке NFS?
**О:** Нет, они независимы. local-path продолжает работать как обычно.
**В:** Данные NFS и local-path будут на одном диске?
**О:** Да, можно настроить оба на одном разделе, в разных каталогах.
**В:** Что если у меня несколько нод?
**О:** NFS сервер нужно поднять на одной ноде, а с других нод должна быть доступна шари. Для multi-node лучше использовать отдельный сервер или distributed storage (Longhorn, Rook/Ceph).
**В:** Можно ли использовать существующий NTFS-раздел для NFS?
**О:** Не рекомендуется — NTFS не поддерживает права Linux (no_root_squash не сработает корректно), возможны проблемы с блокировками и производительностью.
+326
View File
@@ -0,0 +1,326 @@
name: ci
on:
push:
branches:
- "**"
pull_request:
workflow_dispatch:
env:
REGISTRY: gcr.forust.xyz
jobs:
lint-prettier:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check formatting with Prettier
shell: bash
run: |
mapfile -t prettier_files < <(
git ls-files \
| grep -E '\.(md|json|ya?ml|html|css)$' \
| grep -Ev '^(\.docs/|\.zed/|errorpages/html/|homepages/(forust_files|xdfnx_files)/)'
)
if [ "${#prettier_files[@]}" -eq 0 ]; then
echo "No Prettier-managed files found."
exit 0
fi
docker run --rm \
-v "$PWD:/work" \
-w /work \
node:22-alpine \
sh -lc 'npx --yes prettier@3 --check --ignore-unknown "$@"' sh "${prettier_files[@]}"
lint-ruff:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Lint Python with Ruff
shell: bash
run: |
docker run --rm \
-v "$PWD:/work" \
-w /work \
ghcr.io/astral-sh/ruff:latest \
check .
lint-yaml:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Lint YAML syntax
shell: bash
run: |
docker run --rm \
-v "$PWD:/work" \
-w /work \
cytopia/yamllint:latest \
-c .yamllint .
lint-dockerfiles:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Lint Dockerfiles
shell: bash
run: |
mapfile -t dockerfiles < <(
git ls-files ':(glob)**/Dockerfile' ':(glob)**/Dockerfile.*'
)
if [ "${#dockerfiles[@]}" -eq 0 ]; then
echo "No Dockerfiles found."
exit 0
fi
docker run --rm \
-v "$PWD:/work" \
-w /work \
--entrypoint hadolint \
hadolint/hadolint:latest-debian \
-c .hadolint.yaml "${dockerfiles[@]}"
validate:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Validate Kubernetes manifests
shell: bash
run: |
mapfile -t manifests < <(
git ls-files ':(glob)**/k8s/**/*.yaml' ':(glob)**/k8s/**/*.yml' \
| grep -Ev '(^|/)(kustomization\.ya?ml|.*\.example\.ya?ml|.*values\.ya?ml|patch-.*\.ya?ml)$'
)
if [ "${#manifests[@]}" -eq 0 ]; then
echo "No Kubernetes manifests found."
exit 0
fi
docker run --rm \
-v "$PWD:/work" \
-w /work \
ghcr.io/yannh/kubeconform:latest \
-strict \
-ignore-missing-schemas \
-summary \
"${manifests[@]}"
build:
needs: [lint-prettier, lint-ruff, lint-yaml, lint-dockerfiles, validate]
if: github.event_name != 'pull_request' && (github.ref_name == 'main' || github.ref_name == 'dev')
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detect changed docker-built services
id: services
shell: bash
run: |
base="${{ github.event.before }}"
if [ -z "$base" ] || [ "$base" = "0000000000000000000000000000000000000000" ]; then
base="$(git rev-list --max-parents=0 HEAD)"
fi
mapfile -t changed_files < <(git diff --name-only "$base" "${GITHUB_SHA}")
services=()
add_service() {
local name="$1"
local seen=0
for existing in "${services[@]}"; do
if [ "$existing" = "$name" ]; then
seen=1
break
fi
done
if [ "$seen" -eq 0 ]; then
services+=("$name")
fi
}
for file in "${changed_files[@]}"; do
case "$file" in
dtek_notif/*)
add_service dtek_notif
;;
errorpages/*)
add_service errorpages
;;
userbot/*)
add_service userbot
;;
homepages/*)
add_service homepages
;;
edu_master/phpsessid-bot/*|edu_master/webinar-checker/*|edu_master/compose.yaml)
add_service edu_master
;;
esac
done
if [ "${#services[@]}" -eq 0 ]; then
echo "No docker-built services changed."
echo "services=" >> "$GITHUB_OUTPUT"
exit 0
fi
printf '%s\n' "${services[@]}" | tee /tmp/services.txt
echo "services=$(paste -sd, /tmp/services.txt)" >> "$GITHUB_OUTPUT"
- name: Log in to registry
if: steps.services.outputs.services != ''
shell: bash
run: |
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login "${REGISTRY}" \
-u "${{ secrets.REGISTRY_USERNAME }}" \
--password-stdin
- name: Build and push changed images
if: steps.services.outputs.services != ''
shell: bash
run: |
IFS=, read -r -a services <<< "${{ steps.services.outputs.services }}"
for service in "${services[@]}"; do
case "$service" in
dtek_notif)
image="${REGISTRY}/forust/dtek-notif"
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" dtek_notif
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
;;
errorpages)
image="${REGISTRY}/forust/error-pages"
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" errorpages
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
;;
userbot)
image="${REGISTRY}/forust/userbot"
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" userbot
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
;;
homepages)
for service in forust xdfnx; do
case "$service" in
forust)
image="${REGISTRY}/forust/forust-homepage"
;;
xdfnx)
image="${REGISTRY}/forust/xdfnx-homepage"
;;
esac
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" -f "homepages/Dockerfile.${service}" homepages
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
done
;;
edu_master)
for service in session-keeper webinar-checker; do
case "$service" in
session-keeper)
context="edu_master/phpsessid-bot"
image="${REGISTRY}/forust/session-keeper"
;;
webinar-checker)
context="edu_master/webinar-checker"
image="${REGISTRY}/forust/webinar-checker"
;;
esac
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" "$context"
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
done
;;
esac
done
-39
View File
@@ -1,39 +0,0 @@
name: Deploy to Server
run-name: Deploying to ${{ runner.os}} server on ${{ gitea.ref }}
on:
push:
branches:
- main
- ci/gitea-actions
jobs:
deploy:
runs-on: prod
steps:
- name: Fetch and Diff Analysis
id: diff
run: |
cd ${{ secrets.PROD_DIR }}
git fetch origin main
CHANGES=$(git diff --name-only HEAD origin/main | cut -d/ -f1 | sort -u | tr '\n' ' ')
echo "dirs=$CHANGES" >> $GITHUB_OUTPUT
echo "Changed dirs: $CHANGES"
- name: Sync Server Files
run: |
cd ${{ secrets.PROD_DIR }}
git reset --hard origin/main
echo "Server files synced with origin/main"
- name: Deploy Services
run: |
cd ${{ secrets.PROD_DIR }}
for dir in ${{ steps.diff.outputs.dirs }}; do
if [ -d "$dir" ] && ([ -f "$dir/compose.yaml" ] || [ -f "$dir/docker-compose.yaml" ]); then
echo ">>> Deploying $dir"
cd "$dir"
DOCKER_BUILDKIT=1 BUILDKIT_PROGRESS=plain docker compose up -d --build --no-color
cd ..
else
echo ">>> Skipping $dir: no compose file found"
fi
done
+326
View File
@@ -0,0 +1,326 @@
name: ci
on:
push:
branches:
- "**"
pull_request:
workflow_dispatch:
env:
REGISTRY: gcr.forust.xyz
jobs:
lint-prettier:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check formatting with Prettier
shell: bash
run: |
mapfile -t prettier_files < <(
git ls-files \
| grep -E '\.(md|json|ya?ml|html|css)$' \
| grep -Ev '^(\.docs/|\.zed/|errorpages/html/|homepages/(forust_files|xdfnx_files)/)'
)
if [ "${#prettier_files[@]}" -eq 0 ]; then
echo "No Prettier-managed files found."
exit 0
fi
docker run --rm \
-v "$PWD:/work" \
-w /work \
node:22-alpine \
sh -lc 'npx --yes prettier@3 --check --ignore-unknown "$@"' sh "${prettier_files[@]}"
lint-ruff:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Lint Python with Ruff
shell: bash
run: |
docker run --rm \
-v "$PWD:/work" \
-w /work \
ghcr.io/astral-sh/ruff:latest \
check .
lint-yaml:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Lint YAML syntax
shell: bash
run: |
docker run --rm \
-v "$PWD:/work" \
-w /work \
cytopia/yamllint:latest \
-c .yamllint .
lint-dockerfiles:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Lint Dockerfiles
shell: bash
run: |
mapfile -t dockerfiles < <(
git ls-files ':(glob)**/Dockerfile' ':(glob)**/Dockerfile.*'
)
if [ "${#dockerfiles[@]}" -eq 0 ]; then
echo "No Dockerfiles found."
exit 0
fi
docker run --rm \
-v "$PWD:/work" \
-w /work \
--entrypoint hadolint \
hadolint/hadolint:latest-debian \
-c .hadolint.yaml "${dockerfiles[@]}"
validate:
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Validate Kubernetes manifests
shell: bash
run: |
mapfile -t manifests < <(
git ls-files ':(glob)**/k8s/**/*.yaml' ':(glob)**/k8s/**/*.yml' \
| grep -Ev '(^|/)(kustomization\.ya?ml|.*\.example\.ya?ml|.*values\.ya?ml|patch-.*\.ya?ml)$'
)
if [ "${#manifests[@]}" -eq 0 ]; then
echo "No Kubernetes manifests found."
exit 0
fi
docker run --rm \
-v "$PWD:/work" \
-w /work \
ghcr.io/yannh/kubeconform:latest \
-strict \
-ignore-missing-schemas \
-summary \
"${manifests[@]}"
build:
needs: [lint-prettier, lint-ruff, lint-yaml, lint-dockerfiles, validate]
if: github.event_name != 'pull_request' && (github.ref_name == 'main' || github.ref_name == 'dev')
runs-on: [self-hosted, linux, arch, homelab]
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detect changed docker-built services
id: services
shell: bash
run: |
base="${{ github.event.before }}"
if [ -z "$base" ] || [ "$base" = "0000000000000000000000000000000000000000" ]; then
base="$(git rev-list --max-parents=0 HEAD)"
fi
mapfile -t changed_files < <(git diff --name-only "$base" "${GITHUB_SHA}")
services=()
add_service() {
local name="$1"
local seen=0
for existing in "${services[@]}"; do
if [ "$existing" = "$name" ]; then
seen=1
break
fi
done
if [ "$seen" -eq 0 ]; then
services+=("$name")
fi
}
for file in "${changed_files[@]}"; do
case "$file" in
dtek_notif/*)
add_service dtek_notif
;;
errorpages/*)
add_service errorpages
;;
userbot/*)
add_service userbot
;;
homepages/*)
add_service homepages
;;
edu_master/phpsessid-bot/*|edu_master/webinar-checker/*|edu_master/compose.yaml)
add_service edu_master
;;
esac
done
if [ "${#services[@]}" -eq 0 ]; then
echo "No docker-built services changed."
echo "services=" >> "$GITHUB_OUTPUT"
exit 0
fi
printf '%s\n' "${services[@]}" | tee /tmp/services.txt
echo "services=$(paste -sd, /tmp/services.txt)" >> "$GITHUB_OUTPUT"
- name: Log in to registry
if: steps.services.outputs.services != ''
shell: bash
run: |
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login "${REGISTRY}" \
-u "${{ secrets.REGISTRY_USERNAME }}" \
--password-stdin
- name: Build and push changed images
if: steps.services.outputs.services != ''
shell: bash
run: |
IFS=, read -r -a services <<< "${{ steps.services.outputs.services }}"
for service in "${services[@]}"; do
case "$service" in
dtek_notif)
image="${REGISTRY}/forust/dtek-notif"
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" dtek_notif
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
;;
errorpages)
image="${REGISTRY}/forust/error-pages"
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" errorpages
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
;;
userbot)
image="${REGISTRY}/forust/userbot"
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" userbot
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
;;
homepages)
for service in forust xdfnx; do
case "$service" in
forust)
image="${REGISTRY}/forust/forust-homepage"
;;
xdfnx)
image="${REGISTRY}/forust/xdfnx-homepage"
;;
esac
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" -f "homepages/Dockerfile.${service}" homepages
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
done
;;
edu_master)
for service in session-keeper webinar-checker; do
case "$service" in
session-keeper)
context="edu_master/phpsessid-bot"
image="${REGISTRY}/forust/session-keeper"
;;
webinar-checker)
context="edu_master/webinar-checker"
image="${REGISTRY}/forust/webinar-checker"
;;
esac
tags=("latest")
case "${GITHUB_REF_NAME}" in
main)
tags+=("main" "prod")
;;
dev)
tags+=("dev")
;;
esac
build_args=()
for tag in "${tags[@]}"; do
build_args+=(-t "${image}:${tag}")
done
docker build "${build_args[@]}" "$context"
for tag in "${tags[@]}"; do
docker push "${image}:${tag}"
done
done
;;
esac
done
-41
View File
@@ -1,41 +0,0 @@
## BINARY MODE, USE WITH THE GITHUB RUNNER BINARY INSTALLED ON THE SERVER
name: Deploy to Server
run-name: Deploying onto server on ${{ github.ref }}
on:
push:
branches:
- main
- ci/actions
jobs:
deploy:
runs-on: [prod, self-hosted]
steps:
- name: Fetch and Diff Analysis
id: diff
run: |
cd ${{ secrets.PROD_DIR }}
git fetch origin main
CHANGES=$(git diff --name-only HEAD origin/main | cut -d/ -f1 | sort -u | tr '\n' ' ')
echo "dirs=$CHANGES" >> $GITHUB_OUTPUT
echo "Changed dirs: $CHANGES"
- name: Sync Server Files
run: |
cd ${{ secrets.PROD_DIR }}
git reset --hard origin/main
echo "Server files synced with origin/main"
- name: Deploy Services
run: |
cd ${{ secrets.PROD_DIR }}
for dir in ${{ steps.diff.outputs.dirs }}; do
if [ -d "$dir" ] && ([ -f "$dir/compose.yaml" ] || [ -f "$dir/docker-compose.yaml" ]); then
echo ">>> Deploying $dir"
cd "$dir"
DOCKER_BUILDKIT=1 BUILDKIT_PROGRESS=plain docker compose up -d --build --no-color
cd ..
else
echo ">>> Skipping $dir: no compose file found"
fi
done
+1 -2
View File
@@ -40,7 +40,7 @@ traefik/letsencrypt/acme.json
traefik/dynamic/fileservers.yml
traefik/dynamic/*.local.y*ml.*
traefik/dynamic/*.external.y*ml
traefik/k8s/fileservers.y*ml
traefik/logs/*
@@ -106,4 +106,3 @@ temp/*
traefik/k8s/local-tls.yaml
converters/k8s/config.yaml
convertx/k8s/config.yaml
traefik/k8s/crowdsec-middleware.yaml
+13 -12
View File
@@ -9,31 +9,32 @@
"hard_tabs": false,
"format_on_save": "on",
"formatter": {
"language_server": { "name": "yaml-language-server" }
}
"language_server": { "name": "yaml-language-server" },
},
},
"Python": {
"tab_size": 4,
"format_on_save": "on",
"language_servers": ["pyright", "ruff"],
"formatter": {
"language_server": { "name": "ruff" }
}
}
"language_server": { "name": "ruff" },
},
},
},
"lsp": {
"yaml-language-server": {
"settings": {
"yaml": {
"schemas": {
"kubernetes": ["**/k8s/*.yaml", "**/k8s/*.yml"]
"kubernetes": ["**/k8s/*.yaml", "**/k8s/*.yml"],
},
"validate": true,
"completion": true,
"format": {
"enable": true
}
}
}
}
}
"enable": true,
},
},
},
},
},
}
+7 -16
View File
@@ -10,7 +10,12 @@ spec:
- match: Host(`adguard.forust.xyz`) || Host(`dns.forust.xyz`)
kind: Rule
middlewares:
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
services:
- name: adguard-service
port: 3000
- match: (Host(`adguard.forust.xyz`) || Host(`dns.forust.xyz`)) && PathPrefix(`/dns-query`)
kind: Rule
middlewares:
services:
- name: adguard-service
port: 3000
@@ -31,22 +36,8 @@ spec:
services:
- name: adguard-service
port: 3000
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: adguard-doh
namespace: adguard
spec:
entryPoints:
- websecure
routes:
- match: (Host(`adguard.forust.xyz`) || Host(`dns.forust.xyz`)) && PathPrefix(`/dns-query`)
- match: (Host(`adguard.workstation.internal`) || Host(`dns.workstation.internal`) || Host(`adguard.gigaforust.internal`) || Host(`dns.gigaforust.internal`)) && PathPrefix(`/dns-query`)
kind: Rule
middlewares:
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
services:
- name: adguard-service
port: 3000
tls:
certResolver: letsencrypt
-1
View File
@@ -10,7 +10,6 @@ spec:
- match: Host(`auth.forust.xyz`)
kind: Rule
middlewares:
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
services:
- name: authentik-server-service
port: 9000
+1 -1
View File
@@ -7,7 +7,7 @@
"api_key": {
"api_key": "api_key_here",
"account_email": "your_email_here"
}
},
"zone_id": "your_zone-id",
"subdomains": [
{ "name": "", "proxied": true },
-1
View File
@@ -10,7 +10,6 @@ spec:
- match: Host(`cmk.forust.xyz`)
kind: Rule
middlewares:
- name: crowdsec-crowdsec-bouncer@kubernetescrd
services:
- name: checkmk-service
port: 5000
-14
View File
@@ -1,14 +0,0 @@
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: crowdsec-bouncer
namespace: crowdsec
spec:
plugin:
crowdsec-bouncer:
enabled: true
LogLevel: INFO
CrowdsecMode: live
CrowdsecLapiScheme: http
CrowdsecLapiHost: crowdsec-service.crowdsec.svc.cluster.local:8080
CrowdsecLapiKeyFile: "/etc/traefik/secrets/traefik-api-key"
-57
View File
@@ -1,57 +0,0 @@
container_runtime: containerd
agent:
env:
- name: COLLECTIONS
value: "crowdsecurity/traefik crowdsecurity/base-http-scenarios crowdsecurity/sshd"
extraVolumes:
- name: journal-dir
hostPath:
path: /var/log/journal
type: DirectoryOrCreate
- name: run-journal-dir
hostPath:
path: /run/log/journal
type: DirectoryOrCreate
extraVolumeMounts:
- name: journal-dir
mountPath: /var/log/journal
readOnly: true
- name: run-journal-dir
mountPath: /run/log/journal
readOnly: true
acquisition:
- namespace: traefik
podName: "*traefik*"
program: traefik
poll_without_inotify: true
acquisitionCustom: |
- source: journalctl
journalctl_filter:
- _SYSTEMD_UNIT=sshd.service
labels:
type: syslog
resources:
requests:
cpu: 50m
memory: 100Mi
limits:
cpu: 200m
memory: 500Mi
lapi:
env:
- name: COLLECTIONS
value: "crowdsecurity/traefik crowdsecurity/base-http-scenarios crowdsecurity/sshd"
service:
type: NodePort
nodePort: 30011
resources:
requests:
cpu: 50m
memory: 150Mi
limits:
cpu: 200m
memory: 500Mi
-1
View File
@@ -18,7 +18,6 @@ spec:
- match: Host(`dockmon.forust.xyz`)
kind: Rule
middlewares:
- name: crowdsec-crowdsec-bouncer@kubernetescrd
- name: security-headers@file
services:
- name: dockmon-service
-1
View File
@@ -10,7 +10,6 @@ spec:
- match: Host(`downtify.forust.xyz`)
kind: Rule
middlewares:
- name: crowdsec-crowdsec-bouncer@kubernetescrd
- name: security-chain@file
services:
- name: downtify-service
+284 -314
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -3,10 +3,10 @@ FROM python:3.11-slim
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y redis-tools && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y --no-install-recommends redis-tools && rm -rf /var/lib/apt/lists/*
# Install dependencies
RUN pip install requests redis
RUN pip install --no-cache-dir requests==2.32.3 redis==5.2.1
# Copy application code
COPY . .
+36 -33
View File
@@ -1,17 +1,16 @@
import logging
import os
import time
import requests
import logging
import redis
from datetime import datetime
import redis
import requests
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# Load configuration (adapted to .env keys)
def _env(key, default=None):
v = os.getenv(key, default)
@@ -19,21 +18,26 @@ def _env(key, default=None):
return v[1:-1]
return v
LOGIN = _env('KEEPER_LOGIN')
PASSWORD = _env('KEEPER_PASSWORD')
EDU_BASE = _env('EDU_URL_BASE', 'https://edu.edu.vn.ua')
EDU_LOGIN_PATH = _env('EDU_URL_LOGIN', '/user/login')
EDU_COURSES_PATH = _env('EDU_URL_COURSES', '/course/userlist')
URL_LOGIN = f"{EDU_BASE.rstrip('/')}/{EDU_LOGIN_PATH.lstrip('/')}"
URL_VERIFY = f"{EDU_BASE.rstrip('/')}/{EDU_COURSES_PATH.lstrip('/')}"
URL_LOGIN = f'{EDU_BASE.rstrip("/")}/{EDU_LOGIN_PATH.lstrip("/")}'
URL_VERIFY = f'{EDU_BASE.rstrip("/")}/{EDU_COURSES_PATH.lstrip("/")}'
INTERVAL = int(_env('KEEPER_INTERVAL', 10))
USER_AGENT = _env('USER_AGENT', 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36')
USER_AGENT = _env(
'USER_AGENT',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36',
)
REDIS_HOST = _env('REDIS_HOST', 'redis')
REDIS_PORT = int(_env('REDIS_PORT', 6379))
SUCCESS_FILE = '/tmp/last_success'
SUCCESS_FILE = '/tmp/last_success' # noqa: S108
def touch_success_file():
"""Updates the timestamp of the success file for healthchecks."""
@@ -41,18 +45,19 @@ def touch_success_file():
with open(SUCCESS_FILE, 'w') as f:
f.write(str(datetime.now().timestamp()))
except Exception as e:
logger.error(f"Failed to touch success file: {e}")
logger.error(f'Failed to touch success file: {e}')
def main():
logger.info("Starting Session Keeper Bot")
logger.info('Starting Session Keeper Bot')
# Connect to Redis
try:
redis_client = redis.Redis(host=REDIS_HOST, port=REDIS_PORT, decode_responses=True)
redis_client.ping()
logger.info(f"Connected to Redis at {REDIS_HOST}:{REDIS_PORT}")
logger.info(f'Connected to Redis at {REDIS_HOST}:{REDIS_PORT}')
except Exception as e:
logger.error(f"Failed to connect to Redis: {e}")
logger.error(f'Failed to connect to Redis: {e}')
return
session = requests.Session()
@@ -72,19 +77,16 @@ def main():
'Sec-Ch-Ua-Mobile': '?0',
'Sec-Ch-Ua-Platform': '"Linux"',
'Accept-Encoding': 'gzip, deflate, br',
'Priority': 'u=0, i'
'Priority': 'u=0, i',
}
session.headers.update(headers)
while True:
try:
logger.info("Attempting login...")
logger.info('Attempting login...')
# Login payload
payload = {
'login': LOGIN,
'password': PASSWORD
}
payload = {'login': LOGIN, 'password': PASSWORD}
# Perform Login
# Note: The user request shows a POST to /user/login with form data
@@ -93,17 +95,17 @@ def main():
login_response = session.post(URL_LOGIN, data=payload, allow_redirects=True)
logger.info(f"Login Response Status: {login_response.status_code}")
logger.info(f"Cookies after login: {session.cookies.get_dict()}")
logger.info(f'Login Response Status: {login_response.status_code}')
logger.info(f'Cookies after login: {session.cookies.get_dict()}')
# Verify Session
logger.info("Verifying session...")
logger.info('Verifying session...')
verify_response = session.get(URL_VERIFY, allow_redirects=False)
logger.info(f"Verify Response Status: {verify_response.status_code}")
logger.info(f'Verify Response Status: {verify_response.status_code}')
if verify_response.status_code == 200:
logger.info("Session verification SUCCESS (200 OK).")
logger.info('Session verification SUCCESS (200 OK).')
touch_success_file()
# Save PHPSESSID to Redis
@@ -111,19 +113,20 @@ def main():
if phpsessid:
try:
redis_client.set('EDU_PHPSESSID', phpsessid)
logger.info(f"Saved PHPSESSID to Redis: {phpsessid}")
logger.info(f'Saved PHPSESSID to Redis: {phpsessid}')
except Exception as e:
logger.error(f"Failed to save PHPSESSID to Redis: {e}")
logger.error(f'Failed to save PHPSESSID to Redis: {e}')
elif verify_response.status_code == 302:
logger.warning("Session verification FAILED (302 Redirect). Session might be invalid.")
logger.warning('Session verification FAILED (302 Redirect). Session might be invalid.')
else:
logger.warning(f"Session verification returned unexpected status: {verify_response.status_code}")
logger.warning(f'Session verification returned unexpected status: {verify_response.status_code}')
except Exception as e:
logger.error(f"An error occurred: {e}")
logger.error(f'An error occurred: {e}')
logger.info(f"Sleeping for {INTERVAL} minutes...")
logger.info(f'Sleeping for {INTERVAL} minutes...')
time.sleep(INTERVAL * 60)
if __name__ == "__main__":
if __name__ == '__main__':
main()
+1 -1
View File
@@ -3,7 +3,7 @@ FROM python:3.11-slim
WORKDIR /app
# Install dependencies
RUN pip install --upgrade pip && pip install playwright==1.56.0 redis requests "python-telegram-bot[job-queue]"
RUN pip install --no-cache-dir pip==25.0.1 && pip install --no-cache-dir playwright==1.56.0 redis==5.2.1 requests==2.32.3 "python-telegram-bot[job-queue]==21.10"
COPY checker.py .
File diff suppressed because it is too large Load Diff
+2
View File
@@ -16,5 +16,7 @@ data:
GITEA__security__REVERSE_PROXY_TRUSTED_PROXIES: "*"
GITEA__mailer__ENABLED: "false"
GITEA__log__logger__access__MODE: "console, file"
USER_UID: "1000"
USER_GID: "1000"
+7 -14
View File
@@ -10,7 +10,12 @@ spec:
- match: Host(`gitea.forust.xyz`)
kind: Rule
middlewares:
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
services:
- name: gitea-service
port: 3000
- match: Host(`gcr.forust.xyz`) && PathPrefix(`/v2`)
kind: Rule
middlewares:
services:
- name: gitea-service
port: 3000
@@ -31,23 +36,11 @@ spec:
services:
- name: gitea-service
port: 3000
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: gitea-registry
namespace: gitea
spec:
entryPoints:
- websecure
routes:
- match: Host(`gcr.forust.xyz`) && PathPrefix(`/v2`)
- match: (Host(`gcr.workstation.internal`) || Host(`gcr.gigaforust.internal`)) && PathPrefix(`/v2`)
kind: Rule
services:
- name: gitea-service
port: 3000
tls:
certResolver: letsencrypt
---
apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
+34
View File
@@ -65,6 +65,40 @@ services:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.services.headplane.loadbalancer.server.port=3000"
# Middleware: add /admin prefix for root requests
- "traefik.http.middlewares.headplane-prefix.addPrefix.prefix=/admin"
# Prod Root Router
- "traefik.http.routers.headplane-root.rule=Host(`hp.forust.xyz`)"
- "traefik.http.routers.headplane-root.entrypoints=websecure"
- "traefik.http.routers.headplane-root.middlewares=headplane-prefix"
- "traefik.http.routers.headplane-root.tls.certresolver=letsencrypt"
# Prod Router
- "traefik.http.routers.headplane.rule=Host(`hp.forust.xyz`) && PathPrefix(`/admin`)"
- "traefik.http.routers.headplane.entrypoints=websecure"
- "traefik.http.routers.headplane.tls.certresolver=letsencrypt"
# Local Root Router
- "traefik.http.routers.headplane-root-local.rule=Host(`hp.workstation.internal`)"
- "traefik.http.routers.headplane-root-local.entrypoints=websecure"
- "traefik.http.routers.headplane-root-local.middlewares=headplane-prefix"
- "traefik.http.routers.headplane-root-local.tls=true"
# Local Router
- "traefik.http.routers.headplane-local.rule=Host(`hp.workstation.internal`) && PathPrefix(`/admin`)"
- "traefik.http.routers.headplane-local.entrypoints=websecure"
- "traefik.http.routers.headplane-local.tls=true"
# Dev Root Router
- "traefik.http.routers.headplane-root-dev.rule=Host(`hp.gigaforust.internal`)"
- "traefik.http.routers.headplane-root-dev.entrypoints=websecure"
- "traefik.http.routers.headplane-root-dev.middlewares=headplane-prefix"
- "traefik.http.routers.headplane-root-dev.tls=true"
# Dev Router
- "traefik.http.routers.headplane-dev.rule=Host(`hp.gigaforust.internal`) && PathPrefix(`/admin`)"
- "traefik.http.routers.headplane-dev.entrypoints=websecure"
- "traefik.http.routers.headplane-dev.tls=true"
web:
image: goodieshq/headscale-admin:latest
restart: unless-stopped
+19 -25
View File
@@ -1,27 +1,21 @@
{
"groups": {
"group:admin": [
"admin@"
],
"group:users": []
},
"tagOwners": {},
"hosts": {},
"acls": [
{
"randomizeClientPort": false,
"#ha-meta": {
"name": "users",
"open": true
},
"action": "accept",
"src": [
"autogroup:member"
],
"dst": [
"autogroup:self:*"
]
}
],
"ssh": []
"groups": {
"group:admin": ["admin@"],
"group:users": []
},
"tagOwners": {},
"hosts": {},
"acls": [
{
"randomizeClientPort": false,
"#ha-meta": {
"name": "users",
"open": true
},
"action": "accept",
"src": ["autogroup:member"],
"dst": ["autogroup:self:*"]
}
],
"ssh": []
}
+27
View File
@@ -57,3 +57,30 @@ ports:
endpoints:
- addresses:
- "192.168.88.100"
---
apiVersion: v1
kind: Service
metadata:
name: headplane-external
namespace: headscale
spec:
ports:
- port: 3000
targetPort: 13000
name: http
---
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
name: headplane-external
namespace: headscale
labels:
kubernetes.io/service-name: headplane-external
addressType: IPv4
ports:
- port: 13000
protocol: TCP
name: http
endpoints:
- addresses:
- "192.168.88.100"
+61 -60
View File
@@ -1,7 +1,16 @@
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: headplane-prefix
namespace: headscale
spec:
addPrefix:
prefix: "/admin"
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-server-prod
name: headscale-prod
namespace: headscale
spec:
entryPoints:
@@ -10,17 +19,52 @@ spec:
- match: Host(`hs.forust.xyz`)
kind: Rule
middlewares:
- name: crowdsec-crowdsec-bouncer@kubernetescrd
services:
- name: headscale-server-external
port: 8080
- match: Host(`hs.forust.xyz`) && PathPrefix(`/admin`)
kind: Rule
middlewares:
services:
- name: headscale-ui-external
port: 80
- match: Host(`hs.forust.xyz`) && PathPrefix(`/metrics`)
kind: Rule
middlewares:
services:
- name: headscale-server-external
port: 9090
tls:
certResolver: letsencrypt
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-server-local
name: headplane-prod
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: Host(`hp.forust.xyz`)
kind: Rule
middlewares:
- name: headplane-prefix
services:
- name: headplane-external
port: 3000
- match: Host(`hp.forust.xyz`) && PathPrefix(`/admin`)
kind: Rule
services:
- name: headplane-external
port: 3000
tls:
certResolver: letsencrypt
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-local
namespace: headscale
spec:
entryPoints:
@@ -31,76 +75,33 @@ spec:
services:
- name: headscale-server-external
port: 8080
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-ui-prod
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: Host(`hs.forust.xyz`) && PathPrefix(`/admin`)
kind: Rule
middlewares:
- name: crowdsec-crowdsec-bouncer@kubernetescrd
- name: security-chain@file
services:
- name: headscale-ui-external
port: 80
tls:
certResolver: letsencrypt
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-ui-local
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^hs\.(workstation|gigaforust)\.internal$`) && PathPrefix(`/admin`)
- match: (Host(`hs.workstation.internal`) || Host(`hs.gigaforust.internal`)) && PathPrefix(`/admin`)
kind: Rule
services:
- name: headscale-ui-external
port: 80
- match: (Host(`hs.workstation.internal`) || Host(`hs.gigaforust.internal`)) && PathPrefix(`/metrics`)
kind: Rule
services:
- name: headscale-server-external
port: 9090
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-metrics-prod
name: headplane-local
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: Host(`hs.forust.xyz`) && PathPrefix(`/metrics`)
- match: Host(`hp.workstation.internal`) || Host(`hp.gigaforust.internal`)
kind: Rule
middlewares:
- name: crowdsec-crowdsec-bouncer@kubernetescrd
- name: headplane-prefix
services:
- name: headscale-server-external
port: 9090
tls:
certResolver: letsencrypt
domains:
- main: hs.forust.xyz
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: headscale-metrics-local
namespace: headscale
spec:
entryPoints:
- websecure
routes:
- match: HostRegexp(`^hs\.(workstation|gigaforust)\.internal$`) && PathPrefix(`/metrics`)
- name: headplane-external
port: 3000
- match: (Host(`hp.workstation.internal`) || Host(`hp.gigaforust.internal`)) && PathPrefix(`/admin`)
kind: Rule
services:
- name: headscale-server-external
port: 9090
- name: headplane-external
port: 3000
Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 53 KiB

+205 -192
View File
@@ -1,212 +1,225 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>MrForust // XRock</title>
<script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="assets/css/style.css">
</head>
<body>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" />
<link rel="stylesheet" href="assets/css/style.css" />
</head>
<body>
<div class="container">
<header>
<h1 class="glitch" data-text="MrForust">Mr-Forust</h1>
<p class="subtitle">> CTF Player / XRock_Team / Just Signal.</p>
</header>
<header>
<h1 class="glitch" data-text="MrForust">Mr-Forust</h1>
<p class="subtitle">> CTF Player / XRock_Team / Just Signal.</p>
</header>
<hr>
<hr />
<div class="grid-2">
<section id="contacts">
<h2>./contacts</h2>
<ul class="link-list">
<li>
<i class="fab fa-github"></i>
<a href="https://github.com/mr-forust" target="_blank">github/mr-forust</a>
</li>
<li>
<i class="fas fa-flag"></i>
<a href="https://tryhackme.com/p/MrForust" target="_blank">tryhackme/MrForust</a>
</li>
<li>
<i class="fab fa-telegram-plane"></i>
<a href="https://t.me/MrForust" target="_blank">telegram/MrForust</a>
</li>
<li>
<i class="fab fa-discord"></i>
<span>discord/mr.forust</span>
</li>
<li>
<i class="fas fa-envelope"></i>
<a href="mailto:contact@forust.xyz">mail/contact@forust.xyz</a>
</li>
<li>
<i class="fa-solid fa-key"></i>
<a href=".well-known/pgp-key.asc">security/PGP Key</a>
</li>
<li>
<p class="comment"># PGP Key Fingerprint: A777 7CB7 D9C4 0A97 443D CCF0 7A3D A455 F820 5B82</p>
</li>
</ul>
</section>
<section id="tools">
<h2>./tools</h2>
<ul class="link-list">
<li>
<i class="fa fa-pie-chart"></i>
<a href="https://forust.xyz/glance" target="_blank">forust/dashboard</a>
<p class="comment"># Glance dashboard</p>
</li>
<li>
<i class="fa fa-refresh"></i>
<a href="https://forust.xyz/convert" target="_blank">forust/converter</a>
<p class="comment"># ConvertX instance</p>
</li>
<li>
<i class="fa-solid fa-file-pdf"></i>
<a href="https://pdf.forust.xyz" target="_blank">pdf.forust.xyz</a>
<p class="comment"># BentoPDF instance</p>
</li>
</ul>
</section>
</div>
<section id="stack">
<h2>./skills</h2>
<div class="grid-2">
<section id="socials">
<h2>./socials</h2>
<ul class="link-list">
<li>
<i class="fab fa-github"></i>
<a href="https://github.com/mr-forust" target="_blank">github/mr-forust</a>
</li>
<li>
<i class="fas fa-flag"></i>
<a href="https://tryhackme.com/p/MrForust" target="_blank">tryhackme/MrForust</a>
</li>
<li>
<i class="fab fa-telegram-plane"></i>
<a href="https://t.me/MrForust" target="_blank">telegram/MrForust</a>
</li>
<li>
<i class="fab fa-discord"></i>
<span>discord/mr.forust</span>
</li>
<li>
<i class="fas fa-envelope"></i>
<a href="mailto:contact@forust.xyz">mail/contact@forust.xyz</a>
</li>
<li>
<i class="fa-solid fa-key"></i>
<a href=".well-known/pgp-key.asc">security/PGP Key</a>
</li>
<li>
<p class="comment"># PGP Key Fingerprint: A777 7CB7 D9C4 0A97 443D CCF0 7A3D A455 F820 5B82</p>
</li>
</ul>
</section>
<section id="tools">
<h2>./tools</h2>
<ul class="link-list">
<li>
<i class="fa fa-pie-chart"></i>
<a href="https://forust.xyz/glance" target="_blank">forust/dashboard</a>
</li>
<li>
<i class="fa fa-refresh"></i>
<a href="https://forust.xyz/convert" target="_blank">forust/converter</a>
</li>
<li>
<i class="fa-solid fa-file-pdf"></i>
<a href="https://pdf.forust.xyz" target="_blank">pdf.forust.xyz</a>
</li>
</ul>
</section>
<div>
<div class="skill-item">
<span>ArchLinux # btw</span>
<span class="level">[#######...]</span>
</div>
<div class="skill-item"><span>Kubernetes</span> <span class="level">[###.......]</span></div>
<div class="skill-item"><span>Docker</span> <span class="level">[####......]</span></div>
<div class="skill-item">
<span>Docker Compose</span>
<span class="level">[#####.....]</span>
</div>
<div class="skill-item"><span>Web Pentest</span> <span class="level">[#####.....]</span></div>
<div class="skill-item"><span>Burpsuite</span> <span class="level">[#####.....]</span></div>
<div class="skill-item"><span>Steganography</span> <span class="level">[####......]</span></div>
</div>
<div>
<div class="skill-item"><span>Cryptography</span> <span class="level">[####......]</span></div>
<div class="skill-item"><span>OSINT</span> <span class="level">[####......]</span></div>
<div class="skill-item"><span>Python</span> <span class="level">[###.......]</span></div>
<div class="skill-item"><span>HTML</span> <span class="level">[###.......]</span></div>
<div class="skill-item"><span>Bash</span> <span class="level">[##........]</span></div>
<div class="skill-item"><span>Golang</span> <span class="level">[#.........]</span></div>
</div>
</div>
</section>
<section id="stack">
<h2>./skills</h2>
<div class="grid-2">
<div>
<div class="skill-item">
<span>ArchLinux # btw</span>
<span class="level">[#######...]</span>
</div>
<div class="skill-item">
<span>Kubernetes</span> <span class="level">[###.......]</span>
</div>
<div class="skill-item">
<span>Docker</span> <span class="level">[####......]</span>
</div>
<div class="skill-item">
<span>Docker Compose</span> <span class="level">[#####.....]</span>
</div>
<div class="skill-item">
<span>Web Pentest</span> <span class="level">[#####.....]</span>
</div>
<div class="skill-item">
<span>Burpsuite</span> <span class="level">[#####.....]</span>
</div>
<div class="skill-item">
<span>Steganography</span> <span class="level">[####......]</span>
</div>
</div>
<div>
<div class="skill-item">
<span>Cryptography</span> <span class="level">[####......]</span>
</div>
<div class="skill-item">
<span>OSINT</span> <span class="level">[####......]</span>
</div>
<div class="skill-item">
<span>Python</span> <span class="level">[###.......]</span>
</div>
<div class="skill-item">
<span>HTML</span> <span class="level">[###.......]</span>
</div>
<div class="skill-item">
<span>Bash</span> <span class="level">[##........]</span>
</div>
<div class="skill-item">
<span>Golang</span> <span class="level">[#.........]</span>
</div>
</div>
</div>
</section>
<section id="team">
<h2>./xrock_team</h2>
<p class="comment"># It's a select caste. Cybershamans. Cryptoanarchists. Shadows on the net..</p>
<section id="team">
<h2>./xrock_team</h2>
<p class="comment"># It's a select caste. Cybershamans. Cryptoanarchists. Shadows on the net..</p>
<div class="team-grid">
<div class="member">
<div
class="avatar"
style="
background-image: url(&quot;assets/images/team/mrforust.jpg&quot;);
background-size: cover;
background-position: center;
"
></div>
<a href="https://github.com/mr-forust" target="_blank">MrForust</a>
</div>
<div class="team-grid">
<div class="member">
<div class="avatar"
style="background-image: url('assets/images/team/mrforust.jpg'); background-size: cover; background-position: center;">
</div>
<a href="https://github.com/mr-forust" target="_blank">MrForust</a>
</div>
<div class="member">
<div
class="avatar"
style="
background-image: url(&quot;assets/images/team/anna.jpg&quot;);
background-size: cover;
background-position: center;
"
></div>
<a href="./assets/images/love.png" target="_blank">Anna~</a>
</div>
<div class="member">
<div class="avatar"
style="background-image: url('assets/images/team/anna.jpg'); background-size: cover; background-position: center;">
</div>
<a href="./assets/images/love.png" target="_blank">Anna~</a>
</div>
<div class="member">
<div
class="avatar"
style="
background-image: url(&quot;assets/images/team/chernuha.jpg&quot;);
background-size: cover;
background-position: center;
"
></div>
<a href="https://chernuha.space" target="_blank">Chernuha</a>
</div>
<div class="member">
<div class="avatar"
style="background-image: url('assets/images/team/chernuha.jpg'); background-size: cover; background-position: center;">
</div>
<a href="https://chernuha.space" target="_blank">Chernuha</a>
</div>
<div class="member">
<div
class="avatar"
style="
background-image: url(&quot;assets/images/team/hudan.jpg&quot;);
background-size: cover;
background-position: center;
"
></div>
<a href="https://hudan.xyz" target="_blank">p1ngvi</a>
</div>
<div class="member">
<div class="avatar"
style="background-image: url('assets/images/team/hudan.jpg'); background-size: cover; background-position: center;">
</div>
<a href="https://hudan.xyz" target="_blank">p1ngvi</a>
</div>
<div class="member">
<div
class="avatar"
style="
background-image: url(&quot;assets/images/team/xdfnx.jpg&quot;);
background-size: cover;
background-position: center;
"
></div>
<a href="https://xdfnx.cfd" target="_blank">xdfnx</a>
</div>
</div>
</section>
<div class="member">
<div class="avatar"
style="background-image: url('assets/images/team/xdfnx.jpg'); background-size: cover; background-position: center;">
</div>
<a href="https://xdfnx.cfd" target="_blank">xdfnx</a>
</div>
</div>
</section>
<section id="projects">
<h2>./projects</h2>
<ul class="repo-list">
<li>
<a href="https://gitea.forust.xyz/forust/gosleep" target="_blank">forust/gosleep</a>
<span class="comment">// linux sleep timer written in rust (originally in go)</span>
</li>
</ul>
</section>
<section id="repos">
<h2>./favorite_repos</h2>
<ul class="repo-list">
<li>
<a href="https://github.com/TDesktop-x64/tdesktop" target="_blank">TDesktop-x64/tdesktop</a>
<span class="comment">// unofficial telegram client with some additions</span>
</li>
<li>
<a href="https://github.com/traefik/traefik" target="_blank">traefik/traefik</a>
<span class="comment">// beloved reverse-proxy</span>
</li>
<li>
<a href="https://github.com/unhappychoice/gitlogue" target="_blank">unhappychoice/gitlogue</a>
<span class="comment">// nice git log visualizer</span>
</li>
<li>
<a href="https://github.com/tstack/lnav" target="_blank">tstack/lnav</a>
<span class="comment">// powerful log reader</span>
</li>
<li>
<a href="https://github.com/mountain-loop/yaak" target="_blank">mountain-loop/yaak</a>
<span class="comment">// modern, fancy api client</span>
</li>
<li>
<a href="https://github.com/pear-devs/pear-desktop" target="_blank">pear-devs/pear-desktop</a>
<span class="comment">// music client with a lot of features</span>
</li>
<li>
<a href="https://github.com/epi052/feroxbuster" target="_blank">epi052/feroxbuster</a>
<span class="comment">// directory discovery</span>
</li>
</ul>
</section>
<section id="repos">
<h2>./favorite_repos</h2>
<ul class="repo-list">
<li>
<a href="https://github.com/TDesktop-x64/tdesktop" target="_blank">TDesktop-x64/tdesktop</a>
<span class="comment">// unofficial telegram client with some additions</span>
</li>
<li>
<a href="https://github.com/traefik/traefik" target="_blank">traefik/traefik</a>
<span class="comment">// beloved reverse-proxy</span>
</li>
<li>
<a href="https://github.com/unhappychoice/gitlogue" target="_blank">unhappychoice/gitlogue</a>
<span class="comment">// nice git log visualizer</span>
</li>
<li>
<a href="https://github.com/tstack/lnav" target="_blank">tstack/lnav</a>
<span class="comment">// powerful log reader</span>
</li>
<li>
<a href="https://github.com/mountain-loop/yaak" target="_blank">mountain-loop/yaak</a>
<span class="comment">// modern, fancy api client</span>
</li>
<li>
<a href="https://github.com/pear-devs/pear-desktop" target="_blank">pear-devs/pear-desktop</a>
<span class="comment">// music client with a lot of features</span>
</li>
<li>
<a href="https://github.com/epi052/feroxbuster" target="_blank">epi052/feroxbuster</a>
<span class="comment">// directory discovery</span>
</li>
</ul>
</section>
<footer>
<p>root@xrock:~$ cat <a href="miku.html">./miku</a></p>
<p>miku?</p>
<p>root@xrock:~$ shutdown -h now</p>
<p>&copy; XRock - Just Signal.</p>
</footer>
<footer>
<p>root@xrock:~$ cat <a href="miku.html">./miku</a></p>
<p>miku?</p>
<p>root@xrock:~$ shutdown -h now</p>
<p>&copy; XRock - Just Signal.</p>
</footer>
</div>
</body>
</body>
</html>
+1 -3
View File
@@ -10,7 +10,6 @@ spec:
- match: Host(`forust.xyz`) || Host(`www.forust.xyz`)
kind: Rule
middlewares:
- name: crowdsec-crowdsec-bouncer@kubernetescrd
priority: 10
services:
- name: forust-homepage-service
@@ -43,10 +42,9 @@ spec:
entryPoints:
- websecure
routes:
- match: Host(`xdfnx.cfd`) || Host(`www.xdfnx.cfd`)
- match: Host(`xdfnx.cfd`)
kind: Rule
middlewares:
- name: crowdsec-crowdsec-bouncer@kubernetescrd
services:
- name: xdfnx-homepage-service
port: 80
File diff suppressed because it is too large Load Diff
-1
View File
@@ -10,7 +10,6 @@ spec:
- match: Host(`status.forust.xyz`)
kind: Rule
middlewares:
- name: crowdsec-crowdsec-bouncer@kubernetescrd
services:
- name: kener-service
port: 3000
-1
View File
@@ -10,7 +10,6 @@ spec:
- match: Host(`n8n.forust.xyz`)
kind: Rule
middlewares:
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
services:
- name: n8n-service
port: 5678
-1
View File
@@ -10,7 +10,6 @@ spec:
- match: Host(`nm.forust.xyz`)
kind: Rule
middlewares:
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
services:
- name: netronome-service
port: 7575
-2
View File
@@ -12,7 +12,6 @@ spec:
kind: Rule
middlewares:
- name: nextcloud-chain@file
- name: crowdsec-crowdsec-bouncer@kubernetescrd
services:
- name: nextcloud-apache
port: 11000
@@ -31,7 +30,6 @@ spec:
- match: Host(`nextcloud.workstation.internal`) || Host(`nextcloud.gigaforust.internal`)
kind: Rule
middlewares:
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
- name: nextcloud-chain@file
services:
- name: nextcloud-apache
-1
View File
@@ -10,7 +10,6 @@ spec:
- match: Host(`portainer.forust.xyz`)
kind: Rule
middlewares:
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
services:
- name: portainer-service
port: 9000
-1
View File
@@ -10,7 +10,6 @@ spec:
- match: Host(`grafana.forust.xyz`)
kind: Rule
middlewares:
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
- name: "security-chain@file"
services:
- name: prometheus-stack-grafana
+4
View File
@@ -0,0 +1,4 @@
{
"venvPath": "/home/forust/homelab/userbot",
"venv": ".venv"
}
-1
View File
@@ -10,7 +10,6 @@ spec:
- match: Host(`s.forust.xyz`) || Host(`search.forust.xyz`)
kind: Rule
middlewares:
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
services:
- name: searxng-service
port: 8080
-1
View File
@@ -10,7 +10,6 @@ spec:
- match: Host(`termix.forust.xyz`)
kind: Rule
middlewares:
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
services:
- name: termix-service
port: 8080
+23
View File
@@ -0,0 +1,23 @@
http:
routers:
fs1-public:
rule: "Host(`fs1.domain.xyz`)"
entrypoints:
- websecure
service: fs1
middlewares:
- security-chain@file
tls: {}
fs1-workstation:
rule: "Host(`fs1.workstation.internal`)"
entrypoints:
- websecure
service: fs1
tls: {}
services:
fs1:
loadBalancer:
servers:
- url: "http://127.0.0.1:3923" # Copyparty port example
-1
View File
@@ -11,7 +11,6 @@ spec:
- match: Host(`traefik.forust.xyz`)
kind: Rule
middlewares:
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
services:
- name: api@internal
kind: TraefikService
+10 -26
View File
@@ -1,5 +1,9 @@
# Auto-generated by forust | See https://github.com/traefik/traefik-helm-chart/blob/master/values.yaml
hostNetwork: false
image:
registry: docker.io/library
repository: traefik
tag: v3.7.6
securityContext:
capabilities:
@@ -23,16 +27,7 @@ updateStrategy:
type: Recreate
deployment:
initContainers:
- name: volume-permissions
image: busybox:latest
command:
- sh
- -c
- "mkdir -p /data/letsencrypt && touch /data/letsencrypt/acme.json && chmod 600 /data/letsencrypt/acme.json"
volumeMounts:
- name: data
mountPath: /data
enabled: true
providers:
kubernetesIngress:
@@ -123,10 +118,6 @@ volumes:
- name: traefik-dynamic
mountPath: /etc/traefik/dynamic
type: configMap
- name: crowdsec-bouncer-secrets
mountPath: /etc/traefik/secrets
type: secret
additionalArguments:
- "--providers.file.directory=/etc/traefik/dynamic"
- "--providers.file.watch=true"
@@ -134,15 +125,8 @@ additionalArguments:
- "--entryPoints.websecure.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22,192.168.1.1,192.168.1.0/24,192.168.88.0/24,192.168.88.1"
- "--entryPoints.web.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22,192.168.1.1,192.168.1.0/24,192.168.88.0/24,192.168.88.1"
logs:
general:
level: INFO
access:
enabled: true
format: common
experimental:
plugins:
crowdsec-bouncer:
moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin
version: v1.3.3
log:
level: INFO
accessLog:
enabled: true
format: common
-1
View File
@@ -10,7 +10,6 @@ spec:
- match: Host(`uptime.forust.xyz`)
kind: Rule
middlewares:
- name: crowdsec-crowdsec-bouncer@kubernetescrd
services:
- name: uptime-kuma-service
port: 3001
+4
View File
@@ -1,11 +1,15 @@
FROM python:3.11-slim AS builder
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
WORKDIR /src
COPY requirements.txt .
RUN pip install --no-cache-dir --user -r requirements.txt
FROM python:3.11-slim
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
mediainfo \
+6 -6
View File
@@ -3,7 +3,7 @@ import re
from io import BytesIO
import requests
from bs4 import BeautifulSoup as bs
from bs4 import BeautifulSoup
from pyrogram import Client, filters
from pyrogram.errors import RPCError
from pyrogram.types import InputMediaPhoto, Message
@@ -12,7 +12,7 @@ from utils.misc import modules_help, prefix
@Client.on_message(filters.command('icon', prefix) & filters.me)
async def search_icon(_, message: Message):
if not len(message.command) == 2:
if len(message.command) != 2:
return await message.edit_text('Please provide some text to search icons from Flaticon.com.')
query = message.text.split(maxsplit=1)[1]
@@ -21,8 +21,8 @@ async def search_icon(_, message: Message):
url = f'https://www.flaticon.com/search?word={search_query}'
try:
html_content = requests.get(url).text
soup = bs(html_content, 'html.parser')
html_content = requests.get(url, timeout=10).text
soup = BeautifulSoup(html_content, 'html.parser')
results = soup.find_all(
'img',
src=re.compile(r'https://cdn-icons-png.flaticon.com/128/[0-9]+/[0-9]+.png'),
@@ -68,7 +68,7 @@ async def freepik_search(client: Client, message: Message):
try:
url = f'https://www.freepik.com/api/regular/search?locale=en&term={match}'
json_content = requests.get(url).json()
json_content = requests.get(url, timeout=10).json()
results = []
for i in json_content['items']:
results.append(i['preview']['url'])
@@ -81,7 +81,7 @@ async def freepik_search(client: Client, message: Message):
media_group = []
for img_url in img_urls:
icon = requests.get(img_url)
icon = requests.get(img_url, timeout=10)
if icon.status_code == 200:
media_group.append(InputMediaPhoto(media=BytesIO(icon.content)))
+2 -2
View File
@@ -21,7 +21,7 @@ async def imgur(_, message: Message):
url = 'https://api.imgur.com/3/image'
headers = {'Authorization': 'Client-ID a10ad04550b0648'}
# Upload image to Imgur and get URL
response = requests.post(url, headers=headers, data={'image': base64_data})
response = requests.post(url, headers=headers, data={'image': base64_data}, timeout=10)
result = response.json()
await msg.edit_text(result['data']['link'])
elif message.reply_to_message and message.reply_to_message.animation:
@@ -35,7 +35,7 @@ async def imgur(_, message: Message):
url = 'https://api.imgur.com/3/image'
headers = {'Authorization': 'Client-ID a10ad04550b0648'}
# Upload animation to Imgur and get URL
response = requests.post(url, headers=headers, data={'image': base64_data})
response = requests.post(url, headers=headers, data={'image': base64_data}, timeout=10)
result = response.json()
await msg.edit_text(result['data']['link'])
else:
+3 -3
View File
@@ -30,7 +30,7 @@ def resize_image(image_bytes):
async def download_image(url):
try:
response = requests.get(url)
response = requests.get(url, timeout=10)
if response.status_code == 200:
img_bytes = BytesIO(response.content)
return resize_image(img_bytes)
@@ -40,7 +40,7 @@ async def download_image(url):
@Client.on_message(filters.command('pinterest', prefix) & filters.me)
async def pinterest_search(client: Client, message: Message):
async def pinterest_search(_client: Client, message: Message):
if len(message.command) < 2:
await message.edit('Usage: `pinterest [number] <query>`', parse_mode=enums.ParseMode.MARKDOWN)
return
@@ -52,7 +52,7 @@ async def pinterest_search(client: Client, message: Message):
status_message = await message.edit('Searching for images...', parse_mode=enums.ParseMode.MARKDOWN)
url = f'{API_URL}{query}'
response = requests.get(url)
response = requests.get(url, timeout=10)
if response.status_code == 200:
data = response.json()
+1 -1
View File
@@ -65,7 +65,7 @@ def upload_image(photo_path):
"""Uploads an image to tmpfiles.org and returns the direct download URL."""
try:
with open(photo_path, 'rb') as image_file:
response = requests.post('https://tmpfiles.org/api/v1/upload', files={'file': image_file})
response = requests.post('https://tmpfiles.org/api/v1/upload', files={'file': image_file}, timeout=10)
if response.status_code == 200:
data = response.json()
url = data['data']['url']
+1 -2
View File
@@ -51,7 +51,7 @@ async def unsplash(client: Client, message: Message):
for ia in range(len(images), count):
img = data['results'][ia]['urls']['raw']
if img.startswith('https://images.unsplash.com/photo'):
image_content = requests.get(img).content
image_content = requests.get(img, timeout=10).content
with open(f'{unsplash_dir}/unsplash_{ia}.jpg', 'wb') as f:
f.write(image_content)
imgr = f'{unsplash_dir}/unsplash_{ia}.jpg'
@@ -77,7 +77,6 @@ async def unsplash(client: Client, message: Message):
modules_help['unsplash'] = {
'unsplash': '[keyword]*',
'unsplash': '[keyword]* [number of results you want]*\n'
'Makes a request to <code>unsplash.com</code> and sends the image with the keyword you provided.\n\n'
'<b>Note:</b>\n1. The number of results you can get is limited to 10.\n'
+3 -3
View File
@@ -29,7 +29,7 @@ def resize_image(image_bytes):
async def download_image(url):
try:
response = requests.get(url)
response = requests.get(url, timeout=10)
if response.status_code == 200:
img_bytes = BytesIO(response.content)
resized_img_bytes = resize_image(img_bytes)
@@ -40,7 +40,7 @@ async def download_image(url):
@Client.on_message(filters.command(['unsplash2', 'usp2'], prefix) & filters.me)
async def imgsearch(client: Client, message: Message):
async def imgsearch(_client: Client, message: Message):
if len(message.command) < 2:
await message.edit('Usage: `img [number] <query>`', parse_mode=enums.ParseMode.MARKDOWN)
return
@@ -52,7 +52,7 @@ async def imgsearch(client: Client, message: Message):
status_message = await message.edit('Searching for images...', parse_mode=enums.ParseMode.MARKDOWN)
url = f'{API_URL}{query}'
response = requests.get(url)
response = requests.get(url, timeout=10)
if response.status_code == 200:
data = response.json()
+4 -5
View File
@@ -39,6 +39,7 @@
# "pySmartDL",
# ]
# ///
import contextlib
import logging
import os
import platform
@@ -108,7 +109,7 @@ def load_missing_modules():
module_path = f'{custom_modules_path}/{module_name}.py'
if not os.path.exists(module_path) and module_name in modules_dict:
url = f'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/{modules_dict[module_name]}.py'
resp = requests.get(url)
resp = requests.get(url, timeout=10)
if resp.ok:
with open(module_path, 'wb') as f:
f.write(resp.content)
@@ -130,7 +131,7 @@ async def main():
except sqlite3.OperationalError as e:
if str(e) == 'database is locked' and os.name == 'posix':
logging.warning('Session file is locked. Trying to kill blocking process...')
subprocess.run(['fuser', '-k', 'my_account.session'], check=True)
subprocess.run(['fuser', '-k', 'my_account.session'], check=True) # noqa: S607
restart()
raise
except (errors.NotAcceptable, errors.Unauthorized) as e:
@@ -151,10 +152,8 @@ async def main():
'restart': '<b>Restart completed!</b>',
'update': '<b>Update process completed!</b>',
}[info['type']]
try:
with contextlib.suppress(errors.RPCError):
await app.edit_message_text(info['chat_id'], info['message_id'], text)
except errors.RPCError:
pass
db.remove('core.updater', 'restart_info')
# required for sessionkiller module
+1 -4
View File
@@ -15,10 +15,7 @@ def prettify(val: int) -> str:
async def ghoul_counter(_, message: Message):
await message.delete()
if len(message.command) > 1 and message.command[1].isdigit():
counter = int(message.command[1])
else:
counter = 1000
counter = int(message.command[1]) if len(message.command) > 1 and message.command[1].isdigit() else 1000
msg = await message.reply(prettify(counter), quote=False)
+2 -2
View File
@@ -29,8 +29,8 @@ class Chat(Object):
self,
*,
client: 'Client' = None,
id: id,
type: type,
id: id, # noqa: A002
type: type, # noqa: A002
is_verified: bool = None,
is_restricted: bool = None,
is_creator: bool = None,
+1 -4
View File
@@ -47,10 +47,7 @@ async def afk_handler(_, message: types.Message):
@Client.on_message(filters.command('afk', prefix) & filters.me)
async def afk(_, message):
if len(message.text.split()) >= 2:
reason = message.text.split(' ', maxsplit=1)[1]
else:
reason = 'None'
reason = message.text.split(' ', maxsplit=1)[1] if len(message.text.split()) >= 2 else 'None'
afk_info['start'] = int(datetime.datetime.now().timestamp())
afk_info['is_afk'] = True
+1 -1
View File
@@ -8,7 +8,7 @@ from utils.scripts import format_exc, import_library
genai = import_library('google.generativeai', 'google-generativeai')
from utils.config import gemini_key
from utils.config import gemini_key # noqa: E402
genai.configure(api_key=gemini_key)
+3 -3
View File
@@ -18,11 +18,11 @@ async def amogus(client: Client, message: Message):
parse_mode=enums.ParseMode.HTML,
)
clr = randint(1, 12)
clr = randint(1, 12) # noqa: S311
url = 'https://raw.githubusercontent.com/The-MoonTg-project/AmongUs/master/'
font = ImageFont.truetype(BytesIO(get(url + 'bold.ttf').content), 60)
imposter = Image.open(BytesIO(get(f'{url}{clr}.png').content))
font = ImageFont.truetype(BytesIO(get(url + 'bold.ttf', timeout=10).content), 60)
imposter = Image.open(BytesIO(get(f'{url}{clr}.png', timeout=10).content))
text_ = '\n'.join(['\n'.join(wrap(part, 30)) for part in text.split('\n')])
bbox = ImageDraw.Draw(Image.new('RGB', (1, 1))).multiline_textbbox((0, 0), text_, font, stroke_width=2)
+17 -19
View File
@@ -10,18 +10,20 @@ from PIL import Image, ImageDraw, ImageFont
from pyrogram import Client, filters
from pyrogram.types import Message
from utils.misc import modules_help, prefix
from utils.scripts import ReplyCheck, edit_or_reply
from utils.scripts import edit_or_reply, reply_check
async def amongus_gen(text: str, clr: int) -> str:
url = 'https://github.com/TgCatUB/CatUserbot-Resources/raw/master/Resources/Amongus/'
font = ImageFont.truetype(
BytesIO(
requests.get('https://github.com/TgCatUB/CatUserbot-Resources/raw/master/Resources/fonts/bold.ttf').content
requests.get(
'https://github.com/TgCatUB/CatUserbot-Resources/raw/master/Resources/fonts/bold.ttf', timeout=10
).content
),
60,
)
imposter = Image.open(BytesIO(requests.get(f'{url}{clr}.png').content))
imposter = Image.open(BytesIO(requests.get(f'{url}{clr}.png', timeout=10).content))
text_ = '\n'.join('\n'.join(wrap(part, 30)) for part in text.split('\n'))
bbox = ImageDraw.Draw(Image.new('RGB', (1, 1))).multiline_textbbox((0, 0), text_, font, stroke_width=2)
w, h = bbox[2], bbox[3]
@@ -42,10 +44,12 @@ async def amongus_gen(text: str, clr: int) -> str:
async def get_imposter_img(text: str) -> BytesIO:
background = requests.get(
f'https://github.com/TgCatUB/CatUserbot-Resources/raw/master/Resources/imposter/impostor{randint(1, 22)}.png'
f'https://github.com/TgCatUB/CatUserbot-Resources/raw/master/Resources/imposter/impostor{randint(1, 22)}.png', # noqa: S311
timeout=10,
).content
font = requests.get(
'https://github.com/TgCatUB/CatUserbot-Resources/raw/master/Resources/fonts/roboto_regular.ttf'
'https://github.com/TgCatUB/CatUserbot-Resources/raw/master/Resources/fonts/roboto_regular.ttf',
timeout=10,
).content
font = BytesIO(font)
font = ImageFont.truetype(font, 30)
@@ -79,9 +83,9 @@ async def amongus_cmd(client: Client, message: Message):
text = text.replace(f'-c{clr}', '')
clr = int(clr)
if clr > 12 or clr < 1:
clr = randint(1, 12)
clr = randint(1, 12) # noqa: S311
except IndexError:
clr = randint(1, 12)
clr = randint(1, 12) # noqa: S311
if not text:
if not reply:
@@ -94,24 +98,21 @@ async def amongus_cmd(client: Client, message: Message):
await client.send_sticker(
message.chat.id,
imposter_file,
reply_to_message_id=ReplyCheck(message),
reply_to_message_id=reply_check(message),
)
@Client.on_message(filters.command('imposter', prefix) & filters.me)
async def imposter_cmd(client: Client, message: Message):
remain = randint(1, 2)
remain = randint(1, 2) # noqa: S311
imps = ["wasn't the impostor", 'was the impostor']
if message.reply_to_message:
user = message.reply_to_message.from_user
text = f'{user.first_name} {choice(imps)}.'
text = f'{user.first_name} {choice(imps)}.' # noqa: S311
else:
args = message.text.split()[1:]
if args:
text = ' '.join(args)
else:
text = f'{message.from_user.first_name} {choice(imps)}.'
text = ' '.join(args) if args else f'{message.from_user.first_name} {choice(imps)}.' # noqa: S311
text += f'\n{remain} impostor(s) remain.'
imposter_file = await get_imposter_img(text)
@@ -119,7 +120,7 @@ async def imposter_cmd(client: Client, message: Message):
await client.send_photo(
message.chat.id,
imposter_file,
reply_to_message_id=ReplyCheck(message),
reply_to_message_id=reply_check(message),
)
@@ -128,10 +129,7 @@ async def imp_animation(client: Client, message: Message):
name = ' '.join(message.command[1:]) if len(message.command) > 1 else ''
if not name:
reply = message.reply_to_message
if reply:
name = reply.from_user.first_name
else:
name = message.from_user.first_name
name = reply.from_user.first_name if reply else message.from_user.first_name
cmd = message.command[0].lower()
text1 = await edit_or_reply(message, 'Uhmm... Something is wrong here!!')
+1 -1
View File
@@ -187,7 +187,7 @@ async def timer_blankx(_, message: Message):
)
j = 10
k = j
for j in range(j):
for _j in range(j):
await message.edit_text(txt + str(k), parse_mode=enums.ParseMode.HTML)
k = k + 10
await asyncio.sleep(1)
+20 -20
View File
@@ -43,22 +43,22 @@ async def anime_search(client: Client, message: Message):
result = response.json()
averageScore = result['averageScore']
average_score = result['average_score']
try:
coverImage_url = result['imageUrl']
coverImage = requests.get(url=coverImage_url).content
cover_image_url = result['imageUrl']
cover_image = requests.get(url=cover_image_url, timeout=10).content
async with aiofiles.open('coverImage.jpg', mode='wb') as f:
await f.write(coverImage)
await f.write(cover_image)
except Exception:
coverImage = None
cover_image = None
title = result['title']['english']
trailer = result['trailer']['id']
description = result['description']
episodes = result['episodes']
genres = ', '.join(result['genres'])
isAdult = result['isAdult']
is_adult = result['is_adult']
status = result['status']
studios = ', '.join(result['studios'])
@@ -68,7 +68,7 @@ async def anime_search(client: Client, message: Message):
[
InputMediaPhoto(
'coverImage.jpg',
caption=f"<b>Title:</b> <code>{title}</code>\n<b>Average Score:</b> <code>{averageScore}</code>\n<b>Status:</b> <code>{status}</code>\n<b>Genres:</b> <code>{genres}</code>\n<b>Episodes:</b> <code>{episodes}</code>\n<b>Is Adult:</b> <code>{isAdult}</code>\n<b>Studios:</b> <code>{studios}</code>\n<b>Description:</b> <code>{description}</code>\n<b>Trailer:</b> <a href='https://youtu.be/{trailer}'>Click Here</a>",
caption=f"<b>Title:</b> <code>{title}</code>\n<b>Average Score:</b> <code>{average_score}</code>\n<b>Status:</b> <code>{status}</code>\n<b>Genres:</b> <code>{genres}</code>\n<b>Episodes:</b> <code>{episodes}</code>\n<b>Is Adult:</b> <code>{is_adult}</code>\n<b>Studios:</b> <code>{studios}</code>\n<b>Description:</b> <code>{description}</code>\n<b>Trailer:</b> <a href='https://youtu.be/{trailer}'>Click Here</a>",
)
],
)
@@ -81,7 +81,7 @@ async def anime_search(client: Client, message: Message):
[
InputMediaPhoto(
'coverImage.jpg',
caption=f"<b>Title:</b> <code>{title}</code>\n<b>Average Score:</b> <code>{averageScore}</code>\n<b>Status:</b> <code>{status}</code>\n<b>Genres:</b> <code>{genres}</code>\n<b>Episodes:</b> <code>{episodes}</code>\n<b>Is Adult:</b> <code>{isAdult}</code>\n<b>Studios:</b> <code>{studios}</code>\n<b>Description:</b> <code>{description}</code>\n<b>Trailer:</b> <a href='https://youtu.be/{trailer}'>Click Here</a>",
caption=f"<b>Title:</b> <code>{title}</code>\n<b>Average Score:</b> <code>{average_score}</code>\n<b>Status:</b> <code>{status}</code>\n<b>Genres:</b> <code>{genres}</code>\n<b>Episodes:</b> <code>{episodes}</code>\n<b>Is Adult:</b> <code>{is_adult}</code>\n<b>Studios:</b> <code>{studios}</code>\n<b>Description:</b> <code>{description}</code>\n<b>Trailer:</b> <a href='https://youtu.be/{trailer}'>Click Here</a>",
)
],
)
@@ -109,22 +109,22 @@ async def manga_search(client: Client, message: Message):
result = response.json()
averageScore = result['averageScore']
average_score = result['average_score']
try:
coverImage_url = result['imageUrl']
coverImage = requests.get(url=coverImage_url).content
cover_image_url = result['imageUrl']
cover_image = requests.get(url=cover_image_url, timeout=10).content
async with aiofiles.open('coverImage.jpg', mode='wb') as f:
await f.write(coverImage)
await f.write(cover_image)
except Exception:
coverImage = None
cover_image = None
title = result['title']['english']
trailer = result['trailer']['id']
description = result['description']
chapters = result['chapters']
genres = ', '.join(result['genres'])
isAdult = result['isAdult']
is_adult = result['is_adult']
status = result['status']
studios = ', '.join(result['studios'])
@@ -134,7 +134,7 @@ async def manga_search(client: Client, message: Message):
[
InputMediaPhoto(
'coverImage.jpg',
caption=f"<b>Title:</b> <code>{title}</code>\n<b>Average Score:</b> <code>{averageScore}</code>\n<b>Status:</b> <code>{status}</code>\n<b>Genres:</b> <code>{genres}</code>\n<b>Chapters:</b> <code>{chapters}</code>\n<b>Is Adult:</b> <code>{isAdult}</code>\n<b>Studios:</b> <code>{studios}</code>\n<b>Description:</b> <code>{description}</code>\n<b>Trailer:</b> <a href='https://youtu.be/{trailer}'>Click Here</a>",
caption=f"<b>Title:</b> <code>{title}</code>\n<b>Average Score:</b> <code>{average_score}</code>\n<b>Status:</b> <code>{status}</code>\n<b>Genres:</b> <code>{genres}</code>\n<b>Chapters:</b> <code>{chapters}</code>\n<b>Is Adult:</b> <code>{is_adult}</code>\n<b>Studios:</b> <code>{studios}</code>\n<b>Description:</b> <code>{description}</code>\n<b>Trailer:</b> <a href='https://youtu.be/{trailer}'>Click Here</a>",
)
],
)
@@ -147,7 +147,7 @@ async def manga_search(client: Client, message: Message):
[
InputMediaPhoto(
'coverImage.jpg',
caption=f"<b>Title:</b> <code>{title}</code>\n<b>Average Score:</b> <code>{averageScore}</code>\n<b>Status:</b> <code>{status}</code>\n<b>Genres:</b> <code>{genres}</code>\n<b>Chapters:</b> <code>{chapters}</code>\n<b>Is Adult:</b> <code>{isAdult}</code>\n<b>Studios:</b> <code>{studios}</code>\n<b>Description:</b> <code>{description}</code>\n<b>Trailer:</b> <a href='https://youtu.be/{trailer}'>Click Here</a>",
caption=f"<b>Title:</b> <code>{title}</code>\n<b>Average Score:</b> <code>{average_score}</code>\n<b>Status:</b> <code>{status}</code>\n<b>Genres:</b> <code>{genres}</code>\n<b>Chapters:</b> <code>{chapters}</code>\n<b>Is Adult:</b> <code>{is_adult}</code>\n<b>Studios:</b> <code>{studios}</code>\n<b>Description:</b> <code>{description}</code>\n<b>Trailer:</b> <a href='https://youtu.be/{trailer}'>Click Here</a>",
)
],
)
@@ -176,13 +176,13 @@ async def character(client: Client, message: Message):
result = response.json()
try:
coverImage_url = result['image']['large']
coverImage = requests.get(url=coverImage_url).content
cover_image_url = result['image']['large']
cover_image = requests.get(url=cover_image_url, timeout=10).content
async with aiofiles.open('coverImage.jpg', mode='wb') as f:
await f.write(coverImage)
await f.write(cover_image)
except Exception:
coverImage = None
cover_image = None
age = result['age']
description = result['description']
+1 -1
View File
@@ -49,7 +49,7 @@ async def random():
@Client.on_message(filters.command(['arnd', 'arandom'], prefix) & filters.me)
async def anime_handler(client: Client, message: Message):
async def anime_handler(_client: Client, message: Message):
try:
await message.edit('<b>Searching art</b>', parse_mode=enums.ParseMode.HTML)
ra = await random()
+1 -1
View File
@@ -24,7 +24,7 @@ from utils.scripts import format_exc
def get_neko_media(query):
return requests.get(f'https://nekos.life/api/v2/img/{query}').json()['url']
return requests.get(f'https://nekos.life/api/v2/img/{query}', timeout=10).json()['url']
@Client.on_message(filters.command('neko', prefix) & filters.me)
+1 -1
View File
@@ -25,7 +25,7 @@ async def aniquotes_handler(client: Client, message: Message):
result = await client.get_inline_bot_results('@quotafbot', query)
return await message.reply_inline_bot_result(
query_id=result.query_id,
result_id=result.results[randint(1, 2)].id,
result_id=result.results[randint(1, 2)].id, # noqa: S311
reply_to_message_id=(message.reply_to_message.id if message.reply_to_message else None),
)
except Exception as e:
+1 -1
View File
@@ -11,7 +11,7 @@ def id_generator() -> str:
@Client.on_message(filters.command(['bbox', 'blackbox'], prefix) & filters.me)
async def blackbox(client, message):
async def blackbox(_client, message):
m = message
msg = await m.edit_text('🔍')
+2 -4
View File
@@ -11,11 +11,10 @@ async def calc(_, message: Message):
return
args = ' '.join(message.command[1:])
try:
result = str(eval(args))
result = str(eval(args)) # noqa: S307
if len(result) > 4096:
i = 0
for x in range(0, len(result), 4096):
for i, x in enumerate(range(0, len(result), 4096)):
if i == 0:
await message.edit(
f'<i>{args}</i><b>=</b><code>{result[x : x + 4000]}</code>',
@@ -23,7 +22,6 @@ async def calc(_, message: Message):
)
else:
await message.reply(f'<code>{result[x : x + 4096]}</code>', parse_mode='HTML')
i += 1
await asyncio.sleep(0.18)
else:
await message.edit(f'<i>{args}</i><b>=</b><code>{result}</code>', parse_mode='HTML')
+2 -2
View File
@@ -7,7 +7,7 @@ from utils.scripts import format_exc, import_library
clarifai = import_library('clarifai')
from clarifai.client.model import Model
from clarifai.client.model import Model # noqa: E402
@Client.on_message(filters.command('cdxl', prefix) & filters.me)
@@ -24,7 +24,7 @@ async def cdxl(c: Client, message: Message):
await message.edit_text(f'<b>Usage: </b><code>{prefix}vdxl [prompt/reply to prompt]</code>')
return
inference_params = dict(width=1024, height=1024, steps=50, cfg_scale=9.0)
inference_params = {'width': 1024, 'height': 1024, 'steps': 50, 'cfg_scale': 9.0}
model_prediction = Model(
'https://clarifai.com/stability-ai/stable-diffusion-2/models/stable-diffusion-xl'
+8 -8
View File
@@ -5,17 +5,17 @@ from utils.scripts import import_library
cohere = import_library('cohere')
import cohere
import cohere # noqa: F811, E402
co = cohere.Client(cohere_key)
from pyrogram import Client, enums, filters
from pyrogram.errors import MessageTooLong
from pyrogram.types import Message
from utils.db import db
from utils.misc import modules_help, prefix
from utils.rentry import paste as rentry_paste
from utils.scripts import format_exc
from pyrogram import Client, enums, filters # noqa: E402
from pyrogram.errors import MessageTooLong # noqa: E402
from pyrogram.types import Message # noqa: E402
from utils.db import db # noqa: E402
from utils.misc import modules_help, prefix # noqa: E402
from utils.rentry import paste as rentry_paste # noqa: E402
from utils.scripts import format_exc # noqa: E402
@Client.on_message(filters.command('cohere', prefix) & filters.me)
+7 -5
View File
@@ -9,22 +9,24 @@ from utils.scripts import import_library
requests = import_library('requests')
PIL = import_library('PIL', 'pillow')
from PIL import Image, ImageDraw, ImageFont
from PIL import Image, ImageDraw, ImageFont # noqa: E402
@Client.on_message(filters.command(['dem'], prefix) & filters.me)
async def demotivator(client: Client, message: Message):
await message.edit('<code>Process of demotivation...</code>', parse_mode=enums.ParseMode.HTML)
font = requests.get('https://github.com/The-MoonTg-project/files/blob/main/Times%20New%20Roman.ttf?raw=true')
font = requests.get(
'https://github.com/The-MoonTg-project/files/blob/main/Times%20New%20Roman.ttf?raw=true', timeout=10
)
f = font.content
template_dem = requests.get('https://raw.githubusercontent.com/files/main/demotivator.png')
template_dem = requests.get('https://raw.githubusercontent.com/files/main/demotivator.png', timeout=10)
if message.reply_to_message:
words = ['random', 'text', 'typing', 'fuck']
if message.reply_to_message.photo:
donwloads = await client.download_media(message.reply_to_message.photo.file_id)
photo = Image.open(f'{donwloads}')
resize_photo = photo.resize((469, 312))
text = message.text.split(' ', maxsplit=1)[1] if len(message.text.split()) > 1 else random.choice(words)
text = message.text.split(' ', maxsplit=1)[1] if len(message.text.split()) > 1 else random.choice(words) # noqa: S311
im = Image.open(BytesIO(template_dem.content))
im.paste(resize_photo, (65, 48))
text_font = ImageFont.truetype(BytesIO(f), 22)
@@ -38,7 +40,7 @@ async def demotivator(client: Client, message: Message):
donwloads = await client.download_media(message.reply_to_message.sticker.file_id)
photo = Image.open(f'{donwloads}')
resize_photo = photo.resize((469, 312))
text = message.text.split(' ', maxsplit=1)[1] if len(message.text.split()) > 1 else random.choice(words)
text = message.text.split(' ', maxsplit=1)[1] if len(message.text.split()) > 1 else random.choice(words) # noqa: S311
im = Image.open(BytesIO(template_dem.content))
im.paste(resize_photo, (65, 48))
text_font = ImageFont.truetype(BytesIO(f), 22)
+3 -3
View File
@@ -6,12 +6,12 @@ from utils.misc import modules_help, prefix
from utils.scripts import import_library
lottie = import_library('lottie')
from lottie.exporters import exporters
from lottie.importers import importers
from lottie.exporters import exporters # noqa: E402
from lottie.importers import importers # noqa: E402
@Client.on_message(filters.command('destroy', prefix) & filters.me)
async def destroy_sticker(client: Client, message: Message):
async def destroy_sticker(_client: Client, message: Message):
"""Destroy animated stickers by modifying their animation properties"""
try:
reply = message.reply_to_message
+13 -12
View File
@@ -22,7 +22,7 @@ from utils.misc import modules_help, prefix
def subprocess_run(cmd):
reply = ''
cmd_args = cmd.split()
subproc = Popen(
subproc = Popen( # noqa: S603
cmd_args,
stdout=PIPE,
stderr=PIPE,
@@ -30,11 +30,11 @@ def subprocess_run(cmd):
executable='bash',
)
talk = subproc.communicate()
exitCode = subproc.returncode
if exitCode != 0:
exit_code = subproc.returncode
if exit_code != 0:
reply += (
'```An error was detected while running the subprocess:\n'
f'exit code: {exitCode}\n'
f'exit code: {exit_code}\n'
f'stdout: {talk[0]}\n'
f'stderr: {talk[1]}```'
)
@@ -93,7 +93,7 @@ def gdrive(url: str) -> str:
elif link.find('uc?id=') != -1:
file_id = link.split('uc?id=')[1].strip()
url = f'{drive}/uc?export=download&id={file_id}'
download = requests.get(url, stream=True, allow_redirects=False)
download = requests.get(url, stream=True, allow_redirects=False, timeout=10)
cookies = download.cookies
try:
# In case of small file size, Google downloads directly
@@ -112,7 +112,7 @@ def gdrive(url: str) -> str:
if page_element is not None:
export = drive + page_element.get('href')
name = page.find('span', {'class': 'uc-name-size'}).text
response = requests.get(export, stream=True, allow_redirects=False, cookies=cookies)
response = requests.get(export, stream=True, allow_redirects=False, cookies=cookies, timeout=10)
dl_url = response.headers['location']
if 'accounts.google.com' in dl_url:
name = page.find('span', {'class': 'uc-name-size'}).text
@@ -138,7 +138,7 @@ def yandex_disk(url: str) -> str:
return reply
api = 'https://cloud-api.yandex.net/v1/disk/public/resources/download?public_key={}'
try:
dl_url = requests.get(api.format(link)).json()['href']
dl_url = requests.get(api.format(link), timeout=10).json()['href']
name = dl_url.split('filename=')[1].split('&disposition')[0]
reply += f'[{name}]({dl_url})\n'
except KeyError:
@@ -181,7 +181,7 @@ def mediafire(url: str) -> str:
reply = '`No MediaFire links found`\n'
return reply
reply = ''
page = BeautifulSoup(requests.get(link).content, 'lxml')
page = BeautifulSoup(requests.get(link, timeout=10).content, 'lxml')
info = page.find('a', {'aria-label': 'Download file'})
dl_url = info.get('href')
size = re.findall(r'\(.*\)', info.text)[0]
@@ -201,7 +201,7 @@ def sourceforge(url: str) -> str:
reply = f'Mirrors for __{file_path.split("/")[-1]}__\n'
project = re.findall(r'projects?/(.*?)/files', link)[0]
mirrors = f'https://sourceforge.net/settings/mirror_choices?projectname={project}&filename={file_path}'
page = BeautifulSoup(requests.get(mirrors).content, 'html.parser')
page = BeautifulSoup(requests.get(mirrors, timeout=10).content, 'html.parser')
info = page.find('ul', {'id': 'mirrorList'}).findAll('li')
for mirror in info[1:]:
name = re.findall(r'\((.*)\)', mirror.text.strip())[0]
@@ -218,7 +218,7 @@ def osdn(url: str) -> str:
except IndexError:
reply = '`No OSDN links found`\n'
return reply
page = BeautifulSoup(requests.get(link, allow_redirects=True).content, 'lxml')
page = BeautifulSoup(requests.get(link, allow_redirects=True, timeout=10).content, 'lxml')
info = page.find('a', {'class': 'mirror_link'})
link = urllib.parse.unquote(osdn_link + info['href'])
reply = f'Mirrors for __{link.split("/")[-1]}__\n'
@@ -285,13 +285,14 @@ def useragent():
"""
useragents = BeautifulSoup(
requests.get(
'https://developers.whatismybrowser.com/useragents/explore/operating_system_name/android/'
'https://developers.whatismybrowser.com/useragents/explore/operating_system_name/android/',
timeout=10,
).content,
'lxml',
).findAll('td', {'class': 'useragent'})
if not useragents:
return 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
user_agent = choice(useragents)
user_agent = choice(useragents) # noqa: S311
return user_agent.text
+1 -1
View File
@@ -4,7 +4,7 @@ from utils.misc import prefix
@Client.on_message(filters.command('duck', prefix) & filters.me)
async def duckgo(client: Client, message: Message):
async def duckgo(_client: Client, message: Message):
input_str = ' '.join(message.command[1:])
sample_url = 'https://duckduckgo.com/?q={}'.format(input_str.replace(' ', '+'))
if sample_url:
+1 -1
View File
@@ -8,7 +8,7 @@ from utils.misc import modules_help, prefix
@Client.on_message(filters.command('durov', prefix) & filters.me)
async def durov(_, message: Message):
await message.edit(
f'<b>Random post from channel: https://t.me/durov/{randint(21, 36500)}</b>',
f'<b>Random post from channel: https://t.me/durov/{randint(21, 36500)}</b>', # noqa: S311
parse_mode=enums.ParseMode.HTML,
)
+1 -1
View File
@@ -29,7 +29,7 @@ from utils.misc import modules_help, prefix
@Client.on_message(filters.command('example_edit', prefix) & filters.me)
async def example_edit(client: Client, message: Message):
async def example_edit(_client: Client, message: Message):
try:
await message.edit('<code>This is an example module</code>')
except Exception as e:
+1 -1
View File
@@ -36,7 +36,7 @@ async def download_sticker(url, filename):
@Client.on_message(filters.command(['f'], prefix) & filters.me)
async def random_stiker(client: Client, message: Message):
await message.delete()
random = randint(1, 63)
random = randint(1, 63) # noqa: S311
index = f'00{random}' if random < 10 else f'0{random}'
sticker = f'https://www.chpic.su/_data/stickers/f/FforRespect/FforRespect_{index}.webp'
await download_sticker(sticker, 'f.webp')
+1 -1
View File
@@ -32,7 +32,7 @@ async def fakeactions_handler(client: Client, message: Message):
sec = int(message.command[1])
if sec > 60:
sec = 60
except:
except Exception:
sec = None
await message.delete()
+4 -4
View File
@@ -36,7 +36,7 @@ def set_filters_chat(chat_id, filters_):
async def contains_filter(_, __, m):
return m.text and m.text.lower() in get_filters_chat(m.chat.id).keys()
return m.text and m.text.lower() in get_filters_chat(m.chat.id)
contains = filters.create(contains_filter)
@@ -115,7 +115,7 @@ async def filter_handler(client: Client, message: Message):
return await message.edit(f'<b>Usage</b>: <code>{prefix}filter [name] (Reply required)</code>')
name = message.text.split(maxsplit=1)[1].lower()
chat_filters = get_filters_chat(message.chat.id)
if name in chat_filters.keys():
if name in chat_filters:
return await message.edit(f'<b>Filter</b> <code>{name}</code> already exists.')
if not message.reply_to_message:
return await message.edit('<b>Reply to message</b> please.')
@@ -186,7 +186,7 @@ async def filter_del_handler(_, message: Message):
)
name = message.text.split(maxsplit=1)[1].lower()
chat_filters = get_filters_chat(message.chat.id)
if name not in chat_filters.keys():
if name not in chat_filters:
return await message.edit(
f"<b>Filter</b> <code>{name}</code> doesn't exists.",
)
@@ -208,7 +208,7 @@ async def filter_search_handler(_, message: Message):
)
name = message.text.split(maxsplit=1)[1].lower()
chat_filters = get_filters_chat(message.chat.id)
if name not in chat_filters.keys():
if name not in chat_filters:
return await message.edit(
f"<b>Filter</b> <code>{name}</code> doesn't exists.",
)
+2 -5
View File
@@ -85,14 +85,11 @@ REPLACEMENT_MAP = {
@Client.on_message(filters.command('flip', prefix) & filters.me)
async def flip(client: Client, message: Message):
async def flip(_client: Client, message: Message):
text = ' '.join(message.command[1:])
final_str = ''
for char in text:
if char in REPLACEMENT_MAP:
new_char = REPLACEMENT_MAP[char]
else:
new_char = char
new_char = REPLACEMENT_MAP.get(char, char)
final_str += new_char
if text != final_str:
await message.edit(final_str)
+3 -3
View File
@@ -9,9 +9,9 @@ from utils.scripts import format_exc, progress
def schellwithflux(args):
API_URL = 'https://randydev-ryuzaki-api.hf.space/api/v1/akeno/fluxai'
api_url = 'https://randydev-ryuzaki-api.hf.space/api/v1/akeno/fluxai'
payload = {'user_id': 1191668125, 'args': args} # Please don't edit here
response = requests.post(API_URL, json=payload)
response = requests.post(api_url, json=payload, timeout=10)
if response.status_code != 200:
print(f'Error status {response.status_code}')
return None
@@ -19,7 +19,7 @@ def schellwithflux(args):
@Client.on_message(filters.command('fluxai', prefix) & filters.me)
async def imgfluxai_(client: Client, message: Message):
async def imgfluxai_(_client: Client, message: Message):
question = message.text.split(' ', 1)[1] if len(message.command) > 1 else None
if not question:
return await message.reply_text('Please provide a question for Flux.')
+5 -5
View File
@@ -37,20 +37,20 @@ async def _wrap_edit(message: Message, text: str):
async def phase1(message: Message):
"""Big scroll"""
BIG_SCROLL = '🧡💛💚💙💜🖤🤎'
big_scroll = '🧡💛💚💙💜🖤🤎'
await _wrap_edit(message, joined_heart)
for heart in BIG_SCROLL:
for heart in big_scroll:
await _wrap_edit(message, joined_heart.replace(R, heart))
await asyncio.sleep(SLEEP)
async def phase2(message: Message):
"""Per-heart randomiser"""
ALL = ['❤️'] + list('🧡💛💚💙💜🤎🖤') # don't include white heart
all_hearts = ['❤️'] + list('🧡💛💚💙💜🤎🖤') # don't include white heart
format_heart = joined_heart.replace(R, '{}')
for _ in range(5):
heart = format_heart.format(*random.choices(ALL, k=heartlet_len))
heart = format_heart.format(*random.choices(all_hearts, k=heartlet_len)) # noqa: S311
await _wrap_edit(message, heart)
await asyncio.sleep(SLEEP)
@@ -75,7 +75,7 @@ async def phase4(message: Message):
@Client.on_message(filters.command('hearts', prefix) & filters.me)
async def hearts(client: Client, message: Message):
async def hearts(_client: Client, message: Message):
await phase1(message)
await phase2(message)
await phase3(message)
+1 -1
View File
@@ -34,7 +34,7 @@ async def help_cmd(_, message: Message):
command_name = message.command[1].lower()
module_found = False
for module_name, commands in modules_help.items():
for command in commands.keys():
for command in commands:
if command.split()[0] == command_name:
cmd = command.split(maxsplit=1)
cmd_desc = commands[command]
+1 -1
View File
@@ -13,7 +13,7 @@ async def kokodrilo_explodando(_, message: Message):
amount = int(message.command[1])
for _ in range(amount):
await message.edit('🐊')
await asyncio.sleep(random.uniform(1, 2.5))
await asyncio.sleep(random.uniform(1, 2.5)) # noqa: S311
await message.edit('💥')
await asyncio.sleep(1.8)
+16 -10
View File
@@ -51,7 +51,7 @@ async def get_mod_hash(_, message: Message):
if len(message.command) == 1:
return
url = message.command[1].lower()
resp = requests.get(url)
resp = requests.get(url, timeout=10)
if not resp.ok:
await message.edit(f'<b>Troubleshooting with downloading module <code>{url}</code></b>')
return
@@ -85,7 +85,7 @@ async def loadmod(_, message: Message):
module_name = url.lower()
try:
f = requests.get(
'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/full.txt'
'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/full.txt', timeout=10
).text
except Exception:
return await message.edit('Failed to fetch custom modules list')
@@ -97,9 +97,10 @@ async def loadmod(_, message: Message):
return
else:
modules_hashes = requests.get(
'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/modules_hashes.txt'
'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/modules_hashes.txt',
timeout=10,
).text
resp = requests.get(url)
resp = requests.get(url, timeout=10)
if not resp.ok:
await message.edit(
@@ -118,7 +119,7 @@ async def loadmod(_, message: Message):
module_name = url.split('/')[-1].split('.')[0]
resp = requests.get(url)
resp = requests.get(url, timeout=10)
if not resp.ok:
await message.edit(f'<b>Module <code>{module_name}</code> is not found</b>')
return
@@ -136,7 +137,7 @@ async def loadmod(_, message: Message):
content = f.read()
modules_hashes = requests.get(
'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/modules_hashes.txt'
'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/modules_hashes.txt', timeout=10
).text
if hashlib.sha256(content).hexdigest() not in modules_hashes:
@@ -214,7 +215,9 @@ async def load_all_mods(_, message: Message):
os.mkdir(f'{BASE_PATH}/modules/custom_modules')
try:
f = requests.get('https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/full.txt').text
f = requests.get(
'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/full.txt', timeout=10
).text
except Exception:
return await message.edit('Failed to fetch custom modules list')
modules_list = f.splitlines()
@@ -222,7 +225,7 @@ async def load_all_mods(_, message: Message):
await message.edit('<b>Loading modules...</b>')
for module_name in modules_list:
url = f'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/{module_name}.py'
resp = requests.get(url)
resp = requests.get(url, timeout=10)
if not resp.ok:
continue
with open(f'./modules/custom_modules/{module_name.split("/")[1]}.py', 'wb') as f:
@@ -281,13 +284,16 @@ async def updateallmods(_, message: Message):
if not module_name.endswith('.py'):
continue
try:
f = requests.get('https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/full.txt').text
f = requests.get(
'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/full.txt', timeout=10
).text
except Exception:
return await message.edit('Failed to fetch custom modules list')
modules_dict = {line.split('/')[-1].split()[0]: line.strip() for line in f.splitlines()}
if module_name in modules_dict:
resp = requests.get(
f'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/{modules_dict[module_name]}.py'
f'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/{modules_dict[module_name]}.py',
timeout=10,
)
if not resp.ok:
modules_installed.remove(module_name)
+1 -1
View File
@@ -23,7 +23,7 @@ from utils.scripts import import_library, prefix, with_reply
import_library('markitdown')
from markitdown import MarkItDown
from markitdown import MarkItDown # noqa: E402
@Client.on_message(filters.command(['markitdown', 'mkdn'], prefix) & filters.me)
+1 -1
View File
@@ -7,7 +7,7 @@ from utils.misc import modules_help, prefix
from utils.scripts import import_library
PIL = import_library('PIL', 'pillow')
from PIL import Image, ImageOps
from PIL import Image, ImageOps # noqa: E402
async def make(client, message, o):
+14 -15
View File
@@ -139,22 +139,21 @@ async def autofwd_main(client: Client, message: Message):
source_chats = db.get('custom.autofwd', 'chatsrc')
target_chats = db.get('custom.autofwd', 'chatto')
if source_chats is not None and chat_id in source_chats:
if target_chats is not None:
for chat in target_chats:
if source_chats is not None and chat_id in source_chats and target_chats is not None:
for chat in target_chats:
try:
await message.copy(chat)
except Exception as e:
try:
await message.copy(chat)
except Exception as e:
try:
await client.send_message(
'me',
f'Auto Forwarding Failed for Chat with id: <code>{chat_id}</code> to <code>{chat}</code>\n\n{e}',
)
except MessageTooLong:
await client.send_message(
'me',
f'Auto Forwarding Failed for Chat with id: <code>{chat_id}</code> to <code>{chat}</code>, Please check logs!',
)
await client.send_message(
'me',
f'Auto Forwarding Failed for Chat with id: <code>{chat_id}</code> to <code>{chat}</code>\n\n{e}',
)
except MessageTooLong:
await client.send_message(
'me',
f'Auto Forwarding Failed for Chat with id: <code>{chat_id}</code> to <code>{chat}</code>, Please check logs!',
)
modules_help['autofwd'] = {
+16 -16
View File
@@ -63,7 +63,7 @@ async def backup(client: Client, message: Message):
@Client.on_message(filters.command(['restore', 'res'], prefix) & filters.me)
async def restore(client: Client, message: Message):
async def restore(_client: Client, message: Message):
"""
Restore the database
"""
@@ -98,7 +98,7 @@ async def restore(client: Client, message: Message):
@Client.on_message(filters.command(['backupmods', 'bms'], prefix) & filters.me)
async def backupmods(client: Client, message: Message):
async def backupmods(_client: Client, message: Message):
"""
Backup the modules
"""
@@ -112,8 +112,8 @@ async def backupmods(client: Client, message: Message):
for mod in modules_help:
if os.path.isfile(f'modules/custom_modules/{mod}.py'):
f = open(f'backups/{mod}.py', 'wb')
f.write(open(f'modules/custom_modules/{mod}.py', 'rb').read())
with open(f'backups/{mod}.py', 'wb') as f, open(f'modules/custom_modules/{mod}.py', 'rb') as src:
f.write(src.read())
await message.edit(
text='<b>All modules backed up to:</b> <code>backups/</code> folder',
parse_mode=enums.ParseMode.HTML,
@@ -123,7 +123,7 @@ async def backupmods(client: Client, message: Message):
@Client.on_message(filters.command(['backupmod', 'bm'], prefix) & filters.me)
async def backupmod(client: Client, message: Message):
async def backupmod(_client: Client, message: Message):
"""
Backup the module
"""
@@ -133,7 +133,7 @@ async def backupmod(client: Client, message: Message):
try:
mod = message.text.split(maxsplit=1)[1].split('.')[0]
except:
except Exception:
return await message.edit(
f'<b>Usage:</b> <code>{prefix}backupmod [module]</code>',
parse_mode=enums.ParseMode.HTML,
@@ -142,8 +142,8 @@ async def backupmod(client: Client, message: Message):
await message.edit('<b>Backing up module...</b>', parse_mode=enums.ParseMode.HTML)
if os.path.isfile(f'modules/custom_modules/{mod}.py'):
f = open(f'backups/{mod}.py', 'wb')
f.write(open(f'modules/custom_modules/{mod}.py', 'rb').read())
with open(f'backups/{mod}.py', 'wb') as f, open(f'modules/custom_modules/{mod}.py', 'rb') as src:
f.write(src.read())
else:
return await message.edit(
f'<b>Module <code>{mod}</code> not found.</b>',
@@ -159,7 +159,7 @@ async def backupmod(client: Client, message: Message):
@Client.on_message(filters.command(['restoremod', 'resmod'], prefix) & filters.me)
async def restoremod(client: Client, message: Message):
async def restoremod(_client: Client, message: Message):
"""
Restore the module
"""
@@ -169,7 +169,7 @@ async def restoremod(client: Client, message: Message):
try:
mod = message.text.split(maxsplit=1)[1].split('.')[0]
except:
except Exception:
return await message.edit(
f'<b>Usage:</b> <code>{prefix}restoremod [module]</code>',
parse_mode=enums.ParseMode.HTML,
@@ -178,11 +178,11 @@ async def restoremod(client: Client, message: Message):
await message.edit('<b>Restoring module...</b>', parse_mode=enums.ParseMode.HTML)
if os.path.isfile(f'backups/{mod}.py'):
f = open(f'modules/custom_modules/{mod}.py', 'wb')
f.write(open(f'backups/{mod}.py', 'rb').read())
with open(f'modules/custom_modules/{mod}.py', 'wb') as f, open(f'backups/{mod}.py', 'rb') as src:
f.write(src.read())
else:
return await message.edit(
f'<b>Module <code>{mod}</code> not found.</b>',
text='<b>Backup file <code>{mod}</code> not found</b>',
parse_mode=enums.ParseMode.HTML,
)
await message.edit(
@@ -195,7 +195,7 @@ async def restoremod(client: Client, message: Message):
@Client.on_message(filters.command(['restoremods', 'resmods'], prefix) & filters.me)
async def restoremods(client: Client, message: Message):
async def restoremods(_client: Client, message: Message):
"""
Restore the modules
"""
@@ -209,8 +209,8 @@ async def restoremods(client: Client, message: Message):
if mod.endswith('.py'):
if os.path.isfile(f'modules/{mod}'):
continue
f = open(f'modules/custom_modules/{mod}', 'wb')
f.write(open(f'backups/{mod}', 'rb').read())
with open(f'modules/custom_modules/{mod}', 'wb') as f, open(f'backups/{mod}', 'rb') as src:
f.write(src.read())
await message.edit(
text='<b>All modules restored from:</b> <code>backups/</code> folder',
parse_mode=enums.ParseMode.HTML,
+2 -2
View File
@@ -16,7 +16,7 @@ def get_marine_life_details(species_name):
'per_page': 1,
}
response = requests.get(INATURALIST_API_URL, params=params)
response = requests.get(INATURALIST_API_URL, params=params, timeout=10)
if response.status_code == 200:
data = response.json()
@@ -25,7 +25,7 @@ def get_marine_life_details(species_name):
species = observation['taxon']['name']
common_name = observation['taxon']['preferred_common_name']
photo_url = observation['photos'][0]['url'] if observation['photos'] else 'No photo available'
description = observation['description'] if 'description' in observation else 'No description available.'
description = observation.get('description', 'No description available.')
return {
'species': species,
'common_name': common_name,
+1 -1
View File
@@ -41,7 +41,7 @@ def format_time_12hr(time_str: str) -> str:
@Client.on_message(filters.command('prayer', prefix) & filters.me)
async def namaz_times(client: Client, message: Message):
async def namaz_times(_client: Client, message: Message):
if message.reply_to_message:
city_name = message.reply_to_message.text
country_name = DEFAULT_COUNTRY # Default to Pakistan if no country is provided
+29 -26
View File
@@ -16,9 +16,12 @@
import base64
import os
from io import BytesIO
import aiofiles
import aiohttp
import requests
from PIL import Image, ImageEnhance
from pyrogram import Client, enums, filters
from pyrogram.errors import MediaCaptionTooLong, MessageTooLong
from pyrogram.types import InputMediaPhoto, Message
@@ -91,7 +94,7 @@ async def make_rayso(code: str, title: str, theme: str):
'language': 'auto',
'darkMode': False,
}
response = requests.post(f'{url}/rayso', data=data, headers=headers)
response = requests.post(f'{url}/rayso', data=data, headers=headers, timeout=10)
if response.status_code != 200:
return None
result = response.json()
@@ -134,7 +137,7 @@ async def sgemini(_, message: Message):
await message.edit_text('prompt not provided!')
return
await message.edit_text('Processing...')
response = requests.get(url=f'{url}/bard?query={prompt}', headers=headers)
response = requests.get(url=f'{url}/bard?query={prompt}', headers=headers, timeout=10)
if response.status_code != 200:
await message.edit_text('Something went wrong!')
return
@@ -163,17 +166,17 @@ async def app(client: Client, message: Message):
result = response.json()
try:
coverImage_url = result['results'][0]['icon']
coverImage = requests.get(url=coverImage_url).content
async with aiofiles.open('coverImage.jpg', mode='wb') as f:
await f.write(coverImage)
cover_image_url = result['results'][0]['icon']
cover_image = requests.get(url=cover_image_url, timeout=10).content
async with aiofiles.open('cover_image.jpg', mode='wb') as f:
await f.write(cover_image)
except Exception:
coverImage = None
cover_image = None
description = result['results'][0]['description']
developer = result['results'][0]['developer']
IsFree = result['results'][0]['free']
is_free = result['results'][0]['free']
genre = result['results'][0]['genre']
package_name = result['results'][0]['id']
title = result['results'][0]['title']
@@ -186,8 +189,8 @@ async def app(client: Client, message: Message):
chat_id,
[
InputMediaPhoto(
'coverImage.jpg',
caption=f'<b>Title:</b> <code>{title}</code>\n<b>Rating:</b> <code>{rating}</code>\n<b>IsFree:</b> <code>{IsFree}</code>\n<b>Price:</b> <code>{price}</code>\n<b>Package Name:</b> <code>{package_name}</code>\n<b>Genres:</b> <code>{genre}</code>\n<b>Developer:</b> <code>{developer}\n<b>Description:</b> {description}\n<b>Link:</b> {link}',
'cover_image.jpg',
caption=f'<b>Title:</b> <code>{title}</code>\n<b>Rating:</b> <code>{rating}</code>\n<b>is_free:</b> <code>{is_free}</code>\n<b>Price:</b> <code>{price}</code>\n<b>Package Name:</b> <code>{package_name}</code>\n<b>Genres:</b> <code>{genre}</code>\n<b>Developer:</b> <code>{developer}\n<b>Description:</b> {description}\n<b>Link:</b> {link}',
)
],
)
@@ -199,16 +202,16 @@ async def app(client: Client, message: Message):
chat_id,
[
InputMediaPhoto(
'coverImage.jpg',
caption=f'<b>Title:</b> <code>{title}</code>\n<b>Rating:</b> <code>{rating}</code>\n<b>IsFree:</b> <code>{IsFree}</code>\n<b>Price:</b> <code>{price}</code>\n<b>Package Name:</b> <code>{package_name}</code>\n<b>Genres:</b> <code>{genre}</code>\n<b>Developer:</b> <code>{developer}\n<b>Description:</b> {description}\n<b>Link:</b> {link}',
'cover_image.jpg',
caption=f'<b>Title:</b> <code>{title}</code>\n<b>Rating:</b> <code>{rating}</code>\n<b>is_free:</b> <code>{is_free}</code>\n<b>Price:</b> <code>{price}</code>\n<b>Package Name:</b> <code>{package_name}</code>\n<b>Genres:</b> <code>{genre}</code>\n<b>Developer:</b> <code>{developer}\n<b>Description:</b> {description}\n<b>Link:</b> {link}',
)
],
)
except Exception as e:
await message.edit_text(format_exc(e))
finally:
if os.path.exists('coverImage.jpg'):
os.remove('coverImage.jpg')
if os.path.exists('cover_image.jpg'):
os.remove('cover_image.jpg')
@Client.on_message(filters.command('tsearch', prefix) & filters.me)
@@ -222,14 +225,14 @@ async def tsearch(client: Client, message: Message):
else:
message.edit_text("What should i search? You didn't provided me with any value to search")
response = requests.get(url=f'{url}/torrent?query={query}&limit={limit}', headers=headers)
response = requests.get(url=f'{url}/torrent?query={query}&limit={limit}', headers=headers, timeout=10)
if response.status_code != 200:
await message.edit_text('Something went wrong')
return
result = response.json()
coverImage_url = result['results'][0]['thumbnail']
cover_image_url = result['results'][0]['thumbnail']
description = result['results'][0]['description']
genre = result['results'][0]['genre']
category = result['results'][0]['category']
@@ -261,17 +264,17 @@ async def tsearch(client: Client, message: Message):
content=all_results_content,
)
if coverImage_url is not None:
coverImage = requests.get(url=coverImage_url).content
async with aiofiles.open('coverImage.jpg', mode='wb') as f:
await f.write(coverImage)
if cover_image_url is not None:
cover_image = requests.get(url=cover_image_url, timeout=10).content
async with aiofiles.open('cover_image.jpg', mode='wb') as f:
await f.write(cover_image)
await message.delete()
await client.send_media_group(
chat_id,
[
InputMediaPhoto(
'coverImage.jpg',
'cover_image.jpg',
caption=f"<b>Title:</b> <code>{title}</code>\n<b>Category:</b> <code>{category}</code>\n<b>Language:</b> <code>{language}</code>\n<b>Size:</b> <code>{size}</code>\n<b>Genres:</b> <code>{genre}</code>\n<b>Description:</b> {description}\n<b>Magnet Link:</b> <a href='{link_result}'>Click Here</a>\n<b>More Results:</b> <a href='{link_results}'>Click Here</a>",
)
],
@@ -289,7 +292,7 @@ async def tsearch(client: Client, message: Message):
chat_id,
[
InputMediaPhoto(
'coverImage.jpg',
'cover_image.jpg',
caption=f"<b>Title:</b> <code>{title}</code>\n<b>Category:</b> <code>{category}</code>\n<b>Language:</b> <code>{language}</code>\n<b>Size:</b> <code>{size}</code>\n<b>Genres:</b> <code>{genre}</code>\n<b>Description:</b> {description}\n<b>Magnet Link:</b> <a href='{link_result}'>Click Here</a>",
)
],
@@ -305,8 +308,8 @@ async def tsearch(client: Client, message: Message):
except Exception as e:
await message.edit_text(format_exc(e))
finally:
if os.path.exists('coverImage.jpg'):
os.remove('coverImage.jpg')
if os.path.exists('cover_image.jpg'):
os.remove('cover_image.jpg')
@Client.on_message(filters.command('stts', prefix) & filters.me)
@@ -339,7 +342,7 @@ async def tts(client: Client, message: Message):
return
data = {'text': prompt, 'character': character}
response = requests.post(url=f'{url}/speech', headers=headers, json=data)
response = requests.post(url=f'{url}/speech', headers=headers, json=data, timeout=10)
if response.status_code != 200:
await message.edit_text('Something went wrong')
return
@@ -416,7 +419,7 @@ async def ccgen(_, message: Message):
await message.edit_text('Code not provided!')
return
await message.edit_text('Processing...')
response = requests.get(url=f'{url}/ccgen?bins={bins}', headers=headers)
response = requests.get(url=f'{url}/ccgen?bins={bins}', headers=headers, timeout=10)
if response.status_code != 200:
await message.edit_text('Something went wrong')
return
+12 -13
View File
@@ -15,6 +15,7 @@
#  along with this program.  If not, see <https://www.gnu.org/licenses/>.
import asyncio
import contextlib
import os
import requests
@@ -101,10 +102,8 @@ async def delete_search_data(client, chat_id, message_id):
search_key = f'{chat_id}_{key}'
if search_key in search_results and search_results[search_key]['message_id'] == message_id:
del search_results[search_key]
try:
with contextlib.suppress(BaseException):
await client.delete_messages(chat_id, message_id)
except:
pass
break
@@ -162,7 +161,7 @@ def format_apple_music_result(data):
async def search_music(api_url, format_function, message, query):
await message.edit('Searching...')
url = f'{api_url}{query}&limit=10'
response = requests.get(url)
response = requests.get(url, timeout=10)
if response.status_code == 200:
try:
@@ -195,7 +194,7 @@ async def google_search(client: Client, message: Message):
await message.edit('Searching...')
url = f'{GOOGLE_SEARCH_URL}{query}'
response = requests.get(url)
response = requests.get(url, timeout=10)
if response.status_code == 200:
data = response.json()
results, formatted_results = format_google_results(data['data'])
@@ -228,7 +227,7 @@ async def youtube_search(client: Client, message: Message):
await message.edit('Searching...')
url = f'{YOUTUBE_SEARCH_URL}{query}'
response = requests.get(url)
response = requests.get(url, timeout=10)
if response.status_code == 200:
data = response.json()
results, formatted_results = format_youtube_results(data['data'])
@@ -261,7 +260,7 @@ async def movie_search(client, message: Message):
await message.edit('Searching...')
url = f'{MOVIE_SEARCH_URL}{query}'
response = requests.get(url)
response = requests.get(url, timeout=10)
if response.status_code == 200:
data = response.json()
results, formatted_results = format_movie_results(data['data'])
@@ -301,7 +300,7 @@ async def apk_search(client, message: Message):
await message.edit('Searching...')
url = f'{APK_SEARCH_URL}{query}'
response = requests.get(url)
response = requests.get(url, timeout=10)
if response.status_code == 200:
data = response.json()
results, formatted_results = format_apk_results(data['BK9'])
@@ -330,7 +329,7 @@ async def gptweb(_, message: Message):
await message.edit('Thinking...')
query = ' '.join(message.command[1:])
url = f'{URL}/gptweb?text={query}'
response = requests.get(url)
response = requests.get(url, timeout=10)
if response.status_code == 200:
data = response.json()
await message.edit(
@@ -349,7 +348,7 @@ async def gemini(_, message: Message):
await message.edit('Thinking...')
query = ' '.join(message.command[1:])
url = f'{URL}/gemini?query={query}'
response = requests.get(url)
response = requests.get(url, timeout=10)
if response.status_code == 200:
data = response.json()
await message.edit(
@@ -441,7 +440,7 @@ async def handle_reply(client: Client, message: Message):
f'Votes: {movie["vote_count"]}'
)
if 'image' in movie:
response = requests.get(movie['image'])
response = requests.get(movie['image'], timeout=10)
if response.status_code == 200:
with open('movie_image.jpg', 'wb') as f:
f.write(response.content)
@@ -457,7 +456,7 @@ async def handle_reply(client: Client, message: Message):
await message.reply(caption, parse_mode=enums.ParseMode.MARKDOWN)
elif search_key.endswith('_apk'):
apk_url = f'{APK_DOWNLOAD_URL}{results[index]["link"]}'
fetch_apk_url = requests.get(apk_url)
fetch_apk_url = requests.get(apk_url, timeout=10)
if fetch_apk_url.status_code != 200:
await message.edit('Failed to fetch APK data.')
else:
@@ -470,7 +469,7 @@ async def handle_reply(client: Client, message: Message):
await message.edit('File size is too large to download.')
else:
apk_file_name = f'{data_apk["BK9"]["title"]}.apk'
response = requests.get(download_url)
response = requests.get(download_url, timeout=10)
if response.status_code != 200:
await message.edit('Failed to download the APK file.')
+1 -1
View File
@@ -27,7 +27,7 @@ async def search_cmd(client: Client, message: Message):
cmd = message.command[1]
word = message.command[2].lower()
timeout = float(message.command[3]) if len(message.command) > 3 else 2
except:
except Exception:
return await message.edit(
f'<b>Usage:</b> <code>{prefix}search [/cmd]* [search_word]* [timeout=2.0]</code>',
parse_mode=enums.ParseMode.HTML,
+2 -2
View File
@@ -8,8 +8,8 @@ from utils.scripts import format_exc, import_library
import_library('lxml_html_clean')
import_library('newspaper', 'newspaper3k')
nltk = import_library('nltk')
from newspaper import Article
from newspaper.article import ArticleException
from newspaper import Article # noqa: E402
from newspaper.article import ArticleException # noqa: E402
nltk.download('all')
+2 -2
View File
@@ -15,9 +15,9 @@ gladia_url = 'https://api.gladia.io/v2/transcription/'
# Function to make fetch requests to the Gladia API
def make_fetch_request(url, headers, method='GET', data=None):
if method == 'POST':
response = requests.post(url, headers=headers, json=data)
response = requests.post(url, headers=headers, json=data, timeout=10)
else:
response = requests.get(url, headers=headers)
response = requests.get(url, headers=headers, timeout=10)
return response.json()
+1 -1
View File
@@ -105,7 +105,7 @@ async def notes(_, message: Message):
await message.edit('<b>Loading...</b>')
text = 'Available notes:\n\n'
collection = db.get_collection('core.notes')
for note in collection.keys():
for note in collection:
if note[:4] == 'note':
text += f'<code>{note[4:]}</code>\n'
await message.edit(text)
+4 -4
View File
@@ -8,9 +8,9 @@ from utils.scripts import import_library
import_library('pyzerox', 'py-zerox')
import litellm
from pyzerox import zerox
from pyzerox.errors import ModelAccessError, NotAVisionModel
import litellm # noqa: E402
from pyzerox import zerox # noqa: E402
from pyzerox.errors import ModelAccessError, NotAVisionModel # noqa: E402
kwargs = {}
@@ -28,7 +28,7 @@ async def pdf2md(client: Client, message: Message):
if not message.reply_to_message.document:
await message.edit('Reply to a pdf file')
return
if not message.reply_to_message.document.mime_type == 'application/pdf':
if message.reply_to_message.document.mime_type != 'application/pdf':
await message.edit('Reply to a pdf file')
return
if gemini_key == '':
+3 -3
View File
@@ -24,9 +24,9 @@ async def prussian_cmd(_, message: Message):
]
splitted = message.reply_to_message.text.split()
for i in range(0, len(splitted), random.randint(2, 3)):
for j in range(1, 2):
splitted.insert(i, random.choice(words))
for i in range(0, len(splitted), random.randint(2, 3)): # noqa: S311
for _j in range(1, 2):
splitted.insert(i, random.choice(words)) # noqa: S311
await message.edit(' '.join(splitted), parse_mode=enums.ParseMode.HTML)
+3 -3
View File
@@ -41,7 +41,7 @@ async def user_exec(_: Client, message: Message):
try:
with redirect_stdout(stdout):
exec(code) # skipcq
exec(code) # skipcq # noqa: S102
text = f'<b>Code:</b>\n<code>{code}</code>\n\n<b>Result</b>:\n<code>{stdout.getvalue()}</code>'
if message.command[0] == 'exnoedit':
await message.reply(text)
@@ -53,7 +53,7 @@ async def user_exec(_: Client, message: Message):
# noinspection PyUnusedLocal
@Client.on_message(filters.command(['ev', 'eval'], prefix) & filters.me)
async def user_eval(client: Client, message: Message):
async def user_eval(_client: Client, message: Message):
if len(message.command) == 1:
await message.edit("<b>Code to eval isn't provided</b>")
return
@@ -61,7 +61,7 @@ async def user_eval(client: Client, message: Message):
code = message.text.split(maxsplit=1)[1]
try:
result = eval(code) # skipcq
result = eval(code) # skipcq # noqa: S307
await message.edit(f'<b>Expression:</b>\n<code>{code}</code>\n\n<b>Result</b>:\n<code>{result}</code>')
except Exception as e:
await message.edit(format_exc(e))
+17 -14
View File
@@ -51,14 +51,14 @@ async def convert_to_image(message, client) -> None | str:
path_s = await client.download_media(message.reply_to_message)
final_path = 'lottie_proton.png'
cmd = f'lottie_convert.py --frame 0 -if lottie -of png {path_s} {final_path}'
await exec(cmd) # skipcq
await exec(cmd) # skipcq # noqa: S102
elif message.reply_to_message.audio:
thumb = message.reply_to_message.audio.thumbs[0].file_id
final_path = await client.download_media(thumb)
elif message.reply_to_message.video or message.reply_to_message.animation:
final_path = 'fetched_thumb.png'
vid_path = await client.download_media(message.reply_to_message)
await exec(f'ffmpeg -i {vid_path} -filter:v scale=500:500 -an {final_path}') # skipcq
await exec(f'ffmpeg -i {vid_path} -filter:v scale=500:500 -an {final_path}') # skipcq # noqa: S102
elif message.reply_to_message.document:
if (
message.reply_to_message.document.mime_type == 'image/jpeg'
@@ -83,6 +83,7 @@ def remove_background(photo_data):
files={'image_file': image_data},
data={'size': 'auto'},
headers={'X-Api-Key': rmbg_key},
timeout=10,
)
if response.status_code == 200:
return BytesIO(response.content)
@@ -118,21 +119,23 @@ async def rmbg(client: Client, message: Message):
start = datetime.now()
await pablo.edit('sending to ReMove.BG')
input_file_name = cool
files = {
'image_file': (input_file_name, open(input_file_name, 'rb')),
}
r = requests.post(
'https://api.remove.bg/v1.0/removebg',
headers={'X-Api-Key': rmbg_key},
files=files,
allow_redirects=True,
stream=True,
)
with open(input_file_name, 'rb') as f:
files = {
'image_file': (input_file_name, f),
}
r = requests.post(
'https://api.remove.bg/v1.0/removebg',
headers={'X-Api-Key': rmbg_key},
files=files,
allow_redirects=True,
stream=True,
timeout=10,
)
if os.path.exists(cool):
os.remove(cool)
output_file_name = r
contentType = output_file_name.headers.get('content-type')
if 'image' in contentType:
content_type = output_file_name.headers.get('content-type')
if 'image' in content_type:
with io.BytesIO(output_file_name.content) as remove_bg_image:
remove_bg_image.name = 'BG_rem.png'
await client.send_document(message.chat.id, remove_bg_image, reply_to_message_id=message.id)
+1 -1
View File
@@ -30,7 +30,7 @@ async def shell(_, message: Message):
return await message.edit('<b>Specify the command in message text</b>')
cmd_text = message.text.split(maxsplit=1)[1]
cmd_args = cmd_text.split()
cmd_obj = Popen(
cmd_obj = Popen( # noqa: S603
cmd_args,
stdout=PIPE,
stderr=PIPE,
+8 -7
View File
@@ -26,12 +26,12 @@ async def tiktok_stalk(_, message: Message):
await message.edit('Fetching TikTok profile...')
url = f'{TIKTOK_API_URL}{query}'
response = requests.get(url)
response = requests.get(url, timeout=10)
if response.status_code == 200:
data = response.json().get('result', {})
if data:
profile_pic_url = data.get('profile', '')
profile_pic = requests.get(profile_pic_url).content
profile_pic = requests.get(profile_pic_url, timeout=10).content
profile_pic_stream = io.BytesIO(profile_pic)
profile_pic_stream.name = 'profile.jpg'
@@ -67,7 +67,8 @@ async def ipinfo(_, message: Message):
await m.edit_text('🔎')
try:
url = requests.get(
f'http://ip-api.com/json/{searchip}?fields=status,message,continent,continentCode,country,countryCode,region,regionName,city,district,zip,lat,lon,timezone,offset,currency,isp,org,as,asname,reverse,mobile,proxy,hosting,query'
f'http://ip-api.com/json/{searchip}?fields=status,message,continent,continentCode,country,countryCode,region,regionName,city,district,zip,lat,lon,timezone,offset,currency,isp,org,as,asname,reverse,mobile,proxy,hosting,query',
timeout=10,
)
response = json.loads(url.text)
text = f"""
@@ -95,7 +96,7 @@ async def ipinfo(_, message: Message):
<b>Proxy:</b> <code>{response['proxy']}</code>
<b>Hosting:</b> <code>{response['hosting']}</code>"""
await m.edit_text(text)
except:
except Exception:
await m.edit_text('Unable To Find Info!')
@@ -113,12 +114,12 @@ async def instagram_stalk(_, message: Message):
await message.edit('Fetching Instagram profile...')
url = f'{INSTAGRAM_API_URL}{query}'
response = requests.get(url)
response = requests.get(url, timeout=10)
if response.status_code == 200:
data = response.json().get('result', {}).get('user_info', {})
if data:
profile_pic_url = data.get('profile_pic_url', '')
profile_pic = requests.get(profile_pic_url).content
profile_pic = requests.get(profile_pic_url, timeout=10).content
profile_pic_stream = io.BytesIO(profile_pic)
profile_pic_stream.name = 'profile.jpg'
@@ -157,7 +158,7 @@ async def github_stalk(_, message: Message):
await message.edit('Fetching GitHub profile...')
url = f'{GH_STALK}{query}'
response = requests.get(url)
response = requests.get(url, timeout=10)
if response.status_code == 200:
data = response.json()
created_at = data.get('created_at', 'N/A')
+4 -6
View File
@@ -21,7 +21,7 @@ imageio = import_library('imageio')
def create_gif(filename: str, offset: int, fps: int = 2, typ: str = 'spin'):
img = Image.open(f'downloads/{filename}')
if typ.lower() != 'spin':
img = img.resize((random.randint(200, 1280), random.randint(200, 1280)), Image.ANTIALIAS)
img = img.resize((random.randint(200, 1280), random.randint(200, 1280)), Image.ANTIALIAS) # noqa: S311 # noqa: S311
imageio.mimsave(
'downloads/video.gif',
[img.rotate(-(i % 360)) for i in range(1, 361, offset)],
@@ -101,11 +101,9 @@ async def spin_handler(client: Client, message: Message):
filename = 'sticker.webp'
elif message.reply_to_message.text:
result = await quote_cmd(client, message)
if result[1]:
filename = 'sticker.png'
else:
filename = 'sticker.webp'
open('downloads/' + filename, 'wb').write(result[0].getbuffer())
filename = 'sticker.png' if result[1] else 'sticker.webp'
with open('downloads/' + filename, 'wb') as f:
f.write(result[0].getbuffer())
coro = False
else:
filename = 'photo.jpg'

Some files were not shown because too many files have changed in this diff Show More