Does anyone know in what format thumbnails are to be imported into the Peertube API? Currently, I’m using base64 but to no avail. My function down below retrieves an image from a url (in this case, it’s the argument "content url" ) and converts it into base64. I’ve tried sending the base64 with and without the headers (i.e. "data:image/jpeg;base64," ) but the PeerTube API will process neither.
By quickly looking the code of the update API endpoint:
I can see that it calls the function buildVideoThumbnailsFromReq:
If I read correctly this piece of code, it reads req.files.thumbnailfile to get the file.
I think that in ExpressJS req.files is the list of uploaded files in a request. So, I think you just have to add a file thumbnailfile in your request payload (just send the raw file).
By the way, the update API documentation says that the request body must be a multipart/form-data, and that the thumbnailfile parameter is a binary one. This match with my reading of the above code.
Thank you so much for the quick response! I just tried both of your suggestions but PeerTube still won’t upload thumbnails (the size of the image I’m debugging with is 640x360). Here is my journey of trouble-shooting:
I used the raw response (blob) and had the function return response.content, that gave a Payload Too Large error
I then took content_decoded and deleted the ".decode(‹ utf-8 ›)" part and then returned that, but PeerTube didn’t take it and just auto-generated a thumbnail
And then I tried giving it the URL to the image, that didn’t work either
Just for fun I gave it literal binary (1’s and 0’s) and of course that didn’t work. It was too big of a payload.
I’m wondering what else I could I try. But again, thank you for your time and the good ideas!
Sorry, but I’m not at liberty to share the code, but I can share the function that sends the request.
def create_peertube_video(peertube_user,avideo_user,peertube_channel,avideo_video,peertube_videos):
avideo_video_title = avideo_video['title']
log.log(f'\t\tImporting Avideo Video "{avideo_video_title}" to PeerTube',__file__)
max_title_length = int(peertube_config['data']['max_video_title_length'])
avideo_video_title_clipped = avideo_video_title[:max_title_length] if len(avideo_video_title) > max_title_length else avideo_video_title
if not(avideo_video.get('duration_in_seconds')):
log.log(f'\t\t\tAvideo Video "{avideo_video_title}" is missing crucial data',__file__)
return
if is_peertube_video(avideo_video,peertube_channel,peertube_videos):
log.log(f'\t\t\tAvideo Video "{avideo_video_title}" already exists on PeerTube',__file__)
return
if not(is_valid_date(avideo_video,peertube_channel)):
log.log(f'\t\t\tAvideo Video "{avideo_video_title}" doesn\'t have a valid date (see "config/peertube/config.json" for allowed dates)',__file__)
return
avideo_video_source_url = get_avideo_video_source_url(avideo_video)
if not(avideo_video_source_url):
log.log(f'\t\t\tAvideo Video "{avideo_video_title}" is not a valid media format (see "config/peertube/config.json" for allowed content formats)',__file__)
return
data = {
'channelId': peertube_channel['id'],
'name': avideo_video_title_clipped,
'targetUrl': avideo_video_source_url,
'commentsEnabled': True,
'downloadEnabled': avideo_video['can_download'],
'language': 'en',
'nsfw': False,
'originallyPublishedAt': avideo_video['videoCreation'],
'privacy': 1,
'thumbnailfile': get_base64(avideo_video['Thumbnail']),
'waitTranscoding': False
}
if avideo_video['description'] and avideo_video['description'] != '\n\n':
data['description'] = avideo_video['description']
if avideo_video['donationLink']:
data['support'] = avideo_video['donationLink']
response = peertube_api.call('import_video',{
'data':data
})
if response.status_code == 200:
log.log(f'\t\t\tAvideo Video "{avideo_video_title}" is now importing to PeerTube',__file__)
thumbnail_url = avideo_video['Thumbnail']
log.log(f'\t\t\tThumbnail URL: "{thumbnail_url}"',__file__)
else:
log.log(f'\t\t\tCould not import Avideo Video "{avideo_video_title}"',__file__)
log.log(response.json(),__file__)
return
peertube_api is a class that handles the API calls. It contains a function call which recieves a call_type and a call_data. The call type is used to retrieve all of the call’s important data (Whether it’s a GET, POST, … and then the url extenstion to that particular call). The call_data just contains everything needed for the call, whether it be data or params. The headers are automatically taken care of within the class. The data variable, in the above code, is sent straight to the API without any formatting or data-corruption along the way.
Is this class sending the data using multipart/form-data?
As explained here POST - HTTP | MDN , application/x-www-form-urlencoded is not suitable to binary data.
If your class is using multipart/form-data (and is correctly encoding the multipart data), it should work by removing the get_base64 (just send the raw data).
Before you came up with that suggestion, I was passing the file into the data argument of my POST request. In order to send the data in multipart/form-data, I had to send the file in through a different argument called files. So now I’m sending the raw file to PeerTube and this is the response I get back:
{
"type": "about:blank",
"title": "Bad Request",
"detail": "Incorrect request parameters: thumbnailfile",
"instance": "/api/v1/videos/imports",
"status": 400,
"invalid-params": {
"thumbnailfile": {
"msg": "This thumbnail file is not supported or too large. Please, make sure it is of the following type: .png, .jpg, .jpeg, .webp",
"param": "thumbnailfile", "location": "body"
}
},
"error": "Incorrect request parameters: thumbnailfile"
}
I renamed the get_base64 function to the more appropriate get_thumbnail. Here’s the new code here:
So now PeerTube is actually receiving and processing the file. The file that I’m passing is a « .jpeg » but the API doesn’t recognize it as such or it’s too big, which I doubt. The image is only 640x360.
Checking the Peertube code, it can be one of these:
filesize > 4MB
incorrect mimetype: the file mimetype must be one of: 'image/png, image/jpg, image/jpeg, image/webp (you have to specify the mime type using the content-disposition header)
It finally works! After looking into how python requests manages the content-disposition, I found out how to pass the content type (image/jpeg) into the script. Thank you so much for your invaluable guidance!