diff --git a/CHANGELOG.md b/CHANGELOG.md index b507c12..441aa2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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) diff --git a/README.md b/README.md index 4139c9f..03c9de6 100644 --- a/README.md +++ b/README.md @@ -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 😘 \ No newline at end of file +Thanks to: @LecygneNoir, @Zykino, @meewan, @rigelk 😘 \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index 39dd1d9..05567b2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -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"}, ] diff --git a/prismedia/__init__.py b/prismedia/__init__.py index 7ec26e8..d1dde1f 100644 --- a/prismedia/__init__.py +++ b/prismedia/__init__.py @@ -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 diff --git a/prismedia/genconfig.py b/prismedia/genconfig.py index f03e423..d3a29c7 100644 --- a/prismedia/genconfig.py +++ b/prismedia/genconfig.py @@ -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__': diff --git a/prismedia/pt_upload.py b/prismedia/pt_upload.py index 6b43151..adb5a36 100644 --- a/prismedia/pt_upload.py +++ b/prismedia/pt_upload.py @@ -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 diff --git a/prismedia/upload.py b/prismedia/upload.py index 7220b7d..bae465b 100755 --- a/prismedia/upload.py +++ b/prismedia/upload.py @@ -7,11 +7,12 @@ prismedia - tool to upload videos to Peertube and Youtube Usage: prismedia --file= [options] prismedia -f --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) diff --git a/prismedia/utils.py b/prismedia/utils.py index 86d4a33..817af5f 100644 --- a/prismedia/utils.py +++ b/prismedia/utils.py @@ -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'): diff --git a/prismedia/yt_upload.py b/prismedia/yt_upload.py index 22db640..e8809c5 100644 --- a/prismedia/yt_upload.py +++ b/prismedia/yt_upload.py @@ -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)) diff --git a/pyproject.toml b/pyproject.toml index b8e946c..329aa51 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -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 ", @@ -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" diff --git a/requirements.txt b/requirements.txt index be9ff52..fcbe966 100644 --- a/requirements.txt +++ b/requirements.txt @@ -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