Skip to content

Commit

Permalink
Use publish service
Browse files Browse the repository at this point in the history
  • Loading branch information
omouren committed Feb 5, 2021
1 parent 671f8da commit 2fedb9a
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 42 deletions.
13 changes: 6 additions & 7 deletions examples/live-replay-to-igtv.example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,15 @@ async function login() {
.toBuffer();

// Upload the thumbnail with a broadcast id for a replay and get uploadId
let upload = await ig.upload.photo({file, broadcastId: broadcast_id});

let igtv = await ig.media.configureToIgtv({
upload_id: upload.upload_id,
let igtv = await ig.publish.liveIgtv({
file,
broadcastId: broadcast_id,
title: 'A title',
caption: 'A description',
igtv_share_preview_to_feed: '1',
}, 2000)
igtv_share_preview_to_feed: '1'
});

console.log(`Live posted to IGTV : ${igtv.upload_id}`));
console.log(`Live posted to IGTV : ${igtv.upload_id}`);
// now you're basically done
})();

Expand Down
9 changes: 9 additions & 0 deletions src/errors/ig-upload-live-igtv-error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { IgResponseError } from './ig-response.error';
import { IgResponse } from '../types';
import { UploadRepositoryVideoResponseRootObject } from '../responses';

export class IgUploadLiveIgtvError extends IgResponseError {
constructor(response: IgResponse<UploadRepositoryVideoResponseRootObject>) {
super(response);
}
}
1 change: 1 addition & 0 deletions src/errors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ export * from './ig-challenge-wrong-code.error';
export * from './ig-exact-user-not-found-error';
export * from './ig-user-id-not-found.error';
export * from './ig-upload-video-error';
export * from './ig-upload-live-igtv-error';
export * from './ig-user-has-logged-out.error';
export * from './ig-configure-video-error';
51 changes: 18 additions & 33 deletions src/repositories/media.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import { MediaRepositoryConfigureResponseRootObject } from '../responses';
import Chance = require('chance');
import { MediaRepositoryCheckOffensiveCommentResponseRootObject } from '../responses';
import { StoryMusicQuestionResponse, StoryTextQuestionResponse } from '../types/story-response.options';
import { IgResponseError } from "../errors";

