mirror of https://github.com/devine-dl/devine.git
Overhaul tooling, linting, editor configs, and README
This commit is contained in:
parent
c159672181
commit
959590a6bb
|
@ -1,9 +1,5 @@
|
|||
version = 1
|
||||
|
||||
exclude_patterns = [
|
||||
"**_pb2.py" # protobuf files
|
||||
]
|
||||
|
||||
[[analyzers]]
|
||||
name = "python"
|
||||
enabled = true
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{feature,json,md,yaml,yml,toml}]
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
3
.flake8
3
.flake8
|
@ -1,3 +0,0 @@
|
|||
[flake8]
|
||||
exclude = .venv,build,dist,*_pb2.py,*.pyi
|
||||
max-line-length = 120
|
|
@ -0,0 +1 @@
|
|||
* text=auto eol=lf
|
|
@ -15,32 +15,32 @@ jobs:
|
|||
name: Tagged Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10.x'
|
||||
- name: Install Poetry
|
||||
uses: abatilo/actions-poetry@v2.3.0
|
||||
with:
|
||||
poetry-version: '1.4.2'
|
||||
- name: Install dependencies
|
||||
run: poetry install
|
||||
- name: Build project
|
||||
run: poetry build
|
||||
- name: Upload wheel
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Python Wheel
|
||||
path: "dist/*.whl"
|
||||
- name: Deploy release
|
||||
uses: marvinpinto/action-automatic-releases@latest
|
||||
with:
|
||||
prerelease: false
|
||||
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
files: |
|
||||
dist/*.whl
|
||||
- name: Publish to PyPI
|
||||
env:
|
||||
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_TOKEN }}
|
||||
run: poetry publish
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- name: Install Poetry
|
||||
uses: abatilo/actions-poetry@v2
|
||||
with:
|
||||
poetry-version: 1.6.1
|
||||
- name: Install project
|
||||
run: poetry install --only main
|
||||
- name: Build project
|
||||
run: poetry build
|
||||
- name: Upload wheel
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Python Wheel
|
||||
path: "dist/*.whl"
|
||||
- name: Deploy release
|
||||
uses: marvinpinto/action-automatic-releases@latest
|
||||
with:
|
||||
prerelease: false
|
||||
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
files: |
|
||||
dist/*.whl
|
||||
- name: Publish to PyPI
|
||||
env:
|
||||
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_TOKEN }}
|
||||
run: poetry publish
|
||||
|
|
|
@ -7,32 +7,38 @@ on:
|
|||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.11"
|
||||
- name: Install poetry
|
||||
uses: abatilo/actions-poetry@v2
|
||||
with:
|
||||
poetry-version: 1.6.1
|
||||
- name: Install project
|
||||
run: poetry install --all-extras
|
||||
- name: Run pre-commit which does various checks
|
||||
run: poetry run pre-commit run --all-files --show-diff-on-failure
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ['3.9', '3.10', '3.11']
|
||||
|
||||
python-version: ["3.9", "3.10", "3.11"]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install flake8
|
||||
run: python -m pip install flake8
|
||||
- name: Lint with flake8
|
||||
run: |
|
||||
# stop the build if there are Python syntax errors or undefined names
|
||||
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
|
||||
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
|
||||
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
|
||||
- name: Install poetry
|
||||
uses: abatilo/actions-poetry@v2.3.0
|
||||
with:
|
||||
poetry-version: 1.4.2
|
||||
- name: Install project
|
||||
run: poetry install --no-dev
|
||||
- name: Build project
|
||||
run: poetry build
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install poetry
|
||||
uses: abatilo/actions-poetry@v2
|
||||
with:
|
||||
poetry-version: 1.6.1
|
||||
- name: Install project
|
||||
run: poetry install --all-extras --only main
|
||||
- name: Build project
|
||||
run: poetry build
|
||||
|
|
|
@ -36,6 +36,7 @@ parts/
|
|||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
@ -54,14 +55,17 @@ 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
|
||||
|
@ -71,6 +75,7 @@ coverage.xml
|
|||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
|
@ -83,16 +88,49 @@ instance/
|
|||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# celery beat schedule file
|
||||
# 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
|
||||
|
@ -113,13 +151,26 @@ venv.bak/
|
|||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# JetBrains project settings
|
||||
.idea
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.directory
|
||||
.idea/dataSources.local.xml
|
||||
.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/
|
||||
|
|
|
@ -2,17 +2,17 @@
|
|||
# See https://pre-commit.com/hooks.html for more hooks
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/mtkennerly/pre-commit-hooks
|
||||
rev: v0.3.0
|
||||
hooks:
|
||||
- id: poetry-ruff
|
||||
- repo: https://github.com/pycqa/isort
|
||||
rev: 5.12.0
|
||||
hooks:
|
||||
- id: isort
|
||||
- repo: https://github.com/pycqa/flake8
|
||||
rev: 6.0.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.4.0
|
||||
rev: v4.5.0
|
||||
hooks:
|
||||
- id: end-of-file-fixer
|
||||
- id: trailing-whitespace
|
||||
args: [--markdown-linebreak-ext=md]
|
||||
- id: end-of-file-fixer
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"recommendations": [
|
||||
"EditorConfig.EditorConfig",
|
||||
"streetsidesoftware.code-spell-checker",
|
||||
"ms-python.python",
|
||||
"ms-python.vscode-pylance",
|
||||
"charliermarsh.ruff",
|
||||
"ms-python.isort",
|
||||
"ms-python.mypy-type-checker",
|
||||
"redhat.vscode-yaml",
|
||||
"tamasfe.even-better-toml"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
# Development
|
||||
|
||||
This project is managed using [Poetry](https://python-poetry.org), a fantastic Python packaging and dependency manager.
|
||||
Install the latest version of Poetry before continuing. Development currently requires Python 3.9+.
|
||||
|
||||
## Set up
|
||||
|
||||
Starting from Zero? Not sure where to begin? Here's steps on setting up this Python project using Poetry. Note that
|
||||
Poetry installation instructions should be followed from the Poetry Docs: https://python-poetry.org/docs/#installation
|
||||
|
||||
1. While optional, It's recommended to configure Poetry to install Virtual environments within project folders:
|
||||
```shell
|
||||
poetry config virtualenvs.in-project true
|
||||
```
|
||||
This makes it easier for Visual Studio Code to detect the Virtual Environment, as well as other IDEs and systems.
|
||||
I've also had issues with Poetry creating duplicate Virtual environments in the default folder for an unknown
|
||||
reason which quickly filled up my System storage.
|
||||
2. Clone the Repository:
|
||||
```shell
|
||||
git clone https://github.com/devine-dl/devine
|
||||
cd devine
|
||||
```
|
||||
3. Install the Project with Poetry:
|
||||
```shell
|
||||
poetry install
|
||||
```
|
||||
This creates a Virtual environment and then installs all project dependencies and executables into the Virtual
|
||||
environment. Your System Python environment is not affected at all.
|
||||
4. Now activate the Virtual environment:
|
||||
```shell
|
||||
poetry shell
|
||||
```
|
||||
Note:
|
||||
- You can alternatively just prefix `poetry run` to any command you wish to run under the Virtual environment.
|
||||
- I recommend entering the Virtual environment and all further instructions will have assumed you did.
|
||||
- JetBrains PyCharm has integrated support for Poetry and automatically enters Poetry Virtual environments, assuming
|
||||
the Python Interpreter on the bottom right is set up correctly.
|
||||
- For more information, see: https://python-poetry.org/docs/basic-usage/#using-your-virtual-environment
|
||||
5. Install Pre-commit tooling to ensure safe and quality commits:
|
||||
```shell
|
||||
pre-commit install
|
||||
```
|
||||
|
||||
## Building Source and Wheel distributions
|
||||
|
||||
poetry build
|
||||
|
||||
You can optionally specify `-f` to build `sdist` or `wheel` only.
|
||||
Built files can be found in the `/dist` directory.
|
309
README.md
309
README.md
|
@ -3,6 +3,10 @@
|
|||
<a href="https://github.com/devine-dl/devine">Devine</a>
|
||||
<br/>
|
||||
<sup><em>Open-Source Movie, TV, and Music Downloading Solution</em></sup>
|
||||
<br/>
|
||||
<a href="https://discord.gg/34K2MGDrBN">
|
||||
<img src="https://img.shields.io/discord/841055398240059422?label=&logo=discord&logoColor=ffffff&color=7289DA&labelColor=7289DA" alt="Discord">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
|
@ -15,34 +19,43 @@
|
|||
<a href="https://deepsource.io/gh/devine-dl/devine/?ref=repository-badge">
|
||||
<img src="https://deepsource.io/gh/devine-dl/devine.svg/?label=active+issues&token=1ADCbjJ3FPiGT_s0Y0rlugGU" alt="DeepSource">
|
||||
</a>
|
||||
<a href="https://discord.gg/34K2MGDrBN">
|
||||
<img src="https://img.shields.io/discord/841055398240059422?label=&logo=discord&logoColor=ffffff&color=7289DA&labelColor=7289DA" alt="Discord">
|
||||
<br/>
|
||||
<a href="https://github.com/astral-sh/ruff">
|
||||
<img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Linter: Ruff">
|
||||
</a>
|
||||
<a href="https://python-poetry.org">
|
||||
<img src="https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json" alt="Dependency management: Poetry">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## Features
|
||||
|
||||
- 🎥 Supports Movies, TV shows, and Music
|
||||
- 🧩 Easy installation via PIP/PyPI
|
||||
- 👥 Multi-profile authentication per-service with credentials or cookies
|
||||
- 🚀 Seamless Installation via [pip](#installation)
|
||||
- 🎥 Movie, Episode, and Song Service Frameworks
|
||||
- 🛠️ Built-in [DASH] and [HLS] Parsers
|
||||
- 🔒 Widevine DRM integration via [pywidevine](https://github.com/devine-dl/pywidevine)
|
||||
- 💾 Local & Remote DRM Key-vaults
|
||||
- 🌍 Local & Remote Widevine CDMs
|
||||
- 👥 Multi-profile Authentication per-service with Credentials and/or Cookies
|
||||
- 🤖 Automatic P2P filename structure with Group Tag
|
||||
- 🛠️ Flexible Service framework system
|
||||
- 📦 Portable Installations
|
||||
- 🗃️ Local and Remote SQL-based Key Vault database
|
||||
- ⚙️ YAML for Configuration
|
||||
- 🌍 Local and Remote Widevine CDMs
|
||||
- ❤️ Fully Open-Source! Pull Requests Welcome
|
||||
|
||||
[DASH]: <devine/core/manifests/dash.py>
|
||||
[HLS]: <devine/core/manifests/hls.py>
|
||||
|
||||
## Installation
|
||||
|
||||
```shell
|
||||
$ pip install devine
|
||||
```
|
||||
|
||||
> __Note__ If you see warnings about a path not being in your PATH environment variable, add it, or `devine` won't run.
|
||||
> [!NOTE]
|
||||
> If pip gives you a warning about a path not being in your PATH environment variable then promptly add that path then
|
||||
> close all open command prompt/terminal windows, or `devine` won't work as it will not be found.
|
||||
|
||||
Voilà 🎉! You now have the `devine` package installed and a `devine` executable is now available.
|
||||
Check it out with `devine --help`!
|
||||
Voilà 🎉 — You now have the `devine` package installed!
|
||||
A command-line interface is now available, try `devine --help`.
|
||||
|
||||
### Dependencies
|
||||
|
||||
|
@ -68,77 +81,165 @@ able to be found.
|
|||
[MKVToolNix]: <https://mkvtoolnix.download/downloads.html>
|
||||
[shaka-packager]: <https://github.com/google/shaka-packager/releases/latest>
|
||||
|
||||
### Services
|
||||
## Usage
|
||||
|
||||
Devine does not come with any infringing Service code. You must develop your own Service code and place them in
|
||||
the `/devine/services` directory. There are different ways the add services depending on your installation type.
|
||||
In some cases you may use multiple of these methods to have separate copies.
|
||||
First, take a look at `devine --help` for a full help document, listing all commands available and giving you more
|
||||
information on what can be done with Devine.
|
||||
|
||||
Please refrain from making or using Service code unless you have full rights to do so. I also recommend ensuring that
|
||||
you keep the Service code private and secure, i.e. a private repository or keeping it offline.
|
||||
Here's a checklist on what I recommend getting started with, in no particular order,
|
||||
|
||||
No matter which method you use, make sure that you install any further dependencies needed by the services. There's
|
||||
currently no way to have these dependencies automatically install apart from within the Fork method.
|
||||
- [ ] Add [Services](#services), these will be used in `devine dl`.
|
||||
- [ ] Add [Profiles](#profiles-cookies--credentials), these are your cookies and credentials.
|
||||
- [ ] Add [Widevine Provisions](#widevine-provisions), also known as CDMs, these are used for DRM-protected content.
|
||||
- [ ] Set your Group Tag, the text at the end of the final filename, e.g., `devine cfg tag NOGRP` for `...-NOGRP`.
|
||||
- [ ] Set Up a Local Key Vault, take a look at the [Key Vaults Config](CONFIG.md#keyvaults-listdict).
|
||||
|
||||
> __Warning__ Please be careful with who you trust and what you run. The users you collaborate with on Service
|
||||
And here's some more advanced things you could take a look at,
|
||||
|
||||
- [ ] Setting default Headers that the Request Session uses.
|
||||
- [ ] Setting default Profiles and CDM Provisions to use for services.
|
||||
- [ ] NordVPN and Hola Proxy Providers for automatic proxies.
|
||||
- [ ] Hosting and/or Using Remote Key Vaults.
|
||||
- [ ] Serving and/or Using Remote CDM Provisions.
|
||||
|
||||
Documentation on the config is available in the [CONFIG.md](CONFIG.md) file, it has a lot of handy settings.
|
||||
If you start to get sick of putting something in your CLI call, then I recommend taking a look at it!
|
||||
|
||||
## Services
|
||||
|
||||
Unlike similar project's such as [youtube-dl], Devine does not currently come with any Services. You must develop your
|
||||
own Services and only use Devine with Services you have the legal right to do so.
|
||||
|
||||
> [!NOTE]
|
||||
> If you made a Service for Devine that does not use Widevine or any other DRM systems, feel free to make a Pull Request
|
||||
> and make your service available to others. Any Service on [youtube-dl] (or [yt-dlp]) would be able to be added to the
|
||||
> Devine repository as they both use the [Unlicense license] therefore direct reading and porting of their code would be
|
||||
> legal.
|
||||
|
||||
[youtube-dl]: <https://github.com/ytdl-org/youtube-dl>
|
||||
[yt-dlp]: <https://github.com/yt-dlp/yt-dlp>
|
||||
[Unlicense license]: <https://choosealicense.com/licenses/unlicense>
|
||||
|
||||
### Creating a Service
|
||||
|
||||
> [!WARNING]
|
||||
> Only create or use Service Code with Services you have full legal right to do so.
|
||||
|
||||
A Service consists of a folder with an `__init__.py` file. The file must contain a class of the same name as the folder.
|
||||
The class must inherit the [Service] class and implement all the abstracted methods. It must finally implement a new
|
||||
method named `cli` where you define CLI arguments.
|
||||
|
||||
1. Make a new folder within `/devine/services`. The folder name you choose will be what's known as the [Service Tag].
|
||||
This "tag" is used in the final output filename of downloaded files, for various code-checks, lookup keys in
|
||||
key-vault databases, and more.
|
||||
2. Within the new folder create an `__init__.py` file and write a class inheriting the [Service] class. It must be named
|
||||
the exact same as the folder. It is case-sensitive.
|
||||
3. Implement all the methods of the Service class you are inheriting that are marked as abstract.
|
||||
4. Define CLI arguments by implementing a `cli` method. This method must be static (i.e. `@staticmethod`). For example
|
||||
to implement the bare minimum to receive a Title ID of sorts:
|
||||
```python
|
||||
@staticmethod
|
||||
@click.command(name="YT", short_help="https://youtube.com", help=__doc__)
|
||||
@click.argument("title", type=str)
|
||||
@click.pass_context
|
||||
def cli(ctx, **kwargs):
|
||||
return YT(ctx, **kwargs)
|
||||
```
|
||||
You must implement this `cli` method, even if you do not want or need any CLI arguments. It is required for the core
|
||||
CLI functionality to be able to find and call the class.
|
||||
5. Accept the CLI arguments by overriding the constructor (the `__init__()` method):
|
||||
```python
|
||||
def __init__(self, ctx, title):
|
||||
self.title = title
|
||||
super().__init__(ctx) # important
|
||||
# ... the title is now available across all methods by calling self.title
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> - All methods of your class inherited from `Service` marked as abstract (`@abstractmethod`) MUST be implemented by
|
||||
> your class.
|
||||
> - When overriding any method (e.g., `__init__()` method) you MUST super call it, e.g., `super().__init__()` at the
|
||||
> top of the override. This does not apply to any abstract methods, as they are unimplemented.
|
||||
> - If preparing your Requests Session with global headers or such, then you should override the `get_session` method,
|
||||
> then modify `self.session`. Do not manually make `self.session` from scratch.
|
||||
|
||||
> [!TIP]
|
||||
> 1. To make web requests use the `self.session` class instance variable, e.g. `self.session.get(url)`.
|
||||
> 2. If you make a `config.yaml` file next to your `__init__.py`, you can access it with `self.config`.
|
||||
> 3. You can include any arbitrary file within your Service folder for use by your Service. For example TLS certificate
|
||||
> files, or other python files with helper functions and classes.
|
||||
|
||||
[Service]: <devine/core/service.py>
|
||||
[Service Tag]: <#service-tags>
|
||||
|
||||
### Service Tags
|
||||
|
||||
Service tags generally follow these rules:
|
||||
|
||||
- Tag must be between 2-4 characters long, consisting of just `[A-Z0-9i]{2,4}`.
|
||||
- Lower-case `i` is only used for select services. Specifically BBC iPlayer and iTunes.
|
||||
- If the Service's commercial name has a `+` or `Plus`, the last character should be a `P`.
|
||||
E.g., `ATVP` for `Apple TV+`, `DSCP` for `Discovery+`, `DSNP` for `Disney+`, and `PMTP` for `Paramount+`.
|
||||
|
||||
These rules are not exhaustive and should only be used as a guide. You don't strictly have to follow these rules, but
|
||||
I recommend doing so for consistency.
|
||||
|
||||
### Sharing Services
|
||||
|
||||
Sending and receiving zipped Service folders is quite cumbersome. Let's explore alternative routes to collaborating on
|
||||
Service Code.
|
||||
|
||||
> [!WARNING]
|
||||
> Please be careful with who you trust and what you run. The users you collaborate with on Service
|
||||
> code could update it with malicious code that you would run via devine on the next call.
|
||||
|
||||
#### via Copy & Paste
|
||||
#### Forking
|
||||
|
||||
If you have service code already and wish to just install and use it locally, then simply putting it into the Services
|
||||
directory of your local pip installation will do the job. However, this method is the worst in terms of collaboration.
|
||||
If you are collaborating with a team on multiple services then forking the project is the best way to go.
|
||||
|
||||
1. Get the installation directory by running the following in terminal,
|
||||
`python -c 'import os,devine.__main__ as a;print(os.path.dirname(a.__file__))'`
|
||||
2. Head to the installation directory and create a `services` folder if one is not yet created.
|
||||
3. Within that `services` folder you may install or create service code.
|
||||
1. [Fork the project](https://github.com/devine-dl/devine/fork) and make sure it is Private.
|
||||
2. (optionally) Hard reset to the latest stable version by tag. E.g., `git reset --hard v1.0.0`.
|
||||
3. Add all your Services to the `/devine/services` folder and commit them to your fork.
|
||||
|
||||
> __Warning__ Uninstalling Python or Devine may result in the Services you installed being deleted. Make sure you back
|
||||
> up the services before uninstalling.
|
||||
Now commit changes or additions within that services folder to your forked repository.
|
||||
Once committed all your other team members can easily pull changes as well as push new changes.
|
||||
|
||||
#### via a Forked Repository
|
||||
When a new update comes out you can easily rebase your fork to that commit to update. However, please make sure you
|
||||
look at changes between each version before rebasing and resolve any breaking changes and deprecations when rebasing to
|
||||
a new version.
|
||||
|
||||
If you are collaborating with a team on multiple services then forking the project is the best way to go. I recommend
|
||||
forking the project then hard resetting to the latest stable update by tag. Once a new stable update comes out you can
|
||||
easily rebase your fork to that commit to update.
|
||||
If you are new to `git` then take a look at [GitHub Desktop](https://desktop.github.com).
|
||||
|
||||
However, please make sure you look at changes between each version before rebasing and resolve any breaking changes and
|
||||
deprecations when rebasing to a new version.
|
||||
> [!TIP]
|
||||
> A huge benefit with this method is that you can also sync dependencies by your own Services as well!
|
||||
> Just use `poetry` to add or modify dependencies appropriately and commit the changed `poetry.lock`.
|
||||
> However, if the core project also has dependency changes your `poetry.lock` changes will conflict and you
|
||||
> will need to learn how to do conflict resolution/rebasing. It is worth it though!
|
||||
|
||||
1. Fork the project with `git` or GitHub [(fork)](https://github.com/devine-dl/devine/fork).
|
||||
2. Head inside the root `devine` directory and create a `services` directory.
|
||||
3. Within that `services` folder you may install or create service code.
|
||||
#### Symlinking
|
||||
|
||||
You may now commit changes or additions within that services folder to your forked repository.
|
||||
Once committed all your other team members can easily sync and contribute changes.
|
||||
|
||||
> __Note__ You may add Service-specific Python dependencies using `poetry` that can install alongside the project.
|
||||
> Just do note that this will complicate rebasing when even the `poetry.lock` gets updates in the upstream project.
|
||||
|
||||
#### via Cloud storage (symlink)
|
||||
|
||||
This is a great option for those who wish to do something like the forking method, but without the need of constantly
|
||||
rebasing their fork to the latest version. Overall less knowledge on git would be required, but each user would need
|
||||
to do a bit of symlinking compared to the fork method.
|
||||
This is a great option for those who wish to do something like the forking method, but may not care what changes
|
||||
happened or when and just want changes synced across a team.
|
||||
|
||||
This also opens up the ways you can host or collaborate on Service code. As long as you can receive a directory that
|
||||
updates with just the services within it, then you're good to go. Options could include an FTP server, Shared Google
|
||||
Drive, a non-fork repository with just services, and more.
|
||||
|
||||
1. Follow the steps in the [Copy & Paste method](#via-copy--paste) to create the `services` folder.
|
||||
2. Use any Cloud Source that gives you a pseudo-directory to access the Service files. E.g., rclone or google drive fs.
|
||||
3. Symlink the services directory from your Cloud Source to the new services folder you made.
|
||||
(you may need to delete it first)
|
||||
1. Use any Cloud Source that gives you a pseudo-directory to access the Service files like a normal drive. E.g., rclone,
|
||||
Google Drive Desktop (aka File Stream), Air Drive, CloudPool, etc.
|
||||
2. Create a `services` directory somewhere in it and have all your services within it.
|
||||
3. [Symlink](https://en.wikipedia.org/wiki/Symbolic_link) the `services` directory to the `/devine` folder. You should
|
||||
end up with `/devine/services` folder containing services, not `/devine/services/services`.
|
||||
|
||||
Of course, you have to make sure the original folder keeps receiving and downloading/streaming those changes, or that
|
||||
you keep git pulling those changes. You must also make sure that the version of devine you have locally is supported by
|
||||
the Services code.
|
||||
You have to make sure the original folder keeps receiving and downloading/streaming those changes. You must also make
|
||||
sure that the version of devine you have locally is supported by the Service code.
|
||||
|
||||
> __Note__ If you're using a cloud source that downloads the file once it gets opened, you don't have to worry as those
|
||||
> will automatically download. Python importing the files triggers the download to begin. However, it may cause a delay
|
||||
> on startup.
|
||||
> [!NOTE]
|
||||
> If you're using a cloud source that downloads the file once it gets opened, you don't have to worry as those will
|
||||
> automatically download. Python importing the files triggers the download to begin. However, it may cause a delay on
|
||||
> startup.
|
||||
|
||||
### Profiles (Cookies & Credentials)
|
||||
## Profiles (Cookies & Credentials)
|
||||
|
||||
Just like a streaming service, devine associates both a cookie and/or credential as a Profile. You can associate up to
|
||||
one cookie and one credential per-profile, depending on which (or both) are needed by the Service. This system allows
|
||||
|
@ -155,7 +256,7 @@ You can also delete a credential with `devine auth delete`. E.g., to delete the
|
|||
> __Note__ Profile names are case-sensitive and unique per-service. They also have no arbitrary character or length
|
||||
> limit, but for convenience I don't recommend using any special characters as your terminal may get confused.
|
||||
|
||||
#### Cookie file format and Extensions
|
||||
### Cookie file format and Extensions
|
||||
|
||||
Cookies must be in the standard Netscape cookies file format.
|
||||
Recommended Cookie exporter extensions:
|
||||
|
@ -172,7 +273,7 @@ Any other extension that exports to the standard Netscape format should theoreti
|
|||
> versions floating around (usually just older versions of the extension), but since there are safe alternatives I'd
|
||||
> just avoid it altogether. Source: https://reddit.com/r/youtubedl/comments/10ar7o7
|
||||
|
||||
### Widevine Provisions
|
||||
## Widevine Provisions
|
||||
|
||||
A Widevine Provision is needed for acquiring licenses containing decryption keys for DRM-protected content.
|
||||
They are not needed if you will be using devine on DRM-free services. Please do not ask for any Widevine Device Files,
|
||||
|
@ -188,50 +289,9 @@ From here you can then set which WVD to use for each specific service. It's best
|
|||
provision where possible.
|
||||
|
||||
An alternative would be using a pywidevine Serve-compliant CDM API. Of course, you would need to know someone who is
|
||||
serving one, and they would need to give you access. Take a look at the [remote_cdm](CONFIG.md#remotecdm--listdict--)
|
||||
serving one, and they would need to give you access. Take a look at the [remote_cdm](CONFIG.md#remotecdm-listdict)
|
||||
config option for setup information. For further information on it see the pywidevine repository.
|
||||
|
||||
## Usage
|
||||
|
||||
First, take a look at `devine --help` for a full help document, listing all commands available and giving you more
|
||||
information on what can be done with Devine.
|
||||
|
||||
Here's a checklist on what I recommend getting started with, in no particular order,
|
||||
|
||||
- [ ] Add [Services](#services), these will be used in `devine dl`.
|
||||
- [ ] Add [Profiles](#profiles--cookies--credentials-), these are your cookies and credentials.
|
||||
- [ ] Add [Widevine Provisions](#widevine-provisions), also known as CDMs, these are used for DRM-protected content.
|
||||
- [ ] Set your Group Tag, the text at the end of the final filename, e.g., `devine cfg tag NOGRP` for ...-NOGRP.
|
||||
- [ ] Set Up a Local Key Vault, take a look at the [Key Vaults Config](CONFIG.md#keyvaults--listdict--).
|
||||
|
||||
And here's some more advanced things you could take a look at,
|
||||
|
||||
- [ ] Setting default Headers that the Request Session uses.
|
||||
- [ ] Setting default Profiles and CDM Provisions to use for services.
|
||||
- [ ] NordVPN and Hola Proxy Providers for automatic proxies.
|
||||
- [ ] Hosting and/or Using Remote Key Vaults.
|
||||
- [ ] Serving and/or Using Remote CDM Provisions.
|
||||
|
||||
Documentation on the config is available in the [CONFIG.md](CONFIG.md) file, it has a lot of handy settings.
|
||||
If you start to get sick of putting something in your CLI call, then I recommend taking a look at it!
|
||||
|
||||
## Development
|
||||
|
||||
The following steps are instructions on downloading, preparing, and running the code under a [Poetry] environment.
|
||||
You can skip steps 3-5 with a simple `pip install .` call instead, but you miss out on a wide array of benefits.
|
||||
|
||||
1. `git clone https://github.com/devine-dl/devine`
|
||||
2. `cd devine`
|
||||
3. (optional) `poetry config virtualenvs.in-project true`
|
||||
4. `poetry install`
|
||||
5. `poetry run devine --help`
|
||||
|
||||
As seen in Step 5, running the `devine` executable is somewhat different to a normal PIP installation.
|
||||
See [Poetry's Docs] on various ways of making calls under the virtual-environment.
|
||||
|
||||
[Poetry]: <https://python-poetry.org>
|
||||
[Poetry's Docs]: <https://python-poetry.org/docs/basic-usage/#using-your-virtual-environment>
|
||||
|
||||
## End User License Agreement
|
||||
|
||||
Devine and it's community pages should be treated with the same kindness as other projects.
|
||||
|
@ -246,31 +306,22 @@ Please refrain from spam or asking for questions that infringe upon a Service's
|
|||
back immediately.
|
||||
5. Be kind to one another and do not single anyone out.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
1. This project requires a valid Google-provisioned Private/Public Keypair and a Device-specific Client Identification
|
||||
blob; neither of which are included with this project.
|
||||
2. Public testing provisions are available and provided by Google to use for testing projects such as this one.
|
||||
3. License Servers have the ability to block requests from any provision, and are likely already blocking test provisions
|
||||
on production endpoints. Therefore, have the ability to block the usage of Devine by themselves.
|
||||
4. This project does not condone piracy or any action against the terms of the Service or DRM system.
|
||||
5. All efforts in this project have been the result of Reverse-Engineering and Publicly available research.
|
||||
|
||||
## Credit
|
||||
|
||||
- The awesome community for their shared research and insight into the Widevine Protocol and Key Derivation.
|
||||
|
||||
## Contributors
|
||||
|
||||
<a href="https://github.com/rlaphoenix"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/17136956?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt=""/></a>
|
||||
<a href="https://github.com/mnmll"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/22942379?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt=""/></a>
|
||||
<a href="https://github.com/shirt-dev"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/2660574?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt=""/></a>
|
||||
<a href="https://github.com/nyuszika7h"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/482367?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt=""/></a>
|
||||
<a href="https://github.com/bccornfo"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/98013276?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt=""/></a>
|
||||
<a href="https://github.com/Arias800"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/24809312?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt=""/></a>
|
||||
<a href="https://github.com/varyg1001"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/88599103?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt=""/></a>
|
||||
<a href="https://github.com/Hollander-1908"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/93162595?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt=""/></a>
|
||||
<a href="https://github.com/rlaphoenix"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/17136956?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt="rlaphoenix"/></a>
|
||||
<a href="https://github.com/mnmll"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/22942379?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt="mnmll"/></a>
|
||||
<a href="https://github.com/shirt-dev"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/2660574?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt="shirt-dev"/></a>
|
||||
<a href="https://github.com/nyuszika7h"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/482367?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt="nyuszika7h"/></a>
|
||||
<a href="https://github.com/bccornfo"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/98013276?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt="bccornfo"/></a>
|
||||
<a href="https://github.com/Arias800"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/24809312?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt="Arias800"/></a>
|
||||
<a href="https://github.com/varyg1001"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/88599103?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt="varyg1001"/></a>
|
||||
<a href="https://github.com/Hollander-1908"><img src="https://images.weserv.nl/?url=avatars.githubusercontent.com/u/93162595?v=4&h=25&w=25&fit=cover&mask=circle&maxage=7d" alt="Hollander-1908"/></a>
|
||||
|
||||
## License
|
||||
## Licensing
|
||||
|
||||
© 2019-2023 rlaphoenix — [GNU General Public License, Version 3.0](LICENSE)
|
||||
This software is licensed under the terms of [GNU General Public License, Version 3.0](LICENSE).
|
||||
You can find a copy of the license in the LICENSE file in the root folder.
|
||||
|
||||
* * *
|
||||
|
||||
© rlaphoenix 2019-2023
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,76 +1,91 @@
|
|||
[build-system]
|
||||
requires = ['poetry-core>=1.0.0']
|
||||
build-backend = 'poetry.core.masonry.api'
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry]
|
||||
name = 'devine'
|
||||
version = '2.2.0'
|
||||
description = 'Open-Source Movie, TV, and Music Downloading Solution'
|
||||
license = 'GPL-3.0-only'
|
||||
authors = ['rlaphoenix <rlaphoenix@pm.me>']
|
||||
readme = 'README.md'
|
||||
homepage = 'https://github.com/devine-dl/devine'
|
||||
repository = 'https://github.com/devine-dl/devine'
|
||||
keywords = ['widevine', 'drm', 'downloader']
|
||||
name = "devine"
|
||||
version = "2.2.0"
|
||||
description = "Open-Source Movie, TV, and Music Downloading Solution."
|
||||
license = "GPL-3.0-only"
|
||||
authors = ["rlaphoenix <rlaphoenix@pm.me>"]
|
||||
readme = "README.md"
|
||||
homepage = "https://github.com/devine-dl/devine"
|
||||
repository = "https://github.com/devine-dl/devine"
|
||||
keywords = ["python", "downloader", "drm", "widevine"]
|
||||
classifiers = [
|
||||
'Development Status :: 4 - Beta',
|
||||
'Environment :: Console',
|
||||
'Intended Audience :: End Users/Desktop',
|
||||
'Natural Language :: English',
|
||||
'Operating System :: OS Independent',
|
||||
'Topic :: Multimedia :: Video',
|
||||
'Topic :: Security :: Cryptography',
|
||||
"Development Status :: 4 - Beta",
|
||||
"Environment :: Console",
|
||||
"Intended Audience :: End Users/Desktop",
|
||||
"Natural Language :: English",
|
||||
"Operating System :: OS Independent",
|
||||
"Topic :: Multimedia :: Video",
|
||||
"Topic :: Security :: Cryptography",
|
||||
]
|
||||
include = [
|
||||
{ path = "CHANGELOG.md", format = "sdist" },
|
||||
{ path = "README.md", format = "sdist" },
|
||||
{ path = "LICENSE", format = "sdist" },
|
||||
]
|
||||
|
||||
[tool.poetry.urls]
|
||||
"Issues" = "https://github.com/devine-dl/devine/issues"
|
||||
"Discussions" = "https://github.com/devine-dl/devine/discussions"
|
||||
"Changelog" = "https://github.com/devine-dl/devine/blob/master/CHANGELOG.md"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.9.0,<3.12"
|
||||
appdirs = "^1.4.4"
|
||||
Brotli = "^1.0.9"
|
||||
click = "^8.1.4"
|
||||
Brotli = "^1.1.0"
|
||||
click = "^8.1.7"
|
||||
construct = "^2.8.8"
|
||||
crccheck = "^1.3.0"
|
||||
jsonpickle = "^3.0.1"
|
||||
jsonpickle = "^3.0.2"
|
||||
langcodes = { extras = ["data"], version = "^3.3.0" }
|
||||
lxml = "^4.9.3"
|
||||
pproxy = "^2.7.8"
|
||||
protobuf = "4.21.6"
|
||||
pycaption = "^2.1.1"
|
||||
pycryptodomex = "^3.18.0"
|
||||
pyjwt = "^2.7.0"
|
||||
pycryptodomex = "^3.19.0"
|
||||
pyjwt = "^2.8.0"
|
||||
pymediainfo = "^6.0.1"
|
||||
pymp4 = "^1.4.0"
|
||||
pymysql = "^1.1.0"
|
||||
pywidevine = { extras = ["serve"], version = "^1.6.0" }
|
||||
PyYAML = "^6.0"
|
||||
PyYAML = "^6.0.1"
|
||||
requests = { extras = ["socks"], version = "^2.31.0" }
|
||||
rich = "^13.4.2"
|
||||
rich = "^13.5.3"
|
||||
"rlaphoenix.m3u8" = "^3.4.0"
|
||||
"ruamel.yaml" = "^0.17.32"
|
||||
sortedcontainers = "^2.4.0"
|
||||
subtitle-filter = "^1.4.6"
|
||||
Unidecode = "^1.3.6"
|
||||
urllib3 = "^2.0.3"
|
||||
urllib3 = "^2.0.4"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pre-commit = "^3.3.3"
|
||||
mypy = "^1.4.1"
|
||||
pre-commit = "^3.4.0"
|
||||
mypy = "^1.5.1"
|
||||
mypy-protobuf = "^3.3.0"
|
||||
types-protobuf = "^3.19.22"
|
||||
types-PyMySQL = "^1.1.0.0"
|
||||
types-requests = "^2.31.0.1"
|
||||
types-protobuf = "^4.24.0.1"
|
||||
types-PyMySQL = "^1.1.0.1"
|
||||
types-requests = "^2.31.0.2"
|
||||
isort = "^5.12.0"
|
||||
ruff = "^0.0.292"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
devine = 'devine.core.__main__:main'
|
||||
devine = "devine.core.__main__:main"
|
||||
|
||||
[tool.ruff]
|
||||
force-exclude = true
|
||||
line-length = 120
|
||||
select = ["E4", "E7", "E9", "F", "W"]
|
||||
|
||||
[tool.isort]
|
||||
line_length = 120
|
||||
line_length = 118
|
||||
|
||||
[tool.mypy]
|
||||
exclude = '_pb2\.pyi?$'
|
||||
check_untyped_defs = true
|
||||
disallow_incomplete_defs = true
|
||||
disallow_untyped_defs = true
|
||||
follow_imports = 'silent'
|
||||
follow_imports = "silent"
|
||||
ignore_missing_imports = true
|
||||
no_implicit_optional = true
|
||||
|
|
Loading…
Reference in New Issue