Commit Graph
25 Commits
Author SHA1 Message Date
4cuckandCursor 5219453120 Add the profile posts menu and stop treating prices as tickers.
Hide Articles unless that account has some, and leave amounts like $250,000 as plain text.

Co-authored-by: Cursor <[email protected]>
2026-10-25 21:04:19 +00:00
4cuckandCursor 74c1afa0e2 Add a profile Articles tab so long posts can be opened from the account.
The list uses the same UserArticlesTweets query the web client sends, and each card opens the article page.

Co-authored-by: Cursor <[email protected]>
2026-10-25 20:29:20 +00:00
4cuckandCursor 2689a1f1d4 Add Explore, game highlights, and trending stories.
Move accounts that cannot change their settings out of the live pool so they can be fixed later.

Co-authored-by: Cursor <[email protected]>
2026-10-20 08:08:43 +00:00
4cuckandCursor 5094ab658e Add broadcast and community pages plus HLS playback, and tighten preferences.
Skip the Cloudflare cache warning when media is not proxied.

Co-authored-by: Cursor <[email protected]>
2026-10-12 22:50:25 +00:00
4cuck 5d609d621e Read X's live GraphQL ids, skip accounts X refuses search, and stop retry loops.
- Read each operation's current query id and feature flags from X's web
  client, keep them in graphql-ops.json, refresh them hourly, and read them
  again when two accounts get nothing back for the same call.
- Leave an account out of an operation for a day when X answers it with an
  empty 404 while another account gets results. Check unchecked accounts'
  search access in the background and prefer accounts known to work.
- Send search the way Chrome does (variables, features, referer) and load
  X's script chunks with Chrome's headers. Keep a transaction-id refusal only
  when dropping the id helped.
- Require three handshakes before using a browser version; one lucky
  handshake let Chrome 152 through while X refused it.
- Add a round-robin fallback proxy pool for HTML 429s, with clients shared
  per browser so exits reuse connections.
- Drop the browser auto-retry and the per-account retries on empty answers,
  and log expected empty answers at trace.
2026-10-09 20:42:33 +00:00
4cuck b8fe22b76d Add a Lists search tab and open list pages with their banner and posts. 2026-10-06 04:20:29 +00:00
4cuck 979b7b89cf Add a profile Reposts tab and send X requests in the captured Chrome header order. 2026-10-06 02:55:30 +00:00
4cuck 164d631694 Present every account as a real browser and speed up the upstream path.
The hand-rolled hyper/rustls transport advertised a rustls ClientHello with
http/1.1 only, a fingerprint no browser has. Requests now go through primp:
each session gets its own client with a browser's TLS and HTTP/2 fingerprint
and matching headers, drawn from the session id so an account keeps its
browser across restarts like its proxy port. The mix is weighted like desktop
traffic and the OS always fits the engine. Each engine uses the newest version
X's edge accepts, found by a handshake at startup, since Chrome 152 is refused.
Sessions multiplex one pinged HTTP/2 connection each and resume TLS with PSK.

