]> gitweb.ps.run Git - lolstats/commitdiff
sass
authorPatrick Schönberger <patrick.schoenberger@posteo.de>
Thu, 13 Dec 2018 09:57:10 +0000 (10:57 +0100)
committerPatrick Schönberger <patrick.schoenberger@posteo.de>
Thu, 13 Dec 2018 09:57:10 +0000 (10:57 +0100)
server champions und regionen
matches angefangen

html/index.html
html/script.js
html/style.css
html/style.sass [new file with mode: 0644]
index.js
package-lock.json
package.json

index d35e28fd37052fcf0368bd3725ed0020b2757e89..25d8fce19075ac55c5e92a7b1a7943d114efd36b 100644 (file)
@@ -2,6 +2,7 @@
 <html>
   <head>
     <meta charset="utf-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />
     <title>Advanced League of Legends Match History & Statistics</title>
     <link href="https://fonts.googleapis.com/css?family=Noto+Sans+SC:700" rel="stylesheet">
     <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">
@@ -23,7 +24,7 @@
         -->
         <div id="inputpanel">
           <select id="regionselect">
-            <option v-for="r in regions" :value="r">{{ r }}</option>
+            <option v-for="(url, name) in regions" :value="name">{{ name }}</option>
           </select>
           <input v-on:keyup.enter="submit" id="nameinput" type="text" placeholder="Summoner Name">
           <button v-on:click="submit" id="gobutton"><span class="fas fa-arrow-right"></span></button>
           <label for="champselect">Champion</label>
           <select id="champselect">
             <option>All</option>
-            <option v-for="c in champions">{{ c.name }}</option>
+            <option v-for="c in champions">{{ c }}</option>
           </select>
           <button id="refreshbutton" v-on:click="refreshHistory">Refresh</button>
         </div>
+        <hr />
         <div id="matchlist">
           <table>
             <tr>
index 25f1565c26f2f69cc3f5805cd2cc4c7f0054bfae..a10dd69025fc42e1d9c09c3eb3cfeeefc600f81e 100644 (file)
@@ -1,8 +1,14 @@
 function getRegions() {
-  return [ "euw", "na", "kr", "br" ];
+  $.ajax("/lol/regions")
+    .done((data) => {
+      app.regions = JSON.parse(data);
+    });
 }
 function getChampions() {
-  return [ {name: "Aatrox"}, {name: "Annie"}, {name: "Braum"}, {name: "Not"} ];
+  $.ajax("/lol/champions")
+    .done((data) => {
+      app.champions = JSON.parse(data);
+    });
 }
 function getMatchProps() {
   return [
@@ -11,10 +17,10 @@ function getMatchProps() {
   ];
 }
 function getMatches() {
-  return [
-    {champ: "Xerath", lane: "Middle"},
-    {champ: "Quinn", lane: "Bottom"},
-  ];
+  $.ajax("/lol/matches?region=" + app.region + "&summoner=" + app.summoner);
+    .done((data) => {
+      app.matches = JSON.parse(data);
+    });
 }
 function getInfo() {
   app.summoner = $("#nameinput").val();
@@ -92,10 +98,10 @@ let app = new Vue({
     summoner: "",
     region: "",
     view: "",
-    regions: getRegions(),
-    champions: getChampions(),
-    matchprops: getMatchProps(),
-    matches: getMatches(),
+    regions: [],
+    champions: [],
+    matchprops: [],
+    matches: [],
   },
   methods: {
     submit: function() {
@@ -113,6 +119,7 @@ let app = new Vue({
       setUrl();
     },
     refreshHistory: function() {
+      getMatches();
     },
   },
 });
@@ -145,4 +152,6 @@ window.addEventListener('popstate', () => {
 window.addEventListener('load', () => {
   let view = parseUrl();
   setView(view);
+  getRegions();
+  getChampions();
 });
index b012d2216b44758541fa141e5ded86b5bbb8027f..6145c2da5fe14c26ed98b2ce6c48b20424f82c34 100644 (file)
@@ -1,70 +1,40 @@
 body {
-  font-family: 'Noto Sans SC', sans-serif;
+  font-family: "Noto Sans SC", sans-serif;
   font-weight: bold;
   padding: 0px;
   margin: 0px;
 }
+
 #background {
   position: fixed;
   width: 100%;
   height: 100%;
-  background-color: rgb(200, 50, 50);
+  background-color: #c83232;
   box-shadow: 0 0 400px rgba(0, 0, 0, 0.6) inset;
 }
-input, select, button {
-  font-size:inherit;
-  border: none;
-}
-@keyframes startup {
-  0% {
-    top: 50%;
-    transform: translate(-50%, -50%);
-    width: 65%;
-  }
-  100% {
-    top: 0%;
-    transform: translate(-50%, 0%);
-    width: calc(100% - 20px);
-  }
-}
-@keyframes startdown {
-  100% {
-    top: 50%;
-    transform: translate(-50%, -50%);
-    width: 65%;
-  }
-  0% {
-    top: 0%;
-    transform: translate(-50%, 0%);
-    width: calc(100% - 20px);
-  }
-}
-#start.slideup {
-  animation: startup 0.3s forwards linear;
-}
-#start.slidedown {
-  animation: startdown 0.3s forwards linear;
-}
-#start.up {
-  top: 0%;
-  transform: translate(-50%, 0%);
-  width: calc(100% - 20px);
-}
-#start.down {
-  top: 50%;
-  transform: translate(-50%, -50%);
-  width: 65%;
-}
+
 #start {
   position: absolute;
