542 lines
10 KiB
Crystal
542 lines
10 KiB
Crystal
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
|