26 Commits

Author SHA1 Message Date
  LecygneNoir 03a8f4e71f Merge branch 'release/v0.12.2' 1 year ago
  LecygneNoir 5ca5ff5238 Release v0.12.2 to fix broken dependencies 1 year ago
  LecygneNoir 6c16b2f037 Merge tag 'v0.12.1' into develop 2 years ago
  LecygneNoir 36110432da Merge branch 'hotfix/v0.12.1' 2 years ago
  LecygneNoir 388f76b855 Fix a bug in when configuring log level 2 years ago
  LecygneNoir ef92fed69d Merge tag 'v0.12.0' into develop 2 years ago
  LecygneNoir bcb0e267f3 Merge branch 'release/v0.12.0' 2 years ago
  LecygneNoir 8bc79853c8 Bump version to v0.12.0 and prepare poetry build for v0.12.0 2 years ago
  LecygneNoir 45a1cbccff Merge branch 'feature/remove_formatcheck' into develop 2 years ago
  LecygneNoir 0a1360d8e2 Prepare changelo for v0.12.0 2 years ago
  LecygneNoir f8ae2b1c5e Update libraries and dependencies for prismedia 2 years ago
  LecygneNoir 0a53e77bd6 Add auto search for thumbnail based on .png in addition to .jpg and .jpeg 2 years ago
  LecygneNoir 2f7629ef1e Remove format checks for videos and thumbnail as Youtube and Peertube have no limitation anymore 2 years ago
  LecygneNoir e0a63ed4b2 Revert README to use prismedia as it's indeed the binary script installed through pip 3 years ago
  LecygneNoir ba2a1ebb79 Merge branch 'feature/improve_genconfig' into develop 3 years ago
  LecygneNoir cf3d4c32c3 Better resilience for the genconfig function thanks to happy path and @Zykino suggestion! 3 years ago
  LecygneNoir 85f0fe9b6f Add ask_overwirte function to utils in order to be more general and usable in other modules 3 years ago
  LecygneNoir 1a006f3b6c Improve genconfig system and documentation for easier use, cf #55 3 years ago
  LecygneNoir cdef038323 Move logger initialization in __init__.py to be able to use it from any module 3 years ago
  LecygneNoir cbf3386bac Remove confusing warning when using genconfig, see #55 3 years ago
  LecygneNoir ca733e0dc3 Merge pull request 'hearthbeat (keepalive ?)' (#54) from Zykino/prismedia:hearthbeat into develop 3 years ago
  Zykino a4f162320d Fix some spacing formatting and documentation 3 years ago
  Zykino 29b1747c3e Visit all of Youtube’s playlists 3 years ago
  Zykino ea39fe9854 Fix some spacing 3 years ago
  Zykino a725e848ab Add an option to use some credits easiely 3 years ago
  LecygneNoir 9b6da1e3dc Merge tag 'v0.11.0' into develop 3 years ago
11 changed files with 581 additions and 487 deletions
Split View
  1. +40
    -15
      CHANGELOG.md
  2. +53
    -44
      README.md
  3. +269
    -245
      poetry.lock
  4. +8
    -1
      prismedia/__init__.py
  5. +11
    -2
      prismedia/genconfig.py
  6. +1
    -1
      prismedia/pt_upload.py
  7. +29
    -57
      prismedia/upload.py
  8. +13
    -0
      prismedia/utils.py
  9. +43
    -17
      prismedia/yt_upload.py
  10. +17
    -17
      pyproject.toml
  11. +97
    -88
      requirements.txt

+ 40
- 15
CHANGELOG.md View File

@ -1,10 +1,35 @@
# Changelog
## v0.12.2
### Fix
- Adjust dependencies version, as `oauthlib` and `request-oauthlib` are incompatible with peertube process in their new versions
- Add `pytz` as explicit dependency since the previous unexplicit dependancy now install `pytz-deprecation-shim` - which does not work
- Remove peertube-mirror link as it's now (unfortunately) a dead project (fix #63)
## v0.12.1
### Fix
- Fix an error when setting log level in configuration
## 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
- 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)
### 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)
## v0.10.3
@ -15,7 +40,7 @@
### Fixes
- Fix a typo in log (missing space when displaying thumbnail) (see #49)
- Add pagination when searching playlist in Peertube as default pagination show only 14 playlists (see #41)
- Add pagination when searching playlist in Peertube as default pagination show only 14 playlists (see #41)
- Add a check to avoid uploading video on Peertube with more than 5 tags (see #48)
- Revert the workaround for Youtube playlist bug now the bug is fixed by Youtube (see #47)
@ -29,8 +54,8 @@
### Features
- Add the possibility to specify strict checks option to never forgot parameters when uploading (see #36)
- Improve logging system, add options for batch upload and print url-only in the stdout (see #29)
- --debug option is now deprecated in favor of --log=debug
- --debug option is now deprecated in favor of --log=debug
### Fixes
- Workaround against the Youtube API breakdown while adding video in playlist. See #47 for details. Should be removed once Google fix their bugs.
@ -45,7 +70,7 @@
## v0.9.0
### Upgrade from v0.8.0
Now using [poetry](https://python-poetry.org/) for packaging and installing! It's easier to maintain and publish package, but means changes when using prismedia from command line.
Now using [poetry](https://python-poetry.org/) for packaging and installing! It's easier to maintain and publish package, but means changes when using prismedia from command line.
**Using poetry** (recommanded)
@ -60,8 +85,8 @@ poetry install
prismedia -h
```
**From source**
Prismedia is now seen as a python module, so you need to use `python -m prismedia` instead of `./prismedia_upload.py`.
**From source**
Prismedia is now seen as a python module, so you need to use `python -m prismedia` instead of `./prismedia_upload.py`.
Once you have pulled the new v0.9.0, you may update by using:
```
pip install -r requirements.txt
@ -77,12 +102,12 @@ python -m prismedia -h
## v0.8.0
### Breaking changes
Now work with python 3! Support of python 2 is no longer available.
Now work with python 3! Support of python 2 is no longer available.
You should now use python 3 in order to use prismedia
### Features
- Add a requirements.txt file to make installing requirement easier.
- Add a debug option to show some infos before uploading (thanks to @zykino)
- Add a requirements.txt file to make installing requirement easier.
- Add a debug option to show some infos before uploading (thanks to @zykino)
- Now uploading to Peertube before Youtube (thanks to @zykino)
## v0.7.1
@ -93,7 +118,7 @@ Fix bug #42 , crash on Peertube when video has only one tag
## v0.7.0
### Features
Support Peertube channel additionally with playlist for Peertube!
Support Peertube channel additionally with playlist for Peertube!
Peertube only as channel are Peertube's feature. See #40 for details.
### Fixes
@ -121,7 +146,7 @@ New feature, the Peertube playlists are now supported!
We do not use channel in place of playlist anymore.
## v0.6.1-1 Hotfix
This fix prepares the python3 compatibility.
This fix prepares the python3 compatibility.
**Warning** you need a new prerequisites: python-unidecode
- Remove mastodon tags (mt) options as it's deprecated. Compatibility between Peertube and Mastodon is complete.
@ -157,4 +182,4 @@ This release is fully compatible with Peertube v1.0.0!
### Fixes
- Display datetime for output
- plan video only if upload is successful
- plan video only if upload is successful

+ 53
- 44
README.md View File

@ -23,60 +23,62 @@ 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`)
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`)
Otherwise, you can use [poetry](https://python-poetry.org), which create a virtualenv for the project directly
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:
https://domain.example/api/v1/oauth-clients/local
You can set ``OAUTHLIB_INSECURE_TRANSPORT`` to 1 if you do not use https (not recommended)
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
*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``.
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`.
Prismedia will try to use this file at each launch, and re-ask for authentication if it does not exist.
**Oauth**:
The default youtube_secret.json should allow you to upload some videos.
**Oauth**:
The default youtube_secret.json should allow you to upload some videos.
If you plan a larger usage, please consider creating your own youtube_secret file:
- Go to the [Google console](https://console.developers.google.com/).
@ -89,54 +91,61 @@ If you plan a larger usage, please consider creating your own youtube_secret fil
- Save this JSON as your youtube_secret.json file.
## Usage
Support only mp4 for cross compatibility between Youtube and Peertube.
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:
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:
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
@ -212,7 +221,7 @@ Available strict options:
- [x] Usable on Desktop (Linux and/or Windows and/or MacOS)
- [x] Different schedules on platforms to prepare preview
- [x] Possibility to force the presence of upload options
- [ ] Copy and forget, eg possibility to copy video in a directory, and prismedia uploads itself: [Work in progress](https://git.lecygnenoir.info/Zykino/prismedia-autoupload) thanks to @Zykino 🎉 (Discussions in [issue 27](https://git.lecygnenoir.info/LecygneNoir/prismedia/issues/27))
- [ ] Copy and forget, eg possibility to copy video in a directory, and prismedia uploads itself: [Work in progress](https://git.lecygnenoir.info/Zykino/prismedia-autoupload) thanks to @Zykino 🎉 (Discussions in [issue 27](https://git.lecygnenoir.info/LecygneNoir/prismedia/issues/27))
- [ ] A usable graphical interface
## Compatibility
@ -221,7 +230,7 @@ Available strict options:
- If you use peertube before 1.0.0-beta4, use the version inside tag 1.0.0-beta3
## Inspirations
Inspired by [peeror](https://git.rigelk.eu/rigelk/peeror) and [youtube-upload](https://github.com/tokland/youtube-upload)
Inspired by peeror (First peertube mirror by Rigelk) and [youtube-upload](https://github.com/tokland/youtube-upload)
## Contributors
Thanks to: @Zykino, @meewan, @rigelk 😘
Thanks to: @LecygneNoir, @Zykino, @meewan, @rigelk 😘

+ 269
- 245
poetry.lock View File

@ -8,19 +8,28 @@ version = "0.1.0"
[[package]]
category = "main"
description = "Extensible memoizing collections and decorators"
name = "cachetools"
description = "Backport of the standard library zoneinfo module"
marker = "python_version >= \"3.6\" and python_version < \"3.9\" or python_version < \"3.9\""
name = "backports.zoneinfo"
optional = false
python-versions = "*"
version = "3.1.1"
python-versions = ">=3.6"
version = "0.2.1"
[package.dependencies]
[package.dependencies.importlib-resources]
python = "<3.7"
version = "*"
[package.extras]
tzdata = ["tzdata"]
[[package]]
category = "main"
description = "Extensible memoizing collections and decorators"
name = "cachetools"
optional = false
python-versions = "~=3.5"
version = "4.2.0"
python-versions = "*"
version = "3.1.1"
[[package]]
category = "main"
@ -28,15 +37,19 @@ description = "Python package for providing Mozilla's CA Bundle."
name = "certifi"
optional = false
python-versions = "*"
version = "2020.12.5"
version = "2021.10.8"
[[package]]
category = "main"
description = "Universal encoding detector for Python 2 and 3"
name = "chardet"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
marker = "python_version >= \"3\""
name = "charset-normalizer"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "4.0.0"
python-versions = ">=3.5.0"
version = "2.0.12"
[package.extras]
unicode_backport = ["unicodedata2"]
[[package]]
category = "main"
@ -51,23 +64,23 @@ 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.2.0"
[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)", "jaraco.tidelift (>=1.4)"]
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "types-backports", "pytest-black (>=0.3.7)", "pytest-mypy"]
[[package]]
category = "main"
description = "Backports and enhancements for the contextlib module"
name = "contextlib2"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "0.6.0.post1"
python-versions = ">=3.6"
version = "21.6.0"
[[package]]
category = "main"
@ -83,49 +96,24 @@ 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"
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"
python-versions = ">=3.6"
version = "2.7.2"
[package.dependencies]
google-auth = ">=1.21.1,<2.0dev"
googleapis-common-protos = ">=1.6.0,<2.0dev"
google-auth = ">=1.25.0,<3.0dev"
googleapis-common-protos = ">=1.52.0,<2.0dev"
protobuf = ">=3.12.0"
pytz = "*"
requests = ">=2.18.0,<3.0.0dev"
setuptools = ">=40.3.0"
six = ">=1.13.0"
[package.extras]
grpc = ["grpcio (>=1.29.0,<2.0dev)"]
grpc = ["grpcio (>=1.33.2,<2.0dev)", "grpcio-status (>=1.33.2,<2.0dev)"]
grpcgcp = ["grpcio-gcp (>=0.2.2)"]
grpcio-gcp = ["grpcio-gcp (>=0.2.2)"]
@ -134,37 +122,15 @@ 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"
[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"
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"
python-versions = ">=3.6"
version = "2.44.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)"]
google-api-core = ">=1.31.5,<2.0.0 || >2.3.0,<3.0.0dev"
google-auth = ">=1.16.0,<3.0.0dev"
google-auth-httplib2 = ">=0.1.0"
httplib2 = ">=0.15.0,<1dev"
uritemplate = ">=3.0.1,<5"
[[package]]
category = "main"
@ -172,12 +138,11 @@ 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 = "2.6.5"
[package.dependencies]
cachetools = ">=2.0.0,<5.0"
cachetools = ">=2.0.0,<6.0"
pyasn1-modules = ">=0.2.1"
setuptools = ">=40.3.0"
six = ">=1.9.0"
[package.dependencies.rsa]
@ -185,7 +150,9 @@ python = ">=3.6"
version = ">=3.1.4,<5"
[package.extras]
aiohttp = ["aiohttp (>=3.6.2,<4.0.0dev)"]
aiohttp = ["requests (>=2.20.0,<3.0.0dev)", "aiohttp (>=3.6.2,<4.0.0dev)"]
pyopenssl = ["pyopenssl (>=20.0.0)"]
reauth = ["pyu2f (>=0.1.5)"]
[[package]]
category = "main"
@ -193,53 +160,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.5.1"
[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.56.0"
[package.dependencies]
protobuf = ">=3.6.0"
protobuf = ">=3.12.0"
[package.extras]
grpc = ["grpcio (>=1.0.0)"]
@ -249,16 +201,40 @@ category = "main"
description = "A comprehensive HTTP client library."
name = "httplib2"
optional = false
python-versions = "*"
version = "0.12.3"
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "0.20.4"
[package.dependencies]
[package.dependencies.pyparsing]
python = ">=3.1"
version = ">=2.4.2,<3.0.0 || >3.0.0,<3.0.1 || >3.0.1,<3.0.2 || >3.0.2,<3.0.3 || >3.0.3,<4"
[[package]]
category = "main"
description = "Internationalized Domain Names in Applications (IDNA)"
marker = "python_version >= \"3\""
name = "idna"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "2.10"
python-versions = ">=3.5"
version = "3.3"
[[package]]
category = "main"
description = "Read resources from Python packages"
marker = "python_version >= \"3.6\" and python_version < \"3.7\" or python_version < \"3.7\""
name = "importlib-resources"
optional = false
python-versions = ">=3.6"
version = "5.4.0"
[package.dependencies]
[package.dependencies.zipp]
python = "<3.10"
version = ">=3.1.0"
[package.extras]
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-black (>=0.3.7)", "pytest-mypy"]
[[package]]
category = "main"
@ -279,11 +255,8 @@ category = "main"
description = "Protocol Buffers"
name = "protobuf"
optional = false
python-versions = "*"
version = "3.14.0"
[package.dependencies]
six = ">=1.9"
python-versions = ">=3.5"
version = "3.19.4"
[[package]]
category = "main"
@ -306,61 +279,79 @@ pyasn1 = ">=0.4.6,<0.5.0"
[[package]]
category = "main"
description = "File type identification using libmagic"
name = "python-magic"
description = "Python parsing module"
marker = "python_version > \"3.0\""
name = "pyparsing"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "0.4.20"
python-versions = ">=3.6"
version = "3.0.7"
[package.extras]
diagrams = ["jinja2", "railroad-diagrams"]
[[package]]
category = "main"
description = "File type identification using libmagic binary package"
marker = "platform_system == \"Windows\""
name = "python-magic-bin"
description = "World timezone definitions, modern and historical"
name = "pytz"
optional = false
python-versions = "*"
version = "0.4.14"
version = "2022.1"
[[package]]
category = "main"
description = "World timezone definitions, modern and historical"
name = "pytz"
description = "Shims to make deprecation of pytz easier"
name = "pytz-deprecation-shim"
optional = false
python-versions = "*"
version = "2020.5"
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
version = "0.1.0.post0"
[package.dependencies]
[package.dependencies."backports.zoneinfo"]
python = ">=3.6,<3.9"
version = "*"
[package.dependencies.tzdata]
python = ">=3.6"
version = "*"
[[package]]
category = "main"
description = "Python HTTP for Humans."
name = "requests"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "2.25.1"
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
version = "2.27.1"
[package.dependencies]
certifi = ">=2017.4.17"
chardet = ">=3.0.2,<5"
idna = ">=2.5,<3"
urllib3 = ">=1.21.1,<1.27"
[package.dependencies.charset-normalizer]
python = ">=3"
version = ">=2.0.0,<2.1.0"
[package.dependencies.idna]
python = ">=3"
version = ">=2.5,<4"
[package.extras]
security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"]
use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
[[package]]
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.1.0"
[package.dependencies]
oauthlib = ">=0.6.2"
oauthlib = ">=2.1.0,<3.0.0"
requests = ">=2.0.0"
[package.extras]
rsa = ["oauthlib (>=0.6.2)", "requests (>=2.0.0)"]
rsa = ["oauthlib (>=2.1.0,<3.0.0)"]
[[package]]
category = "main"
@ -385,25 +376,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.5"
[package.dependencies]
contextlib2 = ">=0.5.5"
@ -414,34 +393,52 @@ description = "Python 2 and 3 compatibility utilities"
name = "six"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
version = "1.15.0"
version = "1.16.0"
[[package]]
category = "main"
description = "Provider of IANA time zone data"
marker = "python_version >= \"3.6\" or platform_system == \"Windows\""
name = "tzdata"
optional = false
python-versions = ">=2"
version = "2022.1"
[[package]]
category = "main"
description = "tzinfo object for the local timezone"
name = "tzlocal"
optional = false
python-versions = "*"
version = "1.5.1"
python-versions = ">=3.6"
version = "4.2"
[package.dependencies]
pytz = "*"
pytz-deprecation-shim = "*"
tzdata = "*"
[package.dependencies."backports.zoneinfo"]
python = "<3.9"
version = "*"
[package.extras]
devenv = ["black", "pyroma", "pytest-cov", "zest.releaser"]
test = ["pytest-mock (>=3.3)", "pytest (>=4.3)"]
[[package]]
category = "main"
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"
python-versions = ">=3.5"
version = "1.3.4"
[[package]]
category = "main"
description = "URI templates"
description = "Implementation of RFC 6570 URI Templates"
name = "uritemplate"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "3.0.1"
python-versions = ">=3.6"
version = "4.1.1"
[[package]]
category = "main"
@ -457,117 +454,139 @@ 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"
description = "Backport of pathlib-compatible object wrapper for zip files"
marker = "python_version >= \"3.6\" and python_version < \"3.7\" or python_version < \"3.7\""
name = "zipp"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
version = "1.26.2"
python-versions = ">=3.6"
version = "3.6.0"
[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)"]
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
[metadata]
content-hash = "41a9471d93da0f5e3d684cdf9e8f981659030d67f29ef6bf55c07a0d49a3ee93"
python-versions = ">=3.5"
content-hash = "be6573f03c921c7e695d02a9d03b766a756d2c5a61619cbebea44c85a4f66bf6"
python-versions = ">=3.6"
[metadata.files]
args = [
{file = "args-0.1.0.tar.gz", hash = "sha256:a785b8d837625e9b61c39108532d95b85274acd679693b71ebb5156848fcf814"},
]
"backports.zoneinfo" = [
{file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"},
{file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"},
{file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546"},
{file = "backports.zoneinfo-0.2.1-cp36-cp36m-win32.whl", hash = "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08"},
{file = "backports.zoneinfo-0.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7"},
{file = "backports.zoneinfo-0.2.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac"},
{file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf"},
{file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570"},
{file = "backports.zoneinfo-0.2.1-cp37-cp37m-win32.whl", hash = "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b"},
{file = "backports.zoneinfo-0.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582"},
{file = "backports.zoneinfo-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987"},
{file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1"},
{file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9"},
{file = "backports.zoneinfo-0.2.1-cp38-cp38-win32.whl", hash = "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328"},
{file = "backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6"},
{file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"},
]
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"},
{file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"},
{file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"},
{file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"},
]
chardet = [
{file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"},
{file = "chardet-4.0.0.tar.gz", hash = "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa"},
charset-normalizer = [
{file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"},
{file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"},
]
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.2.0-py3-none-any.whl", hash = "sha256:e8b39238fb6f0153a069aa253d349467c3c4737934f253ef6abac5fe0eca1e5d"},
{file = "configparser-5.2.0.tar.gz", hash = "sha256:1b35798fdf1713f1c3139016cfcbc461f09edbf099d1fb658d4b7479fcaa3daa"},
]
contextlib2 = [
{file = "contextlib2-0.6.0.post1-py2.py3-none-any.whl", hash = "sha256:3355078a159fbb44ee60ea80abd0d87b80b78c248643b49aa6d94673b413609b"},
{file = "contextlib2-0.6.0.post1.tar.gz", hash = "sha256:01f490098c18b19d2bd5bb5dc445b2054d2fa97f09a4280ba2c5f3c394c8162e"},
{file = "contextlib2-21.6.0-py2.py3-none-any.whl", hash = "sha256:3fbdb64466afd23abaf6c977627b75b6139a5a3e8ce38405c5b413aed7a0471f"},
{file = "contextlib2-21.6.0.tar.gz", hash = "sha256:ab1e2bfe1d01d968e1b7e8d9023bc51ef3509bba217bb730cee3827e1ee82869"},
]
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-2.7.2.tar.gz", hash = "sha256:65480309a7437f739e4476da037af02a3ec8263f1d1f89f72bbdc8f54fe402d2"},
{file = "google_api_core-2.7.2-py3-none-any.whl", hash = "sha256:8fcbe52dc129fd83dca4e638a76f22b3a11579c493e643134e50e9870b233302"},
]
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.44.0.tar.gz", hash = "sha256:fc9c31737b82a592d29636c6f77af9cf9666e45ed966d0a5ebe20711aa0df83c"},
{file = "google_api_python_client-2.44.0-py2.py3-none-any.whl", hash = "sha256:0588acf65ea0569ece979c4eecdd5366c98ba314c1212a86a2808de0b7bcd02b"},
]
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-2.6.5.tar.gz", hash = "sha256:04e224f241c0566477bb35a8a93be8c635210de743bde454d49393cfb605266d"},
{file = "google_auth-2.6.5-py2.py3-none-any.whl", hash = "sha256:9a88ee548f6fd49467e2e443dfbfe10344e5a270629a137a3a0b3437ec6b02a6"},
]
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.5.1.tar.gz", hash = "sha256:30596b824fc6808fdaca2f048e4998cc40fb4b3599eaea66d28dc7085b36c5b8"},
{file = "google_auth_oauthlib-0.5.1-py2.py3-none-any.whl", hash = "sha256:24f67735513c4c7134dbde2f1dee5a1deb6acc8dfcb577d7bff30d213a28e7b0"},
]
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.56.0.tar.gz", hash = "sha256:4007500795bcfc269d279f0f7d253ae18d6dc1ff5d5a73613ffe452038b1ec5f"},
{file = "googleapis_common_protos-1.56.0-py2.py3-none-any.whl", hash = "sha256:60220c89b8bd5272159bed4929ecdc1243ae1f73437883a499a44a1cbc084086"},
]
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.20.4-py3-none-any.whl", hash = "sha256:8b6a905cb1c79eefd03f8669fd993c36dc341f7c558f056cb5a33b5c2f458543"},
{file = "httplib2-0.20.4.tar.gz", hash = "sha256:58a98e45b4b1a48273073f905d2961666ecf0fbac4250ea5b47aef259eb5c585"},
]
idna = [
{file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},
{file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"},
{file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"},
{file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"},
]
importlib-resources = [
{file = "importlib_resources-5.4.0-py3-none-any.whl", hash = "sha256:33a95faed5fc19b4bc16b29a6eeae248a3fe69dd55d4d229d2b480e23eeaad45"},
{file = "importlib_resources-5.4.0.tar.gz", hash = "sha256:d756e2f85dd4de2ba89be0b21dba2a3bbec2e871a42a3a16719258a11f87506b"},
]
oauthlib = [
{file = "oauthlib-2.1.0-py2.py3-none-any.whl", hash = "sha256:d883b36b21a6ad813953803edfa563b1b579d79ca758fe950d1bc9e8b326025b"},
{file = "oauthlib-2.1.0.tar.gz", hash = "sha256:ac35665a61c1685c56336bda97d5eefa246f1202618a1d6f34fccb1bdd404162"},
]
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.19.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f51d5a9f137f7a2cec2d326a74b6e3fc79d635d69ffe1b036d39fc7d75430d37"},
{file = "protobuf-3.19.4-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:09297b7972da685ce269ec52af761743714996b4381c085205914c41fcab59fb"},
{file = "protobuf-3.19.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:072fbc78d705d3edc7ccac58a62c4c8e0cec856987da7df8aca86e647be4e35c"},
{file = "protobuf-3.19.4-cp310-cp310-win32.whl", hash = "sha256:7bb03bc2873a2842e5ebb4801f5c7ff1bfbdf426f85d0172f7644fcda0671ae0"},
{file = "protobuf-3.19.4-cp310-cp310-win_amd64.whl", hash = "sha256:f358aa33e03b7a84e0d91270a4d4d8f5df6921abe99a377828839e8ed0c04e07"},
{file = "protobuf-3.19.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:1c91ef4110fdd2c590effb5dca8fdbdcb3bf563eece99287019c4204f53d81a4"},
{file = "protobuf-3.19.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c438268eebb8cf039552897d78f402d734a404f1360592fef55297285f7f953f"},
{file = "protobuf-3.19.4-cp36-cp36m-win32.whl", hash = "sha256:835a9c949dc193953c319603b2961c5c8f4327957fe23d914ca80d982665e8ee"},
{file = "protobuf-3.19.4-cp36-cp36m-win_amd64.whl", hash = "sha256:4276cdec4447bd5015453e41bdc0c0c1234eda08420b7c9a18b8d647add51e4b"},
{file = "protobuf-3.19.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6cbc312be5e71869d9d5ea25147cdf652a6781cf4d906497ca7690b7b9b5df13"},
{file = "protobuf-3.19.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:54a1473077f3b616779ce31f477351a45b4fef8c9fd7892d6d87e287a38df368"},
{file = "protobuf-3.19.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:435bb78b37fc386f9275a7035fe4fb1364484e38980d0dd91bc834a02c5ec909"},
{file = "protobuf-3.19.4-cp37-cp37m-win32.whl", hash = "sha256:16f519de1313f1b7139ad70772e7db515b1420d208cb16c6d7858ea989fc64a9"},
{file = "protobuf-3.19.4-cp37-cp37m-win_amd64.whl", hash = "sha256:cdc076c03381f5c1d9bb1abdcc5503d9ca8b53cf0a9d31a9f6754ec9e6c8af0f"},
{file = "protobuf-3.19.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:69da7d39e39942bd52848438462674c463e23963a1fdaa84d88df7fbd7e749b2"},
{file = "protobuf-3.19.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:48ed3877fa43e22bcacc852ca76d4775741f9709dd9575881a373bd3e85e54b2"},
{file = "protobuf-3.19.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd95d1dfb9c4f4563e6093a9aa19d9c186bf98fa54da5252531cc0d3a07977e7"},
{file = "protobuf-3.19.4-cp38-cp38-win32.whl", hash = "sha256:b38057450a0c566cbd04890a40edf916db890f2818e8682221611d78dc32ae26"},
{file = "protobuf-3.19.4-cp38-cp38-win_amd64.whl", hash = "sha256:7ca7da9c339ca8890d66958f5462beabd611eca6c958691a8fe6eccbd1eb0c6e"},
{file = "protobuf-3.19.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:36cecbabbda242915529b8ff364f2263cd4de7c46bbe361418b5ed859677ba58"},
{file = "protobuf-3.19.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:c1068287025f8ea025103e37d62ffd63fec8e9e636246b89c341aeda8a67c934"},
{file = "protobuf-3.19.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96bd766831596d6014ca88d86dc8fe0fb2e428c0b02432fd9db3943202bf8c5e"},
{file = "protobuf-3.19.4-cp39-cp39-win32.whl", hash = "sha256:84123274d982b9e248a143dadd1b9815049f4477dc783bf84efe6250eb4b836a"},
{file = "protobuf-3.19.4-cp39-cp39-win_amd64.whl", hash = "sha256:3112b58aac3bac9c8be2b60a9daf6b558ca3f7681c130dcdd788ade7c9ffbdca"},
{file = "protobuf-3.19.4-py2.py3-none-any.whl", hash = "sha256:8961c3a78ebfcd000920c9060a262f082f29838682b1f7201889300c1fbe0616"},
{file = "protobuf-3.19.4.tar.gz", hash = "sha256:9df0c10adf3e83015ced42a9a7bd64e13d06c4cf45c340d2c63020ea04499d0a"},
]
pyasn1 = [
{file = "pyasn1-0.4.8-py2.4.egg", hash = "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3"},
@ -599,26 +618,26 @@ 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-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"},
{file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"},
]
pytz = [
{file = "pytz-2020.5-py2.py3-none-any.whl", hash = "sha256:16962c5fb8db4a8f63a26646d8886e9d769b6c511543557bc84e9569fb9a9cb4"},
{file = "pytz-2020.5.tar.gz", hash = "sha256:180befebb1927b16f6b57101720075a984c019ac16b1b7575673bea42c6c3da5"},
{file = "pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"},
{file = "pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7"},
]
pytz-deprecation-shim = [
{file = "pytz_deprecation_shim-0.1.0.post0-py2.py3-none-any.whl", hash = "sha256:8314c9692a636c8eb3bda879b9f119e350e93223ae83e70e80c31675a0fdc1a6"},
{file = "pytz_deprecation_shim-0.1.0.post0.tar.gz", hash = "sha256:af097bae1b616dde5c5744441e2ddc69e74dfdcb0c263129610d85b87445a59d"},
]
requests = [
{file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"},
{file = "requests-2.25.1.tar.gz", hash = "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804"},
{file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"},
{file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"},
]
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.1.0.tar.gz", hash = "sha256:eabd8eb700ebed81ba080c6ead96d39d6bdc39996094bd23000204f6965786b0"},
{file = "requests_oauthlib-1.1.0-py2.py3-none-any.whl", hash = "sha256:be76f2bb72ca5525998e81d47913e09b1ca8b7957ae89b46f787a79e68ad5e61"},
{file = "requests_oauthlib-1.1.0-py3.7.egg", hash = "sha256:490229d14a98e1b69612dcc1a22887ec14f5487dc1b8c6d7ba7f77a42ce7347b"},
]
requests-toolbelt = [
{file = "requests-toolbelt-0.9.1.tar.gz", hash = "sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0"},
@ -627,31 +646,36 @@ 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.5-py2.py3-none-any.whl", hash = "sha256:f3ffdeeada09ec34bf40d7d79996d9f7175db93b7a5065de0faa7f41083c1e6c"},
{file = "schema-0.7.5.tar.gz", hash = "sha256:f06717112c61895cabc4707752b88716e8420a8819d71404501e114f91043197"},
]
six = [
{file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"},
{file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"},
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
]
tzdata = [
{file = "tzdata-2022.1-py2.py3-none-any.whl", hash = "sha256:238e70234214138ed7b4e8a0fab0e5e13872edab3be586ab8198c407620e2ab9"},
{file = "tzdata-2022.1.tar.gz", hash = "sha256:8b536a8ec63dc0751342b3984193a3118f8fca2afe25752bb9b7fffd398552d3"},
]
tzlocal = [
{file = "tzlocal-1.5.1.tar.gz", hash = "sha256:4ebeb848845ac898da6519b9b31879cf13b6626f7184c496037b818e238f2c4e"},
{file = "tzlocal-4.2-py3-none-any.whl", hash = "sha256:89885494684c929d9191c57aa27502afc87a579be5cdd3225c77c463ea043745"},
{file = "tzlocal-4.2.tar.gz", hash = "sha256:ee5842fa3a795f023514ac2d801c4a81d1743bbe642e3940143326b3a00addd7"},
]
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.3.4-py3-none-any.whl", hash = "sha256:afa04efcdd818a93237574791be9b2817d7077c25a068b00f8cff7baa4e59257"},
{file = "Unidecode-1.3.4.tar.gz", hash = "sha256:8e4352fb93d5a735c788110d2e7ac8e8031eb06ccbfe8d324ab71735015f9342"},
]
uritemplate = [
{file = "uritemplate-3.0.1-py2.py3-none-any.whl", hash = "sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f"},
{file = "uritemplate-3.0.1.tar.gz", hash = "sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae"},
{file = "uritemplate-4.1.1-py2.py3-none-any.whl", hash = "sha256:830c08b8d99bdd312ea4ead05994a38e8936266f84b9a7878232db50b044e02e"},
{file = "uritemplate-4.1.1.tar.gz", hash = "sha256:4346edfc5c3b79f694bccd6d6099a322bbeb628dbf2cd86eea55a456ce5124f0"},
]
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"},
]
zipp = [
{file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"},
{file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"},
]

+ 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

+ 29
- 57
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.
@ -59,7 +62,6 @@ Logging options
-u --url-only Display generated URL after upload directly on stdout, implies --quiet
--batch Display generated URL after upload with platform information for easier parsing. Implies --quiet
Be careful --batch and --url-only are mutually exclusives.
--debug (Deprecated) Alias for --log=debug. Ignored if --log is set
Strict options:
Strict options allow you to force some option to be present when uploading a video. It's useful to be sure you do not
@ -106,12 +108,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 +123,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.2"
VALID_PRIVACY_STATUSES = ('public', 'private', 'unlisted')
VALID_CATEGORIES = (
@ -154,20 +142,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 +195,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):
@ -262,19 +227,20 @@ def configureLogs(options):
if options.get('--batch') or options.get('--url-only'):
options['--quiet'] = True
if options.get('--quiet'):
# We need to set both log level in the same time
logger.setLevel(50)
ch.setLevel(50)
elif options.get('--log'):
numeric_level = getattr(logging, options["--log"], None)
# We need to set both log level in the same time
logger.setLevel(numeric_level)
ch.setLevel(numeric_level)
elif options.get('--debug'):
logger.warning("DEPRECATION: --debug is deprecated, please use --log=debug instead")
logger.setLevel(10)
ch.setLevel(10)
for handler in logger.handlers or logger.parent.handlers:
if options.get('--quiet'):
# We need to set both log level in the same time
logger.setLevel(50)
handler.setLevel(50)
elif options.get('--log'):
numeric_level = getattr(logging, options["--log"], None)
# We need to set both log level in the same time
logger.setLevel(numeric_level)
handler.setLevel(numeric_level)
elif options.get('--debug'):
# Deprecated,
logger.setLevel(10)
handler.setLevel(10)
def configureStdoutLogs():
@ -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))

+ 17
- 17
pyproject.toml View File

@ -1,6 +1,6 @@
[tool.poetry]
name = "prismedia"
version = "0.11.0"
version = "0.12.2"
description = "scripting your way to upload videos on peertube and youtube"
authors = [
"LecygneNoir <git@lecygnenoir.info>",
@ -17,33 +17,33 @@ 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 = "=1.1.0"
requests-toolbelt = ">=0.9.1"
pytz = "=2022.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"