Spaces:
Runtime error
Runtime error
AkshitShubham
commited on
Commit
•
41ca5f7
1
Parent(s):
47d04a3
Upload folder using huggingface_hub
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +2 -2
- .gitignore +199 -199
- Dockerfile +67 -67
- README.md +192 -181
- beta/api/api.py +40 -40
- beta/api/api_dl.py +35 -35
- beta/api/blueprints/api_pref_manager.py +39 -39
- beta/api/blueprints/client_info_routes.py +103 -103
- beta/api/blueprints/leagacy_create_task.py +40 -40
- beta/api/blueprints/session_lodge.py +82 -82
- beta/api/blueprints/template_routes.py +24 -24
- beta/api/blueprints/while_dl_and_post_dl.py +34 -34
- beta/api/mr_manager/boss_manager.py +7 -7
- beta/api/mr_manager/client_manager.py +119 -119
- beta/api/mr_manager/task_manager.py +105 -105
- beta/shellLogic/TokenUpdate.py +35 -35
- beta/shellLogic/handleLogics/HandleBasicCMDUtils.py +64 -64
- beta/shellLogic/handleLogics/HandleKeyAndAvailiblity.py +39 -39
- beta/shellLogic/handleLogics/HandleShellDL.py +62 -62
- beta/shellLogic/logic.py +29 -29
- beta/shellLogic/logicError.py +5 -5
- beta/shellLogic/shell.py +60 -60
- beta/shellLogic/simpleParser.py +5 -5
- beta/shellLogic/update.py +20 -20
- beta/util.py +46 -46
- defaults.json +14 -14
- defaults.linux.json +14 -14
- mainLogic/big4/cleanup.py +37 -37
- mainLogic/big4/decrypt/decrypt.py +54 -54
- mainLogic/big4/decrypt/key.old.py +85 -85
- mainLogic/big4/decrypt/key.py +138 -138
- mainLogic/big4/dl_obsolete.py +175 -175
- mainLogic/big4/downloadv2.py +96 -96
- mainLogic/big4/merge.py +35 -35
- mainLogic/downloader.py +117 -117
- mainLogic/error.py +86 -86
- mainLogic/main.py +126 -126
- mainLogic/startup/checkup.py +200 -200
- mainLogic/startup/flareCheck.py +17 -17
- mainLogic/startup/userPrefs.py +58 -58
- mainLogic/utils/basicUtils.py +25 -25
- mainLogic/utils/gen_utils.py +79 -79
- mainLogic/utils/glv.py +73 -73
- mainLogic/utils/glv_var.py +23 -23
- mainLogic/utils/keyUtils.py +25 -25
- mainLogic/utils/os2.py +70 -70
- mainLogic/utils/process.py +64 -64
- pwdl.bat +45 -45
- pwdl.py +32 -32
- run.py +2 -2
.gitattributes
CHANGED
@@ -1,2 +1,2 @@
|
|
1 |
-
# Auto detect text files and perform LF normalization
|
2 |
-
* text=auto
|
|
|
1 |
+
# Auto detect text files and perform LF normalization
|
2 |
+
* text=auto
|
.gitignore
CHANGED
@@ -1,199 +1,199 @@
|
|
1 |
-
# Created by https://www.toptal.com/developers/gitignore/api/python
|
2 |
-
# Edit at https://www.toptal.com/developers/gitignore?templates=python
|
3 |
-
|
4 |
-
### Python ###
|
5 |
-
# Byte-compiled / optimized / DLL files
|
6 |
-
__pycache__/
|
7 |
-
*.py[cod]
|
8 |
-
*$py.class
|
9 |
-
|
10 |
-
# IDE
|
11 |
-
.idea/
|
12 |
-
|
13 |
-
# Download Files
|
14 |
-
webdl/
|
15 |
-
|
16 |
-
# CSV Files
|
17 |
-
*.csv
|
18 |
-
|
19 |
-
# C extensions
|
20 |
-
*.so
|
21 |
-
|
22 |
-
# Distribution / packaging
|
23 |
-
.Python
|
24 |
-
build/
|
25 |
-
develop-eggs/
|
26 |
-
dist/
|
27 |
-
downloads/
|
28 |
-
eggs/
|
29 |
-
.eggs/
|
30 |
-
lib/
|
31 |
-
lib64/
|
32 |
-
parts/
|
33 |
-
sdist/
|
34 |
-
var/
|
35 |
-
wheels/
|
36 |
-
share/python-wheels/
|
37 |
-
*.egg-info/
|
38 |
-
.installed.cfg
|
39 |
-
*.egg
|
40 |
-
MANIFEST
|
41 |
-
|
42 |
-
# PyInstaller
|
43 |
-
# Usually these files are written by a python script from a template
|
44 |
-
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
45 |
-
*.manifest
|
46 |
-
*.spec
|
47 |
-
|
48 |
-
# Installer logs
|
49 |
-
pip-log.txt
|
50 |
-
pip-delete-this-directory.txt
|
51 |
-
|
52 |
-
# Unit test / coverage reports
|
53 |
-
htmlcov/
|
54 |
-
.tox/
|
55 |
-
.nox/
|
56 |
-
.coverage
|
57 |
-
.coverage.*
|
58 |
-
.cache
|
59 |
-
nosetests.xml
|
60 |
-
coverage.xml
|
61 |
-
*.cover
|
62 |
-
*.py,cover
|
63 |
-
.hypothesis/
|
64 |
-
.pytest_cache/
|
65 |
-
cover/
|
66 |
-
|
67 |
-
# Translations
|
68 |
-
*.mo
|
69 |
-
*.pot
|
70 |
-
|
71 |
-
# Django stuff:
|
72 |
-
*.log
|
73 |
-
local_settings.py
|
74 |
-
db.sqlite3
|
75 |
-
db.sqlite3-journal
|
76 |
-
|
77 |
-
# Flask stuff:
|
78 |
-
instance/
|
79 |
-
.webassets-cache
|
80 |
-
|
81 |
-
# Scrapy stuff:
|
82 |
-
.scrapy
|
83 |
-
|
84 |
-
# Sphinx documentation
|
85 |
-
docs/_build/
|
86 |
-
|
87 |
-
# PyBuilder
|
88 |
-
.pybuilder/
|
89 |
-
target/
|
90 |
-
|
91 |
-
# Jupyter Notebook
|
92 |
-
.ipynb_checkpoints
|
93 |
-
|
94 |
-
# IPython
|
95 |
-
profile_default/
|
96 |
-
ipython_config.py
|
97 |
-
|
98 |
-
# pyenv
|
99 |
-
# For a library or package, you might want to ignore these files since the code is
|
100 |
-
# intended to run in multiple environments; otherwise, check them in:
|
101 |
-
# .python-version
|
102 |
-
|
103 |
-
# pipenv
|
104 |
-
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
105 |
-
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
106 |
-
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
107 |
-
# install all needed dependencies.
|
108 |
-
#Pipfile.lock
|
109 |
-
|
110 |
-
# poetry
|
111 |
-
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
112 |
-
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
113 |
-
# commonly ignored for libraries.
|
114 |
-
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
115 |
-
#poetry.lock
|
116 |
-
|
117 |
-
# pdm
|
118 |
-
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
119 |
-
#pdm.lock
|
120 |
-
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
121 |
-
# in version control.
|
122 |
-
# https://pdm.fming.dev/#use-with-ide
|
123 |
-
.pdm.toml
|
124 |
-
|
125 |
-
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
126 |
-
__pypackages__/
|
127 |
-
|
128 |
-
# Celery stuff
|
129 |
-
celerybeat-schedule
|
130 |
-
celerybeat.pid
|
131 |
-
|
132 |
-
# SageMath parsed files
|
133 |
-
*.sage.py
|
134 |
-
|
135 |
-
# Environments
|
136 |
-
.env
|
137 |
-
.venv
|
138 |
-
env/
|
139 |
-
venv/
|
140 |
-
ENV/
|
141 |
-
env.bak/
|
142 |
-
venv.bak/
|
143 |
-
|
144 |
-
# Spyder project settings
|
145 |
-
.spyderproject
|
146 |
-
.spyproject
|
147 |
-
|
148 |
-
# Rope project settings
|
149 |
-
.ropeproject
|
150 |
-
|
151 |
-
# mkdocs documentation
|
152 |
-
/site
|
153 |
-
|
154 |
-
# mypy
|
155 |
-
.mypy_cache/
|
156 |
-
.dmypy.json
|
157 |
-
dmypy.json
|
158 |
-
|
159 |
-
# Pyre type checker
|
160 |
-
.pyre/
|
161 |
-
|
162 |
-
# pytype static type analyzer
|
163 |
-
.pytype/
|
164 |
-
|
165 |
-
# Cython debug symbols
|
166 |
-
cython_debug/
|
167 |
-
|
168 |
-
# PyCharm
|
169 |
-
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
170 |
-
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
171 |
-
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
172 |
-
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
173 |
-
#.idea/
|
174 |
-
|
175 |
-
### Python Patch ###
|
176 |
-
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
|
177 |
-
poetry.toml
|
178 |
-
|
179 |
-
# ruff
|
180 |
-
.ruff_cache/
|
181 |
-
|
182 |
-
# LSP config files
|
183 |
-
pyrightconfig.json
|
184 |
-
|
185 |
-
# End of https://www.toptal.com/developers/gitignore/api/python
|
186 |
-
pwdlv3.lnk
|
187 |
-
*.mp4
|
188 |
-
/bin/Logs/
|
189 |
-
*.m4s
|
190 |
-
/tmp
|
191 |
-
/bin
|
192 |
-
*.un~
|
193 |
-
*.py~
|
194 |
-
|
195 |
-
# ignore all *.test.py files
|
196 |
-
*.test.py
|
197 |
-
clients.json
|
198 |
-
clients.json
|
199 |
-
/csv_files/
|
|
|
1 |
+
# Created by https://www.toptal.com/developers/gitignore/api/python
|
2 |
+
# Edit at https://www.toptal.com/developers/gitignore?templates=python
|
3 |
+
|
4 |
+
### Python ###
|
5 |
+
# Byte-compiled / optimized / DLL files
|
6 |
+
__pycache__/
|
7 |
+
*.py[cod]
|
8 |
+
*$py.class
|
9 |
+
|
10 |
+
# IDE
|
11 |
+
.idea/
|
12 |
+
|
13 |
+
# Download Files
|
14 |
+
webdl/
|
15 |
+
|
16 |
+
# CSV Files
|
17 |
+
*.csv
|
18 |
+
|
19 |
+
# C extensions
|
20 |
+
*.so
|
21 |
+
|
22 |
+
# Distribution / packaging
|
23 |
+
.Python
|
24 |
+
build/
|
25 |
+
develop-eggs/
|
26 |
+
dist/
|
27 |
+
downloads/
|
28 |
+
eggs/
|
29 |
+
.eggs/
|
30 |
+
lib/
|
31 |
+
lib64/
|
32 |
+
parts/
|
33 |
+
sdist/
|
34 |
+
var/
|
35 |
+
wheels/
|
36 |
+
share/python-wheels/
|
37 |
+
*.egg-info/
|
38 |
+
.installed.cfg
|
39 |
+
*.egg
|
40 |
+
MANIFEST
|
41 |
+
|
42 |
+
# PyInstaller
|
43 |
+
# Usually these files are written by a python script from a template
|
44 |
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
45 |
+
*.manifest
|
46 |
+
*.spec
|
47 |
+
|
48 |
+
# Installer logs
|
49 |
+
pip-log.txt
|
50 |
+
pip-delete-this-directory.txt
|
51 |
+
|
52 |
+
# Unit test / coverage reports
|
53 |
+
htmlcov/
|
54 |
+
.tox/
|
55 |
+
.nox/
|
56 |
+
.coverage
|
57 |
+
.coverage.*
|
58 |
+
.cache
|
59 |
+
nosetests.xml
|
60 |
+
coverage.xml
|
61 |
+
*.cover
|
62 |
+
*.py,cover
|
63 |
+
.hypothesis/
|
64 |
+
.pytest_cache/
|
65 |
+
cover/
|
66 |
+
|
67 |
+
# Translations
|
68 |
+
*.mo
|
69 |
+
*.pot
|
70 |
+
|
71 |
+
# Django stuff:
|
72 |
+
*.log
|
73 |
+
local_settings.py
|
74 |
+
db.sqlite3
|
75 |
+
db.sqlite3-journal
|
76 |
+
|
77 |
+
# Flask stuff:
|
78 |
+
instance/
|
79 |
+
.webassets-cache
|
80 |
+
|
81 |
+
# Scrapy stuff:
|
82 |
+
.scrapy
|
83 |
+
|
84 |
+
# Sphinx documentation
|
85 |
+
docs/_build/
|
86 |
+
|
87 |
+
# PyBuilder
|
88 |
+
.pybuilder/
|
89 |
+
target/
|
90 |
+
|
91 |
+
# Jupyter Notebook
|
92 |
+
.ipynb_checkpoints
|
93 |
+
|
94 |
+
# IPython
|
95 |
+
profile_default/
|
96 |
+
ipython_config.py
|
97 |
+
|
98 |
+
# pyenv
|
99 |
+
# For a library or package, you might want to ignore these files since the code is
|
100 |
+
# intended to run in multiple environments; otherwise, check them in:
|
101 |
+
# .python-version
|
102 |
+
|
103 |
+
# pipenv
|
104 |
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
105 |
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
106 |
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
107 |
+
# install all needed dependencies.
|
108 |
+
#Pipfile.lock
|
109 |
+
|
110 |
+
# poetry
|
111 |
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
112 |
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
113 |
+
# commonly ignored for libraries.
|
114 |
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
115 |
+
#poetry.lock
|
116 |
+
|
117 |
+
# pdm
|
118 |
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
119 |
+
#pdm.lock
|
120 |
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
121 |
+
# in version control.
|
122 |
+
# https://pdm.fming.dev/#use-with-ide
|
123 |
+
.pdm.toml
|
124 |
+
|
125 |
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
126 |
+
__pypackages__/
|
127 |
+
|
128 |
+
# Celery stuff
|
129 |
+
celerybeat-schedule
|
130 |
+
celerybeat.pid
|
131 |
+
|
132 |
+
# SageMath parsed files
|
133 |
+
*.sage.py
|
134 |
+
|
135 |
+
# Environments
|
136 |
+
.env
|
137 |
+
.venv
|
138 |
+
env/
|
139 |
+
venv/
|
140 |
+
ENV/
|
141 |
+
env.bak/
|
142 |
+
venv.bak/
|
143 |
+
|
144 |
+
# Spyder project settings
|
145 |
+
.spyderproject
|
146 |
+
.spyproject
|
147 |
+
|
148 |
+
# Rope project settings
|
149 |
+
.ropeproject
|
150 |
+
|
151 |
+
# mkdocs documentation
|
152 |
+
/site
|
153 |
+
|
154 |
+
# mypy
|
155 |
+
.mypy_cache/
|
156 |
+
.dmypy.json
|
157 |
+
dmypy.json
|
158 |
+
|
159 |
+
# Pyre type checker
|
160 |
+
.pyre/
|
161 |
+
|
162 |
+
# pytype static type analyzer
|
163 |
+
.pytype/
|
164 |
+
|
165 |
+
# Cython debug symbols
|
166 |
+
cython_debug/
|
167 |
+
|
168 |
+
# PyCharm
|
169 |
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
170 |
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
171 |
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
172 |
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
173 |
+
#.idea/
|
174 |
+
|
175 |
+
### Python Patch ###
|
176 |
+
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
|
177 |
+
poetry.toml
|
178 |
+
|
179 |
+
# ruff
|
180 |
+
.ruff_cache/
|
181 |
+
|
182 |
+
# LSP config files
|
183 |
+
pyrightconfig.json
|
184 |
+
|
185 |
+
# End of https://www.toptal.com/developers/gitignore/api/python
|
186 |
+
pwdlv3.lnk
|
187 |
+
*.mp4
|
188 |
+
/bin/Logs/
|
189 |
+
*.m4s
|
190 |
+
/tmp
|
191 |
+
/bin
|
192 |
+
*.un~
|
193 |
+
*.py~
|
194 |
+
|
195 |
+
# ignore all *.test.py files
|
196 |
+
*.test.py
|
197 |
+
clients.json
|
198 |
+
clients.json
|
199 |
+
/csv_files/
|
Dockerfile
CHANGED
@@ -1,67 +1,67 @@
|
|
1 |
-
# Use an official Python runtime as a parent image
|
2 |
-
FROM python:3.12-slim
|
3 |
-
|
4 |
-
# Set the working directory in the container to /app
|
5 |
-
WORKDIR /app
|
6 |
-
|
7 |
-
# Add the current directory contents into the container at /app
|
8 |
-
ADD . /app
|
9 |
-
|
10 |
-
# Install ffmpeg and curl
|
11 |
-
RUN apt-get update && apt-get install -y ffmpeg curl
|
12 |
-
|
13 |
-
# Create a virtual environment and activate it
|
14 |
-
RUN python -m venv /opt/venv
|
15 |
-
|
16 |
-
# Ensure the virtual environment is used
|
17 |
-
ENV PATH="/opt/venv/bin:$PATH"
|
18 |
-
|
19 |
-
# Install any needed packages specified in requirements.txt
|
20 |
-
RUN pip install --no-cache-dir -r requirements.txt
|
21 |
-
|
22 |
-
# Make port 7680 available to the world outside this container
|
23 |
-
EXPOSE 5000
|
24 |
-
|
25 |
-
# Copy defaults.json from the given URL
|
26 |
-
COPY ./defaults.linux.json ./defaults.json
|
27 |
-
|
28 |
-
# Run setup script commands
|
29 |
-
RUN curl -o defaults.json https://raw.githubusercontent.com/shubhamakshit/pwdlv3/main/defaults.linux.json && \
|
30 |
-
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && \
|
31 |
-
if command -v python &> /dev/null; then \
|
32 |
-
echo "Python is installed" && \
|
33 |
-
if [[ $(uname -o) != "Android" ]]; then \
|
34 |
-
python get-pip.py; \
|
35 |
-
fi && \
|
36 |
-
python -m pip install -r requirements.txt; \
|
37 |
-
elif command -v python3 &> /dev/null; then \
|
38 |
-
echo "Python3 is installed" && \
|
39 |
-
if [[ $(uname -o) != "Android" ]]; then \
|
40 |
-
python3 get-pip.py; \
|
41 |
-
fi && \
|
42 |
-
python3 -m pip install -r requirements.txt; \
|
43 |
-
else \
|
44 |
-
echo "Python is not installed" && \
|
45 |
-
exit 1; \
|
46 |
-
fi && \
|
47 |
-
rm get-pip.py && \
|
48 |
-
mkdir -p /app/bin && \
|
49 |
-
curl -o /app/bin/mp4decrypt https://raw.githubusercontent.com/shubhamakshit/pwdlv3_assets/main/$(uname -o)/$(uname -m)/mp4decrypt && \
|
50 |
-
curl -o /app/bin/vsd https://raw.githubusercontent.com/shubhamakshit/pwdlv3_assets/main/$(uname -o)/$(uname -m)/vsd && \
|
51 |
-
chmod +x /app/bin/* && \
|
52 |
-
if ! grep -q "alias pwdl" ~/.bashrc; then \
|
53 |
-
echo "alias pwdl='python3 /app/pwdl.py'" >> ~/.bashrc; \
|
54 |
-
fi && \
|
55 |
-
echo "Please restart your terminal or run 'source ~/.bashrc' to apply the alias."
|
56 |
-
|
57 |
-
# Create webdl directory
|
58 |
-
RUN mkdir /app/webdl
|
59 |
-
|
60 |
-
#set flask app
|
61 |
-
ENV FLASK_DEBUG=1
|
62 |
-
ENV FLASK_ENV=development
|
63 |
-
ENV FLASK_APP=run:app
|
64 |
-
|
65 |
-
ENTRYPOINT ["flask", "run", "--host=0.0.0.0"]
|
66 |
-
|
67 |
-
|
|
|
1 |
+
# Use an official Python runtime as a parent image
|
2 |
+
FROM python:3.12-slim
|
3 |
+
|
4 |
+
# Set the working directory in the container to /app
|
5 |
+
WORKDIR /app
|
6 |
+
|
7 |
+
# Add the current directory contents into the container at /app
|
8 |
+
ADD . /app
|
9 |
+
|
10 |
+
# Install ffmpeg and curl
|
11 |
+
RUN apt-get update && apt-get install -y ffmpeg curl
|
12 |
+
|
13 |
+
# Create a virtual environment and activate it
|
14 |
+
RUN python -m venv /opt/venv
|
15 |
+
|
16 |
+
# Ensure the virtual environment is used
|
17 |
+
ENV PATH="/opt/venv/bin:$PATH"
|
18 |
+
|
19 |
+
# Install any needed packages specified in requirements.txt
|
20 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
21 |
+
|
22 |
+
# Make port 7680 available to the world outside this container
|
23 |
+
EXPOSE 5000
|
24 |
+
|
25 |
+
# Copy defaults.json from the given URL
|
26 |
+
COPY ./defaults.linux.json ./defaults.json
|
27 |
+
|
28 |
+
# Run setup script commands
|
29 |
+
RUN curl -o defaults.json https://raw.githubusercontent.com/shubhamakshit/pwdlv3/main/defaults.linux.json && \
|
30 |
+
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && \
|
31 |
+
if command -v python &> /dev/null; then \
|
32 |
+
echo "Python is installed" && \
|
33 |
+
if [[ $(uname -o) != "Android" ]]; then \
|
34 |
+
python get-pip.py; \
|
35 |
+
fi && \
|
36 |
+
python -m pip install -r requirements.txt; \
|
37 |
+
elif command -v python3 &> /dev/null; then \
|
38 |
+
echo "Python3 is installed" && \
|
39 |
+
if [[ $(uname -o) != "Android" ]]; then \
|
40 |
+
python3 get-pip.py; \
|
41 |
+
fi && \
|
42 |
+
python3 -m pip install -r requirements.txt; \
|
43 |
+
else \
|
44 |
+
echo "Python is not installed" && \
|
45 |
+
exit 1; \
|
46 |
+
fi && \
|
47 |
+
rm get-pip.py && \
|
48 |
+
mkdir -p /app/bin && \
|
49 |
+
curl -o /app/bin/mp4decrypt https://raw.githubusercontent.com/shubhamakshit/pwdlv3_assets/main/$(uname -o)/$(uname -m)/mp4decrypt && \
|
50 |
+
curl -o /app/bin/vsd https://raw.githubusercontent.com/shubhamakshit/pwdlv3_assets/main/$(uname -o)/$(uname -m)/vsd && \
|
51 |
+
chmod +x /app/bin/* && \
|
52 |
+
if ! grep -q "alias pwdl" ~/.bashrc; then \
|
53 |
+
echo "alias pwdl='python3 /app/pwdl.py'" >> ~/.bashrc; \
|
54 |
+
fi && \
|
55 |
+
echo "Please restart your terminal or run 'source ~/.bashrc' to apply the alias."
|
56 |
+
|
57 |
+
# Create webdl directory
|
58 |
+
RUN mkdir /app/webdl
|
59 |
+
|
60 |
+
#set flask app
|
61 |
+
ENV FLASK_DEBUG=1
|
62 |
+
ENV FLASK_ENV=development
|
63 |
+
ENV FLASK_APP=run:app
|
64 |
+
|
65 |
+
ENTRYPOINT ["flask", "run", "--host=0.0.0.0"]
|
66 |
+
|
67 |
+
|
README.md
CHANGED
@@ -1,181 +1,192 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
#
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
#
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
- **
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
|
164 |
-
|
|
165 |
-
|
|
166 |
-
|
|
167 |
-
|
|
168 |
-
|
|
169 |
-
|
|
170 |
-
|
|
171 |
-
|
|
172 |
-
|
|
173 |
-
|
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
title: PhysicsWallah M3u8 Parser
|
3 |
+
emoji: 💻🐳
|
4 |
+
colorFrom: gray
|
5 |
+
colorTo: green
|
6 |
+
sdk: docker
|
7 |
+
pinned: false
|
8 |
+
suggested_storage: small
|
9 |
+
license: mit
|
10 |
+
---
|
11 |
+
|
12 |
+
# Table of Contents
|
13 |
+
1. [Project Information](#project-information)
|
14 |
+
2. [Tools Used](#tools-used)
|
15 |
+
3. [Getting Started](#getting-started)
|
16 |
+
- [Windows](#windows)
|
17 |
+
- [Linux](#linux)
|
18 |
+
4. [Usage](#usage)
|
19 |
+
5. [API Reference](#api-reference)
|
20 |
+
6. [Docker Usage](#docker-usage)
|
21 |
+
7. [Shell Usage (Beta)](#shell-usage-beta)
|
22 |
+
8. [Error Codes](#error-codes)
|
23 |
+
9. [Contributing](#contributing)
|
24 |
+
10. [License](#license)
|
25 |
+
|
26 |
+
# Project Information
|
27 |
+
`pwdlv3` is a project aimed at downloading videos from pw.live. It is written in Python and JavaScript, and uses pip for dependency management.
|
28 |
+
|
29 |
+
# Tools Used
|
30 |
+
|
31 |
+
- **Python**: Backend logic scripting.
|
32 |
+
- **JavaScript**: Frontend logic handling.
|
33 |
+
- **pip**: Dependency management.
|
34 |
+
- **Flask**: HTTP requests handling and web UI rendering.
|
35 |
+
- **Docker**: Containerization for consistent application deployment.
|
36 |
+
- **VSD**: Downloading MPD (MPEG-DASH) files. [More about VSD](https://github.com/clitic/vsd).
|
37 |
+
- **Bento4's mp4decrypt**: Decrypting encrypted MP4 files.
|
38 |
+
- **FFmpeg**: Merging audio and video files.
|
39 |
+
|
40 |
+
# Getting Started
|
41 |
+
|
42 |
+
## Windows
|
43 |
+
1. Clone the repository:
|
44 |
+
```bash
|
45 |
+
git clone https://github.com/username/pwdlv3.git
|
46 |
+
```
|
47 |
+
2. Navigate to the project directory:
|
48 |
+
```bash
|
49 |
+
cd pwdlv3
|
50 |
+
```
|
51 |
+
3. Install the required dependencies:
|
52 |
+
```bash
|
53 |
+
pip install -r requirements.txt
|
54 |
+
```
|
55 |
+
4. Run the setup script:
|
56 |
+
```bash
|
57 |
+
pwdl.bat
|
58 |
+
```
|
59 |
+
|
60 |
+
## Linux
|
61 |
+
1. Clone the repository:
|
62 |
+
```bash
|
63 |
+
git clone https://github.com/username/pwdlv3.git
|
64 |
+
```
|
65 |
+
2. Navigate to the project directory:
|
66 |
+
```bash
|
67 |
+
cd pwdlv3
|
68 |
+
```
|
69 |
+
3. Install the required dependencies:
|
70 |
+
```bash
|
71 |
+
pip install -r requirements.txt
|
72 |
+
```
|
73 |
+
4. Run the setup script:
|
74 |
+
```bash
|
75 |
+
./setup.sh
|
76 |
+
```
|
77 |
+
|
78 |
+
# Usage
|
79 |
+
|
80 |
+
Run the project with the following command:
|
81 |
+
|
82 |
+
```bash
|
83 |
+
python pwdl.py --options
|
84 |
+
```
|
85 |
+
|
86 |
+
- Download a single video:
|
87 |
+
```bash
|
88 |
+
python pwdl.py --id VIDEO_ID --name VIDEO_NAME
|
89 |
+
```
|
90 |
+
- Download multiple videos from a CSV file:
|
91 |
+
```bash
|
92 |
+
python pwdl.py --csv-file FILE_PATH
|
93 |
+
```
|
94 |
+
- Start the shell:
|
95 |
+
```bash
|
96 |
+
python pwdl.py --shell
|
97 |
+
```
|
98 |
+
- Start the WebUI:
|
99 |
+
```bash
|
100 |
+
python pwdl.py --webui
|
101 |
+
```
|
102 |
+
|
103 |
+
# API Reference
|
104 |
+
|
105 |
+
The project provides several API endpoints for interacting with the video downloading service:
|
106 |
+
|
107 |
+
- **POST /api/create_task**: Create a new download task.
|
108 |
+
- **Request Body**: JSON with 'id' (video ID) and 'name' (output file name).
|
109 |
+
- **Response**: JSON with 'task_id'.
|
110 |
+
|
111 |
+
- **GET /api/progress/<task_id>**: Get the progress of a download task.
|
112 |
+
- **Response**: JSON with progress information.
|
113 |
+
|
114 |
+
- **GET /api/get-file/<task_id>/<name>**: Download the completed video file.
|
115 |
+
- **Response**: Video file download.
|
116 |
+
|
117 |
+
- **GET /key/vid_id**: Get the decryption key for a video.
|
118 |
+
- **Query Parameters**: 'vid_id' and 'token'.
|
119 |
+
- **Response**: JSON with 'key'.
|
120 |
+
|
121 |
+
These endpoints are also available without the '/api' prefix. For example, use `/create_task` instead of `/api/create_task`.
|
122 |
+
|
123 |
+
# Docker Usage
|
124 |
+
|
125 |
+
The Dockerfile is used to create a Docker image that encapsulates the entire application, including all dependencies.
|
126 |
+
|
127 |
+
## Building the Docker Image
|
128 |
+
|
129 |
+
Navigate to the project directory and run:
|
130 |
+
|
131 |
+
```bash
|
132 |
+
docker build -t shubhamakshit/pwdl .
|
133 |
+
```
|
134 |
+
|
135 |
+
## Running the Docker Image
|
136 |
+
|
137 |
+
Run the Docker image with:
|
138 |
+
|
139 |
+
```bash
|
140 |
+
docker run -p 5000:5000 shubhamakshit/pwdl
|
141 |
+
```
|
142 |
+
|
143 |
+
Access the application at `http://localhost:5000`.
|
144 |
+
|
145 |
+
# Shell Usage (Beta)
|
146 |
+
|
147 |
+
Start the interactive shell with:
|
148 |
+
|
149 |
+
```bash
|
150 |
+
python pwdl.py --shell
|
151 |
+
```
|
152 |
+
|
153 |
+
Available commands:
|
154 |
+
|
155 |
+
- `get_key <vid_id> <token>`: Get the decryption key for a video.
|
156 |
+
- `tkn-up <token>`: Update the token in the default settings.
|
157 |
+
- `exit`: Exit the shell.
|
158 |
+
|
159 |
+
Note: This feature is in beta and may change.
|
160 |
+
|
161 |
+
# Error Codes
|
162 |
+
|
163 |
+
| Code | Description |
|
164 |
+
| ---- | ----------- |
|
165 |
+
| 0 | No error |
|
166 |
+
| 1 | defaults.json not found |
|
167 |
+
| 2 | Dependency not found |
|
168 |
+
| 3 | Dependency not found in default settings |
|
169 |
+
| 4 | CSV file not found |
|
170 |
+
| 5 | Download failed |
|
171 |
+
| 6 | Could not make directory |
|
172 |
+
| 7 | Token not found in default settings |
|
173 |
+
| 8 | Overwrite aborted by user |
|
174 |
+
| 22 | Can't load file |
|
175 |
+
| 23 | Flare is not started |
|
176 |
+
| 24 | Request failed due to unknown reason |
|
177 |
+
| 25 | Key extraction failed |
|
178 |
+
| 26 | Key not provided |
|
179 |
+
| 27 | Could not download audio |
|
180 |
+
| 28 | Could not download video |
|
181 |
+
| 29 | Could not decrypt audio |
|
182 |
+
| 30 | Could not decrypt video |
|
183 |
+
| 31 | Method is patched |
|
184 |
+
| 32 | Could not extract key |
|
185 |
+
|
186 |
+
# Contributing
|
187 |
+
|
188 |
+
Instructions for how to contribute to the project will be provided here.
|
189 |
+
|
190 |
+
# License
|
191 |
+
|
192 |
+
Information about the project's license will be provided here.
|
beta/api/api.py
CHANGED
@@ -1,40 +1,40 @@
|
|
1 |
-
import os
|
2 |
-
from flask import Flask
|
3 |
-
from flask_cors import CORS
|
4 |
-
from mainLogic.utils.glv import Global
|
5 |
-
from beta.api.mr_manager.boss_manager import Boss
|
6 |
-
|
7 |
-
from beta.api.blueprints.api_pref_manager import api_prefs
|
8 |
-
from beta.api.blueprints.template_routes import template_blueprint
|
9 |
-
from beta.api.blueprints.session_lodge import session_lodge
|
10 |
-
from beta.api.blueprints.while_dl_and_post_dl import dl_and_post_dl
|
11 |
-
from beta.api.blueprints.leagacy_create_task import legacy_create_task
|
12 |
-
from beta.api.blueprints.client_info_routes import client_info
|
13 |
-
|
14 |
-
app = Flask(__name__)
|
15 |
-
CORS(app)
|
16 |
-
|
17 |
-
# Initialize ClientManager and TaskManager
|
18 |
-
client_manager = Boss.client_manager
|
19 |
-
task_manager = Boss.task_manager
|
20 |
-
OUT_DIR = Boss.OUT_DIR
|
21 |
-
|
22 |
-
try:
|
23 |
-
if not os.path.exists(OUT_DIR):
|
24 |
-
os.makedirs(OUT_DIR)
|
25 |
-
except Exception as e:
|
26 |
-
Global.errprint(f"Could not create output directory {OUT_DIR}")
|
27 |
-
Global.sprint(f"Defaulting to './' ")
|
28 |
-
Global.errprint(f"Error: {e}")
|
29 |
-
OUT_DIR = './'
|
30 |
-
|
31 |
-
|
32 |
-
app.register_blueprint(api_prefs)
|
33 |
-
app.register_blueprint(legacy_create_task)
|
34 |
-
app.register_blueprint(template_blueprint)
|
35 |
-
app.register_blueprint(session_lodge)
|
36 |
-
app.register_blueprint(dl_and_post_dl)
|
37 |
-
app.register_blueprint(client_info)
|
38 |
-
|
39 |
-
if __name__ == '__main__':
|
40 |
-
app.run(debug=True, port=7680)
|
|
|
1 |
+
import os
|
2 |
+
from flask import Flask
|
3 |
+
from flask_cors import CORS
|
4 |
+
from mainLogic.utils.glv import Global
|
5 |
+
from beta.api.mr_manager.boss_manager import Boss
|
6 |
+
|
7 |
+
from beta.api.blueprints.api_pref_manager import api_prefs
|
8 |
+
from beta.api.blueprints.template_routes import template_blueprint
|
9 |
+
from beta.api.blueprints.session_lodge import session_lodge
|
10 |
+
from beta.api.blueprints.while_dl_and_post_dl import dl_and_post_dl
|
11 |
+
from beta.api.blueprints.leagacy_create_task import legacy_create_task
|
12 |
+
from beta.api.blueprints.client_info_routes import client_info
|
13 |
+
|
14 |
+
app = Flask(__name__)
|
15 |
+
CORS(app)
|
16 |
+
|
17 |
+
# Initialize ClientManager and TaskManager
|
18 |
+
client_manager = Boss.client_manager
|
19 |
+
task_manager = Boss.task_manager
|
20 |
+
OUT_DIR = Boss.OUT_DIR
|
21 |
+
|
22 |
+
try:
|
23 |
+
if not os.path.exists(OUT_DIR):
|
24 |
+
os.makedirs(OUT_DIR)
|
25 |
+
except Exception as e:
|
26 |
+
Global.errprint(f"Could not create output directory {OUT_DIR}")
|
27 |
+
Global.sprint(f"Defaulting to './' ")
|
28 |
+
Global.errprint(f"Error: {e}")
|
29 |
+
OUT_DIR = './'
|
30 |
+
|
31 |
+
|
32 |
+
app.register_blueprint(api_prefs)
|
33 |
+
app.register_blueprint(legacy_create_task)
|
34 |
+
app.register_blueprint(template_blueprint)
|
35 |
+
app.register_blueprint(session_lodge)
|
36 |
+
app.register_blueprint(dl_and_post_dl)
|
37 |
+
app.register_blueprint(client_info)
|
38 |
+
|
39 |
+
if __name__ == '__main__':
|
40 |
+
app.run(debug=True, port=7680)
|
beta/api/api_dl.py
CHANGED
@@ -1,35 +1,35 @@
|
|
1 |
-
import os
|
2 |
-
from mainLogic.utils.gen_utils import delete_old_files
|
3 |
-
from mainLogic.main import Main
|
4 |
-
from mainLogic.startup.checkup import CheckState
|
5 |
-
from mainLogic.utils.glv import Global
|
6 |
-
from mainLogic.utils import glv_var
|
7 |
-
|
8 |
-
|
9 |
-
def download_pw_video(task_id, name, id, out_dir, client_id, session_id, progress_callback):
|
10 |
-
# Create directories for client_id and session_id if they don't exist
|
11 |
-
client_session_dir = os.path.join(out_dir, client_id, session_id)
|
12 |
-
os.makedirs(client_session_dir, exist_ok=True)
|
13 |
-
|
14 |
-
print(f"Downloading {name} with id {id} to {client_session_dir}")
|
15 |
-
|
16 |
-
ch = CheckState()
|
17 |
-
state = ch.checkup(glv_var.EXECUTABLES, directory="./", verbose=False)
|
18 |
-
prefs = state['prefs']
|
19 |
-
|
20 |
-
if 'webui-del-time' in prefs:
|
21 |
-
del_time = int(prefs['webui-del-time'])
|
22 |
-
else:
|
23 |
-
del_time = 45
|
24 |
-
|
25 |
-
delete_old_files(glv_var.api_webdl_directory, del_time)
|
26 |
-
|
27 |
-
vsd = state['vsd']
|
28 |
-
ffmpeg = state['ffmpeg']
|
29 |
-
mp4d = state['mp4decrypt']
|
30 |
-
verbose = True
|
31 |
-
Main(id=id,
|
32 |
-
name=f"{name}-{task_id}",
|
33 |
-
token=prefs['token'],
|
34 |
-
directory=client_session_dir, tmpDir="/*auto*/", vsdPath=vsd, ffmpeg=ffmpeg, mp4d=mp4d, verbose=verbose,
|
35 |
-
progress_callback=progress_callback).process()
|
|
|
1 |
+
import os
|
2 |
+
from mainLogic.utils.gen_utils import delete_old_files
|
3 |
+
from mainLogic.main import Main
|
4 |
+
from mainLogic.startup.checkup import CheckState
|
5 |
+
from mainLogic.utils.glv import Global
|
6 |
+
from mainLogic.utils import glv_var
|
7 |
+
|
8 |
+
|
9 |
+
def download_pw_video(task_id, name, id, out_dir, client_id, session_id, progress_callback):
|
10 |
+
# Create directories for client_id and session_id if they don't exist
|
11 |
+
client_session_dir = os.path.join(out_dir, client_id, session_id)
|
12 |
+
os.makedirs(client_session_dir, exist_ok=True)
|
13 |
+
|
14 |
+
print(f"Downloading {name} with id {id} to {client_session_dir}")
|
15 |
+
|
16 |
+
ch = CheckState()
|
17 |
+
state = ch.checkup(glv_var.EXECUTABLES, directory="./", verbose=False)
|
18 |
+
prefs = state['prefs']
|
19 |
+
|
20 |
+
if 'webui-del-time' in prefs:
|
21 |
+
del_time = int(prefs['webui-del-time'])
|
22 |
+
else:
|
23 |
+
del_time = 45
|
24 |
+
|
25 |
+
delete_old_files(glv_var.api_webdl_directory, del_time)
|
26 |
+
|
27 |
+
vsd = state['vsd']
|
28 |
+
ffmpeg = state['ffmpeg']
|
29 |
+
mp4d = state['mp4decrypt']
|
30 |
+
verbose = True
|
31 |
+
Main(id=id,
|
32 |
+
name=f"{name}-{task_id}",
|
33 |
+
token=prefs['token'],
|
34 |
+
directory=client_session_dir, tmpDir="/*auto*/", vsdPath=vsd, ffmpeg=ffmpeg, mp4d=mp4d, verbose=verbose,
|
35 |
+
progress_callback=progress_callback).process()
|
beta/api/blueprints/api_pref_manager.py
CHANGED
@@ -1,39 +1,39 @@
|
|
1 |
-
import os
|
2 |
-
|
3 |
-
from flask import Blueprint, request, jsonify
|
4 |
-
|
5 |
-
from mainLogic.utils.glv import Global
|
6 |
-
from mainLogic.utils.glv_var import PREFS_FILE
|
7 |
-
|
8 |
-
api_prefs = Blueprint('api_prefs', __name__)
|
9 |
-
|
10 |
-
@api_prefs.route('/api/prefs/defaults.json', methods=['GET'])
|
11 |
-
@api_prefs.route('/prefs/defaults.json', methods=['GET'])
|
12 |
-
def get_prefs():
|
13 |
-
import json as js
|
14 |
-
file_path = PREFS_FILE
|
15 |
-
if not os.path.exists(file_path):
|
16 |
-
return jsonify({'error': 'file not found'}), 404
|
17 |
-
with open(file_path, 'r') as file:
|
18 |
-
data = js.load(file)
|
19 |
-
return jsonify(data), 200
|
20 |
-
|
21 |
-
|
22 |
-
@api_prefs.route('/api/update/defaults.json', methods=['POST'])
|
23 |
-
@api_prefs.route('/update/defaults.json', methods=['POST'])
|
24 |
-
def update_prefs():
|
25 |
-
import json as js
|
26 |
-
file_path = PREFS_FILE
|
27 |
-
if not os.path.exists(file_path):
|
28 |
-
return jsonify({'error': 'file not found'}), 404
|
29 |
-
try:
|
30 |
-
data = request.json
|
31 |
-
except:
|
32 |
-
return jsonify({'error': 'Invalid JSON'}), 400
|
33 |
-
with open(file_path, 'r') as file:
|
34 |
-
data = js.load(file)
|
35 |
-
data.update(request.json)
|
36 |
-
with open(file_path, 'w') as file:
|
37 |
-
js.dump(data, file, indent=4)
|
38 |
-
return jsonify(data), 200
|
39 |
-
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
from flask import Blueprint, request, jsonify
|
4 |
+
|
5 |
+
from mainLogic.utils.glv import Global
|
6 |
+
from mainLogic.utils.glv_var import PREFS_FILE
|
7 |
+
|
8 |
+
api_prefs = Blueprint('api_prefs', __name__)
|
9 |
+
|
10 |
+
@api_prefs.route('/api/prefs/defaults.json', methods=['GET'])
|
11 |
+
@api_prefs.route('/prefs/defaults.json', methods=['GET'])
|
12 |
+
def get_prefs():
|
13 |
+
import json as js
|
14 |
+
file_path = PREFS_FILE
|
15 |
+
if not os.path.exists(file_path):
|
16 |
+
return jsonify({'error': 'file not found'}), 404
|
17 |
+
with open(file_path, 'r') as file:
|
18 |
+
data = js.load(file)
|
19 |
+
return jsonify(data), 200
|
20 |
+
|
21 |
+
|
22 |
+
@api_prefs.route('/api/update/defaults.json', methods=['POST'])
|
23 |
+
@api_prefs.route('/update/defaults.json', methods=['POST'])
|
24 |
+
def update_prefs():
|
25 |
+
import json as js
|
26 |
+
file_path = PREFS_FILE
|
27 |
+
if not os.path.exists(file_path):
|
28 |
+
return jsonify({'error': 'file not found'}), 404
|
29 |
+
try:
|
30 |
+
data = request.json
|
31 |
+
except:
|
32 |
+
return jsonify({'error': 'Invalid JSON'}), 400
|
33 |
+
with open(file_path, 'r') as file:
|
34 |
+
data = js.load(file)
|
35 |
+
data.update(request.json)
|
36 |
+
with open(file_path, 'w') as file:
|
37 |
+
js.dump(data, file, indent=4)
|
38 |
+
return jsonify(data), 200
|
39 |
+
|
beta/api/blueprints/client_info_routes.py
CHANGED
@@ -1,103 +1,103 @@
|
|
1 |
-
from flask import Blueprint, request, jsonify
|
2 |
-
from beta.api.mr_manager.boss_manager import Boss
|
3 |
-
from mainLogic.big4.decrypt.key import LicenseKeyFetcher
|
4 |
-
|
5 |
-
client_manager = Boss.client_manager
|
6 |
-
task_manager = Boss.task_manager
|
7 |
-
OUT_DIR = Boss.OUT_DIR
|
8 |
-
|
9 |
-
client_info = Blueprint('client_info', __name__)
|
10 |
-
|
11 |
-
@client_info.route('/api/session/<client_id>/<session_id>', methods=['GET'])
|
12 |
-
@client_info.route('/session/<client_id>/<session_id>', methods=['GET'])
|
13 |
-
def get_session(client_id, session_id):
|
14 |
-
# if client_id == 'anonymous' or session_id == 'anonymous':
|
15 |
-
# return jsonify({'error': 'Access to anonymous sessions is not allowed'}), 403
|
16 |
-
|
17 |
-
client_info = client_manager.get_client_info(client_id)
|
18 |
-
if client_info and session_id in client_info['sessions']:
|
19 |
-
session_info = client_info['sessions'][session_id]
|
20 |
-
return jsonify(session_info), 200
|
21 |
-
else:
|
22 |
-
return jsonify({'error': 'Session not found'}), 404
|
23 |
-
|
24 |
-
|
25 |
-
@client_info.route('/api/client/<client_id>', methods=['GET'])
|
26 |
-
@client_info.route('/client/<client_id>', methods=['GET'])
|
27 |
-
def get_client(client_id):
|
28 |
-
|
29 |
-
client_info = client_manager.get_client_info(client_id)
|
30 |
-
if client_info:
|
31 |
-
return jsonify(client_info), 200
|
32 |
-
else:
|
33 |
-
return jsonify({'error': 'Client not found'}), 404
|
34 |
-
|
35 |
-
|
36 |
-
@client_info.route('/api/session/<client_id>/<session_id>/active', methods=['GET'])
|
37 |
-
@client_info.route('/session/<client_id>/<session_id>/active', methods=['GET'])
|
38 |
-
def check_session_active(client_id, session_id):
|
39 |
-
if client_id == 'anonymous' or session_id == 'anonymous':
|
40 |
-
return jsonify({'error': 'Access to anonymous sessions is not allowed'}), 403
|
41 |
-
|
42 |
-
client_info = client_manager.get_client_info(client_id)
|
43 |
-
if client_info and session_id in client_info['sessions']:
|
44 |
-
session_info = client_info['sessions'][session_id]
|
45 |
-
tasks = session_info['tasks']
|
46 |
-
for task_id in tasks:
|
47 |
-
status = tasks[task_id]['status']
|
48 |
-
if status == 'running':
|
49 |
-
return jsonify({'active': True}), 200
|
50 |
-
return jsonify({'active': False}), 200
|
51 |
-
else:
|
52 |
-
return jsonify({'error': 'Session not found'}), 404
|
53 |
-
|
54 |
-
|
55 |
-
def is_session_active(client_id, session_id):
|
56 |
-
if client_id == 'anonymous' or session_id == 'anonymous':
|
57 |
-
return {'error': 'Access to anonymous sessions is not allowed'}, 403
|
58 |
-
|
59 |
-
client_info = client_manager.get_client_info(client_id)
|
60 |
-
if client_info and session_id in client_info['sessions']:
|
61 |
-
session_info = client_info['sessions'][session_id]
|
62 |
-
tasks = session_info['tasks']
|
63 |
-
for task_id, task in tasks.items():
|
64 |
-
if task['status'] == 'running':
|
65 |
-
return {'active': True}, 200
|
66 |
-
return {'active': False}, 200
|
67 |
-
else:
|
68 |
-
return {'error': 'Session not found'}, 404
|
69 |
-
|
70 |
-
|
71 |
-
@client_info.route('/api/client/<client_id>/active_sessions', methods=['GET'])
|
72 |
-
@client_info.route('/client/<client_id>/active_sessions', methods=['GET'])
|
73 |
-
def get_active_sessions(client_id):
|
74 |
-
if client_id == 'anonymous':
|
75 |
-
return jsonify({'error': 'Access to anonymous client is not allowed'}), 403
|
76 |
-
|
77 |
-
client_info = client_manager.get_client_info(client_id)
|
78 |
-
|
79 |
-
if client_info:
|
80 |
-
active_sessions = []
|
81 |
-
for session_id in client_info['sessions']:
|
82 |
-
session_data = is_session_active(client_id, session_id)
|
83 |
-
if session_data[1] != 200:
|
84 |
-
return jsonify(session_data[0]), session_data[1]
|
85 |
-
active = session_data[0].get('active', False)
|
86 |
-
|
87 |
-
if active:
|
88 |
-
active_sessions.append(session_id)
|
89 |
-
return jsonify({"active_sessions": active_sessions}), 200
|
90 |
-
return jsonify({'error': 'Client not found'}), 404
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
@client_info.route('/api/key/vid_id', methods=['GET'])
|
95 |
-
@client_info.route('/key/vid_id', methods=['GET'])
|
96 |
-
def get_key():
|
97 |
-
vid_id = request.args.get('vid_id')
|
98 |
-
token = request.args.get('token')
|
99 |
-
if not vid_id or not token:
|
100 |
-
return jsonify({'error': 'vid_id and token are required'}), 400
|
101 |
-
fetcher = LicenseKeyFetcher(token)
|
102 |
-
key = fetcher.get_key(vid_id)
|
103 |
-
return jsonify({'key': key}), 200
|
|
|
1 |
+
from flask import Blueprint, request, jsonify
|
2 |
+
from beta.api.mr_manager.boss_manager import Boss
|
3 |
+
from mainLogic.big4.decrypt.key import LicenseKeyFetcher
|
4 |
+
|
5 |
+
client_manager = Boss.client_manager
|
6 |
+
task_manager = Boss.task_manager
|
7 |
+
OUT_DIR = Boss.OUT_DIR
|
8 |
+
|
9 |
+
client_info = Blueprint('client_info', __name__)
|
10 |
+
|
11 |
+
@client_info.route('/api/session/<client_id>/<session_id>', methods=['GET'])
|
12 |
+
@client_info.route('/session/<client_id>/<session_id>', methods=['GET'])
|
13 |
+
def get_session(client_id, session_id):
|
14 |
+
# if client_id == 'anonymous' or session_id == 'anonymous':
|
15 |
+
# return jsonify({'error': 'Access to anonymous sessions is not allowed'}), 403
|
16 |
+
|
17 |
+
client_info = client_manager.get_client_info(client_id)
|
18 |
+
if client_info and session_id in client_info['sessions']:
|
19 |
+
session_info = client_info['sessions'][session_id]
|
20 |
+
return jsonify(session_info), 200
|
21 |
+
else:
|
22 |
+
return jsonify({'error': 'Session not found'}), 404
|
23 |
+
|
24 |
+
|
25 |
+
@client_info.route('/api/client/<client_id>', methods=['GET'])
|
26 |
+
@client_info.route('/client/<client_id>', methods=['GET'])
|
27 |
+
def get_client(client_id):
|
28 |
+
|
29 |
+
client_info = client_manager.get_client_info(client_id)
|
30 |
+
if client_info:
|
31 |
+
return jsonify(client_info), 200
|
32 |
+
else:
|
33 |
+
return jsonify({'error': 'Client not found'}), 404
|
34 |
+
|
35 |
+
|
36 |
+
@client_info.route('/api/session/<client_id>/<session_id>/active', methods=['GET'])
|
37 |
+
@client_info.route('/session/<client_id>/<session_id>/active', methods=['GET'])
|
38 |
+
def check_session_active(client_id, session_id):
|
39 |
+
if client_id == 'anonymous' or session_id == 'anonymous':
|
40 |
+
return jsonify({'error': 'Access to anonymous sessions is not allowed'}), 403
|
41 |
+
|
42 |
+
client_info = client_manager.get_client_info(client_id)
|
43 |
+
if client_info and session_id in client_info['sessions']:
|
44 |
+
session_info = client_info['sessions'][session_id]
|
45 |
+
tasks = session_info['tasks']
|
46 |
+
for task_id in tasks:
|
47 |
+
status = tasks[task_id]['status']
|
48 |
+
if status == 'running':
|
49 |
+
return jsonify({'active': True}), 200
|
50 |
+
return jsonify({'active': False}), 200
|
51 |
+
else:
|
52 |
+
return jsonify({'error': 'Session not found'}), 404
|
53 |
+
|
54 |
+
|
55 |
+
def is_session_active(client_id, session_id):
|
56 |
+
if client_id == 'anonymous' or session_id == 'anonymous':
|
57 |
+
return {'error': 'Access to anonymous sessions is not allowed'}, 403
|
58 |
+
|
59 |
+
client_info = client_manager.get_client_info(client_id)
|
60 |
+
if client_info and session_id in client_info['sessions']:
|
61 |
+
session_info = client_info['sessions'][session_id]
|
62 |
+
tasks = session_info['tasks']
|
63 |
+
for task_id, task in tasks.items():
|
64 |
+
if task['status'] == 'running':
|
65 |
+
return {'active': True}, 200
|
66 |
+
return {'active': False}, 200
|
67 |
+
else:
|
68 |
+
return {'error': 'Session not found'}, 404
|
69 |
+
|
70 |
+
|
71 |
+
@client_info.route('/api/client/<client_id>/active_sessions', methods=['GET'])
|
72 |
+
@client_info.route('/client/<client_id>/active_sessions', methods=['GET'])
|
73 |
+
def get_active_sessions(client_id):
|
74 |
+
if client_id == 'anonymous':
|
75 |
+
return jsonify({'error': 'Access to anonymous client is not allowed'}), 403
|
76 |
+
|
77 |
+
client_info = client_manager.get_client_info(client_id)
|
78 |
+
|
79 |
+
if client_info:
|
80 |
+
active_sessions = []
|
81 |
+
for session_id in client_info['sessions']:
|
82 |
+
session_data = is_session_active(client_id, session_id)
|
83 |
+
if session_data[1] != 200:
|
84 |
+
return jsonify(session_data[0]), session_data[1]
|
85 |
+
active = session_data[0].get('active', False)
|
86 |
+
|
87 |
+
if active:
|
88 |
+
active_sessions.append(session_id)
|
89 |
+
return jsonify({"active_sessions": active_sessions}), 200
|
90 |
+
return jsonify({'error': 'Client not found'}), 404
|
91 |
+
|
92 |
+
|
93 |
+
|
94 |
+
@client_info.route('/api/key/vid_id', methods=['GET'])
|
95 |
+
@client_info.route('/key/vid_id', methods=['GET'])
|
96 |
+
def get_key():
|
97 |
+
vid_id = request.args.get('vid_id')
|
98 |
+
token = request.args.get('token')
|
99 |
+
if not vid_id or not token:
|
100 |
+
return jsonify({'error': 'vid_id and token are required'}), 400
|
101 |
+
fetcher = LicenseKeyFetcher(token)
|
102 |
+
key = fetcher.get_key(vid_id)
|
103 |
+
return jsonify({'key': key}), 200
|
beta/api/blueprints/leagacy_create_task.py
CHANGED
@@ -1,40 +1,40 @@
|
|
1 |
-
from flask import Blueprint, request, jsonify
|
2 |
-
from beta.api.api_dl import download_pw_video
|
3 |
-
from beta.api.mr_manager.boss_manager import Boss
|
4 |
-
from mainLogic.utils.gen_utils import generate_safe_folder_name
|
5 |
-
|
6 |
-
legacy_create_task = Blueprint('legacy_create_task', __name__)
|
7 |
-
|
8 |
-
client_manager = Boss.client_manager
|
9 |
-
task_manager = Boss.task_manager
|
10 |
-
OUT_DIR = Boss.OUT_DIR
|
11 |
-
|
12 |
-
@legacy_create_task.route('/api/create_task', methods=['POST'])
|
13 |
-
@legacy_create_task.route('/create_task', methods=['POST'])
|
14 |
-
def create_task():
|
15 |
-
data = request.json
|
16 |
-
client_id = data.get('client_id', 'anonymous')
|
17 |
-
session_id = data.get('session_id', 'anonymous')
|
18 |
-
id = data.get('id')
|
19 |
-
name = data.get('name')
|
20 |
-
|
21 |
-
# Generate safe names
|
22 |
-
name = generate_safe_folder_name(name)
|
23 |
-
|
24 |
-
if not id or not name:
|
25 |
-
return jsonify({'error': 'id and name are required'}), 400
|
26 |
-
|
27 |
-
args = {
|
28 |
-
'name': name,
|
29 |
-
'id': id,
|
30 |
-
'out_dir': OUT_DIR,
|
31 |
-
'client_id': client_id,
|
32 |
-
'session_id': session_id
|
33 |
-
}
|
34 |
-
|
35 |
-
client_manager.add_client(client_id)
|
36 |
-
client_manager.add_session(client_id, session_id)
|
37 |
-
|
38 |
-
task_id = task_manager.create_task(client_id, session_id, download_pw_video, args)
|
39 |
-
return jsonify({'task_id': task_id}), 202
|
40 |
-
|
|
|
1 |
+
from flask import Blueprint, request, jsonify
|
2 |
+
from beta.api.api_dl import download_pw_video
|
3 |
+
from beta.api.mr_manager.boss_manager import Boss
|
4 |
+
from mainLogic.utils.gen_utils import generate_safe_folder_name
|
5 |
+
|
6 |
+
legacy_create_task = Blueprint('legacy_create_task', __name__)
|
7 |
+
|
8 |
+
client_manager = Boss.client_manager
|
9 |
+
task_manager = Boss.task_manager
|
10 |
+
OUT_DIR = Boss.OUT_DIR
|
11 |
+
|
12 |
+
@legacy_create_task.route('/api/create_task', methods=['POST'])
|
13 |
+
@legacy_create_task.route('/create_task', methods=['POST'])
|
14 |
+
def create_task():
|
15 |
+
data = request.json
|
16 |
+
client_id = data.get('client_id', 'anonymous')
|
17 |
+
session_id = data.get('session_id', 'anonymous')
|
18 |
+
id = data.get('id')
|
19 |
+
name = data.get('name')
|
20 |
+
|
21 |
+
# Generate safe names
|
22 |
+
name = generate_safe_folder_name(name)
|
23 |
+
|
24 |
+
if not id or not name:
|
25 |
+
return jsonify({'error': 'id and name are required'}), 400
|
26 |
+
|
27 |
+
args = {
|
28 |
+
'name': name,
|
29 |
+
'id': id,
|
30 |
+
'out_dir': OUT_DIR,
|
31 |
+
'client_id': client_id,
|
32 |
+
'session_id': session_id
|
33 |
+
}
|
34 |
+
|
35 |
+
client_manager.add_client(client_id)
|
36 |
+
client_manager.add_session(client_id, session_id)
|
37 |
+
|
38 |
+
task_id = task_manager.create_task(client_id, session_id, download_pw_video, args)
|
39 |
+
return jsonify({'task_id': task_id}), 202
|
40 |
+
|
beta/api/blueprints/session_lodge.py
CHANGED
@@ -1,82 +1,82 @@
|
|
1 |
-
from flask import Blueprint, request, jsonify
|
2 |
-
from beta.api.api_dl import download_pw_video
|
3 |
-
from mainLogic.utils.gen_utils import generate_random_word
|
4 |
-
from beta.api.mr_manager.boss_manager import Boss
|
5 |
-
from mainLogic.utils.gen_utils import generate_safe_folder_name
|
6 |
-
|
7 |
-
|
8 |
-
session_lodge = Blueprint('session_lodge', __name__)
|
9 |
-
|
10 |
-
client_manager = Boss.client_manager
|
11 |
-
task_manager = Boss.task_manager
|
12 |
-
OUT_DIR = Boss.OUT_DIR
|
13 |
-
|
14 |
-
|
15 |
-
@session_lodge.route('/api/client/<client_id>/<session_id>/create_session', methods=['POST'])
|
16 |
-
@session_lodge.route('/client/<client_id>/<session_id>/create_session', methods=['POST'])
|
17 |
-
def create_session(client_id, session_id):
|
18 |
-
clients = client_manager.get_client_info(client_id)
|
19 |
-
if not clients:
|
20 |
-
client_manager.add_client(client_id)
|
21 |
-
|
22 |
-
session = client_manager.get_client_info(client_id).get('sessions', {}).get(session_id)
|
23 |
-
if not session:
|
24 |
-
client_manager.add_session(client_id, session_id)
|
25 |
-
sess_name = generate_random_word()
|
26 |
-
print(f"Generated session name: {sess_name}")
|
27 |
-
client_manager.set_session_name(client_id, session_id, sess_name)
|
28 |
-
data = request.json
|
29 |
-
ids = data.get('ids', [])
|
30 |
-
names = data.get('names', [])
|
31 |
-
|
32 |
-
|
33 |
-
if not ids or not names:
|
34 |
-
return jsonify({'error': 'ids and names are required'}), 400
|
35 |
-
|
36 |
-
if len(ids) != len(names):
|
37 |
-
return jsonify({'error': 'ids and names must be of equal length'}), 400
|
38 |
-
|
39 |
-
names_safe = [generate_safe_folder_name(name) for name in names]
|
40 |
-
names = names_safe
|
41 |
-
|
42 |
-
task_ids = []
|
43 |
-
|
44 |
-
for i in range(len(ids)):
|
45 |
-
id = ids[i]
|
46 |
-
name = names[i]
|
47 |
-
print(f"Creating task for {name} with id {id}")
|
48 |
-
args = {
|
49 |
-
'name': name,
|
50 |
-
'id': id,
|
51 |
-
'out_dir': OUT_DIR,
|
52 |
-
'client_id': client_id,
|
53 |
-
'session_id': session_id
|
54 |
-
}
|
55 |
-
task_id = task_manager.create_task(client_id, session_id, download_pw_video, args, inactive=True)
|
56 |
-
task_ids.append(task_id)
|
57 |
-
|
58 |
-
return jsonify({'task_ids': task_ids}), 202
|
59 |
-
|
60 |
-
|
61 |
-
@session_lodge.route('/api/start/<task_id>',methods=['GET','POST'])
|
62 |
-
@session_lodge.route('/start/<task_id>',methods=['GET','POST'])
|
63 |
-
def start_task(task_id):
|
64 |
-
try:
|
65 |
-
task_manager.start_task(task_id)
|
66 |
-
return jsonify({'success': True}), 200
|
67 |
-
except Exception as e:
|
68 |
-
print(e)
|
69 |
-
return jsonify({'error': str(e)}), 500
|
70 |
-
|
71 |
-
@session_lodge.route('/api/client/<client_id>/delete_client')
|
72 |
-
@session_lodge.route('/client/<client_id>/delete_client')
|
73 |
-
def delete_client_route(client_id):
|
74 |
-
client_manager.remove_client(client_id)
|
75 |
-
return jsonify({'message': f'Client with ID {client_id} deleted successfully'}), 200
|
76 |
-
|
77 |
-
@session_lodge.route('/api/client/<client_id>/<session_id>/delete_session')
|
78 |
-
@session_lodge.route('/client/<client_id>/<session_id>/delete_session')
|
79 |
-
def delete_session_route(client_id, session_id):
|
80 |
-
client_manager.remove_session(client_id, session_id)
|
81 |
-
return jsonify({'message': f'Session with ID {session_id} for client {client_id} deleted successfully'}), 200
|
82 |
-
|
|
|
1 |
+
from flask import Blueprint, request, jsonify
|
2 |
+
from beta.api.api_dl import download_pw_video
|
3 |
+
from mainLogic.utils.gen_utils import generate_random_word
|
4 |
+
from beta.api.mr_manager.boss_manager import Boss
|
5 |
+
from mainLogic.utils.gen_utils import generate_safe_folder_name
|
6 |
+
|
7 |
+
|
8 |
+
session_lodge = Blueprint('session_lodge', __name__)
|
9 |
+
|
10 |
+
client_manager = Boss.client_manager
|
11 |
+
task_manager = Boss.task_manager
|
12 |
+
OUT_DIR = Boss.OUT_DIR
|
13 |
+
|
14 |
+
|
15 |
+
@session_lodge.route('/api/client/<client_id>/<session_id>/create_session', methods=['POST'])
|
16 |
+
@session_lodge.route('/client/<client_id>/<session_id>/create_session', methods=['POST'])
|
17 |
+
def create_session(client_id, session_id):
|
18 |
+
clients = client_manager.get_client_info(client_id)
|
19 |
+
if not clients:
|
20 |
+
client_manager.add_client(client_id)
|
21 |
+
|
22 |
+
session = client_manager.get_client_info(client_id).get('sessions', {}).get(session_id)
|
23 |
+
if not session:
|
24 |
+
client_manager.add_session(client_id, session_id)
|
25 |
+
sess_name = generate_random_word()
|
26 |
+
print(f"Generated session name: {sess_name}")
|
27 |
+
client_manager.set_session_name(client_id, session_id, sess_name)
|
28 |
+
data = request.json
|
29 |
+
ids = data.get('ids', [])
|
30 |
+
names = data.get('names', [])
|
31 |
+
|
32 |
+
|
33 |
+
if not ids or not names:
|
34 |
+
return jsonify({'error': 'ids and names are required'}), 400
|
35 |
+
|
36 |
+
if len(ids) != len(names):
|
37 |
+
return jsonify({'error': 'ids and names must be of equal length'}), 400
|
38 |
+
|
39 |
+
names_safe = [generate_safe_folder_name(name) for name in names]
|
40 |
+
names = names_safe
|
41 |
+
|
42 |
+
task_ids = []
|
43 |
+
|
44 |
+
for i in range(len(ids)):
|
45 |
+
id = ids[i]
|
46 |
+
name = names[i]
|
47 |
+
print(f"Creating task for {name} with id {id}")
|
48 |
+
args = {
|
49 |
+
'name': name,
|
50 |
+
'id': id,
|
51 |
+
'out_dir': OUT_DIR,
|
52 |
+
'client_id': client_id,
|
53 |
+
'session_id': session_id
|
54 |
+
}
|
55 |
+
task_id = task_manager.create_task(client_id, session_id, download_pw_video, args, inactive=True)
|
56 |
+
task_ids.append(task_id)
|
57 |
+
|
58 |
+
return jsonify({'task_ids': task_ids}), 202
|
59 |
+
|
60 |
+
|
61 |
+
@session_lodge.route('/api/start/<task_id>',methods=['GET','POST'])
|
62 |
+
@session_lodge.route('/start/<task_id>',methods=['GET','POST'])
|
63 |
+
def start_task(task_id):
|
64 |
+
try:
|
65 |
+
task_manager.start_task(task_id)
|
66 |
+
return jsonify({'success': True}), 200
|
67 |
+
except Exception as e:
|
68 |
+
print(e)
|
69 |
+
return jsonify({'error': str(e)}), 500
|
70 |
+
|
71 |
+
@session_lodge.route('/api/client/<client_id>/delete_client')
|
72 |
+
@session_lodge.route('/client/<client_id>/delete_client')
|
73 |
+
def delete_client_route(client_id):
|
74 |
+
client_manager.remove_client(client_id)
|
75 |
+
return jsonify({'message': f'Client with ID {client_id} deleted successfully'}), 200
|
76 |
+
|
77 |
+
@session_lodge.route('/api/client/<client_id>/<session_id>/delete_session')
|
78 |
+
@session_lodge.route('/client/<client_id>/<session_id>/delete_session')
|
79 |
+
def delete_session_route(client_id, session_id):
|
80 |
+
client_manager.remove_session(client_id, session_id)
|
81 |
+
return jsonify({'message': f'Session with ID {session_id} for client {client_id} deleted successfully'}), 200
|
82 |
+
|
beta/api/blueprints/template_routes.py
CHANGED
@@ -1,25 +1,25 @@
|
|
1 |
-
from flask import Blueprint, request, jsonify, render_template
|
2 |
-
|
3 |
-
from mainLogic.utils.glv import Global
|
4 |
-
|
5 |
-
template_blueprint = Blueprint('template_blueprint', __name__)
|
6 |
-
|
7 |
-
@template_blueprint.route('/')
|
8 |
-
def index():
|
9 |
-
return render_template('index.html')
|
10 |
-
|
11 |
-
@template_blueprint.route('/util')
|
12 |
-
def util():
|
13 |
-
return render_template('util.html')
|
14 |
-
|
15 |
-
@template_blueprint.route('/prefs')
|
16 |
-
def prefs():
|
17 |
-
return render_template('prefs.html')
|
18 |
-
|
19 |
-
@template_blueprint.route('/help')
|
20 |
-
def help():
|
21 |
-
return render_template('help.html')
|
22 |
-
|
23 |
-
@template_blueprint.route('/sessions')
|
24 |
-
def sessions():
|
25 |
return render_template('sessions.html')
|
|
|
1 |
+
from flask import Blueprint, request, jsonify, render_template
|
2 |
+
|
3 |
+
from mainLogic.utils.glv import Global
|
4 |
+
|
5 |
+
template_blueprint = Blueprint('template_blueprint', __name__)
|
6 |
+
|
7 |
+
@template_blueprint.route('/')
|
8 |
+
def index():
|
9 |
+
return render_template('index.html')
|
10 |
+
|
11 |
+
@template_blueprint.route('/util')
|
12 |
+
def util():
|
13 |
+
return render_template('util.html')
|
14 |
+
|
15 |
+
@template_blueprint.route('/prefs')
|
16 |
+
def prefs():
|
17 |
+
return render_template('prefs.html')
|
18 |
+
|
19 |
+
@template_blueprint.route('/help')
|
20 |
+
def help():
|
21 |
+
return render_template('help.html')
|
22 |
+
|
23 |
+
@template_blueprint.route('/sessions')
|
24 |
+
def sessions():
|
25 |
return render_template('sessions.html')
|
beta/api/blueprints/while_dl_and_post_dl.py
CHANGED
@@ -1,35 +1,35 @@
|
|
1 |
-
import os
|
2 |
-
|
3 |
-
from flask import Blueprint, jsonify, send_file
|
4 |
-
from beta.api.mr_manager.boss_manager import Boss
|
5 |
-
|
6 |
-
client_manager = Boss.client_manager
|
7 |
-
task_manager = Boss.task_manager
|
8 |
-
OUT_DIR = Boss.OUT_DIR
|
9 |
-
|
10 |
-
dl_and_post_dl = Blueprint('dl_and_post_dl', __name__)
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
@dl_and_post_dl.route('/api/progress/<task_id>', methods=['GET'])
|
15 |
-
@dl_and_post_dl.route('/progress/<task_id>', methods=['GET'])
|
16 |
-
def get_progress(task_id):
|
17 |
-
progress = task_manager.get_progress(task_id)
|
18 |
-
return jsonify(progress), 200
|
19 |
-
|
20 |
-
|
21 |
-
@dl_and_post_dl.route('/api/get-file/<task_id>/<name>', methods=['GET'])
|
22 |
-
@dl_and_post_dl.route('/get-file/<task_id>/<name>', methods=['GET'])
|
23 |
-
def get_file(task_id, name):
|
24 |
-
task_info = task_manager.get_progress(task_id)
|
25 |
-
|
26 |
-
if task_info['status'] == 'not found':
|
27 |
-
return jsonify({'error': 'file not found'}), 404
|
28 |
-
|
29 |
-
client_session_dir = os.path.join(OUT_DIR, task_info['client_id'], task_info['session_id'])
|
30 |
-
|
31 |
-
file_path = os.path.join(client_session_dir, f"{name}-{task_id}.mp4")
|
32 |
-
if not os.path.exists(file_path):
|
33 |
-
return jsonify({'error': 'file not found'}), 404
|
34 |
-
|
35 |
return send_file(file_path, as_attachment=True,download_name=f"{name}.mp4")
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
from flask import Blueprint, jsonify, send_file
|
4 |
+
from beta.api.mr_manager.boss_manager import Boss
|
5 |
+
|
6 |
+
client_manager = Boss.client_manager
|
7 |
+
task_manager = Boss.task_manager
|
8 |
+
OUT_DIR = Boss.OUT_DIR
|
9 |
+
|
10 |
+
dl_and_post_dl = Blueprint('dl_and_post_dl', __name__)
|
11 |
+
|
12 |
+
|
13 |
+
|
14 |
+
@dl_and_post_dl.route('/api/progress/<task_id>', methods=['GET'])
|
15 |
+
@dl_and_post_dl.route('/progress/<task_id>', methods=['GET'])
|
16 |
+
def get_progress(task_id):
|
17 |
+
progress = task_manager.get_progress(task_id)
|
18 |
+
return jsonify(progress), 200
|
19 |
+
|
20 |
+
|
21 |
+
@dl_and_post_dl.route('/api/get-file/<task_id>/<name>', methods=['GET'])
|
22 |
+
@dl_and_post_dl.route('/get-file/<task_id>/<name>', methods=['GET'])
|
23 |
+
def get_file(task_id, name):
|
24 |
+
task_info = task_manager.get_progress(task_id)
|
25 |
+
|
26 |
+
if task_info['status'] == 'not found':
|
27 |
+
return jsonify({'error': 'file not found'}), 404
|
28 |
+
|
29 |
+
client_session_dir = os.path.join(OUT_DIR, task_info['client_id'], task_info['session_id'])
|
30 |
+
|
31 |
+
file_path = os.path.join(client_session_dir, f"{name}-{task_id}.mp4")
|
32 |
+
if not os.path.exists(file_path):
|
33 |
+
return jsonify({'error': 'file not found'}), 404
|
34 |
+
|
35 |
return send_file(file_path, as_attachment=True,download_name=f"{name}.mp4")
|
beta/api/mr_manager/boss_manager.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
-
from beta.api.mr_manager.client_manager import ClientManager
|
2 |
-
from beta.api.mr_manager.task_manager import TaskManager
|
3 |
-
from mainLogic.utils import glv_var
|
4 |
-
|
5 |
-
class Boss:
|
6 |
-
client_manager = ClientManager('clients.json')
|
7 |
-
task_manager = TaskManager(client_manager)
|
8 |
OUT_DIR = glv_var.api_webdl_directory
|
|
|
1 |
+
from beta.api.mr_manager.client_manager import ClientManager
|
2 |
+
from beta.api.mr_manager.task_manager import TaskManager
|
3 |
+
from mainLogic.utils import glv_var
|
4 |
+
|
5 |
+
class Boss:
|
6 |
+
client_manager = ClientManager('clients.json')
|
7 |
+
task_manager = TaskManager(client_manager)
|
8 |
OUT_DIR = glv_var.api_webdl_directory
|
beta/api/mr_manager/client_manager.py
CHANGED
@@ -1,119 +1,119 @@
|
|
1 |
-
import json
|
2 |
-
import os
|
3 |
-
|
4 |
-
class ClientManager:
|
5 |
-
def __init__(self, json_file_path):
|
6 |
-
self.json_file_path = json_file_path
|
7 |
-
self.clients = self.load_data()
|
8 |
-
|
9 |
-
def load_data(self):
|
10 |
-
if not os.path.exists(self.json_file_path):
|
11 |
-
return {}
|
12 |
-
try:
|
13 |
-
with open(self.json_file_path, 'r') as file:
|
14 |
-
return json.load(file)
|
15 |
-
except json.JSONDecodeError:
|
16 |
-
return {}
|
17 |
-
|
18 |
-
def save_data(self):
|
19 |
-
with open(self.json_file_path, 'w') as file:
|
20 |
-
json.dump(self.clients, file, indent=4)
|
21 |
-
|
22 |
-
def client_exists(self, client_id):
|
23 |
-
return client_id in self.clients
|
24 |
-
|
25 |
-
def session_exists(self, client_id, session_id):
|
26 |
-
return client_id in self.clients and session_id in self.clients[client_id]['sessions']
|
27 |
-
|
28 |
-
def add_client(self, client_id="anonymous"):
|
29 |
-
if client_id not in self.clients:
|
30 |
-
self.clients[client_id] = {
|
31 |
-
"name": "Anonymous" if client_id == "anonymous" else "",
|
32 |
-
"client_id": client_id,
|
33 |
-
"sessions": {}
|
34 |
-
}
|
35 |
-
self.save_data()
|
36 |
-
else:
|
37 |
-
print(f"Client with ID {client_id} already exists.")
|
38 |
-
|
39 |
-
def remove_client(self, client_id):
|
40 |
-
if client_id in self.clients:
|
41 |
-
del self.clients[client_id]
|
42 |
-
self.save_data()
|
43 |
-
else:
|
44 |
-
print(f"Client with ID {client_id} does not exist.")
|
45 |
-
|
46 |
-
def add_session(self, client_id="anonymous", session_id="anonymous"):
|
47 |
-
if client_id in self.clients:
|
48 |
-
if session_id not in self.clients[client_id]['sessions']:
|
49 |
-
self.clients[client_id]['sessions'][session_id] = {"tasks": {}, "name": ""}
|
50 |
-
self.save_data()
|
51 |
-
else:
|
52 |
-
print(f"Session with ID {session_id} already exists for client {client_id}.")
|
53 |
-
else:
|
54 |
-
print(f"Client with ID {client_id} does not exist.")
|
55 |
-
|
56 |
-
def remove_session(self, client_id, session_id):
|
57 |
-
if client_id in self.clients and session_id in self.clients[client_id]['sessions']:
|
58 |
-
del self.clients[client_id]['sessions'][session_id]
|
59 |
-
self.save_data()
|
60 |
-
else:
|
61 |
-
print(f"Session with ID {session_id} does not exist for client {client_id}.")
|
62 |
-
|
63 |
-
def add_task(self, client_id, session_id, task_id, task_info):
|
64 |
-
if client_id in self.clients and session_id in self.clients[client_id]['sessions']:
|
65 |
-
self.clients[client_id]['sessions'][session_id]['tasks'][task_id] = task_info
|
66 |
-
self.save_data()
|
67 |
-
else:
|
68 |
-
print(f"Either client with ID {client_id} or session with ID {session_id} does not exist.")
|
69 |
-
|
70 |
-
def update_task(self, task_info):
|
71 |
-
client_id = task_info['client_id']
|
72 |
-
session_id = task_info['session_id']
|
73 |
-
task_id = task_info['task_id']
|
74 |
-
if client_id in self.clients and session_id in self.clients[client_id]['sessions']:
|
75 |
-
if task_id in self.clients[client_id]['sessions'][session_id]['tasks']:
|
76 |
-
self.clients[client_id]['sessions'][session_id]['tasks'][task_id] = task_info
|
77 |
-
self.save_data()
|
78 |
-
else:
|
79 |
-
print(f"Task with ID {task_id} does not exist in session {session_id} for client {client_id}.")
|
80 |
-
else:
|
81 |
-
print(f"Either client with ID {client_id} or session with ID {session_id} does not exist.")
|
82 |
-
|
83 |
-
def remove_task(self, client_id, session_id, task_id):
|
84 |
-
if client_id in self.clients and session_id in self.clients[client_id]['sessions']:
|
85 |
-
if task_id in self.clients[client_id]['sessions'][session_id]['tasks']:
|
86 |
-
del self.clients[client_id]['sessions'][session_id]['tasks'][task_id]
|
87 |
-
self.save_data()
|
88 |
-
else:
|
89 |
-
print(f"Task with ID {task_id} does not exist in session {session_id} for client {client_id}.")
|
90 |
-
else:
|
91 |
-
print(f"Either client with ID {client_id} or session with ID {session_id} does not exist.")
|
92 |
-
|
93 |
-
def get_client_info(self, client_id):
|
94 |
-
if client_id in self.clients:
|
95 |
-
return self.clients[client_id]
|
96 |
-
else:
|
97 |
-
print(f"Client with ID {client_id} does not exist.")
|
98 |
-
return None
|
99 |
-
|
100 |
-
def set_session_name(self, client_id, session_id, name):
|
101 |
-
if client_id in self.clients and session_id in self.clients[client_id]['sessions']:
|
102 |
-
self.clients[client_id]['sessions'][session_id]['name'] = name
|
103 |
-
self.save_data()
|
104 |
-
else:
|
105 |
-
print(f"Either client with ID {client_id} or session with ID {session_id} does not exist.")
|
106 |
-
|
107 |
-
def delete_session(self, client_id, session_id):
|
108 |
-
if client_id in self.clients and session_id in self.clients[client_id]['sessions']:
|
109 |
-
del self.clients[client_id]['sessions'][session_id]
|
110 |
-
self.save_data()
|
111 |
-
else:
|
112 |
-
print(f"Session with ID {session_id} does not exist for client {client_id}.")
|
113 |
-
|
114 |
-
def delete_client(self, client_id):
|
115 |
-
if client_id in self.clients:
|
116 |
-
del self.clients[client_id]
|
117 |
-
self.save_data()
|
118 |
-
else:
|
119 |
-
print(f"Client with ID {client_id} does not exist.")
|
|
|
1 |
+
import json
|
2 |
+
import os
|
3 |
+
|
4 |
+
class ClientManager:
|
5 |
+
def __init__(self, json_file_path):
|
6 |
+
self.json_file_path = json_file_path
|
7 |
+
self.clients = self.load_data()
|
8 |
+
|
9 |
+
def load_data(self):
|
10 |
+
if not os.path.exists(self.json_file_path):
|
11 |
+
return {}
|
12 |
+
try:
|
13 |
+
with open(self.json_file_path, 'r') as file:
|
14 |
+
return json.load(file)
|
15 |
+
except json.JSONDecodeError:
|
16 |
+
return {}
|
17 |
+
|
18 |
+
def save_data(self):
|
19 |
+
with open(self.json_file_path, 'w') as file:
|
20 |
+
json.dump(self.clients, file, indent=4)
|
21 |
+
|
22 |
+
def client_exists(self, client_id):
|
23 |
+
return client_id in self.clients
|
24 |
+
|
25 |
+
def session_exists(self, client_id, session_id):
|
26 |
+
return client_id in self.clients and session_id in self.clients[client_id]['sessions']
|
27 |
+
|
28 |
+
def add_client(self, client_id="anonymous"):
|
29 |
+
if client_id not in self.clients:
|
30 |
+
self.clients[client_id] = {
|
31 |
+
"name": "Anonymous" if client_id == "anonymous" else "",
|
32 |
+
"client_id": client_id,
|
33 |
+
"sessions": {}
|
34 |
+
}
|
35 |
+
self.save_data()
|
36 |
+
else:
|
37 |
+
print(f"Client with ID {client_id} already exists.")
|
38 |
+
|
39 |
+
def remove_client(self, client_id):
|
40 |
+
if client_id in self.clients:
|
41 |
+
del self.clients[client_id]
|
42 |
+
self.save_data()
|
43 |
+
else:
|
44 |
+
print(f"Client with ID {client_id} does not exist.")
|
45 |
+
|
46 |
+
def add_session(self, client_id="anonymous", session_id="anonymous"):
|
47 |
+
if client_id in self.clients:
|
48 |
+
if session_id not in self.clients[client_id]['sessions']:
|
49 |
+
self.clients[client_id]['sessions'][session_id] = {"tasks": {}, "name": ""}
|
50 |
+
self.save_data()
|
51 |
+
else:
|
52 |
+
print(f"Session with ID {session_id} already exists for client {client_id}.")
|
53 |
+
else:
|
54 |
+
print(f"Client with ID {client_id} does not exist.")
|
55 |
+
|
56 |
+
def remove_session(self, client_id, session_id):
|
57 |
+
if client_id in self.clients and session_id in self.clients[client_id]['sessions']:
|
58 |
+
del self.clients[client_id]['sessions'][session_id]
|
59 |
+
self.save_data()
|
60 |
+
else:
|
61 |
+
print(f"Session with ID {session_id} does not exist for client {client_id}.")
|
62 |
+
|
63 |
+
def add_task(self, client_id, session_id, task_id, task_info):
|
64 |
+
if client_id in self.clients and session_id in self.clients[client_id]['sessions']:
|
65 |
+
self.clients[client_id]['sessions'][session_id]['tasks'][task_id] = task_info
|
66 |
+
self.save_data()
|
67 |
+
else:
|
68 |
+
print(f"Either client with ID {client_id} or session with ID {session_id} does not exist.")
|
69 |
+
|
70 |
+
def update_task(self, task_info):
|
71 |
+
client_id = task_info['client_id']
|
72 |
+
session_id = task_info['session_id']
|
73 |
+
task_id = task_info['task_id']
|
74 |
+
if client_id in self.clients and session_id in self.clients[client_id]['sessions']:
|
75 |
+
if task_id in self.clients[client_id]['sessions'][session_id]['tasks']:
|
76 |
+
self.clients[client_id]['sessions'][session_id]['tasks'][task_id] = task_info
|
77 |
+
self.save_data()
|
78 |
+
else:
|
79 |
+
print(f"Task with ID {task_id} does not exist in session {session_id} for client {client_id}.")
|
80 |
+
else:
|
81 |
+
print(f"Either client with ID {client_id} or session with ID {session_id} does not exist.")
|
82 |
+
|
83 |
+
def remove_task(self, client_id, session_id, task_id):
|
84 |
+
if client_id in self.clients and session_id in self.clients[client_id]['sessions']:
|
85 |
+
if task_id in self.clients[client_id]['sessions'][session_id]['tasks']:
|
86 |
+
del self.clients[client_id]['sessions'][session_id]['tasks'][task_id]
|
87 |
+
self.save_data()
|
88 |
+
else:
|
89 |
+
print(f"Task with ID {task_id} does not exist in session {session_id} for client {client_id}.")
|
90 |
+
else:
|
91 |
+
print(f"Either client with ID {client_id} or session with ID {session_id} does not exist.")
|
92 |
+
|
93 |
+
def get_client_info(self, client_id):
|
94 |
+
if client_id in self.clients:
|
95 |
+
return self.clients[client_id]
|
96 |
+
else:
|
97 |
+
print(f"Client with ID {client_id} does not exist.")
|
98 |
+
return None
|
99 |
+
|
100 |
+
def set_session_name(self, client_id, session_id, name):
|
101 |
+
if client_id in self.clients and session_id in self.clients[client_id]['sessions']:
|
102 |
+
self.clients[client_id]['sessions'][session_id]['name'] = name
|
103 |
+
self.save_data()
|
104 |
+
else:
|
105 |
+
print(f"Either client with ID {client_id} or session with ID {session_id} does not exist.")
|
106 |
+
|
107 |
+
def delete_session(self, client_id, session_id):
|
108 |
+
if client_id in self.clients and session_id in self.clients[client_id]['sessions']:
|
109 |
+
del self.clients[client_id]['sessions'][session_id]
|
110 |
+
self.save_data()
|
111 |
+
else:
|
112 |
+
print(f"Session with ID {session_id} does not exist for client {client_id}.")
|
113 |
+
|
114 |
+
def delete_client(self, client_id):
|
115 |
+
if client_id in self.clients:
|
116 |
+
del self.clients[client_id]
|
117 |
+
self.save_data()
|
118 |
+
else:
|
119 |
+
print(f"Client with ID {client_id} does not exist.")
|
beta/api/mr_manager/task_manager.py
CHANGED
@@ -1,105 +1,105 @@
|
|
1 |
-
import threading
|
2 |
-
import uuid
|
3 |
-
|
4 |
-
class TaskManager:
|
5 |
-
def __init__(self, client_manager):
|
6 |
-
self.tasks = {}
|
7 |
-
self.lock = threading.Lock()
|
8 |
-
self.client_manager = client_manager
|
9 |
-
self.inactive_tasks = {}
|
10 |
-
|
11 |
-
def handle_completion(self, task_id):
|
12 |
-
print(f"Task {task_id} completed")
|
13 |
-
with self.lock:
|
14 |
-
self.tasks[task_id]['status'] = 'completed'
|
15 |
-
self.client_manager.update_task(self.tasks[task_id])
|
16 |
-
|
17 |
-
on_task_complete = handle_completion
|
18 |
-
|
19 |
-
def create_task(self, client_id, session_id, target, *args, inactive=False):
|
20 |
-
task_id = str(uuid.uuid4())
|
21 |
-
print(f"Args: {args}")
|
22 |
-
args_dict = args[0]
|
23 |
-
try:
|
24 |
-
name = args_dict['name']
|
25 |
-
id = args_dict['id']
|
26 |
-
out_dir = args_dict['out_dir']
|
27 |
-
except KeyError:
|
28 |
-
raise ValueError('name, id, and out_dir are required in args')
|
29 |
-
|
30 |
-
client_id = args_dict.get('client_id', client_id)
|
31 |
-
session_id = args_dict.get('session_id', session_id)
|
32 |
-
|
33 |
-
task_info = {
|
34 |
-
'task_id': task_id,
|
35 |
-
'progress': {
|
36 |
-
'progress': 0
|
37 |
-
},
|
38 |
-
'status': 'created' if inactive else 'running', # Set status to 'created' if inactive
|
39 |
-
'name': name,
|
40 |
-
'out_dir': out_dir,
|
41 |
-
'id': id,
|
42 |
-
'client_id': client_id,
|
43 |
-
'session_id': session_id
|
44 |
-
}
|
45 |
-
|
46 |
-
with self.lock:
|
47 |
-
self.tasks[task_id] = task_info
|
48 |
-
self.client_manager.add_task(client_id, session_id, task_id, task_info)
|
49 |
-
|
50 |
-
if not inactive:
|
51 |
-
thread = threading.Thread(target=self._run_task, args=(task_info, target, name, id, out_dir, client_id, session_id, *args[1:]))
|
52 |
-
thread.start()
|
53 |
-
else:
|
54 |
-
self.inactive_tasks[task_id] = {
|
55 |
-
'target': target,
|
56 |
-
'args': args,
|
57 |
-
'task_info': task_info
|
58 |
-
}
|
59 |
-
|
60 |
-
return task_id
|
61 |
-
|
62 |
-
def start_task(self, task_id):
|
63 |
-
with self.lock:
|
64 |
-
if task_id in self.tasks:
|
65 |
-
if self.tasks[task_id]['status'] == 'created':
|
66 |
-
task_info = self.tasks[task_id]
|
67 |
-
target = self._get_target_function(task_id) # Replace with your actual logic to retrieve the target function
|
68 |
-
thread = threading.Thread(target=self._run_task, args=(task_info, target, task_info['name'], task_info['id'], task_info['out_dir'], task_info['client_id'], task_info['session_id']))
|
69 |
-
thread.start()
|
70 |
-
self.tasks[task_id]['status'] = 'running'
|
71 |
-
else:
|
72 |
-
raise ValueError(f"Task {task_id} is already running or completed.")
|
73 |
-
|
74 |
-
def _run_task(self, task_info, target, *args):
|
75 |
-
task_id = task_info['task_id']
|
76 |
-
try:
|
77 |
-
print(task_id, [*args], lambda progress: self._update_progress(task_id, progress))
|
78 |
-
target(task_id, *args, progress_callback=lambda progress: self._update_progress(task_id, progress))
|
79 |
-
with self.lock:
|
80 |
-
self.tasks[task_id]['url'] = f'/get-file/{task_id}/{self.tasks[task_id]["name"]}'
|
81 |
-
self.tasks[task_id]['status'] = 'completed'
|
82 |
-
self.client_manager.update_task(self.tasks[task_id])
|
83 |
-
except Exception as e:
|
84 |
-
with self.lock:
|
85 |
-
self.tasks[task_id]['status'] = 'failed'
|
86 |
-
self.tasks[task_id]['error'] = str(e)
|
87 |
-
self.client_manager.update_task(self.tasks[task_id])
|
88 |
-
|
89 |
-
def _update_progress(self, task_id, progress):
|
90 |
-
with self.lock:
|
91 |
-
if task_id in self.tasks:
|
92 |
-
self.tasks[task_id]['progress'] = progress
|
93 |
-
self.client_manager.update_task(self.tasks[task_id])
|
94 |
-
|
95 |
-
def get_progress(self, task_id):
|
96 |
-
with self.lock:
|
97 |
-
return self.tasks.get(task_id, {'status': 'not found'})
|
98 |
-
|
99 |
-
def _get_target_function(self, task_id):
|
100 |
-
if task_id in self.inactive_tasks:
|
101 |
-
return self.inactive_tasks[task_id]['target']
|
102 |
-
else:
|
103 |
-
raise ValueError(f"Task {task_id} is not inactive.")
|
104 |
-
|
105 |
-
|
|
|
1 |
+
import threading
|
2 |
+
import uuid
|
3 |
+
|
4 |
+
class TaskManager:
|
5 |
+
def __init__(self, client_manager):
|
6 |
+
self.tasks = {}
|
7 |
+
self.lock = threading.Lock()
|
8 |
+
self.client_manager = client_manager
|
9 |
+
self.inactive_tasks = {}
|
10 |
+
|
11 |
+
def handle_completion(self, task_id):
|
12 |
+
print(f"Task {task_id} completed")
|
13 |
+
with self.lock:
|
14 |
+
self.tasks[task_id]['status'] = 'completed'
|
15 |
+
self.client_manager.update_task(self.tasks[task_id])
|
16 |
+
|
17 |
+
on_task_complete = handle_completion
|
18 |
+
|
19 |
+
def create_task(self, client_id, session_id, target, *args, inactive=False):
|
20 |
+
task_id = str(uuid.uuid4())
|
21 |
+
print(f"Args: {args}")
|
22 |
+
args_dict = args[0]
|
23 |
+
try:
|
24 |
+
name = args_dict['name']
|
25 |
+
id = args_dict['id']
|
26 |
+
out_dir = args_dict['out_dir']
|
27 |
+
except KeyError:
|
28 |
+
raise ValueError('name, id, and out_dir are required in args')
|
29 |
+
|
30 |
+
client_id = args_dict.get('client_id', client_id)
|
31 |
+
session_id = args_dict.get('session_id', session_id)
|
32 |
+
|
33 |
+
task_info = {
|
34 |
+
'task_id': task_id,
|
35 |
+
'progress': {
|
36 |
+
'progress': 0
|
37 |
+
},
|
38 |
+
'status': 'created' if inactive else 'running', # Set status to 'created' if inactive
|
39 |
+
'name': name,
|
40 |
+
'out_dir': out_dir,
|
41 |
+
'id': id,
|
42 |
+
'client_id': client_id,
|
43 |
+
'session_id': session_id
|
44 |
+
}
|
45 |
+
|
46 |
+
with self.lock:
|
47 |
+
self.tasks[task_id] = task_info
|
48 |
+
self.client_manager.add_task(client_id, session_id, task_id, task_info)
|
49 |
+
|
50 |
+
if not inactive:
|
51 |
+
thread = threading.Thread(target=self._run_task, args=(task_info, target, name, id, out_dir, client_id, session_id, *args[1:]))
|
52 |
+
thread.start()
|
53 |
+
else:
|
54 |
+
self.inactive_tasks[task_id] = {
|
55 |
+
'target': target,
|
56 |
+
'args': args,
|
57 |
+
'task_info': task_info
|
58 |
+
}
|
59 |
+
|
60 |
+
return task_id
|
61 |
+
|
62 |
+
def start_task(self, task_id):
|
63 |
+
with self.lock:
|
64 |
+
if task_id in self.tasks:
|
65 |
+
if self.tasks[task_id]['status'] == 'created':
|
66 |
+
task_info = self.tasks[task_id]
|
67 |
+
target = self._get_target_function(task_id) # Replace with your actual logic to retrieve the target function
|
68 |
+
thread = threading.Thread(target=self._run_task, args=(task_info, target, task_info['name'], task_info['id'], task_info['out_dir'], task_info['client_id'], task_info['session_id']))
|
69 |
+
thread.start()
|
70 |
+
self.tasks[task_id]['status'] = 'running'
|
71 |
+
else:
|
72 |
+
raise ValueError(f"Task {task_id} is already running or completed.")
|
73 |
+
|
74 |
+
def _run_task(self, task_info, target, *args):
|
75 |
+
task_id = task_info['task_id']
|
76 |
+
try:
|
77 |
+
print(task_id, [*args], lambda progress: self._update_progress(task_id, progress))
|
78 |
+
target(task_id, *args, progress_callback=lambda progress: self._update_progress(task_id, progress))
|
79 |
+
with self.lock:
|
80 |
+
self.tasks[task_id]['url'] = f'/get-file/{task_id}/{self.tasks[task_id]["name"]}'
|
81 |
+
self.tasks[task_id]['status'] = 'completed'
|
82 |
+
self.client_manager.update_task(self.tasks[task_id])
|
83 |
+
except Exception as e:
|
84 |
+
with self.lock:
|
85 |
+
self.tasks[task_id]['status'] = 'failed'
|
86 |
+
self.tasks[task_id]['error'] = str(e)
|
87 |
+
self.client_manager.update_task(self.tasks[task_id])
|
88 |
+
|
89 |
+
def _update_progress(self, task_id, progress):
|
90 |
+
with self.lock:
|
91 |
+
if task_id in self.tasks:
|
92 |
+
self.tasks[task_id]['progress'] = progress
|
93 |
+
self.client_manager.update_task(self.tasks[task_id])
|
94 |
+
|
95 |
+
def get_progress(self, task_id):
|
96 |
+
with self.lock:
|
97 |
+
return self.tasks.get(task_id, {'status': 'not found'})
|
98 |
+
|
99 |
+
def _get_target_function(self, task_id):
|
100 |
+
if task_id in self.inactive_tasks:
|
101 |
+
return self.inactive_tasks[task_id]['target']
|
102 |
+
else:
|
103 |
+
raise ValueError(f"Task {task_id} is not inactive.")
|
104 |
+
|
105 |
+
|
beta/shellLogic/TokenUpdate.py
CHANGED
@@ -1,35 +1,35 @@
|
|
1 |
-
from mainLogic.utils.glv import Global
|
2 |
-
from beta.shellLogic import simpleParser
|
3 |
-
from mainLogic.utils.glv_var import PREFS_FILE
|
4 |
-
from beta.shellLogic.update import UpdateJSONFile
|
5 |
-
class TokenUpdate:
|
6 |
-
|
7 |
-
def __init__(self):
|
8 |
-
|
9 |
-
self.file_path = PREFS_FILE
|
10 |
-
# hard coding 'defaults.json' as to ../../defaults.json
|
11 |
-
#Global.errprint("Warning! This is a beta feature. Use at your own risk.")
|
12 |
-
#Global.errprint("Hard Coded to use 'defaults.json' as to ../../defaults.json (in Global.PREFERENCES_FILE)")
|
13 |
-
self.commandList = {
|
14 |
-
"tkn-up":{
|
15 |
-
"func": self.update
|
16 |
-
}
|
17 |
-
}
|
18 |
-
|
19 |
-
def update(self,args=[]):
|
20 |
-
if args:
|
21 |
-
u = UpdateJSONFile(self.file_path)
|
22 |
-
u.update('token',args[0])
|
23 |
-
Global.sprint("Token updated successfully.")
|
24 |
-
else:
|
25 |
-
Global.errprint("Please provide a token to update.")
|
26 |
-
|
27 |
-
def parseAndRun(self,command,args=[]):
|
28 |
-
# simpleParser.parseAndRun(self.commandList, command, args)
|
29 |
-
if command in self.commandList:
|
30 |
-
self.commandList[command]["func"](args)
|
31 |
-
else:
|
32 |
-
Global.errprint("Command not found.")
|
33 |
-
|
34 |
-
|
35 |
-
|
|
|
1 |
+
from mainLogic.utils.glv import Global
|
2 |
+
from beta.shellLogic import simpleParser
|
3 |
+
from mainLogic.utils.glv_var import PREFS_FILE
|
4 |
+
from beta.shellLogic.update import UpdateJSONFile
|
5 |
+
class TokenUpdate:
|
6 |
+
|
7 |
+
def __init__(self):
|
8 |
+
|
9 |
+
self.file_path = PREFS_FILE
|
10 |
+
# hard coding 'defaults.json' as to ../../defaults.json
|
11 |
+
#Global.errprint("Warning! This is a beta feature. Use at your own risk.")
|
12 |
+
#Global.errprint("Hard Coded to use 'defaults.json' as to ../../defaults.json (in Global.PREFERENCES_FILE)")
|
13 |
+
self.commandList = {
|
14 |
+
"tkn-up":{
|
15 |
+
"func": self.update
|
16 |
+
}
|
17 |
+
}
|
18 |
+
|
19 |
+
def update(self,args=[]):
|
20 |
+
if args:
|
21 |
+
u = UpdateJSONFile(self.file_path)
|
22 |
+
u.update('token',args[0])
|
23 |
+
Global.sprint("Token updated successfully.")
|
24 |
+
else:
|
25 |
+
Global.errprint("Please provide a token to update.")
|
26 |
+
|
27 |
+
def parseAndRun(self,command,args=[]):
|
28 |
+
# simpleParser.parseAndRun(self.commandList, command, args)
|
29 |
+
if command in self.commandList:
|
30 |
+
self.commandList[command]["func"](args)
|
31 |
+
else:
|
32 |
+
Global.errprint("Command not found.")
|
33 |
+
|
34 |
+
|
35 |
+
|
beta/shellLogic/handleLogics/HandleBasicCMDUtils.py
CHANGED
@@ -1,64 +1,64 @@
|
|
1 |
-
import sys
|
2 |
-
from beta.shellLogic import simpleParser
|
3 |
-
from mainLogic.utils.os2 import SysFunc
|
4 |
-
|
5 |
-
os2 = SysFunc()
|
6 |
-
|
7 |
-
|
8 |
-
class HandleBasicCMDUtils:
|
9 |
-
# basic class for handling basic commands
|
10 |
-
# every such class must have a method to parse command (regex based) a help for each command handled by the class
|
11 |
-
|
12 |
-
def __init__(self):
|
13 |
-
self.commandList = {
|
14 |
-
"cls":
|
15 |
-
{
|
16 |
-
"desc": "Clear the screen",
|
17 |
-
"regex": r"cls",
|
18 |
-
"func": self.cls
|
19 |
-
},
|
20 |
-
|
21 |
-
"cd":
|
22 |
-
{
|
23 |
-
"desc": "Change directory",
|
24 |
-
"regex": r"cd",
|
25 |
-
"func": self.cd
|
26 |
-
},
|
27 |
-
"cmd":
|
28 |
-
{
|
29 |
-
"desc": "Run a command",
|
30 |
-
"regex": r"cmd",
|
31 |
-
"func": self.cmd
|
32 |
-
},
|
33 |
-
"exit":
|
34 |
-
{
|
35 |
-
"desc": "Exit the shell",
|
36 |
-
"regex": r"exit",
|
37 |
-
"func": self.exit_shell
|
38 |
-
},
|
39 |
-
}
|
40 |
-
|
41 |
-
def cls(self, args=[]):
|
42 |
-
os2.clear()
|
43 |
-
if args: print(args)
|
44 |
-
|
45 |
-
def exit_shell(self, args=[]):
|
46 |
-
sys.exit(0)
|
47 |
-
|
48 |
-
def cd(self, args=[]):
|
49 |
-
if args:
|
50 |
-
os2.cd(args[0])
|
51 |
-
else:
|
52 |
-
os2.cd()
|
53 |
-
|
54 |
-
def cmd(self, args=[]):
|
55 |
-
import os
|
56 |
-
os.system(" ".join(args))
|
57 |
-
|
58 |
-
def parseAndRun(self, command, args=[]):
|
59 |
-
# for key in self.commandList:
|
60 |
-
# if re.match(self.commandList[key]["regex"], command):
|
61 |
-
# self.commandList[key]["func"]()
|
62 |
-
# return
|
63 |
-
# raise logicError.commandNotFound(command)
|
64 |
-
simpleParser.parseAndRun(self.commandList, command, args)
|
|
|
1 |
+
import sys
|
2 |
+
from beta.shellLogic import simpleParser
|
3 |
+
from mainLogic.utils.os2 import SysFunc
|
4 |
+
|
5 |
+
os2 = SysFunc()
|
6 |
+
|
7 |
+
|
8 |
+
class HandleBasicCMDUtils:
|
9 |
+
# basic class for handling basic commands
|
10 |
+
# every such class must have a method to parse command (regex based) a help for each command handled by the class
|
11 |
+
|
12 |
+
def __init__(self):
|
13 |
+
self.commandList = {
|
14 |
+
"cls":
|
15 |
+
{
|
16 |
+
"desc": "Clear the screen",
|
17 |
+
"regex": r"cls",
|
18 |
+
"func": self.cls
|
19 |
+
},
|
20 |
+
|
21 |
+
"cd":
|
22 |
+
{
|
23 |
+
"desc": "Change directory",
|
24 |
+
"regex": r"cd",
|
25 |
+
"func": self.cd
|
26 |
+
},
|
27 |
+
"cmd":
|
28 |
+
{
|
29 |
+
"desc": "Run a command",
|
30 |
+
"regex": r"cmd",
|
31 |
+
"func": self.cmd
|
32 |
+
},
|
33 |
+
"exit":
|
34 |
+
{
|
35 |
+
"desc": "Exit the shell",
|
36 |
+
"regex": r"exit",
|
37 |
+
"func": self.exit_shell
|
38 |
+
},
|
39 |
+
}
|
40 |
+
|
41 |
+
def cls(self, args=[]):
|
42 |
+
os2.clear()
|
43 |
+
if args: print(args)
|
44 |
+
|
45 |
+
def exit_shell(self, args=[]):
|
46 |
+
sys.exit(0)
|
47 |
+
|
48 |
+
def cd(self, args=[]):
|
49 |
+
if args:
|
50 |
+
os2.cd(args[0])
|
51 |
+
else:
|
52 |
+
os2.cd()
|
53 |
+
|
54 |
+
def cmd(self, args=[]):
|
55 |
+
import os
|
56 |
+
os.system(" ".join(args))
|
57 |
+
|
58 |
+
def parseAndRun(self, command, args=[]):
|
59 |
+
# for key in self.commandList:
|
60 |
+
# if re.match(self.commandList[key]["regex"], command):
|
61 |
+
# self.commandList[key]["func"]()
|
62 |
+
# return
|
63 |
+
# raise logicError.commandNotFound(command)
|
64 |
+
simpleParser.parseAndRun(self.commandList, command, args)
|
beta/shellLogic/handleLogics/HandleKeyAndAvailiblity.py
CHANGED
@@ -1,39 +1,39 @@
|
|
1 |
-
from mainLogic.big4.decrypt.key import LicenseKeyFetcher
|
2 |
-
from beta.shellLogic import simpleParser
|
3 |
-
from mainLogic.utils.glv import Global
|
4 |
-
from mainLogic.utils import glv_var
|
5 |
-
|
6 |
-
class HandleKeyAndAvailiblity:
|
7 |
-
|
8 |
-
def __init__(self):
|
9 |
-
from mainLogic.startup.checkup import CheckState
|
10 |
-
ch = CheckState()
|
11 |
-
self.token = ch.checkup(glv_var.EXECUTABLES,verbose=False)['prefs']['token']
|
12 |
-
self.lkf = LicenseKeyFetcher(self.token)
|
13 |
-
self.commandList = {
|
14 |
-
"get_key":{
|
15 |
-
"regex": r"(get_key|key)",
|
16 |
-
"func": self.get_key,
|
17 |
-
},
|
18 |
-
"check":{
|
19 |
-
"func": self.check
|
20 |
-
}
|
21 |
-
|
22 |
-
}
|
23 |
-
|
24 |
-
def get_key(self,args=[]):
|
25 |
-
if args:
|
26 |
-
self.lkf.get_key(args[0])
|
27 |
-
|
28 |
-
def check(self,args=[]):
|
29 |
-
print("Checking the availiblity of the key...")
|
30 |
-
if args:
|
31 |
-
if self.lkf.get_key(args[0],verbose=False):
|
32 |
-
print("Key is available")
|
33 |
-
else:
|
34 |
-
print("Key is not available")
|
35 |
-
else:
|
36 |
-
print("Please provide a key to check")
|
37 |
-
|
38 |
-
def parseAndRun(self,command,args=[]):
|
39 |
-
simpleParser.parseAndRun(self.commandList, command, args)
|
|
|
1 |
+
from mainLogic.big4.decrypt.key import LicenseKeyFetcher
|
2 |
+
from beta.shellLogic import simpleParser
|
3 |
+
from mainLogic.utils.glv import Global
|
4 |
+
from mainLogic.utils import glv_var
|
5 |
+
|
6 |
+
class HandleKeyAndAvailiblity:
|
7 |
+
|
8 |
+
def __init__(self):
|
9 |
+
from mainLogic.startup.checkup import CheckState
|
10 |
+
ch = CheckState()
|
11 |
+
self.token = ch.checkup(glv_var.EXECUTABLES,verbose=False)['prefs']['token']
|
12 |
+
self.lkf = LicenseKeyFetcher(self.token)
|
13 |
+
self.commandList = {
|
14 |
+
"get_key":{
|
15 |
+
"regex": r"(get_key|key)",
|
16 |
+
"func": self.get_key,
|
17 |
+
},
|
18 |
+
"check":{
|
19 |
+
"func": self.check
|
20 |
+
}
|
21 |
+
|
22 |
+
}
|
23 |
+
|
24 |
+
def get_key(self,args=[]):
|
25 |
+
if args:
|
26 |
+
self.lkf.get_key(args[0])
|
27 |
+
|
28 |
+
def check(self,args=[]):
|
29 |
+
print("Checking the availiblity of the key...")
|
30 |
+
if args:
|
31 |
+
if self.lkf.get_key(args[0],verbose=False):
|
32 |
+
print("Key is available")
|
33 |
+
else:
|
34 |
+
print("Key is not available")
|
35 |
+
else:
|
36 |
+
print("Please provide a key to check")
|
37 |
+
|
38 |
+
def parseAndRun(self,command,args=[]):
|
39 |
+
simpleParser.parseAndRun(self.commandList, command, args)
|
beta/shellLogic/handleLogics/HandleShellDL.py
CHANGED
@@ -1,62 +1,62 @@
|
|
1 |
-
from mainLogic.big4.downloadv2 import Download
|
2 |
-
from mainLogic.startup.checkup import CheckState
|
3 |
-
from mainLogic.utils.glv import Global
|
4 |
-
from mainLogic.main import Main
|
5 |
-
from beta.shellLogic import simpleParser
|
6 |
-
from mainLogic.utils import glv_var
|
7 |
-
from mainLogic import downloader
|
8 |
-
|
9 |
-
|
10 |
-
class HandleShellDL:
|
11 |
-
|
12 |
-
def __init__(self):
|
13 |
-
self.commandList = {
|
14 |
-
"edl":{
|
15 |
-
"func": self.edownload
|
16 |
-
},
|
17 |
-
"dl":{
|
18 |
-
"func": self.download
|
19 |
-
}
|
20 |
-
}
|
21 |
-
|
22 |
-
def edownload(self,args=[]):
|
23 |
-
# print(args)
|
24 |
-
if not args or len(args) < 2:
|
25 |
-
print("Please provide a name and id")
|
26 |
-
return
|
27 |
-
|
28 |
-
name = args[0]
|
29 |
-
id = args[1]
|
30 |
-
|
31 |
-
ch =CheckState()
|
32 |
-
state = ch.checkup(glv_var.EXECUTABLES,verbose=False)
|
33 |
-
prefs = state['prefs']
|
34 |
-
|
35 |
-
Download(
|
36 |
-
vsd_path=prefs['vsd'],
|
37 |
-
url=Download.buildUrl(id),
|
38 |
-
name=name,
|
39 |
-
tmp_path=prefs['tmpDir'],
|
40 |
-
output_path=prefs['dir'],
|
41 |
-
).download()
|
42 |
-
|
43 |
-
def download(self,args=[]):
|
44 |
-
if not args or len(args) < 2:
|
45 |
-
print("Please provide a name and id")
|
46 |
-
return
|
47 |
-
|
48 |
-
name = args[0]
|
49 |
-
id = args[1]
|
50 |
-
|
51 |
-
downloader.main(
|
52 |
-
id=id,
|
53 |
-
name=name,
|
54 |
-
)
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
def parseAndRun(self,command,args=[]):
|
61 |
-
simpleParser.parseAndRun(self.commandList, command, args)
|
62 |
-
|
|
|
1 |
+
from mainLogic.big4.downloadv2 import Download
|
2 |
+
from mainLogic.startup.checkup import CheckState
|
3 |
+
from mainLogic.utils.glv import Global
|
4 |
+
from mainLogic.main import Main
|
5 |
+
from beta.shellLogic import simpleParser
|
6 |
+
from mainLogic.utils import glv_var
|
7 |
+
from mainLogic import downloader
|
8 |
+
|
9 |
+
|
10 |
+
class HandleShellDL:
|
11 |
+
|
12 |
+
def __init__(self):
|
13 |
+
self.commandList = {
|
14 |
+
"edl":{
|
15 |
+
"func": self.edownload
|
16 |
+
},
|
17 |
+
"dl":{
|
18 |
+
"func": self.download
|
19 |
+
}
|
20 |
+
}
|
21 |
+
|
22 |
+
def edownload(self,args=[]):
|
23 |
+
# print(args)
|
24 |
+
if not args or len(args) < 2:
|
25 |
+
print("Please provide a name and id")
|
26 |
+
return
|
27 |
+
|
28 |
+
name = args[0]
|
29 |
+
id = args[1]
|
30 |
+
|
31 |
+
ch =CheckState()
|
32 |
+
state = ch.checkup(glv_var.EXECUTABLES,verbose=False)
|
33 |
+
prefs = state['prefs']
|
34 |
+
|
35 |
+
Download(
|
36 |
+
vsd_path=prefs['vsd'],
|
37 |
+
url=Download.buildUrl(id),
|
38 |
+
name=name,
|
39 |
+
tmp_path=prefs['tmpDir'],
|
40 |
+
output_path=prefs['dir'],
|
41 |
+
).download()
|
42 |
+
|
43 |
+
def download(self,args=[]):
|
44 |
+
if not args or len(args) < 2:
|
45 |
+
print("Please provide a name and id")
|
46 |
+
return
|
47 |
+
|
48 |
+
name = args[0]
|
49 |
+
id = args[1]
|
50 |
+
|
51 |
+
downloader.main(
|
52 |
+
id=id,
|
53 |
+
name=name,
|
54 |
+
)
|
55 |
+
|
56 |
+
|
57 |
+
|
58 |
+
|
59 |
+
|
60 |
+
def parseAndRun(self,command,args=[]):
|
61 |
+
simpleParser.parseAndRun(self.commandList, command, args)
|
62 |
+
|
beta/shellLogic/logic.py
CHANGED
@@ -1,30 +1,30 @@
|
|
1 |
-
from mainLogic.utils.os2 import SysFunc
|
2 |
-
from beta.shellLogic.handleLogics.HandleBasicCMDUtils import HandleBasicCMDUtils
|
3 |
-
from beta.shellLogic.handleLogics.HandleKeyAndAvailiblity import HandleKeyAndAvailiblity
|
4 |
-
from beta.shellLogic.handleLogics.HandleShellDL import HandleShellDL
|
5 |
-
from beta.shellLogic.TokenUpdate import TokenUpdate
|
6 |
-
|
7 |
-
os2 = SysFunc()
|
8 |
-
f1 = HandleBasicCMDUtils()
|
9 |
-
key_utils = HandleKeyAndAvailiblity()
|
10 |
-
dl_utils = HandleShellDL()
|
11 |
-
token_update = TokenUpdate()
|
12 |
-
|
13 |
-
commands_available={
|
14 |
-
# command: [location_of_function,help_class]
|
15 |
-
"exit": [f1.parseAndRun,""],
|
16 |
-
"cls" : [f1.parseAndRun,""],
|
17 |
-
"cd" : [f1.parseAndRun,""],
|
18 |
-
"cmd" : [f1.parseAndRun,""],
|
19 |
-
"get_key":[key_utils.parseAndRun,""],
|
20 |
-
"check": [key_utils.parseAndRun,""],
|
21 |
-
"edl": [dl_utils.parseAndRun,""],
|
22 |
-
"dl":[dl_utils.parseAndRun,""],
|
23 |
-
"tkn-up":[token_update.parseAndRun,""],
|
24 |
-
|
25 |
-
|
26 |
-
}
|
27 |
-
|
28 |
-
def execute(command,args=[]):
|
29 |
-
if command in commands_available:
|
30 |
commands_available[command][0](command,args)
|
|
|
1 |
+
from mainLogic.utils.os2 import SysFunc
|
2 |
+
from beta.shellLogic.handleLogics.HandleBasicCMDUtils import HandleBasicCMDUtils
|
3 |
+
from beta.shellLogic.handleLogics.HandleKeyAndAvailiblity import HandleKeyAndAvailiblity
|
4 |
+
from beta.shellLogic.handleLogics.HandleShellDL import HandleShellDL
|
5 |
+
from beta.shellLogic.TokenUpdate import TokenUpdate
|
6 |
+
|
7 |
+
os2 = SysFunc()
|
8 |
+
f1 = HandleBasicCMDUtils()
|
9 |
+
key_utils = HandleKeyAndAvailiblity()
|
10 |
+
dl_utils = HandleShellDL()
|
11 |
+
token_update = TokenUpdate()
|
12 |
+
|
13 |
+
commands_available={
|
14 |
+
# command: [location_of_function,help_class]
|
15 |
+
"exit": [f1.parseAndRun,""],
|
16 |
+
"cls" : [f1.parseAndRun,""],
|
17 |
+
"cd" : [f1.parseAndRun,""],
|
18 |
+
"cmd" : [f1.parseAndRun,""],
|
19 |
+
"get_key":[key_utils.parseAndRun,""],
|
20 |
+
"check": [key_utils.parseAndRun,""],
|
21 |
+
"edl": [dl_utils.parseAndRun,""],
|
22 |
+
"dl":[dl_utils.parseAndRun,""],
|
23 |
+
"tkn-up":[token_update.parseAndRun,""],
|
24 |
+
|
25 |
+
|
26 |
+
}
|
27 |
+
|
28 |
+
def execute(command,args=[]):
|
29 |
+
if command in commands_available:
|
30 |
commands_available[command][0](command,args)
|
beta/shellLogic/logicError.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
-
class commandNotFound(Exception):
|
2 |
-
def __init__(self, command):
|
3 |
-
self.command = command
|
4 |
-
|
5 |
-
def __str__(self):
|
6 |
return f"Command '{self.command}' not found"
|
|
|
1 |
+
class commandNotFound(Exception):
|
2 |
+
def __init__(self, command):
|
3 |
+
self.command = command
|
4 |
+
|
5 |
+
def __str__(self):
|
6 |
return f"Command '{self.command}' not found"
|
beta/shellLogic/shell.py
CHANGED
@@ -1,61 +1,61 @@
|
|
1 |
-
from prompt_toolkit import PromptSession
|
2 |
-
from mainLogic.utils.glv import Global
|
3 |
-
from mainLogic.startup.checkup import CheckState
|
4 |
-
import json
|
5 |
-
|
6 |
-
from mainLogic.utils.glv_var import EXECUTABLES
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
from prompt_toolkit.completion import Completer, Completion
|
11 |
-
from prompt_toolkit.completion.filesystem import PathCompleter
|
12 |
-
from prompt_toolkit.document import Document
|
13 |
-
|
14 |
-
class CustomCompleter(Completer):
|
15 |
-
def __init__(self):
|
16 |
-
self.file_completer = PathCompleter()
|
17 |
-
|
18 |
-
def get_completions(self, document: Document, complete_event):
|
19 |
-
text = document.text_before_cursor
|
20 |
-
if text.startswith('cd '):
|
21 |
-
for completion in self.file_completer.get_completions(document, complete_event):
|
22 |
-
yield completion
|
23 |
-
|
24 |
-
def main():
|
25 |
-
# Initialize Prompt Toolkit session
|
26 |
-
session = PromptSession()
|
27 |
-
|
28 |
-
# Perform checkup and get preferences
|
29 |
-
# Hardcoded verbose to False
|
30 |
-
state = CheckState().checkup(EXECUTABLES, './', verbose=False)
|
31 |
-
prefs = state['prefs']
|
32 |
-
|
33 |
-
# Convert preferences to JSON string for display
|
34 |
-
prefs_json = json.dumps(prefs, indent=4)
|
35 |
-
|
36 |
-
# Add a custom completer
|
37 |
-
custom_completer = CustomCompleter()
|
38 |
-
|
39 |
-
from beta.shellLogic import logic
|
40 |
-
|
41 |
-
# Command-line interface loop
|
42 |
-
while True:
|
43 |
-
try:
|
44 |
-
user_input = session.prompt('|pwdl> ', completer=custom_completer)
|
45 |
-
|
46 |
-
# just in case the user hits enter without typing anything
|
47 |
-
if not user_input: continue
|
48 |
-
|
49 |
-
command = user_input.split()[0]
|
50 |
-
args = user_input.split()[1:]
|
51 |
-
if not args: args = []
|
52 |
-
|
53 |
-
logic.execute(command, args)
|
54 |
-
|
55 |
-
except KeyboardInterrupt:
|
56 |
-
continue
|
57 |
-
except EOFError:
|
58 |
-
break
|
59 |
-
|
60 |
-
if __name__ == "__main__":
|
61 |
main()
|
|
|
1 |
+
from prompt_toolkit import PromptSession
|
2 |
+
from mainLogic.utils.glv import Global
|
3 |
+
from mainLogic.startup.checkup import CheckState
|
4 |
+
import json
|
5 |
+
|
6 |
+
from mainLogic.utils.glv_var import EXECUTABLES
|
7 |
+
|
8 |
+
|
9 |
+
|
10 |
+
from prompt_toolkit.completion import Completer, Completion
|
11 |
+
from prompt_toolkit.completion.filesystem import PathCompleter
|
12 |
+
from prompt_toolkit.document import Document
|
13 |
+
|
14 |
+
class CustomCompleter(Completer):
|
15 |
+
def __init__(self):
|
16 |
+
self.file_completer = PathCompleter()
|
17 |
+
|
18 |
+
def get_completions(self, document: Document, complete_event):
|
19 |
+
text = document.text_before_cursor
|
20 |
+
if text.startswith('cd '):
|
21 |
+
for completion in self.file_completer.get_completions(document, complete_event):
|
22 |
+
yield completion
|
23 |
+
|
24 |
+
def main():
|
25 |
+
# Initialize Prompt Toolkit session
|
26 |
+
session = PromptSession()
|
27 |
+
|
28 |
+
# Perform checkup and get preferences
|
29 |
+
# Hardcoded verbose to False
|
30 |
+
state = CheckState().checkup(EXECUTABLES, './', verbose=False)
|
31 |
+
prefs = state['prefs']
|
32 |
+
|
33 |
+
# Convert preferences to JSON string for display
|
34 |
+
prefs_json = json.dumps(prefs, indent=4)
|
35 |
+
|
36 |
+
# Add a custom completer
|
37 |
+
custom_completer = CustomCompleter()
|
38 |
+
|
39 |
+
from beta.shellLogic import logic
|
40 |
+
|
41 |
+
# Command-line interface loop
|
42 |
+
while True:
|
43 |
+
try:
|
44 |
+
user_input = session.prompt('|pwdl> ', completer=custom_completer)
|
45 |
+
|
46 |
+
# just in case the user hits enter without typing anything
|
47 |
+
if not user_input: continue
|
48 |
+
|
49 |
+
command = user_input.split()[0]
|
50 |
+
args = user_input.split()[1:]
|
51 |
+
if not args: args = []
|
52 |
+
|
53 |
+
logic.execute(command, args)
|
54 |
+
|
55 |
+
except KeyboardInterrupt:
|
56 |
+
continue
|
57 |
+
except EOFError:
|
58 |
+
break
|
59 |
+
|
60 |
+
if __name__ == "__main__":
|
61 |
main()
|
beta/shellLogic/simpleParser.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
-
def parseAndRun(commandlist,command,args=[],obj=None):
|
2 |
-
if command in commandlist: func = commandlist[command]["func"]
|
3 |
-
|
4 |
-
if not func: return
|
5 |
-
|
6 |
func(args)
|
|
|
1 |
+
def parseAndRun(commandlist,command,args=[],obj=None):
|
2 |
+
if command in commandlist: func = commandlist[command]["func"]
|
3 |
+
|
4 |
+
if not func: return
|
5 |
+
|
6 |
func(args)
|
beta/shellLogic/update.py
CHANGED
@@ -1,20 +1,20 @@
|
|
1 |
-
import json
|
2 |
-
|
3 |
-
|
4 |
-
class UpdateJSONFile:
|
5 |
-
def __init__(self, file_path):
|
6 |
-
self.file_path = file_path
|
7 |
-
self.data = None
|
8 |
-
self.load()
|
9 |
-
|
10 |
-
def load(self):
|
11 |
-
with open(self.file_path, 'r') as file:
|
12 |
-
self.data = json.load(file)
|
13 |
-
|
14 |
-
def save(self):
|
15 |
-
with open(self.file_path, 'w') as file:
|
16 |
-
json.dump(self.data, file, indent=4)
|
17 |
-
|
18 |
-
def update(self, key, value):
|
19 |
-
self.data[key] = value
|
20 |
-
self.save()
|
|
|
1 |
+
import json
|
2 |
+
|
3 |
+
|
4 |
+
class UpdateJSONFile:
|
5 |
+
def __init__(self, file_path):
|
6 |
+
self.file_path = file_path
|
7 |
+
self.data = None
|
8 |
+
self.load()
|
9 |
+
|
10 |
+
def load(self):
|
11 |
+
with open(self.file_path, 'r') as file:
|
12 |
+
self.data = json.load(file)
|
13 |
+
|
14 |
+
def save(self):
|
15 |
+
with open(self.file_path, 'w') as file:
|
16 |
+
json.dump(self.data, file, indent=4)
|
17 |
+
|
18 |
+
def update(self, key, value):
|
19 |
+
self.data[key] = value
|
20 |
+
self.save()
|
beta/util.py
CHANGED
@@ -1,47 +1,47 @@
|
|
1 |
-
import json
|
2 |
-
|
3 |
-
csv_file = input('Enter CSV file:')
|
4 |
-
|
5 |
-
json = ''
|
6 |
-
|
7 |
-
x = json.loads(json)
|
8 |
-
|
9 |
-
import re
|
10 |
-
|
11 |
-
def extract_uuid(text):
|
12 |
-
"""
|
13 |
-
Extracts UUIDs from a string using a regular expression.
|
14 |
-
|
15 |
-
Args:
|
16 |
-
text: The string to search for UUIDs.
|
17 |
-
|
18 |
-
Returns:
|
19 |
-
A list of extracted UUIDs, or an empty list if none are found.
|
20 |
-
"""
|
21 |
-
pattern = r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
|
22 |
-
matches = re.findall(pattern, text)
|
23 |
-
return matches
|
24 |
-
|
25 |
-
def generate_safe_filename(filename):
|
26 |
-
"""
|
27 |
-
Converts a filename to a safe format containing only alphabets, periods (.), and colons (:).
|
28 |
-
|
29 |
-
Args:
|
30 |
-
filename: The original filename to be converted.
|
31 |
-
|
32 |
-
Returns:
|
33 |
-
A safe filename string with only allowed characters.
|
34 |
-
"""
|
35 |
-
# Replace all characters except alphabets, periods, and colons with underscores
|
36 |
-
safe_filename = re.sub(r"[^\w\.\:]", "_", filename)
|
37 |
-
return safe_filename
|
38 |
-
|
39 |
-
lines = []
|
40 |
-
|
41 |
-
for videos in x['data']:
|
42 |
-
|
43 |
-
line = f"{generate_safe_filename(videos['title'])},{extract_uuid(videos['content'][0]['videoUrl'])[0]}"
|
44 |
-
lines.append(line)
|
45 |
-
|
46 |
-
with open(csv_file, 'w') as f:
|
47 |
f.write('\n'.join(lines))
|
|
|
1 |
+
import json
|
2 |
+
|
3 |
+
csv_file = input('Enter CSV file:')
|
4 |
+
|
5 |
+
json = ''
|
6 |
+
|
7 |
+
x = json.loads(json)
|
8 |
+
|
9 |
+
import re
|
10 |
+
|
11 |
+
def extract_uuid(text):
|
12 |
+
"""
|
13 |
+
Extracts UUIDs from a string using a regular expression.
|
14 |
+
|
15 |
+
Args:
|
16 |
+
text: The string to search for UUIDs.
|
17 |
+
|
18 |
+
Returns:
|
19 |
+
A list of extracted UUIDs, or an empty list if none are found.
|
20 |
+
"""
|
21 |
+
pattern = r"[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
|
22 |
+
matches = re.findall(pattern, text)
|
23 |
+
return matches
|
24 |
+
|
25 |
+
def generate_safe_filename(filename):
|
26 |
+
"""
|
27 |
+
Converts a filename to a safe format containing only alphabets, periods (.), and colons (:).
|
28 |
+
|
29 |
+
Args:
|
30 |
+
filename: The original filename to be converted.
|
31 |
+
|
32 |
+
Returns:
|
33 |
+
A safe filename string with only allowed characters.
|
34 |
+
"""
|
35 |
+
# Replace all characters except alphabets, periods, and colons with underscores
|
36 |
+
safe_filename = re.sub(r"[^\w\.\:]", "_", filename)
|
37 |
+
return safe_filename
|
38 |
+
|
39 |
+
lines = []
|
40 |
+
|
41 |
+
for videos in x['data']:
|
42 |
+
|
43 |
+
line = f"{generate_safe_filename(videos['title'])},{extract_uuid(videos['content'][0]['videoUrl'])[0]}"
|
44 |
+
lines.append(line)
|
45 |
+
|
46 |
+
with open(csv_file, 'w') as f:
|
47 |
f.write('\n'.join(lines))
|
defaults.json
CHANGED
@@ -1,15 +1,15 @@
|
|
1 |
-
{
|
2 |
-
"cloudfront_id": "d1d34p8vz63oiq",
|
3 |
-
"patched": false,
|
4 |
-
"os-info": "winX64",
|
5 |
-
"tmpDir": "%temp%",
|
6 |
-
"verbose": false,
|
7 |
-
"vsd": "$script/bin/vsd.exe",
|
8 |
-
"ffmpeg": "",
|
9 |
-
"hr": true,
|
10 |
-
"mp4decrypt": "$script/bin/mp4decrypt.exe",
|
11 |
-
"webui-del-time": "2",
|
12 |
-
"webui": true,
|
13 |
-
"webui-port": "5000",
|
14 |
-
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjAxODgxMDkuNzQ0LCJkYXRhIjp7Il9pZCI6IjY0MzE3NTQyNDBlOTc5MDAxODAwMjAyYiIsInVzZXJuYW1lIjoiOTQ3MjUwNzEwMCIsImZpcnN0TmFtZSI6IkFrc2hpdCBTaHViaGFtIiwibGFzdE5hbWUiOiIiLCJvcmdhbml6YXRpb24iOnsiX2lkIjoiNWViMzkzZWU5NWZhYjc0NjhhNzlkMTg5Iiwid2Vic2l0ZSI6InBoeXNpY3N3YWxsYWguY29tIiwibmFtZSI6IlBoeXNpY3N3YWxsYWgifSwiZW1haWwiOiJha3NoaXRzaHViaGFtbWFzQGdtYWlsLmNvbSIsInJvbGVzIjpbIjViMjdiZDk2NTg0MmY5NTBhNzc4YzZlZiJdLCJjb3VudHJ5R3JvdXAiOiJJTiIsInR5cGUiOiJVU0VSIn0sImlhdCI6MTcxOTU4MzMwOX0.GjYMN5M1k6zQlS_xM1ZJq91qaeDBIHSQOP07DpFgGJE"
|
15 |
}
|
|
|
1 |
+
{
|
2 |
+
"cloudfront_id": "d1d34p8vz63oiq",
|
3 |
+
"patched": false,
|
4 |
+
"os-info": "winX64",
|
5 |
+
"tmpDir": "%temp%",
|
6 |
+
"verbose": false,
|
7 |
+
"vsd": "$script/bin/vsd.exe",
|
8 |
+
"ffmpeg": "",
|
9 |
+
"hr": true,
|
10 |
+
"mp4decrypt": "$script/bin/mp4decrypt.exe",
|
11 |
+
"webui-del-time": "2",
|
12 |
+
"webui": true,
|
13 |
+
"webui-port": "5000",
|
14 |
+
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjAxODgxMDkuNzQ0LCJkYXRhIjp7Il9pZCI6IjY0MzE3NTQyNDBlOTc5MDAxODAwMjAyYiIsInVzZXJuYW1lIjoiOTQ3MjUwNzEwMCIsImZpcnN0TmFtZSI6IkFrc2hpdCBTaHViaGFtIiwibGFzdE5hbWUiOiIiLCJvcmdhbml6YXRpb24iOnsiX2lkIjoiNWViMzkzZWU5NWZhYjc0NjhhNzlkMTg5Iiwid2Vic2l0ZSI6InBoeXNpY3N3YWxsYWguY29tIiwibmFtZSI6IlBoeXNpY3N3YWxsYWgifSwiZW1haWwiOiJha3NoaXRzaHViaGFtbWFzQGdtYWlsLmNvbSIsInJvbGVzIjpbIjViMjdiZDk2NTg0MmY5NTBhNzc4YzZlZiJdLCJjb3VudHJ5R3JvdXAiOiJJTiIsInR5cGUiOiJVU0VSIn0sImlhdCI6MTcxOTU4MzMwOX0.GjYMN5M1k6zQlS_xM1ZJq91qaeDBIHSQOP07DpFgGJE"
|
15 |
}
|
defaults.linux.json
CHANGED
@@ -1,15 +1,15 @@
|
|
1 |
-
{
|
2 |
-
"flare_url": "http://localhost:8191/v1",
|
3 |
-
"cloudfront_id": "d1d34p8vz63oiq",
|
4 |
-
"patched": false,
|
5 |
-
"os-info": "linux",
|
6 |
-
"tmpDir": "/tmp",
|
7 |
-
"verbose": false,
|
8 |
-
"vsd": "$script/bin/vsd",
|
9 |
-
"ffmpeg": "",
|
10 |
-
"mp4decrypt": "$script/bin/mp4decrypt",
|
11 |
-
"webui-del-time": 45,
|
12 |
-
"webui": true,
|
13 |
-
"webui-port": "5000",
|
14 |
-
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTkwNTM1MjAuNDgxLCJkYXRhIjp7Il9pZCI6IjY0MzE3NTQyNDBlOTc5MDAxODAwMjAyYiIsInVzZXJuYW1lIjoiOTQ3MjUwNzEwMCIsImZpcnN0TmFtZSI6IkFrc2hpdCBTaHViaGFtIiwibGFzdE5hbWUiOiIiLCJvcmdhbml6YXRpb24iOnsiX2lkIjoiNWViMzkzZWU5NWZhYjc0NjhhNzlkMTg5Iiwid2Vic2l0ZSI6InBoeXNpY3N3YWxsYWguY29tIiwibmFtZSI6IlBoeXNpY3N3YWxsYWgifSwiZW1haWwiOiJha3NoaXRzaHViaGFtbWFzQGdtYWlsLmNvbSIsInJvbGVzIjpbIjViMjdiZDk2NTg0MmY5NTBhNzc4YzZlZiJdLCJjb3VudHJ5R3JvdXAiOiJJTiIsInR5cGUiOiJVU0VSIn0sImlhdCI6MTcxODQ0ODcyMH0.PC0u4feVyT4WSzhBfpfPYB2YKwArJxYJER4R8c2gdD8"
|
15 |
}
|
|
|
1 |
+
{
|
2 |
+
"flare_url": "http://localhost:8191/v1",
|
3 |
+
"cloudfront_id": "d1d34p8vz63oiq",
|
4 |
+
"patched": false,
|
5 |
+
"os-info": "linux",
|
6 |
+
"tmpDir": "/tmp",
|
7 |
+
"verbose": false,
|
8 |
+
"vsd": "$script/bin/vsd",
|
9 |
+
"ffmpeg": "",
|
10 |
+
"mp4decrypt": "$script/bin/mp4decrypt",
|
11 |
+
"webui-del-time": 45,
|
12 |
+
"webui": true,
|
13 |
+
"webui-port": "5000",
|
14 |
+
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MTkwNTM1MjAuNDgxLCJkYXRhIjp7Il9pZCI6IjY0MzE3NTQyNDBlOTc5MDAxODAwMjAyYiIsInVzZXJuYW1lIjoiOTQ3MjUwNzEwMCIsImZpcnN0TmFtZSI6IkFrc2hpdCBTaHViaGFtIiwibGFzdE5hbWUiOiIiLCJvcmdhbml6YXRpb24iOnsiX2lkIjoiNWViMzkzZWU5NWZhYjc0NjhhNzlkMTg5Iiwid2Vic2l0ZSI6InBoeXNpY3N3YWxsYWguY29tIiwibmFtZSI6IlBoeXNpY3N3YWxsYWgifSwiZW1haWwiOiJha3NoaXRzaHViaGFtbWFzQGdtYWlsLmNvbSIsInJvbGVzIjpbIjViMjdiZDk2NTg0MmY5NTBhNzc4YzZlZiJdLCJjb3VudHJ5R3JvdXAiOiJJTiIsInR5cGUiOiJVU0VSIn0sImlhdCI6MTcxODQ0ODcyMH0.PC0u4feVyT4WSzhBfpfPYB2YKwArJxYJER4R8c2gdD8"
|
15 |
}
|
mainLogic/big4/cleanup.py
CHANGED
@@ -1,37 +1,37 @@
|
|
1 |
-
import os
|
2 |
-
from mainLogic.utils.glv import Global
|
3 |
-
class Clean:
|
4 |
-
|
5 |
-
def removeFile(self,file,verbose):
|
6 |
-
try:
|
7 |
-
os.remove(file)
|
8 |
-
if verbose: Global.sprint(f"Removed file: {file}")
|
9 |
-
except:
|
10 |
-
Global.errprint(f"Could not remove file: {file}")
|
11 |
-
|
12 |
-
def remove(self,path,file,verbose=True):
|
13 |
-
|
14 |
-
audio_enc = f"{path}/{file}-Audio-enc.mp4"
|
15 |
-
video_enc = f"{path}/{file}-Video-enc.mp4"
|
16 |
-
|
17 |
-
audio = f"{path}/{file}-Audio.mp4"
|
18 |
-
video = f"{path}/{file}-Video.mp4"
|
19 |
-
|
20 |
-
if verbose:
|
21 |
-
Global.hr()
|
22 |
-
Global.dprint("Removing TemporaryDL Files...")
|
23 |
-
Global.hr()
|
24 |
-
|
25 |
-
if verbose: Global.dprint("Removing Audio...")
|
26 |
-
self.removeFile(audio_enc,verbose)
|
27 |
-
|
28 |
-
if verbose: Global.dprint("Removing Video...")
|
29 |
-
self.removeFile(video_enc,verbose)
|
30 |
-
|
31 |
-
if verbose: Global.dprint("Removing Dncrypted Audio...")
|
32 |
-
self.removeFile(audio,verbose)
|
33 |
-
|
34 |
-
if verbose: Global.dprint("Removing Dncrypted Video...")
|
35 |
-
self.removeFile(video,verbose)
|
36 |
-
|
37 |
-
|
|
|
1 |
+
import os
|
2 |
+
from mainLogic.utils.glv import Global
|
3 |
+
class Clean:
|
4 |
+
|
5 |
+
def removeFile(self,file,verbose):
|
6 |
+
try:
|
7 |
+
os.remove(file)
|
8 |
+
if verbose: Global.sprint(f"Removed file: {file}")
|
9 |
+
except:
|
10 |
+
Global.errprint(f"Could not remove file: {file}")
|
11 |
+
|
12 |
+
def remove(self,path,file,verbose=True):
|
13 |
+
|
14 |
+
audio_enc = f"{path}/{file}-Audio-enc.mp4"
|
15 |
+
video_enc = f"{path}/{file}-Video-enc.mp4"
|
16 |
+
|
17 |
+
audio = f"{path}/{file}-Audio.mp4"
|
18 |
+
video = f"{path}/{file}-Video.mp4"
|
19 |
+
|
20 |
+
if verbose:
|
21 |
+
Global.hr()
|
22 |
+
Global.dprint("Removing TemporaryDL Files...")
|
23 |
+
Global.hr()
|
24 |
+
|
25 |
+
if verbose: Global.dprint("Removing Audio...")
|
26 |
+
self.removeFile(audio_enc,verbose)
|
27 |
+
|
28 |
+
if verbose: Global.dprint("Removing Video...")
|
29 |
+
self.removeFile(video_enc,verbose)
|
30 |
+
|
31 |
+
if verbose: Global.dprint("Removing Dncrypted Audio...")
|
32 |
+
self.removeFile(audio,verbose)
|
33 |
+
|
34 |
+
if verbose: Global.dprint("Removing Dncrypted Video...")
|
35 |
+
self.removeFile(video,verbose)
|
36 |
+
|
37 |
+
|
mainLogic/big4/decrypt/decrypt.py
CHANGED
@@ -1,55 +1,55 @@
|
|
1 |
-
from mainLogic.utils.glv import Global
|
2 |
-
from mainLogic.utils.process import shell
|
3 |
-
from mainLogic.utils.basicUtils import BasicUtils
|
4 |
-
from mainLogic import error
|
5 |
-
import os
|
6 |
-
|
7 |
-
class Decrypt:
|
8 |
-
|
9 |
-
def decrypt(self,path,name,key,mp4d="mp4decrypt",out="None",outfile="",verbose=True,suppress_exit=False):
|
10 |
-
|
11 |
-
Global.hr()
|
12 |
-
|
13 |
-
# making path absolute if not already absolute
|
14 |
-
path = BasicUtils.abspath(path)
|
15 |
-
Global.dprint(f"Decrypting {out}...")
|
16 |
-
|
17 |
-
# during various tests
|
18 |
-
# it was found that the decrypted audio file is named as <name>.en.m4a
|
19 |
-
# hence a simple logic to work around this issue is to check if the file exists
|
20 |
-
# if not os.path.exists(f'{path}/{name}.m4a') and out == "Audio":
|
21 |
-
# name = name + ".en"
|
22 |
-
|
23 |
-
# setting extension based on out
|
24 |
-
# i.e if out is Audio then extension is 'm4a' else 'mp4'
|
25 |
-
# extension = "m4a" if out == "Audio" else "mp4"
|
26 |
-
extension = "mp4" # temporary fix
|
27 |
-
|
28 |
-
decrypt_command = f'{mp4d} --key 1:{key} {path}/{name}.{extension} {path}/{"" if not outfile else outfile+"-" }{out}.mp4'
|
29 |
-
|
30 |
-
if verbose: Global.dprint(f"{out} Decryption Started..."); Global.dprint(f'{decrypt_command}')
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
# the main part where the decryption happens
|
35 |
-
code = shell(f'{decrypt_command}',stderr="",stdout="")
|
36 |
-
|
37 |
-
# simple check to see if the decryption was successful or not
|
38 |
-
if code == 0:
|
39 |
-
Global.dprint(f"{out} Decrypted Successfully")
|
40 |
-
else:
|
41 |
-
|
42 |
-
# if decryption failed then print error message and exit
|
43 |
-
error.errorList[f"couldNotDecrypt{out}"]["func"]()
|
44 |
-
if not suppress_exit:
|
45 |
-
exit(error.errorList[f"couldNotDecrypt{out}"]["code"])
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
# decrypts audio
|
50 |
-
def decryptAudio(self,path,name,key,mp4d="mp4decrypt",outfile='None',verbose=True,suppress_exit=False):
|
51 |
-
self.decrypt(path,name,key,mp4d,"Audio",outfile,verbose,suppress_exit=suppress_exit)
|
52 |
-
|
53 |
-
# decrypts video
|
54 |
-
def decryptVideo(self,path,name,key,mp4d="mp4decrypt",outfile='None',verbose=True,suppress_exit=False):
|
55 |
self.decrypt(path,name,key,mp4d,"Video",outfile,verbose,suppress_exit=suppress_exit)
|
|
|
1 |
+
from mainLogic.utils.glv import Global
|
2 |
+
from mainLogic.utils.process import shell
|
3 |
+
from mainLogic.utils.basicUtils import BasicUtils
|
4 |
+
from mainLogic import error
|
5 |
+
import os
|
6 |
+
|
7 |
+
class Decrypt:
|
8 |
+
|
9 |
+
def decrypt(self,path,name,key,mp4d="mp4decrypt",out="None",outfile="",verbose=True,suppress_exit=False):
|
10 |
+
|
11 |
+
Global.hr()
|
12 |
+
|
13 |
+
# making path absolute if not already absolute
|
14 |
+
path = BasicUtils.abspath(path)
|
15 |
+
Global.dprint(f"Decrypting {out}...")
|
16 |
+
|
17 |
+
# during various tests
|
18 |
+
# it was found that the decrypted audio file is named as <name>.en.m4a
|
19 |
+
# hence a simple logic to work around this issue is to check if the file exists
|
20 |
+
# if not os.path.exists(f'{path}/{name}.m4a') and out == "Audio":
|
21 |
+
# name = name + ".en"
|
22 |
+
|
23 |
+
# setting extension based on out
|
24 |
+
# i.e if out is Audio then extension is 'm4a' else 'mp4'
|
25 |
+
# extension = "m4a" if out == "Audio" else "mp4"
|
26 |
+
extension = "mp4" # temporary fix
|
27 |
+
|
28 |
+
decrypt_command = f'{mp4d} --key 1:{key} {path}/{name}.{extension} {path}/{"" if not outfile else outfile+"-" }{out}.mp4'
|
29 |
+
|
30 |
+
if verbose: Global.dprint(f"{out} Decryption Started..."); Global.dprint(f'{decrypt_command}')
|
31 |
+
|
32 |
+
|
33 |
+
|
34 |
+
# the main part where the decryption happens
|
35 |
+
code = shell(f'{decrypt_command}',stderr="",stdout="")
|
36 |
+
|
37 |
+
# simple check to see if the decryption was successful or not
|
38 |
+
if code == 0:
|
39 |
+
Global.dprint(f"{out} Decrypted Successfully")
|
40 |
+
else:
|
41 |
+
|
42 |
+
# if decryption failed then print error message and exit
|
43 |
+
error.errorList[f"couldNotDecrypt{out}"]["func"]()
|
44 |
+
if not suppress_exit:
|
45 |
+
exit(error.errorList[f"couldNotDecrypt{out}"]["code"])
|
46 |
+
|
47 |
+
|
48 |
+
|
49 |
+
# decrypts audio
|
50 |
+
def decryptAudio(self,path,name,key,mp4d="mp4decrypt",outfile='None',verbose=True,suppress_exit=False):
|
51 |
+
self.decrypt(path,name,key,mp4d,"Audio",outfile,verbose,suppress_exit=suppress_exit)
|
52 |
+
|
53 |
+
# decrypts video
|
54 |
+
def decryptVideo(self,path,name,key,mp4d="mp4decrypt",outfile='None',verbose=True,suppress_exit=False):
|
55 |
self.decrypt(path,name,key,mp4d,"Video",outfile,verbose,suppress_exit=suppress_exit)
|
mainLogic/big4/decrypt/key.old.py
CHANGED
@@ -1,86 +1,86 @@
|
|
1 |
-
# import requests
|
2 |
-
# import json
|
3 |
-
# from bs4 import BeautifulSoup as BS
|
4 |
-
# import re
|
5 |
-
# from utils.keyUtils import base64_to_hex
|
6 |
-
# from utils.glv import Global
|
7 |
-
# import error
|
8 |
-
#
|
9 |
-
#
|
10 |
-
# def log_info(id, verbose, attempt=0):
|
11 |
-
# if verbose:
|
12 |
-
# Global.dprint("Starting the script for key extraction" +( f" Retry: {attempt}" if attempt > 0 else ""))
|
13 |
-
# Global.sprint(f'id -> {id}')
|
14 |
-
# Global.sprint("Sending request to the server")
|
15 |
-
# Global.dprint(f"Hardcoded URL: request.get -> http://studyrays.site/drmplayer.php?v=https://d1d34p8vz63oiq"
|
16 |
-
# f".cloudfront.net/{id}/master.mpd")
|
17 |
-
#
|
18 |
-
#
|
19 |
-
# def send_request(id):
|
20 |
-
# try:
|
21 |
-
#
|
22 |
-
# import http.client
|
23 |
-
#
|
24 |
-
# conn = http.client.HTTPSConnection("api.scrapingant.com")
|
25 |
-
#
|
26 |
-
# conn.request("GET",
|
27 |
-
# f"/v2/general?url=https%3A%2F%2Fstudyrays.site%2Fdrmplayer.php%3Fv%3Dhttps%3A%2F%2Fd1d34p8vz63oiq.cloudfront.net%2F{id}%2Fmaster.mpd&x-api-key=806b77b95dd643caae01d4e240da9159&proxy_type=residential&proxy_country=IN&browser=false")
|
28 |
-
#
|
29 |
-
# res = conn.getresponse()
|
30 |
-
#
|
31 |
-
# return res.read()
|
32 |
-
#
|
33 |
-
# except requests.exceptions.RequestException as e:
|
34 |
-
# error.errorList["flareNotStarted"]["func"]()
|
35 |
-
# exit(error.errorList["flareNotStarted"]["code"])
|
36 |
-
#
|
37 |
-
#
|
38 |
-
# def parse_response(response):
|
39 |
-
# try:
|
40 |
-
#
|
41 |
-
# return response.decode('utf-8')
|
42 |
-
#
|
43 |
-
# except (KeyError, json.JSONDecodeError):
|
44 |
-
# error.errorList["requestFailedDueToUnknownReason"]["func"](response.status_code)
|
45 |
-
# exit(error.errorList["requestFailedDueToUnknownReason"]["code"])
|
46 |
-
#
|
47 |
-
#
|
48 |
-
# def extract_key(html):
|
49 |
-
#
|
50 |
-
# soup = BS(html, 'html.parser')
|
51 |
-
# scripts = soup.find_all('script')
|
52 |
-
#
|
53 |
-
# for script in scripts:
|
54 |
-
# script_content = script.text
|
55 |
-
# if 'const protData' in script_content:
|
56 |
-
# protData_script = script_content
|
57 |
-
# break
|
58 |
-
# else:
|
59 |
-
# return None
|
60 |
-
#
|
61 |
-
# pattern = r'const\s+protData\s*=\s*({.*?});'
|
62 |
-
# match = re.search(pattern, protData_script, re.DOTALL)
|
63 |
-
#
|
64 |
-
# if match:
|
65 |
-
# protData_content = match.group(1)
|
66 |
-
# keylist = json.loads(protData_content)['org.w3.clearkey']['clearkeys']
|
67 |
-
# for kid in keylist:
|
68 |
-
# return base64_to_hex(keylist[kid])
|
69 |
-
# return None
|
70 |
-
#
|
71 |
-
# # main function
|
72 |
-
# def getKey(id, verbose=True,retries=2):
|
73 |
-
#
|
74 |
-
# for attempt in range(retries):
|
75 |
-
# log_info(id, verbose, attempt)
|
76 |
-
#
|
77 |
-
# response = send_request(id)
|
78 |
-
# html = parse_response(response)
|
79 |
-
#
|
80 |
-
# key = extract_key(html)
|
81 |
-
# if key:
|
82 |
-
# return key
|
83 |
-
# else:
|
84 |
-
# if verbose:
|
85 |
-
# Global.sprint("protData variable not found in the script. Retrying!")
|
86 |
# return -1
|
|
|
1 |
+
# import requests
|
2 |
+
# import json
|
3 |
+
# from bs4 import BeautifulSoup as BS
|
4 |
+
# import re
|
5 |
+
# from utils.keyUtils import base64_to_hex
|
6 |
+
# from utils.glv import Global
|
7 |
+
# import error
|
8 |
+
#
|
9 |
+
#
|
10 |
+
# def log_info(id, verbose, attempt=0):
|
11 |
+
# if verbose:
|
12 |
+
# Global.dprint("Starting the script for key extraction" +( f" Retry: {attempt}" if attempt > 0 else ""))
|
13 |
+
# Global.sprint(f'id -> {id}')
|
14 |
+
# Global.sprint("Sending request to the server")
|
15 |
+
# Global.dprint(f"Hardcoded URL: request.get -> http://studyrays.site/drmplayer.php?v=https://d1d34p8vz63oiq"
|
16 |
+
# f".cloudfront.net/{id}/master.mpd")
|
17 |
+
#
|
18 |
+
#
|
19 |
+
# def send_request(id):
|
20 |
+
# try:
|
21 |
+
#
|
22 |
+
# import http.client
|
23 |
+
#
|
24 |
+
# conn = http.client.HTTPSConnection("api.scrapingant.com")
|
25 |
+
#
|
26 |
+
# conn.request("GET",
|
27 |
+
# f"/v2/general?url=https%3A%2F%2Fstudyrays.site%2Fdrmplayer.php%3Fv%3Dhttps%3A%2F%2Fd1d34p8vz63oiq.cloudfront.net%2F{id}%2Fmaster.mpd&x-api-key=806b77b95dd643caae01d4e240da9159&proxy_type=residential&proxy_country=IN&browser=false")
|
28 |
+
#
|
29 |
+
# res = conn.getresponse()
|
30 |
+
#
|
31 |
+
# return res.read()
|
32 |
+
#
|
33 |
+
# except requests.exceptions.RequestException as e:
|
34 |
+
# error.errorList["flareNotStarted"]["func"]()
|
35 |
+
# exit(error.errorList["flareNotStarted"]["code"])
|
36 |
+
#
|
37 |
+
#
|
38 |
+
# def parse_response(response):
|
39 |
+
# try:
|
40 |
+
#
|
41 |
+
# return response.decode('utf-8')
|
42 |
+
#
|
43 |
+
# except (KeyError, json.JSONDecodeError):
|
44 |
+
# error.errorList["requestFailedDueToUnknownReason"]["func"](response.status_code)
|
45 |
+
# exit(error.errorList["requestFailedDueToUnknownReason"]["code"])
|
46 |
+
#
|
47 |
+
#
|
48 |
+
# def extract_key(html):
|
49 |
+
#
|
50 |
+
# soup = BS(html, 'html.parser')
|
51 |
+
# scripts = soup.find_all('script')
|
52 |
+
#
|
53 |
+
# for script in scripts:
|
54 |
+
# script_content = script.text
|
55 |
+
# if 'const protData' in script_content:
|
56 |
+
# protData_script = script_content
|
57 |
+
# break
|
58 |
+
# else:
|
59 |
+
# return None
|
60 |
+
#
|
61 |
+
# pattern = r'const\s+protData\s*=\s*({.*?});'
|
62 |
+
# match = re.search(pattern, protData_script, re.DOTALL)
|
63 |
+
#
|
64 |
+
# if match:
|
65 |
+
# protData_content = match.group(1)
|
66 |
+
# keylist = json.loads(protData_content)['org.w3.clearkey']['clearkeys']
|
67 |
+
# for kid in keylist:
|
68 |
+
# return base64_to_hex(keylist[kid])
|
69 |
+
# return None
|
70 |
+
#
|
71 |
+
# # main function
|
72 |
+
# def getKey(id, verbose=True,retries=2):
|
73 |
+
#
|
74 |
+
# for attempt in range(retries):
|
75 |
+
# log_info(id, verbose, attempt)
|
76 |
+
#
|
77 |
+
# response = send_request(id)
|
78 |
+
# html = parse_response(response)
|
79 |
+
#
|
80 |
+
# key = extract_key(html)
|
81 |
+
# if key:
|
82 |
+
# return key
|
83 |
+
# else:
|
84 |
+
# if verbose:
|
85 |
+
# Global.sprint("protData variable not found in the script. Retrying!")
|
86 |
# return -1
|
mainLogic/big4/decrypt/key.py
CHANGED
@@ -1,138 +1,138 @@
|
|
1 |
-
import requests
|
2 |
-
import re
|
3 |
-
import base64
|
4 |
-
import json
|
5 |
-
from mainLogic.big4.dl_obsolete import DL
|
6 |
-
from mainLogic.utils.glv import Global
|
7 |
-
|
8 |
-
class LicenseKeyFetcher:
|
9 |
-
def __init__(self, token):
|
10 |
-
self.token = token
|
11 |
-
|
12 |
-
def build_license_url(self, encoded_otp_key):
|
13 |
-
return f"https://api.penpencil.co/v1/videos/get-otp?key={encoded_otp_key}&isEncoded=true"
|
14 |
-
|
15 |
-
def get_headers(self):
|
16 |
-
headers = {
|
17 |
-
"accept": "*/*",
|
18 |
-
"accept-language": "en-US,en;q=0.9,la;q=0.8",
|
19 |
-
"authorization": f"Bearer {self.token}",
|
20 |
-
"cache-control": "no-cache",
|
21 |
-
"client-id": "5eb393ee95fab7468a79d189",
|
22 |
-
"client-type": "WEB",
|
23 |
-
"client-version": "200",
|
24 |
-
"content-type": "application/json",
|
25 |
-
"dnt": "1",
|
26 |
-
"origin": "https://www.pw.live",
|
27 |
-
"pragma": "no-cache",
|
28 |
-
"priority": "u=1, i",
|
29 |
-
"randomid": "180ff4c6-9ec3-4329-b1b5-1ad2f6746795",
|
30 |
-
"referer": "https://www.pw.live/",
|
31 |
-
"sec-ch-ua": "\"Google Chrome\";v=\"125\", \"Chromium\";v=\"125\", \"Not.A/Brand\";v=\"24\"",
|
32 |
-
"sec-ch-ua-mobile": "?0",
|
33 |
-
"sec-ch-ua-platform": "\"Windows\"",
|
34 |
-
"sec-fetch-dest": "empty",
|
35 |
-
"sec-fetch-mode": "cors",
|
36 |
-
"sec-fetch-site": "cross-site",
|
37 |
-
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
|
38 |
-
}
|
39 |
-
return headers
|
40 |
-
|
41 |
-
def key_char_at(self, key, i):
|
42 |
-
return ord(key[i % len(key)])
|
43 |
-
|
44 |
-
def b64_encode(self, data):
|
45 |
-
if not data:
|
46 |
-
return data
|
47 |
-
encoded = base64.b64encode(bytes(data)).decode('utf-8')
|
48 |
-
return encoded
|
49 |
-
|
50 |
-
def get_key_final(self, otp):
|
51 |
-
decoded_bytes = base64.b64decode(otp)
|
52 |
-
length = len(decoded_bytes)
|
53 |
-
decoded_ints = [int(byte) for byte in decoded_bytes]
|
54 |
-
|
55 |
-
result = "".join(
|
56 |
-
chr(
|
57 |
-
decoded_ints[i] ^ ord(self.token[i % len(self.token)])
|
58 |
-
)
|
59 |
-
for i in range(length)
|
60 |
-
)
|
61 |
-
|
62 |
-
return result
|
63 |
-
|
64 |
-
def xor_encrypt(self, data):
|
65 |
-
return [ord(c) ^ self.key_char_at(self.token, i) for i, c in enumerate(data)]
|
66 |
-
|
67 |
-
def insert_zeros(self, hex_string):
|
68 |
-
result = "00"
|
69 |
-
for i in range(0, len(hex_string), 2):
|
70 |
-
result += hex_string[i:i+2]
|
71 |
-
if i + 2 < len(hex_string):
|
72 |
-
result += "00"
|
73 |
-
return result
|
74 |
-
|
75 |
-
def extract_kid_from_mpd(self, url):
|
76 |
-
response = requests.get(url)
|
77 |
-
response.raise_for_status()
|
78 |
-
mpd_content = response.text
|
79 |
-
pattern = r'default_KID="([0-9a-fA-F-]+)"'
|
80 |
-
match = re.search(pattern, mpd_content)
|
81 |
-
return match.group(1) if match else None
|
82 |
-
|
83 |
-
def get_key(self, id, verbose=True):
|
84 |
-
if verbose: Global.hr()
|
85 |
-
|
86 |
-
if verbose: Global.dprint("Beginning to get the key for the video... & Audio :) ")
|
87 |
-
if verbose: Global.dprint(f"ID: {id}")
|
88 |
-
if verbose: Global.dprint("Building the URL to get the key...")
|
89 |
-
|
90 |
-
try:
|
91 |
-
url = DL.buildUrl(id)
|
92 |
-
if verbose: Global.sprint(f"URL: {url}")
|
93 |
-
|
94 |
-
if verbose: Global.dprint("Extracting the KID from the MPD file...")
|
95 |
-
kid = self.extract_kid_from_mpd(url).replace("-", "")
|
96 |
-
if verbose: Global.sprint(f"KID: {kid}")
|
97 |
-
|
98 |
-
if verbose: Global.dprint("Encrypting the KID to get the key...")
|
99 |
-
otp_key = self.b64_encode(self.xor_encrypt(kid))
|
100 |
-
if verbose: Global.sprint(f"OTP Key: {otp_key}")
|
101 |
-
|
102 |
-
if verbose: Global.dprint("Encoding the OTP key to hex...")
|
103 |
-
encoded_otp_key_step1 = otp_key.encode('utf-8').hex()
|
104 |
-
encoded_otp_key = self.insert_zeros(encoded_otp_key_step1)
|
105 |
-
if verbose: Global.sprint(f"Encoded OTP Key: {encoded_otp_key}")
|
106 |
-
|
107 |
-
if verbose: Global.dprint("Building the license URL...")
|
108 |
-
license_url = self.build_license_url(encoded_otp_key)
|
109 |
-
if verbose: Global.sprint(f"License URL: {license_url}")
|
110 |
-
|
111 |
-
if verbose: Global.dprint("Getting the headers...")
|
112 |
-
headers = self.get_headers()
|
113 |
-
if verbose: Global.sprint(f"Headers: {json.dumps(headers, indent=4)}")
|
114 |
-
|
115 |
-
if verbose: Global.dprint("Making a request to the server to get the license (key)...")
|
116 |
-
response = requests.get(license_url, headers=headers)
|
117 |
-
if verbose: Global.sprint(f"Response: {response}")
|
118 |
-
|
119 |
-
if response.status_code == 200:
|
120 |
-
if 'data' in response.json() and 'otp' in response.json()['data']:
|
121 |
-
if verbose: Global.sprint("Key received successfully!")
|
122 |
-
key = self.get_key_final(response.json()['data']['otp'])
|
123 |
-
if verbose: Global.sprint(f"Key: {key}")
|
124 |
-
|
125 |
-
if verbose:Global.hr()
|
126 |
-
return (kid,key)
|
127 |
-
else:
|
128 |
-
Global.errprint("Could not get the key from the server. Exiting...")
|
129 |
-
return None
|
130 |
-
|
131 |
-
except Exception as e:
|
132 |
-
Global.errprint(f"An error occurred while getting the key: {e}")
|
133 |
-
return None
|
134 |
-
|
135 |
-
# Example usage
|
136 |
-
# TOKEN = "your_token_here"
|
137 |
-
# fetcher = LicenseKeyFetcher(TOKEN)
|
138 |
-
# key = fetcher.get_key(video_id)
|
|
|
1 |
+
import requests
|
2 |
+
import re
|
3 |
+
import base64
|
4 |
+
import json
|
5 |
+
from mainLogic.big4.dl_obsolete import DL
|
6 |
+
from mainLogic.utils.glv import Global
|
7 |
+
|
8 |
+
class LicenseKeyFetcher:
|
9 |
+
def __init__(self, token):
|
10 |
+
self.token = token
|
11 |
+
|
12 |
+
def build_license_url(self, encoded_otp_key):
|
13 |
+
return f"https://api.penpencil.co/v1/videos/get-otp?key={encoded_otp_key}&isEncoded=true"
|
14 |
+
|
15 |
+
def get_headers(self):
|
16 |
+
headers = {
|
17 |
+
"accept": "*/*",
|
18 |
+
"accept-language": "en-US,en;q=0.9,la;q=0.8",
|
19 |
+
"authorization": f"Bearer {self.token}",
|
20 |
+
"cache-control": "no-cache",
|
21 |
+
"client-id": "5eb393ee95fab7468a79d189",
|
22 |
+
"client-type": "WEB",
|
23 |
+
"client-version": "200",
|
24 |
+
"content-type": "application/json",
|
25 |
+
"dnt": "1",
|
26 |
+
"origin": "https://www.pw.live",
|
27 |
+
"pragma": "no-cache",
|
28 |
+
"priority": "u=1, i",
|
29 |
+
"randomid": "180ff4c6-9ec3-4329-b1b5-1ad2f6746795",
|
30 |
+
"referer": "https://www.pw.live/",
|
31 |
+
"sec-ch-ua": "\"Google Chrome\";v=\"125\", \"Chromium\";v=\"125\", \"Not.A/Brand\";v=\"24\"",
|
32 |
+
"sec-ch-ua-mobile": "?0",
|
33 |
+
"sec-ch-ua-platform": "\"Windows\"",
|
34 |
+
"sec-fetch-dest": "empty",
|
35 |
+
"sec-fetch-mode": "cors",
|
36 |
+
"sec-fetch-site": "cross-site",
|
37 |
+
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
|
38 |
+
}
|
39 |
+
return headers
|
40 |
+
|
41 |
+
def key_char_at(self, key, i):
|
42 |
+
return ord(key[i % len(key)])
|
43 |
+
|
44 |
+
def b64_encode(self, data):
|
45 |
+
if not data:
|
46 |
+
return data
|
47 |
+
encoded = base64.b64encode(bytes(data)).decode('utf-8')
|
48 |
+
return encoded
|
49 |
+
|
50 |
+
def get_key_final(self, otp):
|
51 |
+
decoded_bytes = base64.b64decode(otp)
|
52 |
+
length = len(decoded_bytes)
|
53 |
+
decoded_ints = [int(byte) for byte in decoded_bytes]
|
54 |
+
|
55 |
+
result = "".join(
|
56 |
+
chr(
|
57 |
+
decoded_ints[i] ^ ord(self.token[i % len(self.token)])
|
58 |
+
)
|
59 |
+
for i in range(length)
|
60 |
+
)
|
61 |
+
|
62 |
+
return result
|
63 |
+
|
64 |
+
def xor_encrypt(self, data):
|
65 |
+
return [ord(c) ^ self.key_char_at(self.token, i) for i, c in enumerate(data)]
|
66 |
+
|
67 |
+
def insert_zeros(self, hex_string):
|
68 |
+
result = "00"
|
69 |
+
for i in range(0, len(hex_string), 2):
|
70 |
+
result += hex_string[i:i+2]
|
71 |
+
if i + 2 < len(hex_string):
|
72 |
+
result += "00"
|
73 |
+
return result
|
74 |
+
|
75 |
+
def extract_kid_from_mpd(self, url):
|
76 |
+
response = requests.get(url)
|
77 |
+
response.raise_for_status()
|
78 |
+
mpd_content = response.text
|
79 |
+
pattern = r'default_KID="([0-9a-fA-F-]+)"'
|
80 |
+
match = re.search(pattern, mpd_content)
|
81 |
+
return match.group(1) if match else None
|
82 |
+
|
83 |
+
def get_key(self, id, verbose=True):
|
84 |
+
if verbose: Global.hr()
|
85 |
+
|
86 |
+
if verbose: Global.dprint("Beginning to get the key for the video... & Audio :) ")
|
87 |
+
if verbose: Global.dprint(f"ID: {id}")
|
88 |
+
if verbose: Global.dprint("Building the URL to get the key...")
|
89 |
+
|
90 |
+
try:
|
91 |
+
url = DL.buildUrl(id)
|
92 |
+
if verbose: Global.sprint(f"URL: {url}")
|
93 |
+
|
94 |
+
if verbose: Global.dprint("Extracting the KID from the MPD file...")
|
95 |
+
kid = self.extract_kid_from_mpd(url).replace("-", "")
|
96 |
+
if verbose: Global.sprint(f"KID: {kid}")
|
97 |
+
|
98 |
+
if verbose: Global.dprint("Encrypting the KID to get the key...")
|
99 |
+
otp_key = self.b64_encode(self.xor_encrypt(kid))
|
100 |
+
if verbose: Global.sprint(f"OTP Key: {otp_key}")
|
101 |
+
|
102 |
+
if verbose: Global.dprint("Encoding the OTP key to hex...")
|
103 |
+
encoded_otp_key_step1 = otp_key.encode('utf-8').hex()
|
104 |
+
encoded_otp_key = self.insert_zeros(encoded_otp_key_step1)
|
105 |
+
if verbose: Global.sprint(f"Encoded OTP Key: {encoded_otp_key}")
|
106 |
+
|
107 |
+
if verbose: Global.dprint("Building the license URL...")
|
108 |
+
license_url = self.build_license_url(encoded_otp_key)
|
109 |
+
if verbose: Global.sprint(f"License URL: {license_url}")
|
110 |
+
|
111 |
+
if verbose: Global.dprint("Getting the headers...")
|
112 |
+
headers = self.get_headers()
|
113 |
+
if verbose: Global.sprint(f"Headers: {json.dumps(headers, indent=4)}")
|
114 |
+
|
115 |
+
if verbose: Global.dprint("Making a request to the server to get the license (key)...")
|
116 |
+
response = requests.get(license_url, headers=headers)
|
117 |
+
if verbose: Global.sprint(f"Response: {response}")
|
118 |
+
|
119 |
+
if response.status_code == 200:
|
120 |
+
if 'data' in response.json() and 'otp' in response.json()['data']:
|
121 |
+
if verbose: Global.sprint("Key received successfully!")
|
122 |
+
key = self.get_key_final(response.json()['data']['otp'])
|
123 |
+
if verbose: Global.sprint(f"Key: {key}")
|
124 |
+
|
125 |
+
if verbose:Global.hr()
|
126 |
+
return (kid,key)
|
127 |
+
else:
|
128 |
+
Global.errprint("Could not get the key from the server. Exiting...")
|
129 |
+
return None
|
130 |
+
|
131 |
+
except Exception as e:
|
132 |
+
Global.errprint(f"An error occurred while getting the key: {e}")
|
133 |
+
return None
|
134 |
+
|
135 |
+
# Example usage
|
136 |
+
# TOKEN = "your_token_here"
|
137 |
+
# fetcher = LicenseKeyFetcher(TOKEN)
|
138 |
+
# key = fetcher.get_key(video_id)
|
mainLogic/big4/dl_obsolete.py
CHANGED
@@ -1,175 +1,175 @@
|
|
1 |
-
import re
|
2 |
-
|
3 |
-
from mainLogic import error
|
4 |
-
from mainLogic.utils.process import shell
|
5 |
-
from mainLogic.utils.glv import Global
|
6 |
-
from mainLogic.utils.basicUtils import BasicUtils
|
7 |
-
class DL:
|
8 |
-
|
9 |
-
@staticmethod
|
10 |
-
def buildUrl(id):
|
11 |
-
if id == None:
|
12 |
-
error.errorList["idNotProvided"]["func"]()
|
13 |
-
exit(error.errorList["idNotProvided"]["code"])
|
14 |
-
|
15 |
-
return f"https://d1d34p8vz63oiq.cloudfront.net/{id}/master.mpd"
|
16 |
-
|
17 |
-
def download(self,id,name=None,
|
18 |
-
type="",
|
19 |
-
directory="./",
|
20 |
-
tmpDir="/*auto*/",
|
21 |
-
nm3Path='nm3',
|
22 |
-
ffmpeg='ffmpeg',
|
23 |
-
verbose=True,
|
24 |
-
progress_callback=None):
|
25 |
-
if id == None:
|
26 |
-
error.errorList["idNotProvided"]["func"]()
|
27 |
-
exit(error.errorList["idNotProvided"]["code"])
|
28 |
-
|
29 |
-
if name == None: name = id
|
30 |
-
|
31 |
-
|
32 |
-
url = DL.buildUrl(id)
|
33 |
-
|
34 |
-
# setting identifier and filter based on type
|
35 |
-
|
36 |
-
# identifier is used to identify the type of file
|
37 |
-
identifier = "a" if type == "Audio" else "v" if type == "Video" else "av"
|
38 |
-
|
39 |
-
# filter is used to filter the output of the shell command
|
40 |
-
filter = r"^Aud" if type == "Audio" else r"^Vid"
|
41 |
-
|
42 |
-
# command to download the file
|
43 |
-
command = f'{nm3Path} {url} --save-dir {directory} {"--tmp-dir "+tmpDir if not tmpDir == "/*auto*/" else "" } --save-name {name} -s{identifier} best'
|
44 |
-
if verbose: Global.sprint(f"Command to download: {command}")
|
45 |
-
|
46 |
-
# Download the audio file using the id
|
47 |
-
code = shell(f'{command}',
|
48 |
-
filter=filter,
|
49 |
-
progress_callback=progress_callback,
|
50 |
-
handleProgress=self.handleDownloadProgress,
|
51 |
-
)
|
52 |
-
|
53 |
-
if code == 0:
|
54 |
-
return True
|
55 |
-
else:
|
56 |
-
error.errorList[f"couldNotDownload{type}"]["func"]()
|
57 |
-
exit(error.errorList[f"couldNotDownload{type}"]["code"])
|
58 |
-
|
59 |
-
def downloadAudioAndVideo(self,
|
60 |
-
id,
|
61 |
-
name=None,
|
62 |
-
directory="./",
|
63 |
-
tmpDir="/*auto*/",
|
64 |
-
nm3Path='nm3',
|
65 |
-
ffmpeg='ffmpeg',
|
66 |
-
verbose=True,
|
67 |
-
progress_callback=None):
|
68 |
-
if id == None:
|
69 |
-
error.errorList["idNotProvided"]["func"]()
|
70 |
-
exit(error.errorList["idNotProvided"]["code"])
|
71 |
-
|
72 |
-
if name == None: name = id; Global.dprint(f"Name not provided, using id as name: {name}")
|
73 |
-
|
74 |
-
# removing limitations of relative path
|
75 |
-
if not tmpDir == "/*auto*/": BasicUtils.abspath(tmpDir)
|
76 |
-
directory = BasicUtils.abspath(directory)
|
77 |
-
|
78 |
-
if verbose:
|
79 |
-
Global.hr()
|
80 |
-
Global.dprint(f"ID: {id}")
|
81 |
-
Global.dprint(f"Name: {name}")
|
82 |
-
Global.dprint(f"Directory: {directory}")
|
83 |
-
Global.dprint(f"TmpDir: {tmpDir}")
|
84 |
-
Global.dprint(f"Nm3Path: {nm3Path}")
|
85 |
-
Global.hr()
|
86 |
-
Global.dprint(f"Starting DL...")
|
87 |
-
|
88 |
-
# section to download audio
|
89 |
-
Global.hr(); Global.dprint("Downloading Audio..."); Global.hr()
|
90 |
-
self.dlAudio(id,
|
91 |
-
name,
|
92 |
-
directory,
|
93 |
-
tmpDir,
|
94 |
-
nm3Path,
|
95 |
-
verbose,
|
96 |
-
progress_callback=progress_callback)
|
97 |
-
|
98 |
-
# section to download video
|
99 |
-
Global.hr(); Global.dprint("Downloading Video..."); Global.hr()
|
100 |
-
self.dlVideo(id,
|
101 |
-
name,
|
102 |
-
directory,
|
103 |
-
tmpDir,
|
104 |
-
nm3Path,
|
105 |
-
verbose,
|
106 |
-
progress_callback=progress_callback)
|
107 |
-
|
108 |
-
if progress_callback:
|
109 |
-
progress_callback({
|
110 |
-
"progress": 80,
|
111 |
-
"str": "download-completed",
|
112 |
-
"next": "decryption"
|
113 |
-
})
|
114 |
-
|
115 |
-
# return the paths of the downloaded files
|
116 |
-
return [f"{directory}/{name}.mp4",f"{directory}/{name}.m4a"]
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
def dlAudio(self,id,name=None,directory="./",tmpDir="/*auto*/",nm3Path='nm3',verbose=True,progress_callback=None):
|
122 |
-
self.download(id,
|
123 |
-
name,
|
124 |
-
"Audio",
|
125 |
-
directory,
|
126 |
-
tmpDir,
|
127 |
-
nm3Path,
|
128 |
-
verbose=verbose,
|
129 |
-
progress_callback=progress_callback)
|
130 |
-
|
131 |
-
def dlVideo(self,id,name=None,directory="./",tmpDir="/*auto*/",nm3Path='nm3',verbose=True,progress_callback=None):
|
132 |
-
self.download(id,
|
133 |
-
name,
|
134 |
-
"Video",
|
135 |
-
directory,
|
136 |
-
tmpDir,
|
137 |
-
nm3Path,
|
138 |
-
verbose=verbose,
|
139 |
-
progress_callback=progress_callback)
|
140 |
-
|
141 |
-
|
142 |
-
def handleDownloadProgress(self,output):
|
143 |
-
|
144 |
-
|
145 |
-
progress = {
|
146 |
-
"str": output,
|
147 |
-
"dl-progress": 0,
|
148 |
-
"progress": 0,
|
149 |
-
"next": "Aud"
|
150 |
-
}
|
151 |
-
|
152 |
-
# formats the output to get the progress
|
153 |
-
pattern = re.compile(r"[0-9][0-9][0-9]?%")
|
154 |
-
progress_percent = pattern.findall(output)
|
155 |
-
|
156 |
-
if progress_percent:
|
157 |
-
|
158 |
-
progress["dl-progress"] = int(progress_percent[0].replace("%",""))
|
159 |
-
|
160 |
-
if "Aud" in output:
|
161 |
-
progress["progress"] = progress["dl-progress"] * 0.4
|
162 |
-
progress["next"] = "Vid"
|
163 |
-
|
164 |
-
if "Vid" in output:
|
165 |
-
progress["progress"] = progress["dl-progress"] * 0.4 + 40
|
166 |
-
progress["next"] = "decryption"
|
167 |
-
|
168 |
-
|
169 |
-
return progress
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
|
|
1 |
+
import re
|
2 |
+
|
3 |
+
from mainLogic import error
|
4 |
+
from mainLogic.utils.process import shell
|
5 |
+
from mainLogic.utils.glv import Global
|
6 |
+
from mainLogic.utils.basicUtils import BasicUtils
|
7 |
+
class DL:
|
8 |
+
|
9 |
+
@staticmethod
|
10 |
+
def buildUrl(id):
|
11 |
+
if id == None:
|
12 |
+
error.errorList["idNotProvided"]["func"]()
|
13 |
+
exit(error.errorList["idNotProvided"]["code"])
|
14 |
+
|
15 |
+
return f"https://d1d34p8vz63oiq.cloudfront.net/{id}/master.mpd"
|
16 |
+
|
17 |
+
def download(self,id,name=None,
|
18 |
+
type="",
|
19 |
+
directory="./",
|
20 |
+
tmpDir="/*auto*/",
|
21 |
+
nm3Path='nm3',
|
22 |
+
ffmpeg='ffmpeg',
|
23 |
+
verbose=True,
|
24 |
+
progress_callback=None):
|
25 |
+
if id == None:
|
26 |
+
error.errorList["idNotProvided"]["func"]()
|
27 |
+
exit(error.errorList["idNotProvided"]["code"])
|
28 |
+
|
29 |
+
if name == None: name = id
|
30 |
+
|
31 |
+
|
32 |
+
url = DL.buildUrl(id)
|
33 |
+
|
34 |
+
# setting identifier and filter based on type
|
35 |
+
|
36 |
+
# identifier is used to identify the type of file
|
37 |
+
identifier = "a" if type == "Audio" else "v" if type == "Video" else "av"
|
38 |
+
|
39 |
+
# filter is used to filter the output of the shell command
|
40 |
+
filter = r"^Aud" if type == "Audio" else r"^Vid"
|
41 |
+
|
42 |
+
# command to download the file
|
43 |
+
command = f'{nm3Path} {url} --save-dir {directory} {"--tmp-dir "+tmpDir if not tmpDir == "/*auto*/" else "" } --save-name {name} -s{identifier} best'
|
44 |
+
if verbose: Global.sprint(f"Command to download: {command}")
|
45 |
+
|
46 |
+
# Download the audio file using the id
|
47 |
+
code = shell(f'{command}',
|
48 |
+
filter=filter,
|
49 |
+
progress_callback=progress_callback,
|
50 |
+
handleProgress=self.handleDownloadProgress,
|
51 |
+
)
|
52 |
+
|
53 |
+
if code == 0:
|
54 |
+
return True
|
55 |
+
else:
|
56 |
+
error.errorList[f"couldNotDownload{type}"]["func"]()
|
57 |
+
exit(error.errorList[f"couldNotDownload{type}"]["code"])
|
58 |
+
|
59 |
+
def downloadAudioAndVideo(self,
|
60 |
+
id,
|
61 |
+
name=None,
|
62 |
+
directory="./",
|
63 |
+
tmpDir="/*auto*/",
|
64 |
+
nm3Path='nm3',
|
65 |
+
ffmpeg='ffmpeg',
|
66 |
+
verbose=True,
|
67 |
+
progress_callback=None):
|
68 |
+
if id == None:
|
69 |
+
error.errorList["idNotProvided"]["func"]()
|
70 |
+
exit(error.errorList["idNotProvided"]["code"])
|
71 |
+
|
72 |
+
if name == None: name = id; Global.dprint(f"Name not provided, using id as name: {name}")
|
73 |
+
|
74 |
+
# removing limitations of relative path
|
75 |
+
if not tmpDir == "/*auto*/": BasicUtils.abspath(tmpDir)
|
76 |
+
directory = BasicUtils.abspath(directory)
|
77 |
+
|
78 |
+
if verbose:
|
79 |
+
Global.hr()
|
80 |
+
Global.dprint(f"ID: {id}")
|
81 |
+
Global.dprint(f"Name: {name}")
|
82 |
+
Global.dprint(f"Directory: {directory}")
|
83 |
+
Global.dprint(f"TmpDir: {tmpDir}")
|
84 |
+
Global.dprint(f"Nm3Path: {nm3Path}")
|
85 |
+
Global.hr()
|
86 |
+
Global.dprint(f"Starting DL...")
|
87 |
+
|
88 |
+
# section to download audio
|
89 |
+
Global.hr(); Global.dprint("Downloading Audio..."); Global.hr()
|
90 |
+
self.dlAudio(id,
|
91 |
+
name,
|
92 |
+
directory,
|
93 |
+
tmpDir,
|
94 |
+
nm3Path,
|
95 |
+
verbose,
|
96 |
+
progress_callback=progress_callback)
|
97 |
+
|
98 |
+
# section to download video
|
99 |
+
Global.hr(); Global.dprint("Downloading Video..."); Global.hr()
|
100 |
+
self.dlVideo(id,
|
101 |
+
name,
|
102 |
+
directory,
|
103 |
+
tmpDir,
|
104 |
+
nm3Path,
|
105 |
+
verbose,
|
106 |
+
progress_callback=progress_callback)
|
107 |
+
|
108 |
+
if progress_callback:
|
109 |
+
progress_callback({
|
110 |
+
"progress": 80,
|
111 |
+
"str": "download-completed",
|
112 |
+
"next": "decryption"
|
113 |
+
})
|
114 |
+
|
115 |
+
# return the paths of the downloaded files
|
116 |
+
return [f"{directory}/{name}.mp4",f"{directory}/{name}.m4a"]
|
117 |
+
|
118 |
+
|
119 |
+
|
120 |
+
|
121 |
+
def dlAudio(self,id,name=None,directory="./",tmpDir="/*auto*/",nm3Path='nm3',verbose=True,progress_callback=None):
|
122 |
+
self.download(id,
|
123 |
+
name,
|
124 |
+
"Audio",
|
125 |
+
directory,
|
126 |
+
tmpDir,
|
127 |
+
nm3Path,
|
128 |
+
verbose=verbose,
|
129 |
+
progress_callback=progress_callback)
|
130 |
+
|
131 |
+
def dlVideo(self,id,name=None,directory="./",tmpDir="/*auto*/",nm3Path='nm3',verbose=True,progress_callback=None):
|
132 |
+
self.download(id,
|
133 |
+
name,
|
134 |
+
"Video",
|
135 |
+
directory,
|
136 |
+
tmpDir,
|
137 |
+
nm3Path,
|
138 |
+
verbose=verbose,
|
139 |
+
progress_callback=progress_callback)
|
140 |
+
|
141 |
+
|
142 |
+
def handleDownloadProgress(self,output):
|
143 |
+
|
144 |
+
|
145 |
+
progress = {
|
146 |
+
"str": output,
|
147 |
+
"dl-progress": 0,
|
148 |
+
"progress": 0,
|
149 |
+
"next": "Aud"
|
150 |
+
}
|
151 |
+
|
152 |
+
# formats the output to get the progress
|
153 |
+
pattern = re.compile(r"[0-9][0-9][0-9]?%")
|
154 |
+
progress_percent = pattern.findall(output)
|
155 |
+
|
156 |
+
if progress_percent:
|
157 |
+
|
158 |
+
progress["dl-progress"] = int(progress_percent[0].replace("%",""))
|
159 |
+
|
160 |
+
if "Aud" in output:
|
161 |
+
progress["progress"] = progress["dl-progress"] * 0.4
|
162 |
+
progress["next"] = "Vid"
|
163 |
+
|
164 |
+
if "Vid" in output:
|
165 |
+
progress["progress"] = progress["dl-progress"] * 0.4 + 40
|
166 |
+
progress["next"] = "decryption"
|
167 |
+
|
168 |
+
|
169 |
+
return progress
|
170 |
+
|
171 |
+
|
172 |
+
|
173 |
+
|
174 |
+
|
175 |
+
|
mainLogic/big4/downloadv2.py
CHANGED
@@ -1,96 +1,96 @@
|
|
1 |
-
import re
|
2 |
-
|
3 |
-
from mainLogic import error
|
4 |
-
from mainLogic.utils.process import shell
|
5 |
-
from mainLogic.utils.glv import Global
|
6 |
-
|
7 |
-
|
8 |
-
class Download:
|
9 |
-
|
10 |
-
@staticmethod
|
11 |
-
def buildUrl(id):
|
12 |
-
if id == None:
|
13 |
-
error.errorList["idNotProvided"]["func"]()
|
14 |
-
exit(error.errorList["idNotProvided"]["code"])
|
15 |
-
|
16 |
-
return f"https://d1d34p8vz63oiq.cloudfront.net/{id}/master.mpd"
|
17 |
-
|
18 |
-
def __init__(self,
|
19 |
-
vsd_path,
|
20 |
-
url,
|
21 |
-
name=None,
|
22 |
-
tmp_path="./",
|
23 |
-
output_path="./",
|
24 |
-
progress_callback=None
|
25 |
-
):
|
26 |
-
self.vsd_path = vsd_path
|
27 |
-
self.url = url
|
28 |
-
self.name = name
|
29 |
-
self.tmp_path = tmp_path + '/' + name
|
30 |
-
self.output_path = output_path
|
31 |
-
self.progress_callback = progress_callback
|
32 |
-
|
33 |
-
def perform_cleanup(self):
|
34 |
-
|
35 |
-
import shutil
|
36 |
-
|
37 |
-
shutil.move(self.tmp_path + "/vsd_audio_master_mpd.mp4", self.output_path + '/' + self.name + "-Video-enc.mp4")
|
38 |
-
shutil.move(self.tmp_path + "/vsd_video_master_mpd.mp4", self.output_path + '/' + self.name + "-Audio-enc.mp4")
|
39 |
-
|
40 |
-
try:
|
41 |
-
shutil.rmtree(self.tmp_path)
|
42 |
-
except Exception as e:
|
43 |
-
Global.errprint(f"Could not remove tmp directory : {e}")
|
44 |
-
|
45 |
-
return (
|
46 |
-
self.output_path + '/' + self.name + "-Video-enc.mp4", self.output_path + '/' + self.name + "-Audio-enc.mp4")
|
47 |
-
|
48 |
-
def download(self):
|
49 |
-
"""
|
50 |
-
Download the video file from the given URL and save it to the output path.
|
51 |
-
"""
|
52 |
-
# Download the video file
|
53 |
-
# Save the video file to the output path
|
54 |
-
shell([
|
55 |
-
f"{self.vsd_path}",
|
56 |
-
"save",
|
57 |
-
f"{self.url}",
|
58 |
-
"--skip-prompts",
|
59 |
-
"--raw-prompts",
|
60 |
-
"-t",
|
61 |
-
"16",
|
62 |
-
"--no-decrypt",
|
63 |
-
"-d",
|
64 |
-
f'{self.tmp_path}'],
|
65 |
-
filter=r"^\d+\.\d+ / \d+ MiB [╸━]+ \d+(\.\d+)?% •\s+\d+/\d+ • \d+:\d+ > \d+:\d+ • \d+(\.\d+)? SEG/s • .+$",
|
66 |
-
progress_callback=self.progress_callback,
|
67 |
-
handleProgress=self.handleDownloadProgress,
|
68 |
-
inline_progress=True,
|
69 |
-
|
70 |
-
)
|
71 |
-
|
72 |
-
return self.perform_cleanup()
|
73 |
-
|
74 |
-
def handleDownloadProgress(self, progress):
|
75 |
-
"""
|
76 |
-
Handle the progress of the download process.
|
77 |
-
"""
|
78 |
-
|
79 |
-
# extract percentage from the progress string (using) regex
|
80 |
-
# and convert it to float
|
81 |
-
|
82 |
-
output = {
|
83 |
-
"str": progress,
|
84 |
-
|
85 |
-
}
|
86 |
-
|
87 |
-
pattern = r"(\d+(\.\d+)?)%"
|
88 |
-
match = re.search(pattern, progress)
|
89 |
-
if match:
|
90 |
-
progress_f = float(match.group(1)) * 0.8
|
91 |
-
else:
|
92 |
-
progress_f = 0.0
|
93 |
-
|
94 |
-
output["progress"] = progress_f
|
95 |
-
|
96 |
-
return output
|
|
|
1 |
+
import re
|
2 |
+
|
3 |
+
from mainLogic import error
|
4 |
+
from mainLogic.utils.process import shell
|
5 |
+
from mainLogic.utils.glv import Global
|
6 |
+
|
7 |
+
|
8 |
+
class Download:
|
9 |
+
|
10 |
+
@staticmethod
|
11 |
+
def buildUrl(id):
|
12 |
+
if id == None:
|
13 |
+
error.errorList["idNotProvided"]["func"]()
|
14 |
+
exit(error.errorList["idNotProvided"]["code"])
|
15 |
+
|
16 |
+
return f"https://d1d34p8vz63oiq.cloudfront.net/{id}/master.mpd"
|
17 |
+
|
18 |
+
def __init__(self,
|
19 |
+
vsd_path,
|
20 |
+
url,
|
21 |
+
name=None,
|
22 |
+
tmp_path="./",
|
23 |
+
output_path="./",
|
24 |
+
progress_callback=None
|
25 |
+
):
|
26 |
+
self.vsd_path = vsd_path
|
27 |
+
self.url = url
|
28 |
+
self.name = name
|
29 |
+
self.tmp_path = tmp_path + '/' + name
|
30 |
+
self.output_path = output_path
|
31 |
+
self.progress_callback = progress_callback
|
32 |
+
|
33 |
+
def perform_cleanup(self):
|
34 |
+
|
35 |
+
import shutil
|
36 |
+
|
37 |
+
shutil.move(self.tmp_path + "/vsd_audio_master_mpd.mp4", self.output_path + '/' + self.name + "-Video-enc.mp4")
|
38 |
+
shutil.move(self.tmp_path + "/vsd_video_master_mpd.mp4", self.output_path + '/' + self.name + "-Audio-enc.mp4")
|
39 |
+
|
40 |
+
try:
|
41 |
+
shutil.rmtree(self.tmp_path)
|
42 |
+
except Exception as e:
|
43 |
+
Global.errprint(f"Could not remove tmp directory : {e}")
|
44 |
+
|
45 |
+
return (
|
46 |
+
self.output_path + '/' + self.name + "-Video-enc.mp4", self.output_path + '/' + self.name + "-Audio-enc.mp4")
|
47 |
+
|
48 |
+
def download(self):
|
49 |
+
"""
|
50 |
+
Download the video file from the given URL and save it to the output path.
|
51 |
+
"""
|
52 |
+
# Download the video file
|
53 |
+
# Save the video file to the output path
|
54 |
+
shell([
|
55 |
+
f"{self.vsd_path}",
|
56 |
+
"save",
|
57 |
+
f"{self.url}",
|
58 |
+
"--skip-prompts",
|
59 |
+
"--raw-prompts",
|
60 |
+
"-t",
|
61 |
+
"16",
|
62 |
+
"--no-decrypt",
|
63 |
+
"-d",
|
64 |
+
f'{self.tmp_path}'],
|
65 |
+
filter=r"^\d+\.\d+ / \d+ MiB [╸━]+ \d+(\.\d+)?% •\s+\d+/\d+ • \d+:\d+ > \d+:\d+ • \d+(\.\d+)? SEG/s • .+$",
|
66 |
+
progress_callback=self.progress_callback,
|
67 |
+
handleProgress=self.handleDownloadProgress,
|
68 |
+
inline_progress=True,
|
69 |
+
|
70 |
+
)
|
71 |
+
|
72 |
+
return self.perform_cleanup()
|
73 |
+
|
74 |
+
def handleDownloadProgress(self, progress):
|
75 |
+
"""
|
76 |
+
Handle the progress of the download process.
|
77 |
+
"""
|
78 |
+
|
79 |
+
# extract percentage from the progress string (using) regex
|
80 |
+
# and convert it to float
|
81 |
+
|
82 |
+
output = {
|
83 |
+
"str": progress,
|
84 |
+
|
85 |
+
}
|
86 |
+
|
87 |
+
pattern = r"(\d+(\.\d+)?)%"
|
88 |
+
match = re.search(pattern, progress)
|
89 |
+
if match:
|
90 |
+
progress_f = float(match.group(1)) * 0.8
|
91 |
+
else:
|
92 |
+
progress_f = 0.0
|
93 |
+
|
94 |
+
output["progress"] = progress_f
|
95 |
+
|
96 |
+
return output
|
mainLogic/big4/merge.py
CHANGED
@@ -1,36 +1,36 @@
|
|
1 |
-
import os
|
2 |
-
from mainLogic.error import errorList
|
3 |
-
from mainLogic.utils.process import shell
|
4 |
-
from mainLogic.utils.glv import Global
|
5 |
-
from mainLogic.utils.os2 import SysFunc
|
6 |
-
class Merge:
|
7 |
-
|
8 |
-
def mergeCommandBuilder(self,ffmpeg_path,input1,input2,output,overwrite=False):
|
9 |
-
|
10 |
-
return f'{ffmpeg_path} {"-y" if overwrite else ""} -i {input1} -i {input2} -c copy {output}'
|
11 |
-
|
12 |
-
|
13 |
-
def ffmpegMerge(self,input1,input2,output,ffmpeg_path="ffmpeg",verbose=False):
|
14 |
-
|
15 |
-
input1,input2,output = SysFunc.modify_path(input1),SysFunc.modify_path(input2),SysFunc.modify_path(output)
|
16 |
-
|
17 |
-
if verbose: Global.hr();Global.dprint('Attempting ffmpeg merge')
|
18 |
-
# if verbose: Global.dprint(f'{ffmpeg_path} -i {input1} -i {input2} -c copy {output}')
|
19 |
-
|
20 |
-
if os.path.exists(output):
|
21 |
-
|
22 |
-
Global.errprint("Warninbg: Output file already exists. Overwriting...")
|
23 |
-
consent = input("Do you want to continue? (y/n): ")
|
24 |
-
|
25 |
-
if consent.lower() != 'y':
|
26 |
-
errorList['overWriteAbortedByUser']['func']()
|
27 |
-
exit(errorList['overWriteAbortedByUser']['code'])
|
28 |
-
|
29 |
-
if verbose:
|
30 |
-
Global.dprint(f"Running: {self.mergeCommandBuilder(ffmpeg_path,input1,input2,output,overwrite=True)}")
|
31 |
-
shell(self.mergeCommandBuilder(ffmpeg_path,input1,input2,output,overwrite=True),filter='.*')
|
32 |
-
else:
|
33 |
-
shell(self.mergeCommandBuilder(ffmpeg_path,input1,input2,output,overwrite=True), stderr="", stdout="")
|
34 |
-
|
35 |
-
|
36 |
return output
|
|
|
1 |
+
import os
|
2 |
+
from mainLogic.error import errorList
|
3 |
+
from mainLogic.utils.process import shell
|
4 |
+
from mainLogic.utils.glv import Global
|
5 |
+
from mainLogic.utils.os2 import SysFunc
|
6 |
+
class Merge:
|
7 |
+
|
8 |
+
def mergeCommandBuilder(self,ffmpeg_path,input1,input2,output,overwrite=False):
|
9 |
+
|
10 |
+
return f'{ffmpeg_path} {"-y" if overwrite else ""} -i {input1} -i {input2} -c copy {output}'
|
11 |
+
|
12 |
+
|
13 |
+
def ffmpegMerge(self,input1,input2,output,ffmpeg_path="ffmpeg",verbose=False):
|
14 |
+
|
15 |
+
input1,input2,output = SysFunc.modify_path(input1),SysFunc.modify_path(input2),SysFunc.modify_path(output)
|
16 |
+
|
17 |
+
if verbose: Global.hr();Global.dprint('Attempting ffmpeg merge')
|
18 |
+
# if verbose: Global.dprint(f'{ffmpeg_path} -i {input1} -i {input2} -c copy {output}')
|
19 |
+
|
20 |
+
if os.path.exists(output):
|
21 |
+
|
22 |
+
Global.errprint("Warninbg: Output file already exists. Overwriting...")
|
23 |
+
consent = input("Do you want to continue? (y/n): ")
|
24 |
+
|
25 |
+
if consent.lower() != 'y':
|
26 |
+
errorList['overWriteAbortedByUser']['func']()
|
27 |
+
exit(errorList['overWriteAbortedByUser']['code'])
|
28 |
+
|
29 |
+
if verbose:
|
30 |
+
Global.dprint(f"Running: {self.mergeCommandBuilder(ffmpeg_path,input1,input2,output,overwrite=True)}")
|
31 |
+
shell(self.mergeCommandBuilder(ffmpeg_path,input1,input2,output,overwrite=True),filter='.*')
|
32 |
+
else:
|
33 |
+
shell(self.mergeCommandBuilder(ffmpeg_path,input1,input2,output,overwrite=True), stderr="", stdout="")
|
34 |
+
|
35 |
+
|
36 |
return output
|
mainLogic/downloader.py
CHANGED
@@ -1,117 +1,117 @@
|
|
1 |
-
import sys
|
2 |
-
import os
|
3 |
-
from mainLogic.error import errorList
|
4 |
-
from mainLogic.utils.glv import Global
|
5 |
-
from mainLogic.utils.os2 import SysFunc
|
6 |
-
from mainLogic.main import Main
|
7 |
-
from beta.shellLogic import shell
|
8 |
-
from mainLogic.startup.checkup import CheckState
|
9 |
-
from mainLogic.utils.gen_utils import generate_safe_folder_name
|
10 |
-
from mainLogic.utils import glv_var
|
11 |
-
|
12 |
-
# global variables
|
13 |
-
prefs = {}
|
14 |
-
glv = Global()
|
15 |
-
|
16 |
-
# hardcoding the list of executables required for the script to run
|
17 |
-
EXECUTABLES = glv_var.EXECUTABLES
|
18 |
-
|
19 |
-
def check_dependencies(directory, verbose):
|
20 |
-
"""Check if all dependencies are installed."""
|
21 |
-
global prefs
|
22 |
-
state = CheckState().checkup(EXECUTABLES, directory=directory, verbose=verbose)
|
23 |
-
prefs = state['prefs']
|
24 |
-
return state
|
25 |
-
|
26 |
-
def start_shell():
|
27 |
-
"""Start the shell if requested."""
|
28 |
-
shell.main()
|
29 |
-
|
30 |
-
def start_webui(port, verbose):
|
31 |
-
"""Start the WebUI if requested."""
|
32 |
-
from run import app
|
33 |
-
if not prefs['webui']:
|
34 |
-
Global.errprint("WebUI is not enabled in the preferences. Exiting ...")
|
35 |
-
sys.exit(1)
|
36 |
-
|
37 |
-
if 'webui-port' in prefs:
|
38 |
-
port = prefs['webui-port']
|
39 |
-
|
40 |
-
if verbose:
|
41 |
-
Global.hr()
|
42 |
-
Global.dprint(f"Starting WebUI on port {port}")
|
43 |
-
|
44 |
-
app.run(host="0.0.0.0", debug=True, port=port)
|
45 |
-
|
46 |
-
def download_process(id, name, state, verbose, simulate=False):
|
47 |
-
"""Process a single download or simulate the download."""
|
48 |
-
if simulate:
|
49 |
-
print("Simulating the download process. No files will be downloaded.")
|
50 |
-
print(f"Id to be processed: {id}")
|
51 |
-
print(f"Name to be processed: {name}")
|
52 |
-
return
|
53 |
-
|
54 |
-
try:
|
55 |
-
Main(
|
56 |
-
id=id,
|
57 |
-
name=generate_safe_folder_name(name),
|
58 |
-
directory=prefs['dir'],
|
59 |
-
ffmpeg=state['ffmpeg'],
|
60 |
-
vsdPath=state['vsd'],
|
61 |
-
token=prefs['token'],
|
62 |
-
mp4d=state['mp4decrypt'],
|
63 |
-
tmpDir=prefs['tmpDir'],
|
64 |
-
verbose=verbose
|
65 |
-
).process()
|
66 |
-
except Exception as e:
|
67 |
-
if verbose:
|
68 |
-
Global.hr()
|
69 |
-
glv.errprint(f"Error: {e}")
|
70 |
-
errorList['downloadFailed']['func'](name, id)
|
71 |
-
sys.exit(errorList['downloadFailed']['code'])
|
72 |
-
|
73 |
-
def handle_csv_file(csv_file, state, verbose, simulate=False):
|
74 |
-
"""Handle processing of CSV file."""
|
75 |
-
if not os.path.exists(csv_file):
|
76 |
-
errorList['csvFileNotFound']['func'](csv_file)
|
77 |
-
sys.exit(errorList['csvFileNotFound']['code'])
|
78 |
-
|
79 |
-
if simulate:
|
80 |
-
print("Simulating the download csv process. No files will be downloaded.")
|
81 |
-
print(f"File to be processed: {csv_file}")
|
82 |
-
return
|
83 |
-
|
84 |
-
with open(csv_file, 'r') as f:
|
85 |
-
for line in f:
|
86 |
-
name, id = line.strip().split(',')
|
87 |
-
name = generate_safe_folder_name(name)
|
88 |
-
download_process(id, name, state, verbose)
|
89 |
-
|
90 |
-
def main(csv_file=None, id=None, name=None, directory=None, verbose=False, shell=False, webui_port=None, simulate=False):
|
91 |
-
if shell:
|
92 |
-
start_shell()
|
93 |
-
|
94 |
-
glv.vout = verbose
|
95 |
-
|
96 |
-
state = check_dependencies(directory, glv.vout)
|
97 |
-
|
98 |
-
if webui_port is not None:
|
99 |
-
start_webui(webui_port, glv.vout)
|
100 |
-
|
101 |
-
if simulate:
|
102 |
-
if csv_file:
|
103 |
-
handle_csv_file(csv_file, state, glv.vout, simulate=True)
|
104 |
-
elif id and name:
|
105 |
-
download_process(id, name, state, glv.vout, simulate=True)
|
106 |
-
return
|
107 |
-
|
108 |
-
if csv_file and (id or name):
|
109 |
-
print("Both csv file and id (or name) is provided. Unable to decide. Aborting! ...")
|
110 |
-
sys.exit(3)
|
111 |
-
|
112 |
-
if csv_file:
|
113 |
-
handle_csv_file(csv_file, state, glv.vout)
|
114 |
-
elif id and name:
|
115 |
-
download_process(id, name, state, glv.vout)
|
116 |
-
else:
|
117 |
-
sys.exit(1)
|
|
|
1 |
+
import sys
|
2 |
+
import os
|
3 |
+
from mainLogic.error import errorList
|
4 |
+
from mainLogic.utils.glv import Global
|
5 |
+
from mainLogic.utils.os2 import SysFunc
|
6 |
+
from mainLogic.main import Main
|
7 |
+
from beta.shellLogic import shell
|
8 |
+
from mainLogic.startup.checkup import CheckState
|
9 |
+
from mainLogic.utils.gen_utils import generate_safe_folder_name
|
10 |
+
from mainLogic.utils import glv_var
|
11 |
+
|
12 |
+
# global variables
|
13 |
+
prefs = {}
|
14 |
+
glv = Global()
|
15 |
+
|
16 |
+
# hardcoding the list of executables required for the script to run
|
17 |
+
EXECUTABLES = glv_var.EXECUTABLES
|
18 |
+
|
19 |
+
def check_dependencies(directory, verbose):
|
20 |
+
"""Check if all dependencies are installed."""
|
21 |
+
global prefs
|
22 |
+
state = CheckState().checkup(EXECUTABLES, directory=directory, verbose=verbose)
|
23 |
+
prefs = state['prefs']
|
24 |
+
return state
|
25 |
+
|
26 |
+
def start_shell():
|
27 |
+
"""Start the shell if requested."""
|
28 |
+
shell.main()
|
29 |
+
|
30 |
+
def start_webui(port, verbose):
|
31 |
+
"""Start the WebUI if requested."""
|
32 |
+
from run import app
|
33 |
+
if not prefs['webui']:
|
34 |
+
Global.errprint("WebUI is not enabled in the preferences. Exiting ...")
|
35 |
+
sys.exit(1)
|
36 |
+
|
37 |
+
if 'webui-port' in prefs:
|
38 |
+
port = prefs['webui-port']
|
39 |
+
|
40 |
+
if verbose:
|
41 |
+
Global.hr()
|
42 |
+
Global.dprint(f"Starting WebUI on port {port}")
|
43 |
+
|
44 |
+
app.run(host="0.0.0.0", debug=True, port=port)
|
45 |
+
|
46 |
+
def download_process(id, name, state, verbose, simulate=False):
|
47 |
+
"""Process a single download or simulate the download."""
|
48 |
+
if simulate:
|
49 |
+
print("Simulating the download process. No files will be downloaded.")
|
50 |
+
print(f"Id to be processed: {id}")
|
51 |
+
print(f"Name to be processed: {name}")
|
52 |
+
return
|
53 |
+
|
54 |
+
try:
|
55 |
+
Main(
|
56 |
+
id=id,
|
57 |
+
name=generate_safe_folder_name(name),
|
58 |
+
directory=prefs['dir'],
|
59 |
+
ffmpeg=state['ffmpeg'],
|
60 |
+
vsdPath=state['vsd'],
|
61 |
+
token=prefs['token'],
|
62 |
+
mp4d=state['mp4decrypt'],
|
63 |
+
tmpDir=prefs['tmpDir'],
|
64 |
+
verbose=verbose
|
65 |
+
).process()
|
66 |
+
except Exception as e:
|
67 |
+
if verbose:
|
68 |
+
Global.hr()
|
69 |
+
glv.errprint(f"Error: {e}")
|
70 |
+
errorList['downloadFailed']['func'](name, id)
|
71 |
+
sys.exit(errorList['downloadFailed']['code'])
|
72 |
+
|
73 |
+
def handle_csv_file(csv_file, state, verbose, simulate=False):
|
74 |
+
"""Handle processing of CSV file."""
|
75 |
+
if not os.path.exists(csv_file):
|
76 |
+
errorList['csvFileNotFound']['func'](csv_file)
|
77 |
+
sys.exit(errorList['csvFileNotFound']['code'])
|
78 |
+
|
79 |
+
if simulate:
|
80 |
+
print("Simulating the download csv process. No files will be downloaded.")
|
81 |
+
print(f"File to be processed: {csv_file}")
|
82 |
+
return
|
83 |
+
|
84 |
+
with open(csv_file, 'r') as f:
|
85 |
+
for line in f:
|
86 |
+
name, id = line.strip().split(',')
|
87 |
+
name = generate_safe_folder_name(name)
|
88 |
+
download_process(id, name, state, verbose)
|
89 |
+
|
90 |
+
def main(csv_file=None, id=None, name=None, directory=None, verbose=False, shell=False, webui_port=None, simulate=False):
|
91 |
+
if shell:
|
92 |
+
start_shell()
|
93 |
+
|
94 |
+
glv.vout = verbose
|
95 |
+
|
96 |
+
state = check_dependencies(directory, glv.vout)
|
97 |
+
|
98 |
+
if webui_port is not None:
|
99 |
+
start_webui(webui_port, glv.vout)
|
100 |
+
|
101 |
+
if simulate:
|
102 |
+
if csv_file:
|
103 |
+
handle_csv_file(csv_file, state, glv.vout, simulate=True)
|
104 |
+
elif id and name:
|
105 |
+
download_process(id, name, state, glv.vout, simulate=True)
|
106 |
+
return
|
107 |
+
|
108 |
+
if csv_file and (id or name):
|
109 |
+
print("Both csv file and id (or name) is provided. Unable to decide. Aborting! ...")
|
110 |
+
sys.exit(3)
|
111 |
+
|
112 |
+
if csv_file:
|
113 |
+
handle_csv_file(csv_file, state, glv.vout)
|
114 |
+
elif id and name:
|
115 |
+
download_process(id, name, state, glv.vout)
|
116 |
+
else:
|
117 |
+
sys.exit(1)
|
mainLogic/error.py
CHANGED
@@ -1,86 +1,86 @@
|
|
1 |
-
from mainLogic.utils.glv import Global
|
2 |
-
|
3 |
-
errorList = {
|
4 |
-
"noError": {
|
5 |
-
"code": 0,
|
6 |
-
"func": lambda: None,
|
7 |
-
},
|
8 |
-
"defaultsNotFound" : {
|
9 |
-
"code": 1,
|
10 |
-
"func": lambda: Global.errprint("defaults.json not found. Exiting..."),
|
11 |
-
},
|
12 |
-
"dependencyNotFound": {
|
13 |
-
"code": 2,
|
14 |
-
"func": lambda x=None: Global.errprint(f"{'Dependency' if x == None else x } not found. Exiting..."),
|
15 |
-
},
|
16 |
-
"dependencyNotFoundInPrefs":
|
17 |
-
{
|
18 |
-
"code": 3,
|
19 |
-
"func": lambda x=None: Global.errprint(f"{'Dependency' if x == None else x } not found in default settings. Exiting..."),
|
20 |
-
},
|
21 |
-
"csvFileNotFound": {
|
22 |
-
"code": 4,
|
23 |
-
"func": lambda fileName: Global.errprint(f"CSV file {fileName} not found. Exiting..."),
|
24 |
-
},
|
25 |
-
"downloadFailed": {
|
26 |
-
"code": 5,
|
27 |
-
"func": lambda name, id: Global.errprint(f"Download failed for {name} with id {id}. (Main.process exited) Exiting..."),
|
28 |
-
},
|
29 |
-
"couldNotMakeDir":{
|
30 |
-
"code": 6,
|
31 |
-
"func": lambda dirName: Global.errprint(f"Could not make directory {dirName}. Exiting..."),
|
32 |
-
},
|
33 |
-
"tokenNotFound": {
|
34 |
-
"code": 7,
|
35 |
-
"func": lambda: Global.errprint("Token not found in default settings. Exiting..."),
|
36 |
-
},
|
37 |
-
"overWriteAbortedByUser": {
|
38 |
-
"code": 8,
|
39 |
-
"func": lambda: Global.errprint("Overwrite aborted by user. Exiting..."),
|
40 |
-
},
|
41 |
-
"cantLoadFile": {
|
42 |
-
"code": 22,
|
43 |
-
"func": lambda fileName: Global.errprint(f"Can't load file {fileName}"),
|
44 |
-
},
|
45 |
-
"flareNotStarted": {
|
46 |
-
"code": 23,
|
47 |
-
"func": lambda: Global.errprint("Flare is not started. Start the flare server first.")
|
48 |
-
},
|
49 |
-
"requestFailedDueToUnknownReason": {
|
50 |
-
"code": 24,
|
51 |
-
"func": lambda status_code: Global.errprint("Request failed due to unknown reason. Status Code: " + str(status_code))
|
52 |
-
},
|
53 |
-
"keyExtractionFailed": {
|
54 |
-
"code": 25,
|
55 |
-
"func": lambda id: Global.errprint(f"Key extraction failed for id -> {id}. Exiting...")
|
56 |
-
},
|
57 |
-
"keyNotProvided": {
|
58 |
-
"code": 26,
|
59 |
-
"func": lambda: Global.errprint("Key not provided. Exiting...")
|
60 |
-
},
|
61 |
-
"couldNotDownloadAudio": {
|
62 |
-
"code": 27,
|
63 |
-
"func": lambda id: Global.errprint(f"Could not download audio for id -> {id} Exiting...")
|
64 |
-
},
|
65 |
-
"couldNotDownloadVideo": {
|
66 |
-
"code": 28,
|
67 |
-
"func": lambda: Global.errprint(f"Could not download video for {id} Exiting...")
|
68 |
-
},
|
69 |
-
"couldNotDecryptAudio": {
|
70 |
-
"code": 29,
|
71 |
-
"func": lambda: Global.errprint("Could not decrypt audio. Exiting...")
|
72 |
-
},
|
73 |
-
"couldNotDecryptVideo": {
|
74 |
-
"code": 30,
|
75 |
-
"func": lambda: Global.errprint("Could not decrypt video. Exiting...")
|
76 |
-
},
|
77 |
-
"methodPatched": {
|
78 |
-
"code": 31,
|
79 |
-
"func": lambda: Global.errprint("Method is patched. Exiting...")
|
80 |
-
},
|
81 |
-
"couldNotExtractKey": {
|
82 |
-
"code": 32,
|
83 |
-
"func": lambda: Global.errprint("Could not extract key. Exiting...")
|
84 |
-
},
|
85 |
-
}
|
86 |
-
|
|
|
1 |
+
from mainLogic.utils.glv import Global
|
2 |
+
|
3 |
+
errorList = {
|
4 |
+
"noError": {
|
5 |
+
"code": 0,
|
6 |
+
"func": lambda: None,
|
7 |
+
},
|
8 |
+
"defaultsNotFound" : {
|
9 |
+
"code": 1,
|
10 |
+
"func": lambda: Global.errprint("defaults.json not found. Exiting..."),
|
11 |
+
},
|
12 |
+
"dependencyNotFound": {
|
13 |
+
"code": 2,
|
14 |
+
"func": lambda x=None: Global.errprint(f"{'Dependency' if x == None else x } not found. Exiting..."),
|
15 |
+
},
|
16 |
+
"dependencyNotFoundInPrefs":
|
17 |
+
{
|
18 |
+
"code": 3,
|
19 |
+
"func": lambda x=None: Global.errprint(f"{'Dependency' if x == None else x } not found in default settings. Exiting..."),
|
20 |
+
},
|
21 |
+
"csvFileNotFound": {
|
22 |
+
"code": 4,
|
23 |
+
"func": lambda fileName: Global.errprint(f"CSV file {fileName} not found. Exiting..."),
|
24 |
+
},
|
25 |
+
"downloadFailed": {
|
26 |
+
"code": 5,
|
27 |
+
"func": lambda name, id: Global.errprint(f"Download failed for {name} with id {id}. (Main.process exited) Exiting..."),
|
28 |
+
},
|
29 |
+
"couldNotMakeDir":{
|
30 |
+
"code": 6,
|
31 |
+
"func": lambda dirName: Global.errprint(f"Could not make directory {dirName}. Exiting..."),
|
32 |
+
},
|
33 |
+
"tokenNotFound": {
|
34 |
+
"code": 7,
|
35 |
+
"func": lambda: Global.errprint("Token not found in default settings. Exiting..."),
|
36 |
+
},
|
37 |
+
"overWriteAbortedByUser": {
|
38 |
+
"code": 8,
|
39 |
+
"func": lambda: Global.errprint("Overwrite aborted by user. Exiting..."),
|
40 |
+
},
|
41 |
+
"cantLoadFile": {
|
42 |
+
"code": 22,
|
43 |
+
"func": lambda fileName: Global.errprint(f"Can't load file {fileName}"),
|
44 |
+
},
|
45 |
+
"flareNotStarted": {
|
46 |
+
"code": 23,
|
47 |
+
"func": lambda: Global.errprint("Flare is not started. Start the flare server first.")
|
48 |
+
},
|
49 |
+
"requestFailedDueToUnknownReason": {
|
50 |
+
"code": 24,
|
51 |
+
"func": lambda status_code: Global.errprint("Request failed due to unknown reason. Status Code: " + str(status_code))
|
52 |
+
},
|
53 |
+
"keyExtractionFailed": {
|
54 |
+
"code": 25,
|
55 |
+
"func": lambda id: Global.errprint(f"Key extraction failed for id -> {id}. Exiting...")
|
56 |
+
},
|
57 |
+
"keyNotProvided": {
|
58 |
+
"code": 26,
|
59 |
+
"func": lambda: Global.errprint("Key not provided. Exiting...")
|
60 |
+
},
|
61 |
+
"couldNotDownloadAudio": {
|
62 |
+
"code": 27,
|
63 |
+
"func": lambda id: Global.errprint(f"Could not download audio for id -> {id} Exiting...")
|
64 |
+
},
|
65 |
+
"couldNotDownloadVideo": {
|
66 |
+
"code": 28,
|
67 |
+
"func": lambda: Global.errprint(f"Could not download video for {id} Exiting...")
|
68 |
+
},
|
69 |
+
"couldNotDecryptAudio": {
|
70 |
+
"code": 29,
|
71 |
+
"func": lambda: Global.errprint("Could not decrypt audio. Exiting...")
|
72 |
+
},
|
73 |
+
"couldNotDecryptVideo": {
|
74 |
+
"code": 30,
|
75 |
+
"func": lambda: Global.errprint("Could not decrypt video. Exiting...")
|
76 |
+
},
|
77 |
+
"methodPatched": {
|
78 |
+
"code": 31,
|
79 |
+
"func": lambda: Global.errprint("Method is patched. Exiting...")
|
80 |
+
},
|
81 |
+
"couldNotExtractKey": {
|
82 |
+
"code": 32,
|
83 |
+
"func": lambda: Global.errprint("Could not extract key. Exiting...")
|
84 |
+
},
|
85 |
+
}
|
86 |
+
|
mainLogic/main.py
CHANGED
@@ -1,126 +1,126 @@
|
|
1 |
-
from mainLogic.utils.basicUtils import BasicUtils
|
2 |
-
from mainLogic.utils.os2 import SysFunc
|
3 |
-
from mainLogic.utils.glv import Global
|
4 |
-
from mainLogic.big4.cleanup import Clean
|
5 |
-
from mainLogic.big4.decrypt.key import LicenseKeyFetcher
|
6 |
-
from mainLogic.big4.downloadv2 import Download
|
7 |
-
from mainLogic.big4.decrypt.decrypt import Decrypt
|
8 |
-
from mainLogic.big4.merge import Merge
|
9 |
-
import os
|
10 |
-
|
11 |
-
|
12 |
-
class Main:
|
13 |
-
"""
|
14 |
-
Main class to handle the processing of video and audio files including download,
|
15 |
-
decryption, merging, and cleanup.
|
16 |
-
|
17 |
-
Attributes:
|
18 |
-
id (str): Identifier for the process.
|
19 |
-
name (str): Name for the process. Defaults to the value of `id`.
|
20 |
-
directory (str): Directory to store the files. Defaults to "./".
|
21 |
-
tmpDir (str): Temporary directory for intermediate files. Defaults to './tmp/'.
|
22 |
-
vsdPath (str): Path to the vsd binary. Defaults to 'vsd'.
|
23 |
-
ffmpeg (str): Path to the ffmpeg binary. Defaults to 'ffmpeg'.
|
24 |
-
mp4d (str): Path to the mp4decrypt binary. Defaults to 'mp4decrypt'.
|
25 |
-
token (str): Auth Token for the process.
|
26 |
-
verbose (bool): Flag for verbose output. Defaults to True.
|
27 |
-
suppress_exit (bool): Flag to suppress exit on error. Defaults to False.
|
28 |
-
progress_callback (function): Callback function to report progress. Defaults to None.
|
29 |
-
"""
|
30 |
-
|
31 |
-
def __init__(self,
|
32 |
-
id,
|
33 |
-
name=None,
|
34 |
-
directory="./",
|
35 |
-
tmpDir="/*auto*/",
|
36 |
-
vsdPath='nm3',
|
37 |
-
ffmpeg="ffmpeg",
|
38 |
-
mp4d="mp4decrypt",
|
39 |
-
token=None, verbose=True, suppress_exit=False, progress_callback=None):
|
40 |
-
|
41 |
-
os2 = SysFunc()
|
42 |
-
|
43 |
-
self.id = id
|
44 |
-
self.name = name if name else id
|
45 |
-
self.directory = directory
|
46 |
-
self.tmpDir = BasicUtils.abspath(tmpDir) if tmpDir != '/*auto*/' else BasicUtils.abspath('./tmp/')
|
47 |
-
|
48 |
-
# Create tmp directory if it does not exist
|
49 |
-
os2.create_dir(self.tmpDir, verbose=verbose)
|
50 |
-
|
51 |
-
self.vsd = vsdPath if vsdPath != 'vsd' else 'vsd'
|
52 |
-
self.ffmpeg = BasicUtils.abspath(ffmpeg) if ffmpeg != 'ffmpeg' else 'ffmpeg'
|
53 |
-
self.mp4d = BasicUtils.abspath(mp4d) if mp4d != 'mp4decrypt' else 'mp4decrypt'
|
54 |
-
self.token = token
|
55 |
-
self.verbose = verbose
|
56 |
-
self.suppress_exit = suppress_exit
|
57 |
-
self.progress_callback = progress_callback
|
58 |
-
|
59 |
-
def process(self):
|
60 |
-
"""
|
61 |
-
Main processing function to handle downloading, decrypting, merging, and cleanup of files.
|
62 |
-
"""
|
63 |
-
|
64 |
-
if self.verbose:
|
65 |
-
Global.dprint("Starting Main Process... for ID: " + self.id)
|
66 |
-
|
67 |
-
# 1. Downloading Files (New Download Method using VSD)
|
68 |
-
|
69 |
-
audio, video = Download(self.vsd,
|
70 |
-
Download.buildUrl(self.id),
|
71 |
-
self.name,
|
72 |
-
self.tmpDir,
|
73 |
-
self.directory,
|
74 |
-
progress_callback=self.progress_callback).download()
|
75 |
-
Global.sprint("\nDownload completed.")
|
76 |
-
if self.verbose: Global.sprint(f"Audio: {audio}\nVideo: {video}")
|
77 |
-
|
78 |
-
# 2. Decrypting Files
|
79 |
-
|
80 |
-
Global.sprint("Please wait while we decrypt the files...\nFetching key may take some time.")
|
81 |
-
|
82 |
-
TOKEN = self.token
|
83 |
-
fetcher = LicenseKeyFetcher(TOKEN)
|
84 |
-
key = fetcher.get_key(self.id, verbose=self.verbose)[1]
|
85 |
-
|
86 |
-
decrypt = Decrypt()
|
87 |
-
|
88 |
-
decrypt.decryptAudio(self.directory, f'{self.name}-Audio-enc', key, mp4d=self.mp4d, outfile=self.name,
|
89 |
-
verbose=self.verbose, suppress_exit=self.suppress_exit)
|
90 |
-
decrypt.decryptVideo(self.directory, f'{self.name}-Video-enc', key, mp4d=self.mp4d, outfile=self.name,
|
91 |
-
verbose=self.verbose, suppress_exit=self.suppress_exit)
|
92 |
-
|
93 |
-
# Call the progress callback for decryption completion
|
94 |
-
if self.progress_callback:
|
95 |
-
self.progress_callback({
|
96 |
-
"progress": 90,
|
97 |
-
"str": "decryption-completed",
|
98 |
-
"next": "merging"
|
99 |
-
})
|
100 |
-
|
101 |
-
# 3. Merging Files
|
102 |
-
|
103 |
-
merge = Merge()
|
104 |
-
merge.ffmpegMerge(f"{self.directory}/{self.name}-Video.mp4",
|
105 |
-
f"{self.directory}/{self.name}-Audio.mp4",
|
106 |
-
f"{self.directory}/{self.name}.mp4",
|
107 |
-
ffmpeg_path=self.ffmpeg, verbose=self.verbose)
|
108 |
-
|
109 |
-
# Call the progress callback for merge completion
|
110 |
-
if self.progress_callback:
|
111 |
-
self.progress_callback({
|
112 |
-
"progress": 99,
|
113 |
-
"str": "merge-completed",
|
114 |
-
"next": "cleanup"
|
115 |
-
})
|
116 |
-
|
117 |
-
# 4. Cleanup
|
118 |
-
clean = Clean()
|
119 |
-
clean.remove(self.directory, f'{self.name}', self.verbose)
|
120 |
-
|
121 |
-
if self.progress_callback:
|
122 |
-
self.progress_callback({
|
123 |
-
"progress": 100,
|
124 |
-
"str": "cleanup-completed",
|
125 |
-
"next": "done"
|
126 |
-
})
|
|
|
1 |
+
from mainLogic.utils.basicUtils import BasicUtils
|
2 |
+
from mainLogic.utils.os2 import SysFunc
|
3 |
+
from mainLogic.utils.glv import Global
|
4 |
+
from mainLogic.big4.cleanup import Clean
|
5 |
+
from mainLogic.big4.decrypt.key import LicenseKeyFetcher
|
6 |
+
from mainLogic.big4.downloadv2 import Download
|
7 |
+
from mainLogic.big4.decrypt.decrypt import Decrypt
|
8 |
+
from mainLogic.big4.merge import Merge
|
9 |
+
import os
|
10 |
+
|
11 |
+
|
12 |
+
class Main:
|
13 |
+
"""
|
14 |
+
Main class to handle the processing of video and audio files including download,
|
15 |
+
decryption, merging, and cleanup.
|
16 |
+
|
17 |
+
Attributes:
|
18 |
+
id (str): Identifier for the process.
|
19 |
+
name (str): Name for the process. Defaults to the value of `id`.
|
20 |
+
directory (str): Directory to store the files. Defaults to "./".
|
21 |
+
tmpDir (str): Temporary directory for intermediate files. Defaults to './tmp/'.
|
22 |
+
vsdPath (str): Path to the vsd binary. Defaults to 'vsd'.
|
23 |
+
ffmpeg (str): Path to the ffmpeg binary. Defaults to 'ffmpeg'.
|
24 |
+
mp4d (str): Path to the mp4decrypt binary. Defaults to 'mp4decrypt'.
|
25 |
+
token (str): Auth Token for the process.
|
26 |
+
verbose (bool): Flag for verbose output. Defaults to True.
|
27 |
+
suppress_exit (bool): Flag to suppress exit on error. Defaults to False.
|
28 |
+
progress_callback (function): Callback function to report progress. Defaults to None.
|
29 |
+
"""
|
30 |
+
|
31 |
+
def __init__(self,
|
32 |
+
id,
|
33 |
+
name=None,
|
34 |
+
directory="./",
|
35 |
+
tmpDir="/*auto*/",
|
36 |
+
vsdPath='nm3',
|
37 |
+
ffmpeg="ffmpeg",
|
38 |
+
mp4d="mp4decrypt",
|
39 |
+
token=None, verbose=True, suppress_exit=False, progress_callback=None):
|
40 |
+
|
41 |
+
os2 = SysFunc()
|
42 |
+
|
43 |
+
self.id = id
|
44 |
+
self.name = name if name else id
|
45 |
+
self.directory = directory
|
46 |
+
self.tmpDir = BasicUtils.abspath(tmpDir) if tmpDir != '/*auto*/' else BasicUtils.abspath('./tmp/')
|
47 |
+
|
48 |
+
# Create tmp directory if it does not exist
|
49 |
+
os2.create_dir(self.tmpDir, verbose=verbose)
|
50 |
+
|
51 |
+
self.vsd = vsdPath if vsdPath != 'vsd' else 'vsd'
|
52 |
+
self.ffmpeg = BasicUtils.abspath(ffmpeg) if ffmpeg != 'ffmpeg' else 'ffmpeg'
|
53 |
+
self.mp4d = BasicUtils.abspath(mp4d) if mp4d != 'mp4decrypt' else 'mp4decrypt'
|
54 |
+
self.token = token
|
55 |
+
self.verbose = verbose
|
56 |
+
self.suppress_exit = suppress_exit
|
57 |
+
self.progress_callback = progress_callback
|
58 |
+
|
59 |
+
def process(self):
|
60 |
+
"""
|
61 |
+
Main processing function to handle downloading, decrypting, merging, and cleanup of files.
|
62 |
+
"""
|
63 |
+
|
64 |
+
if self.verbose:
|
65 |
+
Global.dprint("Starting Main Process... for ID: " + self.id)
|
66 |
+
|
67 |
+
# 1. Downloading Files (New Download Method using VSD)
|
68 |
+
|
69 |
+
audio, video = Download(self.vsd,
|
70 |
+
Download.buildUrl(self.id),
|
71 |
+
self.name,
|
72 |
+
self.tmpDir,
|
73 |
+
self.directory,
|
74 |
+
progress_callback=self.progress_callback).download()
|
75 |
+
Global.sprint("\nDownload completed.")
|
76 |
+
if self.verbose: Global.sprint(f"Audio: {audio}\nVideo: {video}")
|
77 |
+
|
78 |
+
# 2. Decrypting Files
|
79 |
+
|
80 |
+
Global.sprint("Please wait while we decrypt the files...\nFetching key may take some time.")
|
81 |
+
|
82 |
+
TOKEN = self.token
|
83 |
+
fetcher = LicenseKeyFetcher(TOKEN)
|
84 |
+
key = fetcher.get_key(self.id, verbose=self.verbose)[1]
|
85 |
+
|
86 |
+
decrypt = Decrypt()
|
87 |
+
|
88 |
+
decrypt.decryptAudio(self.directory, f'{self.name}-Audio-enc', key, mp4d=self.mp4d, outfile=self.name,
|
89 |
+
verbose=self.verbose, suppress_exit=self.suppress_exit)
|
90 |
+
decrypt.decryptVideo(self.directory, f'{self.name}-Video-enc', key, mp4d=self.mp4d, outfile=self.name,
|
91 |
+
verbose=self.verbose, suppress_exit=self.suppress_exit)
|
92 |
+
|
93 |
+
# Call the progress callback for decryption completion
|
94 |
+
if self.progress_callback:
|
95 |
+
self.progress_callback({
|
96 |
+
"progress": 90,
|
97 |
+
"str": "decryption-completed",
|
98 |
+
"next": "merging"
|
99 |
+
})
|
100 |
+
|
101 |
+
# 3. Merging Files
|
102 |
+
|
103 |
+
merge = Merge()
|
104 |
+
merge.ffmpegMerge(f"{self.directory}/{self.name}-Video.mp4",
|
105 |
+
f"{self.directory}/{self.name}-Audio.mp4",
|
106 |
+
f"{self.directory}/{self.name}.mp4",
|
107 |
+
ffmpeg_path=self.ffmpeg, verbose=self.verbose)
|
108 |
+
|
109 |
+
# Call the progress callback for merge completion
|
110 |
+
if self.progress_callback:
|
111 |
+
self.progress_callback({
|
112 |
+
"progress": 99,
|
113 |
+
"str": "merge-completed",
|
114 |
+
"next": "cleanup"
|
115 |
+
})
|
116 |
+
|
117 |
+
# 4. Cleanup
|
118 |
+
clean = Clean()
|
119 |
+
clean.remove(self.directory, f'{self.name}', self.verbose)
|
120 |
+
|
121 |
+
if self.progress_callback:
|
122 |
+
self.progress_callback({
|
123 |
+
"progress": 100,
|
124 |
+
"str": "cleanup-completed",
|
125 |
+
"next": "done"
|
126 |
+
})
|
mainLogic/startup/checkup.py
CHANGED
@@ -1,200 +1,200 @@
|
|
1 |
-
from mainLogic import error
|
2 |
-
import os
|
3 |
-
from mainLogic.utils.os2 import SysFunc
|
4 |
-
from mainLogic.utils.glv import Global
|
5 |
-
|
6 |
-
class CheckState:
|
7 |
-
|
8 |
-
def __init__(self) -> None:
|
9 |
-
pass
|
10 |
-
|
11 |
-
def post_checkup(self,prefs,verbose=True):
|
12 |
-
|
13 |
-
"""
|
14 |
-
Post Checkup Function
|
15 |
-
1. Setting up the tmpDir
|
16 |
-
2. Setting up the output directory
|
17 |
-
3. Setting up the horizontal rule
|
18 |
-
"""
|
19 |
-
|
20 |
-
OUT_DIRECTORY = ""
|
21 |
-
|
22 |
-
# setting up prefs
|
23 |
-
if 'tmpDir' in prefs:
|
24 |
-
tmpDir = SysFunc.modify_path(prefs['tmpDir'])
|
25 |
-
if not os.path.exists(tmpDir):
|
26 |
-
try:
|
27 |
-
os.makedirs(tmpDir)
|
28 |
-
except OSError as exc: # Guard against failure
|
29 |
-
error.errorList["couldNotMakeDir"]['func'](tmpDir)
|
30 |
-
Global.errprint("Failed to create TmpDir")
|
31 |
-
Global.errprint("Falling Back to Default")
|
32 |
-
else:
|
33 |
-
tmpDir = './tmp/'
|
34 |
-
|
35 |
-
# setting up directory for pwdl
|
36 |
-
if "dir" in prefs:
|
37 |
-
try:
|
38 |
-
if not os.path.exists(os.path.expandvars(prefs['dir'])):
|
39 |
-
try:
|
40 |
-
os.makedirs(os.path.expandvars(prefs['dir']))
|
41 |
-
except OSError as exc:
|
42 |
-
error.errorList["couldNotMakeDir"]['func'](os.path.expandvars(prefs['dir']))
|
43 |
-
Global.errprint("Failed to create Output Directory")
|
44 |
-
Global.errprint("Falling Back to Default")
|
45 |
-
except TypeError:
|
46 |
-
pass
|
47 |
-
except Exception as e:
|
48 |
-
Global.errprint(f"Error: {e}")
|
49 |
-
Global.errprint("Falling back to default")
|
50 |
-
OUT_DIRECTORY = './'
|
51 |
-
|
52 |
-
try: OUT_DIRECTORY = os.path.abspath(os.path.expandvars(prefs['dir']))
|
53 |
-
|
54 |
-
# if the user provides a non-string value for the directory or dir is not found
|
55 |
-
except TypeError: OUT_DIRECTORY = './'
|
56 |
-
|
57 |
-
# if the directory is not found
|
58 |
-
except Exception as e:
|
59 |
-
Global.errprint(f"Error: {e}")
|
60 |
-
Global.errprint("Falling back to default")
|
61 |
-
OUT_DIRECTORY = './'
|
62 |
-
else:
|
63 |
-
OUT_DIRECTORY = './'
|
64 |
-
|
65 |
-
# setting up hr (horizontal rule)
|
66 |
-
if not 'hr' in prefs:
|
67 |
-
Global.disable_hr = False
|
68 |
-
elif not prefs['hr']:
|
69 |
-
Global.disable_hr = True
|
70 |
-
|
71 |
-
prefs['tmpDir'] = tmpDir
|
72 |
-
prefs['dir'] = OUT_DIRECTORY
|
73 |
-
|
74 |
-
|
75 |
-
def check_token(self,token,id="90dbede8-66a8-40e8-82ce-a2048b5c063d",verbose=False):
|
76 |
-
from mainLogic.big4.decrypt.key import LicenseKeyFetcher
|
77 |
-
lc_fetcher = LicenseKeyFetcher(token)
|
78 |
-
try:
|
79 |
-
key = lc_fetcher.get_key(id,verbose=verbose)
|
80 |
-
return key
|
81 |
-
except Exception as e:
|
82 |
-
Global.errprint(f"An error occurred while getting the key: {e}")
|
83 |
-
Global.errprint("Your Token is Invalid! ")
|
84 |
-
return None
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
def checkup(self,executable,directory="./",verbose=True):
|
89 |
-
|
90 |
-
state = {}
|
91 |
-
|
92 |
-
# set script path to ../startup
|
93 |
-
# this is the path to the folder containing the pwdl.py file
|
94 |
-
# since the checkup.py is in the startup folder, we need to go one level up
|
95 |
-
# if verbose: Global.hr();Global.dprint("Setting script path...")
|
96 |
-
# if verbose: Global.errprint('Warning! Hard Coded \'$script\' location to checkup.py/../../')
|
97 |
-
#
|
98 |
-
# Global.script_path = os.path.abspath(os.path.join(os.path.dirname(__file__),'../..'))
|
99 |
-
# default_json = os.path.join(Global.script_path,'defaults.json')
|
100 |
-
#
|
101 |
-
# # check if defaults.json exists
|
102 |
-
# # and if it does, load the preferences
|
103 |
-
# if verbose: Global.hr();Global.dprint("Checking for default settings...")
|
104 |
-
#
|
105 |
-
# if verbose: Global.hr();Global.dprint(f"Checking at {default_json}")
|
106 |
-
# if verbose: Global.errprint('Warning!\nHard Coded \'defaults.json\' location to $script/default.json ')
|
107 |
-
#
|
108 |
-
# if not os.path.exists(default_json):
|
109 |
-
# error.errorList["defaultsNotFound"]["func"]()
|
110 |
-
# exit(error.errorList["defaultsNotFound"]["code"])
|
111 |
-
#
|
112 |
-
# if verbose: Global.sprint("Default settings found."); Global.hr()
|
113 |
-
|
114 |
-
# load the preferences
|
115 |
-
from mainLogic.startup.userPrefs import PreferencesLoader
|
116 |
-
prefs = PreferencesLoader(verbose=verbose).prefs
|
117 |
-
|
118 |
-
# check if method is patched (currently via userPrefs.py)
|
119 |
-
if 'patched' in prefs:
|
120 |
-
if prefs['patched']:
|
121 |
-
error.errorList["methodPatched"]["func"]()
|
122 |
-
exit(error.errorList["methodPatched"]["code"])
|
123 |
-
|
124 |
-
# FLare no longer required
|
125 |
-
# if verbose: Global.hr(); Global.dprint("Checking for Flare...")
|
126 |
-
# default url is localhost:8191
|
127 |
-
# however user can change it in the preferences file
|
128 |
-
# if verbose: Global.dprint(f"Checking at {prefs['flare_url'] if 'flare_url' in prefs else 'http://localhost:8191/v1'}")
|
129 |
-
# if not checkFlare(prefs['flare_url'] if 'flare_url' in prefs else 'http://localhost:8191/v1'):
|
130 |
-
# error.errorList["flareNotStarted"]["func"]()
|
131 |
-
# exit(error.errorList["flareNotStarted"]["code"])
|
132 |
-
#
|
133 |
-
# if verbose: Global.sprint("Flare is running."); Global.hr()
|
134 |
-
|
135 |
-
os2 = SysFunc()
|
136 |
-
|
137 |
-
found= []
|
138 |
-
notFound = []
|
139 |
-
|
140 |
-
for exe in executable:
|
141 |
-
if verbose: Global.hr(); Global.dprint(f"Checking for {exe}...")
|
142 |
-
|
143 |
-
if os2.which(exe) == 1:
|
144 |
-
if verbose: error.errorList["dependencyNotFound"]["func"](exe)
|
145 |
-
if verbose: print(f"{exe} not found on path! Checking in default settings...")
|
146 |
-
|
147 |
-
# add exe's which are found to the found list
|
148 |
-
found.append(exe)
|
149 |
-
# add exe's which are not found to the notFound list
|
150 |
-
notFound.append(exe)
|
151 |
-
|
152 |
-
else:
|
153 |
-
if verbose: Global.sprint(f"{exe} found.")
|
154 |
-
state[exe] = exe
|
155 |
-
|
156 |
-
if len(notFound) > 0:
|
157 |
-
|
158 |
-
if verbose: Global.hr();Global.dprint("Following dependencies were not found on path. Checking in default settings...")
|
159 |
-
if verbose: Global.dprint(notFound); Global.hr()
|
160 |
-
|
161 |
-
for exe in notFound:
|
162 |
-
|
163 |
-
if verbose: Global.dprint(f"Checking for {exe} in default settings...")
|
164 |
-
|
165 |
-
if exe in prefs:
|
166 |
-
|
167 |
-
if verbose: Global.sprint(f"Key for {exe} found in default settings.")
|
168 |
-
if verbose: Global.sprint(f"Value: {prefs[exe]}")
|
169 |
-
if verbose: Global.dprint(f"Checking for {exe} at '{prefs[exe].strip()}' ...")
|
170 |
-
|
171 |
-
if not os.path.exists(prefs[exe].strip()):
|
172 |
-
Global.errprint(f"{exe} not found at {prefs[exe].strip()}")
|
173 |
-
error.errorList["dependencyNotFoundInPrefs"]["func"](exe)
|
174 |
-
exit(error.errorList["dependencyNotFoundInPrefs"]["code"])
|
175 |
-
|
176 |
-
if verbose: Global.sprint(f"{exe} found at {prefs[exe].strip()}")
|
177 |
-
state[exe] = prefs[exe].strip()
|
178 |
-
|
179 |
-
|
180 |
-
else:
|
181 |
-
error.errorList["dependencyNotFoundInPrefs"]["func"](exe)
|
182 |
-
exit(error.errorList["dependencyNotFoundInPrefs"]["code"])
|
183 |
-
|
184 |
-
if verbose: Global.hr()
|
185 |
-
|
186 |
-
# checking for token
|
187 |
-
if 'token' in prefs:
|
188 |
-
self.check_token(prefs['token'],verbose=verbose)
|
189 |
-
else:
|
190 |
-
error.errorList["tokenNotFound"]["func"]()
|
191 |
-
exit(error.errorList["tokenNotFound"]["code"])
|
192 |
-
|
193 |
-
state['prefs'] = prefs
|
194 |
-
prefs['dir'] = directory
|
195 |
-
self.post_checkup(prefs,verbose)
|
196 |
-
|
197 |
-
|
198 |
-
return state
|
199 |
-
|
200 |
-
|
|
|
1 |
+
from mainLogic import error
|
2 |
+
import os
|
3 |
+
from mainLogic.utils.os2 import SysFunc
|
4 |
+
from mainLogic.utils.glv import Global
|
5 |
+
|
6 |
+
class CheckState:
|
7 |
+
|
8 |
+
def __init__(self) -> None:
|
9 |
+
pass
|
10 |
+
|
11 |
+
def post_checkup(self,prefs,verbose=True):
|
12 |
+
|
13 |
+
"""
|
14 |
+
Post Checkup Function
|
15 |
+
1. Setting up the tmpDir
|
16 |
+
2. Setting up the output directory
|
17 |
+
3. Setting up the horizontal rule
|
18 |
+
"""
|
19 |
+
|
20 |
+
OUT_DIRECTORY = ""
|
21 |
+
|
22 |
+
# setting up prefs
|
23 |
+
if 'tmpDir' in prefs:
|
24 |
+
tmpDir = SysFunc.modify_path(prefs['tmpDir'])
|
25 |
+
if not os.path.exists(tmpDir):
|
26 |
+
try:
|
27 |
+
os.makedirs(tmpDir)
|
28 |
+
except OSError as exc: # Guard against failure
|
29 |
+
error.errorList["couldNotMakeDir"]['func'](tmpDir)
|
30 |
+
Global.errprint("Failed to create TmpDir")
|
31 |
+
Global.errprint("Falling Back to Default")
|
32 |
+
else:
|
33 |
+
tmpDir = './tmp/'
|
34 |
+
|
35 |
+
# setting up directory for pwdl
|
36 |
+
if "dir" in prefs:
|
37 |
+
try:
|
38 |
+
if not os.path.exists(os.path.expandvars(prefs['dir'])):
|
39 |
+
try:
|
40 |
+
os.makedirs(os.path.expandvars(prefs['dir']))
|
41 |
+
except OSError as exc:
|
42 |
+
error.errorList["couldNotMakeDir"]['func'](os.path.expandvars(prefs['dir']))
|
43 |
+
Global.errprint("Failed to create Output Directory")
|
44 |
+
Global.errprint("Falling Back to Default")
|
45 |
+
except TypeError:
|
46 |
+
pass
|
47 |
+
except Exception as e:
|
48 |
+
Global.errprint(f"Error: {e}")
|
49 |
+
Global.errprint("Falling back to default")
|
50 |
+
OUT_DIRECTORY = './'
|
51 |
+
|
52 |
+
try: OUT_DIRECTORY = os.path.abspath(os.path.expandvars(prefs['dir']))
|
53 |
+
|
54 |
+
# if the user provides a non-string value for the directory or dir is not found
|
55 |
+
except TypeError: OUT_DIRECTORY = './'
|
56 |
+
|
57 |
+
# if the directory is not found
|
58 |
+
except Exception as e:
|
59 |
+
Global.errprint(f"Error: {e}")
|
60 |
+
Global.errprint("Falling back to default")
|
61 |
+
OUT_DIRECTORY = './'
|
62 |
+
else:
|
63 |
+
OUT_DIRECTORY = './'
|
64 |
+
|
65 |
+
# setting up hr (horizontal rule)
|
66 |
+
if not 'hr' in prefs:
|
67 |
+
Global.disable_hr = False
|
68 |
+
elif not prefs['hr']:
|
69 |
+
Global.disable_hr = True
|
70 |
+
|
71 |
+
prefs['tmpDir'] = tmpDir
|
72 |
+
prefs['dir'] = OUT_DIRECTORY
|
73 |
+
|
74 |
+
|
75 |
+
def check_token(self,token,id="90dbede8-66a8-40e8-82ce-a2048b5c063d",verbose=False):
|
76 |
+
from mainLogic.big4.decrypt.key import LicenseKeyFetcher
|
77 |
+
lc_fetcher = LicenseKeyFetcher(token)
|
78 |
+
try:
|
79 |
+
key = lc_fetcher.get_key(id,verbose=verbose)
|
80 |
+
return key
|
81 |
+
except Exception as e:
|
82 |
+
Global.errprint(f"An error occurred while getting the key: {e}")
|
83 |
+
Global.errprint("Your Token is Invalid! ")
|
84 |
+
return None
|
85 |
+
|
86 |
+
|
87 |
+
|
88 |
+
def checkup(self,executable,directory="./",verbose=True):
|
89 |
+
|
90 |
+
state = {}
|
91 |
+
|
92 |
+
# set script path to ../startup
|
93 |
+
# this is the path to the folder containing the pwdl.py file
|
94 |
+
# since the checkup.py is in the startup folder, we need to go one level up
|
95 |
+
# if verbose: Global.hr();Global.dprint("Setting script path...")
|
96 |
+
# if verbose: Global.errprint('Warning! Hard Coded \'$script\' location to checkup.py/../../')
|
97 |
+
#
|
98 |
+
# Global.script_path = os.path.abspath(os.path.join(os.path.dirname(__file__),'../..'))
|
99 |
+
# default_json = os.path.join(Global.script_path,'defaults.json')
|
100 |
+
#
|
101 |
+
# # check if defaults.json exists
|
102 |
+
# # and if it does, load the preferences
|
103 |
+
# if verbose: Global.hr();Global.dprint("Checking for default settings...")
|
104 |
+
#
|
105 |
+
# if verbose: Global.hr();Global.dprint(f"Checking at {default_json}")
|
106 |
+
# if verbose: Global.errprint('Warning!\nHard Coded \'defaults.json\' location to $script/default.json ')
|
107 |
+
#
|
108 |
+
# if not os.path.exists(default_json):
|
109 |
+
# error.errorList["defaultsNotFound"]["func"]()
|
110 |
+
# exit(error.errorList["defaultsNotFound"]["code"])
|
111 |
+
#
|
112 |
+
# if verbose: Global.sprint("Default settings found."); Global.hr()
|
113 |
+
|
114 |
+
# load the preferences
|
115 |
+
from mainLogic.startup.userPrefs import PreferencesLoader
|
116 |
+
prefs = PreferencesLoader(verbose=verbose).prefs
|
117 |
+
|
118 |
+
# check if method is patched (currently via userPrefs.py)
|
119 |
+
if 'patched' in prefs:
|
120 |
+
if prefs['patched']:
|
121 |
+
error.errorList["methodPatched"]["func"]()
|
122 |
+
exit(error.errorList["methodPatched"]["code"])
|
123 |
+
|
124 |
+
# FLare no longer required
|
125 |
+
# if verbose: Global.hr(); Global.dprint("Checking for Flare...")
|
126 |
+
# default url is localhost:8191
|
127 |
+
# however user can change it in the preferences file
|
128 |
+
# if verbose: Global.dprint(f"Checking at {prefs['flare_url'] if 'flare_url' in prefs else 'http://localhost:8191/v1'}")
|
129 |
+
# if not checkFlare(prefs['flare_url'] if 'flare_url' in prefs else 'http://localhost:8191/v1'):
|
130 |
+
# error.errorList["flareNotStarted"]["func"]()
|
131 |
+
# exit(error.errorList["flareNotStarted"]["code"])
|
132 |
+
#
|
133 |
+
# if verbose: Global.sprint("Flare is running."); Global.hr()
|
134 |
+
|
135 |
+
os2 = SysFunc()
|
136 |
+
|
137 |
+
found= []
|
138 |
+
notFound = []
|
139 |
+
|
140 |
+
for exe in executable:
|
141 |
+
if verbose: Global.hr(); Global.dprint(f"Checking for {exe}...")
|
142 |
+
|
143 |
+
if os2.which(exe) == 1:
|
144 |
+
if verbose: error.errorList["dependencyNotFound"]["func"](exe)
|
145 |
+
if verbose: print(f"{exe} not found on path! Checking in default settings...")
|
146 |
+
|
147 |
+
# add exe's which are found to the found list
|
148 |
+
found.append(exe)
|
149 |
+
# add exe's which are not found to the notFound list
|
150 |
+
notFound.append(exe)
|
151 |
+
|
152 |
+
else:
|
153 |
+
if verbose: Global.sprint(f"{exe} found.")
|
154 |
+
state[exe] = exe
|
155 |
+
|
156 |
+
if len(notFound) > 0:
|
157 |
+
|
158 |
+
if verbose: Global.hr();Global.dprint("Following dependencies were not found on path. Checking in default settings...")
|
159 |
+
if verbose: Global.dprint(notFound); Global.hr()
|
160 |
+
|
161 |
+
for exe in notFound:
|
162 |
+
|
163 |
+
if verbose: Global.dprint(f"Checking for {exe} in default settings...")
|
164 |
+
|
165 |
+
if exe in prefs:
|
166 |
+
|
167 |
+
if verbose: Global.sprint(f"Key for {exe} found in default settings.")
|
168 |
+
if verbose: Global.sprint(f"Value: {prefs[exe]}")
|
169 |
+
if verbose: Global.dprint(f"Checking for {exe} at '{prefs[exe].strip()}' ...")
|
170 |
+
|
171 |
+
if not os.path.exists(prefs[exe].strip()):
|
172 |
+
Global.errprint(f"{exe} not found at {prefs[exe].strip()}")
|
173 |
+
error.errorList["dependencyNotFoundInPrefs"]["func"](exe)
|
174 |
+
exit(error.errorList["dependencyNotFoundInPrefs"]["code"])
|
175 |
+
|
176 |
+
if verbose: Global.sprint(f"{exe} found at {prefs[exe].strip()}")
|
177 |
+
state[exe] = prefs[exe].strip()
|
178 |
+
|
179 |
+
|
180 |
+
else:
|
181 |
+
error.errorList["dependencyNotFoundInPrefs"]["func"](exe)
|
182 |
+
exit(error.errorList["dependencyNotFoundInPrefs"]["code"])
|
183 |
+
|
184 |
+
if verbose: Global.hr()
|
185 |
+
|
186 |
+
# checking for token
|
187 |
+
if 'token' in prefs:
|
188 |
+
self.check_token(prefs['token'],verbose=verbose)
|
189 |
+
else:
|
190 |
+
error.errorList["tokenNotFound"]["func"]()
|
191 |
+
exit(error.errorList["tokenNotFound"]["code"])
|
192 |
+
|
193 |
+
state['prefs'] = prefs
|
194 |
+
prefs['dir'] = directory
|
195 |
+
self.post_checkup(prefs,verbose)
|
196 |
+
|
197 |
+
|
198 |
+
return state
|
199 |
+
|
200 |
+
|
mainLogic/startup/flareCheck.py
CHANGED
@@ -1,17 +1,17 @@
|
|
1 |
-
import requests
|
2 |
-
|
3 |
-
def checkFlare(flareUrl="http://localhost:8191/v1"):
|
4 |
-
|
5 |
-
url = f"{flareUrl}"
|
6 |
-
headers = {"Content-Type": "application/json"}
|
7 |
-
data = {
|
8 |
-
"cmd": "request.get",
|
9 |
-
"url": "http://www.google.com/",
|
10 |
-
"maxTimeout": 60000
|
11 |
-
}
|
12 |
-
try:
|
13 |
-
response = requests.post(url, headers=headers, json=data)
|
14 |
-
return response.ok
|
15 |
-
except Exception as e:
|
16 |
-
return False
|
17 |
-
|
|
|
1 |
+
import requests
|
2 |
+
|
3 |
+
def checkFlare(flareUrl="http://localhost:8191/v1"):
|
4 |
+
|
5 |
+
url = f"{flareUrl}"
|
6 |
+
headers = {"Content-Type": "application/json"}
|
7 |
+
data = {
|
8 |
+
"cmd": "request.get",
|
9 |
+
"url": "http://www.google.com/",
|
10 |
+
"maxTimeout": 60000
|
11 |
+
}
|
12 |
+
try:
|
13 |
+
response = requests.post(url, headers=headers, json=data)
|
14 |
+
return response.ok
|
15 |
+
except Exception as e:
|
16 |
+
return False
|
17 |
+
|
mainLogic/startup/userPrefs.py
CHANGED
@@ -1,58 +1,58 @@
|
|
1 |
-
import json
|
2 |
-
from mainLogic import error
|
3 |
-
import os
|
4 |
-
from mainLogic.utils.glv_var import vars, PREFS_FILE as pf
|
5 |
-
|
6 |
-
PREFS_FILE = pf
|
7 |
-
|
8 |
-
class PreferencesLoader:
|
9 |
-
|
10 |
-
def __init__(self, file_name=None, verbose=True):
|
11 |
-
global PREFS_FILE
|
12 |
-
self.file_name = file_name
|
13 |
-
self.prefs = {}
|
14 |
-
|
15 |
-
if file_name:
|
16 |
-
if os.path.exists(file_name):
|
17 |
-
PREFS_FILE = file_name
|
18 |
-
|
19 |
-
|
20 |
-
if verbose:
|
21 |
-
print(f"Warning! Hard Coded '$script' location to {vars['$script']}")
|
22 |
-
print(f"goes to userPrefs.py/..(mainLogic)/..(pwdlv3)/pwdl.py")
|
23 |
-
|
24 |
-
self.file_name = PREFS_FILE
|
25 |
-
|
26 |
-
|
27 |
-
self.load_preferences()
|
28 |
-
|
29 |
-
# if verbose is true, print the preferences
|
30 |
-
if verbose:
|
31 |
-
self.print_preferences()
|
32 |
-
|
33 |
-
def load_preferences(self):
|
34 |
-
try:
|
35 |
-
|
36 |
-
with open(self.file_name, 'r') as json_file:
|
37 |
-
|
38 |
-
# read the contents of the file (so that we can replace the variables with their values)
|
39 |
-
contents = json_file.read()
|
40 |
-
|
41 |
-
# replace the variables with their values
|
42 |
-
for var in vars:
|
43 |
-
contents = contents.replace(var, vars[var])
|
44 |
-
|
45 |
-
# replace the backslashes with forward slashes
|
46 |
-
contents.replace('\\', '/')
|
47 |
-
|
48 |
-
self.prefs = json.loads(contents)
|
49 |
-
|
50 |
-
# if the file is not found, print an error message and exit
|
51 |
-
except FileNotFoundError:
|
52 |
-
error.errorList["cantLoadFile"]["func"](self.file_name)
|
53 |
-
exit(error.errorList["cantLoadFile"]["code"])
|
54 |
-
|
55 |
-
# print the preferences (internal function)
|
56 |
-
def print_preferences(self):
|
57 |
-
for key in self.prefs:
|
58 |
-
print(f'{key} : {self.prefs[key]}')
|
|
|
1 |
+
import json
|
2 |
+
from mainLogic import error
|
3 |
+
import os
|
4 |
+
from mainLogic.utils.glv_var import vars, PREFS_FILE as pf
|
5 |
+
|
6 |
+
PREFS_FILE = pf
|
7 |
+
|
8 |
+
class PreferencesLoader:
|
9 |
+
|
10 |
+
def __init__(self, file_name=None, verbose=True):
|
11 |
+
global PREFS_FILE
|
12 |
+
self.file_name = file_name
|
13 |
+
self.prefs = {}
|
14 |
+
|
15 |
+
if file_name:
|
16 |
+
if os.path.exists(file_name):
|
17 |
+
PREFS_FILE = file_name
|
18 |
+
|
19 |
+
|
20 |
+
if verbose:
|
21 |
+
print(f"Warning! Hard Coded '$script' location to {vars['$script']}")
|
22 |
+
print(f"goes to userPrefs.py/..(mainLogic)/..(pwdlv3)/pwdl.py")
|
23 |
+
|
24 |
+
self.file_name = PREFS_FILE
|
25 |
+
|
26 |
+
|
27 |
+
self.load_preferences()
|
28 |
+
|
29 |
+
# if verbose is true, print the preferences
|
30 |
+
if verbose:
|
31 |
+
self.print_preferences()
|
32 |
+
|
33 |
+
def load_preferences(self):
|
34 |
+
try:
|
35 |
+
|
36 |
+
with open(self.file_name, 'r') as json_file:
|
37 |
+
|
38 |
+
# read the contents of the file (so that we can replace the variables with their values)
|
39 |
+
contents = json_file.read()
|
40 |
+
|
41 |
+
# replace the variables with their values
|
42 |
+
for var in vars:
|
43 |
+
contents = contents.replace(var, vars[var])
|
44 |
+
|
45 |
+
# replace the backslashes with forward slashes
|
46 |
+
contents.replace('\\', '/')
|
47 |
+
|
48 |
+
self.prefs = json.loads(contents)
|
49 |
+
|
50 |
+
# if the file is not found, print an error message and exit
|
51 |
+
except FileNotFoundError:
|
52 |
+
error.errorList["cantLoadFile"]["func"](self.file_name)
|
53 |
+
exit(error.errorList["cantLoadFile"]["code"])
|
54 |
+
|
55 |
+
# print the preferences (internal function)
|
56 |
+
def print_preferences(self):
|
57 |
+
for key in self.prefs:
|
58 |
+
print(f'{key} : {self.prefs[key]}')
|
mainLogic/utils/basicUtils.py
CHANGED
@@ -1,25 +1,25 @@
|
|
1 |
-
import os
|
2 |
-
|
3 |
-
class BasicUtils:
|
4 |
-
|
5 |
-
@staticmethod
|
6 |
-
def delete_old_files(directory, minutes):
|
7 |
-
"""
|
8 |
-
Delete files in the given directory which are older than the given number of minutes.
|
9 |
-
"""
|
10 |
-
import time
|
11 |
-
|
12 |
-
current_time = time.time()
|
13 |
-
|
14 |
-
for file in os.listdir(directory):
|
15 |
-
file_path = os.path.join(directory, file)
|
16 |
-
|
17 |
-
if os.path.isfile(file_path):
|
18 |
-
file_time = os.path.getmtime(file_path)
|
19 |
-
|
20 |
-
if current_time - file_time >= minutes * 60:
|
21 |
-
os.remove(file_path)
|
22 |
-
|
23 |
-
@staticmethod
|
24 |
-
def abspath(path):
|
25 |
-
return str(os.path.abspath(os.path.expandvars(path))).replace("\\", "/")
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
class BasicUtils:
|
4 |
+
|
5 |
+
@staticmethod
|
6 |
+
def delete_old_files(directory, minutes):
|
7 |
+
"""
|
8 |
+
Delete files in the given directory which are older than the given number of minutes.
|
9 |
+
"""
|
10 |
+
import time
|
11 |
+
|
12 |
+
current_time = time.time()
|
13 |
+
|
14 |
+
for file in os.listdir(directory):
|
15 |
+
file_path = os.path.join(directory, file)
|
16 |
+
|
17 |
+
if os.path.isfile(file_path):
|
18 |
+
file_time = os.path.getmtime(file_path)
|
19 |
+
|
20 |
+
if current_time - file_time >= minutes * 60:
|
21 |
+
os.remove(file_path)
|
22 |
+
|
23 |
+
@staticmethod
|
24 |
+
def abspath(path):
|
25 |
+
return str(os.path.abspath(os.path.expandvars(path))).replace("\\", "/")
|
mainLogic/utils/gen_utils.py
CHANGED
@@ -1,79 +1,79 @@
|
|
1 |
-
import os
|
2 |
-
import random
|
3 |
-
import re
|
4 |
-
import time
|
5 |
-
import requests
|
6 |
-
|
7 |
-
|
8 |
-
def setup_directory():
|
9 |
-
pass
|
10 |
-
|
11 |
-
|
12 |
-
def generate_safe_folder_name(folder_name: str) -> str:
|
13 |
-
"""
|
14 |
-
Generate a safe folder name by replacing spaces with underscores and removing special characters.
|
15 |
-
|
16 |
-
Parameters:
|
17 |
-
folder_name (str): The original folder name.
|
18 |
-
|
19 |
-
Returns:
|
20 |
-
str: The safe folder name.
|
21 |
-
"""
|
22 |
-
# Replace spaces with underscores
|
23 |
-
safe_name = folder_name.replace(' ', '_')
|
24 |
-
|
25 |
-
# Remove any characters that are not alphanumeric or underscores
|
26 |
-
safe_name = re.sub(r'[^a-zA-Z0-9_]', '', safe_name)
|
27 |
-
|
28 |
-
return safe_name
|
29 |
-
|
30 |
-
|
31 |
-
def delete_old_files(base_path, t):
|
32 |
-
"""
|
33 |
-
Delete all files in a folder structure /subfolder1/subfolder2/
|
34 |
-
that are older than 't' minutes.
|
35 |
-
|
36 |
-
Parameters:
|
37 |
-
- base_path (str): The base directory to start the search.
|
38 |
-
- t (int): The age threshold in minutes.
|
39 |
-
"""
|
40 |
-
# Convert the time 't' from minutes to seconds
|
41 |
-
age_threshold = t * 60
|
42 |
-
|
43 |
-
print(f"Deleting files older than {age_threshold} seconds")
|
44 |
-
|
45 |
-
current_time = time.time()
|
46 |
-
|
47 |
-
print(os.listdir(base_path))
|
48 |
-
|
49 |
-
# Walk through the directory
|
50 |
-
for subfolder1 in os.listdir(base_path):
|
51 |
-
subfolder1_path = os.path.join(base_path, subfolder1)
|
52 |
-
print('\t'+subfolder1_path)
|
53 |
-
if os.path.isdir(subfolder1_path):
|
54 |
-
for subfolder2 in os.listdir(subfolder1_path):
|
55 |
-
print('\t\t'+subfolder2)
|
56 |
-
subfolder2_path = os.path.join(subfolder1_path, subfolder2)
|
57 |
-
if os.path.isdir(subfolder2_path):
|
58 |
-
for root, dirs, files in os.walk(subfolder2_path):
|
59 |
-
for file in files:
|
60 |
-
file_path = os.path.join(root, file)
|
61 |
-
file_age = current_time - os.path.getmtime(file_path)
|
62 |
-
print(f"File: {file_path}, Age: {file_age}")
|
63 |
-
if int(file_age) > int(age_threshold):
|
64 |
-
os.remove(file_path)
|
65 |
-
print(f"Deleted: {file_path}")
|
66 |
-
|
67 |
-
|
68 |
-
def generate_random_word():
|
69 |
-
word_site = "https://www.mit.edu/~ecprice/wordlist.10000"
|
70 |
-
response = requests.get(word_site)
|
71 |
-
words = response.content.splitlines()
|
72 |
-
|
73 |
-
int1 = random.randint(0, len(words) - 1)
|
74 |
-
int2 = random.randint(0, len(words) - 1)
|
75 |
-
|
76 |
-
word1 = words[int1].decode("utf-8")
|
77 |
-
word2 = words[int2].decode("utf-8")
|
78 |
-
|
79 |
-
return f"{word1}-{word2}"
|
|
|
1 |
+
import os
|
2 |
+
import random
|
3 |
+
import re
|
4 |
+
import time
|
5 |
+
import requests
|
6 |
+
|
7 |
+
|
8 |
+
def setup_directory():
|
9 |
+
pass
|
10 |
+
|
11 |
+
|
12 |
+
def generate_safe_folder_name(folder_name: str) -> str:
|
13 |
+
"""
|
14 |
+
Generate a safe folder name by replacing spaces with underscores and removing special characters.
|
15 |
+
|
16 |
+
Parameters:
|
17 |
+
folder_name (str): The original folder name.
|
18 |
+
|
19 |
+
Returns:
|
20 |
+
str: The safe folder name.
|
21 |
+
"""
|
22 |
+
# Replace spaces with underscores
|
23 |
+
safe_name = folder_name.replace(' ', '_')
|
24 |
+
|
25 |
+
# Remove any characters that are not alphanumeric or underscores
|
26 |
+
safe_name = re.sub(r'[^a-zA-Z0-9_]', '', safe_name)
|
27 |
+
|
28 |
+
return safe_name
|
29 |
+
|
30 |
+
|
31 |
+
def delete_old_files(base_path, t):
|
32 |
+
"""
|
33 |
+
Delete all files in a folder structure /subfolder1/subfolder2/
|
34 |
+
that are older than 't' minutes.
|
35 |
+
|
36 |
+
Parameters:
|
37 |
+
- base_path (str): The base directory to start the search.
|
38 |
+
- t (int): The age threshold in minutes.
|
39 |
+
"""
|
40 |
+
# Convert the time 't' from minutes to seconds
|
41 |
+
age_threshold = t * 60
|
42 |
+
|
43 |
+
print(f"Deleting files older than {age_threshold} seconds")
|
44 |
+
|
45 |
+
current_time = time.time()
|
46 |
+
|
47 |
+
print(os.listdir(base_path))
|
48 |
+
|
49 |
+
# Walk through the directory
|
50 |
+
for subfolder1 in os.listdir(base_path):
|
51 |
+
subfolder1_path = os.path.join(base_path, subfolder1)
|
52 |
+
print('\t'+subfolder1_path)
|
53 |
+
if os.path.isdir(subfolder1_path):
|
54 |
+
for subfolder2 in os.listdir(subfolder1_path):
|
55 |
+
print('\t\t'+subfolder2)
|
56 |
+
subfolder2_path = os.path.join(subfolder1_path, subfolder2)
|
57 |
+
if os.path.isdir(subfolder2_path):
|
58 |
+
for root, dirs, files in os.walk(subfolder2_path):
|
59 |
+
for file in files:
|
60 |
+
file_path = os.path.join(root, file)
|
61 |
+
file_age = current_time - os.path.getmtime(file_path)
|
62 |
+
print(f"File: {file_path}, Age: {file_age}")
|
63 |
+
if int(file_age) > int(age_threshold):
|
64 |
+
os.remove(file_path)
|
65 |
+
print(f"Deleted: {file_path}")
|
66 |
+
|
67 |
+
|
68 |
+
def generate_random_word():
|
69 |
+
word_site = "https://www.mit.edu/~ecprice/wordlist.10000"
|
70 |
+
response = requests.get(word_site)
|
71 |
+
words = response.content.splitlines()
|
72 |
+
|
73 |
+
int1 = random.randint(0, len(words) - 1)
|
74 |
+
int2 = random.randint(0, len(words) - 1)
|
75 |
+
|
76 |
+
word1 = words[int1].decode("utf-8")
|
77 |
+
word2 = words[int2].decode("utf-8")
|
78 |
+
|
79 |
+
return f"{word1}-{word2}"
|
mainLogic/utils/glv.py
CHANGED
@@ -1,74 +1,74 @@
|
|
1 |
-
from colorama import Fore, Style, init
|
2 |
-
import mainLogic.utils.glv_var
|
3 |
-
import shutil
|
4 |
-
|
5 |
-
from mainLogic.utils import glv_var
|
6 |
-
|
7 |
-
# Initialize colorama
|
8 |
-
init()
|
9 |
-
|
10 |
-
class Global:
|
11 |
-
|
12 |
-
# PREFERENCES_FILE is currently not used in mainLogic Project
|
13 |
-
# only used in beta project
|
14 |
-
import os
|
15 |
-
disable_hr = False
|
16 |
-
|
17 |
-
def __init__(self, vout=True, outDir="./"):
|
18 |
-
self.outDir = outDir
|
19 |
-
self.vout = vout
|
20 |
-
|
21 |
-
@staticmethod
|
22 |
-
def set_color(color, style=None):
|
23 |
-
"""Prints text in the specified color and style."""
|
24 |
-
print(getattr(Fore, color), end="")
|
25 |
-
if style:
|
26 |
-
print(getattr(Style, style), end="")
|
27 |
-
|
28 |
-
@staticmethod
|
29 |
-
def reset():
|
30 |
-
"""Resets text color and style to defaults."""
|
31 |
-
print(Style.RESET_ALL, end="")
|
32 |
-
|
33 |
-
@staticmethod
|
34 |
-
def print_colored(text, color, style=None):
|
35 |
-
"""Prints text in the specified color and style, resetting afterward."""
|
36 |
-
Global.set_color(color, style)
|
37 |
-
print(text)
|
38 |
-
Global.reset()
|
39 |
-
|
40 |
-
@staticmethod
|
41 |
-
def dprint(text):
|
42 |
-
"""Prints debug text in yellow."""
|
43 |
-
Global.print_colored(text, "YELLOW")
|
44 |
-
|
45 |
-
@staticmethod
|
46 |
-
def errprint(text):
|
47 |
-
"""Prints error text in red."""
|
48 |
-
Global.print_colored(text, "RED")
|
49 |
-
|
50 |
-
@staticmethod
|
51 |
-
def setDebug():
|
52 |
-
"""Sets the text color to yellow (for debugging)."""
|
53 |
-
Global.set_color("YELLOW")
|
54 |
-
|
55 |
-
@staticmethod
|
56 |
-
def setSuccess():
|
57 |
-
"""Sets the text color to green (for success messages)."""
|
58 |
-
Global.set_color("GREEN")
|
59 |
-
|
60 |
-
@staticmethod
|
61 |
-
def sprint(text):
|
62 |
-
"""Prints success text in green."""
|
63 |
-
Global.print_colored(text, "GREEN")
|
64 |
-
|
65 |
-
@staticmethod
|
66 |
-
def hr():
|
67 |
-
|
68 |
-
# Disable horizontal rule if set
|
69 |
-
if Global.disable_hr:
|
70 |
-
return
|
71 |
-
|
72 |
-
"""Fills the entire terminal with = (one row only)."""
|
73 |
-
columns, _ = shutil.get_terminal_size()
|
74 |
print("-" * columns)
|
|
|
1 |
+
from colorama import Fore, Style, init
|
2 |
+
import mainLogic.utils.glv_var
|
3 |
+
import shutil
|
4 |
+
|
5 |
+
from mainLogic.utils import glv_var
|
6 |
+
|
7 |
+
# Initialize colorama
|
8 |
+
init()
|
9 |
+
|
10 |
+
class Global:
|
11 |
+
|
12 |
+
# PREFERENCES_FILE is currently not used in mainLogic Project
|
13 |
+
# only used in beta project
|
14 |
+
import os
|
15 |
+
disable_hr = False
|
16 |
+
|
17 |
+
def __init__(self, vout=True, outDir="./"):
|
18 |
+
self.outDir = outDir
|
19 |
+
self.vout = vout
|
20 |
+
|
21 |
+
@staticmethod
|
22 |
+
def set_color(color, style=None):
|
23 |
+
"""Prints text in the specified color and style."""
|
24 |
+
print(getattr(Fore, color), end="")
|
25 |
+
if style:
|
26 |
+
print(getattr(Style, style), end="")
|
27 |
+
|
28 |
+
@staticmethod
|
29 |
+
def reset():
|
30 |
+
"""Resets text color and style to defaults."""
|
31 |
+
print(Style.RESET_ALL, end="")
|
32 |
+
|
33 |
+
@staticmethod
|
34 |
+
def print_colored(text, color, style=None):
|
35 |
+
"""Prints text in the specified color and style, resetting afterward."""
|
36 |
+
Global.set_color(color, style)
|
37 |
+
print(text)
|
38 |
+
Global.reset()
|
39 |
+
|
40 |
+
@staticmethod
|
41 |
+
def dprint(text):
|
42 |
+
"""Prints debug text in yellow."""
|
43 |
+
Global.print_colored(text, "YELLOW")
|
44 |
+
|
45 |
+
@staticmethod
|
46 |
+
def errprint(text):
|
47 |
+
"""Prints error text in red."""
|
48 |
+
Global.print_colored(text, "RED")
|
49 |
+
|
50 |
+
@staticmethod
|
51 |
+
def setDebug():
|
52 |
+
"""Sets the text color to yellow (for debugging)."""
|
53 |
+
Global.set_color("YELLOW")
|
54 |
+
|
55 |
+
@staticmethod
|
56 |
+
def setSuccess():
|
57 |
+
"""Sets the text color to green (for success messages)."""
|
58 |
+
Global.set_color("GREEN")
|
59 |
+
|
60 |
+
@staticmethod
|
61 |
+
def sprint(text):
|
62 |
+
"""Prints success text in green."""
|
63 |
+
Global.print_colored(text, "GREEN")
|
64 |
+
|
65 |
+
@staticmethod
|
66 |
+
def hr():
|
67 |
+
|
68 |
+
# Disable horizontal rule if set
|
69 |
+
if Global.disable_hr:
|
70 |
+
return
|
71 |
+
|
72 |
+
"""Fills the entire terminal with = (one row only)."""
|
73 |
+
columns, _ = shutil.get_terminal_size()
|
74 |
print("-" * columns)
|
mainLogic/utils/glv_var.py
CHANGED
@@ -1,24 +1,24 @@
|
|
1 |
-
# defining some variables that can be used in the preferences file
|
2 |
-
import os
|
3 |
-
from mainLogic.utils.basicUtils import BasicUtils
|
4 |
-
|
5 |
-
vars = {
|
6 |
-
|
7 |
-
# $script is the path to the folder containing the pwdl.py file
|
8 |
-
# Since the userPrefs.py is in the startup folder,
|
9 |
-
# we need to go one level up however we make the exception that if the pwdl.py is in the same folder as
|
10 |
-
# the startup folder, we don't need to go one level up
|
11 |
-
"$script": BasicUtils.abspath(os.path.dirname(__file__) + (
|
12 |
-
'/../..' if not os.path.exists(os.path.dirname(__file__) + '../pwdl.py') else '')),
|
13 |
-
"$home": os.path.expanduser("~"),
|
14 |
-
}
|
15 |
-
env_file = os.getenv('PWDL_PREF_FILE')
|
16 |
-
if env_file and os.path.exists(env_file):
|
17 |
-
print(f"Using preferences file: {env_file}")
|
18 |
-
PREFS_FILE = env_file
|
19 |
-
else:
|
20 |
-
print(f"Using default preferences file: {os.path.join(vars['$script'], 'defaults.json')}")
|
21 |
-
PREFS_FILE = os.path.join(vars["$script"], 'defaults.json')
|
22 |
-
|
23 |
-
api_webdl_directory = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../webdl'))
|
24 |
EXECUTABLES = ['ffmpeg', 'mp4decrypt', 'vsd']
|
|
|
1 |
+
# defining some variables that can be used in the preferences file
|
2 |
+
import os
|
3 |
+
from mainLogic.utils.basicUtils import BasicUtils
|
4 |
+
|
5 |
+
vars = {
|
6 |
+
|
7 |
+
# $script is the path to the folder containing the pwdl.py file
|
8 |
+
# Since the userPrefs.py is in the startup folder,
|
9 |
+
# we need to go one level up however we make the exception that if the pwdl.py is in the same folder as
|
10 |
+
# the startup folder, we don't need to go one level up
|
11 |
+
"$script": BasicUtils.abspath(os.path.dirname(__file__) + (
|
12 |
+
'/../..' if not os.path.exists(os.path.dirname(__file__) + '../pwdl.py') else '')),
|
13 |
+
"$home": os.path.expanduser("~"),
|
14 |
+
}
|
15 |
+
env_file = os.getenv('PWDL_PREF_FILE')
|
16 |
+
if env_file and os.path.exists(env_file):
|
17 |
+
print(f"Using preferences file: {env_file}")
|
18 |
+
PREFS_FILE = env_file
|
19 |
+
else:
|
20 |
+
print(f"Using default preferences file: {os.path.join(vars['$script'], 'defaults.json')}")
|
21 |
+
PREFS_FILE = os.path.join(vars["$script"], 'defaults.json')
|
22 |
+
|
23 |
+
api_webdl_directory = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../webdl'))
|
24 |
EXECUTABLES = ['ffmpeg', 'mp4decrypt', 'vsd']
|
mainLogic/utils/keyUtils.py
CHANGED
@@ -1,25 +1,25 @@
|
|
1 |
-
"""
|
2 |
-
Obsolete module:
|
3 |
-
no longer used in the project
|
4 |
-
used when key.old.py was being used
|
5 |
-
"""
|
6 |
-
|
7 |
-
import base64
|
8 |
-
|
9 |
-
def base64_to_hex(base64_str):
|
10 |
-
# Replace special characters not in base64 list with '/'
|
11 |
-
base64_str = base64_str.replace('-', '+').replace('_', '/')
|
12 |
-
|
13 |
-
# Add padding if necessary
|
14 |
-
padding = len(base64_str) % 4
|
15 |
-
if padding:
|
16 |
-
base64_str += '=' * (4 - padding)
|
17 |
-
|
18 |
-
# Convert base64 to bytes
|
19 |
-
base64_bytes = base64_str.encode('utf-8')
|
20 |
-
|
21 |
-
# Decode base64 bytes to hex bytes
|
22 |
-
hex_bytes = base64.b64decode(base64_bytes).hex()
|
23 |
-
|
24 |
-
return hex_bytes
|
25 |
-
|
|
|
1 |
+
"""
|
2 |
+
Obsolete module:
|
3 |
+
no longer used in the project
|
4 |
+
used when key.old.py was being used
|
5 |
+
"""
|
6 |
+
|
7 |
+
import base64
|
8 |
+
|
9 |
+
def base64_to_hex(base64_str):
|
10 |
+
# Replace special characters not in base64 list with '/'
|
11 |
+
base64_str = base64_str.replace('-', '+').replace('_', '/')
|
12 |
+
|
13 |
+
# Add padding if necessary
|
14 |
+
padding = len(base64_str) % 4
|
15 |
+
if padding:
|
16 |
+
base64_str += '=' * (4 - padding)
|
17 |
+
|
18 |
+
# Convert base64 to bytes
|
19 |
+
base64_bytes = base64_str.encode('utf-8')
|
20 |
+
|
21 |
+
# Decode base64 bytes to hex bytes
|
22 |
+
hex_bytes = base64.b64decode(base64_bytes).hex()
|
23 |
+
|
24 |
+
return hex_bytes
|
25 |
+
|
mainLogic/utils/os2.py
CHANGED
@@ -1,71 +1,71 @@
|
|
1 |
-
import platform
|
2 |
-
import os
|
3 |
-
from mainLogic import error
|
4 |
-
from mainLogic.utils.process import shell
|
5 |
-
from mainLogic.utils.glv import Global
|
6 |
-
# 0 - linux
|
7 |
-
# 1 - windows
|
8 |
-
# 2 - mac (currently not supported)
|
9 |
-
|
10 |
-
class SysFunc:
|
11 |
-
def __init__(self,os=1 if "Windows" in platform.system() else 0 if "Linux" in platform.system() else -1):
|
12 |
-
if os == -1:
|
13 |
-
raise Exception("UnsupportedOS")
|
14 |
-
self.os = os
|
15 |
-
|
16 |
-
def create_dir(self,dirName,verbose=False):
|
17 |
-
try:
|
18 |
-
if not os.path.exists(dirName):
|
19 |
-
if verbose: Global.dprint(f"Creating directory {dirName}")
|
20 |
-
os.makedirs(dirName)
|
21 |
-
except:
|
22 |
-
if verbose: Global.errprint(f"Could not make directory {dirName}. Exiting...")
|
23 |
-
error.errorList["couldNotMakeDir"]["func"](dirName)
|
24 |
-
exit(error.errorList["couldNotMakeDir"]["code"])
|
25 |
-
|
26 |
-
if verbose: Global.dprint(f"Directory {dirName} created")
|
27 |
-
def clear(self):
|
28 |
-
if self.os == 0:
|
29 |
-
os.system("clear")
|
30 |
-
elif self.os == 1:
|
31 |
-
os.system("cls")
|
32 |
-
else:
|
33 |
-
raise Exception("UnsupportedOS")
|
34 |
-
|
35 |
-
|
36 |
-
def which(self,program):
|
37 |
-
|
38 |
-
if self.os == 0:
|
39 |
-
if shell('which',stderr="",stdout="") != 1 and shell('which',stderr="",stdout="") != 255:
|
40 |
-
error.errorList["dependencyNotFound"]["func"]('which')
|
41 |
-
exit(error.errorList["dependencyNotFound"]["code"])
|
42 |
-
else:
|
43 |
-
self.whichPresent = True
|
44 |
-
|
45 |
-
return shell(f"which {program}",stderr="",stdout="")
|
46 |
-
|
47 |
-
elif self.os == 1:
|
48 |
-
|
49 |
-
if shell('where',stderr="",stdout="") != 2:
|
50 |
-
error.errorList["dependencyNotFound"]["func"]('where')
|
51 |
-
exit(error.errorList["dependencyNotFound"]["code"])
|
52 |
-
else:
|
53 |
-
self.whichPresent = True
|
54 |
-
return shell(f"where {program}" , stderr="",stdout="")
|
55 |
-
else:
|
56 |
-
raise Exception("UnsupportedOS")
|
57 |
-
|
58 |
-
@staticmethod
|
59 |
-
def modify_path(path):
|
60 |
-
expanded_path = os.path.expandvars(path)
|
61 |
-
absolute_path = os.path.abspath(expanded_path)
|
62 |
-
modified_path = absolute_path.replace(os.sep, '/')
|
63 |
-
return modified_path
|
64 |
-
|
65 |
-
def cd(self,dir=None):
|
66 |
-
try:
|
67 |
-
if dir: os.chdir(dir)
|
68 |
-
else: os.chdir(os.path.expanduser("~"))
|
69 |
-
except Exception as e:
|
70 |
-
Global.errprint(f"Could not change directory : {e}")
|
71 |
|
|
|
1 |
+
import platform
|
2 |
+
import os
|
3 |
+
from mainLogic import error
|
4 |
+
from mainLogic.utils.process import shell
|
5 |
+
from mainLogic.utils.glv import Global
|
6 |
+
# 0 - linux
|
7 |
+
# 1 - windows
|
8 |
+
# 2 - mac (currently not supported)
|
9 |
+
|
10 |
+
class SysFunc:
|
11 |
+
def __init__(self,os=1 if "Windows" in platform.system() else 0 if "Linux" in platform.system() else -1):
|
12 |
+
if os == -1:
|
13 |
+
raise Exception("UnsupportedOS")
|
14 |
+
self.os = os
|
15 |
+
|
16 |
+
def create_dir(self,dirName,verbose=False):
|
17 |
+
try:
|
18 |
+
if not os.path.exists(dirName):
|
19 |
+
if verbose: Global.dprint(f"Creating directory {dirName}")
|
20 |
+
os.makedirs(dirName)
|
21 |
+
except:
|
22 |
+
if verbose: Global.errprint(f"Could not make directory {dirName}. Exiting...")
|
23 |
+
error.errorList["couldNotMakeDir"]["func"](dirName)
|
24 |
+
exit(error.errorList["couldNotMakeDir"]["code"])
|
25 |
+
|
26 |
+
if verbose: Global.dprint(f"Directory {dirName} created")
|
27 |
+
def clear(self):
|
28 |
+
if self.os == 0:
|
29 |
+
os.system("clear")
|
30 |
+
elif self.os == 1:
|
31 |
+
os.system("cls")
|
32 |
+
else:
|
33 |
+
raise Exception("UnsupportedOS")
|
34 |
+
|
35 |
+
|
36 |
+
def which(self,program):
|
37 |
+
|
38 |
+
if self.os == 0:
|
39 |
+
if shell('which',stderr="",stdout="") != 1 and shell('which',stderr="",stdout="") != 255:
|
40 |
+
error.errorList["dependencyNotFound"]["func"]('which')
|
41 |
+
exit(error.errorList["dependencyNotFound"]["code"])
|
42 |
+
else:
|
43 |
+
self.whichPresent = True
|
44 |
+
|
45 |
+
return shell(f"which {program}",stderr="",stdout="")
|
46 |
+
|
47 |
+
elif self.os == 1:
|
48 |
+
|
49 |
+
if shell('where',stderr="",stdout="") != 2:
|
50 |
+
error.errorList["dependencyNotFound"]["func"]('where')
|
51 |
+
exit(error.errorList["dependencyNotFound"]["code"])
|
52 |
+
else:
|
53 |
+
self.whichPresent = True
|
54 |
+
return shell(f"where {program}" , stderr="",stdout="")
|
55 |
+
else:
|
56 |
+
raise Exception("UnsupportedOS")
|
57 |
+
|
58 |
+
@staticmethod
|
59 |
+
def modify_path(path):
|
60 |
+
expanded_path = os.path.expandvars(path)
|
61 |
+
absolute_path = os.path.abspath(expanded_path)
|
62 |
+
modified_path = absolute_path.replace(os.sep, '/')
|
63 |
+
return modified_path
|
64 |
+
|
65 |
+
def cd(self,dir=None):
|
66 |
+
try:
|
67 |
+
if dir: os.chdir(dir)
|
68 |
+
else: os.chdir(os.path.expanduser("~"))
|
69 |
+
except Exception as e:
|
70 |
+
Global.errprint(f"Could not change directory : {e}")
|
71 |
|
mainLogic/utils/process.py
CHANGED
@@ -1,64 +1,64 @@
|
|
1 |
-
import subprocess
|
2 |
-
import re
|
3 |
-
import sys
|
4 |
-
|
5 |
-
def shell(command, filter=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, progress_callback=None, handleProgress=None, inline_progress=False):
|
6 |
-
import os
|
7 |
-
|
8 |
-
# Set PYTHONUNBUFFERED environment variable
|
9 |
-
os.environ['PYTHONUNBUFFERED'] = '1'
|
10 |
-
|
11 |
-
command = to_list(command)
|
12 |
-
|
13 |
-
|
14 |
-
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, encoding='utf-8', universal_newlines=True)
|
15 |
-
|
16 |
-
while True:
|
17 |
-
try:
|
18 |
-
output = process.stdout.readline()
|
19 |
-
output = output.strip()
|
20 |
-
|
21 |
-
if output == '' and process.poll() is not None:
|
22 |
-
break
|
23 |
-
|
24 |
-
if output:
|
25 |
-
if filter is not None and re.search(filter, output):
|
26 |
-
# Call the progress callback with the filtered output
|
27 |
-
if progress_callback:
|
28 |
-
if handleProgress:
|
29 |
-
progress_callback(handleProgress(output))
|
30 |
-
else:
|
31 |
-
progress_callback(output)
|
32 |
-
|
33 |
-
if inline_progress:
|
34 |
-
# Update progress in the same line
|
35 |
-
sys.stdout.write('\r' + output.strip())
|
36 |
-
sys.stdout.flush()
|
37 |
-
else:
|
38 |
-
# Print output normally
|
39 |
-
if not stdout == '' or not stdout == None:
|
40 |
-
continue
|
41 |
-
print(output)
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
except UnicodeEncodeError:
|
46 |
-
sys.stdout.write("\rUnicodeEncodeError")
|
47 |
-
sys.stdout.flush()
|
48 |
-
pass
|
49 |
-
except Exception as e:
|
50 |
-
print(f"Error: {e}")
|
51 |
-
|
52 |
-
# Wait for the process to complete and get the return code
|
53 |
-
return_code = process.wait()
|
54 |
-
|
55 |
-
return return_code
|
56 |
-
|
57 |
-
def to_list(variable):
|
58 |
-
if isinstance(variable, list):
|
59 |
-
return variable
|
60 |
-
elif variable is None:
|
61 |
-
return []
|
62 |
-
else:
|
63 |
-
# Convert to string and then to list by splitting at whitespaces
|
64 |
-
return variable.split()
|
|
|
1 |
+
import subprocess
|
2 |
+
import re
|
3 |
+
import sys
|
4 |
+
|
5 |
+
def shell(command, filter=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, progress_callback=None, handleProgress=None, inline_progress=False):
|
6 |
+
import os
|
7 |
+
|
8 |
+
# Set PYTHONUNBUFFERED environment variable
|
9 |
+
os.environ['PYTHONUNBUFFERED'] = '1'
|
10 |
+
|
11 |
+
command = to_list(command)
|
12 |
+
|
13 |
+
|
14 |
+
process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, encoding='utf-8', universal_newlines=True)
|
15 |
+
|
16 |
+
while True:
|
17 |
+
try:
|
18 |
+
output = process.stdout.readline()
|
19 |
+
output = output.strip()
|
20 |
+
|
21 |
+
if output == '' and process.poll() is not None:
|
22 |
+
break
|
23 |
+
|
24 |
+
if output:
|
25 |
+
if filter is not None and re.search(filter, output):
|
26 |
+
# Call the progress callback with the filtered output
|
27 |
+
if progress_callback:
|
28 |
+
if handleProgress:
|
29 |
+
progress_callback(handleProgress(output))
|
30 |
+
else:
|
31 |
+
progress_callback(output)
|
32 |
+
|
33 |
+
if inline_progress:
|
34 |
+
# Update progress in the same line
|
35 |
+
sys.stdout.write('\r' + output.strip())
|
36 |
+
sys.stdout.flush()
|
37 |
+
else:
|
38 |
+
# Print output normally
|
39 |
+
if not stdout == '' or not stdout == None:
|
40 |
+
continue
|
41 |
+
print(output)
|
42 |
+
|
43 |
+
|
44 |
+
|
45 |
+
except UnicodeEncodeError:
|
46 |
+
sys.stdout.write("\rUnicodeEncodeError")
|
47 |
+
sys.stdout.flush()
|
48 |
+
pass
|
49 |
+
except Exception as e:
|
50 |
+
print(f"Error: {e}")
|
51 |
+
|
52 |
+
# Wait for the process to complete and get the return code
|
53 |
+
return_code = process.wait()
|
54 |
+
|
55 |
+
return return_code
|
56 |
+
|
57 |
+
def to_list(variable):
|
58 |
+
if isinstance(variable, list):
|
59 |
+
return variable
|
60 |
+
elif variable is None:
|
61 |
+
return []
|
62 |
+
else:
|
63 |
+
# Convert to string and then to list by splitting at whitespaces
|
64 |
+
return variable.split()
|
pwdl.bat
CHANGED
@@ -1,45 +1,45 @@
|
|
1 |
-
@echo off
|
2 |
-
REM Batch script for running the Python script pwdl.py
|
3 |
-
|
4 |
-
REM Check if Python is installed
|
5 |
-
py --version >nul 2>&1
|
6 |
-
if errorlevel 1 (
|
7 |
-
echo Python is not installed or not found in the PATH.
|
8 |
-
exit /b 1
|
9 |
-
)
|
10 |
-
|
11 |
-
REM Define paths to executables
|
12 |
-
set SCRIPT_DIR=%~dp0
|
13 |
-
set BIN_DIR=%SCRIPT_DIR%bin
|
14 |
-
set MP4DECRYPT=%BIN_DIR%\mp4decrypt.exe
|
15 |
-
set VSD=%BIN_DIR%\vsd.exe
|
16 |
-
|
17 |
-
REM Check if bin directory exists, create if it doesn't
|
18 |
-
if not exist "%BIN_DIR%" (
|
19 |
-
mkdir "%BIN_DIR%"
|
20 |
-
)
|
21 |
-
|
22 |
-
REM Check if mp4decrypt.exe exists
|
23 |
-
if not exist "%MP4DECRYPT%" (
|
24 |
-
echo mp4decrypt.exe not found. Downloading...
|
25 |
-
powershell -Command "Invoke-WebRequest -Uri 'https://github.com/shubhamakshit/pwdlv3_assets/raw/main/Windows/x86_64/mp4decrypt.exe' -OutFile '%MP4DECRYPT%'" >nul 2>&1
|
26 |
-
if errorlevel 1 (
|
27 |
-
echo Failed to download mp4decrypt.exe
|
28 |
-
) else (
|
29 |
-
echo Successfully downloaded mp4decrypt.exe
|
30 |
-
)
|
31 |
-
)
|
32 |
-
|
33 |
-
REM Check if vsd.exe exists
|
34 |
-
if not exist "%VSD%" (
|
35 |
-
echo vsd.exe not found. Downloading...
|
36 |
-
powershell -Command "Invoke-WebRequest -Uri 'https://github.com/shubhamakshit/pwdlv3_assets/raw/main/Windows/x86_64/vsd.exe' -OutFile '%VSD%'" >nul 2>&1
|
37 |
-
if errorlevel 1 (
|
38 |
-
echo Failed to download vsd.exe
|
39 |
-
) else (
|
40 |
-
echo Successfully downloaded vsd.exe
|
41 |
-
)
|
42 |
-
)
|
43 |
-
|
44 |
-
REM Run the Python script with the provided arguments
|
45 |
-
py "%~dp0pwdl.py" %*
|
|
|
1 |
+
@echo off
|
2 |
+
REM Batch script for running the Python script pwdl.py
|
3 |
+
|
4 |
+
REM Check if Python is installed
|
5 |
+
py --version >nul 2>&1
|
6 |
+
if errorlevel 1 (
|
7 |
+
echo Python is not installed or not found in the PATH.
|
8 |
+
exit /b 1
|
9 |
+
)
|
10 |
+
|
11 |
+
REM Define paths to executables
|
12 |
+
set SCRIPT_DIR=%~dp0
|
13 |
+
set BIN_DIR=%SCRIPT_DIR%bin
|
14 |
+
set MP4DECRYPT=%BIN_DIR%\mp4decrypt.exe
|
15 |
+
set VSD=%BIN_DIR%\vsd.exe
|
16 |
+
|
17 |
+
REM Check if bin directory exists, create if it doesn't
|
18 |
+
if not exist "%BIN_DIR%" (
|
19 |
+
mkdir "%BIN_DIR%"
|
20 |
+
)
|
21 |
+
|
22 |
+
REM Check if mp4decrypt.exe exists
|
23 |
+
if not exist "%MP4DECRYPT%" (
|
24 |
+
echo mp4decrypt.exe not found. Downloading...
|
25 |
+
powershell -Command "Invoke-WebRequest -Uri 'https://github.com/shubhamakshit/pwdlv3_assets/raw/main/Windows/x86_64/mp4decrypt.exe' -OutFile '%MP4DECRYPT%'" >nul 2>&1
|
26 |
+
if errorlevel 1 (
|
27 |
+
echo Failed to download mp4decrypt.exe
|
28 |
+
) else (
|
29 |
+
echo Successfully downloaded mp4decrypt.exe
|
30 |
+
)
|
31 |
+
)
|
32 |
+
|
33 |
+
REM Check if vsd.exe exists
|
34 |
+
if not exist "%VSD%" (
|
35 |
+
echo vsd.exe not found. Downloading...
|
36 |
+
powershell -Command "Invoke-WebRequest -Uri 'https://github.com/shubhamakshit/pwdlv3_assets/raw/main/Windows/x86_64/vsd.exe' -OutFile '%VSD%'" >nul 2>&1
|
37 |
+
if errorlevel 1 (
|
38 |
+
echo Failed to download vsd.exe
|
39 |
+
) else (
|
40 |
+
echo Successfully downloaded vsd.exe
|
41 |
+
)
|
42 |
+
)
|
43 |
+
|
44 |
+
REM Run the Python script with the provided arguments
|
45 |
+
py "%~dp0pwdl.py" %*
|
pwdl.py
CHANGED
@@ -1,32 +1,32 @@
|
|
1 |
-
import argparse
|
2 |
-
from mainLogic import downloader
|
3 |
-
|
4 |
-
|
5 |
-
def parse_arguments():
|
6 |
-
"""Parse command-line arguments."""
|
7 |
-
parser = argparse.ArgumentParser(description='PhysicsWallah M3u8 parser.')
|
8 |
-
parser.add_argument('--csv-file', type=str, help='Input csv file. Legacy Support too.')
|
9 |
-
parser.add_argument('--id', type=str,
|
10 |
-
help='PhysicsWallh Video Id for single usage. Incompatible with --csv-file. Must be used with --name')
|
11 |
-
parser.add_argument('--name', type=str,
|
12 |
-
help='Name for the output file. Incompatible with --csv-file. Must be used with --id')
|
13 |
-
parser.add_argument('--dir', type=str, help='Output Directory')
|
14 |
-
parser.add_argument('--verbose', action='store_true', help='Verbose Output')
|
15 |
-
parser.add_argument('--shell', action='store_true', help='Start the shell')
|
16 |
-
parser.add_argument('--webui', nargs='?', const=-1, type=int, help='Start the Webui')
|
17 |
-
parser.add_argument('--simulate', action='store_true',
|
18 |
-
help='Simulate the download process. No files will be downloaded.')
|
19 |
-
return parser.parse_args()
|
20 |
-
|
21 |
-
if __name__ == "__main__":
|
22 |
-
args = parse_arguments()
|
23 |
-
downloader.main(
|
24 |
-
csv_file=args.csv_file,
|
25 |
-
id=args.id,
|
26 |
-
name=args.name,
|
27 |
-
directory=args.dir,
|
28 |
-
verbose=args.verbose,
|
29 |
-
shell=args.shell,
|
30 |
-
webui_port=args.webui,
|
31 |
-
simulate=args.simulate
|
32 |
-
)
|
|
|
1 |
+
import argparse
|
2 |
+
from mainLogic import downloader
|
3 |
+
|
4 |
+
|
5 |
+
def parse_arguments():
|
6 |
+
"""Parse command-line arguments."""
|
7 |
+
parser = argparse.ArgumentParser(description='PhysicsWallah M3u8 parser.')
|
8 |
+
parser.add_argument('--csv-file', type=str, help='Input csv file. Legacy Support too.')
|
9 |
+
parser.add_argument('--id', type=str,
|
10 |
+
help='PhysicsWallh Video Id for single usage. Incompatible with --csv-file. Must be used with --name')
|
11 |
+
parser.add_argument('--name', type=str,
|
12 |
+
help='Name for the output file. Incompatible with --csv-file. Must be used with --id')
|
13 |
+
parser.add_argument('--dir', type=str, help='Output Directory')
|
14 |
+
parser.add_argument('--verbose', action='store_true', help='Verbose Output')
|
15 |
+
parser.add_argument('--shell', action='store_true', help='Start the shell')
|
16 |
+
parser.add_argument('--webui', nargs='?', const=-1, type=int, help='Start the Webui')
|
17 |
+
parser.add_argument('--simulate', action='store_true',
|
18 |
+
help='Simulate the download process. No files will be downloaded.')
|
19 |
+
return parser.parse_args()
|
20 |
+
|
21 |
+
if __name__ == "__main__":
|
22 |
+
args = parse_arguments()
|
23 |
+
downloader.main(
|
24 |
+
csv_file=args.csv_file,
|
25 |
+
id=args.id,
|
26 |
+
name=args.name,
|
27 |
+
directory=args.dir,
|
28 |
+
verbose=args.verbose,
|
29 |
+
shell=args.shell,
|
30 |
+
webui_port=args.webui,
|
31 |
+
simulate=args.simulate
|
32 |
+
)
|
run.py
CHANGED
@@ -1,3 +1,3 @@
|
|
1 |
-
import beta.api.api
|
2 |
-
|
3 |
app = beta.api.api.app
|
|
|
1 |
+
import beta.api.api
|
2 |
+
|
3 |
app = beta.api.api.app
|