TwitterユーザーID取得

  • /*
     * @title TwitterユーザーID取得
     * @description Twitterユーザーのscreen_nameからユーザーIDを取得する
     * @include https://twitter.com/*
     * @license MIT License
     * @require 
     * @javascript_url
     */
    
    (async () => {
    'use strict';
    
    const error_alert = (error_message) => {
        console.error(error_message);
        alert(error_message);
    };
    
    let screen_name = window.getSelection().toString() || prompt('Input screen-name of user', '');
    if (screen_name === null) return;
    screen_name = screen_name.trim().replace(/^@/, '');
    if (! screen_name) {
        error_alert('screen-name is empty');
        return;
    }
    
    const api_info = await (async () => {
        try {
            const main_js_url = document.querySelector('link[as="script"][href*="main"]')?.href ?? document.querySelector('script[src*="main"][src$=".js"]')?.src;
            if (! main_js_url) {
                throw new Error(`URL of main*.js is not found`);
            }
            const response = await fetch(main_js_url);
            if (! response.ok) {
                throw new Error(`HTTP response status code=${response.status}`);
            }
            const main_js_text = await response.text();
            const api_info_json = main_js_text.match(/\{e\.exports=(\{[^}]*?operationName:"UserByScreenName"[\s\S]*?\})\},\d+:e=>\{e.exports/)[1].replace(/(\w+)(?=:)/g, '"$1"');
            const api_info = JSON.parse(api_info_json);
            return api_info;
        }
        catch (error) {
            error_alert(`Fetch API-Information failure: ${error}`);
            return null;
        }
    })();
    if (! api_info) return;
    
    const user_id = await (async () => {
        const base_url = `https://x.com/i/api/graphql/${api_info.queryId}/UserByScreenName`;
        const api2_auth_bearer = 'AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA';
        const csrf_token = document.cookie.match(/ct0=(.*?)(?:;|$)/)[1];
        const search_params = {
            variables: {
                "screen_name": screen_name,
                "withGrokTranslatedBio": false
            },
            features: {
                "hidden_profile_subscriptions_enabled": true,
                "profile_label_improvements_pcf_label_in_post_enabled": true,
                "responsive_web_profile_redirect_enabled": false,
                "rweb_tipjar_consumption_enabled": false,
                "verified_phone_label_enabled": false,
                "subscriptions_verification_info_is_identity_verified_enabled": true,
                "subscriptions_verification_info_verified_since_enabled": true,
                "highlights_tweets_tab_ui_enabled": true,
                "responsive_web_twitter_article_notes_tab_enabled": true,
                "subscriptions_feature_can_gift_premium": true,
                "creator_subscriptions_tweet_preview_api_enabled": true,
                "responsive_web_graphql_skip_user_profile_image_extensions_enabled": false,
                "responsive_web_graphql_timeline_navigation_enabled": true
            },
            fieldToggles: {
                "withPayments": false,
                "withAuxiliaryUserLabels": true
            },
        };
        const url_object = new URL(base_url);
        Object.entries(search_params).forEach(([key, value]) => {
            url_object.searchParams.append(key, JSON.stringify(value));
        });
        
        try {
            const response = await fetch(url_object.href, {
                method: 'GET',
                headers: {
                    'authorization': `Bearer ${api2_auth_bearer}`,
                    'x-csrf-token': csrf_token,
                    'x-twitter-active-user': 'yes',
                    'x-twitter-auth-type': 'OAuth2Session',
                    'x-twitter-client-language': 'en',
                },
                mode: 'cors',
                credentials: 'include',
            });
            if (! response.ok) {
                throw new Error(`HTTP response status code=${response.status}`);
            }
            const user_info = await response.json();
            const user_id = user_info?.data?.user?.result?.rest_id;
            
            if (! user_id) {
                throw new Error('Response does not include the ID of the user');
            }
            return user_id;
        }
        catch (error) {
            error_alert(`"${screen_name}" is not found: ${error}`);
            return null;
        }
        
    })();
    if (! user_id) return;
    
    try {
        await navigator.clipboard.writeText(user_id);
    }
    catch (error) {
        console.error(`Copy result to clipboard failure: ${error}`);
    }
    finally {
        let prompt_required = true;
        try {
            const target = window.getSelection().anchorNode.children[0];
            if (target.tagName == 'INPUT') {
                const event = new Event('input', {bubbles: true});
                const tracker = target._valueTracker;
                const last_value = target.value;
                const new_value = last_value.substring(0, target.selectionStart) + user_id + last_value.substring(target.selectionEnd);
                
                target.value = new_value;
                event.simulated = true;
                if (tracker) tracker.setValue(last_value);
                target.dispatchEvent(event);
                prompt_required = false;
            }
        }
        catch (error) {
            console.error(`Failed to rewrite screen name to user ID: ${error}`);
        }
        if ( prompt_required ) {
            prompt(`User ID of ${screen_name}`, user_id);
        }
    }
    })();
    
  • Permalink
    このページへの個別リンクです。
    RAW
    書かれたコードへの直接のリンクです。
    Packed
    文字列が圧縮された書かれたコードへのリンクです。
    Userscript
    Greasemonkey 等で利用する場合の .user.js へのリンクです。
    Loader
    @require やソースコードが長い場合に多段ロードする Loader コミのコードへのリンクです。
    Metadata
    コード中にコメントで @xxx と書かれたメタデータの JSON です。

History

  1. 2026/01/29 20:10:49 - 01/29
  2. 2020/10/30 01:48:24 - 2020-10-30
  3. 2020/10/30 01:42:17 - 2020-10-30
  4. 2020/10/30 01:40:12 - 2020-10-30
  5. 2020/10/29 17:34:00 - 2020-10-29
  6. 2020/10/29 17:06:47 - 2020-10-29
  7. 2020/10/29 15:53:56 - 2020-10-29
  8. 2020/10/29 15:09:30 - 2020-10-29
  9. 2020/10/29 15:02:09 - 2020-10-29