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