Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions .env.dist
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
FAIRPOST_FEED_PATH=feed
FAIRPOST_FEED_INTERVAL=6 #days
FAIRPOST_FEED_PLATFORMS=asyoutube,asfacebook,aslinkedin,asinstagram,astiktok,asreddit,astwitter

FAIRPOST_FEED_PLATFORMS=
# FAIRPOST_FEED_PLATFORMS=facebook,asyoutube,asfacebook,aslinkedin,asinstagram,astiktok,asreddit,astwitter

# AYRSHARE
FAIRPOST_AYRSHARE_API_KEY=xxxx

FAIRPOST_REDDIT_SUBREDDIT=generative
FAIRPOST_REDDIT_SUBREDDIT=generative


# facebook
# FAIRPOST_FACEBOOK_APP_ID=xxx
# FAIRPOST_FACEBOOK_APP_SECRET=xxx
# FAIRPOST_FACEBOOK_PAGE_ID=xxx
# FAIRPOST_FACEBOOK_PAGE_ACCESS_TOKEN=xxx
# FAIRPOST_FACEBOOK_PUBLISH_POSTS=true
42 changes: 30 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,32 +71,50 @@ fairpost.js publish-due-posts
This will publish any scheduled posts that are past their due date.


## Arguments
## Other commands

Each of these commands (and others) accept `--arguments`
Other commands accept `--arguments`
that may help you, for example, to immediately publish
a certain post to a certain platform if you like.

But more commonly, you would call this script
every day and just add posts to the feed folder as
time goes by.
The script will then automatically prepare these posts,
every day.
The script will then automatically prepare the posts,
schedule the next post using a certain interval,
publish any post when it is due, and schedule the
next post automatically.
next post automatically. All you have to do is
add folders with content.



## Cli

```
fairpost.js help
fairpost.js get-feed
# basic commands:
# basic commands:
fairpost.js help
fairpost.js get-feed [--config=xxx]
fairpost.js test-platform --platform=xxx
fairpost.js test-platforms [--platforms=xxx,xxx]
fairpost.js get-platform --platform=xxx
fairpost.js get-platforms [--platforms=xxx,xxx]
fairpost.js get-folder --folder=xxx
fairpost.js get-folders [--folders=xxx,xxx]
fairpost.js prepare-posts [--platforms=xxx,xxx] [--folders=xxx,xxx]
fairpost.js get-posts [--status=xxx] [--platforms=xxx,xxx] [--folders=xxx,xxx]
fairpost.js schedule-next-post [--date=xxxx-xx-xx] [--platforms=xxx,xxx] [--folders=xxx,xxx]
fairpost.js publish-due-posts [--platforms=xxx,xxx] [--folders=xxx,xxx] [--dry-run]
fairpost.js get-post --folder=xxx --platform=xxx
fairpost.js get-posts [--status=xxx] [--folders=xxx,xxx] [--platforms=xxx,xxx]
fairpost.js prepare-post --folder=xxx --platform=xxx
fairpost.js prepare-posts [--folders=xxx,xxx] [--platforms=xxx,xxx]
fairpost.js schedule-post --folder=xxx --platform=xxx --date=xxxx-xx-xx
fairpost.js schedule-posts [--folders=xxx,xxx] [--platforms=xxx,xxx] --date=xxxx-xx-xx
fairpost.js publish-post --folders=xxx --platforms=xxx [--dry-run]
fairpost.js publish-posts [--folders=xxx,xxx] [--platforms=xxx,xxx]

# feed planning:
fairpost.js schedule-next-post [--date=xxxx-xx-xx] [--folders=xxx,xxx] [--platforms=xxx,xxx]
fairpost.js publish-due-posts [--folders=xxx,xxx] [--platforms=xxx,xxx] [--dry-run]

# platform tools:
fairpost.js facebook-get-page-token --app-user-id=xxx --user-token=xxx
```

### Common arguments
Expand Down
99 changes: 99 additions & 0 deletions docs/Facebook.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Platform: Facebook

The `facebook` platform manage a facebook **page* (not your feed)
using the plain graph api - no extensions installed.

## Setting up the Facebook platform


### Create a new App in your facebook account
- go to https://developers.facebook.com/
- create an app that can manage pages
- for instagram, you'll need to attach a business account (...) that is connected to a facebook page
- under 'settings', find your app ID
- save this as `FAIRPOST_FACEBOOK_APP_ID` in your .env
- under 'settings', find your app secret
- save this as `FAIRPOST_FACEBOOK_APP_SECRET` in your .env

### Find the page id of the page you want the app to manage
- go to https://business.facebook.com/
- find your page (currently under 'settings > business assets')
- note the page id
- save this as `FAIRPOST_FACEBOOK_PAGE_ID` in your .env

### Get a (short lived) Page Access Token for the page you want the app to manage