-  width: 65%;
-  left: 50%;
+  margin: 7px;
+  left: calc(50% - 7px);
   top: 50%;
   transform: translate(-50%, -50%);
-  padding: 10px;
   text-align: center;
   background-color: transparent;
-  font-size: 5rem;
+  border-radius: 4px;
+  background-color: white;
+  box-shadow: 1px 1px 40px rgba(0, 0, 0, 0.8);
+}
+
+@media only screen and (orientation: landscape) {
+  #start {
+    width: 65%;
+  }
+}
+@media only screen and (orientation: portrait) {
+  #start {
+    width: 85%;
+  }
 }
 #title {
   width: 100%;
@@ -72,89 +42,176 @@ input, select, button {
   text-shadow: 1px 1px 40px black;
   user-select: none;
 }
+
 #inputpanel {
-  border-radius: 5px;
-  width: calc(100% - 20px);
-  height: 50px;
-  background-color: white;
-  padding: 10px;
-  box-shadow: 1px 1px 40px rgba(0, 0, 0, 0.8);
-  font-size: 2rem;
+  width: calc(100% - 14px);
+  height: 7vmin;
+  font-size: 4.5vmin;
   position: relative;
+  margin: 7px;
 }
-#regionselect {
-  width: 110px;
-  height: 50px;
+
+#matchhistory, #stats {
+  position: absolute;
+  font-size: 2.5vmin;
+  width: calc(100% - 14px);
+  min-height: calc(100% - (7vmin + 21px) - 14px);
+  margin: 7px;
+  top: calc(7vmin + 21px);
+  background-color: white;
+  border-radius: 4px;
+  text-align: center;
+}
+
+#historyfilters {
   position: relative;
-  top: 0px;
-  padding: 0px 0px 0px 10px;
-  margin: 5px;
+  width: calc(100% - 14px);
+  height: calc(21vmin + 14px);
+  margin: 7px;
+}
+
+#matchlist {
+  width: calc(100% - 14px);
+  margin: 7px;
+  height: auto;
+}
+
+hr {
+  margin: 0;
+}
+
+select {
   text-align: center;
-  background-color: rgb(200, 50, 50);
+}
+
+select:hover {
+  background-color: #b41e1e;
+}
+
+select > option {
+  background-color: #c83232;
+}
+
+input {
+  border: none;
+  outline: none;
+  font-size: inherit;
+}
+
+button, select {
+  vertical-align: baseline;
+  width: 18vmin;
+  height: 7vmin;
+  background-color: #c83232;
   color: white;
-  border-radius: 5px;
+  border-radius: 4px;
   border: none;
   outline: none;
+  font-size: inherit;
+}
+
+button:hover {
+  background-color: #b41e1e;
+}
+
+.bottom-right {
+  position: absolute;
+  right: 0px;
+  bottom: 0px;
+}
+
+#regionselect {
   text-transform: uppercase;
   position: absolute;
