Compare commits
23 Commits
1ec2749319
...
2.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 33d69c2ed3 | |||
| a808515c1d | |||
| b1c87b1adf | |||
| af895a5173 | |||
| 7d71c48536 | |||
| deb8746347 | |||
| c449beac80 | |||
| f3166ceaa5 | |||
| 22cb492bbc | |||
| 79e4b5b99b | |||
| e3742971dc | |||
| ce48d37d86 | |||
| 7f0eadff2f | |||
| 88d6405fb6 | |||
| dee8935f9c | |||
| 284b9342ce | |||
| a09c0f86d5 | |||
| ee6245d77a | |||
| bd1dc3190c | |||
| a1fe5ff70c | |||
| d1e036bdcf | |||
| 5455d1e2f1 | |||
| 055d72129a |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -15,3 +15,7 @@ pom.xml.asc
|
||||
.calva
|
||||
*.svg
|
||||
/logs
|
||||
# Native executable
|
||||
riot
|
||||
# A weid link
|
||||
/bin/*
|
||||
31
README.md
31
README.md
@@ -6,9 +6,6 @@ application to quick get some relevant data.
|
||||
|
||||
The library and the CLI application are separated, you can use the library independently.
|
||||
|
||||
CLI application should be compatible with [babashka](https://babashka.org/), so
|
||||
will use external libraries compatible with it.
|
||||
|
||||
# The API and the tokens
|
||||
|
||||
Accessing the API requires one or more API tokens. Each videogame has their own
|
||||
@@ -78,9 +75,7 @@ all functionality provided by v1.1.
|
||||
### General
|
||||
|
||||
* [x] Reestructure all project to use `deps.edn`, `tools.clj` and subprojects
|
||||
* [ ] Use babashka compatible libraries and `bb.edn`
|
||||
* [ ] Gitea actions for automatic test executing
|
||||
* [ ] Distribute CLI as self executable (bb, jlink or graal)
|
||||
* [ ] Distribute CLI as self executable (jlink or graal)
|
||||
|
||||
### Library
|
||||
|
||||
@@ -88,19 +83,19 @@ all functionality provided by v1.1.
|
||||
* [x] Fuctions for calling Riot API and read result as clojure data structures (EDN format)
|
||||
* [x] Get [PUUID](https://developer.riotgames.com/docs/lol#summoner-names-to-riot-ids_obtaining-puuid-and-summonerid-from-riotid) for a player
|
||||
* [x] Get basic player info
|
||||
* [ ] Format raw data
|
||||
* [x] Format raw data
|
||||
|
||||
### CLI
|
||||
* [ ] Babashka compatible CLI
|
||||
* [ ] Basic parameters for log level and override API tokens
|
||||
* [ ] Obtain basic player info
|
||||
* [ ] Last games for player (LOL, TFT and others)
|
||||
* [ ] Is the player playing just now?
|
||||
* [ ] Contiuosly check if the player es playing
|
||||
* [ ] Write status check to a file, to save an activity log
|
||||
* [ ] Format output as fancy table
|
||||
* [ ] Format output as CSV
|
||||
* [ ] Calculte basic statistics
|
||||
* [x] Rich and easy to use CLI
|
||||
* [x] Basic parameters for log level and override API tokens
|
||||
* [x] Obtain basic player info
|
||||
* [x] Last games for player (LOL, TFT and others)
|
||||
* [x] Is the player playing just now?
|
||||
* [x] Contiuosly check if the player es playing
|
||||
* [x] Format output as fancy table
|
||||
* [x] Format output as CSV
|
||||
* [x] Format output as JSON
|
||||
* [x] Calculte basic statistics
|
||||
* [ ] Calculate advanced statistics: win strike, adversaries, etc.
|
||||
|
||||
|
||||
@@ -108,7 +103,7 @@ all functionality provided by v1.1.
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 ruben
|
||||
Copyright (c) 2026 ruben
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
|
||||
190
build.clj
190
build.clj
@@ -1,176 +1,44 @@
|
||||
(ns build
|
||||
(:refer-clojure :exclude [test])
|
||||
(:require [clojure.tools.build.api :as b]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.pprint :as pp]
|
||||
[clojure.java.basis :as basis]))
|
||||
(:require [clojure.tools.build.api :as b]))
|
||||
|
||||
(def lib-group "es.rcorral")
|
||||
(def artifact-prefix "clj-totp")
|
||||
(def subprojs-base "projects")
|
||||
(def curr-version (format "2.0.%s" (b/git-count-revs nil)))
|
||||
(def lib 'es.rcorral/riot-clojure)
|
||||
(def version (format "2.0.%s" (b/git-count-revs nil))) ;; or read from file, etc
|
||||
(def class-dir "target/classes")
|
||||
(def src-dirs ["src"])
|
||||
(def jar-file (format "target/%s-%s.jar" (name lib) version))
|
||||
(def uber-file (format "target/%s-%s-standalone.jar" (name lib) version))
|
||||
(def main-ns "riot.app")
|
||||
|
||||
;; delay to defer side effects (artifact downloads)
|
||||
(def basis (delay (b/create-basis {:project "deps.edn"})))
|
||||
|
||||
;; Builds artifact's full descriptor for each subproject
|
||||
(defn lib [subproj]
|
||||
(symbol (str lib-group "/" artifact-prefix "-" subproj )))
|
||||
(defn clean [_]
|
||||
(b/delete {:path "target"}))
|
||||
|
||||
(defn jar [_]
|
||||
(b/write-pom {:class-dir class-dir
|
||||
:lib lib
|
||||
:version version
|
||||
:basis @basis
|
||||
:src-dirs ["src"]})
|
||||
(b/copy-dir {:src-dirs ["src" "resources"]
|
||||
:target-dir class-dir})
|
||||
(b/jar {:class-dir class-dir
|
||||
:jar-file jar-file}))
|
||||
|
||||
;; Basis for each subproject, using their own deps.edn
|
||||
;; Injects :extra-deps from :build as additional dependencies
|
||||
(defn basis [subproj]
|
||||
(delay (b/create-basis {:project (str subprojs-base "/" subproj "/deps.edn")
|
||||
;; Inject extra deps as deps
|
||||
:extra {:deps (get-in (basis/initial-basis) [:aliases :build :extra-deps])}
|
||||
})))
|
||||
|
||||
|
||||
;; Show basis generated for a subproject
|
||||
#_{:clojure-lsp/ignore [:clojure-lsp/unused-public-var]}
|
||||
(defn show-basis [subproj]
|
||||
(println (with-out-str
|
||||
(pp/pprint
|
||||
@(basis subproj)
|
||||
;(basis/initial-basis)
|
||||
))))
|
||||
|
||||
(comment
|
||||
(pp/pprint (keys (basis/initial-basis)))
|
||||
(pp/pprint (:deps (basis/initial-basis)))
|
||||
(pp/pprint (:libs (basis/initial-basis)))
|
||||
(pp/pprint (sort (keys (:aliases (basis/initial-basis)))))
|
||||
(get-in (basis/initial-basis) [:aliases :build :extra-deps])
|
||||
)
|
||||
|
||||
;; Target dir for each subproject
|
||||
(defn target-dir [subproj]
|
||||
(str "target/" subproj))
|
||||
|
||||
|
||||
;; Path for compiled classes
|
||||
(defn class-dir [subproj]
|
||||
(str (target-dir subproj) "/" "classes"))
|
||||
|
||||
|
||||
;; Jar file for each subproject. :uber type adds -standalone suffix
|
||||
(defn jar-file [subproj version type]
|
||||
(format "target/%s-%s-%s%s.jar" artifact-prefix subproj version
|
||||
(if (= type :uber) "-standalone" "")))
|
||||
|
||||
|
||||
;; Clean target dir for subproject
|
||||
(defn clean [{:keys [subproj]}]
|
||||
(b/delete {:path (target-dir subproj)})
|
||||
(println "Project" subproj "cleaned"))
|
||||
|
||||
|
||||
;; Compile java classes, only if java subdir exists
|
||||
(defn compile-java [{:keys [subproj]}]
|
||||
(let [java-dir (str subprojs-base "/" subproj "/java")]
|
||||
(if (.exists (io/file java-dir))
|
||||
(do
|
||||
(println "Compiling java code for" subproj)
|
||||
(b/javac {:src-dirs [java-dir]
|
||||
:class-dir (class-dir subproj)
|
||||
:basis @(basis subproj)
|
||||
:javac-opts ["-source" "11" "--target" "11" "-proc:none"]}))
|
||||
(println "Java dir" java-dir "not found"))))
|
||||
|
||||
|
||||
;; Create a jar file
|
||||
(defn jar
|
||||
"Build a simple jar file, with no dependencies included."
|
||||
[{:keys [subproj version]
|
||||
:or {version curr-version}}]
|
||||
(let [target-dir (target-dir subproj)
|
||||
class-dir (class-dir subproj)
|
||||
src-dir (str subprojs-base "/" subproj "/src")
|
||||
resources-dir (str subprojs-base "/" subproj "/resources")
|
||||
basis (basis subproj)
|
||||
jar-file (jar-file subproj version :plain)]
|
||||
;; Clean only class dir
|
||||
(b/delete {:path class-dir})
|
||||
;; Copy code
|
||||
(b/copy-dir {:src-dirs [src-dir]
|
||||
:target-dir class-dir})
|
||||
;; Copy resources
|
||||
(b/copy-dir {:src-dirs [resources-dir]
|
||||
:target-dir target-dir})
|
||||
;; Compile java code, if exists
|
||||
(compile-java {:subproj subproj})
|
||||
;; Build jar
|
||||
(b/jar {:class-dir class-dir
|
||||
:basis @basis
|
||||
:jar-file jar-file
|
||||
:lib (lib subproj)
|
||||
:version version})
|
||||
(println "Generated jar file:" jar-file)))
|
||||
|
||||
|
||||
;; Create an uber jar, with all dependencies inside
|
||||
#_{:clojure-lsp/ignore [:clojure-lsp/unused-public-var]}
|
||||
(defn uber
|
||||
"Build a uberjar with all dependencies included"
|
||||
[{:keys [subproj version main-ns]
|
||||
:or {version curr-version}}]
|
||||
(let [target-dir (target-dir subproj)
|
||||
basis (basis subproj)
|
||||
class-dir (class-dir subproj)
|
||||
src-dir (str subprojs-base "/" subproj "/src")
|
||||
resources-dir (str subprojs-base "/" subproj "/resources")
|
||||
uber-file (jar-file subproj version :uber)]
|
||||
;(println "Using basis: ")(show-basis subproj)
|
||||
[_]
|
||||
(b/delete {:path class-dir})
|
||||
(b/copy-dir {:src-dirs [src-dir]
|
||||
(b/copy-dir {:src-dirs src-dirs
|
||||
:target-dir class-dir})
|
||||
(b/copy-dir {:src-dirs src-dirs
|
||||
:target-dir class-dir})
|
||||
(b/copy-dir {:src-dirs [resources-dir]
|
||||
:target-dir target-dir})
|
||||
(compile-java {:subproj subproj})
|
||||
(b/compile-clj {:basis @basis
|
||||
:src-dirs [src-dir] :class-dir class-dir})
|
||||
:src-dirs src-dirs
|
||||
:class-dir class-dir})
|
||||
(b/uber {:class-dir class-dir
|
||||
:uber-file uber-file
|
||||
:basis @basis
|
||||
:main main-ns})
|
||||
(println "Generated uberjar executable:" uber-file)))
|
||||
|
||||
|
||||
;; Multimethod to get the name of all subdirs in a dir.
|
||||
;; Accepts strings or files
|
||||
(defmulti get-subdirs type)
|
||||
|
||||
(defmethod get-subdirs
|
||||
java.lang.String [dir]
|
||||
(get-subdirs (io/file dir)))
|
||||
|
||||
(defmethod get-subdirs
|
||||
java.io.File [dir]
|
||||
(if (.isDirectory dir)
|
||||
(filter #(.isDirectory %) (.listFiles dir))
|
||||
(println "Directory" subprojs-base "doesn't exists!")))
|
||||
|
||||
|
||||
;; Get the name of all subdir in a given directory
|
||||
(defn get-subdir-names
|
||||
"Get a list projects in the 'projects' directory"
|
||||
[dir-name]
|
||||
(map #(.getName %) (get-subdirs dir-name)))
|
||||
|
||||
(comment
|
||||
(get-subdirs "projects")
|
||||
(get-subdirs (io/file "projects"))
|
||||
(get-subdir-names "projects")
|
||||
)
|
||||
|
||||
|
||||
;; Generate jar files for all projects
|
||||
(defn jar-all
|
||||
"Build jar files for all projects"
|
||||
[& {:keys [version]
|
||||
:or {version curr-version}}]
|
||||
(dorun (map #(jar {:subproj % :version version}) (get-subdir-names subprojs-base))))
|
||||
|
||||
(comment
|
||||
(jar-all )
|
||||
|
||||
)
|
||||
(println "Generated uberjar executable:" uber-file))
|
||||
|
||||
77
deps.edn
77
deps.edn
@@ -1,19 +1,27 @@
|
||||
{:paths ["projects/core/src"
|
||||
"projects/core/resources"
|
||||
"projects/cli/src"]
|
||||
{:paths ["src" "test" "resources"]
|
||||
|
||||
:deps {org.clojure/clojure {:mvn/version "1.12.1"}
|
||||
;; Local subprojects
|
||||
clj-tmpl/core {:local/root "projects/core"}
|
||||
clj-tmpl/cli {:local/root "projects/cli"}
|
||||
}
|
||||
;; https://juxt.github.io/tick/
|
||||
tick/tick {:mvn/version "1.0"}
|
||||
;; https://github.com/lambdaisland/cli
|
||||
com.lambdaisland/cli {:mvn/version "1.27.121"}
|
||||
;; https://github.com/tokenmill/timewords
|
||||
lt.tokenmill/timewords {:mvn/version "0.5.0"}
|
||||
;; https://github.com/clj-commons/pretty
|
||||
org.clj-commons/pretty {:mvn/version "3.6.8"}
|
||||
;; https://github.com/babashka/http-client
|
||||
org.babashka/http-client {:mvn/version "0.4.22"}
|
||||
;; https://github.com/dakrone/cheshire?tab=readme-ov-file
|
||||
cheshire/cheshire {:mvn/version "6.1.0"}
|
||||
;; https://git.rcorral.es/ruben/clojure-utils
|
||||
rcorral/clojure-utils {:git/url "https://git.rcorral.es/ruben/clojure-utils"
|
||||
:git/tag "v0.2.0"
|
||||
:sha "4b1a7b1bc28b88ada871262806b8c4f3c000426f"}
|
||||
;; https://cljdoc.org/d/com.github.clj-easy/graal-build-time/1.0.5/doc/readme
|
||||
com.github.clj-easy/graal-build-time {:mvn/version "1.0.5"}}
|
||||
|
||||
:aliases {;; Execute the app.
|
||||
:run {:main-opts ["-m" "riot.app"]}
|
||||
;:run {:exec-fn totp.app/-main}
|
||||
|
||||
;; Execute the app (prepared for more subprojects)
|
||||
:run/cli {:main-opts ["-m" "riot.app"]}
|
||||
|
||||
;; Kaocha runner. You can use the 'kaocha' wrapper located in ~/bin/kaocha
|
||||
;; Check test.edn for kaocha runner's config
|
||||
@@ -23,29 +31,30 @@
|
||||
|
||||
;; Run with clj -T:build function-in-build
|
||||
:build {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
|
||||
;; Used by all compilations
|
||||
:extra-deps {clj-tmpl/core {:local/root "projects/core"}}
|
||||
:ns-default build}
|
||||
|
||||
;; Aliases for easy building
|
||||
:build/core {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
|
||||
:ns-default build
|
||||
:exec-fn jar
|
||||
:exec-args {:subproj "core"}}
|
||||
|
||||
:build/cli {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
|
||||
:ns-default build
|
||||
:exec-fn jar
|
||||
:exec-args {:subproj "cli"}}
|
||||
|
||||
;; Build all projects
|
||||
:build/all {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
|
||||
:ns-default build
|
||||
:exec-fn jar-all}
|
||||
:ns-default build
|
||||
:exec-fn jar}
|
||||
|
||||
;; Build uber jar for CLI app
|
||||
:uber/cli {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
|
||||
:ns-default build
|
||||
:exec-fn uber
|
||||
:exec-args {:subproj "cli" :main-ns "riot.app"}}}}
|
||||
:uber {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
|
||||
:ns-default build
|
||||
:exec-fn uber}
|
||||
|
||||
;; Conjure / cider connector
|
||||
:repl/conjure {:extra-deps {nrepl/nrepl {:mvn/version "1.0.0"}
|
||||
cider/cider-nrepl {:mvn/version "0.42.1"}}
|
||||
:main-opts ["--main" "nrepl.cmdline"
|
||||
"--middleware" "[cider.nrepl/cider-middleware]"
|
||||
"--interactive"]}
|
||||
|
||||
;; Native image. You must link your native-image executable to a relative path: bin/native-executable
|
||||
:native-image {:main-opts ["--main" "clj.native-image" "riot.app"
|
||||
"--enable-url-protocols=http,https"
|
||||
"--report-unsupported-elements-at-runtime"
|
||||
"--initialize-at-build-time"
|
||||
"-H:Name=riot"]
|
||||
:jvm-opts ["-Dclojure.compiler.direct-linking=true"]
|
||||
:extra-deps {taylorwood/clj.native-image
|
||||
{:git/url "https://github.com/taylorwood/clj.native-image.git"
|
||||
:sha "5227df16ead1fef7cddd94e6853d810e7d08579b"}}}
|
||||
}}
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
{:paths ["src" "resources" "target/classes"]
|
||||
:deps {org.clojure/clojure {:mvn/version "1.12.1"}
|
||||
;; https://github.com/lambdaisland/cli
|
||||
com.lambdaisland/cli {:mvn/version "1.27.121"}
|
||||
;; https://github.com/tokenmill/timewords
|
||||
lt.tokenmill/timewords {:mvn/version "0.5.0"}
|
||||
}
|
||||
:aliases {;; Execute the app
|
||||
;:run {:main-opts ["-m" "totp.app"]}
|
||||
}}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
(ns riot.app
|
||||
#_{:clj-kondo/ignore [:refer-all]}
|
||||
(:require [riot.commands :refer :all]
|
||||
[lambdaisland.cli :as cli])
|
||||
(:gen-class))
|
||||
|
||||
(defn -main [& args]
|
||||
(cli/dispatch
|
||||
{:name "cmd-test"
|
||||
:command #'cmd-test ; The function to call
|
||||
:flags ["-v, --verbose" "Increases verbosity"
|
||||
"--input FILE" "Specify the input file"]}
|
||||
args))
|
||||
|
||||
|
||||
(comment
|
||||
|
||||
(-main "-v" "--input" "boniato.txt" "position1" "pos2")
|
||||
)
|
||||
@@ -1,14 +0,0 @@
|
||||
(ns riot.commands
|
||||
#_{:clj-kondo/ignore [:refer-all]}
|
||||
(:require [riot.core :refer :all]
|
||||
[riot.data :refer :all]
|
||||
[clojure.pprint :as pp]
|
||||
[clojure.string :as s])
|
||||
(:gen-class))
|
||||
|
||||
|
||||
(defn cmd-test
|
||||
[params]
|
||||
(println "Options:")
|
||||
(pp/pprint opts)
|
||||
(println "Positional args:" (s/join "," (:lambdaisland.cli/argv opts))))
|
||||
@@ -1,18 +0,0 @@
|
||||
{:paths ["src" "resources" "target/classes"]
|
||||
:deps {org.clojure/clojure {:mvn/version "1.12.1"}
|
||||
;; https://github.com/babashka/http-client
|
||||
org.babashka/http-client {:mvn/version "0.4.22"}
|
||||
;; https://github.com/dakrone/cheshire?tab=readme-ov-file
|
||||
cheshire/cheshire {:mvn/version "6.1.0"}
|
||||
;; https://juxt.github.io/tick/
|
||||
tick/tick {:mvn/version "1.0"}
|
||||
}
|
||||
|
||||
:aliases {;; Kaocha runner. You can use the 'kaocha' wrapper located in ~/bin/kaocha
|
||||
:test {:extra-paths ["test"]
|
||||
:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}}
|
||||
:main-opts ["-m" "kaocha.runner"]}
|
||||
;; enable logging for java.net.http
|
||||
:debug-full {:jvm-opts ["-Djdk.httpclient.HttpClient.log=errors,requests,headers,frames[:control:data:window:all..],content,ssl,trace,channel"]}
|
||||
:debug {:jvm-opts ["-Djdk.httpclient.HttpClient.log=errors,requests,headers,content"]}}}
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
(ns riot.core
|
||||
(:require [babashka.http-client :as http]
|
||||
[cheshire.core :as json]
|
||||
[clojure.string :as s]
|
||||
[clojure.pprint :as pp]))
|
||||
|
||||
;;
|
||||
;; API KEY MANAGEMENT
|
||||
;;
|
||||
|
||||
(defn get-key-from-env
|
||||
"Get api key from environment variable"
|
||||
[key]
|
||||
(System/getenv (name key)))
|
||||
|
||||
|
||||
(defn get-and-save-key-from-env
|
||||
"Get api key from environment and store in the KEYS map. It key is not found in
|
||||
the environment, it tries to load the development key as a fallback. If none api
|
||||
key is found, return nil"
|
||||
[KEYS default-key key]
|
||||
(if-let [value (get-key-from-env key)]
|
||||
(reset! (key KEYS) value)
|
||||
(if-let [value_dev (get-key-from-env key)]
|
||||
(reset! (default-key KEYS) value_dev)
|
||||
nil)))
|
||||
|
||||
|
||||
(defn get-api-key
|
||||
"Get API key from KEYS map. If it is not found in the KEYS map, try to load it from
|
||||
the environment. If the API key doesn't exists in the environment, try to load the
|
||||
development key (the default key). If none found, print and error and return nil"
|
||||
[KEYS default-key keytype]
|
||||
(if (contains? KEYS keytype)
|
||||
(if-let [key-value (deref (keytype KEYS))]
|
||||
key-value
|
||||
(if-let [def-key-value (deref (default-key KEYS))]
|
||||
def-key-value
|
||||
(get-and-save-key-from-env KEYS default-key keytype)))
|
||||
(println "Invalid key type. Available keys:" (keys KEYS))))
|
||||
|
||||
|
||||
(defn set-api-key
|
||||
"Force the value of an API key in the KEYS map"
|
||||
[KEYS keytype value]
|
||||
(when (contains? KEYS keytype)
|
||||
(reset! (keytype KEYS) value)))
|
||||
|
||||
|
||||
;;
|
||||
;; GENERATE URLS
|
||||
;;
|
||||
|
||||
(defn get-url
|
||||
"Get URL for using the API."
|
||||
[path & parts]
|
||||
(when path
|
||||
(s/join "/" (concat [path] (vec parts)))))
|
||||
|
||||
|
||||
(defn url-encode-param
|
||||
"Encode URL, replacing spaces with %20 and deleting invalid characters"
|
||||
[value]
|
||||
(when value
|
||||
(s/escape value { \ "%20"})))
|
||||
|
||||
|
||||
(defn replace-params
|
||||
"Replace params in path"
|
||||
[path params-map]
|
||||
;(println "replacing" path "witn" params-map)
|
||||
(if (and path params-map (not-empty params-map))
|
||||
(reduce-kv
|
||||
#(s/replace %1 ((comp re-pattern str) %2) (url-encode-param (str %3)))
|
||||
(get-url path)
|
||||
params-map)
|
||||
path))
|
||||
|
||||
|
||||
(defn get-known-url
|
||||
"Get url from ENDPOINTS map."
|
||||
[ENDPOINTS url-name params-map]
|
||||
(if-let [url (get-in ENDPOINTS [url-name :uri])]
|
||||
(replace-params url params-map)
|
||||
(println "Unknown URL name" url-name)))
|
||||
|
||||
|
||||
;;
|
||||
;; HELPERS
|
||||
;;
|
||||
|
||||
(defn success
|
||||
"Return a success that stores HTTP result code and parsed JSON data"
|
||||
[status json-data]
|
||||
{:success true :http-code status :value json-data})
|
||||
|
||||
(defn failure
|
||||
"Return a success that stores HTTP result code and parsed JSON data"
|
||||
[status error-data]
|
||||
{:success false :http-code status :error error-data})
|
||||
|
||||
|
||||
;;
|
||||
;; CALL GET ENDPOINTS
|
||||
;;
|
||||
|
||||
(defn call-api
|
||||
"Call the api using one of the supported URLs or a string. You can pass optional
|
||||
maps for params:
|
||||
- path-params: parameters in the path.
|
||||
- query-params: parameters in the query part of the URL
|
||||
- header-params: headers added to the default headers
|
||||
|
||||
The key-provider is a function that accepts the url as param and returns the api
|
||||
key.
|
||||
|
||||
The api-key-header is the name of the header param that holds the API key. If
|
||||
the endpoint don't requiere an API key, you can provide nil or empty string.
|
||||
|
||||
The URL can be a keyword of the map ENDPOINTS or a URL. Each path param must have
|
||||
the same name as the key in the path-params map, including the ':' For example,
|
||||
given this url:
|
||||
http://example.com/api/get-user-by-id/:user
|
||||
|
||||
It has a path param called ':user'. If you provide this map:
|
||||
:path-params {:user 2345}
|
||||
|
||||
it will expanded to:
|
||||
http://example.com/api/get-user-by-id/2345
|
||||
|
||||
If you provide query-params, the will added after the question mark. For example, if
|
||||
you call the function as follows:
|
||||
(call-api \"http://example.com/api/get-user-by-id/:user\"
|
||||
:path-params {:user 2345}
|
||||
:query-params {:detail \"full\"})
|
||||
|
||||
this will output the following string:
|
||||
\"http://example.com/api/get-user-by-id/2345?detail=full\"
|
||||
|
||||
This function returns a success if everythin goes well or a failure when http status
|
||||
code is different from 200 or an exception is raised.
|
||||
"
|
||||
; Very simple arity to call a simple URL and the the JSON result
|
||||
([url]
|
||||
(call-api {} #(apply (constantly "") %) nil url))
|
||||
; The complete call. You must personalize ENDPOINTS, key-provider and api-key-header
|
||||
; for your API
|
||||
([ENDPOINTS key-provider api-key-header url & {:keys [path-params query-params header-params debug]
|
||||
:or {path-params {} query-params {} header-params {} debug false}}]
|
||||
;(println "Endpoints:" (count ENDPOINTS) "Key provider:" key-provider "api key header:" api-key-header)
|
||||
(let [; Process path-parameters
|
||||
processed-url (if (keyword? url)
|
||||
(get-known-url ENDPOINTS url path-params)
|
||||
(replace-params url path-params))
|
||||
; Try to get an api key (if required)
|
||||
api-key (if (keyword? url) (key-provider url) (println "No api key for URL " url))
|
||||
; Fixed headers, without api key
|
||||
headers-no-key (merge {"Accept" "application/json"}
|
||||
header-params)
|
||||
; Headers with api key
|
||||
headers (if (and (some? api-key-header) (string? api-key))
|
||||
(merge headers-no-key {api-key-header api-key})
|
||||
headers-no-key)]
|
||||
;(println "URL:" processed-url "Query" query-params "headers: " headers)
|
||||
(try
|
||||
; Call the api and catch the result
|
||||
(let [response (http/get processed-url {:headers headers
|
||||
:query-params query-params
|
||||
:throw false})]
|
||||
; If debug activated, print all data from response
|
||||
(when debug (println "RESPONSE:")(pp/pprint response))
|
||||
; Check HTTP response code.
|
||||
(if (= 200 (:status response))
|
||||
(success 200 (json/parse-string (:body response) keyword))
|
||||
(do
|
||||
(println "Error response: HTTP code" (:status response))
|
||||
(failure (:status response) (:body response)))))
|
||||
(catch Exception exc
|
||||
(prn "An exception has been thrown while calling the api" (.getMessage exc))
|
||||
(failure nil (.getMessage exc)))))))
|
||||
|
||||
|
||||
|
||||
(comment
|
||||
(call-api "https://status.search.google.com/incidents.json")
|
||||
|
||||
(call-api "http://example.com")
|
||||
|
||||
)
|
||||
@@ -1,198 +0,0 @@
|
||||
(ns riot.data
|
||||
(:require [riot.core :refer :all]
|
||||
[riot.riot-api :refer :all]
|
||||
[clojure.string :as s]
|
||||
[tick.core :as t]))
|
||||
|
||||
;;
|
||||
;; High functions to work with RIOT API.
|
||||
;;
|
||||
;; This file has a lot of utilities for working with data obtained with the help
|
||||
;; of riot-api's functions
|
||||
|
||||
|
||||
;; Get matches list
|
||||
|
||||
(defn get-lol-matches
|
||||
"Get LOL matches for player"
|
||||
[puuid & {:keys [startTime endTime queue type start count] :as params}]
|
||||
;(println "Params:" params)
|
||||
(let [response (call-riot-api :lol-matches-by-puuid
|
||||
:path-params {:puuid puuid}
|
||||
:query-params params)]
|
||||
(if (:success response)
|
||||
(:value response)
|
||||
(do (println "No LOL matches found") response))))
|
||||
|
||||
|
||||
(defn get-tft-matches
|
||||
"Get TFT matches for player"
|
||||
[puuid & {:keys [startTime endTime queue type start count] :as params}]
|
||||
(println "Params:" params)
|
||||
(let [response (call-riot-api :tft-matches-by-puuid
|
||||
:path-params {:puuid puuid}
|
||||
:query-params params)]
|
||||
(if (:success response)
|
||||
(:value response)
|
||||
(do (println "No TFT matches found") response))))
|
||||
|
||||
(comment
|
||||
|
||||
(get-lol-matches (lol-get-uuid "Walid Georgey" "EUW") :count 5)
|
||||
(get-lol-matches (lol-get-uuid "Errepunto" "4595") :count 5)
|
||||
|
||||
(get-tft-matches (tft-get-uuid "Walid Georgey" "EUW") :count 5)
|
||||
(get-tft-matches (tft-get-uuid "Errepunto" "4595") :count 5)
|
||||
)
|
||||
|
||||
|
||||
;; Get matches data
|
||||
|
||||
(defn create-match-data
|
||||
[matchId participants gameStartTimestamp gameEndTimestamp gameDuration gameType endOfGameResult]
|
||||
{:id matchId
|
||||
:participants participants
|
||||
:start gameStartTimestamp
|
||||
:end gameEndTimestamp
|
||||
:duration gameDuration
|
||||
:type gameType
|
||||
:result endOfGameResult})
|
||||
|
||||
(defn create-participant
|
||||
[puuid championName deaths kills win]
|
||||
{:puuid puuid
|
||||
:champion championName
|
||||
:deaths deaths
|
||||
:kills kills
|
||||
:win win})
|
||||
|
||||
(defn get-lol-match-data
|
||||
"Get data from a LOL match"
|
||||
[id]
|
||||
(let [response (call-riot-api :lol-match-by-id :path-params {:match-id id})
|
||||
info (get-in response [:value :info])
|
||||
meta (get-in response [:value :metadata])]
|
||||
;(println "Value:" info)
|
||||
(if (:success response)
|
||||
(create-match-data (:matchId meta)
|
||||
(map #(create-participant (:puuid %)
|
||||
(:championName %)
|
||||
(:deaths %)
|
||||
(:kills %)
|
||||
(:win %))
|
||||
(:participants info))
|
||||
(:gameStartTimestamp info)
|
||||
(:gameEndTimestamp info)
|
||||
(:gameDuration info)
|
||||
(:gameType info)
|
||||
(:endOfGameResult info))
|
||||
(do (println "No match data found") response))))
|
||||
|
||||
(defn get-tft-match-data
|
||||
"Get data from a TFT match"
|
||||
[id]
|
||||
(let [response (call-riot-api :tft-match-by-id :path-params {:match-id id})
|
||||
info (get-in response [:value :info])
|
||||
meta (get-in response [:value :metadata])]
|
||||
;(println "Value:" info)
|
||||
(if (:success response)
|
||||
(create-match-data (:match_id meta)
|
||||
(map #(create-participant (:puuid %)
|
||||
nil
|
||||
nil
|
||||
(:players_eliminated %)
|
||||
(:win %))
|
||||
(:participants info))
|
||||
(:game_datetime info)
|
||||
(+ (:game_datetime info) (int (* 1000 (:game_length info))))
|
||||
(int (:game_length info))
|
||||
(:tft_game_type info)
|
||||
(:endOfGameResult info))
|
||||
(do (println "No match data found") response))))
|
||||
|
||||
(comment
|
||||
(get-lol-match-data "EUW1_7673677826")
|
||||
(get-tft-match-data "EUW1_7674912532")
|
||||
|
||||
(call-riot-api :tft-match-by-id :path-params {:match-id "EUW1_7674912532"})
|
||||
|
||||
(System/currentTimeMillis)
|
||||
1767819383643
|
||||
1767819383643
|
||||
)
|
||||
|
||||
|
||||
;; Check if it's playing
|
||||
|
||||
(defn is-playing-lol?
|
||||
[puuid]
|
||||
(let [response (call-riot-api :lol-spectator
|
||||
:path-params {:puuid puuid})
|
||||
http-code (:http-code response)]
|
||||
(= 200 http-code)))
|
||||
|
||||
(defn is-playing-tft?
|
||||
[puuid]
|
||||
(let [response (call-riot-api :tft-spectator
|
||||
:path-params {:puuid puuid})
|
||||
http-code (:http-code response)]
|
||||
(= 200 http-code)))
|
||||
|
||||
(comment
|
||||
(is-playing-lol? (lol-get-uuid "Walid Georgey" "EUW"))
|
||||
(is-playing-tft? (lol-get-uuid "Walid Georgey" "EUW"))
|
||||
)
|
||||
|
||||
|
||||
;; Format dates and times
|
||||
|
||||
(defn format-millis
|
||||
([millis]
|
||||
(format-millis "yyyy-MM-dd HH:mm:ss" millis))
|
||||
([format millis]
|
||||
(t/format (t/formatter format)
|
||||
(t/zoned-date-time (t/instant millis)))))
|
||||
|
||||
|
||||
(defn match-format-dates
|
||||
([data]
|
||||
(match-format-dates "yyyy-MM-dd HH:mm:ss" data))
|
||||
([date-format data]
|
||||
(-> data
|
||||
(update-in [:start] (partial format-millis date-format))
|
||||
(update-in [:end] (partial format-millis date-format)))))
|
||||
|
||||
(comment
|
||||
(t/format (t/formatter "yyyy-MM-dd HH:mm:ss")
|
||||
(t/zoned-date-time (t/instant (System/currentTimeMillis))))
|
||||
|
||||
(match-format-dates (get-lol-match-data "EUW1_7673677826"))
|
||||
(match-format-dates (get-tft-match-data "EUW1_7674912532"))
|
||||
)
|
||||
|
||||
|
||||
(defn format-duration
|
||||
[seconds]
|
||||
(let [duration (t/new-duration seconds :seconds)
|
||||
minutes (t/minutes duration)
|
||||
seconds (- (t/seconds duration) (* 60 minutes))]
|
||||
(format "%02d:%02d" minutes seconds)))
|
||||
|
||||
(defn match-format-durations
|
||||
[data]
|
||||
(update-in data [:duration] format-duration))
|
||||
|
||||
(comment
|
||||
(t/format (t/formatter "HH:mm:ss") (t/new-duration 2106 :seconds))
|
||||
(t/hours (t/new-duration 2106 :seconds))
|
||||
(t/minutes (t/new-duration 2106 :seconds))
|
||||
(t/seconds (t/new-duration 2106 :seconds))
|
||||
|
||||
(format-duration 2106)
|
||||
|
||||
(match-format-durations (get-lol-match-data "EUW1_7673677826"))
|
||||
(match-format-durations (get-tft-match-data "EUW1_7674912532"))
|
||||
)
|
||||
|
||||
|
||||
;;
|
||||
@@ -1,173 +0,0 @@
|
||||
(ns riot.riot-api
|
||||
(:require [riot.core :refer :all]
|
||||
[riot.riot-config :refer :all]))
|
||||
|
||||
|
||||
;;
|
||||
;; ADAPT API GENERIC METHODS TO RIOT API
|
||||
;;
|
||||
;; You need to adapt 3 things from the generic core:
|
||||
;; - A method for setting (override) the API key
|
||||
;; - A method for supply the API
|
||||
;; - A wrapper for calling call-api with this API endpoint, and keyprovider
|
||||
;;
|
||||
;; Maps with keys and supported endpoints are in a separated file (riot-data.clj)
|
||||
;;
|
||||
|
||||
; Not needed, but useful
|
||||
(def get-riot-api-key (partial get-api-key RIOT-KEYS :RIOT_DEV_KEY))
|
||||
|
||||
; Not used by core, but useful for frontends
|
||||
(def set-riot-api-key (partial set-api-key RIOT-KEYS))
|
||||
|
||||
; Key provider for this API
|
||||
(defn riot-key-provider
|
||||
[url]
|
||||
(if-let [api-key (get-riot-api-key (get-in ENDPOINTS [url :api-key]))]
|
||||
api-key
|
||||
(println "No API key found")))
|
||||
|
||||
(comment
|
||||
(get-in ENDPOINTS [:lol-status :api-key])
|
||||
|
||||
(riot-key-provider :lol-status)
|
||||
)
|
||||
|
||||
; Wrapper for ease use of call-api
|
||||
(def call-riot-api (partial call-api ENDPOINTS riot-key-provider "X-Riot-Token"))
|
||||
|
||||
;;
|
||||
;; HELPER FUNCTIONS
|
||||
;;
|
||||
(defn lol-get-uuid
|
||||
"Get PUUID from player's name and tag for LOL endpoints"
|
||||
[player-name player-tag]
|
||||
(:puuid (:value (call-riot-api :lol-account-by-riot-id
|
||||
:path-params {:player-name player-name :player-tag player-tag}))))
|
||||
|
||||
(defn tft-get-uuid
|
||||
"Get PUUID from player's name and tag for TFT endpoints"
|
||||
[player-name player-tag]
|
||||
(:puuid (:value (call-riot-api :tft-account-by-riot-id
|
||||
:path-params {:player-name player-name :player-tag player-tag}))))
|
||||
|
||||
|
||||
;;
|
||||
;; USAGE EXAMPLES
|
||||
;;
|
||||
|
||||
(comment
|
||||
|
||||
(set-riot-api-key :RIOT_DEV_KEY "RGAPI-c5f2c1da-8b8a-4e2b-861b-5d3f671173be")
|
||||
|
||||
(lol-get-uuid "Walid Georgey" "EUW")
|
||||
|
||||
(tft-get-uuid "Walid Georgey" "EUW")
|
||||
|
||||
;; Examples calling the API
|
||||
(call-riot-api :lol-account-by-puuid
|
||||
:path-params {:puuid "Walid Georgey" :player-tag "EUW"})
|
||||
|
||||
(:value (call-riot-api :lol-status))
|
||||
|
||||
(call-riot-api :champion-mastery-by-puuid
|
||||
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :champion-mastery-by-puuid-and-champion
|
||||
:path-params {:championId 45
|
||||
:puuid (lol-get-uuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :champion-mastery-by-puuid-top
|
||||
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")}
|
||||
:query-params {:count 1})
|
||||
|
||||
(call-riot-api :champion-rotations)
|
||||
|
||||
(call-riot-api :summoner-by-puuid
|
||||
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :league-all-by-puuid
|
||||
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :league-by-id
|
||||
:path-params {:league-id "35642608-b436-48a0-ac0f-b64eb6dfc14e"})
|
||||
|
||||
(call-riot-api :clash-by-puuid
|
||||
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :clash-tournaments)
|
||||
|
||||
(call-riot-api :lol-matches-by-puuid
|
||||
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")}
|
||||
:query-params {:count 5})
|
||||
|
||||
(call-riot-api :lol-match-by-id
|
||||
:path-params {:match-id "EUW1_7673677826"})
|
||||
|
||||
(call-riot-api :lol-match-timeline-by-id
|
||||
:path-params {:match-id "EUW1_7673677826"})
|
||||
|
||||
(call-riot-api :lol-challenges-config)
|
||||
|
||||
(call-riot-api :lol-challenge-config-by-id
|
||||
:path-params {:challenge-id 402109})
|
||||
|
||||
(call-riot-api :lol-challenges-percentiles)
|
||||
|
||||
(call-riot-api :lol-challenges-percentiles-by-id
|
||||
:path-params {:challenge-id 402109})
|
||||
|
||||
(call-riot-api :lol-challenge-leaderboard
|
||||
:path-params {:challenge-id 402109
|
||||
:level "CHALLENGER"})
|
||||
|
||||
(call-riot-api :lol-challenge-by-puuid
|
||||
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :lol-champion-mastery-by-puuid
|
||||
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :lol-champion-mastery-by-puuid-champion
|
||||
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")
|
||||
:champion-id 777})
|
||||
|
||||
(call-riot-api :lol-champion-mastery-by-puuid-top
|
||||
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")}
|
||||
:query-params {:count 5})
|
||||
|
||||
(call-riot-api :lol-champion-mastery-scores-by-puuid
|
||||
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :lol-spectator
|
||||
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")})
|
||||
|
||||
;; TFT
|
||||
(call-riot-api :tft-summoner-by-puuid
|
||||
:path-params {:puuid (tft-get-uuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :tft-status)
|
||||
|
||||
(call-riot-api :tft-matches-by-puuid
|
||||
:path-params {:puuid (tft-get-uuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :tft-match-by-id
|
||||
:path-params {:match-id "EUW1_7666482502"})
|
||||
|
||||
(call-riot-api :tft-spectator
|
||||
:path-params {:puuid (tft-get-uuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :tft-league-by-puuid
|
||||
:path-params {:puuid (tft-get-uuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :tft-league-challenger)
|
||||
|
||||
(call-riot-api :tft-league-grandmaster-by-queue)
|
||||
|
||||
(call-riot-api :tft-league-master-by-queue)
|
||||
|
||||
(call-riot-api :tft-league-top-rated-ladders
|
||||
:path-params {:queue "RANKED_TFT_TURBO"})
|
||||
|
||||
(call-riot-api :tft-league-by-league-id
|
||||
:path-params {:league-id "abc"})
|
||||
)
|
||||
@@ -1,10 +0,0 @@
|
||||
(ns riot.core-test
|
||||
#_{:clj-kondo/ignore [:refer-all]}
|
||||
(:require [clojure.test :refer :all]
|
||||
[tmpl.core :refer :all])
|
||||
(:import (java.util Arrays)))
|
||||
|
||||
(deftest generate-greeting-test
|
||||
(testing "Some test cases"
|
||||
(is (generate-greeting nil nil)) ;; Not nill
|
||||
(is (= "Hello test" (generate-greeting :medium "test")))))
|
||||
114
src/riot/app.clj
Normal file
114
src/riot/app.clj
Normal file
@@ -0,0 +1,114 @@
|
||||
(ns riot.app
|
||||
#_{:clj-kondo/ignore [:refer-all]}
|
||||
(:require [rcorral.api.core :refer :all]
|
||||
[riot.commands :refer :all]
|
||||
[riot.riot-api :refer :all]
|
||||
[lambdaisland.cli :as cli]
|
||||
[clojure.pprint :as pp])
|
||||
(:gen-class))
|
||||
|
||||
(def VERSION "2.0")
|
||||
|
||||
|
||||
(defn set-keys
|
||||
[params]
|
||||
(when (:dev-key params) (set-riot-api-key :RIOT_DEV_KEY (:dev-key params)))
|
||||
(when (:lol-key params) (set-riot-api-key :RIOT_LOL_KEY (:lol-key params)))
|
||||
(when (:tft-key params) (set-riot-api-key :RIOT_TFT_KEY (:tft-key params))))
|
||||
|
||||
(defn check-debug
|
||||
[params]
|
||||
(reset! debug (:verbose params))
|
||||
(reset! debug-http (:debug-http params))
|
||||
(when @debug (pp/pprint params)))
|
||||
|
||||
|
||||
|
||||
(defn cmd-check-playing-adapter
|
||||
[params]
|
||||
(check-debug params)
|
||||
(set-keys params)
|
||||
(cmd-check-playing (:username params) (:usertag params)
|
||||
:lol (:lol params)
|
||||
:tft (:tft params)
|
||||
:template (:template params)
|
||||
:continuous (:continuous params)
|
||||
:every-seconds (:period params)
|
||||
:max (:max params)
|
||||
:header (:header params)))
|
||||
|
||||
(defn cmd-show-matches-adapter
|
||||
[params]
|
||||
(check-debug params)
|
||||
(set-keys params)
|
||||
(cmd-show-matches (:username params) (:usertag params)
|
||||
:lol (:lol params)
|
||||
:tft (:tft params)
|
||||
:format (:format params)
|
||||
:since (:since params)
|
||||
:until (:until params)
|
||||
:max (:max params)))
|
||||
|
||||
(defn cmd-show-stats-adapter
|
||||
[params]
|
||||
(check-debug params)
|
||||
(set-keys params)
|
||||
(cmd-show-stats (:username params) (:usertag params)
|
||||
:lol (:lol params)
|
||||
:tft (:tft params)
|
||||
:format (:format params)
|
||||
:since (:since params)
|
||||
:until (:until params)
|
||||
:max (:max params)))
|
||||
|
||||
|
||||
;;[player-name player-tag & {:keys [lol tft template continuous every-seconds max]
|
||||
|
||||
(def options {:name "riot client"
|
||||
:doc "A CLI client for RIOT api"
|
||||
:commands ["playing <username> <usertag>"
|
||||
{:doc "Check if the player is playing"
|
||||
:command #'cmd-check-playing-adapter
|
||||
:flags ["--[no-]lol" {:doc "Check if playing LOL" :default true}
|
||||
"--[no-]tft" {:doc "Check if playing TFT" :default true}
|
||||
"-t, --template <template>" {:doc "Text template"}
|
||||
"-c, --[no-]continuous" {:doc "Print continuosly" :default false}
|
||||
"-p, --period <seconds>" {:doc "If printing continuosly, period in seconds" :parse parse-long :default 60}
|
||||
"-m, --max <max>" {:doc "If printing continuosly, max number of checks." :parse parse-long :default -1}
|
||||
"--[no-]header" {:doc "If true, print a header over each check" :default true}]}
|
||||
|
||||
"matches <username> <usertag>"
|
||||
{:doc "Show information about matches"
|
||||
:command #'cmd-show-matches-adapter
|
||||
:flags ["--[no-]lol" {:doc "Check if playing LOL" :default true}
|
||||
"--[no-]tft" {:doc "Check if playing TFT" :default true}
|
||||
"-f, --format <ptable|table|edn|edn-full|csv|json>" {:doc "Output format" :parse keyword :default "ptable"}
|
||||
"-s, --since <time>" {:doc "Obtain registries since <time>"}
|
||||
"-u, --until <time>" {:doc "Obtain registries until <time>"}
|
||||
"-m, --max <max>" {:doc "Max number of registries for each game type"}]}
|
||||
|
||||
"stats <username> <usertag>"
|
||||
{:doc "Show statistics about matches"
|
||||
:command #'cmd-show-stats-adapter
|
||||
:flags ["--[no-]lol" {:doc "Check if playing LOL" :default true}
|
||||
"--[no-]tft" {:doc "Check if playing TFT" :default true}
|
||||
"-f, --format <ptable|table|edn|csv>" {:doc "Output format" :parse keyword :default "ptable"}
|
||||
"-s, --since <time>" {:doc "Obtain registries since <time>"}
|
||||
"-u, --until <time>" {:doc "Obtain registries until <time>"}
|
||||
"-m, --max <max>" {:doc "Max number of registries for each game type"}]}
|
||||
]
|
||||
|
||||
:flags ["-v, --verbose" "Increases verbosity"
|
||||
"--debug-http" "Show HTTP request/response data"
|
||||
"--dev-key <DEV key>" "Development API key"
|
||||
"--lol-key <LOL key>" "API key for LOL"
|
||||
"--tft-key <TFT key>" "API key for TFT"]})
|
||||
|
||||
(defn -main [& args]
|
||||
(cli/dispatch options args))
|
||||
|
||||
|
||||
(comment
|
||||
|
||||
(-main "-v" "--input" "boniato.txt" "position1" "pos2")
|
||||
)
|
||||
205
src/riot/commands.clj
Normal file
205
src/riot/commands.clj
Normal file
@@ -0,0 +1,205 @@
|
||||
(ns riot.commands
|
||||
#_{:clj-kondo/ignore [:refer-all]}
|
||||
(:require [rcorral.api.core :refer :all]
|
||||
[rcorral.util :refer :all]
|
||||
[rcorral.date-util :refer :all]
|
||||
[riot.riot-api :refer :all]
|
||||
[riot.riot-data :refer :all]
|
||||
[clojure.pprint :as pp]
|
||||
[clojure.string :as s]
|
||||
[clj-commons.format.table :as table]
|
||||
[cheshire.core :as json])
|
||||
(:gen-class))
|
||||
|
||||
(defn cmd-test
|
||||
[params]
|
||||
(println "Options:")
|
||||
(pp/pprint params)
|
||||
(println "Positional args:" (s/join "," (:lambdaisland.cli/argv params))))
|
||||
|
||||
(defn cmd-check-playing
|
||||
"Check if the player is playing right now."
|
||||
[player-name player-tag & {:keys [lol tft template continuous every-seconds max header]
|
||||
:or {lol true
|
||||
tft true
|
||||
template ":formatted-ts - :game: :playing"
|
||||
continuous false
|
||||
every-seconds 60
|
||||
max nil
|
||||
header true}
|
||||
:as params}]
|
||||
(when @debug
|
||||
(println "CMD check playing")
|
||||
(pp/pprint params))
|
||||
(let [check-fn (fn [] (is-playing? player-name player-tag params))
|
||||
task-fn (fn []
|
||||
(when header (println (millis->str (System/currentTimeMillis)) ": Player" (str player-name "#" player-tag)))
|
||||
(let [playing (check-fn)]
|
||||
(run! #(println (replace-map (or template "Playing :game? :playing") %)) playing)
|
||||
playing))]
|
||||
(if continuous
|
||||
(run-every task-fn every-seconds max)
|
||||
(let [playing (task-fn)]
|
||||
(if (some :playing playing)
|
||||
(System/exit 0)
|
||||
(System/exit 1))))))
|
||||
|
||||
(comment
|
||||
(reset! debug true)
|
||||
|
||||
(some? (is-playing? "Walid Georgey" "EUW"))
|
||||
|
||||
(cmd-check-playing "Walid Georgey" "EUW") ;; This kills the REPL
|
||||
(cmd-check-playing "Walid Georgey" "EUW" :continuous true :max 2) ;; Infinite loop if max is nil
|
||||
)
|
||||
(defn print-table
|
||||
[matches-data]
|
||||
(let [no-participants (map #(dissoc % :participants) matches-data)
|
||||
formatted (map (comp match-format-dates match-format-durations) no-participants)]
|
||||
(pp/print-table [:id :game :type :start :end :duration :winner :champion :placement]
|
||||
(reverse (sort-by :start formatted)))))
|
||||
|
||||
(defn print-pretty-table
|
||||
[matches-data]
|
||||
(let [no-participants (map #(dissoc % :participants) matches-data)
|
||||
formatted (map (comp match-format-dates match-format-durations) no-participants)]
|
||||
(table/print-table [:id
|
||||
{:key :game :title "Game Type" :align :center :formatter (comp s/upper-case name)}
|
||||
:type
|
||||
:start
|
||||
:end
|
||||
:duration
|
||||
:winner
|
||||
:champion
|
||||
{:key :placement :align :center}]
|
||||
(reverse (sort-by :start formatted)))))
|
||||
|
||||
(defn print-edn
|
||||
[matches-data]
|
||||
(pp/pprint (mapv #(select-keys % [:id :game :type :start :end :duration :winner :champion :placement]) matches-data)))
|
||||
|
||||
(defn print-edn-full
|
||||
[matches-data]
|
||||
(pp/pprint matches-data))
|
||||
|
||||
(defn print-json
|
||||
[matches-data]
|
||||
(println (json/generate-string matches-data {:pretty true})))
|
||||
|
||||
(comment
|
||||
(print-json [{:game :lol,
|
||||
:id "EUW1_7673677826",
|
||||
:start 1767732132677,
|
||||
:end 1767733603865,
|
||||
:duration 1471,
|
||||
:type "MATCHED_GAME",
|
||||
:result "GameComplete"
|
||||
:winner true}
|
||||
{:game :tft,
|
||||
:id "EUW1_7674912532",
|
||||
:start 1767819383643,
|
||||
:end 1767821490357,
|
||||
:duration 2106,
|
||||
:type "pairs",
|
||||
:result "GameComplete"
|
||||
:winner false}])
|
||||
)
|
||||
|
||||
(defn print-csv
|
||||
([matches-data]
|
||||
(print-csv matches-data ";"))
|
||||
([matches-data separator]
|
||||
(when-let [m-data (map #(dissoc % :participants) matches-data)]
|
||||
(println (s/join separator (map name (keys (first m-data)))))
|
||||
(run! #(println (s/join separator (vals %))) m-data))))
|
||||
|
||||
(comment
|
||||
(print-csv [{:game :lol,
|
||||
:id "EUW1_7673677826",
|
||||
:start 1767732132677,
|
||||
:end 1767733603865,
|
||||
:duration 1471,
|
||||
:type "MATCHED_GAME",
|
||||
:result "GameComplete"
|
||||
:winner true}
|
||||
{:game :tft,
|
||||
:id "EUW1_7674912532",
|
||||
:start 1767819383643,
|
||||
:end 1767821490357,
|
||||
:duration 2106,
|
||||
:type "pairs",
|
||||
:result "GameComplete"
|
||||
:winner false}]
|
||||
":"))
|
||||
|
||||
(defn add-calculated-data
|
||||
[puuid match-data]
|
||||
(-> match-data
|
||||
(assoc :winner (player-won? puuid match-data))
|
||||
(assoc :champion (:champion (filter-by-player puuid match-data)))
|
||||
(assoc :placement (:placement (filter-by-player puuid match-data)))
|
||||
))
|
||||
|
||||
(defn get-matches
|
||||
[player-name player-tag & {:keys [lol tft since until max]
|
||||
:or {lol true
|
||||
tft true}
|
||||
:as params}]
|
||||
(let [call-params (cond-> {}
|
||||
max (assoc :count max)
|
||||
since (assoc :startTime (/ (process-time-literal since) 1000))
|
||||
until (assoc :endTime (/ (process-time-literal until) 1000)))
|
||||
lol-puuid (get-lol-puuid player-name player-tag)
|
||||
tft-puuid (get-tft-puuid player-name player-tag)]
|
||||
(when @debug (println "Params") (pp/pprint call-params))
|
||||
(cond-> []
|
||||
lol (concat (map #(add-calculated-data lol-puuid (get-lol-match-data %))
|
||||
(get-lol-matches lol-puuid call-params)))
|
||||
tft (concat (map #(add-calculated-data tft-puuid (get-tft-match-data %))
|
||||
(get-tft-matches tft-puuid call-params))))))
|
||||
|
||||
(comment
|
||||
(reset! debug true)
|
||||
|
||||
(get-matches "Walid Georgey" "EUW" :max 3))
|
||||
|
||||
|
||||
(defn cmd-show-matches
|
||||
"Show basic info about matches played by player"
|
||||
[player-name player-tag & {:keys [format]
|
||||
:or {format :table}
|
||||
:as params}]
|
||||
(when @debug
|
||||
(println "CMD show matches")
|
||||
(pp/pprint params))
|
||||
(let [matches-data (get-matches player-name player-tag params)]
|
||||
;; Then, match data
|
||||
(case format
|
||||
:table (print-table matches-data)
|
||||
:edn (print-edn matches-data)
|
||||
:edn-full (print-edn-full matches-data)
|
||||
:csv (print-csv matches-data)
|
||||
:json (print-json matches-data)
|
||||
:ptable (print-pretty-table matches-data)
|
||||
(do (println "No valid format " format) (System/exit 1)))))
|
||||
|
||||
(comment
|
||||
(set-riot-api-key :RIOT_DEV_KEY "RGAPI-bbbed5c8-d4d7-4de4-a7e7-b8366afee5a4")
|
||||
(cmd-show-matches "Walid Georgey" "EUW")
|
||||
(cmd-show-matches "Walid Georgey" "EUW" :since "yesterday" :max 2))
|
||||
|
||||
(defn print-stats
|
||||
[player-name player-tag matches-data]
|
||||
(println "Statistics")
|
||||
(pp/pprint (create-basic-stats player-name player-tag matches-data)))
|
||||
|
||||
(defn cmd-show-stats
|
||||
"Show basic info about matches played by player"
|
||||
[player-name player-tag & {:as params}]
|
||||
(when @debug
|
||||
(println "CMD show stats")
|
||||
(binding [pp/*print-right-margin* 80
|
||||
pp/*print-miser-width* 40]
|
||||
(pp/pprint params)))
|
||||
(let [matches-data (get-matches player-name player-tag params)]
|
||||
(print-stats player-name player-tag matches-data)))
|
||||
@@ -1,4 +1,19 @@
|
||||
(ns riot.riot-config)
|
||||
(ns riot.riot-api
|
||||
(:require [rcorral.api.core :refer :all])
|
||||
(:gen-class))
|
||||
|
||||
|
||||
;;
|
||||
;; ADAPT API GENERIC METHODS TO RIOT API
|
||||
;;
|
||||
;; You need to adapt 3 things from the generic core:
|
||||
;; - A method for setting (override) the API key
|
||||
;; - A method for supply the API
|
||||
;; - A wrapper for calling call-api with this API endpoint, and keyprovider
|
||||
;;
|
||||
;; Maps with keys and supported endpoints are in a separated file (riot-data.clj)
|
||||
;;
|
||||
|
||||
|
||||
;;
|
||||
;; API KEYS
|
||||
@@ -451,4 +466,181 @@
|
||||
:header-params {}}
|
||||
|
||||
;; END OF ENDPOINT DEFINITIONS
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
;;
|
||||
;; KEY MANAGEMENT
|
||||
;;
|
||||
|
||||
; Not needed, but useful
|
||||
(def get-riot-api-key (partial get-api-key RIOT-KEYS :RIOT_DEV_KEY))
|
||||
|
||||
; Not used by core, but useful for frontends
|
||||
(def set-riot-api-key (partial set-api-key RIOT-KEYS))
|
||||
|
||||
|
||||
;;
|
||||
;; MAIN API FUNCTIONS
|
||||
;;
|
||||
|
||||
; Key provider for this API
|
||||
(defn riot-key-provider
|
||||
[url params headers] ;; Provider must accept params and headers, but we don't need them
|
||||
(when @debug (println "Getting key for" url))
|
||||
(if-let [api-key (get-riot-api-key (get-in ENDPOINTS [url :api-key]))]
|
||||
;; Return params unmodified and headers with the api header
|
||||
[params (assoc headers "X-Riot-Token" api-key)]
|
||||
(println "No API key found for" url)))
|
||||
|
||||
(comment
|
||||
(get-in ENDPOINTS [:lol-status :api-key])
|
||||
|
||||
(riot-key-provider :lol-status {:param1 "1" :param2 "two"} {"Accept" "data"})
|
||||
)
|
||||
|
||||
; Wrapper for ease use of call-api
|
||||
(defn call-riot-api
|
||||
[url & {:as cfg-params}]
|
||||
(call-api ENDPOINTS riot-key-provider url cfg-params))
|
||||
|
||||
;;
|
||||
;; HELPERS
|
||||
;;
|
||||
|
||||
(defn get-lol-puuid
|
||||
"Get PUUID from player's name and tag for LOL endpoints"
|
||||
[player-name player-tag]
|
||||
(:puuid (:value (call-riot-api :lol-account-by-riot-id
|
||||
:path-params {:player-name player-name :player-tag player-tag}))))
|
||||
|
||||
(defn get-tft-puuid
|
||||
"Get PUUID from player's name and tag for TFT endpoints"
|
||||
[player-name player-tag]
|
||||
(:puuid (:value (call-riot-api :tft-account-by-riot-id
|
||||
:path-params {:player-name player-name :player-tag player-tag}))))
|
||||
|
||||
|
||||
;;
|
||||
;; USAGE EXAMPLES
|
||||
;;
|
||||
|
||||
(comment
|
||||
|
||||
(set-riot-api-key :RIOT_DEV_KEY "RGAPI-bbbed5c8-d4d7-4de4-a7e7-b8366afee5a4")
|
||||
(deref (:RIOT_DEV_KEY RIOT-KEYS))
|
||||
|
||||
(call-riot-api :lol-account-by-riot-id :path-params {:player-name "Walid Georgey"
|
||||
:player-tag "EUW"})
|
||||
|
||||
(get-lol-puuid "Walid Georgey" "EUW")
|
||||
|
||||
(get-tft-puuid "Walid Georgey" "EUW")
|
||||
|
||||
;; Examples calling the API
|
||||
(call-riot-api :lol-account-by-puuid
|
||||
:path-params {:puuid "Walid Georgey" :player-tag "EUW"})
|
||||
|
||||
(:value (call-riot-api :lol-status))
|
||||
|
||||
(call-riot-api :champion-mastery-by-puuid
|
||||
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :champion-mastery-by-puuid-and-champion
|
||||
:path-params {:championId 45
|
||||
:puuid (get-lol-puuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :champion-mastery-by-puuid-top
|
||||
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")}
|
||||
:query-params {:count 1})
|
||||
|
||||
(call-riot-api :champion-rotations)
|
||||
|
||||
(call-riot-api :summoner-by-puuid
|
||||
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :league-all-by-puuid
|
||||
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :league-by-id
|
||||
:path-params {:league-id "35642608-b436-48a0-ac0f-b64eb6dfc14e"})
|
||||
|
||||
(call-riot-api :clash-by-puuid
|
||||
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :clash-tournaments)
|
||||
|
||||
(call-riot-api :lol-matches-by-puuid
|
||||
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")}
|
||||
:query-params {:count 5})
|
||||
|
||||
(call-riot-api :lol-match-by-id
|
||||
:path-params {:match-id "EUW1_7673677826"})
|
||||
|
||||
(call-riot-api :lol-match-timeline-by-id
|
||||
:path-params {:match-id "EUW1_7673677826"})
|
||||
|
||||
(call-riot-api :lol-challenges-config)
|
||||
|
||||
(call-riot-api :lol-challenge-config-by-id
|
||||
:path-params {:challenge-id 402109})
|
||||
|
||||
(call-riot-api :lol-challenges-percentiles)
|
||||
|
||||
(call-riot-api :lol-challenges-percentiles-by-id
|
||||
:path-params {:challenge-id 402109})
|
||||
|
||||
(call-riot-api :lol-challenge-leaderboard
|
||||
:path-params {:challenge-id 402109
|
||||
:level "CHALLENGER"})
|
||||
|
||||
(call-riot-api :lol-challenge-by-puuid
|
||||
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :lol-champion-mastery-by-puuid
|
||||
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :lol-champion-mastery-by-puuid-champion
|
||||
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")
|
||||
:champion-id 777})
|
||||
|
||||
(call-riot-api :lol-champion-mastery-by-puuid-top
|
||||
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")}
|
||||
:query-params {:count 5})
|
||||
|
||||
(call-riot-api :lol-champion-mastery-scores-by-puuid
|
||||
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :lol-spectator
|
||||
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")})
|
||||
|
||||
;; TFT
|
||||
(call-riot-api :tft-summoner-by-puuid
|
||||
:path-params {:puuid (get-tft-puuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :tft-status)
|
||||
|
||||
(call-riot-api :tft-matches-by-puuid
|
||||
:path-params {:puuid (get-tft-puuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :tft-match-by-id
|
||||
:path-params {:match-id "EUW1_7666482502"})
|
||||
|
||||
(call-riot-api :tft-spectator
|
||||
:path-params {:puuid (get-tft-puuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :tft-league-by-puuid
|
||||
:path-params {:puuid (get-tft-puuid "Walid Georgey" "EUW")})
|
||||
|
||||
(call-riot-api :tft-league-challenger)
|
||||
|
||||
(call-riot-api :tft-league-grandmaster-by-queue)
|
||||
|
||||
(call-riot-api :tft-league-master-by-queue)
|
||||
|
||||
(call-riot-api :tft-league-top-rated-ladders
|
||||
:path-params {:queue "RANKED_TFT_TURBO"})
|
||||
|
||||
(call-riot-api :tft-league-by-league-id
|
||||
:path-params {:league-id "abc"})
|
||||
)
|
||||
339
src/riot/riot_data.clj
Normal file
339
src/riot/riot_data.clj
Normal file
@@ -0,0 +1,339 @@
|
||||
(ns riot.riot-data
|
||||
(:require [rcorral.api.core :refer :all]
|
||||
[rcorral.date-util :refer :all]
|
||||
[riot.riot-api :refer :all]
|
||||
[tick.core :as t])
|
||||
(:import [java.util Date])
|
||||
(:gen-class))
|
||||
|
||||
;;
|
||||
;; High functions to work with RIOT API.
|
||||
;;
|
||||
;; This file has a lot of utilities for working with data obtained with the help
|
||||
;; of riot-api's functions
|
||||
|
||||
(def GAME-TYPES #{:lol :tft})
|
||||
|
||||
|
||||
;; Get matches list
|
||||
|
||||
(defn get-lol-matches
|
||||
"Get LOL matches for player"
|
||||
[puuid & {:as params}]
|
||||
;(println "Params:" params)
|
||||
(let [response (call-riot-api :lol-matches-by-puuid
|
||||
:path-params {:puuid puuid}
|
||||
:query-params params)]
|
||||
(if (:success response)
|
||||
(:value response)
|
||||
(do (println "No LOL matches found") response))))
|
||||
|
||||
|
||||
(defn get-tft-matches
|
||||
"Get TFT matches for player"
|
||||
[puuid & {:as params}]
|
||||
;(println "Params:" params)
|
||||
(let [response (call-riot-api :tft-matches-by-puuid
|
||||
:path-params {:puuid puuid}
|
||||
:query-params params)]
|
||||
(if (:success response)
|
||||
(:value response)
|
||||
(do (println "No TFT matches found") response))))
|
||||
|
||||
(comment
|
||||
|
||||
(get-lol-matches (get-lol-puuid "Walid Georgey" "EUW") :count 5)
|
||||
(get-lol-matches (get-lol-puuid "Errepunto" "4595") :count 5)
|
||||
|
||||
(get-tft-matches (get-tft-puuid "Walid Georgey" "EUW") :count 5)
|
||||
(get-tft-matches (get-tft-puuid "Errepunto" "4595") :count 5)
|
||||
)
|
||||
|
||||
|
||||
;; Get matches data
|
||||
|
||||
(defn filter-by-game
|
||||
[game matches]
|
||||
(filter #(= game (:game %)) matches))
|
||||
|
||||
|
||||
(defn filter-by-player
|
||||
[puuid match-data]
|
||||
(first (filter #(= (:puuid %) puuid) (:participants match-data))))
|
||||
|
||||
|
||||
(defn player-won?
|
||||
[puuid match-data]
|
||||
(if (and puuid match-data)
|
||||
(:win (filter-by-player puuid match-data))
|
||||
(do (println "Invalid puuid or match data") false)))
|
||||
|
||||
(defn player-alive?
|
||||
[puuid participants]
|
||||
(let [player-data (first (filter #(= (:puuid %) puuid) participants))
|
||||
max-round (apply max (mapv :last_round participants))]
|
||||
(= (:last_round player-data) max-round)))
|
||||
|
||||
|
||||
|
||||
(defn create-match-data
|
||||
[game matchId participants gameStartTimestamp gameEndTimestamp gameDuration gameType endOfGameResult]
|
||||
{:game game
|
||||
:id matchId
|
||||
:participants participants
|
||||
:start gameStartTimestamp
|
||||
:end gameEndTimestamp
|
||||
:duration gameDuration
|
||||
:type gameType
|
||||
:result endOfGameResult})
|
||||
|
||||
(defn create-participant
|
||||
[puuid championName deaths kills win placement]
|
||||
{:puuid puuid
|
||||
:champion championName
|
||||
:deaths deaths
|
||||
:kills kills
|
||||
:win win
|
||||
:placement placement})
|
||||
|
||||
(defn get-lol-match-data
|
||||
"Get data from a LOL match"
|
||||
[id]
|
||||
(let [response (call-riot-api :lol-match-by-id :path-params {:match-id id})
|
||||
info (get-in response [:value :info])
|
||||
meta (get-in response [:value :metadata])]
|
||||
;(println "Value:" info)
|
||||
(if (:success response)
|
||||
(create-match-data :lol
|
||||
(:matchId meta)
|
||||
(map #(create-participant (:puuid %)
|
||||
(:championName %)
|
||||
(:deaths %)
|
||||
(:kills %)
|
||||
(:win %)
|
||||
(if (:win %) 1 2))
|
||||
(:participants info))
|
||||
(:gameStartTimestamp info)
|
||||
(:gameEndTimestamp info)
|
||||
(:gameDuration info)
|
||||
(:gameType info)
|
||||
(:endOfGameResult info))
|
||||
(do (println "No match data found") response))))
|
||||
|
||||
(defn get-tft-match-data
|
||||
"Get data from a TFT match"
|
||||
[id]
|
||||
(let [response (call-riot-api :tft-match-by-id :path-params {:match-id id})
|
||||
info (get-in response [:value :info])
|
||||
meta (get-in response [:value :metadata])]
|
||||
;(println "Value:" info)
|
||||
(if (:success response)
|
||||
(create-match-data :tft
|
||||
(:match_id meta)
|
||||
(map #(create-participant (:puuid %)
|
||||
(get-in % [:companion :species] nil)
|
||||
(if (player-alive? (:puuid %) (:participants info)) 0 1)
|
||||
(:players_eliminated %)
|
||||
(:win %)
|
||||
(:placement %))
|
||||
(:participants info))
|
||||
(:game_datetime info)
|
||||
(+ (:game_datetime info) (int (* 1000 (:game_length info))))
|
||||
(int (:game_length info))
|
||||
(:tft_game_type info)
|
||||
(:endOfGameResult info))
|
||||
(do (println "No match data found") response))))
|
||||
|
||||
(comment
|
||||
(get-lol-match-data "EUW1_7673677826")
|
||||
(get-tft-match-data "EUW1_7674912532")
|
||||
|
||||
(player-won? (get-lol-puuid "Walid Georgey" "EUW")
|
||||
(get-lol-match-data "EUW1_7673677826"))
|
||||
|
||||
(player-won? (get-tft-puuid "Walid Georgey" "EUW")
|
||||
(get-tft-match-data "EUW1_7695774670"))
|
||||
|
||||
(get-tft-match-data "EUW1_7695029198")
|
||||
|
||||
(player-alive? "aWw6WWUdssl6KXMqTsgVZn4iyPfC3J2sa0sdQ7lFzQX0zzV5dzivGE-ihn3OIARf5alUkO2pPu4ztA";(get-tft-puuid "Walid Georgey" "EUW")
|
||||
(:participants (:info (:value (call-riot-api :tft-match-by-id :path-params {:match-id "EUW1_7695774670"})))))
|
||||
|
||||
|
||||
|
||||
(call-riot-api :tft-match-by-id :path-params {:match-id "EUW1_7695774670"})
|
||||
|
||||
(System/currentTimeMillis)
|
||||
1767819383643
|
||||
1767819383643
|
||||
)
|
||||
|
||||
;; Check if it's playing
|
||||
|
||||
(defn is-playing-lol?
|
||||
[puuid]
|
||||
(let [response (call-riot-api :lol-spectator
|
||||
:path-params {:puuid puuid})
|
||||
http-code (:http-code response)]
|
||||
(= 200 http-code)))
|
||||
|
||||
(defn is-playing-tft?
|
||||
[puuid]
|
||||
(let [response (call-riot-api :tft-spectator
|
||||
:path-params {:puuid puuid})
|
||||
http-code (:http-code response)]
|
||||
(= 200 http-code)))
|
||||
|
||||
|
||||
(defn create-playing
|
||||
[timestamp game playing player-name player-tag]
|
||||
{:timestamp timestamp
|
||||
:formatted-ts (millis->str timestamp)
|
||||
:game game
|
||||
:playing playing
|
||||
:player-name player-name
|
||||
:player-tag player-tag})
|
||||
|
||||
(comment
|
||||
(is-playing-lol? (get-lol-puuid "Walid Georgey" "EUW"))
|
||||
(is-playing-tft? (get-tft-puuid "Walid Georgey" "EUW"))
|
||||
)
|
||||
|
||||
(defn is-playing?
|
||||
[player-name player-tag & {:keys [lol tft]
|
||||
:or {lol true
|
||||
tft true}}]
|
||||
(let [now (System/currentTimeMillis)]
|
||||
(cond-> []
|
||||
lol (conj (create-playing now :lol (is-playing-lol? (get-lol-puuid player-name player-tag)) player-name player-tag))
|
||||
tft (conj (create-playing now :tft (is-playing-tft? (get-tft-puuid player-name player-tag)) player-name player-tag)))))
|
||||
|
||||
(comment
|
||||
(is-playing? "Walid Georgey" "EUW")
|
||||
)
|
||||
|
||||
|
||||
;; Format dates and times
|
||||
|
||||
(defn match-format-dates
|
||||
([data]
|
||||
(match-format-dates "yyyy-MM-dd HH:mm:ss" data))
|
||||
([date-format data]
|
||||
(-> data
|
||||
(update-in [:start] (partial millis->str date-format))
|
||||
(update-in [:end] (partial millis->str date-format)))))
|
||||
|
||||
(comment
|
||||
(t/format (t/formatter "yyyy-MM-dd HH:mm:ss")
|
||||
(t/zoned-date-time (t/instant (System/currentTimeMillis))))
|
||||
|
||||
(millis->str 1769153258168)
|
||||
|
||||
(t/format (t/formatter "yyyy-MM-dd HH:mm:ss")
|
||||
(t/in (t/instant 1769153258168) (t/zone "UTC")))
|
||||
|
||||
|
||||
(t/format (t/formatter "yyyy-MM-dd HH:mm:ss")
|
||||
(t/zoned-date-time (t/instant 1769153258168)))
|
||||
|
||||
(t/format (t/formatter "yyyy-MM-dd HH:mm:ss")
|
||||
(t/zoned-date-time (t/in (t/instant 1769153258168) (t/zone "UTC"))))
|
||||
|
||||
(t/zone)
|
||||
|
||||
(match-format-dates (get-lol-match-data "EUW1_7673677826"))
|
||||
(match-format-dates (get-tft-match-data "EUW1_7674912532"))
|
||||
)
|
||||
|
||||
|
||||
(defn match-format-durations
|
||||
[data]
|
||||
(update-in data [:duration] duration->str))
|
||||
|
||||
(comment
|
||||
(t/format (t/formatter "HH:mm:ss") (t/new-duration 2106 :seconds))
|
||||
(t/hours (t/new-duration 2106 :seconds))
|
||||
(t/minutes (t/new-duration 2106 :seconds))
|
||||
(t/seconds (t/new-duration 2106 :seconds))
|
||||
|
||||
(duration->str (+ (* 60 35) 6))
|
||||
(duration->str (+ (* 60 60 17) (* 60 35) 6))
|
||||
(duration->str (+ (* 24 60 60 3) (* 60 60 17) (* 60 35) 6))
|
||||
|
||||
(match-format-durations (get-lol-match-data "EUW1_7673677826"))
|
||||
(match-format-durations (get-tft-match-data "EUW1_7674912532"))
|
||||
)
|
||||
|
||||
|
||||
;; Stats
|
||||
|
||||
(defn play-time-statistics
|
||||
[matches]
|
||||
(let [num-matches (count matches)
|
||||
total (reduce + 0 (map :duration matches))
|
||||
average (if (zero? num-matches) 0 (float (/ total num-matches)))]
|
||||
{:total total
|
||||
:total-formatted (duration->str total)
|
||||
:average average
|
||||
:average-formatted (duration->str (int average))}))
|
||||
|
||||
(defn win-statistics
|
||||
[matches]
|
||||
(let [total (count matches)
|
||||
win (count (filter :winner matches))
|
||||
loss (- total win)]
|
||||
{:total total
|
||||
:win win
|
||||
:loss loss
|
||||
:win-percent (if (zero? total) 0 (float (* 100 (/ win total))))
|
||||
:loss-percent (if (zero? total) 0 (float (* 100 (/ loss total))))}))
|
||||
|
||||
|
||||
(defn kd-ratio
|
||||
[p-data]
|
||||
(let [kills (or (:kills p-data) 0)
|
||||
deaths (or (:deaths p-data) 0)]
|
||||
(if (> deaths 0) (float (/ kills deaths)) 0)))
|
||||
|
||||
|
||||
(defn kill-statistics
|
||||
[puuid matches]
|
||||
(let [total (count matches)
|
||||
; extracts player's data from participands, and adds match's id and k/d ratio
|
||||
player-data (map (fn [p m] (-> p
|
||||
(assoc :match-id (:id m))
|
||||
(assoc :k-d (kd-ratio p))))
|
||||
(map #(filter-by-player puuid %) matches)
|
||||
matches)
|
||||
total-kills (reduce + (map #(:kills %) player-data))
|
||||
total-deaths (reduce + (map #(:deaths %) player-data))
|
||||
ratio-total (if (and total-deaths total-kills (> total-kills 0)) (float (/ total-kills total-deaths)) 0)]
|
||||
{:total total
|
||||
:deads (or total-deaths 0)
|
||||
:kills (or total-kills 0)
|
||||
:ratio ratio-total
|
||||
:best-ratio (:k-d (last (sort-by :k-d player-data)))
|
||||
:worst-ratio (:k-d (first (sort-by :k-d player-data)))
|
||||
:best-champion (:champion (last (sort-by :k-d player-data)))
|
||||
:worst-champion (:champion (first (sort-by :k-d player-data)))
|
||||
:best-match (:match-id (last (sort-by :k-d player-data)))
|
||||
:worst-match (:match-id (first (sort-by :k-d player-data)))}))
|
||||
|
||||
(defn create-basic-stats
|
||||
[player-name player-tag matches]
|
||||
(let [lol-games (filter-by-game :lol matches)
|
||||
tft-games (filter-by-game :tft matches)]
|
||||
{:win-stats {:all (win-statistics matches)
|
||||
:lol (win-statistics lol-games)
|
||||
:tft (win-statistics tft-games)}
|
||||
:play-time {:all (play-time-statistics matches)
|
||||
:lol (play-time-statistics lol-games)
|
||||
:tft (play-time-statistics tft-games)}
|
||||
:kill-stats {:lol (kill-statistics (get-lol-puuid player-name player-tag) lol-games)
|
||||
:tft (kill-statistics (get-tft-puuid player-name player-tag) tft-games)}}))
|
||||
|
||||
(comment
|
||||
(create-basic-stats "Walid Georgey" "EUW"
|
||||
(concat (map get-lol-match-data (get-lol-matches (get-lol-puuid "Walid Georgey" "EUW") :count 5))
|
||||
(map get-tft-match-data (get-tft-matches (get-tft-puuid "Walid Georgey" "EUW") :count 5))))
|
||||
)
|
||||
@@ -1,6 +1,6 @@
|
||||
#kaocha/v1
|
||||
{:tests [{:test-paths ["projects/core/src" "projects/core/test"]}]
|
||||
{:tests [{:test-paths ["src" "test"]}]
|
||||
:plugins [:kaocha.plugin/cloverage]
|
||||
:cloverage/opts {:src-ns-path ["projects/core/src" "projects/core/test"]
|
||||
:ns-regex ["tmpl\\..*(?<!test)$"] ;; All starting with "totp" but not ending by "test"
|
||||
:cloverage/opts {:src-ns-path ["src"]
|
||||
;;:ns-regex ["totp\\..*(?<!test)$"] ;; All starting with "totp" but not ending by "test"
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user