diff --git a/scripts/.tiktok-tokens b/scripts/.tiktok-tokens new file mode 100644 index 0000000..557693e --- /dev/null +++ b/scripts/.tiktok-tokens @@ -0,0 +1,2 @@ +ACCESS_TOKEN="act.6olZAg0uSnTVR6hO2jTTEpak8FPmtEEdS8uzTPmlTtVl06vZ8hswkOHGLyAV!6393.u1" +REFRESH_TOKEN="rft.v0FuyZmcsNbeZNZSKo9Pojwq1LYUxp5YeTPXkqb3wxfP0FGb53zY7YcxHyUM!6431.u1" diff --git a/scripts/sync-tiktok.sh b/scripts/sync-tiktok.sh new file mode 100644 index 0000000..f62a0f6 --- /dev/null +++ b/scripts/sync-tiktok.sh @@ -0,0 +1,191 @@ +#!/bin/bash +# /opt/scripts/sync-tiktok.sh +# TikTok analytics sync for Firefrost Gaming +# Runs via cron, refreshes token automatically, syncs to Arbiter + +set -e + +# Config +TOKEN_FILE="/opt/scripts/.tiktok-tokens" +ARBITER_URL="https://discord-bot.firefrostgaming.com/api/internal/social" +ARBITER_TOKEN="6fYF1akCRW6pM2F8n3S3RxeIod4YgRniUJNEQurvBP4=" + +# TikTok App credentials (sandbox) +CLIENT_KEY="sbawse6t5serp8xdqp" +CLIENT_SECRET="Ib24OixwLnjZbB8KXAUcYn6ewM60KKDp" + +# Load existing tokens +if [ -f "$TOKEN_FILE" ]; then + source "$TOKEN_FILE" +else + echo "ERROR: Token file not found at $TOKEN_FILE" + echo "Create it with:" + echo " ACCESS_TOKEN=act.xxxxx" + echo " REFRESH_TOKEN=rft.xxxxx" + exit 1 +fi + +# Function to refresh access token +refresh_token() { + echo "Refreshing TikTok access token..." + + RESPONSE=$(curl -s -X POST 'https://open.tiktokapis.com/v2/oauth/token/' \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -d "client_key=$CLIENT_KEY" \ + -d "client_secret=$CLIENT_SECRET" \ + -d "refresh_token=$REFRESH_TOKEN" \ + -d 'grant_type=refresh_token') + + # Check for error + ERROR=$(echo "$RESPONSE" | grep -o '"error":"[^"]*"' | cut -d'"' -f4) + if [ -n "$ERROR" ] && [ "$ERROR" != "ok" ]; then + echo "ERROR: Token refresh failed: $ERROR" + echo "$RESPONSE" + exit 1 + fi + + # Extract new tokens + NEW_ACCESS=$(echo "$RESPONSE" | grep -o '"access_token":"[^"]*"' | cut -d'"' -f4) + NEW_REFRESH=$(echo "$RESPONSE" | grep -o '"refresh_token":"[^"]*"' | cut -d'"' -f4) + + if [ -n "$NEW_ACCESS" ]; then + ACCESS_TOKEN="$NEW_ACCESS" + echo "Access token refreshed successfully" + fi + + if [ -n "$NEW_REFRESH" ]; then + REFRESH_TOKEN="$NEW_REFRESH" + fi + + # Save updated tokens + cat > "$TOKEN_FILE" << TOKENS +ACCESS_TOKEN="$ACCESS_TOKEN" +REFRESH_TOKEN="$REFRESH_TOKEN" +TOKENS + chmod 600 "$TOKEN_FILE" +} + +# Function to sync account stats +sync_account_stats() { + echo "Fetching TikTok account stats..." + + RESPONSE=$(curl -s -X GET \ + 'https://open.tiktokapis.com/v2/user/info/?fields=display_name,follower_count,following_count,likes_count,video_count' \ + -H "Authorization: Bearer $ACCESS_TOKEN") + + # Check for auth error (token expired) + ERROR=$(echo "$RESPONSE" | grep -o '"code":"[^"]*"' | head -1 | cut -d'"' -f4) + if [ "$ERROR" = "access_token_invalid" ]; then + echo "Access token expired, refreshing..." + refresh_token + # Retry + RESPONSE=$(curl -s -X GET \ + 'https://open.tiktokapis.com/v2/user/info/?fields=display_name,follower_count,following_count,likes_count,video_count' \ + -H "Authorization: Bearer $ACCESS_TOKEN") + fi + + FOLLOWERS=$(echo "$RESPONSE" | grep -o '"follower_count":[0-9]*' | cut -d':' -f2) + FOLLOWING=$(echo "$RESPONSE" | grep -o '"following_count":[0-9]*' | cut -d':' -f2) + LIKES=$(echo "$RESPONSE" | grep -o '"likes_count":[0-9]*' | cut -d':' -f2) + VIDEOS=$(echo "$RESPONSE" | grep -o '"video_count":[0-9]*' | cut -d':' -f2) + + echo " Followers: $FOLLOWERS, Following: $FOLLOWING, Likes: $LIKES, Videos: $VIDEOS" + + # Sync to Arbiter + curl -s -X POST "$ARBITER_URL/snapshot" \ + -H "Authorization: Bearer $ARBITER_TOKEN" \ + -H "Content-Type: application/json" \ + -d "{ + \"platform\": \"tiktok\", + \"handle\": \"playfirefrost\", + \"followers\": ${FOLLOWERS:-0}, + \"following\": ${FOLLOWING:-0}, + \"posts\": ${VIDEOS:-0} + }" > /dev/null + + echo " Account snapshot synced to Arbiter" +} + +# Function to sync video stats +sync_videos() { + echo "Fetching TikTok video stats..." + + RESPONSE=$(curl -s -X POST \ + 'https://open.tiktokapis.com/v2/video/list/?fields=id,title,create_time,view_count,like_count,comment_count,share_count' \ + -H "Authorization: Bearer $ACCESS_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"max_count": 50}') + + # Check for auth error + ERROR=$(echo "$RESPONSE" | grep -o '"code":"access_token_invalid"') + if [ -n "$ERROR" ]; then + echo "Access token expired, refreshing..." + refresh_token + RESPONSE=$(curl -s -X POST \ + 'https://open.tiktokapis.com/v2/video/list/?fields=id,title,create_time,view_count,like_count,comment_count,share_count' \ + -H "Authorization: Bearer $ACCESS_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"max_count": 50}') + fi + + # Parse and sync each video using Python for JSON handling + python3 << PYTHON +import json +import subprocess +import sys + +response = '''$RESPONSE''' +data = json.loads(response) + +if 'data' not in data or 'videos' not in data['data']: + print(" No videos found or error in response") + sys.exit(0) + +videos = data['data']['videos'] +print(f" Found {len(videos)} videos") + +for video in videos: + video_id = video.get('id', '') + title = video.get('title', '')[:100] # Truncate for post_url field + views = video.get('view_count', 0) + likes = video.get('like_count', 0) + comments = video.get('comment_count', 0) + shares = video.get('share_count', 0) + + # Create post URL + post_url = f"https://www.tiktok.com/@playfirefrost/video/{video_id}" + + payload = { + "platform": "tiktok", + "post_url": post_url, + "views": views, + "likes": likes, + "comments": comments, + "shares": shares + } + + result = subprocess.run([ + 'curl', '-s', '-X', 'POST', + '$ARBITER_URL/sync', + '-H', 'Authorization: Bearer $ARBITER_TOKEN', + '-H', 'Content-Type: application/json', + '-d', json.dumps(payload) + ], capture_output=True, text=True) + + print(f" {video_id}: {views} views, {likes} likes") + +print(" All videos synced to Arbiter") +PYTHON +} + +# Main +echo "=== TikTok Sync $(date) ===" + +# Refresh token proactively (do this every run to keep token fresh) +refresh_token + +# Sync data +sync_account_stats +sync_videos + +echo "=== Sync complete ==="