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
18 changes: 12 additions & 6 deletions .env.dist
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,23 @@ FAIRPOST_FEED_PATH=feed
FAIRPOST_FEED_INTERVAL=6 #days

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

# AYRSHARE
FAIRPOST_AYRSHARE_API_KEY=xxxx

FAIRPOST_REDDIT_SUBREDDIT=generative
# ayrshare
# FAIRPOST_AYRSHARE_API_KEY=xxxx
# FAIRPOST_AYRSHARE_SUBREDDIT=xxxx


# 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
# FAIRPOST_FACEBOOK_PUBLISH_POSTS=true

# instagram
# FAIRPOST_INSTAGRAM_APP_ID=xxx
# FAIRPOST_INSTAGRAM_APP_SECRET=xxx
# FAIRPOST_INSTAGRAM_USER_ID=xxx
# FAIRPOST_INSTAGRAM_PAGE_ID=xxx
# FAIRPOST_INSTAGRAM_PAGE_ACCESS_TOKEN=xxx
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,11 @@ fairpost.js [command] [arguments] --report=json
To add support for a new platform, add a class to `src/platforms`
extending `src/classes/Platform`. You want to override at least the
method `preparePost(folder: Folder)` and
`publishPost(post: Post, dryrun:boolean = false)`.
`publishPost(post: Post, dryrun:boolean = false)`.

Then add a platformId for your platform to `src/platforms/index.js` and
enable your platform in your `.env`.




36 changes: 36 additions & 0 deletions docs/Ayrshare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Platform: Ayrshare

