Browse Source

Merge branch 'feature/thumbnail' into develop

develop
LecygneNoir 4 years ago
parent
commit
dea06c6e8f
6 changed files with 95 additions and 23 deletions
  1. +12
    -3
      README.md
  2. +14
    -12
      lib/pt_upload.py
  3. +26
    -1
      lib/utils.py
  4. +27
    -7
      lib/yt_upload.py
  5. +1
    -0
      nfo_example.txt
  6. +15
    -0
      prismedia_upload.py

+ 12
- 3
README.md View File

@ -69,6 +69,12 @@ Specify description and tags:
./prismedia_upload.py --file="yourvideo.mp4" -d "My supa description" -t "tag1,tag2,foo"
```
Provide a thumbnail:
```
./prismedia_upload.py --file="yourvideo.mp4" -d "Video with thumbnail" --thumbnail="/path/to/your/thumbnail.jpg"
```
Use a NFO file to specify your video options:
@ -111,7 +117,10 @@ Options:
--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
For Peertube, requires the "atd", "curl" and "jq" utilities installed on the system
For Peertube, requires the "atd" and "curl utilities installed on the system
--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
-h --help Show this help.
--version Show version.
@ -145,8 +154,8 @@ Languages:
- [x] enabling/disabling comment (Peertube only as Youtube API does not support it)
- [x] nsfw (Peertube only as Youtube API does not support it)
- [x] set default language
- [ ] thumbnail/preview (YT workflow: upload video, upload thumbnail, add thumbnail to video)
- [ ] multiple lines description (see [issue 4](https://git.lecygnenoir.info/LecygneNoir/prismedia/issues/4))
- [x] thumbnail/preview
- [x] multiple lines description (see [issue 4](https://git.lecygnenoir.info/LecygneNoir/prismedia/issues/4))
- [ ] add videos to playlist (YT & PT workflow: upload video, find playlist id, add video to playlist)
- [x] Use a config file (NFO) file to retrieve videos arguments
- [x] Allow to choose peertube or youtube upload (to resume failed upload for example)

+ 14
- 12
lib/pt_upload.py View File

@ -47,12 +47,11 @@ def upload_video(oauth, secret, options):
user_info = json.loads(oauth.get(url + "/api/v1/users/me").content)
return str(user_info["id"])
def get_videofile(path):
def get_file(path):
mimetypes.init()
return (basename(path), open(abspath(path), 'rb'),
mimetypes.types_map[splitext(path)[1]])
path = options.get('--file')
url = secret.get('peertube', 'peertube_url')
# We need to transform fields into tuple to deal with tags as
@ -60,12 +59,12 @@ def upload_video(oauth, secret, options):
# https://github.com/requests/toolbelt/issues/190 and
# https://github.com/requests/toolbelt/issues/205
fields = [
("name", options.get('--name') or splitext(basename(path))[0]),
("name", options.get('--name') or splitext(basename(options.get('--file')))[0]),
("licence", "1"),
("description", options.get('--description') or "default description"),
("nsfw", str(int(options.get('--nsfw')) or "0")),
("channelId", get_userinfo()),
("videofile", get_videofile(path))
("videofile", get_file(options.get('--file')))
]
if options.get('--tags'):
@ -76,7 +75,7 @@ def upload_video(oauth, secret, options):
continue
# Tag more than 30 chars crashes Peertube, so exit and check tags
if len(strtag) >= 30:
logging.warning("Sorry, Peertube does not support tag with more than 30 characters, please reduce your tag size")
logging.warning("Peertube: Sorry, Peertube does not support tag with more than 30 characters, please reduce your tag size")
exit(1)
# If Mastodon compatibility is enabled, clean tags from special characters
if options.get('--mt'):
@ -105,6 +104,9 @@ def upload_video(oauth, secret, options):
else:
fields.append(("commentsEnabled", "1"))
if options.get('--thumbnail'):
fields.append(("thumbnailfile", get_file(options.get('--thumbnail'))))
multipart_data = MultipartEncoder(fields)
headers = {
@ -120,13 +122,13 @@ def upload_video(oauth, secret, options):
jresponse = jresponse['video']
uuid = jresponse['uuid']
idvideo = str(jresponse['id'])
template = ('Peertube : Video was successfully uploaded.\n'
'Watch it at %s/videos/watch/%s.')
logging.info('Peertube : Video was successfully uploaded.')
template = 'Peertube: Watch it at %s/videos/watch/%s.'
logging.info(template % (url, uuid))
if options.get('--publishAt'):
utils.publishAt(str(options.get('--publishAt')), oauth, url, idvideo, secret)
else:
logging.error(('Peertube : The upload failed with an unexpected response: '
logging.error(('Peertube: The upload failed with an unexpected response: '
'%s') % response)
exit(1)
@ -136,16 +138,16 @@ def run(options):
try:
secret.read(PEERTUBE_SECRETS_FILE)
except Exception as e:
logging.error("Error loading " + str(PEERTUBE_SECRETS_FILE) + ": " + str(e))
logging.error("Peertube: Error loading " + str(PEERTUBE_SECRETS_FILE) + ": " + str(e))
exit(1)
insecure_transport = secret.get('peertube', 'OAUTHLIB_INSECURE_TRANSPORT')
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = insecure_transport
oauth = get_authenticated_service(secret)
try:
logging.info('Peertube : Uploading file...')
logging.info('Peertube: Uploading video...')
upload_video(oauth, secret, options)
except Exception as e:
if hasattr(e, 'message'):
logging.error("Error: " + str(e.message))
logging.error("Peertube: Error: " + str(e.message))
else:
logging.error("Error: " + str(e))
logging.error("Peertube: Error: " + str(e))

+ 26
- 1
lib/utils.py View File

@ -98,6 +98,32 @@ def getLanguage(language, platform):
return PEERTUBE_LANGUAGE[language.lower()]
def remove_empty_kwargs(**kwargs):
good_kwargs = {}
if kwargs is not None:
for key, value in kwargs.iteritems():
if value:
good_kwargs[key] = value
return good_kwargs
def searchThumbnail(options):
video_directory = dirname(options.get('--file')) + "/"
# First, check for thumbnail based on videoname
if options.get('--name'):
if isfile(video_directory + options.get('--name') + ".jpg"):
options['--thumbnail'] = video_directory + options.get('--name') + ".jpg"
elif isfile(video_directory + options.get('--name') + ".jpeg"):
options['--thumbnail'] = video_directory + options.get('--name') + ".jpeg"
# 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]
if isfile(video_directory + video_file + ".jpg"):
options['--thumbnail'] = video_directory + video_file + ".jpg"
elif isfile(video_directory + video_file + ".jpeg"):
options['--thumbnail'] = video_directory + video_file + ".jpeg"
return options
# return the nfo as a RawConfigParser object
def loadNFO(options):
video_directory = dirname(options.get('--file')) + "/"
@ -117,7 +143,6 @@ def loadNFO(options):
else:
if options.get('--name'):
nfo_file = video_directory + options.get('--name') + ".txt"
print nfo_file
if isfile(nfo_file):
try:
logging.info("Using " + nfo_file + " as NFO, loading...")

+ 27
- 7
lib/yt_upload.py View File

@ -20,6 +20,7 @@ from googleapiclient.errors import HttpError
from googleapiclient.http import MediaFileUpload
from google_auth_oauthlib.flow import InstalledAppFlow
import utils
logging.basicConfig(format='%(asctime)s %(message)s', level=logging.INFO)
@ -126,25 +127,44 @@ def initialize_upload(youtube, options):
body=body,
media_body=MediaFileUpload(path, chunksize=-1, resumable=True)
)
resumable_upload(insert_request)
video_id = resumable_upload(insert_request, 'video', 'insert')
# If we get a video_id, upload is successful and we are able to set thumbnail
if video_id and options.get('--thumbnail'):
set_thumbnail(youtube, options.get('--thumbnail'), videoId=video_id)
def set_thumbnail(youtube, media_file, **kwargs):
kwargs = utils.remove_empty_kwargs(**kwargs) # See full sample for function
request = youtube.thumbnails().set(
media_body=MediaFileUpload(media_file, chunksize=-1,
resumable=True),
**kwargs
)
# See full sample for function
return resumable_upload(request, 'thumbnail', 'set')
# This method implements an exponential backoff strategy to resume a
# failed upload.
def resumable_upload(request):
def resumable_upload(request, resource, method):
response = None
error = None
retry = 0
while response is None:
try:
logging.info('Youtube : Uploading file...')
template = 'Youtube: Uploading %s...'
logging.info(template % resource)
status, response = request.next_chunk()
if response is not None:
if 'id' in response:
template = ('Youtube : Video was successfully '
'uploaded.\n'
'Watch it at https://youtu.be/%s (post-encoding could take some time)')
if method == 'insert' and 'id' in response:
logging.info('Youtube : Video was successfully uploaded.')
template = 'Youtube: Watch it at https://youtu.be/%s (post-encoding could take some time)'
logging.info(template % response['id'])
return response['id']
elif method != 'insert' or "id" not in response:
logging.info('Youtube: Thumbnail was successfully set.')
else:
template = ('Youtube : The upload failed with an '
'unexpected response: %s')

+ 1
- 0
nfo_example.txt View File

@ -17,6 +17,7 @@ category = Films
cca = True
privacy = private
disable-comments = True
thumbnail = /path/to/your/thumbnail.jpg # Set the absolute path to your thumbnail
nsfw = True
platform = youtube, peertube
language = French

+ 15
- 0
prismedia_upload.py View File

@ -34,6 +34,9 @@ Options:
DATE should be on the form YYYY-MM-DDThh:mm:ss eg: 2018-03-12T19:00:00
DATE should be in the future
For Peertube, requires the "atd" and "curl utilities installed on the system
--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
-h --help Show this help.
--version Show version.
@ -151,6 +154,12 @@ def validatePublish(publish):
return False
return True
def validateThumbnail(thumbnail):
supported_types = ['image/jpg', 'image/jpeg']
if magic.from_file(thumbnail, mime=True) in supported_types:
return thumbnail
else:
return False
if __name__ == '__main__':
@ -199,12 +208,18 @@ if __name__ == '__main__':
Optional('--cca'): bool,
Optional('--disable-comments'): bool,
Optional('--nsfw'): bool,
Optional('--thumbnail'): Or(None, And(
str, validateThumbnail, error='thumbnail is not supported, please use jpg/jpeg'),
),
'--help': bool,
'--version': bool
})
options = utils.parseNFO(options)
if not options.get('--thumbnail'):
options = utils.searchThumbnail(options)
try:
options = schema.validate(options)
except SchemaError as e:

Loading…
Cancel
Save