Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
fc83176522
|
|||
|
0506aaaac8
|
|||
|
bd9724da69
|
|||
|
3bad433f1a
|
|||
|
2bd7a5176f
|
|||
|
a9ff01261b
|
|||
|
1362ebc3c2
|
|||
|
2de6131ba7
|
|||
|
1762962f32
|
|||
|
7fb9e46c05
|
|||
|
b33488342a
|
|||
|
d53b14b1de
|
|||
|
a6a6d933da
|
|||
| 0803f3efff | |||
| ec0420962b | |||
| b407202e53 | |||
| b9b8474455 | |||
| 76853637bc | |||
| dac3777fc4 | |||
| bb5a3697f2 | |||
| e73aacb900 | |||
| ea483da645 | |||
| 85d35f86a7 | |||
| 3d03ab1ea4 | |||
| 4ca3ccdad3 | |||
| 10e26cda72 | |||
| c648dfd147 | |||
| 2f97821dc6 | |||
| 3d78b90f3a | |||
| 3dc8228e22 | |||
| 93171ad8e6 | |||
| dca7ad0902 |
@@ -0,0 +1,24 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.{json,jsonc}]
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
||||||
|
|
||||||
|
[*.py]
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
[{Makefile,makefile}]
|
||||||
|
indent_style = tab
|
||||||
@@ -36,4 +36,4 @@ jobs:
|
|||||||
else
|
else
|
||||||
echo ">>> Skipping $dir: no compose file found"
|
echo ">>> Skipping $dir: no compose file found"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -104,4 +104,6 @@ temp/*
|
|||||||
*/k8s/*secret*
|
*/k8s/*secret*
|
||||||
!*/k8s/*secret*.example
|
!*/k8s/*secret*.example
|
||||||
traefik/k8s/local-tls.yaml
|
traefik/k8s/local-tls.yaml
|
||||||
|
converters/k8s/config.yaml
|
||||||
convertx/k8s/config.yaml
|
convertx/k8s/config.yaml
|
||||||
|
traefik/k8s/crowdsec-middleware.yaml
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
ignored:
|
||||||
|
- DL3008
|
||||||
|
- DL3042
|
||||||
|
- DL3018
|
||||||
|
- DL3059
|
||||||
|
trustedRegistries:
|
||||||
|
- docker.io
|
||||||
|
- ghcr.io
|
||||||
|
- quay.io
|
||||||
|
- gcr.forust.xyz
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"default": true,
|
||||||
|
"MD013": false,
|
||||||
|
"MD024": false,
|
||||||
|
"MD033": false,
|
||||||
|
"MD041": false,
|
||||||
|
"MD046": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
bracketSameLine: true
|
||||||
|
htmlWhitespaceSensitivity: css
|
||||||
|
printWidth: 120
|
||||||
|
tabWidth: 2
|
||||||
|
trailingComma: all
|
||||||
|
proseWrap: preserve
|
||||||
|
endOfLine: lf
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
extends: default
|
||||||
|
|
||||||
|
rules:
|
||||||
|
comments:
|
||||||
|
min-spaces-from-content: 1
|
||||||
|
comments-indentation: false
|
||||||
|
document-start: disable
|
||||||
|
line-length: disable
|
||||||
|
braces:
|
||||||
|
min-spaces-inside: 0
|
||||||
|
max-spaces-inside: 1
|
||||||
|
brackets:
|
||||||
|
min-spaces-inside: 0
|
||||||
|
max-spaces-inside: 1
|
||||||
|
indentation:
|
||||||
|
spaces: 2
|
||||||
|
indent-sequences: consistent
|
||||||
|
truthy:
|
||||||
|
allowed-values:
|
||||||
|
- "true"
|
||||||
|
- "false"
|
||||||
|
- "on"
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"tab_size": 2,
|
||||||
|
"soft_wrap": "prefer_line",
|
||||||
|
"preferred_line_length": 120,
|
||||||
|
"format_on_save": "on",
|
||||||
|
"languages": {
|
||||||
|
"YAML": {
|
||||||
|
"tab_size": 2,
|
||||||
|
"hard_tabs": false,
|
||||||
|
"format_on_save": "on",
|
||||||
|
"formatter": {
|
||||||
|
"language_server": { "name": "yaml-language-server" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Python": {
|
||||||
|
"tab_size": 4,
|
||||||
|
"format_on_save": "on",
|
||||||
|
"formatter": {
|
||||||
|
"language_server": { "name": "ruff" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lsp": {
|
||||||
|
"yaml-language-server": {
|
||||||
|
"settings": {
|
||||||
|
"yaml": {
|
||||||
|
"schemas": {
|
||||||
|
"kubernetes": ["**/k8s/*.yaml", "**/k8s/*.yml"]
|
||||||
|
},
|
||||||
|
"validate": true,
|
||||||
|
"completion": true,
|
||||||
|
"format": {
|
||||||
|
"enable": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,11 +17,11 @@ services:
|
|||||||
labels:
|
labels:
|
||||||
- "traefik.enable=true"
|
- "traefik.enable=true"
|
||||||
- "traefik.http.services.adguard.loadbalancer.server.port=3000"
|
- "traefik.http.services.adguard.loadbalancer.server.port=3000"
|
||||||
|
|
||||||
# Prod Router
|
# Prod Router
|
||||||
- "traefik.http.routers.adguard.rule=Host(`dns.forust.xyz`) || Host(`adguard.forust.xyz`)"
|
- "traefik.http.routers.adguard.rule=Host(`dns.forust.xyz`) || Host(`adguard.forust.xyz`)"
|
||||||
- "traefik.http.routers.adguard.entrypoints=websecure"
|
- "traefik.http.routers.adguard.entrypoints=websecure"
|
||||||
- "traefik.http.routers.adguard.tls=true"
|
- "traefik.http.routers.adguard.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.adguard-local.rule=Host(`adguard.workstation.internal`) || Host(`dns.workstation.internal`)"
|
- "traefik.http.routers.adguard-local.rule=Host(`adguard.workstation.internal`) || Host(`dns.workstation.internal`)"
|
||||||
- "traefik.http.routers.adguard-local.entrypoints=websecure"
|
- "traefik.http.routers.adguard-local.entrypoints=websecure"
|
||||||
@@ -31,10 +31,10 @@ services:
|
|||||||
- "traefik.http.routers.adguard-dev.entrypoints=websecure"
|
- "traefik.http.routers.adguard-dev.entrypoints=websecure"
|
||||||
- "traefik.http.routers.adguard-dev.tls=true"
|
- "traefik.http.routers.adguard-dev.tls=true"
|
||||||
# DoH Router
|
# DoH Router
|
||||||
- "traefik.http.routers.dns.rule=(Host(`dns.forust.xyz`) && PathPrefix(`/dns-query`))"
|
- "traefik.http.routers.dns-over-https.rule=(Host(`dns.forust.xyz` || Host(`adguard.forust.xyz`)) && PathPrefix(`/dns-query`))"
|
||||||
- "traefik.http.routers.dns.entrypoints=websecure"
|
- "traefik.http.routers.dns-over-https.entrypoints=websecure"
|
||||||
- "traefik.http.routers.dns.tls.certresolver=letsencrypt"
|
- "traefik.http.routers.dns-over-https.tls.certresolver=letsencrypt"
|
||||||
|
|
||||||
# Glance Metadata
|
# Glance Metadata
|
||||||
- glance.name=adguard
|
- glance.name=adguard
|
||||||
- glance.url=https://adguard.forust.xyz/
|
- glance.url=https://adguard.forust.xyz/
|
||||||
|
|||||||
@@ -1,5 +1,31 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Service
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: adguard-lb-service
|
||||||
|
namespace: adguard
|
||||||
|
annotations:
|
||||||
|
metallb.io/loadBalancerIPs: "192.168.80.3"
|
||||||
|
spec:
|
||||||
|
type: LoadBalancer
|
||||||
|
externalTrafficPolicy: Local
|
||||||
|
selector:
|
||||||
|
app: adguard
|
||||||
|
ports:
|
||||||
|
- name: dns-udp
|
||||||
|
port: 53
|
||||||
|
targetPort: 53
|
||||||
|
protocol: UDP
|
||||||
|
- name: dns-tcp
|
||||||
|
port: 53
|
||||||
|
targetPort: 53
|
||||||
|
protocol: TCP
|
||||||
|
- name: dot
|
||||||
|
port: 853
|
||||||
|
targetPort: 853
|
||||||
|
protocol: TCP
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: adguard-service
|
name: adguard-service
|
||||||
namespace: adguard
|
namespace: adguard
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^(adguard|dns)\.forust\.xyz$`)
|
- match: Host(`adguard.forust.xyz`) || Host(`dns.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
|
||||||
services:
|
services:
|
||||||
- name: adguard-service
|
- name: adguard-service
|
||||||
port: 3000
|
port: 3000
|
||||||
@@ -24,7 +26,7 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^(adguard|dns)\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`adguard.workstation.internal`) || Host(`dns.workstation.internal`) || Host(`adguard.gigaforust.internal`) || Host(`dns.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: adguard-service
|
- name: adguard-service
|
||||||
@@ -39,24 +41,12 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^(adguard|dns)\.forust\.xyz$`) && PathPrefix(`/dns-query`)
|
- match: (Host(`adguard.forust.xyz`) || Host(`dns.forust.xyz`)) && PathPrefix(`/dns-query`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
|
||||||
services:
|
services:
|
||||||
- name: adguard-service
|
- name: adguard-service
|
||||||
port: 3000
|
port: 3000
|
||||||
tls:
|
tls:
|
||||||
certResolver: letsencrypt
|
certResolver: letsencrypt
|
||||||
---
|
|
||||||
apiVersion: traefik.io/v1alpha1
|
|
||||||
kind: IngressRouteTCP
|
|
||||||
metadata:
|
|
||||||
name: adguard-dot
|
|
||||||
namespace: adguard
|
|
||||||
spec:
|
|
||||||
entryPoints:
|
|
||||||
- dot
|
|
||||||
routes:
|
|
||||||
- match: HostSNI(`*`)
|
|
||||||
services:
|
|
||||||
- name: adguard-service
|
|
||||||
port: 853
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ services:
|
|||||||
# Prod Router
|
# Prod Router
|
||||||
- "traefik.http.routers.authentik-server.rule=Host(`auth.forust.xyz`)"
|
- "traefik.http.routers.authentik-server.rule=Host(`auth.forust.xyz`)"
|
||||||
- "traefik.http.routers.authentik-server.entrypoints=websecure"
|
- "traefik.http.routers.authentik-server.entrypoints=websecure"
|
||||||
- "traefik.http.routers.authentik-server.tls=true"
|
- "traefik.http.routers.authentik-server.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.authentik-server-local.rule=Host(`auth.workstation.internal`)"
|
- "traefik.http.routers.authentik-server-local.rule=Host(`auth.workstation.internal`)"
|
||||||
- "traefik.http.routers.authentik-server-local.entrypoints=websecure"
|
- "traefik.http.routers.authentik-server-local.entrypoints=websecure"
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^auth\.forust\.xyz$`)
|
- match: Host(`auth.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
|
||||||
services:
|
services:
|
||||||
- name: authentik-server-service
|
- name: authentik-server-service
|
||||||
port: 9000
|
port: 9000
|
||||||
@@ -24,9 +26,8 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^auth\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`auth.workstation.internal`) || Host(`auth.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: authentik-server-service
|
- name: authentik-server-service
|
||||||
port: 9000
|
port: 9000
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
security_opt:
|
security_opt:
|
||||||
- no-new-privileges:true
|
- no-new-privileges:true
|
||||||
network_mode: 'host'
|
network_mode: "host"
|
||||||
# https://github.com/timothymiller/cloudflare-ddns#-quick-start
|
# https://github.com/timothymiller/cloudflare-ddns#-quick-start
|
||||||
environment:
|
environment:
|
||||||
- CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN:?Cloudflare API token is required}
|
- CLOUDFLARE_API_TOKEN=${CLOUDFLARE_API_TOKEN:?Cloudflare API token is required}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ services:
|
|||||||
# Prod Router
|
# Prod Router
|
||||||
- "traefik.http.routers.checkmk.rule=Host(`cmk.forust.xyz`)"
|
- "traefik.http.routers.checkmk.rule=Host(`cmk.forust.xyz`)"
|
||||||
- "traefik.http.routers.checkmk.entrypoints=websecure"
|
- "traefik.http.routers.checkmk.entrypoints=websecure"
|
||||||
- "traefik.http.routers.checkmk.tls=true"
|
- "traefik.http.routers.checkmk.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.checkmk-local.rule=Host(`cmk.workstation.internal`)"
|
- "traefik.http.routers.checkmk-local.rule=Host(`cmk.workstation.internal`)"
|
||||||
- "traefik.http.routers.checkmk-local.entrypoints=websecure"
|
- "traefik.http.routers.checkmk-local.entrypoints=websecure"
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^cmk\.forust\.xyz$`)
|
- match: Host(`cmk.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-crowdsec-bouncer@kubernetescrd
|
||||||
services:
|
services:
|
||||||
- name: checkmk-service
|
- name: checkmk-service
|
||||||
port: 5000
|
port: 5000
|
||||||
@@ -24,9 +26,8 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^cmk\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`cmk.workstation.internal`) || Host(`cmk.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: checkmk-service
|
- name: checkmk-service
|
||||||
port: 5000
|
port: 5000
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
ACCOUNT_REGISTRATION=false
|
||||||
|
HTTP_ALLOWED=false
|
||||||
|
ALLOW_UNAUTHENTICAED=false
|
||||||
|
AUTO_DELETE_EVERY_N_HOURS=24
|
||||||
|
WEBROOT=/convert
|
||||||
|
HIDE_HISTORY=false
|
||||||
|
LANGUAGE=en
|
||||||
|
UNAUTHED_USER_SHARING=false
|
||||||
|
MAX_CONVERT_PROCESS=0
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
services:
|
||||||
|
convertx:
|
||||||
|
container_name: convertx
|
||||||
|
image: ghcr.io/c4illin/convertx:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "9992:3000"
|
||||||
|
# https://github.com/C4illin/ConvertX#environment-variables
|
||||||
|
environment:
|
||||||
|
- JWT_SECRET=$(JWT_SECRET)
|
||||||
|
- ACCOUNT_REGISTRATION=$(ACCOUNT_REGISTRATION:-false)
|
||||||
|
- HTTP_ALLOWED=$(HTTP_ALLOWED:-false)
|
||||||
|
- ALLOW_UNAUTHENTICATED=$(ALLOW_UNAUTHENTICATED:-false)
|
||||||
|
- AUTO_DELETE_EVERY_N_HOURS=$(AUTO_DELETE_EVERY_N_HOURS:-24)
|
||||||
|
- WEBROOT=$(WEBROOT)
|
||||||
|
- HIDE_HISTORY=$(HIDE_HISTORY:-false)
|
||||||
|
- LANGUAGE=$(LANGUAGE:-en)
|
||||||
|
- UNAUTHENTICATED_USER_SHARING=$(UNAUTHENTICATED_USER_SHARING:-false)
|
||||||
|
- MAX_CONVERT_PROCESS=$(MAX_CONVERT_PROCESS:-0)
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.services.convertx.loadbalancer.server.port=3000"
|
||||||
|
# Prod Router
|
||||||
|
- "traefik.http.routers.convertx.rule=(Host(`forust.xyz`) || Host(`www.forust.xyz`)) && PathPrefix(`/convert`)"
|
||||||
|
- "traefik.http.routers.convertx.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.convertx.priority=50"
|
||||||
|
- "traefik.http.routers.convertx.tls.certresolver=letsencrypt"
|
||||||
|
# Local Router
|
||||||
|
- "traefik.http.routers.convertx-local.rule=Host(`workstation.internal`) && PathPrefix(`/convert`)"
|
||||||
|
- "traefik.http.routers.convertx-local.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.convertx-local.priority=50"
|
||||||
|
- "traefik.http.routers.convertx-local.tls=true"
|
||||||
|
# Dev Router
|
||||||
|
- "traefik.http.routers.convertx-dev.rule=Host(`gigaforust.internal`) && PathPrefix(`/convert`)"
|
||||||
|
- "traefik.http.routers.convertx-dev.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.convertx-dev.priority=50"
|
||||||
|
- "traefik.http.routers.convertx-dev.tls=true"
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
volumes:
|
||||||
|
- data:/app/data
|
||||||
|
|
||||||
|
bentopdf:
|
||||||
|
container_name: bentopdf
|
||||||
|
image: bentopdf/bentopdf:latest
|
||||||
|
restart: unless-stopped
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.services.bentopdf.loadbalancer.server.port=8080"
|
||||||
|
|
||||||
|
# Prod router
|
||||||
|
- "traefik.http.routers.bentopdf.rule=Host(`pdf.forust.xyz`)"
|
||||||
|
- "traefik.http.routers.bentopdf.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.bentopdf.tls.certresolver=letsencrypt"
|
||||||
|
- "traefik.http.routers.bentopdf.tls=true"
|
||||||
|
# Local router
|
||||||
|
- "traefik.http.routers.bentopdf-local.rule=Host(`pdf.wokstation.internal`)"
|
||||||
|
- "traefik.http.routers.bentopdf-local.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.bentopdf-local.tls=true"
|
||||||
|
# Dev router
|
||||||
|
- "traefik.http.routers.bentopdf-dev.rule=Host(`pdf.gigaforust.internal`)"
|
||||||
|
- "traefik.http.routers.bentopdf-dev.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.bentopdf-dev.tls=true"
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
|
volumes:
|
||||||
|
data:
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
kind: Service
|
||||||
|
apiVersion: v1
|
||||||
|
metadata:
|
||||||
|
name: bentopdf-service
|
||||||
|
namespace: converters
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: bentopdf
|
||||||
|
ports:
|
||||||
|
- port: 8080
|
||||||
|
targetPort: 8080
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: bentopdf-deployment
|
||||||
|
namespace: converters
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: bentopdf
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: bentopdf
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: bentopdf/bentopdf:latest
|
||||||
|
imagePullPolicy: Always
|
||||||
|
name: bentopdf
|
||||||
|
ports:
|
||||||
|
- containerPort: 8080
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "50Mi"
|
||||||
|
cpu: "50m"
|
||||||
|
ephemeral-storage: "100Mi"
|
||||||
|
limits:
|
||||||
|
memory: "700Mi"
|
||||||
|
cpu: "700m"
|
||||||
|
ephemeral-storage: "5Gi"
|
||||||
@@ -3,7 +3,7 @@ apiVersion: v1
|
|||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
metadata:
|
metadata:
|
||||||
name: convertx-config
|
name: convertx-config
|
||||||
namespace: convertx
|
namespace: converters
|
||||||
data:
|
data:
|
||||||
ACCOUNT_REGISTRATION: "false"
|
ACCOUNT_REGISTRATION: "false"
|
||||||
HTTP_ALLOWED: "false"
|
HTTP_ALLOWED: "false"
|
||||||
@@ -2,7 +2,7 @@ apiVersion: v1
|
|||||||
kind: Service
|
kind: Service
|
||||||
metadata:
|
metadata:
|
||||||
name: convertx-service
|
name: convertx-service
|
||||||
namespace: convertx
|
namespace: converters
|
||||||
spec:
|
spec:
|
||||||
selector:
|
selector:
|
||||||
app: convertx
|
app: convertx
|
||||||
@@ -14,7 +14,7 @@ apiVersion: apps/v1
|
|||||||
kind: Deployment
|
kind: Deployment
|
||||||
metadata:
|
metadata:
|
||||||
name: convertx-deployment
|
name: convertx-deployment
|
||||||
namespace: convertx
|
namespace: converters
|
||||||
spec:
|
spec:
|
||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
@@ -54,7 +54,7 @@ apiVersion: v1
|
|||||||
kind: PersistentVolumeClaim
|
kind: PersistentVolumeClaim
|
||||||
metadata:
|
metadata:
|
||||||
name: convertx-pvc
|
name: convertx-pvc
|
||||||
namespace: convertx
|
namespace: converters
|
||||||
spec:
|
spec:
|
||||||
accessModes:
|
accessModes:
|
||||||
- ReadWriteOnce
|
- ReadWriteOnce
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: convertx-prod
|
||||||
|
namespace: converters
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: (Host(`forust.xyz`) || Host(`www.forust.xyz`)) && PathPrefix(`/convert`)
|
||||||
|
kind: Rule
|
||||||
|
priority: 50
|
||||||
|
services:
|
||||||
|
- name: convertx-service
|
||||||
|
port: 3000
|
||||||
|
tls:
|
||||||
|
certResolver: letsencrypt
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: convertx-local
|
||||||
|
namespace: converters
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: (Host(`workstation.internal`) || Host(`gigaforust.internal`)) && PathPrefix(`/convert`)
|
||||||
|
kind: Rule
|
||||||
|
priority: 50
|
||||||
|
services:
|
||||||
|
- name: convertx-service
|
||||||
|
port: 3000
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: bentopdf-prod
|
||||||
|
namespace: converters
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`pdf.forust.xyz`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: bentopdf-service
|
||||||
|
port: 8080
|
||||||
|
tls:
|
||||||
|
certResolver: letsencrypt
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: bentopdf-local
|
||||||
|
namespace: converters
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`pdf.workstation.internal`) || Host(`pdf.gigaforust.internal`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: bentopdf-service
|
||||||
|
port: 8080
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: Namespace
|
kind: Namespace
|
||||||
metadata:
|
metadata:
|
||||||
name: convertx
|
name: converters
|
||||||
@@ -2,6 +2,7 @@ apiVersion: v1
|
|||||||
kind: Secret
|
kind: Secret
|
||||||
metadata:
|
metadata:
|
||||||
name: convertx-secrets
|
name: convertx-secrets
|
||||||
|
namespace: converters
|
||||||
type: Opaque
|
type: Opaque
|
||||||
stringData:
|
stringData:
|
||||||
jwt-secret: ""
|
jwt-secret: ""
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
services:
|
|
||||||
convertx:
|
|
||||||
container_name: convertx
|
|
||||||
image: ghcr.io/c4illin/convertx:latest
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "9992:3000"
|
|
||||||
# https://github.com/C4illin/ConvertX#environment-variables
|
|
||||||
environment:
|
|
||||||
- JWT_SECRET=$(JWT_SECRET)
|
|
||||||
- ACCOUNT_REGISTRATION=$(ACCOUNT_REGISTRATION:-false)
|
|
||||||
- HTTP_ALLOWED=$(HTTP_ALLOWED:-false)
|
|
||||||
- ALLOW_UNAUTHENTICATED=$(ALLOW_UNAUTHENTICATED:-false)
|
|
||||||
- AUTO_DELETE_EVERY_N_HOURS=$(AUTO_DELETE_EVERY_N_HOURS:-24)
|
|
||||||
- WEBROOT=$(WEBROOT)
|
|
||||||
- HIDE_HISTORY=$(HIDE_HISTORY:-false)
|
|
||||||
- LANGUAGE=$(LANGUAGE:-en)
|
|
||||||
- UNAUTHENTICATED_USER_SHARING=$(UNAUTHENTICATED_USER_SHARING:-false)
|
|
||||||
- MAX_CONVERT_PROCESS=$(MAX_CONVERT_PROCESS:-0)
|
|
||||||
labels:
|
|
||||||
- "traefik.enable=true"
|
|
||||||
- "traefik.http.services.convertx.loadbalancer.server.port=3000"
|
|
||||||
# Prod Router
|
|
||||||
- "traefik.http.routers.convertx.rule=Host(`convert.forust.xyz`)"
|
|
||||||
- "traefik.http.routers.convertx.entrypoints=websecure"
|
|
||||||
- "traefik.http.routers.convertx.tls=true"
|
|
||||||
# Local Router
|
|
||||||
- "traefik.http.routers.convertx-local.rule=Host(`convert.workstation.internal`)"
|
|
||||||
- "traefik.http.routers.convertx-local.entrypoints=websecure"
|
|
||||||
- "traefik.http.routers.convertx-local.tls=true"
|
|
||||||
# Dev Router
|
|
||||||
- "traefik.http.routers.convertx-dev.rule=Host(`convertx.gigaforust.internal`)"
|
|
||||||
- "traefik.http.routers.convertx-dev.entrypoints=websecure"
|
|
||||||
- "traefik.http.routers.convertx-dev.tls=true"
|
|
||||||
networks:
|
|
||||||
- proxy
|
|
||||||
volumes:
|
|
||||||
- data:/app/data
|
|
||||||
networks:
|
|
||||||
proxy:
|
|
||||||
external: true
|
|
||||||
volumes:
|
|
||||||
data:
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
apiVersion: traefik.io/v1alpha1
|
|
||||||
kind: IngressRoute
|
|
||||||
metadata:
|
|
||||||
name: convertx-prod
|
|
||||||
namespace: convertx
|
|
||||||
spec:
|
|
||||||
entryPoints:
|
|
||||||
- websecure
|
|
||||||
routes:
|
|
||||||
- match: HostRegexp(`^forust\.xyz$`) && PathPrefix(`/convert`)
|
|
||||||
kind: Rule
|
|
||||||
services:
|
|
||||||
- name: convertx-service
|
|
||||||
port: 3000
|
|
||||||
tls:
|
|
||||||
certResolver: letsencrypt
|
|
||||||
---
|
|
||||||
apiVersion: traefik.io/v1alpha1
|
|
||||||
kind: IngressRoute
|
|
||||||
metadata:
|
|
||||||
name: convertx-local
|
|
||||||
namespace: convertx
|
|
||||||
spec:
|
|
||||||
entryPoints:
|
|
||||||
- websecure
|
|
||||||
routes:
|
|
||||||
- match: HostRegexp(`^(workstation|gigaforust)\.internal$`) && PathPrefix(`/convert`)
|
|
||||||
kind: Rule
|
|
||||||
services:
|
|
||||||
- name: convertx-service
|
|
||||||
port: 3000
|
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
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"
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
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
|
||||||
+41
-41
@@ -1,46 +1,46 @@
|
|||||||
services:
|
services:
|
||||||
dockmon:
|
dockmon:
|
||||||
image: darthnorse/dockmon:latest
|
image: darthnorse/dockmon:latest
|
||||||
container_name: dockmon
|
container_name: dockmon
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# ports:
|
# ports:
|
||||||
# - 8000:443
|
# - 8000:443
|
||||||
volumes:
|
volumes:
|
||||||
- data:/app/data
|
- data:/app/data
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: [ "CMD", "curl", "-k", "-f", "https://localhost:443/health" ]
|
test: ["CMD", "curl", "-k", "-f", "https://localhost:443/health"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 3
|
retries: 3
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=true"
|
- "traefik.enable=true"
|
||||||
- "traefik.http.services.dockmon.loadbalancer.server.port=443"
|
- "traefik.http.services.dockmon.loadbalancer.server.port=443"
|
||||||
- "traefik.http.services.dockmon.loadbalancer.server.scheme=https"
|
- "traefik.http.services.dockmon.loadbalancer.server.scheme=https"
|
||||||
- "traefik.http.services.dockmon.loadbalancer.serverstransport=insecureTransport@file"
|
- "traefik.http.services.dockmon.loadbalancer.serverstransport=insecureTransport@file"
|
||||||
|
|
||||||
# Prod Router
|
# Prod Router
|
||||||
- "traefik.http.routers.dockmon.rule=Host(`dockmon.forust.xyz`)"
|
- "traefik.http.routers.dockmon.rule=Host(`dockmon.forust.xyz`)"
|
||||||
- "traefik.http.routers.dockmon.entrypoints=websecure"
|
- "traefik.http.routers.dockmon.entrypoints=websecure"
|
||||||
- "traefik.http.routers.dockmon.middlewares=security-headers@file"
|
- "traefik.http.routers.dockmon.middlewares=security-headers@file"
|
||||||
- "traefik.http.routers.dockmon.tls=true"
|
- "traefik.http.routers.dockmon.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.dockmon-local.rule=Host(`dockmon.workstation.internal`)"
|
- "traefik.http.routers.dockmon-local.rule=Host(`dockmon.workstation.internal`)"
|
||||||
- "traefik.http.routers.dockmon-local.entrypoints=websecure"
|
- "traefik.http.routers.dockmon-local.entrypoints=websecure"
|
||||||
- "traefik.http.routers.dockmon-local.tls=true"
|
- "traefik.http.routers.dockmon-local.tls=true"
|
||||||
# Dev Router
|
# Dev Router
|
||||||
- "traefik.http.routers.dockmon-dev.rule=Host(`dockmon.gigaforust.internal`)"
|
- "traefik.http.routers.dockmon-dev.rule=Host(`dockmon.gigaforust.internal`)"
|
||||||
- "traefik.http.routers.dockmon-dev.entrypoints=websecure"
|
- "traefik.http.routers.dockmon-dev.entrypoints=websecure"
|
||||||
- "traefik.http.routers.dockmon-dev.tls=true"
|
- "traefik.http.routers.dockmon-dev.tls=true"
|
||||||
|
|
||||||
# Glance Metadata
|
# Glance Metadata
|
||||||
- glance.name=dockmon
|
- glance.name=dockmon
|
||||||
- glance.url=https://dockmon.forust.xyz/
|
- glance.url=https://dockmon.forust.xyz/
|
||||||
- glance.description=Dockmon is a lightweight Docker container monitoring and management tool with a user-friendly web interface.
|
- glance.description=Dockmon is a lightweight Docker container monitoring and management tool with a user-friendly web interface.
|
||||||
networks:
|
networks:
|
||||||
- proxy
|
- proxy
|
||||||
volumes:
|
volumes:
|
||||||
data:
|
data:
|
||||||
networks:
|
networks:
|
||||||
proxy:
|
proxy:
|
||||||
external: true
|
external: true
|
||||||
|
|||||||
@@ -15,9 +15,10 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^dockmon\.forust\.xyz$`)
|
- match: Host(`dockmon.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
middlewares:
|
middlewares:
|
||||||
|
- name: crowdsec-crowdsec-bouncer@kubernetescrd
|
||||||
- name: security-headers@file
|
- name: security-headers@file
|
||||||
services:
|
services:
|
||||||
- name: dockmon-service
|
- name: dockmon-service
|
||||||
@@ -35,10 +36,9 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^dockmon\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`dockmon.workstation.internal`) || Host(`dockmon.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: dockmon-service
|
- name: dockmon-service
|
||||||
port: 443
|
port: 443
|
||||||
serversTransport: dockmon-transport
|
serversTransport: dockmon-transport
|
||||||
|
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ services:
|
|||||||
- "traefik.enable=true"
|
- "traefik.enable=true"
|
||||||
- "traefik.http.services.downtify.loadbalancer.server.port=8000"
|
- "traefik.http.services.downtify.loadbalancer.server.port=8000"
|
||||||
|
|
||||||
# Prod Router
|
# Prod Router
|
||||||
- "traefik.http.routers.downtify.rule=Host(`downtify.forust.xyz`)"
|
- "traefik.http.routers.downtify.rule=Host(`downtify.forust.xyz`)"
|
||||||
- "traefik.http.routers.downtify.entrypoints=websecure"
|
- "traefik.http.routers.downtify.entrypoints=websecure"
|
||||||
- "traefik.http.routers.downtify.middlewares=security-chain@file"
|
- "traefik.http.routers.downtify.middlewares=security-chain@file"
|
||||||
- "traefik.http.routers.downtify.tls=true"
|
- "traefik.http.routers.downtify.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.downtify-local.rule=Host(`downtify.workstation.internal`)"
|
- "traefik.http.routers.downtify-local.rule=Host(`downtify.workstation.internal`)"
|
||||||
- "traefik.http.routers.downtify-local.entrypoints=websecure"
|
- "traefik.http.routers.downtify-local.entrypoints=websecure"
|
||||||
|
|||||||
@@ -7,9 +7,10 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^downtify\.forust\.xyz$`)
|
- match: Host(`downtify.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
middlewares:
|
middlewares:
|
||||||
|
- name: crowdsec-crowdsec-bouncer@kubernetescrd
|
||||||
- name: security-chain@file
|
- name: security-chain@file
|
||||||
services:
|
services:
|
||||||
- name: downtify-service
|
- name: downtify-service
|
||||||
@@ -26,9 +27,8 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^downtify\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`downtify.workstation.internal`) || Host(`downtify.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: downtify-service
|
- name: downtify-service
|
||||||
port: 8000
|
port: 8000
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- redis-data:/data
|
- redis-data:/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: [ "CMD", "redis-cli", "ping" ]
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
timeout: 3s
|
timeout: 3s
|
||||||
retries: 5
|
retries: 5
|
||||||
@@ -25,7 +25,7 @@ services:
|
|||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: [ "CMD-SHELL", "redis-cli -h redis EXISTS EDU_PHPSESSID | grep -q 1" ]
|
test: ["CMD-SHELL", "redis-cli -h redis EXISTS EDU_PHPSESSID | grep -q 1"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 10
|
retries: 10
|
||||||
|
|||||||
+2
-3
@@ -12,7 +12,7 @@ services:
|
|||||||
- GITEA__database__USER=gitea
|
- GITEA__database__USER=gitea
|
||||||
- GITEA__database__PASSWD=gitea
|
- GITEA__database__PASSWD=gitea
|
||||||
- GITEA__database__NAME=gitea
|
- GITEA__database__NAME=gitea
|
||||||
#Server
|
# Server
|
||||||
- GITEA__server__ROOT_URL=https://gitea.forust.xyz
|
- GITEA__server__ROOT_URL=https://gitea.forust.xyz
|
||||||
- GITEA__server__SSH_DOMAIN=gitssh.forust.xyz
|
- GITEA__server__SSH_DOMAIN=gitssh.forust.xyz
|
||||||
- GITEA__server__SSH_PORT=2221
|
- GITEA__server__SSH_PORT=2221
|
||||||
@@ -36,7 +36,7 @@ services:
|
|||||||
# Prod Router
|
# Prod Router
|
||||||
- "traefik.http.routers.gitea.rule=Host(`gitea.forust.xyz`)"
|
- "traefik.http.routers.gitea.rule=Host(`gitea.forust.xyz`)"
|
||||||
- "traefik.http.routers.gitea.entrypoints=websecure"
|
- "traefik.http.routers.gitea.entrypoints=websecure"
|
||||||
- "traefik.http.routers.gitea.tls=true"
|
- "traefik.http.routers.gitea.tls.certresolver"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.gitea-local.rule=Host(`gitea.workstation.internal`)"
|
- "traefik.http.routers.gitea-local.rule=Host(`gitea.workstation.internal`)"
|
||||||
- "traefik.http.routers.gitea-local.entrypoints=websecure"
|
- "traefik.http.routers.gitea-local.entrypoints=websecure"
|
||||||
@@ -53,7 +53,6 @@ services:
|
|||||||
- "traefik.http.routers.gitea-registry.rule=Host(`gcr.forust.xyz`) && PathPrefix(`/v2`)"
|
- "traefik.http.routers.gitea-registry.rule=Host(`gcr.forust.xyz`) && PathPrefix(`/v2`)"
|
||||||
- "traefik.http.routers.gitea-registry.entrypoints=websecure"
|
- "traefik.http.routers.gitea-registry.entrypoints=websecure"
|
||||||
- "traefik.http.routers.gitea-registry.tls.certresolver=letsencrypt"
|
- "traefik.http.routers.gitea-registry.tls.certresolver=letsencrypt"
|
||||||
- "traefik.http.routers.gitea-registry.tls=true"
|
|
||||||
ports:
|
ports:
|
||||||
- "2221:22"
|
- "2221:22"
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^gitea\.forust\.xyz$`)
|
- match: Host(`gitea.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
|
||||||
services:
|
services:
|
||||||
- name: gitea-service
|
- name: gitea-service
|
||||||
port: 3000
|
port: 3000
|
||||||
@@ -24,12 +26,11 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^gitea\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`gitea.workstation.internal`) || Host(`gitea.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: gitea-service
|
- name: gitea-service
|
||||||
port: 3000
|
port: 3000
|
||||||
|
|
||||||
---
|
---
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
+8
-5
@@ -15,19 +15,22 @@ services:
|
|||||||
- "traefik.services.glance.loadbalancer.server.port=8080"
|
- "traefik.services.glance.loadbalancer.server.port=8080"
|
||||||
|
|
||||||
# Prod Router
|
# Prod Router
|
||||||
- "traefik.http.routers.glance.rule=Host(`glance.forust.xyz`)"
|
- "traefik.http.routers.glance.rule=(Host(`forust.xyz`) || Host(`www.forust.xyz`)) && PathPrefix(`/glance`)"
|
||||||
- "traefik.http.routers.glance.entrypoints=websecure"
|
- "traefik.http.routers.glance.entrypoints=websecure"
|
||||||
- "traefik.http.routers.glance.tls=true"
|
- "traefik.http.routers.glance.priority=50"
|
||||||
|
- "traefik.http.routers.glance.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.glance-local.rule=Host(`glance.workstation.internal`)"
|
- "traefik.http.routers.glance-local.rule=Host(`workstation.internal`) && PathPrefix(`/glance`)"
|
||||||
- "traefik.http.routers.glance-local.entrypoints=websecure"
|
- "traefik.http.routers.glance-local.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.glance-local.priority=50"
|
||||||
- "traefik.http.routers.glance-local.tls=true"
|
- "traefik.http.routers.glance-local.tls=true"
|
||||||
# Dev Router
|
# Dev Router
|
||||||
- "traefik.http.routers.glance-dev.rule=Host(`glance.gigaforust.internal`)"
|
- "traefik.http.routers.glance-dev.rule=Host(`gigaforust.internal`) && PathPrefix(`/glance`)"
|
||||||
- "traefik.http.routers.glance-dev.entrypoints=websecure"
|
- "traefik.http.routers.glance-dev.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.glance-dev.priority=50"
|
||||||
- "traefik.http.routers.glance-dev.tls=true"
|
- "traefik.http.routers.glance-dev.tls=true"
|
||||||
networks:
|
networks:
|
||||||
- proxy
|
- proxy
|
||||||
networks:
|
networks:
|
||||||
proxy:
|
proxy:
|
||||||
external: true
|
external: true
|
||||||
|
|||||||
@@ -64,7 +64,6 @@
|
|||||||
name: Apple
|
name: Apple
|
||||||
- symbol: MSFT
|
- symbol: MSFT
|
||||||
name: Microsoft
|
name: Microsoft
|
||||||
|
|
||||||
|
|
||||||
- type: releases
|
- type: releases
|
||||||
cache: 1d
|
cache: 1d
|
||||||
|
|||||||
+11
-13
@@ -1,15 +1,13 @@
|
|||||||
- name: Monitoring
|
- name: Monitoring
|
||||||
columns:
|
columns:
|
||||||
- size: small
|
- size: small
|
||||||
widgets:
|
widgets:
|
||||||
- type: dns-stats
|
- type: dns-stats
|
||||||
service: adguard
|
service: adguard
|
||||||
url: http://adguardhome:3000
|
url: http://adguardhome:3000
|
||||||
username: forust
|
username: forust
|
||||||
password: ${ADGUARD_PASSWORD}
|
password: ${ADGUARD_PASSWORD}
|
||||||
- size: full
|
- size: full
|
||||||
widgets:
|
widgets:
|
||||||
- type: docker-containers
|
- type: docker-containers
|
||||||
hide-by-default: false
|
hide-by-default: false
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ data:
|
|||||||
glance.yml: |
|
glance.yml: |
|
||||||
server:
|
server:
|
||||||
assets-path: /app/assets
|
assets-path: /app/assets
|
||||||
|
proxied: true
|
||||||
|
base-url: /glance
|
||||||
theme:
|
theme:
|
||||||
# Перевели #050505 и #e0e0e0 в формат HSL для Glance
|
# Перевели #050505 и #e0e0e0 в формат HSL для Glance
|
||||||
background-color: 0 0 2 # Истинно черный фон
|
background-color: 0 0 2 # Истинно черный фон
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ spec:
|
|||||||
readOnly: true
|
readOnly: true
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
memory: "10Mi"
|
memory: "30Mi"
|
||||||
cpu: "20m"
|
cpu: "20m"
|
||||||
limits:
|
limits:
|
||||||
memory: "100Mi"
|
memory: "100Mi"
|
||||||
|
|||||||
+17
-5
@@ -7,10 +7,11 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^forust\.xyz$`)
|
- match: (Host(`forust.xyz`) || Host(`www.forust.xyz`)) && PathPrefix(`/glance`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
priority: 50
|
||||||
middlewares:
|
middlewares:
|
||||||
- name: glance-strupprefix
|
- name: glance-stripprefix
|
||||||
services:
|
services:
|
||||||
- name: glance-service
|
- name: glance-service
|
||||||
port: 8080
|
port: 8080
|
||||||
@@ -26,10 +27,21 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^glance\.(workstation|gigaforust)\.internal$`)
|
- match: (Host(`glance.workstation.internal`) || Host(`glance.gigaforust.internal`)) && PathPrefix(`/glance`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: glance-stripprefix
|
||||||
|
priority: 50
|
||||||
services:
|
services:
|
||||||
- name: glance-service
|
- name: glance-service
|
||||||
port: 8080
|
port: 8080
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: Middleware
|
||||||
|
metadata:
|
||||||
|
name: glance-stripprefix
|
||||||
|
namespace: glance
|
||||||
|
spec:
|
||||||
|
stripPrefix:
|
||||||
|
prefixes:
|
||||||
|
- /glance
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ services:
|
|||||||
- "traefik.http.routers.headscale.rule=Host(`hs.forust.xyz`)"
|
- "traefik.http.routers.headscale.rule=Host(`hs.forust.xyz`)"
|
||||||
- "traefik.http.routers.headscale.entrypoints=websecure"
|
- "traefik.http.routers.headscale.entrypoints=websecure"
|
||||||
- "traefik.http.routers.headscale.service=headscale"
|
- "traefik.http.routers.headscale.service=headscale"
|
||||||
- "traefik.http.routers.headscale.tls=true"
|
- "traefik.http.routers.headscale.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.headscale-local.rule=Host(`hs.workstation.internal`)"
|
- "traefik.http.routers.headscale-local.rule=Host(`hs.workstation.internal`)"
|
||||||
- "traefik.http.routers.headscale-local.entrypoints=websecure"
|
- "traefik.http.routers.headscale-local.entrypoints=websecure"
|
||||||
@@ -57,7 +57,7 @@ services:
|
|||||||
container_name: headplane
|
container_name: headplane
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- '13000:3000'
|
- "13000:3000"
|
||||||
volumes:
|
volumes:
|
||||||
- ./config/headplane.yaml:/etc/headplane/config.yaml
|
- ./config/headplane.yaml:/etc/headplane/config.yaml
|
||||||
- ./config/headscale.yaml:/etc/headscale/config.yaml
|
- ./config/headscale.yaml:/etc/headscale/config.yaml
|
||||||
@@ -78,7 +78,7 @@ services:
|
|||||||
- "traefik.http.routers.headscale-ui.rule=Host(`hs.forust.xyz`) && PathPrefix(`/admin`)"
|
- "traefik.http.routers.headscale-ui.rule=Host(`hs.forust.xyz`) && PathPrefix(`/admin`)"
|
||||||
- "traefik.http.routers.headscale-ui.entrypoints=websecure"
|
- "traefik.http.routers.headscale-ui.entrypoints=websecure"
|
||||||
- "traefik.http.routers.headscale-ui.middlewares=security-chain@file"
|
- "traefik.http.routers.headscale-ui.middlewares=security-chain@file"
|
||||||
- "traefik.http.routers.headscale-ui.tls=true"
|
- "traefik.http.routers.headscale-ui.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.headscale-ui-local.rule=Host(`hs.workstation.internal`) && PathPrefix(`/admin`)"
|
- "traefik.http.routers.headscale-ui-local.rule=Host(`hs.workstation.internal`) && PathPrefix(`/admin`)"
|
||||||
- "traefik.http.routers.headscale-ui-local.entrypoints=websecure"
|
- "traefik.http.routers.headscale-ui-local.entrypoints=websecure"
|
||||||
|
|||||||
@@ -33,7 +33,9 @@ derp:
|
|||||||
auto_update_enabled: true
|
auto_update_enabled: true
|
||||||
update_frequency: 24h
|
update_frequency: 24h
|
||||||
disable_check_updates: false
|
disable_check_updates: false
|
||||||
ephemeral_node_inactivity_timeout: 30m
|
node:
|
||||||
|
ephemeral:
|
||||||
|
inactivity_timeout: 30m
|
||||||
database:
|
database:
|
||||||
type: sqlite
|
type: sqlite
|
||||||
debug: false
|
debug: false
|
||||||
@@ -76,4 +78,3 @@ unix_socket: /var/run/headscale/headscale.sock
|
|||||||
unix_socket_permission: "0770"
|
unix_socket_permission: "0770"
|
||||||
logtail:
|
logtail:
|
||||||
enabled: false
|
enabled: false
|
||||||
randomize_client_port: false
|
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
"tagOwners": {},
|
"tagOwners": {},
|
||||||
"hosts": {},
|
"hosts": {},
|
||||||
"acls": [
|
"acls": [
|
||||||
{
|
{
|
||||||
|
"randomizeClientPort": false,
|
||||||
"#ha-meta": {
|
"#ha-meta": {
|
||||||
"name": "users",
|
"name": "users",
|
||||||
"open": true
|
"open": true
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^hs\.forust\.xyz$`)
|
- match: Host(`hs.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-crowdsec-bouncer@kubernetescrd
|
||||||
services:
|
services:
|
||||||
- name: headscale-server-external
|
- name: headscale-server-external
|
||||||
port: 8080
|
port: 8080
|
||||||
@@ -24,7 +26,7 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^hs\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`hs.workstation.internal`) || Host(`hs.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: headscale-server-external
|
- name: headscale-server-external
|
||||||
@@ -40,9 +42,10 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^hs\.forust\.xyz$`) && PathPrefix(`/admin`)
|
- match: Host(`hs.forust.xyz`) && PathPrefix(`/admin`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
middlewares:
|
middlewares:
|
||||||
|
- name: crowdsec-crowdsec-bouncer@kubernetescrd
|
||||||
- name: security-chain@file
|
- name: security-chain@file
|
||||||
services:
|
services:
|
||||||
- name: headscale-ui-external
|
- name: headscale-ui-external
|
||||||
@@ -75,13 +78,17 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^hs\.forust\.xyz$`) && PathPrefix(`/metrics`)
|
- match: Host(`hs.forust.xyz`) && PathPrefix(`/metrics`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-crowdsec-bouncer@kubernetescrd
|
||||||
services:
|
services:
|
||||||
- name: headscale-server-external
|
- name: headscale-server-external
|
||||||
port: 9090
|
port: 9090
|
||||||
tls:
|
tls:
|
||||||
certResolver: letsencrypt
|
certResolver: letsencrypt
|
||||||
|
domains:
|
||||||
|
- main: hs.forust.xyz
|
||||||
---
|
---
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
@@ -97,5 +104,3 @@ spec:
|
|||||||
services:
|
services:
|
||||||
- name: headscale-server-external
|
- name: headscale-server-external
|
||||||
port: 9090
|
port: 9090
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,14 +19,17 @@ services:
|
|||||||
# Prod Router
|
# Prod Router
|
||||||
- "traefik.http.routers.forust-homepage.rule=Host(`forust.xyz`) || Host(`www.forust.xyz`)"
|
- "traefik.http.routers.forust-homepage.rule=Host(`forust.xyz`) || Host(`www.forust.xyz`)"
|
||||||
- "traefik.http.routers.forust-homepage.entrypoints=websecure"
|
- "traefik.http.routers.forust-homepage.entrypoints=websecure"
|
||||||
- "traefik.http.routers.forust-homepage.tls=true"
|
- "traefik.http.routers.forust-homepage.priority=10"
|
||||||
|
- "traefik.http.routers.forust-homepage.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.forust-homepage-local.rule=Host(`landing.workstation.internal`)"
|
- "traefik.http.routers.forust-homepage-local.rule=Host(`landing.workstation.internal`)"
|
||||||
- "traefik.http.routers.forust-homepage-local.entrypoints=websecure"
|
- "traefik.http.routers.forust-homepage-local.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.forust-homepage-local.priority=10"
|
||||||
- "traefik.http.routers.forust-homepage-local.tls=true"
|
- "traefik.http.routers.forust-homepage-local.tls=true"
|
||||||
# Dev Router
|
# Dev Router
|
||||||
- "traefik.http.routers.forust-homepage-dev.rule=Host(`landing.gigaforust.internal`)"
|
- "traefik.http.routers.forust-homepage-dev.rule=Host(`landing.gigaforust.internal`)"
|
||||||
- "traefik.http.routers.forust-homepage-dev.entrypoints=websecure"
|
- "traefik.http.routers.forust-homepage-dev.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.forust-homepage-dev.priority=10"
|
||||||
- "traefik.http.routers.forust-homepage-dev.tls=true"
|
- "traefik.http.routers.forust-homepage-dev.tls=true"
|
||||||
xdfnx:
|
xdfnx:
|
||||||
build:
|
build:
|
||||||
@@ -47,7 +50,6 @@ services:
|
|||||||
- "traefik.http.routers.xdfnx.rule=Host(`xdfnx.cfd`) || Host(`www.xdfnx.cfd`)"
|
- "traefik.http.routers.xdfnx.rule=Host(`xdfnx.cfd`) || Host(`www.xdfnx.cfd`)"
|
||||||
- "traefik.http.routers.xdfnx.entrypoints=websecure"
|
- "traefik.http.routers.xdfnx.entrypoints=websecure"
|
||||||
- "traefik.http.routers.xdfnx.tls.certresolver=letsencrypt"
|
- "traefik.http.routers.xdfnx.tls.certresolver=letsencrypt"
|
||||||
- "traefik.http.routers.xdfnx.tls=true"
|
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.xdfnx-local.rule=Host(`xdfnx.workstation.internal`)"
|
- "traefik.http.routers.xdfnx-local.rule=Host(`xdfnx.workstation.internal`)"
|
||||||
- "traefik.http.routers.xdfnx-local.entrypoints=websecure"
|
- "traefik.http.routers.xdfnx-local.entrypoints=websecure"
|
||||||
|
|||||||
@@ -20,49 +20,61 @@
|
|||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<section id="socials">
|
<div class="grid-2">
|
||||||
<h2>./socials</h2>
|
<section id="socials">
|
||||||
<ul class="link-list">
|
<h2>./socials</h2>
|
||||||
<li>
|
<ul class="link-list">
|
||||||
<i class="fab fa-github"></i>
|
<li>
|
||||||
<a href="https://github.com/mr-forust" target="_blank">github/mr-forust</a>
|
<i class="fab fa-github"></i>
|
||||||
</li>
|
<a href="https://github.com/mr-forust" target="_blank">github/mr-forust</a>
|
||||||
<li>
|
</li>
|
||||||
<i class="fas fa-flag"></i>
|
<li>
|
||||||
<a href="https://tryhackme.com/p/MrForust" target="_blank">tryhackme/MrForust</a>
|
<i class="fas fa-flag"></i>
|
||||||
</li>
|
<a href="https://tryhackme.com/p/MrForust" target="_blank">tryhackme/MrForust</a>
|
||||||
<li>
|
</li>
|
||||||
<i class="fab fa-telegram-plane"></i>
|
<li>
|
||||||
<a href="https://t.me/MrForust" target="_blank">telegram/MrForust</a>
|
<i class="fab fa-telegram-plane"></i>
|
||||||
</li>
|
<a href="https://t.me/MrForust" target="_blank">telegram/MrForust</a>
|
||||||
<li>
|
</li>
|
||||||
<i class="fab fa-discord"></i>
|
<li>
|
||||||
<span>discord/mr.forust</span>
|
<i class="fab fa-discord"></i>
|
||||||
</li>
|
<span>discord/mr.forust</span>
|
||||||
<li>
|
</li>
|
||||||
<i class="fas fa-envelope"></i>
|
<li>
|
||||||
<a href="mailto:contact@forust.xyz">mail/contact@forust.xyz</a>
|
<i class="fas fa-envelope"></i>
|
||||||
</li>
|
<a href="mailto:contact@forust.xyz">mail/contact@forust.xyz</a>
|
||||||
<li>
|
</li>
|
||||||
<i class="fa fa-pie-chart"></i>
|
<li>
|
||||||
<a href="https://forust.xyz/glance">forust/dashboard</a>
|
<i class="fa-solid fa-key"></i>
|
||||||
</li>
|
<a href=".well-known/pgp-key.asc">security/PGP Key</a>
|
||||||
<li>
|
</li>
|
||||||
<i class="fa fa-refresh"></i>
|
<li>
|
||||||
<a href="https://forust.xyz/convert">forust/converter</a>
|
<p class="comment"># PGP Key Fingerprint: A777 7CB7 D9C4 0A97 443D CCF0 7A3D A455 F820 5B82</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
</ul>
|
||||||
<i class="fa-solid fa-key"></i>
|
</section>
|
||||||
<a href=".well-known/pgp-key.asc">security/PGP Key</a>
|
|
||||||
</li>
|
<section id="tools">
|
||||||
<li>
|
<h2>./tools</h2>
|
||||||
<p class="comment"># PGP Key Fingerprint: A777 7CB7 D9C4 0A97 443D CCF0 7A3D A455 F820 5B82</p>
|
<ul class="link-list">
|
||||||
</li>
|
<li>
|
||||||
</ul>
|
<i class="fa fa-pie-chart"></i>
|
||||||
</section>
|
<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>
|
||||||
|
|
||||||
<section id="stack">
|
<section id="stack">
|
||||||
<h2>./skills_and_tools</h2>
|
<h2>./skills</h2>
|
||||||
<div class="grid-2">
|
<div class="grid-2">
|
||||||
<div>
|
<div>
|
||||||
<div class="skill-item">
|
<div class="skill-item">
|
||||||
@@ -168,6 +180,10 @@
|
|||||||
<a href="https://github.com/unhappychoice/gitlogue" target="_blank">unhappychoice/gitlogue</a>
|
<a href="https://github.com/unhappychoice/gitlogue" target="_blank">unhappychoice/gitlogue</a>
|
||||||
<span class="comment">// nice git log visualizer</span>
|
<span class="comment">// nice git log visualizer</span>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://github.com/tstack/lnav" target="_blank">tstack/lnav</a>
|
||||||
|
<span class="comment">// powerful log reader</span>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://github.com/mountain-loop/yaak" target="_blank">mountain-loop/yaak</a>
|
<a href="https://github.com/mountain-loop/yaak" target="_blank">mountain-loop/yaak</a>
|
||||||
<span class="comment">// modern, fancy api client</span>
|
<span class="comment">// modern, fancy api client</span>
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ spec:
|
|||||||
containers:
|
containers:
|
||||||
- name: forust-homepage
|
- name: forust-homepage
|
||||||
image: gcr.forust.xyz/forust/forust-homepage:latest
|
image: gcr.forust.xyz/forust/forust-homepage:latest
|
||||||
|
imagePullPolicy: Always
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 80
|
- containerPort: 80
|
||||||
resources:
|
resources:
|
||||||
@@ -68,6 +69,7 @@ spec:
|
|||||||
containers:
|
containers:
|
||||||
- name: xdfnx-homepage
|
- name: xdfnx-homepage
|
||||||
image: gcr.forust.xyz/forust/xdfnx-homepage:latest
|
image: gcr.forust.xyz/forust/xdfnx-homepage:latest
|
||||||
|
imagePullPolicy: Always
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 80
|
- containerPort: 80
|
||||||
resources:
|
resources:
|
||||||
|
|||||||
@@ -7,8 +7,11 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^(forust\.xyz|www\.forust\.xyz)$`)
|
- match: Host(`forust.xyz`) || Host(`www.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-crowdsec-bouncer@kubernetescrd
|
||||||
|
priority: 10
|
||||||
services:
|
services:
|
||||||
- name: forust-homepage-service
|
- name: forust-homepage-service
|
||||||
port: 80
|
port: 80
|
||||||
@@ -24,8 +27,9 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^landing\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`landing.workstation.internal`) || Host(`landing.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
priority: 10
|
||||||
services:
|
services:
|
||||||
- name: forust-homepage-service
|
- name: forust-homepage-service
|
||||||
port: 80
|
port: 80
|
||||||
@@ -39,8 +43,10 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^(xdfnx\.cfd|www\.xdfnx\.cfd)$`)
|
- match: Host(`xdfnx.cfd`) || Host(`www.xdfnx.cfd`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-crowdsec-bouncer@kubernetescrd
|
||||||
services:
|
services:
|
||||||
- name: xdfnx-homepage-service
|
- name: xdfnx-homepage-service
|
||||||
port: 80
|
port: 80
|
||||||
@@ -56,9 +62,8 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^xdfnx\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`xdfnx.workstation.internal`) || Host(`xdfnx.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: xdfnx-homepage-service
|
- name: xdfnx-homepage-service
|
||||||
port: 80
|
port: 80
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -23,7 +23,7 @@ services:
|
|||||||
# Prod Router
|
# Prod Router
|
||||||
- "traefik.http.routers.kener.rule=Host(`status.forust.xyz`)"
|
- "traefik.http.routers.kener.rule=Host(`status.forust.xyz`)"
|
||||||
- "traefik.http.routers.kener.entrypoints=websecure"
|
- "traefik.http.routers.kener.entrypoints=websecure"
|
||||||
- "traefik.http.routers.kener.tls=true"
|
- "traefik.http.routers.kener.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.kener-local.rule=Host(`status.workstation.internal`)"
|
- "traefik.http.routers.kener-local.rule=Host(`status.workstation.internal`)"
|
||||||
- "traefik.http.routers.kener-local.entrypoints=websecure"
|
- "traefik.http.routers.kener-local.entrypoints=websecure"
|
||||||
@@ -42,7 +42,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- redis:/data
|
- redis:/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: [ "CMD", "redis-cli", "ping" ]
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
interval: 6s
|
interval: 6s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^status\.forust\.xyz$`)
|
- match: Host(`status.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-crowdsec-bouncer@kubernetescrd
|
||||||
services:
|
services:
|
||||||
- name: kener-service
|
- name: kener-service
|
||||||
port: 3000
|
port: 3000
|
||||||
@@ -24,9 +26,8 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^status\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`status.workstation.internal`) || Host(`status.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: kener-service
|
- name: kener-service
|
||||||
port: 3000
|
port: 3000
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: kener
|
- name: kener
|
||||||
image: rajnandan1/kener:4.0.23
|
image: rajnandan1/kener:4.1.0
|
||||||
envFrom:
|
envFrom:
|
||||||
- configMapRef:
|
- configMapRef:
|
||||||
name: kener-config
|
name: kener-config
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ services:
|
|||||||
- "traefik.http.routers.metube.rule=Host(`metube.forust.xyz`)"
|
- "traefik.http.routers.metube.rule=Host(`metube.forust.xyz`)"
|
||||||
- "traefik.http.routers.metube.entrypoints=websecure"
|
- "traefik.http.routers.metube.entrypoints=websecure"
|
||||||
- "traefik.http.routers.metube.middlewares=security-chain@file"
|
- "traefik.http.routers.metube.middlewares=security-chain@file"
|
||||||
- "traefik.http.routers.metube.tls=true"
|
- "traefik.http.routers.metube.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.metube-local.rule=Host(`metube.workstation.internal`)"
|
- "traefik.http.routers.metube-local.rule=Host(`metube.workstation.internal`)"
|
||||||
- "traefik.http.routers.metube-local.entrypoints=websecure"
|
- "traefik.http.routers.metube-local.entrypoints=websecure"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^metube\.forust\.xyz$`)
|
- match: Host(`metube.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
middlewares:
|
middlewares:
|
||||||
- name: security-headers@file
|
- name: security-headers@file
|
||||||
@@ -26,9 +26,8 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^metube\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`metube.workstation.internal`) || Host(`metube.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: metube-service
|
- name: metube-service
|
||||||
port: 8081
|
port: 8081
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -32,7 +32,7 @@ services:
|
|||||||
# Prod Router
|
# Prod Router
|
||||||
- "traefik.http.routers.n8n.rule=Host(`n8n.forust.xyz`)"
|
- "traefik.http.routers.n8n.rule=Host(`n8n.forust.xyz`)"
|
||||||
- "traefik.http.routers.n8n.entrypoints=websecure"
|
- "traefik.http.routers.n8n.entrypoints=websecure"
|
||||||
- "traefik.http.routers.n8n.tls=true"
|
- "traefik.http.routers.n8n.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.n8n-local.rule=Host(`n8n.workstation.internal`)"
|
- "traefik.http.routers.n8n-local.rule=Host(`n8n.workstation.internal`)"
|
||||||
- "traefik.http.routers.n8n-local.entrypoints=websecure"
|
- "traefik.http.routers.n8n-local.entrypoints=websecure"
|
||||||
@@ -54,4 +54,4 @@ networks:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
node-data:
|
node-data:
|
||||||
files:
|
files:
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^n8n\.forust\.xyz$`)
|
- match: Host(`n8n.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
|
||||||
services:
|
services:
|
||||||
- name: n8n-service
|
- name: n8n-service
|
||||||
port: 5678
|
port: 5678
|
||||||
@@ -24,9 +26,8 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^n8n\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`n8n.workstation.internal`) || Host(`n8n.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: n8n-service
|
- name: n8n-service
|
||||||
port: 5678
|
port: 5678
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ services:
|
|||||||
# Prod Router
|
# Prod Router
|
||||||
- "traefik.http.routers.netronome.rule=Host(`nm.forust.xyz`)"
|
- "traefik.http.routers.netronome.rule=Host(`nm.forust.xyz`)"
|
||||||
- "traefik.http.routers.netronome.entrypoints=websecure"
|
- "traefik.http.routers.netronome.entrypoints=websecure"
|
||||||
- "traefik.http.routers.netronome.tls=true"
|
- "traefik.http.routers.netronome.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.netronome-local.rule=Host(`nm.workstation.internal`)"
|
- "traefik.http.routers.netronome-local.rule=Host(`nm.workstation.internal`)"
|
||||||
- "traefik.http.routers.netronome-local.entrypoints=websecure"
|
- "traefik.http.routers.netronome-local.entrypoints=websecure"
|
||||||
@@ -41,7 +41,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- data:/var/lib/postgresql/data
|
- data:/var/lib/postgresql/data
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: [ "CMD-SHELL", "pg_isready -U netronome" ]
|
test: ["CMD-SHELL", "pg_isready -U netronome"]
|
||||||
interval: 5s
|
interval: 5s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
@@ -51,7 +51,6 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
data:
|
data:
|
||||||
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
proxy:
|
proxy:
|
||||||
external: true
|
external: true
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^nm\.forust\.xyz$`)
|
- match: Host(`nm.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
|
||||||
services:
|
services:
|
||||||
- name: netronome-service
|
- name: netronome-service
|
||||||
port: 7575
|
port: 7575
|
||||||
@@ -24,9 +26,8 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^nm\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`nm.workstation.internal`) || Host(`nm.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: netronome-service
|
- name: netronome-service
|
||||||
port: 7575
|
port: 7575
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
container_name: nextcloud-aio-mastercontainer # Do not change
|
container_name: nextcloud-aio-mastercontainer # Do not change
|
||||||
volumes:
|
volumes:
|
||||||
- nextcloud_aio_mastercontainer:/mnt/docker-aio-config # Do not change (backup)
|
- nextcloud_aio_mastercontainer:/mnt/docker-aio-config # Do not change (backup)
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
- /dev/dri:/dev/dri
|
- /dev/dri:/dev/dri
|
||||||
ports:
|
ports:
|
||||||
@@ -25,7 +25,7 @@ services:
|
|||||||
# - "traefik.http.routers.nextcloud-aio.rule=Host(`naio.forust.xyz`)"
|
# - "traefik.http.routers.nextcloud-aio.rule=Host(`naio.forust.xyz`)"
|
||||||
# - "traefik.http.routers.nextcloud-aio.entrypoints=websecure"
|
# - "traefik.http.routers.nextcloud-aio.entrypoints=websecure"
|
||||||
# - "traefik.http.routers.nextcloud-aio.middlewares=security-chain@file"
|
# - "traefik.http.routers.nextcloud-aio.middlewares=security-chain@file"
|
||||||
# - "traefik.http.routers.nextcloud-aio.tls=true"
|
# - "traefik.http.routers.nextcloud-aio.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.nextcloud-aio-local.rule=Host(`naio.workstation.internal`)"
|
- "traefik.http.routers.nextcloud-aio-local.rule=Host(`naio.workstation.internal`)"
|
||||||
- "traefik.http.routers.nextcloud-aio-local.entrypoints=websecure"
|
- "traefik.http.routers.nextcloud-aio-local.entrypoints=websecure"
|
||||||
|
|||||||
+24
-24
@@ -8,10 +8,11 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^nextcloud\.forust\.xyz$`)
|
- match: Host(`nextcloud.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
middlewares:
|
middlewares:
|
||||||
- name: nextcloud-chain@file
|
- name: nextcloud-chain@file
|
||||||
|
- name: crowdsec-crowdsec-bouncer@kubernetescrd
|
||||||
services:
|
services:
|
||||||
- name: nextcloud-apache
|
- name: nextcloud-apache
|
||||||
port: 11000
|
port: 11000
|
||||||
@@ -27,34 +28,34 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^nextcloud\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`nextcloud.workstation.internal`) || Host(`nextcloud.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
middlewares:
|
middlewares:
|
||||||
|
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
|
||||||
- name: nextcloud-chain@file
|
- name: nextcloud-chain@file
|
||||||
services:
|
services:
|
||||||
- name: nextcloud-apache
|
- name: nextcloud-apache
|
||||||
port: 11000
|
port: 11000
|
||||||
|
# ---
|
||||||
---
|
|
||||||
# Nextcloud AIO
|
# Nextcloud AIO
|
||||||
apiVersion: traefik.io/v1alpha1
|
# apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
# kind: IngressRoute
|
||||||
metadata:
|
# metadata:
|
||||||
name: naio-prod
|
# name: naio-prod
|
||||||
namespace: nextcloud
|
# namespace: nextcloud
|
||||||
spec:
|
# spec:
|
||||||
entryPoints:
|
# entryPoints:
|
||||||
- websecure
|
# - websecure
|
||||||
routes:
|
# routes:
|
||||||
- match: HostRegexp(`^naio\.forust\.xyz$`)
|
# - match: Host(`naio.forust.xyz`)
|
||||||
kind: Rule
|
# kind: Rule
|
||||||
services:
|
# services:
|
||||||
- name: nextcloud-aio
|
# - name: nextcloud-aio
|
||||||
port: 8888
|
# port: 8888
|
||||||
scheme: https
|
# scheme: https
|
||||||
serversTransport: insecure-transport # <-- Ссылка на ваш CRD ресурс вместо @file
|
# serversTransport: insecure-transport
|
||||||
tls:
|
# tls:
|
||||||
certResolver: letsencrypt
|
# certResolver: letsencrypt
|
||||||
---
|
---
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
@@ -65,11 +66,10 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^naio\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`naio.workstation.internal`) || Host(`naio.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: nextcloud-aio
|
- name: nextcloud-aio
|
||||||
port: 8888
|
port: 8888
|
||||||
scheme: https
|
scheme: https
|
||||||
serversTransport: insecure-transport
|
serversTransport: insecure-transport
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -107,7 +107,7 @@ services:
|
|||||||
# Prod Router
|
# Prod Router
|
||||||
- "traefik.http.routers.penpot.rule=Host(`penpot.forust.xyz`)"
|
- "traefik.http.routers.penpot.rule=Host(`penpot.forust.xyz`)"
|
||||||
- "traefik.http.routers.penpot.entrypoints=websecure"
|
- "traefik.http.routers.penpot.entrypoints=websecure"
|
||||||
- "traefik.http.routers.penpot.tls=true"
|
- "traefik.http.routers.penpot.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.penpot-local.rule=Host(`penpot.workstation.internal`)"
|
- "traefik.http.routers.penpot-local.rule=Host(`penpot.workstation.internal`)"
|
||||||
- "traefik.http.routers.penpot-local.entrypoints=websecure"
|
- "traefik.http.routers.penpot-local.entrypoints=websecure"
|
||||||
@@ -117,7 +117,7 @@ services:
|
|||||||
- "traefik.http.routers.penpot-dev.entrypoints=websecure"
|
- "traefik.http.routers.penpot-dev.entrypoints=websecure"
|
||||||
- "traefik.http.routers.penpot-dev.tls=true"
|
- "traefik.http.routers.penpot-dev.tls=true"
|
||||||
environment:
|
environment:
|
||||||
<<: [ *penpot-flags, *penpot-http-body-size ]
|
<<: [*penpot-flags, *penpot-http-body-size]
|
||||||
penpot-backend:
|
penpot-backend:
|
||||||
image: "penpotapp/backend:${PENPOT_VERSION:-latest}"
|
image: "penpotapp/backend:${PENPOT_VERSION:-latest}"
|
||||||
restart: always
|
restart: always
|
||||||
@@ -137,7 +137,7 @@ services:
|
|||||||
## Configuration envronment variables for the backend container.
|
## Configuration envronment variables for the backend container.
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
<<: [ *penpot-flags, *penpot-public-uri, *penpot-http-body-size, *penpot-secret-key ]
|
<<: [*penpot-flags, *penpot-public-uri, *penpot-http-body-size, *penpot-secret-key]
|
||||||
|
|
||||||
## The PREPL host. Mainly used for external programatic access to penpot backend
|
## The PREPL host. Mainly used for external programatic access to penpot backend
|
||||||
## (example: admin). By default it will listen on `localhost` but if you are going to use
|
## (example: admin). By default it will listen on `localhost` but if you are going to use
|
||||||
@@ -200,7 +200,7 @@ services:
|
|||||||
- penpot
|
- penpot
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
<<: [ *penpot-secret-key ]
|
<<: [*penpot-secret-key]
|
||||||
# Don't touch it; this uses an internal docker network to
|
# Don't touch it; this uses an internal docker network to
|
||||||
# communicate with the frontend.
|
# communicate with the frontend.
|
||||||
PENPOT_PUBLIC_URI: http://penpot-frontend:8080
|
PENPOT_PUBLIC_URI: http://penpot-frontend:8080
|
||||||
@@ -214,7 +214,7 @@ services:
|
|||||||
stop_signal: SIGINT
|
stop_signal: SIGINT
|
||||||
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: [ "CMD-SHELL", "pg_isready -U penpot" ]
|
test: ["CMD-SHELL", "pg_isready -U penpot"]
|
||||||
interval: 2s
|
interval: 2s
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
retries: 5
|
retries: 5
|
||||||
@@ -237,7 +237,7 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: [ "CMD-SHELL", "valkey-cli ping | grep PONG" ]
|
test: ["CMD-SHELL", "valkey-cli ping | grep PONG"]
|
||||||
interval: 1s
|
interval: 1s
|
||||||
timeout: 3s
|
timeout: 3s
|
||||||
retries: 5
|
retries: 5
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ services:
|
|||||||
# Prod Router
|
# Prod Router
|
||||||
- "traefik.http.routers.portainer.rule=Host(`portainer.forust.xyz`)"
|
- "traefik.http.routers.portainer.rule=Host(`portainer.forust.xyz`)"
|
||||||
- "traefik.http.routers.portainer.entrypoints=websecure"
|
- "traefik.http.routers.portainer.entrypoints=websecure"
|
||||||
- "traefik.http.routers.portainer.tls=true"
|
- "traefik.http.routers.portainer.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.portainer-local.rule=Host(`portainer.workstation.internal`)"
|
- "traefik.http.routers.portainer-local.rule=Host(`portainer.workstation.internal`)"
|
||||||
- "traefik.http.routers.portainer-local.entrypoints=websecure"
|
- "traefik.http.routers.portainer-local.entrypoints=websecure"
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^portainer\.forust\.xyz$`)
|
- match: Host(`portainer.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
|
||||||
services:
|
services:
|
||||||
- name: portainer-service
|
- name: portainer-service
|
||||||
port: 9000
|
port: 9000
|
||||||
@@ -24,9 +26,8 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^portainer\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`portainer.workstation.internal`) || Host(`portainer.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: portainer-service
|
- name: portainer-service
|
||||||
port: 9000
|
port: 9000
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
GRAFANA_ADMIN_USER=admin
|
||||||
|
GRAFANA_ADMIN_PASSWORD=changeme
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
route:
|
||||||
|
receiver: default
|
||||||
|
|
||||||
|
receivers:
|
||||||
|
- name: default
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
services:
|
||||||
|
grafana:
|
||||||
|
image: grafana/grafana:11.6.0
|
||||||
|
container_name: prometheus-grafana
|
||||||
|
restart: unless-stopped
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
environment:
|
||||||
|
GF_SECURITY_ADMIN_USER: ${GRAFANA_ADMIN_USER:-admin}
|
||||||
|
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD:?grafana admin password required}
|
||||||
|
volumes:
|
||||||
|
- grafana-data:/var/lib/grafana
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.services.prometheus-grafana.loadbalancer.server.port=3000"
|
||||||
|
|
||||||
|
# Prod Router
|
||||||
|
- "traefik.http.routers.grafana.rule=Host(`grafana.forust.xyz`)"
|
||||||
|
- "traefik.http.routers.grafana.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.grafana.tls=true"
|
||||||
|
# Local Router
|
||||||
|
- "traefik.http.routers.grafana-local.rule=Host(`grafana.workstation.internal`)"
|
||||||
|
- "traefik.http.routers.grafana-local.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.grafana-local.tls=true"
|
||||||
|
# Dev Router
|
||||||
|
- "traefik.http.routers.grafana-dev.rule=Host(`grafana.gigaforust.internal`)"
|
||||||
|
- "traefik.http.routers.grafana-dev.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.grafana-dev.tls=true"
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
|
||||||
|
prometheus:
|
||||||
|
image: prom/prometheus:v3.2.1
|
||||||
|
container_name: prometheus-prometheus
|
||||||
|
restart: unless-stopped
|
||||||
|
command:
|
||||||
|
- "--config.file=/etc/prometheus/prometheus.yaml"
|
||||||
|
- "--storage.tsdb.path=/prometheus"
|
||||||
|
- "--storage.tsdb.retention.time=90d"
|
||||||
|
volumes:
|
||||||
|
- prometheus-data:/prometheus
|
||||||
|
- ./prometheus.yaml:/etc/prometheus/prometheus.yaml:ro
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
|
||||||
|
alertmanager:
|
||||||
|
image: prom/alertmanager:v0.28.1
|
||||||
|
container_name: prometheus-alertmanager
|
||||||
|
restart: unless-stopped
|
||||||
|
command:
|
||||||
|
- "--config.file=/etc/alertmanager/alertmanager.yaml"
|
||||||
|
- "--storage.path=/alertmanager"
|
||||||
|
volumes:
|
||||||
|
- alertmanager-data:/alertmanager
|
||||||
|
- ./alertmanager.yaml:/etc/alertmanager/alertmanager.yaml:ro
|
||||||
|
networks:
|
||||||
|
- proxy
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
grafana-data:
|
||||||
|
prometheus-data:
|
||||||
|
alertmanager-data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
grafana:
|
||||||
|
grafana.ini:
|
||||||
|
server:
|
||||||
|
domain: grafana.forust.xyz
|
||||||
|
root_url: https://grafana.forust.xyz
|
||||||
|
auth.anonymous:
|
||||||
|
enabled: false
|
||||||
|
users:
|
||||||
|
allow_sign_up: false
|
||||||
|
admin:
|
||||||
|
existingSecret: grafana-admin
|
||||||
|
userKey: admin-user
|
||||||
|
passwordKey: admin-password
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
size: 10Gi
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
service:
|
||||||
|
port: 80
|
||||||
|
|
||||||
|
prometheus:
|
||||||
|
prometheusSpec:
|
||||||
|
storageSpec:
|
||||||
|
volumeClaimTemplate:
|
||||||
|
spec:
|
||||||
|
storageClassName: "local-path"
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 40Gi
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "700Mi"
|
||||||
|
cpu: 200m
|
||||||
|
limits:
|
||||||
|
memory: "2Gi"
|
||||||
|
alertmanager:
|
||||||
|
alertmanagerSpec:
|
||||||
|
storage:
|
||||||
|
volumeClaimTemplate:
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 20Gi
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: grafana-prod
|
||||||
|
namespace: prometheus
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`grafana.forust.xyz`)
|
||||||
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
|
||||||
|
- name: "security-chain@file"
|
||||||
|
services:
|
||||||
|
- name: prometheus-stack-grafana
|
||||||
|
port: 80
|
||||||
|
tls:
|
||||||
|
certResolver: letsencrypt
|
||||||
|
domains:
|
||||||
|
- main: grafana.forust.xyz
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: grafana-local
|
||||||
|
namespace: prometheus
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`grafana.workstation.internal`) || Host(`grafana.gigaforust.internal`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
- name: prometheus-stack-grafana
|
||||||
|
port: 80
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: prometheus
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: grafana-admin
|
||||||
|
namespace: prometheus
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
admin-user: "admin"
|
||||||
|
admin-password: ""
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
global:
|
||||||
|
scrape_interval: 15s
|
||||||
|
evaluation_interval: 15s
|
||||||
|
|
||||||
|
scrape_configs:
|
||||||
|
- job_name: prometheus
|
||||||
|
static_configs:
|
||||||
|
- targets: ["localhost:9090"]
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
target-version = "py311"
|
||||||
|
line-length = 120
|
||||||
|
|
||||||
|
[lint]
|
||||||
|
select = ["E", "F", "W", "I", "N", "UP", "S", "B", "A", "C4", "SIM", "ARG"]
|
||||||
|
ignore = ["E501", "S101"]
|
||||||
|
|
||||||
|
[format]
|
||||||
|
quote-style = "single"
|
||||||
|
indent-style = "space"
|
||||||
|
line-ending = "lf"
|
||||||
@@ -6,15 +6,15 @@ services:
|
|||||||
image: docker.io/searxng/searxng:${SEARXNG_VERSION:-latest}
|
image: docker.io/searxng/searxng:${SEARXNG_VERSION:-latest}
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# ports:
|
# ports:
|
||||||
# - ${SEARXNG_PORT:-8080}
|
# - ${SEARXNG_PORT:-8080}
|
||||||
env_file: .env
|
env_file: .env
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=true"
|
- "traefik.enable=true"
|
||||||
- "traefik.http.services.searxng.loadbalancer.server.port=8080"
|
- "traefik.http.services.searxng.loadbalancer.server.port=8080"
|
||||||
# Prod Router
|
# Prod Router
|
||||||
- "traefik.http.routers.searxng.rule=Host(`s.forust.xyz` || `searxng.forust.xyz`)"
|
- "traefik.http.routers.searxng.rule=Host(`s.forust.xyz` || `search.forust.xyz`)"
|
||||||
- "traefik.http.routers.searxng.entrypoints=websecure"
|
- "traefik.http.routers.searxng.entrypoints=websecure"
|
||||||
- "traefik.http.routers.searxng.tls=true"
|
- "traefik.http.routers.searxng.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.searxng-local.rule=Host(`s.workstation.internal` || `searxng.workstation.internal`)"
|
- "traefik.http.routers.searxng-local.rule=Host(`s.workstation.internal` || `searxng.workstation.internal`)"
|
||||||
- "traefik.http.routers.searxng-local.entrypoints=websecure"
|
- "traefik.http.routers.searxng-local.entrypoints=websecure"
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^(s|searxng)\.forust\.xyz$`)
|
- match: Host(`s.forust.xyz`) || Host(`search.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
|
||||||
services:
|
services:
|
||||||
- name: searxng-service
|
- name: searxng-service
|
||||||
port: 8080
|
port: 8080
|
||||||
@@ -24,9 +26,8 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^(s|searxng)\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`s.workstation.internal`) || Host(`searxng.workstation.internal`) || Host(`s.gigaforust.internal`) || Host(`searxng.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: searxng-service
|
- name: searxng-service
|
||||||
port: 8080
|
port: 8080
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -16,7 +16,7 @@ services:
|
|||||||
# Prod Router
|
# Prod Router
|
||||||
- "traefik.http.routers.termix.rule=Host(`termix.forust.xyz`)"
|
- "traefik.http.routers.termix.rule=Host(`termix.forust.xyz`)"
|
||||||
- "traefik.http.routers.termix.entrypoints=websecure"
|
- "traefik.http.routers.termix.entrypoints=websecure"
|
||||||
- "traefik.http.routers.termix.tls=true"
|
- "traefik.http.routers.termix.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.termix-local.rule=Host(`termix.workstation.internal`)"
|
- "traefik.http.routers.termix-local.rule=Host(`termix.workstation.internal`)"
|
||||||
- "traefik.http.routers.termix-local.entrypoints=websecure"
|
- "traefik.http.routers.termix-local.entrypoints=websecure"
|
||||||
@@ -31,4 +31,4 @@ networks:
|
|||||||
proxy:
|
proxy:
|
||||||
external: true
|
external: true
|
||||||
volumes:
|
volumes:
|
||||||
data:
|
data:
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^termix\.forust\.xyz$`)
|
- match: Host(`termix.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
|
||||||
services:
|
services:
|
||||||
- name: termix-service
|
- name: termix-service
|
||||||
port: 8080
|
port: 8080
|
||||||
@@ -24,9 +26,8 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^termix\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`termix.workstation.internal`) || Host(`termix.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: termix-service
|
- name: termix-service
|
||||||
port: 8080
|
port: 8080
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ services:
|
|||||||
# # STAGING
|
# # STAGING
|
||||||
# - "--certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
|
# - "--certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||||
|
|
||||||
# Cloudflare
|
# Cloudflare
|
||||||
- "--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"
|
- "--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"
|
||||||
- "--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"
|
- "--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"
|
||||||
# Logging
|
# Logging
|
||||||
@@ -49,7 +49,7 @@ services:
|
|||||||
- "traefik.http.routers.traefik-dashboard.entrypoints=websecure"
|
- "traefik.http.routers.traefik-dashboard.entrypoints=websecure"
|
||||||
- "traefik.http.routers.traefik-dashboard.middlewares=security-chain@file"
|
- "traefik.http.routers.traefik-dashboard.middlewares=security-chain@file"
|
||||||
- "traefik.http.routers.traefik-dashboard.service=api@internal"
|
- "traefik.http.routers.traefik-dashboard.service=api@internal"
|
||||||
- "traefik.http.routers.traefik-dashboard.tls=true"
|
- "traefik.http.routers.traefik-dashboard.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.traefik-dashboard-local.rule=Host(`traefik.workstation.internal`)"
|
- "traefik.http.routers.traefik-dashboard-local.rule=Host(`traefik.workstation.internal`)"
|
||||||
- "traefik.http.routers.traefik-dashboard-local.entrypoints=websecure"
|
- "traefik.http.routers.traefik-dashboard-local.entrypoints=websecure"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
http:
|
http:
|
||||||
serversTransports:
|
serversTransports:
|
||||||
insecureTransport:
|
insecureTransport:
|
||||||
insecureSkipVerify: true
|
insecureSkipVerify: true
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ http:
|
|||||||
service: nextcloud
|
service: nextcloud
|
||||||
middlewares:
|
middlewares:
|
||||||
- nextcloud-chain
|
- nextcloud-chain
|
||||||
tls: {}
|
tls:
|
||||||
|
certresolver: letsencrypt
|
||||||
|
|
||||||
# Nextcloud dev
|
# Nextcloud dev
|
||||||
nextcloud-local:
|
nextcloud-local:
|
||||||
|
|||||||
@@ -8,8 +8,10 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^traefik\.forust\.xyz$`)
|
- match: Host(`traefik.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: "crowdsec-crowdsec-bouncer@kubernetescrd"
|
||||||
services:
|
services:
|
||||||
- name: api@internal
|
- name: api@internal
|
||||||
kind: TraefikService
|
kind: TraefikService
|
||||||
@@ -25,9 +27,8 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^traefik\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`traefik.workstation.internal`) || Host(`traefik.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: api@internal
|
- name: api@internal
|
||||||
kind: TraefikService
|
kind: TraefikService
|
||||||
|
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ data:
|
|||||||
- security-headers@file
|
- security-headers@file
|
||||||
authentik:
|
authentik:
|
||||||
forwardAuth:
|
forwardAuth:
|
||||||
address: "http://authentik-server:9000/outpost.goauthentik.io/auth/traefik"
|
address: "http://authentik-server-service.authentik.svc:9000/outpost.goauthentik.io/auth/traefik"
|
||||||
trustForwardHeader: true
|
trustForwardHeader: true
|
||||||
maxResponseBodySize: 1048576
|
maxResponseBodySize: 1048576
|
||||||
authResponseHeaders:
|
authResponseHeaders:
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ service:
|
|||||||
type: LoadBalancer
|
type: LoadBalancer
|
||||||
annotations:
|
annotations:
|
||||||
metallb.io/loadBalancerIPs: "192.168.80.2"
|
metallb.io/loadBalancerIPs: "192.168.80.2"
|
||||||
|
spec:
|
||||||
|
externalTrafficPolicy: Local
|
||||||
api:
|
api:
|
||||||
dashboard: true
|
dashboard: true
|
||||||
insecure: true
|
insecure: true
|
||||||
@@ -75,12 +77,22 @@ ports:
|
|||||||
protocol: UDP
|
protocol: UDP
|
||||||
expose:
|
expose:
|
||||||
default: true
|
default: true
|
||||||
dot:
|
metrics:
|
||||||
port: 853
|
port: 9100
|
||||||
exposedPort: 853
|
exposedPort: 9100
|
||||||
protocol: TCP
|
protocol: TCP
|
||||||
expose:
|
expose:
|
||||||
default: true
|
default: false
|
||||||
|
|
||||||
|
metrics:
|
||||||
|
prometheus:
|
||||||
|
enabled: true
|
||||||
|
entryPoint: metrics
|
||||||
|
serviceMonitor:
|
||||||
|
enabled: true
|
||||||
|
additionalLabels:
|
||||||
|
release: prometheus-stack
|
||||||
|
namespace: prometheus
|
||||||
|
|
||||||
ingressRoute:
|
ingressRoute:
|
||||||
dashboard:
|
dashboard:
|
||||||
@@ -111,14 +123,26 @@ volumes:
|
|||||||
- name: traefik-dynamic
|
- name: traefik-dynamic
|
||||||
mountPath: /etc/traefik/dynamic
|
mountPath: /etc/traefik/dynamic
|
||||||
type: configMap
|
type: configMap
|
||||||
|
- name: crowdsec-bouncer-secrets
|
||||||
|
mountPath: /etc/traefik/secrets
|
||||||
|
type: secret
|
||||||
|
|
||||||
additionalArguments:
|
additionalArguments:
|
||||||
- "--providers.file.directory=/etc/traefik/dynamic"
|
- "--providers.file.directory=/etc/traefik/dynamic"
|
||||||
- "--providers.file.watch=true"
|
- "--providers.file.watch=true"
|
||||||
|
- "--providers.kubernetesCRD.allowCrossNamespace=true"
|
||||||
|
- "--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:
|
logs:
|
||||||
general:
|
general:
|
||||||
level: INFO
|
level: INFO
|
||||||
format: json
|
|
||||||
access:
|
access:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
format: common
|
||||||
|
|
||||||
|
experimental:
|
||||||
|
plugins:
|
||||||
|
crowdsec-bouncer:
|
||||||
|
moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin
|
||||||
|
version: v1.3.3
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ services:
|
|||||||
# Prod Router
|
# Prod Router
|
||||||
- "traefik.http.routers.uptime-kuma.rule=Host(`uptime.forust.xyz`)"
|
- "traefik.http.routers.uptime-kuma.rule=Host(`uptime.forust.xyz`)"
|
||||||
- "traefik.http.routers.uptime-kuma.entrypoints=websecure"
|
- "traefik.http.routers.uptime-kuma.entrypoints=websecure"
|
||||||
- "traefik.http.routers.uptime-kuma.tls=true"
|
- "traefik.http.routers.uptime-kuma.tls.certresolver=letsencrypt"
|
||||||
# Local Router
|
# Local Router
|
||||||
- "traefik.http.routers.uptime-kuma-local.rule=Host(`uptime.workstation.internal`)"
|
- "traefik.http.routers.uptime-kuma-local.rule=Host(`uptime.workstation.internal`)"
|
||||||
- "traefik.http.routers.uptime-kuma-local.entrypoints=websecure"
|
- "traefik.http.routers.uptime-kuma-local.entrypoints=websecure"
|
||||||
@@ -29,4 +29,4 @@ volumes:
|
|||||||
data:
|
data:
|
||||||
networks:
|
networks:
|
||||||
proxy:
|
proxy:
|
||||||
external: true
|
external: true
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^uptime\.forust\.xyz$`)
|
- match: Host(`uptime.forust.xyz`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
|
middlewares:
|
||||||
|
- name: crowdsec-crowdsec-bouncer@kubernetescrd
|
||||||
services:
|
services:
|
||||||
- name: uptime-kuma-service
|
- name: uptime-kuma-service
|
||||||
port: 3001
|
port: 3001
|
||||||
@@ -24,9 +26,8 @@ spec:
|
|||||||
entryPoints:
|
entryPoints:
|
||||||
- websecure
|
- websecure
|
||||||
routes:
|
routes:
|
||||||
- match: HostRegexp(`^uptime\.(workstation|gigaforust)\.internal$`)
|
- match: Host(`uptime.workstation.internal`) || Host(`uptime.gigaforust.internal`)
|
||||||
kind: Rule
|
kind: Rule
|
||||||
services:
|
services:
|
||||||
- name: uptime-kuma-service
|
- name: uptime-kuma-service
|
||||||
port: 3001
|
port: 3001
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,7 @@
|
|||||||
"name": "Moon-userbot",
|
"name": "Moon-userbot",
|
||||||
"description": "A Simple, Fast, Customizable, Ai powered Userbot for Telegram with most easiest installation.",
|
"description": "A Simple, Fast, Customizable, Ai powered Userbot for Telegram with most easiest installation.",
|
||||||
"logo": "https://camo.githubusercontent.com/1efdfa6416b3cd08471d865ca9ebf0fbdd38602ea95425f18a9bec6aeeefe49b/68747470733a2f2f74656c656772612e70682f66696c652f3063333763326662306631393463633163303334342e6a7067",
|
"logo": "https://camo.githubusercontent.com/1efdfa6416b3cd08471d865ca9ebf0fbdd38602ea95425f18a9bec6aeeefe49b/68747470733a2f2f74656c656772612e70682f66696c652f3063333763326662306631393463633163303334342e6a7067",
|
||||||
"keywords": [
|
"keywords": ["telegram", "Moon-userbot", "bot", "python", "pyrogram"],
|
||||||
"telegram",
|
|
||||||
"Moon-userbot",
|
|
||||||
"bot",
|
|
||||||
"python",
|
|
||||||
"pyrogram"
|
|
||||||
],
|
|
||||||
"env": {
|
"env": {
|
||||||
"API_ID": {
|
"API_ID": {
|
||||||
"description": "Get it from my.telegram.org",
|
"description": "Get it from my.telegram.org",
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ from flask import Flask
|
|||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
|
||||||
@app.route("/")
|
@app.route('/')
|
||||||
def hello_world():
|
def hello_world():
|
||||||
return "This is Moon"
|
return 'This is Moon'
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == '__main__':
|
||||||
app.run()
|
app.run()
|
||||||
|
|||||||
+15
-15
@@ -1,17 +1,17 @@
|
|||||||
services:
|
services:
|
||||||
- type: worker
|
- type: worker
|
||||||
name: Moon-Userbot
|
name: Moon-Userbot
|
||||||
runtime: docker
|
runtime: docker
|
||||||
repo: https://github.com/The-MoonTg-project/Moon-Userbot
|
repo: https://github.com/The-MoonTg-project/Moon-Userbot
|
||||||
plan: starter
|
plan: starter
|
||||||
envVars:
|
envVars:
|
||||||
- key: STABILITY_KEY
|
- key: STABILITY_KEY
|
||||||
sync: false
|
sync: false
|
||||||
- key: CLARIFAI_PAT
|
- key: CLARIFAI_PAT
|
||||||
sync: false
|
sync: false
|
||||||
- key: .env
|
- key: .env
|
||||||
sync: false
|
sync: false
|
||||||
region: oregon
|
region: oregon
|
||||||
dockerContext: .
|
dockerContext: .
|
||||||
dockerfilePath: ./Dockerfile
|
dockerfilePath: ./Dockerfile
|
||||||
version: "1"
|
version: "1"
|
||||||
|
|||||||
+19
-9
@@ -1,18 +1,28 @@
|
|||||||
|
FROM python:3.11-slim AS builder
|
||||||
|
|
||||||
|
WORKDIR /src
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir --user -r requirements.txt
|
||||||
|
|
||||||
FROM python:3.11-slim
|
FROM python:3.11-slim
|
||||||
|
|
||||||
WORKDIR /app
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
git wget ffmpeg mediainfo && \
|
git \
|
||||||
rm -rf /var/lib/apt/lists/*
|
mediainfo \
|
||||||
|
wget \
|
||||||
|
xz-utils \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
COPY requirements.txt /app/
|
RUN wget -qO- https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz | \
|
||||||
|
tar xJ && \
|
||||||
RUN python -m pip install --no-cache-dir --upgrade pip && \
|
cp ffmpeg-*-static/ffmpeg /usr/local/bin/ && \
|
||||||
python -m pip install --no-cache-dir -r /app/requirements.txt
|
cp ffmpeg-*-static/ffprobe /usr/local/bin/ && \
|
||||||
|
rm -rf ffmpeg-*
|
||||||
|
|
||||||
|
COPY --from=builder /root/.local /usr/local
|
||||||
COPY . /app
|
COPY . /app
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED=1
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
CMD ["python", "-u", "main.py"]
|
CMD ["python", "-u", "main.py"]
|
||||||
|
|||||||
+36
-41
@@ -1,83 +1,80 @@
|
|||||||
import re
|
|
||||||
import requests
|
|
||||||
import random
|
import random
|
||||||
|
import re
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
|
import requests
|
||||||
from bs4 import BeautifulSoup as bs
|
from bs4 import BeautifulSoup as bs
|
||||||
|
|
||||||
from pyrogram import Client, filters
|
from pyrogram import Client, filters
|
||||||
from pyrogram.types import Message, InputMediaPhoto
|
|
||||||
from pyrogram.errors import RPCError
|
from pyrogram.errors import RPCError
|
||||||
|
from pyrogram.types import InputMediaPhoto, Message
|
||||||
from utils.misc import modules_help, prefix
|
from utils.misc import modules_help, prefix
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command("icon", prefix) & filters.me)
|
@Client.on_message(filters.command('icon', prefix) & filters.me)
|
||||||
async def search_icon(_, message: Message):
|
async def search_icon(_, message: Message):
|
||||||
if not len(message.command) == 2:
|
if not len(message.command) == 2:
|
||||||
return await message.edit_text(
|
return await message.edit_text('Please provide some text to search icons from Flaticon.com.')
|
||||||
"Please provide some text to search icons from Flaticon.com."
|
|
||||||
)
|
|
||||||
query = message.text.split(maxsplit=1)[1]
|
query = message.text.split(maxsplit=1)[1]
|
||||||
|
|
||||||
await message.edit_text("Searching for icons...")
|
await message.edit_text('Searching for icons...')
|
||||||
search_query = query.replace(" ", "%20")
|
search_query = query.replace(' ', '%20')
|
||||||
url = f"https://www.flaticon.com/search?word={search_query}"
|
url = f'https://www.flaticon.com/search?word={search_query}'
|
||||||
|
|
||||||
try:
|
try:
|
||||||
html_content = requests.get(url).text
|
html_content = requests.get(url).text
|
||||||
soup = bs(html_content, "html.parser")
|
soup = bs(html_content, 'html.parser')
|
||||||
results = soup.find_all(
|
results = soup.find_all(
|
||||||
"img",
|
'img',
|
||||||
src=re.compile(r"https://cdn-icons-png.flaticon.com/128/[0-9]+/[0-9]+.png"),
|
src=re.compile(r'https://cdn-icons-png.flaticon.com/128/[0-9]+/[0-9]+.png'),
|
||||||
)
|
)
|
||||||
|
|
||||||
if not results:
|
if not results:
|
||||||
return await message.edit("No results found.")
|
return await message.edit('No results found.')
|
||||||
|
|
||||||
random.shuffle(results)
|
random.shuffle(results)
|
||||||
icons = []
|
icons = []
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
icons.append(results[i]["src"].replace("128", "512"))
|
icons.append(results[i]['src'].replace('128', '512'))
|
||||||
|
|
||||||
for icon in icons:
|
for icon in icons:
|
||||||
await message.reply_document(icon)
|
await message.reply_document(icon)
|
||||||
|
|
||||||
return await message.delete()
|
return await message.delete()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await message.edit(f"An error occurred: {e}")
|
await message.edit(f'An error occurred: {e}')
|
||||||
print(f"Error: {e}")
|
print(f'Error: {e}')
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command("freepik", prefix) & filters.me)
|
@Client.on_message(filters.command('freepik', prefix) & filters.me)
|
||||||
async def freepik_search(client: Client, message: Message):
|
async def freepik_search(client: Client, message: Message):
|
||||||
parts = message.text.split(" ", 1)
|
parts = message.text.split(' ', 1)
|
||||||
if len(parts) < 2:
|
if len(parts) < 2:
|
||||||
await message.edit_text("Please provide a search query!")
|
await message.edit_text('Please provide a search query!')
|
||||||
return
|
return
|
||||||
|
|
||||||
query = parts[1]
|
query = parts[1]
|
||||||
limit = 5
|
limit = 5
|
||||||
if " ; " in query:
|
if ' ; ' in query:
|
||||||
match, limit_str = query.split(" ; ", 1)
|
match, limit_str = query.split(' ; ', 1)
|
||||||
try:
|
try:
|
||||||
limit = int(limit_str)
|
limit = int(limit_str)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
await message.edit_text("Invalid limit! Using the default value of 5.")
|
await message.edit_text('Invalid limit! Using the default value of 5.')
|
||||||
else:
|
else:
|
||||||
match = query
|
match = query
|
||||||
|
|
||||||
match = match.replace(" ", "%20")
|
match = match.replace(' ', '%20')
|
||||||
await message.edit_text("Searching Freepik...")
|
await message.edit_text('Searching Freepik...')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
url = f"https://www.freepik.com/api/regular/search?locale=en&term={match}"
|
url = f'https://www.freepik.com/api/regular/search?locale=en&term={match}'
|
||||||
json_content = requests.get(url).json()
|
json_content = requests.get(url).json()
|
||||||
results = []
|
results = []
|
||||||
for i in json_content["items"]:
|
for i in json_content['items']:
|
||||||
results.append(i["preview"]["url"])
|
results.append(i['preview']['url'])
|
||||||
|
|
||||||
if results is None:
|
if results is None:
|
||||||
return await message.edit_text("No results found.")
|
return await message.edit_text('No results found.')
|
||||||
|
|
||||||
random.shuffle(results)
|
random.shuffle(results)
|
||||||
img_urls = results[:limit]
|
img_urls = results[:limit]
|
||||||
@@ -89,27 +86,25 @@ async def freepik_search(client: Client, message: Message):
|
|||||||
media_group.append(InputMediaPhoto(media=BytesIO(icon.content)))
|
media_group.append(InputMediaPhoto(media=BytesIO(icon.content)))
|
||||||
|
|
||||||
if not media_group:
|
if not media_group:
|
||||||
await message.edit_text("No images could be downloaded.")
|
await message.edit_text('No images could be downloaded.')
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await client.send_media_group(chat_id=message.chat.id, media=media_group)
|
await client.send_media_group(chat_id=message.chat.id, media=media_group)
|
||||||
except RPCError:
|
except RPCError:
|
||||||
await message.edit_text(
|
await message.edit_text('Failed to send some images. Retrying individually...')
|
||||||
"Failed to send some images. Retrying individually..."
|
|
||||||
)
|
|
||||||
for media in media_group:
|
for media in media_group:
|
||||||
try:
|
try:
|
||||||
await message.reply_photo(photo=media.media)
|
await message.reply_photo(photo=media.media)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await message.edit_text(f"Error sending image: {e}")
|
await message.edit_text(f'Error sending image: {e}')
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await message.edit_text(f"Failed to fetch data: {e}")
|
await message.edit_text(f'Failed to fetch data: {e}')
|
||||||
print(f"Error: {e}")
|
print(f'Error: {e}')
|
||||||
|
|
||||||
|
|
||||||
modules_help["icons"] = {
|
modules_help['icons'] = {
|
||||||
"icon [query]": "Search for icons on Flaticon.",
|
'icon [query]': 'Search for icons on Flaticon.',
|
||||||
"freepik [query] [limit]": "Search for images on Freepik. Limit is optional and defaults to 5.",
|
'freepik [query] [limit]': 'Search for images on Freepik. Limit is optional and defaults to 5.',
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-21
@@ -1,52 +1,47 @@
|
|||||||
import os
|
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
|
||||||
from pyrogram import Client, filters
|
from pyrogram import Client, filters
|
||||||
from pyrogram.types import Message
|
from pyrogram.types import Message
|
||||||
|
|
||||||
from utils.misc import modules_help, prefix
|
from utils.misc import modules_help, prefix
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command(["imgur"], prefix) & filters.me)
|
@Client.on_message(filters.command(['imgur'], prefix) & filters.me)
|
||||||
async def imgur(_, message: Message):
|
async def imgur(_, message: Message):
|
||||||
# Check if a reply exists
|
# Check if a reply exists
|
||||||
msg = await message.edit_text("🎉 Please wait. trying to upload...")
|
msg = await message.edit_text('🎉 Please wait. trying to upload...')
|
||||||
if message.reply_to_message and message.reply_to_message.photo:
|
if message.reply_to_message and message.reply_to_message.photo:
|
||||||
# Download the photo
|
# Download the photo
|
||||||
photo_path = await message.reply_to_message.download()
|
photo_path = await message.reply_to_message.download()
|
||||||
# Read the photo file and encode as base64
|
# Read the photo file and encode as base64
|
||||||
with open(photo_path, "rb") as file:
|
with open(photo_path, 'rb') as file:
|
||||||
data = file.read()
|
data = file.read()
|
||||||
base64_data = base64.b64encode(data)
|
base64_data = base64.b64encode(data)
|
||||||
# Set API endpoint and headers for image upload
|
# Set API endpoint and headers for image upload
|
||||||
url = "https://api.imgur.com/3/image"
|
url = 'https://api.imgur.com/3/image'
|
||||||
headers = {"Authorization": "Client-ID a10ad04550b0648"}
|
headers = {'Authorization': 'Client-ID a10ad04550b0648'}
|
||||||
# Upload image to Imgur and get URL
|
# 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})
|
||||||
result = response.json()
|
result = response.json()
|
||||||
await msg.edit_text(result["data"]["link"])
|
await msg.edit_text(result['data']['link'])
|
||||||
elif message.reply_to_message and message.reply_to_message.animation:
|
elif message.reply_to_message and message.reply_to_message.animation:
|
||||||
# Download the animation (GIF)
|
# Download the animation (GIF)
|
||||||
animation_path = await message.reply_to_message.download()
|
animation_path = await message.reply_to_message.download()
|
||||||
# Read the animation file and encode as base64
|
# Read the animation file and encode as base64
|
||||||
with open(animation_path, "rb") as file:
|
with open(animation_path, 'rb') as file:
|
||||||
data = file.read()
|
data = file.read()
|
||||||
base64_data = base64.b64encode(data)
|
base64_data = base64.b64encode(data)
|
||||||
# Set API endpoint and headers for animation upload
|
# Set API endpoint and headers for animation upload
|
||||||
url = "https://api.imgur.com/3/image"
|
url = 'https://api.imgur.com/3/image'
|
||||||
headers = {"Authorization": "Client-ID a10ad04550b0648"}
|
headers = {'Authorization': 'Client-ID a10ad04550b0648'}
|
||||||
# Upload animation to Imgur and get URL
|
# 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})
|
||||||
result = response.json()
|
result = response.json()
|
||||||
await msg.edit_text(result["data"]["link"])
|
await msg.edit_text(result['data']['link'])
|
||||||
else:
|
else:
|
||||||
await msg.edit_text(
|
await msg.edit_text('Please reply to a photo or animation (GIF) to upload to Imgur.')
|
||||||
"Please reply to a photo or animation (GIF) to upload to Imgur."
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
modules_help["imgur"] = {
|
modules_help['imgur'] = {
|
||||||
"imgur [img]*": "upload a photo or animation (GIF) to imgur",
|
'imgur [img]*': 'upload a photo or animation (GIF) to imgur',
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-26
@@ -1,55 +1,47 @@
|
|||||||
from pyrogram import Client, filters
|
|
||||||
from pyrogram.types import Message
|
|
||||||
|
|
||||||
from utils.misc import prefix, modules_help
|
|
||||||
|
|
||||||
|
|
||||||
from pyrogram import Client, filters
|
|
||||||
from pyrogram.types import Message
|
|
||||||
from pyrogram.errors import MessageNotModified
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import pygments
|
import pygments
|
||||||
from pygments.formatters import ImageFormatter
|
from pygments.formatters import ImageFormatter
|
||||||
from pygments.lexers import Python3Lexer
|
from pygments.lexers import Python3Lexer
|
||||||
|
from pyrogram import Client, filters
|
||||||
|
from pyrogram.errors import MessageNotModified
|
||||||
|
from pyrogram.types import Message
|
||||||
|
from utils.misc import modules_help, prefix
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command("ncode", prefix) & filters.me)
|
@Client.on_message(filters.command('ncode', prefix) & filters.me)
|
||||||
async def coder_print(client, message: Message):
|
async def coder_print(client, message: Message):
|
||||||
if message.reply_to_message:
|
if message.reply_to_message:
|
||||||
reply_message = message.reply_to_message
|
reply_message = message.reply_to_message
|
||||||
if reply_message.media:
|
if reply_message.media:
|
||||||
download_path = await client.download_media(reply_message)
|
download_path = await client.download_media(reply_message)
|
||||||
with open(download_path, "r") as file:
|
with open(download_path) as file:
|
||||||
code = file.read()
|
code = file.read()
|
||||||
if os.path.exists(download_path):
|
if os.path.exists(download_path):
|
||||||
os.remove(download_path)
|
os.remove(download_path)
|
||||||
pygments.highlight(
|
pygments.highlight(
|
||||||
f"{code}",
|
f'{code}',
|
||||||
Python3Lexer(),
|
Python3Lexer(),
|
||||||
ImageFormatter(font_name="DejaVu Sans Mono", line_numbers=True),
|
ImageFormatter(font_name='DejaVu Sans Mono', line_numbers=True),
|
||||||
"result.png",
|
'result.png',
|
||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
sent_message = await message.edit_text(
|
sent_message = await message.edit_text('Pasting this code on my page...')
|
||||||
"Pasting this code on my page..."
|
|
||||||
)
|
|
||||||
await client.send_document(
|
await client.send_document(
|
||||||
chat_id=message.chat.id,
|
chat_id=message.chat.id,
|
||||||
document="result.png",
|
document='result.png',
|
||||||
caption="Code highlighted by Pygments",
|
caption='Code highlighted by Pygments',
|
||||||
reply_to_message_id=message.id,
|
reply_to_message_id=message.id,
|
||||||
)
|
)
|
||||||
except MessageNotModified:
|
except MessageNotModified:
|
||||||
pass
|
pass
|
||||||
await sent_message.delete()
|
await sent_message.delete()
|
||||||
if os.path.exists("result.png"):
|
if os.path.exists('result.png'):
|
||||||
os.remove("result.png")
|
os.remove('result.png')
|
||||||
else:
|
else:
|
||||||
return await message.reply_text("Please reply to a text or a file.")
|
return await message.reply_text('Please reply to a text or a file.')
|
||||||
else:
|
else:
|
||||||
return await message.reply_text("Please reply to a text or a file.")
|
return await message.reply_text('Please reply to a text or a file.')
|
||||||
|
|
||||||
|
|
||||||
modules_help["ncode"] = {
|
modules_help['ncode'] = {'ncode': 'Highlight the code using Pygments and send it as an image.'}
|
||||||
"ncode": "Highlight the code using Pygments and send it as an image."
|
|
||||||
}
|
|
||||||
|
|||||||
+24
-35
@@ -1,13 +1,14 @@
|
|||||||
from pyrogram import Client, filters, enums
|
|
||||||
from pyrogram.types import Message, InputMediaPhoto
|
|
||||||
from io import BytesIO
|
|
||||||
from PIL import Image
|
|
||||||
import requests
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from PIL import Image
|
||||||
|
from pyrogram import Client, enums, filters
|
||||||
|
from pyrogram.types import InputMediaPhoto, Message
|
||||||
from utils.misc import modules_help, prefix
|
from utils.misc import modules_help, prefix
|
||||||
|
|
||||||
# Pinterest API URL
|
# Pinterest API URL
|
||||||
API_URL = "https://bk9.fun/pinterest/search?q="
|
API_URL = 'https://bk9.fun/pinterest/search?q='
|
||||||
|
|
||||||
|
|
||||||
def resize_image(image_bytes):
|
def resize_image(image_bytes):
|
||||||
@@ -17,13 +18,13 @@ def resize_image(image_bytes):
|
|||||||
if img.size > max_size:
|
if img.size > max_size:
|
||||||
img.thumbnail(max_size)
|
img.thumbnail(max_size)
|
||||||
output = BytesIO()
|
output = BytesIO()
|
||||||
img.save(output, format="JPEG")
|
img.save(output, format='JPEG')
|
||||||
output.seek(0)
|
output.seek(0)
|
||||||
return output
|
return output
|
||||||
image_bytes.seek(0) # Reset pointer if not resized
|
image_bytes.seek(0) # Reset pointer if not resized
|
||||||
return image_bytes
|
return image_bytes
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error resizing image: {e}")
|
print(f'Error resizing image: {e}')
|
||||||
return image_bytes
|
return image_bytes
|
||||||
|
|
||||||
|
|
||||||
@@ -34,69 +35,57 @@ async def download_image(url):
|
|||||||
img_bytes = BytesIO(response.content)
|
img_bytes = BytesIO(response.content)
|
||||||
return resize_image(img_bytes)
|
return resize_image(img_bytes)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error downloading image: {e}")
|
print(f'Error downloading image: {e}')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command("pinterest", prefix) & filters.me)
|
@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:
|
if len(message.command) < 2:
|
||||||
await message.edit(
|
await message.edit('Usage: `pinterest [number] <query>`', parse_mode=enums.ParseMode.MARKDOWN)
|
||||||
"Usage: `pinterest [number] <query>`", parse_mode=enums.ParseMode.MARKDOWN
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
num_pics = int(message.command[1]) if message.command[1].isdigit() else 10
|
num_pics = int(message.command[1]) if message.command[1].isdigit() else 10
|
||||||
query = " ".join(message.command[2:])
|
query = ' '.join(message.command[2:])
|
||||||
|
|
||||||
# Update status
|
# Update status
|
||||||
status_message = await message.edit(
|
status_message = await message.edit('Searching for images...', parse_mode=enums.ParseMode.MARKDOWN)
|
||||||
"Searching for images...", parse_mode=enums.ParseMode.MARKDOWN
|
|
||||||
)
|
|
||||||
|
|
||||||
url = f"{API_URL}{query}"
|
url = f'{API_URL}{query}'
|
||||||
response = requests.get(url)
|
response = requests.get(url)
|
||||||
|
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
data = response.json()
|
data = response.json()
|
||||||
if data.get("status"):
|
if data.get('status'):
|
||||||
urls = [item["images_url"] for item in data.get("BK9", [])[:num_pics]]
|
urls = [item['images_url'] for item in data.get('BK9', [])[:num_pics]]
|
||||||
images = [download_image(img_url) for img_url in urls]
|
images = [download_image(img_url) for img_url in urls]
|
||||||
|
|
||||||
# Download images
|
# Download images
|
||||||
downloaded_images = await asyncio.gather(*images)
|
downloaded_images = await asyncio.gather(*images)
|
||||||
|
|
||||||
media = [
|
media = [InputMediaPhoto(media=img_bytes) for img_bytes in downloaded_images if img_bytes]
|
||||||
InputMediaPhoto(media=img_bytes)
|
|
||||||
for img_bytes in downloaded_images
|
|
||||||
if img_bytes
|
|
||||||
]
|
|
||||||
|
|
||||||
if media:
|
if media:
|
||||||
await status_message.edit(
|
await status_message.edit('Uploading pictures...', parse_mode=enums.ParseMode.MARKDOWN)
|
||||||
"Uploading pictures...", parse_mode=enums.ParseMode.MARKDOWN
|
|
||||||
)
|
|
||||||
while media:
|
while media:
|
||||||
batch = media[:10]
|
batch = media[:10]
|
||||||
media = media[10:]
|
media = media[10:]
|
||||||
await message.reply_media_group(batch)
|
await message.reply_media_group(batch)
|
||||||
await status_message.delete() # Delete status message after uploading
|
await status_message.delete() # Delete status message after uploading
|
||||||
else:
|
else:
|
||||||
await status_message.edit(
|
await status_message.edit('No valid images found.', parse_mode=enums.ParseMode.MARKDOWN)
|
||||||
"No valid images found.", parse_mode=enums.ParseMode.MARKDOWN
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
await status_message.edit(
|
await status_message.edit(
|
||||||
"No images found for the given query.",
|
'No images found for the given query.',
|
||||||
parse_mode=enums.ParseMode.MARKDOWN,
|
parse_mode=enums.ParseMode.MARKDOWN,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await status_message.edit(
|
await status_message.edit(
|
||||||
"An error occurred, please try again later.",
|
'An error occurred, please try again later.',
|
||||||
parse_mode=enums.ParseMode.MARKDOWN,
|
parse_mode=enums.ParseMode.MARKDOWN,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
modules_help["pinterest"] = {
|
modules_help['pinterest'] = {
|
||||||
"pinterest [number]* [query]": "Get images from Pinterest. Default number of images is 10",
|
'pinterest [number]* [query]': 'Get images from Pinterest. Default number of images is 10',
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-32
@@ -1,26 +1,27 @@
|
|||||||
from utils.misc import modules_help, prefix
|
import os
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
from modules.url import generate_screenshot
|
||||||
from pyrogram import Client, filters
|
from pyrogram import Client, filters
|
||||||
from pyrogram.types import Message
|
from pyrogram.types import Message
|
||||||
from modules.url import generate_screenshot
|
from utils.misc import modules_help, prefix
|
||||||
import os
|
|
||||||
|
|
||||||
# API endpoints for reverse image search engines
|
# API endpoints for reverse image search engines
|
||||||
SEARCH_ENGINES = {
|
SEARCH_ENGINES = {
|
||||||
"lens": "https://lens.google.com/uploadbyurl?url={image}",
|
'lens': 'https://lens.google.com/uploadbyurl?url={image}',
|
||||||
"reverse": "https://www.google.com/searchbyimage?sbisrc=4chanx&image_url={image}&safe=off",
|
'reverse': 'https://www.google.com/searchbyimage?sbisrc=4chanx&image_url={image}&safe=off',
|
||||||
"tineye": "https://www.tineye.com/search?url={image}",
|
'tineye': 'https://www.tineye.com/search?url={image}',
|
||||||
"bing": "https://www.bing.com/images/search?view=detailv2&iss=sbi&form=SBIVSP&sbisrc=UrlPaste&q=imgurl:{image}",
|
'bing': 'https://www.bing.com/images/search?view=detailv2&iss=sbi&form=SBIVSP&sbisrc=UrlPaste&q=imgurl:{image}',
|
||||||
"yandex": "https://yandex.com/images/search?source=collections&&url={image}&rpt=imageview",
|
'yandex': 'https://yandex.com/images/search?source=collections&&url={image}&rpt=imageview',
|
||||||
"saucenao": "https://saucenao.com/search.php?db=999&url={image}",
|
'saucenao': 'https://saucenao.com/search.php?db=999&url={image}',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command("risearch", prefix) & filters.reply)
|
@Client.on_message(filters.command('risearch', prefix) & filters.reply)
|
||||||
async def reverse_image_search(client: Client, message: Message):
|
async def reverse_image_search(client: Client, message: Message):
|
||||||
if not message.reply_to_message or not message.reply_to_message.photo:
|
if not message.reply_to_message or not message.reply_to_message.photo:
|
||||||
await message.reply_text(
|
await message.reply_text(
|
||||||
f"Please reply to an image with <code>{prefix}risearch [engine]</code> or <code>{prefix}risearch</code>."
|
f'Please reply to an image with <code>{prefix}risearch [engine]</code> or <code>{prefix}risearch</code>.'
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -31,16 +32,14 @@ async def reverse_image_search(client: Client, message: Message):
|
|||||||
else list(SEARCH_ENGINES.keys())
|
else list(SEARCH_ENGINES.keys())
|
||||||
)
|
)
|
||||||
|
|
||||||
invalid_engines = [
|
invalid_engines = [engine for engine in engines_to_use if engine not in SEARCH_ENGINES]
|
||||||
engine for engine in engines_to_use if engine not in SEARCH_ENGINES
|
|
||||||
]
|
|
||||||
if invalid_engines:
|
if invalid_engines:
|
||||||
await message.reply_text(
|
await message.reply_text(
|
||||||
f"Invalid engine(s): {', '.join(invalid_engines)}. Available: {', '.join(SEARCH_ENGINES.keys())}"
|
f'Invalid engine(s): {", ".join(invalid_engines)}. Available: {", ".join(SEARCH_ENGINES.keys())}'
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
processing_message = await message.edit_text("Processing the image...")
|
processing_message = await message.edit_text('Processing the image...')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Download and upload the image
|
# Download and upload the image
|
||||||
@@ -48,7 +47,7 @@ async def reverse_image_search(client: Client, message: Message):
|
|||||||
img_url = upload_image(photo_path)
|
img_url = upload_image(photo_path)
|
||||||
print(img_url)
|
print(img_url)
|
||||||
if not img_url:
|
if not img_url:
|
||||||
await processing_message.edit("Error: Could not upload the image.")
|
await processing_message.edit('Error: Could not upload the image.')
|
||||||
return
|
return
|
||||||
|
|
||||||
# Perform searches for the selected engines
|
# Perform searches for the selected engines
|
||||||
@@ -56,7 +55,7 @@ async def reverse_image_search(client: Client, message: Message):
|
|||||||
search_url = SEARCH_ENGINES[engine].format(image=img_url)
|
search_url = SEARCH_ENGINES[engine].format(image=img_url)
|
||||||
await send_screenshot(client, message, search_url, engine)
|
await send_screenshot(client, message, search_url, engine)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await processing_message.edit(f"An error occurred: {e}")
|
await processing_message.edit(f'An error occurred: {e}')
|
||||||
finally:
|
finally:
|
||||||
if photo_path and os.path.exists(photo_path):
|
if photo_path and os.path.exists(photo_path):
|
||||||
os.remove(photo_path)
|
os.remove(photo_path)
|
||||||
@@ -65,15 +64,13 @@ async def reverse_image_search(client: Client, message: Message):
|
|||||||
def upload_image(photo_path):
|
def upload_image(photo_path):
|
||||||
"""Uploads an image to tmpfiles.org and returns the direct download URL."""
|
"""Uploads an image to tmpfiles.org and returns the direct download URL."""
|
||||||
try:
|
try:
|
||||||
with open(photo_path, "rb") as image_file:
|
with open(photo_path, 'rb') as image_file:
|
||||||
response = requests.post(
|
response = requests.post('https://tmpfiles.org/api/v1/upload', files={'file': image_file})
|
||||||
"https://tmpfiles.org/api/v1/upload", files={"file": image_file}
|
|
||||||
)
|
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
data = response.json()
|
data = response.json()
|
||||||
url = data["data"]["url"]
|
url = data['data']['url']
|
||||||
pic_url = url.split("/")[-2] + "/" + url.split("/")[-1]
|
pic_url = url.split('/')[-2] + '/' + url.split('/')[-1]
|
||||||
direct_download_url = url.replace(f"/{pic_url}", f"/dl/{pic_url}")
|
direct_download_url = url.replace(f'/{pic_url}', f'/dl/{pic_url}')
|
||||||
print(direct_download_url)
|
print(direct_download_url)
|
||||||
return direct_download_url
|
return direct_download_url
|
||||||
else:
|
else:
|
||||||
@@ -89,17 +86,15 @@ async def send_screenshot(client, message, url, engine_name):
|
|||||||
await client.send_photo(
|
await client.send_photo(
|
||||||
message.chat.id,
|
message.chat.id,
|
||||||
screenshot_data,
|
screenshot_data,
|
||||||
caption=f"<b>{engine_name.capitalize()} Result</b>\nURL: <code>{url}</code>",
|
caption=f'<b>{engine_name.capitalize()} Result</b>\nURL: <code>{url}</code>',
|
||||||
reply_to_message_id=message.id,
|
reply_to_message_id=message.id,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await message.reply(
|
await message.reply(f'Failed to take screenshot for {engine_name.capitalize()}.')
|
||||||
f"Failed to take screenshot for {engine_name.capitalize()}."
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# Add module details to help
|
# Add module details to help
|
||||||
modules_help["risearch"] = {
|
modules_help['risearch'] = {
|
||||||
"risearch": f"Reply to a photo with `{prefix}risearch [engine]` (e.g., `{prefix}risearch lens`, `{prefix}risearch bing`) "
|
'risearch': f'Reply to a photo with `{prefix}risearch [engine]` (e.g., `{prefix}risearch lens`, `{prefix}risearch bing`) '
|
||||||
f"\nor use `{prefix}risearch` to analyze the image with all engines.",
|
f'\nor use `{prefix}risearch` to analyze the image with all engines.',
|
||||||
}
|
}
|
||||||
|
|||||||
+36
-44
@@ -1,64 +1,60 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import json
|
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
import requests
|
||||||
from pyrogram import Client, enums, filters
|
from pyrogram import Client, enums, filters
|
||||||
from pyrogram.types import Message
|
from pyrogram.types import Message
|
||||||
import requests
|
|
||||||
from utils.misc import modules_help, prefix
|
from utils.misc import modules_help, prefix
|
||||||
|
|
||||||
|
|
||||||
class AioHttp:
|
class AioHttp:
|
||||||
async def get_json(self, link):
|
async def get_json(self, link):
|
||||||
headers = {
|
headers = {
|
||||||
"accept": "*/*",
|
'accept': '*/*',
|
||||||
"accept-language": "en-US",
|
'accept-language': 'en-US',
|
||||||
"cache-control": "no-cache",
|
'cache-control': 'no-cache',
|
||||||
"client-geo-region": "global",
|
'client-geo-region': 'global',
|
||||||
"dnt": "1",
|
'dnt': '1',
|
||||||
"pragma": "no-cache",
|
'pragma': 'no-cache',
|
||||||
"priority": "u=1, i",
|
'priority': 'u=1, i',
|
||||||
"sec-ch-ua": '"Chromium";v="130", "Microsoft Edge";v="130", "Not?A_Brand";v="99"',
|
'sec-ch-ua': '"Chromium";v="130", "Microsoft Edge";v="130", "Not?A_Brand";v="99"',
|
||||||
"sec-ch-ua-mobile": "?0",
|
'sec-ch-ua-mobile': '?0',
|
||||||
"sec-ch-ua-platform": '"Windows"',
|
'sec-ch-ua-platform': '"Windows"',
|
||||||
"sec-fetch-dest": "empty",
|
'sec-fetch-dest': 'empty',
|
||||||
"sec-fetch-mode": "cors",
|
'sec-fetch-mode': 'cors',
|
||||||
"sec-fetch-site": "same-origin",
|
'sec-fetch-site': 'same-origin',
|
||||||
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0",
|
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0',
|
||||||
}
|
}
|
||||||
|
|
||||||
async with aiohttp.ClientSession() as session:
|
async with aiohttp.ClientSession() as session, session.get(link, headers=headers) as resp:
|
||||||
async with session.get(link, headers=headers) as resp:
|
return await resp.json()
|
||||||
return await resp.json()
|
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command("unsplash", prefix) & filters.me)
|
@Client.on_message(filters.command('unsplash', prefix) & filters.me)
|
||||||
async def unsplash(client: Client, message: Message):
|
async def unsplash(client: Client, message: Message):
|
||||||
if len(message.command) > 1 and isinstance(message.command[1], str):
|
if len(message.command) > 1 and isinstance(message.command[1], str):
|
||||||
keyword = message.command[1]
|
keyword = message.command[1]
|
||||||
unsplash_dir = "downloads/unsplash/"
|
unsplash_dir = 'downloads/unsplash/'
|
||||||
if not os.path.exists(unsplash_dir):
|
if not os.path.exists(unsplash_dir):
|
||||||
os.makedirs(unsplash_dir)
|
os.makedirs(unsplash_dir)
|
||||||
|
|
||||||
if len(message.command) > 2 and 2 <= int(message.command[2]) <= 10:
|
if len(message.command) > 2 and 2 <= int(message.command[2]) <= 10:
|
||||||
await message.edit(
|
await message.edit('<b>Getting Pictures</b>', parse_mode=enums.ParseMode.HTML)
|
||||||
"<b>Getting Pictures</b>", parse_mode=enums.ParseMode.HTML
|
|
||||||
)
|
|
||||||
count = int(message.command[2])
|
count = int(message.command[2])
|
||||||
images = []
|
images = []
|
||||||
data = await AioHttp().get_json(
|
data = await AioHttp().get_json(
|
||||||
f"https://unsplash.com/napi/search/photos?page=1&per_page={count}&query={keyword}"
|
f'https://unsplash.com/napi/search/photos?page=1&per_page={count}&query={keyword}'
|
||||||
)
|
)
|
||||||
while len(images) < count:
|
while len(images) < count:
|
||||||
for ia in range(len(images), count):
|
for ia in range(len(images), count):
|
||||||
img = data["results"][ia]["urls"]["raw"]
|
img = data['results'][ia]['urls']['raw']
|
||||||
if img.startswith("https://images.unsplash.com/photo"):
|
if img.startswith('https://images.unsplash.com/photo'):
|
||||||
image_content = requests.get(img).content
|
image_content = requests.get(img).content
|
||||||
with open(f"{unsplash_dir}/unsplash_{ia}.jpg", "wb") as f:
|
with open(f'{unsplash_dir}/unsplash_{ia}.jpg', 'wb') as f:
|
||||||
f.write(image_content)
|
f.write(image_content)
|
||||||
imgr = f"{unsplash_dir}/unsplash_{ia}.jpg"
|
imgr = f'{unsplash_dir}/unsplash_{ia}.jpg'
|
||||||
images.append(imgr)
|
images.append(imgr)
|
||||||
else:
|
else:
|
||||||
images.append(img)
|
images.append(img)
|
||||||
@@ -72,23 +68,19 @@ async def unsplash(client: Client, message: Message):
|
|||||||
shutil.rmtree(unsplash_dir)
|
shutil.rmtree(unsplash_dir)
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
await message.edit(
|
await message.edit('<b>Getting Picture</b>', parse_mode=enums.ParseMode.HTML)
|
||||||
"<b>Getting Picture</b>", parse_mode=enums.ParseMode.HTML
|
|
||||||
)
|
|
||||||
data = await AioHttp().get_json(
|
data = await AioHttp().get_json(
|
||||||
f"https://unsplash.com/napi/search/photos?page=1&per_page=1&query={keyword}"
|
f'https://unsplash.com/napi/search/photos?page=1&per_page=1&query={keyword}'
|
||||||
)
|
|
||||||
img = data["results"][0]["urls"]["raw"]
|
|
||||||
await asyncio.gather(
|
|
||||||
message.delete(), client.send_document(message.chat.id, str(img))
|
|
||||||
)
|
)
|
||||||
|
img = data['results'][0]['urls']['raw']
|
||||||
|
await asyncio.gather(message.delete(), client.send_document(message.chat.id, str(img)))
|
||||||
|
|
||||||
|
|
||||||
modules_help["unsplash"] = {
|
modules_help['unsplash'] = {
|
||||||
"unsplash": f"[keyword]*",
|
'unsplash': '[keyword]*',
|
||||||
"unsplash": f"[keyword]* [number of results you want]*\n"
|
'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"
|
'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"
|
'<b>Note:</b>\n1. The number of results you can get is limited to 10.\n'
|
||||||
"2. Keyword is required and should be of one word only!.\n"
|
'2. Keyword is required and should be of one word only!.\n'
|
||||||
"3. Images are sent as document to maintain quality.",
|
'3. Images are sent as document to maintain quality.',
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-36
@@ -1,12 +1,13 @@
|
|||||||
from pyrogram import Client, filters, enums
|
|
||||||
from pyrogram.types import Message, InputMediaPhoto
|
|
||||||
from io import BytesIO
|
|
||||||
from PIL import Image
|
|
||||||
import requests
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from io import BytesIO
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from PIL import Image
|
||||||
|
from pyrogram import Client, enums, filters
|
||||||
|
from pyrogram.types import InputMediaPhoto, Message
|
||||||
from utils.misc import modules_help, prefix
|
from utils.misc import modules_help, prefix
|
||||||
|
|
||||||
API_URL = "https://bk9.fun/search/unsplash?q="
|
API_URL = 'https://bk9.fun/search/unsplash?q='
|
||||||
|
|
||||||
|
|
||||||
def resize_image(image_bytes):
|
def resize_image(image_bytes):
|
||||||
@@ -16,13 +17,13 @@ def resize_image(image_bytes):
|
|||||||
if img.size > max_size:
|
if img.size > max_size:
|
||||||
img.thumbnail(max_size)
|
img.thumbnail(max_size)
|
||||||
output = BytesIO()
|
output = BytesIO()
|
||||||
img.save(output, format="JPEG")
|
img.save(output, format='JPEG')
|
||||||
output.seek(0)
|
output.seek(0)
|
||||||
return output
|
return output
|
||||||
image_bytes.seek(0) # Reset pointer if not resized
|
image_bytes.seek(0) # Reset pointer if not resized
|
||||||
return image_bytes
|
return image_bytes
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error resizing image: {e}")
|
print(f'Error resizing image: {e}')
|
||||||
return image_bytes
|
return image_bytes
|
||||||
|
|
||||||
|
|
||||||
@@ -34,70 +35,58 @@ async def download_image(url):
|
|||||||
resized_img_bytes = resize_image(img_bytes)
|
resized_img_bytes = resize_image(img_bytes)
|
||||||
return resized_img_bytes
|
return resized_img_bytes
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error downloading image: {e}")
|
print(f'Error downloading image: {e}')
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command(["unsplash2", "usp2"], prefix) & filters.me)
|
@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:
|
if len(message.command) < 2:
|
||||||
await message.edit(
|
await message.edit('Usage: `img [number] <query>`', parse_mode=enums.ParseMode.MARKDOWN)
|
||||||
"Usage: `img [number] <query>`", parse_mode=enums.ParseMode.MARKDOWN
|
|
||||||
)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
num_pics = int(message.command[1]) if message.command[1].isdigit() else 10
|
num_pics = int(message.command[1]) if message.command[1].isdigit() else 10
|
||||||
query = " ".join(message.command[2:])
|
query = ' '.join(message.command[2:])
|
||||||
|
|
||||||
# Update status
|
# Update status
|
||||||
status_message = await message.edit(
|
status_message = await message.edit('Searching for images...', parse_mode=enums.ParseMode.MARKDOWN)
|
||||||
"Searching for images...", parse_mode=enums.ParseMode.MARKDOWN
|
|
||||||
)
|
|
||||||
|
|
||||||
url = f"{API_URL}{query}"
|
url = f'{API_URL}{query}'
|
||||||
response = requests.get(url)
|
response = requests.get(url)
|
||||||
|
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
data = response.json()
|
data = response.json()
|
||||||
if data.get("status"):
|
if data.get('status'):
|
||||||
urls = data.get("BK9", [])[:num_pics]
|
urls = data.get('BK9', [])[:num_pics]
|
||||||
images = [download_image(img_url) for img_url in urls]
|
images = [download_image(img_url) for img_url in urls]
|
||||||
|
|
||||||
# Download images
|
# Download images
|
||||||
downloaded_images = await asyncio.gather(*images)
|
downloaded_images = await asyncio.gather(*images)
|
||||||
|
|
||||||
media = [
|
media = [InputMediaPhoto(media=img_bytes) for img_bytes in downloaded_images if img_bytes]
|
||||||
InputMediaPhoto(media=img_bytes)
|
|
||||||
for img_bytes in downloaded_images
|
|
||||||
if img_bytes
|
|
||||||
]
|
|
||||||
|
|
||||||
if media:
|
if media:
|
||||||
await status_message.edit(
|
await status_message.edit('Uploading pictures...', parse_mode=enums.ParseMode.MARKDOWN)
|
||||||
"Uploading pictures...", parse_mode=enums.ParseMode.MARKDOWN
|
|
||||||
)
|
|
||||||
while media:
|
while media:
|
||||||
batch = media[:10]
|
batch = media[:10]
|
||||||
media = media[10:]
|
media = media[10:]
|
||||||
await message.reply_media_group(batch)
|
await message.reply_media_group(batch)
|
||||||
await status_message.delete() # Delete status message after uploading
|
await status_message.delete() # Delete status message after uploading
|
||||||
else:
|
else:
|
||||||
await status_message.edit(
|
await status_message.edit('No valid images found.', parse_mode=enums.ParseMode.MARKDOWN)
|
||||||
"No valid images found.", parse_mode=enums.ParseMode.MARKDOWN
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
await status_message.edit(
|
await status_message.edit(
|
||||||
"No images found for the given query.",
|
'No images found for the given query.',
|
||||||
parse_mode=enums.ParseMode.MARKDOWN,
|
parse_mode=enums.ParseMode.MARKDOWN,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
await status_message.edit(
|
await status_message.edit(
|
||||||
"An error occurred, please try again later.",
|
'An error occurred, please try again later.',
|
||||||
parse_mode=enums.ParseMode.MARKDOWN,
|
parse_mode=enums.ParseMode.MARKDOWN,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
modules_help["unsplash2"] = {
|
modules_help['unsplash2'] = {
|
||||||
"unsplash2 [number]* [query]": "Get HD images. Default number of images is 10",
|
'unsplash2 [number]* [query]': 'Get HD images. Default number of images is 10',
|
||||||
"usp2 [number]* [query]": "Get HD images. Default number of images is 10",
|
'usp2 [number]* [query]': 'Get HD images. Default number of images is 10',
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-24
@@ -1,23 +1,23 @@
|
|||||||
from datetime import datetime
|
|
||||||
import sys
|
import sys
|
||||||
from pyrogram import Client
|
from datetime import datetime
|
||||||
|
|
||||||
|
from pyrogram import Client
|
||||||
from utils import config
|
from utils import config
|
||||||
|
|
||||||
common_params = {
|
common_params = {
|
||||||
"api_id": config.api_id,
|
'api_id': config.api_id,
|
||||||
"api_hash": config.api_hash,
|
'api_hash': config.api_hash,
|
||||||
"hide_password": True,
|
'hide_password': True,
|
||||||
"test_mode": config.test_server,
|
'test_mode': config.test_server,
|
||||||
}
|
}
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == '__main__':
|
||||||
if config.STRINGSESSION:
|
if config.STRINGSESSION:
|
||||||
common_params["session_string"] = config.STRINGSESSION
|
common_params['session_string'] = config.STRINGSESSION
|
||||||
|
|
||||||
app = Client("my_account", **common_params)
|
app = Client('my_account', **common_params)
|
||||||
|
|
||||||
if config.db_type in ["mongo", "mongodb"]:
|
if config.db_type in ['mongo', 'mongodb']:
|
||||||
from pymongo import MongoClient, errors
|
from pymongo import MongoClient, errors
|
||||||
|
|
||||||
db = MongoClient(config.db_url)
|
db = MongoClient(config.db_url)
|
||||||
@@ -26,27 +26,27 @@ if __name__ == "__main__":
|
|||||||
except errors.ConnectionFailure as e:
|
except errors.ConnectionFailure as e:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"MongoDB server isn't available! "
|
"MongoDB server isn't available! "
|
||||||
f"Provided url: {config.db_url}. "
|
f'Provided url: {config.db_url}. '
|
||||||
"Enter valid URL and restart installation"
|
'Enter valid URL and restart installation'
|
||||||
) from e
|
) from e
|
||||||
|
|
||||||
install_type = sys.argv[1] if len(sys.argv) > 1 else "3"
|
install_type = sys.argv[1] if len(sys.argv) > 1 else '3'
|
||||||
if install_type == "1":
|
if install_type == '1':
|
||||||
restart = "pm2 restart Moon"
|
restart = 'pm2 restart Moon'
|
||||||
elif install_type == "2":
|
elif install_type == '2':
|
||||||
restart = "sudo systemctl restart Moon"
|
restart = 'sudo systemctl restart Moon'
|
||||||
else:
|
else:
|
||||||
restart = "cd Moon-Userbot/ && python main.py"
|
restart = 'cd Moon-Userbot/ && python main.py'
|
||||||
|
|
||||||
app.start()
|
app.start()
|
||||||
try:
|
try:
|
||||||
app.send_message(
|
app.send_message(
|
||||||
"me",
|
'me',
|
||||||
f"<b>[{datetime.now()}] Userbot launched! \n"
|
f'<b>[{datetime.now()}] Userbot launched! \n'
|
||||||
"Custom modules: @moonub_modules\n"
|
'Custom modules: @moonub_modules\n'
|
||||||
f"For restart, enter:</b>\n"
|
f'For restart, enter:</b>\n'
|
||||||
f"<code>{restart}</code>",
|
f'<code>{restart}</code>',
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[ERROR]: Sending Message to me failed! {e}")
|
print(f'[ERROR]: Sending Message to me failed! {e}')
|
||||||
app.stop()
|
app.stop()
|
||||||
|
|||||||
+51
-60
@@ -39,92 +39,88 @@
|
|||||||
# "pySmartDL",
|
# "pySmartDL",
|
||||||
# ]
|
# ]
|
||||||
# ///
|
# ///
|
||||||
import os
|
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
import sqlite3
|
|
||||||
import platform
|
import platform
|
||||||
|
import sqlite3
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
from pyrogram import Client, idle, errors
|
|
||||||
from pyrogram.enums.parse_mode import ParseMode
|
|
||||||
from pyrogram.raw.functions.account import GetAuthorizations, DeleteAccount
|
|
||||||
import requests
|
import requests
|
||||||
|
from pyrogram import Client, errors, idle
|
||||||
|
from pyrogram.enums.parse_mode import ParseMode
|
||||||
|
from pyrogram.raw.functions.account import DeleteAccount, GetAuthorizations
|
||||||
from utils import config
|
from utils import config
|
||||||
from utils.db import db
|
from utils.db import db
|
||||||
from utils.misc import gitrepo, userbot_version
|
from utils.misc import userbot_version
|
||||||
from utils.scripts import restart
|
|
||||||
from utils.rentry import rentry_cleanup_job
|
|
||||||
from utils.module import ModuleManager
|
from utils.module import ModuleManager
|
||||||
|
from utils.rentry import rentry_cleanup_job
|
||||||
|
from utils.scripts import restart
|
||||||
|
|
||||||
SCRIPT_PATH = os.path.dirname(os.path.realpath(__file__))
|
SCRIPT_PATH = os.path.dirname(os.path.realpath(__file__))
|
||||||
if SCRIPT_PATH != os.getcwd():
|
if os.getcwd() != SCRIPT_PATH:
|
||||||
os.chdir(SCRIPT_PATH)
|
os.chdir(SCRIPT_PATH)
|
||||||
|
|
||||||
common_params = {
|
common_params = {
|
||||||
"api_id": config.api_id,
|
'api_id': config.api_id,
|
||||||
"api_hash": config.api_hash,
|
'api_hash': config.api_hash,
|
||||||
"hide_password": True,
|
'hide_password': True,
|
||||||
"workdir": SCRIPT_PATH,
|
'workdir': SCRIPT_PATH,
|
||||||
"app_version": userbot_version,
|
'app_version': userbot_version,
|
||||||
"device_model": f"mUserbot",
|
'device_model': 'mUserbot',
|
||||||
"system_version": platform.version() + " " + platform.machine(),
|
'system_version': platform.version() + ' ' + platform.machine(),
|
||||||
"sleep_threshold": 30,
|
'sleep_threshold': 30,
|
||||||
"test_mode": config.test_server,
|
'test_mode': config.test_server,
|
||||||
"parse_mode": ParseMode.HTML,
|
'parse_mode': ParseMode.HTML,
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.STRINGSESSION:
|
if config.STRINGSESSION:
|
||||||
common_params["session_string"] = config.STRINGSESSION
|
common_params['session_string'] = config.STRINGSESSION
|
||||||
|
|
||||||
app = Client("my_account", **common_params)
|
app = Client('my_account', **common_params)
|
||||||
|
|
||||||
|
|
||||||
def load_missing_modules():
|
def load_missing_modules():
|
||||||
all_modules = db.get("custom.modules", "allModules", [])
|
all_modules = db.get('custom.modules', 'allModules', [])
|
||||||
if not all_modules:
|
if not all_modules:
|
||||||
return
|
return
|
||||||
|
|
||||||
custom_modules_path = f"{SCRIPT_PATH}/modules/custom_modules"
|
custom_modules_path = f'{SCRIPT_PATH}/modules/custom_modules'
|
||||||
os.makedirs(custom_modules_path, exist_ok=True)
|
os.makedirs(custom_modules_path, exist_ok=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
resp = requests.get(
|
resp = 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,
|
timeout=10,
|
||||||
)
|
)
|
||||||
if not resp.ok:
|
if not resp.ok:
|
||||||
logging.error(
|
logging.error(
|
||||||
"Failed to fetch custom modules list: HTTP %s",
|
'Failed to fetch custom modules list: HTTP %s',
|
||||||
resp.status_code,
|
resp.status_code,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
f = resp.text
|
f = resp.text
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.error("Failed to fetch custom modules list: %s", e)
|
logging.error('Failed to fetch custom modules list: %s', e)
|
||||||
return
|
return
|
||||||
modules_dict = {
|
modules_dict = {line.split('/')[-1].split()[0]: line.strip() for line in f.splitlines()}
|
||||||
line.split("/")[-1].split()[0]: line.strip() for line in f.splitlines()
|
|
||||||
}
|
|
||||||
|
|
||||||
for module_name in all_modules:
|
for module_name in all_modules:
|
||||||
module_path = f"{custom_modules_path}/{module_name}.py"
|
module_path = f'{custom_modules_path}/{module_name}.py'
|
||||||
if not os.path.exists(module_path) and module_name in modules_dict:
|
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"
|
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)
|
||||||
if resp.ok:
|
if resp.ok:
|
||||||
with open(module_path, "wb") as f:
|
with open(module_path, 'wb') as f:
|
||||||
f.write(resp.content)
|
f.write(resp.content)
|
||||||
logging.info("Loaded missing module: %s", module_name)
|
logging.info('Loaded missing module: %s', module_name)
|
||||||
else:
|
else:
|
||||||
logging.warning("Failed to load module: %s", module_name)
|
logging.warning('Failed to load module: %s', module_name)
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||||
handlers=[logging.FileHandler("moonlogs.txt"), logging.StreamHandler()],
|
handlers=[logging.FileHandler('moonlogs.txt'), logging.StreamHandler()],
|
||||||
level=logging.INFO,
|
level=logging.INFO,
|
||||||
)
|
)
|
||||||
DeleteAccount.__new__ = None
|
DeleteAccount.__new__ = None
|
||||||
@@ -132,49 +128,44 @@ async def main():
|
|||||||
try:
|
try:
|
||||||
await app.start()
|
await app.start()
|
||||||
except sqlite3.OperationalError as e:
|
except sqlite3.OperationalError as e:
|
||||||
if str(e) == "database is locked" and os.name == "posix":
|
if str(e) == 'database is locked' and os.name == 'posix':
|
||||||
logging.warning(
|
logging.warning('Session file is locked. Trying to kill blocking process...')
|
||||||
"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)
|
|
||||||
restart()
|
restart()
|
||||||
raise
|
raise
|
||||||
except (errors.NotAcceptable, errors.Unauthorized) as e:
|
except (errors.NotAcceptable, errors.Unauthorized) as e:
|
||||||
logging.error(
|
logging.error(
|
||||||
"%s: %s\nMoving session file to my_account.session-old...",
|
'%s: %s\nMoving session file to my_account.session-old...',
|
||||||
e.__class__.__name__,
|
e.__class__.__name__,
|
||||||
e,
|
e,
|
||||||
)
|
)
|
||||||
os.rename("./my_account.session", "./my_account.session-old")
|
os.rename('./my_account.session', './my_account.session-old')
|
||||||
restart()
|
restart()
|
||||||
|
|
||||||
load_missing_modules()
|
load_missing_modules()
|
||||||
module_manager = ModuleManager.get_instance()
|
module_manager = ModuleManager.get_instance()
|
||||||
await module_manager.load_modules(app)
|
await module_manager.load_modules(app)
|
||||||
|
|
||||||
if info := db.get("core.updater", "restart_info"):
|
if info := db.get('core.updater', 'restart_info'):
|
||||||
text = {
|
text = {
|
||||||
"restart": "<b>Restart completed!</b>",
|
'restart': '<b>Restart completed!</b>',
|
||||||
"update": "<b>Update process completed!</b>",
|
'update': '<b>Update process completed!</b>',
|
||||||
}[info["type"]]
|
}[info['type']]
|
||||||
try:
|
try:
|
||||||
await app.edit_message_text(info["chat_id"], info["message_id"], text)
|
await app.edit_message_text(info['chat_id'], info['message_id'], text)
|
||||||
except errors.RPCError:
|
except errors.RPCError:
|
||||||
pass
|
pass
|
||||||
db.remove("core.updater", "restart_info")
|
db.remove('core.updater', 'restart_info')
|
||||||
|
|
||||||
# required for sessionkiller module
|
# required for sessionkiller module
|
||||||
if db.get("core.sessionkiller", "enabled", False):
|
if db.get('core.sessionkiller', 'enabled', False):
|
||||||
db.set(
|
db.set(
|
||||||
"core.sessionkiller",
|
'core.sessionkiller',
|
||||||
"auths_hashes",
|
'auths_hashes',
|
||||||
[
|
[auth.hash for auth in (await app.invoke(GetAuthorizations())).authorizations],
|
||||||
auth.hash
|
|
||||||
for auth in (await app.invoke(GetAuthorizations())).authorizations
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
|
||||||
logging.info("Moon-Userbot started!")
|
logging.info('Moon-Userbot started!')
|
||||||
|
|
||||||
app.loop.create_task(rentry_cleanup_job())
|
app.loop.create_task(rentry_cleanup_job())
|
||||||
|
|
||||||
@@ -183,5 +174,5 @@ async def main():
|
|||||||
await app.stop()
|
await app.stop()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == '__main__':
|
||||||
app.run(main())
|
app.run(main())
|
||||||
|
|||||||
@@ -2,20 +2,16 @@ from asyncio import sleep
|
|||||||
|
|
||||||
from pyrogram import Client, filters
|
from pyrogram import Client, filters
|
||||||
from pyrogram.types import Message
|
from pyrogram.types import Message
|
||||||
|
|
||||||
from utils.misc import modules_help, prefix
|
from utils.misc import modules_help, prefix
|
||||||
|
|
||||||
digits = {
|
digits = {str(i): el for i, el in enumerate(['0️⃣', '1️⃣', '2️⃣', '3️⃣', '4️⃣', '5️⃣', '6️⃣', '7️⃣', '8️⃣', '9️⃣'])}
|
||||||
str(i): el
|
|
||||||
for i, el in enumerate(["0️⃣", "1️⃣", "2️⃣", "3️⃣", "4️⃣", "5️⃣", "6️⃣", "7️⃣", "8️⃣", "9️⃣"])
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def prettify(val: int) -> str:
|
def prettify(val: int) -> str:
|
||||||
return "".join(digits[i] for i in str(val))
|
return ''.join(digits[i] for i in str(val))
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command("ghoul", prefix) & filters.me)
|
@Client.on_message(filters.command('ghoul', prefix) & filters.me)
|
||||||
async def ghoul_counter(_, message: Message):
|
async def ghoul_counter(_, message: Message):
|
||||||
await message.delete()
|
await message.delete()
|
||||||
|
|
||||||
@@ -33,9 +29,7 @@ async def ghoul_counter(_, message: Message):
|
|||||||
await msg.edit(prettify(counter))
|
await msg.edit(prettify(counter))
|
||||||
await sleep(1)
|
await sleep(1)
|
||||||
|
|
||||||
await msg.edit("<b>🤡 GHOUL 🤡</b>")
|
await msg.edit('<b>🤡 GHOUL 🤡</b>')
|
||||||
|
|
||||||
|
|
||||||
modules_help["1000-7"] = {
|
modules_help['1000-7'] = {'ghoul [count_from]': 'counting from 1000 (or given [count_from] to 0 as a ghoul'}
|
||||||
"ghoul [count_from]": "counting from 1000 (or given [count_from] to 0 as a ghoul"
|
|
||||||
}
|
|
||||||
|
|||||||
+93
-104
@@ -16,60 +16,57 @@
|
|||||||
|
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
|
|
||||||
from pyrogram.enums import ChatType
|
|
||||||
from pyrogram import Client, ContinuePropagation, filters
|
from pyrogram import Client, ContinuePropagation, filters
|
||||||
|
from pyrogram.enums import ChatType
|
||||||
from pyrogram.errors import (
|
from pyrogram.errors import (
|
||||||
UserAdminInvalid,
|
|
||||||
ChatAdminRequired,
|
ChatAdminRequired,
|
||||||
RPCError,
|
RPCError,
|
||||||
|
UserAdminInvalid,
|
||||||
)
|
)
|
||||||
from pyrogram.raw import functions
|
from pyrogram.raw import functions
|
||||||
from pyrogram.types import Message, ChatPermissions
|
from pyrogram.types import ChatPermissions, Message
|
||||||
|
|
||||||
from utils.db import db
|
from utils.db import db
|
||||||
from utils.scripts import format_exc, with_reply
|
|
||||||
from utils.misc import modules_help, prefix
|
|
||||||
|
|
||||||
from utils.handlers import (
|
from utils.handlers import (
|
||||||
BanHandler,
|
|
||||||
UnbanHandler,
|
|
||||||
KickHandler,
|
|
||||||
KickDeletedAccountsHandler,
|
|
||||||
TimeMuteHandler,
|
|
||||||
TimeUnmuteHandler,
|
|
||||||
TimeMuteUsersHandler,
|
|
||||||
UnmuteHandler,
|
|
||||||
MuteHandler,
|
|
||||||
DemoteHandler,
|
|
||||||
PromoteHandler,
|
|
||||||
AntiChannelsHandler,
|
AntiChannelsHandler,
|
||||||
DeleteHistoryHandler,
|
|
||||||
AntiRaidHandler,
|
AntiRaidHandler,
|
||||||
|
BanHandler,
|
||||||
|
DeleteHistoryHandler,
|
||||||
|
DemoteHandler,
|
||||||
|
KickDeletedAccountsHandler,
|
||||||
|
KickHandler,
|
||||||
|
MuteHandler,
|
||||||
|
PromoteHandler,
|
||||||
|
TimeMuteHandler,
|
||||||
|
TimeMuteUsersHandler,
|
||||||
|
TimeUnmuteHandler,
|
||||||
|
UnbanHandler,
|
||||||
|
UnmuteHandler,
|
||||||
)
|
)
|
||||||
|
from utils.misc import modules_help, prefix
|
||||||
|
from utils.scripts import format_exc, with_reply
|
||||||
|
|
||||||
|
db_cache: dict = db.get_collection('core.ats')
|
||||||
db_cache: dict = db.get_collection("core.ats")
|
|
||||||
|
|
||||||
|
|
||||||
def update_cache():
|
def update_cache():
|
||||||
db_cache.clear()
|
db_cache.clear()
|
||||||
db_cache.update(db.get_collection("core.ats"))
|
db_cache.update(db.get_collection('core.ats'))
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.group & ~filters.me)
|
@Client.on_message(filters.group & ~filters.me)
|
||||||
async def admintool_handler(_, message: Message):
|
async def admintool_handler(_, message: Message):
|
||||||
if message.sender_chat and (
|
if message.sender_chat and (
|
||||||
message.sender_chat.type == "supergroup"
|
message.sender_chat.type == 'supergroup'
|
||||||
or message.sender_chat.id == db_cache.get(f"linked{message.chat.id}", 0)
|
or message.sender_chat.id == db_cache.get(f'linked{message.chat.id}', 0)
|
||||||
):
|
):
|
||||||
raise ContinuePropagation
|
raise ContinuePropagation
|
||||||
|
|
||||||
if message.sender_chat and db_cache.get(f"antich{message.chat.id}", False):
|
if message.sender_chat and db_cache.get(f'antich{message.chat.id}', False):
|
||||||
with suppress(RPCError):
|
with suppress(RPCError):
|
||||||
await message.delete()
|
await message.delete()
|
||||||
await message.chat.ban_member(message.sender_chat.id)
|
await message.chat.ban_member(message.sender_chat.id)
|
||||||
|
|
||||||
tmuted_users = db_cache.get(f"c{message.chat.id}", [])
|
tmuted_users = db_cache.get(f'c{message.chat.id}', [])
|
||||||
if (
|
if (
|
||||||
message.from_user
|
message.from_user
|
||||||
and message.from_user.id in tmuted_users
|
and message.from_user.id in tmuted_users
|
||||||
@@ -79,7 +76,7 @@ async def admintool_handler(_, message: Message):
|
|||||||
with suppress(RPCError):
|
with suppress(RPCError):
|
||||||
await message.delete()
|
await message.delete()
|
||||||
|
|
||||||
if db_cache.get(f"antiraid{message.chat.id}", False):
|
if db_cache.get(f'antiraid{message.chat.id}', False):
|
||||||
with suppress(RPCError):
|
with suppress(RPCError):
|
||||||
await message.delete()
|
await message.delete()
|
||||||
if message.from_user:
|
if message.from_user:
|
||||||
@@ -87,11 +84,9 @@ async def admintool_handler(_, message: Message):
|
|||||||
elif message.sender_chat:
|
elif message.sender_chat:
|
||||||
await message.chat.ban_member(message.sender_chat.id)
|
await message.chat.ban_member(message.sender_chat.id)
|
||||||
|
|
||||||
if message.new_chat_members and db_cache.get(
|
if message.new_chat_members and db_cache.get(f'welcome_enabled{message.chat.id}', False):
|
||||||
f"welcome_enabled{message.chat.id}", False
|
|
||||||
):
|
|
||||||
await message.reply(
|
await message.reply(
|
||||||
db_cache.get(f"welcome_text{message.chat.id}"),
|
db_cache.get(f'welcome_text{message.chat.id}'),
|
||||||
disable_web_page_preview=True,
|
disable_web_page_preview=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -111,88 +106,88 @@ async def get_user_and_name(message):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command(["ban"], prefix) & filters.me)
|
@Client.on_message(filters.command(['ban'], prefix) & filters.me)
|
||||||
async def ban_command(client: Client, message: Message):
|
async def ban_command(client: Client, message: Message):
|
||||||
handler = BanHandler(client, message)
|
handler = BanHandler(client, message)
|
||||||
await handler.handle_ban()
|
await handler.handle_ban()
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command(["unban"], prefix) & filters.me)
|
@Client.on_message(filters.command(['unban'], prefix) & filters.me)
|
||||||
async def unban_command(client: Client, message: Message):
|
async def unban_command(client: Client, message: Message):
|
||||||
handler = UnbanHandler(client, message)
|
handler = UnbanHandler(client, message)
|
||||||
await handler.handle_unban()
|
await handler.handle_unban()
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command(["kick"], prefix) & filters.me)
|
@Client.on_message(filters.command(['kick'], prefix) & filters.me)
|
||||||
async def kick_command(client: Client, message: Message):
|
async def kick_command(client: Client, message: Message):
|
||||||
handler = KickHandler(client, message)
|
handler = KickHandler(client, message)
|
||||||
await handler.handle_kick()
|
await handler.handle_kick()
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command(["kickdel"], prefix) & filters.me)
|
@Client.on_message(filters.command(['kickdel'], prefix) & filters.me)
|
||||||
async def kickdel_cmd(client: Client, message: Message):
|
async def kickdel_cmd(client: Client, message: Message):
|
||||||
handler = KickDeletedAccountsHandler(client, message)
|
handler = KickDeletedAccountsHandler(client, message)
|
||||||
await handler.kick_deleted_accounts()
|
await handler.kick_deleted_accounts()
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command(["tmute"], prefix) & filters.me)
|
@Client.on_message(filters.command(['tmute'], prefix) & filters.me)
|
||||||
async def tmute_command(client: Client, message: Message):
|
async def tmute_command(client: Client, message: Message):
|
||||||
handler = TimeMuteHandler(client, message)
|
handler = TimeMuteHandler(client, message)
|
||||||
await handler.handle_tmute()
|
await handler.handle_tmute()
|
||||||
update_cache()
|
update_cache()
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command(["tunmute"], prefix) & filters.me)
|
@Client.on_message(filters.command(['tunmute'], prefix) & filters.me)
|
||||||
async def tunmute_command(client: Client, message: Message):
|
async def tunmute_command(client: Client, message: Message):
|
||||||
handler = TimeUnmuteHandler(client, message)
|
handler = TimeUnmuteHandler(client, message)
|
||||||
await handler.handle_tunmute()
|
await handler.handle_tunmute()
|
||||||
update_cache()
|
update_cache()
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command(["tmute_users"], prefix) & filters.me)
|
@Client.on_message(filters.command(['tmute_users'], prefix) & filters.me)
|
||||||
async def tunmute_users_command(client: Client, message: Message):
|
async def tunmute_users_command(client: Client, message: Message):
|
||||||
handler = TimeMuteUsersHandler(client, message)
|
handler = TimeMuteUsersHandler(client, message)
|
||||||
await handler.list_tmuted_users()
|
await handler.list_tmuted_users()
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command(["unmute"], prefix) & filters.me)
|
@Client.on_message(filters.command(['unmute'], prefix) & filters.me)
|
||||||
async def unmute_command(client: Client, message: Message):
|
async def unmute_command(client: Client, message: Message):
|
||||||
handler = UnmuteHandler(client, message)
|
handler = UnmuteHandler(client, message)
|
||||||
await handler.handle_unmute()
|
await handler.handle_unmute()
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command(["mute"], prefix) & filters.me)
|
@Client.on_message(filters.command(['mute'], prefix) & filters.me)
|
||||||
async def mute_command(client: Client, message: Message):
|
async def mute_command(client: Client, message: Message):
|
||||||
handler = MuteHandler(client, message)
|
handler = MuteHandler(client, message)
|
||||||
await handler.handle_mute()
|
await handler.handle_mute()
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command(["demote"], prefix) & filters.me)
|
@Client.on_message(filters.command(['demote'], prefix) & filters.me)
|
||||||
async def demote_command(client: Client, message: Message):
|
async def demote_command(client: Client, message: Message):
|
||||||
handler = DemoteHandler(client, message)
|
handler = DemoteHandler(client, message)
|
||||||
await handler.handle_demote()
|
await handler.handle_demote()
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command(["promote"], prefix) & filters.me)
|
@Client.on_message(filters.command(['promote'], prefix) & filters.me)
|
||||||
async def promote_command(client: Client, message: Message):
|
async def promote_command(client: Client, message: Message):
|
||||||
handler = PromoteHandler(client, message)
|
handler = PromoteHandler(client, message)
|
||||||
await handler.handle_promote()
|
await handler.handle_promote()
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command(["antich"], prefix))
|
@Client.on_message(filters.command(['antich'], prefix))
|
||||||
async def anti_channels(client: Client, message: Message):
|
async def anti_channels(client: Client, message: Message):
|
||||||
handler = AntiChannelsHandler(client, message)
|
handler = AntiChannelsHandler(client, message)
|
||||||
await handler.handle_anti_channels()
|
await handler.handle_anti_channels()
|
||||||
update_cache()
|
update_cache()
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command(["delete_history", "dh"], prefix))
|
@Client.on_message(filters.command(['delete_history', 'dh'], prefix))
|
||||||
async def delete_history(client: Client, message: Message):
|
async def delete_history(client: Client, message: Message):
|
||||||
handler = DeleteHistoryHandler(client, message)
|
handler = DeleteHistoryHandler(client, message)
|
||||||
await handler.handle_delete_history()
|
await handler.handle_delete_history()
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command(["report_spam", "rs"], prefix))
|
@Client.on_message(filters.command(['report_spam', 'rs'], prefix))
|
||||||
@with_reply
|
@with_reply
|
||||||
async def report_spam(client: Client, message: Message):
|
async def report_spam(client: Client, message: Message):
|
||||||
try:
|
try:
|
||||||
@@ -210,33 +205,33 @@ async def report_spam(client: Client, message: Message):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
await message.edit(format_exc(e))
|
await message.edit(format_exc(e))
|
||||||
else:
|
else:
|
||||||
await message.edit(f"<b>Message</a> from {name} was reported</b>")
|
await message.edit(f'<b>Message</a> from {name} was reported</b>')
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command("pin", prefix) & filters.me)
|
@Client.on_message(filters.command('pin', prefix) & filters.me)
|
||||||
@with_reply
|
@with_reply
|
||||||
async def pin(_, message: Message):
|
async def pin(_, message: Message):
|
||||||
try:
|
try:
|
||||||
await message.reply_to_message.pin()
|
await message.reply_to_message.pin()
|
||||||
await message.edit("<b>Pinned!</b>")
|
await message.edit('<b>Pinned!</b>')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await message.edit(format_exc(e))
|
await message.edit(format_exc(e))
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command("unpin", prefix) & filters.me)
|
@Client.on_message(filters.command('unpin', prefix) & filters.me)
|
||||||
@with_reply
|
@with_reply
|
||||||
async def unpin(_, message: Message):
|
async def unpin(_, message: Message):
|
||||||
try:
|
try:
|
||||||
await message.reply_to_message.unpin()
|
await message.reply_to_message.unpin()
|
||||||
await message.edit("<b>Unpinned!</b>")
|
await message.edit('<b>Unpinned!</b>')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await message.edit(format_exc(e))
|
await message.edit(format_exc(e))
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command("ro", prefix) & filters.me)
|
@Client.on_message(filters.command('ro', prefix) & filters.me)
|
||||||
async def ro(client: Client, message: Message):
|
async def ro(client: Client, message: Message):
|
||||||
if message.chat.type not in [ChatType.GROUP, ChatType.SUPERGROUP]:
|
if message.chat.type not in [ChatType.GROUP, ChatType.SUPERGROUP]:
|
||||||
await message.edit("<b>Invalid chat type</b>")
|
await message.edit('<b>Invalid chat type</b>')
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -250,42 +245,39 @@ async def ro(client: Client, message: Message):
|
|||||||
perms.can_invite_users,
|
perms.can_invite_users,
|
||||||
perms.can_pin_messages,
|
perms.can_pin_messages,
|
||||||
]
|
]
|
||||||
db.set("core.ats", f"ro{message.chat.id}", perms_list)
|
db.set('core.ats', f'ro{message.chat.id}', perms_list)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await client.set_chat_permissions(message.chat.id, ChatPermissions())
|
await client.set_chat_permissions(message.chat.id, ChatPermissions())
|
||||||
except (UserAdminInvalid, ChatAdminRequired):
|
except (UserAdminInvalid, ChatAdminRequired):
|
||||||
await message.edit("<b>No rights</b>")
|
await message.edit('<b>No rights</b>')
|
||||||
else:
|
else:
|
||||||
await message.edit(
|
await message.edit(f'<b>Read-only mode activated!\nTurn off with:</b><code>{prefix}unro</code>')
|
||||||
"<b>Read-only mode activated!\n"
|
|
||||||
f"Turn off with:</b><code>{prefix}unro</code>"
|
|
||||||
)
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await message.edit(format_exc(e))
|
await message.edit(format_exc(e))
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command("unro", prefix) & filters.me)
|
@Client.on_message(filters.command('unro', prefix) & filters.me)
|
||||||
async def unro(client: Client, message: Message):
|
async def unro(client: Client, message: Message):
|
||||||
if message.chat.type not in [ChatType.GROUP, ChatType.SUPERGROUP]:
|
if message.chat.type not in [ChatType.GROUP, ChatType.SUPERGROUP]:
|
||||||
await message.edit("<b>Invalid chat type</b>")
|
await message.edit('<b>Invalid chat type</b>')
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
perms_list = db.get(
|
perms_list = db.get(
|
||||||
"core.ats",
|
'core.ats',
|
||||||
f"ro{message.chat.id}",
|
f'ro{message.chat.id}',
|
||||||
[True, True, False, False, False, False, False],
|
[True, True, False, False, False, False, False],
|
||||||
)
|
)
|
||||||
|
|
||||||
common_perms = {
|
common_perms = {
|
||||||
"can_send_messages": perms_list[0],
|
'can_send_messages': perms_list[0],
|
||||||
"can_send_media_messages": perms_list[1],
|
'can_send_media_messages': perms_list[1],
|
||||||
"can_send_polls": perms_list[2],
|
'can_send_polls': perms_list[2],
|
||||||
"can_add_web_page_previews": perms_list[3],
|
'can_add_web_page_previews': perms_list[3],
|
||||||
"can_change_info": perms_list[4],
|
'can_change_info': perms_list[4],
|
||||||
"can_invite_users": perms_list[5],
|
'can_invite_users': perms_list[5],
|
||||||
"can_pin_messages": perms_list[6],
|
'can_pin_messages': perms_list[6],
|
||||||
}
|
}
|
||||||
|
|
||||||
perms = ChatPermissions(**common_perms)
|
perms = ChatPermissions(**common_perms)
|
||||||
@@ -293,61 +285,58 @@ async def unro(client: Client, message: Message):
|
|||||||
try:
|
try:
|
||||||
await client.set_chat_permissions(message.chat.id, perms)
|
await client.set_chat_permissions(message.chat.id, perms)
|
||||||
except (UserAdminInvalid, ChatAdminRequired):
|
except (UserAdminInvalid, ChatAdminRequired):
|
||||||
await message.edit("<b>No rights</b>")
|
await message.edit('<b>No rights</b>')
|
||||||
else:
|
else:
|
||||||
await message.edit("<b>Read-only mode disabled!</b>")
|
await message.edit('<b>Read-only mode disabled!</b>')
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await message.edit(format_exc(e))
|
await message.edit(format_exc(e))
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command("antiraid", prefix) & filters.me)
|
@Client.on_message(filters.command('antiraid', prefix) & filters.me)
|
||||||
async def antiraid(client: Client, message: Message):
|
async def antiraid(client: Client, message: Message):
|
||||||
handler = AntiRaidHandler(client, message)
|
handler = AntiRaidHandler(client, message)
|
||||||
await handler.handle_antiraid()
|
await handler.handle_antiraid()
|
||||||
update_cache()
|
update_cache()
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command(["welcome", "wc"], prefix) & filters.me)
|
@Client.on_message(filters.command(['welcome', 'wc'], prefix) & filters.me)
|
||||||
async def welcome(_, message: Message):
|
async def welcome(_, message: Message):
|
||||||
if message.chat.type not in [ChatType.GROUP, ChatType.SUPERGROUP]:
|
if message.chat.type not in [ChatType.GROUP, ChatType.SUPERGROUP]:
|
||||||
return await message.edit("<b>Unsupported chat type</b>")
|
return await message.edit('<b>Unsupported chat type</b>')
|
||||||
|
|
||||||
if len(message.command) > 1:
|
if len(message.command) > 1:
|
||||||
text = message.text.split(maxsplit=1)[1]
|
text = message.text.split(maxsplit=1)[1]
|
||||||
db.set("core.ats", f"welcome_enabled{message.chat.id}", True)
|
db.set('core.ats', f'welcome_enabled{message.chat.id}', True)
|
||||||
db.set("core.ats", f"welcome_text{message.chat.id}", text)
|
db.set('core.ats', f'welcome_text{message.chat.id}', text)
|
||||||
|
|
||||||
await message.edit(
|
await message.edit(f'<b>Welcome enabled in this chat\nText:</b> <code>{text}</code>')
|
||||||
f"<b>Welcome enabled in this chat\nText:</b> <code>{text}</code>"
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
db.set("core.ats", f"welcome_enabled{message.chat.id}", False)
|
db.set('core.ats', f'welcome_enabled{message.chat.id}', False)
|
||||||
await message.edit("<b>Welcome disabled in this chat</b>")
|
await message.edit('<b>Welcome disabled in this chat</b>')
|
||||||
|
|
||||||
update_cache()
|
update_cache()
|
||||||
|
|
||||||
|
|
||||||
modules_help["admintool"] = {
|
modules_help['admintool'] = {
|
||||||
"ban [reply]/[username/id]* [reason] [report_spam] [delete_history]": "ban user in chat",
|
'ban [reply]/[username/id]* [reason] [report_spam] [delete_history]': 'ban user in chat',
|
||||||
"unban [reply]/[username/id]* [reason]": "unban user in chat",
|
'unban [reply]/[username/id]* [reason]': 'unban user in chat',
|
||||||
"kick [reply]/[userid]* [reason] [report_spam] [delete_history]": "kick user out of chat",
|
'kick [reply]/[userid]* [reason] [report_spam] [delete_history]': 'kick user out of chat',
|
||||||
"mute [reply]/[userid]* [reason] [1m]/[1h]/[1d]/[1w]": "mute user in chat",
|
'mute [reply]/[userid]* [reason] [1m]/[1h]/[1d]/[1w]': 'mute user in chat',
|
||||||
"unmute [reply]/[userid]* [reason]": "unmute user in chat",
|
'unmute [reply]/[userid]* [reason]': 'unmute user in chat',
|
||||||
"promote [reply]/[userid]* [prefix]": "promote user in chat",
|
'promote [reply]/[userid]* [prefix]': 'promote user in chat',
|
||||||
"demote [reply]/[userid]* [reason]": "demote user in chat",
|
'demote [reply]/[userid]* [reason]': 'demote user in chat',
|
||||||
"tmute [reply]/[username/id]* [reason]": "delete all new messages from user in chat",
|
'tmute [reply]/[username/id]* [reason]': 'delete all new messages from user in chat',
|
||||||
"tunmute [reply]/[username/id]* [reason]": "stop deleting all messages from user in chat",
|
'tunmute [reply]/[username/id]* [reason]': 'stop deleting all messages from user in chat',
|
||||||
"tmute_users": "list of tmuted (.tmute) users",
|
'tmute_users': 'list of tmuted (.tmute) users',
|
||||||
"antich [enable/disable]": "turn on/off blocking channels in this chat",
|
'antich [enable/disable]': 'turn on/off blocking channels in this chat',
|
||||||
"delete_history [reply]/[username/id]* [reason]": "delete history from member in chat",
|
'delete_history [reply]/[username/id]* [reason]': 'delete history from member in chat',
|
||||||
"report_spam [reply]*": "report spam message in chat",
|
'report_spam [reply]*': 'report spam message in chat',
|
||||||
"pin [reply]*": "Pin replied message",
|
'pin [reply]*': 'Pin replied message',
|
||||||
"unpin [reply]*": "Unpin replied message",
|
'unpin [reply]*': 'Unpin replied message',
|
||||||
"ro": "enable read-only mode",
|
'ro': 'enable read-only mode',
|
||||||
"unro": "disable read-only mode",
|
'unro': 'disable read-only mode',
|
||||||
"antiraid [on|off]": "when enabled, anyone who writes message will be blocked. Useful in raids. "
|
'antiraid [on|off]': 'when enabled, anyone who writes message will be blocked. Useful in raids. '
|
||||||
"Running without arguments equals to toggling state",
|
'Running without arguments equals to toggling state',
|
||||||
"welcome [text]*": "enable auto-welcome to new users in groups. "
|
'welcome [text]*': 'enable auto-welcome to new users in groups. Running without text equals to disable',
|
||||||
"Running without text equals to disable",
|
'kickdel': 'Kick all deleted accounts',
|
||||||
"kickdel": "Kick all deleted accounts",
|
|
||||||
}
|
}
|
||||||
|
|||||||
+84
-104
@@ -14,12 +14,12 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from collections.abc import AsyncGenerator
|
||||||
from time import perf_counter
|
from time import perf_counter
|
||||||
from typing import AsyncGenerator, List, Optional, Union
|
from typing import Optional
|
||||||
|
|
||||||
from pyrogram import Client, enums, filters, raw, types, utils
|
from pyrogram import Client, enums, filters, raw, types, utils
|
||||||
from pyrogram.types.object import Object
|
from pyrogram.types.object import Object
|
||||||
|
|
||||||
from utils.misc import modules_help, prefix
|
from utils.misc import modules_help, prefix
|
||||||
from utils.scripts import format_exc
|
from utils.scripts import format_exc
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ class Chat(Object):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
client: "Client" = None,
|
client: 'Client' = None,
|
||||||
id: id,
|
id: id,
|
||||||
type: type,
|
type: type,
|
||||||
is_verified: bool = None,
|
is_verified: bool = None,
|
||||||
@@ -41,7 +41,7 @@ class Chat(Object):
|
|||||||
username: str = None,
|
username: str = None,
|
||||||
first_name: str = None,
|
first_name: str = None,
|
||||||
last_name: str = None,
|
last_name: str = None,
|
||||||
photo: "types.ChatPhoto" = None,
|
photo: 'types.ChatPhoto' = None,
|
||||||
bio: str = None,
|
bio: str = None,
|
||||||
description: str = None,
|
description: str = None,
|
||||||
dc_id: int = None,
|
dc_id: int = None,
|
||||||
@@ -51,12 +51,12 @@ class Chat(Object):
|
|||||||
sticker_set_name: str = None,
|
sticker_set_name: str = None,
|
||||||
can_set_sticker_set: bool = None,
|
can_set_sticker_set: bool = None,
|
||||||
members_count: int = None,
|
members_count: int = None,
|
||||||
restrictions: List["types.Restriction"] = None,
|
restrictions: list['types.Restriction'] = None,
|
||||||
permissions: "types.ChatPermissions" = None,
|
permissions: 'types.ChatPermissions' = None,
|
||||||
distance: int = None,
|
distance: int = None,
|
||||||
linked_chat: "types.Chat" = None,
|
linked_chat: 'types.Chat' = None,
|
||||||
send_as_chat: "types.Chat" = None,
|
send_as_chat: 'types.Chat' = None,
|
||||||
available_reactions: Optional["types.ChatReactions"] = None,
|
available_reactions: Optional['types.ChatReactions'] = None,
|
||||||
is_admin: bool = False,
|
is_admin: bool = False,
|
||||||
deactivated: bool = False,
|
deactivated: bool = False,
|
||||||
):
|
):
|
||||||
@@ -94,98 +94,82 @@ class Chat(Object):
|
|||||||
self.deactivated = deactivated
|
self.deactivated = deactivated
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse_user_chat(client, user: raw.types.User) -> "Chat":
|
def _parse_user_chat(client, user: raw.types.User) -> 'Chat':
|
||||||
peer_id = user.id
|
peer_id = user.id
|
||||||
|
|
||||||
return Chat(
|
return Chat(
|
||||||
id=peer_id,
|
id=peer_id,
|
||||||
type=enums.ChatType.BOT if user.bot else enums.ChatType.PRIVATE,
|
type=enums.ChatType.BOT if user.bot else enums.ChatType.PRIVATE,
|
||||||
is_verified=getattr(user, "verified", None),
|
is_verified=getattr(user, 'verified', None),
|
||||||
is_restricted=getattr(user, "restricted", None),
|
is_restricted=getattr(user, 'restricted', None),
|
||||||
is_scam=getattr(user, "scam", None),
|
is_scam=getattr(user, 'scam', None),
|
||||||
is_fake=getattr(user, "fake", None),
|
is_fake=getattr(user, 'fake', None),
|
||||||
is_support=getattr(user, "support", None),
|
is_support=getattr(user, 'support', None),
|
||||||
username=user.username,
|
username=user.username,
|
||||||
first_name=user.first_name,
|
first_name=user.first_name,
|
||||||
last_name=user.last_name,
|
last_name=user.last_name,
|
||||||
photo=types.ChatPhoto._parse(client, user.photo, peer_id, user.access_hash),
|
photo=types.ChatPhoto._parse(client, user.photo, peer_id, user.access_hash),
|
||||||
restrictions=types.List(
|
restrictions=types.List([types.Restriction._parse(r) for r in user.restriction_reason]) or None,
|
||||||
[types.Restriction._parse(r) for r in user.restriction_reason]
|
dc_id=getattr(getattr(user, 'photo', None), 'dc_id', None),
|
||||||
)
|
|
||||||
or None,
|
|
||||||
dc_id=getattr(getattr(user, "photo", None), "dc_id", None),
|
|
||||||
client=client,
|
client=client,
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse_chat_chat(client, chat: raw.types.Chat) -> "Chat":
|
def _parse_chat_chat(client, chat: raw.types.Chat) -> 'Chat':
|
||||||
peer_id = -chat.id
|
peer_id = -chat.id
|
||||||
return Chat(
|
return Chat(
|
||||||
id=peer_id,
|
id=peer_id,
|
||||||
type=enums.ChatType.GROUP,
|
type=enums.ChatType.GROUP,
|
||||||
title=chat.title,
|
title=chat.title,
|
||||||
is_creator=getattr(chat, "creator", None),
|
is_creator=getattr(chat, 'creator', None),
|
||||||
photo=types.ChatPhoto._parse(
|
photo=types.ChatPhoto._parse(client, getattr(chat, 'photo', None), peer_id, 0),
|
||||||
client, getattr(chat, "photo", None), peer_id, 0
|
permissions=types.ChatPermissions._parse(getattr(chat, 'default_banned_rights', None)),
|
||||||
),
|
members_count=getattr(chat, 'participants_count', None),
|
||||||
permissions=types.ChatPermissions._parse(
|
dc_id=getattr(getattr(chat, 'photo', None), 'dc_id', None),
|
||||||
getattr(chat, "default_banned_rights", None)
|
has_protected_content=getattr(chat, 'noforwards', None),
|
||||||
),
|
|
||||||
members_count=getattr(chat, "participants_count", None),
|
|
||||||
dc_id=getattr(getattr(chat, "photo", None), "dc_id", None),
|
|
||||||
has_protected_content=getattr(chat, "noforwards", None),
|
|
||||||
client=client,
|
client=client,
|
||||||
is_admin=bool(getattr(chat, "admin_rights", False)),
|
is_admin=bool(getattr(chat, 'admin_rights', False)),
|
||||||
deactivated=chat.deactivated,
|
deactivated=chat.deactivated,
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse_channel_chat(client, channel: raw.types.Channel) -> "Chat":
|
def _parse_channel_chat(client, channel: raw.types.Channel) -> 'Chat':
|
||||||
peer_id = utils.get_channel_id(channel.id)
|
peer_id = utils.get_channel_id(channel.id)
|
||||||
restriction_reason = getattr(channel, "restriction_reason", [])
|
restriction_reason = getattr(channel, 'restriction_reason', [])
|
||||||
|
|
||||||
return Chat(
|
return Chat(
|
||||||
id=peer_id,
|
id=peer_id,
|
||||||
type=(
|
type=(enums.ChatType.SUPERGROUP if getattr(channel, 'megagroup', None) else enums.ChatType.CHANNEL),
|
||||||
enums.ChatType.SUPERGROUP
|
is_verified=getattr(channel, 'verified', None),
|
||||||
if getattr(channel, "megagroup", None)
|
is_restricted=getattr(channel, 'restricted', None),
|
||||||
else enums.ChatType.CHANNEL
|
is_creator=getattr(channel, 'creator', None),
|
||||||
),
|
is_scam=getattr(channel, 'scam', None),
|
||||||
is_verified=getattr(channel, "verified", None),
|
is_fake=getattr(channel, 'fake', None),
|
||||||
is_restricted=getattr(channel, "restricted", None),
|
|
||||||
is_creator=getattr(channel, "creator", None),
|
|
||||||
is_scam=getattr(channel, "scam", None),
|
|
||||||
is_fake=getattr(channel, "fake", None),
|
|
||||||
title=channel.title,
|
title=channel.title,
|
||||||
username=getattr(channel, "username", None),
|
username=getattr(channel, 'username', None),
|
||||||
photo=types.ChatPhoto._parse(
|
photo=types.ChatPhoto._parse(
|
||||||
client,
|
client,
|
||||||
getattr(channel, "photo", None),
|
getattr(channel, 'photo', None),
|
||||||
peer_id,
|
peer_id,
|
||||||
getattr(channel, "access_hash", 0),
|
getattr(channel, 'access_hash', 0),
|
||||||
),
|
),
|
||||||
restrictions=types.List(
|
restrictions=types.List([types.Restriction._parse(r) for r in restriction_reason]) or None,
|
||||||
[types.Restriction._parse(r) for r in restriction_reason]
|
permissions=types.ChatPermissions._parse(getattr(channel, 'default_banned_rights', None)),
|
||||||
)
|
members_count=getattr(channel, 'participants_count', None),
|
||||||
or None,
|
dc_id=getattr(getattr(channel, 'photo', None), 'dc_id', None),
|
||||||
permissions=types.ChatPermissions._parse(
|
has_protected_content=getattr(channel, 'noforwards', None),
|
||||||
getattr(channel, "default_banned_rights", None)
|
is_admin=bool(getattr(channel, 'admin_rights', False)),
|
||||||
),
|
|
||||||
members_count=getattr(channel, "participants_count", None),
|
|
||||||
dc_id=getattr(getattr(channel, "photo", None), "dc_id", None),
|
|
||||||
has_protected_content=getattr(channel, "noforwards", None),
|
|
||||||
is_admin=bool(getattr(channel, "admin_rights", False)),
|
|
||||||
client=client,
|
client=client,
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse(
|
def _parse(
|
||||||
client,
|
client,
|
||||||
message: Union[raw.types.Message, raw.types.MessageService],
|
message: raw.types.Message | raw.types.MessageService,
|
||||||
users: dict,
|
users: dict,
|
||||||
chats: dict,
|
chats: dict,
|
||||||
is_chat: bool,
|
is_chat: bool,
|
||||||
) -> "Chat":
|
) -> 'Chat':
|
||||||
from_id = utils.get_raw_peer_id(message.from_id)
|
from_id = utils.get_raw_peer_id(message.from_id)
|
||||||
peer_id = utils.get_raw_peer_id(message.peer_id)
|
peer_id = utils.get_raw_peer_id(message.peer_id)
|
||||||
chat_id = (peer_id or from_id) if is_chat else (from_id or peer_id)
|
chat_id = (peer_id or from_id) if is_chat else (from_id or peer_id)
|
||||||
@@ -211,9 +195,9 @@ class Dialog(Object):
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
client: "Client" = None,
|
client: 'Client' = None,
|
||||||
chat: "types.Chat",
|
chat: 'types.Chat',
|
||||||
top_message: "types.Message",
|
top_message: 'types.Message',
|
||||||
unread_messages_count: int,
|
unread_messages_count: int,
|
||||||
unread_mentions_count: int,
|
unread_mentions_count: int,
|
||||||
unread_mark: bool,
|
unread_mark: bool,
|
||||||
@@ -229,7 +213,7 @@ class Dialog(Object):
|
|||||||
self.is_pinned = is_pinned
|
self.is_pinned = is_pinned
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse(client, dialog: "raw.types.Dialog", messages, users, chats) -> "Dialog":
|
def _parse(client, dialog: 'raw.types.Dialog', messages, users, chats) -> 'Dialog':
|
||||||
return Dialog(
|
return Dialog(
|
||||||
chat=Chat._parse_dialog(client, dialog.peer, users, chats),
|
chat=Chat._parse_dialog(client, dialog.peer, users, chats),
|
||||||
top_message=messages.get(utils.get_peer_id(dialog.peer)),
|
top_message=messages.get(utils.get_peer_id(dialog.peer)),
|
||||||
@@ -241,9 +225,7 @@ class Dialog(Object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def get_dialogs(
|
async def get_dialogs(self: 'Client', limit: int = 0) -> AsyncGenerator['types.Dialog', None] | None:
|
||||||
self: "Client", limit: int = 0
|
|
||||||
) -> Optional[AsyncGenerator["types.Dialog", None]]:
|
|
||||||
current = 0
|
current = 0
|
||||||
total = limit or (1 << 31) - 1
|
total = limit or (1 << 31) - 1
|
||||||
limit = min(100, total)
|
limit = min(100, total)
|
||||||
@@ -287,7 +269,7 @@ async def get_dialogs(
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command("admlist", prefix) & filters.me)
|
@Client.on_message(filters.command('admlist', prefix) & filters.me)
|
||||||
async def admlist(client: Client, message: types.Message):
|
async def admlist(client: Client, message: types.Message):
|
||||||
await message.edit("<b>Retrieving information... (it'll take some time)</b>")
|
await message.edit("<b>Retrieving information... (it'll take some time)</b>")
|
||||||
|
|
||||||
@@ -298,48 +280,46 @@ async def admlist(client: Client, message: types.Message):
|
|||||||
owned_usernamed_chats = []
|
owned_usernamed_chats = []
|
||||||
async for dialog in get_dialogs(client):
|
async for dialog in get_dialogs(client):
|
||||||
chat = dialog.chat
|
chat = dialog.chat
|
||||||
if getattr(chat, "deactivated", False):
|
if getattr(chat, 'deactivated', False):
|
||||||
continue
|
continue
|
||||||
if getattr(chat, "is_creator", False) and getattr(chat, "username", None):
|
if getattr(chat, 'is_creator', False) and getattr(chat, 'username', None):
|
||||||
owned_usernamed_chats.append(chat)
|
owned_usernamed_chats.append(chat)
|
||||||
elif getattr(chat, "is_creator", False):
|
elif getattr(chat, 'is_creator', False):
|
||||||
owned_chats.append(chat)
|
owned_chats.append(chat)
|
||||||
elif getattr(chat, "is_admin", False):
|
elif getattr(chat, 'is_admin', False):
|
||||||
adminned_chats.append(chat)
|
adminned_chats.append(chat)
|
||||||
|
|
||||||
text = "<b>Adminned chats:</b>\n"
|
text = '<b>Adminned chats:</b>\n'
|
||||||
for index, chat in enumerate(adminned_chats):
|
for index, chat in enumerate(adminned_chats):
|
||||||
cid = str(chat.id).replace("-100", "")
|
cid = str(chat.id).replace('-100', '')
|
||||||
text += f"{index + 1}. <a href=https://t.me/c/{cid}/1>{chat.title}</a>\n"
|
text += f'{index + 1}. <a href=https://t.me/c/{cid}/1>{chat.title}</a>\n'
|
||||||
|
|
||||||
text += "\n<b>Owned chats:</b>\n"
|
text += '\n<b>Owned chats:</b>\n'
|
||||||
for index, chat in enumerate(owned_chats):
|
for index, chat in enumerate(owned_chats):
|
||||||
cid = str(chat.id).replace("-100", "")
|
cid = str(chat.id).replace('-100', '')
|
||||||
text += f"{index + 1}. <a href=https://t.me/c/{cid}/1>{chat.title}</a>\n"
|
text += f'{index + 1}. <a href=https://t.me/c/{cid}/1>{chat.title}</a>\n'
|
||||||
|
|
||||||
text += "\n<b>Owned chats with username:</b>\n"
|
text += '\n<b>Owned chats with username:</b>\n'
|
||||||
for index, chat in enumerate(owned_usernamed_chats):
|
for index, chat in enumerate(owned_usernamed_chats):
|
||||||
cid = str(chat.id).replace("-100", "")
|
cid = str(chat.id).replace('-100', '')
|
||||||
text += f"{index + 1}. <a href=https://t.me/c/{cid}/1>{chat.title}</a>\n"
|
text += f'{index + 1}. <a href=https://t.me/c/{cid}/1>{chat.title}</a>\n'
|
||||||
|
|
||||||
stop = perf_counter()
|
stop = perf_counter()
|
||||||
total_count = (
|
total_count = len(adminned_chats) + len(owned_chats) + len(owned_usernamed_chats)
|
||||||
len(adminned_chats) + len(owned_chats) + len(owned_usernamed_chats)
|
|
||||||
)
|
|
||||||
await message.edit(
|
await message.edit(
|
||||||
text + "\n"
|
text + '\n'
|
||||||
f"<b><u>Total:</u></b> {total_count}"
|
f'<b><u>Total:</u></b> {total_count}'
|
||||||
f"\n<b><u>Adminned chats:</u></b> {len(adminned_chats)}\n"
|
f'\n<b><u>Adminned chats:</u></b> {len(adminned_chats)}\n'
|
||||||
f"<b><u>Owned chats:</u></b> {len(owned_chats)}\n"
|
f'<b><u>Owned chats:</u></b> {len(owned_chats)}\n'
|
||||||
f"<b><u>Owned chats with username:</u></b> {len(owned_usernamed_chats)}\n\n"
|
f'<b><u>Owned chats with username:</u></b> {len(owned_usernamed_chats)}\n\n'
|
||||||
f"Done in {round(stop - start, 3)} seconds.",
|
f'Done in {round(stop - start, 3)} seconds.',
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await message.edit(format_exc(e))
|
await message.edit(format_exc(e))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
@Client.on_message(filters.command("admcount", prefix) & filters.me)
|
@Client.on_message(filters.command('admcount', prefix) & filters.me)
|
||||||
async def admcount(client: Client, message: types.Message):
|
async def admcount(client: Client, message: types.Message):
|
||||||
await message.edit("<b>Retrieving information... (it'll take some time)</b>")
|
await message.edit("<b>Retrieving information... (it'll take some time)</b>")
|
||||||
|
|
||||||
@@ -350,31 +330,31 @@ async def admcount(client: Client, message: types.Message):
|
|||||||
owned_usernamed_chats = 0
|
owned_usernamed_chats = 0
|
||||||
async for dialog in get_dialogs(client):
|
async for dialog in get_dialogs(client):
|
||||||
chat = dialog.chat
|
chat = dialog.chat
|
||||||
if getattr(chat, "deactivated", False):
|
if getattr(chat, 'deactivated', False):
|
||||||
continue
|
continue
|
||||||
if getattr(chat, "is_creator", False) and getattr(chat, "username", None):
|
if getattr(chat, 'is_creator', False) and getattr(chat, 'username', None):
|
||||||
owned_usernamed_chats += 1
|
owned_usernamed_chats += 1
|
||||||
elif getattr(chat, "is_creator", False):
|
elif getattr(chat, 'is_creator', False):
|
||||||
owned_chats += 1
|
owned_chats += 1
|
||||||
elif getattr(chat, "is_admin", False):
|
elif getattr(chat, 'is_admin', False):
|
||||||
adminned_chats += 1
|
adminned_chats += 1
|
||||||
|
|
||||||
stop = perf_counter()
|
stop = perf_counter()
|
||||||
total_count = adminned_chats + owned_chats + owned_usernamed_chats
|
total_count = adminned_chats + owned_chats + owned_usernamed_chats
|
||||||
await message.edit(
|
await message.edit(
|
||||||
f"<b><u>Total:</u></b> {total_count}"
|
f'<b><u>Total:</u></b> {total_count}'
|
||||||
f"\n<b><u>Adminned chats:</u></b> {adminned_chats}\n"
|
f'\n<b><u>Adminned chats:</u></b> {adminned_chats}\n'
|
||||||
f"<b><u>Owned chats:</u></b> {owned_chats}\n"
|
f'<b><u>Owned chats:</u></b> {owned_chats}\n'
|
||||||
f"<b><u>Owned chats with username:</u></b> {owned_usernamed_chats}\n\n"
|
f'<b><u>Owned chats with username:</u></b> {owned_usernamed_chats}\n\n'
|
||||||
f"Done in {round(stop - start, 3)} seconds.\n\n"
|
f'Done in {round(stop - start, 3)} seconds.\n\n'
|
||||||
f"<b>Get full list: </b><code>{prefix}admlist</code>",
|
f'<b>Get full list: </b><code>{prefix}admlist</code>',
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await message.edit(format_exc(e))
|
await message.edit(format_exc(e))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
modules_help["admlist"] = {
|
modules_help['admlist'] = {
|
||||||
"admcount": "Get count of adminned and owned chats",
|
'admcount': 'Get count of adminned and owned chats',
|
||||||
"admlist": "Get list of adminned and owned chats",
|
'admlist': 'Get list of adminned and owned chats',
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user