Ayrshare (https://www.ayrshare.com/) is a platform / service
that does what FairPost does. I don't know why you would
use both.

But if you have an Ayrshare account, you can enable
it here and enable the platforms that you have connected
to Ayrshare, to publish to those platforms via Ayrshare.

Ayrshare posts will not be scheduled on Ayrshare;
they will be published instantly. Use Fairpost for
scheduling posts.

The Ayrshare platforms supported by FairPost are
- asfacebook
- asinstagram
- aslinkedin
- asreddit
- astiktok
- asyoutube

## Setting up the Ayrshare platform

- get an account at Ayrshare
- get your Api key at https://app.ayrshare.com/api
- store this key as FAIRPOST_AYRSHARE_API_KEY

### Enable and test the facebook platform
- Add one or more of the 'as*' platforms to `FAIRPOST_FEED_PLATFORMS` in `.env`
- call `./fairpost.js test-platforms`

# Limitations

Ayrshare applies different limitations to each platform.
For details, check the Ayrshare documentation.
2 changes: 1 addition & 1 deletion docs/Facebook.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ This token should last forever. It involves get a long-lived user token and then

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

# Limitations

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

The `instagram` platform manage a instagram account
that is connected to a facebook **page**
using the plain facebook graph api - no extensions installed.

It publishes **photo**, **video**, or
**carousels** posts on that instagram account.

It uses the related facebook account to
upload temporary files, because the instagram
api requires files in posts to have an url.

## Setting up the Instagram platform


### Create a new App in your facebook account
- create an Instagram business account
- connect a Facebook page to your Instagram business account
- go to https://developers.facebook.com/
- create an app that can manage pages
- include the "Instagram Graph API" product as a new product
- under 'settings', find your app ID
- save this as `FAIRPOST_INSTAGRAM_APP_ID` in your .env
- under 'settings', find your app secret
- save this as `FAIRPOST_INSTAGRAM_APP_SECRET` in your .env


### Find your instagram user id
- go to https://www.instagram.com/web/search/topsearch/?query={username}
- find your fbid_v2
- note the user id
- save this as `FAIRPOST_INSTAGRAM_USER_ID` in your .env

### Get a (short lived) Page Access Token for the page related to the instagram account 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
- instagram_basic
- instagram_content_publish
- request a (short lived) page access token
- save this as `FAIRPOST_INSTAGRAM_PAGE_ACCESS_TOKEN` in your .env

### Get a (long lived) Page Access Token for the page related to the instagram account 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
- instagram_basic
- instagram_content_publish
- 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_INSTAGRAM_PAGE_ACCESS_TOKEN` in your .env

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

# Limitations

## Images

- Carousels are limited to 10 images, videos, or a mix of the two.
- Carousel images are all cropped based on the first image in the carousel, with the default being a 1:1 aspect ratio.


### Supported Formats
Instagram supports the following formats:
- JPEG

### File Size

xxx

# Random documentation

https://developers.facebook.com/docs/instagram-api/guides/content-publishing

- only jpeg
- rate limit w endpoint
- upload media first

POST /{ig-user-id}/media — upload media and create media containers.
POST /{ig-user-id}/media_publish — publish uploaded media using their media containers.
GET /{ig-container-id}?fields=status_code — check media container publishing eligibility and status.
GET /{ig-user-id}/content_publishing_limit — check app user's current publishing rate limit usage.

~~~
GET /{ig-container-id}?fields=status_code endpoint. This endpoint will return one of the following:

EXPIRED — The container was not published within 24 hours and has expired.
ERROR — The container failed to complete the publishing process.
FINISHED — The container and its media object are ready to be published.
IN_PROGRESS — The container is still in the publishing process.
PUBLISHED — The container's media object has been published.
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "ayrshare-feed",
"version": "1.0.0",
"description": "Feeds data to ayrshare based on folders in feed dir; marks folder that are done.",
"name": "fairpost",
"version": "1.1.0",
"description": "Feeds data to social media platforms based on folders in a dir",
"main": "index.js",
"scripts": {
"build": "tsc",
Expand Down
7 changes: 5 additions & 2 deletions src/Feed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,11 @@ export default class Feed {
getPlatforms(platformIds?: PlatformId[]): Platform[] {
Logger.trace("Feed", "getPlatforms", platformIds);
return (
platformIds?.map((platformId) => this.platforms[platformId]) ??
Object.values(this.platforms)
platformIds
?.map((platformId) => this.platforms[platformId])
.filter(function (p) {
return p !== undefined;
}) ?? Object.values(this.platforms)
);
}

Expand Down
5 changes: 4 additions & 1 deletion src/Platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,10 @@ export default class Platform {
async publishPost(post: Post, dryrun: boolean = false): Promise<boolean> {
Logger.trace("Platform", "publishPost", post.id, dryrun);
post.results.push({
error: "publishing not implemented for " + this.id,
date: new Date(),
success: false,
error: new Error("publishing not implemented for " + this.id),
response: {},
});
post.published = undefined;
post.status = PostStatus.FAILED;
Expand Down
11 changes: 10 additions & 1 deletion src/Post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export default class Post {
status: PostStatus = PostStatus.UNKNOWN;
scheduled?: Date;
published?: Date;
results: object[] = [];
results: PostResult[] = [];
title: string = "";
body?: string;
tags?: string;
Expand All @@ -21,6 +21,7 @@ export default class Post {
video: string[];
other: string[];
};
link?: string;

constructor(folder: Folder, platform: Platform, data?: object) {
this.folder = folder;
Expand Down Expand Up @@ -70,6 +71,14 @@ export default class Post {
}
}

export interface PostResult {
date: Date;
dryrun?: boolean;
error?: Error;
success: boolean;
response: object;
}

export enum PostStatus {
UNKNOWN = "unknown",
UNSCHEDULED = "unscheduled",
Expand Down
2 changes: 1 addition & 1 deletion src/platforms/AsReddit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default class AsReddit extends Ayrshare {

constructor() {
super();
this.SUBREDDIT = process.env.FAIRPOST_REDDIT_SUBREDDIT;
this.SUBREDDIT = process.env.FAIRPOST_AYRSHARE_SUBREDDIT;
}

async preparePost(folder: Folder): Promise<Post | undefined> {
Expand Down
Loading