Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(page): adds requests to publish stories to page #315

Merged
merged 1 commit into from
Jan 24, 2024
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
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ This package is made by independent contributors and is in no way officially rel

You can find what changed in each version by checking the [Changelog](changelog/changelog.md).

## New since 5.0
## New since 6.1

You can now use this lib to publish reels to your page! Check out the [Publishing media](#publishing-media) section.
You can now use this lib to publish stories to your page! Check out the [Publishing media](#publishing-media) section.

## Installation

Expand Down Expand Up @@ -94,9 +94,11 @@ Publishing Media through the Instagram Graph API, and conversely through this li

1. Create an IG Container object. The request will return the container id.
- For photos use `PostPagePhotoMediaRequest`.
- For videos use `PostPageVideoMediaRequest`.
- ~~For videos use `PostPageVideoMediaRequest`.~~ Instagram has removed the ability to publish normal/legacy videos through their API. Videos are now always reels.
- For reels use `PostPageReelMediaRequest`.
- For carousels check the [Publishing Carousels section below](#publishing-carousels).
- For Story videos use `PostPageStoryPhotoMediaRequest`
- For Story videos use `PostPageStoryVideoMediaRequest`
2. Wait for the IG Container status to move to `FINISHED` (check the status through the `GetContainerRequest`).
3. Publish the IG Container (through the `PostPublishMediaRequest`).

Expand Down Expand Up @@ -222,4 +224,4 @@ request.execute().then((response: GetAuthorizedFacebookPagesResponse) => {

## Release Process

Releases of this lib should be very incremental. When a new resource is supported a release will be issued soon after without waiting to pile up new features to do big releases.
This project follows [Semantic Release](https://github.com/semantic-release/) with a publish on every commit to `master`.
32 changes: 32 additions & 0 deletions src/it/page/PublishMediaRequests.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,38 @@ describe('PublishMedia', () => {
expect(response.getMediaType()).toEqual(MediaTypeInResponses.VIDEO);
expect(response.getMediaProductType()).toEqual(MediaProductType.REEL);
});

it('Publishes story image media', async () => {
const media = getRandomPhoto();
const postStoryRequest = getClient().newPostPageStoriesPhotoMediaRequest(media.url);

const containerId = await createContainerAndWaitToBeReady(postStoryRequest);

const mediaId = await publishMedia(containerId);
const getMediaRequest = getClient().newGetMediaInfoRequest(mediaId);
const response = await getMediaRequest.execute();

expect(response.getId()).toEqual(mediaId);
expect(response.getOwnerId()).toEqual(getPageId());
expect(response.getMediaType()).toEqual(MediaTypeInResponses.IMAGE);
expect(response.getMediaProductType()).toEqual(MediaProductType.STORY);
});

it('Publishes story video media', async () => {
const media = getRandomVideo();
const postStoryRequest = getClient().newPostPageStoriesVideoMediaRequest(media.url);

const containerId = await createContainerAndWaitToBeReady(postStoryRequest);

const mediaId = await publishMedia(containerId);
const getMediaRequest = getClient().newGetMediaInfoRequest(mediaId);
const response = await getMediaRequest.execute();

expect(response.getId()).toEqual(mediaId);
expect(response.getOwnerId()).toEqual(getPageId());
expect(response.getMediaType()).toEqual(MediaTypeInResponses.VIDEO);
expect(response.getMediaProductType()).toEqual(MediaProductType.STORY);
});
});

function waitForContainerToBeReady(containerId: string): Promise<boolean> {
Expand Down
28 changes: 28 additions & 0 deletions src/main/Client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ import { GetPageStoriesRequest } from './requests/page/stories/GetPageStoriesReq
import { GetTagsRequest } from './requests/page/tags/GetTagsRequest';
import { UserTag } from './requests/Params';
import { PostPageReelMediaRequest } from './requests/page/media/PostPageReelMediaRequest';
import { PostPageStoriesPhotoMediaRequest } from './requests/page/media/PostPageStoriesPhotoMediaRequest';
import { PostPageStoriesVideoMediaRequest } from './requests/page/media/PostPageStoriesVideoMediaRequest';

/**
* A client that creating requests.
Expand Down Expand Up @@ -456,6 +458,32 @@ export class Client {
).withApiVersion(this.apiVersion);
}

/**
* Build a new {@link PostPageStoriesPhotoMediaRequest}.
*
* @param imageUrl the image URL.
*
* @returns a new {@link PostPageStoriesPhotoMediaRequest}.
*/
public newPostPageStoriesPhotoMediaRequest(imageUrl: string): PostPageStoriesPhotoMediaRequest {
return new PostPageStoriesPhotoMediaRequest(this.accessToken, this.pageId, imageUrl).withApiVersion(
this.apiVersion
);
}

/**
* Build a new {@link PostPageStoriesVideoMediaRequest}.
*
* @param videoUrl the video URL.
*
* @returns a new {@link PostPageStoriesVideoMediaRequest}.
*/
public newPostPageStoriesVideoMediaRequest(videoUrl: string): PostPageStoriesVideoMediaRequest {
return new PostPageStoriesVideoMediaRequest(this.accessToken, this.pageId, videoUrl).withApiVersion(
this.apiVersion
);
}

/**
* Builds a new {@link PostPublishMediaRequest}.
*
Expand Down
32 changes: 3 additions & 29 deletions src/main/requests/page/media/AbstractPostPageMediaRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,41 +20,13 @@ export abstract class AbstractPostPageMediaRequest extends AbstractRequest<Creat
*
* @param accessToken the access token.
* @param pageId the page id.
* @param caption the caption.
* @param locationId the location id.
*/
protected constructor(accessToken: string, pageId: string, caption?: string, locationId?: string) {
protected constructor(accessToken: string, pageId: string) {
super(accessToken);
this.pageId = pageId;
this.params.caption = caption;
this.params.location_id = locationId;
this.params.media_type = this.mediaType();
}

/**
* Sets the caption in the request.
*
* @param caption the caption.
*
* @returns this object, for chained invocation.
*/
public withCaption(caption: string): this {
this.params.caption = caption;
return this;
}

/**
* Sets the location id in the request.
*
* @param locationId the location id.
*
* @returns this object, for chained invocation.
*/
public withLocationId(locationId: string): this {
this.params.location_id = locationId;
return this;
}

/**
* @inheritdoc
*/
Expand Down Expand Up @@ -96,4 +68,6 @@ export enum MediaType {
CAROUSEL = 'CAROUSEL',

REEL = 'REELS',

STORIES = 'STORIES',
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { AbstractPostPageMediaRequest, MediaType } from './AbstractPostPageMediaRequest';

/**
* An abstract request that creates a new Media container for media that goes to stories.
*
* @author Tiago Grosso <tiagogrosso99@gmail.com>
*/
export abstract class AbstractPostPageStoriesMediaRequest extends AbstractPostPageMediaRequest {
/**
* The constructor
*
* @param accessToken the access token.
* @param pageId the page id.
* @param caption the caption.
* @param locationId the location id.
*/
protected constructor(accessToken: string, pageId: string) {
super(accessToken, pageId);
}

/**
* Gets the media type of the object to create.
*
* @returns the media type.
*/
protected mediaType(): MediaType | undefined {
return MediaType.STORIES;
}
}
54 changes: 54 additions & 0 deletions src/main/requests/page/media/AbstractPostTimelineMediaRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { AbstractPostPageMediaRequest, MediaType } from './AbstractPostPageMediaRequest';

/**
* An abstract request that creates a new Media container for media that goes to the timeline.
*
* @author Tiago Grosso <tiagogrosso99@gmail.com>
* @since 3.0.0
*/
export abstract class AbstractPostPageTimelineMediaRequest extends AbstractPostPageMediaRequest {
/**
* The constructor
*
* @param accessToken the access token.
* @param pageId the page id.
* @param caption the caption.
* @param locationId the location id.
*/
protected constructor(accessToken: string, pageId: string, caption?: string, locationId?: string) {
super(accessToken, pageId);
this.params.caption = caption;
this.params.location_id = locationId;
}

/**
* Sets the caption in the request.
*
* @param caption the caption.
*
* @returns this object, for chained invocation.
*/
public withCaption(caption: string): this {
this.params.caption = caption;
return this;
}

/**
* Sets the location id in the request.
*
* @param locationId the location id.
*
* @returns this object, for chained invocation.
*/
public withLocationId(locationId: string): this {
this.params.location_id = locationId;
return this;
}

/**
* Gets the media type of the object to create.
*
* @returns the media type.
*/
protected abstract mediaType(): MediaType | undefined;
}
5 changes: 3 additions & 2 deletions src/main/requests/page/media/PostPageCarouselMediaRequest.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { AbstractPostPageMediaRequest, MediaType } from './AbstractPostPageMediaRequest';
import { MediaType } from './AbstractPostPageMediaRequest';
import { AbstractPostPageTimelineMediaRequest } from './AbstractPostTimelineMediaRequest';

/**
* A request that creates a new Carousel Media container.
*
* @author Tiago Grosso <tiagogrosso99@gmail.com>
* @since 3.0.0
*/
export class PostPageCarouselMediaRequest extends AbstractPostPageMediaRequest {
export class PostPageCarouselMediaRequest extends AbstractPostPageTimelineMediaRequest {
/**
* The constructor
*
Expand Down
5 changes: 3 additions & 2 deletions src/main/requests/page/media/PostPagePhotoMediaRequest.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { UserTag } from '../../Params';
import { AbstractPostPageMediaRequest, MediaType } from './AbstractPostPageMediaRequest';
import { MediaType } from './AbstractPostPageMediaRequest';
import { AbstractPostPageTimelineMediaRequest } from './AbstractPostTimelineMediaRequest';

/**
* A request that creates a new Photo Media container.
*
* @author Tiago Grosso <tiagogrosso99@gmail.com>
* @since 1.1.0
*/
export class PostPagePhotoMediaRequest extends AbstractPostPageMediaRequest {
export class PostPagePhotoMediaRequest extends AbstractPostPageTimelineMediaRequest {
/**
* The constructor
*
Expand Down
5 changes: 3 additions & 2 deletions src/main/requests/page/media/PostPageReelMediaRequest.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { AbstractPostPageMediaRequest, MediaType } from './AbstractPostPageMediaRequest';
import { MediaType } from './AbstractPostPageMediaRequest';
import { AbstractPostPageTimelineMediaRequest } from './AbstractPostTimelineMediaRequest';

/**
* * A request that creates a new Reels Media container.
* *
* * @author Tiago Grosso <tiagogrosso99@gmail.com>
* * @since 5.0.0
* */
export class PostPageReelMediaRequest extends AbstractPostPageMediaRequest {
export class PostPageReelMediaRequest extends AbstractPostPageTimelineMediaRequest {
/**
* The constructor
*
Expand Down
13 changes: 13 additions & 0 deletions src/main/requests/page/media/PostPageStoriesPhotoMediaRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { AbstractPostPageStoriesMediaRequest } from './AbstractPostPageStoriesMediaRequest';

/**
* A request that creates a new photo media container for stories.
*
* @author Tiago Grosso <tiagogrosso99@gmail.com>
*/
export class PostPageStoriesPhotoMediaRequest extends AbstractPostPageStoriesMediaRequest {
constructor(accessToken: string, pageId: string, imageUrl: string) {
super(accessToken, pageId);
this.params.image_url = imageUrl;
}
}
13 changes: 13 additions & 0 deletions src/main/requests/page/media/PostPageStoriesVideoMediaRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { AbstractPostPageStoriesMediaRequest } from './AbstractPostPageStoriesMediaRequest';

/**
* A request that creates a new video media container for stories.
*
* @author Tiago Grosso <tiagogrosso99@gmail.com>
*/
export class PostPageStoriesVideoMediaRequest extends AbstractPostPageStoriesMediaRequest {
constructor(accessToken: string, pageId: string, videoUrl: string) {
super(accessToken, pageId);
this.params.video_url = videoUrl;
}
}
36 changes: 36 additions & 0 deletions src/test/Client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ import { GetPageMediaRequest } from '../main/requests/page/media/GetPageMediaReq
import { PostPageCarouselMediaRequest } from '../main/requests/page/media/PostPageCarouselMediaRequest';
import { PostPagePhotoMediaRequest } from '../main/requests/page/media/PostPagePhotoMediaRequest';
import { PostPageReelMediaRequest } from '../main/requests/page/media/PostPageReelMediaRequest';
import { PostPageStoriesPhotoMediaRequest } from '../main/requests/page/media/PostPageStoriesPhotoMediaRequest';
import { PostPageStoriesVideoMediaRequest } from '../main/requests/page/media/PostPageStoriesVideoMediaRequest';
import { PostPublishMediaRequest } from '../main/requests/page/media_publish/PostPublishMediaRequest';
import { GetPageRecentlySearchedHashtagsRequest } from '../main/requests/page/recently_searched_hashtags/GetPageRecentlySearchedHashtagsRequest';
import { GetPageStoriesRequest } from '../main/requests/page/stories/GetPageStoriesRequest';
Expand Down Expand Up @@ -568,6 +570,40 @@ describe('Client', () => {
);
});

it('Builds a PostPageStoriesPhotoMediaRequest', () => {
expect(client.newPostPageStoriesPhotoMediaRequest(TestConstants.MEDIA_URL)).toEqual(
new PostPageStoriesPhotoMediaRequest(
TestConstants.ACCESS_TOKEN,
TestConstants.PAGE_ID,
TestConstants.MEDIA_URL
)
);
expect(clientExplicitVersion.newPostPageStoriesPhotoMediaRequest(TestConstants.MEDIA_URL)).toEqual(
new PostPageStoriesPhotoMediaRequest(
TestConstants.ACCESS_TOKEN,
TestConstants.PAGE_ID,
TestConstants.MEDIA_URL
).withApiVersion(TestConstants.API_VERSION)
);
});

it('Builds a PostPageStoriesVideoMediaRequest', () => {
expect(client.newPostPageStoriesVideoMediaRequest(TestConstants.MEDIA_URL)).toEqual(
new PostPageStoriesVideoMediaRequest(
TestConstants.ACCESS_TOKEN,
TestConstants.PAGE_ID,
TestConstants.MEDIA_URL
)
);
expect(clientExplicitVersion.newPostPageStoriesVideoMediaRequest(TestConstants.MEDIA_URL)).toEqual(
new PostPageStoriesVideoMediaRequest(
TestConstants.ACCESS_TOKEN,
TestConstants.PAGE_ID,
TestConstants.MEDIA_URL
).withApiVersion(TestConstants.API_VERSION)
);
});

it('Builds a GetPageStoriesRequest', () => {
expect(client.newGetPageStoriesRequest()).toEqual(
new GetPageStoriesRequest(TestConstants.ACCESS_TOKEN, TestConstants.PAGE_ID)
Expand Down
Loading