AkshitShubham commited on
Commit
41ca5f7
1 Parent(s): 47d04a3

Upload folder using huggingface_hub

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +2 -2
  2. .gitignore +199 -199
  3. Dockerfile +67 -67
  4. README.md +192 -181
  5. beta/api/api.py +40 -40
  6. beta/api/api_dl.py +35 -35
  7. beta/api/blueprints/api_pref_manager.py +39 -39
  8. beta/api/blueprints/client_info_routes.py +103 -103
  9. beta/api/blueprints/leagacy_create_task.py +40 -40
  10. beta/api/blueprints/session_lodge.py +82 -82
  11. beta/api/blueprints/template_routes.py +24 -24
  12. beta/api/blueprints/while_dl_and_post_dl.py +34 -34
  13. beta/api/mr_manager/boss_manager.py +7 -7
  14. beta/api/mr_manager/client_manager.py +119 -119
  15. beta/api/mr_manager/task_manager.py +105 -105
  16. beta/shellLogic/TokenUpdate.py +35 -35
  17. beta/shellLogic/handleLogics/HandleBasicCMDUtils.py +64 -64
  18. beta/shellLogic/handleLogics/HandleKeyAndAvailiblity.py +39 -39
  19. beta/shellLogic/handleLogics/HandleShellDL.py +62 -62
  20. beta/shellLogic/logic.py +29 -29
  21. beta/shellLogic/logicError.py +5 -5
  22. beta/shellLogic/shell.py +60 -60
  23. beta/shellLogic/simpleParser.py +5 -5
  24. beta/shellLogic/update.py +20 -20
  25. beta/util.py +46 -46
  26. defaults.json +14 -14
  27. defaults.linux.json +14 -14
  28. mainLogic/big4/cleanup.py +37 -37
  29. mainLogic/big4/decrypt/decrypt.py +54 -54
  30. mainLogic/big4/decrypt/key.old.py +85 -85
  31. mainLogic/big4/decrypt/key.py +138 -138
  32. mainLogic/big4/dl_obsolete.py +175 -175
  33. mainLogic/big4/downloadv2.py +96 -96
  34. mainLogic/big4/merge.py +35 -35
  35. mainLogic/downloader.py +117 -117
  36. mainLogic/error.py +86 -86
  37. mainLogic/main.py +126 -126
  38. mainLogic/startup/checkup.py +200 -200
  39. mainLogic/startup/flareCheck.py +17 -17
  40. mainLogic/startup/userPrefs.py +58 -58
  41. mainLogic/utils/basicUtils.py +25 -25
  42. mainLogic/utils/gen_utils.py +79 -79
  43. mainLogic/utils/glv.py +73 -73
  44. mainLogic/utils/glv_var.py +23 -23
  45. mainLogic/utils/keyUtils.py +25 -25
  46. mainLogic/utils/os2.py +70 -70
  47. mainLogic/utils/process.py +64 -64
  48. pwdl.bat +45 -45
  49. pwdl.py +32 -32
  50. 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
