A suite to track Project Diva score statistics and ratings / D4DJ event data.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
projectdivar/frontend/src/App.js

1984 lines
168 KiB

import React, {useState,useEffect,useRef} from 'react';
import logo from './logo.svg';
import './App.css';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useRouteMatch,
useParams,
useHistory
} from "react-router-dom";
import {
Modal,
Button,
Form,
Badge
} from "react-bootstrap";
const REMOTE_ADDR = "http://45.33.13.215:4502";
const axios = require('axios');
var IMAGE_CAMERA=(p)=>{
return(
<svg {...p} width="1em" height="1em" viewBox="0 0 16 16" className="bi bi-camera-fill link cursor" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d="M10.5 8.5a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0z"/>
<path fillRule="evenodd" d="M2 4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2h-1.172a2 2 0 0 1-1.414-.586l-.828-.828A2 2 0 0 0 9.172 2H6.828a2 2 0 0 0-1.414.586l-.828.828A2 2 0 0 1 3.172 4H2zm.5 2a.5.5 0 1 0 0-1 .5.5 0 0 0 0 1zm9 2.5a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0z"/>
</svg>
)
}
var IMAGE_BUG=(p)=>{
return(
<svg width="1em" height="1em" viewBox="0 0 16 16" className="bi bi-bug-fill" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fillRule="evenodd" d="M4.978.855a.5.5 0 1 0-.956.29l.41 1.352A4.985 4.985 0 0 0 3 6h10a4.985 4.985 0 0 0-1.432-3.503l.41-1.352a.5.5 0 1 0-.956-.29l-.291.956A4.978 4.978 0 0 0 8 1a4.979 4.979 0 0 0-2.731.811l-.29-.956zM13 6v1H8.5v8.975A5 5 0 0 0 13 11h.5a.5.5 0 0 1 .5.5v.5a.5.5 0 1 0 1 0v-.5a1.5 1.5 0 0 0-1.5-1.5H13V9h1.5a.5.5 0 0 0 0-1H13V7h.5A1.5 1.5 0 0 0 15 5.5V5a.5.5 0 0 0-1 0v.5a.5.5 0 0 1-.5.5H13zm-5.5 9.975V7H3V6h-.5a.5.5 0 0 1-.5-.5V5a.5.5 0 0 0-1 0v.5A1.5 1.5 0 0 0 2.5 7H3v1H1.5a.5.5 0 0 0 0 1H3v1h-.5A1.5 1.5 0 0 0 1 11.5v.5a.5.5 0 1 0 1 0v-.5a.5.5 0 0 1 .5-.5H3a5 5 0 0 0 4.5 4.975z"/>
</svg>
)
}
var IMAGE_CONTROLLER=(p)=>{
return(
<svg width="1em" height="1em" {...p} viewBox="0 0 16 16" className="bi bi-controller" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fillRule="evenodd" d="M11.119 2.693c.904.19 1.75.495 2.235.98.407.408.779 1.05 1.094 1.772.32.733.599 1.591.805 2.466.206.875.34 1.78.364 2.606.024.815-.059 1.602-.328 2.21a1.42 1.42 0 0 1-1.445.83c-.636-.067-1.115-.394-1.513-.773a11.307 11.307 0 0 1-.739-.809c-.126-.147-.25-.291-.368-.422-.728-.804-1.597-1.527-3.224-1.527-1.627 0-2.496.723-3.224 1.527-.119.131-.242.275-.368.422-.243.283-.494.576-.739.81-.398.378-.877.705-1.513.772a1.42 1.42 0 0 1-1.445-.83c-.27-.608-.352-1.395-.329-2.21.024-.826.16-1.73.365-2.606.206-.875.486-1.733.805-2.466.315-.722.687-1.364 1.094-1.772.486-.485 1.331-.79 2.235-.98.932-.196 2.03-.292 3.119-.292 1.089 0 2.187.096 3.119.292zm-6.032.979c-.877.185-1.469.443-1.733.708-.276.276-.587.783-.885 1.465a13.748 13.748 0 0 0-.748 2.295 12.351 12.351 0 0 0-.339 2.406c-.022.755.062 1.368.243 1.776a.42.42 0 0 0 .426.24c.327-.034.61-.199.929-.502.212-.202.4-.423.615-.674.133-.156.276-.323.44-.505C4.861 9.97 5.978 9.026 8 9.026s3.139.943 3.965 1.855c.164.182.307.35.44.505.214.25.403.472.615.674.318.303.601.468.929.503a.42.42 0 0 0 .426-.241c.18-.408.265-1.02.243-1.776a12.354 12.354 0 0 0-.339-2.406 13.753 13.753 0 0 0-.748-2.295c-.298-.682-.61-1.19-.885-1.465-.264-.265-.856-.523-1.733-.708-.85-.179-1.877-.27-2.913-.27-1.036 0-2.063.091-2.913.27z"/>
<path d="M11.5 6.026a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0zm-1 1a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0zm2 0a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0zm-1 1a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0zm-7-2.5h1v3h-1v-3z"/>
<path d="M3.5 6.526h3v1h-3v-1zM3.051 3.26a.5.5 0 0 1 .354-.613l1.932-.518a.5.5 0 0 1 .258.966l-1.932.518a.5.5 0 0 1-.612-.354zm9.976 0a.5.5 0 0 0-.353-.613l-1.932-.518a.5.5 0 1 0-.259.966l1.932.518a.5.5 0 0 0 .612-.354z"/>
</svg>
)
}
var IMAGE_ARCADE=(p)=>{
return(
<svg width="1em" height="1em" {...p} viewBox="0 0 16 16" className="bi bi-joystick" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d="M7.106 15.553L.553 12.276A1 1 0 0 1 0 11.382V9.471a1 1 0 0 1 .606-.89L6 6.269v1.088L1 9.5l5.658 2.83a3 3 0 0 0 2.684 0L15 9.5l-5-2.143V6.27l5.394 2.312a1 1 0 0 1 .606.89v1.911a1 1 0 0 1-.553.894l-6.553 3.277a2 2 0 0 1-1.788 0z"/>
<path fillRule="evenodd" d="M7.5 9.5v-6h1v6h-1z"/>
<path d="M10 9.75c0 .414-.895.75-2 .75s-2-.336-2-.75S6.895 9 8 9s2 .336 2 .75zM10 2a2 2 0 1 1-4 0 2 2 0 0 1 4 0z"/>
</svg>
)
}
var IMAGE_TABLET=(p)=>{
return(
<svg width="1em" height="1em" {...p} viewBox="0 0 16 16" className="bi bi-tablet-landscape" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path fillRule="evenodd" d="M1 4v8a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1zm-1 8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H2a2 2 0 0 0-2 2v8z"/>
<path fillRule="evenodd" d="M14 8a1 1 0 1 0-2 0 1 1 0 0 0 2 0z"/>
</svg>
)
}
var IMAGE_MIXMODE=(p)=>{
return(
<svg width="1em" height="1em" {...p} viewBox="0 0 16 16" className="bi" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<g
stroke="none"
strokeWidth="1"
fillRule="evenodd"
id="g22"
transform="matrix(0.23504594,0.08739104,-0.08739104,0.23504594,7.4047351,-0.89601877)">
<g
id="g20">
<g
transform="translate(26,16)"
id="g10">
<path
d="m 6,28 c -2.7614237,0 -5,-2.238576 -5,-5 0,-2.761424 2.2385763,-5 5,-5 2.7614238,0 5,2.238576 5,5 0,2.761424 -2.2385762,5 -5,5 z m 0,-2 c 1.6568543,0 3,-1.343146 3,-3 0,-1.656854 -1.3431457,-3 -3,-3 -1.6568543,0 -3,1.343146 -3,3 0,1.656854 1.3431457,3 3,3 z"
fillRule="nonzero"
id="path6" />
<path
d="M 6,4 C 4.8954305,4 4,3.1045695 4,2 4,0.8954305 4.8954305,0 6,0 7.1045695,0 8,0.8954305 8,2 8,3.1045695 7.1045695,4 6,4 Z m 0,8 C 4.8954305,12 4,11.10457 4,10 4,8.8954305 4.8954305,8 6,8 7.1045695,8 8,8.8954305 8,10 8,11.10457 7.1045695,12 6,12 Z M 2,8 C 0.8954305,8 0,7.1045695 0,6 0,4.8954305 0.8954305,4 2,4 3.1045695,4 4,4.8954305 4,6 4,7.1045695 3.1045695,8 2,8 Z m 8,0 C 8.8954305,8 8,7.1045695 8,6 8,4.8954305 8.8954305,4 10,4 c 1.10457,0 2,0.8954305 2,2 0,1.1045695 -0.89543,2 -2,2 z"
id="path8" />
</g>
<g
transform="matrix(-1,0,0,1,41.130435,11)"
fillRule="nonzero"
id="g18">
<path
d="M 16.26087,41 V 2.7254902 H 9.1304348 C 5.1912482,2.7254902 2,5.9136707 2,9.8463828 V 33.879107 C 2,37.806243 5.1950878,41 9.1304348,41 Z M 0,9.8463828 C 0,4.8090529 4.0867262,0.7254902 9.1304348,0.7254902 h 8.1226402 c 0.556589,0 1.007795,0.4461589 1.007795,1.0032974 V 43 H 9.1304348 C 4.0878349,43 0,38.908131 0,33.879107 Z"
id="path12" />
<path
d="m 17.930435,5.8998424 c 0,0.08424 0.05524,0.1393733 0.130435,0.1393733 h -0.130435 z m 0.130435,5.9040796 c -0.06814,0 -0.130435,0.06182 -0.130435,0.139373 v -0.139373 z m -0.130435,0 h -0.739131 v 1 h 0.869566 c 0.04437,0 0.08793,-0.0032 0.130434,-0.0095 V 5.0490748 c -0.04255,-0.00649 -0.0861,-0.00986 -0.130434,-0.00986 h -0.869566 v 1 h 0.739131 z M 17.191304,5.0392157 h 0.869566 c 0.480247,0 0.869565,0.3957278 0.869565,0.8606267 v 6.0434526 c 0,0.475311 -0.38597,0.860627 -0.869565,0.860627 h -0.869566 z"
id="path14" />
<path
d="m 17.930435,29.19396 c 0,0.08424 0.05524,0.139373 0.130435,0.139373 h -0.130435 z m 0.130435,5.904079 c -0.06814,0 -0.130435,0.06182 -0.130435,0.139373 v -0.139373 z m -0.130435,0 h -0.739131 v 1 h 0.869566 c 0.04437,0 0.08793,-0.0032 0.130434,-0.0095 v -7.745343 c -0.04255,-0.0065 -0.0861,-0.0099 -0.130434,-0.0099 h -0.869566 v 1 h 0.739131 z m -0.739131,-6.764706 h 0.869566 c 0.480247,0 0.869565,0.395728 0.869565,0.860627 v 6.043452 c 0,0.475312 -0.38597,0.860627 -0.869565,0.860627 h -0.869566 z"
id="path16" />
</g>
</g>
</g>
<g
id="g22-6"
fillRule="evenodd"
strokeWidth="1"
stroke="none"
transform="matrix(0.23714163,-0.08153304,0.08153304,0.23714163,-6.7259967,1.4700063)">
<g
id="g20-4">
<g
id="g10-4"
transform="translate(26,16)">
<path
id="path6-5"
fillRule="nonzero"
d="M 6,10 C 3.2385763,10 1,7.7614237 1,5 1,2.2385763 3.2385763,0 6,0 c 2.7614238,0 5,2.2385763 5,5 0,2.7614237 -2.2385762,5 -5,5 z M 6,8 C 7.6568543,8 9,6.6568543 9,5 9,3.3431458 7.6568543,2 6,2 4.3431457,2 3,3.3431458 3,5 3,6.6568543 4.3431457,8 6,8 Z" />
<path
id="path8-1"
d="m 6,22 c -1.1045695,0 -2,-0.895431 -2,-2 0,-1.10457 0.8954305,-2 2,-2 1.1045695,0 2,0.89543 2,2 0,1.104569 -0.8954305,2 -2,2 z m 0,8 c -1.1045695,0 -2,-0.895431 -2,-2 0,-1.10457 0.8954305,-2 2,-2 1.1045695,0 2,0.89543 2,2 0,1.104569 -0.8954305,2 -2,2 z M 2,26 c -1.1045695,0 -2,-0.895431 -2,-2 0,-1.10457 0.8954305,-2 2,-2 1.1045695,0 2,0.89543 2,2 0,1.104569 -0.8954305,2 -2,2 z m 8,0 c -1.1045695,0 -2,-0.895431 -2,-2 0,-1.10457 0.8954305,-2 2,-2 1.10457,0 2,0.89543 2,2 0,1.104569 -0.89543,2 -2,2 z" />
</g>
<g
id="g18-1"
fillRule="nonzero"
transform="translate(23,11)">
<path
id="path12-2"
d="M 16.117647,41 V 2.7254902 H 9.0588235 C 5.1595194,2.7254902 2,5.8842795 2,9.781461 V 33.944029 C 2,37.841438 5.1598077,41 9.0588235,41 Z M 0,9.781461 C 0,4.7799864 4.0546734,0.7254902 9.0588235,0.7254902 h 8.0589335 c 0.552224,0 0.99989,0.4461589 0.99989,1.0032974 V 43 H 9.0588235 C 4.0557734,43 0,38.946542 0,33.944029 Z" />
<path
id="path14-3"
d="m 17.780392,5.8998424 c 0,0.082482 0.05656,0.1393733 0.137255,0.1393733 h -0.137255 z m 0.137255,5.9040796 c -0.07367,0 -0.137255,0.06359 -0.137255,0.139373 v -0.139373 z m -0.137255,0 h -0.72549 v 1 h 0.862745 c 0.04676,0 0.0926,-0.0037 0.137255,-0.01071 V 5.0503178 c -0.0447,-0.0073 -0.09054,-0.011102 -0.137255,-0.011102 h -0.862745 v 1 h 0.72549 z m -0.72549,-6.7647063 h 0.862745 c 0.476481,0 0.862745,0.3957278 0.862745,0.8606267 v 6.0434526 c 0,0.475311 -0.382942,0.860627 -0.862745,0.860627 h -0.862745 z" />
<path
id="path16-0"
d="m 17.780392,29.19396 c 0,0.08248 0.05656,0.139373 0.137255,0.139373 h -0.137255 z m 0.137255,5.904079 c -0.07367,0 -0.137255,0.06359 -0.137255,0.139373 v -0.139373 z m -0.137255,0 h -0.72549 v 1 h 0.862745 c 0.04676,0 0.0926,-0.0037 0.137255,-0.01071 V 28.34443 c -0.0447,-0.0073 -0.09054,-0.0111 -0.137255,-0.0111 h -0.862745 v 1 h 0.72549 z m -0.72549,-6.764706 h 0.862745 c 0.476481,0 0.862745,0.395728 0.862745,0.860627 v 6.043452 c 0,0.475312 -0.382942,0.860627 -0.862745,0.860627 h -0.862745 z" />
</g>
</g>
</g>
</svg>
)
}
var IMAGE_JOYCONS=(p)=>{
return(
<svg width="1em" height="1em" {...p} viewBox="0 0 16 16" className="bi" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<g
stroke="none"
strokeWidth="1"
fillRule="evenodd"
id="g22"
transform="matrix(0.37879869,0,0,0.37879869,0.40087271,-4.4665372)">
<g
id="g20">
<g
transform="translate(26,16)"
id="g10">
<path
d="m 6,28 c -2.7614237,0 -5,-2.238576 -5,-5 0,-2.761424 2.2385763,-5 5,-5 2.7614238,0 5,2.238576 5,5 0,2.761424 -2.2385762,5 -5,5 z m 0,-2 c 1.6568543,0 3,-1.343146 3,-3 0,-1.656854 -1.3431457,-3 -3,-3 -1.6568543,0 -3,1.343146 -3,3 0,1.656854 1.3431457,3 3,3 z"
fillRule="nonzero"
id="path6" />
<path
d="M 6,4 C 4.8954305,4 4,3.1045695 4,2 4,0.8954305 4.8954305,0 6,0 7.1045695,0 8,0.8954305 8,2 8,3.1045695 7.1045695,4 6,4 Z m 0,8 C 4.8954305,12 4,11.10457 4,10 4,8.8954305 4.8954305,8 6,8 7.1045695,8 8,8.8954305 8,10 8,11.10457 7.1045695,12 6,12 Z M 2,8 C 0.8954305,8 0,7.1045695 0,6 0,4.8954305 0.8954305,4 2,4 3.1045695,4 4,4.8954305 4,6 4,7.1045695 3.1045695,8 2,8 Z m 8,0 C 8.8954305,8 8,7.1045695 8,6 8,4.8954305 8.8954305,4 10,4 c 1.10457,0 2,0.8954305 2,2 0,1.1045695 -0.89543,2 -2,2 z"
id="path8" />
</g>
<g
transform="matrix(-1,0,0,1,41.130435,11)"
fillRule="nonzero"
id="g18">
<path
d="M 16.26087,41 V 2.7254902 H 9.1304348 C 5.1912482,2.7254902 2,5.9136707 2,9.8463828 V 33.879107 C 2,37.806243 5.1950878,41 9.1304348,41 Z M 0,9.8463828 C 0,4.8090529 4.0867262,0.7254902 9.1304348,0.7254902 h 8.1226402 c 0.556589,0 1.007795,0.4461589 1.007795,1.0032974 V 43 H 9.1304348 C 4.0878349,43 0,38.908131 0,33.879107 Z"
id="path12" />
<path
d="m 17.930435,5.8998424 c 0,0.08424 0.05524,0.1393733 0.130435,0.1393733 h -0.130435 z m 0.130435,5.9040796 c -0.06814,0 -0.130435,0.06182 -0.130435,0.139373 v -0.139373 z m -0.130435,0 h -0.739131 v 1 h 0.869566 c 0.04437,0 0.08793,-0.0032 0.130434,-0.0095 V 5.0490748 c -0.04255,-0.00649 -0.0861,-0.00986 -0.130434,-0.00986 h -0.869566 v 1 h 0.739131 z M 17.191304,5.0392157 h 0.869566 c 0.480247,0 0.869565,0.3957278 0.869565,0.8606267 v 6.0434526 c 0,0.475311 -0.38597,0.860627 -0.869565,0.860627 h -0.869566 z"
id="path14" />
<path
d="m 17.930435,29.19396 c 0,0.08424 0.05524,0.139373 0.130435,0.139373 h -0.130435 z m 0.130435,5.904079 c -0.06814,0 -0.130435,0.06182 -0.130435,0.139373 v -0.139373 z m -0.130435,0 h -0.739131 v 1 h 0.869566 c 0.04437,0 0.08793,-0.0032 0.130434,-0.0095 v -7.745343 c -0.04255,-0.0065 -0.0861,-0.0099 -0.130434,-0.0099 h -0.869566 v 1 h 0.739131 z m -0.739131,-6.764706 h 0.869566 c 0.480247,0 0.869565,0.395728 0.869565,0.860627 v 6.043452 c 0,0.475312 -0.38597,0.860627 -0.869565,0.860627 h -0.869566 z"
id="path16" />
</g>
</g>
</g>
<g
id="g22-6"
fillRule="evenodd"
strokeWidth="1"
stroke="none"
transform="matrix(0.37879869,0,0,0.37879869,-8.7351179,-4.4850005)">
<g
id="g20-4">
<g
id="g10-4"
transform="translate(26,16)">
<path
id="path6-5"
fillRule="nonzero"
d="M 6,10 C 3.2385763,10 1,7.7614237 1,5 1,2.2385763 3.2385763,0 6,0 c 2.7614238,0 5,2.2385763 5,5 0,2.7614237 -2.2385762,5 -5,5 z M 6,8 C 7.6568543,8 9,6.6568543 9,5 9,3.3431458 7.6568543,2 6,2 4.3431457,2 3,3.3431458 3,5 3,6.6568543 4.3431457,8 6,8 Z" />
<path
id="path8-1"
d="m 6,22 c -1.1045695,0 -2,-0.895431 -2,-2 0,-1.10457 0.8954305,-2 2,-2 1.1045695,0 2,0.89543 2,2 0,1.104569 -0.8954305,2 -2,2 z m 0,8 c -1.1045695,0 -2,-0.895431 -2,-2 0,-1.10457 0.8954305,-2 2,-2 1.1045695,0 2,0.89543 2,2 0,1.104569 -0.8954305,2 -2,2 z M 2,26 c -1.1045695,0 -2,-0.895431 -2,-2 0,-1.10457 0.8954305,-2 2,-2 1.1045695,0 2,0.89543 2,2 0,1.104569 -0.8954305,2 -2,2 z m 8,0 c -1.1045695,0 -2,-0.895431 -2,-2 0,-1.10457 0.8954305,-2 2,-2 1.10457,0 2,0.89543 2,2 0,1.104569 -0.89543,2 -2,2 z" />
</g>
<g
id="g18-1"
fillRule="nonzero"
transform="translate(23,11)">
<path
id="path12-2"
d="M 16.117647,41 V 2.7254902 H 9.0588235 C 5.1595194,2.7254902 2,5.8842795 2,9.781461 V 33.944029 C 2,37.841438 5.1598077,41 9.0588235,41 Z M 0,9.781461 C 0,4.7799864 4.0546734,0.7254902 9.0588235,0.7254902 h 8.0589335 c 0.552224,0 0.99989,0.4461589 0.99989,1.0032974 V 43 H 9.0588235 C 4.0557734,43 0,38.946542 0,33.944029 Z" />
<path
id="path14-3"
d="m 17.780392,5.8998424 c 0,0.082482 0.05656,0.1393733 0.137255,0.1393733 h -0.137255 z m 0.137255,5.9040796 c -0.07367,0 -0.137255,0.06359 -0.137255,0.139373 v -0.139373 z m -0.137255,0 h -0.72549 v 1 h 0.862745 c 0.04676,0 0.0926,-0.0037 0.137255,-0.01071 V 5.0503178 c -0.0447,-0.0073 -0.09054,-0.011102 -0.137255,-0.011102 h -0.862745 v 1 h 0.72549 z m -0.72549,-6.7647063 h 0.862745 c 0.476481,0 0.862745,0.3957278 0.862745,0.8606267 v 6.0434526 c 0,0.475311 -0.382942,0.860627 -0.862745,0.860627 h -0.862745 z" />
<path
id="path16-0"
d="m 17.780392,29.19396 c 0,0.08248 0.05656,0.139373 0.137255,0.139373 h -0.137255 z m 0.137255,5.904079 c -0.07367,0 -0.137255,0.06359 -0.137255,0.139373 v -0.139373 z m -0.137255,0 h -0.72549 v 1 h 0.862745 c 0.04676,0 0.0926,-0.0037 0.137255,-0.01071 V 28.34443 c -0.0447,-0.0073 -0.09054,-0.0111 -0.137255,-0.0111 h -0.862745 v 1 h 0.72549 z m -0.72549,-6.764706 h 0.862745 c 0.476481,0 0.862745,0.395728 0.862745,0.860627 v 6.043452 c 0,0.475312 -0.382942,0.860627 -0.862745,0.860627 h -0.862745 z" />
</g>
</g>
</g>
</svg>
)
}
var RATING_cool=new Image();
RATING_cool.src="data:image/png;base64,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
var RATING_fine=new Image();
RATING_fine.src="data:image/png;base64,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
var RATING_safe=new Image();
RATING_safe.src="data:image/png;base64,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
var RATING_sad=new Image();
RATING_sad.src="data:image/png;base64,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
var RATING_worst=new Image();
RATING_worst.src="data:image/png;base64,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
function Logo(){
var note_arrow=new Image();
note_arrow.src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAABjCAYAAACWsFAzAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AYht+mSkVaHOwg4pChOlkVFXGUKhbBQmkrtOpgcukfNGlIUlwcBdeCgz+LVQcXZ10dXAVB8AfEydFJ0UVK/C4ptIjxjuMe3vvel7vvAKFRYarZNQGommWk4jExm1sVA68IIERzDOMSM/VEejEDz/F1Dx/f76I8y7vuzxFS8iYDfCLxHNMNi3iDeGbT0jnvE4dZSVKIz4lHDbog8SPXZZffOBcdFnhm2Mik5onDxGKxg+UOZiVDJZ4mjiiqRvlC1mWF8xZntVJjrXvyFwbz2kqa67SGEMcSEkhChIwayqjAQpR2jRQTKTqPefgHHX+SXDK5ymDkWEAVKiTHD/4Hv3trFqYm3aRgDOh+se2PYSCwCzTrtv19bNvNE8D/DFxpbX+1Acx+kl5va5EjoG8buLhua/IecLkDDDzpkiE5kp+WUCgA72f0TTmg/xboXXP71jrH6QOQoV4t3wAHh8BIkbLXPd7d09m3f2ta/fsBxMxyyECtw/8AAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfkBw0TDjpHpB7sAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAfVJREFUWMPtlr9q21AUxr8j7CuERQ0lUzA0gzw0VgzxliV5Bs15kA4tWQN5Db9AwG+gxdiDwe6fJc3gKTWdTDRK/jL0KpVry5KSDi2+P7hwOTrn49xzrg4XKOarXjux8j7UarW3AAjgi17UtmocHb37CIDT6ZSz2YwAqG3lOD5+LwCu6vU6ARxQA+BA2660TzGu22AQBA9JkpDkiuQqSRIGQfDgug2WTYoAHkmec5NzAI/aJx/f71yLCIfD4Zw5jEaj7yJC3+9cbwi0Wi0BcGFZFgFcxnGcp8M4jgngUvte6NjfOI5Dz/Putf+K+axIst1u3zuOs35EEblTSpHkIctzqJSiiNyldbmxbZvj8fjTNm9d2K1Kk8nkg23b9P3OTdqlW93qSkK6XrcAKAAoIvgVo/uf2YtIri3dk4TV7Z6cKqXOMneoyn2DUuqs2z05TaUlPULFjCSNtV6QydbMLPwljJARMkJG6F8RqhU5DAaDUkKybWxm5/PWoPWZvS9d+wZg+YL4pY59Fmo0m803VVV0TGOt/cvlsrBbf74Nsm+Aff1FsjUouvE7M/I8D2EYIgxDeJ73up92sVi8/mi9Xg/9fv95X4Z53oNzF3pazPdlZruuCxGptFzX3eja5yiKflbNIooiAPgBg8FgMBgMBoPBYPjfeQJefdQWdKdLVQAAAABJRU5ErkJggg=="
var note_circle=new Image();
var note_circle_shadow=new Image();
var notes=[new Image(),new Image(),new Image(),new Image()]
notes[0].src="data:image/png;base64,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
notes[1].src="data:image/png;base64,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
notes[2].src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEMAAABHCAYAAABcW/plAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AYht+mSkVaHOwg4pChOlkVFXGUKhbBQmkrtOpgcukfNGlIUlwcBdeCgz+LVQcXZ10dXAVB8AfEydFJ0UVK/C4ptIjxjuMe3vvel7vvAKFRYarZNQGommWk4jExm1sVA68IIERzDOMSM/VEejEDz/F1Dx/f76I8y7vuzxFS8iYDfCLxHNMNi3iDeGbT0jnvE4dZSVKIz4lHDbog8SPXZZffOBcdFnhm2Mik5onDxGKxg+UOZiVDJZ4mjiiqRvlC1mWF8xZntVJjrXvyFwbz2kqa67SGEMcSEkhChIwayqjAQpR2jRQTKTqPefgHHX+SXDK5ymDkWEAVKiTHD/4Hv3trFqYm3aRgDOh+se2PYSCwCzTrtv19bNvNE8D/DFxpbX+1Acx+kl5va5EjoG8buLhua/IecLkDDDzpkiE5kp+WUCgA72f0TTmg/xboXXP71jrH6QOQoV4t3wAHh8BIkbLXPd7d09m3f2ta/fsBxMxyyECtw/8AAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfkBw0VOy+MxUQDAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAA5tJREFUeNrtnM9rE0EUx79vN7EVAgaDVy9aQfHYa1s8e/FQeiiePXjTU72WgkchIL3rxSoKgkjBHpQg0j+gVkqVYC45VEJN2t3szs7zMNlk06YtbXbrTnYehNn8YNj3me9783ZmCK2svHoKyHEwjwHyEsDjAI+p9qxm7XZbsnYBcgFC2mx2dvaJZVnd9wSAkVHzvDbl8/neEMJY13LhxdT1KSzdW0r1zbLnQv7ZAfkEEgQKAMjT9fF84yVe//p4PIxSoYTpiel0w3CaCC7WQW2C5RMooFPDeF/9dHSm00nGHAgQh6k4/oSsFwzfU+mek0n7Oa0yXAQGYXgg1WoVuVxOTxjs+yAmgCkWZaytrbFt2/qFCQsP8IP+MOGM5gxu7wMSIAlQQmWiNjCk0wLJuFXR35EeOUMGwL4DSFKvuJTBPsCyownSA4Z0W6q4CkOEKWZlBJqECTN4rwUS6IZJUs+/qYfBfhvseoAkkOyU3wkl0KHCpP63jsUPi4lPqew4IIEuCGKljYe37uP25RvpgNHYa2D5y/J/U83dq3eGhJHrBIeirFc5HreRrV6dZBobjPn5eczMJL8EsLHxHeVyOQkyZqVL20d4A8PAMDAMjDRZYnVGsVh8Njc39zjufldXVyfK5fKWUYYJEwNjtHKGDiZZLRYxq3I80zCEIEgmvZQRXcthTqbfVMHgyAVHHGdWclYtwRPU1j5ncMS56DVAhz7jYxQgEzxaEyuM0BEwEEjAE1EHqe97HqTTUZlNhAQ80UtGfkBtT5BWh6SsxLIRQ7vTYrmzxAIHAvBdyFZjVIsuPhD8DOYAkIFyXvjqsIjnASIABxK829S7/LYA21abUhSFIZ19iNr2YTaRjd7uxq8ELAkkN8mdj+VtwLYGKIMCBjlHxz11oVBnIwcgcU4HXakzetR/88mFiSSQRwMTIw1USue0XYwOW6QcDluKQKDOb/L2ecBgqC28gbMEDT5DxSeMJh0e2dCxqMNApI38fmC3dA4wiDHcSEdGNBzB8Qu9kc7UI/y3rxVsb/3oJad8fuHd2zcLcd9wvV5PP4xarYZardb32fr6ul5TLYzFo4ybxWvgBz9HBoZRhoFhYBgYBoaBYWAYGAaGgWFgGBipelD7+PszrryYHHmH94RzMgxP+thxG9lWxuRkvxqazSZc182E83RgQZX4wHZ3pVLB5uZmJv9GwiRQA8PAMDAMjGGLrtAKhQJKpdKjLML4BwfkgOBZ+ypaAAAAAElFTkSuQmCC"
notes[3].src="data:image/png;base64,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
var shadownotes=[new Image(),new Image(),new Image(),new Image()]
shadownotes[0].src="data:image/png;base64,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
shadownotes[1].src="data:image/png;base64,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"
shadownotes[2].src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEYAAABKCAYAAAAG7CL/AAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AYht+mSkVaHOwg4pChOlkVFXGUKhbBQmkrtOpgcukfNGlIUlwcBdeCgz+LVQcXZ10dXAVB8AfEydFJ0UVK/C4ptIjxjuMe3vvel7vvAKFRYarZNQGommWk4jExm1sVA68IIERzDOMSM/VEejEDz/F1Dx/f76I8y7vuzxFS8iYDfCLxHNMNi3iDeGbT0jnvE4dZSVKIz4lHDbog8SPXZZffOBcdFnhm2Mik5onDxGKxg+UOZiVDJZ4mjiiqRvlC1mWF8xZntVJjrXvyFwbz2kqa67SGEMcSEkhChIwayqjAQpR2jRQTKTqPefgHHX+SXDK5ymDkWEAVKiTHD/4Hv3trFqYm3aRgDOh+se2PYSCwCzTrtv19bNvNE8D/DFxpbX+1Acx+kl5va5EjoG8buLhua/IecLkDDDzpkiE5kp+WUCgA72f0TTmg/xboXXP71jrH6QOQoV4t3wAHh8BIkbLXPd7d09m3f2ta/fsBxMxyyECtw/8AAAAGYktHRAAAAAAAAPlDu38AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfkBw0WAROERVikAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAAQ1JREFUeNrt2r0KglAcQPGjFATR2BSt4Ri0NfcE9ZrRG/QGQWvQ7NQLBH3YkESZW2aa54x3uMgPvcP/GkTRPMH2wGi3Wz0WQk3yE0YYYYQR5ge1JADgAhBFc2EyDYHls4cw97rAwjPGw1cYYYQRRhhhhBFGGBNGGGGEEUaYylXGBG8AHIGgoP0SoAPEdYc5AKeC92z/wxsTAjxfmH9SOskPS3loE0YYYYQRRhhhhBFGGGFMGGGEKb4y5jFXeP0jsqg96w7T5zujzdrDxHX8lDxjhBFGGGGEEUYYYYQRRhgTRhhhhBFGmCrXAtaZtTMwBXpNh5nlrG+ASZNh3ib36TXHFhh7xpgwwggjTKndAANPGt4oQR7PAAAAAElFTkSuQmCC"
shadownotes[3].src="data:image/png;base64,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"
var divar=new Image();
divar.src="data:image/png;base64,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
var logo;
var timer=0;
var startpoint = [Math.random()*1000-500,Math.random()*1000-500]
var scorepoint = [Math.random()*10-5,Math.random()*10-5]
var pos = [...startpoint];
var hitrating=-1;
var timer2=0;
var notetype=0;
setTimeout(()=>{
logo=document.getElementById("logo");
var draw = logo.getContext("2d");
draw.font="64px Open Sans Condensed";
var size=draw.measureText("Pr ject")
logo.width=size.width
setInterval(()=>{
if (hitrating==-1) {
pos[0]-=startpoint[0]/20;
pos[1]-=startpoint[1]/20;
if ((Math.abs(pos[0])<32 && Math.abs(pos[1])<32 && Math.random()*10<1)
|| (Math.abs(pos[0])<16 && Math.abs(pos[1])<16 && Math.random()*4<1)
|| (Math.abs(pos[0])<4 && Math.abs(pos[1])<4 && Math.random()*2<1)) {
scorepoint = [Math.random()*30-15,Math.random()*30-15]
var distance = Math.abs(pos[0])+Math.abs(pos[1])
if (distance>32) {
hitrating=4;
} else
if (distance>16) {
hitrating=3;
} else
if (distance>4) {
hitrating=2;
} else
if (distance>2) {
hitrating=1;
} else {
hitrating=0;
}
timer2=Math.random()*400+350;
}
if (timer>1300) {
hitrating=4;
timer2=350;
}
}
if (hitrating!=-1 && timer2<=0) {
hitrating=-1;
notetype=Math.floor(Math.random()*4)
startpoint = [Math.random()*1000-500,Math.random()*1000-500]
pos = [...startpoint];
timer=0;
}
var draw = logo.getContext("2d");
draw.clearRect(0, 0, logo.width, logo.height);
draw.font="64px Open Sans Condensed";
var size=draw.measureText("Pr ject")
draw.fillStyle="#000000";
draw.fillText("Pr ject",0,48);
draw.font="28px Open Sans Condensed";
draw.fillStyle="#FFFFFF";
draw.drawImage(divar,14,45,152,32);
if (hitrating==-1) {
draw.drawImage(shadownotes[notetype],70-19,14,36,36);
draw.drawImage(notes[notetype],70-19+pos[0],14+pos[1],36,36);
draw.save();
drawImage(note_arrow,70+22-4-19,14-19+38,0.5,((timer/50)*18)*(Math.PI/180));
draw.restore();
} else {
switch (hitrating) {
case 0:{
draw.drawImage(RATING_cool,70-19+scorepoint[0],14+scorepoint[1]);
}break;
case 1:{
draw.drawImage(RATING_fine,70-19+scorepoint[0],14+scorepoint[1]);
}break;
case 2:{
draw.drawImage(RATING_safe,70-19+scorepoint[0],14+scorepoint[1]);
}break;
case 3:{
draw.drawImage(RATING_sad,70-19+scorepoint[0],14+scorepoint[1]);
}break;
case 4:{
draw.drawImage(RATING_worst,70-19+scorepoint[0],14+scorepoint[1]);
}break;
}
}
timer+=50;
timer2-=50;
//p.setSiteCounter(p.siteCounter+1);
},50)
},300);
function drawImage(image, x, y, scale, rotation){
var draw = logo.getContext("2d");
draw.setTransform(scale, 0, 0, scale, x, y); // sets scale and origin
draw.rotate(rotation);
draw.drawImage(image, -image.width / 2, -image.height / 2);
}
return (<>
<canvas className="homelink" id="logo" width="0" height="84"/>
</>);
}
function Sort(p){
let { sort,sortOrder } = useParams();
return (
<>
<Link to={"/rankings/"+p.order+"/"+((p.order===sort)?(sortOrder==="desc")?"asc":"desc":"desc")} onClick={()=>{p.setIsLoading(true);p.setUpdateUsers(!p.updateUsers)}}>{p.label}</Link>{(sort===p.order?<>{(sortOrder==="desc")?<>▼</>:<></>}</>:<></>)}
</>
)
}
function ProfileDataContainer(p){
return (
<div className={"col-md-"+p.width+" border"} onMouseOver={()=>{if (p.setMouseOver) {p.setMouseOver(true)}}} onMouseOut={()=>{if(p.setMouseOver){p.setMouseOver(false)}}}>
<div className="row">
<div className="text-center label col-6 col-md-12">
{p.label}
</div>
<div className="data col-6 col-md-12 text-center">
{p.data}
</div>
</div>
</div>
);
}
function StatisticsPanel(p) {
return (
<>
<div className="row">
<div className="col-md-1"></div>
<ProfileDataContainer label="Play Count" data={p.playcount} width="2"/>
<ProfileDataContainer label="FC Count" data={p.fccount} width="2"/>
<ProfileDataContainer setMouseOver={p.setMouseOver} label="Cleared" data={p.cleared} width="4"/>
<ProfileDataContainer label="Accuracy" data={p.accuracy} width="2"/>
<div className="col-md-1"></div>
</div>
</>
)
}
function HitCountsPanel(p) {
return (
<>
<div className="row text-center">
<div className="col-md-1">
</div>
<div className="col-md-2 border">
<div className="row">
<div className="col-6 col-md-12">
<img src={RATING_cool.src} height="16"/>
</div>
<div className="col-6 col-md-12">
{p.user.cool}
</div>
</div>
</div>
<div className="col-md-2 border">
<div className="row">
<div className="col-6 col-md-12">
<img src={RATING_fine.src} height="16"/>
</div>
<div className="col-6 col-md-12">
{p.user.fine}
</div>
</div>
</div>
<div className="col-md-2 border">
<div className="row">
<div className="col-6 col-md-12">
<img src={RATING_safe.src} height="16"/>
</div>
<div className="col-6 col-md-12">
{p.user.safe}
</div>
</div>
</div>
<div className="col-md-2 border">
<div className="row">
<div className="col-6 col-md-12">
<img src={RATING_sad.src} height="16"/>
</div>
<div className="col-6 col-md-12">
{p.user.sad}
</div>
</div>
</div>
<div className="col-md-2 border">
<div className="row">
<div className="col-6 col-md-12">
<img src={RATING_worst.src} height="16"/>
</div>
<div className="col-6 col-md-12">
{p.user.worst}
</div>
</div>
</div>
<div className="col-md-1">
</div>
</div>
</>
)
}
function SongName(p){
//console.log(p.song)
return (
<>
{(p.song)?(p.song.english_name===p.song.name)?
<>{p.song.name}</>
:
<>{p.song.name}<br/>{(p.song.romanized_name.length>0)?p.song.romanized_name:p.song.english_name}</>
:<></>
}
</>
)
}
function CalculateBadge(difficulty) {
switch (difficulty) {
case "E":{
return "primary";
}break;
case "N":{
return "info";
}break;
case "H":{
return "success";
}break;
case "EX":{
return "warning";
}break;
case "EXEX":{
return "danger";
}break;
}
}
function FormatRating(rating) {
if (rating) {
if (rating.includes(".5")) {
return rating;
} else {
return Math.floor(rating)
}
}
}
function Difficulty(p) {
return (
<>
<span className={"badge badge-"+CalculateBadge(p.play.difficulty)}>{(p.song && p.song.rating && p.song.rating[p.play.difficulty])?FormatRating(p.song.rating[p.play.difficulty]):<></>} {p.play.difficulty}</span>
</>
);
}
function ImageDisplayer(p) {
var [zoom,setZoom] = useState(false)
//p.play
return(
<Modal
size="xl"
aria-labelledby="contained-modal-title-vcenter"
centered
scrollable
show={p.modalVisible}
onHide={()=>{p.setModalVisible(false)}}
>
{(p.play!==undefined&&p.songs[p.play.songid])?<><Modal.Header closeButton>
<Modal.Title id="contained-modal-title-vcenter">
{`${p.username}'s ${p.songs[p.play.songid].name} Play - [${p.play.difficulty}] ${p.play.percent}%`}
</Modal.Title>
</Modal.Header>
<Modal.Body>
<img src={p.play.src} width={(zoom)?"auto":"100%"} className={(zoom)?"zoomout":"zoomin"} onClick={()=>{setZoom(!zoom)}}/>
</Modal.Body></>:<></>}
</Modal>
)
}
function Play(p) {
function GetModifiedDiff(name) {
switch (name) {
case "E":{
return "easy";
}
case "N":{
return "normal";
}
case "H":{
return "hard";
}
case "EX":{
return "ex";
}
case "EXEX":{
return "exex";
}
}
}
function GetDateDiff() {
var hours = Math.floor((Date.now()-new Date(p.play.date))/1000/60/60);
var days = Math.floor(hours/24)
if (hours<24) {return <>{hours} {"hour"+((hours!==1)?"s":"")} ago</>}
return <>{days} {"day"+((days!==1)?"s":"")} ago</>
}
function GetDateDisplay(timeStampBelow) {
var date = new Date(p.play.date);
var months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]
return <>{months[date.getMonth()]+" "+date.getDate()+" "+date.getFullYear()+" "+date.getHours()+":"+((date.getMinutes()<10)?"0"+date.getMinutes():date.getMinutes())}<span className={"tinytime infront "+((timeStampBelow)?"moveDown":"")}>{GetDateDiff()}</span></>
}
if (p.mini) {
return (
<>
<div className={"d-none d-md-block below border border-bottom "+((p.play.src)?"background-songs-click":"")} onClick={(p.play.src)?()=>{p.setModalSrc(p.play)
p.setModalVisible(true)}:null}>
<div className={((p.play.fine==0&&p.play.safe==0&&p.play.sad==0&&p.play.worst==0)?"pfchighlight":(p.play.safe==0&&p.play.sad==0&&p.play.worst==0)?"fchighlight":"")}>
<div className={"row align-middle"}>
<div className="col-md-2 order-1 order-md-1 text-center border-right align-middle text-nowrap overflow-hidden">{(p.title&&p.song)?<>{p.song.name}<br/></>:<></>}{((p.play.fine==0&&p.play.safe==0&&p.play.sad==0&&p.play.worst==0)?<span className="badge pfc">PFC</span>:(p.play.safe==0&&p.play.sad==0&&p.play.worst==0)?<span className="badge fc">FC</span>:<></>)} <Difficulty play={p.play} song={p.song}/> {Math.floor(p.play.score)} pts</div>
<div className="col-md-3 order-3 order-md-2 text-center border-right align-middle text-nowrap overflow-hidden">{GetDateDisplay()}</div>
<div className="col-md-7 order-2 order-md-3">
<div className="row">
<div className="col-12 order-1 order-md-1 col-md-5 text-center">
{p.play.cool+"/"+p.play.fine+"/"+p.play.safe+"/"+p.play.sad+"/"+p.play.worst}
</div>
<div className="col-6 order-3 order-md-2 col-md-2 text-left text-md-left">
{(p.play.mod!==null&&p.play.mod.length>0)?
<ModDisplay side={true} badge={CalculateBadge(p.play.difficulty)} diff={GetModifiedDiff(p.play.difficulty)}
hs={p.play.mod=="HS"?1:0} hd={p.play.mod=="HD"?1:0} sd={p.play.mod=="SD"?1:0}/>
:<></>
}
</div>
<div className="col-6 order-2 order-md-3 col-md-3 text-right text-md-left">
<b>{p.play.percent}%</b>
</div>
<div className="col-6 order-2 order-md-3 col-md-2 text-right text-md-left">
{(p.play.src)?<IMAGE_CAMERA/>:<></>}
</div>
</div>
</div>
</div>
</div>
</div>
<div className={"d-block d-small d-md-none "+((p.play.src)?"background-songs-click":"")} onClick={(p.play.src)?()=>{p.setModalSrc(p.play)
p.setModalVisible(true)}:null}>
<div className={((p.play.fine==0&&p.play.safe==0&&p.play.sad==0&&p.play.worst==0)?"pfchighlight":(p.play.safe==0&&p.play.sad==0&&p.play.worst==0)?"fchighlight":"")}>{(p.title&&p.song)?<>{p.song.name}<br/></>:<></>}
{<div className="row"><div className="offset-4 col-4 text-center">{((p.play.fine==0&&p.play.safe==0&&p.play.sad==0&&p.play.worst==0)?<span className="badge pfc">PFC</span>:(p.play.safe==0&&p.play.sad==0&&p.play.worst==0)?<span className="badge fc">FC</span>:<></>)}<Difficulty play={p.play} song={p.song}/></div></div>}
<div className="row">
<div className="offset-2 col-4 text-center">
{Math.floor(p.play.score)} pts
<br/>
{p.play.cool+"/"+p.play.fine+"/"+p.play.safe+"/"+p.play.sad+"/"+p.play.worst}
</div>
<div className="col-4 text-center">
<b>{p.play.percent}%</b> {(p.play.mod!==null&&p.play.mod.length>0)?<ModDisplay side={true} badge={CalculateBadge(p.play.difficulty)} diff={GetModifiedDiff(p.play.difficulty)}
hs={p.play.mod=="HS"?1:0} hd={p.play.mod=="HD"?1:0} sd={p.play.mod=="SD"?1:0}/>:<></>}
<span className="pl-2"/>
{(p.play.src)?<IMAGE_CAMERA/>:<></>}
<br/>
{GetDateDisplay(true)}
</div>
</div>
</div>
</div>
</>
);
} else {
return (
<>
<div className={"row align-middle "+((p.play.fine==0&&p.play.safe==0&&p.play.sad==0&&p.play.worst==0)?"pfchighlight":(p.play.safe==0&&p.play.sad==0&&p.play.worst==0)?"fchighlight":"")+((p.play.src)?" background-songs-click":"")} onClick={(p.play.src)?()=>{p.setModalSrc(p.play)
p.setModalVisible(true)}:null}>
{(p.index!==undefined)?<div className=" col-md-1 text-center border-right align-middle text-nowrap overflow-hidden"><span className="d-none d-md-block">{p.index+1}</span>{((p.play.fine==0&&p.play.safe==0&&p.play.sad==0&&p.play.worst==0)?<span className="badge pfc">PFC</span>:(p.play.safe==0&&p.play.sad==0&&p.play.worst==0)?<span className="badge fc">FC</span>:<></>)}</div>:<></>}
<div className="col-md-3 text-center border-right align-middle text-nowrap overflow-hidden"><SongName song={p.song}/><span className="tinytime">{GetDateDiff()}</span></div>
<div className="col-md-2 text-center border-right align-middle text-nowrap overflow-hidden">{Math.floor(p.play.score)} pts<br/><Difficulty play={p.play} song={p.song}/></div>
<div className="col-md-6">
<div className="row">
<div className="order-1 order-md-1 col-md-4 numbers text-center">
<div className="row justify-content-center">
<div className="col-4 col-md-5">
<img src={RATING_cool.src} className="pr-2" height="16"/>
</div>
<div className="col-4 col-md-7">
{p.play.cool}
</div>
</div>
</div>
<div className="order-3 order-md-2 col-md-4 numbers text-center">
<div className="row justify-content-center">
<div className="col-4 col-md-5">
<img src={RATING_safe.src} className="pr-2" height="16"/>
</div>
<div className="col-4 col-md-7">
{p.play.safe}
</div>
</div></div>
<div className="order-5 order-md-3 col-md-4 numbers text-center">
<div className="row justify-content-center">
<div className="col-4 col-md-5">
<img src={RATING_worst.src} className="pr-2" height="16"/>
</div>
<div className="col-4 col-md-7">
{p.play.worst}
</div>
</div></div>
<div className="order-2 order-md-4 order-sm-2 col-md-4 numbers text-center">
<div className="row justify-content-center">
<div className="col-4 col-md-5">
<img src={RATING_fine.src} className="pr-2" height="16"/>
</div>
<div className="col-4 col-md-7">
{p.play.fine}
</div>
</div></div>
<div className="order-4 order-md-5 col-md-4 numbers text-center">
<div className="row justify-content-center">
<div className="col-4 col-md-5">
<img src={RATING_sad.src} className="pr-2" height="16"/>
</div>
<div className="col-4 col-md-7">
{p.play.sad}
</div>
</div></div>
<div className="order-6 order-md-6 col-md-4 numbers text-center"><b>{p.play.percent}% {(p.play.src)?<span className="pl-4"><IMAGE_CAMERA onClick={()=>{p.setModalSrc(p.play)
p.setModalVisible(true)}}/></span>:<></>}</b></div>
</div>
</div>
</div>
</>
);
}
}
function LoadMore(p) {
var [offset,setOffset] = useState(p.params.limit)
var [params,setParams] = useState(p.params)
var [loading,setLoading] = useState(false)
var [visible,setVisible] = useState(false)
var [update,setUpdate] = useState(false)
useEffect(()=>{
axios.get(p.url+constructParams(params))
.then((data)=>{
if (data.data.length>0) {
setVisible(true)
}
})
},[update])
function constructParams(params) {
var st = Object.keys(params).reduce((str,key)=>{
if (str==="") {
return str+="?"+key+"="+params[key]
} else {
return str+="&"+key+"="+params[key]
}
},"")
return st
}
if (!visible){
return (<></>)
}
else
if (p.listItem) {
return (
<li className="list-group-item list-group-item-action homelink" onClick={()=>{
setLoading(true)
axios.get(p.url+constructParams(params))
.then((data)=>{
if (data.data.length>0) {
var newVals = [...p.value]
data.data.forEach((val)=>{
newVals.push(val)
})
p.setValue(newVals)
//console.log(newVals)
var obj = {...params}
obj.offset+=offset
setParams(obj)
setLoading(false)
if (data.data.length<p.params.limit) {
setVisible(false)
}
} else {
setVisible(false)
setLoading(false)
}
})
}
}>
<div className="row text-center">
<div className="col-12">
{(!loading)?<h6 className="link"><i>- Load More -</i></h6>:<div className="spinner-grow text-primary" role="status"><span className="sr-only">Loading...</span></div>
}
</div>
</div>
</li>
)
} else
return (
<div className="row text-center homelink" onClick={()=>{
setLoading(true)
axios.get(p.url+constructParams(params))
.then((data)=>{
if (!data.data) {
setVisible(false)
} else
if (data.data.length>0) {
var newVals = [...p.value]
data.data.forEach((val)=>{
newVals.push(val)
})
p.setValue(newVals)
//console.log(newVals)
var obj = {...params}
obj.offset+=offset
setParams(obj)
setLoading(false)
if (data.data.length<p.params.limit) {
setVisible(false)
}
} else {
setVisible(false)
setLoading(false)
}
})
}
}>
<div className="col-12">
{(!loading)?<h6 className="link"><i>- Load More -</i></h6>:<div className="spinner-grow text-primary" role="status"><span className="sr-only">Loading...</span></div>
}
</div>
</div>
)
}
function BestPlaysPanel(p) {
var [bestPlays,setBestPlays] = useState([])
var [update,setUpdate] = useState(false)
useEffect(()=>{
axios.get("http://www.projectdivar.com/bestplays/"+p.username+"?fails=false&limit=5&offset=0")
.then((data)=>{setBestPlays(data.data);})
},[update,p.username])
var content=<div className="col-md-12 mt-3 mb-3">
<ul className="list-group list-group-flush border border-danger rounded-lg">
{bestPlays.map((play,i)=>{return <li key={play.id} className={"list-group-item list-group-item-action "+(i%2==0?"background-list-1":"background-list-2")}>
<Play setModalSrc={p.setModalSrc} setModalVisible={p.setModalVisible} index={i} play={play} song={p.songs[play.songid]}/>
</li>})}
<LoadMore listItem={true} url={"http://www.projectdivar.com/bestplays/"+p.username} params={{fails:false,limit:15,offset:5}} value={bestPlays} setValue={setBestPlays}/>
</ul>
</div>
return (
<>
<div className="row ml-3 mr-3">
{content}
</div>
</>
);
}
function ModDisplay(p) {
const[tooltip,setTooltip] = useState("")
const[visibility,setVisibility] = useState(false)
return (
<span className={"border border-"+p.badge+" rounded "+p.diff+"-background"} style={{fontSize:"18px"}}>
{(p.hs>0)?<span style={{color:"#b33"}} onMouseOver={()=>{setTooltip("High Speed - "+p.diff.toUpperCase());setVisibility(true)}} onMouseOut={()=>{setVisibility(false)}}></span>:<></>}
{(p.hd>0)?<span onMouseOver={()=>{setTooltip("Hidden - "+p.diff.toUpperCase());setVisibility(true)}} onMouseOut={()=>{setVisibility(false)}} style={{color:"#968a0e"}}></span>:<></>}
{(p.sd>0)?<span onMouseOver={()=>{setTooltip("Sudden - "+p.diff.toUpperCase());setVisibility(true)}} onMouseOut={()=>{setVisibility(false)}} style={{color:"#49b"}}></span>:<></>}
{(visibility)?<span style={{position:"absolute"}} className={((p.side)?"display-tooltipside":"display-tooltip")+" alert alert-dark "+p.diff+"-background"}>{tooltip}</span>:<></>}
</span>
)
}
function PlayDetail(p) {
const[tooltip,setTooltip] = useState("")
const[visibility,setVisibility] = useState(false)
const[style,setStyle] = useState("")
return (
<>
<td>
{(p.song.report.rank>0)?p.song.report.rank:<i>Not Played</i>}
</td>
<td>
{(p.song.report.rank>0)?<>{p.song.report.score}</>:""}
</td>
<td>
{(p.song.report.rank>0)?<>{p.song.report.percent}%</>:""}
</td>
<td>
{p.song.report.ecount>0?<span className="badge badge-primary" onMouseOver={()=>{setTooltip(<>{p.song.report.eclearcount+" / "+p.song.report.ecount+" ("+(Math.floor((p.song.report.eclearcount/p.song.report.ecount)*100))+"% pass rate)"}{(p.song.report.efccount>0)?<><br/>{"★FC'd "+p.song.report.efccount+" time"+(p.song.report.efccount!=1?"s":"")}</>:<></>}{(p.song.report.epfccount>0)?<><br/>{"✪Perfected "+p.song.report.epfccount+" time"+(p.song.report.epfccount!=1?"s":"")}</>:<></>}</>);setStyle("easy");setVisibility(true)}} onMouseOut={()=>{setVisibility(false)}}>{p.song.report.epfccount>0?"":p.song.report.efccount>0?"":""}{p.song.report.ecount}</span>:<></>}
{p.song.report.ncount>0?<span className="badge badge-info" onMouseOver={()=>{setTooltip(<>{p.song.report.nclearcount+" / "+p.song.report.ncount+" ("+(Math.floor((p.song.report.nclearcount/p.song.report.ncount)*100))+"% pass rate)"}{(p.song.report.nfccount>0)?<><br/>{"★FC'd "+p.song.report.nfccount+" time"+(p.song.report.nfccount!=1?"s":"")}</>:<></>}{(p.song.report.npfccount>0)?<><br/>{"✪Perfected "+p.song.report.npfccount+" time"+(p.song.report.npfccount!=1?"s":"")}</>:<></>}</>);setStyle("normal");setVisibility(true)}} onMouseOut={()=>{setVisibility(false)}}>{p.song.report.npfccount>0?"":p.song.report.nfccount>0?"":""}{p.song.report.ncount}</span>:<></>}
{p.song.report.hcount>0?<span className="badge badge-success" onMouseOver={()=>{setTooltip(<>{p.song.report.hclearcount+" / "+p.song.report.hcount+" ("+(Math.floor((p.song.report.hclearcount/p.song.report.hcount)*100))+"% pass rate)"}{(p.song.report.hfccount>0)?<><br/>{"★FC'd "+p.song.report.hfccount+" time"+(p.song.report.hfccount!=1?"s":"")}</>:<></>}{(p.song.report.hpfccount>0)?<><br/>{"✪Perfected "+p.song.report.hpfccount+" time"+(p.song.report.hpfccount!=1?"s":"")}</>:<></>}</>);setStyle("hard");setVisibility(true)}} onMouseOut={()=>{setVisibility(false)}}>{p.song.report.hpfccount>0?"":p.song.report.hfccount>0?"":""}{p.song.report.hcount}</span>:<></>}
{p.song.report.excount>0?<span className="badge badge-warning" onMouseOver={()=>{setTooltip(<>{p.song.report.exclearcount+" / "+p.song.report.excount+" ("+(Math.floor((p.song.report.exclearcount/p.song.report.excount)*100))+"% pass rate)"}{(p.song.report.exfccount>0)?<><br/>{"★FC'd "+p.song.report.exfccount+" time"+(p.song.report.exfccount!=1?"s":"")}</>:<></>}{(p.song.report.expfccount>0)?<><br/>{"✪Perfected "+p.song.report.expfccount+" time"+(p.song.report.expfccount!=1?"s":"")}</>:<></>}</>);setStyle("ex");setVisibility(true)}} onMouseOut={()=>{setVisibility(false)}}>{p.song.report.expfccount>0?"":p.song.report.exfccount>0?"":""}{p.song.report.excount}</span>:<></>}
{p.song.report.exexcount>0?<span className="badge badge-danger" onMouseOver={()=>{setTooltip(<>{p.song.report.exexclearcount+" / "+p.song.report.exexcount+" ("+(Math.floor((p.song.report.exexclearcount/p.song.report.exexcount)*100))+"% pass rate)"}{(p.song.report.exexfccount>0)?<><br/>{"★FC'd "+p.song.report.exexfccount+" time"+(p.song.report.exexfccount!=1?"s":"")}</>:<></>}{(p.song.report.exexpfccount>0)?<><br/>{"✪Perfected "+p.song.report.exexpfccount+" time"+(p.song.report.exexpfccount!=1?"s":"")}</>:<></>}</>);setStyle("exex");setVisibility(true)}} onMouseOut={()=>{setVisibility(false)}}>{p.song.report.exexpfccount>0?"":p.song.report.exexfccount>0?"":""}{p.song.report.exexcount}</span>:<></>}
{(visibility)?<span style={{position:"absolute"}} className={"display-tooltip alert alert-dark "+style+"-background"}>{tooltip}</span>:<></>}
</td>
<td>
{(p.song.report.ehscount>0||p.song.report.ehdcount>0||p.song.report.esdcount>0)?
<ModDisplay badge="primary" diff="easy"
hs={p.song.report.ehscount} hd={p.song.report.ehdcount} sd={p.song.report.esdcount}/>
:<></>
}
{(p.song.report.nhscount>0||p.song.report.nhdcount>0||p.song.report.nsdcount>0)?
<ModDisplay badge="info" diff="normal"
hs={p.song.report.nhscount} hd={p.song.report.nhdcount} sd={p.song.report.nsdcount}/>
:<></>
}
{(p.song.report.hhscount>0||p.song.report.hhdcount>0||p.song.report.hsdcount>0)?
<ModDisplay badge="success" diff="hard"
hs={p.song.report.hhscount} hd={p.song.report.hhdcount} sd={p.song.report.hsdcount}/>
:<></>
}
{(p.song.report.exhscount>0||p.song.report.exhdcount>0||p.song.report.exsdcount>0)?
<ModDisplay badge="warning" diff="ex"
hs={p.song.report.exhscount} hd={p.song.report.exhdcount} sd={p.song.report.exsdcount}/>
:<></>
}
{(p.song.report.exexhscount>0||p.song.report.exexhdcount>0||p.song.report.exexsdcount>0)?
<ModDisplay badge="danger" diff="exex"
hs={p.song.report.exexhscount} hd={p.song.report.exexhdcount} sd={p.song.report.exexsdcount}/>
:<></>
}
</td>
</>
);
}
function PlayData(p) {
var [data,setData] = useState([])
var [update,setUpdate] = useState(false)
useEffect(()=>{
axios.get("http://projectdivar.com/plays/"+p.username+"/"+p.song.id)
.then((data)=>{setData(data.data);})
},[update])
return (
<>
<div className="text-center background-songs below">
<h5>Individual Plays for {p.song.name} from {p.username}</h5>
<div className="border rounded">
{data.map((play,i)=><Play setModalSrc={p.setModalSrc} setModalVisible={p.setModalVisible} key={i} play={play} mini={true} song={p.song}/>)}
<LoadMore url={"http://www.projectdivar.com/plays/"+p.username+"/"+p.song.id} params={{limit:15,offset:5}} value={data} setValue={setData}/>
</div>
</div>
</>
)
}
var cumulativeOffset = function(element) {
var top = 0, left = 0;
do {
top += element.offsetTop || 0;
left += element.offsetLeft || 0;
element = element.offsetParent;
} while(element);
return {
top: top,
left: left
};
};
function HoverSongName(p) {
let match = useRouteMatch({
path: "/user/"+p.username+"/"+p.to,
exact: true
});
var [name,setName] = useState(p.song.name)
var [expand,setExpand] = useState(<></>)
var [toggle,setToggle] = useState(match)
let history = useHistory();
useEffect(()=>{
if ((p.song.report.ecount+p.song.report.ncount+p.song.report.hcount+p.song.report.excount+p.song.report.exexcount>0)) {
if (toggle) {
setExpand(<tr className="fadein">
<td colSpan="6"><PlayData setModalSrc={p.setModalSrc} setModalVisible={p.setModalVisible} song={p.song} username={p.username}/></td>
</tr>)
window.scroll(0,cumulativeOffset(document.getElementById("songRow_"+p.song.name)).top-document.getElementById("songRow_"+p.song.name).getBoundingClientRect().height);
} else {
setExpand(<></>)
}
}
},[toggle])
return (
<>
<tr id={"songRow_"+p.song.name} key={p.song.id} className="lighthover cursor" onClick={(e)=>{
if ((p.song.report.ecount+p.song.report.ncount+p.song.report.hcount+p.song.report.excount+p.song.report.exexcount>0)) {
if (!toggle) {
setToggle(true)
history.push("/user/"+p.username+"/"+p.to)
} else {
setToggle(false)
}
}
//console.log(e.target.getBoundingClientRect()+"/"+window.pageYOffset)
}
}>
<td className="overflow-hidden">
{(p.song.report.ecount+p.song.report.ncount+p.song.report.hcount+p.song.report.excount+p.song.report.exexcount>0)?((toggle)?<></>:<>⯈</>):<></>} {name} <span className="tinytext">{(p.song.romanized_name.length>0)?<>{(p.song.romanized_name!==p.song.name)?<>{p.song.romanized_name}</>:<></>}</>:<>{(p.song.english_name!==p.song.name)?<>{p.song.english_name}</>:<></>}</>}</span>
</td>
<PlayDetail song={p.song}/>
</tr>
{expand}
</>
)
}
function HasSong(song,user) {
//console.log(JSON.stringify(song)+"/"+JSON.stringify(user))
return (song.mega39s&&user.megamix)||
(song.futuretone&&user.futuretone)
}
function CompletionPanel(p) {
const [report,setReport] = useState([])
const [song,setSong] = useState("")
const [filter,setFilter] = useState({})
const [style,setStyle] = useState(true)
const [update,setUpdate] = useState(false)
useEffect(()=>{
axios.get("http://projectdivar.com/completionreport/"+p.username)
.then((data)=>{setReport(data.data)})
.catch((err)=>{console.log(err.message)})
},[update,p.username])
return (
<>
<SongSearch songs={p.songs} song={song} setSong={setSong} setStyle={setStyle} filteredSongs={filter} setFilteredSongs={setFilter}/>
<table className="table table-sm">
<thead>
<tr id="headerbar">
<th scope="col" className={(style)?"scrollingHeader":""}>
Song Name
</th>
<th className={(style)?"scrollingHeader":""}>
Ranking
</th>
<th className={(style)?"scrollingHeader":""}>
Score
</th>
<th className={(style)?"scrollingHeader":""}>
%
</th>
<th className={(style)?"scrollingHeader":""}>
Play Count
</th>
<th className={(style)?"scrollingHeader":""}>
Mods
</th>
</tr>
</thead>
<tbody>
{report.filter((report)=>Object.keys(filter).length==0||report.id in filter).map((song,i)=>{return (HasSong(song,p.user))?<HoverSongName setModalSrc={p.setModalSrc} setModalVisible={p.setModalVisible} to={song.name} song={song} key={song.id} username={p.username}/>:<></>
})}
</tbody>
<tfoot>
<tr><td colSpan="8" id="footer" className={(style)?"scrollingFooter":""}>
<span className="badge badge-primary">Easy</span> <span className="badge badge-info">Normal</span> <span className="badge badge-success">Hard</span> <span className="badge badge-warning">Extreme</span> <span className="badge badge-danger">Extra Extreme</span> <span className="badge badge-light"> = FC</span> <span className="badge badge-light"> = Perfect FCs</span>
</td></tr>
</tfoot>
</table>
</>
);
}
function Panel() {
return (
<>
[Placeholder Panel]
</>
);
}
const CalculateAccuracy=(cool,fine,safe,sad,worst)=>{
var noteCount = cool+fine+safe+sad+worst;
var sum = cool+(fine*0.5)+(safe*0.1)+(sad*0.05);
return Math.round((sum/noteCount)*10000)/100+"%";
}
function ClearBadge(p) {
var [display,setDisplay] = useState(<></>)
/*<span className="badge badge-primary">{easy}/{diffs.E}
{(fcdata&&fcdata.E>0)?<><br/>{fcdata.E}</>:<></>}
{(pfcdata&&pfcdata.E>0)?<><br/>{pfcdata.E}</>:<></>}</span>*/
function toggle(state) {
if (state) {
setDisplay(<>{((p.fcdata&&p.fcdata[p.diff]>0)?<><br/> {p.fcdata[p.diff]}</>:<></>)}
{((p.pfcdata&&p.pfcdata[p.diff]>0)?<><br/> {p.pfcdata[p.diff]}</>:<></>)}</>)
} else {
setDisplay(<></>)
}
}
useEffect(()=>{
toggle(p.mouseOver)
},[p.mouseOver])
return(
<>
<span className={"badge badge-"+CalculateBadge(p.diff)} onTouchStart={()=>{toggle(true)}}>{p.count}/{p.diffs[p.diff]}{display}</span>
</>
)
}
function FavoritePlaystyle(p) {
switch (p.playstyle){
case "PS4 Controller":{
return <ProfileDataContainer playstyle_icon={true} label="Favorite Playstyle" data={p.playstyle} width="4"/>
}
case "Joycons":{
return <ProfileDataContainer playstyle_icon={true} label="Favorite Playstyle" data={p.playstyle} width="4"/>
}
case "Mix Mode":{
return <ProfileDataContainer playstyle_icon={true} label="Favorite Playstyle" data={p.playstyle} width="4"/>
}
case "Arcade Controller":{
return <ProfileDataContainer playstyle_icon={true} label="Favorite Playstyle" data={p.playstyle} width="4"/>
}
case "Touch Screen":{
return <ProfileDataContainer playstyle_icon={true} label="Favorite Playstyle" data={p.playstyle} width="4"/>
}
default:{
return <></>
}
}
}
function GamesPanel(p) {
return (
<div className="d-none d-sm-none d-md-block float-right">
{p.user.megamix&&<img style={{position:"absolute",right:"0px",top:"-8px"}} className="pr-2" src="http://projectdivar.com/files/mega39s.png"/>}
{p.user.futuretone&&<img style={{position:"absolute",right:(p.user.megamix)?"112px":"0px",top:"-8px"}} className="pl-2" src="http://projectdivar.com/files/futuretone.png"/>}
</div>
)
}
function Profile(p){
let { username } = useParams();
let match = useRouteMatch();
var [updateProfile,setProfile] = useState(false);
var [playcount,setPlayCount] = useState(0);
var [fccount,setFCCount] = useState(0);
var [cleared,setClear] = useState("");
var [accuracy,setAccuracy] = useState("-%");
var [rating,setRating] = useState(0);
var [lastPlayed,setLastPlayed] = useState(new Date());
var [update,setUpdate] = useState(false);
var [diffs,setDiffs] = useState({});
var [user,setUserData] = useState({});
var [render,setRender] = useState(false);
var [modalsrc,setModalSrc] = useState({})
var [modalVisible,setModalVisible] = useState(false);
var [mouseOver,setMouseOver] = useState(false);
function CalculateClear(easy,normal,hard,ex,exex,fcdata,pfcdata) {
return <>
<ClearBadge mouseOver={mouseOver} diff="E" count={easy} diffs={diffs} fcdata={fcdata} pfcdata={pfcdata}/>
<ClearBadge mouseOver={mouseOver} diff="N" count={normal} diffs={diffs} fcdata={fcdata} pfcdata={pfcdata}/>
<ClearBadge mouseOver={mouseOver} diff="H" count={hard} diffs={diffs} fcdata={fcdata} pfcdata={pfcdata}/>
<ClearBadge mouseOver={mouseOver} diff="EX" count={ex} diffs={diffs} fcdata={fcdata} pfcdata={pfcdata}/>
<ClearBadge mouseOver={mouseOver} diff="EXEX" count={exex} diffs={diffs} fcdata={fcdata} pfcdata={pfcdata}/>
</>
}
useEffect(()=>{
axios.get("http://projectdivar.com:4501/userdata/"+username)
.then((data)=>{setUserData(data.data);setPlayCount(data.data.playcount);setFCCount(data.data.fccount);setRating(data.data.rating);setLastPlayed(data.data.last_played);setAccuracy(CalculateAccuracy(data.data.cool,data.data.fine,data.data.safe,data.data.sad,data.data.worst))});
axios.get("http://projectdivar.com:4501/songdiffs")
.then((data)=>{setDiffs(data.data)})
setModalVisible(false);
},[update,username])
useEffect(()=>{
if (user!={}) {
setClear(CalculateClear(user.eclear,user.nclear,user.hclear,user.exclear,user.exexclear,user.fcdata,user.pfcdata))
}
},[diffs,user,mouseOver])
useEffect(()=>{
setRender(user!==undefined&&playcount!==undefined&&fccount!==undefined&&rating!==undefined&&lastPlayed!==undefined&&accuracy!==undefined&&diffs!==undefined&&cleared!==undefined)
},[user,playcount,fccount,rating,lastPlayed,accuracy,diffs,cleared])
return (
<>
<ImageDisplayer username={username} songs={p.songs} play={modalsrc} modalVisible={modalVisible} setModalVisible={setModalVisible}></ImageDisplayer>
<GamesPanel name="Games" user={user}/>
<h2>{username+"'s Profile"}</h2>
{(render)?<>
{user.playstyle&&user.playstyle.length>0&&
<div className="row">
<div className="col-md-4"></div>
<FavoritePlaystyle playstyle={user.playstyle}/>
<div className="col-md-4"></div>
</div>}
<StatisticsPanel name="Statistics" setMouseOver={setMouseOver} username={username} playcount={playcount} fccount={fccount} cleared={cleared} accuracy={accuracy}/>
<HitCountsPanel name="Hit Counts" username={username} user={user}/>
<BestPlaysPanel name="Best Plays" setModalVisible={setModalVisible} setModalSrc={setModalSrc} username={username} songs={p.songs}/>
<CompletionPanel name="Progress" user={user} setModalVisible={setModalVisible} setModalSrc={setModalSrc} username={username} songs={p.songs}/>
<Panel name="Activity" username={username}/>
</>
:<></>
}
</>
);
}
function Rankings(){
let { sort,sortOrder } = useParams();
let match = useRouteMatch();
var [users,setUsers] = useState([]);
var [updateUsers,setUpdateUsers] = useState(false);
var [isLoading,setIsLoading] = useState(true);
useEffect(()=>{
axios.get("http://projectdivar.com:4501/users/"+sort+"/"+sortOrder+"?limit=100&offset=0")
.then((data)=>{setUsers(data.data)
setIsLoading(false);})
//.then(()=>{console.log(users)})
},[updateUsers])
return (
<>
<table>
<thead>
<tr>
<th className="header"><Sort setIsLoading={setIsLoading} updateUsers={updateUsers} setUpdateUsers={setUpdateUsers} label="Username" order="username"/></th>
<th className="header"><Sort setIsLoading={setIsLoading} updateUsers={updateUsers} setUpdateUsers={setUpdateUsers} label="Last Played" order="last_played"/></th>
<th className="header"><Sort setIsLoading={setIsLoading} updateUsers={updateUsers} updateUsers={updateUsers} setUpdateUsers={setUpdateUsers} setUpdateUsers={setUpdateUsers} label="Rating" order="rating"/></th>
<th className="header"><Sort setIsLoading={setIsLoading} updateUsers={updateUsers} setUpdateUsers={setUpdateUsers} label="Play Count" order="playcount"/></th>
<th className="header"><Sort setIsLoading={setIsLoading} updateUsers={updateUsers} setUpdateUsers={setUpdateUsers} label="FC Count" order="fccount"/></th>
</tr>
</thead>
{users.map((user,i)=>
<tbody key={i}>
<tr>
<td className={(isLoading)?"loading":""}><Link to={"/user/"+user.username}>{user.username}</Link></td>
<td className={(isLoading)?"loading":""} className={(isLoading)?"loading":""} className={(isLoading)?"loading":""}>{user.last_played}</td>
<td className={(isLoading)?"loading":""} className={(isLoading)?"loading":""}>{user.rating}</td>
<td className={(isLoading)?"loading":""}>{user.playcount}</td>
<td className={(isLoading)?"loading":""}>{user.fccount}</td>
</tr>
</tbody>)}
</table>
</>
);
}
function ImageUpload(p) {
var [file,setFile] = useState(null);
var [fileProcess,setFileProcess] = useState(0);
var [error,setError] = useState(null);
var [success,setSuccess] = useState(null);
var [fileProgress,setFileProgress] = useState(0);
var [update,setUpdate] = useState(false);
var [authToken,setAuthToken] = useState(false);
useEffect(()=>{
axios.post("http://projectdivar.com/authenticate/authToken",{username:localStorage.getItem("username"),
authCode:localStorage.getItem("authToken")})
.then((data)=>{
setAuthToken(data.data.authentication_token)
})
},[update])
var prepFile = (e)=>{
setFile(e.currentTarget.files[0])
setError(null);
}
var uploadFile = (e)=>{
setError(null);
if (!file) {setError("No file selected!");return;}
if (file.type!=="application/x-zip-compressed" &&
file.type!=="image/jpeg" && file.type!=="image/png") {
setError("File type is invalid! Please provide a .zip/.jpg/.png file!")
setFileProcess(0)
return;
}
const data = new FormData()
data.append('file', file)
data.append("username",localStorage.getItem("username"));
data.append("authentication_token",authToken);
if (!data.has("username") || !data.has("authentication_token")) {setError("Authentication failed!");return;}
if (file.size>15*1024*1024) {
setError("File size is too large! Max is 15MB! Consider splitting your plays into chunks (Recommended 50 files per zip).");return;
}
//console.log(file)
setFileProcess(1);
axios.post("http://projectdivar.com/upload", data, {
onUploadProgress: function(progressEvent) {
//console.log(progressEvent)
setFileProgress(Math.round((progressEvent.loaded * 100) / progressEvent.total))
}})
.then(res => {
setSuccess(res.data);
setFileProgress(100)
setFileProcess(0)
})
.catch((err)=>{setError(err.message);setFileProgress(0);setFileProcess(0)})
}
switch (fileProcess) {
default:{
return (
<form method="post" action="#" id="#">
<div className="files form-group color">
<h3>Submit your play</h3>
<i>Plays can be a single image or a bunch of images in a zip file!</i>
<hr/>
{(success!=null)?<h4 className="success">{success}</h4>:<></>}
<div style={{position:"relative",top:"0px"}}>
<input type="file" name="file" className="form-control" onChange={(e)=>{prepFile(e)}} disabled={fileProcess===1}/>
<div className="uploadicon"/>
<div className="dragText">or drag it here</div>
</div>
{(error!==null)?<div className="error">{error}</div>:<></>}
<button type="button" className="btn btn-primary btn-block" onClick={(e)=>{uploadFile(e)}} disabled={fileProcess===1}>
{fileProcess===1?<>Uploading...<span className="spinner-border"/>
<div className="progress" style={{position:"relative"}}>
<div className={"progress-bar"} style={{width:fileProgress+"%"}} role="progressbar" aria-valuemin="0" aria-valuemax="100"></div>
<div style={{position:"relative"}}>{fileProgress+"%"}</div>
</div>
</>:<>Upload</>}</button>
</div>
</form>);
}
}
}
function SongSearch(p) {
//Requires: p.songs / p.song / p.setSong / p.filteredSongs / p.setFilteredSongs
const [song,setSong] = useState("")
const [focused,setFocused] = useState(false)
useEffect(()=>{
if (p.setStyle) {
if (focused) {
p.setStyle(false)
} else {
p.setStyle(true)
}
}
},[focused])
return (
<>
<input className="form-control form-control-lg" value={song} placeholder={"🔍 Search by Song,Artist,Vocaloid"} onKeyDown={(e)=>{if (e.key==="Enter") {setFocused(false);e.target.blur()}}} onFocus={()=>{setFocused(true)}} onChange={(e)=>{
if (p.setFilteredSongs){p.setFilteredSongs({})}
setSong(e.target.value)
}
} onBlur={()=>{
setTimeout(()=>{setFocused(false)},250)
}
}/>
{(focused)?
<div className="overflow-auto rounded-lg" style={{background:"#eef",position:"absolute",width:"95%",height:"240px"}}>{
Object.keys(p.songs).filter((key)=>
{
var s = p.songs[key]
return s.name.toLowerCase().includes(song.toLowerCase())||s.romanized_name.toLowerCase().includes(song.toLowerCase())||s.english_name.toLowerCase().includes(song.toLowerCase())||s.artist.toLowerCase().includes(song.toLowerCase())||s.vocaloid.toLowerCase().includes(song.toLowerCase())
}).map((key)=>{
if (p.setFilteredSongs&&p.filteredSongs) {
var obj = p.filteredSongs;
obj[key]=true
//console.log(obj)
p.setFilteredSongs(obj)
}
return <div key={key} className="pb-1 homelink highest" onClick={()=>{setSong(p.songs[key].name);p.setSong(p.songs[key].name);setFocused(false);if(p.setFilteredSongs&&p.filteredSongs){var obj={};obj[key]=true;p.setFilteredSongs(obj)}}}>
<div className="d-flex flex-row">
<div className="p-2">
<img className="centered" src={p.songs[key].album_art.replace("album_art","album_art/small")}/>
</div>
<div className="p-8">
<h4>{p.songs[key].name}</h4>{(p.songs[key].romanized_name)?p.songs[key].romanized_name:p.songs[key].english_name}
</div>
</div>
</div>})}</div>:<></>}
More stuff goes here.
</>
)
}
function SimpleUpload(p){
const [song,setSong] = useState("")
const [percentage,setPercentage] = useState("")
return (
<>
<SongSearch song={song} setSong={setSong} songs={p.songs}/>
{(song.length>0?<>
<div className="input-group">
<div className="input-group-prepend">
<label htmlFor="validationCustomUsername">
<span className="input-group-text" id= "inputGroupPrepend">Song %</span>
</label>
<input type="text" className="form-control" id="validationCustomUsername" value={percentage} placeholder="101.46%" aria-describedby="inputGroupPrepend"
onChange={(e)=>{
if (!e.target.value.includes("%")) {
e.target.value+="%"
e.target.selectionStart=e.target.selectionEnd=e.target.value.length-1
}
setPercentage(e.target.value)}}
required/>
<small className="text-muted">
Input the % you got on the results screen.
</small>
</div>
</div>
</>:<></>)}
</>
)
}
function Submit(p) {
return (
<div className="row">
<div className="col-12 col-md-8">
<Switch>
<Route path="/submitplay/simple">
<SimpleUpload songs={p.songs}/>
</Route>
<Route path="/submitplay/detail">
Detailed
</Route>
<Route path="/submitplay/switch">
<h2>Nintendo Switch/Twitter Upload</h2>
Want to upload your scores to the website conveniently? Go to <Link to="/usersettings">Edit Profile Settings</Link> and enter your Twitter username, then follow the steps below!
<hr/>
<div className="row mb-4">
<div className="col-4 m-6">
<h4>Step 1</h4>
From your Nintendo Switch Album, select up to 4 results screenshots that you want the DivaRBot to parse.
</div>
<div className="col-8 m-6">
<img width="100%" className="border rounded shadow" src="http://projectdivar.com/files/switch1.png"/>
</div>
</div>
<div className="row">
<div className="col-8 m-6">
<img width="100%" className="border rounded shadow" src="http://projectdivar.com/files/switch2.png"/>
</div>
<div className="col-4 m-6">
<h4>Step 2</h4>
Make sure to include <b>@divarbot</b> so the bot can find your plays! Then submit and the bot will process them in just a few minutes! Check your scores out after they have been processed.
</div>
</div>
</Route>
<Route path="/submitplay/image">
<ImageUpload/>
</Route>
<Route path="/submitplay">
<h2>Select a submission method</h2>
{false&&<><div className="card">
<Link to="/submitplay/simple" className="nostyle">
<div className="card-body">
<h5 className="card-title">Manual Submit</h5>
<p className="card-text">Submit your plays by entering the clear % of a song</p>
<p className="card-text"><small className="text-muted">The simplest way to submit plays, type in a %, tweak the other values quickly, then submit your play! Optionally include a screenshot.</small></p>
</div>
</Link>
</div>
<br/></>}
<div className="card">
<Link to="/submitplay/image" className="nostyle">
<div className="card-body">
<h5 className="card-title">Image Upload</h5>
<p className="card-text">Upload images from your Nintendo Switch for automatic processing/scoring!</p>
<p className="card-text"><small className="text-muted">Put up to 50 images in a zip file to mass-upload your screenshotted plays to your profile. You will need to extract them from your microSD card from your Nintendo Switch.</small></p>
</div>
</Link>
</div>
<br/>
<div className="card">
<Link to="/submitplay/switch" className="nostyle">
<div className="card-body">
<h5 className="card-title">Nintendo Switch/Twitter Upload</h5>
<p className="card-text">Setup your account for uploading through Twitter using your Nintendo Switch!</p>
<p className="card-text"><small className="text-muted">You can select up to 4 images to post to Twitter at one time.</small></p>
</div>
</Link>
</div>
</Route>
</Switch>
</div>
</div>
)
}
function RecentPlays(p) {
const [update,setUpdate] = useState(false)
const [recentPlayData,setRecentPlayData] = useState([])
useEffect(()=>{
const interval = setInterval(()=>{
axios.get("http://projectdivar.com/recentplays/sigonasr2")
.then((data)=>{
setRecentPlayData(data.data);
})
.catch((err)=>{})
},5000);
return ()=>{clearInterval(interval)}
},[update])
return (
<>
{recentPlayData.map((play,i)=><Play index={i} play={play} song={p.songs[play.songid]} title={true} mini={true}/>)}
</>
)
}
function LoginInfo(p) {
const [username,setUsername] = useState(undefined)
const [authToken,setAuthToken] = useState(undefined)
const [loggedIn,setLoggedIn] = useState(false)
//Load our storage data if exists.
useEffect(()=>{
try {
setUsername(localStorage.getItem("username"))
setAuthToken(localStorage.getItem("authToken"))
}catch{
console.log("Not logged in!");
}
},[p.update])
useEffect(()=>{
if (username!==undefined&&authToken!==undefined) {
axios.post("http://projectdivar.com/authenticate/login",{username:username,authCode:authToken})
.then((data)=>{
setLoggedIn(true);
p.setUsername(username);
p.setUserSettings(data.data)
})
.catch((err)=>{
setLoggedIn(false);
})
}
},[username,authToken])
return (
<>
{loggedIn?<>
Welcome, <b>{username}</b>!<br/>
<Link to={"/user/"+username}>My Profile</Link><br/>
<Link to={"/usersettings"}>Edit Profile Settings</Link><br/>
<Link to="/auth">App Auth Code</Link><br/>
</>:<>
<Link to="/login">Login</Link><br/>
<Link to="/register">Register</Link>
</>}
</>
)
}
function Login(p) {
const [username,setUsername] = useState("")
const [authCode,setAuthCode] = useState("")
const [authCodeVisible,setAuthCodeVisible] = useState(false)
const [error,setError] = useState(false)
const [disabled,setDisabled] = useState(false)
let history = useHistory();
if (p.isLoggedIn) {
history.push("/")
}
return (
<>
<Form>
{error&&<h3 style={{color:"red"}}>{error}</h3>}
{authCodeVisible&&<><h3>We have sent you an email containing your login code!</h3>
<br/>
Please submit it to finish the login process.
</>}
<Form.Group controlId="formUsername">
<Form.Label>Username</Form.Label>
<Form.Control disabled={authCodeVisible} isInvalid={username.length<1} onChange={(e)=>{setUsername(e.currentTarget.value)}} placeholder="MikuMiku" value={username} />
<Form.Text className="text-muted">
We will send an email to the registered email of this account.
</Form.Text>
</Form.Group>
{authCodeVisible&&<>
<div className="row">
<div className="col-4">
<Form.Group controlId="formCode">
<Form.Label>Authentication Code</Form.Label>
<Form.Control type="password" isInvalid={authCode.length!=5} onChange={(e)=>{setAuthCode(e.currentTarget.value)}} placeholder="XXXXX" value={authCode} />
<Form.Text className="text-muted">
Please enter the code you received in your email here. Then submit again.
</Form.Text>
</Form.Group>
</div>
</div></>
}
<Button disabled={disabled} variant="primary" type="submit" onClick={(e)=>{e.preventDefault()
if (username.length>=1) {
setDisabled(true)
setError(false)
if (authCode.length===5) {
axios.post("http://projectdivar.com/authenticate/login",{username:username,authCode:authCode})
.then((data)=>{
localStorage.setItem("username",username)
localStorage.setItem("authToken",authCode)
p.setLoginPanelUpdate(true)
history.push("/")
})
.catch((err)=>{
if (err) {
setError("Invalid Authentication Code!")
setDisabled(false)
}
})
} else {
axios.post("http://projectdivar.com/sendemail/login",{username:username})
.then((data)=>{
setAuthCodeVisible(true)
setDisabled(false)
})
.catch((err)=>{
if (err) {
setError("Invalid credentials provided!")
setDisabled(false)
}
})
}
}
}}>
{authCodeVisible?"Submit Code":"Login"}
</Button>
</Form>
</>
)
}
function Register(p) {
const [username,setUsername] = useState("")
const [email,setEmail] = useState("")
const [authCode,setAuthCode] = useState("")
const [authCodeVisible,setAuthCodeVisible] = useState(false)
const [error,setError] = useState(false)
const [disabled,setDisabled] = useState(false)
let history = useHistory();
if (p.isLoggedIn) {
history.push("/")
}
return (
<>
<Form>
{error&&<h3 style={{color:"red"}}>{error}</h3>}
{authCodeVisible&&<><h3>We have sent you an email containing your registration code!</h3>
<br/>
Please submit it to finish the registration process.
</>}
<Form.Group controlId="formUsername">
<Form.Label>Username</Form.Label>
<Form.Control disabled={authCodeVisible} isInvalid={username.length<1} onChange={(e)=>{setUsername(e.currentTarget.value)}} placeholder="MikuMiku" value={username} />
</Form.Group>
<Form.Group controlId="formEmail">
<Form.Label>Email Address</Form.Label>
<Form.Control disabled={authCodeVisible} type="email" disabled={authCodeVisible} isInvalid={email.length<1} onChange={(e)=>{setEmail(e.currentTarget.value)}} placeholder="MikuMiku@39.net" value={email} />
<Form.Text className="text-muted">
Please provide a valid email address! We use your email account as your "password", so it is a requirement for this site.
</Form.Text>
</Form.Group>
{authCodeVisible&&<>
<div className="row">
<div className="col-4">
<Form.Group controlId="formAuthCode">
<Form.Label>Authentication Code</Form.Label>
<Form.Control type="password" isInvalid={authCode.length!=5} onChange={(e)=>{setAuthCode(e.currentTarget.value)}} placeholder="XXXXX" value={authCode} />
<Form.Text className="text-muted">
Please enter the code you received in your email here. Then submit again.
</Form.Text>
</Form.Group>
</div>
</div></>
}
<Button disabled={disabled} variant="primary" type="submit" onClick={(e)=>{e.preventDefault()
if (username.length>=1&&email.length>=1) {
setDisabled(true)
setError(false)
if (authCode.length===5) {
axios.post("http://projectdivar.com/authenticate/login",{username:username,authCode:authCode})
.then((data)=>{
localStorage.setItem("username",username)
localStorage.setItem("authToken",authCode)
p.setLoginPanelUpdate(true)
return axios.patch("http://projectdivar.com/updateRegisteredState",{username:username,authCode:authCode})
})
.then((data)=>{
//console.log(data)
history.push("/")
})
.catch((err)=>{
if (err) {
setError("Invalid Authentication Code!")
setDisabled(false)
}
})
} else {
axios.post("http://projectdivar.com/sendemail/register",{username:username,email:email})
.then((data)=>{
setAuthCodeVisible(true)
setDisabled(false)
})
.catch((err)=>{
if (err) {
setError("Username or Email already in use!")
setDisabled(false)
}
})
}
}
}}>
{authCodeVisible?"Submit Code":"Register"}
</Button>
</Form>
</>
)
}
function UserSettings(p) {
let history = useHistory();
const [playStyle,setPlayStyle] = useState(p.userSettings.playstyle)
const [playStyleHover,setPlayStyleHover] = useState(undefined)
const [twitter,setTwitter] = useState(p.userSettings.twitter_name)
const [twitterChange,setTwitterChange] = useState(false)
const [message,setMessage] = useState(false)
const [error,setError] = useState(false)
if (p.username===undefined) {
history.push("/")
}
return (
<>
<Form.Group controlId="playstyle" onMouseOut={()=>{setPlayStyleHover(undefined)}}>
<Form.Label>Favorite Playstyle</Form.Label> - <b>{playStyle}</b>
<br/>
<Button onClick={()=>{setPlayStyle("PS4 Controller")}} onMouseOver={()=>{setPlayStyleHover("PS4 Controller")}} variant={playStyle==="PS4 Controller"?"info":"outline-info"}><IMAGE_CONTROLLER width={36} height={36}/></Button>
<Button onClick={()=>{setPlayStyle("Joycons")}} onMouseOver={()=>{setPlayStyleHover("Joycons")}} variant={playStyle==="Joycons"?"primary":"outline-primary"}><IMAGE_JOYCONS width={36} height={36}/></Button>
<Button onClick={()=>{setPlayStyle("Mix Mode")}} onMouseOver={()=>{setPlayStyleHover("Mix Mode")}} variant={playStyle==="Mix Mode"?"secondary":"outline-secondary"}><IMAGE_MIXMODE width={36} height={36}/></Button>
<Button onClick={()=>{setPlayStyle("Arcade Controller")}} onMouseOver={()=>{setPlayStyleHover("Arcade Controller")}} variant={playStyle==="Arcade Controller"?"success":"outline-success"}><IMAGE_ARCADE width={36} height={36}/></Button>
<Button onClick={()=>{setPlayStyle("Touch Screen")}} onMouseOver={()=>{setPlayStyleHover("Touch Screen")}} variant={playStyle==="Touch Screen"?"warning":"outline-warning"}><IMAGE_TABLET width={36} height={36}/></Button>
<Form.Text className="text-muted">
{playStyleHover?<>Change playstyle to <b>{playStyleHover}</b></>:<>Your playstyle will be included in your submitted plays.</>}
</Form.Text>
</Form.Group>
<hr/>
<Form.Group controlId="twitter" onMouseOut={()=>{setPlayStyleHover(undefined)}}>
<Form.Label>Twitter Username:</Form.Label>
<Form.Control onChange={(e)=>{setTwitter(e.currentTarget.value);setTwitterChange(true)}} value={twitter} placeholder="MikuMiku"/>
<Form.Text className="text-muted">
If you input your Twitter username, you can submit screenshots to <b>@divarbot</b> (with "@divarbot" in the message) and your plays will auto-submit from Twitter at any time.
</Form.Text>
</Form.Group>
<Button onClick={()=>{
var obj = {username:localStorage.getItem("username"),
authCode:localStorage.getItem("authToken"),
playStyle:playStyle}
if (playStyle===undefined||playStyle===null) {
setError("Please select a play style before saving!")
return;
}
if (twitterChange) {
obj.twitterName=twitter;
}
setError(false)
setMessage(false)
axios.post("http://projectdivar.com/updateuser",obj)
.then((data)=>{
setMessage(data.data)
p.setUserSettings({...p.userSettings,playStyle:playStyle,twitter_name:twitter})
setTwitterChange(false)
})
.catch((err)=>{
setError(err.message)
})
}}>Save Changes</Button>
{message&&<h3 style={{color:"green"}}>{message}</h3>}
{error&&<h3 style={{color:"red"}}>{error}</h3>}
</>
)
}
function UserAuth(p) {
const[showAuthCode,setShowAuthCode] = useState(false)
const[authToken,setAuthToken] = useState("")
let history = useHistory();
if (!p.isLoggedIn) {
history.push("/")
}
return(<>
Your <b>App Authentication Code</b> is used for verifying your identity when using apps such as <b>DivaBot</b>. By clicking the <b>{"<Reveal Code>"}</b> button, you understand that you should not share this code or show it to anyone!
<br/><br/>
{showAuthCode?
<input readOnly value={authToken}></input>
:<button onClick={()=>{
axios.post("http://projectdivar.com/authenticate/authToken",{username:localStorage.getItem("username"),
authCode:localStorage.getItem("authToken")})
.then((data)=>{
setAuthToken(data.data.authentication_token)
setShowAuthCode(true)
})
.catch((err)=>{
setAuthToken(err.message)
})
}
}>
{"<Click to reveal App Authentication Code>"}
</button>
}
</>)
}
function ReleaseList(p) {
return(
<>
<ul className="list-group">
{p.releases.map((release,i)=>
<li key={i} className="list-group-item">
<b>{release[0]}</b> - <a href={release[1]}>{release[1].replace("http://projectdivar.com/files/releases/","")}</a> <i>(Released {release[2]})</i> - {release[3]}
</li>
)}
</ul>
</>
)
}
function DivaBot() {
const releases=[
["05B","http://projectdivar.com/files/releases/DivaBot05B.zip","22 Sep 2020",<> <Badge variant="info" pill>Recommended</Badge> <i>Improved song select recognition speed.</i></>],
["05A","http://projectdivar.com/files/releases/DivaBot05A.zip","21 Sep 2020",<> <i>Added multi-monitor support. Use calibration to switch monitors.</i></>],
["05","http://projectdivar.com/files/releases/DivaBot05.zip","21 Sep 2020",<> <i>Added Miku FC. Huge optimizations to result screen capture, improve menu detection algorithms.</i></>],
["04B","http://projectdivar.com/files/releases/DivaBot04A2.zip","20 Sep 2020",<> <i>Redo the calibrator and improve Future Tone recognition.</i></>],
["04A","http://projectdivar.com/files/releases/DivaBot04A1.zip","19 Sep 2020",<> <IMAGE_BUG/> <i>Fix issues with Future tone songs with *s in them.</i></>],
["04","http://projectdivar.com/files/releases/DivaBot04.zip","19 Sep 2020",<> <IMAGE_BUG/> <i>Update so everything's working! Future Tone compatibility live!</i></>],
["03-beta","http://projectdivar.com/files/releases/DivaBot03-beta.zip","19 Sep 2020",<><IMAGE_BUG/> <Badge variant="success" pill>BUGGED</Badge> <i>Added Future Tone compatibility. Works with Megamix or Future Tone.</i></>],
["03","http://projectdivar.com/files/releases/DivaBot03.zip","17 Sep 2020",<><Badge variant="warning" pill>Megamix ONLY</Badge> <i>DLC Update - Compatibility with removed 'bpm' field from database. Fixed bug with ":" in song names.</i></>],
]
const incompatiblereleases=[
["02A","http://projectdivar.com/files/releases/DivaBot02A.zip","14 Sep 2020",<><Badge variant="warning" pill>Incompatible</Badge> <i>Label Headers and Redo Song Calibration features added</i></>],
["02","http://projectdivar.com/files/releases/DivaBot02.zip","14 Sep 2020",<><Badge variant="warning" pill>Incompatible!</Badge></>],
["01B","http://projectdivar.com/files/releases/DivaBot01B.zip","13 Sep 2020",<><IMAGE_BUG/> <Badge variant="warning" pill>Incompatible</Badge> <Badge variant="success" pill>BUGGED</Badge> <b>DO NOT USE!</b></>],
["01A","http://projectdivar.com/files/releases/DivaBot01A.zip","13 Sep 2020",<><IMAGE_BUG/> <Badge variant="warning" pill>Incompatible</Badge> <Badge variant="success" pill>BUGGED</Badge> <b>DO NOT USE!</b> <i>Speed Improvements</i></>],
["01","http://projectdivar.com/files/releases/DivaBot01.zip","13 Sep 2020",<><IMAGE_BUG/> <Badge variant="warning" pill>Incompatible</Badge> <Badge variant="success" pill>BUGGED</Badge> <b>DO NOT USE!</b> <i>Initial Release</i></>]
]
return (
<>
<b>DivaBot</b> was created by <b>sigonasr2</b> in order to allow Project Diva streamers to personalize their stream setups with their personal scores and achievements into their game.
<br/><br/>
The app works by monitoring your game's capture area as you are streaming in order to identify what song you are playing, and what scores you achieve. It is used with this website to make score
submitting and tracking easier.
<br/>
The app currently supports <b>Megamix</b> and <b>Future Tone</b>. Other games will be supported in the future.
<hr/>
<h3>Setup Instructions</h3>
{<iframe width="100%" height="480" src="https://www.youtube.com/embed/IAPpbp5EFto" frameBorder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowFullScreen></iframe>}
<hr/>
<h3>Downloads</h3>
<ReleaseList releases={releases}/>
<hr/>
<h3>Repository - Open Source Software</h3>
I don't believe in keeping things secret and you shouldn't be open to just downloading whatever you find on the Internet.
<br/><br/><b>This app and Project DivaR</b> itself is open source. You can find its source code <a href="https://github.com/sigonasr2/DivaBot" target="_blank">at this link</a>.
<br/><br/>
If you need an open discussion about how this program works or have any feedbacks/concerns, please contact me via the <b>Project DivaR Discord</b> server (<b>@sigonasr2</b>).
<hr/>
<h3>Incompatible Downloads</h3>
Downloads stored below no longer work due to infrastructure changes or updates that break old apps.
<ReleaseList releases={incompatiblereleases}/>
<hr/>
</>
)
}
function StreamData() {
const [imageSet,setImageSet] = useState(0);
const [rando1,setRando1] = useState(Date.now());
const [rando2,setRando2] = useState(Date.now());
useEffect(()=>{
setTimeout(()=>{
if (imageSet===0) {
setImageSet(50)
setRando1(Date.now())
} else {
setImageSet(0)
setRando2(Date.now())
}
},5000)
},[imageSet])
return(
<>
{(imageSet===0)?<><img style={{visibility:"visible"}} src={"http://projectdivar.com:8080/feed/output0.png?"+rando1} id={rando1}/><img style={{visibility:"hidden"}} id={rando2} src={"http://projectdivar.com:8080/feed/output2.png?"+rando2}/></>:<><img style={{visibility:"visible"}} id={rando2} src={"http://projectdivar.com:8080/feed/output2.png?"+rando2}/><img id={rando1} style={{visibility:"hidden"}} src={"http://projectdivar.com:8080/feed/output0.png?"+rando1}/></>}
</>
)
}
function Website() {
const [songs,setSongs] = useState([])
const [update,setUpdate] = useState(false)
const [tooltip,setTooltip] = useState("")
const [loginPanelUpdate,setLoginPanelUpdate] = useState(false)
const [username,setUsername] = useState(undefined)
const [userSettings,setUserSettings] = useState({})
useEffect(()=>{
axios.get("http://www.projectdivar.com/songs")
.then((data)=>{
setSongs(data.data)
})
},[update])
return (
<div className="row">
<div className="col-md-2 pt-3 pb-3 overflow-hidden text-center">
<h3 className="d-none d-md-block">Menu</h3>
<LoginInfo setUserSettings={setUserSettings} setUsername={setUsername} update={loginPanelUpdate}/>
<br/><br/>
<Link to="/rankings/rating/desc">Rankings</Link><br/>
<Link to="/submitplay">Submit Scores</Link><br/>
<Link to="/divabot">DivaBot</Link><br/>
<hr/>
<a href="http://discord.gg/eJ3cMzM"><img src="http://projectdivar.com/files/discord_button_small.png"/></a>
</div>
<div className="col-md-10 pt-3 pb-3">
<Switch>
<Route path="/rankings/:sort/:sortOrder">
<Rankings/>
</Route>
<Route path="/user/:username">
{(songs)?
<Profile songs={songs}/>:<></>
}
</Route>
<Route path="/usersettings">
{
<UserSettings setUserSettings={setUserSettings} userSettings={userSettings} username={username}/>
}
</Route>
<Route path="/submitplay">
<Submit songs={songs}/>
</Route>
<Route path="/divabot">
<h1 className="title">DivaBot</h1>
<DivaBot/>
</Route>
<Route path="/auth">
<h1 className="title">App Authentication Token</h1>
<UserAuth username={username} isLoggedIn={username!==undefined}/>
</Route>
<Route path="/recentplays">
<h1 className="title">Project DivaR</h1>
<RecentPlays songs={songs}/>
</Route>
<Route path="/login">
<h1 className="title">Login to Project DivaR</h1>
<Login isLoggedIn={username!==undefined} setLoginPanelUpdate={setLoginPanelUpdate}/>
</Route>
<Route path="/register">
<h1 className="title">Register New Account</h1>
<Register isLoggedIn={username!==undefined} setLoginPanelUpdate={setLoginPanelUpdate}/>
</Route>
<Route path="/stream">
<h1 className="title">Stream</h1>
<StreamData/>
</Route>
<Route path="/">
<h1 className="title">Project DivaR</h1>
Under construction!
</Route>
</Switch>
</div>
</div>
);
}
/*window.onmousemove = function(e) {
var obj = document.getElementById("display-tooltip")
if (obj!=null) {
//var offset = obj.parentElement.getBoundingClientRect();
var tipDist = 15;
obj.style.top = (e.clientY + tipDist) + 'px';
obj.style.left = (e.clientX + tipDist) + 'px';
}
}*/
function App() {
return (
<Router>
<div className="container-fluid content">
<div className="row">
<div className="topbar col-md-12 pt-1 overflow-hidden border rounded text-center">
<div>
<Link to="/">
<Logo/>
</Link>
</div>
</div>
</div>
<Website/>
</div>
</Router>
)
}
export default App;