export class MediaRepository extends Repository {
public async info(mediaId: string): Promise<MediaInfoResponseRootObject> {
Expand Down Expand Up @@ -577,7 +576,7 @@ export class MediaRepository extends Repository {
return body;
}

public async configureToIgtv(options: MediaConfigureToIgtvOptions, retryDelay: number = 1000) {
public async configureToIgtv(options: MediaConfigureToIgtvOptions) {
const form: MediaConfigureToIgtvOptions = defaultsDeep(options, {
caption: '',
date_time_original: new Date().toISOString().replace(/[-:]/g, ''),
Expand All @@ -600,38 +599,24 @@ export class MediaRepository extends Repository {
const retryContext = options.retryContext;
delete form.retryContext;

let body = null;
let response = null;
while (!body) {
try {
response = await this.client.request.send({
url: '/api/v1/media/configure_to_igtv/',
method: 'POST',
qs: {
video: '1',
},
headers: {
is_igtv_video: '1',
retry_context: JSON.stringify(retryContext),
},
form: this.client.request.sign({
...form,
_csrftoken: this.client.state.cookieCsrfToken,
_uid: this.client.state.cookieUserId,
_uuid: this.client.state.uuid,
}),
});
const { body } = await this.client.request.send({
url: '/api/v1/media/configure_to_igtv/',
method: 'POST',
qs: {
video: '1',
},
headers: {
is_igtv_video: '1',
retry_context: JSON.stringify(retryContext),
},
form: this.client.request.sign({
...form,
_csrftoken: this.client.state.cookieCsrfToken,
_uid: this.client.state.cookieUserId,
_uuid: this.client.state.uuid,
}),
});

body = response.body;
} catch (e) {
// Endpoint can return an error "202 Accepted; Transcode not finished yet" if Instagram has not finished to process the upload, retry after a delay
if (!(e instanceof IgResponseError && e.response.statusCode === 202)) {
throw e;
} else {
await new Promise(resolve => setTimeout(resolve, retryDelay));
}
}
}
return body;
}

Expand Down
52 changes: 51 additions & 1 deletion src/services/publish.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ import {
UploadVideoOptions,
} from '../types';
import { PostingLocation, PostingStoryOptions } from '../types/posting.options';
import { IgConfigureVideoError, IgResponseError, IgUploadVideoError } from '../errors';
import { IgConfigureVideoError, IgResponseError, IgUploadLiveIgtvError, IgUploadVideoError } from '../errors';
import { StatusResponse, UploadRepositoryVideoResponseRootObject } from '../responses';
import { PostingIgtvOptions } from '../types/posting.igtv.options';
import { PostingLiveIgtvOptions } from "../types/posting.live-igtv.options";
import sizeOf = require('image-size');
import Bluebird = require('bluebird');
import Chance = require('chance');
Expand Down Expand Up @@ -52,6 +53,22 @@ export class PublishService extends Repository {
};
}

/**
* @param transcodeDelayInMs The delay for instagram to transcode the video
*/
public static catchLiveIgtvTranscodeError(transcodeDelayInMs: number) {
return error => {
if (error.response.statusCode === 202) {
PublishService.publishDebug(
`Received trancode error: ${JSON.stringify(error.response.body)}, waiting ${transcodeDelayInMs}ms`,
);
return Bluebird.delay(transcodeDelayInMs);
} else {
throw new IgUploadLiveIgtvError(error.response as IgResponse<UploadRepositoryVideoResponseRootObject>);
}
};
}

/**
* Gets duration in ms, width and height info for a video in the mp4 container
* @param buffer Buffer, containing the video-file
Expand Down Expand Up @@ -453,6 +470,39 @@ export class PublishService extends Repository {
}
}

public async liveIgtv(options: PostingLiveIgtvOptions) {
const uploadedPhoto = await this.client.upload.photo({
file: options.file,
broadcastId: options.broadcastId,
});

await Bluebird.try(() =>
this.client.media.uploadFinish({
upload_id: uploadedPhoto.upload_id,
source_type: '4',
}),
).catch(IgResponseError, PublishService.catchLiveIgtvTranscodeError(options.transcodeDelay || 5000));

const configureOptions: MediaConfigureToIgtvOptions = {
upload_id: uploadedPhoto.upload_id,
title: options.title,
caption: options.caption,
igtv_share_preview_to_feed: options.igtv_share_preview_to_feed,
length: 0
};

for (let i = 0; i < 6; i++) {
try {
return await this.client.media.configureToIgtv(configureOptions);
} catch (e) {
if (i >= 5 || e.response.statusCode >= 400) {
throw new IgConfigureVideoError(e.response, configureOptions);
}
await Bluebird.delay((i + 1) * 2 * 1000);
}
}
}

private async regularVideo(options: UploadVideoOptions) {
options = defaults(options, {
uploadId: Date.now(),
Expand Down
2 changes: 1 addition & 1 deletion src/types/media.configure-to-igtv.options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export interface MediaConfigureToIgtvOptions {
upload_id: string;
title: string;
length: number;
extra: { source_width: number; source_height: number };
extra?: { source_width: number; source_height: number };
caption?: string;
// will be converted to a json-string
feed_preview_crop?:
Expand Down
8 changes: 8 additions & 0 deletions src/types/posting.live-igtv.options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export interface PostingLiveIgtvOptions {
file: Buffer;
title: string;
caption?: string;
broadcastId: string;
igtv_share_preview_to_feed?: '1' | '0';
transcodeDelay?: number
}

0 comments on commit 2fedb9a

Please sign in to comment.