Compare commits

62 Commits

Author SHA1 Message Date
c1d58c838d Update README.md
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-13 14:06:18 +01:00
f13e5ba712 Check if it's playing now
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-08 00:47:26 +01:00
b311b47c4e Get basic data from matches
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-08 00:39:51 +01:00
938b618532 Rename riot-data to riot-config
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-07 23:19:56 +01:00
8772d28db3 TFT endpoints
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-07 23:17:56 +01:00
deb75e6946 Improve error handling using monads
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-07 21:24:02 +01:00
e0510db928 More doc fixes
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-07 16:51:44 +01:00
55b855f99f Improved code documentation
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-07 15:38:30 +01:00
f02629bb45 Improve exception handling
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-07 13:51:58 +01:00
34b701e1d2 Fixed calling the API
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-07 11:12:56 +01:00
49891244a9 Broken
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-07 01:45:49 +01:00
5c671f841e Code reestructuration
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-07 00:51:43 +01:00
1bcd75218e More endpoints for LOL
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-07 00:25:36 +01:00
420a92635a More endpoints
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-06 12:48:51 +01:00
2f33c139df More metadata and documentation
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-06 11:57:31 +01:00
22be4ad137 Endpoints has metadata
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-06 11:48:29 +01:00
fd947b87e0 Comments
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-04 01:54:46 +01:00
5162f76ffc Convert parameters to string
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-04 01:52:11 +01:00
8bc4b993a8 escape space character in URL
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-04 01:47:09 +01:00
18cea38c16 call the api with several endpoints
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-04 01:19:47 +01:00
9182e50179 Get PUUID for player
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2026-01-04 00:31:53 +01:00
fb1d9a7312 begin the core
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2025-12-31 17:32:58 +01:00
1109c5a965 More files to the base
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2025-12-31 16:42:33 +01:00
e7e270d1ec Empty base multiproject configuration 2025-12-31 16:40:33 +01:00
0c2c5954ba Empty 2.0 version
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2025-12-31 09:57:15 +01:00
d49d80af94 Merged branch 1.1
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2025-08-12 09:27:57 +02:00
68cf337f48 Update README.md
All checks were successful
Compile and test using leiningen / Run tests (push) Successful in 9m44s
2025-08-12 08:44:37 +02:00
4ecab127af Update test/riot/core_test.clj
All checks were successful
Compile and test using leiningen / Run tests (push) Successful in 9m39s
2025-08-12 08:29:38 +02:00
61f8639a67 Update test/riot/data_test.clj
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
2025-08-12 08:28:14 +02:00
7f0866cbac Fix some tests
Some checks failed
Compile and test using leiningen / Run tests (push) Failing after 5m17s
2025-08-12 08:16:52 +02:00
f2fbeaaa4d exclude :tft and :timezone from default tests
Some checks failed
Compile and test using leiningen / Run tests (push) Failing after 5m16s
2025-08-12 01:08:19 +02:00
abf0b9dbde Exclude tests that relay in the timezone
Some checks failed
Compile and test using leiningen / Run tests (push) Failing after 5m11s
2025-08-12 00:36:45 +02:00
c881b8ae49 Deactivate TFT tests
Some checks failed
Compile and test using leiningen / Run tests (push) Failing after 5m12s
2025-08-12 00:17:33 +02:00
19eb496d35 More changes to actions
Some checks failed
Compile and test using leiningen / Run tests (push) Failing after 5m25s
2025-08-11 23:56:26 +02:00
156bbdb20f Trying to deploy on maven repository
Some checks failed
Compile and test using leiningen / Run tests (push) Failing after 5m12s
2025-08-11 23:42:35 +02:00
83ffa76f1f goodbye demo
Some checks failed
Compile and test using leiningen / Run tests (push) Failing after 5m9s
2025-08-11 23:19:24 +02:00
de6c41d9f8 Update .gitea/workflows/compile.yaml
Some checks failed
Compile and test using leiningen / Run tests (push) Has been cancelled
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 8s
2025-08-11 23:18:26 +02:00
af58b8602a Run lein deps
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Has been cancelled
Compile and test using leiningen / Run tests (push) Has been cancelled
2025-08-11 23:18:02 +02:00
f2ca083dde Let's try chatgpt response...
Some checks failed
Compile and test using leiningen / Run tests (push) Failing after 5m47s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 8s
2025-08-11 23:09:08 +02:00
117275043c Triying to install Leiningen automatically
Some checks failed
Compile and test using leiningen / Run tests (push) Failing after 5m50s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 9s
2025-08-11 22:58:22 +02:00
b0ae302c2f Triying with versións from example
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 8s
Compile and test using leiningen / Run tests (push) Failing after 4m43s
2025-08-11 20:08:59 +02:00
05963e9fec Update .gitea/workflows/compile.yaml
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 8s
Compile and test using leiningen / Run tests (push) Failing after 12s
2025-08-11 20:04:11 +02:00
914fbb57e2 Ok, let's forget graalvm for now...
Some checks failed
Compile and test using leiningen / Run tests (push) Failing after 4m56s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 8s
2025-08-11 19:54:36 +02:00
3f8409f007 Trying another graal version
Some checks failed
Compile and test using leiningen / Run tests (push) Failing after 12s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 8s
2025-08-11 19:53:21 +02:00
8c51ef4da5 Trying to configure an usefull gitea actions
Some checks failed
Compile and test using leiningen / Run tests (push) Failing after 2m29s
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 9s
2025-08-11 19:47:25 +02:00
44b8e62b5e Show endOfGameResult data item
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 9s
2025-08-11 01:01:52 +02:00
cceae6eadd Check zero divisions
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 11s
2025-08-11 00:22:25 +02:00
d20d7bbbcf Simple statistics
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 39s
2025-08-03 01:02:03 +02:00
c09f5681c2 Added log dependency
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 57s
2025-07-31 11:28:30 +02:00
25349fef02 Added log support
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 9s
2025-07-18 00:29:19 +02:00
35eca77223 Adding logging dependency
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 8s
2025-07-17 11:14:58 +02:00
3317241f86 Logging
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 9s
2025-07-17 00:32:09 +02:00
c90ab941df Today by default and include current playing info
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 8s
2025-07-16 09:35:32 +02:00
eed4104ae3 Clean the CLI parameters
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 8s
2025-07-16 00:41:59 +02:00
3b54917551 Better help text
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 8s
2025-07-15 21:52:02 +02:00
43c2d31d4f Pretty table and simplified parameters
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 8s
2025-07-15 21:43:49 +02:00
df414c37d0 Ignore example svg files
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 18s
2025-07-15 19:22:33 +02:00
3f405d1723 Simple demo Gitea Action
All checks were successful
Gitea Actions Demo / Explore-Gitea-Actions (push) Successful in 1m15s
2025-07-15 13:00:50 +02:00
93ce4e7539 Update README.md 2025-07-15 12:54:33 +02:00
3d86c3b7be Update README.md 2025-07-15 12:47:07 +02:00
2fd314b972 Update README.md 2025-07-15 12:38:29 +02:00
515c51a4bc Configuring development of v1.1
Configure project and adapt the README.md for the next development
branch (1.1)
2025-07-15 12:30:34 +02:00
64 changed files with 1386 additions and 5049 deletions

View File

@@ -0,0 +1,48 @@
name: Compile and test using leiningen
run-name: ${{ gitea.actor }} testing the code
on: [push]
jobs:
clojure:
name: Run tests
runs-on: ubuntu-latest
steps:
# Checkouts code
- name: Checkout
uses: actions/checkout@v3
# Install Java
- name: Install java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
# Optional: cache dependencies
- name: Cache dependencias
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-m2-${{ hashFiles('**/project.clj') }}
restore-keys: |
${{ runner.os }}-m2-
# Get leiningen's version
- name: Get clojure version
run: clojure --version
# Test the code
#- name: Run tests
# env:
# TFT_API: ${{ secrets.DEV_API }}
# run: lein test
# Send jar to repository
#- name: Deploy on Gitea Maven
# if: github.ref == 'refs/heads/main'
# env:
# GITEA_USER: ${{ secrets.DEPLOY_USER }}
# GITEA_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
# run: |
# lein deploy gitea

7
.gitignore vendored
View File

@@ -7,10 +7,11 @@ pom.xml.asc
*.jar
*.class
/.lein-*
/.nrepl-port
/**/.nrepl-port
/.prepl-port
.hgignore
.hg/
.cpcache
.clj-kondo
.lsp
.calva
*.svg
/logs

5
.idea/.gitignore generated vendored
View File

@@ -1,5 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Environment-dependent path to Maven home directory
/mavenHomeManager.xml

View File

@@ -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
View File

@@ -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>

View File

@@ -1,7 +0,0 @@
<component name="ProjectDictionaryState">
<dictionary name="project">
<words>
<w>puuid</w>
</words>
</dictionary>
</component>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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
View File