-  left: 5px;
-  top: 5px;
+  left: 0;
   z-index: 1;
 }
-#regionselect:hover {
-  background-color: rgb(180, 30, 30);
-}
-#regionselect>option {
-  background-color: rgb(200, 50, 50);
-}
+
 #nameinput {
   text-align: center;
   border-bottom: 1px solid lightgray;
-  outline: none;
-  margin: 5px;
-  width: calc(100% - 220px - 10px);
-  height: 50px;
+  width: calc(100% - 36vmin);
+  height: 7vmin;
   position: absolute;
-  left: 110px;
-  top: 5px;
+  left: 18vmin;
+  top: 0px;
 }
+
 #gobutton, #statsbutton, #historybutton {
   position: absolute;
-  top: 5px;
-  right: 5px;
+  margin: 0px;
+  top: 0px;
+  right: 0px;
   z-index: 1;
 }
+
 #refreshbutton {
   position: absolute;
-  right: 5px;
-  bottom: 5px;
+  right: 0px;
+  bottom: 0px;
 }
-button {
-  vertical-align: baseline;
-  margin: 5px;
-  width: 110px;
-  height: 50px;
-  background-color: rgb(200, 50, 50);
-  color: white;
-  border-radius: 5px;
-  outline: none;
+
+@keyframes startup {
+  0% {
+    top: 50%;
+    transform: translate(-50%, -50%);
+    @media only screen and (orientation: landscape) {
+      width: 65%;
+    }
+    @media only screen and (orientation: portrait) {
+      width: 85%;
+    }
+  }
+  100% {
+    top: 0%;
+    transform: translate(-50%, 0%);
+    width: calc(100% - 14px);
+  }
+}
+@keyframes startdown {
+  100% {
+    top: 50%;
+    transform: translate(-50%, -50%);
+    @media only screen and (orientation: landscape) {
+      width: 65%;
+    }
+    @media only screen and (orientation: portrait) {
+      width: 85%;
+    }
+  }
+  0% {
+    top: 0%;
+    transform: translate(-50%, 0%);
+    width: calc(100% - 14px);
+  }
 }
-#gobutton:hover {
-  background-color: rgba(180, 30, 30);
+#start.slideup {
+  animation: startup 0.3s forwards linear;
 }
-#matchhistory, #stats {
-  position: absolute;
-  width: calc(100% - 20px);
-  min-height: calc(100% - 90px - 10px);
-  margin: 10px;
-  top: 80px;
-  background-color: white;
-  border-radius: 5px;
-  text-align: center;  
-  overflow: visible;
+
+#start.slidedown {
+  animation: startdown 0.3s forwards linear;
 }
-.bottom-right {
-  position: absolute;
-  right: 0px;
-  bottom: 0px;
+
+#start.up {
+  top: 0;
+  width: calc(100% - 14px);
+  transform: translate(-50%, 0%);
+}
+
+#start.down {
+  top: 50%;
+  transform: translate(-50%, -50%);
+}
+@media only screen and (orientation: landscape) {
+  #start.down {
+    width: 65%;
+  }
+}
+@media only screen and (orientation: portrait) {
+  #start.down {
+    width: 85%;
+  }
 }
