Browse Source

Merge branch 'feature/recording_date' into develop

pull/52/head
LecygneNoir 3 years ago
parent
commit
1a937098d8
6 changed files with 94 additions and 107 deletions
  1. +5
    -0
      CHANGELOG.md
  2. +8
    -86
      README.md
  3. +13
    -4
      prismedia/pt_upload.py
  4. +40
    -8
      prismedia/upload.py
  5. +7
    -3
      prismedia/utils.py
  6. +21
    -6
      prismedia/yt_upload.py

+ 5
- 0
CHANGELOG.md View File

@ -1,5 +1,10 @@
# Changelog
## v0.11.0
## Features
- Add the configuration of Original date of Record for Youtube and Peertube (see #50)
## v0.10.3
### Fix

+ 8
- 86
README.md View File

@ -92,24 +92,27 @@ 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))
Upload a video:
Here are some demonstration of main usage you would like!
Upload a video:
```
prismedia --file="yourvideo.mp4"
```
Specify description and tags:
```
prismedia --file="yourvideo.mp4" -d "My supa description" -t "tag1,tag2,foo"
```
Provide a thumbnail:
```
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.:
```
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)
@ -118,90 +121,9 @@ prismedia --file="yourvideo.mp4" --nfo /path/to/your/nfo.txt
```
Use --help to get all available options:
Take a look at all available options with `--help`!
```
Options:
-f, --file=STRING Path to the video file to upload in mp4. 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.
WARN: tags with punctuation (!, ', ", ?, ...)
are not supported by Mastodon to be published from Peertube
-c, --category=STRING Category for the videos, see below. (default: Films)
--cca License should be CreativeCommon Attribution (affects Youtube upload only)
-p, --privacy=STRING Choose between public, unlisted or private. (default: private)
--disable-comments Disable comments (Peertube only as YT API does not support) (default: comments are enabled)
--nsfw Set the video as No Safe For Work (Peertube only as YT API does not support) (default: video is safe)
--nfo=STRING Configure a specific nfo file to set options for the video.
By default Prismedia search a .txt based on the video name and will
decode the file as UTF-8 (so make sure your nfo file is UTF-8 encoded)
See nfo_example.txt for more details
--platform=STRING List of platform(s) to upload to, comma separated.
Supported platforms are youtube and peertube (default is both)
--language=STRING Specify the default language for video. See below for supported language. (default is English)
--publishAt=DATE Publish the video at the given DATE using local server timezone.
DATE should be on the form YYYY-MM-DDThh:mm:ss eg: 2018-03-12T19:00:00
DATE should be in the future
--peertubeAt=DATE
--youtubeAt=DATE Override publishAt for the corresponding platform. Allow to create preview on specific platform
--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
--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)
Only relevant if --channel is set.
--playlist=STRING Set the playlist to use for the video.
If the playlist is not found, spawn an error except if --playlistCreate is set.
--playlistCreate Create the playlist if not exists. (default do not create)
Only relevant if --playlist is set.
-h --help Show this help.
--version Show version.
Logging options
-q --quiet Suppress any log except Critical (alias for --log=critical).
--log=STRING Log level, between debug, info, warning, error, critical. Ignored if --quiet is set (default to info)
-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
forget something when uploading a video, for example if you use multiples NFO. You may force the presence of description,
tags, thumbnail, ...
All strict option are optionals and are provided only to avoid errors when uploading :-)
All strict options can be specified in NFO directly, the only strict option mandatory on cli is --withNFO
All strict options are off by default
--withNFO Prevent the upload without a NFO, either specified via cli or found in the directory
--withThumbnail Prevent the upload without a thumbnail
--withName Prevent the upload if no name are found
--withDescription Prevent the upload without description
--withTags Prevent the upload without tags
--withPlaylist Prevent the upload if no playlist
--withPublishAt Prevent the upload if no schedule
--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
Categories:
Category is the type of video you upload. Default is films.
Here are available categories from Peertube and Youtube:
music, films, vehicles,
sports, travels, gaming, people,
comedy, entertainment, news,
how to, education, activism, science & technology,
science, technology, animals
Languages:
Language of the video (audio track), choose one. Default is English
Here are available languages from Peertube and Youtube:
Arabic, English, French, German, Hindi, Italian,
Japanese, Korean, Mandarin, Portuguese, Punjabi, Russian, Spanish
prismedia --help
```
## Enhanced use of NFO

+ 13
- 4
prismedia/pt_upload.py View File

@ -63,6 +63,13 @@ def get_channel_by_name(user_info, options):
return channel['id']
def convert_peertube_date(date):
date = datetime.datetime.strptime(date, '%Y-%m-%dT%H:%M:%S')
tz = get_localzone()
tz = pytz.timezone(str(tz))
return tz.localize(date).isoformat()
def create_channel(oauth, url, options):
template = ('Peertube: Channel %s does not exist, creating it.')
logger.info(template % (str(options.get('--channel'))))
@ -255,16 +262,18 @@ def upload_video(oauth, secret, options):
publishAt = options.get('--publishAt')
if 'publishAt' in locals():
publishAt = datetime.datetime.strptime(publishAt, '%Y-%m-%dT%H:%M:%S')
tz = get_localzone()
tz = pytz.timezone(str(tz))
publishAt = tz.localize(publishAt).isoformat()
publishAt = convert_peertube_date(publishAt)
fields.append(("scheduleUpdate[updateAt]", publishAt))
fields.append(("scheduleUpdate[privacy]", str(PEERTUBE_PRIVACY["public"])))
fields.append(("privacy", str(PEERTUBE_PRIVACY["private"])))
else:
fields.append(("privacy", str(PEERTUBE_PRIVACY[privacy or "private"])))
# Set originalDate except if the user force no originalDate
if options.get('--originalDate'):
originalDate = convert_peertube_date(options.get('--originalDate'))
fields.append(("originallyPublishedAt", originalDate))
if options.get('--thumbnail'):
fields.append(("thumbnailfile", get_file(options.get('--thumbnail'))))
fields.append(("previewfile", get_file(options.get('--thumbnail'))))

+ 40
- 8
prismedia/upload.py View File

@ -34,6 +34,10 @@ Options:
DATE should be in the future
--peertubeAt=DATE
--youtubeAt=DATE Override publishAt for the corresponding platform. Allow to create preview on specific platform
--originalDate=DATE Configure the video as initially recorded at DATE
DATE should be on the form YYYY-MM-DDThh:mm:ss eg: 2018-03-12T19:00:00
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
@ -71,6 +75,7 @@ Strict options:
--withTags Prevent the upload without tags
--withPlaylist Prevent the upload if no playlist
--withPublishAt Prevent the upload if no schedule
--withOriginalDate Prevent the upload if no original date configured
--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
@ -190,11 +195,11 @@ def validateLanguage(language):
return False
def validatePublish(publish):
def validatePublishDate(publishDate):
# Check date format and if date is future
try:
now = datetime.datetime.now()
publishAt = datetime.datetime.strptime(publish, '%Y-%m-%dT%H:%M:%S')
publishAt = datetime.datetime.strptime(publishDate, '%Y-%m-%dT%H:%M:%S')
if now >= publishAt:
return False
except ValueError:
@ -202,6 +207,18 @@ def validatePublish(publish):
return True
def validateOriginalDate(originalDate):
# Check date format and if date is past
try:
now = datetime.datetime.now()
originalDate = datetime.datetime.strptime(originalDate, '%Y-%m-%dT%H:%M:%S')
if now <= originalDate:
return False
except ValueError:
return False
return True
def validateThumbnail(thumbnail):
supported_types = ['image/jpg', 'image/jpeg']
if os.path.exists(thumbnail) and \
@ -217,6 +234,7 @@ def validateLogLevel(loglevel):
return False
return True
def _optionnalOrStrict(key, scope, error):
option = key.replace('-', '')
option = option[0].upper() + option[1:]
@ -280,6 +298,7 @@ def main():
Optional('--withTags', default=False): bool,
Optional('--withPlaylist', default=False): bool,
Optional('--withPublishAt', default=False): bool,
Optional('--withOriginalDate', default=False): bool,
Optional('--withPlatform', default=False): bool,
Optional('--withCategory', default=False): bool,
Optional('--withLanguage', default=False): bool,
@ -298,6 +317,7 @@ def main():
Hook('--language', handler=_optionnalOrStrict): object,
Hook('--platform', handler=_optionnalOrStrict): object,
Hook('--publishAt', handler=_optionnalOrStrict): object,
Hook('--originalDate', handler=_optionnalOrStrict): object,
Hook('--thumbnail', handler=_optionnalOrStrict): object,
Hook('--channel', handler=_optionnalOrStrict): object,
Hook('--playlist', handler=_optionnalOrStrict): object,
@ -336,19 +356,25 @@ def main():
Optional('--platform'): Or(None, And(str, validatePlatform, error="Sorry, upload platform not supported")),
Optional('--publishAt'): Or(None, And(
str,
validatePublish,
error="DATE should be the form YYYY-MM-DDThh:mm:ss and has to be in the future")
validatePublishDate,
error="Publish Date should be the form YYYY-MM-DDThh:mm:ss and has to be in the future")
),
Optional('--peertubeAt'): Or(None, And(
str,
validatePublish,
error="DATE should be the form YYYY-MM-DDThh:mm:ss and has to be in the future")
validatePublishDate,
error="Publish Date should be the form YYYY-MM-DDThh:mm:ss and has to be in the future")
),
Optional('--youtubeAt'): Or(None, And(
str,
validatePublish,
error="DATE should be the form YYYY-MM-DDThh:mm:ss and has to be in the future")
validatePublishDate,
error="Publish Date should be the form YYYY-MM-DDThh:mm:ss and has to be in the future")
),
Optional('--originalDate'): Or(None, And(
str,
validateOriginalDate,
error="Original date should be the form YYYY-MM-DDThh:mm:ss and has to be in the past")
),
Optional('--auto-originalDate'): bool,
Optional('--cca'): bool,
Optional('--disable-comments'): bool,
Optional('--nsfw'): bool,
@ -377,6 +403,12 @@ def main():
options = utils.parseNFO(options)
# If after loading NFO we still has no original date and --auto-originalDate is enabled,
# then we need to search from the file
# We need to do that before the strict validation in case --withOriginalDate is enabled
if not options.get('--originalDate') and options.get('--auto-originalDate'):
options['--originalDate'] = utils.searchOriginalDate(options)
# Once NFO are loaded, we need to revalidate strict options in case some were in NFO
try:
options = earlyoptionSchema.validate(options)

+ 7
- 3
prismedia/utils.py View File

@ -2,12 +2,11 @@
# coding: utf-8
from configparser import RawConfigParser, NoOptionError, NoSectionError
from os.path import dirname, splitext, basename, isfile
from os.path import dirname, splitext, basename, isfile, getmtime
import re
from os import devnull
from subprocess import check_call, CalledProcessError, STDOUT
import unidecode
import logging
import datetime
logger = logging.getLogger('Prismedia')
@ -135,6 +134,11 @@ def searchThumbnail(options):
return options
def searchOriginalDate(options):
fileModificationDate = getmtime(options.get('--file'))
return datetime.datetime.fromtimestamp(fileModificationDate).isoformat()
# return the nfo as a RawConfigParser object
def loadNFO(filename):
try:

+ 21
- 6
prismedia/yt_upload.py View File

@ -89,6 +89,15 @@ def check_authenticated_scopes():
os.remove(CREDENTIALS_PATH)
def convert_youtube_date(date):
# Youtube needs microsecond and the local timezone from ISO 8601
date = date + ".000001"
date = datetime.datetime.strptime(date, '%Y-%m-%dT%H:%M:%S.%f')
tz = get_localzone()
tz = pytz.timezone(str(tz))
return tz.localize(date).isoformat()
def initialize_upload(youtube, options):
path = options.get('--file')
tags = None
@ -107,6 +116,8 @@ def initialize_upload(youtube, options):
if options.get('--cca'):
license = "creativeCommon"
# We set recordingDetails empty because it's easier to add options if it already exists
# and if empty, it does not cause problem during upload
body = {
"snippet": {
"title": options.get('--name') or splitext(basename(path))[0],
@ -119,6 +130,9 @@ def initialize_upload(youtube, options):
"status": {
"privacyStatus": str(options.get('--privacy') or "private"),
"license": str(license or "youtube"),
},
"recordingDetails": {
}
}
@ -128,15 +142,16 @@ def initialize_upload(youtube, options):
elif options.get('--publishAt'):
publishAt = options.get('--publishAt')
# Check if publishAt variable exists in local variables
if 'publishAt' in locals():
# Youtube needs microsecond and the local timezone from ISO 8601
publishAt = publishAt + ".000001"
publishAt = datetime.datetime.strptime(publishAt, '%Y-%m-%dT%H:%M:%S.%f')
tz = get_localzone()
tz = pytz.timezone(str(tz))
publishAt = tz.localize(publishAt).isoformat()
publishAt = convert_youtube_date(publishAt)
body['status']['publishAt'] = str(publishAt)
# Set originalDate except if the user force no originalDate
if options.get('--originalDate'):
originalDate = convert_youtube_date(options.get('--originalDate'))
body['recordingDetails']['recordingDate'] = str(originalDate)
if options.get('--playlist'):
playlist_id = get_playlist_by_name(youtube, options.get('--playlist'))
if not playlist_id and options.get('--playlistCreate'):

Loading…
Cancel
Save