mirror of
https://git.lecygnenoir.info/LecygneNoir/prismedia.git
synced 2025-10-03 09:29:16 +02:00
Merge pull request 'hearthbeat (keepalive ?)' (#54) from Zykino/prismedia:hearthbeat into develop
Reviewed-on: https://git.lecygnenoir.info/LecygneNoir/prismedia/pulls/54 Thanks a lot for the idea and the feature!
This commit is contained in:
commit
ca733e0dc3
4 changed files with 87 additions and 48 deletions
51
README.md
51
README.md
|
@ -24,22 +24,19 @@ Scripting your way to upload videos to peertube and youtube. Works with Python 3
|
||||||
### From pip
|
### From pip
|
||||||
|
|
||||||
Simply install with
|
Simply install with
|
||||||
|
```sh
|
||||||
```bash
|
|
||||||
pip install prismedia
|
pip install prismedia
|
||||||
```
|
```
|
||||||
|
|
||||||
Upgrade with
|
Upgrade with
|
||||||
|
```sh
|
||||||
```bash
|
|
||||||
pip install --upgrade prismedia
|
pip install --upgrade prismedia
|
||||||
```
|
```
|
||||||
|
|
||||||
### From source
|
### From source
|
||||||
|
|
||||||
Get the source:
|
Get the source:
|
||||||
|
```sh
|
||||||
```bash
|
|
||||||
git clone https://git.lecygnenoir.info/LecygneNoir/prismedia.git prismedia
|
git clone https://git.lecygnenoir.info/LecygneNoir/prismedia.git prismedia
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -49,11 +46,10 @@ You may use pip to install requirements: `pip install -r requirements.txt` if yo
|
||||||
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)
|
(Or use the existing virtualenv if one is activated)
|
||||||
|
|
||||||
```
|
```sh
|
||||||
poetry install
|
poetry install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
Generate sample files with `python -m prismedia.genconfig`.
|
Generate sample files with `python -m prismedia.genconfig`.
|
||||||
|
@ -72,7 +68,7 @@ Youtube uses combination of oauth and API access to identify.
|
||||||
The first time you connect, prismedia will open your browser to ask you to authenticate to
|
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.
|
Youtube and allow the app to use your Youtube channel.
|
||||||
**It is here you choose which channel you will upload to**.
|
**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.
|
Prismedia will try to use this file at each launch, and re-ask for authentication if it does not exist.
|
||||||
|
|
||||||
**Oauth**:
|
**Oauth**:
|
||||||
|
@ -95,35 +91,42 @@ Support only mp4 for cross compatibility between Youtube and Peertube.
|
||||||
Here are some demonstration of main usage you would like!
|
Here are some demonstration of main usage you would like!
|
||||||
|
|
||||||
Upload a video:
|
Upload a video:
|
||||||
```
|
```sh
|
||||||
prismedia --file="yourvideo.mp4"
|
python -m prismedia --file="yourvideo.mp4"
|
||||||
```
|
```
|
||||||
|
|
||||||
Specify description and tags:
|
Specify description and tags:
|
||||||
```
|
```sh
|
||||||
prismedia --file="yourvideo.mp4" -d "My supa description" -t "tag1,tag2,foo"
|
python -m prismedia --file="yourvideo.mp4" -d "My supa description" -t "tag1,tag2,foo"
|
||||||
```
|
```
|
||||||
|
|
||||||
Provide a thumbnail:
|
Provide a thumbnail:
|
||||||
```
|
```sh
|
||||||
prismedia --file="yourvideo.mp4" -d "Video with thumbnail" --thumbnail="/path/to/your/thumbnail.jpg"
|
python -m 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 does not exist.:
|
||||||
```
|
```sh
|
||||||
prismedia --file="yourvideo.mp4" --platform=peertube --channel="Cooking recipes" --playlist="Cake recipes" --channelCreate --playlistCreate
|
python -m 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)
|
(See [Enhanced NFO](#enhanced-use-of-nfo) for more precise example)
|
||||||
```
|
```sh
|
||||||
prismedia --file="yourvideo.mp4" --nfo /path/to/your/nfo.txt
|
python -m 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).
|
||||||
|
|
||||||
|
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
|
||||||
|
python -m prismedia --hearthbeat
|
||||||
|
```
|
||||||
|
|
||||||
Take a look at all available options with `--help`!
|
Take a look at all available options with `--help`!
|
||||||
```
|
```sh
|
||||||
prismedia --help
|
python -m prismedia --help
|
||||||
```
|
```
|
||||||
|
|
||||||
## Enhanced use of NFO
|
## Enhanced use of NFO
|
||||||
|
@ -136,7 +139,7 @@ Basically, Prismedia will now load options in this order, using the last value f
|
||||||
`nfo.txt < directory_name.txt < video_name.txt < command line NFO < command line argument`
|
`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:
|
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/
|
$ tree Recipes/
|
||||||
Recipes/
|
Recipes/
|
||||||
├── cli_nfo.txt
|
├── cli_nfo.txt
|
||||||
|
@ -150,8 +153,8 @@ Recipes/
|
||||||
```
|
```
|
||||||
|
|
||||||
By using
|
By using
|
||||||
```
|
```sh
|
||||||
prismedia --file=/path/to/Recipes/yourvideo1.mp4 --nfo=/path/to/Recipes/cli_nfo.txt --cca
|
python -m prismedia --file=/path/to/Recipes/yourvideo1.mp4 --nfo=/path/to/Recipes/cli_nfo.txt --cca
|
||||||
```
|
```
|
||||||
|
|
||||||
Prismedia will:
|
Prismedia will:
|
||||||
|
|
|
@ -373,7 +373,7 @@ def create_callback(encoder, progress_type):
|
||||||
else:
|
else:
|
||||||
# Print a blank line to not (partly) override the progress bar
|
# Print a blank line to not (partly) override the progress bar
|
||||||
print()
|
print()
|
||||||
logger.info("Peertube : Upload finish, Processing…")
|
logger.info("Peertube: Upload finish, Processing…")
|
||||||
|
|
||||||
return callback
|
return callback
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ prismedia - tool to upload videos to Peertube and Youtube
|
||||||
Usage:
|
Usage:
|
||||||
prismedia --file=<FILE> [options]
|
prismedia --file=<FILE> [options]
|
||||||
prismedia -f <FILE> --tags=STRING [options]
|
prismedia -f <FILE> --tags=STRING [options]
|
||||||
|
prismedia --hearthbeat
|
||||||
prismedia -h | --help
|
prismedia -h | --help
|
||||||
prismedia --version
|
prismedia --version
|
||||||
|
|
||||||
|
@ -50,6 +51,9 @@ Options:
|
||||||
--playlistCreate Create the playlist if not exists. (default do not create)
|
--playlistCreate Create the playlist if not exists. (default do not create)
|
||||||
Only relevant if --playlist is set.
|
Only relevant if --playlist is set.
|
||||||
--progress=STRING Set the progress bar view, one of percentage, bigFile (MB), accurate (KB).
|
--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.
|
-h --help Show this help.
|
||||||
--version Show version.
|
--version Show version.
|
||||||
|
|
||||||
|
@ -396,11 +400,17 @@ def main():
|
||||||
Optional('--playlist'): Or(None, str),
|
Optional('--playlist'): Or(None, str),
|
||||||
Optional('--playlistCreate'): bool,
|
Optional('--playlistCreate'): bool,
|
||||||
Optional('--progress'): Or(None, And(str, validateProgress, error="Sorry, progress visualisation not supported")),
|
Optional('--progress'): Or(None, And(str, validateProgress, error="Sorry, progress visualisation not supported")),
|
||||||
|
'--hearthbeat': bool,
|
||||||
'--help': bool,
|
'--help': bool,
|
||||||
'--version': bool,
|
'--version': bool,
|
||||||
# This allow to return all other options for further use: https://github.com/keleshev/schema#extra-keys
|
# This allow to return all other options for further use: https://github.com/keleshev/schema#extra-keys
|
||||||
object: object
|
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
|
# We need to validate early options first as withNFO and logs options should be prioritized
|
||||||
try:
|
try:
|
||||||
options = earlyoptionSchema.validate(options)
|
options = earlyoptionSchema.validate(options)
|
||||||
|
|
|
@ -60,6 +60,7 @@ def get_authenticated_service():
|
||||||
check_authenticated_scopes()
|
check_authenticated_scopes()
|
||||||
flow = InstalledAppFlow.from_client_secrets_file(
|
flow = InstalledAppFlow.from_client_secrets_file(
|
||||||
CLIENT_SECRETS_FILE, SCOPES)
|
CLIENT_SECRETS_FILE, SCOPES)
|
||||||
|
|
||||||
if exists(CREDENTIALS_PATH):
|
if exists(CREDENTIALS_PATH):
|
||||||
with open(CREDENTIALS_PATH, 'r') as f:
|
with open(CREDENTIALS_PATH, 'r') as f:
|
||||||
credential_params = json.load(f)
|
credential_params = json.load(f)
|
||||||
|
@ -181,14 +182,24 @@ def initialize_upload(youtube, options):
|
||||||
|
|
||||||
|
|
||||||
def get_playlist_by_name(youtube, playlist_name):
|
def get_playlist_by_name(youtube, playlist_name):
|
||||||
|
pageToken = ""
|
||||||
|
while pageToken != None:
|
||||||
response = youtube.playlists().list(
|
response = youtube.playlists().list(
|
||||||
part='snippet,id',
|
part='snippet,id',
|
||||||
mine=True,
|
mine=True,
|
||||||
maxResults=50
|
maxResults=50,
|
||||||
|
pageToken=pageToken
|
||||||
).execute()
|
).execute()
|
||||||
|
|
||||||
for playlist in response["items"]:
|
for playlist in response["items"]:
|
||||||
if playlist["snippet"]['title'] == playlist_name:
|
if playlist["snippet"]["title"] == playlist_name:
|
||||||
return playlist['id']
|
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):
|
def create_playlist(youtube, playlist_name):
|
||||||
|
@ -331,6 +342,21 @@ def resumable_upload(request, resource, method, options):
|
||||||
time.sleep(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):
|
def run(options):
|
||||||
youtube = get_authenticated_service()
|
youtube = get_authenticated_service()
|
||||||
try:
|
try:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue