Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] Twitter feeds? #454

Open
Darthagnon opened this issue Aug 23, 2022 · 3 comments
Open

[Feature Request] Twitter feeds? #454

Darthagnon opened this issue Aug 23, 2022 · 3 comments

Comments

@Darthagnon
Copy link

Darthagnon commented Aug 23, 2022

No, it's impossible. If your reader can support adding local RSS and loading article images, it may still be possible. thank you.

chrome_wwSVFbRSz1
Not sure what you mean by "image articles", but FeedBro supports it, loading plaintext and images. They must be using a custom workaround, maybe something like this. Currently, attempts to add a Twitter feed to FluentReader gives an XML parse error (possibly related: #429)

Originally posted by @Darthagnon in #23 (comment)

@Darthagnon
Copy link
Author

Darthagnon commented Aug 23, 2022

Been doing some more research. Here's the blog article explaining how a dev implemented RSS feeds from twitter back in the day (and here is his Gist.

I've also taken a brief look at the Feedbro source (available, once you install the Feedbro extension, at
C:\Users\Username\AppData\Local\Publisher\Browser\User Data\Default\Extensions\mefgmmbdailogpfhfblcnnjfmnpnmdfa\version\scripts-core\feedbro.min.js

@Darthagnon
Copy link
Author

Darthagnon commented Aug 23, 2022

Relevant snippet of feedbro.min.js

I don't fully understand it, but seeing an authtoken and a bunch of references to graphQL, I'm wondering if Feedbro is abusing a workaround in Twitter's social network sharing graphQL implementation to extract images and stringified text?

Click me to see the code; I am very very long (~760 lines JS)
feedbro.TwPlugin.authToken = "AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA";
feedbro.TwPlugin.cachedToken = null;
feedbro.TwPlugin.prototype.canParse = function (b) {
    if (b == undefined || b == "") {
        return false
    }
    b = this.mapUrl(b);
    var c = b.substring(0, 20);
    var a = b.substring(20);
    return c == "https://twitter.com/" && a != "notifications" && a != "home" && a.indexOf("messages") != 0 && a.indexOf("i/bookmarks") != 0
};
feedbro.TwPlugin.prototype.mapUrl = function (a) {
    if (a && a.substring(0, 26) == "https://mobile.twitter.com") {
        a = "https://twitter.com/" + a.substring(27)
    }
    return a
};
feedbro.TwPlugin.prototype.parse = function (d, c, a, e) {
    var b = this;
    d.url = this.mapUrl(d.url);
    this.getCachedGuestToken(function (f) {
        b.doParse(d, c, a, e)
    })
};
feedbro.TwPlugin.prototype.getCachedGuestToken = function (a) {
    if (feedbro.TwPlugin.cachedToken == null || this.isTokenExpired(feedbro.TwPlugin.cachedToken)) {
        this.getGuestToken(function (b) {
            if (b && b.token) {
                feedbro.TwPlugin.cachedToken = b
            } else {
                feedbro.TwPlugin.cachedToken = {
                    remaining: 0,
                    init: 0
                }
            }
            a(b)
        })
    } else {
        feedbro.TwPlugin.cachedToken.lastUse = new Date().getTime();
        a(feedbro.TwPlugin.cachedToken)
    }
};
feedbro.TwPlugin.prototype.getGuestToken = function (a) {
    fetchTimeout("https://api.twitter.com/1.1/guest/activate.json", 20000, {
        method: "POST",
        credentials: "omit",
        headers: {
            authorization: "Bearer " + feedbro.TwPlugin.authToken,
            "accept-language": "en-US,en;q=0.5",
            accept: "text/html,application/json,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
        }
    }).then(function (b) {
        return b.json()
    }).then(function (c) {
        var b = new Date().getTime();
        if (c == null) {
            c = {}
        }
        a({
            token: c.guest_token,
            remaining: 187,
            init: b,
            reset: b + (15 * 60 * 1000),
            lastUse: b
        })
    })["catch"](a)
};
feedbro.TwPlugin.prototype.isTokenExpired = function (b) {
    var d = 2 * 60 * 60 * 1000;
    var c = 1 * 60 * 60 * 1000;
    var a = new Date().getTime();
    return b == null || b.init < (a - d) || b.remaining < 10 || a > b.reset || b.lastUse < (a - c)
};
feedbro.TwPlugin.prototype.doParse = function (f, d, a, g) {
    var b = this;
    try {
        this.getUrl(f.url, a, function (l, j, h, k) {
            try {
                if (j && j.globalObjects) {
                    d(f.url, l, b.parseTweets(j, h, k), a, g, true)
                } else {
                    d(f.url, l, b.parseTimeline(j, h, k), a, g, true)
                }
            } catch (i) {
                d(f.url, l, "", a, g, true)
            }
        })
    } catch (c) {
        var e = new feedbro.FetchWrapper(500);
        a.error = {};
        a.error.message = "Internal Server Error";
        a.error.code = 500;
        a.status = 500;
        d(f.url, e, "", a, g, true)
    }
};
feedbro.TwPlugin.prototype.getUserProfile = function (c, a, e) {
    var d = c.match(/^https:\/\/twitter\.com\/(\w+)/)[1];
    var b = "https://twitter.com/i/api/graphql/7mjxD3-C6BxitPMVQ6w0-Q/UserByScreenName?variables=%7B%22screen_name%22%3A%22" + d + "%22%2C%22withSafetyModeUserFields%22%3Atrue%2C%22withSuperFollowsUserFields%22%3Atrue%7D";
    this.loadJson(b, a, function (g, f) {
        e(f, c)
    })
};
feedbro.TwPlugin.prototype.getThread = function (c, a, d) {
    var b = this;
    this.getUserProfile(c, a, function (f, e) {
        b.loadThread(e, f, a, d)
    })
};
feedbro.TwPlugin.prototype.loadThread = function (a, c, i, h) {
    var f = 0;
    var d = a.match(/status\/(\d+)/);
    if (d) {
        f = d[1]
    }
    var e = 0;
    if (c && c.data && c.data.user) {
        if (c.data.user.result) {
            e = c.data.user.result.rest_id
        } else {
            e = c.data.user.rest_id
        }
    }
    var b = {
        focalTweetId: f,
        with_rux_injections: false,
        includePromotedContent: true,
        withCommunity: true,
        withQuickPromoteEligibilityTweetFields: true,
        withBirdwatchNotes: false,
        withSuperFollowsUserFields: true,
        withDownvotePerspective: false,
        withReactionsMetadata: false,
        withReactionsPerspective: false,
        withSuperFollowsTweetFields: true,
        withVoice: true,
        withV2Timeline: false,
        __fs_dont_mention_me_view_api_enabled: false,
        __fs_interactive_text_enabled: true,
        __fs_responsive_web_uc_gql_enabled: false
    };
    var g = "https://twitter.com/i/api/graphql/LJ_TjoWGgNTXCl7gfx4Njw/TweetDetail?variables=" + encodeURIComponent(JSON.stringify(b));
    this.loadJson(g, i, function (l, j) {
        var k;
        if (c && c.data && c.data.user) {
            if (c.data.user.result) {
                k = c.data.user.result.legacy
            } else {
                if (c.data.user.legacy) {
                    k = c.data.user.legacy
                }
            }
        }
        if (k) {
            h(l, j, a, e != 0 ? (k.name + " (@" + k.screen_name + ") Thread " + f + " | Twitter") : "")
        } else {
            h(l, j, a, "Suspended")
        }
    })
};
feedbro.TwPlugin.prototype.loadUserTweets = function (c, e, a, g) {
    var d = 0;
    if (e && e.data && e.data.user) {
        if (e.data.user.result) {
            d = e.data.user.result.rest_id
        } else {
            d = e.data.user.rest_id
        }
    }
    var f = {
        userId: d,
        count: 40,
        includePromotedContent: true,
        withQuickPromoteEligibilityTweetFields: true,
        withSuperFollowsUserFields: true,
        withBirdwatchPivots: false,
        withDownvotePerspective: false,
        withReactionsMetadata: false,
        withReactionsPerspective: false,
        withSuperFollowsTweetFields: true,
        withVoice: true,
        withV2Timeline: false,
        __fs_interactive_text: false,
        __fs_dont_mention_me_view_api_enabled: false
    };
    var b = "https://twitter.com/i/api/graphql/DhQ8lYnLh5T5K8aVUgHVnQ/UserTweets?variables=" + encodeURIComponent(JSON.stringify(f));
    this.loadJson(b, a, function (j, h) {
        var i;
        if (e && e.data && e.data.user) {
            if (e.data.user.result) {
                i = e.data.user.result.legacy
            } else {
                if (e.data.user.legacy) {
                    i = e.data.user.legacy
                }
            }
        }
        if (i) {
            g(j, h, c, d != 0 ? (i.name + " (@" + i.screen_name + ") | Twitter") : "")
        } else {
            g(j, h, c, "Suspended")
        }
    })
};
feedbro.TwPlugin.prototype.getUserTweets = function (c, a, d) {
    var b = this;
    this.getUserProfile(c, a, function (f, e) {
        b.loadUserTweets(e, f, a, d)
    })
};
feedbro.TwPlugin.prototype.getListTweets = function (d, a, f) {
    var b = d.match(/^https:\/\/twitter\.com\/i\/lists\/(\d+)/)[1];
    var e = {
        listId: b,
        count: 20,
        withSuperFollowsUserFields: true,
        withBirdwatchPivots: false,
        withDownvotePerspective: false,
        withReactionsMetadata: false,
        withReactionsPerspective: false,
        withSuperFollowsTweetFields: true,
        __fs_interactive_text: false,
        __fs_dont_mention_me_view_api_enabled: false
    };
    var c = "https://twitter.com/i/api/graphql/mwIBwcZV981Bnjb2lPNYfw/ListLatestTweetsTimeline?variables=" + encodeURIComponent(JSON.stringify(e));
    this.loadJson(c, a, function (h, g) {
        f(h, g, d, "List " + b)
    })
};
feedbro.TwPlugin.prototype.getHashtagTweets = function (g, d, i) {
    var e = g.indexOf("hashtag/") + 8;
    var c = g.indexOf("?", e);
    var h = g.substring(e, c > 0 ? c : g.length);
    var f = "https://api.twitter.com/2/search/adaptive.json?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&skip_status=1&cards_platform=Web-12&include_cards=1&include_ext_alt_text=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&send_error_codes=true&simple_quoted_tweet=true&q=%23" + h + "&count=20&query_source=hashtag_click&pc=1&spelling_corrections=1&ext=mediaStats%2ChighlightedLabel%2CcameraMoment&include_quote_count=true";
    if (g.indexOf("&f=live") != -1) {
        f = f + "&tweet_search_mode=live"
    }
    this.loadJson(f, d, function (b, a) {
        i(b, a, g, "#" + decodeURIComponent(h) + " - Search")
    })
};
feedbro.TwPlugin.prototype.getSearchTweets = function (g, d, i) {
    var e = g.indexOf("q=") + 2;
    var c = g.indexOf("&", e);
    var h = g.substring(e, c > 0 ? c : g.length);
    var f = "https://api.twitter.com/2/search/adaptive.json?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&skip_status=1&cards_platform=Web-12&include_cards=1&include_ext_alt_text=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&send_error_codes=true&simple_quoted_tweet=true&q=" + h + "&count=20&query_source=typed_query&pc=1&spelling_corrections=1&ext=mediaStats%2ChighlightedLabel%2CcameraMoment&include_quote_count=true";
    if (g.indexOf("&f=live") != -1) {
        f = f + "&tweet_search_mode=live"
    }
    this.loadJson(f, d, function (b, a) {
        i(b, a, g, decodeURIComponent(h) + " - Search")
    })
};
feedbro.TwPlugin.prototype.getExploreTweets = function (c, a, d) {
    var b = "https://api.twitter.com/2/guide.json?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&skip_status=1&cards_platform=Web-12&include_cards=1&include_ext_alt_text=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&send_error_codes=true&simple_quoted_tweet=true&include_page_configuration=true&count=20&ext=mediaStats%2ChighlightedLabel%2CcameraMoment&include_quote_count=true";
    this.loadJson(b, a, function (f, e) {
        d(f, e, c, "Explore")
    })
};
feedbro.TwPlugin.prototype.loadJson = function (c, b, d) {
    var a = new feedbro.FetchWrapper(500);
    fetchTimeout(c, 20000, {
        method: "GET",
        credentials: "omit",
        headers: {
            authorization: "Bearer " + feedbro.TwPlugin.authToken,
            "accept-language": "en-US,en;q=0.5",
            accept: "*/*",
            "x-guest-token": feedbro.TwPlugin.cachedToken ? feedbro.TwPlugin.cachedToken.token : "",
            "x-twitter-client-language": "en",
            "x-twitter-active-user": "yes",
            "cache-control": "no-cache"
        }
    }).then(function (e) {
        a.status = e.status + 0;
        if (e.status == 200) {
            if (feedbro.TwPlugin.cachedToken) {
                feedbro.TwPlugin.cachedToken.remaining = parseInt(e.headers.get("x-rate-limit-remaining") || "0", 10);
                feedbro.TwPlugin.cachedToken.reset = parseInt(e.headers.get("x-rate-limit-reset"), 10) * 1000
            }
            return e.json()
        } else {
            throw new Error(e.status + 0)
        }
    }).then(function (e) {
        d(a, e)
    })["catch"](function (e) {
        if (e.name == "AbortError") {
            b.error = {};
            b.error.message = "Network error";
            b.error.code = 398;
            b.status = 398;
            a.status = 0
        }
        d(a, null)
    })
};
feedbro.TwPlugin.prototype.getUrl = function (c, a, d) {
    var b = c.substring(20);
    if (b.indexOf("i/lists/") == 0) {
        this.getListTweets(c, a, d)
    } else {
        if (b.indexOf("hashtag/") == 0) {
            this.getHashtagTweets(c, a, d)
        } else {
            if (b.indexOf("search?") == 0) {
                this.getSearchTweets(c, a, d)
            } else {
                if (b.indexOf("explore") == 0) {
                    this.getExploreTweets(c, a, d)
                } else {
                    if (b != "notifications" && b.indexOf("messages") != 0 && b.indexOf("i/bookmarks") != 0) {
                        this.getUserTweets(c, a, d)
                    } else {
                        d(undefined)
                    }
                }
            }
        }
    }
};
feedbro.TwPlugin.prototype.parseTweets = function (B, c, C) {
    var t = '<?xml version="1.0" encoding="UTF-8"?>\n<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">\n<channel>\n';
    if (B != undefined) {
        var j = /#(\D\S+)/g;
        var g = /@(\w+)/g;
        var r = /\b(?:https?|ftp):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim;
        var k = [];
        var b;
        var q = B.globalObjects.tweets;
        var n = B.globalObjects.users;
        var u,
        a,
        D,
        m = Object.keys(q);
        var y;
        var w;
        var p;
        var e;
        var s;
        var o;
        var f;
        var x;
        var A;
        var l;
        var h;
        var v;
        var z;
        m.sort(function (E, i) {
            return new Date(q[i].created_at).getTime() - new Date(q[E].created_at).getTime()
        });
        try {
            for (u = 0; u < m.length; u++) {
                a = q[m[u]];
                x = a;
                if (a.source == 0) {
                    continue
                }
                D = n[a.user_id_str];
                o = D;
                f = a.id_str;
                s = a.created_at;
                if (a.retweeted_status_id_str != undefined) {
                    z = a.retweeted_status_id_str;
                    a = q[z];
                    D = n[a.user_id_str];
                    q[z].source = 0
                }
                A = undefined;
                e = undefined;
                if (a.is_quote_status) {
                    A = a.full_text;
                    if (q[a.quoted_status_id_str] != undefined) {
                        e = q[a.quoted_status_id_str];
                        q[a.quoted_status_id_str].source = 0
                    }
                }
                y = undefined;
                w = undefined;
                v = this.getContent(a);
                y = v.card;
                w = v.media;
                p = this.getAuthorHeader(D, x.retweeted_status_id_str != undefined ? o : null, a);
                b = {
                    author: o.name + " (@" + o.screen_name + ")",
                    publishedDate: new Date(s),
                    guid: o.screen_name + "-" + f,
                    link: "https://twitter.com/" + o.screen_name + "/status/" + f,
                    content: a.full_text,
                    title: this._strings.truncate((A || a.full_text).replace(r, ""), 100, "&#x2026;")
                };
                b.content = "<p class='tweet-text'>" + b.content + "</p>";
                b.content = feedbro.Strings.linkify(b.content, true, "twitter-tweet-link");
                b.content = b.content.replace(j, this.hashtagMapper);
                b.content = b.content.replace(g, this.usernameMapper);
                if (w && !y) {
                    b.content += w
                }
                if (y) {
                    b.content += y
                }
                if (e) {
                    h = "";
                    D = n[e.user_id_str];
                    v = this.getContent(e);
                    l = e.full_text;
                    l = feedbro.Strings.linkify(l, true, "twitter-tweet-link");
                    l = l.replace(j, this.hashtagMapper);
                    l = l.replace(g, this.usernameMapper);
                    h += "<div class='twitter-quoted-tweet'>";
                    h += "  <div class='twitter-quoted-author'>";
                    h += "    <img class='twitter-authorimage-quoted' src='" + D.profile_image_url_https + "'>";
                    h += "    <span class='twitter-author-name-quoted'>" + D.name + "</span>";
                    h += "    <span class='twitter-author-username-quoted'><a target='_blank' class='twitter-username' href='https://twitter.com/" + D.screen_name + "' rel='noopener noreferrer'>@" + D.screen_name + "</a></span>";
                    h += "    <span class='twitter-timestamp-quoted'> &#183; " + this.getDateTag(e.created_at, D, e.id_str) + "</span>";
                    h += "  </div>";
                    h += "  <div class='twitter-quoted-content'>" + l + "</div>";
                    if (v.media && !v.card) {
                        h += v.media
                    } else {
                        if (v.card) {
                            h += v.card
                        }
                    }
                    h += "</div>";
                    b.content += h
                }
                b.content = p + b.content;
                if (A) {
                    b.content += "</div>"
                }
                k.push(b)
            }
        } catch (d) {}
        return feedbro.Strings.toRSS(C + " | Twitter", c, k)
    } else {
        t += "	<title>No Content Found</title>\n";
        t += "	<link>" + c.replace(/&/g, "&amp;") + "</link>\n"
    }
    t += "</channel>\n</rss>";
    return t
};
feedbro.TwPlugin.prototype.getSizeAttribute = function (a) {
    if (a && a.original_info) {
        return "width='" + a.original_info.width + "' height='" + a.original_info.height + "' "
    } else {
        return ""
    }
};
feedbro.TwPlugin.prototype.getContent = function (l) {
    var f,
    d,
    a,
    h,
    g,
    b,
    m,
    c,
    k,
    i;
    if (l.extended_entities && l.extended_entities.media) {
        d = this.getMedia(l)
    }
    if (l.card && l.card.binding_values && l.card.name != "promo_website") {
        f = this.createCardWithAttributes(l.card.binding_values, l.card.url)
    }
    return {
        card: f,
        media: d
    }
};
feedbro.TwPlugin.prototype.linkMapper = function (b, a) {
    return "<a target='_blank' class='twitter-tweet-link' rel='noopener noreferrer' href='" + b + "'>" + a + "</a>"
};
feedbro.TwPlugin.prototype.hashtagMapper = function (a, b) {
    return "<a target='_blank' class='twitter-hashtag' rel='noopener noreferrer' href='https://twitter.com/hashtag/" + b + "?src=hashtag_click'>#" + b + "</a>"
};
feedbro.TwPlugin.prototype.usernameMapper = function (b, a) {
    return "<a target='_blank' class='twitter-username' rel='noopener noreferrer' href='https://twitter.com/" + a + "'>" + b + "</a>"
};
feedbro.TwPlugin.prototype.parseTimeline = function (b, a, d) {
    var c = this.parseTwitterTimeline(b, d);
    if (c.title == null && a != null) {
        c.title = a.substring(a.lastIndexOf("/") + 1) + " | Twitter"
    }
    return feedbro.Strings.toRSS(c.title || "User | Twitter", a || "", c.items)
};
feedbro.TwPlugin.prototype.parseTwitterTimeline = function (s, c) {
    var l = [];
    var f,
    k;
    var e,
    g,
    q,
    d,
    b,
    m,
    a = c,
    p;
    if (s.data.user) {
        if (s.data.user.result.timeline_v2) {
            f = s.data.user.result.timeline_v2.timeline.instructions
        } else {
            f = s.data.user.result.timeline.timeline.instructions
        }
    } else {
        if (s.data.list) {
            f = s.data.list.tweets_timeline.timeline.instructions
        } else {
            if (s.data.threaded_conversation_with_injections) {
                f = s.data.threaded_conversation_with_injections.instructions
            }
        }
    }
    for (e = 0; e < f.length; e++) {
        k = f[e];
        if (k.entries) {
            for (g = 0; g < k.entries.length; g++) {
                l.push(k.entries[g])
            }
        } else {
            if (k.entry && k.type == "TimelinePinEntry") {
                l.push(k.entry)
            }
        }
    }
    var o = [];
    var n = /\b(?:https?|ftp):\/\/[a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|]/gim;
    for (e = 0; e < l.length; e++) {
        q = l[e];
        if (q.content.entryType == "TimelineTimelineItem") {
            if (q.content.itemContent.tweet_results == null) {
                continue
            }
            b = q.content.itemContent.tweet_results.result;
            if (b == null || b.tombstone) {
                continue
            }
            var h;
            if (b.core == null && b.tweet && b.tweet.legacy) {
                d = b.tweet.core.user_results.result.legacy;
                h = b.tweet.legacy
            } else {
                if (b.core) {
                    d = b.core.user_results.result.legacy;
                    h = b.legacy
                } else {
                    continue
                }
            }
            if (h.retweeted_status_result) {
                m = this.getRetweet(h.retweeted_status_result.result, d);
                p = h.retweeted_status_result.result.legacy.full_text
            } else {
                m = this.getAuthorHeader(d, null, h);
                m += this.getTweetBody(h) + this.getMedia(h) + this.getCard(b) + this.getQuote(b);
                p = h.full_text
            }
            p = this._strings.truncate(p.replace(n, ""), 100, "&#x2026;");
            var r = {
                publishedDate: new Date(h.created_at),
                author: d.name + " (@" + d.screen_name + ")",
                content: m,
                title: p,
                link: "https://twitter.com/" + d.screen_name + "/status/" + h.id_str
            };
            o.push(r);
            if (a == null) {
                a = d.name + " (@" + d.screen_name + ") | Twitter"
            }
        }
    }
    return {
        title: a,
        items: o
    }
};
feedbro.TwPlugin.prototype.createTweetTextHtml = function (d) {
    var c = d.full_text;
    c = c.replace(/#(\D\S+)/g, this.hashtagMapper);
    c = c.replace(/@(\w+)/g, this.usernameMapper);
    if (d.entities && d.entities.urls && d.entities.urls.length > 0) {
        var a,
        b = d.entities.urls;
        for (a = 0; a < b.length; a++) {
            c = c.replace(b[a].url, "<a class='twitter-tweet-link' target='_blank' rel='noopener noreferrer' href='" + b[a].expanded_url + "'>" + b[a].display_url + "</a>")
        }
    }
    return c
};
feedbro.TwPlugin.prototype.getAuthorHeader = function (b, d, a) {
    var c = "<header>";
    if (d != null) {
        c += "  <div class='twitter-retweet-header'>" + d.name + " Retweeted</div>"
    }
    c += "  <a target='_blank' href='https://twitter.com/" + b.screen_name + "' rel='noopener noreferrer'>";
    c += "    <img class='twitter-authorimage' alt='' src='" + b.profile_image_url_https + "'>";
    c += "  </a><span class='twitter-fullname'>" + b.name + "</span>";
    c += "  <span><a target='_blank' class='twitter-username' href='https://twitter.com/" + b.screen_name + "' rel='noopener noreferrer'>@" + b.screen_name + "</a></span>";
    c += "</header>";
    return c
};
feedbro.TwPlugin.prototype.getDateTag = function (f, d, h) {
    var b = new Date(f);
    if (isNaN(b) || d == null) {
        return ""
    }
    var c = this._months[b.getMonth()] + " " + b.getDate();
    var a = b.getHours(),
    e = b.getMinutes();
    var g = (a < 10 ? "0" + a : a) + ":" + (e < 10 ? "0" + e : e) + " " + c + ", " + b.getFullYear();
    return "<a class='twitter-timestamp' title='" + g + "' href='https://twitter.com/" + d.screen_name + "/status/" + h + "' target='_blank' rel='noopener noreferrer'>" + c + "</a>"
};
feedbro.TwPlugin.prototype.getRetweet = function (a, d) {
    if (a == null || a.core == null || a.core.user_results == null || a.core.user_results.result == null || a.core.user_results.result.legacy == null || a.legacy == null || a.tombstone || a.legacy.tombstone) {
        return "<div class='twitter-deleted-tweet'>This tweet is not available.</div>"
    }
    var c = a.core.user_results.result.legacy;
    var b = a.legacy;
    return this.getAuthorHeader(c, d, b) + this.getTweetBody(b) + this.getMedia(b) + this.getCard(a) + this.getQuote(a)
};
feedbro.TwPlugin.prototype.getQuote = function (e) {
    if (e.quoted_status_result) {
        var a = e.quoted_status_result;
        if (a.result.tombstone) {
            return "<div class='twitter-quoted-tweet'>This tweet was deleted by the Tweet author.</div>"
        } else {
            var c = a.result.core.user_results.result.legacy;
            var b = a.result.legacy;
            var d = this.createTweetTextHtml(b) + this.getMedia(b);
            return this.getQuoteHtml(c, d, b.created_at, b.id_str)
        }
    } else {
        return ""
    }
};
feedbro.TwPlugin.prototype.getQuoteHtml = function (a, c, d, e) {
    var b = "";
    b += "<div class='twitter-quoted-tweet'>";
    b += "  <div class='twitter-quoted-author'>";
    b += "    <img class='twitter-authorimage-quoted' alt='' src='" + a.profile_image_url_https + "'>";
    b += "    <span class='twitter-author-name-quoted'>" + a.name + "</span>";
    b += "    <span class='twitter-author-username-quoted'><a target='_blank' class='twitter-username' href='https://twitter.com/" + a.screen_name + "' rel='noopener noreferrer'>@" + a.screen_name + "</a></span>";
    b += "    <span class='twitter-timestamp-quoted'> &#183; " + this.getDateTag(d, a, e) + "</span>";
    b += "  </div>";
    b += "  <div class='twitter-quoted-content'>" + c + "</div>";
    b += "</div>";
    return b
};
feedbro.TwPlugin.prototype.getCard = function (b) {
    if (b.card && !b.quoted_status_result && b.card.name != "promo_website") {
        var e = b.card;
        var f,
        d,
        c = b.card.legacy.binding_values,
        a = {};
        for (f = 0; f < c.length; f++) {
            d = c[f];
            a[d.key] = d.value
        }
        return this.createCardWithAttributes(a, e.legacy.url)
    } else {
        return ""
    }
};
feedbro.TwPlugin.prototype.createCardWithAttributes = function (b, f) {
    var i,
    d,
    c,
    h,
    g;
    i = "<div class='twitter-card'>";
    i += "<a target='_blank' rel='noopener noreferrer' class='twitter-card-url' href='" + f + "'>";
    if (b.photo_image_full_size) {
        g = b.photo_image_full_size.image_value;
        d = g.url
    } else {
        if (b.photo_image_full_size_large) {
            g = b.photo_image_full_size_large.image_value;
            d = g.url
        } else {
            if (b.photo_image_full_size_small) {
                g = b.photo_image_full_size_small.image_value;
                d = g.url
            }
        }
    }
    if (b.thumbnail_image_large) {
        h = b.thumbnail_image_large.image_value
    } else {
        if (b.thumbnail_image) {
            h = b.thumbnail_image.image_value
        }
    }
    if (d) {
        c = "width='" + g.width + "' height='" + g.height + "'";
        i += "<div class='twitter-card-image'><img alt='' src='" + d + "' " + c + "></div>"
    } else {
        if (h) {
            i += "<div class='twitter-thumb'><img alt='' class='twitter-thumb-image' src='" + h.url + "'></div>"
        }
    }
    if (b.title && b.title.string_value) {
        i += "<div class='twitter-card-title'>" + this._strings.escapeHtml(b.title.string_value) + "</div>"
    }
    if (b.description && b.description.string_value) {
        i += "<div class='twitter-card-description'>" + this._strings.escapeHtml(b.description.string_value) + "</div>"
    }
    if (b.domain) {
        i += "<div class='twitter-card-url'>" + b.domain.string_value + "</div>"
    }
    i += "</a></div>";
    return i
};
feedbro.TwPlugin.prototype.getTweetBody = function (a) {
    return "<p class='tweet-text'>" + this.createTweetTextHtml(a) + "</p>"
};
feedbro.TwPlugin.prototype.getMedia = function (g) {
    if (g.extended_entities && g.extended_entities.media) {
        var f = g.extended_entities.media[0];
        var e,
        b,
        d = "";
        if (f.type == "photo") {
            b = this.getSizeAttribute(f);
            d = "<div class='twitter-media-photo'><img alt='' class='twitter-media-photo' " + b + "src='" + f.media_url_https + "'></div>"
        } else {
            if ((f.type == "video" || f.type == "animated_gif") && f.video_info && f.video_info.variants && f.video_info.variants.length > 0) {
                var c = f.video_info.variants;
                var a = c[0];
                if (a.bitrate == undefined) {
                    a.bitrate = 0
                }
                for (e = 1; e < c.length; e++) {
                    if (c[e].bitrate > a.bitrate) {
                        a = c[e]
                    }
                }
                b = this.getSizeAttribute(f);
                d = "<div>";
                d += '<div class="youtubevideo" data-link="' + a.url + '"><img alt="" src="' + f.media_url_https + '" ' + b + ' class="thumb"><div class="play"></div></div>';
                d += "</div>"
            }
        }
        return d
    } else {
        return ""
    }
};
feedbro.TwPlugin.prototype.testParse = function (b, c) {
    var a = this;
    fetch(b).then(function (d) {
        return d.json()
    }).then(function (d) {
        c(a.parseTimeline(d), a.parseTimelineHtml(d))
    })
};
feedbro.TwPlugin.prototype.parseTimelineHtml = function (d, a) {
    var e = this.parseTwitterTimeline(d)

@rauldipeas
Copy link

I'm getting the Twitter feed through Nitter, with images, videos and so on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants