This commit is contained in:
payacom
2026-08-31 20:45:41 +03:30
parent fa9f23c61d
commit 3f416a7a60
367 changed files with 621895 additions and 6443 deletions

View File

@@ -0,0 +1,93 @@
const axios = require('axios')
const PostModel = require('../models/PostModel')
const InstagramImportedPostModel = require('../models/InstagramImportedPostModel')
const { saveBase64PostFiles } = require('./postBase64Files')
const { resolvePostModerationStatus } = require('./contentModeration')
const { savePostWithModerationStatus } = require('./postStatusSave')
const path = require('path')
const imageDir = path.join(__dirname, '../storage/posts/images')
const videoDir = path.join(__dirname, '../storage/posts/videos')
/**
* CAROUSEL_ALBUM items need a second Graph API call (children edge) to resolve
* each slide's own media_url — intentionally out of scope for v1, single
* image/video posts only.
*/
const SUPPORTED_MEDIA_TYPES = ['IMAGE', 'VIDEO']
async function downloadMediaAsFile (mediaUrl, mediaType) {
const response = await axios.get(mediaUrl, {
responseType: 'arraybuffer',
timeout: 20000,
})
const contentType =
response.headers['content-type'] ||
(mediaType === 'VIDEO' ? 'video/mp4' : 'image/jpeg')
const base64Data = `data:${contentType};base64,${Buffer.from(response.data).toString('base64')}`
const ext = mediaType === 'VIDEO' ? 'mp4' : 'jpg'
return {
data: base64Data,
type: contentType,
name: `instagram-import.${ext}`,
}
}
/**
* Imports one Instagram media item as a Modstagram post, if not already imported
* and if its type is supported. Shared by the manual/automatic import endpoints
* and the recurring sync cron — same dedup + storage + moderation path either way.
* Returns the created post, or null if the item was skipped (already imported /
* unsupported type).
*/
async function importInstagramMedia (user, mediaItem) {
if (!SUPPORTED_MEDIA_TYPES.includes(mediaItem.media_type)) {
return null
}
if (!mediaItem.media_url) {
return null
}
const alreadyImported = await InstagramImportedPostModel.findOne({
user: user._id,
instagram_media_id: String(mediaItem.id),
})
if (alreadyImported) {
return null
}
const file = await downloadMediaAsFile(mediaItem.media_url, mediaItem.media_type)
const [savedFile] = await saveBase64PostFiles([file], imageDir, videoDir)
const filePaths = [
{
path: savedFile.path,
type: savedFile.mimetype.startsWith('video/') ? 'video' : 'image',
},
]
const captionText = mediaItem.caption ? String(mediaItem.caption).trim().slice(0, 2000) : null
const moderation = resolvePostModerationStatus({ caption: captionText, filePaths })
if (moderation.status === 'reject') {
return null
}
const post = await savePostWithModerationStatus(PostModel, {
user_id: user._id,
caption: captionText,
files: filePaths,
type: filePaths[0].type,
status: moderation.status,
})
await InstagramImportedPostModel.create({
user: user._id,
instagram_media_id: String(mediaItem.id),
post: post._id,
})
return post
}
module.exports = { importInstagramMedia, SUPPORTED_MEDIA_TYPES }