CORRUPTED_ENTITY 视频帖子 linkedin api

问题描述 投票:0回答:1

我们尝试用linkedin API制作视频帖子,在上传初始化、视频分割、上传、上传最终确定和发布的整个过程中我没有没有错误,我们甚至第一次成功发布,但现在不再了帖子已发布。

以同样的方式,当我尝试发布重复的 linkedin 帖子时,它会拒绝,因为它是重复的帖子


代码:

上传视频:

    async initializeUploadToLinkedinVideo(filePath) {
        const params = [
            { value: this.profileUrn, name: 'profileUrn' },
            { value: this.token, name: 'token' },
            { value: filePath, name: 'filePath' }
        ]
        const error = verifyParams(params)
        if (error) {
            return error
        }

        let fileSize
        try {
            fileSize = await getSize(filePath)
            if (fileSize === 0) {
                return { error: 'File size is 0' }
            }
        } catch (e) {
            console.error('Error getting file size:', e)
            return { error: 'Failed to get file size' }
        }

        try {
            const uploadResponse = await axios.post(
                `https://api.linkedin.com/rest/videos?action=initializeUpload`,
                {
                    initializeUploadRequest: {
                        owner: this.profileUrn,
                        fileSizeBytes: fileSize,
                        uploadCaptions: false,
                        uploadThumbnail: false
                    }
                },
                {
                    headers: {
                        'Authorization': `Bearer ${this.token}`,
                        'X-Restli-Protocol-Version': '2.0.0',
                        'LinkedIn-Version': '202405',
                        'Content-Type': 'application/json'
                    }
                }
            )
            return uploadResponse.data
        } catch (e) {
            console.error(`Error during LinkedIn initialize upload video:`, e.response ? e.response.data : e.message)
            return { error: 'Failed to upload to LinkedIn' }
        }
    }

    async uploadToLinkedinVideo(filePath, uploadInstructions) {
        const params = [
            { value: this.token, name: 'token'},
            { value: uploadInstructions, name: 'uploadInstructions' },
            { value: filePath, name: 'filePath' }
        ]
        const error = verifyParams(params)
        if (error) {
            return error
        }

        let videoSplit
        try {
            videoSplit = await videoSplitter(filePath, uploadInstructions)
            if (videoSplit?.error) {
                console.error('Error splitting video:', videoSplit.error)
                return videoSplit
            }
        } catch (e) {
            console.error('Error splitting video:', e)
            return { error: 'Failed to split video' }
        }

        console.log('videoSplit:', videoSplit)

        try {
            const uploadPromises = videoSplit.map(async (video) => {
                const { outputFilePath, uploadUrl } = video
                const fileStream = fs.createReadStream(outputFilePath)
                const formData = new FormData()
                formData.append('file', fileStream)

                const uploadResponse = await axios.put(uploadUrl, formData,
                    {
                        headers: {
                            ...formData.getHeaders()
                        }
                    }
                )
                return {
                    status: uploadResponse.status,
                    etag: uploadResponse.headers.etag
                }
            })
            return await Promise.all(uploadPromises)
        } catch (e) {
            console.error('Error during LinkedIn upload video:', e.response ? e.response.data : e.message)
            return { error: 'Failed to upload to LinkedIn' }
        }
    }

    async finalizeVideoUpload(videoUrn, eTags) {
        const params = [
            { value: this.token, name: 'token' },
            { value: videoUrn, name: 'videoUrn' }
        ]
        const error = verifyParams(params)
        if (error) {
            return error
        }

        try {
            const finalizeResponse = await axios.post(
                `https://api.linkedin.com/rest/videos?action=finalizeUpload`,
                {
                    finalizeUploadRequest: {
                        video: videoUrn,
                        uploadToken: "",
                        uploadedPartIds: eTags
                    }
                },
                {
                    headers: {
                        "Authorization": `Bearer ${this.token}`,
                        "X-Restli-Protocol-Version": "2.0.0",
                        "LinkedIn-Version": "202405",
                        "Content-Type": "application/json"
                    }
                }
            )
            return finalizeResponse.status
        } catch (e) {
            console.error('Error during LinkedIn finalize video upload:', e.response ? e.response.data : e.message)
            return { error: 'Failed to finalize video upload' }
        }
    }

    async initializeAndUploadToLinkedinVideo(filePath) {
        const initializeUploadToLinkedinResponse = await this.initializeUploadToLinkedinVideo(filePath)
        console.log('initializeUploadToLinkedinResponse:', initializeUploadToLinkedinResponse)
        if (initializeUploadToLinkedinResponse?.error) {
            return initializeUploadToLinkedinResponse
        }

        const videoUrn = initializeUploadToLinkedinResponse?.value?.video
        if (!videoUrn) {
            return { error: 'Failed to get video URN' }
        }

        const uploadInstructions = initializeUploadToLinkedinResponse?.value?.uploadInstructions
        console.log('uploadInstructions:', uploadInstructions)
        if (!uploadInstructions) {
            return { error: 'Failed to get upload instructions' }
        }

        const uploadToLinkedinResponse = await this.uploadToLinkedinVideo(filePath, uploadInstructions)
        console.log('uploadToLinkedinResponse:', uploadToLinkedinResponse)
        if (uploadToLinkedinResponse?.error) {
            return uploadToLinkedinResponse
        }

        const eTags = uploadToLinkedinResponse.map(upload => upload.etag)
        const finalizeVideoUploadResponse = await this.finalizeVideoUpload(videoUrn, eTags)
        console.log('finalizeVideoUploadResponse:', finalizeVideoUploadResponse)
        if (finalizeVideoUploadResponse?.error) {
            return finalizeVideoUploadResponse
        }
        if (finalizeVideoUploadResponse !== 200) {
            return { error: 'Failed to finalize video upload' }
        }

        return videoUrn
    }

