Twitter Media Downloader

ワンクリックで動画・画像を保存する。

< Twitter Media Downloaderについてのフィードバック

レート:良 – スクリプトは良好に動作する

§
投稿日: 2025/04/26

seems like the tweetdetail api is gone after checking the error messages in console, could mean total death of this Userscript which is sad.
Downloaded more than 1700 media files with it.
o7 R.I.P.

Does this API problem mean that even the author can’t fix it?

§
投稿日: 2025/04/26

It still exists. But looks like the url and/or parameters changed a bit.

§
投稿日: 2025/04/26

I've tried to edit the script to have the exact same parameters as the valid query the front end does when navigating to a Tweet, but no success, the requests gets bounced. It's not exactly my area of expertise but if anyone wants to finish or know what's missing, here it is: Starting from the fetchJson function:

        fetchJson: async function (status_id) {
            let base_url = `https://${host}/i/api/graphql/_8aYOgEDz35BrBcBal1-_w/TweetDetail`;
            let variables = {
                "focalTweetId": status_id,
                "with_rux_injections": false,
                "rankingMode": "Relevance",
                "includePromotedContent": true,
                "withCommunity": true,
                "withQuickPromoteEligibilityTweetFields": true,
                "withBirdwatchNotes": true,
                "withVoice": true
            };
            let features = {
                "rweb_video_screen_enabled": false,
                "profile_label_improvements_pcf_label_in_post_enabled": true,
                "rweb_tipjar_consumption_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,
                "premium_content_api_read_enabled": false,
                "communities_web_enable_tweet_community_results_fetch": true,
                "c9s_tweet_anatomy_moderator_badge_enabled": true,
                "responsive_web_grok_analyze_button_fetch_trends_enabled": false,
                "responsive_web_grok_analyze_post_followups_enabled": true,
                "responsive_web_jetfuel_frame": false,
                "responsive_web_grok_share_attachment_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,
                "responsive_web_grok_show_grok_translated_post": false,
                "responsive_web_grok_analysis_button_from_backend": 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,
                "longform_notetweets_rich_text_read_enabled": true,
                "longform_notetweets_inline_media_enabled": true,
                "responsive_web_grok_image_annotation_enabled": true,
                "responsive_web_enhance_cards_enabled": false
            };
            let fieldToggles = {
                "withArticleRichContentState": true,
                "withArticlePlainText": false,
                "withGrokAnalyze": false,
                "withDisallowedReplyControls": false
            };

            // Custom encoding function to ensure specials chars becomes their %XX versions
            const customEncode = (obj) => {
                return JSON.stringify(obj)
                    .replace(/:/g, '%3A')
                    .replace(/,/g, '%2C')
                    .replace(/{/g, '%7B')
                    .replace(/}/g, '%7D');
            };

            let url = `${base_url}?variables=${customEncode(variables)}&features=${customEncode(features)}&fieldToggles=${customEncode(fieldToggles)}`;

            let cookies = this.getCookie();
            let headers = {
                'authorization': 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA',
                'x-twitter-active-user': 'yes',
                'x-twitter-client-language': cookies.lang,
                'x-csrf-token': cookies.ct0
            };

            // Add guest token if ct0 has length of 32
            if (cookies.ct0.length == 32) headers['x-guest-token'] = cookies.gt;

            // Fetch and process the tweet
            let tweet_detail = await fetch(url, {headers: headers}).then(result => {
                console.log(result);
                return result.json()
            });

            let tweet_entrie = tweet_detail.data.threaded_conversation_with_injections_v2.instructions[0].entries.find(n => n.entryId == `tweet-${status_id}`);
            let tweet_result = tweet_entrie.content.itemContent.tweet_results.result;
            return tweet_result.tweet || tweet_result;
        },
§
投稿日: 2025/04/26

yea i went a bit on a search and totally forgot that gallery-dl also used the same old entry
it requires a transaction-id now but instead of using it right now they're using another work around with something called "restid"
link to github issue > https://github.com/mikf/gallery-dl/issues/7382 <
im not smarty pants with that stuff, so even the 10min of me trying to figure it out i gave up lmao

§
投稿日: 2025/04/26
編集日: 2025/04/26

Has anyone been able to crack down a hotfix?

§
投稿日: 2025/04/26

Flkalas the one who made "TwitterMediaAssist" said this about his extension on GibHub. Should a workaround exist, hopefully it can fix this one too.

返信を投稿

返信を投稿するにはログインしてください。