@@ -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
View File

@@ -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
View File

@@ -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>

137
README.md
View File

@@ -1,79 +1,110 @@
# riot-clojure
This is a simple tool for using Riot Games public API. Those APIs are HUGE and
privide a lot of information, but this tool is focused in the time data of matches.
Riot Games provides a lot of nice endpoints with a lot of data for all their games.
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
starting and ending timestams we can create a chronogram with the time spent
playing.
The library and the CLI application are separated, you can use the library independently.
This simple program needs a developer API. You can obtain a 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.
CLI application should be compatible with [babashka](https://babashka.org/), so
will use external libraries compatible with it.
By default, the application searchs for the API key in the environment variable
`RIOT_API`. If you prefer to provide the key via parameter, you must use `-k KEY` or
`--key=KEY`.
# The API and the tokens
## Goals
Accessing the API requires one or more API tokens. Each videogame has their own
group of endpoints, secured with an API. Development APIs can access to all
andpoints, but they must be refreshed every 24 hours.
Goals of the project, ordered from easiest to hardest:
You can obtain a token for free in the [official developer web](https://developer.riotgames.com/).
* [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
* [ ] 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
The library and the application will take the API token from environment. CLI application
has optional parameters that override the environment variables.
| Game | Environment variable | CLI parameter |
| ---------- | -------------------- | ------------- |
| all | `RIOT_DEV_KEY` | `--dev-key` |
| LOL | `RIOT_LOL_KEY` | `--lol-key` |
| TFT | `RIOT_TFT_KEY` | `--tft-key` |
*more to came*
## Installation
# Usage
## CLI
### Installation
Download from http://example.com/FIXME.
Download release from https://git.rcorral.es/ruben/riot-clojure/releases.
## Usage
### Example
FIXME: explanation
Using the Java uberjar
$ java -jar riot-clojure-0.1.0-standalone.jar [args]
## Options
Using the linux native image:
$ ./riot [args]
FIXME: listing of options this app accepts.
Both are equivalent. In the examples we will use the native image, because is shorter.
## Examples
### Options
...
Run the application without params or wich `-?` param to show all options:
### Bugs
$ ./riot -?
...
### Tipycal usages
### Any Other Sections
### That You Think
### Might be Useful
Show all matches from a march the 1st (in ISO format):
## License
$ ./riot t <username> <tag> -s "2025-03-01"
Get te same data in CSV and store it in a file:
$ ./riot t <username> <tag> -s "2025-03-01" -o csv > results.csv
Don't format durations, show them in seconds
$ ./riot t <username> <tag> -s "2025-03-01" --no-format-durations
## Library
# Version
**Notes about v2.0:** This is complete rewriting of the project, with all
I have learn in the last months. The objetive for this version is to implement
all functionality provided by v1.1.
## Status
### General
* [x] Reestructure all project to use `deps.edn`, `tools.clj` and subprojects
* [ ] Use babashka compatible libraries and `bb.edn`
* [ ] Gitea actions for automatic test executing
* [ ] Distribute CLI as self executable (bb, jlink or graal)
### Library
* [x] Read tokens from environment and a function to override them manually
* [x] Fuctions for calling Riot API and read result as clojure data structures (EDN format)
* [x] Get [PUUID](https://developer.riotgames.com/docs/lol#summoner-names-to-riot-ids_obtaining-puuid-and-summonerid-from-riotid) for a player
* [x] Get basic player info
* [ ] Format raw data
### CLI
* [ ] Babashka compatible CLI
* [ ] Basic parameters for log level and override API tokens
* [ ] Obtain basic player info
* [ ] Last games for player (LOL, TFT and others)
* [ ] Is the player playing just now?
* [ ] Contiuosly check if the player es playing
* [ ] Write status check to a file, to save an activity log
* [ ] Format output as fancy table
* [ ] Format output as CSV
* [ ] Calculte basic statistics
* [ ] Calculate advanced statistics: win strike, adversaries, etc.
# License
MIT License

176
build.clj Normal file
View File

@@ -0,0 +1,176 @@
(ns build
(:refer-clojure :exclude [test])
(:require [clojure.tools.build.api :as b]
[clojure.java.io :as io]
[clojure.pprint :as pp]
[clojure.java.basis :as basis]))
(def lib-group "es.rcorral")
(def artifact-prefix "clj-totp")
(def subprojs-base "projects")
(def curr-version (format "2.0.%s" (b/git-count-revs nil)))
;; Builds artifact's full descriptor for each subproject
(defn lib [subproj]
(symbol (str lib-group "/" artifact-prefix "-" subproj )))
;; Basis for each subproject, using their own deps.edn
;; Injects :extra-deps from :build as additional dependencies
(defn basis [subproj]
(delay (b/create-basis {:project (str subprojs-base "/" subproj "/deps.edn")
;; Inject extra deps as deps
:extra {:deps (get-in (basis/initial-basis) [:aliases :build :extra-deps])}
})))
;; Show basis generated for a subproject
#_{:clojure-lsp/ignore [:clojure-lsp/unused-public-var]}
(defn show-basis [subproj]
(println (with-out-str
(pp/pprint
@(basis subproj)
;(basis/initial-basis)
))))
(comment
(pp/pprint (keys (basis/initial-basis)))
(pp/pprint (:deps (basis/initial-basis)))
(pp/pprint (:libs (basis/initial-basis)))
(pp/pprint (sort (keys (:aliases (basis/initial-basis)))))
(get-in (basis/initial-basis) [:aliases :build :extra-deps])
)
;; Target dir for each subproject
(defn target-dir [subproj]
(str "target/" subproj))
;; Path for compiled classes
(defn class-dir [subproj]
(str (target-dir subproj) "/" "classes"))
;; Jar file for each subproject. :uber type adds -standalone suffix
(defn jar-file [subproj version type]
(format "target/%s-%s-%s%s.jar" artifact-prefix subproj version
(if (= type :uber) "-standalone" "")))
;; Clean target dir for subproject
(defn clean [{:keys [subproj]}]
(b/delete {:path (target-dir subproj)})
(println "Project" subproj "cleaned"))
;; Compile java classes, only if java subdir exists
(defn compile-java [{:keys [subproj]}]
(let [java-dir (str subprojs-base "/" subproj "/java")]
(if (.exists (io/file java-dir))
(do
(println "Compiling java code for" subproj)
(b/javac {:src-dirs [java-dir]
:class-dir (class-dir subproj)
:basis @(basis subproj)
:javac-opts ["-source" "11" "--target" "11" "-proc:none"]}))
(println "Java dir" java-dir "not found"))))
;; Create a jar file
(defn jar
"Build a simple jar file, with no dependencies included."
[{:keys [subproj version]
:or {version curr-version}}]
(let [target-dir (target-dir subproj)
class-dir (class-dir subproj)
src-dir (str subprojs-base "/" subproj "/src")
resources-dir (str subprojs-base "/" subproj "/resources")
basis (basis subproj)
jar-file (jar-file subproj version :plain)]
;; Clean only class dir
(b/delete {:path class-dir})
;; Copy code
(b/copy-dir {:src-dirs [src-dir]
:target-dir class-dir})
;; Copy resources
(b/copy-dir {:src-dirs [resources-dir]
:target-dir target-dir})
;; Compile java code, if exists
(compile-java {:subproj subproj})
;; Build jar
(b/jar {:class-dir class-dir
:basis @basis
:jar-file jar-file
:lib (lib subproj)
:version version})
(println "Generated jar file:" jar-file)))
;; Create an uber jar, with all dependencies inside
#_{:clojure-lsp/ignore [:clojure-lsp/unused-public-var]}
(defn uber
"Build a uberjar with all dependencies included"
[{:keys [subproj version main-ns]
:or {version curr-version}}]
(let [target-dir (target-dir subproj)
basis (basis subproj)
class-dir (class-dir subproj)
src-dir (str subprojs-base "/" subproj "/src")
resources-dir (str subprojs-base "/" subproj "/resources")
uber-file (jar-file subproj version :uber)]
;(println "Using basis: ")(show-basis subproj)
(b/delete {:path class-dir})
(b/copy-dir {:src-dirs [src-dir]
:target-dir class-dir})
(b/copy-dir {:src-dirs [resources-dir]
:target-dir target-dir})
(compile-java {:subproj subproj})
(b/compile-clj {:basis @basis
:src-dirs [src-dir] :class-dir class-dir})
(b/uber {:class-dir class-dir
:uber-file uber-file
:basis @basis
:main main-ns})
(println "Generated uberjar executable:" uber-file)))
;; Multimethod to get the name of all subdirs in a dir.
;; Accepts strings or files
(defmulti get-subdirs type)
(defmethod get-subdirs
java.lang.String [dir]
(get-subdirs (io/file dir)))
(defmethod get-subdirs
java.io.File [dir]
(if (.isDirectory dir)
(filter #(.isDirectory %) (.listFiles dir))
(println "Directory" subprojs-base "doesn't exists!")))
;; Get the name of all subdir in a given directory
(defn get-subdir-names
"Get a list projects in the 'projects' directory"
[dir-name]
(map #(.getName %) (get-subdirs dir-name)))
(comment
(get-subdirs "projects")
(get-subdirs (io/file "projects"))
(get-subdir-names "projects")
)
;; Generate jar files for all projects
(defn jar-all
"Build jar files for all projects"
[& {:keys [version]
:or {version curr-version}}]
(dorun (map #(jar {:subproj % :version version}) (get-subdir-names subprojs-base))))
(comment
(jar-all )
)

51
deps.edn Executable file
View File

@@ -0,0 +1,51 @@
{:paths ["projects/core/src"
"projects/core/resources"
"projects/cli/src"]
:deps {org.clojure/clojure {:mvn/version "1.12.1"}
;; Local subprojects
clj-tmpl/core {:local/root "projects/core"}
clj-tmpl/cli {:local/root "projects/cli"}
}
:aliases {;; Execute the app.
:run {:main-opts ["-m" "riot.app"]}
;:run {:exec-fn totp.app/-main}
;; Execute the app (prepared for more subprojects)
:run/cli {:main-opts ["-m" "riot.app"]}
;; Kaocha runner. You can use the 'kaocha' wrapper located in ~/bin/kaocha
;; Check test.edn for kaocha runner's config
:test {:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}
lambdaisland/kaocha-cloverage {:mvn/version "1.1.89"}}
:main-opts ["-m" "kaocha.runner"]}
;; Run with clj -T:build function-in-build
:build {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
;; Used by all compilations
:extra-deps {clj-tmpl/core {:local/root "projects/core"}}
:ns-default build}
;; Aliases for easy building
:build/core {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
:ns-default build
:exec-fn jar
:exec-args {:subproj "core"}}
:build/cli {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
:ns-default build
:exec-fn jar
:exec-args {:subproj "cli"}}
;; Build all projects
:build/all {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
:ns-default build
:exec-fn jar-all}
;; Build uber jar for CLI app
:uber/cli {:deps {io.github.clojure/tools.build {:mvn/version "0.10.10"}}
:ns-default build
:exec-fn uber
:exec-args {:subproj "cli" :main-ns "riot.app"}}}}

View 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

View File

@@ -1,3 +0,0 @@
# Introduction to riot-clojure
TODO: write [great documentation](http://jacobian.org/writing/what-to-write/)

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

View File

@@ -1,30 +0,0 @@
(defproject riot-clojure "1.0.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"]
[buddy/buddy-core "1.12.0-430"]
[org.clojure/tools.namespace "1.5.0"]
[lt.tokenmill/timewords "0.5.0"]]
: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"]]}})

8
projects/cli/deps.edn Executable file
View File

@@ -0,0 +1,8 @@
{:paths ["src" "resources" "target/classes"]
:deps {org.clojure/clojure {:mvn/version "1.12.1"}
cli-matic/cli-matic {:mvn/version "0.5.4"} ;; https://github.com/l3nz/cli-matic
}
:aliases {;; Execute the app
;:run {:main-opts ["-m" "totp.app"]}
}}

View File

@@ -0,0 +1,9 @@
(ns riot.app
#_{:clj-kondo/ignore [:refer-all]}
(:require [riot.core :refer :all])
(:gen-class))
(def cli-options {})
(defn -main [& args]
(greeting-emisor (generate-greeting :high "Juan")))

15
projects/core/deps.edn Executable file
View File

@@ -0,0 +1,15 @@
{:paths ["src" "resources" "target/classes"]
:deps {org.clojure/clojure {:mvn/version "1.12.1"}
;; https://github.com/babashka/http-client
org.babashka/http-client {:mvn/version "0.4.22"}
;; https://github.com/dakrone/cheshire?tab=readme-ov-file
cheshire/cheshire {:mvn/version "6.1.0"}}
:aliases {;; Kaocha runner. You can use the 'kaocha' wrapper located in ~/bin/kaocha
:test {:extra-paths ["test"]
:extra-deps {lambdaisland/kaocha {:mvn/version "1.91.1392"}}
:main-opts ["-m" "kaocha.runner"]}
;; enable logging for java.net.http
:debug-full {:jvm-opts ["-Djdk.httpclient.HttpClient.log=errors,requests,headers,frames[:control:data:window:all..],content,ssl,trace,channel"]}
:debug {:jvm-opts ["-Djdk.httpclient.HttpClient.log=errors,requests,headers,content"]}}}

View File

@@ -0,0 +1,189 @@
(ns riot.core
(:require [babashka.http-client :as http]
[cheshire.core :as json]
[clojure.string :as s]
[clojure.pprint :as pp]))
;;
;; API KEY MANAGEMENT
;;
(defn get-key-from-env
"Get api key from environment variable"
[key]
(System/getenv (name key)))
(defn get-and-save-key-from-env
"Get api key from environment and store in the KEYS map. It key is not found in
the environment, it tries to load the development key as a fallback. If none api
key is found, return nil"
[KEYS default-key key]
(if-let [value (get-key-from-env key)]
(reset! (key KEYS) value)
(if-let [value_dev (get-key-from-env key)]
(reset! (default-key KEYS) value_dev)
nil)))
(defn get-api-key
"Get API key from KEYS map. If it is not found in the KEYS map, try to load it from
the environment. If the API key doesn't exists in the environment, try to load the
development key (the default key). If none found, print and error and return nil"
[KEYS default-key keytype]
(if (contains? KEYS keytype)
(if-let [key-value (deref (keytype KEYS))]
key-value
(if-let [def-key-value (deref (default-key KEYS))]
def-key-value
(get-and-save-key-from-env KEYS default-key keytype)))
(println "Invalid key type. Available keys:" (keys KEYS))))
(defn set-api-key
"Force the value of an API key in the KEYS map"
[KEYS keytype value]
(when (contains? KEYS keytype)
(reset! (keytype KEYS) value)))
;;
;; GENERATE URLS
;;
(defn get-url
"Get URL for using the API."
[path & parts]
(when path
(s/join "/" (concat [path] (vec parts)))))
(defn url-encode-param
"Encode URL, replacing spaces with %20 and deleting invalid characters"
[value]
(when value
(s/escape value { \ "%20"})))
(defn replace-params
"Replace params in path"
[path params-map]
;(println "replacing" path "witn" params-map)
(if (and path params-map (not-empty params-map))
(reduce-kv
#(s/replace %1 ((comp re-pattern str) %2) (url-encode-param (str %3)))
(get-url path)
params-map)
path))
(defn get-known-url
"Get url from ENDPOINTS map."
[ENDPOINTS url-name params-map]
(if-let [url (get-in ENDPOINTS [url-name :uri])]
(replace-params url params-map)
(println "Unknown URL name" url-name)))
;;
;; HELPERS
;;
(defn success
"Return a success that stores HTTP result code and parsed JSON data"
[status json-data]
{:success true :http-code status :value json-data})
(defn failure
"Return a success that stores HTTP result code and parsed JSON data"
[status error-data]
{:success false :http-code status :error error-data})
;;
;; CALL GET ENDPOINTS
;;
(defn call-api
"Call the api using one of the supported URLs or a string. You can pass optional
maps for params:
- path-params: parameters in the path.
- query-params: parameters in the query part of the URL
- header-params: headers added to the default headers
The key-provider is a function that accepts the url as param and returns the api
key.
The api-key-header is the name of the header param that holds the API key. If
the endpoint don't requiere an API key, you can provide nil or empty string.
The URL can be a keyword of the map ENDPOINTS or a URL. Each path param must have
the same name as the key in the path-params map, including the ':' For example,
given this url:
http://example.com/api/get-user-by-id/:user
It has a path param called ':user'. If you provide this map:
:path-params {:user 2345}
it will expanded to:
http://example.com/api/get-user-by-id/2345
If you provide query-params, the will added after the question mark. For example, if
you call the function as follows:
(call-api \"http://example.com/api/get-user-by-id/:user\"
:path-params {:user 2345}
:query-params {:detail \"full\"})
this will output the following string:
\"http://example.com/api/get-user-by-id/2345?detail=full\"
This function returns a success if everythin goes well or a failure when http status
code is different from 200 or an exception is raised.
"
; Very simple arity to call a simple URL and the the JSON result
([url]
(call-api {} #(apply (constantly "") %) nil url))
; The complete call. You must personalize ENDPOINTS, key-provider and api-key-header
; for your API
([ENDPOINTS key-provider api-key-header url & {:keys [path-params query-params header-params debug]
:or {path-params {} query-params {} header-params {} debug false}}]
;(println "Endpoints:" (count ENDPOINTS) "Key provider:" key-provider "api key header:" api-key-header)
(let [; Process path-parameters
processed-url (if (keyword? url)
(get-known-url ENDPOINTS url path-params)
(replace-params url path-params))
; Try to get an api key (if required)
api-key (if (keyword? url) (key-provider url) (println "No api key for URL " url))
; Fixed headers, without api key
headers-no-key (merge {"Accept" "application/json"}
header-params)
; Headers with api key
headers (if (and (some? api-key-header) (string? api-key))
(merge headers-no-key {api-key-header api-key})
headers-no-key)]
;(println "URL:" processed-url "Query" query-params "headers: " headers)
(try
; Call the api and catch the result
(let [response (http/get processed-url {:headers headers
:query-params query-params
:throw false})]
; If debug activated, print all data from response
(when debug (println "RESPONSE:")(pp/pprint response))
; Check HTTP response code.
(if (= 200 (:status response))
(success 200 (json/parse-string (:body response) keyword))
(do
(println "Error response: HTTP code" (:status response))
(failure (:status response) (:body response)))))
(catch Exception exc
(prn "An exception has been thrown while calling the api" (.getMessage exc))
(failure nil (.getMessage exc)))))))
(comment
(call-api "https://status.search.google.com/incidents.json")
(call-api "http://example.com")
)

View File

@@ -0,0 +1,138 @@
(ns riot.data
(:require [riot.core :refer :all]
[riot.riot-api :refer :all]))
;;
;; High functions to work with RIOT API.
;;
;; This file has a lot of utilities for working with data obtained with the help
;; of riot-api's functions
;; Get matches list
(defn get-lol-matches
"Get LOL matches for player"
[puuid & {:keys [startTime endTime queue type start count] :as params}]
;(println "Params:" params)
(let [response (call-riot-api :lol-matches-by-puuid
:path-params {:puuid puuid}
:query-params params)]
(if (:success response)
(:value response)
(do (println "No LOL matches found") response))))
(defn get-tft-matches
"Get TFT matches for player"
[puuid & {:keys [startTime endTime queue type start count] :as params}]
(println "Params:" params)
(let [response (call-riot-api :tft-matches-by-puuid
:path-params {:puuid puuid}
:query-params params)]
(if (:success response)
(:value response)
(do (println "No TFT matches found") response))))
(comment
(get-lol-matches (lol-get-uuid "Walid Georgey" "EUW") :count 5)
(get-lol-matches (lol-get-uuid "Errepunto" "4595") :count 5)
(get-tft-matches (tft-get-uuid "Walid Georgey" "EUW") :count 5)
(get-tft-matches (tft-get-uuid "Errepunto" "4595") :count 5)
)
;; Get matches data
(defn create-match-data
[matchId participants gameStartTimestamp gameEndTimestamp gameDuration gameType endOfGameResult]
{:id matchId
:participants participants
:start gameStartTimestamp
:end gameEndTimestamp
:duration gameDuration
:type gameType
:result endOfGameResult})
(defn create-participant
[puuid championName deaths kills win]
{:puuid puuid
:champion championName
:deaths deaths
:kills kills
:win win})
(defn get-lol-match-data
"Get data from a LOL match"
[id]
(let [response (call-riot-api :lol-match-by-id :path-params {:match-id id})
info (get-in response [:value :info])
meta (get-in response [:value :metadata])]
;(println "Value:" info)
(if (:success response)
(create-match-data (:matchId meta)
(map #(create-participant (:puuid %)
(:championName %)
(:deaths %)
(:kills %)
(:win %))
(:participants info))
(:gameStartTimestamp info)
(:gameEndTimestamp info)
(:gameDuration info)
(:gameType info)
(:endOfGameResult info))
(do (println "No match data found") response))))
(defn get-tft-match-data
"Get data from a TFT match"
[id]
(let [response (call-riot-api :tft-match-by-id :path-params {:match-id id})
info (get-in response [:value :info])
meta (get-in response [:value :metadata])]
;(println "Value:" info)
(if (:success response)
(create-match-data (:match_id meta)
(map #(create-participant (:puuid %)
nil
nil
(:players_eliminated %)
(:win %))
(:participants info))
(:game_datetime info)
(+ (:game_datetime info) (int (* 1000 (:game_length info))))
(int (:game_length info))
(:tft_game_type info)
(:endOfGameResult info))
(do (println "No match data found") response))))
(comment
(get-lol-match-data "EUW1_7673677826")
(get-tft-match-data "EUW1_7674912532")
(System/currentTimeMillis)
1767819383643
1767819383643
)
;; Check if it's playing
(defn is-playing-lol?
[puuid]
(let [response (call-riot-api :lol-spectator
:path-params {:puuid puuid})
http-code (:http-code response)]
(= 200 http-code)))
(defn is-playing-tft?
[puuid]
(let [response (call-riot-api :tft-spectator
:path-params {:puuid puuid})
http-code (:http-code response)]
(= 200 http-code)))
(comment
(is-playing-lol? (lol-get-uuid "Walid Georgey" "EUW"))
(is-playing-tft? (lol-get-uuid "Walid Georgey" "EUW"))
)

View File

@@ -0,0 +1,174 @@
(ns riot.riot-api
(:require [riot.core :refer :all]
[riot.riot-config :refer :all]))
;;
;; ADAPT API GENERIC METHODS TO RIOT API
;;
;; You need to adapt 3 things from the generic core:
;; - A method for setting (override) the API key
;; - A method for supply the API
;; - A wrapper for calling call-api with this API endpoint, and keyprovider
;;
;; Maps with keys and supported endpoints are in a separated file (riot-data.clj)
;;
; Not needed, but useful
(def get-riot-api-key (partial get-api-key RIOT-KEYS :RIOT_DEV_KEY))
; Not used by core, but useful for frontends
(def set-riot-api-key (partial set-api-key RIOT-KEYS))
; Key provider for this API
(defn riot-key-provider
[url]
(if-let [api-key (get-riot-api-key (get-in ENDPOINTS [url :api-key]))]
api-key
(println "No API key found")))
(comment
(get-in ENDPOINTS [:lol-status :api-key])
(riot-key-provider :lol-status)
)
; Wrapper for ease use of call-api
(def call-riot-api (partial call-api ENDPOINTS riot-key-provider "X-Riot-Token"))
;;
;; HELPER FUNCTIONS
;;
(defn lol-get-uuid
"Get PUUID from player's name and tag for LOL endpoints"
[player-name player-tag]
(:puuid (:value (call-riot-api :lol-account-by-riot-id
:path-params {:player-name player-name :player-tag player-tag}))))
(defn tft-get-uuid
"Get PUUID from player's name and tag for TFT endpoints"
[player-name player-tag]
(:puuid (:value (call-riot-api :tft-account-by-riot-id
:path-params {:player-name player-name :player-tag player-tag}))))
;;
;; USAGE EXAMPLES
;;
(comment
(set-riot-api-key :RIOT_DEV_KEY "RGAPI-a8d1f915-859b-4bad-99d8-0a163e349f77")
(lol-get-uuid "Walid Georgey" "EUW")
(tft-get-uuid "Walid Georgey" "EUW")
;; Examples calling the API
(call-riot-api :lol-account-by-puuid
:path-params {:puuid "Walid Georgey" :player-tag "EUW"})
(:value (call-riot-api :lol-status))
(call-riot-api :champion-mastery-by-puuid
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")})
(call-riot-api :champion-mastery-by-puuid-and-champion
:path-params {:championId 45
:puuid (lol-get-uuid "Walid Georgey" "EUW")})
(call-riot-api :champion-mastery-by-puuid-top
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")}
:query-params {:count 1})
(call-riot-api :champion-rotations)
(call-riot-api :summoner-by-puuid
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")})
(call-riot-api :league-all-by-puuid
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")})
(call-riot-api :league-by-id
:path-params {:league-id "35642608-b436-48a0-ac0f-b64eb6dfc14e"})
(call-riot-api :clash-by-puuid
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")})
(call-riot-api :clash-tournaments)
(call-riot-api :lol-matches-by-puuid
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")}
:query-params {:count 5})
(call-riot-api :lol-match-by-id
:path-params {:match-id "EUW1_7673677826"})
(call-riot-api :lol-match-timeline-by-id
:path-params {:match-id "EUW1_7673677826"})
(call-riot-api :lol-challenges-config)
(call-riot-api :lol-challenge-config-by-id
:path-params {:challenge-id 402109})
(call-riot-api :lol-challenges-percentiles)
(call-riot-api :lol-challenges-percentiles-by-id
:path-params {:challenge-id 402109})
(call-riot-api :lol-challenge-leaderboard
:path-params {:challenge-id 402109
:level "CHALLENGER"})
(call-riot-api :lol-challenge-by-puuid
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")})
(call-riot-api :lol-champion-mastery-by-puuid
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")})
(call-riot-api :lol-champion-mastery-by-puuid-champion
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")
:champion-id 777})
(call-riot-api :lol-champion-mastery-by-puuid-top
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")}
:query-params {:count 5})
(call-riot-api :lol-champion-mastery-scores-by-puuid
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")})
(call-riot-api :lol-spectator
:path-params {:puuid (lol-get-uuid "Walid Georgey" "EUW")})
;; TFT
(call-riot-api :tft-summoner-by-puuid
:path-params {:puuid (tft-get-uuid "Walid Georgey" "EUW")})
(call-riot-api :tft-status)
(call-riot-api :tft-matches-by-puuid
:path-params {:puuid (tft-get-uuid "Walid Georgey" "EUW")})
(call-riot-api :tft-match-by-id
:path-params {:match-id "EUW1_7666482502"})
(call-riot-api :tft-spectator
:path-params {:puuid (tft-get-uuid "Walid Georgey" "EUW")})
(call-riot-api :tft-league-by-puuid
:path-params {:puuid (tft-get-uuid "Walid Georgey" "EUW")})
(call-riot-api :tft-league-challenger)
(call-riot-api :tft-league-grandmaster-by-queue)
(call-riot-api :tft-league-master-by-queue)
(call-riot-api :tft-league-top-rated-ladders
:path-params {:queue "RANKED_TFT_TURBO"})
(call-riot-api :tft-league-by-league-id
:path-params {:league-id "abc"})
)

View File

@@ -0,0 +1,454 @@
(ns riot.riot-config)
;;
;; API KEYS
;;
(def RIOT-KEYS {:RIOT_DEV_KEY (atom nil)
:RIOT_LOL_KEY (atom nil)
:RIOT_TFT_KEY (atom nil)})
;;
;; KNOWN ENDPOINTS
;;
;; Each endpoint has a URL with path params (denoted as keywords, with ':') and
;; some informative metadata about parameters and some logical grouping.
;;
;; For now, metadata is optional and it is not used in the core, but is very
;; usefull for programmers like you.
(def ENDPOINTS
{;; account v1
:account-by-puuid
{:uri "https://europe.api.riotgames.com/riot/account/v1/accounts/by-puuid/:puuid"
:api-key :RIOT_LOL_KEY
:groups ["account"]
:path-params {:puuid {:required true :type :string}}
:query-params {}
:header-params {}}
:lol-account-by-riot-id
{:uri "https://europe.api.riotgames.com/riot/account/v1/accounts/by-riot-id/:player-name/:player-tag"
:api-key :RIOT_LOL_KEY
:groups ["lol" "account"]
:path-params {:player-name {:required true :type :string}
:player-tag {:required true :type :string}}
:query-params {}
:header-params {}}
:account-active-shards
{:uri "https://europe.api.riotgames.com/riot/account/v1/active-shards/by-game/:game/by-puuid/:puuid"
:api-key :RIOT_LOL_KEY
:groups ["account"]
:path-params {:game {:required true :type :string}
:puuid {:required true :type :string}}
:query-params {}
:header-params {}}
;; LOL status v4
:lol-status
{:uri "https://euw1.api.riotgames.com/lol/status/v4/platform-data"
:api-key :RIOT_LOL_KEY
:groups ["lol" "status"]
:path-params {}
:query-params {}
:header-params {}}
;; champion-mastery-v4
:champion-mastery-by-puuid
{:uri "https://euw1.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/:puuid"
:api-key :RIOT_LOL_KEY
:groups ["lol" "champion-mastery"]
:path-params {:puuid {:required true :type :string}}
:query-params {}
:header-params {}}
:champion-mastery-by-puuid-and-champion
{:uri "https://euw1.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/:puuid/by-champion/:championId"
:api-key :RIOT_LOL_KEY
:groups ["lol" "champion-mastery"]
:path-params {:puuid {:required true :type :string}
:championId {:required true :type :string}}
:query-params {}
:header-params {}}
:champion-mastery-by-puuid-top
{:uri "https://euw1.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/:puuid/top"
:api-key :RIOT_LOL_KEY
:groups ["lol" "champion-mastery"]
:path-params {:puuid {:required true :type :string}}
:query-params {:count {:required false :type :int :default 3}}
:header-params {}}
;; champion v3
:champion-rotations
{:uri "https://euw1.api.riotgames.com/lol/platform/v3/champion-rotations"
:api-key :RIOT_LOL_KEY
:groups ["lol" "champion"]
:path-params {}
:query-params {}
:header-params {}}
;; summoner v4
:summoner-by-puuid
{:uri "https://euw1.api.riotgames.com/lol/summoner/v4/summoners/by-puuid/:puuid"
:api-key :RIOT_LOL_KEY
:groups ["lol" "summoner"]
:path-params {:puuid {:required true :type :string}}
:query-params {}
:header-params {}}
;; leage v4
:league-challenger-by-queue
{:uri "https://euw1.api.riotgames.com/lol/league/v4/challengerleagues/by-queue/:queue"
:api-key :RIOT_LOL_KEY
:groups ["lol" "league"]
:path-params {:queue {:required true :type :string}}
:query-params {}
:header-params {}}
:league-all-by-puuid
{:uri "https://euw1.api.riotgames.com/lol/league/v4/entries/by-puuid/:puuid"
:api-key :RIOT_LOL_KEY
:groups ["lol" "league"]
:path-params {:puuid {:required true :type :string}}
:query-params {}
:header-params {}}
:league-all-queue-tier-division
{:uri "https://euw1.api.riotgames.com/lol/league/v4/entries/:queue/:tier/:division"
:api-key :RIOT_LOL_KEY
:groups ["lol" "league"]
:path-params {:queue {:required true :type :string}
:tier {:required true :type :string}
:division {:required true :type :string}}
:query-params {:page {:required false :type :int :default 1}}
:header-params {}}
:league-grandmaster-by-queue
{:uri "https://euw1.api.riotgames.com/lol/league/v4/grandmasterleagues/by-queue/:queue"
:api-key :RIOT_LOL_KEY
:groups ["lol" "league"]
:path-params {:queue {:required true :type :string}}
:query-params {}
:header-params {}}
:league-by-id
{:uri "https://euw1.api.riotgames.com/lol/league/v4/leagues/:league-id"
:api-key :RIOT_LOL_KEY
:groups ["lol" "league"]
:path-params {:league-id {:required true :type :string}}
:query-params {}
:header-params {}}
:league-by-queue
{:uri "https://euw1.api.riotgames.com/lol/league/v4/masterleagues/by-queue/:queue"
:api-key :RIOT_LOL_KEY
:groups ["lol" "league"]
:path-params {:queue {:required true :type :string}}
:query-params {}
:header-params {}}
;; league-exp v4
:league-exp-by-queue-tier-division
{:uri "https://euw1.api.riotgames.com/lol/league-exp/v4/entries/:queue/:tier/:division"
:api-key :RIOT_LOL_KEY
:groups ["lol" "league"]
:path-params {:queue {:required true :type :string}
:tier {:required true :type :string}
:division {:required true :type :string}}
:query-params {:page {:required false :type :int :default 1}}
:header-params {}}
;; clash v1
:clash-by-puuid
{:uri "https://euw1.api.riotgames.com/lol/clash/v1/players/by-puuid/:puuid"
:api-key :RIOT_LOL_KEY
:groups ["lol" "clash"]
:path-params {:puuid {:required true :type :string}}
:query-params {}
:header-params {}}
:clash-by-team
{:uri "https://euw1.api.riotgames.com/lol/clash/v1/teams/:team-id"
:api-key :RIOT_LOL_KEY
:groups ["lol" "clash"]
:path-params {:team-id {:required true :type :string}}
:query-params {}
:header-params {}}
:clash-tournaments
{:uri "https://euw1.api.riotgames.com/lol/clash/v1/tournaments"
:api-key :RIOT_LOL_KEY
:groups ["lol" "clash"]
:path-params {}
:query-params {}
:header-params {}}
:clash-tournaments-by-team
{:uri "https://euw1.api.riotgames.com/lol/clash/v1/tournaments/by-team/:team-id"
:api-key :RIOT_LOL_KEY
:groups ["lol" "clash"]
:path-params {:team-id {:required true :type :string}}
:query-params {}
:header-params {}}
:clash-tournaments-by-tournament
{:uri "https://euw1.api.riotgames.com/lol/clash/v1/tournaments/:tournament-id"
:api-key :RIOT_LOL_KEY
:groups ["lol" "clash"]
:path-params {:tournament-id {:required true :type :int}}
:query-params {}
:header-params {}}
;; Match v5
:lol-matches-by-puuid
{:uri "https://europe.api.riotgames.com/lol/match/v5/matches/by-puuid/:puuid/ids"
:api-key :RIOT_LOL_KEY
:groups ["lol" "match"]
:path-params {:puuid {:required true :type :string}}
:query-params {:startTime {:required false :type :long}
:endTime {:required false :type :long}
:queue {:required false :type :int}
:type {:required false :type :string}
:start {:required false :type :int :default 0}
:count {:required false :type :int :default 20 :min 0 :max 100}}
:header-params {}}
:lol-match-replays-by-puuid
{:uri "https://europe.api.riotgames.com/lol/match/v5/matches/by-puuid/:puuid/replays"
:api-key :RIOT_LOL_KEY
:groups ["lol" "match"]
:path-params {:puuid {:required true :type :string}}
:query-params {}
:header-params {}}
:lol-match-by-id
{:uri "https://europe.api.riotgames.com/lol/match/v5/matches/:match-id"
:api-key :RIOT_LOL_KEY
:groups ["lol" "match"]
:path-params {:match-id {:required true :type :string}}
:query-params {}
:header-params {}}
:lol-match-timeline-by-id
{:uri "https://europe.api.riotgames.com/lol/match/v5/matches/:match-id/timeline"
:api-key :RIOT_LOL_KEY
:groups ["lol" "match"]
:path-params {:match-id {:required true :type :string}}
:query-params {}
:header-params {}}
;; LOL challenges v1
:lol-challenges-config
{:uri "https://euw1.api.riotgames.com/lol/challenges/v1/challenges/config"
:api-key :RIOT_LOL_KEY
:groups ["lol" "challenges"]
:path-params {}
:query-params {}
:header-params {}}
:lol-challenge-config-by-id
{:uri "https://euw1.api.riotgames.com/lol/challenges/v1/challenges/:challenge-id/config"
:api-key :RIOT_LOL_KEY
:groups ["lol" "challenges"]
:path-params {:challenge-id {:required true :type :long}}
:query-params {}
:header-params {}}
:lol-challenges-percentiles
{:uri "https://euw1.api.riotgames.com/lol/challenges/v1/challenges/percentiles"
:api-key :RIOT_LOL_KEY
:groups ["lol" "challenges"]
:path-params {}
:query-params {}
:header-params {}}
:lol-challenges-percentiles-by-id
{:uri "https://euw1.api.riotgames.com/lol/challenges/v1/challenges/:challenge-id/percentiles"
:api-key :RIOT_LOL_KEY
:groups ["lol" "challenges"]
:path-params {:challenge-id {:required true :type :long}}
:query-params {}
:header-params {}}
:lol-challenge-leaderboard
{:uri "https://euw1.api.riotgames.com/lol/challenges/v1/challenges/:challenge-id/leaderboards/by-level/:level"
:api-key :RIOT_LOL_KEY
:groups ["lol" "challenges"]
:path-params {:challenge-id {:required true :type :long}
:level {:required true :type #{"NONE" "IRON" "BRONZE" "SILVER" "GOLD" "PLATINUM" "DIAMOND" "MASTER" "GRANDMASTER" "CHALLENGER" "HIGHEST_NOT_LEADERBOARD_ONLY" "HIGHEST" "LOWEST"}}}
:query-params {:limit {:required false :type :int}}
:header-params {}}
:lol-challenge-by-puuid
{:uri "https://euw1.api.riotgames.com/lol/challenges/v1/player-data/:puuid"
:api-key :RIOT_LOL_KEY
:groups ["lol" "challenges"]
:path-params {:puuid {:required true :type :string}}
:query-params {}
:header-params {}}
;; LOL champion mastery v4
:lol-champion-mastery-by-puuid
{:uri "https://euw1.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/:puuid"
:api-key :RIOT_LOL_KEY
:groups ["lol" "champion-mastery"]
:path-params {:puuid {:required true :type :string}}
:query-params {}
:header-params {}}
:lol-champion-mastery-by-puuid-champion
{:uri "https://euw1.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/:puuid/by-champion/:champion-id"
:api-key :RIOT_LOL_KEY
:groups ["lol" "champion-mastery"]
:path-params {:puuid {:required true :type :string}
:champion-id {:required true :type :int}}
:query-params {}
:header-params {}}
:lol-champion-mastery-by-puuid-top
{:uri "https://euw1.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/:puuid/top"
:api-key :RIOT_LOL_KEY
:groups ["lol" "champion-mastery"]
:path-params {:puuid {:required true :type :string}}
:query-params {:count {:required false :type :int :default 3}}
:header-params {}}
:lol-champion-mastery-scores-by-puuid
{:uri "https://euw1.api.riotgames.com/lol/champion-mastery/v4/scores/by-puuid/:puuid"
:api-key :RIOT_LOL_KEY
:groups ["lol" "champion-mastery"]
:path-params {:puuid {:required true :type :string}}
:query-params {}
:header-params {}}
;; spectator v5
:lol-spectator
{:uri "https://euw1.api.riotgames.com/lol/spectator/v5/active-games/by-summoner/:puuid"
:api-key :RIOT_LOL_KEY
:groups ["lol" "spectator"]
:path-params {:puuid {:required true :type :string}}
:query-params {}
:header-params {}}
;;
;; TFT
;;
;; account v1
:tft-account-by-riot-id
{:uri "https://europe.api.riotgames.com/riot/account/v1/accounts/by-riot-id/:player-name/:player-tag"
:api-key :RIOT_TFT_KEY
:groups ["tft" "account"]
:path-params {:player-name {:required true :type :string}
:player-tag {:required true :type :string}}
:query-params {}
:header-params {}}
;; tft status v1
:tft-status
{:uri "https://euw1.api.riotgames.com/tft/status/v1/platform-data"
:api-key :RIOT_TFT_KEY
:groups ["tft" "status"]
:path-params {}
:query-params {}
:header-params {}}
;; TFT summoner v1
:tft-summoner-by-puuid
{:uri "https://euw1.api.riotgames.com/tft/summoner/v1/summoners/by-puuid/:puuid"
:api-key :RIOT_TFT_KEY
:groups ["tft" "summoner"]
:path-params {:puuid {:required true :type :string}}
:query-params {}
:header-params {}}
;; TFT match v1
:tft-matches-by-puuid
{:uri "https://europe.api.riotgames.com/tft/match/v1/matches/by-puuid/:puuid/ids"
:api-key :RIOT_TFT_KEY
:groups ["tft" "match"]
:path-params {:puuid {:required true :type :string}}
:query-params {:startTime {:required false :type :long}
:endTime {:required false :type :long}
:queue {:required false :type :int}
:type {:required false :type :string}
:start {:required false :type :int :default 0}
:count {:required false :type :int :default 20 :min 0 :max 100}}
:header-params {}}
:tft-match-by-id
{:uri "https://europe.api.riotgames.com/tft/match/v1/matches/:match-id"
:api-key :RIOT_TFT_KEY
:groups ["tft" "match"]
:path-params {:match-id {:required true :type :string}}
:query-params {}
:header-params {}}
;; TFT espectator v5
:tft-spectator
{:uri "https://euw1.api.riotgames.com/lol/spectator/tft/v5/active-games/by-puuid/:puuid"
:api-key :RIOT_TFT_KEY
:groups ["tft" "spectator"]
:path-params {:puuid {:required true :type :string}}
:query-params {}
:header-params {}}
;; TFT league v1
:tft-league-by-puuid
{:uri "https://euw1.api.riotgames.com/tft/league/v1/by-puuid/:puuid"
:api-key :RIOT_TFT_KEY
:groups ["tft" "spectator"]
:path-params {:puuid {:required true :type :string}}
:query-params {}
:header-params {}}
:tft-league-challenger
{:uri "https://euw1.api.riotgames.com/tft/league/v1/challenger"
:api-key :RIOT_TFT_KEY
:groups ["tft" "spectator"]
:path-params {}
:query-params {:ranked {:required false :type #{"RANKED_TFT" "RANKED_TFT_DOUBLE_UP"}}}
:header-params {}}
:tft-league-by-tier-division
{:uri "https://euw1.api.riotgames.com/tft/league/v1/entries/:tier/:division"
:api-key :RIOT_TFT_KEY
:groups ["tft" "league"]
:path-params {:tier {:required true :type :string}
:division {:required true :type :string}}
:query-params {:queue {:required false :type #{"RANKED_TFT" "RANKED_TFT_DOUBLE_UP"} :default "RANKED_TFT"}
:page {:required false :type int :default 1}}
:header-params {}}
:tft-league-grandmaster-by-queue
{:uri "https://euw1.api.riotgames.com/tft/league/v1/grandmaster"
:api-key :RIOT_TFT_KEY
:groups ["tft" "league"]
:path-params {}
:query-params {:queue {:required false :type #{"RANKED_TFT" "RANKED_TFT_DOUBLE_UP"} :default "RANKED_TFT"}}
:header-params {}}
:tft-league-master-by-queue
{:uri "https://euw1.api.riotgames.com/tft/league/v1/master"
:api-key :RIOT_TFT_KEY
:groups ["tft" "league"]
:path-params {}
:query-params {:queue {:required false :type #{"RANKED_TFT" "RANKED_TFT_DOUBLE_UP"} :default "RANKED_TFT"}}
:header-params {}}
:tft-league-top-rated-ladders
{:uri "https://euw1.api.riotgames.com/tft/league/v1/rated-ladders/:queue/top"
:api-key :RIOT_TFT_KEY
:groups ["tft" "league"]
:path-params {:queue {:required true :type :string}}
:query-params {}
:header-params {}}
;; END OF ENDPOINT DEFINITIONS
})

View File

@@ -0,0 +1,10 @@
(ns riot.core-test
#_{:clj-kondo/ignore [:refer-all]}
(:require [clojure.test :refer :all]
[tmpl.core :refer :all])
(:import (java.util Arrays)))
(deftest generate-greeting-test
(testing "Some test cases"
(is (generate-greeting nil nil)) ;; Not nill
(is (= "Hello test" (generate-greeting :medium "test")))))

View File

@@ -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>

View File

@@ -1,386 +0,0 @@
;; Main CLI application
(ns riot.app
(:require [cli-matic.core :refer [run-cmd]]
[cli-matic.utils :as U]
[clojure.pprint :as pp]
[clojure.string :as str]
[timewords.core :refer [parse]])
(:use [riot.core]
[riot.data]
[slingshot.slingshot :only [try+]])
(:gen-class))
(defn get-puuid-from-params
[api-key params & {:keys [puuid name tag]}]
;(println "get puuid API key" api-key)
(cond
(= 1 (count params)) (first params)
(= 2 (count params)) (get-puuid-from-name (first params) (second params) :api-key api-key)
(some? puuid) puuid
(and (some? name) (some? tag)) (get-puuid-from-name name tag :api-key api-key)))
(comment
(get-puuid-from-params (get-lol-api-key) [] :puuid "annlAfxhJnTwlwRgQZYbGeQpD3jWb-ju7vVKEW_g-EIJf6xQT0eeb-0obARVekrksf8n9XCjcxyHHQ")
(get-puuid-from-params (get-lol-api-key) [] :name "Errepunto" :tag "4595")
(get-puuid-from-params (get-tft-api-key) [] :puuid "annlAfxhJnTwlwRgQZYbGeQpD3jWb-ju7vVKEW_g-EIJf6xQT0eeb-0obARVekrksf8n9XCjcxyHHQ")
(get-puuid-from-params (get-tft-api-key) [] :name "Errepunto" :tag "4595"))
(defn cmd-active
"Checks if a player is online at the moment"
[& {:keys [lol-api-key tft-api-key debug-http _arguments]
:as opts}]
(try+
;(println "Check online" opts)
(let [lol-key (get-lol-api-key lol-api-key)
tft-key (get-tft-api-key tft-api-key)
lol-id (get-puuid-from-params lol-key _arguments opts)
tft-id (get-puuid-from-params tft-key _arguments opts)]
;(println "LOL API key" lol-key "TFT API key" tft-key)
(if (or (nil? lol-id) (nil? tft-id))
(U/exit! "Invalid params" 2)
(if (is-playing? lol-id tft-id :lol-api-key lol-key :tft-api-key tft-key :debug debug-http)
(println "Yes, it's playing")
(println "No, it's not playing right now"))))
(catch [:status 401] _
(U/exit! "Invalid API key" 3))
(catch [:status 404] _
(U/exit! "Unknown user or tag" 5))))
(comment
(cmd-active :_arguments ["annlAfxhJnTwlwRgQZYbGeQpD3jWb-ju7vVKEW_g-EIJf6xQT0eeb-0obARVekrksf8n9XCjcxyHHQ"])
(cmd-active :_arguments ["Errepunto" "4595"]))
(defn format-map
"Format result"
[output x]
(case output
"edn" (pp/pprint x)
"json" (println (as-json x))
"table" (as-ascii-table x)
"csv" (println (as-csv x))
(pp/pprint x))) ;edn as default
(comment
(format-map "json" riot.test-examples/matches-example)
(format-map "csv" riot.test-examples/matches-example2))
(defn format-dates-cond
[format-dates format-durations pattern x]
(let [dur (if format-durations
(with-parsed-durations x)
x)]
(if format-dates
(if (some? pattern)
(with-parsed-dates dur :datetime-format pattern)
(with-parsed-dates dur))
dur)))
(comment
(format-dates-cond false false nil riot.test-examples/matches-example2)
(format-dates-cond false true nil riot.test-examples/matches-example2)
(format-dates-cond true false nil riot.test-examples/matches-example2)
(format-dates-cond true true nil riot.test-examples/matches-example2))
(defn reverse-cond
[rev x] (if rev x (reverse x)))
(defn filter-today-cond
[only-today x] (if only-today (filter match-today? x) x))
(defn filter-columns
[columns x] (if (= "all" columns)
x
(map #(select-keys % (map keyword (str/split columns #","))) x)))
(comment
(filter-columns "all" riot.test-examples/matches-example2)
(filter-columns "start,end" riot.test-examples/matches-example2)
(map #(select-keys % (map keyword (str/split "start,end" #","))) riot.test-examples/matches-example2))
(defn get-date
[x]
(if (nil? x) nil (parse x)))
(defn cmd-timeline
"Get match "
[& {:keys [lol-api-key tft-api-key output count max-total format-dates format-durations date-format reverse order-by show-columns show-active debug-http only-today since until _arguments]
:as opts}]
(try+
;(println "Get timeline" opts)
(let [lol-key (get-lol-api-key lol-api-key)
tft-key (get-tft-api-key tft-api-key)
lol-id (get-puuid-from-params lol-key _arguments opts)
tft-id (get-puuid-from-params tft-key _arguments opts)]
;(println "LOL API key" lol-key "TFT API key" tft-key)
(if (or (nil? lol-id) (nil? tft-id))
(U/exit! "Invalid params" 2)
(->> (get-last-matches lol-id tft-id :lol-api-key lol-key :tft-api-key tft-key :count count :include-current show-active :debug debug-http :order-by (keyword order-by) :since (get-date since) :until (get-date until))
(filter-today-cond only-today)
(reverse-cond reverse)
(take count)
(format-dates-cond format-dates format-durations date-format)
(filter-columns show-columns)
(map)
(format-map 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))))
(comment
(cmd-timeline :_arguments ["dMNR4Aj5OW9jrGj0RUVBRuzfu77p3iO5y1W16ASNp1PI7pxuJWLz14b2pJiUn16DCPlyeREoi0MJ7Q"])
(cmd-timeline :_arguments ["Sarinailo" "EUW"]))
(defn cmd-bulk
"Get all matches"
[& {:keys [lol-api-key tft-api-key output format-dates format-durations date-format reverse order-by show-columns debug-http since until _arguments]
:as opts}]
(try+
;(println "Get timeline" opts)
(let [lol-key (get-lol-api-key lol-api-key)
tft-key (get-tft-api-key tft-api-key)
lol-id (get-puuid-from-params lol-key _arguments opts)
tft-id (get-puuid-from-params tft-key _arguments opts)]
;(println "LOL API key" lol-key "TFT API key" tft-key)
(if (or (nil? lol-id) (nil? tft-id))
(U/exit! "Invalid params" 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 (get-date since) :until (get-date until))
(reverse-cond reverse)
(format-dates-cond format-dates format-durations date-format)
(filter-columns show-columns)
(format-map 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 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"
:description ["Get how much time have you spent on LoL or FTF"
""
"Posible error codes:"
" 0: OK"
" 1: player not playing"
" 2: Invalid params"
" 3: Invalid API key, please, get 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"]
:version "1.0.0"}
: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}]
:commands [{:command "active" :short "a"
:description ["Shows if the player currently playing"
"You can search by PUUID or name and tagline, but not both."
""
"You can set the PUUID passing only one argument or using -p param."
"You can set the name and tag passing two arguments, or using -n and -t."]
:opts [{:option "puuid" :short "p"
:type :string
:as "Summonner's unique PUUID."}
{:option "name" :short "n"
:type :string :default nil
:as "Summoner name (Riot ID)"}
{:option "tag" :short "t"
:type :string :default nil
:as "Summoner tagline"}]
:runs cmd-active}
{:command "last" :short "l"
:description ["Gets time info from last matches."
"You can search by PUUID or name and tagline, but not both."
""
"You can set the PUUID passing only one argument or using -p param."
"You can set the name and tag passing two arguments, or using -n and -t."]
:opts [{:option "puuid" :short "p"
:type :string
:as "Summonner's unique PUUID."}
{:option "name" :short "n"
:type :string :default nil
:as "Summoner name (Riot ID)"}
{:option "tag" :short "t"
:type :string :default nil
:as "Summoner tagline"}
{:option "output" :short "o"
:type #{"edn" "json" "table" "csv"} :default "table"
:as ["Output type. It can be one of:"
" - edn: Clojure's internal EDN format"
" - json: Classic JSON"
" - table: ASCII table (by default)"
" - csv: CSV data, using ',' as field separator"]}
{:option "count" :short "c"
:type :int :default 10
:as "Max number of matches retrieved for each type of game (max value: 100)"}
;{:option "max-total" :short "m"
; :type :int :default 10
; :as "Max number of matches of all types, including current match"}
{: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 "show-active" :short "a"
:type :with-flag :default true
:as "Include current playing match"}
{: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"
" - active: Match is in course"
" - game-type: lol or tft"
" - id: Game unique id"
" - winner: Winner of the match"]}
{:option "only-today"
:type :flag :default false
:as "If true, only shows today played matches"}
{:option "since" :short "s"
:type :string :default nil
:as ["Starting date (included) in 'yyyy-MM-dd' format."
"Other valid values: today, yesterday"]}
{:option "until" :short "u"
:type :string :default nil
:as ["Ending date (not included) in 'yyyy-MM-dd' format."
"Other valid values: today, yesterday, tomorrow"]}]
:runs cmd-timeline}
{:command "timeline" :short "t"
:description ["Get info from LOL and TFT matches in a time range."
"Warning: it can take several minutes to obtain all data, due to api restrictions."
"You can search by PUUID or name and tagline, but not both."
""
"You can set the PUUID passing only one argument or using -p param."
"You can set the name and tag passing two arguments, or using -n and -t."]
:opts [{:option "puuid" :short "p"
:type :string
:as "Summonner's unique PUUID."}
{:option "name" :short "n"
:type :string :default nil
:as "Summoner name (Riot ID)"}
{:option "tag" :short "t"
:type :string :default nil
:as "Summoner tagline"}
{:option "output" :short "o"
:type #{"edn" "json" "table" "csv"} :default "table"
:as ["Output type. It can be one of:"
" - edn: Clojure's internal EDN format"
" - json: Classic JSON"
" - table: ASCII table (by default)"
" - 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 "only-today"
:type :flag :default false
:as "If true, only shows today played matches"}
{:option "since" :short "s"
:type :string :default nil
:as ["Starting date (included) in 'yyyy-MM-dd' format."
"Other valid values: today, yesterday, 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"]}]
:runs cmd-bulk}]})
(defn -main
"Main entry point"
[& args]
(run-cmd args CONFIGURATION))
(defn old-main
"Testing some basic things"
[& args]
(let [player "RdNVioNKYzvFuXI00zurL_8QvaU0E8P61NU0SzwIfbbHHk9HFvxLtSWiDHKuJ9iXb4UC0UUZ3ltLxw"]
;(println "API Key: " (get-lol-api-key))
(println "Last matches:")
(println "Player PUUID: " player)
;(as-json
;(as-ascii-table
; (with-parsed-dates
; (take 10
; (reverse
; (get-last-matches player :count 10 :print-not-active true)))))
(as-ascii-table
(with-parsed-dates-durations
; (filter match-today? ; Only today
(reverse (get-last-matches player :count 10 :print-not-active true))))
;)
))
(comment
; Launch manually
(-main)
(old-main))

View File

@@ -1,488 +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])
(: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-fc8c6d88-2c13-4a43-b53f-3465bb564acc")
(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)))
(comment
(get-in riot.test-examples/response-lol-match [:metadata :participants])
(get-in riot.test-examples/response-lol-match [:info :participants 3])
(get-player-info riot.test-examples/response-lol-match riot.test-examples/example-lol-puuid)
(winner? riot.test-examples/response-lol-match riot.test-examples/example-lol-puuid))
(defn with-winner-status
"Takes the original list of matches and parses durations"
[matches puuid]
(map #(assoc % :winner (winner? % puuid)) matches))
(comment
(with-winner-status riot.test-examples/matches-example riot.test-examples/example-lol-puuid))
;; 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))]
: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 "ftf"))
(make-json-data [:metadata :match_id] :id)
(make-json-data [:none] :winner (constantly false))]
: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))]})
(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 "ftf"))
(make-json-data [:gameId] :id)
(make-json-data [:none] :winner (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 **"))
;; (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}}]
;; (println "get lol start: " start)
(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}}]
(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)
(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)
(query
(create-endpoint server "/tft/match/v1/matches/" match-id)
tft-match-parser
:api-key api-key
:debug debug
:puuid puuid))
(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"}}]
(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")))))
(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"}}]
(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 FTF 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 FTF 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
(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)
(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")
(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 count order-by since until]
:or {lol-api-key (get-lol-api-key)
tft-api-key (get-tft-api-key)
wait-limit-exceeded 15
debug false
server "europe"
count 100
order-by :start}}]
(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)))))

View File

@@ -1,173 +0,0 @@
;; Parsing data
(ns riot.data
(:import [java.time Instant LocalDate ZoneId Duration]
[java.time.format DateTimeFormatter])
(:require [clojure.pprint :as pp]
[clojure.string :as str]
[cheshire.core :refer :all])
(:use [riot.core :refer :all])
(: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-to-datetime
"Conver from UNIX time in millis, to a ZonedDateTime"
[millis]
(when (some? millis)
(.atZone (Instant/ofEpochMilli millis) (ZoneId/systemDefault))))
(defn localdate-to-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 parse-localdate
"Parse a yyyy-MM-dd date to java.time.LocalDate"
[s]
(java.time.LocalDate/parse s (DateTimeFormatter/ofPattern DEFAULT_DATE_FORMAT)))
(defn parse-date-str
[s]
(localdate-to-date (parse-localdate s)))
(defn parse-date-epoch
[millis]
(localdate-to-date (unix-to-datetime 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-to-datetime millis) pattern))))
;; Parse durations
(defn format-duration-seconds
"Converts a duration in seconds to a string with hours 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) (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))))))
(comment
(with-parsed-dates riot.test-examples/matches-example))
(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}))
(comment
(println (as-json (with-parsed-dates-durations riot.test-examples/matches-example
:pretty false))))
(defn as-ascii-table
"Export as ascii table"
[matches]
(pp/print-table matches))
(comment
(as-ascii-table riot.test-examples/matches-example)
(as-ascii-table (with-parsed-dates-durations riot.test-examples/matches-example)))
(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))))))
(comment
(as-csv riot.test-examples/matches-example)
(as-csv riot.test-examples/matches-example2)
(as-csv (with-parsed-dates-durations riot.test-examples/matches-example))
(as-csv (with-parsed-dates-durations riot.test-examples/matches-example2)))

View File

@@ -1,299 +0,0 @@
(ns riot.core-test
(:require [clojure.test :refer :all]
[riot.test-examples :refer :all]
[riot.core :refer :all]
[timewords.core :refer [parse]]
[clojure.pprint :as pp])
(:use [slingshot.slingshot :only [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 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 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 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 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))))

View File

@@ -1,119 +0,0 @@
(ns riot.data-test
(:require [clojure.test :refer :all]
[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 test-unix-to-datetime
(println "* Epoch millis to java.util.Datetime *")
(testing "Get LOL API key"
(is (= (ZonedDateTime/of 2025 4 3 0 0 0 0 (ZoneId/systemDefault))
(unix-to-datetime 1743631200000)))))
;; Format a LocalDateTime o ZonedDateTime as a String
(deftest test-format-datetime
(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-to-datetime 1743631200000)))))
(testing "Personalized time formats"
(is (= "2025-04-03"
(format-datetime (unix-to-datetime 1743631200000) "yyyy-MM-dd")))
(is (= "00:00"
(format-datetime (unix-to-datetime 1743631200000) "HH:00")))))
;; Format a epoch in millis as a String
(deftest 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)))))
;; Epoch in millis for today at 00:00:00 hours. Difficult to test
(deftest 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 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 test-with-parsed-dates
(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 test-with-parsed-dates
(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", :active true, :game-type "lol", :id "EUW1_111111"})
(with-parsed-dates-durations (take 1 matches-example))))))

File diff suppressed because it is too large Load Diff

6
tests.edn Normal file
View File

@@ -0,0 +1,6 @@
#kaocha/v1
{:tests [{:test-paths ["projects/core/src" "projects/core/test"]}]
:plugins [:kaocha.plugin/cloverage]
:cloverage/opts {:src-ns-path ["projects/core/src" "projects/core/test"]
:ns-regex ["tmpl\\..*(?<!test)$"] ;; All starting with "totp" but not ending by "test"
}}