- # Table of Contents
2
- 1. [Project Information](#project-information)
3
- 2. [Tools Used](#tools-used)
4
- 3. [Getting Started](#getting-started)
5
- - [Windows](#windows)
6
- - [Linux](#linux)
7
- 4. [Usage](#usage)
8
- 5. [API Reference](#api-reference)
9
- 6. [Docker Usage](#docker-usage)
10
- 7. [Shell Usage (Beta)](#shell-usage-beta)
11
- 8. [Error Codes](#error-codes)
12
- 9. [Contributing](#contributing)
13
- 10. [License](#license)
14
-
15
- # Project Information
16
- `pwdlv3` is a project aimed at downloading videos from pw.live. It is written in Python and JavaScript, and uses pip for dependency management.
17
-
18
- # Tools Used
19
-
20
- - **Python**: Backend logic scripting.
21
- - **JavaScript**: Frontend logic handling.
22
- - **pip**: Dependency management.
23
- - **Flask**: HTTP requests handling and web UI rendering.
24
- - **Docker**: Containerization for consistent application deployment.
25
- - **VSD**: Downloading MPD (MPEG-DASH) files. [More about VSD](https://github.com/clitic/vsd).
26
- - **Bento4's mp4decrypt**: Decrypting encrypted MP4 files.
27
- - **FFmpeg**: Merging audio and video files.
28
-
29
- # Getting Started
30
-
31
- ## Windows
32
- 1. Clone the repository:
33
- ```bash
34
- git clone https://github.com/username/pwdlv3.git
35
- ```
36
- 2. Navigate to the project directory:
37
- ```bash
38
- cd pwdlv3
39
- ```
40
- 3. Install the required dependencies:
41
- ```bash
42
- pip install -r requirements.txt
43
- ```
44
- 4. Run the setup script:
45
- ```bash
46
- pwdl.bat
47
- ```
48
-
49
- ## Linux
50
- 1. Clone the repository:
51
- ```bash
52
- git clone https://github.com/username/pwdlv3.git
53
- ```
54
- 2. Navigate to the project directory:
55
- ```bash
56
- cd pwdlv3
57
- ```
58
- 3. Install the required dependencies:
59
- ```bash
60
- pip install -r requirements.txt
61
- ```
62
- 4. Run the setup script:
63
- ```bash
64
- ./setup.sh
65
- ```
66
-
67
- # Usage
68
-
69
- Run the project with the following command:
70
-
71
- ```bash
72
- python pwdl.py --options
73
- ```
74
-
75
- - Download a single video:
76
- ```bash
77
- python pwdl.py --id VIDEO_ID --name VIDEO_NAME
78
- ```
79
- - Download multiple videos from a CSV file:
80
- ```bash
81
- python pwdl.py --csv-file FILE_PATH
82
- ```
83
- - Start the shell:
84
- ```bash
85
- python pwdl.py --shell
86
- ```
87
- - Start the WebUI:
88
- ```bash
89
- python pwdl.py --webui
90
- ```
91
-
92
- # API Reference
93
-
94
- The project provides several API endpoints for interacting with the video downloading service:
95
-
96
- - **POST /api/create_task**: Create a new download task.
97
- - **Request Body**: JSON with 'id' (video ID) and 'name' (output file name).
98
- - **Response**: JSON with 'task_id'.
99
-
100
- - **GET /api/progress/<task_id>**: Get the progress of a download task.
101
- - **Response**: JSON with progress information.
102
-
103
- - **GET /api/get-file/<task_id>/<name>**: Download the completed video file.
104
- - **Response**: Video file download.
105
-
106
- - **GET /key/vid_id**: Get the decryption key for a video.
107
- - **Query Parameters**: 'vid_id' and 'token'.
108
- - **Response**: JSON with 'key'.
109
-
110
- These endpoints are also available without the '/api' prefix. For example, use `/create_task` instead of `/api/create_task`.
111
-
112
- # Docker Usage
113
-
114
- The Dockerfile is used to create a Docker image that encapsulates the entire application, including all dependencies.
115
-
116
- ## Building the Docker Image
117
-
118
- Navigate to the project directory and run:
119
-
120
- ```bash
121
- docker build -t shubhamakshit/pwdl .
122
- ```
123
-
124
- ## Running the Docker Image
125
-
126
- Run the Docker image with:
127
-
128
- ```bash
129
- docker run -p 5000:5000 shubhamakshit/pwdl
130
- ```
131
-
132
- Access the application at `http://localhost:5000`.
133
-
134
- # Shell Usage (Beta)
135
-
136
- Start the interactive shell with:
137
-
138
- ```bash
139
- python pwdl.py --shell
140
- ```
141
-
142
- Available commands:
143
-
144
- - `get_key <vid_id> <token>`: Get the decryption key for a video.
145
- - `tkn-up <token>`: Update the token in the default settings.
146
- - `exit`: Exit the shell.
147
-
148
- Note: This feature is in beta and may change.
149
-
150
- # Error Codes
151
-
152
- | Code | Description |
153
- | ---- | ----------- |
154
- | 0 | No error |
155
- | 1 | defaults.json not found |
156
- | 2 | Dependency not found |
157
- | 3 | Dependency not found in default settings |
158
- | 4 | CSV file not found |
159
- | 5 | Download failed |
160
- | 6 | Could not make directory |
161
- | 7 | Token not found in default settings |
162
- | 8 | Overwrite aborted by user |
163
- | 22 | Can't load file |
164
- | 23 | Flare is not started |
165
- | 24 | Request failed due to unknown reason |
166
- | 25 | Key extraction failed |
167
- | 26 | Key not provided |
168
- | 27 | Could not download audio |
169
- | 28 | Could not download video |
170
- | 29 | Could not decrypt audio |
171
- | 30 | Could not decrypt video |
172
- | 31 | Method is patched |
173
- | 32 | Could not extract key |
174
-
175
- # Contributing
176
-
177
- Instructions for how to contribute to the project will be provided here.
178
-
179
- # License
180
-
181
- Information about the project's license will be provided here.
 
 
 
 
 
 
 
 
 
 
 
 
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