module TwAPI::GqlAPI extend self def userResultBy(params) if params.has_key?("id") return %(userResultByID(id: "#{params["id"]}")) else return %(userResultByLogin(login: "#{params["login"]}")) end end def targetUser(params) if params.has_key?("id") return %(targetUserID: "#{params["id"]}" ) else return %(targetUserLogin: "#{params["login"]}") end end def loginOrID(params) if params.has_key?("id") return %(id: "#{params["id"]}") else return %(login: "#{params["login"]}") end end def getUserByLogin(params) logins = params["login"].try &.split(',') channel = Channel(JSON::Any).new responses = [] of JSON::Any queries = [] of String logins.each do |login| query = %( query { userResultByLogin(login: "#{login}") { ... on UserDoesNotExist { key reason } } user(login: "#{login}" lookupType: ALL) { id language login displayName description bannerImageURL profileImageURL(width: 600) createdAt updatedAt deletedAt chatColor emoticonPrefix { name } panels(hideExtensions: false) { id type } followers { totalCount } roles { isStaff isAffiliate isPartner isExtensionsDeveloper } displayBadges { setID title description version } chatSettings { autoModLevel blockLinks chatDelayMs followersOnlyDurationMinutes isBroadcasterLanguageModeEnabled isEmoteOnlyModeEnabled isFastSubsModeEnabled isOptedOutOfGlobalBannedWordsList isSubscribersOnlyModeEnabled isUniqueChatModeEnabled requireVerifiedAccount rules slowModeDurationSeconds } stream { averageFPS bitrate codec createdAt width height id viewersCount type game{displayName} } lastBroadcast { game{displayName} id startedAt title } channel { chatters { count moderators { login } vips { login } } } } } ) queries << query end queries.each do |query| spawn do result = JSON.parse(req(query)) channel.send(result) end end queries.each do responses << channel.receive end return responses end def getUserById(params) ids = params["id"].try &.split(',') channel = Channel(JSON::Any).new responses = [] of JSON::Any queries = [] of String ids.each do |id| query = %( query { userResultByID(id: "#{id}") { ... on UserDoesNotExist { key reason } } user(id: "#{id}" lookupType: ALL) { id language login displayName description bannerImageURL profileImageURL(width: 600) createdAt updatedAt deletedAt chatColor emoticonPrefix { name } panels(hideExtensions: false) { id type } followers { totalCount } roles { isStaff isAffiliate isPartner isExtensionsDeveloper } displayBadges { setID title description version } chatSettings { autoModLevel blockLinks chatDelayMs followersOnlyDurationMinutes isBroadcasterLanguageModeEnabled isEmoteOnlyModeEnabled isFastSubsModeEnabled isOptedOutOfGlobalBannedWordsList isSubscribersOnlyModeEnabled isUniqueChatModeEnabled requireVerifiedAccount rules slowModeDurationSeconds } stream { averageFPS bitrate codec createdAt width height id viewersCount type game{displayName} } lastBroadcast { game{displayName} id startedAt title } channel { chatters { count moderators { login } vips { login } } } } } ) queries << query end queries.each do |query| spawn do result = JSON.parse(req(query)) channel.send(result) end end queries.each do responses << channel.receive end return responses end def getModsVips(params) query = %( query { user(login: "#{params}" lookupType: ALL) { mods(first: 100) { edges { grantedAt isActive node { displayName id login } } } vips(first: 100) { edges { grantedAt node { displayName id login } } } } } ) return JSON.parse(req(query)) end def getFounders(params) query = %( query { user(login: "#{params}" lookupType: ALL) { id login displayName channel { founderBadgeAvailability founders { isSubscribed entitlementStart user { id login displayName } } } } } ) return JSON.parse(req(query)) end def getClips(params) query = %( query { clip(slug: "#{params}") { createdAt creationState durationSeconds embedURL id isPublished language slug thumbnailURL title url videoOffsetSeconds viewCount game { id name } broadcaster { id displayName } curator { id displayName } videoQualities { frameRate quality sourceURL } } } ) return JSON.parse(req(query)) end def getSubage(user, channel) channelId = HelixAPI.getId(channel) query = %( query { userData: userResultByLogin (login: "#{user}") { ... on UserDoesNotExist { key reason } ... on UserError { key } ... on User { id displayName login } } channelData: userResultByLogin (login: "#{channel}") { ... on UserDoesNotExist { key reason } ... on UserError { key } ... on User { id displayName login roles { isAffiliate isPartner } } } info: user (login: "#{user}" lookupType: ALL) { relationship (targetUserID: "#{channelId}") { followedAt cumulative: subscriptionTenure(tenureMethod: CUMULATIVE) { daysRemaining elapsedDays end months start } streak: subscriptionTenure(tenureMethod: STREAK) { daysRemaining elapsedDays end months start } meta: subscriptionBenefit { endsAt purchasedWithPrime renewsAt tier giftMeta: gift { giftDate isGift gifter { displayName login id } } } } } } ) return JSON.parse(req(query)) end def getEmotes(emote) query = %( query { emote(id: "#{emote}") { setID assetType id state suffix text subscriptionTier owner { id login displayName } artist { id login displayName } bitsBadgeTierSummary { threshold } type } } ) return JSON.parse(req(query)) end def getChannelEmotes(channel) query = %( { user(login: "#{channel}") { channel { localEmoteSets { id localEmotes: emotes { artist { id } id type assetType text } } } subEmotes: subscriptionProducts { displayName id tier emotes { id setID text type assetType } } } } ) return JSON.parse(req(query)) end def getEmotes(emote) query = %( query { emote(id: "#{emote}") { setID assetType id state suffix text subscriptionTier owner { id login displayName } artist { id login displayName } bitsBadgeTierSummary { threshold } type } } ) return JSON.parse(req(query)) end def getChannelBadges(channel) query = %( query { user(login: "#{channel}") { broadcastBadges { id normalImageURL: imageURL(size: NORMAL) doubleImageURL: imageURL(size: DOUBLE) quadrupleImageURL: imageURL(size: QUADRUPLE) title description onClickAction clickURL } channel { creatorBadgeFlair { assets { tier } } } } } ) return JSON.parse(req(query)) end def req(query) headers = HTTP::Headers{ "Content-Type" => "application/json", # "Client-Id" => "kimne78kx3ncx6brgo4mv6wki5h1ko", # Can cause problems due to Client-Integrity "Authorization" => "OAuth #{CONFIG.gqlOAuth}", "Client-Id" => "#{CONFIG.gqlClientID}", } data = {"query" => query} response = HTTP::Client.post(CONFIG.gqlEndpoint.to_s, headers: headers, body: data.to_json) if response.success? return (response.body) else raise "GQL Twitch API returned #{response.status_code}: #{response.body.to_s}" end end end