This is good for testing, but you'll have to refresh this token often.

- go to https://developers.facebook.com/tools/explorer/
- select your app
- add permissions
- pages_manage_engagement
- pages_manage_posts
- pages_read_engagement
- pages_read_user_engagement
- publish_video
- business_management
- request a (short lived) page access token
- save this as `FAIRPOST_FACEBOOK_PAGE_ACCESS_TOKEN` in your .env

### Get a (long lived) Page Access Token for the page you want the app to manage

This token should last forever. It involves get a long-lived user token and then requesting the 'accounts' for your 'app scoped user id'; but this app provides a tool to help you do that:

- go to https://developers.facebook.com/tools/explorer/
- select your app
- add permissions
- pages_manage_engagement
- pages_manage_posts
- pages_read_engagement
- pages_read_user_engagement
- publish_video
- business_management
- request a (short lived) user access token
- click 'submit' to submit the default `?me` query
- remember the `id` in the response as your id
- call `./fairpost.js facebook-get-page-token
--app-user-id={your id} --user-token={your token}`
- note the token returned
- save this as `FAIRPOST_FACEBOOK_PAGE_ACCESS_TOKEN` in your .env

### Enable and test the facebook platform
- Add 'facebook' to your `FAIRPOST_FEED_PLATFORMS` in `.env`
- call `./fairpost.js test --platforms=facebook`

# Limitations

## Images

From https://developers.facebook.com/docs/graph-api/reference/page/photos/ :

Facebook strips all location metadata before publishing and resizes images to different dimensions to best support rendering in multiple sizes.


### Supported Formats
Facebook supports the following formats:
- JPEG
- BMP
- PNG
- GIF
- TIFF

### File Size

Files must be 4MB or smaller in size.
For PNG files, try keep the file size below 1 MB. PNG files larger than 1 MB may appear pixelated after upload.

# Random documentation

https://dev.to/xaypanya/how-to-connect-your-nodejs-server-to-facebook-page-api-1hol
https://developers.facebook.com/docs/pages/getting-started
https://developers.facebook.com/docs/pages-api/posts
https://developers.facebook.com/docs/graph-api/reference/page/photos/
https://developers.facebook.com/docs/video-api/guides/publishing

large uploads:
https://developers.facebook.com/docs/graph-api/guides/upload/

https://www.npmjs.com/package/formdata-node
https://medium.com/deno-the-complete-reference/sending-form-data-using-fetch-in-node-js-8cedd0b2af85
109 changes: 100 additions & 9 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
Fairpost cli handler
*/

import * as path from 'path';
import Logger from './src/Logger';
import Feed from './src/Feed';
import { PostStatus } from './src/Post';
import { PlatformSlug } from './src/platforms';
import Facebook from './src/platforms/Facebook';

// arguments
const COMMAND = process.argv[2] ?? 'help'
Expand All @@ -16,7 +18,9 @@ const CONFIG = (getOption('config') as string ) ?? '.env';
const DRY_RUN = !!getOption('dry-run') ?? false;
const REPORT = (getOption('report') as string ) ?? 'text';
const PLATFORMS = (getOption('platforms') as string)?.split(',') as PlatformSlug[] ?? undefined;
const PLATFORM = (getOption('platform') as string) as PlatformSlug ?? undefined;
const FOLDERS = (getOption('folders') as string)?.split(',') ?? undefined;
const FOLDER = (getOption('folder') as string) ?? undefined;
const DATE = (getOption('date') as string) ?? undefined;
const STATUS = (getOption('status') as PostStatus) ?? undefined;

