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