Twitter Media Downloader

Save Video/Photo by One-Click.

< 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.

댓글 남기기

댓글을 남기려면 로그인하세요.