注意:

verifyParams()
getSize()
videoSplitter()
在其他文件中定义,位于根据文档

用于分割视频的函数下方
exports.videoSplitter = async (filePath, uploadInstructions) => {
    const outputDir = `./uploads/linkedin/${filePath.split('/').pop().split('.')[0]}`

    if (!fs.existsSync(outputDir)) {
        fs.mkdirSync(outputDir, { recursive: true })
    }

    const videoPaths = []

    const splitPromise = uploadInstructions.map((range, index) => {
        return new Promise((resolve, reject) => {
            const { firstByte, lastByte, uploadUrl } = range
            const outputFilePath = `${outputDir}/segment_${index + 1}.mp4`
            // Adjust the end position to include the last byte
            const readStream = fs.createReadStream(filePath, { start: firstByte, end: lastByte })
            const writeStream = fs.createWriteStream(outputFilePath)

            readStream.pipe(writeStream)

            readStream.on('end', () => {
                console.log(`Segment ${index + 1} written successfully`)
                const absolutePath = fs.realpathSync(outputFilePath)
                videoPaths.push({ outputFilePath: absolutePath, uploadUrl })
                resolve()
            })

            readStream.on('error', (err) => {
                console.error(`Error reading segment ${index + 1}:`, err)
                reject(err)
            })

            writeStream.on('error', (err) => {
                console.error(`Error writing segment ${index + 1}:`, err)
                reject(err)
            })
        })
    })

    try {
        await Promise.all(splitPromise)
    } catch (e) {
        console.error('Error splitting video:', e)
        return { error: 'Failed to split video', details: e }
    }

    if (videoPaths.length !== uploadInstructions.length) {
        return { error: 'Failed to split video' }
    }

    return videoPaths
}

在发布和获取视频的请求下方:

帖子:

POST https://api.linkedin.com/rest/posts
Authorization: Bearer <ACCESS_TOKEN>
Linkedin-Version: 202405
X-RestLi-Protocol-Version: 2.0.0
Content-Type: application/json

{
  "author": "urn:li:organization:<ORGANIZATION_ID>",
  "commentary": "Post video from api test longer /3!",
  "visibility": "PUBLIC",
  "distribution": {
    "feedDistribution": "MAIN_FEED",
    "targetEntities": [],
    "thirdPartyDistributionChannels": []
  },
  "content": {
    "media": {
      "title": "Post video from api test longer /2!",
      "id": "urn:li:video:<VIDEO_ID>"
    }
  },
  "lifecycleState": "PUBLISHED",
  "isReshareDisabledByAuthor": false
}

得到:

GET https://api.linkedin.com/rest/videos/urn:li:video:<VIDEO_ID>
Authorization: Bearer <ACCESS_TOKEN>
Linkedin-Version: 202405
Content-Type: application/json

# Response:

{
  "owner": "urn:li:organization:<ORGANIZATION_ID>",
  "processingFailureReason": "CORRUPTED_ENTITY",
  "id": "urn:li:video:<VIDEO_ID>",
  "status": "PROCESSING_FAILED"
}

我也尝试过this,但分割视频时遇到问题。

我在尝试上传视频时遇到同样的问题< 4Mb (unsplitted video)

linkedin-api linkedin-jsapi
1个回答
0
投票

问题在于视频的分割方式

videoSplitter()
,这是更正后的功能

const fs = require('fs')
const path = require('path')
const { exec } = require('child_process')

exports.videoSplitter = async (filePath, uploadInstructions) => {
    const outputDir = path.join('./uploads/linkedin', path.basename(filePath, path.extname(filePath)))

    if (!fs.existsSync(outputDir)) {
        fs.mkdirSync(outputDir, { recursive: true })
    }

    const videoPaths = []

    const splitCommand = `split -b 4194303 ${filePath} ${path.join(outputDir, 'part-')}`

    try {
        await new Promise((resolve, reject) => {
            exec(splitCommand, (error, stdout, stderr) => {
                if (error) {
                    console.error(`Error splitting video: ${error}`)
                    reject(error)
                } else {
                    resolve()
                }
            })
        })

        const partFiles = fs.readdirSync(outputDir).filter(file => file.startsWith('part-'))

        if (partFiles.length !== uploadInstructions.length) {
            return { error: 'Failed to split video: mismatch between number of parts and upload instructions' }
        }

        partFiles.forEach((file, index) => {
            const absolutePath = fs.realpathSync(path.join(outputDir, file))
            const uploadUrl = uploadInstructions[index].uploadUrl
            videoPaths.push({ outputFilePath: absolutePath, uploadUrl })
        })

    } catch (e) {
        console.error('Error splitting video:', e)
        return { error: 'Failed to split video', details: e }
    }

    return videoPaths
}

© www.soinside.com 2019 - 2024. All rights reserved.