From e9b6b9695212cebdfa8f94c1a05cad5d54511043 Mon Sep 17 00:00:00 2001 From: Joe Rayhawk Date: Sun, 14 Jan 2024 01:03:09 -0800 Subject: Attempt to modernize followers/followees API Signed-off-by: Joe Rayhawk --- src/twitcr/rest.cr | 47 +++++++++++++++++++---------------------------- util/twitch.cr | 50 ++++++++++++++++++++++++++++++++++---------------- 2 files changed, 53 insertions(+), 44 deletions(-) diff --git a/src/twitcr/rest.cr b/src/twitcr/rest.cr index 1be3190..5e4f881 100644 --- a/src/twitcr/rest.cr +++ b/src/twitcr/rest.cr @@ -55,10 +55,7 @@ module Twitcr::REST headers["Content-Type"] = contenttype end - begin - ENV["DEBUG"] - rescue KeyError - else + if ENV["DEBUG"]? puts method + " " + url_base + api + route #pp headers# probably too sensitive pp body @@ -72,13 +69,16 @@ module Twitcr::REST tls: SSL_CONTEXT ) - begin - ENV["DEBUG"] - rescue KeyError - else + if ENV["DEBUG"]? + pp response.status_code pp response.body end + if response.status_code != 200 + STDERR.puts( "WARNING: twitcr: " + method + " " + url_base + api + route + " status: " + response.status_code.to_s ) + STDERR.puts( response.body ) + end + response.body end @@ -89,33 +89,23 @@ module Twitcr::REST def get_user( id : Array( String ) ); request( "GET", Api::Helix, "/users?login=#{login.join("&login=")}" ) end def follow!( from : UInt64, to : UInt64 ); request( "PUT", Api::Kraken, "/users/#{from.to_s}/follows/channels/#{to.to_s}" ) end def unfollow!( from : UInt64, to : UInt64 ); request( "DELETE", Api::Kraken, "/users/#{from.to_s}/follows/channels/#{to.to_s}" ) end - def get_user_follows( *, from : UInt64, after : String? = nil ) + def get_channels_followed( *, to : UInt64? = nil, from : UInt64, after : String? = nil ) params = Hash( String, String ).new params["first"] = "100" - params["from_id"] = from.to_s - if after ; params["after"] = after end + params["user_id"] = from.to_s + to && ( params["broadcaster_id"] = to.to_s ) + after && ( params["after"] = after ) query_string = HTTP::Params.encode( params ) - if ! query_string.empty?; query_string = "?" + query_string end - request( "GET", Api::Helix, "/users/follows" + query_string ) + request( "GET", Api::Helix, "/channels/followed?" + query_string ) end - def get_user_follows( *, to : UInt64, after : String? = nil ) + def get_channel_followers( *, to : UInt64, from : UInt64? = nil, after : String? = nil ) params = Hash( String, String ).new params["first"] = "100" - params["to_id"] = to.to_s - if after; params["after"] = after end + params["broadcaster_id"] = to.to_s + from && ( params["user_id"] = from.to_s ) + after && ( params["after"] = after ) query_string = HTTP::Params.encode( params ) - if ! query_string.empty?; query_string = "?" + query_string end - request( "GET", Api::Helix, "/users/follows" + query_string ) - end - def get_user_follows( *, to : UInt64, from : UInt64, after : String? = nil ) - params = Hash( String, String ).new - params["first"] = "100" - params["from_id"] = from.to_s - params["to_id"] = to.to_s - if after ; params["after"] = after end - query_string = HTTP::Params.encode( params ) - if ! query_string.empty?; query_string = "?" + query_string end - request( "GET", Api::Helix, "/users/follows" + query_string ) + request( "GET", Api::Helix, "/channels/followers?" + query_string ) end # FIXME: support array of mixed UInt64/String def get_games( name : String ); request( "GET", Api::Helix, "/games?name=#{URI.encode_www_form( name )}" ) end @@ -123,6 +113,7 @@ module Twitcr::REST def get_streams( user_ids : Array( UInt64 ) ); request( "GET", Api::Helix, "/streams?user_id=#{user_ids.join( "&user_id=" )}" ) end def get_streams( user_id : UInt64 ); request( "GET", Api::Helix, "/streams?user_id=#{user_id}" ) end def get_streams( game_id : UInt64 ); request( "GET", Api::Helix, "/streams?first=100&game_id=#{game_id}" ) end + def get_streams( game_id : UInt64, cursor : String ); request( "GET", Api::Helix, "/streams?first=100&game_id=#{game_id}&after=#{cursor}" ) end def get_streams(); request( "GET", Api::Helix, "/streams?first=100" ) end # Kraken returns more information def get_streams_v5( game : String ); request( "GET", Api::Kraken, "/streams?limit=100&game=#{URI.encode_www_form( game )}" ) end diff --git a/util/twitch.cr b/util/twitch.cr index 43980d0..32c79f1 100644 --- a/util/twitch.cr +++ b/util/twitch.cr @@ -60,7 +60,9 @@ when "clips" when "game" pp JSON.parse( client.get_games( ARGV[1].to_u64? || ARGV[1] ) ) when "streams" - if ARGV[1]? + if ARGV[2]? + list_streams( settings, JSON.parse( client.get_streams( game_id = client.game_id( ARGV[1] ), ARGV[2] ) ) ) + elsif ARGV[1]? list_streams( settings, JSON.parse( client.get_streams( game_id = client.game_id( ARGV[1] ) ) ) ) else list_streams( settings, JSON.parse( client.get_streams() ) ) @@ -186,9 +188,11 @@ def list_user_followees( settings, client ) # format overhead foh = format.delete( "^ " ).size - follows = JSON.parse( client.get_user_follows( from: id ) )["data"] + follows = JSON.parse( client.get_channels_followed( from: id ) ) - followsuids = follows.as_a.map { |follow| follow["to_id"].as_s.to_u64 } + pp follows + + followsuids = follows["data"].as_a.map { |follow| follow["broadcaster_id"].as_s.to_u64 } streams = Hash( UInt64, JSON::Any ).new channels = Hash( UInt64, JSON::Any ).new @@ -206,9 +210,9 @@ def list_user_followees( settings, client ) users[ user["id"].as_s.to_u64 ] = user end - follows.as_a.each do |follow| + follows["data"].as_a.each do |follow| - uid = follow["to_id"].as_s.to_u64 + uid = follow["broadcaster_id"].as_s.to_u64 channel = ( channels[uid]? || JSON.parse( "{}" ) ) stream = ( streams[uid]? || JSON.parse( "{}" ) ) @@ -219,7 +223,7 @@ def list_user_followees( settings, client ) begin printf( format, *fcell( follow["followed_at"]?.to_s ), - *fcell( follow["to_login"]?.to_s ), + *fcell( follow["broadcaster_login"]?.to_s ), *fcell( stream["viewer_count"]?.to_s ), #*fcell( channel["followers"]?.to_s ), *fcell( user["view_count"]?.to_s ), @@ -236,10 +240,10 @@ def list_user_followees( settings, client ) pp user end - pp follows["pagination"] - end + pp follows["pagination"] + end def list_user_followers( settings, client ) @@ -257,15 +261,29 @@ def list_user_followers( settings, client ) # format overhead foh = format.delete( "^ " ).size - puts( "\nLast 100 followers:\n" ) if ARGV.size > 2 - followersjson = JSON.parse( client.get_user_follows( to: id, after: ARGV[2] ) ) + followersjson = JSON.parse( client.get_channel_followers( to: id, after: ARGV[2] ) ) else - followersjson = JSON.parse( client.get_user_follows( to: id ) ) + followersjson = JSON.parse( client.get_channel_followers( to: id ) ) + end + + total = followersjson["total"].as_i + puts( "Total followers: " + total.to_s ) + + if ( total == 0 ) + puts( "No followers." ) + return + end + + puts( "\nLast 100 followers:\n" ) + followers = followersjson["data"].as_a + if followers.empty? + puts( "Empty list. Missing moderator:read:followers scope." ) + return end - followers = followersjson["data"] - followersuids = followers.as_a.map { |follow| follow["from_id"].as_s.to_u64 } + + followersuids = followers.map { |follow| follow["user_id"].as_s.to_u64 } streams = Hash( UInt64, JSON::Any ).new channels = Hash( UInt64, JSON::Any ).new @@ -283,7 +301,7 @@ def list_user_followers( settings, client ) users[ user["id"].as_s.to_u64 ] = user end - followers.as_a.each do |follow| + followers.each do |follow| uid = follow["from_id"].as_s.to_u64 @@ -435,11 +453,11 @@ def list_streams( settings, response ) begin printf( format, - *fcell( "twitch.tv/#{stream["user_name"].to_s}" ), + *fcell( "twitch.tv/#{stream["user_login"].to_s}" ), *fcell( stream["type"].as_s[0].to_s ), *fcell( stream["viewer_count"].as_i.to_s ), #*fcell( stream["channel"]["followers"].as_i.to_s ), - *fcell( stream["game_id"].as_s ), + *fcell( stream["game_name"].as_s ), *fcell( stream["title"].to_s ), ) rescue -- cgit v1.2.3