-
-
Save cmj/998f59680e3549e7f181057074eccaa3 to your computer and use it in GitHub Desktop.
#!/bin/bash | |
# Grab oauth token for use with Nitter (requires Twitter account). | |
# results: {"oauth_token":"xxxxxxxxxx-xxxxxxxxx","oauth_token_secret":"xxxxxxxxxxxxxxxxxxxxx"} | |
# 2024-11-14: verified working again | |
# 2025-01-07: added 2FA support | |
username="" | |
password="" | |
# Two-Factor Authentication | |
# You can use any time-based one time password (TOTP) authentication app like Google Authenticator, Authy, Duo Mobile, 1Password, etc.) | |
# - Wait for prompt, use authentication app to get code. | |
# - OR enter here your one-time backup code (limit of 5 active codes, must be used in order created; out of order sequence revokes previous codes) | |
totp_code="" | |
if [[ -z "$username" || -z "$password" ]]; then | |
echo "needs username and password" | |
exit 1 | |
fi | |
bearer_token='AAAAAAAAAAAAAAAAAAAAAFXzAwAAAAAAMHCxpeSDG1gLNLghVe8d74hl6k4%3DRUMF4xAQLsbeBhTSRrCiQpJtxoGWeyHrDb5te2jpGskWDFW82F' | |
guest_token=$(curl -s -XPOST https://api.twitter.com/1.1/guest/activate.json -H "Authorization: Bearer ${bearer_token}" -d "grant_type=client_credentials" | jq -r '.guest_token') | |
base_url='https://api.twitter.com/1.1/onboarding/task.json' | |
header=(-H "Authorization: Bearer ${bearer_token}" -H "User-Agent: TwitterAndroid/10.21.0-release.0" -H "X-Twitter-Active-User: yes" -H "Content-Type: application/json" -H "X-Guest-Token: ${guest_token}") | |
# start flow | |
flow_1=$(curl -si -XPOST "${base_url}?flow_name=login&api_version=1&known_device_token=&sim_country_code=us" "${header[@]}" \ | |
-d '{"flow_token": null, "input_flow_data": {"country_code": null, "flow_context": {"referrer_context": {"referral_details": "utm_source=google-play&utm_medium=organic", "referrer_url": ""}, "start_location": {"location": "deeplink"}}, "requested_variant": null, "target_user_id": 0}}' | |
) | |
# get 'att', now needed in headers, and 'flow_token' from flow_1 | |
att=$(sed -En 's/^att: (.*)\r/\1/p' <<< "${flow_1}") | |
flow_token=$(sed -n '$p' <<< "${flow_1}" | jq -r .flow_token) | |
# username | |
token_2=$(curl -s -XPOST "${base_url}" -H "att: ${att}" "${header[@]}" \ | |
-d '{"flow_token": "'"${flow_token}"'", "subtask_inputs": [{"enter_text": {"suggestion_id": null, "text": "'"${username}"'", "link": "next_link"}, "subtask_id": "LoginEnterUserIdentifier"}]}' | jq -r .flow_token) | |
# password flow and print oauth_token and secret | |
flow_3=$(curl -s -XPOST "${base_url}" -H "att: ${att}" "${header[@]}" \ | |
-d '{"flow_token": "'"${token_2}"'", "subtask_inputs": [{"enter_password": {"password": "'"${password}"'", "link": "next_link"}, "subtask_id": "LoginEnterPassword"}]}') | |
token_3=$(jq -r .flow_token <<< "${flow_3}") | |
check_2fa=$(jq -r .subtasks[0].subtask_id <<< "${flow_3}") | |
if [[ "${check_2fa}" != "LoginTwoFactorAuthChallenge" ]]; then | |
jq -c '.subtasks[0]|if(.open_account) then {oauth_token: .open_account.oauth_token, oauth_token_secret: .open_account.oauth_token_secret} else empty end' <<< "${flow_3}" | |
exit 0 | |
fi | |
# 2FA stuff | |
if [[ -z "$totp_code" ]]; then | |
echo "@${username} - Use your code generator app to generate a code and enter it below." | |
read totp_code | |
fi | |
curl -s -XPOST "${base_url}" -H "att: ${att}" "${header[@]}" \ | |
-d '{"flow_token":"'"${token_3}"'","subtask_inputs":[{"subtask_id":"LoginTwoFactorAuthChallenge","enter_text":{"text":"'"${totp_code}"'","link":"next_link"}}]}' | | |
jq -c 'if(.subtasks[0].open_account) then {oauth_token: .subtasks[0].open_account.oauth_token, oauth_token_secret: .subtasks[0].open_account.oauth_token_secret} else .errors[0].message end' |
Hi @cmj , it is off topic but is there any graphql endpoint for X spaces from which I can find out the participants of a Space? I found one but it doesn't give all participants which is AudioSpaceById
. Is there maybe any which checks if a user is in the space?
Yeah that endpoint doesn't give every single listener. It breaks them out in 3 parts {admins,speakers,listeners}. I've monitored a number of "spaces" and that seems to have a limit on listeners
data, but it does change.
The short of it is, I don't think it's possible to page through all listeners. I don't think twitter had it in place to list all listeners
but I'll look again.
I'll add some of my spaces/broadcasts scripts to https://github.com/cmj/twitter-tools/ soon. I'm going to guess it has to do with the thousands that may listen and that number is so insanely dynamic it's not something one can pull proper data from.
E: Sorry I didn't address your last question. No. These are the known endpoints: https://raw.githubusercontent.com/fa0311/TwitterInternalAPIDocument/refs/heads/master/docs/json/API.json
@muhitrhn I'll have to wait for a large listener group to come live to play with, but for small "spaces" I guess one could do a check.
$ cat 1BdxYEyDoYMxX.json | jq -r '.data.audioSpace.participants.listeners[] | "Listener @\(.twitter_screen_name) (\(.display_name))"' | grep @Renz1337
Listener @Renz1337 (Ellorayni Reynolds)
Which would be this if stream is live:
./AudioSpaceById.sh 1BdxYEyDoYMxX | jq -r '.data.audioSpace.participants.listeners[] | "Listener @\(.twitter_screen_name) (\(.display_name))"' | grep @user
@cmj Right that's the same problem I am facing. I wonder how those data analytics tools does it. Is there any endpoint which checks if a user joined the space?
I played around with Spaces a bit more... The only thing that comes close is the AudioSpaceSearch
, however it's seems impossible to see if a random user joins the stream to listen. It will give results if you search for the host of a stream and sometimes another admin.
I'm not finding any other endpoint that would return the Space someone is actively listening to.
You could, if you knew a general search phrase (or "space" gave me the most) and passively filter all the results for the user. That's obviously going to use a lot of resources, and you also have a listener
limit.
@muhitrhn I stumbled across this endpoint https://x.com/i/api/fleets/v1/fleetline?only_spaces=true
You need to be following the account for you to see them actively listening to a Spaces stream.
Thank you for finding it @cmj! Really appreciate it. So how can I interact with it? It says 410 Gone: The Twitter REST API v1 is no longer active. Please migrate to API v1.1. https://dev.twitter.com/docs/api/1.1/overview
Edit: Nvm now it says 403 forbidden
. I think you can only access it with cookies and csrf? If that's the case can you help me maybe in converting https://github.com/PrivacyDevel/nitter to multi cookies and csrf based? Just telling me what to change will also do.
It worked perfectly. Thank you very much!