kawamataryo / sky-follower-bridge

Instantly find and follow the same users from your X(Twitter) follower on Bluesky.
https://www.sky-follower-bridge.dev
MIT License
614 stars 20 forks source link

Support matching on domain name #86

Open luxaritas opened 1 week ago

luxaritas commented 1 week ago

Since I now have my Bluesky handle set as a domain, and that same domain is used in the "website" field of my twitter profile, it seems like that could be another reasonable option to match on. I imagine this won't be uncommon for folks with personal websites, though wouldn't have the desired result if eg you have your website set to a linktree.

kawamataryo commented 6 days ago

This extension performs searches based on the information displayed on the user list screen of X. Since the information in the website field is not shown on the user list screen, it is difficult...

CleanShot 2024-11-13 at 09 32 16

If you could include a string like bsky.app/profix/xxxxx.xxx in your bio, we would be able to detect it.

xPaw commented 7 hours ago

There's a way to fetch following list with twitter's graphql with a little bit of work, you can see this request being performed when you scroll on following page, which gives you the raw user object that contains the descripton/name/entities/etc.

const params = new URLSearchParams({
    variables: JSON.stringify({
        'userId': (await cookieStore.get("twid")).value.replace('u%3D', ''),
        'count': 50,
        //'cursor': '',
        'includePromotedContent': false
    }),
    features: JSON.stringify({
        rweb_tipjar_consumption_enabled: true,
        responsive_web_graphql_exclude_directive_enabled: true,
        verified_phone_label_enabled: false,
        creator_subscriptions_tweet_preview_api_enabled: true,
        responsive_web_graphql_timeline_navigation_enabled: true,
        responsive_web_graphql_skip_user_profile_image_extensions_enabled: false,
        communities_web_enable_tweet_community_results_fetch: true,
        c9s_tweet_anatomy_moderator_badge_enabled: true,
        articles_preview_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: true,
        tweet_awards_web_tipping_enabled: false,
        creator_subscriptions_quote_tweet_preview_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,
        rweb_video_timestamps_enabled: true,
        longform_notetweets_rich_text_read_enabled: true,
        longform_notetweets_inline_media_enabled: true,
        responsive_web_enhance_cards_enabled: false
    }),
});

// this is not user specific it is hardcoded in the source code
const hardcodedTwitterAuthToken = "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA";
const csrf = (await cookieStore.get("ct0")).value;

const resp = await fetch(`https://x.com/i/api/graphql/eWTmcJY3EMh-dxIR7CYTKw/Following?${params}`, {
    headers: {
        Authorization: hardcodedTwitterAuthToken,
        'x-csrf-token': csrf
    }
});
const json = await resp.json();

console.log(json);