Also: parse each GraphQL body once instead of twice; cut the photo rail from
the cached media page (and file a fetched one) so a profile view and the media
tab share one UserMedia call; skip the duplicate TweetDetail on article posts;
probe SOCKS exits concurrently (startup 12s to 2.5s); stop taking a write lock
per request in the transaction-id refusal check and refresh the id client in
the background.
2026-09-06 17:40:03 +00:00
4cuck 57b64c3b73 Lift X's adult-media age gate and finish the search layout.
Cookie sessions now get a private adult birthdate written once so media stops rendering as the birthdate interstitial. Search drops the broken Lists tab and the timeline/media UI stays consistent with the rest of the layout.
2026-09-02 22:29:42 +00:00
4cuck 1e8707fa47 Turn off X's default NSFW filters on new cookie sessions.
New accounts hide sensitive media and strip it from search, which leaks into teapawt results; each cookie session now POSTs those settings off once at startup.
2026-08-31 14:20:35 +00:00
4cuck 78b57d7534 api: read X's about-account record 2026-08-29 21:43:42 -04:00
4cuck 02ba12c9a9 api: account every authenticated call against its session 2026-08-29 04:15:22 -04:00
4cuck cb0019f7c9 api: refresh the stale SearchTimeline query ID 2026-08-29 03:36:00 -04:00
4cuck 5695b439c9 discord: improve embeds 2026-07-15 16:26:29 -04:00
4cuck 8c59923835 all: cargo fmt 2026-03-20 03:04:00 -04:00
4cuck 29cb6e9010 translate: add click-to-translate for non-English tweets via htmx
Shows a 'Translate post' button on tweets where legacy.lang is not
English. Clicking it fires an htmx GET to /translate/{id} which calls
Twitter's Strato translation API (Google Translate backend) and swaps
the button with the translated text and source language header. Adds
lang and is_translatable fields to the API schema, a Translation
struct, and the translate_tweet client method with cookie-session auth.
2026-03-20 03:04:00 -04:00
4cuck 1c3de8bdfa rss: fix replies feed, deduplicate helpers, use references for threads
Three related RSS improvements:

1. UserRssKind::Replies was grouped with Tweets, calling get_user_tweets
   instead of get_user_tweets_and_replies. Add a dedicated
   user_tweets_and_replies_v2_vars builder for the OAuth path.

2. Remove duplicate strip_html and get_link wrappers from rss.rs — import
   strip_html from layout and tweet_link from renderutils directly.

3. Change render_thread_rss to accept &[&Tweet] instead of &Tweets to
   avoid cloning conversation tweets into a new Vec. The thread_rss route
   handler now builds Vec<&Tweet> references and inlines the Min-Id
   response header since rss_response expects &[Tweet].
2026-03-08 22:09:58 -04:00
4cuck 65b01f2467 all: cargo fmt 2026-03-04 02:57:07 -05:00
4cuck ab8ac3657f tweets: render content disclosure labels and mixed media in quoted tweets 2026-03-03 20:48:47 -05:00
4cuck a520a0b9db status: render /i/status/{id} inline via TweetDetail
TweetResultByIdQuery returns 404 for many tweets. Switch get_tweet to
delegate to get_conversation (TweetDetail endpoint) and return the main
tweet. The /i/status/{id} handler now renders the full conversation page
directly instead of redirecting, matching X.com client-side behaviour.

Remove the now-dead TweetResultByIdQuery endpoint, tweet_vars builder,
TweetResultData schema struct, parse_tweet function, and cache_keys::tweet.
2026-03-03 13:23:38 -05:00
4cuck 331829cd9a status: add retweets page, quotes page, and quote count stat
Retweets page (/{user}/status/{id}/retweets) lists users who retweeted
via the Retweeters GraphQL endpoint, with cursor-based infinite scroll.
Quotes page (/{user}/status/{id}/quotes) shows quoting tweets via search
for quoted_tweet_id:{id}. Both pages share a back-arrow + tab bar header.
The tweet stats row now links retweet count to the retweets page and shows
quote count (when >0) linking to the quotes page. infiniteScroll.js updated
to detect engagement pages and use the .timeline container.
2026-03-01 23:27:33 -05:00
4cuck 219078da24 status: add reply sort toggle (Relevant/Recent/Likes)
Maps Twitter's TweetDetail `rankingMode` variable (Relevance/Recency/Likes)
to a `?sort=` query param. The dropdown sits inside the main tweet's stats
row via TweetRenderer.sort_toggle(), uses CSS :focus-within for no-JS
open/close. Non-default sorts bypass the conversation cache. Also filters
promoted items inside conversationthread entries that were slipping through.
2026-03-01 23:27:33 -05:00
4cuck 9ad17b2f32 notes: add Twitter Articles rendering 2026-03-01 23:27:33 -05:00
4cuck 662aaf153f parser: skip promoted timeline entries and disable promoted content requests 2026-03-01 22:38:26 -05:00
4cuck 9a4cbf74f7 all: init twt 2026-03-01 22:38:26 -05:00