Browse Source

Merge branch 'release/v0.12.0'

master v0.12.0
LecygneNoir 3 years ago
parent
commit
bcb0e267f3
11 changed files with 371 additions and 408 deletions
  1. +14
    -1
      CHANGELOG.md
  2. +41
    -32
      README.md
  3. +112
    -206
      poetry.lock
  4. +8
    -1
      prismedia/__init__.py
  5. +11
    -2
      prismedia/genconfig.py
  6. +1
    -1
      prismedia/pt_upload.py
  7. +15
    -43
      prismedia/upload.py
  8. +13
    -0
      prismedia/utils.py
  9. +43
    -17
      prismedia/yt_upload.py
  10. +16
    -17
      pyproject.toml
  11. +97
    -88
      requirements.txt

+ 14
- 1
CHANGELOG.md View File

@ -1,8 +1,21 @@
# Changelog
## v0.12.0
### Features
- Add `--heartbeat` option to send request to youtube API, avoiding youtube to disabling you API account if you do not upload video often (Thanks @Zykino see #54)
- Rework and improve genconfig process to avoid erasing existing configuration and make it more easy to use
- Add a `prismedia-init` script when installing prismedia to easily generate basic configuration (see #55)
- Update multiple dependencies used for prismedia as they were very old.
- Add auto search for thumbnail in `.png` in addition to `.jpg` and `.jepg`.
### Fixes
- Add pagination for youtube playlist to search for all user playlists (Thanks @Zykino)
- Remove file format check for both videos and thumbnail as Youtube and Peertube now accepts more than .mp4 and .jpg (see #60)
## v0.11.0
## Features
### Features
- Add the configuration of Original date of Record for Youtube and Peertube (see #50)
- Add a progress bar when uploading on Peertube (Thanks @Zykino, see #52)

+ 41
- 32
README.md View File

@ -23,56 +23,58 @@ Scripting your way to upload videos to peertube and youtube. Works with Python 3
### From pip
Simply install with
```bash
Simply install with
```sh
pip install prismedia
```
Upgrade with
```bash
Upgrade with
```sh
pip install --upgrade prismedia
```
### From source
Get the source:
```bash
Get the source:
```sh
git clone https://git.lecygnenoir.info/LecygneNoir/prismedia.git prismedia
```
You may use pip to install requirements: `pip install -r requirements.txt` if you want to use the script directly.
(*note:* requirements are generated via `poetry export -f requirements.txt`)
(**note:** requirements are generated via `poetry export -f requirements.txt`)
Otherwise, you can use [poetry](https://python-poetry.org), which create a virtualenv for the project directly
(Or use the existing virtualenv if one is activated)
```
```sh
poetry install
```
## Configuration
Generate sample files with `python -m prismedia.genconfig`.
Then rename and edit `peertube_secret` and `youtube_secret.json` with your credentials. (see below)
Generate configuration files by running `prismedia-init`.
Then, edit them to fill your credential as explained below.
### Peertube
Set your credentials, peertube server URL.
You can get client_id and client_secret by logging in your peertube website and reaching the URL:
Configuration is in **peertube_secret** file.
You need your usual credentials and Peertube instance URL, in addition with API client_id and client_secret.
You can get client_id and client_secret by logging in your peertube instance and reaching the URL:
https://domain.example/api/v1/oauth-clients/local
You can set ``OAUTHLIB_INSECURE_TRANSPORT`` to 1 if you do not use https (not recommended)
*Alternatively, you can set ``OAUTHLIB_INSECURE_TRANSPORT`` to 1 if you do not use https (not recommended)*
### Youtube
Configuration is in **youtube_secret.json** file.
Youtube uses combination of oauth and API access to identify.
**Credentials**
The first time you connect, prismedia will open your browser to ask you to authenticate to
Youtube and allow the app to use your Youtube channel.
**It is here you choose which channel you will upload to**.
Once authenticated, the token is stored inside the file ``.youtube_credentials.json``.
Once authenticated, the token is stored inside the file `.youtube_credentials.json`.
Prismedia will try to use this file at each launch, and re-ask for authentication if it does not exist.
**Oauth**:
@ -92,51 +94,58 @@ If you plan a larger usage, please consider creating your own youtube_secret fil
Support only mp4 for cross compatibility between Youtube and Peertube.
**Note that all options may be specified in a NFO file!** (see [Enhanced NFO](#enhanced-use-of-nfo))
Here are some demonstration of main usage you would like!
Here are some demonstration of main usage:
Upload a video:
```
```sh
prismedia --file="yourvideo.mp4"
```
Specify description and tags:
```
```sh
prismedia --file="yourvideo.mp4" -d "My supa description" -t "tag1,tag2,foo"
```
Provide a thumbnail:
```
```sh
prismedia --file="yourvideo.mp4" -d "Video with thumbnail" --thumbnail="/path/to/your/thumbnail.jpg"
```
Publish on Peertube only, while using a channel and a playlist, creating them if they does not exist.:
```
Publish on Peertube only, while using a channel and a playlist, creating them if they do not exist:
```sh
prismedia --file="yourvideo.mp4" --platform=peertube --channel="Cooking recipes" --playlist="Cake recipes" --channelCreate --playlistCreate
```
Use a NFO file to specify your video options:
(See [Enhanced NFO](#enhanced-use-of-nfo) for more precise example)
```
```sh
prismedia --file="yourvideo.mp4" --nfo /path/to/your/nfo.txt
```
Use some credits to show some activity for you apikey so the platform know it is used and would not put your quota to 0 (only Youtube currently).
Take a look at all available options with `--help`!
To prevent Youtube from inactivating your apikey after 90days of inactivity it is recommended to launch this command automatically from a script around once a month. It will mwke a call to use a few credits from your daily quota.
On Linux and MacOS, you can use cron, on Windows the "Task Scheduler".
```sh
prismedia --hearthbeat
```
Take a look at all available options with `--help`!
```sh
prismedia --help
```
## Enhanced use of NFO
Since Prismedia v0.9.0, the NFO system has been improved to allow hierarchical loading.
First of all, **if you already used nfo**, either with `--nfo` or by using `videoname.txt`, nothing changes :-)
First, **if you already used nfo**, either with `--nfo` or by using `videoname.txt`, nothing changes :-)
But you are now able to use a more flexible NFO system, by using priorities. This allow you to set some defaults to avoid recreating a full nfo for each video
But you are now able to use a more flexible NFO system, by using priorities. This allows you to set some defaults to avoid recreating a full nfo for each video
Basically, Prismedia will now load options in this order, using the last value found in case of conflict:
`nfo.txt < directory_name.txt < video_name.txt < command line NFO < command line argument`
You'll find a complete set of samples in the [prismedia/samples](prismedia/samples) directory so let's take it as an example:
```
```sh
$ tree Recipes/
Recipes/
├── cli_nfo.txt
@ -149,8 +158,8 @@ Recipes/
└── yourvideo2.txt
```
By using
```
By using
```sh
prismedia --file=/path/to/Recipes/yourvideo1.mp4 --nfo=/path/to/Recipes/cli_nfo.txt --cca
```
@ -186,7 +195,7 @@ Available strict options:
- --withPlatform Prevent the upload if at least one platform is not specified
- --withCategory Prevent the upload if no category
- --withLanguage Prevent upload if no language
- --withChannel Prevent upload if no channel
- --withChannel Prevent upload if no channel
## Features
@ -224,4 +233,4 @@ Available strict options:
Inspired by [peeror](https://git.rigelk.eu/rigelk/peeror) and [youtube-upload](https://github.com/tokland/youtube-upload)
## Contributors
Thanks to: @Zykino, @meewan, @rigelk 😘
Thanks to: @LecygneNoir, @Zykino, @meewan, @rigelk 😘

+ 112
- 206
poetry.lock View File

@ -14,14 +14,6 @@ optional = false
python-versions = "*"
version = "3.1.1"
[[package]]
category = "main"
description = "Extensible memoizing collections and decorators"
name = "cachetools"
optional = false
python-versions = "~=3.5"
version = "4.2.0"
[[package]]
category = "main"
description = "Python package for providing Mozilla's CA Bundle."
@ -51,15 +43,15 @@ args = "*"
[[package]]
category = "main"
description = "Updated configparser from Python 3.7 for Python 2.6+."
description = "Updated configparser from Python 3.8 for Python 2.6+."
name = "configparser"
optional = false
python-versions = ">=2.6"
version = "3.8.1"
python-versions = ">=3.6"
version = "5.0.2"
[package.extras]
docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
testing = ["pytest (>=3.5,<3.7.3 || >3.7.3)", "pytest-checkdocs (>=1.2)", "pytest-flake8"]
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "pytest-black (>=0.3.7)", "pytest-mypy"]
[[package]]
category = "main"
@ -83,29 +75,7 @@ description = "Clean single-source support for Python 3 and 2"
name = "future"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
version = "0.17.1"
[[package]]
category = "main"
description = "Google API client core library"
name = "google-api-core"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
version = "1.23.0"
[package.dependencies]
google-auth = ">=1.21.1,<2.0dev"
googleapis-common-protos = ">=1.6.0,<2.0dev"
protobuf = ">=3.12.0"
pytz = "*"
requests = ">=2.18.0,<3.0.0dev"
setuptools = ">=34.0.0"
six = ">=1.13.0"
[package.extras]
grpc = ["grpcio (>=1.29.0,<2.0dev)"]
grpcgcp = ["grpcio-gcp (>=0.2.2)"]
grpcio-gcp = ["grpcio-gcp (>=0.2.2)"]
version = "0.18.2"
[[package]]
category = "main"
@ -113,11 +83,12 @@ description = "Google API client core library"
name = "google-api-core"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*"
version = "1.25.0"
version = "1.26.3"
[package.dependencies]
google-auth = ">=1.21.1,<2.0dev"
googleapis-common-protos = ">=1.6.0,<2.0dev"
packaging = ">=14.3"
protobuf = ">=3.12.0"
pytz = "*"
requests = ">=2.18.0,<3.0.0dev"
@ -134,45 +105,24 @@ category = "main"
description = "Google API Client Library for Python"
name = "google-api-python-client"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
version = "1.12.2"
python-versions = ">=3.6"
version = "2.1.0"
[package.dependencies]
google-api-core = ">=1.21.0,<2dev"
google-auth = ">=1.16.0"
google-auth-httplib2 = ">=0.0.3"
httplib2 = ">=0.9.2,<1dev"
google-auth = ">=1.16.0,<2dev"
google-auth-httplib2 = ">=0.1.0"
httplib2 = ">=0.15.0,<1dev"
six = ">=1.13.0,<2dev"
uritemplate = ">=3.0.0,<4dev"
[[package]]
category = "main"
description = "Google Authentication Library"
name = "google-auth"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
version = "1.23.0"
[package.dependencies]
cachetools = ">=2.0.0,<5.0"
pyasn1-modules = ">=0.2.1"
setuptools = ">=40.3.0"
six = ">=1.9.0"
[package.dependencies.rsa]
python = ">=3.5"
version = ">=3.1.4,<5"
[package.extras]
aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)"]
[[package]]
category = "main"
description = "Google Authentication Library"
name = "google-auth"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*"
version = "1.24.0"
version = "1.28.1"
[package.dependencies]
cachetools = ">=2.0.0,<5.0"
@ -186,6 +136,7 @@ version = ">=3.1.4,<5"
[package.extras]
aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)"]
pyopenssl = ["pyopenssl (>=20.0.0)"]
[[package]]
category = "main"
@ -193,53 +144,38 @@ description = "Google Authentication Library: httplib2 transport"
name = "google-auth-httplib2"
optional = false
python-versions = "*"
version = "0.0.4"
version = "0.1.0"
[package.dependencies]
google-auth = "*"
httplib2 = ">=0.9.1"
httplib2 = ">=0.15.0"
six = "*"
[[package]]
category = "main"
description = "Google Authentication Library"
name = "google-auth-oauthlib"
optional = false
python-versions = "*"
version = "0.4.1"
[package.dependencies]
google-auth = "*"
requests-oauthlib = ">=0.7.0"
[package.extras]
tool = ["click"]
[[package]]
category = "main"
description = "Google Authentication Library"
name = "google-auth-oauthlib"
optional = false
python-versions = ">=3.6"
version = "0.4.2"
version = "0.4.4"
[package.dependencies]
google-auth = "*"
google-auth = ">=1.0.0"
requests-oauthlib = ">=0.7.0"
[package.extras]
tool = ["click"]
tool = ["click (>=6.0.0)"]
[[package]]
category = "main"
description = "Common protobufs used in Google APIs"
name = "googleapis-common-protos"
optional = false
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
version = "1.52.0"
python-versions = ">=3.6"
version = "1.53.0"
[package.dependencies]
protobuf = ">=3.6.0"
protobuf = ">=3.12.0"
[package.extras]
grpc = ["grpcio (>=1.0.0)"]
@ -250,7 +186,10 @@ description = "A comprehensive HTTP client library."
name = "httplib2"
optional = false
python-versions = "*"
version = "0.12.3"
version = "0.19.1"
[package.dependencies]
pyparsing = ">=2.4.2,<3"
[[package]]
category = "main"
@ -265,14 +204,24 @@ category = "main"
description = "A generic, spec-compliant, thorough implementation of the OAuth request-signing logic"
name = "oauthlib"
optional = false
python-versions = "*"
version = "2.1.0"
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "3.1.0"
[package.extras]
rsa = ["cryptography"]
signals = ["blinker"]
signedtoken = ["cryptography", "pyjwt (>=1.0.0)"]
test = ["nose", "unittest2", "cryptography", "mock", "pyjwt (>=1.0.0)", "blinker"]
[[package]]
category = "main"
description = "Core utilities for Python packages"
name = "packaging"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "20.9"
[package.dependencies]
pyparsing = ">=2.0.2"
[[package]]
category = "main"
@ -280,7 +229,7 @@ description = "Protocol Buffers"
name = "protobuf"
optional = false
python-versions = "*"
version = "3.14.0"
version = "3.15.8"
[package.dependencies]
six = ">=1.9"
@ -306,20 +255,11 @@ pyasn1 = ">=0.4.6,<0.5.0"
[[package]]
category = "main"
description = "File type identification using libmagic"
name = "python-magic"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "0.4.20"
[[package]]
category = "main"
description = "File type identification using libmagic binary package"
marker = "platform_system == \"Windows\""
name = "python-magic-bin"
description = "Python parsing module"
name = "pyparsing"
optional = false
python-versions = "*"
version = "0.4.14"
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
version = "2.4.7"
[[package]]
category = "main"
@ -327,7 +267,7 @@ description = "World timezone definitions, modern and historical"
name = "pytz"
optional = false
python-versions = "*"
version = "2020.5"
version = "2021.1"
[[package]]
category = "main"
@ -352,15 +292,15 @@ category = "main"
description = "OAuthlib authentication support for Requests."
name = "requests-oauthlib"
optional = false
python-versions = "*"
version = "0.8.0"
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.3.0"
[package.dependencies]
oauthlib = ">=0.6.2"
oauthlib = ">=3.0.0"
requests = ">=2.0.0"
[package.extras]
rsa = ["oauthlib (>=0.6.2)", "requests (>=2.0.0)"]
rsa = ["oauthlib (>=3.0.0)"]
[[package]]
category = "main"
@ -385,25 +325,13 @@ version = "4.4"
[package.dependencies]
pyasn1 = ">=0.1.3"
[[package]]
category = "main"
description = "Pure-Python RSA implementation"
marker = "python_version >= \"3.5\""
name = "rsa"
optional = false
python-versions = ">=3.5, <4"
version = "4.7"
[package.dependencies]
pyasn1 = ">=0.1.3"
[[package]]
category = "main"
description = "Simple data validation library"
name = "schema"
optional = false
python-versions = "*"
version = "0.7.3"
version = "0.7.4"
[package.dependencies]
contextlib2 = ">=0.5.5"
@ -422,7 +350,7 @@ description = "tzinfo object for the local timezone"
name = "tzlocal"
optional = false
python-versions = "*"
version = "1.5.1"
version = "2.1"
[package.dependencies]
pytz = "*"
@ -433,7 +361,7 @@ description = "ASCII transliterations of Unicode text"
name = "unidecode"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.1.2"
version = "1.2.0"
[[package]]
category = "main"
@ -455,22 +383,9 @@ version = "1.22"
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
[[package]]
category = "main"
description = "HTTP library with thread-safe connection pooling, file post, and more."
name = "urllib3"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
version = "1.26.2"
[package.extras]
brotli = ["brotlipy (>=0.6.0)"]
secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"]
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
[metadata]
content-hash = "41a9471d93da0f5e3d684cdf9e8f981659030d67f29ef6bf55c07a0d49a3ee93"
python-versions = ">=3.5"
content-hash = "30e57c25d84e4981a4a70f5d30f4b8e2a6163f56b44a1ca170372bfbf91ea527"
python-versions = ">=3.6"
[metadata.files]
args = [
@ -479,8 +394,6 @@ args = [
cachetools = [
{file = "cachetools-3.1.1-py2.py3-none-any.whl", hash = "sha256:428266a1c0d36dc5aca63a2d7c5942e88c2c898d72139fca0e97fdd2380517ae"},
{file = "cachetools-3.1.1.tar.gz", hash = "sha256:8ea2d3ce97850f31e4a08b0e2b5e6c34997d7216a9d2c98e0f3978630d4da69a"},
{file = "cachetools-4.2.0-py3-none-any.whl", hash = "sha256:c6b07a6ded8c78bf36730b3dc452dfff7d95f2a12a2fed856b1a0cb13ca78c61"},
{file = "cachetools-4.2.0.tar.gz", hash = "sha256:3796e1de094f0eaca982441c92ce96c68c89cced4cd97721ab297ea4b16db90e"},
]
certifi = [
{file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"},
@ -494,8 +407,8 @@ clint = [
{file = "clint-0.5.1.tar.gz", hash = "sha256:05224c32b1075563d0b16d0015faaf9da43aa214e4a2140e51f08789e7a4c5aa"},
]
configparser = [
{file = "configparser-3.8.1-py2.py3-none-any.whl", hash = "sha256:45d1272aad6cfd7a8a06cf5c73f2ceb6a190f6acc1fa707e7f82a4c053b28b18"},
{file = "configparser-3.8.1.tar.gz", hash = "sha256:bc37850f0cc42a1725a796ef7d92690651bf1af37d744cc63161dac62cabee17"},
{file = "configparser-5.0.2-py3-none-any.whl", hash = "sha256:af59f2cdd7efbdd5d111c1976ecd0b82db9066653362f0962d7bf1d3ab89a1fa"},
{file = "configparser-5.0.2.tar.gz", hash = "sha256:85d5de102cfe6d14a5172676f09d19c465ce63d6019cf0a4ef13385fc535e828"},
]
contextlib2 = [
{file = "contextlib2-0.6.0.post1-py2.py3-none-any.whl", hash = "sha256:3355078a159fbb44ee60ea80abd0d87b80b78c248643b49aa6d94673b413609b"},
@ -505,69 +418,69 @@ docopt = [
{file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"},
]
future = [
{file = "future-0.17.1.tar.gz", hash = "sha256:67045236dcfd6816dc439556d009594abf643e5eb48992e36beac09c2ca659b8"},
{file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"},
]
google-api-core = [
{file = "google-api-core-1.23.0.tar.gz", hash = "sha256:1bb3c485c38eacded8d685b1759968f6cf47dd9432922d34edb90359eaa391e2"},
{file = "google_api_core-1.23.0-py2.py3-none-any.whl", hash = "sha256:94d8c707d358d8d9e8b0045c42be20efb58433d308bd92cf748511c7825569c8"},
{file = "google-api-core-1.25.0.tar.gz", hash = "sha256:d967beae8d8acdb88fb2f6f769e2ee0ee813042576a08891bded3b8e234150ae"},
{file = "google_api_core-1.25.0-py2.py3-none-any.whl", hash = "sha256:4656345cba9627ab1290eab51300a6397cc50370d99366133df1ae64b744e1eb"},
{file = "google-api-core-1.26.3.tar.gz", hash = "sha256:b914345c7ea23861162693a27703bab804a55504f7e6e9abcaff174d80df32ac"},
{file = "google_api_core-1.26.3-py2.py3-none-any.whl", hash = "sha256:099762d4b4018cd536bcf85136bf337957da438807572db52f21dc61251be089"},
]
google-api-python-client = [
{file = "google-api-python-client-1.12.2.tar.gz", hash = "sha256:54a7d330833a2e7b0587446d7e4ae6d0244925a9a8e1dfe878f3f7e06cdedb62"},
{file = "google_api_python_client-1.12.2-py2.py3-none-any.whl", hash = "sha256:05cb331ed1aa15746f606c7e36ea51dbe7c29b1a5df9bbf58140901fe23d7142"},
{file = "google-api-python-client-2.1.0.tar.gz", hash = "sha256:f9ac377efe69571aea1acc9e15760d4204aca23c4464eb63f963ae4defc95d97"},
{file = "google_api_python_client-2.1.0-py2.py3-none-any.whl", hash = "sha256:921fe10cdff22d1f5b8af7473f9a298efb991fb6ea67dadd6c37fbecfb0575f4"},
]
google-auth = [
{file = "google-auth-1.23.0.tar.gz", hash = "sha256:5176db85f1e7e837a646cd9cede72c3c404ccf2e3373d9ee14b2db88febad440"},
{file = "google_auth-1.23.0-py2.py3-none-any.whl", hash = "sha256:b728625ff5dfce8f9e56a499c8a4eb51443a67f20f6d28b67d5774c310ec4b6b"},
{file = "google-auth-1.24.0.tar.gz", hash = "sha256:0b0e026b412a0ad096e753907559e4bdb180d9ba9f68dd9036164db4fdc4ad2e"},
{file = "google_auth-1.24.0-py2.py3-none-any.whl", hash = "sha256:ce752cc51c31f479dbf9928435ef4b07514b20261b021c7383bee4bda646acb8"},
{file = "google-auth-1.28.1.tar.gz", hash = "sha256:70b39558712826e41f65e5f05a8d879361deaf84df8883e5dd0ec3d0da6ab66e"},
{file = "google_auth-1.28.1-py2.py3-none-any.whl", hash = "sha256:186fe2564634d67fbbb64f3daf8bc8c9cecbb2a7f535ed1a8a71795e50db8d87"},
]
google-auth-httplib2 = [
{file = "google-auth-httplib2-0.0.4.tar.gz", hash = "sha256:8d092cc60fb16517b12057ec0bba9185a96e3b7169d86ae12eae98e645b7bc39"},
{file = "google_auth_httplib2-0.0.4-py2.py3-none-any.whl", hash = "sha256:aeaff501738b289717fac1980db9711d77908a6c227f60e4aa1923410b43e2ee"},
{file = "google-auth-httplib2-0.1.0.tar.gz", hash = "sha256:a07c39fd632becacd3f07718dfd6021bf396978f03ad3ce4321d060015cc30ac"},
{file = "google_auth_httplib2-0.1.0-py2.py3-none-any.whl", hash = "sha256:31e49c36c6b5643b57e82617cb3e021e3e1d2df9da63af67252c02fa9c1f4a10"},
]
google-auth-oauthlib = [
{file = "google-auth-oauthlib-0.4.1.tar.gz", hash = "sha256:88d2cd115e3391eb85e1243ac6902e76e77c5fe438b7276b297fbe68015458dd"},
{file = "google_auth_oauthlib-0.4.1-py2.py3-none-any.whl", hash = "sha256:a92a0f6f41a0fb6138454fbc02674e64f89d82a244ea32f98471733c8ef0e0e1"},
{file = "google-auth-oauthlib-0.4.2.tar.gz", hash = "sha256:65b65bc39ad8cab15039b35e5898455d3d66296d0584d96fe0e79d67d04c51d9"},
{file = "google_auth_oauthlib-0.4.2-py2.py3-none-any.whl", hash = "sha256:d4d98c831ea21d574699978827490a41b94f05d565c617fe1b420e88f1fc8d8d"},
{file = "google-auth-oauthlib-0.4.4.tar.gz", hash = "sha256:09832c6e75032f93818edf1affe4746121d640c625a5bef9b5c96af676e98eee"},
{file = "google_auth_oauthlib-0.4.4-py2.py3-none-any.whl", hash = "sha256:0e92aacacfb94978de3b7972cf4b0f204c3cd206f74ddd0dc0b31e91164e6317"},
]
googleapis-common-protos = [
{file = "googleapis-common-protos-1.52.0.tar.gz", hash = "sha256:560716c807117394da12cecb0a54da5a451b5cf9866f1d37e9a5e2329a665351"},
{file = "googleapis_common_protos-1.52.0-py2.py3-none-any.whl", hash = "sha256:c8961760f5aad9a711d37b675be103e0cc4e9a39327e0d6d857872f698403e24"},
{file = "googleapis-common-protos-1.53.0.tar.gz", hash = "sha256:a88ee8903aa0a81f6c3cec2d5cf62d3c8aa67c06439b0496b49048fb1854ebf4"},
{file = "googleapis_common_protos-1.53.0-py2.py3-none-any.whl", hash = "sha256:f6d561ab8fb16b30020b940e2dd01cd80082f4762fa9f3ee670f4419b4b8dbd0"},
]
httplib2 = [
{file = "httplib2-0.12.3-py3-none-any.whl", hash = "sha256:23914b5487dfe8ef09db6656d6d63afb0cf3054ad9ebc50868ddc8e166b5f8e8"},
{file = "httplib2-0.12.3.tar.gz", hash = "sha256:a18121c7c72a56689efbf1aef990139ad940fee1e64c6f2458831736cd593600"},
{file = "httplib2-0.19.1-py3-none-any.whl", hash = "sha256:2ad195faf9faf079723f6714926e9a9061f694d07724b846658ce08d40f522b4"},
{file = "httplib2-0.19.1.tar.gz", hash = "sha256:0b12617eeca7433d4c396a100eaecfa4b08ee99aa881e6df6e257a7aad5d533d"},
]
idna = [
{file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},
{file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"},
]
oauthlib = [
{file = "oauthlib-2.1.0-py2.py3-none-any.whl", hash = "sha256:d883b36b21a6ad813953803edfa563b1b579d79ca758fe950d1bc9e8b326025b"},
{file = "oauthlib-2.1.0.tar.gz", hash = "sha256:ac35665a61c1685c56336bda97d5eefa246f1202618a1d6f34fccb1bdd404162"},
{file = "oauthlib-3.1.0-py2.py3-none-any.whl", hash = "sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea"},
{file = "oauthlib-3.1.0.tar.gz", hash = "sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889"},
]
packaging = [
{file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"},
{file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"},
]
protobuf = [
{file = "protobuf-3.14.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:629b03fd3caae7f815b0c66b41273f6b1900a579e2ccb41ef4493a4f5fb84f3a"},
{file = "protobuf-3.14.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:5b7a637212cc9b2bcf85dd828b1178d19efdf74dbfe1ddf8cd1b8e01fdaaa7f5"},
{file = "protobuf-3.14.0-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:43b554b9e73a07ba84ed6cf25db0ff88b1e06be610b37656e292e3cbb5437472"},
{file = "protobuf-3.14.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:5e9806a43232a1fa0c9cf5da8dc06f6910d53e4390be1fa06f06454d888a9142"},
{file = "protobuf-3.14.0-cp35-cp35m-win32.whl", hash = "sha256:1c51fda1bbc9634246e7be6016d860be01747354ed7015ebe38acf4452f470d2"},
{file = "protobuf-3.14.0-cp35-cp35m-win_amd64.whl", hash = "sha256:4b74301b30513b1a7494d3055d95c714b560fbb630d8fb9956b6f27992c9f980"},
{file = "protobuf-3.14.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:86a75477addde4918e9a1904e5c6af8d7b691f2a3f65587d73b16100fbe4c3b2"},
{file = "protobuf-3.14.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ecc33531a213eee22ad60e0e2aaea6c8ba0021f0cce35dbf0ab03dee6e2a23a1"},
{file = "protobuf-3.14.0-cp36-cp36m-win32.whl", hash = "sha256:72230ed56f026dd664c21d73c5db73ebba50d924d7ba6b7c0d81a121e390406e"},
{file = "protobuf-3.14.0-cp36-cp36m-win_amd64.whl", hash = "sha256:0fc96785262042e4863b3f3b5c429d4636f10d90061e1840fce1baaf59b1a836"},
{file = "protobuf-3.14.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4e75105c9dfe13719b7293f75bd53033108f4ba03d44e71db0ec2a0e8401eafd"},
{file = "protobuf-3.14.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:2a7e2fe101a7ace75e9327b9c946d247749e564a267b0515cf41dfe450b69bac"},
{file = "protobuf-3.14.0-cp37-cp37m-win32.whl", hash = "sha256:b0d5d35faeb07e22a1ddf8dce620860c8fe145426c02d1a0ae2688c6e8ede36d"},
{file = "protobuf-3.14.0-cp37-cp37m-win_amd64.whl", hash = "sha256:8971c421dbd7aad930c9bd2694122f332350b6ccb5202a8b7b06f3f1a5c41ed5"},
{file = "protobuf-3.14.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9616f0b65a30851e62f1713336c931fcd32c057202b7ff2cfbfca0fc7d5e3043"},
{file = "protobuf-3.14.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:22bcd2e284b3b1d969c12e84dc9b9a71701ec82d8ce975fdda19712e1cfd4e00"},
{file = "protobuf-3.14.0-py2.py3-none-any.whl", hash = "sha256:0e247612fadda953047f53301a7b0407cb0c3cb4ae25a6fde661597a04039b3c"},
{file = "protobuf-3.14.0.tar.gz", hash = "sha256:1d63eb389347293d8915fb47bee0951c7b5dab522a4a60118b9a18f33e21f8ce"},
{file = "protobuf-3.15.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:fad4f971ec38d8df7f4b632c819bf9bbf4f57cfd7312cf526c69ce17ef32436a"},
{file = "protobuf-3.15.8-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:f17b352d7ce33c81773cf81d536ca70849de6f73c96413f17309f4b43ae7040b"},
{file = "protobuf-3.15.8-cp35-cp35m-macosx_10_9_intel.whl", hash = "sha256:4a054b0b5900b7ea7014099e783fb8c4618e4209fffcd6050857517b3f156e18"},
{file = "protobuf-3.15.8-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:efa4c4d4fc9ba734e5e85eaced70e1b63fb3c8d08482d839eb838566346f1737"},
{file = "protobuf-3.15.8-cp35-cp35m-win32.whl", hash = "sha256:07eec4e2ccbc74e95bb9b3afe7da67957947ee95bdac2b2e91b038b832dd71f0"},
{file = "protobuf-3.15.8-cp35-cp35m-win_amd64.whl", hash = "sha256:f9cadaaa4065d5dd4d15245c3b68b967b3652a3108e77f292b58b8c35114b56c"},
{file = "protobuf-3.15.8-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2dc0e8a9e4962207bdc46a365b63a3f1aca6f9681a5082a326c5837ef8f4b745"},
{file = "protobuf-3.15.8-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:f80afc0a0ba13339bbab25ca0409e9e2836b12bb012364c06e97c2df250c3343"},
{file = "protobuf-3.15.8-cp36-cp36m-win32.whl", hash = "sha256:c5566f956a26cda3abdfacc0ca2e21db6c9f3d18f47d8d4751f2209d6c1a5297"},
{file = "protobuf-3.15.8-cp36-cp36m-win_amd64.whl", hash = "sha256:dab75b56a12b1ceb3e40808b5bd9dfdaef3a1330251956e6744e5b6ed8f8830b"},
{file = "protobuf-3.15.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3053f13207e7f13dc7be5e9071b59b02020172f09f648e85dc77e3fcb50d1044"},
{file = "protobuf-3.15.8-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1f0b5d156c3df08cc54bc2c8b8b875648ea4cd7ebb2a9a130669f7547ec3488c"},
{file = "protobuf-3.15.8-cp37-cp37m-win32.whl", hash = "sha256:90270fe5732c1f1ff664a3bd7123a16456d69b4e66a09a139a00443a32f210b8"},
{file = "protobuf-3.15.8-cp37-cp37m-win_amd64.whl", hash = "sha256:f42c2f5fb67da5905bfc03733a311f72fa309252bcd77c32d1462a1ad519521e"},
{file = "protobuf-3.15.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f6077db37bfa16494dca58a4a02bfdacd87662247ad6bc1f7f8d13ff3f0013e1"},
{file = "protobuf-3.15.8-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:510e66491f1a5ac5953c908aa8300ec47f793130097e4557482803b187a8ee05"},
{file = "protobuf-3.15.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5ff9fa0e67fcab442af9bc8d4ec3f82cb2ff3be0af62dba047ed4187f0088b7d"},
{file = "protobuf-3.15.8-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:1c0e9e56202b9dccbc094353285a252e2b7940b74fdf75f1b4e1b137833fabd7"},
{file = "protobuf-3.15.8-py2.py3-none-any.whl", hash = "sha256:a0a08c6b2e6d6c74a6eb5bf6184968eefb1569279e78714e239d33126e753403"},
{file = "protobuf-3.15.8.tar.gz", hash = "sha256:0277f62b1e42210cafe79a71628c1d553348da81cbd553402a7f7549c50b11d0"},
]
pyasn1 = [
{file = "pyasn1-0.4.8-py2.4.egg", hash = "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"},
@ -599,26 +512,22 @@ pyasn1-modules = [
{file = "pyasn1_modules-0.2.8-py3.6.egg", hash = "sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0"},
{file = "pyasn1_modules-0.2.8-py3.7.egg", hash = "sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd"},
]
python-magic = [
{file = "python-magic-0.4.20.tar.gz", hash = "sha256:0cc52ccad086c377b9194014e3dbf98d94b194344630172510a6a3e716b47801"},
{file = "python_magic-0.4.20-py2.py3-none-any.whl", hash = "sha256:33ce94d9395aa269a9c5fac10ae124a5fb328ebe248f36efc5a43922edee662e"},
]
python-magic-bin = [
{file = "python_magic_bin-0.4.14-py2.py3-none-macosx_10_6_intel.whl", hash = "sha256:7b1743b3dbf16601d6eedf4e7c2c9a637901b0faaf24ad4df4d4527e7d8f66a4"},
{file = "python_magic_bin-0.4.14-py2.py3-none-win32.whl", hash = "sha256:34a788c03adde7608028203e2dbb208f1f62225ad91518787ae26d603ae68892"},
{file = "python_magic_bin-0.4.14-py2.py3-none-win_amd64.whl", hash = "sha256:90be6206ad31071a36065a2fc169c5afb5e0355cbe6030e87641c6c62edc2b69"},
pyparsing = [
{file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"},
{file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"},
]
pytz = [
{file = "pytz-2020.5-py2.py3-none-any.whl", hash = "sha256:16962c5fb8db4a8f63a26646d8886e9d769b6c511543557bc84e9569fb9a9cb4"},
{file = "pytz-2020.5.tar.gz", hash = "sha256:180befebb1927b16f6b57101720075a984c019ac16b1b7575673bea42c6c3da5"},
{file = "pytz-2021.1-py2.py3-none-any.whl", hash = "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798"},
{file = "pytz-2021.1.tar.gz", hash = "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da"},
]
requests = [
{file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"},
{file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"},
]
requests-oauthlib = [
{file = "requests-oauthlib-0.8.0.tar.gz", hash = "sha256:883ac416757eada6d3d07054ec7092ac21c7f35cb1d2cf82faf205637081f468"},
{file = "requests_oauthlib-0.8.0-py2.py3-none-any.whl", hash = "sha256:50a8ae2ce8273e384895972b56193c7409601a66d4975774c60c2aed869639ca"},
{file = "requests-oauthlib-1.3.0.tar.gz", hash = "sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a"},
{file = "requests_oauthlib-1.3.0-py2.py3-none-any.whl", hash = "sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d"},
{file = "requests_oauthlib-1.3.0-py3.7.egg", hash = "sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc"},
]
requests-toolbelt = [
{file = "requests-toolbelt-0.9.1.tar.gz", hash = "sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0"},
@ -627,23 +536,22 @@ requests-toolbelt = [
rsa = [
{file = "rsa-4.4-py2.py3-none-any.whl", hash = "sha256:4afbaaecc3e9550c7351fdf0ab3fea1857ff616b85bab59215f00fb42e0e9582"},
{file = "rsa-4.4.tar.gz", hash = "sha256:5d95293bbd0fbee1dd9cb4b72d27b723942eb50584abc8c4f5f00e4bcfa55307"},
{file = "rsa-4.7-py3-none-any.whl", hash = "sha256:a8774e55b59fd9fc893b0d05e9bfc6f47081f46ff5b46f39ccf24631b7be356b"},
{file = "rsa-4.7.tar.gz", hash = "sha256:69805d6b69f56eb05b62daea3a7dbd7aa44324ad1306445e05da8060232d00f4"},
]
schema = [
{file = "schema-0.7.3-py2.py3-none-any.whl", hash = "sha256:c331438b60f634cab5664ab720d3083cc444f924d55269530c36b33e3354276f"},
{file = "schema-0.7.3.tar.gz", hash = "sha256:4cf529318cfd1e844ecbe02f41f7e5aa027463e7403666a52746f31f04f47a5e"},
{file = "schema-0.7.4-py2.py3-none-any.whl", hash = "sha256:cf97e4cd27e203ab6bb35968532de1ed8991bce542a646f0ff1d643629a4945d"},
{file = "schema-0.7.4.tar.gz", hash = "sha256:fbb6a52eb2d9facf292f233adcc6008cffd94343c63ccac9a1cb1f3e6de1db17"},
]
six = [
{file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"},
{file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"},
]
tzlocal = [
{file = "tzlocal-1.5.1.tar.gz", hash = "sha256:4ebeb848845ac898da6519b9b31879cf13b6626f7184c496037b818e238f2c4e"},
{file = "tzlocal-2.1-py2.py3-none-any.whl", hash = "sha256:e2cb6c6b5b604af38597403e9852872d7f534962ae2954c7f35efcb1ccacf4a4"},
{file = "tzlocal-2.1.tar.gz", hash = "sha256:643c97c5294aedc737780a49d9df30889321cbe1204eac2c2ec6134035a92e44"},
]
unidecode = [
{file = "Unidecode-1.1.2-py2.py3-none-any.whl", hash = "sha256:4c9d15d2f73eb0d2649a151c566901f80a030da1ccb0a2043352e1dbf647586b"},
{file = "Unidecode-1.1.2.tar.gz", hash = "sha256:a039f89014245e0cad8858976293e23501accc9ff5a7bdbc739a14a2b7b85cdc"},
{file = "Unidecode-1.2.0-py2.py3-none-any.whl", hash = "sha256:12435ef2fc4cdfd9cf1035a1db7e98b6b047fe591892e81f34e94959591fad00"},
{file = "Unidecode-1.2.0.tar.gz", hash = "sha256:8d73a97d387a956922344f6b74243c2c6771594659778744b2dbdaad8f6b727d"},
]
uritemplate = [
{file = "uritemplate-3.0.1-py2.py3-none-any.whl", hash = "sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f"},
@ -652,6 +560,4 @@ uritemplate = [
urllib3 = [
{file = "urllib3-1.22-py2.py3-none-any.whl", hash = "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b"},
{file = "urllib3-1.22.tar.gz", hash = "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f"},
{file = "urllib3-1.26.2-py2.py3-none-any.whl", hash = "sha256:d8ff90d979214d7b4f8ce956e80f4028fc6860e4431f731ea4a8c08f23f99473"},
{file = "urllib3-1.26.2.tar.gz", hash = "sha256:19188f96923873c92ccb987120ec4acaa12f0461fa9ce5d3d0772bc965a39e08"},
]

+ 8
- 1
prismedia/__init__.py View File

@ -1,5 +1,12 @@
from future import standard_library
standard_library.install_aliases()
import logging
logger = logging.getLogger('Prismedia')
logger.setLevel(logging.INFO)
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s: %(message)s')
ch.setFormatter(formatter)
logger.addHandler(ch)
from . import upload
from . import genconfig

+ 11
- 2
prismedia/genconfig.py View File

@ -1,6 +1,10 @@
from os.path import join, abspath, isfile, dirname
from os.path import join, abspath, isfile, dirname, exists
from os import listdir
from shutil import copyfile
import logging
logger = logging.getLogger('Prismedia')
from . import utils
def genconfig():
@ -8,7 +12,12 @@ def genconfig():
files = [f for f in listdir(path) if isfile(join(path, f))]
for f in files:
copyfile(join(path, f), f)
final_f = f.replace(".sample", "")
if exists(final_f) and not utils.ask_overwrite(final_f + " already exists. Do you want to overwrite it?"):
continue
copyfile(join(path, f), final_f)
logger.info(str(final_f) + " correctly generated, you may now edit it to fill your credentials.")
if __name__ == '__main__':

+ 1
- 1
prismedia/pt_upload.py View File

@ -373,7 +373,7 @@ def create_callback(encoder, progress_type):
else:
# Print a blank line to not (partly) override the progress bar
print()
logger.info("Peertube : Upload finish, Processing…")
logger.info("Peertube: Upload finish, Processing…")
return callback

+ 15
- 43
prismedia/upload.py View File

@ -7,11 +7,12 @@ prismedia - tool to upload videos to Peertube and Youtube
Usage:
prismedia --file=<FILE> [options]
prismedia -f <FILE> --tags=STRING [options]
prismedia --hearthbeat
prismedia -h | --help
prismedia --version
Options:
-f, --file=STRING Path to the video file to upload in mp4. This is the only mandatory option.
-f, --file=STRING Path to the video file to upload. This is the only mandatory option.
--name=NAME Name of the video to upload. (default to video filename)
-d, --description=STRING Description of the video. (default: default description)
-t, --tags=STRING Tags for the video. comma separated.
@ -39,8 +40,7 @@ Options:
DATE should be in the past
--auto-originalDate Automatically use the file modification time as original date
--thumbnail=STRING Path to a file to use as a thumbnail for the video.
Supported types are jpg and jpeg.
By default, prismedia search for an image based on video name followed by .jpg or .jpeg
By default, prismedia search for an image based on video name followed by .jpg, .jpeg or .png
--channel=STRING Set the channel to use for the video (Peertube only)
If the channel is not found, spawn an error except if --channelCreate is set.
--channelCreate Create the channel if not exists. (Peertube only, default do not create)
@ -50,6 +50,9 @@ Options:
--playlistCreate Create the playlist if not exists. (default do not create)
Only relevant if --playlist is set.
--progress=STRING Set the progress bar view, one of percentage, bigFile (MB), accurate (KB).
--hearthbeat Use some credits to show some activity for you apikey so the platform know it is used and would not put your quota to 0 (only Youtube currently)
-h --help Show this help.
--version Show version.
@ -106,12 +109,6 @@ import os
import datetime
import logging
logger = logging.getLogger('Prismedia')
logger.setLevel(logging.INFO)
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s: %(message)s')
ch.setFormatter(formatter)
logger.addHandler(ch)
from docopt import docopt
@ -127,16 +124,8 @@ except ImportError:
' is installed: \n'
'see https://github.com/halst/schema\n')
exit(1)
try:
# noinspection PyUnresolvedReferences
import magic
except ImportError:
logger.critical('This program requires that the `python-magic` library'
' is installed, NOT the Python bindings to libmagic API \n'
'see https://github.com/ahupp/python-magic\n')
exit(1)
VERSION = "prismedia v0.11.0"
VERSION = "prismedia v0.12.0"
VALID_PRIVACY_STATUSES = ('public', 'private', 'unlisted')
VALID_CATEGORIES = (
@ -154,20 +143,6 @@ VALID_LANGUAGES = ('arabic', 'english', 'french',
VALID_PROGRESS = ('percentage', 'bigfile', 'accurate')
def validateVideo(path):
supported_types = ['video/mp4']
detected_type = magic.from_file(path, mime=True)
if detected_type not in supported_types:
print("File", path, "detected type is", detected_type, "which is not one of", supported_types)
force_file = ['y', 'yes']
is_forcing = input("Are you sure you selected the correct file? (y/N)")
if is_forcing.lower() not in force_file:
return False
return path
def validateCategory(category):
if category.lower() in VALID_CATEGORIES:
return True
@ -221,15 +196,6 @@ def validateOriginalDate(originalDate):
return True
def validateThumbnail(thumbnail):
supported_types = ['image/jpg', 'image/jpeg']
if os.path.exists(thumbnail) and \
magic.from_file(thumbnail, mime=True) in supported_types:
return thumbnail
else:
return False
def validateLogLevel(loglevel):
numeric_level = getattr(logging, loglevel, None)
if not isinstance(numeric_level, int):
@ -318,7 +284,7 @@ def main():
})
schema = Schema({
'--file': And(str, os.path.exists, validateVideo, error='file is not supported, please use mp4'),
'--file': And(str, os.path.exists, error='file does not exists, please check path'),
# Strict option checks - at the moment Schema needs to check Hook and Optional separately #
Hook('--name', handler=_optionnalOrStrict): object,
Hook('--description', handler=_optionnalOrStrict): object,
@ -389,18 +355,24 @@ def main():
Optional('--disable-comments'): bool,
Optional('--nsfw'): bool,
Optional('--thumbnail'): Or(None, And(
str, validateThumbnail, error='thumbnail is not supported, please use jpg/jpeg'),
str, os.path.exists, error='Thumbnail does not exists, please check the path.'),
),
Optional('--channel'): Or(None, str),
Optional('--channelCreate'): bool,
Optional('--playlist'): Or(None, str),
Optional('--playlistCreate'): bool,
Optional('--progress'): Or(None, And(str, validateProgress, error="Sorry, progress visualisation not supported")),
'--hearthbeat': bool,
'--help': bool,
'--version': bool,
# This allow to return all other options for further use: https://github.com/keleshev/schema#extra-keys
object: object
})
if options.get('--hearthbeat'):
yt_upload.hearthbeat()
exit(0)
# We need to validate early options first as withNFO and logs options should be prioritized
try:
options = earlyoptionSchema.validate(options)

+ 13
- 0
prismedia/utils.py View File

@ -100,6 +100,15 @@ def getLanguage(language, platform):
return PEERTUBE_LANGUAGE[language.lower()]
def ask_overwrite(question):
while True:
reply = str(input(question + ' (Yes/[No]): ') or "No").lower().strip()
if reply[:1] == 'y':
return True
if reply[:1] == 'n':
return False
def remove_empty_kwargs(**kwargs):
good_kwargs = {}
if kwargs is not None:
@ -117,6 +126,8 @@ def searchThumbnail(options):
options['--thumbnail'] = video_directory + options.get('--name') + ".jpg"
elif isfile(video_directory + options.get('--name') + ".jpeg"):
options['--thumbnail'] = video_directory + options.get('--name') + ".jpeg"
elif isfile(video_directory + options.get('--name') + ".png"):
options['--thumbnail'] = video_directory + options.get('--name') + ".png"
# Then, if we still not have thumbnail, check for thumbnail based on videofile name
if not options.get('--thumbnail'):
video_file = splitext(basename(options.get('--file')))[0]
@ -124,6 +135,8 @@ def searchThumbnail(options):
options['--thumbnail'] = video_directory + video_file + ".jpg"
elif isfile(video_directory + video_file + ".jpeg"):
options['--thumbnail'] = video_directory + video_file + ".jpeg"
elif isfile(video_directory + video_file + ".png"):
options['--thumbnail'] = video_directory + video_file + ".png"
# Display some info after research
if not options.get('--thumbnail'):

+ 43
- 17
prismedia/yt_upload.py View File

@ -1,6 +1,6 @@
#!/usr/bin/env python
# coding: utf-8
# From Youtube samples : https://raw.githubusercontent.com/youtube/api-samples/master/python/upload_video.py # noqa
# From Youtube samples: https://raw.githubusercontent.com/youtube/api-samples/master/python/upload_video.py # noqa
import http.client
import httplib2
@ -60,6 +60,7 @@ def get_authenticated_service():
check_authenticated_scopes()
flow = InstalledAppFlow.from_client_secrets_file(
CLIENT_SECRETS_FILE, SCOPES)
if exists(CREDENTIALS_PATH):
with open(CREDENTIALS_PATH, 'r') as f:
credential_params = json.load(f)
@ -76,7 +77,7 @@ def get_authenticated_service():
p = copy.deepcopy(vars(credentials))
del p["expiry"]
json.dump(p, f)
return build(API_SERVICE_NAME, API_VERSION, credentials=credentials, cache_discovery=False)
return build(API_SERVICE_NAME, API_VERSION, credentials=credentials, cache_discovery=False)
def check_authenticated_scopes():
@ -181,14 +182,24 @@ def initialize_upload(youtube, options):
def get_playlist_by_name(youtube, playlist_name):
response = youtube.playlists().list(
part='snippet,id',
mine=True,
maxResults=50
).execute()
for playlist in response["items"]:
if playlist["snippet"]['title'] == playlist_name:
return playlist['id']
pageToken = ""
while pageToken != None:
response = youtube.playlists().list(
part='snippet,id',
mine=True,
maxResults=50,
pageToken=pageToken
).execute()
for playlist in response["items"]:
if playlist["snippet"]["title"] == playlist_name:
return playlist["id"]
# Ask next page if there are any
if "nextPageToken" in response:
pageToken = response["nextPageToken"]
else:
pageToken = None
def create_playlist(youtube, playlist_name):
@ -293,7 +304,7 @@ def resumable_upload(request, resource, method, options):
status, response = request.next_chunk()
if response is not None:
if method == 'insert' and 'id' in response:
logger.info('Youtube : Video was successfully uploaded.')
logger.info('Youtube: Video was successfully uploaded.')
template = 'Youtube: Watch it at https://youtu.be/%s (post-encoding could take some time)'
logger.info(template % response['id'])
template_stdout = 'https://youtu.be/%s'
@ -305,36 +316,51 @@ def resumable_upload(request, resource, method, options):
elif method != 'insert' or "id" not in response:
logger.info('Youtube: Thumbnail was successfully set.')
else:
template = ('Youtube : The upload failed with an '
template = ('Youtube: The upload failed with an '
'unexpected response: %s')
logger.critical(template % response)
exit(1)
except HttpError as e:
if e.resp.status in RETRIABLE_STATUS_CODES:
template = 'Youtube : A retriable HTTP error %d occurred:\n%s'
template = 'Youtube: A retriable HTTP error %d occurred:\n%s'
error = template % (e.resp.status, e.content)
else:
raise
except RETRIABLE_EXCEPTIONS as e:
error = 'Youtube : A retriable error occurred: %s' % e
error = 'Youtube: A retriable error occurred: %s' % e
if error is not None:
logger.warning(error)
retry += 1
if retry > MAX_RETRIES:
logger.error('Youtube : No longer attempting to retry.')
logger.error('Youtube: No longer attempting to retry.')
max_sleep = 2 ** retry
sleep_seconds = random.random() * max_sleep
logger.warning('Youtube : Sleeping %f seconds and then retrying...'
logger.warning('Youtube: Sleeping %f seconds and then retrying...'
% sleep_seconds)
time.sleep(sleep_seconds)
def hearthbeat():
"""Use the minimums credits possibles of the API so google does not readuce to 0 the allowed credits.
This apparently happens after 90 days without any usage of credits.
For more info see the official documentations:
- General informations about quotas: https://developers.google.com/youtube/v3/getting-started#quota
- Quota costs for API requests: https://developers.google.com/youtube/v3/determine_quota_cost
- ToS (Americas) #Usage and Quotas: https://developers.google.com/youtube/terms/api-services-terms-of-service#usage-and-quotas"""
youtube = get_authenticated_service()
try:
get_playlist_by_name(youtube, "Foo")
except HttpError as e:
logger.error('Youtube: An HTTP error %d occurred on hearthbeat:\n%s' %
(e.resp.status, e.content))
def run(options):
youtube = get_authenticated_service()
try:
initialize_upload(youtube, options)
except HttpError as e:
logger.error('Youtube : An HTTP error %d occurred:\n%s' % (e.resp.status,
logger.error('Youtube: An HTTP error %d occurred:\n%s' % (e.resp.status,
e.content))

+ 16
- 17
pyproject.toml View File

@ -1,6 +1,6 @@
[tool.poetry]
name = "prismedia"
version = "0.11.0"
version = "0.12.0"
description = "scripting your way to upload videos on peertube and youtube"
authors = [
"LecygneNoir <git@lecygnenoir.info>",
@ -17,33 +17,32 @@ homepage = "https://git.lecygnenoir.info/LecygneNoir/prismedia"
keywords = ['peertube', 'youtube', 'prismedia']
[tool.poetry.dependencies]
python = ">=3.5"
clint = "^0.5.1"
configparser = "^3.7.1"
docopt = "^0.6.2"
future = "^0.17.1"
python = ">=3.6"
clint = ">=0.5.1"
configparser = ">=3.7.1"
docopt = ">=0.6.2"
future = ">=0.17.1"
google-api-python-client = ">=1.7.6"
google-auth = ">=1.6.1"
google-auth-httplib2 = ">=0.0.3"
google-auth-oauthlib = ">=0.2.0"
httplib2 = "^0.12.1"
oauthlib = "^2.1.0"
python-magic = "^0.4.15"
python-magic-bin = { version = "^0.4.14", markers = "platform_system == 'Windows'" }
requests = "^2.18.4"
requests-oauthlib = "^0.8.0"
requests-toolbelt = "^0.9.1"
httplib2 = ">=0.12.1"
oauthlib = ">=2.1.0"
requests = ">=2.18.4"
requests-oauthlib = ">=0.8.0"
requests-toolbelt = ">=0.9.1"
schema = ">=0.7.1"
tzlocal = "^1.5.1"
Unidecode = "^1.0.23"
uritemplate = "^3.0.0"
urllib3 = "^1.22"
tzlocal = ">=1.5.1"
Unidecode = ">=1.0.23"
uritemplate = ">=3.0.0"
urllib3 = ">=1.22"
[tool.poetry.dev-dependencies]
[tool.poetry.scripts]
prismedia = 'prismedia.upload:main'
prismedia-init = 'prismedia.genconfig:genconfig'
[build-system]
requires = ["poetry>=0.12"]
build-backend = "poetry.masonry.api"

+ 97
- 88
requirements.txt View File

@ -1,66 +1,77 @@
args==0.1.0 \
--hash=sha256:a785b8d837625e9b61c39108532d95b85274acd679693b71ebb5156848fcf814
cachetools==3.1.1 \
--hash=sha256:428266a1c0d36dc5aca63a2d7c5942e88c2c898d72139fca0e97fdd2380517ae \
--hash=sha256:8ea2d3ce97850f31e4a08b0e2b5e6c34997d7216a9d2c98e0f3978630d4da69a
certifi==2020.4.5.1 \
--hash=sha256:1d987a998c75633c40847cc966fcf5904906c920a7f17ef374f5aa4282abd304 \
--hash=sha256:51fcb31174be6e6664c5f69e3e1691a2d72a1a12e90f872cbdb1567eb47b6519
chardet==3.0.4 \
--hash=sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691 \
--hash=sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae
clint==0.5.1
configparser==3.8.1 \
--hash=sha256:45d1272aad6cfd7a8a06cf5c73f2ceb6a190f6acc1fa707e7f82a4c053b28b18 \
--hash=sha256:bc37850f0cc42a1725a796ef7d92690651bf1af37d744cc63161dac62cabee17
certifi==2020.12.5 \
--hash=sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830 \
--hash=sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c
chardet==4.0.0 \
--hash=sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5 \
--hash=sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa
clint==0.5.1 \
--hash=sha256:05224c32b1075563d0b16d0015faaf9da43aa214e4a2140e51f08789e7a4c5aa
configparser==5.0.2 \
--hash=sha256:af59f2cdd7efbdd5d111c1976ecd0b82db9066653362f0962d7bf1d3ab89a1fa \
--hash=sha256:85d5de102cfe6d14a5172676f09d19c465ce63d6019cf0a4ef13385fc535e828
contextlib2==0.6.0.post1 \
--hash=sha256:3355078a159fbb44ee60ea80abd0d87b80b78c248643b49aa6d94673b413609b \
--hash=sha256:01f490098c18b19d2bd5bb5dc445b2054d2fa97f09a4280ba2c5f3c394c8162e
docopt==0.6.2 \
--hash=sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491
future==0.17.1 \
--hash=sha256:67045236dcfd6816dc439556d009594abf643e5eb48992e36beac09c2ca659b8
google-api-core==1.16.0 \
--hash=sha256:92e962a087f1c4b8d1c5c88ade1c1dfd550047dcffb320c57ef6a534a20403e2 \
--hash=sha256:859f7392676761f2b160c6ee030c3422135ada4458f0948c5690a6a7c8d86294
google-api-python-client==1.8.0 \
--hash=sha256:0f5b42a14e2d2f7dee40f2e4514531dbe95ebde9c2173b1c4040a65c427e7900 \
--hash=sha256:5032ad1af5046889649b3848f2e871889fbb6ae440198a549fe1699581300386
google-auth==1.13.1 \
--hash=sha256:a5ee4c40fef77ea756cf2f1c0adcf475ecb53af6700cf9c133354cdc9b267148 \
--hash=sha256:cab6c707e6ee20e567e348168a5c69dc6480384f777a9e5159f4299ad177dcc0
google-auth-httplib2==0.0.3 \
--hash=sha256:098fade613c25b4527b2c08fa42d11f3c2037dda8995d86de0745228e965d445 \
--hash=sha256:f1c437842155680cf9918df9bc51c1182fda41feef88c34004bd1978c8157e08
google-auth-oauthlib==0.2.0 \
--hash=sha256:226d1d0960f86ba5d9efd426a70b291eaba96f47d071657e0254ea969025728a \
--hash=sha256:81ba22acada4d13b1d83f9371ab19fd61f1250a542d21cf49e4dcf0637a7344a
googleapis-common-protos==1.51.0 \
--hash=sha256:013c91704279119150e44ef770086fdbba158c1f978a6402167d47d5409e226e
httplib2==0.12.3 \
--hash=sha256:23914b5487dfe8ef09db6656d6d63afb0cf3054ad9ebc50868ddc8e166b5f8e8 \
--hash=sha256:a18121c7c72a56689efbf1aef990139ad940fee1e64c6f2458831736cd593600
idna==2.9 \
--hash=sha256:a068a21ceac8a4d63dbfd964670474107f541babbd2250d61922f029858365fa \
--hash=sha256:7588d1c14ae4c77d74036e8c22ff447b26d0fde8f007354fd48a7814db15b7cb
oauthlib==2.1.0 \
--hash=sha256:d883b36b21a6ad813953803edfa563b1b579d79ca758fe950d1bc9e8b326025b \
--hash=sha256:ac35665a61c1685c56336bda97d5eefa246f1202618a1d6f34fccb1bdd404162
protobuf==3.11.3 \
--hash=sha256:ef2c2e56aaf9ee914d3dccc3408d42661aaf7d9bb78eaa8f17b2e6282f214481 \
--hash=sha256:dd9aa4401c36785ea1b6fff0552c674bdd1b641319cb07ed1fe2392388e9b0d7 \
--hash=sha256:310a7aca6e7f257510d0c750364774034272538d51796ca31d42c3925d12a52a \
--hash=sha256:e512b7f3a4dd780f59f1bf22c302740e27b10b5c97e858a6061772668cd6f961 \
--hash=sha256:fdfb6ad138dbbf92b5dbea3576d7c8ba7463173f7d2cb0ca1bd336ec88ddbd80 \
--hash=sha256:e2f8a75261c26b2f5f3442b0525d50fd79a71aeca04b5ec270fc123536188306 \
--hash=sha256:c40973a0aee65422d8cb4e7d7cbded95dfeee0199caab54d5ab25b63bce8135a \
--hash=sha256:adf0e4d57b33881d0c63bb11e7f9038f98ee0c3e334c221f0858f826e8fb0151 \
--hash=sha256:0bae429443cc4748be2aadfdaf9633297cfaeb24a9a02d0ab15849175ce90fab \
--hash=sha256:e11df1ac6905e81b815ab6fd518e79be0a58b5dc427a2cf7208980f30694b956 \
--hash=sha256:7774bbbaac81d3ba86de646c39f154afc8156717972bf0450c9dbfa1dc8dbea2 \
--hash=sha256:8eb9c93798b904f141d9de36a0ba9f9b73cc382869e67c9e642c0aba53b0fc07 \
--hash=sha256:fac513a9dc2a74b99abd2e17109b53945e364649ca03d9f7a0b96aa8d1807d0a \
--hash=sha256:82d7ac987715d8d1eb4068bf997f3053468e0ce0287e2729c30601feb6602fee \
--hash=sha256:73152776dc75f335c476d11d52ec6f0f6925774802cd48d6189f4d5d7fe753f4 \
--hash=sha256:52e586072612c1eec18e1174f8e3bb19d08f075fc2e3f91d3b16c919078469d0 \
--hash=sha256:2affcaba328c4662f3bc3c0e9576ea107906b2c2b6422344cdad961734ff6b93 \
--hash=sha256:24e3b6ad259544d717902777b33966a1a069208c885576254c112663e6a5bb0f \
--hash=sha256:c77c974d1dadf246d789f6dad1c24426137c9091e930dbf50e0a29c1fcf00b1f
future==0.18.2 \
--hash=sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d
google-api-core==1.26.3 \
--hash=sha256:b914345c7ea23861162693a27703bab804a55504f7e6e9abcaff174d80df32ac \
--hash=sha256:099762d4b4018cd536bcf85136bf337957da438807572db52f21dc61251be089
google-api-python-client==2.1.0 \
--hash=sha256:f9ac377efe69571aea1acc9e15760d4204aca23c4464eb63f963ae4defc95d97 \
--hash=sha256:921fe10cdff22d1f5b8af7473f9a298efb991fb6ea67dadd6c37fbecfb0575f4
google-auth==1.28.1 \
--hash=sha256:70b39558712826e41f65e5f05a8d879361deaf84df8883e5dd0ec3d0da6ab66e \
--hash=sha256:186fe2564634d67fbbb64f3daf8bc8c9cecbb2a7f535ed1a8a71795e50db8d87
google-auth-httplib2==0.1.0 \
--hash=sha256:a07c39fd632becacd3f07718dfd6021bf396978f03ad3ce4321d060015cc30ac \
--hash=sha256:31e49c36c6b5643b57e82617cb3e021e3e1d2df9da63af67252c02fa9c1f4a10
google-auth-oauthlib==0.4.4 \
--hash=sha256:09832c6e75032f93818edf1affe4746121d640c625a5bef9b5c96af676e98eee \
--hash=sha256:0e92aacacfb94978de3b7972cf4b0f204c3cd206f74ddd0dc0b31e91164e6317
googleapis-common-protos==1.53.0 \
--hash=sha256:a88ee8903aa0a81f6c3cec2d5cf62d3c8aa67c06439b0496b49048fb1854ebf4 \
--hash=sha256:f6d561ab8fb16b30020b940e2dd01cd80082f4762fa9f3ee670f4419b4b8dbd0
httplib2==0.19.1 \
--hash=sha256:2ad195faf9faf079723f6714926e9a9061f694d07724b846658ce08d40f522b4 \
--hash=sha256:0b12617eeca7433d4c396a100eaecfa4b08ee99aa881e6df6e257a7aad5d533d
idna==2.10 \
--hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0 \
--hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6
oauthlib==3.1.0 \
--hash=sha256:df884cd6cbe20e32633f1db1072e9356f53638e4361bef4e8b03c9127c9328ea \
--hash=sha256:bee41cc35fcca6e988463cacc3bcb8a96224f470ca547e697b604cc697b2f889
packaging==20.9 \
--hash=sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a \
--hash=sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5
protobuf==3.15.8 \
--hash=sha256:fad4f971ec38d8df7f4b632c819bf9bbf4f57cfd7312cf526c69ce17ef32436a \
--hash=sha256:f17b352d7ce33c81773cf81d536ca70849de6f73c96413f17309f4b43ae7040b \
--hash=sha256:4a054b0b5900b7ea7014099e783fb8c4618e4209fffcd6050857517b3f156e18 \
--hash=sha256:efa4c4d4fc9ba734e5e85eaced70e1b63fb3c8d08482d839eb838566346f1737 \
--hash=sha256:07eec4e2ccbc74e95bb9b3afe7da67957947ee95bdac2b2e91b038b832dd71f0 \
--hash=sha256:f9cadaaa4065d5dd4d15245c3b68b967b3652a3108e77f292b58b8c35114b56c \
--hash=sha256:2dc0e8a9e4962207bdc46a365b63a3f1aca6f9681a5082a326c5837ef8f4b745 \
--hash=sha256:f80afc0a0ba13339bbab25ca0409e9e2836b12bb012364c06e97c2df250c3343 \
--hash=sha256:c5566f956a26cda3abdfacc0ca2e21db6c9f3d18f47d8d4751f2209d6c1a5297 \
--hash=sha256:dab75b56a12b1ceb3e40808b5bd9dfdaef3a1330251956e6744e5b6ed8f8830b \
--hash=sha256:3053f13207e7f13dc7be5e9071b59b02020172f09f648e85dc77e3fcb50d1044 \
--hash=sha256:1f0b5d156c3df08cc54bc2c8b8b875648ea4cd7ebb2a9a130669f7547ec3488c \
--hash=sha256:90270fe5732c1f1ff664a3bd7123a16456d69b4e66a09a139a00443a32f210b8 \
--hash=sha256:f42c2f5fb67da5905bfc03733a311f72fa309252bcd77c32d1462a1ad519521e \
--hash=sha256:f6077db37bfa16494dca58a4a02bfdacd87662247ad6bc1f7f8d13ff3f0013e1 \
--hash=sha256:510e66491f1a5ac5953c908aa8300ec47f793130097e4557482803b187a8ee05 \
--hash=sha256:5ff9fa0e67fcab442af9bc8d4ec3f82cb2ff3be0af62dba047ed4187f0088b7d \
--hash=sha256:1c0e9e56202b9dccbc094353285a252e2b7940b74fdf75f1b4e1b137833fabd7 \
--hash=sha256:a0a08c6b2e6d6c74a6eb5bf6184968eefb1569279e78714e239d33126e753403 \
--hash=sha256:0277f62b1e42210cafe79a71628c1d553348da81cbd553402a7f7549c50b11d0
pyasn1==0.4.8 \
--hash=sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3 \
--hash=sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf \
@ -89,39 +100,37 @@ pyasn1-modules==0.2.8 \
--hash=sha256:426edb7a5e8879f1ec54a1864f16b882c2837bfd06eee62f2c982315ee2473ed \
--hash=sha256:cbac4bc38d117f2a49aeedec4407d23e8866ea4ac27ff2cf7fb3e5b570df19e0 \
--hash=sha256:c29a5e5cc7a3f05926aff34e097e84f8589cd790ce0ed41b67aed6857b26aafd
python-magic==0.4.15 \
--hash=sha256:f3765c0f582d2dfc72c15f3b5a82aecfae9498bd29ca840d72f37d7bd38bfcd5 \
--hash=sha256:f2674dcfad52ae6c49d4803fa027809540b130db1dec928cfbb9240316831375
python-magic-bin==0.4.14; platform_system == "Windows" \
--hash=sha256:7b1743b3dbf16601d6eedf4e7c2c9a637901b0faaf24ad4df4d4527e7d8f66a4 \
--hash=sha256:34a788c03adde7608028203e2dbb208f1f62225ad91518787ae26d603ae68892 \
--hash=sha256:90be6206ad31071a36065a2fc169c5afb5e0355cbe6030e87641c6c62edc2b69
pytz==2019.3 \
--hash=sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d \
--hash=sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be
requests==2.23.0 \
--hash=sha256:43999036bfa82904b6af1d99e4882b560e5e2c68e5c4b0aa03b655f3d7d73fee \
--hash=sha256:b3f43d496c6daba4493e7c431722aeb7dbc6288f52a6e04e7b6023b0247817e6
requests-oauthlib==0.8.0 \
--hash=sha256:883ac416757eada6d3d07054ec7092ac21c7f35cb1d2cf82faf205637081f468 \
--hash=sha256:50a8ae2ce8273e384895972b56193c7409601a66d4975774c60c2aed869639ca
pyparsing==2.4.7 \
--hash=sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b \
--hash=sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1
pytz==2021.1 \
--hash=sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798 \
--hash=sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da
requests==2.25.1 \
--hash=sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e \
--hash=sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804
requests-oauthlib==1.3.0 \
--hash=sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a \
--hash=sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d \
--hash=sha256:fa6c47b933f01060936d87ae9327fead68768b69c6c9ea2109c48be30f2d4dbc
requests-toolbelt==0.9.1 \
--hash=sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0 \
--hash=sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f
rsa==4.0 \
--hash=sha256:14ba45700ff1ec9eeb206a2ce76b32814958a98e372006c8fb76ba820211be66 \
--hash=sha256:1a836406405730121ae9823e19c6e806c62bbad73f890574fff50efa4122c487
schema==0.6.8 \
--hash=sha256:d994b0dc4966000037b26898df638e3e2a694cc73636cb2050e652614a350687 \
--hash=sha256:fa1a53fe5f3b6929725a4e81688c250f46838e25d8c1885a10a590c8c01a7b74
six==1.14.0 \
--hash=sha256:8f3cd2e254d8f793e7f3d6d9df77b92252b52637291d0f0da013c76ea2724b6c \
--hash=sha256:236bdbdce46e6e6a3d61a337c0f8b763ca1e8717c03b369e87a7ec7ce1319c0a
tzlocal==1.5.1 \
--hash=sha256:4ebeb848845ac898da6519b9b31879cf13b6626f7184c496037b818e238f2c4e
unidecode==1.1.1 \
--hash=sha256:1d7a042116536098d05d599ef2b8616759f02985c85b4fef50c78a5aaf10822a \
--hash=sha256:2b6aab710c2a1647e928e36d69c21e76b453cd455f4e2621000e54b2a9b8cce8
rsa==4.4; python_version >= "3.6" \
--hash=sha256:4afbaaecc3e9550c7351fdf0ab3fea1857ff616b85bab59215f00fb42e0e9582 \
--hash=sha256:5d95293bbd0fbee1dd9cb4b72d27b723942eb50584abc8c4f5f00e4bcfa55307
schema==0.7.4 \
--hash=sha256:cf97e4cd27e203ab6bb35968532de1ed8991bce542a646f0ff1d643629a4945d \
--hash=sha256:fbb6a52eb2d9facf292f233adcc6008cffd94343c63ccac9a1cb1f3e6de1db17
six==1.15.0 \
--hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced \
--hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259
tzlocal==2.1 \
--hash=sha256:e2cb6c6b5b604af38597403e9852872d7f534962ae2954c7f35efcb1ccacf4a4 \
--hash=sha256:643c97c5294aedc737780a49d9df30889321cbe1204eac2c2ec6134035a92e44
unidecode==1.2.0 \
--hash=sha256:12435ef2fc4cdfd9cf1035a1db7e98b6b047fe591892e81f34e94959591fad00 \
--hash=sha256:8d73a97d387a956922344f6b74243c2c6771594659778744b2dbdaad8f6b727d
uritemplate==3.0.1 \
--hash=sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f \
--hash=sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae

Loading…
Cancel
Save