+
+/*# sourceMappingURL=style.css.map */
diff --git a/html/style.sass b/html/style.sass
new file mode 100644 (file)
index 0000000..cf15189
--- /dev/null
@@ -0,0 +1,158 @@
+$widget-width: 18vmin
+$widget-height: 7vmin
+$color1: rgb(200, 50, 50)
+$color1-dark: rgb(180, 30, 30)
+$color2: white
+$font-size1: 4.5vmin
+$font-size2: 2.5vmin
+$margin: 7px
+$border: 4px
+
+body
+  font-family: 'Noto Sans SC', sans-serif
+  font-weight: bold
+  padding: 0px
+  margin: 0px
+#background
+  position: fixed
+  width: 100%
+  height: 100%
+  background-color: $color1
+  box-shadow: 0 0 400px rgba(0, 0, 0, 0.6) inset
+#start
+  position: absolute
+  margin: $margin
+  left: calc(50% - #{$margin})
+  top: 50%
+  transform: translate(-50%, -50%)
+  text-align: center
+  background-color: transparent
+  border-radius: $border
+  background-color: $color2
+  box-shadow: 1px 1px 40px rgba(0, 0, 0, 0.8)
+@media only screen and (orientation: landscape)
+  #start
+    width: 65%
+@media only screen and (orientation: portrait)
+  #start
+    width: 85%
+#title
+  width: 100%
+  color: $color2
+  text-shadow: 1px 1px 40px black
+  user-select: none
+#inputpanel
+  width: calc(100% - #{2 * $margin})
+  height: $widget-height
+  font-size: $font-size1
+  position: relative
+  margin: $margin
+#matchhistory, #stats
+  position: absolute
+  font-size: $font-size2
+  width: calc(100% - #{2 * $margin})
+  min-height: calc(100% - (#{$widget-height} + #{3 * $margin}) - #{2 * $margin})
+  margin: $margin
+  top: calc(#{$widget-height} + #{3 * $margin})
+  background-color: $color2
+  border-radius: $border
+  text-align: center
+#historyfilters
+  position: relative
+  width: calc(100% - #{2 * $margin})
+  height: calc(#{3 * $widget-height} + #{2 * $margin})
+  margin: $margin
+#matchlist
+  width: calc(100% - #{2 * $margin})
+  margin: $margin
+  height: auto
+hr
+  margin: 0
+select
+  text-align: center
+select:hover
+  background-color: $color1-dark
+select>option
+  background-color: $color1
+input
+  border: none
+  outline: none
+  font-size: inherit
+button, select
+  vertical-align: baseline
+  width: $widget-width
+  height: $widget-height
+  background-color: $color1
+  color: $color2
+  border-radius: $border
+  border: none
+  outline: none
+  font-size: inherit
+button:hover
+  background-color: $color1-dark
+.bottom-right
+  position: absolute
+  right: 0px
+  bottom: 0px
+#regionselect
+  text-transform: uppercase
+  position: absolute
+  left: 0
+  z-index: 1
+#nameinput
+  text-align: center
+  border-bottom: 1px solid lightgray
+  width: calc(100% - #{2 * $widget-width})
+  height: $widget-height
+  position: absolute
+  left: $widget-width
+  top: 0px
+#gobutton, #statsbutton, #historybutton
+  position: absolute
+  margin: 0px
+  top: 0px
+  right: 0px
+  z-index: 1
+#refreshbutton
+  position: absolute
+  right: 0px
+  bottom: 0px
+@keyframes startup
+  0%
+    top: 50%
+    transform: translate(-50%, -50%)
+    @media only screen and (orientation: landscape)
+      width: 65%
+    @media only screen and (orientation: portrait)
+      width: 85%
+  100%
+    top: 0%
+    transform: translate(-50%, 0%)
+    width: calc(100% - #{2 * $margin})
+@keyframes startdown
+  100%
+    top: 50%
+    transform: translate(-50%, -50%)
+    @media only screen and (orientation: landscape)
+      width: 65%
+    @media only screen and (orientation: portrait)
+      width: 85%
+  0%
+    top: 0%
+    transform: translate(-50%, 0%)
+    width: calc(100% - #{2 * $margin})
+#start.slideup
+  animation: startup 0.3s forwards linear
+#start.slidedown
+  animation: startdown 0.3s forwards linear
+#start.up
+  top: 0
+  width: calc(100% - #{2 * $margin})
+  transform: translate(-50%, 0%)
+#start.down
+  top: 50%
+  transform: translate(-50%, -50%)
+  @media only screen and (orientation: landscape)
+    width: 65%
+  @media only screen and (orientation: portrait)
+    width: 85%
index 3cc465ebf78b80163463c15a494ba450bf67a7d8..e9cc8c5a6c648f1b779b1188c82e5b666f19d3bf 100644 (file)
--- a/index.js
+++ b/index.js
@@ -1,8 +1,16 @@
 const express = require("express")
-const JavaScriptObfuscator = require("javascript-obfuscator");
 const fs = require("fs")
+const request = require("request-promise-native")
 const app = express()
 const port = 3000
+const sleep = require('util').promisify(setTimeout)
+
+const patch = "8.24.1";
+const key = "RGAPI-c6cae96a-c4b0-4842-9017-ddd736f3f628";
+let appRateLimit1;
+let appRateLimit120;
+let appRateLimitCount1;
+let appRateLimitCount120;
 
 let rules = [
   ["/lol", "index.html"],
@@ -10,36 +18,121 @@ let rules = [
   ["/lol/style.css", "style.css"],
 ];
 
-let obfuscateJs = false;
-
-function obfuscate(data) {
-  let obfResult = JavaScriptObfuscator.obfuscate(
-    String(data),
-    {
-      compact: true,
-      identifierNamesGenerator: "mangled",
-    }
-  );
-
-  return obfResult.getObfuscatedCode();
-}
-
 for (i in rules) {
   let path = rules[i][0];
   let file = rules[i][1];
   app.get(path, (req, res) => {
-    if (file.endsWith(".js") && obfuscateJs) {
-      fs.readFile("html/" + file, (err, data) => {
-        if (err) throw err;
-
-        let obf = obfuscate(data);
-        res.send(obf);
-      });
-    } else {
-      res.sendFile(__dirname + "/html/" + file);
-    }
+    res.sendFile(__dirname + "/html/" + file);
+  });
+}
+
+async function riotRequest(region, url, params, retries) {
+  if (retries < 1) throw "Error too many tries";
+  let req = "https://" + regions[region] + url + "?api_key=" + key;
+  for (p in params) {
+    req += "&" + p + "=" + params[p];
+  }
+  try {
+    let result = await request({uri: req, resolveWithFullResponse: true, json: true});
+    let appRateLimit = result.headers["x-app-rate-limit"];
+    let appRateLimitCount = result.headers["x-app-rate-limit-count"];
+    appRateLimit1 = appRateLimit.split(",")[0].split(":")[0];
+    appRateLimit120 = appRateLimit.split(",")[1].split(":")[0];
+    appRateLimitCount1 = appRateLimitCount.split(",")[0].split(":")[0];
+    appRateLimitCount120 = appRateLimitCount.split(",")[1].split(":")[0];
+    let delay1 = 1000 / (appRateLimit1 - 1);
+    let delay120 = 120000 / (appRateLimit120 - 1);
+    await sleep(Math.max(delay1, delay120));
+    console.log(Math.max(delay1, delay120));
+    return result.body;
+  } catch (err) {
+    console.log(err.message);
+    return await riotRequest(region, url, params, retries - 1);
+  }
+}
+
+async function getAllMatches(region, accountId) {
+  let matches = [];
+  let totalGames;
+  let bI = 0, eI = 99;
+
+  do {
+    let m = await riotRequest(region, "/lol/match/v4/matchlists/by-account/" + accountId, { beginIndex: bI, endIndex: eI }, 5);
+    console.log(m);
+    totalGames = m.totalGames;
+    matches = matches.concat(m.matches);
+    console.log("Added games " + bI + " to " + eI + ", " + matches.length + " of " + totalGames);
+    bI = eI + 1;
+    eI += 100;
+  } while (bI <= totalGames);
+
+  return matches;
+}
+
+// Static Data
+// -----------
+
+const regions = {
+  "BR": "br1.api.riotgames.com",
+  "EUNE": "eun1.api.riotgames.com",
+  "EUW": "euw1.api.riotgames.com",
+  "JP": "jp1.api.riotgames.com",
+  "KR": "kr.api.riotgames.com",
+  "LAN": "la1.api.riotgames.com",
+  "LAS": "la2.api.riotgames.com",
+  "NA": "na1.api.riotgames.com",
+  "OCE": "oc1.api.riotgames.com",
+  "TR": "tr1.api.riotgames.com",
+  "RU": "ru.api.riotgames.com",
+  "PBE": "pbe1.api.riotgames.com",
+};
+app.get("/lol/regions", (req, res) => {
+  res.send(JSON.stringify(regions));
+});
+let champions = null;
+function getChampions(cb) {
+  request("http://ddragon.leagueoflegends.com/cdn/" + patch + "/data/en_US/champion.json", (err, res, body) => {
+    champions = JSON.parse(body).data;
+    cb();
   });
 }
+app.get("/lol/champions", (req, res) => {
+  if (champions == null)
+    getChampions(() => {
+      res.send(JSON.stringify(Object.keys(champions)));
+    });
+  else
+    res.send(JSON.stringify(Object.keys(champions)));
+});
+let users = {};
+if (fs.existsSync("users.js")) {
+  fs.readFile("users.js", (err, data) => {
+    users = JSON.parse(data);
+  });
+}
+app.get("/lol/matches", async (req, res) => {
+  let region = req.query.region;
+  let summoner = req.query.summoner;
+  let regionUrl = regions[region];
+  try {
+    let data = await riotRequest(region, "/lol/summoner/v4/summoners/by-name/" + summoner, {}, 5);
+    let accountId = data.accountId;
+    if (users[accountId]) {
+      res.send(JSON.stringify(users[accountId]));
+      return;
+    }
+    let matches = await getAllMatches(region, accountId);
+    users[accountId] = matches;
+    fs.writeFile("users.js", JSON.stringify(users), (err) => {
+      console.log("Error writing file: " + err);
+    });
+    res.send(matches);
+  } catch (err) {
+    console.log(err);
+  }
+});
+
+// -----------
 
 app.listen(port, () => {
   console.log("Listening on port %d", port)
index cedffb8b9c5f030c0608737890b841a4ea5b5fa2..6f5b31184b4aab345273bfe9e8dfaa87255022fa 100644 (file)
         "uuid": "^3.3.2"
       }
     },
+    "request-promise-core": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.1.tgz",
+      "integrity": "sha1-Pu4AssWqgyOc+wTFcA2jb4HNCLY=",
+      "requires": {
+        "lodash": "^4.13.1"
+      }
+    },
+    "request-promise-native": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.5.tgz",
+      "integrity": "sha1-UoF3D2jgyXGeUWP9P6tIIhX0/aU=",
+      "requires": {
+        "request-promise-core": "1.1.1",
+        "stealthy-require": "^1.1.0",
+        "tough-cookie": ">=2.3.3"
+      }
+    },
     "restore-cursor": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz",
       "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
       "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
     },
+    "stealthy-require": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
+      "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
+    },
     "string-template": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/string-template/-/string-template-1.0.0.tgz",
index 3cf8065a76a97315a6457d9916abbf00da8eeaa7..aabe1b7c748215f34cd70375be7da2ce67ecbd59 100644 (file)
@@ -8,6 +8,7 @@
     "express": "^4.16.4",
     "javascript-obfuscator": "^0.18.1",
     "request": "^2.88.0",
+    "request-promise-native": "^1.0.5",
     "sqlite3": "^4.0.4"
   },
   "devDependencies": {},