feat: post to tiktok

This commit is contained in:
Nevo David 2024-07-03 20:28:30 +07:00
parent e21278661e
commit e5aa29d13e
4 changed files with 58 additions and 102 deletions

View File

@ -237,4 +237,25 @@ const TikTokPreview: FC = (props) => {
);
};
export default withProvider(TikTokSettings, TikTokPreview, TikTokDto);
export default withProvider(
TikTokSettings,
TikTokPreview,
TikTokDto,
async (items) => {
const [firstItems] = items;
if (items.length !== 1) {
return 'Tiktok items should be one';
}
if (items[0].length !== 1) {
return 'You need one media';
}
if (firstItems[0].path.indexOf('mp4') === -1) {
return 'Item must be a video';
}
return true;
}
);

View File

@ -158,7 +158,7 @@ export default withProvider(
}
if (items[0].length !== 1) {
return 'You need one item';
return 'You need one media';
}
if (firstItems[0].path.indexOf('mp4') === -1) {

View File

@ -4,6 +4,7 @@ export class RefreshToken {
export abstract class SocialAbstract {
async fetch(url: string, options: RequestInit = {}) {
const request = await fetch(url, options);
console.log(request.status);
if (request.status === 401) {
throw new RefreshToken();
}

View File

@ -6,6 +6,7 @@ import {
} from '@gitroom/nestjs-libraries/integrations/social/social.integrations.interface';
import dayjs from 'dayjs';
import { SocialAbstract } from '@gitroom/nestjs-libraries/integrations/social.abstract';
import { TikTokDto } from '@gitroom/nestjs-libraries/dtos/posts/providers-settings/tiktok.dto';
export class TiktokProvider extends SocialAbstract implements SocialProvider {
identifier = 'tiktok';
@ -16,12 +17,12 @@ export class TiktokProvider extends SocialAbstract implements SocialProvider {
const value = {
client_key: process.env.TIKTOK_CLIENT_ID!,
client_secret: process.env.TIKTOK_CLIENT_SECRET!,
grant_type: 'authorization_code',
grant_type: 'refresh_token',
refresh_token: refreshToken,
};
const { access_token, refresh_token } = await (
await this.fetch('https://open.tiktokapis.com/v2/oauth/token/', {
const { access_token, refresh_token, ...all } = await (
await fetch('https://open.tiktokapis.com/v2/oauth/token/', {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
@ -138,117 +139,50 @@ export class TiktokProvider extends SocialAbstract implements SocialProvider {
async post(
id: string,
accessToken: string,
postDetails: PostDetails[]
postDetails: PostDetails<TikTokDto>[]
): Promise<PostResponse[]> {
const [firstPost, ...comments] = postDetails;
let finalId = '';
let finalUrl = '';
if ((firstPost?.media?.[0]?.path?.indexOf('mp4') || -2) > -1) {
const { id: videoId, permalink_url } = await (
await this.fetch(
`https://graph.facebook.com/v20.0/${id}/videos?access_token=${accessToken}&fields=id,permalink_url`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
file_url: firstPost?.media?.[0]?.path!,
description: firstPost.message,
published: true,
}),
}
)
).json();
finalUrl = permalink_url;
finalId = videoId;
} else {
const uploadPhotos = !firstPost?.media?.length
? []
: await Promise.all(
firstPost.media.map(async (media) => {
const { id: photoId } = await (
await this.fetch(
`https://graph.facebook.com/v20.0/${id}/photos?access_token=${accessToken}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
url: media.url,
published: false,
}),
}
)
).json();
return { media_fbid: photoId };
})
);
try {
const [firstPost, ...comments] = postDetails;
const {
id: postId,
permalink_url,
...all
data: { publish_id },
} = await (
await this.fetch(
`https://graph.facebook.com/v20.0/${id}/feed?access_token=${accessToken}&fields=id,permalink_url`,
'https://open.tiktokapis.com/v2/post/publish/video/init/',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Type': 'application/json; charset=UTF-8',
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify({
...(uploadPhotos?.length ? { attached_media: uploadPhotos } : {}),
message: firstPost.message,
published: true,
post_info: {
title: firstPost.message,
privacy_level: firstPost.settings.privacy_level,
disable_duet: firstPost.settings.disable_duet,
disable_comment: firstPost.settings.disable_comment,
disable_stitch: firstPost.settings.disable_stitch,
brand_content_toggle: firstPost.settings.brand_content_toggle,
brand_organic_toggle: firstPost.settings.brand_organic_toggle,
},
source_info: {
source: 'PULL_FROM_URL',
video_url: firstPost?.media?.[0]?.url!,
},
}),
}
)
).json();
finalUrl = permalink_url;
finalId = postId;
return [
{
id: firstPost.id,
releaseURL: `https://www.tiktok.com`,
postId: publish_id,
status: 'success',
},
];
} catch (err) {
return [];
}
const postsArray = [];
for (const comment of comments) {
const data = await (
await this.fetch(
`https://graph.facebook.com/v20.0/${finalId}/comments?access_token=${accessToken}&fields=id,permalink_url`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
...(comment.media?.length
? { attachment_url: comment.media[0].url }
: {}),
message: comment.message,
}),
}
)
).json();
postsArray.push({
id: comment.id,
postId: data.id,
releaseURL: data.permalink_url,
status: 'success',
});
}
return [
{
id: firstPost.id,
postId: finalId,
releaseURL: finalUrl,
status: 'success',
},
...postsArray,
];
}
}