Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 33d69c2ed3 | |||
| a808515c1d | |||
| b1c87b1adf | |||
| af895a5173 | |||
| 7d71c48536 | |||
| deb8746347 | |||
| c449beac80 | |||
| f3166ceaa5 | |||
| 22cb492bbc | |||
| 79e4b5b99b | |||
| e3742971dc | |||
| ce48d37d86 | |||
| 7f0eadff2f | |||
| 88d6405fb6 | |||
| dee8935f9c | |||
| 284b9342ce | |||
| a09c0f86d5 | |||
| ee6245d77a | |||
| bd1dc3190c | |||
| a1fe5ff70c | |||
| d1e036bdcf | |||
| 5455d1e2f1 | |||
| 055d72129a | |||
| 1ec2749319 | |||
| 70190d3cc9 | |||
| 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
|
||||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -7,12 +7,15 @@ 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
|
||||||
*.svg
|
*.svg
|
||||||
/logs
|
/logs
|
||||||
|
# Native executable
|
||||||
|
riot
|
||||||
|
# A weid link
|
||||||
|
/bin/*
|
||||||
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>
|
|
||||||
139
README.md
139
README.md
@@ -1,88 +1,36 @@
|
|||||||
# 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
|
# The API and the tokens
|
||||||
can obtain a developer key from https://developer.riotgames.com/. Developer keys
|
|
||||||
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
|
Accessing the API requires one or more API tokens. Each videogame has their own
|
||||||
`LOL_API` and `TFT_API`. If you prefer to provide the key via parameter, you must use `--lol-api-key` or
|
group of endpoints, secured with an API. Development APIs can access to all
|
||||||
`--tft-api-key` parameters.
|
andpoints, but they must be refreshed every 24 hours.
|
||||||
|
|
||||||
## Features
|
You can obtain a token for free in the [official developer web](https://developer.riotgames.com/).
|
||||||
|
|
||||||
Those features are implemented in v1.1
|
The library and the application will take the API token from environment. CLI application
|
||||||
|
has optional parameters that override the environment variables.
|
||||||
|
|
||||||
* Call the API with development or production keys
|
| Game | Environment variable | CLI parameter |
|
||||||
* Get a list of matches
|
| ---------- | -------------------- | ------------- |
|
||||||
* Get matches between two dates
|
| all | `RIOT_DEV_KEY` | `--dev-key` |
|
||||||
* Check if player is currently playing
|
| LOL | `RIOT_LOL_KEY` | `--lol-key` |
|
||||||
* Show the match's data in several formats:
|
| TFT | `RIOT_TFT_KEY` | `--tft-key` |
|
||||||
* Fancy ASCII table (by default)
|
*more to came*
|
||||||
* 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
|
# Usage
|
||||||
|
## CLI
|
||||||
Goals for version 1.1:
|
### Installation
|
||||||
|
|
||||||
* [x] Simplify CLI options and parameters
|
|
||||||
* [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 +41,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,11 +62,48 @@ 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
|
||||||
|
* [ ] Distribute CLI as self executable (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
|
||||||
|
* [x] Format raw data
|
||||||
|
|
||||||
|
### CLI
|
||||||
|
* [x] Rich and easy to use CLI
|
||||||
|
* [x] Basic parameters for log level and override API tokens
|
||||||
|
* [x] Obtain basic player info
|
||||||
|
* [x] Last games for player (LOL, TFT and others)
|
||||||
|
* [x] Is the player playing just now?
|
||||||
|
* [x] Contiuosly check if the player es playing
|
||||||
|
* [x] Format output as fancy table
|
||||||
|
* [x] Format output as CSV
|
||||||
|
* [x] Format output as JSON
|
||||||
|
* [x] Calculte basic statistics
|
||||||
|
* [ ] Calculate advanced statistics: win strike, adversaries, etc.
|
||||||
|
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2025 ruben
|
Copyright (c) 2026 ruben
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
|||||||
44
build.clj
Normal file
44
build.clj
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
(ns build
|
||||||
|
(:require [clojure.tools.build.api :as b]))
|
||||||
|
|
||||||
|
(def lib 'es.rcorral/riot-clojure)
|
||||||
|
(def version (format "2.0.%s" (b/git-count-revs nil))) ;; or read from file, etc
|
||||||
|
(def class-dir "target/classes")
|
||||||
|
(def src-dirs ["src"])
|
||||||
|
(def jar-file (format "target/%s-%s.jar" (name lib) version))
|
||||||
|
(def uber-file (format "target/%s-%s-standalone.jar" (name lib) version))
|
||||||
|
(def main-ns "riot.app")
|
||||||
|
|
||||||
|
;; delay to defer side effects (artifact downloads)
|
||||||
|
(def basis (delay (b/create-basis {:project "deps.edn"})))
|
||||||
|
|
||||||
|
(defn clean [_]
|
||||||
|
(b/delete {:path "target"}))
|
||||||
|
|
||||||
|
(defn jar [_]
|
||||||
|
(b/write-pom {:class-dir class-dir
|
||||||
|
:lib lib
|
||||||
|
:version version
|
||||||
|
:basis @basis
|
||||||
|
:src-dirs ["src"]})
|
||||||
|
(b/copy-dir {:src-dirs ["src" "resources"]
|
||||||
|
:target-dir class-dir})
|
||||||
|
(b/jar {:class-dir class-dir
|
||||||
|
:jar-file jar-file}))
|
||||||
|
|
||||||
|
(defn uber
|
||||||
|
"Build a uberjar with all dependencies included"
|
||||||
|
[_]
|
||||||
|
(b/delete {:path class-dir})
|
||||||
|
(b/copy-dir {:src-dirs src-dirs
|
||||||
|
:target-dir class-dir})
|
||||||
|
(b/copy-dir {:src-dirs src-dirs
|
||||||
|
:target-dir class-dir})
|
||||||
|
(b/compile-clj {:basis @basis
|
||||||
|
:src-dirs src-dirs
|
||||||
|
:class-dir class-dir})
|
||||||
|
(b/uber {:class-dir class-dir
|
||||||
|
:uber-file uber-file
|
||||||
|
:basis @basis
|
||||||
|
:main main-ns})
|
||||||
|
(println "Generated uberjar executable:" uber-file))
|
||||||
60
deps.edn
Executable file
60
deps.edn
Executable file
@@ -0,0 +1,60 @@
|
|||||||
|
{:paths ["src" "test" "resources"]
|
||||||
|
|
||||||
|
:deps {org.clojure/clojure {:mvn/version "1.12.1"}
|
||||||
|
;; https://juxt.github.io/tick/
|
||||||
|
tick/tick {:mvn/version "1.0"}
|
||||||
|
;; https://github.com/lambdaisland/cli
|
||||||
|
com.lambdaisland/cli {:mvn/version "1.27.121"}
|
||||||
|
;; https://github.com/tokenmill/timewords
|
||||||
|
lt.tokenmill/timewords {:mvn/version "0.5.0"}
|
||||||
|
;; https://github.com/clj-commons/pretty
|
||||||
|
org.clj-commons/pretty {:mvn/version "3.6.8"}
|
||||||
|
;; https://github.com/babashka/http-client
|
||||||
|
org.babashka/http-client {:mvn/version "0.4.22"}
|
||||||
|
;; https://github.com/dakrone/cheshire?tab=readme-ov-file
|
||||||
|
cheshire/cheshire {:mvn/version "6.1.0"}
|
||||||
|
;; https://git.rcorral.es/ruben/clojure-utils
|
||||||
|
rcorral/clojure-utils {:git/url "https://git.rcorral.es/ruben/clojure-utils"
|
||||||
|
:git/tag "v0.2.0"
|
||||||
|
:sha "4b1a7b1bc28b88ada871262806b8c4f3c000426f"}
|
||||||
|
;; https://cljdoc.org/d/com.github.clj-easy/graal-build-time/1.0.5/doc/readme
|
||||||
|
com.github.clj-easy/graal-build-time {:mvn/version "1.0.5"}}
|
||||||
|
|
||||||
|
:aliases {;; Execute the app.
|
||||||
|
:run {:main-opts ["-m" "riot.app"]}
|
||||||
|
|
||||||
|
;; 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"}}
|
||||||
|
:ns-default build
|
||||||
|
:exec-fn jar}
|
||||||
|
|
||||||
|
;; Build uber jar for CLI app
|
||||||
|
:uber {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
|
||||||
|
:ns-default build
|
||||||
|
:exec-fn uber}
|
||||||
|
|
||||||
|
;; Conjure / cider connector
|
||||||
|
:repl/conjure {:extra-deps {nrepl/nrepl {:mvn/version "1.0.0"}
|
||||||
|
cider/cider-nrepl {:mvn/version "0.42.1"}}
|
||||||
|
:main-opts ["--main" "nrepl.cmdline"
|
||||||
|
"--middleware" "[cider.nrepl/cider-middleware]"
|
||||||
|
"--interactive"]}
|
||||||
|
|
||||||
|
;; Native image. You must link your native-image executable to a relative path: bin/native-executable
|
||||||
|
:native-image {:main-opts ["--main" "clj.native-image" "riot.app"
|
||||||
|
"--enable-url-protocols=http,https"
|
||||||
|
"--report-unsupported-elements-at-runtime"
|
||||||
|
"--initialize-at-build-time"
|
||||||
|
"-H:Name=riot"]
|
||||||
|
:jvm-opts ["-Dclojure.compiler.direct-linking=true"]
|
||||||
|
:extra-deps {taylorwood/clj.native-image
|
||||||
|
{:git/url "https://github.com/taylorwood/clj.native-image.git"
|
||||||
|
:sha "5227df16ead1fef7cddd94e6853d810e7d08579b"}}}
|
||||||
|
}}
|
||||||
|
|
||||||
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})
|
|
||||||
@@ -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>
|
|
||||||
340
src/riot/app.clj
340
src/riot/app.clj
@@ -1,260 +1,114 @@
|
|||||||
|
|
||||||
;; Main CLI application
|
|
||||||
|
|
||||||
(ns riot.app
|
(ns riot.app
|
||||||
(:require [cli-matic.core :refer [run-cmd]]
|
#_{:clj-kondo/ignore [:refer-all]}
|
||||||
[cli-matic.utils :as U]
|
(:require [rcorral.api.core :refer :all]
|
||||||
[clojure.pprint :as pp]
|
[riot.commands :refer :all]
|
||||||
[clojure.string :as str]
|
[riot.riot-api :refer :all]
|
||||||
[timewords.core :refer [parse]]
|
[lambdaisland.cli :as cli]
|
||||||
[clojure.tools.logging :as log]
|
[clojure.pprint :as pp])
|
||||||
)
|
|
||||||
(:use [riot.core]
|
|
||||||
[riot.data]
|
|
||||||
[slingshot.slingshot :only [try+]])
|
|
||||||
(:gen-class))
|
(:gen-class))
|
||||||
|
|
||||||
|
(def VERSION "2.0")
|
||||||
(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 set-keys
|
||||||
(defn cmd-active
|
[params]
|
||||||
"Checks if a player is online at the moment"
|
(when (:dev-key params) (set-riot-api-key :RIOT_DEV_KEY (:dev-key params)))
|
||||||
[& {:keys [lol-api-key tft-api-key debug-http lol tft _arguments]
|
(when (:lol-key params) (set-riot-api-key :RIOT_LOL_KEY (:lol-key params)))
|
||||||
:as opts}]
|
(when (:tft-key params) (set-riot-api-key :RIOT_TFT_KEY (:tft-key params))))
|
||||||
(try+
|
|
||||||
;(println "Check online" opts)
|
(defn check-debug
|
||||||
(let [lol-key (when lol (get-lol-api-key lol-api-key))
|
[params]
|
||||||
tft-key (when tft (get-tft-api-key tft-api-key))
|
(reset! debug (:verbose params))
|
||||||
lol-id (when lol (get-puuid-from-params lol-key _arguments opts))
|
(reset! debug-http (:debug-http params))
|
||||||
tft-id (when tft (get-puuid-from-params tft-key _arguments opts))]
|
(when @debug (pp/pprint params)))
|
||||||
(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"
|
(defn cmd-check-playing-adapter
|
||||||
[output x]
|
[params]
|
||||||
(case output
|
(check-debug params)
|
||||||
"table" (as-ascii-table x)
|
(set-keys params)
|
||||||
"ptable" (as-pretty-table x)
|
(cmd-check-playing (:username params) (:usertag params)
|
||||||
"edn" (pp/pprint x)
|
:lol (:lol params)
|
||||||
"json" (println (as-json x))
|
:tft (:tft params)
|
||||||
"csv" (println (as-csv x))
|
:template (:template params)
|
||||||
(pp/pprint x))) ;edn as default
|
:continuous (:continuous params)
|
||||||
|
:every-seconds (:period params)
|
||||||
|
:max (:max params)
|
||||||
|
:header (:header params)))
|
||||||
|
|
||||||
|
(defn cmd-show-matches-adapter
|
||||||
|
[params]
|
||||||
|
(check-debug params)
|
||||||
|
(set-keys params)
|
||||||
|
(cmd-show-matches (:username params) (:usertag params)
|
||||||
|
:lol (:lol params)
|
||||||
|
:tft (:tft params)
|
||||||
|
:format (:format params)
|
||||||
|
:since (:since params)
|
||||||
|
:until (:until params)
|
||||||
|
:max (:max params)))
|
||||||
|
|
||||||
|
(defn cmd-show-stats-adapter
|
||||||
|
[params]
|
||||||
|
(check-debug params)
|
||||||
|
(set-keys params)
|
||||||
|
(cmd-show-stats (:username params) (:usertag params)
|
||||||
|
:lol (:lol params)
|
||||||
|
:tft (:tft params)
|
||||||
|
:format (:format params)
|
||||||
|
:since (:since params)
|
||||||
|
:until (:until params)
|
||||||
|
:max (:max params)))
|
||||||
|
|
||||||
|
|
||||||
(defn format-dates-cond
|
;;[player-name player-tag & {:keys [lol tft template continuous every-seconds max]
|
||||||
"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))
|
|
||||||
|
|
||||||
|
(def options {:name "riot client"
|
||||||
|
:doc "A CLI client for RIOT api"
|
||||||
|
:commands ["playing <username> <usertag>"
|
||||||
|
{:doc "Check if the player is playing"
|
||||||
|
:command #'cmd-check-playing-adapter
|
||||||
|
:flags ["--[no-]lol" {:doc "Check if playing LOL" :default true}
|
||||||
|
"--[no-]tft" {:doc "Check if playing TFT" :default true}
|
||||||
|
"-t, --template <template>" {:doc "Text template"}
|
||||||
|
"-c, --[no-]continuous" {:doc "Print continuosly" :default false}
|
||||||
|
"-p, --period <seconds>" {:doc "If printing continuosly, period in seconds" :parse parse-long :default 60}
|
||||||
|
"-m, --max <max>" {:doc "If printing continuosly, max number of checks." :parse parse-long :default -1}
|
||||||
|
"--[no-]header" {:doc "If true, print a header over each check" :default true}]}
|
||||||
|
|
||||||
(defn format-duration-cond
|
"matches <username> <usertag>"
|
||||||
"Format durations if specified"
|
{:doc "Show information about matches"
|
||||||
[format-durations x]
|
:command #'cmd-show-matches-adapter
|
||||||
(if format-durations
|
:flags ["--[no-]lol" {:doc "Check if playing LOL" :default true}
|
||||||
(with-parsed-durations x)
|
"--[no-]tft" {:doc "Check if playing TFT" :default true}
|
||||||
x))
|
"-f, --format <ptable|table|edn|edn-full|csv|json>" {:doc "Output format" :parse keyword :default "ptable"}
|
||||||
|
"-s, --since <time>" {:doc "Obtain registries since <time>"}
|
||||||
|
"-u, --until <time>" {:doc "Obtain registries until <time>"}
|
||||||
|
"-m, --max <max>" {:doc "Max number of registries for each game type"}]}
|
||||||
|
|
||||||
|
"stats <username> <usertag>"
|
||||||
|
{:doc "Show statistics about matches"
|
||||||
|
:command #'cmd-show-stats-adapter
|
||||||
|
:flags ["--[no-]lol" {:doc "Check if playing LOL" :default true}
|
||||||
|
"--[no-]tft" {:doc "Check if playing TFT" :default true}
|
||||||
|
"-f, --format <ptable|table|edn|csv>" {:doc "Output format" :parse keyword :default "ptable"}
|
||||||
|
"-s, --since <time>" {:doc "Obtain registries since <time>"}
|
||||||
|
"-u, --until <time>" {:doc "Obtain registries until <time>"}
|
||||||
|
"-m, --max <max>" {:doc "Max number of registries for each game type"}]}
|
||||||
|
]
|
||||||
|
|
||||||
(defn calculate-statistics-cond
|
:flags ["-v, --verbose" "Increases verbosity"
|
||||||
"If true, calculate statistics and print them to console"
|
"--debug-http" "Show HTTP request/response data"
|
||||||
[calculate x]
|
"--dev-key <DEV key>" "Development API key"
|
||||||
(when calculate
|
"--lol-key <LOL key>" "API key for LOL"
|
||||||
(log/info "Calculating statistics")
|
"--tft-key <TFT key>" "API key for TFT"]})
|
||||||
(pp/pprint (calculate-statistics x)))
|
|
||||||
x)
|
|
||||||
|
|
||||||
(defn reverse-cond
|
(defn -main [& args]
|
||||||
"If true, data is ordered from nearest to fartest"
|
(cli/dispatch options args))
|
||||||
[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
|
(comment
|
||||||
; Launch manually
|
|
||||||
(-main)
|
(-main "-v" "--input" "boniato.txt" "position1" "pos2")
|
||||||
)
|
)
|
||||||
|
|||||||
205
src/riot/commands.clj
Normal file
205
src/riot/commands.clj
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
(ns riot.commands
|
||||||
|
#_{:clj-kondo/ignore [:refer-all]}
|
||||||
|
(:require [rcorral.api.core :refer :all]
|
||||||
|
[rcorral.util :refer :all]
|
||||||
|
[rcorral.date-util :refer :all]
|
||||||
|
[riot.riot-api :refer :all]
|
||||||
|
[riot.riot-data :refer :all]
|
||||||
|
[clojure.pprint :as pp]
|
||||||
|
[clojure.string :as s]
|
||||||
|
[clj-commons.format.table :as table]
|
||||||
|
[cheshire.core :as json])
|
||||||
|
(:gen-class))
|
||||||
|
|
||||||
|
(defn cmd-test
|
||||||
|
[params]
|
||||||
|
(println "Options:")
|
||||||
|
(pp/pprint params)
|
||||||
|
(println "Positional args:" (s/join "," (:lambdaisland.cli/argv params))))
|
||||||
|
|
||||||
|
(defn cmd-check-playing
|
||||||
|
"Check if the player is playing right now."
|
||||||
|
[player-name player-tag & {:keys [lol tft template continuous every-seconds max header]
|
||||||
|
:or {lol true
|
||||||
|
tft true
|
||||||
|
template ":formatted-ts - :game: :playing"
|
||||||
|
continuous false
|
||||||
|
every-seconds 60
|
||||||
|
max nil
|
||||||
|
header true}
|
||||||
|
:as params}]
|
||||||
|
(when @debug
|
||||||
|
(println "CMD check playing")
|
||||||
|
(pp/pprint params))
|
||||||
|
(let [check-fn (fn [] (is-playing? player-name player-tag params))
|
||||||
|
task-fn (fn []
|
||||||
|
(when header (println (millis->str (System/currentTimeMillis)) ": Player" (str player-name "#" player-tag)))
|
||||||
|
(let [playing (check-fn)]
|
||||||
|
(run! #(println (replace-map (or template "Playing :game? :playing") %)) playing)
|
||||||
|
playing))]
|
||||||
|
(if continuous
|
||||||
|
(run-every task-fn every-seconds max)
|
||||||
|
(let [playing (task-fn)]
|
||||||
|
(if (some :playing playing)
|
||||||
|
(System/exit 0)
|
||||||
|
(System/exit 1))))))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(reset! debug true)
|
||||||
|
|
||||||
|
(some? (is-playing? "Walid Georgey" "EUW"))
|
||||||
|
|
||||||
|
(cmd-check-playing "Walid Georgey" "EUW") ;; This kills the REPL
|
||||||
|
(cmd-check-playing "Walid Georgey" "EUW" :continuous true :max 2) ;; Infinite loop if max is nil
|
||||||
|
)
|
||||||
|
(defn print-table
|
||||||
|
[matches-data]
|
||||||
|
(let [no-participants (map #(dissoc % :participants) matches-data)
|
||||||
|
formatted (map (comp match-format-dates match-format-durations) no-participants)]
|
||||||
|
(pp/print-table [:id :game :type :start :end :duration :winner :champion :placement]
|
||||||
|
(reverse (sort-by :start formatted)))))
|
||||||
|
|
||||||
|
(defn print-pretty-table
|
||||||
|
[matches-data]
|
||||||
|
(let [no-participants (map #(dissoc % :participants) matches-data)
|
||||||
|
formatted (map (comp match-format-dates match-format-durations) no-participants)]
|
||||||
|
(table/print-table [:id
|
||||||
|
{:key :game :title "Game Type" :align :center :formatter (comp s/upper-case name)}
|
||||||
|
:type
|
||||||
|
:start
|
||||||
|
:end
|
||||||
|
:duration
|
||||||
|
:winner
|
||||||
|
:champion
|
||||||
|
{:key :placement :align :center}]
|
||||||
|
(reverse (sort-by :start formatted)))))
|
||||||
|
|
||||||
|
(defn print-edn
|
||||||
|
[matches-data]
|
||||||
|
(pp/pprint (mapv #(select-keys % [:id :game :type :start :end :duration :winner :champion :placement]) matches-data)))
|
||||||
|
|
||||||
|
(defn print-edn-full
|
||||||
|
[matches-data]
|
||||||
|
(pp/pprint matches-data))
|
||||||
|
|
||||||
|
(defn print-json
|
||||||
|
[matches-data]
|
||||||
|
(println (json/generate-string matches-data {:pretty true})))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(print-json [{:game :lol,
|
||||||
|
:id "EUW1_7673677826",
|
||||||
|
:start 1767732132677,
|
||||||
|
:end 1767733603865,
|
||||||
|
:duration 1471,
|
||||||
|
:type "MATCHED_GAME",
|
||||||
|
:result "GameComplete"
|
||||||
|
:winner true}
|
||||||
|
{:game :tft,
|
||||||
|
:id "EUW1_7674912532",
|
||||||
|
:start 1767819383643,
|
||||||
|
:end 1767821490357,
|
||||||
|
:duration 2106,
|
||||||
|
:type "pairs",
|
||||||
|
:result "GameComplete"
|
||||||
|
:winner false}])
|
||||||
|
)
|
||||||
|
|
||||||
|
(defn print-csv
|
||||||
|
([matches-data]
|
||||||
|
(print-csv matches-data ";"))
|
||||||
|
([matches-data separator]
|
||||||
|
(when-let [m-data (map #(dissoc % :participants) matches-data)]
|
||||||
|
(println (s/join separator (map name (keys (first m-data)))))
|
||||||
|
(run! #(println (s/join separator (vals %))) m-data))))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(print-csv [{:game :lol,
|
||||||
|
:id "EUW1_7673677826",
|
||||||
|
:start 1767732132677,
|
||||||
|
:end 1767733603865,
|
||||||
|
:duration 1471,
|
||||||
|
:type "MATCHED_GAME",
|
||||||
|
:result "GameComplete"
|
||||||
|
:winner true}
|
||||||
|
{:game :tft,
|
||||||
|
:id "EUW1_7674912532",
|
||||||
|
:start 1767819383643,
|
||||||
|
:end 1767821490357,
|
||||||
|
:duration 2106,
|
||||||
|
:type "pairs",
|
||||||
|
:result "GameComplete"
|
||||||
|
:winner false}]
|
||||||
|
":"))
|
||||||
|
|
||||||
|
(defn add-calculated-data
|
||||||
|
[puuid match-data]
|
||||||
|
(-> match-data
|
||||||
|
(assoc :winner (player-won? puuid match-data))
|
||||||
|
(assoc :champion (:champion (filter-by-player puuid match-data)))
|
||||||
|
(assoc :placement (:placement (filter-by-player puuid match-data)))
|
||||||
|
))
|
||||||
|
|
||||||
|
(defn get-matches
|
||||||
|
[player-name player-tag & {:keys [lol tft since until max]
|
||||||
|
:or {lol true
|
||||||
|
tft true}
|
||||||
|
:as params}]
|
||||||
|
(let [call-params (cond-> {}
|
||||||
|
max (assoc :count max)
|
||||||
|
since (assoc :startTime (/ (process-time-literal since) 1000))
|
||||||
|
until (assoc :endTime (/ (process-time-literal until) 1000)))
|
||||||
|
lol-puuid (get-lol-puuid player-name player-tag)
|
||||||
|
tft-puuid (get-tft-puuid player-name player-tag)]
|
||||||
|
(when @debug (println "Params") (pp/pprint call-params))
|
||||||
|
(cond-> []
|
||||||
|
lol (concat (map #(add-calculated-data lol-puuid (get-lol-match-data %))
|
||||||
|
(get-lol-matches lol-puuid call-params)))
|
||||||
|
tft (concat (map #(add-calculated-data tft-puuid (get-tft-match-data %))
|
||||||
|
(get-tft-matches tft-puuid call-params))))))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(reset! debug true)
|
||||||
|
|
||||||
|
(get-matches "Walid Georgey" "EUW" :max 3))
|
||||||
|
|
||||||
|
|
||||||
|
(defn cmd-show-matches
|
||||||
|
"Show basic info about matches played by player"
|
||||||
|
[player-name player-tag & {:keys [format]
|
||||||
|
:or {format :table}
|
||||||
|
:as params}]
|
||||||
|
(when @debug
|
||||||
|
(println "CMD show matches")
|
||||||
|
(pp/pprint params))
|
||||||
|
(let [matches-data (get-matches player-name player-tag params)]
|
||||||
|
;; Then, match data
|
||||||
|
(case format
|
||||||
|
:table (print-table matches-data)
|
||||||
|
:edn (print-edn matches-data)
|
||||||
|
:edn-full (print-edn-full matches-data)
|
||||||
|
:csv (print-csv matches-data)
|
||||||
|
:json (print-json matches-data)
|
||||||
|
:ptable (print-pretty-table matches-data)
|
||||||
|
(do (println "No valid format " format) (System/exit 1)))))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(set-riot-api-key :RIOT_DEV_KEY "RGAPI-bbbed5c8-d4d7-4de4-a7e7-b8366afee5a4")
|
||||||
|
(cmd-show-matches "Walid Georgey" "EUW")
|
||||||
|
(cmd-show-matches "Walid Georgey" "EUW" :since "yesterday" :max 2))
|
||||||
|
|
||||||
|
(defn print-stats
|
||||||
|
[player-name player-tag matches-data]
|
||||||
|
(println "Statistics")
|
||||||
|
(pp/pprint (create-basic-stats player-name player-tag matches-data)))
|
||||||
|
|
||||||
|
(defn cmd-show-stats
|
||||||
|
"Show basic info about matches played by player"
|
||||||
|
[player-name player-tag & {:as params}]
|
||||||
|
(when @debug
|
||||||
|
(println "CMD show stats")
|
||||||
|
(binding [pp/*print-right-margin* 80
|
||||||
|
pp/*print-miser-width* 40]
|
||||||
|
(pp/pprint params)))
|
||||||
|
(let [matches-data (get-matches player-name player-tag params)]
|
||||||
|
(print-stats player-name player-tag matches-data)))
|
||||||
@@ -1,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}))
|
|
||||||
)
|
|
||||||
646
src/riot/riot_api.clj
Normal file
646
src/riot/riot_api.clj
Normal file
@@ -0,0 +1,646 @@
|
|||||||
|
(ns riot.riot-api
|
||||||
|
(:require [rcorral.api.core :refer :all])
|
||||||
|
(:gen-class))
|
||||||
|
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; ADAPT API GENERIC METHODS TO RIOT API
|
||||||
|
;;
|
||||||
|
;; You need to adapt 3 things from the generic core:
|
||||||
|
;; - A method for setting (override) the API key
|
||||||
|
;; - A method for supply the API
|
||||||
|
;; - A wrapper for calling call-api with this API endpoint, and keyprovider
|
||||||
|
;;
|
||||||
|
;; Maps with keys and supported endpoints are in a separated file (riot-data.clj)
|
||||||
|
;;
|
||||||
|
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; API KEYS
|
||||||
|
;;
|
||||||
|
|
||||||
|
(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
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; KEY MANAGEMENT
|
||||||
|
;;
|
||||||
|
|
||||||
|
; Not needed, but useful
|
||||||
|
(def get-riot-api-key (partial get-api-key RIOT-KEYS :RIOT_DEV_KEY))
|
||||||
|
|
||||||
|
; Not used by core, but useful for frontends
|
||||||
|
(def set-riot-api-key (partial set-api-key RIOT-KEYS))
|
||||||
|
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; MAIN API FUNCTIONS
|
||||||
|
;;
|
||||||
|
|
||||||
|
; Key provider for this API
|
||||||
|
(defn riot-key-provider
|
||||||
|
[url params headers] ;; Provider must accept params and headers, but we don't need them
|
||||||
|
(when @debug (println "Getting key for" url))
|
||||||
|
(if-let [api-key (get-riot-api-key (get-in ENDPOINTS [url :api-key]))]
|
||||||
|
;; Return params unmodified and headers with the api header
|
||||||
|
[params (assoc headers "X-Riot-Token" api-key)]
|
||||||
|
(println "No API key found for" url)))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(get-in ENDPOINTS [:lol-status :api-key])
|
||||||
|
|
||||||
|
(riot-key-provider :lol-status {:param1 "1" :param2 "two"} {"Accept" "data"})
|
||||||
|
)
|
||||||
|
|
||||||
|
; Wrapper for ease use of call-api
|
||||||
|
(defn call-riot-api
|
||||||
|
[url & {:as cfg-params}]
|
||||||
|
(call-api ENDPOINTS riot-key-provider url cfg-params))
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; HELPERS
|
||||||
|
;;
|
||||||
|
|
||||||
|
(defn get-lol-puuid
|
||||||
|
"Get PUUID from player's name and tag for LOL endpoints"
|
||||||
|
[player-name player-tag]
|
||||||
|
(:puuid (:value (call-riot-api :lol-account-by-riot-id
|
||||||
|
:path-params {:player-name player-name :player-tag player-tag}))))
|
||||||
|
|
||||||
|
(defn get-tft-puuid
|
||||||
|
"Get PUUID from player's name and tag for TFT endpoints"
|
||||||
|
[player-name player-tag]
|
||||||
|
(:puuid (:value (call-riot-api :tft-account-by-riot-id
|
||||||
|
:path-params {:player-name player-name :player-tag player-tag}))))
|
||||||
|
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; USAGE EXAMPLES
|
||||||
|
;;
|
||||||
|
|
||||||
|
(comment
|
||||||
|
|
||||||
|
(set-riot-api-key :RIOT_DEV_KEY "RGAPI-bbbed5c8-d4d7-4de4-a7e7-b8366afee5a4")
|
||||||
|
(deref (:RIOT_DEV_KEY RIOT-KEYS))
|
||||||
|
|
||||||
|
(call-riot-api :lol-account-by-riot-id :path-params {:player-name "Walid Georgey"
|
||||||
|
:player-tag "EUW"})
|
||||||
|
|
||||||
|
(get-lol-puuid "Walid Georgey" "EUW")
|
||||||
|
|
||||||
|
(get-tft-puuid "Walid Georgey" "EUW")
|
||||||
|
|
||||||
|
;; Examples calling the API
|
||||||
|
(call-riot-api :lol-account-by-puuid
|
||||||
|
:path-params {:puuid "Walid Georgey" :player-tag "EUW"})
|
||||||
|
|
||||||
|
(:value (call-riot-api :lol-status))
|
||||||
|
|
||||||
|
(call-riot-api :champion-mastery-by-puuid
|
||||||
|
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")})
|
||||||
|
|
||||||
|
(call-riot-api :champion-mastery-by-puuid-and-champion
|
||||||
|
:path-params {:championId 45
|
||||||
|
:puuid (get-lol-puuid "Walid Georgey" "EUW")})
|
||||||
|
|
||||||
|
(call-riot-api :champion-mastery-by-puuid-top
|
||||||
|
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")}
|
||||||
|
:query-params {:count 1})
|
||||||
|
|
||||||
|
(call-riot-api :champion-rotations)
|
||||||
|
|
||||||
|
(call-riot-api :summoner-by-puuid
|
||||||
|
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")})
|
||||||
|
|
||||||
|
(call-riot-api :league-all-by-puuid
|
||||||
|
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")})
|
||||||
|
|
||||||
|
(call-riot-api :league-by-id
|
||||||
|
:path-params {:league-id "35642608-b436-48a0-ac0f-b64eb6dfc14e"})
|
||||||
|
|
||||||
|
(call-riot-api :clash-by-puuid
|
||||||
|
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")})
|
||||||
|
|
||||||
|
(call-riot-api :clash-tournaments)
|
||||||
|
|
||||||
|
(call-riot-api :lol-matches-by-puuid
|
||||||
|
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")}
|
||||||
|
:query-params {:count 5})
|
||||||
|
|
||||||
|
(call-riot-api :lol-match-by-id
|
||||||
|
:path-params {:match-id "EUW1_7673677826"})
|
||||||
|
|
||||||
|
(call-riot-api :lol-match-timeline-by-id
|
||||||
|
:path-params {:match-id "EUW1_7673677826"})
|
||||||
|
|
||||||
|
(call-riot-api :lol-challenges-config)
|
||||||
|
|
||||||
|
(call-riot-api :lol-challenge-config-by-id
|
||||||
|
:path-params {:challenge-id 402109})
|
||||||
|
|
||||||
|
(call-riot-api :lol-challenges-percentiles)
|
||||||
|
|
||||||
|
(call-riot-api :lol-challenges-percentiles-by-id
|
||||||
|
:path-params {:challenge-id 402109})
|
||||||
|
|
||||||
|
(call-riot-api :lol-challenge-leaderboard
|
||||||
|
:path-params {:challenge-id 402109
|
||||||
|
:level "CHALLENGER"})
|
||||||
|
|
||||||
|
(call-riot-api :lol-challenge-by-puuid
|
||||||
|
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")})
|
||||||
|
|
||||||
|
(call-riot-api :lol-champion-mastery-by-puuid
|
||||||
|
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")})
|
||||||
|
|
||||||
|
(call-riot-api :lol-champion-mastery-by-puuid-champion
|
||||||
|
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")
|
||||||
|
:champion-id 777})
|
||||||
|
|
||||||
|
(call-riot-api :lol-champion-mastery-by-puuid-top
|
||||||
|
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")}
|
||||||
|
:query-params {:count 5})
|
||||||
|
|
||||||
|
(call-riot-api :lol-champion-mastery-scores-by-puuid
|
||||||
|
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")})
|
||||||
|
|
||||||
|
(call-riot-api :lol-spectator
|
||||||
|
:path-params {:puuid (get-lol-puuid "Walid Georgey" "EUW")})
|
||||||
|
|
||||||
|
;; TFT
|
||||||
|
(call-riot-api :tft-summoner-by-puuid
|
||||||
|
:path-params {:puuid (get-tft-puuid "Walid Georgey" "EUW")})
|
||||||
|
|
||||||
|
(call-riot-api :tft-status)
|
||||||
|
|
||||||
|
(call-riot-api :tft-matches-by-puuid
|
||||||
|
:path-params {:puuid (get-tft-puuid "Walid Georgey" "EUW")})
|
||||||
|
|
||||||
|
(call-riot-api :tft-match-by-id
|
||||||
|
:path-params {:match-id "EUW1_7666482502"})
|
||||||
|
|
||||||
|
(call-riot-api :tft-spectator
|
||||||
|
:path-params {:puuid (get-tft-puuid "Walid Georgey" "EUW")})
|
||||||
|
|
||||||
|
(call-riot-api :tft-league-by-puuid
|
||||||
|
:path-params {:puuid (get-tft-puuid "Walid Georgey" "EUW")})
|
||||||
|
|
||||||
|
(call-riot-api :tft-league-challenger)
|
||||||
|
|
||||||
|
(call-riot-api :tft-league-grandmaster-by-queue)
|
||||||
|
|
||||||
|
(call-riot-api :tft-league-master-by-queue)
|
||||||
|
|
||||||
|
(call-riot-api :tft-league-top-rated-ladders
|
||||||
|
:path-params {:queue "RANKED_TFT_TURBO"})
|
||||||
|
|
||||||
|
(call-riot-api :tft-league-by-league-id
|
||||||
|
:path-params {:league-id "abc"})
|
||||||
|
)
|
||||||
339
src/riot/riot_data.clj
Normal file
339
src/riot/riot_data.clj
Normal file
@@ -0,0 +1,339 @@
|
|||||||
|
(ns riot.riot-data
|
||||||
|
(:require [rcorral.api.core :refer :all]
|
||||||
|
[rcorral.date-util :refer :all]
|
||||||
|
[riot.riot-api :refer :all]
|
||||||
|
[tick.core :as t])
|
||||||
|
(:import [java.util Date])
|
||||||
|
(:gen-class))
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; High functions to work with RIOT API.
|
||||||
|
;;
|
||||||
|
;; This file has a lot of utilities for working with data obtained with the help
|
||||||
|
;; of riot-api's functions
|
||||||
|
|
||||||
|
(def GAME-TYPES #{:lol :tft})
|
||||||
|
|
||||||
|
|
||||||
|
;; Get matches list
|
||||||
|
|
||||||
|
(defn get-lol-matches
|
||||||
|
"Get LOL matches for player"
|
||||||
|
[puuid & {:as params}]
|
||||||
|
;(println "Params:" params)
|
||||||
|
(let [response (call-riot-api :lol-matches-by-puuid
|
||||||
|
:path-params {:puuid puuid}
|
||||||
|
:query-params params)]
|
||||||
|
(if (:success response)
|
||||||
|
(:value response)
|
||||||
|
(do (println "No LOL matches found") response))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn get-tft-matches
|
||||||
|
"Get TFT matches for player"
|
||||||
|
[puuid & {:as params}]
|
||||||
|
;(println "Params:" params)
|
||||||
|
(let [response (call-riot-api :tft-matches-by-puuid
|
||||||
|
:path-params {:puuid puuid}
|
||||||
|
:query-params params)]
|
||||||
|
(if (:success response)
|
||||||
|
(:value response)
|
||||||
|
(do (println "No TFT matches found") response))))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
|
||||||
|
(get-lol-matches (get-lol-puuid "Walid Georgey" "EUW") :count 5)
|
||||||
|
(get-lol-matches (get-lol-puuid "Errepunto" "4595") :count 5)
|
||||||
|
|
||||||
|
(get-tft-matches (get-tft-puuid "Walid Georgey" "EUW") :count 5)
|
||||||
|
(get-tft-matches (get-tft-puuid "Errepunto" "4595") :count 5)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
;; Get matches data
|
||||||
|
|
||||||
|
(defn filter-by-game
|
||||||
|
[game matches]
|
||||||
|
(filter #(= game (:game %)) matches))
|
||||||
|
|
||||||
|
|
||||||
|
(defn filter-by-player
|
||||||
|
[puuid match-data]
|
||||||
|
(first (filter #(= (:puuid %) puuid) (:participants match-data))))
|
||||||
|
|
||||||
|
|
||||||
|
(defn player-won?
|
||||||
|
[puuid match-data]
|
||||||
|
(if (and puuid match-data)
|
||||||
|
(:win (filter-by-player puuid match-data))
|
||||||
|
(do (println "Invalid puuid or match data") false)))
|
||||||
|
|
||||||
|
(defn player-alive?
|
||||||
|
[puuid participants]
|
||||||
|
(let [player-data (first (filter #(= (:puuid %) puuid) participants))
|
||||||
|
max-round (apply max (mapv :last_round participants))]
|
||||||
|
(= (:last_round player-data) max-round)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(defn create-match-data
|
||||||
|
[game matchId participants gameStartTimestamp gameEndTimestamp gameDuration gameType endOfGameResult]
|
||||||
|
{:game game
|
||||||
|
:id matchId
|
||||||
|
:participants participants
|
||||||
|
:start gameStartTimestamp
|
||||||
|
:end gameEndTimestamp
|
||||||
|
:duration gameDuration
|
||||||
|
:type gameType
|
||||||
|
:result endOfGameResult})
|
||||||
|
|
||||||
|
(defn create-participant
|
||||||
|
[puuid championName deaths kills win placement]
|
||||||
|
{:puuid puuid
|
||||||
|
:champion championName
|
||||||
|
:deaths deaths
|
||||||
|
:kills kills
|
||||||
|
:win win
|
||||||
|
:placement placement})
|
||||||
|
|
||||||
|
(defn get-lol-match-data
|
||||||
|
"Get data from a LOL match"
|
||||||
|
[id]
|
||||||
|
(let [response (call-riot-api :lol-match-by-id :path-params {:match-id id})
|
||||||
|
info (get-in response [:value :info])
|
||||||
|
meta (get-in response [:value :metadata])]
|
||||||
|
;(println "Value:" info)
|
||||||
|
(if (:success response)
|
||||||
|
(create-match-data :lol
|
||||||
|
(:matchId meta)
|
||||||
|
(map #(create-participant (:puuid %)
|
||||||
|
(:championName %)
|
||||||
|
(:deaths %)
|
||||||
|
(:kills %)
|
||||||
|
(:win %)
|
||||||
|
(if (:win %) 1 2))
|
||||||
|
(:participants info))
|
||||||
|
(:gameStartTimestamp info)
|
||||||
|
(:gameEndTimestamp info)
|
||||||
|
(:gameDuration info)
|
||||||
|
(:gameType info)
|
||||||
|
(:endOfGameResult info))
|
||||||
|
(do (println "No match data found") response))))
|
||||||
|
|
||||||
|
(defn get-tft-match-data
|
||||||
|
"Get data from a TFT match"
|
||||||
|
[id]
|
||||||
|
(let [response (call-riot-api :tft-match-by-id :path-params {:match-id id})
|
||||||
|
info (get-in response [:value :info])
|
||||||
|
meta (get-in response [:value :metadata])]
|
||||||
|
;(println "Value:" info)
|
||||||
|
(if (:success response)
|
||||||
|
(create-match-data :tft
|
||||||
|
(:match_id meta)
|
||||||
|
(map #(create-participant (:puuid %)
|
||||||
|
(get-in % [:companion :species] nil)
|
||||||
|
(if (player-alive? (:puuid %) (:participants info)) 0 1)
|
||||||
|
(:players_eliminated %)
|
||||||
|
(:win %)
|
||||||
|
(:placement %))
|
||||||
|
(:participants info))
|
||||||
|
(:game_datetime info)
|
||||||
|
(+ (:game_datetime info) (int (* 1000 (:game_length info))))
|
||||||
|
(int (:game_length info))
|
||||||
|
(:tft_game_type info)
|
||||||
|
(:endOfGameResult info))
|
||||||
|
(do (println "No match data found") response))))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(get-lol-match-data "EUW1_7673677826")
|
||||||
|
(get-tft-match-data "EUW1_7674912532")
|
||||||
|
|
||||||
|
(player-won? (get-lol-puuid "Walid Georgey" "EUW")
|
||||||
|
(get-lol-match-data "EUW1_7673677826"))
|
||||||
|
|
||||||
|
(player-won? (get-tft-puuid "Walid Georgey" "EUW")
|
||||||
|
(get-tft-match-data "EUW1_7695774670"))
|
||||||
|
|
||||||
|
(get-tft-match-data "EUW1_7695029198")
|
||||||
|
|
||||||
|
(player-alive? "aWw6WWUdssl6KXMqTsgVZn4iyPfC3J2sa0sdQ7lFzQX0zzV5dzivGE-ihn3OIARf5alUkO2pPu4ztA";(get-tft-puuid "Walid Georgey" "EUW")
|
||||||
|
(:participants (:info (:value (call-riot-api :tft-match-by-id :path-params {:match-id "EUW1_7695774670"})))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(call-riot-api :tft-match-by-id :path-params {:match-id "EUW1_7695774670"})
|
||||||
|
|
||||||
|
(System/currentTimeMillis)
|
||||||
|
1767819383643
|
||||||
|
1767819383643
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Check if it's playing
|
||||||
|
|
||||||
|
(defn is-playing-lol?
|
||||||
|
[puuid]
|
||||||
|
(let [response (call-riot-api :lol-spectator
|
||||||
|
:path-params {:puuid puuid})
|
||||||
|
http-code (:http-code response)]
|
||||||
|
(= 200 http-code)))
|
||||||
|
|
||||||
|
(defn is-playing-tft?
|
||||||
|
[puuid]
|
||||||
|
(let [response (call-riot-api :tft-spectator
|
||||||
|
:path-params {:puuid puuid})
|
||||||
|
http-code (:http-code response)]
|
||||||
|
(= 200 http-code)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn create-playing
|
||||||
|
[timestamp game playing player-name player-tag]
|
||||||
|
{:timestamp timestamp
|
||||||
|
:formatted-ts (millis->str timestamp)
|
||||||
|
:game game
|
||||||
|
:playing playing
|
||||||
|
:player-name player-name
|
||||||
|
:player-tag player-tag})
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(is-playing-lol? (get-lol-puuid "Walid Georgey" "EUW"))
|
||||||
|
(is-playing-tft? (get-tft-puuid "Walid Georgey" "EUW"))
|
||||||
|
)
|
||||||
|
|
||||||
|
(defn is-playing?
|
||||||
|
[player-name player-tag & {:keys [lol tft]
|
||||||
|
:or {lol true
|
||||||
|
tft true}}]
|
||||||
|
(let [now (System/currentTimeMillis)]
|
||||||
|
(cond-> []
|
||||||
|
lol (conj (create-playing now :lol (is-playing-lol? (get-lol-puuid player-name player-tag)) player-name player-tag))
|
||||||
|
tft (conj (create-playing now :tft (is-playing-tft? (get-tft-puuid player-name player-tag)) player-name player-tag)))))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(is-playing? "Walid Georgey" "EUW")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
;; Format dates and times
|
||||||
|
|
||||||
|
(defn match-format-dates
|
||||||
|
([data]
|
||||||
|
(match-format-dates "yyyy-MM-dd HH:mm:ss" data))
|
||||||
|
([date-format data]
|
||||||
|
(-> data
|
||||||
|
(update-in [:start] (partial millis->str date-format))
|
||||||
|
(update-in [:end] (partial millis->str date-format)))))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(t/format (t/formatter "yyyy-MM-dd HH:mm:ss")
|
||||||
|
(t/zoned-date-time (t/instant (System/currentTimeMillis))))
|
||||||
|
|
||||||
|
(millis->str 1769153258168)
|
||||||
|
|
||||||
|
(t/format (t/formatter "yyyy-MM-dd HH:mm:ss")
|
||||||
|
(t/in (t/instant 1769153258168) (t/zone "UTC")))
|
||||||
|
|
||||||
|
|
||||||
|
(t/format (t/formatter "yyyy-MM-dd HH:mm:ss")
|
||||||
|
(t/zoned-date-time (t/instant 1769153258168)))
|
||||||
|
|
||||||
|
(t/format (t/formatter "yyyy-MM-dd HH:mm:ss")
|
||||||
|
(t/zoned-date-time (t/in (t/instant 1769153258168) (t/zone "UTC"))))
|
||||||
|
|
||||||
|
(t/zone)
|
||||||
|
|
||||||
|
(match-format-dates (get-lol-match-data "EUW1_7673677826"))
|
||||||
|
(match-format-dates (get-tft-match-data "EUW1_7674912532"))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
(defn match-format-durations
|
||||||
|
[data]
|
||||||
|
(update-in data [:duration] duration->str))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(t/format (t/formatter "HH:mm:ss") (t/new-duration 2106 :seconds))
|
||||||
|
(t/hours (t/new-duration 2106 :seconds))
|
||||||
|
(t/minutes (t/new-duration 2106 :seconds))
|
||||||
|
(t/seconds (t/new-duration 2106 :seconds))
|
||||||
|
|
||||||
|
(duration->str (+ (* 60 35) 6))
|
||||||
|
(duration->str (+ (* 60 60 17) (* 60 35) 6))
|
||||||
|
(duration->str (+ (* 24 60 60 3) (* 60 60 17) (* 60 35) 6))
|
||||||
|
|
||||||
|
(match-format-durations (get-lol-match-data "EUW1_7673677826"))
|
||||||
|
(match-format-durations (get-tft-match-data "EUW1_7674912532"))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
;; Stats
|
||||||
|
|
||||||
|
(defn play-time-statistics
|
||||||
|
[matches]
|
||||||
|
(let [num-matches (count matches)
|
||||||
|
total (reduce + 0 (map :duration matches))
|
||||||
|
average (if (zero? num-matches) 0 (float (/ total num-matches)))]
|
||||||
|
{:total total
|
||||||
|
:total-formatted (duration->str total)
|
||||||
|
:average average
|
||||||
|
:average-formatted (duration->str (int average))}))
|
||||||
|
|
||||||
|
(defn win-statistics
|
||||||
|
[matches]
|
||||||
|
(let [total (count matches)
|
||||||
|
win (count (filter :winner matches))
|
||||||
|
loss (- total win)]
|
||||||
|
{:total total
|
||||||
|
:win win
|
||||||
|
:loss loss
|
||||||
|
:win-percent (if (zero? total) 0 (float (* 100 (/ win total))))
|
||||||
|
:loss-percent (if (zero? total) 0 (float (* 100 (/ loss total))))}))
|
||||||
|
|
||||||
|
|
||||||
|
(defn kd-ratio
|
||||||
|
[p-data]
|
||||||
|
(let [kills (or (:kills p-data) 0)
|
||||||
|
deaths (or (:deaths p-data) 0)]
|
||||||
|
(if (> deaths 0) (float (/ kills deaths)) 0)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn kill-statistics
|
||||||
|
[puuid matches]
|
||||||
|
(let [total (count matches)
|
||||||
|
; extracts player's data from participands, and adds match's id and k/d ratio
|
||||||
|
player-data (map (fn [p m] (-> p
|
||||||
|
(assoc :match-id (:id m))
|
||||||
|
(assoc :k-d (kd-ratio p))))
|
||||||
|
(map #(filter-by-player puuid %) matches)
|
||||||
|
matches)
|
||||||
|
total-kills (reduce + (map #(:kills %) player-data))
|
||||||
|
total-deaths (reduce + (map #(:deaths %) player-data))
|
||||||
|
ratio-total (if (and total-deaths total-kills (> total-kills 0)) (float (/ total-kills total-deaths)) 0)]
|
||||||
|
{:total total
|
||||||
|
:deads (or total-deaths 0)
|
||||||
|
:kills (or total-kills 0)
|
||||||
|
:ratio ratio-total
|
||||||
|
:best-ratio (:k-d (last (sort-by :k-d player-data)))
|
||||||
|
:worst-ratio (:k-d (first (sort-by :k-d player-data)))
|
||||||
|
:best-champion (:champion (last (sort-by :k-d player-data)))
|
||||||
|
:worst-champion (:champion (first (sort-by :k-d player-data)))
|
||||||
|
:best-match (:match-id (last (sort-by :k-d player-data)))
|
||||||
|
:worst-match (:match-id (first (sort-by :k-d player-data)))}))
|
||||||
|
|
||||||
|
(defn create-basic-stats
|
||||||
|
[player-name player-tag matches]
|
||||||
|
(let [lol-games (filter-by-game :lol matches)
|
||||||
|
tft-games (filter-by-game :tft matches)]
|
||||||
|
{:win-stats {:all (win-statistics matches)
|
||||||
|
:lol (win-statistics lol-games)
|
||||||
|
:tft (win-statistics tft-games)}
|
||||||
|
:play-time {:all (play-time-statistics matches)
|
||||||
|
:lol (play-time-statistics lol-games)
|
||||||
|
:tft (play-time-statistics tft-games)}
|
||||||
|
:kill-stats {:lol (kill-statistics (get-lol-puuid player-name player-tag) lol-games)
|
||||||
|
:tft (kill-statistics (get-tft-puuid player-name player-tag) tft-games)}}))
|
||||||
|
|
||||||
|
(comment
|
||||||
|
(create-basic-stats "Walid Georgey" "EUW"
|
||||||
|
(concat (map get-lol-match-data (get-lol-matches (get-lol-puuid "Walid Georgey" "EUW") :count 5))
|
||||||
|
(map get-tft-match-data (get-tft-matches (get-tft-puuid "Walid Georgey" "EUW") :count 5))))
|
||||||
|
)
|
||||||
@@ -1,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
Reference in New Issue
Block a user