From b6487105ab7e87dfe7c87c4c7d717cc47e806732 Mon Sep 17 00:00:00 2001 From: Nicolas Cisco Date: Tue, 19 Jul 2022 18:30:46 +0200 Subject: [PATCH] Added clips (aka reels) feed --- src/core/feed.factory.ts | 7 + src/feeds/clips.feed.ts | 35 +++++ src/feeds/index.ts | 1 + src/responses/clips.feed.response.ts | 215 +++++++++++++++++++++++++++ 4 files changed, 258 insertions(+) create mode 100644 src/feeds/clips.feed.ts create mode 100644 src/responses/clips.feed.response.ts diff --git a/src/core/feed.factory.ts b/src/core/feed.factory.ts index 0ac26f779..0922d9fae 100644 --- a/src/core/feed.factory.ts +++ b/src/core/feed.factory.ts @@ -30,6 +30,7 @@ import { IgtvChannelFeed, LikedFeed, TopicalExploreFeed, + ClipsFeed, } from '../feeds'; import { DirectInboxFeedResponseThreadsItem } from '../responses'; import { plainToClassFromExist } from 'class-transformer'; @@ -324,4 +325,10 @@ export class FeedFactory { ): TopicalExploreFeed { return plainToClassFromExist(new TopicalExploreFeed(this.client), options); } + + public clips(id: string | number) { + return plainToClassFromExist(new ClipsFeed(this.client), { + targetUserId: id, + }); + } } diff --git a/src/feeds/clips.feed.ts b/src/feeds/clips.feed.ts new file mode 100644 index 000000000..2e2e827eb --- /dev/null +++ b/src/feeds/clips.feed.ts @@ -0,0 +1,35 @@ +import { Feed } from '../core/feed'; +import { Expose } from 'class-transformer'; +import { ClipsFeedResponseItemsItem, ClipsFeedResponseRootObject } from '../responses/clips.feed.response'; + +export class ClipsFeed extends Feed { + targetUserId: string; + + @Expose() + private maxId: string; + + protected set state(response: ClipsFeedResponseRootObject) { + this.moreAvailable = response.paging_info.more_available; + this.maxId = response.paging_info.max_id; + } + + async request(): Promise { + const { body } = await this.client.request.send({ + url: '/api/v1/clips/user/', + form: { + target_user_id: this.targetUserId, + max_id: this.maxId, + _csrftoken: this.client.state.cookieCsrfToken, + _uuid: this.client.state.uuid, + }, + method: 'POST', + }); + this.state = body; + return body; + } + + async items(): Promise { + const res = await this.request(); + return res.items; + } +} diff --git a/src/feeds/index.ts b/src/feeds/index.ts index e70782366..fbcfb90de 100644 --- a/src/feeds/index.ts +++ b/src/feeds/index.ts @@ -28,3 +28,4 @@ export * from './igtv.browse.feed'; export * from './igtv.channel.feed'; export * from './liked.feed'; export * from './topical-explore.feed'; +export * from './clips.feed'; diff --git a/src/responses/clips.feed.response.ts b/src/responses/clips.feed.response.ts new file mode 100644 index 000000000..c466958d8 --- /dev/null +++ b/src/responses/clips.feed.response.ts @@ -0,0 +1,215 @@ +export interface ClipsFeedResponseRootObject { + id: string; + items: ClipsFeedResponseItemsItem[]; + paging_info: { + more_available: boolean; + max_id: string; + }; + status: string; +} + +export interface ClipsFeedResponseItemsItem { + media: { + taken_at: number; + pk: string; + id: string; + device_timestamp: number | string; + media_type: number; + code: string; + client_cache_key: string; + filter_type: number; + is_unified_video: boolean; + should_request_ads: boolean; + caption_is_edited: boolean; + like_and_view_counts_disabled: boolean; + commerciality_status: string; + is_paid_partnership: boolean; + is_visual_reply_commenter_notice_enabled: boolean; + has_delayed_metadata: boolean; + comment_likes_enabled: boolean; + comment_threading_enabled: boolean; + has_more_comments: boolean; + next_max_id: string; + max_num_visible_preview_comments: number; + preview_comments: ClipsFeedResponsePreviewCommentsItem[]; + can_view_more_preview_comments: boolean; + comment_count: number; + hide_view_all_comment_entrypoint: boolean; + image_versions2: ClipsFeedResponseImage_versions2; + original_width: number; + original_height: number; + user: ClipsFeedResponseUser_dict; + can_viewer_reshare: boolean; + like_count: number; + photo_of_you: boolean; + is_organic_product_tagging_eligible: boolean; + can_see_insights_as_brand: boolean; + video_subtitles_confidence: string; + is_dash_eligible: number; + video_dash_manifest: string; + video_codec: string; + number_of_qualities: number; + video_versions: ClipsFeedResponseVideoVersionsItem[]; + has_audio: boolean; + video_duration: number; + view_count: number; + play_count: number; + caption: ClipsFeedResponseCaption; + comment_inform_treatment: { + should_have_inform_treatment: boolean; + text: string; + url: string | null; + action_type: string | null; + }; + sharing_friction_info: { + should_have_sharing_friction: boolean; + bloks_app_url: string | null; + sharing_friction_payload: string | null; + }; + can_viewer_save: boolean; + is_in_profile_grid: boolean; + profile_grid_control_enabled: boolean; + organic_tracking_token: string; + has_shared_to_fb: boolean; + product_type: string; + deleted_reason: number; + integrity_review_decision: string; + logging_info_token: string; + }; +} + +export interface ClipsFeedResponsePreviewCommentsItem { + pk: string; + user_id: number; + text: string; + type: number; + created_at: number; + created_at_utc: number; + content_type: string; + status: string; + bit_flags: number; + did_report_as_spam: boolean; + share_enabled: boolean; + user: ClipsFeedResponseUser; + is_covered: boolean; + media_id: string; + has_translation: boolean; + private_reply_status: string; +} + +export interface ClipsFeedResponseUser { + pk: number; + username: string; + full_name: string; + is_private: boolean; + profile_pic_url: string; + profile_pic_id?: string; + is_verified: boolean; +} + +export interface ClipsFeedResponseFriendship_status { + following: boolean; + outgoing_request: boolean; + is_bestie: boolean; + is_restricted: boolean; + followed_by?: boolean; + blocking?: boolean; + muting?: boolean; + is_private?: boolean; + incoming_request?: boolean; +} + +export interface ClipsFeedResponseImage_versions2 { + candidates: ClipsFeedResponseCandidatesItem[]; + additional_candidates: ClipsFeedResponseAdditional_candidates; + animated_thumbnail_spritesheet_info_candidates: ClipsFeedResponseAnimated_thumbnail_spritesheet_info_candidates; +} + +export interface ClipsFeedResponseCandidatesItem { + width: number; + height: number; + url: string; + scans_profile: string; +} + +export interface ClipsFeedResponseAdditional_candidates { + igtv_first_frame: ClipsFeedResponseIgtv_first_frame; + first_frame: ClipsFeedResponseFirst_frame; +} + +export interface ClipsFeedResponseIgtv_first_frame { + width: number; + height: number; + url: string; + scans_profile: string; +} + +export interface ClipsFeedResponseFirst_frame { + width: number; + height: number; + url: string; + scans_profile: string; +} + +export interface ClipsFeedResponseAnimated_thumbnail_spritesheet_info_candidates { + default: { + video_length: number; + thumbnail_width: number; + thumbnail_height: number; + thumbnail_duration: string; + sprite_urls: string[]; + thumbnails_per_row: number; + total_thumbnail_num_per_sprite: number; + max_thumbnails_per_sprite: number; + sprite_width: number; + sprite_height: number; + rendered_width: number; + file_size_kb: number; + }; +} + +export interface ClipsFeedResponseUser_dict { + pk: number; + username: string; + full_name: string; + is_private: boolean; + profile_pic_url: string; + profile_pic_id: string; + friendship_status: ClipsFeedResponseFriendship_status; + is_verified: boolean; + has_anonymous_profile_picture: boolean; + is_unpublished: boolean; + is_favorite: boolean; + has_highlight_reels: boolean; + transparency_product_enabled: boolean; + account_badges: {}[]; + fan_club_info: { + fan_club_id: string; + fan_club_name: string; + }; +} + +export interface ClipsFeedResponseVideoVersionsItem { + type: number; + width: number; + height: number; + url: string; + id: string; +} + +export interface ClipsFeedResponseCaption { + pk: string; + user_id: number; + text: string; + type: number; + created_at: number; + created_at_utc: number; + content_type: string; + status: string; + bit_flags: number; + user: ClipsFeedResponseUser; + did_report_as_spam: boolean; + share_enabled: boolean; + media_id: string; + has_translation: boolean; +}