Expand All @@ -34,7 +38,7 @@ function getOption(key:string):boolean|string|null {
/* main */
async function main() {

let result: any = '';
let result: any;
let report = '';

const feed = new Feed(CONFIG);
Expand All @@ -47,20 +51,43 @@ async function main() {
result = feed;
report = 'Feed: '+feed.path;
break;
case 'get-platform':
const platform = feed.getPlatform(PLATFORM);
report += 'Platform: '+platform.slug+'\n';
result = platform;
break;
case 'get-platforms':
const platforms = feed.getPlatforms(PLATFORMS);
platforms.forEach(platform => {
report += 'Platform: '+platform.slug+'\n';
});
result = platforms;
break;
case 'test-platform':
result = await feed.testPlatform(PLATFORM);
report = "Result: \n"+ JSON.stringify(result,null,'\t');
break;
case 'test-platforms':
result = await feed.testPlatforms(PLATFORMS);
report = "Result: \n"+ JSON.stringify(result,null,'\t');
break;
case 'get-folder':
const folder = feed.getFolder(FOLDER);
report += 'Folder: '+folder.path+'\n';
result = folder;
break;
case 'get-folders':
const folders = feed.getFolders(FOLDERS);
folders.forEach(folder => {
report += 'Folder: '+folder.path+'\n';
});
result = folders;
break;
case 'get-post':
const post = feed.getPost(FOLDER, PLATFORM);
report += post.report();
result = post;
break;
case 'get-posts':
const allposts = feed.getPosts({
paths:FOLDERS,
Expand All @@ -72,6 +99,11 @@ async function main() {
});
result = allposts;
break;
case 'prepare-post':
const preppost = await feed.preparePost(FOLDER,PLATFORM);
report += preppost.report();
result = preppost;
break;
case 'prepare-posts':
const prepposts = await feed.preparePosts({
paths:FOLDERS,
Expand All @@ -82,6 +114,41 @@ async function main() {
});
result = prepposts;
break;
case 'schedule-post':
const schedpost = feed.schedulePost(
FOLDER,PLATFORM, new Date(DATE),
);
report += schedpost.report();
result = schedpost;
break;
case 'schedule-posts':
const schedposts = feed.schedulePosts({
paths: FOLDERS,
platforms: PLATFORMS
}, new Date(DATE));
schedposts.forEach(post => {
report += post.report();
});
result = schedposts;
break;
case 'publish-post':
const pubpost = await feed.publishPost(FOLDER,PLATFORM, DRY_RUN);
report += pubpost.report();
result = pubpost;
break;

case 'publish-posts':
const pubposts = await feed.publishPosts({
paths:FOLDERS,
platforms:PLATFORMS
}, DRY_RUN);
pubposts.forEach(post => {
report += post.report();
});
result = pubposts;
break;

/* feed planning */
case 'schedule-next-posts':
const nextposts = feed.scheduleNextPosts(DATE ? new Date(DATE): undefined,{
paths:FOLDERS,
Expand All @@ -93,31 +160,55 @@ async function main() {
result = nextposts;
break;
case 'publish-due-posts':
const pubposts = await feed.publishDuePosts({
const dueposts = await feed.publishDuePosts({
paths:FOLDERS,
platforms:PLATFORMS
}, DRY_RUN);
pubposts.forEach(post => {
report += post.report();
});
result = nextposts;
result = dueposts;
break;

/* platform specific tools */
case 'facebook-get-page-token':
const userToken = (getOption('user-token') as string );
const appUserId = (getOption('app-user-id') as string );
const facebook = new Facebook();
result = await facebook.getPageToken(appUserId, userToken);
report = 'Page Token: '+result;
break;

default:
const cmd = process.argv[1];
const cmd = path.basename(process.argv[1]);
result = [
'# basic commands:',
`${cmd} help`,
`${cmd} get-feed [--config=xxx]`,
`${cmd} test-platform --platform=xxx`,
`${cmd} test-platforms [--platforms=xxx,xxx]`,
`${cmd} get-platform --platform=xxx`,
`${cmd} get-platforms [--platforms=xxx,xxx]`,
`${cmd} get-folder --folder=xxx`,
`${cmd} get-folders [--folders=xxx,xxx]`,
`${cmd} prepare-posts [--platforms=xxx,xxx] [--folders=xxx,xxx]`,
`${cmd} get-posts [--status=xxx] [--platforms=xxx,xxx] [--folders=xxx,xxx]`,
`${cmd} schedule-next-post [--date=xxxx-xx-xx] [--platforms=xxx,xxx] [--folders=xxx,xxx]`,
`${cmd} publish-due-posts [--platforms=xxx,xxx] [--folders=xxx,xxx] [--dry-run]`
`${cmd} get-post --folder=xxx --platform=xxx`,
`${cmd} get-posts [--status=xxx] [--folders=xxx,xxx] [--platforms=xxx,xxx] `,
`${cmd} prepare-post --folder=xxx --platform=xxx`,
`${cmd} prepare-posts [--folders=xxx,xxx] [--platforms=xxx,xxx]`,
`${cmd} schedule-post --folder=xxx --platform=xxx --date=xxxx-xx-xx `,
`${cmd} schedule-posts [--folders=xxx,xxx] [--platforms=xxx,xxx] --date=xxxx-xx-xx`,
`${cmd} publish-post --folders=xxx --platforms=xxx [--dry-run]`,
`${cmd} publish-posts [--folders=xxx,xxx] [--platforms=xxx,xxx]`,
'\n# feed planning:',
`${cmd} schedule-next-post [--date=xxxx-xx-xx] [--folders=xxx,xxx] [--platforms=xxx,xxx] `,
`${cmd} publish-due-posts [--folders=xxx,xxx] [--platforms=xxx,xxx] [--dry-run]`,
'\n# platform tools:',
`${cmd} facebook-get-page-token --app-user-id=xxx --user-token=xxx`
];
result.forEach(line => report += '\n'+line);
}
} catch (e) {
console.error(e.getMessage());
console.error(e.message);
}

switch(REPORT) {
Expand Down
Loading