Compare commits
27 Commits
v1.1
...
1fbd7258fe
| Author | SHA1 | Date | |
|---|---|---|---|
| 1fbd7258fe | |||
| 5fe64ac55c | |||
| c1d58c838d | |||
| f13e5ba712 | |||
| b311b47c4e | |||
| 938b618532 | |||
| 8772d28db3 | |||
| deb75e6946 | |||
| e0510db928 | |||
| 55b855f99f | |||
| f02629bb45 | |||
| 34b701e1d2 | |||
| 49891244a9 | |||
| 5c671f841e | |||
| 1bcd75218e | |||
| 420a92635a | |||
| 2f33c139df | |||
| 22be4ad137 | |||
| fd947b87e0 | |||
| 5162f76ffc | |||
| 8bc4b993a8 | |||
| 18cea38c16 | |||
| 9182e50179 | |||
| fb1d9a7312 | |||
| 1109c5a965 | |||
| e7e270d1ec | |||
| 0c2c5954ba |
@@ -19,17 +19,6 @@ jobs:
|
|||||||
distribution: 'temurin'
|
distribution: 'temurin'
|
||||||
java-version: '21'
|
java-version: '21'
|
||||||
|
|
||||||
# Install Leiningen
|
|
||||||
- name: Install Leiningen
|
|
||||||
run: |
|
|
||||||
curl https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein > lein
|
|
||||||
chmod +x lein
|
|
||||||
sudo mv lein /usr/local/bin/lein
|
|
||||||
|
|
||||||
# Install dependencies
|
|
||||||
- name: Install dependencies
|
|
||||||
run: lein deps
|
|
||||||
|
|
||||||
# Optional: cache dependencies
|
# Optional: cache dependencies
|
||||||
- name: Cache dependencias
|
- name: Cache dependencias
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
@@ -40,20 +29,20 @@ jobs:
|
|||||||
${{ runner.os }}-m2-
|
${{ runner.os }}-m2-
|
||||||
|
|
||||||
# Get leiningen's version
|
# Get leiningen's version
|
||||||
- name: Get leiningen version
|
- name: Get clojure version
|
||||||
run: lein -v
|
run: clojure --version
|
||||||
|
|
||||||
# Test the code
|
# Test the code
|
||||||
- name: Run tests
|
#- name: Run tests
|
||||||
env:
|
# env:
|
||||||
TFT_API: ${{ secrets.DEV_API }}
|
# TFT_API: ${{ secrets.DEV_API }}
|
||||||
run: lein test
|
# run: lein test
|
||||||
|
|
||||||
# Send jar to repository
|
# Send jar to repository
|
||||||
- name: Deploy on Gitea Maven
|
#- name: Deploy on Gitea Maven
|
||||||
if: github.ref == 'refs/heads/main'
|
# if: github.ref == 'refs/heads/main'
|
||||||
env:
|
# env:
|
||||||
GITEA_USER: ${{ secrets.DEPLOY_USER }}
|
# GITEA_USER: ${{ secrets.DEPLOY_USER }}
|
||||||
GITEA_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
|
# GITEA_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
|
||||||
run: |
|
# run: |
|
||||||
lein deploy gitea
|
# lein deploy gitea
|
||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -7,10 +7,9 @@ pom.xml.asc
|
|||||||
*.jar
|
*.jar
|
||||||
*.class
|
*.class
|
||||||
/.lein-*
|
/.lein-*
|
||||||
/.nrepl-port
|
/**/.nrepl-port
|
||||||
/.prepl-port
|
/.prepl-port
|
||||||
.hgignore
|
.cpcache
|
||||||
.hg/
|
|
||||||
.clj-kondo
|
.clj-kondo
|
||||||
.lsp
|
.lsp
|
||||||
.calva
|
.calva
|
||||||
|
|||||||
5
.idea/.gitignore
generated
vendored
5
.idea/.gitignore
generated
vendored
@@ -1,5 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
# Environment-dependent path to Maven home directory
|
|
||||||
/mavenHomeManager.xml
|
|
||||||
6
.idea/ClojureProjectResolveSettings.xml
generated
6
.idea/ClojureProjectResolveSettings.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ClojureProjectResolveSettings">
|
|
||||||
<currentScheme>IDE</currentScheme>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
18
.idea/compiler.xml
generated
18
.idea/compiler.xml
generated
@@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CompilerConfiguration">
|
|
||||||
<wildcardResourcePatterns>
|
|
||||||
<entry name="!dev-resources:*" />
|
|
||||||
<entry name="!resources:*" />
|
|
||||||
<entry name="!?*.java" />
|
|
||||||
<entry name="!?*.form" />
|
|
||||||
<entry name="!?*.class" />
|
|
||||||
<entry name="!?*.groovy" />
|
|
||||||
<entry name="!?*.scala" />
|
|
||||||
<entry name="!?*.flex" />
|
|
||||||
<entry name="!?*.kt" />
|
|
||||||
<entry name="!?*.clj" />
|
|
||||||
<entry name="!?*.aj" />
|
|
||||||
</wildcardResourcePatterns>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
7
.idea/dictionaries/project.xml
generated
7
.idea/dictionaries/project.xml
generated
@@ -1,7 +0,0 @@
|
|||||||
<component name="ProjectDictionaryState">
|
|
||||||
<dictionary name="project">
|
|
||||||
<words>
|
|
||||||
<w>puuid</w>
|
|
||||||
</words>
|
|
||||||
</dictionary>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: buddy/buddy-core:1.12.0-430">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/buddy/buddy-core/1.12.0-430/buddy-core-1.12.0-430.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
9
.idea/libraries/Leiningen__cheshire_6_0_0.xml
generated
9
.idea/libraries/Leiningen__cheshire_6_0_0.xml
generated
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: cheshire:6.0.0">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/cheshire/cheshire/6.0.0/cheshire-6.0.0.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
9
.idea/libraries/Leiningen__cli_matic_0_5_4.xml
generated
9
.idea/libraries/Leiningen__cli_matic_0_5_4.xml
generated
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: cli-matic:0.5.4">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/cli-matic/cli-matic/0.5.4/cli-matic-0.5.4.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
9
.idea/libraries/Leiningen__clj_http_2_0_0.xml
generated
9
.idea/libraries/Leiningen__clj_http_2_0_0.xml
generated
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: clj-http:2.0.0">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/clj-http/clj-http/2.0.0/clj-http-2.0.0.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
9
.idea/libraries/Leiningen__clj_tuple_0_2_2.xml
generated
9
.idea/libraries/Leiningen__clj_tuple_0_2_2.xml
generated
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: clj-tuple:0.2.2">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/clj-tuple/clj-tuple/0.2.2/clj-tuple-0.2.2.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: com.fasterxml.jackson.core/jackson-core:2.18.3">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/core/jackson-core/2.18.3/jackson-core-2.18.3.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: com.fasterxml.jackson.dataformat/jackson-dataformat-cbor:2.18.3">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/dataformat/jackson-dataformat-cbor/2.18.3/jackson-dataformat-cbor-2.18.3.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: com.fasterxml.jackson.dataformat/jackson-dataformat-smile:2.18.3">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/dataformat/jackson-dataformat-smile/2.18.3/jackson-dataformat-smile-2.18.3.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: commons-codec:1.10">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/commons-codec/commons-codec/1.10/commons-codec-1.10.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
9
.idea/libraries/Leiningen__commons_io_2_4.xml
generated
9
.idea/libraries/Leiningen__commons_io_2_4.xml
generated
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: commons-io:2.4">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/commons-io/commons-io/2.4/commons-io-2.4.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: commons-logging:1.2">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/commons-logging/commons-logging/1.2/commons-logging-1.2.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
9
.idea/libraries/Leiningen__expound_0_9_0.xml
generated
9
.idea/libraries/Leiningen__expound_0_9_0.xml
generated
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: expound:0.9.0">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/expound/expound/0.9.0/expound-0.9.0.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
9
.idea/libraries/Leiningen__nrepl_1_0_0.xml
generated
9
.idea/libraries/Leiningen__nrepl_1_0_0.xml
generated
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: nrepl:1.0.0">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/nrepl/nrepl/1.0.0/nrepl-1.0.0.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: org.apache.httpcomponents/httpclient:4.5">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/apache/httpcomponents/httpclient/4.5/httpclient-4.5.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: org.apache.httpcomponents/httpcore:4.4.1">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/apache/httpcomponents/httpcore/4.4.1/httpcore-4.4.1.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: org.apache.httpcomponents/httpmime:4.5">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/apache/httpcomponents/httpmime/4.5/httpmime-4.5.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: org.bouncycastle/bcpkix-jdk18on:1.78.1">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/bouncycastle/bcpkix-jdk18on/1.78.1/bcpkix-jdk18on-1.78.1.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: org.bouncycastle/bcprov-jdk18on:1.78.1">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/bouncycastle/bcprov-jdk18on/1.78.1/bcprov-jdk18on-1.78.1.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: org.bouncycastle/bcutil-jdk18on:1.78.1">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/bouncycastle/bcutil-jdk18on/1.78.1/bcutil-jdk18on-1.78.1.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: org.clojure/clojure:1.11.1">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/clojure/clojure/1.11.1/clojure-1.11.1.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: org.clojure/core.specs.alpha:0.2.62">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/clojure/core.specs.alpha/0.2.62/core.specs.alpha-0.2.62.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: org.clojure/java.classpath:1.1.0">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/clojure/java.classpath/1.1.0/java.classpath-1.1.0.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: org.clojure/spec.alpha:0.3.218">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/clojure/spec.alpha/0.3.218/spec.alpha-0.3.218.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: org.clojure/test.check:1.1.1">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/clojure/test.check/1.1.1/test.check-1.1.1.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: org.clojure/tools.cli:1.1.230">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/clojure/tools.cli/1.1.230/tools.cli-1.1.230.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: org.clojure/tools.namespace:1.5.0">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/clojure/tools.namespace/1.5.0/tools.namespace-1.5.0.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: org.clojure/tools.reader:1.4.0">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/clojure/tools.reader/1.4.0/tools.reader-1.4.0.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: org.nrepl/incomplete:0.1.0">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/org/nrepl/incomplete/0.1.0/incomplete-0.1.0.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
9
.idea/libraries/Leiningen__potemkin_0_4_1.xml
generated
9
.idea/libraries/Leiningen__potemkin_0_4_1.xml
generated
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: potemkin:0.4.1">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/potemkin/potemkin/0.4.1/potemkin-0.4.1.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
9
.idea/libraries/Leiningen__riddley_0_1_10.xml
generated
9
.idea/libraries/Leiningen__riddley_0_1_10.xml
generated
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: riddley:0.1.10">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/riddley/riddley/0.1.10/riddley-0.1.10.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
9
.idea/libraries/Leiningen__slingshot_0_12_2.xml
generated
9
.idea/libraries/Leiningen__slingshot_0_12_2.xml
generated
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: slingshot:0.12.2">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/slingshot/slingshot/0.12.2/slingshot-0.12.2.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
9
.idea/libraries/Leiningen__tigris_0_1_2.xml
generated
9
.idea/libraries/Leiningen__tigris_0_1_2.xml
generated
@@ -1,9 +0,0 @@
|
|||||||
<component name="libraryTable">
|
|
||||||
<library name="Leiningen: tigris:0.1.2">
|
|
||||||
<CLASSES>
|
|
||||||
<root url="jar://$MAVEN_REPOSITORY$/tigris/tigris/0.1.2/tigris-0.1.2.jar!/" />
|
|
||||||
</CLASSES>
|
|
||||||
<JAVADOC />
|
|
||||||
<SOURCES />
|
|
||||||
</library>
|
|
||||||
</component>
|
|
||||||
11
.idea/misc.xml
generated
11
.idea/misc.xml
generated
@@ -1,11 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="LeiningenProjectsManager">
|
|
||||||
<option name="projectFiles">
|
|
||||||
<set>
|
|
||||||
<option value="file://$PROJECT_DIR$/project.clj" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
<component name="ProjectRootManager" version="2" project-jdk-name="21" project-jdk-type="JavaSDK" />
|
|
||||||
</project>
|
|
||||||
8
.idea/modules.xml
generated
8
.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/riot-clojure.iml" filepath="$PROJECT_DIR$/riot-clojure.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
7
.idea/vcs.xml
generated
7
.idea/vcs.xml
generated
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
140
README.md
140
README.md
@@ -1,88 +1,39 @@
|
|||||||
# riot-clojure
|
# riot-clojure
|
||||||
|
|
||||||
This is a simple tool for using Riot Games public API. Those APIs are HUGE and
|
Riot Games provides a lot of nice endpoints with a lot of data for all their games.
|
||||||
provide a lot of information, but this tool is focused in the time data of matches.
|
This projects provides a library to access those data from Clojure and a small
|
||||||
|
application to quick get some relevant data.
|
||||||
|
|
||||||
The objetive of this tool is extract the playing time of one player. Taking the
|
The library and the CLI application are separated, you can use the library independently.
|
||||||
starting and ending timestamps we can create a chronogram with the time spent
|
|
||||||
playing.
|
|
||||||
|
|
||||||
This simple program needs two API keys: one for LOL and another one for TFT. You
|
CLI application should be compatible with [babashka](https://babashka.org/), so
|
||||||
can obtain a developer key from https://developer.riotgames.com/. Developer keys
|
will use external libraries compatible with it.
|
||||||
are valid for 24 hours only, but you can refresh the key easily from the developer's
|
|
||||||
web site.
|
|
||||||
|
|
||||||
By default, the application searchs for the API key in the environment variables
|
# The API and the tokens
|
||||||
`LOL_API` and `TFT_API`. If you prefer to provide the key via parameter, you must use `--lol-api-key` or
|
|
||||||
`--tft-api-key` parameters.
|
|
||||||
|
|
||||||
## Features
|
Accessing the API requires one or more API tokens. Each videogame has their own
|
||||||
|
group of endpoints, secured with an API. Development APIs can access to all
|
||||||
|
andpoints, but they must be refreshed every 24 hours.
|
||||||
|
|
||||||
Those features are implemented in v1.1
|
You can obtain a token for free in the [official developer web](https://developer.riotgames.com/).
|
||||||
|
|
||||||
* Call the API with development or production keys
|
The library and the application will take the API token from environment. CLI application
|
||||||
* Get a list of matches
|
has optional parameters that override the environment variables.
|
||||||
* Get matches between two dates
|
|
||||||
* Check if player is currently playing
|
|
||||||
* Show the match's data in several formats:
|
|
||||||
* Fancy ASCII table (by default)
|
|
||||||
* Simple ASCII table
|
|
||||||
* Clojure native EDN format
|
|
||||||
* JSON
|
|
||||||
* CSV
|
|
||||||
* Select data fields to show
|
|
||||||
* Format dates and durations
|
|
||||||
* Show the result of the match (win/loss)
|
|
||||||
* Bulk request for hundred of matches
|
|
||||||
* Generate native executables
|
|
||||||
|
|
||||||
## Goals
|
| Game | Environment variable | CLI parameter |
|
||||||
|
| ---------- | -------------------- | ------------- |
|
||||||
|
| all | `RIOT_DEV_KEY` | `--dev-key` |
|
||||||
|
| LOL | `RIOT_LOL_KEY` | `--lol-key` |
|
||||||
|
| TFT | `RIOT_TFT_KEY` | `--tft-key` |
|
||||||
|
*more to came*
|
||||||
|
|
||||||
Goals for version 1.1:
|
# Usage
|
||||||
|
## CLI
|
||||||
* [x] Simplify CLI options and parameters
|
### Installation
|
||||||
* [x] Calculate simple statistics: win/loss rate, hours played every day, etc.
|
|
||||||
* [x] Get more data and delete some unused fields
|
|
||||||
* [x] Clean and refactor some code
|
|
||||||
* [x] Logging
|
|
||||||
* [x] Get only LOL or TFT data
|
|
||||||
* [x] Use Gitea Actions
|
|
||||||
|
|
||||||
Goals of the project, ordered from easiest to hardest:
|
|
||||||
|
|
||||||
* [x] Take API key from environment
|
|
||||||
* [x] Call the API to get basic player data
|
|
||||||
* [x] Make the call to the API flexible
|
|
||||||
* [x] Obtain list of past matches
|
|
||||||
* [x] Obtain list of current matches
|
|
||||||
* [x] Process app parameters
|
|
||||||
* [x] By default, search for player's name and tag
|
|
||||||
* [x] Take API key from parameter
|
|
||||||
* [x] Use PUUID instead of name and tag
|
|
||||||
* [x] Output as simple EDN data with timestamps
|
|
||||||
* [x] Output as simple EDN data with local datetimes
|
|
||||||
* [x] Output as JSON with timestamps
|
|
||||||
* [x] Output as JSON with local datetimes
|
|
||||||
* [x] Output as ASCII table with localdatetimes
|
|
||||||
* [x] By default, output timestamps and local datetimes, and provide parameters
|
|
||||||
to select the output data.
|
|
||||||
* [x] Only checks if it's playing just now
|
|
||||||
* [x] Win / Loss match
|
|
||||||
* [x] Distribution as uberjar
|
|
||||||
* [x] Distribution as native Linux executable
|
|
||||||
* [x] Unit tests: move "comment" manual tests to real unit tests
|
|
||||||
* [ ] Output as a graphical chronogram or calendar.
|
|
||||||
* [ ] Simple web server
|
|
||||||
* [ ] Universal player search
|
|
||||||
* [ ] Simple API to get JSON data
|
|
||||||
* [ ] Simple endpoint to tell if it's playing just now
|
|
||||||
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
Download release from https://git.rcorral.es/ruben/riot-clojure/releases.
|
Download release from https://git.rcorral.es/ruben/riot-clojure/releases.
|
||||||
|
|
||||||
## Usage
|
### Example
|
||||||
|
|
||||||
Using the Java uberjar
|
Using the Java uberjar
|
||||||
|
|
||||||
@@ -93,13 +44,13 @@ Using the linux native image:
|
|||||||
|
|
||||||
Both are equivalent. In the examples we will use the native image, because is shorter.
|
Both are equivalent. In the examples we will use the native image, because is shorter.
|
||||||
|
|
||||||
## Options
|
### Options
|
||||||
|
|
||||||
Run the application without params or wich `-?` param to show all options:
|
Run the application without params or wich `-?` param to show all options:
|
||||||
|
|
||||||
$ ./riot -?
|
$ ./riot -?
|
||||||
|
|
||||||
## Examples
|
### Tipycal usages
|
||||||
|
|
||||||
Show all matches from a march the 1st (in ISO format):
|
Show all matches from a march the 1st (in ISO format):
|
||||||
|
|
||||||
@@ -114,7 +65,46 @@ Don't format durations, show them in seconds
|
|||||||
$ ./riot t <username> <tag> -s "2025-03-01" --no-format-durations
|
$ ./riot t <username> <tag> -s "2025-03-01" --no-format-durations
|
||||||
|
|
||||||
|
|
||||||
## License
|
## Library
|
||||||
|
|
||||||
|
# Version
|
||||||
|
|
||||||
|
**Notes about v2.0:** This is complete rewriting of the project, with all
|
||||||
|
I have learn in the last months. The objetive for this version is to implement
|
||||||
|
all functionality provided by v1.1.
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
### 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)
|
||||||
|
|
||||||
|
### Library
|
||||||
|
|
||||||
|
* [x] Read tokens from environment and a function to override them manually
|
||||||
|
* [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
|
||||||
|
|
||||||
|
### 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
|
||||||
|
* [ ] Calculate advanced statistics: win strike, adversaries, etc.
|
||||||
|
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
|
|||||||
176
build.clj
Normal file
176
build.clj
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
(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]))
|
||||||
|
|
||||||
|
(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)))
|
||||||
|
|
||||||
|
|
||||||
|
;; Builds artifact's full descriptor for each subproject
|
||||||
|
(defn lib [subproj]
|
||||||
|
(symbol (str lib-group "/" artifact-prefix "-" subproj )))
|
||||||
|
|
||||||
|
|
||||||
|
;; 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]
|
||||||
|
: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})
|
||||||
|
(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 )
|
||||||
|
|
||||||
|
)
|
||||||
51
deps.edn
Executable file
51
deps.edn
Executable file
@@ -0,0 +1,51 @@
|
|||||||
|
{:paths ["projects/core/src"
|
||||||
|
"projects/core/resources"
|
||||||
|
"projects/cli/src"]
|
||||||
|
|
||||||
|
: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"}
|
||||||
|
}
|
||||||
|
|
||||||
|
: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
|
||||||
|
:test {:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}
|
||||||
|
lambdaisland/kaocha-cloverage {:mvn/version "1.1.89"}}
|
||||||
|
:main-opts ["-m" "kaocha.runner"]}
|
||||||
|
|
||||||
|
;; 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}
|
||||||
|
|
||||||
|
;; 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"}}}}
|
||||||
|
|
||||||
20
doc/diagram/load_key.plantuml
Normal file
20
doc/diagram/load_key.plantuml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
@startuml Load key
|
||||||
|
|
||||||
|
!pragma useVerticalIf on
|
||||||
|
|
||||||
|
start
|
||||||
|
if (key in map?) then (yes)
|
||||||
|
:return key;
|
||||||
|
elseif (dev key in map?) then (yes)
|
||||||
|
:return dev key;
|
||||||
|
elseif (key in env?) then (yes)
|
||||||
|
:store key in map;
|
||||||
|
:return key;
|
||||||
|
elseif (dev key in env?) then (yes)
|
||||||
|
:store dev key in map;
|
||||||
|
:return dev key;
|
||||||
|
else (nothing)
|
||||||
|
:nil key;
|
||||||
|
endif
|
||||||
|
stop
|
||||||
|
@enduml
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# Introduction to riot-clojure
|
|
||||||
|
|
||||||
TODO: write [great documentation](http://jacobian.org/writing/what-to-write/)
|
|
||||||
BIN
out/doc/diagram/load_key/Load key.png
Normal file
BIN
out/doc/diagram/load_key/Load key.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
53
project.clj
53
project.clj
@@ -1,53 +0,0 @@
|
|||||||
(defproject riot-clojure "1.1.0"
|
|
||||||
:description "Utility for getting for Riot APIs in Clojure"
|
|
||||||
:url "https://git.rcorral.es/ruben/riot-clojure"
|
|
||||||
|
|
||||||
:license {:name "MIT"
|
|
||||||
:url "https://mit-license.org/"}
|
|
||||||
|
|
||||||
:dependencies [[org.clojure/clojure "1.11.1"]
|
|
||||||
[clj-http/clj-http "2.0.0"]
|
|
||||||
[cheshire/cheshire "6.0.0"]
|
|
||||||
[slingshot/slingshot "0.12.2"]
|
|
||||||
[org.clojure/tools.cli "1.1.230"]
|
|
||||||
[cli-matic/cli-matic "0.5.4"] ;; https://github.com/l3nz/cli-matic
|
|
||||||
[buddy/buddy-core "1.12.0-430"]
|
|
||||||
[org.clojure/tools.namespace "1.5.0"]
|
|
||||||
[lt.tokenmill/timewords "0.5.0"] ;; https://github.com/tokenmill/timewords
|
|
||||||
[org.clj-commons/pretty "3.5.0"] ;; https://github.com/clj-commons/pretty
|
|
||||||
[org.clojure/tools.logging "1.3.0"] ;; https://github.com/clojure/tools.logging
|
|
||||||
[org.slf4j/slf4j-api "2.0.17"] ;; https://www.slf4j.org/
|
|
||||||
[ch.qos.logback/logback-classic "1.5.18"]]
|
|
||||||
:jvm-opts ["-Dclojure.tools.logging.factory=clojure.tools.logging.impl/slf4j-factory"]
|
|
||||||
|
|
||||||
:plugins [[io.taylorwood/lein-native-image "0.3.1"]]
|
|
||||||
|
|
||||||
:main ^:skip-aot riot.app
|
|
||||||
:target-path "target/%s"
|
|
||||||
|
|
||||||
:native-image {:name "riot" ;; name of output image, optional
|
|
||||||
:graal-bin "/home/ruben/.sdkman/candidates/java/21.0.2-graalce/" ;; path to GraalVM home, optional
|
|
||||||
:opts ["--verbose"]} ;; pass-thru args to GraalVM native-image, optional
|
|
||||||
|
|
||||||
:profiles {:uberjar {:aot :all
|
|
||||||
:jvm-opts ["-Dclojure.compiler.direct-linking=true"]}
|
|
||||||
:native-image {:jvm-opts ["-Dclojure.compiler.direct-linking=true"]}
|
|
||||||
:dev {:dependencies [[org.clojure/test.check "1.1.1"]]
|
|
||||||
:plugins [[io.taylorwood/lein-native-image "0.3.1"]
|
|
||||||
[lein-binplus "0.6.8"]]}}
|
|
||||||
|
|
||||||
;; lein bin configuration
|
|
||||||
:bin {:name "riot_clj"
|
|
||||||
:bin-path "~/bin"
|
|
||||||
:jvm-opts ["-server" "-Dfile.encoding=utf-8" "$JVM_OPTS"]}
|
|
||||||
|
|
||||||
;; Deploy to repository
|
|
||||||
:repositories {"gitea"
|
|
||||||
{:url "https://git.rcorral.es/api/packages/ruben/maven"
|
|
||||||
:username :env/DEPLOY_USER
|
|
||||||
:password :env/DEPLOY_TOKEN}}
|
|
||||||
|
|
||||||
;; Test selectors
|
|
||||||
:test-selectors {:default (complement (some-fn :tft :timezone))
|
|
||||||
:tft :tft
|
|
||||||
:timezone :timezone})
|
|
||||||
11
projects/cli/deps.edn
Executable file
11
projects/cli/deps.edn
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
{: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"]}
|
||||||
|
}}
|
||||||
|
|
||||||
28
projects/cli/src/riot/app.clj
Normal file
28
projects/cli/src/riot/app.clj
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
(ns riot.app
|
||||||
|
#_{:clj-kondo/ignore [:refer-all]}
|
||||||
|
(:require [riot.core :refer :all]
|
||||||
|
[riot.data :refer :all]
|
||||||
|
[lambdaisland.cli :as cli]
|
||||||
|
[clojure.pprint :as pp]
|
||||||
|
[clojure.string :as s])
|
||||||
|
(:gen-class))
|
||||||
|
|
||||||
|
(defn test-fn
|
||||||
|
[opts]
|
||||||
|
(println "Options:")
|
||||||
|
(pp/pprint opts)
|
||||||
|
(println "Positional args:" (s/join "," (:lambdaisland.cli/argv opts))))
|
||||||
|
|
||||||
|
(defn -main [& args]
|
||||||
|
(cli/dispatch
|
||||||
|
{:name "cli-test"
|
||||||
|
:command #'test-fn ; The function to call
|
||||||
|
:flags ["-v, --verbose" "Increases verbosity"
|
||||||
|
"--input FILE" "Specify the input file"]}
|
||||||
|
args))
|
||||||
|
|
||||||
|
|
||||||
|
(comment
|
||||||
|
|
||||||
|
(-main "-v" "--input" "boniato.txt" "position1" "pos2")
|
||||||
|
)
|
||||||
18
projects/core/deps.edn
Executable file
18
projects/core/deps.edn
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
{: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"]}}}
|
||||||
|
|
||||||
189
projects/core/src/riot/core.clj
Normal file
189
projects/core/src/riot/core.clj
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
(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")
|
||||||
|
|
||||||
|
)
|
||||||
198
projects/core/src/riot/data.clj
Normal file
198
projects/core/src/riot/data.clj
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
(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"))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
;;
|
||||||
173
projects/core/src/riot/riot_api.clj
Normal file
173
projects/core/src/riot/riot_api.clj
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
(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"})
|
||||||
|
)
|
||||||
454
projects/core/src/riot/riot_config.clj
Normal file
454
projects/core/src/riot/riot_config.clj
Normal file
@@ -0,0 +1,454 @@
|
|||||||
|
(ns riot.riot-config)
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; API KEYS
|
||||||
|
;;
|
||||||
|
|
||||||
|
(def RIOT-KEYS {:RIOT_DEV_KEY (atom nil)
|
||||||
|
:RIOT_LOL_KEY (atom nil)
|
||||||
|
:RIOT_TFT_KEY (atom nil)})
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; KNOWN ENDPOINTS
|
||||||
|
;;
|
||||||
|
;; Each endpoint has a URL with path params (denoted as keywords, with ':') and
|
||||||
|
;; some informative metadata about parameters and some logical grouping.
|
||||||
|
;;
|
||||||
|
;; For now, metadata is optional and it is not used in the core, but is very
|
||||||
|
;; usefull for programmers like you.
|
||||||
|
|
||||||
|
(def ENDPOINTS
|
||||||
|
{;; account v1
|
||||||
|
:account-by-puuid
|
||||||
|
{:uri "https://europe.api.riotgames.com/riot/account/v1/accounts/by-puuid/:puuid"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["account"]
|
||||||
|
:path-params {:puuid {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:lol-account-by-riot-id
|
||||||
|
{:uri "https://europe.api.riotgames.com/riot/account/v1/accounts/by-riot-id/:player-name/:player-tag"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "account"]
|
||||||
|
:path-params {:player-name {:required true :type :string}
|
||||||
|
:player-tag {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:account-active-shards
|
||||||
|
{:uri "https://europe.api.riotgames.com/riot/account/v1/active-shards/by-game/:game/by-puuid/:puuid"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["account"]
|
||||||
|
:path-params {:game {:required true :type :string}
|
||||||
|
:puuid {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
;; LOL status v4
|
||||||
|
:lol-status
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/status/v4/platform-data"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "status"]
|
||||||
|
:path-params {}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
;; champion-mastery-v4
|
||||||
|
:champion-mastery-by-puuid
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/:puuid"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "champion-mastery"]
|
||||||
|
:path-params {:puuid {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:champion-mastery-by-puuid-and-champion
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/:puuid/by-champion/:championId"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "champion-mastery"]
|
||||||
|
:path-params {:puuid {:required true :type :string}
|
||||||
|
:championId {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:champion-mastery-by-puuid-top
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/:puuid/top"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "champion-mastery"]
|
||||||
|
:path-params {:puuid {:required true :type :string}}
|
||||||
|
:query-params {:count {:required false :type :int :default 3}}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
;; champion v3
|
||||||
|
:champion-rotations
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/platform/v3/champion-rotations"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "champion"]
|
||||||
|
:path-params {}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
;; summoner v4
|
||||||
|
:summoner-by-puuid
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/summoner/v4/summoners/by-puuid/:puuid"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "summoner"]
|
||||||
|
:path-params {:puuid {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
;; leage v4
|
||||||
|
:league-challenger-by-queue
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/league/v4/challengerleagues/by-queue/:queue"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "league"]
|
||||||
|
:path-params {:queue {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:league-all-by-puuid
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/league/v4/entries/by-puuid/:puuid"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "league"]
|
||||||
|
:path-params {:puuid {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:league-all-queue-tier-division
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/league/v4/entries/:queue/:tier/:division"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "league"]
|
||||||
|
:path-params {:queue {:required true :type :string}
|
||||||
|
:tier {:required true :type :string}
|
||||||
|
:division {:required true :type :string}}
|
||||||
|
:query-params {:page {:required false :type :int :default 1}}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:league-grandmaster-by-queue
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/league/v4/grandmasterleagues/by-queue/:queue"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "league"]
|
||||||
|
:path-params {:queue {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:league-by-id
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/league/v4/leagues/:league-id"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "league"]
|
||||||
|
:path-params {:league-id {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:league-by-queue
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/league/v4/masterleagues/by-queue/:queue"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "league"]
|
||||||
|
:path-params {:queue {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
;; league-exp v4
|
||||||
|
:league-exp-by-queue-tier-division
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/league-exp/v4/entries/:queue/:tier/:division"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "league"]
|
||||||
|
:path-params {:queue {:required true :type :string}
|
||||||
|
:tier {:required true :type :string}
|
||||||
|
:division {:required true :type :string}}
|
||||||
|
:query-params {:page {:required false :type :int :default 1}}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
;; clash v1
|
||||||
|
:clash-by-puuid
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/clash/v1/players/by-puuid/:puuid"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "clash"]
|
||||||
|
:path-params {:puuid {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:clash-by-team
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/clash/v1/teams/:team-id"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "clash"]
|
||||||
|
:path-params {:team-id {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:clash-tournaments
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/clash/v1/tournaments"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "clash"]
|
||||||
|
:path-params {}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:clash-tournaments-by-team
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/clash/v1/tournaments/by-team/:team-id"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "clash"]
|
||||||
|
:path-params {:team-id {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:clash-tournaments-by-tournament
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/clash/v1/tournaments/:tournament-id"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "clash"]
|
||||||
|
:path-params {:tournament-id {:required true :type :int}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
;; Match v5
|
||||||
|
:lol-matches-by-puuid
|
||||||
|
{:uri "https://europe.api.riotgames.com/lol/match/v5/matches/by-puuid/:puuid/ids"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "match"]
|
||||||
|
:path-params {:puuid {:required true :type :string}}
|
||||||
|
:query-params {:startTime {:required false :type :long}
|
||||||
|
:endTime {:required false :type :long}
|
||||||
|
:queue {:required false :type :int}
|
||||||
|
:type {:required false :type :string}
|
||||||
|
:start {:required false :type :int :default 0}
|
||||||
|
:count {:required false :type :int :default 20 :min 0 :max 100}}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:lol-match-replays-by-puuid
|
||||||
|
{:uri "https://europe.api.riotgames.com/lol/match/v5/matches/by-puuid/:puuid/replays"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "match"]
|
||||||
|
:path-params {:puuid {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:lol-match-by-id
|
||||||
|
{:uri "https://europe.api.riotgames.com/lol/match/v5/matches/:match-id"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "match"]
|
||||||
|
:path-params {:match-id {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:lol-match-timeline-by-id
|
||||||
|
{:uri "https://europe.api.riotgames.com/lol/match/v5/matches/:match-id/timeline"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "match"]
|
||||||
|
:path-params {:match-id {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
;; LOL challenges v1
|
||||||
|
:lol-challenges-config
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/challenges/v1/challenges/config"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "challenges"]
|
||||||
|
:path-params {}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:lol-challenge-config-by-id
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/challenges/v1/challenges/:challenge-id/config"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "challenges"]
|
||||||
|
:path-params {:challenge-id {:required true :type :long}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:lol-challenges-percentiles
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/challenges/v1/challenges/percentiles"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "challenges"]
|
||||||
|
:path-params {}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:lol-challenges-percentiles-by-id
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/challenges/v1/challenges/:challenge-id/percentiles"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "challenges"]
|
||||||
|
:path-params {:challenge-id {:required true :type :long}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:lol-challenge-leaderboard
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/challenges/v1/challenges/:challenge-id/leaderboards/by-level/:level"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "challenges"]
|
||||||
|
:path-params {:challenge-id {:required true :type :long}
|
||||||
|
:level {:required true :type #{"NONE" "IRON" "BRONZE" "SILVER" "GOLD" "PLATINUM" "DIAMOND" "MASTER" "GRANDMASTER" "CHALLENGER" "HIGHEST_NOT_LEADERBOARD_ONLY" "HIGHEST" "LOWEST"}}}
|
||||||
|
:query-params {:limit {:required false :type :int}}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:lol-challenge-by-puuid
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/challenges/v1/player-data/:puuid"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "challenges"]
|
||||||
|
:path-params {:puuid {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
;; LOL champion mastery v4
|
||||||
|
:lol-champion-mastery-by-puuid
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/:puuid"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "champion-mastery"]
|
||||||
|
:path-params {:puuid {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:lol-champion-mastery-by-puuid-champion
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/:puuid/by-champion/:champion-id"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "champion-mastery"]
|
||||||
|
:path-params {:puuid {:required true :type :string}
|
||||||
|
:champion-id {:required true :type :int}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:lol-champion-mastery-by-puuid-top
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/:puuid/top"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "champion-mastery"]
|
||||||
|
:path-params {:puuid {:required true :type :string}}
|
||||||
|
:query-params {:count {:required false :type :int :default 3}}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:lol-champion-mastery-scores-by-puuid
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/champion-mastery/v4/scores/by-puuid/:puuid"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "champion-mastery"]
|
||||||
|
:path-params {:puuid {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
;; spectator v5
|
||||||
|
|
||||||
|
:lol-spectator
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/spectator/v5/active-games/by-summoner/:puuid"
|
||||||
|
:api-key :RIOT_LOL_KEY
|
||||||
|
:groups ["lol" "spectator"]
|
||||||
|
:path-params {:puuid {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; TFT
|
||||||
|
;;
|
||||||
|
|
||||||
|
;; account v1
|
||||||
|
:tft-account-by-riot-id
|
||||||
|
{:uri "https://europe.api.riotgames.com/riot/account/v1/accounts/by-riot-id/:player-name/:player-tag"
|
||||||
|
:api-key :RIOT_TFT_KEY
|
||||||
|
:groups ["tft" "account"]
|
||||||
|
:path-params {:player-name {:required true :type :string}
|
||||||
|
:player-tag {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
;; tft status v1
|
||||||
|
:tft-status
|
||||||
|
{:uri "https://euw1.api.riotgames.com/tft/status/v1/platform-data"
|
||||||
|
:api-key :RIOT_TFT_KEY
|
||||||
|
:groups ["tft" "status"]
|
||||||
|
:path-params {}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
;; TFT summoner v1
|
||||||
|
:tft-summoner-by-puuid
|
||||||
|
{:uri "https://euw1.api.riotgames.com/tft/summoner/v1/summoners/by-puuid/:puuid"
|
||||||
|
:api-key :RIOT_TFT_KEY
|
||||||
|
:groups ["tft" "summoner"]
|
||||||
|
:path-params {:puuid {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
;; TFT match v1
|
||||||
|
:tft-matches-by-puuid
|
||||||
|
{:uri "https://europe.api.riotgames.com/tft/match/v1/matches/by-puuid/:puuid/ids"
|
||||||
|
:api-key :RIOT_TFT_KEY
|
||||||
|
:groups ["tft" "match"]
|
||||||
|
:path-params {:puuid {:required true :type :string}}
|
||||||
|
:query-params {:startTime {:required false :type :long}
|
||||||
|
:endTime {:required false :type :long}
|
||||||
|
:queue {:required false :type :int}
|
||||||
|
:type {:required false :type :string}
|
||||||
|
:start {:required false :type :int :default 0}
|
||||||
|
:count {:required false :type :int :default 20 :min 0 :max 100}}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
|
||||||
|
:tft-match-by-id
|
||||||
|
{:uri "https://europe.api.riotgames.com/tft/match/v1/matches/:match-id"
|
||||||
|
:api-key :RIOT_TFT_KEY
|
||||||
|
:groups ["tft" "match"]
|
||||||
|
:path-params {:match-id {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
;; TFT espectator v5
|
||||||
|
|
||||||
|
:tft-spectator
|
||||||
|
{:uri "https://euw1.api.riotgames.com/lol/spectator/tft/v5/active-games/by-puuid/:puuid"
|
||||||
|
:api-key :RIOT_TFT_KEY
|
||||||
|
:groups ["tft" "spectator"]
|
||||||
|
:path-params {:puuid {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
;; TFT league v1
|
||||||
|
:tft-league-by-puuid
|
||||||
|
{:uri "https://euw1.api.riotgames.com/tft/league/v1/by-puuid/:puuid"
|
||||||
|
:api-key :RIOT_TFT_KEY
|
||||||
|
:groups ["tft" "spectator"]
|
||||||
|
:path-params {:puuid {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:tft-league-challenger
|
||||||
|
{:uri "https://euw1.api.riotgames.com/tft/league/v1/challenger"
|
||||||
|
:api-key :RIOT_TFT_KEY
|
||||||
|
:groups ["tft" "spectator"]
|
||||||
|
:path-params {}
|
||||||
|
:query-params {:ranked {:required false :type #{"RANKED_TFT" "RANKED_TFT_DOUBLE_UP"}}}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:tft-league-by-tier-division
|
||||||
|
{:uri "https://euw1.api.riotgames.com/tft/league/v1/entries/:tier/:division"
|
||||||
|
:api-key :RIOT_TFT_KEY
|
||||||
|
:groups ["tft" "league"]
|
||||||
|
:path-params {:tier {:required true :type :string}
|
||||||
|
:division {:required true :type :string}}
|
||||||
|
:query-params {:queue {:required false :type #{"RANKED_TFT" "RANKED_TFT_DOUBLE_UP"} :default "RANKED_TFT"}
|
||||||
|
:page {:required false :type int :default 1}}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:tft-league-grandmaster-by-queue
|
||||||
|
{:uri "https://euw1.api.riotgames.com/tft/league/v1/grandmaster"
|
||||||
|
:api-key :RIOT_TFT_KEY
|
||||||
|
:groups ["tft" "league"]
|
||||||
|
:path-params {}
|
||||||
|
:query-params {:queue {:required false :type #{"RANKED_TFT" "RANKED_TFT_DOUBLE_UP"} :default "RANKED_TFT"}}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:tft-league-master-by-queue
|
||||||
|
{:uri "https://euw1.api.riotgames.com/tft/league/v1/master"
|
||||||
|
:api-key :RIOT_TFT_KEY
|
||||||
|
:groups ["tft" "league"]
|
||||||
|
:path-params {}
|
||||||
|
:query-params {:queue {:required false :type #{"RANKED_TFT" "RANKED_TFT_DOUBLE_UP"} :default "RANKED_TFT"}}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
:tft-league-top-rated-ladders
|
||||||
|
{:uri "https://euw1.api.riotgames.com/tft/league/v1/rated-ladders/:queue/top"
|
||||||
|
:api-key :RIOT_TFT_KEY
|
||||||
|
:groups ["tft" "league"]
|
||||||
|
:path-params {:queue {:required true :type :string}}
|
||||||
|
:query-params {}
|
||||||
|
:header-params {}}
|
||||||
|
|
||||||
|
;; END OF ENDPOINT DEFINITIONS
|
||||||
|
})
|
||||||
10
projects/core/test/riot/core_test.clj
Normal file
10
projects/core/test/riot/core_test.clj
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
(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")))))
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
<configuration>
|
|
||||||
|
|
||||||
<!-- Appender a consola -->
|
|
||||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
|
||||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
|
||||||
<level>INFO</level>
|
|
||||||
</filter>
|
|
||||||
<encoder>
|
|
||||||
<!--<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>-->
|
|
||||||
<pattern>[%-5level] %msg%n</pattern>
|
|
||||||
</encoder>
|
|
||||||
</appender>
|
|
||||||
|
|
||||||
<!-- Appender a archivo con rotación -->
|
|
||||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
|
||||||
<file>logs/riot-app.log</file>
|
|
||||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
|
||||||
<!-- rota cada día, conserva 7 días -->
|
|
||||||
<fileNamePattern>logs/riot-app.%d{yyyy-MM-dd}.log</fileNamePattern>
|
|
||||||
<maxHistory>7</maxHistory>
|
|
||||||
</rollingPolicy>
|
|
||||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
|
||||||
<level>DEBUG</level>
|
|
||||||
</filter>
|
|
||||||
<encoder>
|
|
||||||
<pattern>%d{ISO8601} %-5level %logger{36}:%L - %msg%n</pattern>
|
|
||||||
</encoder>
|
|
||||||
</appender>
|
|
||||||
|
|
||||||
<!-- Nivel de log raíz -->
|
|
||||||
<root level="DEBUG">
|
|
||||||
<appender-ref ref="STDOUT" />
|
|
||||||
<appender-ref ref="FILE" />
|
|
||||||
</root>
|
|
||||||
|
|
||||||
</configuration>
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="JAVA_MODULE" version="4">
|
|
||||||
<component name="BuildSystem">
|
|
||||||
<option name="buildSystemId" value="LEININGEN" />
|
|
||||||
<option name="displayName" value="riot-clojure:1.0.0" />
|
|
||||||
</component>
|
|
||||||
<component name="NewModuleRootManager">
|
|
||||||
<output url="file://$MODULE_DIR$/target/classes" />
|
|
||||||
<output-test url="file://$MODULE_DIR$/target/classes" />
|
|
||||||
<exclude-output />
|
|
||||||
<content url="file://$MODULE_DIR$">
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/dev-resources" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/resources" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
|
||||||
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
|
|
||||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
|
||||||
</content>
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
<orderEntry type="library" name="Leiningen: buddy/buddy-core:1.12.0-430" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: cheshire:6.0.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: cli-matic:0.5.4" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: clj-http:2.0.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: clj-tuple:0.2.2" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: com.fasterxml.jackson.core/jackson-core:2.18.3" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: com.fasterxml.jackson.dataformat/jackson-dataformat-cbor:2.18.3" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: com.fasterxml.jackson.dataformat/jackson-dataformat-smile:2.18.3" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: commons-codec:1.10" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: commons-io:2.4" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: commons-logging:1.2" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: expound:0.9.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: nrepl:1.0.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: org.apache.httpcomponents/httpclient:4.5" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: org.apache.httpcomponents/httpcore:4.4.1" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: org.apache.httpcomponents/httpmime:4.5" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: org.bouncycastle/bcpkix-jdk18on:1.78.1" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: org.bouncycastle/bcprov-jdk18on:1.78.1" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: org.bouncycastle/bcutil-jdk18on:1.78.1" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: org.clojure/clojure:1.11.1" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: org.clojure/core.specs.alpha:0.2.62" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: org.clojure/java.classpath:1.1.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: org.clojure/spec.alpha:0.3.218" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: org.clojure/test.check:1.1.1" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: org.clojure/tools.cli:1.1.230" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: org.clojure/tools.namespace:1.5.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: org.clojure/tools.reader:1.4.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: org.nrepl/incomplete:0.1.0" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: potemkin:0.4.1" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: riddley:0.1.10" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: slingshot:0.12.2" level="project" />
|
|
||||||
<orderEntry type="library" name="Leiningen: tigris:0.1.2" level="project" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
||||||
260
src/riot/app.clj
260
src/riot/app.clj
@@ -1,260 +0,0 @@
|
|||||||
|
|
||||||
;; Main CLI application
|
|
||||||
|
|
||||||
(ns riot.app
|
|
||||||
(:require [cli-matic.core :refer [run-cmd]]
|
|
||||||
[cli-matic.utils :as U]
|
|
||||||
[clojure.pprint :as pp]
|
|
||||||
[clojure.string :as str]
|
|
||||||
[timewords.core :refer [parse]]
|
|
||||||
[clojure.tools.logging :as log]
|
|
||||||
)
|
|
||||||
(:use [riot.core]
|
|
||||||
[riot.data]
|
|
||||||
[slingshot.slingshot :only [try+]])
|
|
||||||
(:gen-class))
|
|
||||||
|
|
||||||
|
|
||||||
(defn get-puuid-from-params
|
|
||||||
[api-key params & {:keys [puuid name tag]}]
|
|
||||||
;(println "get puuid API key" api-key)
|
|
||||||
(cond
|
|
||||||
(= 1 (count params)) (first params)
|
|
||||||
(= 2 (count params)) (get-puuid-from-name (first params) (second params) :api-key api-key)
|
|
||||||
(some? puuid) puuid
|
|
||||||
(and (some? name) (some? tag)) (get-puuid-from-name name tag :api-key api-key)))
|
|
||||||
|
|
||||||
|
|
||||||
#_{:clj-kondo/ignore [:unresolved-symbol]}
|
|
||||||
(defn cmd-active
|
|
||||||
"Checks if a player is online at the moment"
|
|
||||||
[& {:keys [lol-api-key tft-api-key debug-http lol tft _arguments]
|
|
||||||
:as opts}]
|
|
||||||
(try+
|
|
||||||
;(println "Check online" opts)
|
|
||||||
(let [lol-key (when lol (get-lol-api-key lol-api-key))
|
|
||||||
tft-key (when tft (get-tft-api-key tft-api-key))
|
|
||||||
lol-id (when lol (get-puuid-from-params lol-key _arguments opts))
|
|
||||||
tft-id (when tft (get-puuid-from-params tft-key _arguments opts))]
|
|
||||||
(if (and (nil? lol-id) (nil? tft-id))
|
|
||||||
(println "No games to check")
|
|
||||||
(if (is-playing? lol-id tft-id :lol-api-key lol-key :tft-api-key tft-key :debug debug-http)
|
|
||||||
(do (println "Yes, it's playing") true)
|
|
||||||
(do (println "No, it's not playing right now") false))))
|
|
||||||
(catch [:status 401] _
|
|
||||||
(U/exit! "Invalid API key" 3))
|
|
||||||
(catch [:status 404] _
|
|
||||||
(U/exit! "Unknown user or tag" 5))))
|
|
||||||
|
|
||||||
|
|
||||||
(defn format-result
|
|
||||||
"Format result"
|
|
||||||
[output x]
|
|
||||||
(case output
|
|
||||||
"table" (as-ascii-table x)
|
|
||||||
"ptable" (as-pretty-table x)
|
|
||||||
"edn" (pp/pprint x)
|
|
||||||
"json" (println (as-json x))
|
|
||||||
"csv" (println (as-csv x))
|
|
||||||
(pp/pprint x))) ;edn as default
|
|
||||||
|
|
||||||
|
|
||||||
(defn format-dates-cond
|
|
||||||
"Format dates and durations if specified"
|
|
||||||
[format-dates pattern x]
|
|
||||||
(if format-dates
|
|
||||||
(if (some? pattern)
|
|
||||||
(with-parsed-dates x :datetime-format pattern)
|
|
||||||
(with-parsed-dates x))
|
|
||||||
x))
|
|
||||||
|
|
||||||
|
|
||||||
(defn format-duration-cond
|
|
||||||
"Format durations if specified"
|
|
||||||
[format-durations x]
|
|
||||||
(if format-durations
|
|
||||||
(with-parsed-durations x)
|
|
||||||
x))
|
|
||||||
|
|
||||||
|
|
||||||
(defn calculate-statistics-cond
|
|
||||||
"If true, calculate statistics and print them to console"
|
|
||||||
[calculate x]
|
|
||||||
(when calculate
|
|
||||||
(log/info "Calculating statistics")
|
|
||||||
(pp/pprint (calculate-statistics x)))
|
|
||||||
x)
|
|
||||||
|
|
||||||
(defn reverse-cond
|
|
||||||
"If true, data is ordered from nearest to fartest"
|
|
||||||
[rev x] (if rev x (reverse x)))
|
|
||||||
|
|
||||||
|
|
||||||
(defn filter-columns
|
|
||||||
"Filter columns to show. With 'all' shows all columns"
|
|
||||||
[columns x] (if (= "all" columns)
|
|
||||||
x
|
|
||||||
(map #(select-keys % (map keyword (str/split columns #","))) x)))
|
|
||||||
|
|
||||||
(defn get-date
|
|
||||||
"Converts an string into a java.util.Date"
|
|
||||||
[x]
|
|
||||||
(if (nil? x) nil (parse x)))
|
|
||||||
|
|
||||||
|
|
||||||
#_{:clj-kondo/ignore [:unresolved-symbol]}
|
|
||||||
(defn cmd-timeline
|
|
||||||
"Get all matches"
|
|
||||||
[& {:keys [lol-api-key tft-api-key lol tft output format-dates format-durations date-format reverse order-by show-columns debug-http since until statistics _arguments]
|
|
||||||
:as opts}]
|
|
||||||
(try+
|
|
||||||
;(println "Get timeline" opts)
|
|
||||||
(let [lol-key (when lol (get-lol-api-key lol-api-key))
|
|
||||||
tft-key (when tft (get-tft-api-key tft-api-key))
|
|
||||||
lol-id (when lol (get-puuid-from-params lol-key _arguments opts))
|
|
||||||
tft-id (when tft (get-puuid-from-params tft-key _arguments opts))
|
|
||||||
since-date (get-date since)
|
|
||||||
until-date (get-date until)]
|
|
||||||
(log/info (str "Fetching data between " since-date " and " (if (some? until-date) until-date (java.util.Date.))))
|
|
||||||
(if (and (nil? lol-id) (nil? tft-id))
|
|
||||||
(U/exit! "No games selected" 2)
|
|
||||||
(->> (get-matches-info-batch lol-id tft-id :lol-api-key lol-key :tft-api-key tft-key :debug debug-http :order-by (keyword order-by) :since since-date :until until-date)
|
|
||||||
(calculate-statistics-cond statistics)
|
|
||||||
(reverse-cond reverse)
|
|
||||||
(format-dates-cond format-dates date-format)
|
|
||||||
(format-duration-cond format-durations)
|
|
||||||
(filter-columns show-columns)
|
|
||||||
(format-result output))))
|
|
||||||
(catch [:status 401] _
|
|
||||||
(U/exit! "Invalid API key" 3))
|
|
||||||
(catch [:status 404] _
|
|
||||||
(U/exit! "Unknown user or tag" 5))
|
|
||||||
(catch [:status 429] _
|
|
||||||
(U/exit! "Rate limit exceeded, please wait some minutes and try again" 4))
|
|
||||||
(catch [:status 502] _
|
|
||||||
(U/exit! "Server timeout, please wait some minutes and try again" 6))
|
|
||||||
(catch [:status 503] _
|
|
||||||
(U/exit! "Server timeout, please wait some minutes and try again" 6))))
|
|
||||||
|
|
||||||
|
|
||||||
;; More info: https://github.com/l3nz/cli-matic/blob/master/README.md
|
|
||||||
(def CONFIGURATION
|
|
||||||
{:app {:command "riot"
|
|
||||||
:version "1.1.0"
|
|
||||||
:description ["Get how much you play your favourite games"
|
|
||||||
""
|
|
||||||
"EXAMPLE USAGES:"
|
|
||||||
" Get all matches since March 1st 2025:"
|
|
||||||
" riot timeline <your_player_name> <your_tag> -s 2025-03-01"
|
|
||||||
""
|
|
||||||
" Get all matches as CSV, don't format durations:"
|
|
||||||
" riot timeline <your_player_name> <your_tag> -s 2025-03-01 -o csv --no-format-durations > my_matches.csv"
|
|
||||||
""
|
|
||||||
"ERROR CODES:"
|
|
||||||
" 0: OK, no error"
|
|
||||||
" 1: player not playing"
|
|
||||||
" 2: Invalid params"
|
|
||||||
" 3: Invalid API key, please, get and configure an updated one"
|
|
||||||
" 4: Rate limit exceeded, please wait some minutes and try again"
|
|
||||||
" 5: Unknown user and tag"
|
|
||||||
" 6: Server error. Please, try again"]}
|
|
||||||
|
|
||||||
:global-opts [{:option "lol-api-key"
|
|
||||||
:as "API key for LOL data"
|
|
||||||
:type :string :default nil
|
|
||||||
:env "LOL_API"}
|
|
||||||
{:option "tft-api-key"
|
|
||||||
:as "API key for TFT data"
|
|
||||||
:type :string :default nil
|
|
||||||
:env "TFT_API"}
|
|
||||||
{:option "debug-http"
|
|
||||||
:as "Show debug for HTTP connections. I'ts very verbose!"
|
|
||||||
:type :flag
|
|
||||||
:default false}
|
|
||||||
;; {:option "log-level"
|
|
||||||
;; :as "Log level (debug, info, warn, etc)"
|
|
||||||
;; :type :keyword
|
|
||||||
;; :default :info}
|
|
||||||
]
|
|
||||||
|
|
||||||
:commands [{:command "active" :short "a"
|
|
||||||
:description ["Shows if the player is currently playing"
|
|
||||||
"By default only shows LOL matches"]
|
|
||||||
:opts [{:option "lol"
|
|
||||||
:type :with-flag :default true
|
|
||||||
:as "Include LOL matches"}
|
|
||||||
{:option "tft"
|
|
||||||
:type :with-flag :default false
|
|
||||||
:as "Include TFT matches. Experimental"}]
|
|
||||||
:runs cmd-active}
|
|
||||||
|
|
||||||
{:command "timeline" :short "t"
|
|
||||||
:description ["Get info from LOL and TFT (experimental, disabled by default) matches in a time range."
|
|
||||||
""
|
|
||||||
"Warning: it can take several minutes to obtain all data, due to API restrictions."]
|
|
||||||
:opts [{:option "lol"
|
|
||||||
:type :with-flag :default true
|
|
||||||
:as "Include LOL matches"}
|
|
||||||
{:option "tft"
|
|
||||||
:type :with-flag :default false
|
|
||||||
:as "Include TFT matches. Experimental"}
|
|
||||||
{:option "since" :short "s"
|
|
||||||
:type :string :default "today"
|
|
||||||
:as ["Starting date (included) in 'yyyy-MM-dd' format."
|
|
||||||
"Other valid values: 'today', 'yesterday', 'last monday', etc"]}
|
|
||||||
{:option "until" :short "u"
|
|
||||||
:type :string :default nil
|
|
||||||
:as ["Ending date (not included) in 'yyyy-MM-dd' format."
|
|
||||||
"Other valid values: today, yesterday, tomorrow, etc"]}
|
|
||||||
{:option "output" :short "o"
|
|
||||||
:type #{"table" "ptable" "edn" "json" "csv"} :default "ptable"
|
|
||||||
:as ["Output data format. It can be one of:"
|
|
||||||
" - table: ASCII table"
|
|
||||||
" - ptable: Pretty ASCII table (default)"
|
|
||||||
" - edn: Clojure's internal EDN format"
|
|
||||||
" - json: Classic JSON"
|
|
||||||
" - csv: CSV data, using ',' as field separator"]}
|
|
||||||
{:option "order-by"
|
|
||||||
:type #{"start" "end" "duration"} :default "start"
|
|
||||||
:as "Order by field"}
|
|
||||||
{:option "reverse" :short "r"
|
|
||||||
:type :with-flag :default false
|
|
||||||
:as "If true, newer matches are shown last in list"}
|
|
||||||
{:option "format-dates"
|
|
||||||
:type :with-flag :default true
|
|
||||||
:as "Show formatted dates"}
|
|
||||||
{:option "format-durations"
|
|
||||||
:type :with-flag :default true
|
|
||||||
:as "Show formatted durations"}
|
|
||||||
{:option "date-format"
|
|
||||||
:type :string :default nil
|
|
||||||
:as "If format-dates is enabled, specifies the formatter's string"}
|
|
||||||
{:option "show-columns"
|
|
||||||
:type :string :default "all"
|
|
||||||
:as ["Show only selected columns, separated by comma. Supported columns:"
|
|
||||||
" - all: All columns"
|
|
||||||
" - start: Start timestamp"
|
|
||||||
" - end: End timestamp"
|
|
||||||
" - duration: Duration in seconds"
|
|
||||||
" - game-type: lol or tft"
|
|
||||||
" - id: Game unique id"
|
|
||||||
" - winner: Winner of the match"]}
|
|
||||||
{:option "statistics"
|
|
||||||
:type :with-flag :default true
|
|
||||||
:as "Show simple statistics"}]
|
|
||||||
:runs cmd-timeline}]})
|
|
||||||
|
|
||||||
|
|
||||||
(defn -main
|
|
||||||
"Main entry point"
|
|
||||||
[& args]
|
|
||||||
(log/debug "")
|
|
||||||
(log/debug "** Starting application **")
|
|
||||||
(log/debug "")
|
|
||||||
(run-cmd args CONFIGURATION))
|
|
||||||
|
|
||||||
|
|
||||||
(comment
|
|
||||||
; Launch manually
|
|
||||||
(-main)
|
|
||||||
)
|
|
||||||
@@ -1,501 +0,0 @@
|
|||||||
|
|
||||||
;; Core functions to get data from server
|
|
||||||
|
|
||||||
(ns riot.core
|
|
||||||
(:require [clj-http.client :as client]
|
|
||||||
[buddy.core.crypto :as crypto]
|
|
||||||
[buddy.core.codecs :as codecs]
|
|
||||||
[clojure.tools.logging :as log]
|
|
||||||
)
|
|
||||||
(:use [slingshot.slingshot :only [try+]])
|
|
||||||
(:gen-class))
|
|
||||||
|
|
||||||
|
|
||||||
(def API-HOST "api.riotgames.com")
|
|
||||||
|
|
||||||
(def secret-key (codecs/b64->bytes "//EaEeKElZDJSLLJaydGQDKw5DiqUCZ5DdnLvpE6dbo="))
|
|
||||||
(def iv (codecs/b64->bytes "cMN8rAwUoYHk7YwJ7HawFw=="))
|
|
||||||
|
|
||||||
|
|
||||||
;; Keys aren't in plain
|
|
||||||
|
|
||||||
(defn encrypt-data
|
|
||||||
([text] (encrypt-data text secret-key iv))
|
|
||||||
([text key iv]
|
|
||||||
(-> (codecs/str->bytes text)
|
|
||||||
(crypto/encrypt key iv)
|
|
||||||
(codecs/bytes->b64-str))))
|
|
||||||
|
|
||||||
(defn decrypt-data
|
|
||||||
([b64] (decrypt-data b64 secret-key iv))
|
|
||||||
([b64 key iv]
|
|
||||||
(-> (codecs/b64->bytes b64)
|
|
||||||
(crypto/decrypt key iv)
|
|
||||||
(codecs/bytes->str))))
|
|
||||||
|
|
||||||
;;;; API KEYS
|
|
||||||
|
|
||||||
(def DEV_KEY "RGAPI-ec3779d1-bc61-4a2e-a071-34addcc6bd56")
|
|
||||||
(def LOL_KEY "jXL+gA3LIeBPBvrOhLOYSZCiURC7eOtwMXahkxtwpdj6JDtT5NMu25zMz+UY2+9MuHBADjUJh46jSanrV5OBag==")
|
|
||||||
(def TFT_KEY (encrypt-data DEV_KEY secret-key iv))
|
|
||||||
|
|
||||||
(defn get-lol-api-key
|
|
||||||
"Get the API key from the LOL_API environment variable"
|
|
||||||
([key]
|
|
||||||
(if (some? key) key (get-lol-api-key)))
|
|
||||||
([]
|
|
||||||
(let [k (System/getenv "LOL_API")]
|
|
||||||
(if (some? k) k (decrypt-data LOL_KEY secret-key iv)))))
|
|
||||||
|
|
||||||
(defn get-tft-api-key
|
|
||||||
"Get the API key from the TFT_API environment variable"
|
|
||||||
([key]
|
|
||||||
(if (some? key) key (get-tft-api-key)))
|
|
||||||
([]
|
|
||||||
(let [k (System/getenv "TFT_API")]
|
|
||||||
(if (some? k) k (decrypt-data TFT_KEY secret-key iv)))))
|
|
||||||
|
|
||||||
|
|
||||||
;;;; MATCH DATA RESPONSE PARSER
|
|
||||||
|
|
||||||
;; Parsers takes data from a response, and builds a map with standardized keys
|
|
||||||
|
|
||||||
;; Builds a json-data object
|
|
||||||
(defn make-json-data
|
|
||||||
[json-key hash-key & [fn-value]]
|
|
||||||
(if (some? fn-value)
|
|
||||||
{:json-key json-key :hash-key hash-key :fn-value fn-value}
|
|
||||||
{:json-key json-key :hash-key hash-key :fn-value #(identity %)}))
|
|
||||||
|
|
||||||
;; Postprocess functions
|
|
||||||
(defn post-calculate-end
|
|
||||||
[match & _]
|
|
||||||
(assoc match :end
|
|
||||||
(+ (:start match) (* 1000 (int (:duration match))))))
|
|
||||||
|
|
||||||
; Winner?
|
|
||||||
|
|
||||||
(defn pos-in-col
|
|
||||||
"Find the indexes of an element inside a collection.
|
|
||||||
If there are multiple ocurrences, there will be multiple indexes in the result.
|
|
||||||
If the collection is a map, keys are returned"
|
|
||||||
[col x]
|
|
||||||
(reduce-kv (fn [m k v]
|
|
||||||
(if (= v x)
|
|
||||||
(conj m k)
|
|
||||||
m))
|
|
||||||
[] col))
|
|
||||||
|
|
||||||
|
|
||||||
(defn get-player-info
|
|
||||||
[match-resp puuid]
|
|
||||||
(let [participants (get-in match-resp [:metadata :participants])
|
|
||||||
idx (first (pos-in-col participants puuid))
|
|
||||||
player-info (get-in match-resp [:info :participants idx])]
|
|
||||||
player-info))
|
|
||||||
|
|
||||||
|
|
||||||
(defn winner?
|
|
||||||
[match-resp puuid]
|
|
||||||
(:win (get-player-info match-resp puuid)))
|
|
||||||
|
|
||||||
|
|
||||||
(defn post-calculate-win
|
|
||||||
[data response puuid]
|
|
||||||
(assoc data :winner (winner? response puuid)))
|
|
||||||
|
|
||||||
|
|
||||||
(defn with-winner-status
|
|
||||||
"Takes the original list of matches and adds winner info"
|
|
||||||
[matches puuid]
|
|
||||||
(map #(assoc % :winner (winner? % puuid)) matches))
|
|
||||||
|
|
||||||
|
|
||||||
;; json adapters
|
|
||||||
(def player-info-parser {:parser [(make-json-data [:puuid] :puuid)]})
|
|
||||||
|
|
||||||
(def lol-match-parser {:parser [(make-json-data [:info :gameCreation] :start)
|
|
||||||
(make-json-data [:info :gameEndTimestamp] :end)
|
|
||||||
(make-json-data [:info :gameDuration] :duration)
|
|
||||||
;; (make-json-data [:none] :active (constantly false))
|
|
||||||
(make-json-data [:none] :game-type (constantly "lol"))
|
|
||||||
(make-json-data [:metadata :matchId] :id)
|
|
||||||
(make-json-data [:none] :winner (constantly false))
|
|
||||||
(make-json-data [:info :endOfGameResult] :result)]
|
|
||||||
:post post-calculate-win})
|
|
||||||
|
|
||||||
(def tft-match-parser {:parser [(make-json-data [:info :gameCreation] :start)
|
|
||||||
(make-json-data [:none] :end (constantly -1))
|
|
||||||
(make-json-data [:info :game_length] :duration #(int %)) ; rounds to integer
|
|
||||||
;; (make-json-data [:none] :active (constantly false))
|
|
||||||
(make-json-data [:none] :game-type (constantly "tft"))
|
|
||||||
(make-json-data [:metadata :match_id] :id)
|
|
||||||
(make-json-data [:none] :winner (constantly false))
|
|
||||||
(make-json-data [:info :endOfGameResult] :result)]
|
|
||||||
:post #(post-calculate-win
|
|
||||||
(post-calculate-end %1 %2 %3) %2 %3)}) ; end = start + (duration * 1000)
|
|
||||||
|
|
||||||
(def lol-current-parser {:parser [(make-json-data [:gameStartTime] :start)
|
|
||||||
(make-json-data [:none] :end (constantly nil))
|
|
||||||
(make-json-data [:gameLength] :duration)
|
|
||||||
;; (make-json-data [:none] :active (constantly true))
|
|
||||||
(make-json-data [:none] :game-type (constantly "lol"))
|
|
||||||
(make-json-data [:gameId] :id)
|
|
||||||
(make-json-data [:none] :winner (constantly nil))
|
|
||||||
(make-json-data [:none] :result (constantly nil))]})
|
|
||||||
|
|
||||||
(def tft-current-parser {:parser [(make-json-data [:gameStartTime] :start)
|
|
||||||
(make-json-data [:none] :end (constantly nil))
|
|
||||||
(make-json-data [:gameLength] :duration)
|
|
||||||
;; (make-json-data [:none] :active (constantly true))
|
|
||||||
(make-json-data [:none] :game-type (constantly "tft"))
|
|
||||||
(make-json-data [:gameId] :id)
|
|
||||||
(make-json-data [:none] :winner (constantly nil))
|
|
||||||
(make-json-data [:none] :result (constantly nil))]})
|
|
||||||
|
|
||||||
|
|
||||||
(defn parse-response
|
|
||||||
"Takes a parser and a response and resturns a hasmap with known keys"
|
|
||||||
[parser response puuid]
|
|
||||||
(let [data (into {} (map
|
|
||||||
#(vector
|
|
||||||
(:hash-key %)
|
|
||||||
((:fn-value %) (get-in response (:json-key %))))
|
|
||||||
(:parser parser)))
|
|
||||||
postfn (:post parser)]
|
|
||||||
(if (some? postfn)
|
|
||||||
(postfn data response puuid)
|
|
||||||
data)))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defn create-endpoint
|
|
||||||
"Create a URL for the API"
|
|
||||||
[server & parts]
|
|
||||||
(apply str "https://" server "." API-HOST parts))
|
|
||||||
|
|
||||||
|
|
||||||
(defn raw-get-query
|
|
||||||
"Send a query to the API and parsers the result"
|
|
||||||
[url & {:keys [api-key params debug]
|
|
||||||
:or {params nil
|
|
||||||
debug false}}]
|
|
||||||
(when debug (println "** SENDING REQUEST **"))
|
|
||||||
(log/trace "Sending request. Params: " params)
|
|
||||||
;; (println "Params: " params)
|
|
||||||
(:body (client/get url
|
|
||||||
{:debug debug
|
|
||||||
:save-request? true
|
|
||||||
:headers {:X-Riot-Token api-key}
|
|
||||||
:query-params (when (map? params) params)
|
|
||||||
:as :json})))
|
|
||||||
|
|
||||||
|
|
||||||
(defn query
|
|
||||||
"Send a query to the API and parsers the result"
|
|
||||||
[url parser & {:keys [puuid api-key params debug]
|
|
||||||
:or {api-key nil
|
|
||||||
params nil
|
|
||||||
debug false}}]
|
|
||||||
(parse-response parser (raw-get-query url :api-key api-key :params params :debug debug) puuid))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;;;; MAIN QUERY FUNCTIONS
|
|
||||||
|
|
||||||
(defn get-puuid-from-name
|
|
||||||
"Get player's PUUID from its name and tag"
|
|
||||||
[playername tag & {:keys [api-key debug server]
|
|
||||||
:or {debug false
|
|
||||||
server "europe"}}]
|
|
||||||
(:puuid (raw-get-query
|
|
||||||
(create-endpoint server "/riot/account/v1/accounts/by-riot-id/" playername "/" tag)
|
|
||||||
:api-key api-key
|
|
||||||
:debug debug)))
|
|
||||||
|
|
||||||
|
|
||||||
(defn date-to-seconds
|
|
||||||
([] (date-to-seconds (java.util.Date.)))
|
|
||||||
([d]
|
|
||||||
(when (some? d) (quot (.getTime d) 1000))))
|
|
||||||
|
|
||||||
|
|
||||||
(defn query-params
|
|
||||||
"Calculate query params"
|
|
||||||
[& {:keys [count start since until]
|
|
||||||
:or {count 100}}]
|
|
||||||
(cond-> {"count" count}
|
|
||||||
(some? start) (assoc "start" start)
|
|
||||||
(some? since) (assoc "startTime" (date-to-seconds since))
|
|
||||||
(some? until) (assoc "endTime" (date-to-seconds until))))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defn get-lol-matches
|
|
||||||
"Get last LoL match-ids for a given PUUID"
|
|
||||||
[puuid & {:keys [api-key debug server count start since until]
|
|
||||||
:or {api-key (get-lol-api-key)
|
|
||||||
debug false
|
|
||||||
server "europe"
|
|
||||||
count 20
|
|
||||||
start 0}
|
|
||||||
:as params}]
|
|
||||||
;; (println "get lol start: " start)
|
|
||||||
(log/trace "Getting list of LOL matches. Params: " params)
|
|
||||||
(raw-get-query
|
|
||||||
(create-endpoint server "/lol/match/v5/matches/by-puuid/" puuid "/ids")
|
|
||||||
:api-key api-key
|
|
||||||
:params (query-params :count count :start start :since since :until until)
|
|
||||||
:debug debug))
|
|
||||||
|
|
||||||
|
|
||||||
(defn get-tft-matches
|
|
||||||
"Get last TFT match-ids for a given PUUID"
|
|
||||||
[puuid & {:keys [api-key debug server count start since until]
|
|
||||||
:or {api-key (get-tft-api-key)
|
|
||||||
debug false
|
|
||||||
server "europe"
|
|
||||||
count 20
|
|
||||||
start 0}
|
|
||||||
:as params}]
|
|
||||||
(log/trace "Getting list of TFT matches. Params: " params)
|
|
||||||
(raw-get-query
|
|
||||||
(create-endpoint server "/tft/match/v1/matches/by-puuid/" puuid "/ids")
|
|
||||||
:api-key api-key
|
|
||||||
:params (query-params :count count :start start :since since :until until)
|
|
||||||
:debug debug))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defn get-lol-match-info
|
|
||||||
"Get info for a LoL match"
|
|
||||||
[match-id & {:keys [api-key debug server puuid]
|
|
||||||
:or {api-key (get-lol-api-key)
|
|
||||||
debug false
|
|
||||||
server "europe"}}]
|
|
||||||
;; (println "get-lol-match-info match:" match-id)
|
|
||||||
(log/debug "Getting data for LOL match " match-id)
|
|
||||||
(query
|
|
||||||
(create-endpoint server "/lol/match/v5/matches/" match-id)
|
|
||||||
lol-match-parser
|
|
||||||
:api-key api-key
|
|
||||||
:debug debug
|
|
||||||
:puuid puuid))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defn get-tft-match-info
|
|
||||||
"Get info for a TFT match"
|
|
||||||
[match-id & {:keys [api-key debug server puuid]
|
|
||||||
:or {api-key (get-tft-api-key)
|
|
||||||
debug false
|
|
||||||
server "europe"}}]
|
|
||||||
;; (println "get-tft-match-info match:" match-id)
|
|
||||||
(log/debug "Getting data for TFT match " match-id)
|
|
||||||
(query
|
|
||||||
(create-endpoint server "/tft/match/v1/matches/" match-id)
|
|
||||||
tft-match-parser
|
|
||||||
:api-key api-key
|
|
||||||
:debug debug
|
|
||||||
:puuid puuid))
|
|
||||||
|
|
||||||
|
|
||||||
#_{:clj-kondo/ignore [:unresolved-symbol]}
|
|
||||||
(defn get-lol-current-info
|
|
||||||
"Get current LoL match, if any"
|
|
||||||
[puuid & {:keys [api-key debug print-not-active server]
|
|
||||||
:or {api-key (get-lol-api-key)
|
|
||||||
debug false
|
|
||||||
print-not-active false
|
|
||||||
server "euw1"}}]
|
|
||||||
(log/debug "Getting data for current LOL match")
|
|
||||||
(when (some? api-key)
|
|
||||||
(try+
|
|
||||||
(query
|
|
||||||
(create-endpoint server "/lol/spectator/v5/active-games/by-summoner/" puuid)
|
|
||||||
lol-current-parser
|
|
||||||
:api-key api-key
|
|
||||||
:debug debug)
|
|
||||||
(catch [:status 404] _
|
|
||||||
(when print-not-active (println "No active LoL match"))))))
|
|
||||||
|
|
||||||
|
|
||||||
#_{:clj-kondo/ignore [:unresolved-symbol]}
|
|
||||||
(defn get-tft-current-info
|
|
||||||
"Get current TFT match, if any"
|
|
||||||
[puuid & {:keys [api-key debug print-not-active server]
|
|
||||||
:or {api-key (get-tft-api-key)
|
|
||||||
debug false
|
|
||||||
print-not-active false
|
|
||||||
server "euw1"}}]
|
|
||||||
(log/debug "Getting data for current TFT match")
|
|
||||||
(when (some? api-key)
|
|
||||||
(try+
|
|
||||||
(query
|
|
||||||
(create-endpoint server "/lol/spectator/tft/v5/active-games/by-puuid/" puuid)
|
|
||||||
tft-current-parser
|
|
||||||
:api-key api-key
|
|
||||||
:debug debug)
|
|
||||||
(catch [:status 404] _
|
|
||||||
(when print-not-active (println "No active tft match"))))))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defn is-playing?
|
|
||||||
"Checks if player is in and active LoL or TFT match"
|
|
||||||
[lol-puuid tft-puuid & {:keys [lol-api-key tft-api-key debug server print-not-active]
|
|
||||||
:or {lol-api-key (get-lol-api-key)
|
|
||||||
tft-api-key (get-tft-api-key)
|
|
||||||
debug false
|
|
||||||
print-not-active false
|
|
||||||
server "euw1"}}]
|
|
||||||
(or (some? (get-lol-current-info lol-puuid :api-key lol-api-key :server server :debug debug :print-not-active print-not-active))
|
|
||||||
(some? (get-tft-current-info tft-puuid :api-key tft-api-key :server server :debug debug :print-not-active print-not-active))))
|
|
||||||
|
|
||||||
|
|
||||||
(defn get-last-matches
|
|
||||||
"Get info for last LoL or tft matches"
|
|
||||||
[lol-puuid tft-puuid & {:keys [lol-api-key tft-api-key include-current print-not-active debug server1 server2 count start order-by since until]
|
|
||||||
:or {lol-api-key (get-lol-api-key)
|
|
||||||
tft-api-key (get-tft-api-key)
|
|
||||||
include-current true
|
|
||||||
print-not-active false
|
|
||||||
debug false
|
|
||||||
server1 "europe"
|
|
||||||
server2 "euw1"
|
|
||||||
count 20
|
|
||||||
start 0
|
|
||||||
order-by :start}}]
|
|
||||||
(sort-by order-by
|
|
||||||
(filter some?
|
|
||||||
(concat
|
|
||||||
(map
|
|
||||||
#(get-lol-match-info % :api-key lol-api-key :debug debug :server server1 :puuid lol-puuid)
|
|
||||||
(get-lol-matches lol-puuid :api-key lol-api-key :debug debug :server server1 :count count :start start :since since :until until))
|
|
||||||
(map
|
|
||||||
#(get-tft-match-info % :api-key tft-api-key :debug debug :server server1 :puuid tft-puuid)
|
|
||||||
(get-tft-matches tft-puuid :api-key tft-api-key :debug debug :server server1 :count count :start start :since since :until until))
|
|
||||||
(when include-current [(get-lol-current-info lol-puuid :api-key lol-api-key :server server2 :debug debug :print-not-active print-not-active)])
|
|
||||||
(when include-current [(get-tft-current-info tft-puuid :api-key tft-api-key :server server2 :debug debug :print-not-active print-not-active)])))))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;;;; Get data bulk
|
|
||||||
#_{:clj-kondo/ignore [:unresolved-symbol]}
|
|
||||||
(defn get-with-wait
|
|
||||||
"Calls a getter and waits for response. If rate limit has been exceeded, waits for some
|
|
||||||
seconds and retries."
|
|
||||||
[getter & {:keys [wait-limit-exceeded]
|
|
||||||
:or {wait-limit-exceeded 15}}]
|
|
||||||
(try+
|
|
||||||
(getter) ;; Executes getter function
|
|
||||||
(catch [:status 429] _
|
|
||||||
(println "Rate limit exceeded, waiting for" wait-limit-exceeded "seconds")
|
|
||||||
(Thread/sleep (* 1000 wait-limit-exceeded))
|
|
||||||
(get-with-wait getter))))
|
|
||||||
|
|
||||||
|
|
||||||
(defn get-batch-range
|
|
||||||
"Gets data in batches. Getter should be a function with one argument"
|
|
||||||
[getter & {:keys [wait-limit-exceeded first-batch max-batches]
|
|
||||||
:or {wait-limit-exceeded 15
|
|
||||||
first-batch 0
|
|
||||||
max-batches 10}}]
|
|
||||||
;; (println "Obtaining bulk data - range")
|
|
||||||
(log/debug "Getting data in " max-batches " batches")
|
|
||||||
(doall (flatten (concat
|
|
||||||
(map
|
|
||||||
#(get-with-wait (partial getter %) :wait-limit-exceeded wait-limit-exceeded)
|
|
||||||
(range first-batch max-batches))))))
|
|
||||||
|
|
||||||
|
|
||||||
(defn get-batch-seq
|
|
||||||
"Gets data from a secquence. The getter should be a function with one argument"
|
|
||||||
[getter seq & {:keys [wait-limit-exceeded]
|
|
||||||
:or {wait-limit-exceeded 15}}]
|
|
||||||
;; (println "Obtaining bulk data - seq")
|
|
||||||
(doall (flatten (concat
|
|
||||||
(map
|
|
||||||
#(get-with-wait (partial getter %) :wait-limit-exceeded wait-limit-exceeded)
|
|
||||||
seq)))))
|
|
||||||
|
|
||||||
|
|
||||||
(defn get-matches-batch-lol
|
|
||||||
"Get a lot of LOL match IDs"
|
|
||||||
[puuid api-key & {:keys [server since until wait-limit-exceeded first-batch max-batches count debug]
|
|
||||||
:or {server "europe"
|
|
||||||
wait-limit-exceeded 15
|
|
||||||
first-batch 0
|
|
||||||
max-batches 10
|
|
||||||
count 100
|
|
||||||
debug false}}]
|
|
||||||
(when (every? some? [puuid api-key])
|
|
||||||
(get-batch-range #(get-lol-matches puuid :api-key api-key :start (* count %) :since since :until until :server server :wait-limit-exceeded wait-limit-exceeded :debug debug :count count)
|
|
||||||
:wait-limit-exceeded wait-limit-exceeded
|
|
||||||
:first-batch first-batch
|
|
||||||
:max-batches max-batches)))
|
|
||||||
|
|
||||||
|
|
||||||
(defn get-matches-batch-tft
|
|
||||||
"Get a lot of TFT match IDs"
|
|
||||||
[puuid api-key & {:keys [server since until wait-limit-exceeded first-batch max-batches count debug]
|
|
||||||
:or {server "europe"
|
|
||||||
wait-limit-exceeded 15
|
|
||||||
first-batch 0
|
|
||||||
max-batches 10
|
|
||||||
count 100
|
|
||||||
debug false}}]
|
|
||||||
(when (every? some? [puuid api-key])
|
|
||||||
(get-batch-range #(get-tft-matches puuid :api-key api-key :start (* count %) :since since :until until :server server :wait-limit-exceeded wait-limit-exceeded :debug debug :count count)
|
|
||||||
:wait-limit-exceeded wait-limit-exceeded
|
|
||||||
:first-batch first-batch
|
|
||||||
:max-batches max-batches)))
|
|
||||||
|
|
||||||
|
|
||||||
(defn get-matches-info-batch-lol
|
|
||||||
"Get a lot of LOL matches info"
|
|
||||||
[matches-id puuid api-key & {:keys [server wait-limit-exceeded debug]
|
|
||||||
:or {server "europe"
|
|
||||||
wait-limit-exceeded 15
|
|
||||||
debug false}}]
|
|
||||||
;; (println "Matches: " matches-id)
|
|
||||||
(when (every? some? [matches-id puuid api-key])
|
|
||||||
(get-batch-seq #(get-lol-match-info % :puuid puuid :api-key api-key :server server :wait-limit-exceeded wait-limit-exceeded :debug debug)
|
|
||||||
matches-id
|
|
||||||
:wait-limit-exceeded wait-limit-exceeded)))
|
|
||||||
|
|
||||||
|
|
||||||
(defn get-matches-info-batch-tft
|
|
||||||
"Get a lot of TFT matches info"
|
|
||||||
[matches-id puuid api-key & {:keys [server wait-limit-exceeded debug]
|
|
||||||
:or {server "europe"
|
|
||||||
wait-limit-exceeded 15
|
|
||||||
debug false}}]
|
|
||||||
(when (every? some? [matches-id puuid api-key])
|
|
||||||
(get-batch-seq #(get-tft-match-info % :puuid puuid :api-key api-key :server server :wait-limit-exceeded wait-limit-exceeded :debug debug)
|
|
||||||
matches-id
|
|
||||||
:wait-limit-exceeded wait-limit-exceeded)))
|
|
||||||
|
|
||||||
|
|
||||||
(defn get-matches-info-batch
|
|
||||||
"Get a lot of LOL and TFT matches info"
|
|
||||||
[lol-puuid tft-puuid & {:keys [lol-api-key tft-api-key wait-limit-exceeded debug server server2 count order-by since until include-current]
|
|
||||||
:or {lol-api-key (get-lol-api-key)
|
|
||||||
tft-api-key (get-tft-api-key)
|
|
||||||
wait-limit-exceeded 15
|
|
||||||
debug false
|
|
||||||
server "europe"
|
|
||||||
server2 "euw1"
|
|
||||||
count 100
|
|
||||||
order-by :start
|
|
||||||
include-current true}}]
|
|
||||||
(log/debug "Fetching data in batches")
|
|
||||||
(sort-by order-by
|
|
||||||
(filter some?
|
|
||||||
(concat
|
|
||||||
(get-matches-info-batch-lol (get-matches-batch-lol lol-puuid lol-api-key :wait-limit-exceeded wait-limit-exceeded :debug debug :server server :count count :since since :until until)
|
|
||||||
lol-puuid lol-api-key :debug debug :server server :puuid lol-puuid)
|
|
||||||
(get-matches-info-batch-tft (get-matches-batch-tft tft-puuid tft-api-key :wait-limit-exceeded wait-limit-exceeded :debug debug :server server :count count :since since :until until)
|
|
||||||
tft-puuid tft-api-key :debug debug :server server :puuid lol-puuid)
|
|
||||||
(when include-current [(get-lol-current-info lol-puuid :api-key lol-api-key :server server2 :debug debug)])
|
|
||||||
(when include-current [(get-tft-current-info tft-puuid :api-key tft-api-key :server server2 :debug debug)])))))
|
|
||||||
@@ -1,250 +0,0 @@
|
|||||||
|
|
||||||
;; Parsing data
|
|
||||||
|
|
||||||
(ns riot.data
|
|
||||||
(:import [java.time Instant LocalDate ZoneId Duration]
|
|
||||||
[java.time.format DateTimeFormatter])
|
|
||||||
#_{:clj-kondo/ignore [:refer-all]}
|
|
||||||
(:require [clojure.pprint :as pp]
|
|
||||||
[clojure.string :as str]
|
|
||||||
[cheshire.core :refer :all]
|
|
||||||
[riot.core :refer :all]
|
|
||||||
[clj-commons.format.table :refer [print-table] :as table])
|
|
||||||
(:gen-class))
|
|
||||||
|
|
||||||
|
|
||||||
(def DEFAULT_DATE_TIME_FORMAT "yyyy-MM-dd HH:mm:ss")
|
|
||||||
(def DEFAULT_DATE_FORMAT "yyyy-MM-dd")
|
|
||||||
|
|
||||||
|
|
||||||
;; Parse UNIX time
|
|
||||||
|
|
||||||
(defn unix->ZonedDateTime
|
|
||||||
"Convert from UNIX time in millis, to a ZonedDateTime"
|
|
||||||
[millis]
|
|
||||||
(when (some? millis)
|
|
||||||
(.atZone (Instant/ofEpochMilli millis) (ZoneId/systemDefault))))
|
|
||||||
|
|
||||||
(defn unix->LocalDate
|
|
||||||
"Convert from UNIX time in millis to LocalDate"
|
|
||||||
[millis]
|
|
||||||
(when (some? millis)
|
|
||||||
(.toLocalDate (unix->ZonedDateTime millis))))
|
|
||||||
|
|
||||||
(defn LocalDate->Date
|
|
||||||
"Converts a java.time.LocalDate to an ancient java.util.Date"
|
|
||||||
[localdate]
|
|
||||||
(when (some? localdate)
|
|
||||||
(java.util.Date/from (.toInstant (.atZone (.atStartOfDay localdate) (ZoneId/systemDefault))))))
|
|
||||||
|
|
||||||
(defn str->LocalDate
|
|
||||||
"Parse a yyyy-MM-dd date to java.time.LocalDate"
|
|
||||||
[s]
|
|
||||||
(java.time.LocalDate/parse s (DateTimeFormatter/ofPattern DEFAULT_DATE_FORMAT)))
|
|
||||||
|
|
||||||
(defn str->Date
|
|
||||||
[s]
|
|
||||||
(LocalDate->Date (str->LocalDate s)))
|
|
||||||
|
|
||||||
|
|
||||||
(defn unix->Date
|
|
||||||
[millis]
|
|
||||||
(LocalDate->Date (unix->ZonedDateTime millis)))
|
|
||||||
|
|
||||||
|
|
||||||
(defn format-datetime
|
|
||||||
"Converts a LocalDateTime to its string representation"
|
|
||||||
([dtime] (format-datetime dtime DEFAULT_DATE_TIME_FORMAT))
|
|
||||||
([dtime pattern]
|
|
||||||
(when (and (some? dtime) (some? pattern))
|
|
||||||
(.format (DateTimeFormatter/ofPattern pattern) dtime))))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defn format-datetime-millis
|
|
||||||
"Converts a UNIX time in millis to a string representation"
|
|
||||||
([millis] (format-datetime-millis millis DEFAULT_DATE_TIME_FORMAT))
|
|
||||||
([millis pattern]
|
|
||||||
(when (and (some? millis) (some? pattern))
|
|
||||||
(format-datetime (unix->ZonedDateTime millis) pattern))))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;; Parse durations
|
|
||||||
(defn format-duration-seconds
|
|
||||||
"Converts a duration in seconds to a string with hours, minutes and seconds"
|
|
||||||
[seconds]
|
|
||||||
(when (some? seconds)
|
|
||||||
(if (< seconds 3600)
|
|
||||||
(format "%02d:%02d" (quot seconds 60) (rem seconds 60))
|
|
||||||
(format "%02d:%02d:%02d"
|
|
||||||
(quot seconds 3600)
|
|
||||||
(- (quot seconds 60) (* 60 (quot seconds 3600)))
|
|
||||||
(rem seconds 60)))))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defn today-millis
|
|
||||||
"Epoch time in millis for 00:00:00 of today"
|
|
||||||
[]
|
|
||||||
(* 1000 (. (. (LocalDate/now) atStartOfDay (ZoneId/systemDefault)) toEpochSecond)))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defn match-today?
|
|
||||||
"Predicate that is true if the match has been played today.
|
|
||||||
|
|
||||||
A match has been played today if its start date or end date is from today"
|
|
||||||
[match]
|
|
||||||
(or
|
|
||||||
(>= (or (:start match) 0) (today-millis))
|
|
||||||
(>= (or (:end match) 0) (today-millis))))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;; Parse hashmaps
|
|
||||||
|
|
||||||
(defn with-parsed-dates
|
|
||||||
"Takes the original list of matches and parses dates"
|
|
||||||
[matches & {:keys [datetime-format]
|
|
||||||
:or {datetime-format DEFAULT_DATE_TIME_FORMAT}}]
|
|
||||||
(->> matches
|
|
||||||
(map #(update % :start (fn [x] (format-datetime-millis x datetime-format))))
|
|
||||||
(map #(update % :end (fn [x] (format-datetime-millis x datetime-format))))))
|
|
||||||
|
|
||||||
|
|
||||||
(defn with-parsed-durations
|
|
||||||
"Takes the original list of matches and parses durations"
|
|
||||||
[matches]
|
|
||||||
(map #(update % :duration format-duration-seconds) matches))
|
|
||||||
|
|
||||||
|
|
||||||
(defn with-parsed-dates-durations
|
|
||||||
"Takes the original list of matches and parses dates and durations"
|
|
||||||
[matches & {:keys [datetime-format]
|
|
||||||
:or {datetime-format DEFAULT_DATE_TIME_FORMAT}}]
|
|
||||||
(-> matches
|
|
||||||
(with-parsed-durations)
|
|
||||||
(with-parsed-dates :datetime-format datetime-format)))
|
|
||||||
|
|
||||||
|
|
||||||
;;; Export to other formats
|
|
||||||
|
|
||||||
(def headers [[:game-type "Type"]
|
|
||||||
[:start "Start"]
|
|
||||||
[:end "End"]
|
|
||||||
[:duration "Duration"]
|
|
||||||
[:active "Now playing?"]])
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(defn as-json
|
|
||||||
"Take a list with matches and parse it as a JSON string"
|
|
||||||
[matches & {:keys [pretty]
|
|
||||||
:or {pretty true}}]
|
|
||||||
|
|
||||||
(generate-string matches {:pretty pretty}))
|
|
||||||
|
|
||||||
|
|
||||||
(defn as-ascii-table
|
|
||||||
"Export as ascii table"
|
|
||||||
[matches]
|
|
||||||
(pp/print-table matches))
|
|
||||||
|
|
||||||
|
|
||||||
(defn as-pretty-table
|
|
||||||
"Export as an ANSI coloured text table"
|
|
||||||
[matches]
|
|
||||||
(if (and (some? matches) (< 0 (count matches)))
|
|
||||||
(let [columns {:columns (-> (first matches) keys vec)
|
|
||||||
:style table/default-style}]
|
|
||||||
(print-table columns matches))
|
|
||||||
(println "No data available")))
|
|
||||||
|
|
||||||
|
|
||||||
(defn as-csv
|
|
||||||
"Export as CSV"
|
|
||||||
([matches] (as-csv matches ","))
|
|
||||||
([matches separator]
|
|
||||||
(str/join (System/lineSeparator) ; Local EOL characteres
|
|
||||||
(concat
|
|
||||||
[(clojure.string/join separator (map name (keys (first matches))))] ; header
|
|
||||||
(map #(clojure.string/join separator %)
|
|
||||||
(map vals matches))))))
|
|
||||||
|
|
||||||
|
|
||||||
(defn calculate-num-days-played
|
|
||||||
[matches]
|
|
||||||
(count (partition-by #(unix->LocalDate (:start %)) matches))
|
|
||||||
)
|
|
||||||
|
|
||||||
(defn calculate-days-played
|
|
||||||
[matches]
|
|
||||||
(map #(.toString %) (sort (keys (group-by #(unix->LocalDate (:start %)) matches)))))
|
|
||||||
|
|
||||||
(defn calculate-total-seconds-played
|
|
||||||
[matches]
|
|
||||||
(reduce + (filter some? (map :duration matches))))
|
|
||||||
|
|
||||||
(defn calculate-seconds-played-per-day
|
|
||||||
[matches]
|
|
||||||
)
|
|
||||||
|
|
||||||
(defn calculate-statistics
|
|
||||||
"Calculate several statistics about the matches"
|
|
||||||
[matches]
|
|
||||||
(when (and (some? matches) (seq matches))
|
|
||||||
(let [matches-lol (filter #(= (:game-type %) "lol") matches)
|
|
||||||
matches-tft (filter #(= (:game-type %) "tft") matches)
|
|
||||||
total (count matches)
|
|
||||||
total-lol (count matches-lol)
|
|
||||||
total-tft (count matches-tft)
|
|
||||||
win (count (filter :winner matches))
|
|
||||||
win-lol (count (filter :winner matches-lol))
|
|
||||||
win-tft (count (filter :winner matches-tft))
|
|
||||||
loss (- total win)
|
|
||||||
loss-lol (- total-lol win-lol)
|
|
||||||
loss-tft (- total-tft win-tft)
|
|
||||||
win-percent (if (zero? total) 0 (* (/ win total) 100.0))
|
|
||||||
win-percent-lol (if (zero? total-lol) 0 (* (/ win-lol total-lol) 100.0))
|
|
||||||
win-percent-tft (if (zero? total-tft) 0 (* (/ win-tft total-tft) 100.0))
|
|
||||||
num-days-played (calculate-num-days-played matches)
|
|
||||||
num-days-played-lol (calculate-num-days-played matches-lol)
|
|
||||||
num-days-played-tft (calculate-num-days-played matches-tft)
|
|
||||||
days-played (calculate-days-played matches)
|
|
||||||
days-played-lol (calculate-days-played matches-lol)
|
|
||||||
days-played-tft (calculate-days-played matches-tft)
|
|
||||||
seconds-played (calculate-total-seconds-played matches)
|
|
||||||
seconds-played-lol (calculate-total-seconds-played matches-lol)
|
|
||||||
seconds-played-tft (calculate-total-seconds-played matches-tft)
|
|
||||||
seconds-per-day (if (zero? num-days-played) 0 (/ seconds-played num-days-played))
|
|
||||||
seconds-per-day-lol (if (zero? num-days-played-lol) 0 (/ seconds-played-lol num-days-played-lol))
|
|
||||||
seconds-per-day-tft (if (zero? num-days-played-tft) 0 (/ seconds-played-tft num-days-played-tft))]
|
|
||||||
{:total {:all total
|
|
||||||
:lol total-lol
|
|
||||||
:tft total-tft}
|
|
||||||
:win {:all win
|
|
||||||
:lol win-lol
|
|
||||||
:tft win-tft}
|
|
||||||
:loss {:all loss
|
|
||||||
:lol loss-lol
|
|
||||||
:tft loss-tft}
|
|
||||||
:win-percent {:all win-percent
|
|
||||||
:lol win-percent-lol
|
|
||||||
:tft win-percent-tft}
|
|
||||||
:num-days-played {:all num-days-played
|
|
||||||
:lol num-days-played-lol
|
|
||||||
:tft num-days-played-tft}
|
|
||||||
:days-played {:all days-played
|
|
||||||
:lol days-played-lol
|
|
||||||
:tft days-played-tft}
|
|
||||||
:time-played {:all (format-duration-seconds seconds-played)
|
|
||||||
:lol (format-duration-seconds seconds-played-lol)
|
|
||||||
:tft (format-duration-seconds seconds-played-tft)}
|
|
||||||
:played-per-day {:all (format-duration-seconds (int seconds-per-day))
|
|
||||||
:lol (format-duration-seconds (int seconds-per-day-lol))
|
|
||||||
:tft (format-duration-seconds (int seconds-per-day-tft))}})))
|
|
||||||
|
|
||||||
(comment
|
|
||||||
(calculate-statistics '({:winner true} {:winner false} {:winner true}))
|
|
||||||
)
|
|
||||||
@@ -1,301 +0,0 @@
|
|||||||
(ns riot.core-test
|
|
||||||
{:clj-kondo/ignore [:unresolved-symbol]}
|
|
||||||
#_{:clj-kondo/ignore [:refer-all]}
|
|
||||||
(:require [clojure.test :refer :all]
|
|
||||||
[riot.test-examples :refer :all]
|
|
||||||
[riot.core :refer :all]
|
|
||||||
[timewords.core :refer [parse]]
|
|
||||||
[clojure.pprint :as pp]
|
|
||||||
[slingshot.slingshot :refer [try+]]))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;; Tests encryption and decryption of data
|
|
||||||
(deftest test-encryption
|
|
||||||
(println "* Testing encryption *")
|
|
||||||
(let [orig "secret"
|
|
||||||
enc "Dbokabdn7We5iisgONMlfQZKCjqTaGKmuThA8PaNeO8="]
|
|
||||||
(testing "Cypher a text"
|
|
||||||
(is (= "Dbokabdn7We5iisgONMlfQZKCjqTaGKmuThA8PaNeO8=" (encrypt-data orig))))
|
|
||||||
(testing "Decypher a text"
|
|
||||||
(is (= "secret" (decrypt-data enc))))
|
|
||||||
(testing "Cypher and decypher"
|
|
||||||
(is (= orig (decrypt-data (encrypt-data orig)))))))
|
|
||||||
|
|
||||||
|
|
||||||
;; NOTE: we can't test getting API from environment
|
|
||||||
;; Please, unset LOL_KEY or TFT_KEY from your environment before launch tests
|
|
||||||
(deftest test-get-apis
|
|
||||||
(println "* Testing how to get apis *")
|
|
||||||
(testing "Get LOL API key"
|
|
||||||
(is (= (decrypt-data LOL_KEY) (get-lol-api-key)))
|
|
||||||
(is (= (decrypt-data LOL_KEY) (get-lol-api-key nil)))
|
|
||||||
(is (= "abc" (get-lol-api-key "abc"))))
|
|
||||||
(testing "Get TFT API key"
|
|
||||||
;; (is (= (decrypt-data TFT_KEY) (get-tft-api-key)))
|
|
||||||
;; (is (= (decrypt-data TFT_KEY) (get-tft-api-key nil)))
|
|
||||||
(is (= "abc" (get-tft-api-key "abc")))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Make JSON data
|
|
||||||
(deftest test-make-json-data
|
|
||||||
(println "* Testing make-json-data *")
|
|
||||||
(testing "Default fn-value"
|
|
||||||
(are [exp res]
|
|
||||||
(= (select-keys [:json-key :hash-key] exp) (select-keys [:json-key :hash-key] res))
|
|
||||||
{:json-key "key1" :hash-key "key2"} (make-json-data "key1" "key2")
|
|
||||||
{:json-key :key1 :hash-key :key2} (make-json-data :key1 :key2)
|
|
||||||
{:json-key nil :hash-key nil} (make-json-data nil nil)))
|
|
||||||
(testing "With fn-value"
|
|
||||||
(are [exp res] (= exp res)
|
|
||||||
{:json-key "key1" :hash-key "key2" :fn-value +} (make-json-data "key1" "key2" +)
|
|
||||||
{:json-key :key1 :hash-key :key2 :fn-value +} (make-json-data :key1 :key2 +)
|
|
||||||
{:json-key nil :hash-key nil :fn-value +} (make-json-data nil nil +))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Parse a response
|
|
||||||
(deftest test-parse-response
|
|
||||||
(println "* Parse resonse from a query *")
|
|
||||||
(is (= (select-keys response-player-info [:puuid]) (parse-response player-info-parser response-player-info nil))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Find the index of an element inside a collection
|
|
||||||
(deftest test-pos-in-col
|
|
||||||
(println "* Testin index inside a collection *")
|
|
||||||
(testing "Nil values"
|
|
||||||
(is (= [] (pos-in-col nil "abc")))
|
|
||||||
(is (= [] (pos-in-col ["a" "b" "c"] nil))))
|
|
||||||
(testing "Vectors"
|
|
||||||
(is (= [2] (pos-in-col [3 1 2 4 1 5] 2)))
|
|
||||||
(is (= [1 4] (pos-in-col [3 1 2 4 1 5] 1)))
|
|
||||||
(is (= [] (pos-in-col [3 1 2 4 1 5] 9))))
|
|
||||||
(testing "Secuences"
|
|
||||||
(is (= [2] (pos-in-col (clojure.string/split "3 1 2 4 1 5" #" ") "2")))
|
|
||||||
(is (= [1 4] (pos-in-col (clojure.string/split "3 1 2 4 1 5" #" ") "1")))
|
|
||||||
(is (= [] (pos-in-col (clojure.string/split "3 1 2 4 1 5" #" ") "9"))))
|
|
||||||
(testing "Maps"
|
|
||||||
(is (= [:c] (pos-in-col {:a 3 :b 1 :c 2 :d 4 :e 1 :f 5} 2)))
|
|
||||||
(is (= [:b :e] (pos-in-col {:a 3 :b 1 :c 2 :d 4 :e 1 :f 5} 1)))
|
|
||||||
(is (= [] (pos-in-col {:a 3 :b 1 :c 2 :d 4 :e 1 :f 5} 9)))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Create a URL
|
|
||||||
(deftest test-create-endpoint
|
|
||||||
(println "* Testing create URL for a remote endpoint *")
|
|
||||||
(testing "Simple URL"
|
|
||||||
(are [exp res] (= exp res)
|
|
||||||
"https://test.api.riotgames.com" (create-endpoint "test")
|
|
||||||
"https://.api.riotgames.com" (create-endpoint "")
|
|
||||||
"https://.api.riotgames.com" (create-endpoint nil)))
|
|
||||||
(println "* Testing create URL for a remote endpoint *")
|
|
||||||
(testing "Complex URL"
|
|
||||||
(are [exp res] (= exp res)
|
|
||||||
"https://test.api.riotgames.compath" (create-endpoint "test" "path")
|
|
||||||
"https://test.api.riotgames.com/path" (create-endpoint "test" "/path")
|
|
||||||
"https://.api.riotgames.com" (create-endpoint "" "")
|
|
||||||
"https://.api.riotgames.com" (create-endpoint nil nil)
|
|
||||||
"https://test.api.riotgames.com/path/id?query" (create-endpoint "test" "/path/" "id" "?query"))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Make a raw HTML GET query
|
|
||||||
(deftest test-raw-get-query
|
|
||||||
(println "* Testing get raw data from Riot API *")
|
|
||||||
(testing "Get user data raw"
|
|
||||||
(is (= response-player-info (raw-get-query "https://europe.api.riotgames.com/riot/account/v1/accounts/by-riot-id/Errepunto/4595" :api-key (get-lol-api-key))))
|
|
||||||
(is (some? (raw-get-query "https://europe.api.riotgames.com/lol/match/v5/matches/EUW1_7434497430" :api-key (get-lol-api-key))))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Make a query and parse result with a parser
|
|
||||||
(deftest test-query
|
|
||||||
(println "* Testing get parsed data from Riot API *")
|
|
||||||
(testing "Get user data parsed"
|
|
||||||
(is (= (select-keys response-player-info [:puuid]) (query "https://europe.api.riotgames.com/riot/account/v1/accounts/by-riot-id/Errepunto/4595" player-info-parser :api-key (get-lol-api-key))))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Get PUUID
|
|
||||||
(deftest test-get-puuid-from-name
|
|
||||||
(println "* Get PUUID from user name and tag *")
|
|
||||||
(testing "Get PUUID using lol api"
|
|
||||||
(is (= (:puuid response-player-info) (get-puuid-from-name "Errepunto" "4595" :api-key (get-lol-api-key))))
|
|
||||||
; THROWS EXCEPTION ;(is (= nil (get-puuid-from-name "Not_existing" "" :api-key (decrypt-data LOL_KEY))))
|
|
||||||
))
|
|
||||||
|
|
||||||
(comment (get-puuid-from-name example-name example-tag :api-key (get-tft-api-key)))
|
|
||||||
|
|
||||||
;; From java.util.Date to seconds since 1970
|
|
||||||
(deftest ^:timezone test-date-to-seconds
|
|
||||||
(println "* Date to epoch seconds *")
|
|
||||||
(testing "Some dates"
|
|
||||||
(is (nil? (date-to-seconds nil)))
|
|
||||||
(is (some? (date-to-seconds)))
|
|
||||||
(is (= 1738364400 (date-to-seconds (java.util.Date. 125 1 1))))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Get parameter for querying data
|
|
||||||
(deftest ^:timezone test-query-params
|
|
||||||
(println "* Generate query params *")
|
|
||||||
(testing "None params"
|
|
||||||
(is (= {"count" 100} (query-params))))
|
|
||||||
(testing "Start and count"
|
|
||||||
(is (= {"count" 5 "start" 2} (query-params :count 5 :start 2))))
|
|
||||||
(testing "Times"
|
|
||||||
(is (= {"count" 100 "startTime" 1743631200} (query-params :since (java.util.Date. 125 3 3))))
|
|
||||||
(is (= {"count" 100 "startTime" 1743631200 "endTime" 1744236000} (query-params :since (java.util.Date. 125 3 3) :until (java.util.Date. 125 3 10))))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Get LOL matches from PUUID
|
|
||||||
(deftest test-get-lol-matches
|
|
||||||
(println "* Getting LOL matches *")
|
|
||||||
(testing "Famous player"
|
|
||||||
(let [res (get-lol-matches example-lol-puuid :count 5)]
|
|
||||||
(is (seq? res))
|
|
||||||
(is (= 5 (count res)))
|
|
||||||
(is (some? (get-lol-matches example-lol-puuid :since (java.util.Date. 2025 1 1) :until (java.util.Date. 2025 1 31))))))
|
|
||||||
(testing "Never played"
|
|
||||||
(let [res (get-lol-matches example-lol-never-played :count 5)]
|
|
||||||
(is (seq? res))
|
|
||||||
(is (= 0 (count res))))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Get TFT matches from PUUID
|
|
||||||
;; I NEED A PRODUCTION KEY FIRST
|
|
||||||
(comment
|
|
||||||
(deftest test-get-tft-matches
|
|
||||||
(println "* Getting FTF matches *")
|
|
||||||
(testing "Famous player"
|
|
||||||
(let [res (get-tft-matches example-tft-puuid :count 5)]
|
|
||||||
(is (seq? res))
|
|
||||||
(is (= 5 (count res)))))
|
|
||||||
(testing "Never played"
|
|
||||||
(let [res (get-tft-matches example-tft-never-played :count 5)]
|
|
||||||
(is (seq? res))
|
|
||||||
(is (= 0 (count res)))))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Get info from one LOL match
|
|
||||||
(deftest test-get-lol-match-info
|
|
||||||
(println "* Getting one LOL match info *")
|
|
||||||
(let [res (get-lol-match-info "EUW1_7434497430" :puuid example-lol-puuid)]
|
|
||||||
(is (some? res))
|
|
||||||
(is (= example-lol-match res))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Get info from one TFT match
|
|
||||||
;; I NEED A PRODUCTION KEY FIRST
|
|
||||||
(comment
|
|
||||||
(deftest test-get-tft-match-info
|
|
||||||
(println "* Getting one TFT match info *")
|
|
||||||
(let [res (get-tft-match-info "EUW1_7420994275")]
|
|
||||||
(is (some? res))
|
|
||||||
(is (= example-tft-match res)))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Get current LOL playing info
|
|
||||||
;; RESULTS DEPENDS ON PLAYER IS ACTIVE OR NOT
|
|
||||||
(deftest test-get-lol-current-info
|
|
||||||
(println "* Get info from current LOL match *")
|
|
||||||
(let [res (get-lol-current-info example-lol-puuid)]
|
|
||||||
(is (nil? res) (str "Oh, well, the player is playing: " res))) ;; Data only when player is playing.
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
;; Get current LOL playing info
|
|
||||||
;; RESULTS DEPENDS ON PLAYER IS ACTIVE OR NOT
|
|
||||||
;; I NEED A PRODUCTION KEY FIRST
|
|
||||||
(comment
|
|
||||||
(deftest test-get-tft-current-info
|
|
||||||
(println "* Get info from current TFT match *")
|
|
||||||
(let [res (get-tft-current-info example-tft-puuid)]
|
|
||||||
(is (nil? res) (str "Oh, well, the player is playing: " res))) ;; Data only when player is playing.
|
|
||||||
))
|
|
||||||
|
|
||||||
|
|
||||||
;; Check if the player is currently in a match
|
|
||||||
;; RESULTS DEPENDS ON PLAYER IS ACTIVE OR NOT
|
|
||||||
;; I NEED A PRODUCTION KEY FIRST
|
|
||||||
(comment
|
|
||||||
(deftest test-is-playing?
|
|
||||||
(println "* Check player is playing *")
|
|
||||||
(let [res (is-playing? example-lol-puuid example-tft-puuid)]
|
|
||||||
(is (not res) (str "Oh, well, the player is playing: " res))) ;; Data only when player is playing.
|
|
||||||
))
|
|
||||||
|
|
||||||
|
|
||||||
;; Get last LOL and TFT matches
|
|
||||||
;; RESULTS DEPENDS ON PLAYER IS ACTIVE OR NOT
|
|
||||||
(comment
|
|
||||||
(deftest test-get-last-matches
|
|
||||||
(println "* Get last mateches *")
|
|
||||||
(testing "Don't include current"
|
|
||||||
(let [res (is-playing? example-lol-puuid example-tft-puuid :include-current false)]
|
|
||||||
(is (not res) (str "Oh, well, the player is playing: " res))))
|
|
||||||
(testing "Include current"
|
|
||||||
(let [res (is-playing? example-lol-puuid example-tft-puuid)]
|
|
||||||
(is (not res) (str "Oh, well, the player is playing: " res))))))
|
|
||||||
|
|
||||||
|
|
||||||
(deftest test-get-matches-batch-lol
|
|
||||||
(println "* Get lol matches batch *")
|
|
||||||
(testing "Invalid data"
|
|
||||||
(is (= nil (get-matches-batch-lol nil nil)))
|
|
||||||
(is (= nil (get-matches-batch-lol example-lol-puuid nil)))
|
|
||||||
(is (= nil (get-matches-batch-lol nil (get-lol-api-key)))))
|
|
||||||
(testing "Get LOL matches"
|
|
||||||
(is (= 10 (count (get-matches-batch-lol example-lol-puuid (get-lol-api-key) :count 5 :max-batches 2))))))
|
|
||||||
|
|
||||||
(deftest ^:tft test-get-matches-batch-tft
|
|
||||||
(println "* Get tft matches batch *")
|
|
||||||
(testing "Invalid data"
|
|
||||||
(is (= nil (get-matches-batch-tft nil nil)))
|
|
||||||
(is (= nil (get-matches-batch-tft example-tft-puuid nil)))
|
|
||||||
(is (= nil (get-matches-batch-tft nil (get-tft-api-key)))))
|
|
||||||
(testing "Get LOL matches"
|
|
||||||
(is (= 10 (count (get-matches-batch-tft example-tft-puuid (get-tft-api-key) :count 5 :max-batches 2))))))
|
|
||||||
|
|
||||||
|
|
||||||
(deftest test-get-matches-info-batch-lol
|
|
||||||
(println "* Get lol matches info batch *")
|
|
||||||
(testing "Invalid data"
|
|
||||||
(is (= nil (get-matches-info-batch-lol nil nil nil)))
|
|
||||||
(is (= nil (get-matches-info-batch-lol nil example-lol-puuid nil)))
|
|
||||||
(is (= nil (get-matches-info-batch-lol nil nil (get-lol-api-key)))))
|
|
||||||
(testing "Get LOL matches"
|
|
||||||
(is (= 10 (count (get-matches-info-batch-lol
|
|
||||||
(get-matches-batch-lol example-lol-puuid (get-lol-api-key) :count 5 :max-batches 2)
|
|
||||||
example-lol-puuid
|
|
||||||
(get-lol-api-key)))))))
|
|
||||||
|
|
||||||
|
|
||||||
(deftest ^:tft test-get-matches-info-batch-tft
|
|
||||||
(println "* Get tft matches info batch *")
|
|
||||||
(testing "Invalid data"
|
|
||||||
(is (= nil (get-matches-info-batch-tft nil nil nil)))
|
|
||||||
(is (= nil (get-matches-info-batch-tft nil example-tft-puuid nil)))
|
|
||||||
(is (= nil (get-matches-info-batch-tft nil nil (get-tft-api-key)))))
|
|
||||||
(testing "Get tft matches"
|
|
||||||
(is (= 10 (count (get-matches-info-batch-tft
|
|
||||||
(get-matches-batch-tft example-tft-puuid (get-tft-api-key) :count 5 :max-batches 2)
|
|
||||||
example-tft-puuid
|
|
||||||
(get-tft-api-key)))))))
|
|
||||||
|
|
||||||
|
|
||||||
(comment
|
|
||||||
(def matches-lol (get-matches-batch-lol
|
|
||||||
example-lol-puuid
|
|
||||||
(get-lol-api-key)
|
|
||||||
:since (parse "since 5 days") :debug false :count 100 :max-batches 20))
|
|
||||||
|
|
||||||
(count matches-lol) ;; Todos los obtenidos
|
|
||||||
|
|
||||||
(count (set matches-lol)) ;; Esto cuenta sólo los únicos
|
|
||||||
|
|
||||||
(def matches-info (get-matches-info-batch-lol (take 200 matches-lol) example-lol-puuid (get-lol-api-key) :debug false))
|
|
||||||
|
|
||||||
(count matches-info)
|
|
||||||
(count (set matches-info))
|
|
||||||
|
|
||||||
(try+
|
|
||||||
(get-matches-info-batch example-lol-puuid example-tft-puuid)
|
|
||||||
(catch [:status 404] {:keys [request-time headers body] :as excp}
|
|
||||||
(println "NOT Found 404")
|
|
||||||
(pp/pprint excp))))
|
|
||||||
@@ -1,179 +0,0 @@
|
|||||||
(ns riot.data-test
|
|
||||||
(:require [clojure.test :refer :all]
|
|
||||||
[clojure.pprint :as pp]
|
|
||||||
[riot.test-examples :refer :all]
|
|
||||||
[riot.data :refer :all]
|
|
||||||
[riot.core :refer :all])
|
|
||||||
(:import [java.time Instant LocalDate ZoneId Duration ZonedDateTime]
|
|
||||||
[java.time.format DateTimeFormatter]))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;; Convert from epoch in millis (1970-01-01 00:00:00) to ZonedDateTime
|
|
||||||
(deftest ^:timezone test-unix->ZonedDateTime
|
|
||||||
(println "* Epoch millis to java.util.Datetime *")
|
|
||||||
(testing "Synthetic data"
|
|
||||||
(is (= (ZonedDateTime/of 2025 4 3 0 0 0 0 (ZoneId/systemDefault))
|
|
||||||
(unix->ZonedDateTime 1743631200000)))))
|
|
||||||
|
|
||||||
|
|
||||||
(deftest ^:timezone test-unix->LocalDate
|
|
||||||
(println "* Epoch millis to java.time.LocalDate *")
|
|
||||||
(testing "Synthetic data"
|
|
||||||
(is (= (LocalDate/of 2025 4 3) (unix->LocalDate 1743631200000)))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
;; Format a LocalDateTime o ZonedDateTime as a String
|
|
||||||
(deftest ^:timezone test-unix->ZonedDateTime
|
|
||||||
(println "* DateTime to String *")
|
|
||||||
(testing "Null"
|
|
||||||
(is (nil? (format-datetime-millis nil))))
|
|
||||||
(testing "Default format"
|
|
||||||
(is (= "2025-04-03 00:00:00"
|
|
||||||
(format-datetime (unix->ZonedDateTime 1743631200000)))))
|
|
||||||
(testing "Personalized time formats"
|
|
||||||
(is (= "2025-04-03"
|
|
||||||
(format-datetime (unix->ZonedDateTime 1743631200000) "yyyy-MM-dd")))
|
|
||||||
(is (= "00:00"
|
|
||||||
(format-datetime (unix->ZonedDateTime 1743631200000) "HH:00")))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Format a epoch in millis as a String
|
|
||||||
(deftest ^:timezone test-datetime-millis
|
|
||||||
(println "* DateTime to String *")
|
|
||||||
(testing "Null"
|
|
||||||
(is (nil? (format-datetime-millis nil))))
|
|
||||||
(testing "Default format"
|
|
||||||
(is (= "2025-04-03 00:00:00"
|
|
||||||
(format-datetime-millis 1743631200000))))
|
|
||||||
(testing "Personalized time formats"
|
|
||||||
(is (= "2025-04-03"
|
|
||||||
(format-datetime-millis 1743631200000 "yyyy-MM-dd")))
|
|
||||||
(is (= "00:00"
|
|
||||||
(format-datetime-millis 1743631200000 "HH:00")))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Format a duration in seconds to minutes and seconds
|
|
||||||
(deftest test-format-duration-seconds
|
|
||||||
(println "* Duration in seconds to string *")
|
|
||||||
(testing "Nil duration"
|
|
||||||
(is (nil? (format-duration-seconds nil))))
|
|
||||||
(testing "Short durations"
|
|
||||||
(is (= "00:01" (format-duration-seconds 1)))
|
|
||||||
(is (= "01:01" (format-duration-seconds 61)))
|
|
||||||
(is (= "59:59" (format-duration-seconds 3599))))
|
|
||||||
(testing "Long durations"
|
|
||||||
(is (= "01:00:00" (format-duration-seconds 3600)))
|
|
||||||
(is (= "01:00:01" (format-duration-seconds 3601)))
|
|
||||||
(is (= "01:01:01" (format-duration-seconds 3661)))
|
|
||||||
(is (= "05:53:09" (format-duration-seconds 21189)))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
;; Epoch in millis for today at 00:00:00 hours. Difficult to test
|
|
||||||
(deftest ^:timezone test-today-millis
|
|
||||||
(println "* Epoch for today *")
|
|
||||||
(testing "Epoch for today"
|
|
||||||
(is (some? (today-millis)))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Match has been played today
|
|
||||||
(deftest test-match-today?
|
|
||||||
(println "* Has the match been played today? *")
|
|
||||||
(testing "Start date today"
|
|
||||||
(is (match-today? {:start (today-millis)}))
|
|
||||||
(is (match-today? {:start (+ 5000 (today-millis))})))
|
|
||||||
(testing "End date today"
|
|
||||||
(is (match-today? {:end (today-millis)}))
|
|
||||||
(is (match-today? {:end (+ 5000 (today-millis))}))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Parse dates inside a lis of matches
|
|
||||||
(deftest ^:timezone test-with-parsed-dates
|
|
||||||
(println "* Parse dates in a match list*")
|
|
||||||
(testing "Empty or invalid lists"
|
|
||||||
(is (= '() (with-parsed-dates '())))
|
|
||||||
(is (= '({:start nil, :end nil}) (with-parsed-dates '({}))))
|
|
||||||
(is (= '({:a "AAA" :b 2 :start nil, :end nil}) (with-parsed-dates '({:a "AAA" :b 2})))))
|
|
||||||
(testing "Valid list"
|
|
||||||
(is (= '({:start "2025-06-11 19:00:54", :end nil, :duration 1288, :active true, :game-type "lol", :id "EUW1_111111"})
|
|
||||||
(with-parsed-dates (take 1 matches-example))))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Parse durations
|
|
||||||
(deftest ^:timezone test-with-parsed-durations
|
|
||||||
(println "* Parse durations in a match list *")
|
|
||||||
(testing "Empty or invalid lists"
|
|
||||||
(is (= '() (with-parsed-durations '())))
|
|
||||||
(is (= '({:duration nil}) (with-parsed-durations '({}))))
|
|
||||||
(is (= '({:a "AAA" :b 2 :duration nil}) (with-parsed-durations '({:a "AAA" :b 2})))))
|
|
||||||
(testing "Valid list"
|
|
||||||
(is (= '({:start 1749661254854, :end nil, :duration "21:28", :active true, :game-type "lol", :id "EUW1_111111"})
|
|
||||||
(with-parsed-durations (take 1 matches-example))))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Parse dates and durations
|
|
||||||
(deftest ^:timezone test-with-parsed-dates-durations
|
|
||||||
(println "* Parse dates and durations in a match list *")
|
|
||||||
(testing "Empty or invalid lists"
|
|
||||||
(is (= '() (with-parsed-dates-durations '())))
|
|
||||||
(is (= '({:duration nil, :start nil, :end nil})
|
|
||||||
(with-parsed-dates-durations '({}))))
|
|
||||||
(is (= '({:a "AAA" :b 2 :duration nil, :start nil, :end nil})
|
|
||||||
(with-parsed-dates-durations '({:a "AAA" :b 2})))))
|
|
||||||
(testing "Valid list"
|
|
||||||
(is (= '({:start "2025-06-11 19:00:54", :end nil, :duration "21:28", :winner true, :game-type "lol", :id "EUW1_111111", :result "GameComplete"})
|
|
||||||
(with-parsed-dates-durations (take 1 matches-example))))))
|
|
||||||
|
|
||||||
|
|
||||||
;; Pretty table
|
|
||||||
(deftest test-as-pretty-table
|
|
||||||
(println "* Generates a pretty table *")
|
|
||||||
(testing "Some examples, printed to System.out"
|
|
||||||
(is (= nil (as-pretty-table [])))
|
|
||||||
(is (= nil (as-pretty-table nil)))
|
|
||||||
(is (= nil (as-pretty-table matches-example)))
|
|
||||||
(is (= nil (as-pretty-table matches-example2)))))
|
|
||||||
|
|
||||||
|
|
||||||
(deftest test-calculate-statistics
|
|
||||||
(println "* Calculate statistics *")
|
|
||||||
(testing "Simple check"
|
|
||||||
(is (nil? (calculate-statistics nil)))
|
|
||||||
(is (nil? (calculate-statistics '())))
|
|
||||||
(is (map? (calculate-statistics matches-example)))
|
|
||||||
(is (map? (calculate-statistics matches-example2))))
|
|
||||||
(let [data (calculate-statistics matches-example)]
|
|
||||||
(testing "With manual generated data"
|
|
||||||
(is (= 5 (get-in data [:total :all])))
|
|
||||||
(is (= 3 (get-in data [:total :lol])))
|
|
||||||
(is (= 2 (get-in data [:total :tft])))
|
|
||||||
(is (= 3 (get-in data [:win :all])))
|
|
||||||
(is (= 2 (get-in data [:loss :all])))
|
|
||||||
(is (= 60.0 (get-in data [:win-percent :all])))
|
|
||||||
(is (= 3 (get-in data [:num-days-played :all]))))))
|
|
||||||
|
|
||||||
|
|
||||||
(comment
|
|
||||||
matches-example
|
|
||||||
|
|
||||||
(.toLocalDate (unix->ZonedDateTime 1749661254854))
|
|
||||||
|
|
||||||
(partition-by #(unix->LocalDate (:start %)) matches-example)
|
|
||||||
(group-by #(unix->LocalDate (:start %)) matches-example)
|
|
||||||
|
|
||||||
(keys (group-by #(unix->LocalDate (:start %)) matches-example2))
|
|
||||||
|
|
||||||
(calculate-days-played matches-example2)
|
|
||||||
|
|
||||||
(reduce + (filter some? (map :duration matches-example)))
|
|
||||||
|
|
||||||
(calculate-statistics matches-example)
|
|
||||||
|
|
||||||
(calculate-statistics matches-example2)
|
|
||||||
|
|
||||||
(pp/pprint (calculate-statistics matches-example2))
|
|
||||||
)
|
|
||||||
File diff suppressed because it is too large
Load Diff
6
tests.edn
Normal file
6
tests.edn
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#kaocha/v1
|
||||||
|
{:tests [{:test-paths ["projects/core/src" "projects/core/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"
|
||||||
|
}}
|
||||||
Reference in New Issue
Block a user