Skip to content
This repository has been archived by the owner on Sep 10, 2021. It is now read-only.

Commit

Permalink
feat: add methods for listing the For You and Following feeds
Browse files Browse the repository at this point in the history
  • Loading branch information
szdc committed Aug 28, 2018
1 parent 00a7b6e commit 4eb88d0
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 5 deletions.
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ const api = new TikTokAPI(params, { signURL });
* [.postComment(postId, text, [tags])](#postcommentpostid-text-tags)
* [.listCategories(params)](#listcategoriesparams)
* [.searchHashtags(params)](#searchhashtagsparams)
* [.listForYouFeed([params])](#listforyoufeed)
* [.listFollowingFeed([params])](#listfollowingfeed)

#### .loginWithEmail(email, password)

Expand Down Expand Up @@ -306,6 +308,38 @@ api.searchHashtags({

See the [search types](src/types/search.d.ts) for the complete request/response objects.

#### .listForYouFeed([params])

Lists posts in the For You feed.

```javascript
api.listForYouFeed()
.then(res => console.log(res.data.aweme_list))
.catch(console.log);

// Outputs:
// [{ author: {...}, aweme_id: '999', desc: 'description', music: {...}, statistics: {...}, video: {...} }, ...]

```

See the [feed types](src/types/feed.d.ts) for the complete request/response objects.

#### .listFollowingFeed([params])

Lists posts in the Following feed.

```javascript
api.listFollowingFeed()
.then(res => console.log(res.data.aweme_list))
.catch(console.log);

// Outputs:
// [{ author: {...}, aweme_id: '999', desc: 'description', music: {...}, statistics: {...}, video: {...} }, ...]

```

See the [feed types](src/types/feed.d.ts) for the complete request/response objects.

## Resources

* [Reverse engineering the musical.ly API](https://medium.com/@szdc/reverse-engineering-the-musical-ly-api-662331008eb3)
Expand Down
15 changes: 15 additions & 0 deletions src/feed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export enum FeedType {
ForYou,
Following,
}

export enum PullType {
/** The feed was loaded by default, e.g. by clicking the tab or loading the app */
Default,

/** The feed was explicitly refreshed by the user, e.g. by swiping down */
Refresh,

/** More posts were requested by the user, e.g. by swiping up */
LoadMore,
}
48 changes: 43 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ import {
ListCategoriesResponse,
ListCommentsRequest,
ListCommentsResponse,
ListFeedRequest,
ListFeedResponse,
ListFollowersRequest,
ListFollowersResponse,
ListFollowingRequest,
ListFollowingResponse,
ListForYouFeedResponse,
ListPostsRequest,
ListPostsResponse,
LoginRequest,
Expand All @@ -36,11 +39,8 @@ import {
UserSearchRequest,
UserSearchResponse,
} from './types';
import {
paramsOrder,
paramsSerializer,
withDefaultListParams,
} from './params';
import { FeedType, PullType } from './feed';
import { paramsOrder, paramsSerializer, withDefaultListParams } from './params';

export default class TikTokAPI {
readonly config: TikTokAPIConfig;
Expand Down Expand Up @@ -284,6 +284,44 @@ export default class TikTokAPI {
params: withDefaultListParams(params),
})

/**
* Lists posts in the For You feed.
*
* max_cursor should always be 0.
*
* @param params
*/
listForYouFeed = (params?: ListFeedRequest) =>
this.request.get<ListForYouFeedResponse | BaseResponseData>('aweme/v1/feed/', {
params: withDefaultListParams(<ListFeedRequest>{
count: 6,
is_cold_start: 1,
max_cursor: 0,
pull_type: PullType.LoadMore,
type: FeedType.ForYou,
...params,
}),
})

/**
* Lists posts in the Following feed.
*
* max_cursor should always be 0.
*
* @param params
*/
listFollowingFeed = (params?: ListFeedRequest) =>
this.request.get<ListFeedResponse | BaseResponseData>('aweme/v1/feed/', {
params: withDefaultListParams(<ListFeedRequest>{
count: 6,
is_cold_start: 1,
max_cursor: 0,
pull_type: PullType.LoadMore,
type: FeedType.Following,
...params,
}),
})

/**
* Transform using JSONBig to store big numbers accurately (e.g. user IDs) as strings.
*
Expand Down
44 changes: 44 additions & 0 deletions src/types/feed.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {
CursorOffsetRequestParams,
CursorOffsetResponseParams,
ListRequestParams,
ListResponseData,
} from './request';
import { Post } from './post';
import { FeedType, PullType } from '../feed';

export interface ListFeedRequest extends ListRequestParams, CursorOffsetRequestParams {
/** The type of feed to load */
type: FeedType;

/** Your device's current volume level on a scale of 0 to 1, e.g. 0.5 */
volume: number;

/** How the feed was requested */
pull_type: PullType;

/** ??? - empty */
req_from?: string;

/** ??? - 0 */
is_cold_start?: 0 | 1;

/** ??? */
gaid?: string;

/** A user agent for your device */
ad_user_agent?: string;
}

export interface ListFeedResponse extends ListResponseData, CursorOffsetResponseParams {
/** A list of posts in the feed */
aweme_list: Post[];
}

export interface ListForYouFeedResponse extends ListFeedResponse {
/** ??? - 1 */
home_model: number;

/** ??? - 1 */
refresh_clear: number;
}
1 change: 1 addition & 0 deletions src/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './api';
export * from './category';
export * from './comment';
export * from './feed';
export * from './follow';
export * from './follower';
export * from './like';
Expand Down
58 changes: 58 additions & 0 deletions test/feed.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import MockAdapter from 'axios-mock-adapter';
import { assert } from 'chai';
import { describe, it } from 'mocha';

import TikTokAPI, { ListFeedResponse, ListForYouFeedResponse } from '../src';
import {
loadTestData,
mockConfig,
mockParams,
} from './util';

describe('#listForYouFeed()', () => {
it('a successful response should match the interface', async () => {
const api = new TikTokAPI(mockParams, mockConfig);
const mock = new MockAdapter(api.request);
mock
.onGet(new RegExp('aweme/v1/feed/\?.*'))
.reply(200, loadTestData('listForYouFeed.json'), {});

const res = await api.listForYouFeed();
const expected: ListForYouFeedResponse = {
extra: {
now: 1000000000000,
},
aweme_list: [],
max_cursor: 0,
min_cursor: 0,
has_more: 1,
home_model: 1,
refresh_clear: 1,
status_code: 0,
};
assert.deepStrictEqual(res.data, expected);
});
});

describe('#listFollowingFeed()', () => {
it('a successful response should match the interface', async () => {
const api = new TikTokAPI(mockParams, mockConfig);
const mock = new MockAdapter(api.request);
mock
.onGet(new RegExp('aweme/v1/feed/\?.*'))
.reply(200, loadTestData('listFollowingFeed.json'), {});

const res = await api.listFollowingFeed();
const expected: ListFeedResponse = {
extra: {
now: 1000000000000,
},
aweme_list: [],
max_cursor: 0,
min_cursor: 0,
has_more: 1,
status_code: 0,
};
assert.deepStrictEqual(res.data, expected);
});
});
10 changes: 10 additions & 0 deletions test/testdata/listFollowingFeed.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extra": {
"now": 1000000000000
},
"aweme_list": [],
"has_more": 1,
"max_cursor": 0,
"min_cursor": 0,
"status_code": 0
}
12 changes: 12 additions & 0 deletions test/testdata/listForYouFeed.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"extra": {
"now": 1000000000000
},
"aweme_list": [],
"has_more": 1,
"max_cursor": 0,
"min_cursor": 0,
"home_model": 1,
"refresh_clear": 1,
"status_code": 0
}

0 comments on commit 4eb88d0

Please sign in to comment.