/- spider /+ strandio,sr=sortug, server =, strand=strand:spider =, strand-fail=strand-fail:libstrand:spider |% +$ kv [k=@t v=@t] +$ param [k=@t v=json] :: check nitter/src/consts.nim ++ auth-key :: nitters 'Bearer AAAAAAAAAAAAAAAAAAAAAFQODgEAAAAAVHTp76lzh3rFzcHbmHVvQxYYpTw%3DckAlMINMjmCwxUcaXbAN4XqJVdgMJaHqNOFgPMK0zN1qLqLQCF' ++ api-key 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA' ++ api-key2 'Bearer AAAAAAAAAAAAAAAAAAAAAIWCCAAAAAAA2C25AxqI%2BYCS7pdfJKRH8Xh19zA%3D8vpDZzPHaEJhd20MKVWp3UR38YoPpuTX7UD2cVYo3YNikubuxd' :: iphone ++ api-key-3 'Bearer AAAAAAAAAAAAAAAAAAAAAAj4AQAAAAAAPraK64zCZ9CSzdLesbE7LB%2Bw4uE%3DVJQREvQNCZJNiz3rHO7lOXlkVOQkzzdsgu6wWgcazdMUaGoUGm' :: ipad -- TimelineSearch returns data in a different format, making nitter return empty results. on the other hand, it has high rate limits. build separate token pools per endpoint? ++ api-key-4 'Bearer AAAAAAAAAAAAAAAAAAAAAGHtAgAAAAAA%2Bx7ILXNILCqkSGIzy6faIHZ9s3Q%3DQy97w6SIrzE7lQwPJEYQBsArEE2fC25caFwRBvAGi456G09vGR' ++ base-url "https://api.twitter.com/" ++ graphql (weld base-url "graphql/") ++ burl |= [query-id=tape path=tape] ^- tape "{graphql}{query-id}/{path}" ++ urls |% ++ tweet-lurk [query-id="mbnjGF4gOwo5gyp9pe5s4A" path="TweetResultByRestId"] :: logged gets ++ user-by-id [query-id="oPppcargziU1uDQHAUmH-A" path="UserResultByIdQuery"] ++ user-tweets [query-id="VgitpdpNZ-RUIp5D1Z_D-A" path="UserTweets"] ++ user-by-name [query-id="G3KGOASz96M-Qu0nwmGXNg" path="UserByScreenName"] ++ user-replies [query-id="8IS8MaO-2EN6GZZZb8jF0g" path="UserWithProfileTweetsAndRepliesQueryV2"] ++ user-media [query-id="PDfFf8hGeJvUCiTyWtw4wQ" path="MediaTimelineV2"] ++ conversation [query-id="83h5UyHZ9wEKBVzALX8R_g" path="ConversationTimelineV2"] ++ tweet-result [query-id="sITyJdhRPpvpEjg4waUmTA" path="TweetResultByIdQuery"] ++ list-by-id [query-id="iTpgCtbdxrsJfyx0cFjHqg" path="ListByRestId"] ++ list-by-slug [query-id="-kmqNvm5Y-cVrfvBy6docg" path="ListBySlug"] ++ list-members [query-id="P4NpVZDqUD_7MEM84L-8nw" path="ListMembers"] ++ list-timeline [query-id="BbGLL1ZfMibdFNWlk7a0Pw" path="ListTimeline"] ++ tweet-detail [query-id="BbmLpxKh8rX8LNe2LhVujA" path="TweetDetail"] ++ search-timeline [query-id="lZ0GCEojmtQfiUQa5oJSEw" path="SearchTimeline"] :: POST URLs ++ create-tweet [query-id="5V_dkq1jfalfiFOEZ4g47A" path="CreateTweet"] ++ create-retweet [query-id="ojPdsZsimiJrUGLR1sjUtA" path="CreateRetweet"] ++ favorite-tweet [query-id="lI07N6Otwv1PhnEgXILM7A" path="FavoriteTweet"] ++ delete-tweet [query-id="VaenaVgh5q5ih7kvyVjgtg" path="DeleteTweet"] -- :: shit this is legacy ++ notifications-url "https://twitter.com/i/api/2/notifications/all.json" ++ base-variables ^- (list param) :~ ['includePromotedContent' b+%|] ['withHighlightedLabel' b+%|] ['withCommunity' b+%|] ['with_rux_injections' b+%|] ['referrer' s+'tweet'] ['withTweetQuoteCount' b+%&] ['withBirdwatchNotes' b+%|] ['withBirdwatchPivots' b+%|] ['withTweetResult' b+%&] ['withReactions' b+%&] ['withReactionsMetadata' b+%|] ['withReactionsPerspective' b+%|] ['withSuperFollowsTweetFields' b+%|] ['withSuperFollowsUserFields' b+%|] ['withUserResults' b+%|] ['withVoice' b+%&] ['withV2Timeline' b+%&] :: ['withQuickPromoteEligibilityTweetFields' b+%|] == ++ build-variables |= l=(list param) ^- tape %- uri-encode:sr %- trip %- en:json:html %- pairs:enjs:format (weld base-variables l) ++ features-2 ^- tape %- uri-encode:sr %- trip %- en:json:html %- pairs:enjs:format :~ ['android_graphql_skip_api_media_color_palette' b+.n] ['blue_business_profile_image_shape_enabled' b+.n] ['creator_subscriptions_subscription_count_enabled' b+.n] ['creator_subscriptions_tweet_preview_api_enabled' b+.y] ['freedom_of_speech_not_reach_fetch_enabled' b+.n] ['graphql_is_translatable_rweb_tweet_is_translatable_enabled' b+.n] ['hidden_profile_likes_enabled' b+.n] ['highlights_tweets_tab_ui_enabled' b+.n] ['interactive_text_enabled' b+.n] ['longform_notetweets_consumption_enabled' b+.y] ['longform_notetweets_inline_media_enabled' b+.n] ['longform_notetweets_richtext_consumption_enabled' b+.y] ['longform_notetweets_rich_text_read_enabled' b+.n] ['responsive_web_edit_tweet_api_enabled' b+.n] ['responsive_web_home_pinned_timelines_enabled' b+.n] ['responsive_web_enhance_cards_enabled' b+.n] ['responsive_web_graphql_exclude_directive_enabled' b+.y] ['responsive_web_graphql_skip_user_profile_image_extensions_enabled' b+.n] ['responsive_web_graphql_timeline_navigation_enabled' b+.n] ['responsive_web_media_download_video_enabled' b+.n] ['responsive_web_text_conversations_enabled' b+.n] ['responsive_web_twitter_article_tweet_consumption_enabled' b+.n] ['responsive_web_twitter_blue_verified_badge_is_enabled' b+.y] ['rweb_lists_timeline_redesign_enabled' b+.y] ['spaces_2022_h2_clipping' b+.y] ['spaces_2022_h2_spaces_communities' b+.y] ['standardized_nudges_misinfo' b+.n] ['subscriptions_verification_info_enabled' b+.y] ['subscriptions_verification_info_reason_enabled' b+.y] ['subscriptions_verification_info_verified_since_enabled' b+.y] ['super_follow_badge_privacy_enabled' b+.n] ['super_follow_exclusive_tweet_notifications_enabled' b+.n] ['super_follow_tweet_api_enabled' b+.n] ['super_follow_user_api_enabled' b+.n] ['tweet_awards_web_tipping_enabled' b+.n] ['tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled' b+.n] ['tweetypie_unmention_optimization_enabled' b+.n] ['unified_cards_ad_metadata_container_dynamic_card_content_query_enabled' b+.n] ['verified_phone_label_enabled' b+.n] ['vibe_api_enabled' b+.n] ['view_counts_everywhere_api_enabled' b+.n] == ++ post-features ^- (list [@t json]) :~ ['c9s_tweet_anatomy_moderator_badge_enabled' b+.y] ['freedom_of_speech_not_reach_fetch_enabled' b+.y] ['graphql_is_translatable_rweb_tweet_is_translatable_enabled' b+.y] ['longform_notetweets_consumption_enabled' b+.y] ['longform_notetweets_inline_media_enabled' b+.y] ['longform_notetweets_rich_text_read_enabled' b+.y] ['responsive_web_edit_tweet_api_enabled' b+.y] ['responsive_web_enhance_cards_enabled' b+.n] ['responsive_web_graphql_exclude_directive_enabled' b+.y] ['responsive_web_graphql_skip_user_profile_image_extensions_enabled' b+.n] ['responsive_web_graphql_timeline_navigation_enabled' b+.y] ['responsive_web_home_pinned_timelines_enabled' b+.y] ['responsive_web_media_download_video_enabled' b+.n] ['responsive_web_twitter_article_tweet_consumption_enabled' b+.n] ['standardized_nudges_misinfo' b+.y] ['tweet_awards_web_tipping_enabled' b+.n] ['tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled' b+.y] ['tweetypie_unmention_optimization_enabled' b+.y] ['verified_phone_label_enabled' b+.n] ['view_counts_everywhere_api_enabled' b+.y] == ++ features ^- tape %- uri-encode:sr %- trip %- en:json:html %- pairs:enjs:format :~ ['creator_subscriptions_tweet_preview_api_enabled' b+%&] ['freedom_of_speech_not_reach_fetch_enabled' b+%|] ['graphql_is_translatable_rweb_tweet_is_translatable_enabled' b+%&] ['interactive_text_enabled' b+%&] ['longform_notetweets_consumption_enabled' b+%&] ['longform_notetweets_inline_media_enabled' b+%&] ['longform_notetweets_rich_text_read_enabled' b+%|] ['longform_notetweets_richtext_consumption_enabled' b+%|] ['responsive_web_edit_tweet_api_enabled' b+%&] ['responsive_web_enhance_cards_enabled' b+%|] ['responsive_web_home_pinned_timelines_enabled' b+.n] ['responsive_web_graphql_exclude_directive_enabled' b+%&] ['responsive_web_graphql_timeline_navigation_enabled' b+%&] ['responsive_web_graphql_skip_user_profile_image_extensions_enabled' b+%|] ['responsive_web_media_download_video_enabled' b+%&] ['responsive_web_text_conversations_enabled' b+%|] ['responsive_web_twitter_blue_verified_badge_is_enabled' b+%&] ['responsive_web_twitter_article_tweet_consumption_enabled' b+%&] ['rweb_lists_timeline_redesign_enabled' b+%&] ['standardized_nudges_misinfo' b+%&] ['tweet_awards_web_tipping_enabled' b+%|] ['tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled' b+%|] ['tweetypie_unmention_optimization_enabled' b+%&] ['verified_phone_label_enabled' b+%|] ['vibe_api_enabled' b+%&] ['view_counts_everywhere_api_enabled' b+%&] :: ['android_graphql_skip_api_media_color_palette' b+.y] ['super_follow_badge_privacy_enabled' b+.y] ['super_follow_tweet_api_enabled' b+.y] ['subscriptions_verification_info_enabled' b+.y] ['blue_business_profile_image_shape_enabled' b+.n] ['super_follow_user_api_enabled' b+.y] ['creator_subscriptions_subscription_count_enabled' b+.y] ['super_follow_exclusive_tweet_notifications_enabled' b+.y] ['unified_cards_ad_metadata_container_dynamic_card_content_query_enabled' b+.y] :: logged ['c9s_tweet_anatomy_moderator_badge_enabled' b+.n] :: logged profile ['hidden_profile_likes_enabled' b+.n] ['subscriptions_verification_info_verified_since_enabled' b+.n] ['highlights_tweets_tab_ui_enabled' b+.n] ['subscriptions_verification_info_is_identity_verified_enabled' b+.n] ['hidden_profile_subscriptions_enabled' b+.n] == ++ userid-params |= id=@t ^- tape =/ vrs (build-variables ~[['userId' %s id] ['count' %n '20']]) "?variables={vrs}&features={features}" ++ post-params |= id=@t ^- tape =/ vrs (build-variables ~[['tweetId' %s id]]) "?variables={vrs}&features={features}" ++ user-params |= id=@t ^- tape =/ vrs (build-variables ~[['screen_name' %s id]]) "?variables={vrs}&features={features-2}" ++ user-tweets-params |= id=@t ^- tape =/ vrs (build-variables ~[['rest_id' %s id] ['count' %n '100']]) "?variables={vrs}&features={features-2}" ++ legacy-params ^- (list kv) :~ ['include_profile_interstitial_type' '1'] ['include_blocking' '1'] ['include_blocked_by' '1'] ['include_followed_by' '1'] ['include_want_retweets' '1'] ['include_mute_edge' '1'] ['include_can_dm' '1'] ['include_can_media_tag' '1'] ['include_ext_has_nft_avatar' '1'] ['include_ext_is_blue_verified' '1'] ['include_ext_verified_type' '1'] ['skip_status' '1'] ['cards_platform' 'Web-12'] ['include_cards' '1'] ['include_ext_alt_text' 'true'] ['include_ext_limited_action_results' 'false'] ['include_quote_count' 'true'] ['include_reply_count' '1'] ['tweet_mode' 'extended'] ['include_ext_collab_control' 'true'] ['include_ext_views' 'true'] ['include_entities' 'true'] ['include_ext_media_color' 'true'] ['include_ext_media_availability' 'true'] ['include_ext_sensitive_media_warning' 'true'] ['include_ext_trusted_friends_metadata' 'true'] ['send_error_codes' 'true'] ['simple_quoted_tweet' 'true'] ['include_ext_edit_control' 'true'] ['ext' 'mediaStats,highlightedLabel,hasNftAvatar,voiceInfo,enrichments,superFollowMetadata,unmentionInfo,editControl,collab_control,vibe'] == ++ params-to-tape |= l=(list kv) ^- tape %+ roll l |= [i=[k=@t v=@t] a=tape] =/ key (trip k.i) =/ val (trip v.i) ?~ a "{a}key={val}" "{a}&{key}={val}" ++ notes-params %- params-to-tape %+ weld legacy-params :~ ['count' '20'] ['requestContext' 'launch'] == ++ search-params |= [query=@t cursor=@t count=@ type=?(%user %post)] ^- tape =/ base=(list kv) %+ weld legacy-params :~ ['q' query] ['count' (crip "{}")] ['query_source' 'typeahead_click'] :: 'typed_query ['cursor' cursor] ['pc' '1'] ['spelling_corrections' '1'] ['include_ext_edit_control' 'true'] ['ext' 'mediaStats,highlightedLabel,hasNftAvatar,voiceInfo,enrichments,superFollowMetadata,unmentionInfo,editControl,collab_control,vibe'] == =/ full=(list [@t @t]) ?- type %user (snoc base ['result_filter' 'user']) %post (snoc base ['tweet_search_mode' 'live']) == (params-to-tape full) :: requests :: guest-token ++ gt-request ^- request:http =/ method %'POST' =/ url 'https://api.twitter.com/1.1/guest/activate.json' =/ headers :~ ['connection' 'keep-alive'] ['authorization' auth-key] ['content-type' 'application/x-www-form-urlffencoded'] ['x-twitter-active-user' 'yes'] ['x-twitter-client-language' 'en-us'] ['Accept-language' 'en-US,en;q=0.9'] ['Accept' '*/*'] ['origin' 'https://twitter.com'] ['referer' 'https://twitter.com/'] ['DNT' '1'] ['User-agent' 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36'] == [method url headers ~] ++ parse-gt |= res=client-response:iris =/ m (strand ,cord) ^- form:m ?. ?=(%finished -.res) (strand-fail:strand %no-body ~) ?~ full-file.res (strand-fail:strand %no-body ~) =/ body=@t q.data.u.full-file.res =/ jon=(unit json) (de:json:html body) ?~ jon (strand-fail:strand %no-body ~) (pure:m (parse-gt-json u.jon)) ++ parse-gt-json |= =json ^- @t =/ mapi ((om so):dejs:format json) (~(got by mapi) 'guest_token') ::: csrf ++ csrf-token-request ^- request:http =/ method %'GET' =/ url 'https://developer.twitter.com/en' =/ headers :~ ['connection' 'keep-alive'] ['content-type' 'application/x-www-form-urlffencoded'] ['x-twitter-active-user' 'yes'] ['x-twitter-client-language' 'en-us'] ['Accept-language' 'en-US,en;q=0.9'] ['Accept' '*/*'] ['origin' 'https://twitter.com'] ['referer' 'https://twitter.com/'] ['DNT' '1'] ['User-agent' 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36'] == [method url headers ~] ++ parse-csrf |= res=client-response:iris =/ m (strand ,cord) ^- form:m ?. ?=(%finished -.res) (strand-fail:strand %no-body ~) =+ %+ skim headers.response-header.res |= pair=[key=@t value=@t] .=(key.pair 'set-cookie') =/ cookies=(list @t) %+ turn - |= pair=[key=@t value=@t] value.pair :: parse this a bit =/ csrf (extract-csrf cookies) (pure:m csrf) ++ extract-csrf |= cookies=(list @t) ^- @t %+ roll cookies |= [item=@t acc=@t] ?. (contains:string:sr (trip item) "ct0=") acc =+ (split:string:sr (trip item) ";") =+ (split:string:sr (snag 0 -) "=") (crip (snag 1 -)) :: ++ embed-request :: |= id=@t :: =/ endpoint %- crip "{embed-url:endpoints}{(trip id)}" :: =/ method %'GET' :: =/ headers :: :~ :: ['connection' 'keep-alive'] :: ['Accept-language' 'en-US,en;q=0.9'] :: ['Accept' '*/*'] :: ['origin' 'https://platform.twitter.com'] :: ['referer' 'https://platform.twitter.com/'] :: ['DNT' '1'] :: ['User-agent' 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36'] :: == :: [method endpoint headers ~] ++ twatter-request |= [endpoint=@t gt=@t csrf=@t] ^- request:http =/ method %'GET' =/ headers :~ ['connection' 'keep-alive'] ['authorization' auth-key] ['content-type' 'application/json'] ['x-csrf-token' csrf] ['x-guest-token' gt] ['x-twitter-active-user' 'yes'] ['x-twitter-client-language' 'en-us'] ['Accept-language' 'en-US,en;q=0.9'] ['Accept' '*/*'] ['origin' 'https://twitter.com'] ['referer' 'https://twitter.com/'] ['DNT' '1'] ['User-agent' 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36'] :: ['authority' 'api.twitter.com'] == [method endpoint headers ~] :: ++ build-request-url :: |= [endpoint=tape l=(list kv)] ^- @t :: =/ vars (uri-encode:u (build-variables l)) :: =+ (weld base-url:endpoints endpoint) :: =+ (weld - vars) :: (crip -) :: ++ build-request-v2-url :: |= [key=@t query=@t cursor=@t endpoint=tape] ^- @t :: =/ vars (uri-encode:u (build-variables key query cursor)) :: =/ feat (uri-encode:u features) :: =+ (weld base-url:endpoiunts endpoint) :: =+ (weld - vars) :: =+ (weld - "&features={feat}") :: (crip -) :: ++ build-search-url :: |= [query=@t cursor=@t] :: TODO count and replies :: :: " include:nativeretweets", " include:replies" :: =/ q "{} include:nativeretweets exclude:replies" :: :: =/ q "{} include:nativeretweets include:replies" :: =/ qq %- en-urlt:html (en-urlt:html q) :: =/ c %- en-urlt:html (en-urlt:html (trip cursor)) :: :: =/ c (en-urlt:html (trip cursor)) :: :: =/ c (trip cursor) :: =+ :: "include_profile_interstitial_type=1&cursor={c}&include_blocking=1&include_blocked_by=1&include_followed_by=1&include_want_retweets=1&include_mute_edge=1&include_can_dm=1&include_can_media_tag=1&include_ext_has_nft_avatar=1&skip_status=1&cards_platform=Web-12&include_cards=1&include_ext_alt_text=true&include_quote_count=true&include_reply_count=1&tweet_mode=extended&include_entities=true&include_user_entities=true&include_ext_media_color=true&include_ext_media_availability=true&include_ext_sensitive_media_warning=true&send_error_codes=true&simple_quoted_tweet=true&tweet_search_mode=live&q={qq}&count=20&query_source=typed_query&pc=1&spelling_corrections=1&ext=mediaStats%2ChighlightedLabel%2ChasNftAvatar%2CvoiceInfo%2CsuperFollowMetadata" :: =+ (weld search:endpoints (search-params query cursor 20 %post)) :: =+ (weld base-url:endpoints -) :: (crip -) :: =/ url %- crip (weld tweet-lurk (post-params id.u.command)) :: =/ req (twatter-request url gt csrf) ++ lurk-headers :~ ['Connection' 'keep-alive'] ['Content-type' 'application/json'] ['X-twitter-active-user' 'yes'] ['X-twitter-client-language' 'en-us'] ::['x-guest-token' gt] ['Accept-language' 'en-US,en;q=0.9'] ['Accept' '*/*'] ['origin' 'https://twitter.com'] ['referer' 'https://twitter.com/'] ['DNT' '1'] ['User-agent' 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36'] == ++ logged-headers |= [cookie-string=@t csrf=@t] :: =/ cookie-string :: 'guest_id=v1%3A169380915299959910; guest_id_ads=v1%3A169380915299959910; guest_id_marketing=v1%3A169380915299959910; kdt=VZeo5b3hVg9VsnQjJYiUsFLNvQIa1lqnxry4dcXK; auth_token=88ab0ccf40bb6be863354720d504895c7308e647; ct0=9469495056e099284acb28c9889422b02285c3883e8c9e681c287c2b1287e2e4a8d0ed3dff9a1db4ef05152d2d3f9a891031804a5fc80ef0d8b0ab251067558eec751d8241f617517a47f12a5c0b1ba8; twid=u%3D1633158398555353096; lang=en; external_referer=8e8t2xd8A2w%3D|0|F8C7rVpldvGNltGxuH%2ByoRY%2FzjrflHIZH061f%2B5OiIwP17ZTz34ZGg%3D%3D; personalization_id="v1_kxI2MM4RPdOgambYqR1tUA=="' :: =/ csrf '9469495056e099284acb28c9889422b02285c3883e8c9e681c287c2b1287e2e4a8d0ed3dff9a1db4ef05152d2d3f9a891031804a5fc80ef0d8b0ab251067558eec751d8241f617517a47f12a5c0b1ba8' :~ ['Cookie' cookie-string] ['Connection' 'keep-alive'] ['Authorization' api-key] ['Content-type' 'application/json'] ['X-csrf-token' csrf] ['X-twitter-active-user' 'yes'] ['X-twitter-auth-type' 'OAuth2Session'] ['X-twitter-client-language' 'en-us'] ['Accept-language' 'en-US,en;q=0.9'] ['Accept' '*/*'] ['origin' 'https://twitter.com'] ['referer' 'https://twitter.com/'] ['DNT' '1'] ['User-agent' 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36'] :: ['authority' 'api.twitter.com'] == :: ++ build-post-body :: |= p=post-req:tw ^- octs :: =, enjs:format :: %- json-to-octs:server :: %- pairs %- limo :: :~ [%features (pairs post-features)] :: ['queryId' s+(crip query-id:create-tweet:urls)] :: ['variables' (pairs (build-post-vars p))] :: == :: ++ build-post-vars :: |= p=post-req:tw :: =, enjs:format :: =/ text=@t ?. mask.p text.p :: :: TODO automated masking :: 'This tweet is too spicy for Elon Musk\'s friends. To read it click on the link at my bio' :: =/ base-vars :: :~ ['dark_request' b+.n] :: ['semantic_annotation_ids' a+~] :: ['tweet_text' s+text] :: :- 'media' %- pairs :: :~ ['possibly_sensitive' b+.n] :: ['media_entities' a+~] :: == :: == :: ?^ quoting.p :_ base-vars :- 'attachment_url' s+u.quoting.p :: ?^ replying.p :_ base-vars :- 'reply' %- pairs :: :~ ['exclude_reply_user_ids' a+~] :: ['in_reply_to_twitter_id' s+u.replying.p] :: == :: base-vars :: ++ logged-req ^- request:http :: =/ url %- crip (weld user-tweets (userid-params '1633158398555353096')) :: [%'GET' url logged-headers ~] :: :: {"userId":"1633158398555353096","count":20,"includePromotedContent":true,"withQuickPromoteEligibilityTweetFields":true,"withVoice":true,"withV2Timeline":true} :: {"responsive_web_graphql_exclude_directive_enabled":true,"verified_phone_label_enabled":false,"responsive_web_home_pinned_timelines_enabled":true,"creator_subscriptions_tweet_preview_api_enabled":true,"responsive_web_graphql_timeline_navigation_enabled":true,"responsive_web_graphql_skip_user_profile_image_extensions_enabled":false,"c9s_tweet_anatomy_moderator_badge_enabled":true,"tweetypie_unmention_optimization_enabled":true,"responsive_web_edit_tweet_api_enabled":true,"graphql_is_translatable_rweb_tweet_is_translatable_enabled":true,"view_counts_everywhere_api_enabled":true,"longform_notetweets_consumption_enabled":true,"responsive_web_twitter_article_tweet_consumption_enabled":false,"tweet_awards_web_tipping_enabled":false,"freedom_of_speech_not_reach_fetch_enabled":true,"standardized_nudges_misinfo":true,"tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled":true,"longform_notetweets_rich_text_read_enabled":true,"longform_notetweets_inline_media_enabled":true,"responsive_web_media_download_video_enabled":false,"responsive_web_enhance_cards_enabled":false} --