Spaces:
Running
Running
BloodyInside
commited on
Commit
•
947c08e
1
Parent(s):
57c9b03
firsty
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .dockerignore +8 -0
- .expo/README.md +15 -0
- .expo/settings.json +8 -0
- .gitattributes +3 -0
- .gitignore +57 -0
- Dockerfile +42 -0
- README.md +7 -9
- backend/__init__.py +0 -0
- backend/__pycache__/__init__.cpython-312.pyc +0 -0
- backend/__pycache__/admin.cpython-312.pyc +0 -0
- backend/__pycache__/apps.cpython-312.pyc +0 -0
- backend/__pycache__/socket_routing.cpython-312.pyc +0 -0
- backend/__pycache__/urls.cpython-312.pyc +0 -0
- backend/admin.py +3 -0
- backend/api/__init__.py +4 -0
- backend/api/__pycache__/__init__.cpython-311.pyc +0 -0
- backend/api/__pycache__/__init__.cpython-312.pyc +0 -0
- backend/api/__pycache__/admin.cpython-311.pyc +0 -0
- backend/api/__pycache__/admin.cpython-312.pyc +0 -0
- backend/api/__pycache__/borrow_book.cpython-311.pyc +0 -0
- backend/api/__pycache__/borrow_book.cpython-312.pyc +0 -0
- backend/api/__pycache__/cloudflare_turnstile.cpython-312.pyc +0 -0
- backend/api/__pycache__/get_join_library_action.cpython-311.pyc +0 -0
- backend/api/__pycache__/get_join_library_action.cpython-312.pyc +0 -0
- backend/api/__pycache__/get_media_feedback.cpython-311.pyc +0 -0
- backend/api/__pycache__/get_media_feedback.cpython-312.pyc +0 -0
- backend/api/__pycache__/join_library.cpython-311.pyc +0 -0
- backend/api/__pycache__/join_library.cpython-312.pyc +0 -0
- backend/api/__pycache__/queue.cpython-312.pyc +0 -0
- backend/api/__pycache__/security.cpython-311.pyc +0 -0
- backend/api/__pycache__/security.cpython-312.pyc +0 -0
- backend/api/__pycache__/stream_file.cpython-312.pyc +0 -0
- backend/api/__pycache__/test.cpython-312.pyc +0 -0
- backend/api/__pycache__/text_translator.cpython-312.pyc +0 -0
- backend/api/__pycache__/web_scrap.cpython-312.pyc +0 -0
- backend/api/cloudflare_turnstile.py +36 -0
- backend/api/queue.py +109 -0
- backend/api/stream_file.py +53 -0
- backend/api/test.py +17 -0
- backend/api/web_scrap.py +111 -0
- backend/apps.py +6 -0
- backend/invoke_worker/__init__.py +11 -0
- backend/invoke_worker/__pycache__/__init__.cpython-312.pyc +0 -0
- backend/invoke_worker/__pycache__/chapter_queue.cpython-312.pyc +0 -0
- backend/invoke_worker/__pycache__/session.cpython-312.pyc +0 -0
- backend/invoke_worker/chapter_queue.py +266 -0
- backend/invoke_worker/session.py +24 -0
- backend/management/commands/__pycache__/clear_all_sessions.cpython-312.pyc +0 -0
- backend/management/commands/__pycache__/custom_clearsessions.cpython-312.pyc +0 -0
- backend/management/commands/clear_all_sessions.py +11 -0
.dockerignore
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
fly.toml
|
2 |
+
.git/
|
3 |
+
*.sqlite3
|
4 |
+
frontend/node_modules
|
5 |
+
frontend/src
|
6 |
+
venv
|
7 |
+
credentials.txt
|
8 |
+
|
.expo/README.md
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
> Why do I have a folder named ".expo" in my project?
|
2 |
+
|
3 |
+
The ".expo" folder is created when an Expo project is started using "expo start" command.
|
4 |
+
|
5 |
+
> What do the files contain?
|
6 |
+
|
7 |
+
- "devices.json": contains information about devices that have recently opened this project. This is used to populate the "Development sessions" list in your development builds.
|
8 |
+
- "packager-info.json": contains port numbers and process PIDs that are used to serve the application to the mobile device/simulator.
|
9 |
+
- "settings.json": contains the server configuration that is used to serve the application manifest.
|
10 |
+
|
11 |
+
> Should I commit the ".expo" folder?
|
12 |
+
|
13 |
+
No, you should not share the ".expo" folder. It does not contain any information that is relevant for other developers working on the project, it is specific to your machine.
|
14 |
+
|
15 |
+
Upon project creation, the ".expo" folder is already added to your ".gitignore" file.
|
.expo/settings.json
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"hostType": "lan",
|
3 |
+
"lanType": "ip",
|
4 |
+
"dev": true,
|
5 |
+
"minify": false,
|
6 |
+
"urlRandomness": null,
|
7 |
+
"https": false
|
8 |
+
}
|
.gitattributes
CHANGED
@@ -33,3 +33,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
*.ttf filter=lfs diff=lfs merge=lfs -text
|
37 |
+
*.ttc filter=lfs diff=lfs merge=lfs -text
|
38 |
+
*.png filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
frontend/node_modules
|
2 |
+
frontend/static/frontend
|
3 |
+
venv/
|
4 |
+
frontend/.git
|
5 |
+
.env
|
6 |
+
.cache
|
7 |
+
.git
|
8 |
+
*.sqlite3
|
9 |
+
|
10 |
+
frontend/android/
|
11 |
+
log/
|
12 |
+
temp/
|
13 |
+
media/
|
14 |
+
storage/
|
15 |
+
backend/module/utils/image_translator/models/
|
16 |
+
|
17 |
+
backend/module/utils/image_translator/result
|
18 |
+
backend/module/utils/image_translator/*.ckpt
|
19 |
+
backend/module/utils/image_translator/*.pt
|
20 |
+
backend/module/utils/image_translator/.vscode
|
21 |
+
backend/module/utils/image_translator/*.onnx
|
22 |
+
backend/module/utils/image_translator/__pycache__
|
23 |
+
backend/module/utils/image_translator/ocrs
|
24 |
+
backend/module/utils/image_translator/Manga
|
25 |
+
backend/module/utils/image_translator/Manga-translated
|
26 |
+
backend/module/utils/image_translator//models
|
27 |
+
backend/module/utils/image_translator/.env
|
28 |
+
backend/module/utils/image_translator/*.local
|
29 |
+
backend/module/utils/image_translator/*.local.*
|
30 |
+
backend/module/utils/image_translator/test/testdata
|
31 |
+
backend/module/utils/image_translator/.idea
|
32 |
+
backend/module/utils/image_translator/pyvenv.cfg
|
33 |
+
backend/module/utils/image_translator/Scripts
|
34 |
+
backend/module/utils/image_translator/Lib
|
35 |
+
backend/module/utils/image_translator/include
|
36 |
+
backend/module/utils/image_translator/share
|
37 |
+
|
38 |
+
# Distribution / packaging
|
39 |
+
backend/module/utils/image_translator/.Python
|
40 |
+
backend/module/utils/image_translator/build/
|
41 |
+
backend/module/utils/image_translator/develop-eggs/
|
42 |
+
backend/module/utils/image_translator/dist/
|
43 |
+
backend/module/utils/image_translator/downloads/
|
44 |
+
backend/module/utils/image_translator/eggs/
|
45 |
+
backend/module/utils/image_translator/.eggs/
|
46 |
+
backend/module/utils/image_translator/lib/
|
47 |
+
backend/module/utils/image_translator/lib64/
|
48 |
+
backend/module/utils/image_translator/parts/
|
49 |
+
backend/module/utils/image_translator/sdist/
|
50 |
+
backend/module/utils/image_translator/var/
|
51 |
+
backend/module/utils/image_translator/wheels/
|
52 |
+
backend/module/utils/image_translator/share/python-wheels/
|
53 |
+
backend/module/utils/image_translator/*.egg-info/
|
54 |
+
backend/module/utils/image_translator/.installed.cfg
|
55 |
+
backend/module/utils/image_translator/*.egg
|
56 |
+
backend/module/utils/image_translator/MANIFEST
|
57 |
+
backend/module/utils/image_translator/.history
|
Dockerfile
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
ARG PYTHON_VERSION=3.12-slim-bullseye
|
2 |
+
|
3 |
+
FROM python:${PYTHON_VERSION}
|
4 |
+
|
5 |
+
ENV PYTHONDONTWRITEBYTECODE 1
|
6 |
+
ENV PYTHONUNBUFFERED 1
|
7 |
+
|
8 |
+
# install psycopg2 dependencies.
|
9 |
+
RUN apt-get update && apt-get install -y \
|
10 |
+
libpq-dev \
|
11 |
+
gcc \
|
12 |
+
&& rm -rf /var/lib/apt/lists/*
|
13 |
+
|
14 |
+
RUN mkdir -p /code
|
15 |
+
|
16 |
+
WORKDIR /code
|
17 |
+
|
18 |
+
COPY requirements.txt /tmp/requirements.txt
|
19 |
+
RUN set -ex && \
|
20 |
+
pip install --upgrade pip && \
|
21 |
+
pip install -r /tmp/requirements.txt && \
|
22 |
+
rm -rf /root/.cache/
|
23 |
+
COPY . /code
|
24 |
+
|
25 |
+
|
26 |
+
RUN python manage.py makemigrations
|
27 |
+
RUN python manage.py migrate --database=default
|
28 |
+
RUN python manage.py migrate --database=cache
|
29 |
+
RUN python manage.py migrate --database=DB1
|
30 |
+
RUN python manage.py migrate --database=DB2
|
31 |
+
|
32 |
+
|
33 |
+
|
34 |
+
EXPOSE 8000
|
35 |
+
|
36 |
+
# CMD ["gunicorn", "--bind", ":8000", "--workers", "1", "--worker-class", "gevent", "core.wsgi:application"]
|
37 |
+
# CMD ["daphne", "-u", "/tmp/daphne.sock", "core.asgi:application"]
|
38 |
+
CMD ["daphne", "-b", "0.0.0.0", "-p", "7860", "core.asgi:application"]
|
39 |
+
|
40 |
+
# CMD ["gunicorn", "--bind", ":8000", "--workers", "1", "--worker-class", "uvicorn.workers.UvicornWorker", "core.asgi:application"]
|
41 |
+
|
42 |
+
|
README.md
CHANGED
@@ -1,10 +1,8 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
emoji: 🚀
|
4 |
-
colorFrom: green
|
5 |
-
colorTo: purple
|
6 |
-
sdk: docker
|
7 |
-
pinned: false
|
8 |
-
---
|
9 |
|
10 |
-
|
|
|
|
|
|
|
|
|
|
1 |
+
# ComicMTL
|
2 |
+
App that translate whole manga into prefer languages. Currently In development.
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
|
4 |
+
|
5 |
+
Project Status: https://github.com/GoodDay360/ComicMTL/projects?query=is%3Aopen
|
6 |
+
|
7 |
+
### Utilities that used for this project:
|
8 |
+
- [Translator](https://github.com/zyddnys/manga-image-translator)
|
backend/__init__.py
ADDED
File without changes
|
backend/__pycache__/__init__.cpython-312.pyc
ADDED
Binary file (134 Bytes). View file
|
|
backend/__pycache__/admin.cpython-312.pyc
ADDED
Binary file (178 Bytes). View file
|
|
backend/__pycache__/apps.cpython-312.pyc
ADDED
Binary file (442 Bytes). View file
|
|
backend/__pycache__/socket_routing.cpython-312.pyc
ADDED
Binary file (440 Bytes). View file
|
|
backend/__pycache__/urls.cpython-312.pyc
ADDED
Binary file (1.31 kB). View file
|
|
backend/admin.py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
from django.contrib import admin
|
2 |
+
|
3 |
+
# Register your models here.
|
backend/api/__init__.py
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import backend.invoke_worker
|
2 |
+
|
3 |
+
|
4 |
+
|
backend/api/__pycache__/__init__.cpython-311.pyc
ADDED
Binary file (163 Bytes). View file
|
|
backend/api/__pycache__/__init__.cpython-312.pyc
ADDED
Binary file (183 Bytes). View file
|
|
backend/api/__pycache__/admin.cpython-311.pyc
ADDED
Binary file (2.99 kB). View file
|
|
backend/api/__pycache__/admin.cpython-312.pyc
ADDED
Binary file (13.1 kB). View file
|
|
backend/api/__pycache__/borrow_book.cpython-311.pyc
ADDED
Binary file (2.08 kB). View file
|
|
backend/api/__pycache__/borrow_book.cpython-312.pyc
ADDED
Binary file (4.72 kB). View file
|
|
backend/api/__pycache__/cloudflare_turnstile.cpython-312.pyc
ADDED
Binary file (1.91 kB). View file
|
|
backend/api/__pycache__/get_join_library_action.cpython-311.pyc
ADDED
Binary file (1.52 kB). View file
|
|
backend/api/__pycache__/get_join_library_action.cpython-312.pyc
ADDED
Binary file (1.37 kB). View file
|
|
backend/api/__pycache__/get_media_feedback.cpython-311.pyc
ADDED
Binary file (1.97 kB). View file
|
|
backend/api/__pycache__/get_media_feedback.cpython-312.pyc
ADDED
Binary file (1.79 kB). View file
|
|
backend/api/__pycache__/join_library.cpython-311.pyc
ADDED
Binary file (1.74 kB). View file
|
|
backend/api/__pycache__/join_library.cpython-312.pyc
ADDED
Binary file (2.47 kB). View file
|
|
backend/api/__pycache__/queue.cpython-312.pyc
ADDED
Binary file (6.34 kB). View file
|
|
backend/api/__pycache__/security.cpython-311.pyc
ADDED
Binary file (1.7 kB). View file
|
|
backend/api/__pycache__/security.cpython-312.pyc
ADDED
Binary file (1.51 kB). View file
|
|
backend/api/__pycache__/stream_file.cpython-312.pyc
ADDED
Binary file (3.72 kB). View file
|
|
backend/api/__pycache__/test.cpython-312.pyc
ADDED
Binary file (781 Bytes). View file
|
|
backend/api/__pycache__/text_translator.cpython-312.pyc
ADDED
Binary file (1.28 kB). View file
|
|
backend/api/__pycache__/web_scrap.cpython-312.pyc
ADDED
Binary file (7.43 kB). View file
|
|
backend/api/cloudflare_turnstile.py
ADDED
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
import requests, environ, json
|
3 |
+
from django.http import JsonResponse, HttpResponseBadRequest
|
4 |
+
|
5 |
+
from backend.models.model_cache import CloudflareTurnStileCache
|
6 |
+
|
7 |
+
from django_ratelimit.decorators import ratelimit
|
8 |
+
from django.views.decorators.csrf import csrf_exempt
|
9 |
+
from ipware import get_client_ip
|
10 |
+
|
11 |
+
env = environ.Env()
|
12 |
+
|
13 |
+
@csrf_exempt
|
14 |
+
@ratelimit(key='ip', rate='60/m')
|
15 |
+
def verify(request):
|
16 |
+
if request.method != "POST": return HttpResponseBadRequest('Allowed POST request only!', status=400)
|
17 |
+
client_ip, is_routable = get_client_ip(request)
|
18 |
+
payload = json.loads(request.body)
|
19 |
+
token = payload.get("token")
|
20 |
+
form_data = {
|
21 |
+
"secret": env("CLOUDFLARE_TURNSTILE_SECRET"),
|
22 |
+
"response": token,
|
23 |
+
"remoteip": client_ip
|
24 |
+
}
|
25 |
+
req = requests.post(
|
26 |
+
url="https://challenges.cloudflare.com/turnstile/v0/siteverify",
|
27 |
+
data=form_data,
|
28 |
+
)
|
29 |
+
result = req.json()
|
30 |
+
status = result.get("success")
|
31 |
+
if (status):
|
32 |
+
|
33 |
+
queryset = CloudflareTurnStileCache.objects.create(token=token)
|
34 |
+
queryset.refresh_from_db()
|
35 |
+
return JsonResponse(result)
|
36 |
+
else: return HttpResponseBadRequest('Cloudflare turnstile token verificaion failed!', status=511)
|
backend/api/queue.py
ADDED
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
import json, environ, requests, os, subprocess
|
3 |
+
import asyncio, uuid
|
4 |
+
|
5 |
+
from django.http import HttpResponse, JsonResponse, HttpResponseBadRequest
|
6 |
+
from django_ratelimit.decorators import ratelimit
|
7 |
+
from django.views.decorators.csrf import csrf_exempt
|
8 |
+
from asgiref.sync import sync_to_async
|
9 |
+
|
10 |
+
from backend.module import web_scrap
|
11 |
+
from backend.module.utils import manage_image
|
12 |
+
from backend.models.model_cache import SocketRequestChapterQueueCache, ComicStorageCache
|
13 |
+
from core.settings import BASE_DIR
|
14 |
+
from backend.module.utils import cloudflare_turnstile
|
15 |
+
|
16 |
+
|
17 |
+
env = environ.Env()
|
18 |
+
|
19 |
+
|
20 |
+
@csrf_exempt
|
21 |
+
@ratelimit(key='ip', rate='60/m')
|
22 |
+
def request_chapter(request):
|
23 |
+
try:
|
24 |
+
if request.method != "POST": return HttpResponseBadRequest('Allowed POST request only!', status=400)
|
25 |
+
token = request.META.get('HTTP_X_CLOUDFLARE_TURNSTILE_TOKEN')
|
26 |
+
if not cloudflare_turnstile.check(token): return HttpResponseBadRequest('Cloudflare turnstile token not existed or expired!', status=511)
|
27 |
+
|
28 |
+
payload = json.loads(request.body)
|
29 |
+
source = payload.get("source")
|
30 |
+
comic_id = payload.get("comic_id")
|
31 |
+
chapter_id = payload.get("chapter_id")
|
32 |
+
chapter_idx = payload.get("chapter_idx")
|
33 |
+
socket_id = payload.get("socket_id")
|
34 |
+
channel_name = payload.get("channel_name")
|
35 |
+
options = payload.get("options") or {}
|
36 |
+
|
37 |
+
options["translate"]["target"] = options.get("translate").get("target") if options.get("translate").get("state") else ""
|
38 |
+
query_count = ComicStorageCache.objects.filter(
|
39 |
+
source=source,
|
40 |
+
comic_id=comic_id,
|
41 |
+
chapter_id=chapter_id,
|
42 |
+
chapter_idx=chapter_idx,
|
43 |
+
colorize=options.get("colorize"),
|
44 |
+
translate=options.get("translate").get("state"),
|
45 |
+
target_lang = options.get("translate").get("target")
|
46 |
+
).count()
|
47 |
+
|
48 |
+
if query_count: return JsonResponse({"status":"ready"})
|
49 |
+
else:
|
50 |
+
SocketRequestChapterQueueCache(
|
51 |
+
socket_id=socket_id,
|
52 |
+
channel_name=channel_name,
|
53 |
+
source=source,
|
54 |
+
comic_id=comic_id,
|
55 |
+
chapter_id=chapter_id,
|
56 |
+
chapter_idx=chapter_idx,
|
57 |
+
options=options
|
58 |
+
).save()
|
59 |
+
return JsonResponse({"status":"queue"})
|
60 |
+
except Exception as e:
|
61 |
+
print(e)
|
62 |
+
return HttpResponseBadRequest('Internal Error.', status=500)
|
63 |
+
|
64 |
+
|
65 |
+
@csrf_exempt
|
66 |
+
@ratelimit(key='ip', rate='60/m')
|
67 |
+
def request_info(request):
|
68 |
+
try:
|
69 |
+
if request.method != "POST": return HttpResponseBadRequest('Allowed POST request only!', status=400)
|
70 |
+
token = request.META.get('HTTP_X_CLOUDFLARE_TURNSTILE_TOKEN')
|
71 |
+
if not cloudflare_turnstile.check(token): return HttpResponseBadRequest('Cloudflare turnstile token not existed or expired!', status=511)
|
72 |
+
|
73 |
+
payload = json.loads(request.body)
|
74 |
+
socket_id = payload.get("socket_id")
|
75 |
+
source = payload.get("source")
|
76 |
+
comic_id = payload.get("comic_id")
|
77 |
+
chapter_requested = payload.get("chapter_requested")
|
78 |
+
|
79 |
+
|
80 |
+
result_request = {}
|
81 |
+
for chapter in chapter_requested:
|
82 |
+
options = chapter.get("options")
|
83 |
+
query_count = SocketRequestChapterQueueCache.objects.filter(socket_id=socket_id, source=source, comic_id=comic_id, chapter_id=chapter.get("chapter_id")).count()
|
84 |
+
if query_count: result_request[chapter.get("chapter_id")] = {"state":"queue","chapter_idx":chapter.get("chapter_idx"),"options":options}
|
85 |
+
else:
|
86 |
+
query_result = ComicStorageCache.objects.filter(
|
87 |
+
source=source,
|
88 |
+
comic_id=comic_id,
|
89 |
+
chapter_id=chapter.get("chapter_id"),
|
90 |
+
chapter_idx=chapter.get("chapter_idx"),
|
91 |
+
colorize=options.get("colorize"),
|
92 |
+
translate=options.get("translate").get("state"),
|
93 |
+
target_lang = options.get("translate").get("target") if options.get("translate").get("state") else ""
|
94 |
+
).first()
|
95 |
+
|
96 |
+
if query_result:
|
97 |
+
file_path = query_result.file_path
|
98 |
+
if os.path.exists(file_path):
|
99 |
+
result_request[chapter.get("chapter_id")] = {"state":"ready","chapter_idx":chapter.get("chapter_idx"),"options":options}
|
100 |
+
else:
|
101 |
+
ComicStorageCache.objects.filter(id=query_result.id).delete()
|
102 |
+
result_request[chapter.get("chapter_id")] = {"state":"unkown","chapter_idx":chapter.get("chapter_idx"),"options":options}
|
103 |
+
else:
|
104 |
+
result_request[chapter.get("chapter_id")] = {"state":"unkown","chapter_idx":chapter.get("chapter_idx"),"options":options}
|
105 |
+
return JsonResponse(result_request)
|
106 |
+
|
107 |
+
except Exception as e:
|
108 |
+
print(e)
|
109 |
+
return HttpResponseBadRequest('Internal Error.', status=500)
|
backend/api/stream_file.py
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from django.http import StreamingHttpResponse, HttpResponseBadRequest
|
2 |
+
from core.settings import BASE_DIR
|
3 |
+
from django_ratelimit.decorators import ratelimit
|
4 |
+
from django.views.decorators.csrf import csrf_exempt
|
5 |
+
from backend.module.utils import cloudflare_turnstile
|
6 |
+
from backend.models.model_cache import SocketRequestChapterQueueCache, ComicStorageCache
|
7 |
+
|
8 |
+
import os, json, sys
|
9 |
+
|
10 |
+
@csrf_exempt
|
11 |
+
@ratelimit(key='ip', rate='60/m')
|
12 |
+
def download_chapter(request):
|
13 |
+
if request.method != "POST": return HttpResponseBadRequest('Allowed POST request only!', status=400)
|
14 |
+
token = request.META.get('HTTP_X_CLOUDFLARE_TURNSTILE_TOKEN')
|
15 |
+
if not cloudflare_turnstile.check(token): return HttpResponseBadRequest('Cloudflare turnstile token not existed or expired!', status=511)
|
16 |
+
try:
|
17 |
+
payload = json.loads(request.body)
|
18 |
+
source = payload.get("source")
|
19 |
+
comic_id = payload.get("comic_id")
|
20 |
+
chapter_id = payload.get("chapter_id")
|
21 |
+
chapter_idx = payload.get("chapter_idx")
|
22 |
+
options = payload.get("options")
|
23 |
+
|
24 |
+
query_result = ComicStorageCache.objects.filter(
|
25 |
+
source=source,
|
26 |
+
comic_id=comic_id,
|
27 |
+
chapter_id=chapter_id,
|
28 |
+
chapter_idx=chapter_idx,
|
29 |
+
colorize=options.get("colorize"),
|
30 |
+
translate=options.get("translate").get("state"),
|
31 |
+
target_lang = options.get("translate").get("target") if options.get("translate").get("state") else ""
|
32 |
+
).first()
|
33 |
+
|
34 |
+
|
35 |
+
file_path = query_result.file_path
|
36 |
+
file_name = os.path.basename(file_path)
|
37 |
+
chunk_size = 8192
|
38 |
+
|
39 |
+
def file_iterator():
|
40 |
+
with open(file_path, 'rb') as f:
|
41 |
+
while chunk := f.read(chunk_size):
|
42 |
+
yield chunk
|
43 |
+
|
44 |
+
response = StreamingHttpResponse(file_iterator())
|
45 |
+
response['Content-Type'] = 'application/octet-stream'
|
46 |
+
response['Content-Length'] = os.path.getsize(file_path)
|
47 |
+
response['Content-Disposition'] = f'attachment; filename="{file_name}"'
|
48 |
+
return response
|
49 |
+
except Exception as e:
|
50 |
+
exc_type, exc_obj, exc_tb = sys.exc_info()
|
51 |
+
line_number = exc_tb.tb_lineno
|
52 |
+
print(f"Error on line {line_number}: {e}")
|
53 |
+
return HttpResponseBadRequest('Internal Error.', status=500)
|
backend/api/test.py
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
import json, environ, requests, os
|
3 |
+
|
4 |
+
from django.core.files.uploadedfile import TemporaryUploadedFile
|
5 |
+
from django.http import HttpResponse, JsonResponse, HttpResponseBadRequest
|
6 |
+
from django_ratelimit.decorators import ratelimit
|
7 |
+
|
8 |
+
from core.settings import BASE_DIR
|
9 |
+
|
10 |
+
from backend.module import web_scrap
|
11 |
+
|
12 |
+
env = environ.Env()
|
13 |
+
|
14 |
+
|
15 |
+
@ratelimit(key='ip', rate='60/m')
|
16 |
+
def run_1(request):
|
17 |
+
pass
|
backend/api/web_scrap.py
ADDED
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
import json, environ, requests, os, subprocess
|
3 |
+
import asyncio, uuid
|
4 |
+
|
5 |
+
from django.http import HttpResponse, JsonResponse, HttpResponseBadRequest
|
6 |
+
from django_ratelimit.decorators import ratelimit
|
7 |
+
from django.views.decorators.csrf import csrf_exempt
|
8 |
+
from asgiref.sync import sync_to_async
|
9 |
+
|
10 |
+
from backend.module import web_scrap
|
11 |
+
from backend.module.utils import manage_image
|
12 |
+
from backend.models.model_cache import RequestCache
|
13 |
+
from core.settings import BASE_DIR
|
14 |
+
from backend.module.utils import cloudflare_turnstile
|
15 |
+
|
16 |
+
|
17 |
+
env = environ.Env()
|
18 |
+
|
19 |
+
|
20 |
+
@csrf_exempt
|
21 |
+
@ratelimit(key='ip', rate='60/m')
|
22 |
+
def get_list(request):
|
23 |
+
if request.method != "POST": return HttpResponseBadRequest('Allowed POST request only!', status=400)
|
24 |
+
token = request.META.get('HTTP_X_CLOUDFLARE_TURNSTILE_TOKEN')
|
25 |
+
if not cloudflare_turnstile.check(token): return HttpResponseBadRequest('Cloudflare turnstile token not existed or expired!', status=511)
|
26 |
+
|
27 |
+
payload = json.loads(request.body)
|
28 |
+
search = payload.get("search")
|
29 |
+
page = payload.get("page")
|
30 |
+
source = payload.get("source")
|
31 |
+
|
32 |
+
if search.get("text"): DATA = web_scrap.source_control[source].search.scrap(search=search,page=page)
|
33 |
+
else: DATA = web_scrap.source_control["colamanga"].get_list.scrap(page=page)
|
34 |
+
|
35 |
+
return JsonResponse({"data":DATA})
|
36 |
+
|
37 |
+
|
38 |
+
@ratelimit(key='ip', rate='60/m')
|
39 |
+
def search(request):
|
40 |
+
# if request.method != "POST": return HttpResponseBadRequest('Allowed POST request only!', status=400)
|
41 |
+
try:
|
42 |
+
DATA = web_scrap.source_control["colamanga"].search.scrap(search="妖")
|
43 |
+
return JsonResponse({"data":DATA})
|
44 |
+
except Exception as e:
|
45 |
+
return HttpResponseBadRequest(str(e), status=500)
|
46 |
+
|
47 |
+
|
48 |
+
|
49 |
+
@csrf_exempt
|
50 |
+
@ratelimit(key='ip', rate='60/m')
|
51 |
+
def get(request):
|
52 |
+
if request.method != "POST": return HttpResponseBadRequest('Allowed POST request only!', status=400)
|
53 |
+
token = request.META.get('HTTP_X_CLOUDFLARE_TURNSTILE_TOKEN')
|
54 |
+
if not cloudflare_turnstile.check(token): return HttpResponseBadRequest('Cloudflare turnstile token not existed or expired!', status=511)
|
55 |
+
|
56 |
+
payload = json.loads(request.body)
|
57 |
+
id = payload.get("id")
|
58 |
+
source = payload.get("source")
|
59 |
+
|
60 |
+
try:
|
61 |
+
DATA = web_scrap.source_control[source].get.scrap(id=id)
|
62 |
+
return JsonResponse({"data":DATA})
|
63 |
+
except Exception as e:
|
64 |
+
|
65 |
+
return HttpResponseBadRequest(str(e), status=500)
|
66 |
+
|
67 |
+
|
68 |
+
@ratelimit(key='ip', rate='60/m')
|
69 |
+
def get_cover(request,source,id,cover_id):
|
70 |
+
token = request.META.get('HTTP_X_CLOUDFLARE_TURNSTILE_TOKEN')
|
71 |
+
if not cloudflare_turnstile.check(token): return HttpResponseBadRequest('Cloudflare turnstile token not existed or expired!', status=511)
|
72 |
+
|
73 |
+
try:
|
74 |
+
DATA = web_scrap.source_control[source].get_cover.scrap(id=id,cover_id=cover_id)
|
75 |
+
if not DATA: HttpResponseBadRequest('Image Not found!', status=404)
|
76 |
+
response = HttpResponse(DATA, content_type="image/png")
|
77 |
+
response['Content-Disposition'] = f'inline; filename="{id}-{cover_id}.png"'
|
78 |
+
return response
|
79 |
+
except Exception as e:
|
80 |
+
return HttpResponseBadRequest(str(e), status=500)
|
81 |
+
|
82 |
+
|
83 |
+
def get_chapter(request):
|
84 |
+
try:
|
85 |
+
id = "manga-lo816008/1/410.html"
|
86 |
+
job = web_scrap.source_control["colamanga"].get_chapter.scrap(id=id,output_dir=os.path.join(BASE_DIR,"media"))
|
87 |
+
if job.get("status") == "success":
|
88 |
+
chapter_id = id.split("/")[-1].split(".")[0]
|
89 |
+
input_dir = os.path.join(BASE_DIR,"media",id.split("/")[0],chapter_id,"original")
|
90 |
+
merged_output_dir = os.path.join(BASE_DIR,"media",id.split("/")[0],chapter_id,"merged")
|
91 |
+
os.makedirs(merged_output_dir,exist_ok=True)
|
92 |
+
|
93 |
+
manage_image.merge_images_vertically(input_dir=input_dir,output_dir=merged_output_dir,max_size=10*1024*1024)
|
94 |
+
|
95 |
+
translated_merged_output_dir = os.path.join(BASE_DIR,"media",id.split("/")[0],chapter_id,"merged_translated")
|
96 |
+
os.makedirs(translated_merged_output_dir,exist_ok=True)
|
97 |
+
|
98 |
+
|
99 |
+
subprocess.run(
|
100 |
+
["python", "-m", "manga_translator", "-v", "--manga2eng", "--translator=m2m100_big", "-l", "ENG", "-i", f"{merged_output_dir}", "-o", f"{translated_merged_output_dir}"],
|
101 |
+
cwd=os.path.join(BASE_DIR,"backend","module","utils","image_translator"), shell=True, check=True
|
102 |
+
)
|
103 |
+
|
104 |
+
translated_splited_output_dir = os.path.join(BASE_DIR,"media",id.split("/")[0],chapter_id,"translated")
|
105 |
+
|
106 |
+
os.makedirs(translated_splited_output_dir,exist_ok=True)
|
107 |
+
manage_image.split_image_vertically(input_dir=translated_merged_output_dir,output_dir=translated_splited_output_dir)
|
108 |
+
except Exception as e:
|
109 |
+
print(e)
|
110 |
+
|
111 |
+
return JsonResponse({})
|
backend/apps.py
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from django.apps import AppConfig
|
2 |
+
|
3 |
+
|
4 |
+
class BackendConfig(AppConfig):
|
5 |
+
default_auto_field = 'django.db.models.BigAutoField'
|
6 |
+
name = 'backend'
|
backend/invoke_worker/__init__.py
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from core.settings import DEBUG
|
2 |
+
import sys
|
3 |
+
|
4 |
+
if len(sys.argv) > 1 and not (sys.argv[1] in ['migrate', "makemigrations", "clear_all_sessions"]):
|
5 |
+
print("[Worker] Starting Thread...")
|
6 |
+
from backend.invoke_worker import (
|
7 |
+
session,
|
8 |
+
chapter_queue,
|
9 |
+
)
|
10 |
+
print("[Worker] Thread Started!")
|
11 |
+
|
backend/invoke_worker/__pycache__/__init__.cpython-312.pyc
ADDED
Binary file (588 Bytes). View file
|
|
backend/invoke_worker/__pycache__/chapter_queue.cpython-312.pyc
ADDED
Binary file (14.4 kB). View file
|
|
backend/invoke_worker/__pycache__/session.cpython-312.pyc
ADDED
Binary file (1.4 kB). View file
|
|
backend/invoke_worker/chapter_queue.py
ADDED
@@ -0,0 +1,266 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from django_thread import Thread
|
2 |
+
from time import sleep
|
3 |
+
from backend.module.utils import date_utils
|
4 |
+
from django.db import connections
|
5 |
+
from backend.models.model_cache import SocketRequestChapterQueueCache, ComicStorageCache
|
6 |
+
from core.settings import BASE_DIR
|
7 |
+
from backend.module import web_scrap
|
8 |
+
from backend.module.utils import manage_image
|
9 |
+
from backend.module.utils.directory_info import GetDirectorySize
|
10 |
+
|
11 |
+
from channels.layers import get_channel_layer
|
12 |
+
from asgiref.sync import async_to_sync
|
13 |
+
|
14 |
+
from django.db.models import Count
|
15 |
+
|
16 |
+
import requests, environ, os, subprocess, shutil, zipfile, uuid
|
17 |
+
|
18 |
+
env = environ.Env()
|
19 |
+
|
20 |
+
# os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
|
21 |
+
|
22 |
+
STORAGE_DIR = os.path.join(BASE_DIR,"storage")
|
23 |
+
LOG_DIR = os.path.join(BASE_DIR, "log")
|
24 |
+
if not os.path.exists(LOG_DIR): os.makedirs(LOG_DIR)
|
25 |
+
|
26 |
+
MAX_STORAGE_SIZE = 20 * 1024**3
|
27 |
+
|
28 |
+
class Job(Thread):
|
29 |
+
def run(self):
|
30 |
+
while True:
|
31 |
+
input_dir = ""
|
32 |
+
managed_output_dir = ""
|
33 |
+
try:
|
34 |
+
|
35 |
+
query_result = SocketRequestChapterQueueCache.objects.order_by("datetime").first()
|
36 |
+
while True:
|
37 |
+
if (GetDirectorySize(STORAGE_DIR) >= MAX_STORAGE_SIZE):
|
38 |
+
query_result_2 = ComicStorageCache.objects.order_by("datetime").first()
|
39 |
+
if (query_result_2):
|
40 |
+
file_path = query_result_2.file_path
|
41 |
+
if os.path.exists(file_path): os.remove(file_path)
|
42 |
+
ComicStorageCache.objects.filter(id=query_result_2.id).delete()
|
43 |
+
else: break
|
44 |
+
|
45 |
+
if (query_result):
|
46 |
+
socket_id = query_result.socket_id
|
47 |
+
channel_name = query_result.channel_name
|
48 |
+
source = query_result.source
|
49 |
+
comic_id = query_result.comic_id
|
50 |
+
chapter_id = query_result.chapter_id
|
51 |
+
chapter_idx = query_result.chapter_idx
|
52 |
+
options = query_result.options
|
53 |
+
if (options.get("translate").get("state")):
|
54 |
+
target_lang = options.get("translate").get("target")
|
55 |
+
else: target_lang = ""
|
56 |
+
|
57 |
+
stored = ComicStorageCache.objects.filter(
|
58 |
+
source=source,
|
59 |
+
comic_id=comic_id,
|
60 |
+
chapter_id=chapter_id,
|
61 |
+
chapter_idx=chapter_idx,
|
62 |
+
colorize= options.get("colorize"),
|
63 |
+
translate= options.get("translate").get("state"),
|
64 |
+
target_lang= target_lang,
|
65 |
+
).first()
|
66 |
+
if (stored):
|
67 |
+
SocketRequestChapterQueueCache.objects.filter(id=query_result.id).delete()
|
68 |
+
connections['cache'].close()
|
69 |
+
else:
|
70 |
+
connections['cache'].close()
|
71 |
+
|
72 |
+
script = []
|
73 |
+
|
74 |
+
input_dir = os.path.join(STORAGE_DIR,source,comic_id,str(chapter_idx),"temp")
|
75 |
+
|
76 |
+
if (options.get("translate").get("state") and options.get("colorize")):
|
77 |
+
|
78 |
+
managed_output_dir = os.path.join(STORAGE_DIR,source,comic_id,str(chapter_idx),f"{options.get("translate").get("target")}_translated_colorized")
|
79 |
+
script = ["python", "-m", "manga_translator", "-v", "--overwrite", "--attempts=3", "--ocr=mocr", "--no-text-lang-skip", "--det-auto-rotate", "--det-gamma-correct", "--colorize=mc2", "--translator=m2m100_big", "-l", f"{options.get("translate").get("target")}", "-i", f"{input_dir}", "-o", f"{managed_output_dir}"]
|
80 |
+
elif (options.get("translate").get("state") and not options.get("colorize")):
|
81 |
+
|
82 |
+
managed_output_dir = os.path.join(STORAGE_DIR,source,comic_id,str(chapter_idx),f"{options.get("translate").get("target")}_translated")
|
83 |
+
script = ["python", "-m", "manga_translator", "-v", "--overwrite", "--attempts=3", "--ocr=mocr", "--no-text-lang-skip", "--det-auto-rotate", "--det-gamma-correct", "--translator=m2m100_big", "-l", f"{options.get("translate").get("target")}", "-i", f"{input_dir}", "-o", f"{managed_output_dir}"]
|
84 |
+
elif (options.get("colorize") and not options.get("translate").get("state")):
|
85 |
+
|
86 |
+
managed_output_dir = os.path.join(STORAGE_DIR,source,comic_id,str(chapter_idx),"colorized")
|
87 |
+
script = ["python", "-m", "manga_translator", "-v", "--overwrite", "--attempts=3", "--detector=none", "--translator=original", "--colorize=mc2", "--colorization-size=-1", "-i", f"{input_dir}", "-o", f"{managed_output_dir}"]
|
88 |
+
|
89 |
+
if target_lang == "ENG": script.append("--manga2eng")
|
90 |
+
|
91 |
+
|
92 |
+
|
93 |
+
if (options.get("colorize") or options.get("translate").get("state")):
|
94 |
+
if os.path.exists(input_dir): shutil.rmtree(input_dir)
|
95 |
+
if os.path.exists(managed_output_dir): shutil.rmtree(managed_output_dir)
|
96 |
+
|
97 |
+
job = web_scrap.source_control[source].get_chapter.scrap(comic_id=comic_id,chapter_id=chapter_id,output_dir=input_dir)
|
98 |
+
if job.get("status") == "success":
|
99 |
+
with open(os.path.join(LOG_DIR,"image_translator_output.log"), "w") as file:
|
100 |
+
result = subprocess.run(
|
101 |
+
script,
|
102 |
+
cwd=os.path.join(BASE_DIR, "backend", "module", "utils", "image_translator"),
|
103 |
+
shell=True,
|
104 |
+
check=True,
|
105 |
+
stdout=file,
|
106 |
+
stderr=file,
|
107 |
+
text=True,
|
108 |
+
)
|
109 |
+
if result.returncode != 0: raise Exception("Image Translator Execution error!")
|
110 |
+
os.makedirs(managed_output_dir,exist_ok=True)
|
111 |
+
shutil.rmtree(input_dir)
|
112 |
+
|
113 |
+
with zipfile.ZipFile(managed_output_dir + '.zip', 'w') as zipf:
|
114 |
+
for foldername, subfolders, filenames in os.walk(managed_output_dir):
|
115 |
+
for filename in filenames:
|
116 |
+
if filename.endswith(('.png', '.jpg', '.jpeg')):
|
117 |
+
file_path = os.path.join(foldername, filename)
|
118 |
+
zipf.write(file_path, os.path.basename(file_path))
|
119 |
+
shutil.rmtree(managed_output_dir)
|
120 |
+
|
121 |
+
|
122 |
+
ComicStorageCache(
|
123 |
+
source = source,
|
124 |
+
comic_id = comic_id,
|
125 |
+
chapter_id = chapter_id,
|
126 |
+
chapter_idx = chapter_idx,
|
127 |
+
file_path = managed_output_dir + ".zip",
|
128 |
+
colorize = options.get("colorize"),
|
129 |
+
translate = options.get("translate").get("state"),
|
130 |
+
target_lang = target_lang,
|
131 |
+
|
132 |
+
).save()
|
133 |
+
|
134 |
+
|
135 |
+
query_result_3 = SocketRequestChapterQueueCache.objects.filter(id=query_result.id).first()
|
136 |
+
channel_name = query_result_3.channel_name if query_result_3 else ""
|
137 |
+
channel_layer = get_channel_layer()
|
138 |
+
async_to_sync(channel_layer.send)(channel_name, {
|
139 |
+
'type': 'event_send',
|
140 |
+
'data': {
|
141 |
+
"type": "chapter_ready_to_download",
|
142 |
+
"data": {
|
143 |
+
"source": source,
|
144 |
+
"comic_id": comic_id,
|
145 |
+
"chapter_id": chapter_id,
|
146 |
+
"chapter_idx": chapter_idx
|
147 |
+
}
|
148 |
+
}
|
149 |
+
})
|
150 |
+
SocketRequestChapterQueueCache.objects.filter(id=query_result.id).delete()
|
151 |
+
else:
|
152 |
+
input_dir = os.path.join(STORAGE_DIR,source,comic_id,str(chapter_idx),"original")
|
153 |
+
if os.path.exists(input_dir): shutil.rmtree(input_dir)
|
154 |
+
|
155 |
+
job = web_scrap.source_control["colamanga"].get_chapter.scrap(comic_id=comic_id,chapter_id=chapter_id,output_dir=input_dir)
|
156 |
+
|
157 |
+
with zipfile.ZipFile(input_dir + '.zip', 'w') as zipf:
|
158 |
+
for foldername, subfolders, filenames in os.walk(input_dir):
|
159 |
+
for filename in filenames:
|
160 |
+
if filename.endswith(('.png', '.jpg', '.jpeg')):
|
161 |
+
file_path = os.path.join(foldername, filename)
|
162 |
+
zipf.write(file_path, os.path.basename(file_path))
|
163 |
+
shutil.rmtree(input_dir)
|
164 |
+
|
165 |
+
ComicStorageCache(
|
166 |
+
source = source,
|
167 |
+
comic_id = comic_id,
|
168 |
+
chapter_id = chapter_id,
|
169 |
+
chapter_idx = chapter_idx,
|
170 |
+
file_path = input_dir + '.zip',
|
171 |
+
colorize = False,
|
172 |
+
translate = False,
|
173 |
+
target_lang = "",
|
174 |
+
|
175 |
+
).save()
|
176 |
+
query_result_3 = SocketRequestChapterQueueCache.objects.filter(id=query_result.id).first()
|
177 |
+
channel_name = query_result_3.channel_name if query_result_3 else ""
|
178 |
+
channel_layer = get_channel_layer()
|
179 |
+
async_to_sync(channel_layer.send)(channel_name, {
|
180 |
+
'type': 'event_send',
|
181 |
+
'data': {
|
182 |
+
"type": "chapter_ready_to_download",
|
183 |
+
"data": {
|
184 |
+
"source": source,
|
185 |
+
"comic_id": comic_id,
|
186 |
+
"chapter_id": chapter_id,
|
187 |
+
"chapter_idx": chapter_idx
|
188 |
+
}
|
189 |
+
}
|
190 |
+
})
|
191 |
+
SocketRequestChapterQueueCache.objects.filter(id=query_result.id).delete()
|
192 |
+
|
193 |
+
connections['cache'].close()
|
194 |
+
else:
|
195 |
+
connections['cache'].close()
|
196 |
+
sleep(5)
|
197 |
+
except Exception as e:
|
198 |
+
print("[Error] Chapter Queue Socket:", e)
|
199 |
+
if (input_dir):
|
200 |
+
if os.path.exists(input_dir): shutil.rmtree(input_dir)
|
201 |
+
if (managed_output_dir):
|
202 |
+
if os.path.exists(managed_output_dir): shutil.rmtree(managed_output_dir)
|
203 |
+
query_result_3 = SocketRequestChapterQueueCache.objects.filter(id=query_result.id).first()
|
204 |
+
channel_name = query_result_3.channel_name if query_result_3 else ""
|
205 |
+
channel_layer = get_channel_layer()
|
206 |
+
async_to_sync(channel_layer.send)(channel_name, {
|
207 |
+
'type': 'event_send',
|
208 |
+
'data': {
|
209 |
+
"type": "chapter_ready_to_download",
|
210 |
+
"data": {"state":"error"}
|
211 |
+
}
|
212 |
+
})
|
213 |
+
|
214 |
+
SocketRequestChapterQueueCache.objects.filter(id=query_result.id).delete()
|
215 |
+
connections['cache'].close()
|
216 |
+
sleep(10)
|
217 |
+
|
218 |
+
thread = Job()
|
219 |
+
thread.daemon = True
|
220 |
+
thread.start()
|
221 |
+
|
222 |
+
class UpdateSocketQueue(Thread):
|
223 |
+
def run(self):
|
224 |
+
while True:
|
225 |
+
try:
|
226 |
+
queue = 0
|
227 |
+
MAX_QUEUE = SocketRequestChapterQueueCache.objects.count()
|
228 |
+
|
229 |
+
if (MAX_QUEUE):
|
230 |
+
query_result = list(set(SocketRequestChapterQueueCache.objects.order_by("datetime").values_list('socket_id', flat=True).distinct()))
|
231 |
+
for socket_id in query_result:
|
232 |
+
object = {}
|
233 |
+
query_result_2 = SocketRequestChapterQueueCache.objects.filter(socket_id=socket_id).order_by("datetime").values("source","comic_id","chapter_idx")
|
234 |
+
|
235 |
+
for item in query_result_2:
|
236 |
+
source = item.get("source")
|
237 |
+
comic_id = item.get("comic_id")
|
238 |
+
chapter_idx = item.get("chapter_idx")
|
239 |
+
|
240 |
+
object[f"{source}-{comic_id}-{chapter_idx}"] = queue
|
241 |
+
|
242 |
+
queue += 1
|
243 |
+
|
244 |
+
query_result_3 = SocketRequestChapterQueueCache.objects.filter(socket_id=socket_id).first()
|
245 |
+
if (query_result_3):
|
246 |
+
channel_layer = get_channel_layer()
|
247 |
+
async_to_sync(channel_layer.send)(query_result_3.channel_name, {
|
248 |
+
'type': 'event_send',
|
249 |
+
'data': {
|
250 |
+
"type": "chapter_queue_info",
|
251 |
+
"chapter_queue": {
|
252 |
+
"queue": object,
|
253 |
+
"max_queue": MAX_QUEUE,
|
254 |
+
}
|
255 |
+
}
|
256 |
+
})
|
257 |
+
else:
|
258 |
+
pass
|
259 |
+
except Exception as e:
|
260 |
+
print(e)
|
261 |
+
|
262 |
+
connections['cache'].close()
|
263 |
+
sleep(10)
|
264 |
+
thread = UpdateSocketQueue()
|
265 |
+
thread.daemon = True
|
266 |
+
thread.start()
|
backend/invoke_worker/session.py
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from django_thread import Thread
|
2 |
+
from time import sleep
|
3 |
+
from backend.module.utils import date_utils
|
4 |
+
import requests, environ
|
5 |
+
from core import settings
|
6 |
+
|
7 |
+
env = environ.Env()
|
8 |
+
|
9 |
+
class Delete(Thread):
|
10 |
+
def run(self):
|
11 |
+
while True:
|
12 |
+
try:
|
13 |
+
requests.post(f'{settings.WORKER_SERVED_SCOPE}/worker/session/delete_outdated/', headers={"Worker-Token": env("WORKER_TOKEN")})
|
14 |
+
print('[Worker] All expired sessions have been cleared successfully.')
|
15 |
+
sleep(1.5 * 60 * 60)
|
16 |
+
except Exception as e:
|
17 |
+
print(e)
|
18 |
+
sleep(10)
|
19 |
+
|
20 |
+
thread = Delete()
|
21 |
+
thread.daemon = True
|
22 |
+
thread.start()
|
23 |
+
|
24 |
+
|
backend/management/commands/__pycache__/clear_all_sessions.cpython-312.pyc
ADDED
Binary file (1.07 kB). View file
|
|
backend/management/commands/__pycache__/custom_clearsessions.cpython-312.pyc
ADDED
Binary file (893 Bytes). View file
|
|
backend/management/commands/clear_all_sessions.py
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from django.core.management.base import BaseCommand
|
2 |
+
from django.contrib.sessions.models import Session
|
3 |
+
from django.db import connections
|
4 |
+
|
5 |
+
class Command(BaseCommand):
|
6 |
+
help = 'Clear all sessions'
|
7 |
+
|
8 |
+
def handle(self, *args, **options):
|
9 |
+
for db in connections.databases:
|
10 |
+
Session.objects.using(db).all().delete()
|
11 |
+
self.stdout.write('All sessions have been cleared.')
|