Reputation: 31
I cannot programatically upload a video to dailymotion via the api. I can upload manually on the frontend just fine. As part of a larger project i want to automate uploading certain files to dailymotion via api but i just cant seem to get it to publish the video. Everything i have tried says it has uploaded but i can never see the video in the frontend or the site so I am unable to view them or embed them elsewhere. I'm currently trying to upload a single test video from a local environment in the same folder as the project for testing purposes.
Here's where I've ended up:
app.post('/api/dailymotion/upload', async (req, res) =\> {
const localVideoDirectory = path.join(\__dirname, 'videos');
try {
const videos = fs.readdirSync(localVideoDirectory)
.filter(file => file.endsWith('.mp4') || file.endsWith('.mkv') || file.endsWith('.avi'))
.map(file => ({
name: file,
path: path.join(localVideoDirectory, file)
}));
if (!videos || videos.length === 0) {
return res.status(400).send('No video files found in the local directory.');
}
console.log('[π] Found Local Videos:', videos);
const token = await getAccessToken();
const uploadResults = await Promise.all(videos.map(async (video) => {
try {
console.log(`[π] Preparing to upload video: ${video.name}`);
const videoData = fs.readFileSync(video.path);
const form = new FormData();
form.append('file', videoData, video.name);
form.append('title', video.name);
form.append('channel', 'music');
form.append('published', 'true');
form.append('is_created_for_kids', 'false');
// Make the request to upload and publish in one step
const uploadResponse = await axios.post(
`${DAILY_API_BASE}/me/videos`,
form,
{
headers: {
Authorization: `Bearer ${token}`,
...form.getHeaders(),
},
maxContentLength: Infinity,
maxBodyLength: Infinity,
}
);
console.log('[β
] Video Uploaded and Published:', uploadResponse.data);
return uploadResponse.data;
} catch (error) {
console.error(`[β] Error uploading video (${video.name}):`, error.message);
return { error: error.message, video: video.name };
}
}));
res.json(uploadResults);
} catch (error) {
console.error('[β] Error in upload endpoint:', error.message);
res.status(500).send('Error uploading videos.');
}
});
I expected this to work as i have tried to follow the docs and used the api explorer.
Using api explorer returns a simple json object upon success. I get the same back like this:
[β
] Video Uploaded and Published: {
id: 'x9cqoek',
title: 'anpr.mp4',
channel: 'music',
owner: 'x369ws4'
}
When I query the video like this:
curl -X GET -H "Authorization: Bearer <AUTH_TOKEN>" https://api.dailymotion.com/video/x9cqoek?fields=id,title,channel,status,published
It returns this:
{"id":"x9cqoek","title":"anpr.mp4","channel":"music","status":"processing","published":false}
And when I check the encoding progress with this:
curl -X GET -H "Authorization: Bearer \<AUTH_TOKEN\>" https://api.dailymotion.com/video/x9cqoek?fields=encoding_progress
It returns this:
{"encoding_progress":0}
Finally, I tried to manually set it to published using the API:
curl -X POST -H "Authorization: Bearer \<AUTH_TOKEN\>" -F 'published=true' https://api.dailymotion.com/video/x9cqoek
Which just returns this:
{"id":"x9cqoek","title":"anpr.mp4","channel":"music","owner":"x369ws4"}
Re-checking with the above command to determine status returns the same object as before.
I've tried everything I can think of at this point and may just try something else but I'd like to stick with dailymotion if possible. Uploading videos manually works fine and I can use the same auth token to query my uploaded videos and return the ones I upload manually via the site. My videos uploaded by the API never seem to propagate.
Edit - reply to PySir
I don't know how to format the comments correctly yet so apologies for that mess.
Here's The exact quote from the Dailymotion docs:
Upload & Publish at the same time:
You can perform steps 4 and 5 in a single HTTP request by passing all the extra information in the initial POST request as follows:
curl -X POST \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-d 'url=<VIDEO_URL>' \
-d 'title=Dailymotion upload test' \
-d 'channel=videogames' \
-d 'published=true' \
-d 'is_created_for_kids=false' \
"https://api.dailymotion.com/user/<CHANNEL_ID>/videos"
Before, I had done this, which does it in 2 steps and does return the url object that I was then using to make a post request to, to publish and that was less successful than what I have now as I can see the videos on the site, they're just not encoding it as far as I can tell.
app.post('/api/dailymotion/upload', async (req, res) => {
const localVideoDirectory = path.join(__dirname, 'videos'); // Local directory for videos
try {
// Fetch video files from the local directory
const videos = fs.readdirSync(localVideoDirectory)
.filter(file => file.endsWith('.mp4') || file.endsWith('.mkv') || file.endsWith('.avi')) // Filter video files
.map(file => ({
name: file,
path: path.join(localVideoDirectory, file)
}));
if (!videos || videos.length === 0) {
return res.status(400).send('No video files found in the local directory.');
}
console.log('[π] Found Local Videos:', videos);
const token = await getAccessToken();
const channelId = await getChannelId();
const uploadResults = await Promise.all(videos.map(async (video) => {
try {
console.log(`[π] Reading video file: ${video.path}`);
// Read video file as a Buffer
const videoData = fs.readFileSync(video.path);
// Step 1: Get the upload URL from Dailymotion
const uploadUrlResponse = await axios.get(`${DAILY_API_BASE}/file/upload`, {
params: { access_token: token },
});
const uploadUrl = uploadUrlResponse.data.upload_url;
console.log('[π] Upload URL:', uploadUrl);
// Step 2: Upload the video to the Dailymotion upload URL
const FormData = require('form-data');
const form = new FormData();
form.append('file', videoData, video.name);
const uploadResponse = await axios.post(uploadUrl, form, {
headers: { ...form.getHeaders() },
maxContentLength: Infinity,
maxBodyLength: Infinity,
});
console.log('[β
] Upload Response:', uploadResponse.data);
if (!uploadResponse.data || !uploadResponse.data.url) {
throw new Error('Invalid upload response from Dailymotion');
}
// Step 3: Publish the video on Dailymotion
console.log('[β
] Publishing video...');
const publishResponse = await axios.post(
`${DAILY_API_BASE}/me/videos`,
{
url: uploadResponse.data.url,
title: video.name,
channel: 'music',
privacy: 'public',
published: true,
is_created_for_kids: false,
},
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
}
);
console.log('[π€] Published Video:', publishResponse.data);
return publishResponse.data;
} catch (error) {
console.error(`[β] Error uploading video (${video.name}):`, error.message);
return { error: error.message, video: video.name };
}
}));
res.json(uploadResults);
} catch (error) {
console.error('[β] Error uploading videos:', error.message);
res.status(500).send('Error uploading videos.');
}
});
I have tried!! I had less luck with this though, and prefer the idea of doing both in one as it's cleaner/more efficient and minimises code.
Upvotes: 2
Views: 105
Reputation: 31
Thanks to @PySir I got it working!
You were right. You cannot "Upload & Publish" in one step, the video needs to be first uploaded and then you can 'create a video object' on your channel, then publish it. After uploading a video you can then create the object and publish in one step and thats where I was getting confused as the docs say to 'upload & publish'
Anyways, Here's what I used:
app.post('/api/dailymotion/upload', async (req, res) => {
const localVideoDirectory = path.join(__dirname, 'videos');
try {
const videos = fs.readdirSync(localVideoDirectory)
.filter(file => file.endsWith('.mp4') || file.endsWith('.mkv') || file.endsWith('.avi'))
.map(file => ({
name: file,
path: path.join(localVideoDirectory, file),
normalizedName: file.replace(/\.[^/.]+$/, '').toLowerCase(),
}));
if (!videos.length) {
return res.status(400).send('No video files found in the local directory.');
}
console.log('[π] Found Local Videos:', videos);
const token = await getAccessToken();
const existingVideosResponse = await axios.get(`${DAILY_API_BASE}/me/videos`, {
params: { fields: 'title', access_token: token },
});
const existingVideoTitles = existingVideosResponse.data.list.map(video =>
video.title.toLowerCase().trim()
);
console.log('[π] Existing Dailymotion Videos:', existingVideoTitles);
const videosToUpload = videos.filter(video =>
!existingVideoTitles.includes(video.normalizedName)
);
console.log('[π] Videos to Upload:', videosToUpload);
if (!videosToUpload.length) {
return res.status(200).send('All videos are already uploaded.\n');
}
const uploadResults = await Promise.all(videosToUpload.map(async (video) => {
try {
console.log(`[π] Preparing to upload video: ${video.name}`);
const uploadUrlResponse = await axios.get(`${DAILY_API_BASE}/file/upload`, {
params: { access_token: token },
});
const uploadUrl = uploadUrlResponse.data.upload_url;
console.log('[π] Upload URL:', uploadUrl);
const videoData = fs.readFileSync(video.path);
const form = new FormData();
form.append('file', videoData, video.name);
const uploadResponse = await axios.post(uploadUrl, form, {
headers: { ...form.getHeaders() },
maxContentLength: Infinity,
maxBodyLength: Infinity,
});
console.log('[β
] Video Uploaded:', uploadResponse.data);
const videoUrl = uploadResponse.data.url;
const videoName = uploadResponse.data.name;
console.warn('[π] Video URL for Publishing:', videoUrl);
console.warn('[π] Video Name for Publishing:', videoName);
const publishResponse = await axios.post(
`${DAILY_API_BASE}/me/videos`,
{
url: videoUrl,
title: videoName,
channel: 'music',
published: 'true',
is_created_for_kids: 'false',
},
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/x-www-form-urlencoded',
},
}
);
console.log('[β
] Video Published:', publishResponse.data);
return publishResponse.data;
} catch (error) {
console.error(`[β] Error processing video (${video.name}):`, error.response?.data || error.message);
return { error: error.message, video: video.name };
}
}));
res.json(uploadResults);
} catch (error) {
console.error('[β] Error in upload endpoint:', error.message);
res.status(500).send('Error uploading videos.');
}
});
I need to refactor some things now, making it more comprehensive and fault tolerant and point it back to the cloud instance for finding files automatically and finish some styling. Other than that the core logic is there now and I am able to scan for and upload videos programatically! Thank you very much for your patience @PySir
Upvotes: 1
Reputation: 11
I think your API call is not correct, here is the document about video uploading, https://developers.dailymotion.com/guides/upload/, you should firstly upload your video to a server in order to have the video url in the response, then create a video object using the url that you get from previous upload response.
Upvotes: 0