0.2.0
This commit is contained in:
parent
7fbc39436b
commit
c085b71ede
17 changed files with 226065 additions and 379 deletions
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Binaries
|
||||
bin
|
||||
|
||||
# User config
|
||||
config/config.yml
|
||||
|
||||
# libs
|
||||
lib
|
||||
|
||||
# Syncthing
|
||||
.stfolder
|
24
README.md
24
README.md
|
@ -1,16 +1,24 @@
|
|||
## How to run
|
||||
|
||||
- Clone repo
|
||||
- Copy the `config/config.example.yml` to `config/config.yml`
|
||||
- Fill every option
|
||||
- Compile using `shards build --release`
|
||||
- Run `./bin/ivr-api-crystal`
|
||||
|
||||
### TODO
|
||||
|
||||
- ~Use Redis to cache replies and add a new key to report for how much time the JSON is going to be stored in cache (**Already started, but I need to fix it!!**)~ (Only done for the user endpoint)
|
||||
- ~Add other endpoints from api.ivr.fi~ (Almost everything)
|
||||
- CAPTURE MORE THAN 1 PARAM `?login=fuck,fuck`
|
||||
- ~~Use Redis to cache replies and add a new key to report for how much time the JSON is going to be stored in cache~~ Done.
|
||||
- ~~Add other endpoints from api.ivr.fi~~ Almost done.
|
||||
- ~~Capture more than 1 param: `?login=fijxu,fijxu`~~ Done.
|
||||
|
||||
### NOT SO IMPORTANT TODO
|
||||
|
||||
- Rate limiting (can be done in the reverse proxy side)
|
||||
- ~Better shitcode~ Better goodcode
|
||||
- ~STOP USING KEMAL FOR SIMPLE THINGS!~ Nevermind, kemal is pretty useful and it should stay
|
||||
|
||||
- ~~STOP USING KEMAL FOR SIMPLE THINGS~~ Nevermind, kemal is pretty useful and it should stay
|
||||
- `programAgreement { type }` in the Next commit.
|
||||
- Guide on how to get the tokens to get it working
|
||||
- Kick API
|
||||
|
||||
### Suggestions
|
||||
|
||||
3:45 RyanPotat: add team
|
||||
~~3:45 RyanPotat: add team~~ Next commit.
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
# Please fill everything
|
||||
|
||||
helixOAuth: ""
|
||||
helixClientID: ""
|
||||
gqlOAuth: ""
|
||||
gqlClientID: ""
|
||||
apiEndpoint: "https://api.twitch.tv/helix"
|
||||
gqlEndpoint: "https://gql.twitch.tv/gql"
|
||||
redis_url: "tcp://127.0.0.1:6379"
|
||||
port: 8080
|
||||
redis_addr: "127.0.0.1:6379"
|
||||
redis_database: 1
|
||||
port: 8081
|
||||
|
|
47398
schema.graphql
Normal file
47398
schema.graphql
Normal file
File diff suppressed because it is too large
Load diff
178032
schema.json
Normal file
178032
schema.json
Normal file
File diff suppressed because it is too large
Load diff
12
shard.lock
12
shard.lock
|
@ -4,6 +4,10 @@ shards:
|
|||
git: https://github.com/sija/backtracer.cr.git
|
||||
version: 1.2.2
|
||||
|
||||
db:
|
||||
git: https://github.com/crystal-lang/crystal-db.git
|
||||
version: 0.13.1
|
||||
|
||||
exception_page:
|
||||
git: https://github.com/crystal-loot/exception_page.git
|
||||
version: 0.4.1
|
||||
|
@ -12,15 +16,11 @@ shards:
|
|||
git: https://github.com/kemalcr/kemal.git
|
||||
version: 1.5.0
|
||||
|
||||
pool:
|
||||
git: https://github.com/ysbaddaden/pool.git
|
||||
version: 0.2.4
|
||||
|
||||
radix:
|
||||
git: https://github.com/luislavena/radix.git
|
||||
version: 0.4.1
|
||||
|
||||
redis:
|
||||
git: https://github.com/stefanwille/crystal-redis.git
|
||||
version: 2.9.1
|
||||
git: https://github.com/jgaskins/redis.git
|
||||
version: 0.9.0
|
||||
|
||||
|
|
30
shard.yml
30
shard.yml
|
@ -1,30 +1,22 @@
|
|||
name: ivr-api
|
||||
version: 0.1.0
|
||||
name: ivr-crystal
|
||||
version: 0.2.0
|
||||
|
||||
targets:
|
||||
invidious:
|
||||
ivr-api-crystal:
|
||||
main: src/main.cr
|
||||
|
||||
dependencies:
|
||||
kemal:
|
||||
github: kemalcr/kemal
|
||||
# redis:
|
||||
# github: stefanwille/crystal-redis
|
||||
redis:
|
||||
github: stefanwille/crystal-redis
|
||||
github: jgaskins/redis
|
||||
|
||||
authors:
|
||||
- Fijxu
|
||||
|
||||
# authors:
|
||||
# - name <email@example.com>
|
||||
description: |
|
||||
Drop-in api.ivr.fi replacement made using Crystal.
|
||||
|
||||
# description: |
|
||||
# Short description of ivr-api
|
||||
|
||||
# dependencies:
|
||||
# pg:
|
||||
# github: will/crystal-pg
|
||||
# version: "~> 0.5"
|
||||
|
||||
# development_dependencies:
|
||||
# webmock:
|
||||
# github: manastech/webmock.cr
|
||||
|
||||
# license: MIT
|
||||
license: Unlicense
|
||||
|
|
|
@ -3,31 +3,21 @@ require "yaml"
|
|||
class Config
|
||||
include YAML::Serializable
|
||||
|
||||
property helixOAuth : String?
|
||||
property helixClientID : String?
|
||||
property gqlOAuth : String?
|
||||
property gqlClientID : String?
|
||||
property apiEndpoint : String?
|
||||
property gqlEndpoint : String?
|
||||
property redis_url : String?
|
||||
property helixOAuth : String
|
||||
property helixClientID : String
|
||||
property gqlOAuth : String
|
||||
property gqlClientID : String
|
||||
property apiEndpoint : String? = "https://api.twitch.tv/helix"
|
||||
property gqlEndpoint : String? = "https://gql.twitch.tv/gql"
|
||||
property redis_addr : String? = "127.0.0.1:6379"
|
||||
property redis_socket : String?
|
||||
property redis_database : Int32?
|
||||
property port : Int32 = 8080
|
||||
|
||||
def self.load
|
||||
config_file = "config/config.yml"
|
||||
config_yaml = File.read(config_file)
|
||||
config = Config.from_yaml(config_yaml)
|
||||
|
||||
if config.helixOAuth.to_s.empty?
|
||||
puts "Config: 'helixOAuth' is required/can't be empty"
|
||||
exit(1)
|
||||
end
|
||||
|
||||
if config.helixClientID.to_s.empty?
|
||||
puts "Config: 'helixOAuth' is required/can't be empty"
|
||||
exit(1)
|
||||
end
|
||||
|
||||
return config
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,159 +1,215 @@
|
|||
module TwAPI::Routes::Twitch
|
||||
module TwAPI::Datahandlers::Twitch
|
||||
extend self
|
||||
|
||||
def checkBanned(gql)
|
||||
if GqlAPI.urb.includes? "login"
|
||||
if gql["userResultByLogin"]["reason"]?
|
||||
return gql["userResultByLogin"]["reason"]
|
||||
else
|
||||
return nil
|
||||
end
|
||||
elsif GqlAPI.urb.includes? "id"
|
||||
if gql["userResultByID"]["reason"]?
|
||||
return gql["userResultByID"]["reason"]
|
||||
else
|
||||
return nil
|
||||
end
|
||||
private macro error(message)
|
||||
env.response.content_type = "application/json"
|
||||
env.response.status_code = 403
|
||||
error_message = {"error" => {{message}}, "twitchResponse" => gql}.to_json
|
||||
return error_message
|
||||
end
|
||||
|
||||
private macro twitchError
|
||||
env.response.content_type = "application/json"
|
||||
env.response.status_code = 403
|
||||
error_message = {"error" => ex.message, "twitchResponse" => gql}.to_json
|
||||
return error_message
|
||||
end
|
||||
|
||||
private macro skipCache
|
||||
env.params.query["skipCache"]?
|
||||
end
|
||||
|
||||
def isBannedLogin(gql)
|
||||
if gql["userResultByLogin"]["reason"]?
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def parseData(params)
|
||||
if !params.has_key?("login") && !params.has_key?("id")
|
||||
err = {"error" => "No query parameters found"}
|
||||
return err.to_json
|
||||
end
|
||||
login = params["login"]?
|
||||
id = params["id"]?
|
||||
|
||||
if login && (json = REDIS_DB.get(login))
|
||||
# puts(JSON.parse(json))
|
||||
return json
|
||||
elsif id && (json = REDIS_DB.get(id))
|
||||
return json
|
||||
end
|
||||
|
||||
# puts REDIS_DB.get(params["login"]?)
|
||||
# puts REDIS_DB.get(params["id"]?)
|
||||
# if (json = (REDIS_DB.get(params["login"]?.to_s))) || (json = (REDIS_DB.get(params["id"]?.to_s)))
|
||||
# if ((json = REDIS_DB.get(id))
|
||||
# puts json
|
||||
# return json
|
||||
# end
|
||||
|
||||
gql = GqlAPI.queryUser(params)
|
||||
|
||||
if (gql["user"] == nil)
|
||||
err = {"message" => "Specified user does not exist"}
|
||||
return err.to_json
|
||||
end
|
||||
# puts gql
|
||||
|
||||
panels = gql["user"]["panels"]
|
||||
banned = checkBanned(gql)
|
||||
# puts(banned)
|
||||
|
||||
# Using JSON::Builder will be better I guess
|
||||
json_data = [
|
||||
{
|
||||
"cache" => {
|
||||
"isCached" => false,
|
||||
"expireTime" => nil : Int32,
|
||||
},
|
||||
"banned" => false,
|
||||
"reason" => banned,
|
||||
"displayName" => gql["user"]["displayName"],
|
||||
"login" => gql["user"]["login"],
|
||||
"id" => gql["user"]["id"],
|
||||
"bio" => gql["user"]["description"],
|
||||
"follows" => nil,
|
||||
"followers" => gql["user"]["followers"]["totalCount"],
|
||||
"profileViewCount" => nil, # Always null
|
||||
"panelCount" => panels.size,
|
||||
"chatColor" => gql["user"]["chatColor"],
|
||||
"logo" => gql["user"]["profileImageURL"],
|
||||
"banner" => gql["user"]["bannerImageURL"],
|
||||
"verifiedBot" => nil, # Deprecated by twitch
|
||||
"createdAt" => gql["user"]["createdAt"],
|
||||
"updatedAt" => gql["user"]["updatedAt"],
|
||||
"deletedAt" => gql["user"]["deletedAt"],
|
||||
"emotePrefix" => gql["user"]["emoticonPrefix"]["name"],
|
||||
"roles" => {
|
||||
"isAffiliate" => gql["user"]["roles"]["isAffiliate"],
|
||||
"isPartner" => gql["user"]["roles"]["isPartner"],
|
||||
"isStaff" => gql["user"]["roles"]["isStaff"],
|
||||
},
|
||||
"badges" => gql["user"]["displayBadges"],
|
||||
"chatterCount" => gql["user"]["channel"]["chatters"]["count"],
|
||||
"chatSettings" => gql["user"]["chatSettings"],
|
||||
"stream" => gql["user"]["stream"],
|
||||
"lastBroadcast" => gql["user"]["lastBroadcast"],
|
||||
"panels" => panels,
|
||||
},
|
||||
]
|
||||
if banned != nil
|
||||
json_data[0]["banned"] = true
|
||||
end
|
||||
|
||||
if id
|
||||
REDIS_DB.set(id, json_data.to_json, ex: 5)
|
||||
def isBannedId(gql)
|
||||
if gql["userResultByID"]["reason"]?
|
||||
return true
|
||||
else
|
||||
REDIS_DB.set(login.to_s, json_data.to_json, ex: 5)
|
||||
return false
|
||||
end
|
||||
|
||||
return json_data.to_json
|
||||
end
|
||||
|
||||
def user(env)
|
||||
# TODO: Clean this mess shit of else if else if else if
|
||||
if env.params.query
|
||||
params = env.params.query
|
||||
if params.has_key?("login") || params.has_key?("id")
|
||||
begin
|
||||
parseData(params)
|
||||
rescue ex
|
||||
env.response.status_code = 404
|
||||
err = {"error" => "#{ex.message}"}
|
||||
err.to_json
|
||||
end
|
||||
elsif params.has_key?("id")
|
||||
begin
|
||||
parseData(params)
|
||||
rescue ex
|
||||
env.response.status_code = 404
|
||||
err = {"error" => "#{ex.message}"}
|
||||
err.to_json
|
||||
end
|
||||
else
|
||||
env.response.status_code = 404
|
||||
err = {"error" => "Parameter 'login' or 'id' is missing"}
|
||||
err.to_json
|
||||
end
|
||||
else
|
||||
env.response.status_code = 404
|
||||
err = {"error" => "No query parameters found"}
|
||||
err.to_json
|
||||
def banReason(gql)
|
||||
if gql["userResultByLogin"] == nil
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
def userLogin(env)
|
||||
if skipCache != "true"
|
||||
if (json = Utils::Redis.retrieveFromCache("user-login_#{env.params.query["login"].try &.split(',')}"))
|
||||
json = JSON.parse(json)
|
||||
return json.to_json
|
||||
end
|
||||
end
|
||||
|
||||
begin
|
||||
gql = GqlAPI.getUserByLogin(env.params.query)
|
||||
rescue ex
|
||||
twitchError
|
||||
end
|
||||
|
||||
json_data = JSON.build do |json|
|
||||
json.array do
|
||||
gql.each do |gql|
|
||||
gql = gql["data"]
|
||||
|
||||
if (gql["user"] == nil)
|
||||
# v3 could add some feedback error message instead of an empty array.
|
||||
nil # Do not add anything to the array. Just like api.ivr.fi does.
|
||||
else
|
||||
panels = gql["user"]["panels"]
|
||||
banned = isBannedLogin(gql)
|
||||
|
||||
json.object do
|
||||
json.field "banned", banned
|
||||
if banned == true
|
||||
json.field "banReason", gql["userResultByLogin"]["reason"]
|
||||
end
|
||||
json.field "displayName", gql["user"]["displayName"]
|
||||
json.field "login", gql["user"]["login"]
|
||||
json.field "id", gql["user"]["id"]
|
||||
json.field "bio", gql["user"]["description"]
|
||||
json.field "follows", nil
|
||||
json.field "followers", gql["user"]["followers"]["totalCount"]
|
||||
json.field "profileViewCount", nil # Always null
|
||||
json.field "panelCount", panels.size
|
||||
json.field "chatColor", gql["user"]["chatColor"]
|
||||
json.field "logo", gql["user"]["profileImageURL"]
|
||||
json.field "banner", gql["user"]["bannerImageURL"]
|
||||
json.field "verifiedBot", nil # Deprecated by twitch
|
||||
json.field "createdAt", gql["user"]["createdAt"]
|
||||
json.field "updatedAt", gql["user"]["updatedAt"]
|
||||
json.field "deletedAt", gql["user"]["deletedAt"]
|
||||
json.field "emotePrefix", gql["user"]["emoticonPrefix"]["name"]
|
||||
json.field "roles", gql["user"]["roles"]
|
||||
json.field "badges", gql["user"]["displayBadges"]
|
||||
json.field "chatterCount", gql["user"]["channel"]["chatters"]["count"]
|
||||
json.field "chatSettings", gql["user"]["chatSettings"]
|
||||
json.field "stream", gql["user"]["stream"]
|
||||
json.field "lastBroadcast", gql["user"]["lastBroadcast"]
|
||||
json.field "panels", panels
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
begin
|
||||
Utils::Redis.saveJson("user-login_#{env.params.query["login"].try &.split(',')}", json_data)
|
||||
rescue ex
|
||||
puts ex.message
|
||||
end
|
||||
|
||||
return json_data
|
||||
end
|
||||
|
||||
def userId(env)
|
||||
if skipCache != "true"
|
||||
if (json = Utils::Redis.retrieveFromCache("user-id_#{env.params.query["id"].try &.split(',')}"))
|
||||
json = JSON.parse(json)
|
||||
return json.to_json
|
||||
end
|
||||
end
|
||||
|
||||
begin
|
||||
gql = GqlAPI.getUserById(env.params.query)
|
||||
rescue ex
|
||||
twitchError
|
||||
end
|
||||
|
||||
json_data = JSON.build do |json|
|
||||
json.array do
|
||||
gql.each do |gql|
|
||||
gql = gql["data"]
|
||||
|
||||
if (gql["user"] == nil)
|
||||
# v3 could add some feedback error message instead of an empty array.
|
||||
# Do not add anything to the array. Just like api.ivr.fi does.
|
||||
nil
|
||||
else
|
||||
panels = gql["user"]["panels"]
|
||||
banned = isBannedId(gql)
|
||||
|
||||
json.object do
|
||||
json.field "banned", banned
|
||||
if banned == true
|
||||
json.field "banReason", gql["userResultByID"]["reason"]
|
||||
end
|
||||
json.field "displayName", gql["user"]["displayName"]
|
||||
json.field "login", gql["user"]["login"]
|
||||
json.field "id", gql["user"]["id"]
|
||||
json.field "bio", gql["user"]["description"]
|
||||
json.field "follows", nil
|
||||
json.field "followers", gql["user"]["followers"]["totalCount"]
|
||||
json.field "profileViewCount", nil # Always null
|
||||
json.field "panelCount", panels.size
|
||||
json.field "chatColor", gql["user"]["chatColor"]
|
||||
json.field "logo", gql["user"]["profileImageURL"]
|
||||
json.field "banner", gql["user"]["bannerImageURL"]
|
||||
json.field "verifiedBot", nil # Deprecated by twitch
|
||||
json.field "createdAt", gql["user"]["createdAt"]
|
||||
json.field "updatedAt", gql["user"]["updatedAt"]
|
||||
json.field "deletedAt", gql["user"]["deletedAt"]
|
||||
json.field "emotePrefix", gql["user"]["emoticonPrefix"]["name"]
|
||||
json.field "roles", gql["user"]["roles"]
|
||||
json.field "badges", gql["user"]["displayBadges"]
|
||||
json.field "chatterCount", gql["user"]["channel"]["chatters"]["count"]
|
||||
json.field "chatSettings", gql["user"]["chatSettings"]
|
||||
json.field "stream", gql["user"]["stream"]
|
||||
json.field "lastBroadcast", gql["user"]["lastBroadcast"]
|
||||
json.field "panels", panels
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
begin
|
||||
Utils::Redis.saveJson("user-id_#{env.params.query["id"].try &.split(',')}", json_data)
|
||||
rescue ex
|
||||
puts ex.message
|
||||
end
|
||||
|
||||
return json_data
|
||||
end
|
||||
|
||||
def modvip(env)
|
||||
# if !env.params.query.has_key?("login") && !env.params.query.has_key?("id")
|
||||
# err = {"error" => "No query parameters found"}
|
||||
# return err.to_json
|
||||
# else
|
||||
if !env.params.url.has_key?("channel")
|
||||
err = {"error" => "Please insert a channel"}
|
||||
return err.to_json
|
||||
channel = env.params.url["channel"]
|
||||
|
||||
if (json = Utils::Redis.retrieveFromCache("modvip-#{channel}")) && skipCache != "true"
|
||||
json = JSON.parse(json)
|
||||
json.as_h["cache"].as_h["isCached"] = JSON::Any.new(true)
|
||||
json.as_h["cache"].as_h["expireTime"] = JSON::Any.new(Utils::Redis.getExpireTime("modvip-#{channel}"))
|
||||
return json.to_json
|
||||
end
|
||||
|
||||
gql = GqlAPI.getModsVips(env.params.url)["user"]
|
||||
begin
|
||||
gql = GqlAPI.getModsVips(channel)
|
||||
gql = gql["data"]["user"]
|
||||
rescue ex
|
||||
twitchError
|
||||
end
|
||||
|
||||
if (gql == nil)
|
||||
err = {"message" => "Specified user does not exist"}
|
||||
return err.to_json
|
||||
error("Specified channel does no exist")
|
||||
end
|
||||
|
||||
json_data = JSON.build do |json|
|
||||
json.object do
|
||||
json.field "cache" do
|
||||
json.object do
|
||||
json.field "isCached", false
|
||||
json.field "expireTime", nil
|
||||
end
|
||||
end
|
||||
json.field "modCount", gql["mods"]["edges"].size
|
||||
json.field "vipCount", gql["vips"]["edges"].size
|
||||
json.field "mods" do
|
||||
|
@ -196,29 +252,43 @@ module TwAPI::Routes::Twitch
|
|||
end
|
||||
end
|
||||
end
|
||||
Utils::Redis.saveJson("modvip-#{channel}", json_data)
|
||||
|
||||
return json_data
|
||||
end
|
||||
|
||||
# TODO: Add error message if query doesn't exist at all
|
||||
|
||||
def founders(env)
|
||||
# if !env.params.query.has_key?("login") && !env.params.query.has_key?("id")
|
||||
# err = {"error" => "No query parameters found"}
|
||||
# return err.to_json
|
||||
# else
|
||||
if !env.params.url.has_key?("login")
|
||||
err = {"error" => "Please insert a channel"}
|
||||
return err.to_json
|
||||
end
|
||||
gql = GqlAPI.getFounders(env.params.url)["user"]
|
||||
login = env.params.url["login"]
|
||||
|
||||
if (json = Utils::Redis.retrieveFromCache("founders-#{login}")) && skipCache != "true"
|
||||
json = JSON.parse(json)
|
||||
json.as_h["cache"].as_h["isCached"] = JSON::Any.new(true)
|
||||
json.as_h["cache"].as_h["expireTime"] = JSON::Any.new(Utils::Redis.getExpireTime("founders-#{login}"))
|
||||
return json.to_json
|
||||
end
|
||||
|
||||
begin
|
||||
gql = GqlAPI.getFounders(login)
|
||||
gql = gql["data"]["user"]
|
||||
rescue ex
|
||||
twitchError
|
||||
end
|
||||
|
||||
# TODO: use begin rescue for this too!
|
||||
if (gql == nil)
|
||||
err = {"message" => "Specified user does not exist"}
|
||||
return err.to_json
|
||||
error("Specified channel does no exist")
|
||||
end
|
||||
|
||||
json_data = JSON.build do |json|
|
||||
json.object do
|
||||
json.field "cache" do
|
||||
json.object do
|
||||
json.field "isCached", false
|
||||
json.field "expireTime", nil
|
||||
end
|
||||
end
|
||||
json.field "foundersCount", gql["channel"]["founders"].size
|
||||
json.field "founders" do
|
||||
json.array do
|
||||
|
@ -242,27 +312,41 @@ module TwAPI::Routes::Twitch
|
|||
end
|
||||
end
|
||||
end
|
||||
Utils::Redis.saveJson("founders-#{login}", json_data)
|
||||
|
||||
return json_data
|
||||
end
|
||||
|
||||
def clip(env)
|
||||
# if !env.params.query.has_key?("slug")
|
||||
# err = {"error" => "No query parameters found"}
|
||||
# return err.to_jso
|
||||
# else
|
||||
if !env.params.url.has_key?("slug")
|
||||
err = {"error" => "Please insert a slug"}
|
||||
return err.to_json
|
||||
slug = env.params.url["slug"]
|
||||
|
||||
if (json = Utils::Redis.retrieveFromCache("clip-#{slug}")) && skipCache != "true"
|
||||
json = JSON.parse(json)
|
||||
json.as_h["cache"].as_h["isCached"] = JSON::Any.new(true)
|
||||
json.as_h["cache"].as_h["expireTime"] = JSON::Any.new(Utils::Redis.getExpireTime("clip-#{slug}"))
|
||||
return json.to_json
|
||||
end
|
||||
|
||||
gql = GqlAPI.getClips(env.params.url)["clip"]
|
||||
begin
|
||||
gql = GqlAPI.getClips(slug)
|
||||
gql = gql["data"]["clip"]
|
||||
rescue ex
|
||||
twitchError
|
||||
end
|
||||
|
||||
# TODO: use begin rescue for this too! (again)
|
||||
if (gql == nil)
|
||||
err = {"message" => "Specified user does not exist"}
|
||||
return err.to_json
|
||||
error("Slug does not exist")
|
||||
end
|
||||
|
||||
json_data = JSON.build do |json|
|
||||
json.object do
|
||||
json.field "cache" do
|
||||
json.object do
|
||||
json.field "isCached", false
|
||||
json.field "expireTime", nil
|
||||
end
|
||||
end
|
||||
json.field "clip" do
|
||||
json.object do
|
||||
json.field "durationSeconds", gql["durationSeconds"]
|
||||
|
@ -321,22 +405,40 @@ module TwAPI::Routes::Twitch
|
|||
end
|
||||
end
|
||||
end
|
||||
Utils::Redis.saveJson("clip-#{slug}", json_data)
|
||||
|
||||
return json_data
|
||||
end
|
||||
|
||||
def subage(env)
|
||||
if !env.params.url.has_key?("user") || !env.params.url.has_key?("channel")
|
||||
err = {"error" => "No query parameters found"}
|
||||
return err.to_json
|
||||
user = env.params.url["user"]
|
||||
channel = env.params.url["channel"]
|
||||
|
||||
if (json = Utils::Redis.retrieveFromCache("subage-user_#{user}_channel_#{channel}")) && skipCache != "true"
|
||||
json = JSON.parse(json)
|
||||
json.as_h["cache"].as_h["isCached"] = JSON::Any.new(true)
|
||||
json.as_h["cache"].as_h["expireTime"] = JSON::Any.new(Utils::Redis.getExpireTime("subage-user_#{user}_channel_#{channel}"))
|
||||
return json.to_json
|
||||
end
|
||||
|
||||
gql = GqlAPI.getSubage(env.params.url["user"], env.params.url["channel"])
|
||||
if (gql == nil)
|
||||
err = {"message" => "Specified user does not exist"}
|
||||
return err.to_json
|
||||
begin
|
||||
gql = GqlAPI.getSubage(user, channel)
|
||||
gql = gql["data"]
|
||||
rescue ex
|
||||
if (gql == nil)
|
||||
error("Channel does not exist")
|
||||
end
|
||||
twitchError
|
||||
end
|
||||
|
||||
json_data = JSON.build do |json|
|
||||
json.object do
|
||||
json.field "cache" do
|
||||
json.object do
|
||||
json.field "isCached", false
|
||||
json.field "expireTime", nil
|
||||
end
|
||||
end
|
||||
json.field "user" do
|
||||
json.object do
|
||||
json.field "id", gql["userData"]["id"]?
|
||||
|
@ -353,7 +455,7 @@ module TwAPI::Routes::Twitch
|
|||
end
|
||||
json.field "statusHidden", false # TODO: what is this? I need to get it NOW!
|
||||
json.field "followedAt", gql["info"]["relationship"]["followedAt"]
|
||||
if (gql["info"]["relationship"]["streak"] == nil)
|
||||
if (gql["info"]["relationship"]["streak"] == nil) || (gql["info"]["relationship"]["streak"]["elapsedDays"]? == 0)
|
||||
json.field "streak", nil
|
||||
else
|
||||
json.field "streak" do
|
||||
|
@ -366,7 +468,7 @@ module TwAPI::Routes::Twitch
|
|||
end
|
||||
end
|
||||
end
|
||||
if (gql["info"]["relationship"]["cumulative"] == nil)
|
||||
if (gql["info"]["relationship"]["cumulative"] == nil) || (gql["info"]["relationship"]["cumulative"]["elapsedDays"]? == 0)
|
||||
json.field "cumulative", nil
|
||||
else
|
||||
json.field "cumulative" do
|
||||
|
@ -394,23 +496,39 @@ module TwAPI::Routes::Twitch
|
|||
end
|
||||
end
|
||||
end
|
||||
Utils::Redis.saveJson("subage-user_#{user}_channel_#{channel}", json_data)
|
||||
|
||||
return json_data
|
||||
end
|
||||
|
||||
def emotes(env)
|
||||
if !env.params.url.has_key?("emote")
|
||||
err = {"error" => "No query parameters found"}
|
||||
return err.to_json
|
||||
emoteName = env.params.url["emote"]
|
||||
|
||||
if (json = Utils::Redis.retrieveFromCache("emotes-#{emoteName}")) && skipCache != "true"
|
||||
json = JSON.parse(json)
|
||||
json.as_h["cache"].as_h["isCached"] = JSON::Any.new(true)
|
||||
json.as_h["cache"].as_h["expireTime"] = JSON::Any.new(Utils::Redis.getExpireTime("emotes-#{emoteName}"))
|
||||
return json.to_json
|
||||
end
|
||||
|
||||
gql = GqlAPI.getEmotes(env.params.url["emote"])["emote"] # TODO: support if ID or emote name
|
||||
|
||||
if (gql == nil)
|
||||
err = {"message" => "Specified emote does not exist"}
|
||||
return err.to_json
|
||||
begin
|
||||
gql = GqlAPI.getEmotes(emoteName)
|
||||
gql = gql["data"]["emote"]
|
||||
if gql == nil
|
||||
raise "Emote does not exist"
|
||||
end
|
||||
rescue ex
|
||||
twitchError
|
||||
end
|
||||
|
||||
json_data = JSON.build do |json|
|
||||
json.object do
|
||||
json.field "cache" do
|
||||
json.object do
|
||||
json.field "isCached", false
|
||||
json.field "expireTime", nil
|
||||
end
|
||||
end
|
||||
json.field "channelName", gql["owner"]["displayName"]
|
||||
json.field "channelLogin", gql["owner"]["login"]
|
||||
json.field "channelID", gql["owner"]["id"]
|
||||
|
@ -424,20 +542,22 @@ module TwAPI::Routes::Twitch
|
|||
json.field "emoteTier", gql["subscriptionTier"]
|
||||
end
|
||||
end
|
||||
Utils::Redis.saveJson("emotes-#{emoteName}", json_data)
|
||||
|
||||
return json_data
|
||||
end
|
||||
|
||||
def channelEmotes(env)
|
||||
if !env.params.query.has_key?("channel")
|
||||
err = {"error" => "No query parameters found"}
|
||||
return err.to_json
|
||||
end
|
||||
gql = GqlAPI.getChannelEmotes(env.params.query["channel"]) # TODO: Add support for IDs an not just the channel name
|
||||
if (gql == nil)
|
||||
err = {"message" => "Specified user does not exist"}
|
||||
return err.to_json
|
||||
end
|
||||
|
||||
json_data = JSON.build do |json|
|
||||
json.object do
|
||||
json.field "cache" do
|
||||
json.object do
|
||||
json.field "isCached", false
|
||||
json.field "expireTime", nil
|
||||
end
|
||||
end
|
||||
json.field "subProducts" do
|
||||
json.array do
|
||||
gql["user"]["subEmotes"]?.try &.as_a.each do |subEmotes|
|
||||
|
@ -491,14 +611,3 @@ module TwAPI::Routes::Twitch
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
# I'll do this later fuck this shit
|
||||
|
||||
# def globalEmotes(env)
|
||||
# if !env.params.query.has_key?("id") || !env.params.query.has_key?("login")
|
||||
# err = "[]"
|
||||
# return err.to_json
|
||||
# else
|
||||
# gql = GqlAPI.getChannelEmotes(env.params.query)
|
||||
# json_data = JSON.build do |json|
|
||||
# end
|
52
src/main.cr
52
src/main.cr
|
@ -6,57 +6,21 @@ require "redis"
|
|||
|
||||
require "./config"
|
||||
require "./routes/**"
|
||||
require "./datahandlers/**"
|
||||
require "./twitchapi/*"
|
||||
require "./utils/*"
|
||||
|
||||
module TwAPI
|
||||
end
|
||||
|
||||
alias TA = TwAPI
|
||||
|
||||
CONFIG = Config.load
|
||||
CONFIG = Config.load
|
||||
Kemal.config.port = CONFIG.port
|
||||
REDIS_DB = Redis::PooledClient.new(unixsocket: CONFIG.redis_socket || nil, url: CONFIG.redis_url || nil)
|
||||
if REDIS_DB.ping
|
||||
puts "Connected to redis"
|
||||
end
|
||||
REDIS_UTILS = TwAPI::Utils::Redis
|
||||
REDIS_DB = Redis::Client.new(URI.parse("redis://#{CONFIG.redis_addr}/#{CONFIG.redis_database}#?keepalive=true"))
|
||||
puts "Connected to Redis"
|
||||
|
||||
before_all "/v2/*" do |env|
|
||||
env.response.content_type = "application/json"
|
||||
end
|
||||
|
||||
TwAPI::Routing.register_all()
|
||||
|
||||
# get "/v2/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
|
||||
TwAPI::Routes.register_misc
|
||||
TwAPI::Routes.register_all_twitch
|
||||
|
||||
{% if flag?(:release) || flag?(:production) %}
|
||||
Kemal.config.env = "production" if !ENV.has_key?("KEMAL_ENV")
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
module TwAPI::Routing
|
||||
module TwAPI::Routes
|
||||
extend self # To prevent writing self. at the start of every function
|
||||
|
||||
# Thanks Invidious devs
|
||||
{% for http_method in {"get", "post", "delete", "options", "patch", "put"} %}
|
||||
|
||||
macro {{http_method.id}}(path, controller, method = :handle)
|
||||
unless Kemal::Utils.path_starts_with_slash?(\{{path}})
|
||||
raise Kemal::Exceptions::InvalidPathStartException.new({{http_method}}, \{{path}})
|
||||
|
@ -13,11 +12,23 @@ module TwAPI::Routing
|
|||
\{{ controller }}.\{{ method.id }}(env)
|
||||
end
|
||||
end
|
||||
|
||||
{% end %}
|
||||
|
||||
def register_all
|
||||
# get "/"
|
||||
def register_misc
|
||||
before_all "/v2/*" do |env|
|
||||
env.response.content_type = "application/json"
|
||||
end
|
||||
|
||||
get "/" do |env|
|
||||
env.redirect "/v2"
|
||||
end
|
||||
|
||||
get "/v2" do
|
||||
{"message": "Welcome to v2, There is no docs!"}.to_json
|
||||
end
|
||||
end
|
||||
|
||||
def register_all_twitch
|
||||
get "/v2/twitch/user", TwAPI::Routes::Twitch, :user
|
||||
|
||||
get "/v2/twitch/modvip/", TwAPI::Routes::Twitch, :modvip
|
||||
|
|
52
src/routes/twitch.cr
Normal file
52
src/routes/twitch.cr
Normal file
|
@ -0,0 +1,52 @@
|
|||
module TwAPI::Routes::Twitch
|
||||
extend self
|
||||
|
||||
private macro handleData(func)
|
||||
begin
|
||||
TwAPI::Datahandlers::Twitch.{{func}}(env)
|
||||
rescue ex
|
||||
env.response.status_code = 404
|
||||
err = {"error" => "#{ex.message}"}
|
||||
err.to_json
|
||||
end
|
||||
end
|
||||
|
||||
def user(env)
|
||||
if env.params.query.has_key?("login")
|
||||
handleData(userLogin)
|
||||
else
|
||||
handleData(userId)
|
||||
end
|
||||
end
|
||||
|
||||
def modvip(env)
|
||||
handleData(modvip)
|
||||
end
|
||||
|
||||
def founders(env)
|
||||
handleData(founders)
|
||||
end
|
||||
|
||||
def clip(env)
|
||||
handleData(clip)
|
||||
end
|
||||
|
||||
def subage(env)
|
||||
handleData(subage)
|
||||
end
|
||||
|
||||
def emotes(env)
|
||||
handleData(emotes)
|
||||
end
|
||||
end
|
||||
|
||||
# I'll do this later fuck this shit
|
||||
|
||||
# def globalEmotes(env)
|
||||
# if !env.params.query.has_key?("id") || !env.params.query.has_key?("login")
|
||||
# err = "[]"
|
||||
# return err.to_json
|
||||
# else
|
||||
# gql = GqlAPI.getChannelEmotes(env.params.query)
|
||||
# json_data = JSON.build do |json|
|
||||
# end
|
|
@ -1,18 +1,6 @@
|
|||
module GqlAPI
|
||||
module TwAPI::GqlAPI
|
||||
extend self
|
||||
|
||||
@@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}",
|
||||
}
|
||||
@@urb : String = "fuck"
|
||||
|
||||
def urb
|
||||
return @@urb
|
||||
end
|
||||
|
||||
def userResultBy(params)
|
||||
if params.has_key?("id")
|
||||
return %(userResultByID(id: "#{params["id"]}"))
|
||||
|
@ -37,27 +25,22 @@ module GqlAPI
|
|||
end
|
||||
end
|
||||
|
||||
def user(params)
|
||||
if params.has_key?("id")
|
||||
return %(id: "#{params["id"]}" lookupType: ALL)
|
||||
elsif params.has_key?("login")
|
||||
return %(login: "#{params["login"]}" lookupType: ALL)
|
||||
else
|
||||
return %(login: "#{params["channel"]}" lookupType: ALL)
|
||||
end
|
||||
end
|
||||
def getUserByLogin(params)
|
||||
logins = params["login"].try &.split(',')
|
||||
channel = Channel(JSON::Any).new
|
||||
responses = [] of JSON::Any
|
||||
queries = [] of String
|
||||
|
||||
def queryUser(params)
|
||||
@@urb = userResultBy(params)
|
||||
query = %(
|
||||
logins.each do |login|
|
||||
query = %(
|
||||
query {
|
||||
#{userResultBy(params)} {
|
||||
userResultByLogin(login: "#{login}") {
|
||||
... on UserDoesNotExist {
|
||||
key
|
||||
reason
|
||||
}
|
||||
}
|
||||
user(#{user(params)}) {
|
||||
user(login: "#{login}" lookupType: ALL) {
|
||||
id
|
||||
language
|
||||
login
|
||||
|
@ -138,13 +121,140 @@ module GqlAPI
|
|||
}
|
||||
}
|
||||
)
|
||||
return (JSON.parse(gqlReq(query)))["data"]
|
||||
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(env)
|
||||
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(#{user(env)}) {
|
||||
user(login: "#{params}" lookupType: ALL) {
|
||||
mods(first: 100) {
|
||||
edges {
|
||||
grantedAt
|
||||
|
@ -169,13 +279,13 @@ module GqlAPI
|
|||
}
|
||||
}
|
||||
)
|
||||
return (JSON.parse(gqlReq(query)))["data"]
|
||||
return JSON.parse(req(query))
|
||||
end
|
||||
|
||||
def getFounders(env)
|
||||
def getFounders(params)
|
||||
query = %(
|
||||
query {
|
||||
user(#{user(env)}) {
|
||||
user(login: "#{params}" lookupType: ALL) {
|
||||
id
|
||||
login
|
||||
displayName
|
||||
|
@ -194,13 +304,13 @@ module GqlAPI
|
|||
}
|
||||
}
|
||||
)
|
||||
return (JSON.parse(gqlReq(query)))["data"]
|
||||
return JSON.parse(req(query))
|
||||
end
|
||||
|
||||
def getClips(params)
|
||||
query = %(
|
||||
query {
|
||||
clip(slug: "#{params["slug"]}") {
|
||||
clip(slug: "#{params}") {
|
||||
createdAt
|
||||
creationState
|
||||
durationSeconds
|
||||
|
@ -234,14 +344,14 @@ module GqlAPI
|
|||
}
|
||||
}
|
||||
)
|
||||
return (JSON.parse(gqlReq(query)))["data"]
|
||||
return JSON.parse(req(query))
|
||||
end
|
||||
|
||||
def getSubage(user, channel)
|
||||
channelId = HelixAPI.getId(channel)
|
||||
query = %(
|
||||
query {
|
||||
userData: userResultByLogin (login: "#{user}") {
|
||||
userData: userResultByLogin (login: "#{user}") {
|
||||
... on UserDoesNotExist { key reason }
|
||||
... on UserError { key }
|
||||
... on User { id displayName login }
|
||||
|
@ -287,7 +397,7 @@ module GqlAPI
|
|||
}
|
||||
}
|
||||
)
|
||||
return (JSON.parse(gqlReq(query)))["data"]
|
||||
return JSON.parse(req(query))
|
||||
end
|
||||
|
||||
def getEmotes(emote)
|
||||
|
@ -318,7 +428,7 @@ module GqlAPI
|
|||
}
|
||||
}
|
||||
)
|
||||
return (JSON.parse(gqlReq(query)))["data"]
|
||||
return JSON.parse(req(query))
|
||||
end
|
||||
|
||||
def getChannelEmotes(channel)
|
||||
|
@ -352,7 +462,7 @@ module GqlAPI
|
|||
}
|
||||
}
|
||||
)
|
||||
return (JSON.parse(gqlReq(query)))["data"]
|
||||
return JSON.parse(req(query))
|
||||
end
|
||||
|
||||
def getEmotes(emote)
|
||||
|
@ -383,7 +493,7 @@ module GqlAPI
|
|||
}
|
||||
}
|
||||
)
|
||||
return (JSON.parse(gqlReq(query)))["data"]
|
||||
return JSON.parse(req(query))
|
||||
end
|
||||
|
||||
def getChannelBadges(channel)
|
||||
|
@ -410,12 +520,18 @@ module GqlAPI
|
|||
}
|
||||
}
|
||||
)
|
||||
return (JSON.parse(gqlReq(query)))["data"]
|
||||
return JSON.parse(req(query))
|
||||
end
|
||||
|
||||
def gqlReq(query)
|
||||
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)
|
||||
response = HTTP::Client.post(CONFIG.gqlEndpoint.to_s, headers: headers, body: data.to_json)
|
||||
|
||||
if response.success?
|
||||
return (response.body)
|
|
@ -1,40 +0,0 @@
|
|||
module HelixAPI
|
||||
extend self
|
||||
|
||||
@@headers = HTTP::Headers{
|
||||
"Content-Type" => "application/json",
|
||||
"Authorization" => "Bearer #{CONFIG.helixOAuth}",
|
||||
"Client-Id" => "#{CONFIG.helixClientID}",
|
||||
}
|
||||
|
||||
def 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 getId(login)
|
||||
request = "#{CONFIG.apiEndpoint.to_s}/users?login=#{login}"
|
||||
return JSON.parse(helixReq(request))["data"][0]["id"]
|
||||
end
|
||||
|
||||
def helixReq(request)
|
||||
response = HTTP::Client.get(request, headers: @@headers)
|
||||
|
||||
if response.success?
|
||||
return (response.body)
|
||||
else
|
||||
raise "Helix Twitch API returned #{response.status_code}: #{response.body.to_s}"
|
||||
end
|
||||
end
|
||||
end
|
23
src/twitchapi/helixapi.cr
Normal file
23
src/twitchapi/helixapi.cr
Normal file
|
@ -0,0 +1,23 @@
|
|||
module HelixAPI
|
||||
extend self
|
||||
|
||||
def getId(login)
|
||||
request = "#{CONFIG.apiEndpoint.to_s}/users?login=#{login}"
|
||||
return JSON.parse(req(request))["data"][0]["id"]
|
||||
end
|
||||
|
||||
def req(request)
|
||||
headers = HTTP::Headers{
|
||||
"Content-Type" => "application/json",
|
||||
"Authorization" => "Bearer #{CONFIG.helixOAuth}",
|
||||
"Client-Id" => "#{CONFIG.helixClientID}",
|
||||
}
|
||||
response = HTTP::Client.get(request, headers: headers)
|
||||
|
||||
if response.success?
|
||||
return (response.body)
|
||||
else
|
||||
raise "Helix Twitch API returned #{response.status_code}: #{response.body.to_s}"
|
||||
end
|
||||
end
|
||||
end
|
17
src/utils/redis.cr
Normal file
17
src/utils/redis.cr
Normal file
|
@ -0,0 +1,17 @@
|
|||
module TwAPI::Utils::Redis
|
||||
extend self
|
||||
|
||||
def getExpireTime(key)
|
||||
return REDIS_DB.ttl(key)
|
||||
end
|
||||
|
||||
def retrieveFromCache(keyName)
|
||||
if keyName && (json = REDIS_DB.get(keyName))
|
||||
return json
|
||||
end
|
||||
end
|
||||
|
||||
def saveJson(keyName, json_data : String)
|
||||
REDIS_DB.set(keyName, json_data, ex: 60)
|
||||
end
|
||||
end
|
3
src/utils/utils.cr
Normal file
3
src/utils/utils.cr
Normal file
|
@ -0,0 +1,3 @@
|
|||
module TwAPI::Utils
|
||||
extend self
|
||||
end
|
Loading…
Reference in a new issue