upload-post 1.0.1 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yml +45 -0
- package/LICENSE +21 -0
- package/README.md +300 -31
- package/index.d.ts +568 -9
- package/index.js +718 -32
- package/package.json +28 -5
package/index.js
CHANGED
|
@@ -3,15 +3,13 @@ import FormData from 'form-data';
|
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import { createReadStream } from 'fs';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
* @typedef {Object} UploadOptions
|
|
8
|
-
* @property {string} title - Video title
|
|
9
|
-
* @property {string} user - User identifier
|
|
10
|
-
* @property {string[]} platforms - Array of platforms (e.g. ['tiktok'])
|
|
11
|
-
*/
|
|
6
|
+
const API_BASE_URL = 'https://api.upload-post.com/api';
|
|
12
7
|
|
|
13
8
|
/**
|
|
14
9
|
* Upload-Post API client
|
|
10
|
+
*
|
|
11
|
+
* Supports uploading to: TikTok, Instagram, YouTube, LinkedIn, Facebook,
|
|
12
|
+
* Pinterest, Threads, Reddit, Bluesky, X (Twitter)
|
|
15
13
|
*/
|
|
16
14
|
export class UploadPost {
|
|
17
15
|
/**
|
|
@@ -19,42 +17,730 @@ export class UploadPost {
|
|
|
19
17
|
*/
|
|
20
18
|
constructor(apiKey) {
|
|
21
19
|
this.apiKey = apiKey;
|
|
22
|
-
this.baseUrl =
|
|
20
|
+
this.baseUrl = API_BASE_URL;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Make an API request
|
|
25
|
+
* @private
|
|
26
|
+
*/
|
|
27
|
+
async _request(endpoint, method = 'GET', data = null, isFormData = false) {
|
|
28
|
+
const config = {
|
|
29
|
+
method,
|
|
30
|
+
url: `${this.baseUrl}${endpoint}`,
|
|
31
|
+
headers: {
|
|
32
|
+
'Authorization': `Apikey ${this.apiKey}`
|
|
33
|
+
},
|
|
34
|
+
maxContentLength: Infinity,
|
|
35
|
+
maxBodyLength: Infinity
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
if (data) {
|
|
39
|
+
if (isFormData) {
|
|
40
|
+
config.headers = { ...config.headers, ...data.getHeaders() };
|
|
41
|
+
config.data = data;
|
|
42
|
+
} else if (method === 'GET') {
|
|
43
|
+
config.params = data;
|
|
44
|
+
} else {
|
|
45
|
+
config.headers['Content-Type'] = 'application/json';
|
|
46
|
+
config.data = data;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const response = await axios(config);
|
|
52
|
+
return response.data;
|
|
53
|
+
} catch (error) {
|
|
54
|
+
const message = error.response?.data?.message || error.response?.data?.detail || error.message;
|
|
55
|
+
throw new Error(`Upload-Post API error: ${message}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Add common upload parameters to form
|
|
61
|
+
* @private
|
|
62
|
+
*/
|
|
63
|
+
_addCommonParams(form, options) {
|
|
64
|
+
form.append('user', options.user);
|
|
65
|
+
form.append('title', options.title);
|
|
66
|
+
|
|
67
|
+
// Platforms
|
|
68
|
+
const platforms = Array.isArray(options.platforms) ? options.platforms : [options.platforms];
|
|
69
|
+
platforms.forEach(p => form.append('platform[]', p));
|
|
70
|
+
|
|
71
|
+
// Optional common parameters
|
|
72
|
+
if (options.firstComment) form.append('first_comment', options.firstComment);
|
|
73
|
+
if (options.altText) form.append('alt_text', options.altText);
|
|
74
|
+
if (options.scheduledDate) form.append('scheduled_date', options.scheduledDate);
|
|
75
|
+
if (options.timezone) form.append('timezone', options.timezone);
|
|
76
|
+
if (options.addToQueue !== undefined) form.append('add_to_queue', String(options.addToQueue));
|
|
77
|
+
if (options.asyncUpload !== undefined) form.append('async_upload', String(options.asyncUpload));
|
|
78
|
+
|
|
79
|
+
// Platform-specific title overrides
|
|
80
|
+
if (options.blueskyTitle) form.append('bluesky_title', options.blueskyTitle);
|
|
81
|
+
if (options.instagramTitle) form.append('instagram_title', options.instagramTitle);
|
|
82
|
+
if (options.facebookTitle) form.append('facebook_title', options.facebookTitle);
|
|
83
|
+
if (options.tiktokTitle) form.append('tiktok_title', options.tiktokTitle);
|
|
84
|
+
if (options.linkedinTitle) form.append('linkedin_title', options.linkedinTitle);
|
|
85
|
+
if (options.xTitle) form.append('x_title', options.xTitle);
|
|
86
|
+
if (options.youtubeTitle) form.append('youtube_title', options.youtubeTitle);
|
|
87
|
+
if (options.pinterestTitle) form.append('pinterest_title', options.pinterestTitle);
|
|
88
|
+
if (options.threadsTitle) form.append('threads_title', options.threadsTitle);
|
|
89
|
+
|
|
90
|
+
// Platform-specific description overrides
|
|
91
|
+
if (options.description) form.append('description', options.description);
|
|
92
|
+
if (options.linkedinDescription) form.append('linkedin_description', options.linkedinDescription);
|
|
93
|
+
if (options.youtubeDescription) form.append('youtube_description', options.youtubeDescription);
|
|
94
|
+
if (options.facebookDescription) form.append('facebook_description', options.facebookDescription);
|
|
95
|
+
if (options.tiktokDescription) form.append('tiktok_description', options.tiktokDescription);
|
|
96
|
+
if (options.pinterestDescription) form.append('pinterest_description', options.pinterestDescription);
|
|
97
|
+
|
|
98
|
+
// Platform-specific first comment overrides
|
|
99
|
+
if (options.instagramFirstComment) form.append('instagram_first_comment', options.instagramFirstComment);
|
|
100
|
+
if (options.facebookFirstComment) form.append('facebook_first_comment', options.facebookFirstComment);
|
|
101
|
+
if (options.xFirstComment) form.append('x_first_comment', options.xFirstComment);
|
|
102
|
+
if (options.threadsFirstComment) form.append('threads_first_comment', options.threadsFirstComment);
|
|
103
|
+
if (options.youtubeFirstComment) form.append('youtube_first_comment', options.youtubeFirstComment);
|
|
104
|
+
if (options.redditFirstComment) form.append('reddit_first_comment', options.redditFirstComment);
|
|
105
|
+
if (options.blueskyFirstComment) form.append('bluesky_first_comment', options.blueskyFirstComment);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Add TikTok-specific parameters
|
|
110
|
+
* @private
|
|
111
|
+
*/
|
|
112
|
+
_addTiktokParams(form, options, isVideo = true) {
|
|
113
|
+
if (options.tiktokDisableComment !== undefined) form.append('disable_comment', String(options.tiktokDisableComment));
|
|
114
|
+
if (options.brandContentToggle !== undefined) form.append('brand_content_toggle', String(options.brandContentToggle));
|
|
115
|
+
if (options.brandOrganicToggle !== undefined) form.append('brand_organic_toggle', String(options.brandOrganicToggle));
|
|
116
|
+
|
|
117
|
+
if (isVideo) {
|
|
118
|
+
if (options.tiktokPrivacyLevel) form.append('privacy_level', options.tiktokPrivacyLevel);
|
|
119
|
+
if (options.tiktokDisableDuet !== undefined) form.append('disable_duet', String(options.tiktokDisableDuet));
|
|
120
|
+
if (options.tiktokDisableStitch !== undefined) form.append('disable_stitch', String(options.tiktokDisableStitch));
|
|
121
|
+
if (options.tiktokCoverTimestamp !== undefined) form.append('cover_timestamp', options.tiktokCoverTimestamp);
|
|
122
|
+
if (options.tiktokIsAigc !== undefined) form.append('is_aigc', String(options.tiktokIsAigc));
|
|
123
|
+
if (options.tiktokPostMode) form.append('post_mode', options.tiktokPostMode);
|
|
124
|
+
} else {
|
|
125
|
+
// Photo-specific
|
|
126
|
+
if (options.tiktokAutoAddMusic !== undefined) form.append('auto_add_music', String(options.tiktokAutoAddMusic));
|
|
127
|
+
if (options.tiktokPhotoCoverIndex !== undefined) form.append('photo_cover_index', options.tiktokPhotoCoverIndex);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Add Instagram-specific parameters
|
|
133
|
+
* @private
|
|
134
|
+
*/
|
|
135
|
+
_addInstagramParams(form, options, isVideo = true) {
|
|
136
|
+
if (options.instagramMediaType) form.append('media_type', options.instagramMediaType);
|
|
137
|
+
if (options.instagramCollaborators) form.append('collaborators', options.instagramCollaborators);
|
|
138
|
+
if (options.instagramUserTags) form.append('user_tags', options.instagramUserTags);
|
|
139
|
+
if (options.instagramLocationId) form.append('location_id', options.instagramLocationId);
|
|
140
|
+
|
|
141
|
+
if (isVideo) {
|
|
142
|
+
if (options.instagramShareToFeed !== undefined) form.append('share_to_feed', String(options.instagramShareToFeed));
|
|
143
|
+
if (options.instagramCoverUrl) form.append('cover_url', options.instagramCoverUrl);
|
|
144
|
+
if (options.instagramAudioName) form.append('audio_name', options.instagramAudioName);
|
|
145
|
+
if (options.instagramThumbOffset) form.append('thumb_offset', options.instagramThumbOffset);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Add YouTube-specific parameters
|
|
151
|
+
* @private
|
|
152
|
+
*/
|
|
153
|
+
_addYoutubeParams(form, options) {
|
|
154
|
+
if (options.youtubeTags) {
|
|
155
|
+
const tags = Array.isArray(options.youtubeTags) ? options.youtubeTags : options.youtubeTags.split(',').map(t => t.trim());
|
|
156
|
+
tags.forEach(tag => form.append('tags[]', tag));
|
|
157
|
+
}
|
|
158
|
+
if (options.youtubeCategoryId) form.append('categoryId', options.youtubeCategoryId);
|
|
159
|
+
if (options.youtubePrivacyStatus) form.append('privacyStatus', options.youtubePrivacyStatus);
|
|
160
|
+
if (options.youtubeEmbeddable !== undefined) form.append('embeddable', String(options.youtubeEmbeddable));
|
|
161
|
+
if (options.youtubeLicense) form.append('license', options.youtubeLicense);
|
|
162
|
+
if (options.youtubePublicStatsViewable !== undefined) form.append('publicStatsViewable', String(options.youtubePublicStatsViewable));
|
|
163
|
+
if (options.youtubeThumbnailUrl) form.append('thumbnail_url', options.youtubeThumbnailUrl);
|
|
164
|
+
if (options.youtubeSelfDeclaredMadeForKids !== undefined) form.append('selfDeclaredMadeForKids', String(options.youtubeSelfDeclaredMadeForKids));
|
|
165
|
+
if (options.youtubeContainsSyntheticMedia !== undefined) form.append('containsSyntheticMedia', String(options.youtubeContainsSyntheticMedia));
|
|
166
|
+
if (options.youtubeDefaultLanguage) form.append('defaultLanguage', options.youtubeDefaultLanguage);
|
|
167
|
+
if (options.youtubeDefaultAudioLanguage) form.append('defaultAudioLanguage', options.youtubeDefaultAudioLanguage);
|
|
168
|
+
if (options.youtubeAllowedCountries) form.append('allowedCountries', options.youtubeAllowedCountries);
|
|
169
|
+
if (options.youtubeBlockedCountries) form.append('blockedCountries', options.youtubeBlockedCountries);
|
|
170
|
+
if (options.youtubeHasPaidProductPlacement !== undefined) form.append('hasPaidProductPlacement', String(options.youtubeHasPaidProductPlacement));
|
|
171
|
+
if (options.youtubeRecordingDate) form.append('recordingDate', options.youtubeRecordingDate);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Add LinkedIn-specific parameters
|
|
176
|
+
* @private
|
|
177
|
+
*/
|
|
178
|
+
_addLinkedinParams(form, options) {
|
|
179
|
+
if (options.linkedinVisibility) form.append('visibility', options.linkedinVisibility);
|
|
180
|
+
if (options.targetLinkedinPageId) form.append('target_linkedin_page_id', options.targetLinkedinPageId);
|
|
23
181
|
}
|
|
24
182
|
|
|
25
183
|
/**
|
|
26
|
-
*
|
|
27
|
-
* @
|
|
28
|
-
|
|
184
|
+
* Add Facebook-specific parameters
|
|
185
|
+
* @private
|
|
186
|
+
*/
|
|
187
|
+
_addFacebookParams(form, options, isVideo = false, isText = false) {
|
|
188
|
+
if (options.facebookPageId) form.append('facebook_page_id', options.facebookPageId);
|
|
189
|
+
|
|
190
|
+
if (isVideo) {
|
|
191
|
+
if (options.facebookVideoState) form.append('video_state', options.facebookVideoState);
|
|
192
|
+
if (options.facebookMediaType) form.append('facebook_media_type', options.facebookMediaType);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (isText && options.facebookLinkUrl) {
|
|
196
|
+
form.append('facebook_link_url', options.facebookLinkUrl);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Add Pinterest-specific parameters
|
|
202
|
+
* @private
|
|
203
|
+
*/
|
|
204
|
+
_addPinterestParams(form, options, isVideo = false) {
|
|
205
|
+
if (options.pinterestBoardId) form.append('pinterest_board_id', options.pinterestBoardId);
|
|
206
|
+
if (options.pinterestAltText) form.append('pinterest_alt_text', options.pinterestAltText);
|
|
207
|
+
if (options.pinterestLink) form.append('pinterest_link', options.pinterestLink);
|
|
208
|
+
|
|
209
|
+
if (isVideo) {
|
|
210
|
+
if (options.pinterestCoverImageUrl) form.append('pinterest_cover_image_url', options.pinterestCoverImageUrl);
|
|
211
|
+
if (options.pinterestCoverImageContentType) form.append('pinterest_cover_image_content_type', options.pinterestCoverImageContentType);
|
|
212
|
+
if (options.pinterestCoverImageData) form.append('pinterest_cover_image_data', options.pinterestCoverImageData);
|
|
213
|
+
if (options.pinterestCoverImageKeyFrameTime !== undefined) form.append('pinterest_cover_image_key_frame_time', options.pinterestCoverImageKeyFrameTime);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Add X (Twitter) specific parameters
|
|
219
|
+
* @private
|
|
220
|
+
*/
|
|
221
|
+
_addXParams(form, options, isText = false) {
|
|
222
|
+
if (options.xReplySettings && options.xReplySettings !== 'everyone') form.append('reply_settings', options.xReplySettings);
|
|
223
|
+
if (options.xNullcast !== undefined) form.append('nullcast', String(options.xNullcast));
|
|
224
|
+
if (options.xQuoteTweetId) form.append('quote_tweet_id', options.xQuoteTweetId);
|
|
225
|
+
if (options.xGeoPlaceId) form.append('geo_place_id', options.xGeoPlaceId);
|
|
226
|
+
if (options.xForSuperFollowersOnly !== undefined) form.append('for_super_followers_only', String(options.xForSuperFollowersOnly));
|
|
227
|
+
if (options.xCommunityId) form.append('community_id', options.xCommunityId);
|
|
228
|
+
if (options.xShareWithFollowers !== undefined) form.append('share_with_followers', String(options.xShareWithFollowers));
|
|
229
|
+
if (options.xDirectMessageDeepLink) form.append('direct_message_deep_link', options.xDirectMessageDeepLink);
|
|
230
|
+
if (options.xLongTextAsPost !== undefined) form.append('x_long_text_as_post', String(options.xLongTextAsPost));
|
|
231
|
+
|
|
232
|
+
if (!isText) {
|
|
233
|
+
if (options.xTaggedUserIds) {
|
|
234
|
+
const ids = Array.isArray(options.xTaggedUserIds) ? options.xTaggedUserIds : options.xTaggedUserIds.split(',').map(t => t.trim());
|
|
235
|
+
ids.forEach(id => form.append('tagged_user_ids[]', id));
|
|
236
|
+
}
|
|
237
|
+
if (options.xPlaceId) form.append('place_id', options.xPlaceId);
|
|
238
|
+
} else {
|
|
239
|
+
if (options.xPostUrl) form.append('post_url', options.xPostUrl);
|
|
240
|
+
if (options.xCardUri) form.append('card_uri', options.xCardUri);
|
|
241
|
+
|
|
242
|
+
// Poll options
|
|
243
|
+
if (options.xPollOptions) {
|
|
244
|
+
const pollOpts = Array.isArray(options.xPollOptions) ? options.xPollOptions : options.xPollOptions.split(',').map(t => t.trim());
|
|
245
|
+
pollOpts.forEach(opt => form.append('poll_options[]', opt));
|
|
246
|
+
if (options.xPollDuration) form.append('poll_duration', options.xPollDuration);
|
|
247
|
+
if (options.xPollReplySettings) form.append('poll_reply_settings', options.xPollReplySettings);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Add Threads-specific parameters
|
|
254
|
+
* @private
|
|
255
|
+
*/
|
|
256
|
+
_addThreadsParams(form, options) {
|
|
257
|
+
if (options.threadsLongTextAsPost !== undefined) form.append('threads_long_text_as_post', String(options.threadsLongTextAsPost));
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Add Reddit-specific parameters
|
|
262
|
+
* @private
|
|
263
|
+
*/
|
|
264
|
+
_addRedditParams(form, options) {
|
|
265
|
+
if (options.redditSubreddit) form.append('subreddit', options.redditSubreddit);
|
|
266
|
+
if (options.redditFlairId) form.append('flair_id', options.redditFlairId);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Upload a video to social media platforms
|
|
271
|
+
*
|
|
272
|
+
* @param {string} videoPathOrUrl - Path to video file or video URL
|
|
273
|
+
* @param {Object} options - Upload options
|
|
274
|
+
* @param {string} options.title - Video title/caption
|
|
275
|
+
* @param {string} options.user - User identifier (profile name)
|
|
276
|
+
* @param {string[]} options.platforms - Target platforms (tiktok, instagram, youtube, linkedin, facebook, pinterest, threads, bluesky, x)
|
|
277
|
+
* @param {string} [options.description] - Video description
|
|
278
|
+
* @param {string} [options.firstComment] - First comment to post
|
|
279
|
+
* @param {string} [options.scheduledDate] - ISO date for scheduling (e.g., "2024-12-25T10:00:00Z")
|
|
280
|
+
* @param {string} [options.timezone] - Timezone for scheduled date (e.g., "Europe/Madrid")
|
|
281
|
+
* @param {boolean} [options.addToQueue] - Add to posting queue instead of immediate post
|
|
282
|
+
* @param {boolean} [options.asyncUpload=true] - Process upload asynchronously
|
|
283
|
+
*
|
|
284
|
+
* TikTok options:
|
|
285
|
+
* @param {string} [options.tiktokPrivacyLevel] - PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR, SELF_ONLY
|
|
286
|
+
* @param {boolean} [options.tiktokDisableDuet] - Disable duet
|
|
287
|
+
* @param {boolean} [options.tiktokDisableComment] - Disable comments
|
|
288
|
+
* @param {boolean} [options.tiktokDisableStitch] - Disable stitch
|
|
289
|
+
* @param {number} [options.tiktokCoverTimestamp] - Timestamp in ms for video cover
|
|
290
|
+
* @param {boolean} [options.tiktokIsAigc] - AI-generated content flag
|
|
291
|
+
* @param {string} [options.tiktokPostMode] - DIRECT_POST or MEDIA_UPLOAD
|
|
292
|
+
* @param {boolean} [options.brandContentToggle] - Branded content toggle
|
|
293
|
+
* @param {boolean} [options.brandOrganicToggle] - Brand organic toggle
|
|
294
|
+
*
|
|
295
|
+
* Instagram options:
|
|
296
|
+
* @param {string} [options.instagramMediaType] - REELS or STORIES
|
|
297
|
+
* @param {boolean} [options.instagramShareToFeed] - Share to feed
|
|
298
|
+
* @param {string} [options.instagramCollaborators] - Comma-separated collaborator usernames
|
|
299
|
+
* @param {string} [options.instagramCoverUrl] - Custom cover URL
|
|
300
|
+
* @param {string} [options.instagramAudioName] - Audio track name
|
|
301
|
+
* @param {string} [options.instagramUserTags] - Comma-separated user tags
|
|
302
|
+
* @param {string} [options.instagramLocationId] - Location ID
|
|
303
|
+
* @param {string} [options.instagramThumbOffset] - Thumbnail offset
|
|
304
|
+
*
|
|
305
|
+
* YouTube options:
|
|
306
|
+
* @param {string|string[]} [options.youtubeTags] - Video tags
|
|
307
|
+
* @param {string} [options.youtubeCategoryId] - Category ID (e.g., "22" for People & Blogs)
|
|
308
|
+
* @param {string} [options.youtubePrivacyStatus] - public, unlisted, or private
|
|
309
|
+
* @param {boolean} [options.youtubeEmbeddable] - Allow embedding
|
|
310
|
+
* @param {string} [options.youtubeLicense] - youtube or creativeCommon
|
|
311
|
+
* @param {boolean} [options.youtubePublicStatsViewable] - Show public stats
|
|
312
|
+
* @param {string} [options.youtubeThumbnailUrl] - Custom thumbnail URL
|
|
313
|
+
* @param {boolean} [options.youtubeSelfDeclaredMadeForKids] - Made for kids flag
|
|
314
|
+
* @param {boolean} [options.youtubeContainsSyntheticMedia] - AI/synthetic content flag
|
|
315
|
+
* @param {string} [options.youtubeDefaultLanguage] - Title/description language (BCP-47)
|
|
316
|
+
* @param {string} [options.youtubeDefaultAudioLanguage] - Audio language (BCP-47)
|
|
317
|
+
* @param {string} [options.youtubeAllowedCountries] - Comma-separated country codes
|
|
318
|
+
* @param {string} [options.youtubeBlockedCountries] - Comma-separated country codes
|
|
319
|
+
* @param {boolean} [options.youtubeHasPaidProductPlacement] - Paid placement flag
|
|
320
|
+
* @param {string} [options.youtubeRecordingDate] - Recording date (ISO 8601)
|
|
321
|
+
*
|
|
322
|
+
* LinkedIn options:
|
|
323
|
+
* @param {string} [options.linkedinVisibility] - PUBLIC, CONNECTIONS, LOGGED_IN, CONTAINER
|
|
324
|
+
* @param {string} [options.targetLinkedinPageId] - Page ID for organization posts
|
|
325
|
+
*
|
|
326
|
+
* Facebook options:
|
|
327
|
+
* @param {string} [options.facebookPageId] - Facebook Page ID
|
|
328
|
+
* @param {string} [options.facebookVideoState] - PUBLISHED or DRAFT
|
|
329
|
+
* @param {string} [options.facebookMediaType] - REELS or STORIES
|
|
330
|
+
*
|
|
331
|
+
* Pinterest options:
|
|
332
|
+
* @param {string} [options.pinterestBoardId] - Board ID
|
|
333
|
+
* @param {string} [options.pinterestLink] - Destination link
|
|
334
|
+
* @param {string} [options.pinterestCoverImageUrl] - Cover image URL
|
|
335
|
+
* @param {number} [options.pinterestCoverImageKeyFrameTime] - Key frame time in ms
|
|
336
|
+
*
|
|
337
|
+
* X (Twitter) options:
|
|
338
|
+
* @param {string} [options.xReplySettings] - everyone, following, mentionedUsers, subscribers, verified
|
|
339
|
+
* @param {boolean} [options.xNullcast] - Promoted-only post
|
|
340
|
+
* @param {string|string[]} [options.xTaggedUserIds] - User IDs to tag
|
|
341
|
+
* @param {string} [options.xPlaceId] - Location place ID
|
|
342
|
+
* @param {string} [options.xGeoPlaceId] - Geographic place ID
|
|
343
|
+
* @param {boolean} [options.xForSuperFollowersOnly] - Exclusive for super followers
|
|
344
|
+
* @param {string} [options.xCommunityId] - Community ID
|
|
345
|
+
* @param {boolean} [options.xShareWithFollowers] - Share community post with followers
|
|
346
|
+
* @param {boolean} [options.xLongTextAsPost] - Post long text as single post
|
|
347
|
+
*
|
|
348
|
+
* Threads options:
|
|
349
|
+
* @param {boolean} [options.threadsLongTextAsPost] - Post long text as single post (vs thread)
|
|
350
|
+
*
|
|
351
|
+
* @returns {Promise<Object>} API response with request_id for async uploads
|
|
352
|
+
*/
|
|
353
|
+
async upload(videoPathOrUrl, options) {
|
|
354
|
+
const form = new FormData();
|
|
355
|
+
|
|
356
|
+
// Handle video (file path or URL)
|
|
357
|
+
if (videoPathOrUrl.toLowerCase().startsWith('http://') || videoPathOrUrl.toLowerCase().startsWith('https://')) {
|
|
358
|
+
form.append('video', videoPathOrUrl);
|
|
359
|
+
} else {
|
|
360
|
+
if (!fs.existsSync(videoPathOrUrl)) {
|
|
361
|
+
throw new Error(`Video file not found: ${videoPathOrUrl}`);
|
|
362
|
+
}
|
|
363
|
+
form.append('video', createReadStream(videoPathOrUrl));
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
this._addCommonParams(form, options);
|
|
367
|
+
|
|
368
|
+
const platforms = Array.isArray(options.platforms) ? options.platforms : [options.platforms];
|
|
369
|
+
if (platforms.includes('tiktok')) this._addTiktokParams(form, options, true);
|
|
370
|
+
if (platforms.includes('instagram')) this._addInstagramParams(form, options, true);
|
|
371
|
+
if (platforms.includes('youtube')) this._addYoutubeParams(form, options);
|
|
372
|
+
if (platforms.includes('linkedin')) this._addLinkedinParams(form, options);
|
|
373
|
+
if (platforms.includes('facebook')) this._addFacebookParams(form, options, true);
|
|
374
|
+
if (platforms.includes('pinterest')) this._addPinterestParams(form, options, true);
|
|
375
|
+
if (platforms.includes('x')) this._addXParams(form, options, false);
|
|
376
|
+
if (platforms.includes('threads')) this._addThreadsParams(form, options);
|
|
377
|
+
|
|
378
|
+
return this._request('/upload', 'POST', form, true);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Upload photos to social media platforms
|
|
383
|
+
*
|
|
384
|
+
* @param {string[]} photosPathsOrUrls - Array of photo file paths or URLs
|
|
385
|
+
* @param {Object} options - Upload options
|
|
386
|
+
* @param {string} options.title - Post title/caption
|
|
387
|
+
* @param {string} options.user - User identifier (profile name)
|
|
388
|
+
* @param {string[]} options.platforms - Target platforms (tiktok, instagram, linkedin, facebook, x, threads, pinterest, reddit, bluesky)
|
|
389
|
+
* @param {string} [options.description] - Photo description
|
|
390
|
+
* @param {string} [options.firstComment] - First comment to post
|
|
391
|
+
* @param {string} [options.altText] - Alt text for accessibility
|
|
392
|
+
* @param {string} [options.scheduledDate] - ISO date for scheduling
|
|
393
|
+
* @param {string} [options.timezone] - Timezone for scheduled date
|
|
394
|
+
* @param {boolean} [options.addToQueue] - Add to posting queue
|
|
395
|
+
* @param {boolean} [options.asyncUpload=true] - Process upload asynchronously
|
|
396
|
+
*
|
|
397
|
+
* TikTok options:
|
|
398
|
+
* @param {boolean} [options.tiktokAutoAddMusic] - Auto add music
|
|
399
|
+
* @param {boolean} [options.tiktokDisableComment] - Disable comments
|
|
400
|
+
* @param {number} [options.tiktokPhotoCoverIndex] - Index of photo for cover (0-based)
|
|
401
|
+
* @param {boolean} [options.brandContentToggle] - Branded content toggle
|
|
402
|
+
* @param {boolean} [options.brandOrganicToggle] - Brand organic toggle
|
|
403
|
+
*
|
|
404
|
+
* Instagram options:
|
|
405
|
+
* @param {string} [options.instagramMediaType] - IMAGE or STORIES
|
|
406
|
+
* @param {string} [options.instagramCollaborators] - Comma-separated collaborator usernames
|
|
407
|
+
* @param {string} [options.instagramUserTags] - Comma-separated user tags
|
|
408
|
+
* @param {string} [options.instagramLocationId] - Location ID
|
|
409
|
+
*
|
|
410
|
+
* LinkedIn options:
|
|
411
|
+
* @param {string} [options.linkedinVisibility] - PUBLIC (only PUBLIC supported for photos)
|
|
412
|
+
* @param {string} [options.targetLinkedinPageId] - Page ID for organization posts
|
|
413
|
+
*
|
|
414
|
+
* Facebook options:
|
|
415
|
+
* @param {string} [options.facebookPageId] - Facebook Page ID
|
|
416
|
+
*
|
|
417
|
+
* Pinterest options:
|
|
418
|
+
* @param {string} [options.pinterestBoardId] - Board ID
|
|
419
|
+
* @param {string} [options.pinterestAltText] - Alt text
|
|
420
|
+
* @param {string} [options.pinterestLink] - Destination link
|
|
421
|
+
*
|
|
422
|
+
* X (Twitter) options:
|
|
423
|
+
* @param {string} [options.xReplySettings] - Who can reply
|
|
424
|
+
* @param {boolean} [options.xNullcast] - Promoted-only post
|
|
425
|
+
* @param {string|string[]} [options.xTaggedUserIds] - User IDs to tag
|
|
426
|
+
* @param {boolean} [options.xLongTextAsPost] - Post long text as single post
|
|
427
|
+
*
|
|
428
|
+
* Threads options:
|
|
429
|
+
* @param {boolean} [options.threadsLongTextAsPost] - Post long text as single post
|
|
430
|
+
*
|
|
431
|
+
* Reddit options:
|
|
432
|
+
* @param {string} [options.redditSubreddit] - Subreddit name (without r/)
|
|
433
|
+
* @param {string} [options.redditFlairId] - Flair template ID
|
|
434
|
+
*
|
|
29
435
|
* @returns {Promise<Object>} API response
|
|
30
436
|
*/
|
|
31
|
-
async
|
|
437
|
+
async uploadPhotos(photosPathsOrUrls, options) {
|
|
32
438
|
const form = new FormData();
|
|
439
|
+
|
|
440
|
+
// Handle photos (file paths or URLs)
|
|
441
|
+
for (const photoItem of photosPathsOrUrls) {
|
|
442
|
+
if (typeof photoItem === 'string' && (photoItem.toLowerCase().startsWith('http://') || photoItem.toLowerCase().startsWith('https://'))) {
|
|
443
|
+
form.append('photos[]', photoItem);
|
|
444
|
+
} else {
|
|
445
|
+
if (!fs.existsSync(photoItem)) {
|
|
446
|
+
throw new Error(`Photo file not found: ${photoItem}`);
|
|
447
|
+
}
|
|
448
|
+
form.append('photos[]', createReadStream(photoItem));
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
this._addCommonParams(form, options);
|
|
33
453
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
454
|
+
const platforms = Array.isArray(options.platforms) ? options.platforms : [options.platforms];
|
|
455
|
+
if (platforms.includes('tiktok')) this._addTiktokParams(form, options, false);
|
|
456
|
+
if (platforms.includes('instagram')) this._addInstagramParams(form, options, false);
|
|
457
|
+
if (platforms.includes('linkedin')) this._addLinkedinParams(form, options);
|
|
458
|
+
if (platforms.includes('facebook')) this._addFacebookParams(form, options, false);
|
|
459
|
+
if (platforms.includes('pinterest')) this._addPinterestParams(form, options, false);
|
|
460
|
+
if (platforms.includes('x')) this._addXParams(form, options, false);
|
|
461
|
+
if (platforms.includes('threads')) this._addThreadsParams(form, options);
|
|
462
|
+
if (platforms.includes('reddit')) this._addRedditParams(form, options);
|
|
40
463
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
464
|
+
return this._request('/upload_photos', 'POST', form, true);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* Upload text posts to social media platforms
|
|
469
|
+
*
|
|
470
|
+
* @param {Object} options - Upload options
|
|
471
|
+
* @param {string} options.title - Text content for the post
|
|
472
|
+
* @param {string} options.user - User identifier (profile name)
|
|
473
|
+
* @param {string[]} options.platforms - Target platforms (x, linkedin, facebook, threads, reddit, bluesky)
|
|
474
|
+
* @param {string} [options.firstComment] - First comment to post
|
|
475
|
+
* @param {string} [options.scheduledDate] - ISO date for scheduling
|
|
476
|
+
* @param {string} [options.timezone] - Timezone for scheduled date
|
|
477
|
+
* @param {boolean} [options.addToQueue] - Add to posting queue
|
|
478
|
+
* @param {boolean} [options.asyncUpload=true] - Process upload asynchronously
|
|
479
|
+
*
|
|
480
|
+
* LinkedIn options:
|
|
481
|
+
* @param {string} [options.targetLinkedinPageId] - Page ID for organization posts
|
|
482
|
+
*
|
|
483
|
+
* Facebook options:
|
|
484
|
+
* @param {string} [options.facebookPageId] - Facebook Page ID
|
|
485
|
+
* @param {string} [options.facebookLinkUrl] - URL to attach as link preview
|
|
486
|
+
*
|
|
487
|
+
* X (Twitter) options:
|
|
488
|
+
* @param {string} [options.xReplySettings] - Who can reply
|
|
489
|
+
* @param {string} [options.xPostUrl] - URL to attach
|
|
490
|
+
* @param {string} [options.xQuoteTweetId] - Tweet ID to quote
|
|
491
|
+
* @param {string|string[]} [options.xPollOptions] - Poll options (2-4 options)
|
|
492
|
+
* @param {number} [options.xPollDuration] - Poll duration in minutes (5-10080)
|
|
493
|
+
* @param {string} [options.xPollReplySettings] - Who can reply to poll
|
|
494
|
+
* @param {string} [options.xCardUri] - Card URI for Twitter Cards
|
|
495
|
+
* @param {boolean} [options.xLongTextAsPost] - Post long text as single post
|
|
496
|
+
*
|
|
497
|
+
* Threads options:
|
|
498
|
+
* @param {boolean} [options.threadsLongTextAsPost] - Post long text as single post
|
|
499
|
+
*
|
|
500
|
+
* Reddit options:
|
|
501
|
+
* @param {string} [options.redditSubreddit] - Subreddit name (without r/)
|
|
502
|
+
* @param {string} [options.redditFlairId] - Flair template ID
|
|
503
|
+
*
|
|
504
|
+
* @returns {Promise<Object>} API response
|
|
505
|
+
*/
|
|
506
|
+
async uploadText(options) {
|
|
507
|
+
const form = new FormData();
|
|
508
|
+
|
|
509
|
+
this._addCommonParams(form, options);
|
|
510
|
+
|
|
511
|
+
const platforms = Array.isArray(options.platforms) ? options.platforms : [options.platforms];
|
|
512
|
+
if (platforms.includes('linkedin')) this._addLinkedinParams(form, options);
|
|
513
|
+
if (platforms.includes('facebook')) this._addFacebookParams(form, options, false, true);
|
|
514
|
+
if (platforms.includes('x')) this._addXParams(form, options, true);
|
|
515
|
+
if (platforms.includes('threads')) this._addThreadsParams(form, options);
|
|
516
|
+
if (platforms.includes('reddit')) this._addRedditParams(form, options);
|
|
517
|
+
|
|
518
|
+
return this._request('/upload_text', 'POST', form, true);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* Upload a document to LinkedIn (PDF, PPT, PPTX, DOC, DOCX)
|
|
523
|
+
*
|
|
524
|
+
* @param {string} documentPathOrUrl - Path to document file or document URL
|
|
525
|
+
* @param {Object} options - Upload options
|
|
526
|
+
* @param {string} options.title - Post title/caption
|
|
527
|
+
* @param {string} options.user - User identifier (profile name)
|
|
528
|
+
* @param {string} [options.description] - Document description/commentary
|
|
529
|
+
* @param {string} [options.linkedinVisibility] - PUBLIC, CONNECTIONS, LOGGED_IN, CONTAINER
|
|
530
|
+
* @param {string} [options.targetLinkedinPageId] - Page ID for organization posts
|
|
531
|
+
* @param {string} [options.scheduledDate] - ISO date for scheduling
|
|
532
|
+
* @param {string} [options.timezone] - Timezone for scheduled date
|
|
533
|
+
* @param {boolean} [options.addToQueue] - Add to posting queue
|
|
534
|
+
* @param {boolean} [options.asyncUpload=true] - Process upload asynchronously
|
|
535
|
+
*
|
|
536
|
+
* @returns {Promise<Object>} API response
|
|
537
|
+
*/
|
|
538
|
+
async uploadDocument(documentPathOrUrl, options) {
|
|
539
|
+
const form = new FormData();
|
|
540
|
+
|
|
541
|
+
// Handle document (file path or URL)
|
|
542
|
+
if (documentPathOrUrl.toLowerCase().startsWith('http://') || documentPathOrUrl.toLowerCase().startsWith('https://')) {
|
|
543
|
+
form.append('document', documentPathOrUrl);
|
|
544
|
+
} else {
|
|
545
|
+
if (!fs.existsSync(documentPathOrUrl)) {
|
|
546
|
+
throw new Error(`Document file not found: ${documentPathOrUrl}`);
|
|
53
547
|
}
|
|
548
|
+
form.append('document', createReadStream(documentPathOrUrl));
|
|
549
|
+
}
|
|
54
550
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
551
|
+
// Force linkedin platform
|
|
552
|
+
form.append('user', options.user);
|
|
553
|
+
form.append('title', options.title);
|
|
554
|
+
form.append('platform[]', 'linkedin');
|
|
555
|
+
|
|
556
|
+
if (options.description) form.append('description', options.description);
|
|
557
|
+
if (options.scheduledDate) form.append('scheduled_date', options.scheduledDate);
|
|
558
|
+
if (options.timezone) form.append('timezone', options.timezone);
|
|
559
|
+
if (options.addToQueue !== undefined) form.append('add_to_queue', String(options.addToQueue));
|
|
560
|
+
if (options.asyncUpload !== undefined) form.append('async_upload', String(options.asyncUpload));
|
|
561
|
+
|
|
562
|
+
this._addLinkedinParams(form, options);
|
|
563
|
+
|
|
564
|
+
return this._request('/upload_document', 'POST', form, true);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// ==================== Status & History ====================
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Get the status of an async upload
|
|
571
|
+
*
|
|
572
|
+
* @param {string} requestId - The request_id from an async upload
|
|
573
|
+
* @returns {Promise<Object>} Upload status
|
|
574
|
+
*/
|
|
575
|
+
async getStatus(requestId) {
|
|
576
|
+
return this._request('/uploadposts/status', 'GET', { request_id: requestId });
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Get upload history
|
|
581
|
+
*
|
|
582
|
+
* @param {Object} [options] - Query options
|
|
583
|
+
* @param {number} [options.page=1] - Page number
|
|
584
|
+
* @param {number} [options.limit=20] - Items per page (20, 50, or 100)
|
|
585
|
+
* @returns {Promise<Object>} Upload history
|
|
586
|
+
*/
|
|
587
|
+
async getHistory(options = {}) {
|
|
588
|
+
return this._request('/uploadposts/history', 'GET', {
|
|
589
|
+
page: options.page || 1,
|
|
590
|
+
limit: options.limit || 20
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Get analytics for a profile
|
|
596
|
+
*
|
|
597
|
+
* @param {string} profileUsername - Profile username
|
|
598
|
+
* @param {Object} [options] - Query options
|
|
599
|
+
* @param {string[]} [options.platforms] - Filter by platforms (instagram, linkedin, facebook, x)
|
|
600
|
+
* @returns {Promise<Object>} Analytics data
|
|
601
|
+
*/
|
|
602
|
+
async getAnalytics(profileUsername, options = {}) {
|
|
603
|
+
const params = {};
|
|
604
|
+
if (options.platforms && options.platforms.length > 0) {
|
|
605
|
+
params.platforms = options.platforms.join(',');
|
|
58
606
|
}
|
|
607
|
+
return this._request(`/analytics/${encodeURIComponent(profileUsername)}`, 'GET', params);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// ==================== Scheduled Posts ====================
|
|
611
|
+
|
|
612
|
+
/**
|
|
613
|
+
* List scheduled posts
|
|
614
|
+
*
|
|
615
|
+
* @returns {Promise<Object>} List of scheduled posts
|
|
616
|
+
*/
|
|
617
|
+
async listScheduled() {
|
|
618
|
+
return this._request('/uploadposts/schedule', 'GET');
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Cancel a scheduled post
|
|
623
|
+
*
|
|
624
|
+
* @param {string} jobId - Scheduled job ID
|
|
625
|
+
* @returns {Promise<Object>} Cancellation result
|
|
626
|
+
*/
|
|
627
|
+
async cancelScheduled(jobId) {
|
|
628
|
+
return this._request(`/uploadposts/schedule/${jobId}`, 'DELETE');
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* Edit a scheduled post
|
|
633
|
+
*
|
|
634
|
+
* @param {string} jobId - Scheduled job ID
|
|
635
|
+
* @param {Object} options - Edit options
|
|
636
|
+
* @param {string} [options.scheduledDate] - New scheduled date (ISO 8601)
|
|
637
|
+
* @param {string} [options.timezone] - New timezone
|
|
638
|
+
* @returns {Promise<Object>} Edit result
|
|
639
|
+
*/
|
|
640
|
+
async editScheduled(jobId, options) {
|
|
641
|
+
const body = {};
|
|
642
|
+
if (options.scheduledDate) body.scheduled_date = options.scheduledDate;
|
|
643
|
+
if (options.timezone) body.timezone = options.timezone;
|
|
644
|
+
return this._request(`/uploadposts/schedule/${jobId}`, 'POST', body);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// ==================== User Management ====================
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* List all users/profiles
|
|
651
|
+
*
|
|
652
|
+
* @returns {Promise<Object>} List of users
|
|
653
|
+
*/
|
|
654
|
+
async listUsers() {
|
|
655
|
+
return this._request('/uploadposts/users', 'GET');
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Create a new user/profile
|
|
660
|
+
*
|
|
661
|
+
* @param {string} username - Profile name to create
|
|
662
|
+
* @returns {Promise<Object>} Created user
|
|
663
|
+
*/
|
|
664
|
+
async createUser(username) {
|
|
665
|
+
return this._request('/uploadposts/users', 'POST', { username });
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Delete a user/profile
|
|
670
|
+
*
|
|
671
|
+
* @param {string} username - Profile name to delete
|
|
672
|
+
* @returns {Promise<Object>} Deletion result
|
|
673
|
+
*/
|
|
674
|
+
async deleteUser(username) {
|
|
675
|
+
return this._request('/uploadposts/users', 'DELETE', { username });
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Generate a JWT for platform integration
|
|
680
|
+
* Used when integrating Upload-Post into your own platform
|
|
681
|
+
*
|
|
682
|
+
* @param {string} username - Profile username
|
|
683
|
+
* @param {Object} [options] - JWT options
|
|
684
|
+
* @param {string} [options.redirectUrl] - URL to redirect after linking
|
|
685
|
+
* @param {string} [options.logoImage] - Logo image URL for the linking page
|
|
686
|
+
* @param {string} [options.redirectButtonText] - Text for redirect button
|
|
687
|
+
* @param {string[]} [options.platforms] - Platforms to show for connection
|
|
688
|
+
* @returns {Promise<Object>} JWT and connection URL
|
|
689
|
+
*/
|
|
690
|
+
async generateJwt(username, options = {}) {
|
|
691
|
+
const body = { username };
|
|
692
|
+
if (options.redirectUrl) body.redirect_url = options.redirectUrl;
|
|
693
|
+
if (options.logoImage) body.logo_image = options.logoImage;
|
|
694
|
+
if (options.redirectButtonText) body.redirect_button_text = options.redirectButtonText;
|
|
695
|
+
if (options.platforms && options.platforms.length > 0) body.platforms = options.platforms;
|
|
696
|
+
return this._request('/uploadposts/users/generate-jwt', 'POST', body);
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Validate a JWT token
|
|
701
|
+
*
|
|
702
|
+
* @param {string} jwt - JWT token to validate
|
|
703
|
+
* @returns {Promise<Object>} Validation result
|
|
704
|
+
*/
|
|
705
|
+
async validateJwt(jwt) {
|
|
706
|
+
return this._request('/uploadposts/users/validate-jwt', 'POST', { jwt });
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// ==================== Helper Endpoints ====================
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* Get Facebook pages for a profile
|
|
713
|
+
*
|
|
714
|
+
* @param {string} [profile] - Profile username
|
|
715
|
+
* @returns {Promise<Object>} List of Facebook pages
|
|
716
|
+
*/
|
|
717
|
+
async getFacebookPages(profile) {
|
|
718
|
+
const params = profile ? { profile } : {};
|
|
719
|
+
return this._request('/uploadposts/facebook/pages', 'GET', params);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/**
|
|
723
|
+
* Get LinkedIn pages for a profile
|
|
724
|
+
*
|
|
725
|
+
* @param {string} [profile] - Profile username
|
|
726
|
+
* @returns {Promise<Object>} List of LinkedIn pages
|
|
727
|
+
*/
|
|
728
|
+
async getLinkedinPages(profile) {
|
|
729
|
+
const params = profile ? { profile } : {};
|
|
730
|
+
return this._request('/uploadposts/linkedin/pages', 'GET', params);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/**
|
|
734
|
+
* Get Pinterest boards for a profile
|
|
735
|
+
*
|
|
736
|
+
* @param {string} [profile] - Profile username
|
|
737
|
+
* @returns {Promise<Object>} List of Pinterest boards
|
|
738
|
+
*/
|
|
739
|
+
async getPinterestBoards(profile) {
|
|
740
|
+
const params = profile ? { profile } : {};
|
|
741
|
+
return this._request('/uploadposts/pinterest/boards', 'GET', params);
|
|
59
742
|
}
|
|
60
743
|
}
|
|
744
|
+
|
|
745
|
+
// Default export for CommonJS compatibility
|
|
746
|
+
export default UploadPost;
|