Init
This commit is contained in:
commit
9e3e7b5397
7 changed files with 340 additions and 0 deletions
18
shard.lock
Normal file
18
shard.lock
Normal file
|
@ -0,0 +1,18 @@
|
|||
version: 2.0
|
||||
shards:
|
||||
backtracer:
|
||||
git: https://github.com/sija/backtracer.cr.git
|
||||
version: 1.2.2
|
||||
|
||||
exception_page:
|
||||
git: https://github.com/crystal-loot/exception_page.git
|
||||
version: 0.4.1
|
||||
|
||||
kemal:
|
||||
git: https://github.com/kemalcr/kemal.git
|
||||
version: 1.5.0
|
||||
|
||||
radix:
|
||||
git: https://github.com/luislavena/radix.git
|
||||
version: 0.4.1
|
||||
|
28
shard.yml
Normal file
28
shard.yml
Normal file
|
@ -0,0 +1,28 @@
|
|||
name: ivr-api
|
||||
version: 0.1.0
|
||||
|
||||
targets:
|
||||
invidious:
|
||||
main: src/main.cr
|
||||
|
||||
dependencies:
|
||||
kemal:
|
||||
github: kemalcr/kemal
|
||||
|
||||
|
||||
# authors:
|
||||
# - name <email@example.com>
|
||||
|
||||
# description: |
|
||||
# Short description of ivr-api
|
||||
|
||||
# dependencies:
|
||||
# pg:
|
||||
# github: will/crystal-pg
|
||||
# version: "~> 0.5"
|
||||
|
||||
# development_dependencies:
|
||||
# webmock:
|
||||
# github: manastech/webmock.cr
|
||||
|
||||
# license: MIT
|
61
src/api/users.cr
Normal file
61
src/api/users.cr
Normal file
|
@ -0,0 +1,61 @@
|
|||
require "json"
|
||||
require "../twitchapi/*"
|
||||
|
||||
module Users
|
||||
def self.parseData(params)
|
||||
helixUsers = JSON.parse(HelixAPI.users(params))
|
||||
login = helixUsers["data"][0]["login"]
|
||||
id = helixUsers["data"][0]["id"]
|
||||
# gqlUser = JSON.parse(GqlAPI.user(idto))
|
||||
gqlUser = GqlAPI.user(id.to_s)
|
||||
gqlChannel = GqlAPI.channel(id.to_s)
|
||||
|
||||
helixChatColor = JSON.parse(HelixAPI.chatColor(id))
|
||||
# gqlCA = JSON.parse(GqlAPI.gqlReq("ChannelAvatar", "#{login}"))
|
||||
# gqlCS = JSON.parse(GqlAPI.gqlReq("ChannelShell", "#{login}"))
|
||||
|
||||
# gqlUser["chatSettings"]["rules"].to_json.each do |rule|
|
||||
# puts rule
|
||||
# end
|
||||
|
||||
json_data = [
|
||||
{
|
||||
"banned" => false,
|
||||
"displayName" => helixUsers["data"][0]["display_name"],
|
||||
"login" => helixUsers["data"][0]["login"],
|
||||
"id" => helixUsers["data"][0]["id"],
|
||||
"bio" => helixUsers["data"][0]["description"],
|
||||
# "followers" => gqlUser[0]["data"]["user"]["followers"]["totalCount"],
|
||||
"profileViewCount" => nil, # Always null
|
||||
"panelCount" => "",
|
||||
"chatColor" => helixChatColor["data"][0]["color"],
|
||||
"logo" => gqlUser["profileImageURL"],
|
||||
"banner" => gqlUser["bannerImageURL"],
|
||||
"verifiedBot" => nil, # Deprecated by twitch
|
||||
"createdAt" => helixUsers["data"][0]["created_at"],
|
||||
"updatedAt" => nil,
|
||||
"emotePrefix" => "lol",
|
||||
"chatterCount" => gqlChannel["chatters"]["count"],
|
||||
"roles" => {
|
||||
"isAffiliate" => gqlUser["roles"]["isAffiliate"],
|
||||
"isPartner" => gqlUser["roles"]["isPartner"],
|
||||
"isStaff" => gqlUser["roles"]["isStaff"],
|
||||
},
|
||||
"badges" => [
|
||||
{
|
||||
"setID" => "game-developer",
|
||||
"title" => "Game Developer",
|
||||
"description" => "Game Developer for:",
|
||||
"version" => "1",
|
||||
},
|
||||
],
|
||||
|
||||
"chatSettings" => { gqlUser["chatSettings"] },
|
||||
"stream" => gqlUser["stream"],
|
||||
"lastBroadcast" => gqlUser["lastBroadcast"]
|
||||
},
|
||||
]
|
||||
|
||||
return json_data.to_json
|
||||
end
|
||||
end
|
39
src/config.cr
Normal file
39
src/config.cr
Normal file
|
@ -0,0 +1,39 @@
|
|||
require "yaml"
|
||||
|
||||
class Config
|
||||
include YAML::Serializable
|
||||
|
||||
property oauthToken : String?
|
||||
property clientID : String?
|
||||
property apiEndpoint : String?
|
||||
property gqlEndpoint : String?
|
||||
|
||||
def self.load
|
||||
config_file = "config/config.yml"
|
||||
config_yaml = File.read(config_file)
|
||||
config = Config.from_yaml(config_yaml)
|
||||
|
||||
if config.oauthToken.to_s.empty?
|
||||
puts "Config: 'oauthToken' is required/can't be empty"
|
||||
exit(1)
|
||||
end
|
||||
|
||||
if config.clientID.to_s.empty?
|
||||
puts "Config: 'oauthToken' is required/can't be empty"
|
||||
exit(1)
|
||||
end
|
||||
|
||||
if config.apiEndpoint.to_s.empty?
|
||||
puts "Config: 'apiEndpoint' is required/can't be empty"
|
||||
exit(1)
|
||||
end
|
||||
|
||||
if config.gqlEndpoint.to_s.empty?
|
||||
puts "Config: 'apiEndpoint' is required/can't be empty"
|
||||
exit(1)
|
||||
end
|
||||
|
||||
return config
|
||||
end
|
||||
end
|
||||
|
49
src/main.cr
Normal file
49
src/main.cr
Normal file
|
@ -0,0 +1,49 @@
|
|||
require "http/server"
|
||||
require "kemal"
|
||||
require "json"
|
||||
require "uri"
|
||||
require "./config"
|
||||
require "./api/*"
|
||||
require "./twitchapi/*"
|
||||
|
||||
CONFIG = Config.load
|
||||
# puts("oauthToken: #{CONFIG.oauthToken}")
|
||||
# puts("clientID: #{CONFIG.clientID}")
|
||||
|
||||
before_all "/twitch/*" do |env|
|
||||
env.response.content_type = "application/json"
|
||||
end
|
||||
|
||||
get "/twitch/user" do |env|
|
||||
query = env.request.query
|
||||
if query
|
||||
params = URI::Params.parse(query)
|
||||
if params.has_key?("login")
|
||||
begin
|
||||
Users.parseData(params)
|
||||
rescue ex
|
||||
env.response.status_code = 401
|
||||
err = { "error" => "#{ex.message}" }
|
||||
err.to_json
|
||||
end
|
||||
elsif params.has_key?("id")
|
||||
begin
|
||||
Users.parseData(params)
|
||||
rescue ex
|
||||
env.response.status_code = 401
|
||||
err = { "error" => "#{ex.message}" }
|
||||
err.to_json
|
||||
end
|
||||
else
|
||||
env.response.status_code = 401
|
||||
err = { "error" => "Parameter 'login' or 'id' is missing" }
|
||||
err.to_json
|
||||
end
|
||||
else
|
||||
env.response.status_code = 401
|
||||
err = { "error" => "No query parameters found" }
|
||||
err.to_json
|
||||
end
|
||||
end
|
||||
|
||||
Kemal.run
|
110
src/twitchapi/gql.cr
Normal file
110
src/twitchapi/gql.cr
Normal file
|
@ -0,0 +1,110 @@
|
|||
require "json"
|
||||
require "uri"
|
||||
|
||||
module GqlAPI
|
||||
|
||||
@@headers = HTTP::Headers{
|
||||
"Content-Type" => "application/json",
|
||||
# "Client-Id" => "kimne78kx3ncx6brgo4mv6wki5h1ko", # Can cause problems due to Client-Integrity
|
||||
"Client-Id" => "ue6666qo983tsx6so1t0vnawi233wa",
|
||||
}
|
||||
|
||||
def self.gqlOperation(operation : String, login : String)
|
||||
case operation
|
||||
when "ChannelShell"
|
||||
data = [
|
||||
{
|
||||
"operationName" => "#{operation}",
|
||||
"variables" => {
|
||||
"login" => "#{login}",
|
||||
},
|
||||
"extensions" => {
|
||||
"persistedQuery" => {
|
||||
"version" => 1,
|
||||
"sha256Hash" => "580ab410bcd0c1ad194224957ae2241e5d252b2c5173d8e0cce9d32d5bb14efe",
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
when "ChannelAvatar"
|
||||
data = [
|
||||
{
|
||||
"operationName" => "#{operation}",
|
||||
"variables" => {
|
||||
"channelLogin" => "#{login}",
|
||||
},
|
||||
"extensions" => {
|
||||
"persistedQuery" => {
|
||||
"version" => 1,
|
||||
"sha256Hash" => "84ed918aaa9aaf930e58ac81733f552abeef8ac26c0117746865428a7e5c8ab0",
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
end
|
||||
return data.to_json
|
||||
end
|
||||
|
||||
def self.gqlOperation2()
|
||||
data = { "query" => "{}" }
|
||||
return data.to_json
|
||||
end
|
||||
|
||||
def self.user(id : String)
|
||||
data = { "query" => "{user(id:#{id}){
|
||||
bannerImageURL,
|
||||
profileImageURL(width: 600),
|
||||
roles{isStaff,isAffiliate,isPartner,isExtensionsDeveloper},
|
||||
chatSettings{blockLinks,chatDelayMs,slowModeDurationSeconds,followersOnlyDurationMinutes,isBroadcasterLanguageModeEnabled,isEmoteOnlyModeEnabled,isFastSubsModeEnabled,isSubscribersOnlyModeEnabled,isUniqueChatModeEnabled,requireVerifiedAccount,rules},
|
||||
stream{averageFPS,bitrate,codec,createdAt,width,height,id,viewersCount,type,game{displayName}},
|
||||
lastBroadcast{game{displayName},id,startedAt,title}
|
||||
}}" }
|
||||
return JSON.parse(gqlReq(id, data.to_json))["data"]["user"]
|
||||
end
|
||||
|
||||
def self.channel(id : String)
|
||||
data = { "query" => "{channel(id:#{id}){
|
||||
chatters{count,moderators{login},vips{login}}
|
||||
}}" }
|
||||
return JSON.parse(gqlReq(id, data.to_json))["data"]["channel"]
|
||||
end
|
||||
|
||||
def self.gqlReq(id : String, data : String)
|
||||
response = HTTP::Client.post(CONFIG.gqlEndpoint.to_s, headers: @@headers, body: data)
|
||||
|
||||
if response.success?
|
||||
return (response.body)
|
||||
else
|
||||
raise "GQL Twitch API returned #{response.status_code}: #{response.body.to_s}"
|
||||
end
|
||||
end
|
||||
|
||||
# def self.gqlReq(operation : String, login : String)
|
||||
# gqlRequest = gqlOperation2()
|
||||
# puts gqlRequest
|
||||
|
||||
# response = HTTP::Client.post(CONFIG.gqlEndpoint.to_s, headers: @@headers, body: gqlRequest)
|
||||
|
||||
# if response.success?
|
||||
# return (response.body)
|
||||
# else
|
||||
# raise "GQL Twitch API returned #{response.status_code}: #{response.body.to_s}"
|
||||
# end
|
||||
# end
|
||||
end
|
||||
|
||||
{
|
||||
"4": {
|
||||
"extensions": {
|
||||
"persistedQuery": {
|
||||
"sha256Hash": "84ed918aaa9aaf930e58ac81733f552abeef8ac26c0117746865428a7e5c8ab0",
|
||||
"version": 1
|
||||
}
|
||||
},
|
||||
"operationName": "ChannelAvatar",
|
||||
"variables": {
|
||||
"channelLogin": "fijxu"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
35
src/twitchapi/helix.cr
Normal file
35
src/twitchapi/helix.cr
Normal file
|
@ -0,0 +1,35 @@
|
|||
module HelixAPI
|
||||
@@headers = HTTP::Headers{
|
||||
"Content-Type" => "application/json",
|
||||
"Authorization" => "Bearer #{CONFIG.oauthToken}",
|
||||
"Client-Id" => "#{CONFIG.clientID}",
|
||||
}
|
||||
|
||||
def self.users(params)
|
||||
if params.has_key?("login")
|
||||
endpoint = "#{CONFIG.apiEndpoint}/users?login=#{params["login"]}"
|
||||
else
|
||||
endpoint = "#{CONFIG.apiEndpoint}/users?id=#{params["id"]}"
|
||||
end
|
||||
|
||||
response = HTTP::Client.get(endpoint, headers: @@headers)
|
||||
|
||||
if response.success?
|
||||
return (response.body)
|
||||
else
|
||||
raise "Helix Twitch API returned #{response.status_code}: #{response.body.to_s}"
|
||||
end
|
||||
end
|
||||
|
||||
def self.chatColor(id)
|
||||
endpoint = "#{CONFIG.apiEndpoint}/chat/color?user_id=#{id}"
|
||||
|
||||
response = HTTP::Client.get(endpoint, headers: @@headers)
|
||||
|
||||
if response.success?
|
||||
return (response.body)
|
||||
else
|
||||
raise "Helix Twitch API returned #{response.status_code}: #{response.body.to_s}"
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Add table
Reference in a new issue