Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
186 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Twitch shell utilities | ||
|
||
- Simple shell utilities, needed one time or another during testing and development. | ||
- Not all steps are automated — some require very manual copy-paste. | ||
- See the main readme file for setting up Twitch application environment variables. | ||
- See individual files for documentation, but don't expect too much. | ||
- A part of [botten-nappet](https://joelpurra.com/projects/botten-nappet/). | ||
|
||
|
||
```shell | ||
tree ./utilities/shell/ | ||
``` | ||
|
||
```text | ||
./utilities/shell/ | ||
├── README.md | ||
├── download-all-channel-feed-posts.sh | ||
└── manual-authentication-steps.sh | ||
0 directories, 3 files | ||
``` | ||
|
||
|
||
|
||
--- | ||
|
||
[botten-nappet](https://joelpurra.com/projects/botten-nappet/) Copyright © 2018 [Joel Purra](https://joelpurra.com/). Released under [GNU Affero General Public License version 3.0 (AGPL-3.0)](https://www.gnu.org/licenses/agpl.html). [Your donations are appreciated!](https://joelpurra.com/donate/) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
#!/usr/bin/env bash | ||
|
||
set -e | ||
set -u | ||
set -o pipefail | ||
|
||
# --- | ||
# | ||
# Download all Twitch channel feed posts. | ||
# | ||
# Used as a backup tool for when Twitch kills off the channel feed. | ||
# This script might not be useful after that, circa June 2018. | ||
# https://help.twitch.tv/customer/portal/articles/2936769-removing-channel-feed-and-pulse | ||
# | ||
# Outputs a json file with all posts and post details in an array. | ||
# | ||
# NOTE: does not get each post's comments. | ||
# | ||
# NOTE: requires Twitch authorization environment variables to have been set up. | ||
# | ||
# --- | ||
|
||
function die() { | ||
echo -E "FATAL" "$@" >&2 | ||
exit 1 | ||
} | ||
|
||
function fetchCurrentPage() { | ||
curl \ | ||
--silent \ | ||
--header 'Accept: application/vnd.twitchtv.v5+json' \ | ||
--header "Client-ID: ${TWITCH_APP_CLIENT_ID}" \ | ||
--header "Authorization: OAuth ${TWITCH_APP_ACCESS_TOKEN}" \ | ||
"https://api.twitch.tv/kraken/feed/${TWITCH_USER_ID}/posts?limit=100&cursor=${TWITCH_CHANNEL_FEED_POSTS_CURSOR}" | ||
} | ||
|
||
function downloadCurrentPage() { | ||
# TODO: use local variables. | ||
declare TWITCH_CHANNEL_FEED_POSTS_PAGE_OUTPUT="${TWITCH_CHANNEL_FEED_POSTS_PAGE_OUTPUT_PREFIX}${TWITCH_CHANNEL_FEED_POSTS_OFFSET}${TWITCH_CHANNEL_FEED_POSTS_PAGE_OUTPUT_SUFFIX}" | ||
fetchCurrentPage > "$TWITCH_CHANNEL_FEED_POSTS_PAGE_OUTPUT" | ||
|
||
# TODO: use local variables. | ||
TWITCH_CHANNEL_FEED_POSTS_CURSOR="$(cat "$TWITCH_CHANNEL_FEED_POSTS_PAGE_OUTPUT" | jq --raw-output '._cursor')" | ||
TWITCH_CHANNEL_FEED_POSTS_COUNT="$(cat "$TWITCH_CHANNEL_FEED_POSTS_PAGE_OUTPUT" | jq --raw-output '.posts | length')" | ||
TWITCH_CHANNEL_FEED_POSTS_OFFSET="$(( "$TWITCH_CHANNEL_FEED_POSTS_OFFSET" + "$TWITCH_CHANNEL_FEED_POSTS_COUNT" ))" | ||
|
||
# echo "TWITCH_CHANNEL_FEED_POSTS_CURSOR" "$TWITCH_CHANNEL_FEED_POSTS_CURSOR" | ||
# echo "TWITCH_CHANNEL_FEED_POSTS_COUNT" "$TWITCH_CHANNEL_FEED_POSTS_COUNT" | ||
# echo "TWITCH_CHANNEL_FEED_POSTS_OFFSET" "$TWITCH_CHANNEL_FEED_POSTS_OFFSET" | ||
} | ||
|
||
function main() { | ||
# Step 0: check input. | ||
[[ -z "$TWITCH_USER_ID" ]] && die "Environment variable not set" "TWITCH_USER_ID" | ||
[[ -z "$TWITCH_APP_CLIENT_ID" ]] && die "Environment variable not set" "TWITCH_APP_CLIENT_ID" | ||
[[ -z "$TWITCH_APP_ACCESS_TOKEN" ]] && die "Environment variable not set" "TWITCH_APP_ACCESS_TOKEN" | ||
|
||
# Step 1: setup. | ||
# TODO: use local variables. | ||
declare TWITCH_CHANNEL_FEED_POSTS_TIMESTAMP="$(date -u +%FT%TZ | tr -d ':')" | ||
declare TWITCH_CHANNEL_FEED_POSTS_COUNT="0" | ||
declare TWITCH_CHANNEL_FEED_POSTS_OFFSET="0" | ||
declare TWITCH_CHANNEL_FEED_POSTS_CURSOR="" | ||
declare TWITCH_CHANNEL_FEED_POSTS_PAGE_OUTPUT_PREFIX="twitch.channel-feed.posts.${TWITCH_USER_ID}.${TWITCH_CHANNEL_FEED_POSTS_TIMESTAMP}." | ||
declare TWITCH_CHANNEL_FEED_POSTS_PAGE_OUTPUT_SUFFIX=".json" | ||
declare TWITCH_CHANNEL_FEED_POSTS_PAGE_OUTPUT_LIST="${TWITCH_CHANNEL_FEED_POSTS_PAGE_OUTPUT_PREFIX}*${TWITCH_CHANNEL_FEED_POSTS_PAGE_OUTPUT_SUFFIX}" | ||
declare TWITCH_CHANNEL_FEED_POSTS_PAGE_OUTPUT_ALL="${TWITCH_CHANNEL_FEED_POSTS_PAGE_OUTPUT_PREFIX}all${TWITCH_CHANNEL_FEED_POSTS_PAGE_OUTPUT_SUFFIX}" | ||
|
||
# Step 2: run once. | ||
downloadCurrentPage | ||
|
||
# Step 3: loop. | ||
while [[ ! -z "$TWITCH_CHANNEL_FEED_POSTS_CURSOR" ]]; | ||
do | ||
downloadCurrentPage | ||
done | ||
|
||
# Step 3: concatenate. | ||
cat $TWITCH_CHANNEL_FEED_POSTS_PAGE_OUTPUT_LIST | jq --slurp 'map(.posts) | add | sort_by(.created_at)' > "$TWITCH_CHANNEL_FEED_POSTS_PAGE_OUTPUT_ALL" | ||
|
||
# Done! | ||
cat "$TWITCH_CHANNEL_FEED_POSTS_PAGE_OUTPUT_ALL" | jq --arg path "$TWITCH_CHANNEL_FEED_POSTS_PAGE_OUTPUT_ALL" '{ path: $path, count: length, first: .[0].created_at, last: .[-1].created_at }' | ||
} | ||
|
||
main |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
echo "Do not execute this file directly; instead copy-paste examples as needed." >&2 | ||
exit 1 | ||
|
||
# NOTE: requires Twitch application environment variables to be set. | ||
# See "Prepare variables" in the main readme file. | ||
|
||
|
||
# --- | ||
|
||
|
||
# Get an application access token. | ||
# Required: TWITCH_APP_CLIENT_ID | ||
# Required: TWITCH_APP_CLIENT_SECRET | ||
export TWITCH_APP_ACCESS_TOKEN="$(curl --data "client_id=${TWITCH_APP_CLIENT_ID}&client_secret=${TWITCH_APP_CLIENT_SECRET}&grant_type=client_credentials&scope=channel_feed_read" 'https://api.twitch.tv/kraken/oauth2/token' | jq --raw-output '.access_token')" | ||
|
||
# Optional: Revoke an application access token. | ||
# Required: TWITCH_APP_CLIENT_ID | ||
# Required: TWITCH_APP_ACCESS_TOKEN | ||
curl --data "client_id=${TWITCH_APP_CLIENT_ID}&token=${TWITCH_APP_ACCESS_TOKEN}" 'https://api.twitch.tv/kraken/oauth2/revoke' | ||
|
||
|
||
# --- | ||
|
||
|
||
# Sample application access token usage for different Twitch APIs. | ||
# Required: | ||
curl --header "Authorization: Bearer ${TWITCH_APP_ACCESS_TOKEN}" 'https://api.twitch.tv/helix/' | ||
|
||
curl --header "Authorization: OAuth ${TWITCH_APP_ACCESS_TOKEN}" 'https://api.twitch.tv/kraken/' | ||
|
||
curl --header "Authorization: Bearer ${TWITCH_APP_ACCESS_TOKEN}" 'https://api.twitch.tv/helix/webhooks/hub' | ||
|
||
|
||
# --- | ||
|
||
|
||
# Get the user id from user name. | ||
# Required: TWITCH_APP_ACCESS_TOKEN | ||
# Required: TWITCH_USER_NAME | ||
export TWITCH_USER_ID="$(curl --header "Authorization: Bearer ${TWITCH_APP_ACCESS_TOKEN}" "https://api.twitch.tv/helix/users?login=${TWITCH_USER_NAME}" | jq --raw-output '.data[0].id')"; | ||
|
||
|
||
# --- | ||
|
||
|
||
# Authorize a user in your application. | ||
# Required: TWITCH_APP_CLIENT_ID | ||
# Required: TWITCH_APP_CLIENT_SECRET | ||
# Required: TWITCH_APP_OAUTH_REDIRECT_URL | ||
# Required: | ||
# Step 1: setup. | ||
export CSRF_STATE="$(echo "unguessable $(date) even more unguessable" | shasum --algorithm 512 | cut -d ' ' -f 1)" | ||
function urlencode() { python -c "import sys, urllib as ul; print ul.quote_plus(sys.argv[1]);"; } | ||
export TWITCH_APP_OAUTH_REDIRECT_URL_URLENCODED="$(urlencode "$TWITCH_APP_OAUTH_REDIRECT_URL")" | ||
|
||
# Step 2: open up the browser for application authorization. | ||
open "https://api.twitch.tv/kraken/oauth2/authorize?client_id=${TWITCH_APP_CLIENT_ID}&redirect_uri=${TWITCH_APP_OAUTH_REDIRECT_URL_URLENCODED}&response_type=code&scope=channel_feed_read%20channel_subscriptions%20chat_login&force_verify=true&state=${CSRF_STATE}" | ||
|
||
# Step 3: copy the url after the user has been redirected, then execute this line. | ||
export TWITCH_USER_AUTHORIZATION_CODE="$(pbpaste | sed -E -e 's/.*\bcode=([a-zA-Z0-9]*)\b.*/\1/')" | ||
|
||
# Step 4: retrieve the actual user access token. | ||
# NOTE: This can be stored and reused long-term. | ||
export TWITCH_USER_ACCESS_TOKEN="$(curl --data "client_id=${TWITCH_APP_CLIENT_ID}&client_secret=${TWITCH_APP_CLIENT_SECRET}&code=${TWITCH_USER_AUTHORIZATION_CODE}&grant_type=authorization_code&redirect_uri=${TWITCH_APP_OAUTH_REDIRECT_URL_URLENCODED}" 'https://api.twitch.tv/kraken/oauth2/token' | jq --raw-output '.access_token')" | ||
|
||
# Optional: test the access by requesting used details. | ||
# Required: user_read scope. | ||
curl --header "Authorization: OAuth ${TWITCH_USER_ACCESS_TOKEN}" 'https://api.twitch.tv/kraken/user' | ||
|
||
# Optional: revoke the user access token. | ||
curl --data "client_id=${TWITCH_APP_CLIENT_ID}&token=${TWITCH_USER_ACCESS_TOKEN}" 'https://api.twitch.tv/kraken/oauth2/revoke' | ||
|
||
|
||
# --- |