Initial commit
@@ -1,129 +1,26 @@
|
|||||||
# Byte-compiled / optimized / DLL files
|
# Windows thumbnails
|
||||||
__pycache__/
|
Thumbs.db
|
||||||
*.py[cod]
|
Thumbs.db:encryptable
|
||||||
*$py.class
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
|
||||||
# C extensions
|
# Volatile files
|
||||||
*.so
|
tokens/*
|
||||||
|
users/*
|
||||||
|
API/cache/*
|
||||||
|
lobbies/*
|
||||||
|
matches/*
|
||||||
|
requests.json
|
||||||
|
unalike.json
|
||||||
|
users.json
|
||||||
|
|
||||||
# Distribution / packaging
|
# Files that are not appropriate for git
|
||||||
.Python
|
created.txt
|
||||||
build/
|
description.txt
|
||||||
develop-eggs/
|
title.txt
|
||||||
dist/
|
start-wt.bat
|
||||||
downloads/
|
|
||||||
eggs/
|
|
||||||
.eggs/
|
|
||||||
lib/
|
|
||||||
lib64/
|
|
||||||
parts/
|
|
||||||
sdist/
|
|
||||||
var/
|
|
||||||
wheels/
|
|
||||||
pip-wheel-metadata/
|
|
||||||
share/python-wheels/
|
|
||||||
*.egg-info/
|
|
||||||
.installed.cfg
|
|
||||||
*.egg
|
|
||||||
MANIFEST
|
|
||||||
|
|
||||||
# PyInstaller
|
# Sensitive information
|
||||||
# Usually these files are written by a python script from a template
|
api_key.php
|
||||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
local_secret.php
|
||||||
*.manifest
|
account.php
|
||||||
*.spec
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
pip-delete-this-directory.txt
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
htmlcov/
|
|
||||||
.tox/
|
|
||||||
.nox/
|
|
||||||
.coverage
|
|
||||||
.coverage.*
|
|
||||||
.cache
|
|
||||||
nosetests.xml
|
|
||||||
coverage.xml
|
|
||||||
*.cover
|
|
||||||
*.py,cover
|
|
||||||
.hypothesis/
|
|
||||||
.pytest_cache/
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
*.mo
|
|
||||||
*.pot
|
|
||||||
|
|
||||||
# Django stuff:
|
|
||||||
*.log
|
|
||||||
local_settings.py
|
|
||||||
db.sqlite3
|
|
||||||
db.sqlite3-journal
|
|
||||||
|
|
||||||
# Flask stuff:
|
|
||||||
instance/
|
|
||||||
.webassets-cache
|
|
||||||
|
|
||||||
# Scrapy stuff:
|
|
||||||
.scrapy
|
|
||||||
|
|
||||||
# Sphinx documentation
|
|
||||||
docs/_build/
|
|
||||||
|
|
||||||
# PyBuilder
|
|
||||||
target/
|
|
||||||
|
|
||||||
# Jupyter Notebook
|
|
||||||
.ipynb_checkpoints
|
|
||||||
|
|
||||||
# IPython
|
|
||||||
profile_default/
|
|
||||||
ipython_config.py
|
|
||||||
|
|
||||||
# pyenv
|
|
||||||
.python-version
|
|
||||||
|
|
||||||
# pipenv
|
|
||||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
||||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
||||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
||||||
# install all needed dependencies.
|
|
||||||
#Pipfile.lock
|
|
||||||
|
|
||||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
|
||||||
__pypackages__/
|
|
||||||
|
|
||||||
# Celery stuff
|
|
||||||
celerybeat-schedule
|
|
||||||
celerybeat.pid
|
|
||||||
|
|
||||||
# SageMath parsed files
|
|
||||||
*.sage.py
|
|
||||||
|
|
||||||
# Environments
|
|
||||||
.env
|
|
||||||
.venv
|
|
||||||
env/
|
|
||||||
venv/
|
|
||||||
ENV/
|
|
||||||
env.bak/
|
|
||||||
venv.bak/
|
|
||||||
|
|
||||||
# Spyder project settings
|
|
||||||
.spyderproject
|
|
||||||
.spyproject
|
|
||||||
|
|
||||||
# Rope project settings
|
|
||||||
.ropeproject
|
|
||||||
|
|
||||||
# mkdocs documentation
|
|
||||||
/site
|
|
||||||
|
|
||||||
# mypy
|
|
||||||
.mypy_cache/
|
|
||||||
.dmypy.json
|
|
||||||
dmypy.json
|
|
||||||
|
|
||||||
# Pyre type checker
|
|
||||||
.pyre/
|
|
||||||
@@ -0,0 +1,301 @@
|
|||||||
|
<?php
|
||||||
|
// http://zovguran.net/Unalike/API
|
||||||
|
include "../api_key.php";
|
||||||
|
|
||||||
|
if (!empty($_GET["username"]) || !empty($_GET["userid"]))
|
||||||
|
{
|
||||||
|
$id = -1;
|
||||||
|
$online = false;
|
||||||
|
$token = "";
|
||||||
|
|
||||||
|
if (!empty($_GET["username"]))
|
||||||
|
{
|
||||||
|
$username = strtolower($_GET["username"]);
|
||||||
|
$users = json_decode(file_get_contents(getcwd()."/../users.json"), true);
|
||||||
|
if (!empty($users[$username]))
|
||||||
|
{
|
||||||
|
$id = $users[$username];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$id = $username;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!empty($_GET["userid"]))
|
||||||
|
{
|
||||||
|
$id = $_GET["userid"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($id == "~Unalike")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if ($id < 0)
|
||||||
|
{
|
||||||
|
echo "Unauthorized";
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
$base_url_v2 = "https://osu.ppy.sh/api/v2";
|
||||||
|
$base_url_v1 = "https://osu.ppy.sh/api";
|
||||||
|
|
||||||
|
$diffs_redirect = false;
|
||||||
|
$cross_mode = false; // single-output for Python
|
||||||
|
// d = all [d]ifficulties
|
||||||
|
// x = Python [x]ross mode (non-json output, single beatmapset)
|
||||||
|
if (!empty($_GET["b"]) || !empty($_GET["d"]) || !empty($_GET["x"]))
|
||||||
|
{
|
||||||
|
if (!empty($_GET["x"]))
|
||||||
|
{
|
||||||
|
$beatmap = $_GET["x"];
|
||||||
|
$cross_mode = true;
|
||||||
|
}
|
||||||
|
else if (!empty($_GET["d"]))
|
||||||
|
{
|
||||||
|
$beatmap = $_GET["d"];
|
||||||
|
$diffs_redirect = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$beatmap = $_GET["b"];
|
||||||
|
}
|
||||||
|
$url = $base_url_v2 . "/beatmaps/{$beatmap}";
|
||||||
|
|
||||||
|
$cache_as = array(
|
||||||
|
"type" => "beatmap-v2",
|
||||||
|
"id" => $beatmap,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($_GET["u"]))
|
||||||
|
{
|
||||||
|
if (!empty($_GET["u"]))
|
||||||
|
{
|
||||||
|
$user = $_GET["u"];
|
||||||
|
}
|
||||||
|
|
||||||
|
$url = $base_url_v2 . "/users/{$user}/osu";
|
||||||
|
|
||||||
|
$cache_as = array(
|
||||||
|
"type" => "user",
|
||||||
|
"id" => $user,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$legacy_mode = false;
|
||||||
|
// y = [y] u do dis
|
||||||
|
if (!empty($_GET["y"]))
|
||||||
|
{
|
||||||
|
$beatmap = $_GET["y"];
|
||||||
|
$cross_mode = true;
|
||||||
|
$legacy_mode = true;
|
||||||
|
$url = $base_url_v1 . "/get_beatmaps?k={$api_key}&b={$beatmap}";
|
||||||
|
|
||||||
|
$cache_as = array(
|
||||||
|
"type" => "beatmap",
|
||||||
|
"id" => $beatmap,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$filter_diffs = false;
|
||||||
|
// f = difficulty id only [f]ilter
|
||||||
|
if (!empty($_GET["s"]) || !empty($_GET["f"]))
|
||||||
|
{
|
||||||
|
if (!empty($_GET["f"]))
|
||||||
|
{
|
||||||
|
$beatmapset = $_GET["f"];
|
||||||
|
$filter_diffs = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$beatmapset = $_GET["s"];
|
||||||
|
}
|
||||||
|
$url = $base_url_v1 . "/get_beatmaps?k={$api_key}&s={$beatmapset}";
|
||||||
|
|
||||||
|
$cache_as = array(
|
||||||
|
"type" => "beatmapset",
|
||||||
|
"id" => $beatmapset,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// m = [m]ultiplayer match
|
||||||
|
if (!empty($_GET["m"]))
|
||||||
|
{
|
||||||
|
$lobby = $_GET["m"];
|
||||||
|
$url = $base_url_v1 . "/get_match?k={$api_key}&mp={$lobby}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strtolower($id) == "~unalike")
|
||||||
|
{
|
||||||
|
$token = "not-v2-so-no-key-needed-sry-peppy-for-including-this-field";
|
||||||
|
$online = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$token_file = getcwd() . "/../tokens/{$id}.json";
|
||||||
|
if (file_exists($token_file))
|
||||||
|
{
|
||||||
|
$token_json = json_decode(file_get_contents($token_file), true);
|
||||||
|
if (!empty($token_json["access_token"]))
|
||||||
|
{
|
||||||
|
$token = $token_json["access_token"];
|
||||||
|
$online = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// t = [t]est api access
|
||||||
|
if (!empty($_GET["t"]))
|
||||||
|
{
|
||||||
|
if (!empty($token_json["expires_at"]) && $token_json["expires_at"] > (time()+3600))
|
||||||
|
{
|
||||||
|
echo "YES";
|
||||||
|
}
|
||||||
|
else if (!empty($token_json["expires_at"]) && $token_json["expires_at"] > time())
|
||||||
|
{
|
||||||
|
echo "YES+EXPIRING";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
echo "NO";
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($cache_as["type"]) && !empty($cache_as["id"]))
|
||||||
|
{
|
||||||
|
$cache_type = $cache_as["type"];
|
||||||
|
$cache_id = $cache_as["id"];
|
||||||
|
$cache_location = "./cache/{$cache_type}/{$cache_id}.json";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($cache_location) && file_exists($cache_location))
|
||||||
|
{
|
||||||
|
$data = file_get_contents($cache_location);
|
||||||
|
}
|
||||||
|
else if ($online && isset($url) && !empty($token))
|
||||||
|
{
|
||||||
|
// echo '<html style="background:black;color:white;font-family:sans-serif;"><body><pre style="font-family:sans-serif;">';
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $url);
|
||||||
|
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [ "Authorization: Bearer {$token}", "Content-type: application/json" ]);
|
||||||
|
$data = curl_exec($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
|
||||||
|
if (!empty($cache_location) && ($data != "{\"authentication\":\"basic\"}"))
|
||||||
|
{
|
||||||
|
if (!file_exists(dirname($cache_location)))
|
||||||
|
{
|
||||||
|
mkdir(dirname($cache_location), 0777, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
file_put_contents($cache_location, $data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($data))
|
||||||
|
{
|
||||||
|
if ($diffs_redirect || $cross_mode)
|
||||||
|
{
|
||||||
|
$json = json_decode($data, true);
|
||||||
|
if ($legacy_mode)
|
||||||
|
{
|
||||||
|
if (!empty($json[0]["beatmapset_id"]))
|
||||||
|
{
|
||||||
|
$json["beatmapset"] = array("id" => $json[0]["beatmapset_id"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!empty($json["beatmapset"]["id"]))
|
||||||
|
{
|
||||||
|
$beatmapset = $json["beatmapset"]["id"];
|
||||||
|
if ($cross_mode)
|
||||||
|
{
|
||||||
|
echo $beatmapset;
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
else if ($diffs_redirect)
|
||||||
|
{
|
||||||
|
header("Location: " . "../f/" . strval($beatmapset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
header("Content-type: application/json");
|
||||||
|
if ($filter_diffs)
|
||||||
|
{
|
||||||
|
$output = array(
|
||||||
|
"id" => $beatmapset,
|
||||||
|
"artist" => "",
|
||||||
|
"title" => "",
|
||||||
|
"creator" => "",
|
||||||
|
"beatmaps" => [],
|
||||||
|
);
|
||||||
|
|
||||||
|
$modes = array(
|
||||||
|
"0" => "osu",
|
||||||
|
"1" => "taiko",
|
||||||
|
"2" => "fruits",
|
||||||
|
"3" => "mania",
|
||||||
|
);
|
||||||
|
|
||||||
|
$temp_beatmaps = array();
|
||||||
|
$json = json_decode($data, true);
|
||||||
|
foreach ($json as $map)
|
||||||
|
{
|
||||||
|
if (!empty($map["beatmap_id"]) &&
|
||||||
|
!empty($map["approved"]) &&
|
||||||
|
!empty($map["difficultyrating"]) &&
|
||||||
|
!empty($map["artist"]) &&
|
||||||
|
!empty($map["title"]) &&
|
||||||
|
!empty($map["version"]) &&
|
||||||
|
!empty($map["max_combo"]))
|
||||||
|
{
|
||||||
|
$output["artist"] = $map["artist"];
|
||||||
|
$output["title"] = $map["title"];
|
||||||
|
$output["creator"] = $map["creator"];
|
||||||
|
|
||||||
|
$map_output = array(
|
||||||
|
"id" => intval($map["beatmap_id"]),
|
||||||
|
"ranked" => intval($map["approved"]),
|
||||||
|
"difficulty_rating" => floatval($map["difficultyrating"]),
|
||||||
|
"version" => $map["version"],
|
||||||
|
"artist" => $map["artist"],
|
||||||
|
"title" => $map["title"],
|
||||||
|
"creator" => $map["creator"],
|
||||||
|
"max_combo" => $map["max_combo"],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (in_array($map["mode"], array_keys($modes))) // v2 compliance
|
||||||
|
{
|
||||||
|
$map_output["mode"] = $modes[$map["mode"]];
|
||||||
|
}
|
||||||
|
|
||||||
|
$temp_beatmaps[] = $map_output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usort($temp_beatmaps, function($a, $b) {
|
||||||
|
return $a["difficulty_rating"] > $b["difficulty_rating"] ? 1 : ($a["difficulty_rating"] < $b["difficulty_rating"] ? -1 : 0);
|
||||||
|
});
|
||||||
|
$output["beatmaps"] = $temp_beatmaps;
|
||||||
|
|
||||||
|
echo json_encode($output);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
echo $data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
echo json_encode([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
echo "No authentication method was defined.";
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
// http://zovguran.net/Unalike/OAuth/
|
||||||
|
|
||||||
|
if (!empty($_GET["error"]) && $_GET["error"] == "access_denied")
|
||||||
|
{
|
||||||
|
$_SESSION["unalike-osu-username"] = "Guest";
|
||||||
|
$_SESSION["unalike-osu-id"] = -404;
|
||||||
|
$_SESSION["unalike-granted"] = false;
|
||||||
|
header("Location: ../");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
else if (empty($_GET["code"]))
|
||||||
|
{
|
||||||
|
header("Location: ../login/");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
$code = $_GET["code"];
|
||||||
|
include "../api_key.php";
|
||||||
|
$final_uri = "http://zovguran.net/Unalike/";
|
||||||
|
|
||||||
|
$postdata = array(
|
||||||
|
"client_id" => $client_id,
|
||||||
|
"client_secret" => $client_secret,
|
||||||
|
"code" => $code,
|
||||||
|
"grant_type" => "authorization_code",
|
||||||
|
"redirect_uri" => $callback_uri,
|
||||||
|
);
|
||||||
|
|
||||||
|
$poststrings = array();
|
||||||
|
foreach ($postdata as $key => $value) $poststrings[] = "{$key}={$value}";
|
||||||
|
$poststring = implode("&", $poststrings);
|
||||||
|
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, "https://osu.ppy.sh/oauth/token");
|
||||||
|
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POST, true);
|
||||||
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $poststring);
|
||||||
|
$auth_data = curl_exec($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
$auth_json = json_decode($auth_data, true);
|
||||||
|
|
||||||
|
if (!empty($auth_data) && !empty($auth_json))
|
||||||
|
{
|
||||||
|
$now = time();
|
||||||
|
$expiry_date = $now + intval($auth_json["expires_in"]);
|
||||||
|
$auth_json["expires_at"] = $expiry_date;
|
||||||
|
$token = $auth_json["access_token"];
|
||||||
|
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, "https://osu.ppy.sh/api/v2/me/osu");
|
||||||
|
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [ "Authorization: Bearer {$token}", "Content-type: application/json" ]);
|
||||||
|
$profile_data = curl_exec($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
$profile_json = json_decode($profile_data, true);
|
||||||
|
|
||||||
|
if (!empty($profile_data) && !empty($profile_json))
|
||||||
|
{
|
||||||
|
$id = $profile_json["id"];
|
||||||
|
file_put_contents("../users/{$id}.json", $profile_data);
|
||||||
|
file_put_contents("../tokens/{$id}.json", json_encode($auth_json));
|
||||||
|
|
||||||
|
|
||||||
|
$_SESSION["unalike-osu-username"] = $profile_json["username"];
|
||||||
|
$_SESSION["unalike-osu-id"] = $profile_json["id"];
|
||||||
|
$_SESSION["unalike-granted"] = true;
|
||||||
|
|
||||||
|
$db = [];
|
||||||
|
foreach (glob("../users/*.json") as $file)
|
||||||
|
{
|
||||||
|
unset($temp);
|
||||||
|
$temp = json_decode(file_get_contents($file), true);
|
||||||
|
$db[strtolower($temp["username"])] = $temp["id"];
|
||||||
|
$db[strtolower(str_replace(" ", "_", $temp["username"]))] = $temp["id"];
|
||||||
|
}
|
||||||
|
|
||||||
|
$db["~Unalike"] = "~Unalike";
|
||||||
|
|
||||||
|
file_put_contents("../users.json", json_encode($db));
|
||||||
|
|
||||||
|
header("Location: ../");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
echo "Authorization code accepted but user could not be identified.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
echo "Invalid authorization code.";
|
||||||
|
}
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
// http://zovguran.net/Unalike/action/?(a|b|c)
|
||||||
|
|
||||||
|
// header("Content-Type: application/json");
|
||||||
|
// echo json_encode($_GET);
|
||||||
|
|
||||||
|
if (!empty($_SESSION["unalike-osu-id"]) && !empty($_SESSION["unalike-osu-username"]) && !empty($_SESSION["unalike-granted"]) && $_SESSION["unalike-granted"] === true)
|
||||||
|
{
|
||||||
|
$username = $_SESSION["unalike-osu-username"];
|
||||||
|
$username_irc = str_replace(" ", "_", $_SESSION["unalike-osu-username"]);
|
||||||
|
$id = $_SESSION["unalike-osu-id"];
|
||||||
|
|
||||||
|
if (isset($_GET["close"]))
|
||||||
|
{
|
||||||
|
if (!empty($_GET["target"]))
|
||||||
|
{
|
||||||
|
$target = $_GET["target"];
|
||||||
|
$type = "close";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isset($_GET["ping"]))
|
||||||
|
{
|
||||||
|
if (!empty($_GET["target"]))
|
||||||
|
{
|
||||||
|
$target = $_GET["target"];
|
||||||
|
$type = "ping";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isset($_GET["overtake"]))
|
||||||
|
{
|
||||||
|
if (!empty($_GET["target"]))
|
||||||
|
{
|
||||||
|
$target = $_GET["target"];
|
||||||
|
$type = "register";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
echo '<html><body><form action="./">';
|
||||||
|
echo '
|
||||||
|
<input type="hidden" name="overtake" value="form" />
|
||||||
|
<input type="text" name="target" value="" placeholder="#mp_xxxxxxxx" />
|
||||||
|
<input type="submit" value="Manage" /><br>
|
||||||
|
<p>Make sure Unalike\'s user is a referee in the room.</p>
|
||||||
|
<p><a href="../async/lobby/?">Lobby history</a> might be useful for regaining lost access.</p>
|
||||||
|
';
|
||||||
|
echo '</form><form action="../"><input type="submit" value="Back" /></form></body></html>';
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isset($_GET["delay"]))
|
||||||
|
{
|
||||||
|
if (!empty($_GET["target"]) && $_GET["target"] >= 1 && $_GET["target"] <= 7)
|
||||||
|
{
|
||||||
|
$target = floatval($_GET["target"]);
|
||||||
|
$type = "set_delay";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isset($_GET["invite"]))
|
||||||
|
{
|
||||||
|
if (!empty($_GET["target"])) // TARGET IS THE FILTER HERE!
|
||||||
|
{
|
||||||
|
$filter = $_GET["target"];
|
||||||
|
}
|
||||||
|
$target = $username_irc;
|
||||||
|
$type = "invite";
|
||||||
|
}
|
||||||
|
else if (isset($_GET["new"]))
|
||||||
|
{
|
||||||
|
$type = "new_lobby";
|
||||||
|
}
|
||||||
|
else if (isset($_GET["sync"]))
|
||||||
|
{
|
||||||
|
$type = "sync_all";
|
||||||
|
}
|
||||||
|
else if (isset($_GET["shutdown"]))
|
||||||
|
{
|
||||||
|
$type = "shutdown";
|
||||||
|
}
|
||||||
|
else if (isset($_GET["start"]))
|
||||||
|
{
|
||||||
|
$type = "start";
|
||||||
|
}
|
||||||
|
|
||||||
|
$action = $_GET;
|
||||||
|
|
||||||
|
if (!empty($type))
|
||||||
|
{
|
||||||
|
|
||||||
|
$action = array(
|
||||||
|
"type" => $type,
|
||||||
|
"issuer" => [
|
||||||
|
"username" => $username,
|
||||||
|
"username_irc" => $username_irc,
|
||||||
|
"id" => $id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!empty($target))
|
||||||
|
{
|
||||||
|
$action["target"] = $target;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($filter))
|
||||||
|
{
|
||||||
|
$action["filter"] = $filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
$json = json_decode(file_get_contents("../requests.json"), true);
|
||||||
|
if (empty($json))
|
||||||
|
{
|
||||||
|
$json = array($action);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$json[] = $action;
|
||||||
|
}
|
||||||
|
file_put_contents("../requests.json", json_encode($json));
|
||||||
|
|
||||||
|
header("Location: ../");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
echo "Unknown action.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
echo "Authentication error.";
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
// http://zovguran.net/Unalike/async/
|
||||||
|
|
||||||
|
$unalike = json_decode(file_get_contents("../unalike.json"), true);
|
||||||
|
// if (!empty($unalike))
|
||||||
|
// {
|
||||||
|
// $requests = json_decode(file_get_contents("../requests.json"), true);
|
||||||
|
// if (!empty($requests))
|
||||||
|
// {
|
||||||
|
// $unalike["busy"] = true;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// $unalike["busy"] = false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
header("Content-Type: application/json");
|
||||||
|
echo json_encode($unalike);
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<div class="background-color card-osu card-osu-topless">
|
||||||
|
<div class="card-title">
|
||||||
|
<h3 class="cover-image song-info" style="padding:30px 50px;background: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.6)), url('[[ COVER_IMAGE ]]');background-size:cover;">
|
||||||
|
[[ SONG_INFO ]]
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div style="margin-top:25px;">
|
||||||
|
<div style="display:flex;flex-flow: row wrap;justify-content:flex-end;">
|
||||||
|
<p style="flex: 1 0 auto;min-width:200px;">[[ STATE ]]</p>
|
||||||
|
<button onclick="hiddenFunctionClick(this, 'action/?invite&target=[[ CHANNEL ]]', 1)" class="button-osu button-osu-management button-positive" style="margin:0 10px 0 0;flex:0 0 0;min-width:140px;" putDisabledHere>
|
||||||
|
<div class="button-symbol">📤</div>
|
||||||
|
<div class="button-label">Invite</div>
|
||||||
|
</button>
|
||||||
|
<button onclick="hiddenFunctionClick(this, 'action/?close&target=[[ CHANNEL ]]', 3)" class="button-osu button-osu-round button-negative" style="flex: 0 0 0;" putDisabledHere>❌</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>[[ PLAYERS ]]</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
// http://zovguran.net/Unalike/async/
|
||||||
|
|
||||||
|
$relative_prefix = "../../lobbies/";
|
||||||
|
$original_suffix = ".json";
|
||||||
|
$users_suffix = $original_suffix;
|
||||||
|
|
||||||
|
$absolute_prefix = "/Unalike/lobbies/";
|
||||||
|
|
||||||
|
$call_prefix = "";
|
||||||
|
$call_suffix = "";
|
||||||
|
|
||||||
|
$recent_count = 6;
|
||||||
|
|
||||||
|
$selected_match = false;
|
||||||
|
|
||||||
|
$output = array();
|
||||||
|
|
||||||
|
|
||||||
|
$all_lobbies = glob($relative_prefix . "*" . $original_suffix);
|
||||||
|
natsort($all_lobbies);
|
||||||
|
$all_lobbies = array_reverse($all_lobbies);
|
||||||
|
$recent_lobbies = array_slice($all_lobbies, 0, $recent_count);
|
||||||
|
|
||||||
|
|
||||||
|
foreach ($recent_lobbies as $relative_file)
|
||||||
|
{
|
||||||
|
$json = json_decode(file_get_contents($relative_file), true);
|
||||||
|
if (!empty($json))
|
||||||
|
{
|
||||||
|
$output[] = $json;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
header("Content-Type: application/json");
|
||||||
|
echo json_encode($output);
|
||||||
@@ -0,0 +1,283 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
// http://zovguran.net/Unalike/async/
|
||||||
|
|
||||||
|
$api_url = "http://localhost:80/Unalike/API";
|
||||||
|
|
||||||
|
$users_prefix = "../../users/";
|
||||||
|
|
||||||
|
$relative_prefix = "../../matches/";
|
||||||
|
$original_suffix = ".json";
|
||||||
|
$users_suffix = $original_suffix;
|
||||||
|
|
||||||
|
$absolute_prefix = "/Unalike/matches/";
|
||||||
|
|
||||||
|
$call_prefix = "";
|
||||||
|
$call_suffix = "";
|
||||||
|
|
||||||
|
$recent_count = 6;
|
||||||
|
|
||||||
|
$selected_match = false;
|
||||||
|
|
||||||
|
$output = array();
|
||||||
|
|
||||||
|
if (!empty($_GET["select"]) && file_exists($relative_prefix . $_GET["select"] . $original_suffix))
|
||||||
|
{
|
||||||
|
$selected_match = $relative_prefix . $_GET["select"] . $original_suffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($selected_match))
|
||||||
|
{
|
||||||
|
if (file_exists($selected_match))
|
||||||
|
{
|
||||||
|
$output = json_decode(file_get_contents($selected_match), true);
|
||||||
|
if (!empty($output) && !empty($output["games"]) && !empty($output["games"][0]["scores"]))
|
||||||
|
{
|
||||||
|
foreach ($output["games"][0]["scores"] as $key => $score)
|
||||||
|
{
|
||||||
|
if (!empty($score["user_id"]))
|
||||||
|
{
|
||||||
|
$username = "Guest";
|
||||||
|
if (file_exists($users_prefix . $score["user_id"] . $users_suffix))
|
||||||
|
{
|
||||||
|
$user = json_decode(file_get_contents($users_prefix . $score["user_id"] . $users_suffix), true);
|
||||||
|
if (!empty($user) && !empty($user["username"]))
|
||||||
|
{
|
||||||
|
$username = $user["username"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!empty($_SESSION["unalike-osu-id"]) && !empty($_SESSION["unalike-osu-username"]) && !empty($_SESSION["unalike-granted"]) && $_SESSION["unalike-granted"] === true)
|
||||||
|
{
|
||||||
|
$caller = str_replace(" ", "_", $_SESSION["unalike-osu-username"]);
|
||||||
|
$url = $api_url . "/" . $caller . "/u/" . $score["user_id"];
|
||||||
|
$raw = file_get_contents($url);
|
||||||
|
$user = json_decode($raw, true);
|
||||||
|
if (!empty($user) && !empty($user["username"]))
|
||||||
|
{
|
||||||
|
$username = $user["username"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$output["games"][0]["scores"][$key]["username"] = $username;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$all_matches = glob($relative_prefix . "*" . $original_suffix);
|
||||||
|
natsort($all_matches);
|
||||||
|
$all_matches = array_reverse($all_matches);
|
||||||
|
$recent_matches = array_slice($all_matches, 0, $recent_count);
|
||||||
|
|
||||||
|
$link_to_file = false;
|
||||||
|
|
||||||
|
foreach ($recent_matches as $relative_file)
|
||||||
|
{
|
||||||
|
if ($link_to_file)
|
||||||
|
{
|
||||||
|
$output[] = str_replace($relative_prefix, $absolute_prefix, $relative_file);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$output[] = str_replace($original_suffix, $call_suffix, str_replace($relative_prefix, $call_prefix, $relative_file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_GET["render"]))
|
||||||
|
{
|
||||||
|
$needed_beatmaps = array();
|
||||||
|
foreach ($output["games"][0]["scores"] as $score)
|
||||||
|
{
|
||||||
|
$needed_beatmaps[] = $score["beatmap_id"];
|
||||||
|
}
|
||||||
|
|
||||||
|
$needed_beatmaps = array_unique($needed_beatmaps);
|
||||||
|
|
||||||
|
$userid = 0;
|
||||||
|
$beatmaps = array();
|
||||||
|
if (!empty($_SESSION["unalike-osu-id"]) && !empty($_SESSION["unalike-osu-username"]) && !empty($_SESSION["unalike-granted"]) && $_SESSION["unalike-granted"] === true)
|
||||||
|
{
|
||||||
|
$caller = str_replace(" ", "_", $_SESSION["unalike-osu-username"]);
|
||||||
|
$userid = $_SESSION["unalike-osu-id"];
|
||||||
|
|
||||||
|
foreach ($needed_beatmaps as $beatmap_id)
|
||||||
|
{
|
||||||
|
$url = $api_url . "/" . $caller . "/b/" . $beatmap_id;
|
||||||
|
$raw = file_get_contents($url);
|
||||||
|
$beatmaps[$beatmap_id] = json_decode($raw, true);
|
||||||
|
$beatmaps[$beatmap_id] = json_decode($raw, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach ($needed_beatmaps as $beatmap_id)
|
||||||
|
{
|
||||||
|
$beatmaps[$beatmap_id] = array( // dummy
|
||||||
|
"id" => $beatmap_id,
|
||||||
|
"url" => "login/",
|
||||||
|
"beatmapset" => [
|
||||||
|
"title" => "Results",
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$sample_beatmap = array_key_first($beatmaps);
|
||||||
|
|
||||||
|
$match_template = file_get_contents("match_template.html");
|
||||||
|
$score_template = file_get_contents("score_template.html");
|
||||||
|
|
||||||
|
$scores = "";
|
||||||
|
|
||||||
|
foreach ($output["games"][0]["scores"] as $score)
|
||||||
|
{
|
||||||
|
$name = $score["username"];
|
||||||
|
if ($userid == $score["user_id"])
|
||||||
|
{
|
||||||
|
$name = '<span class="positive-color">' . $name . '</span>';
|
||||||
|
}
|
||||||
|
$beatmap_id = $score["beatmap_id"];
|
||||||
|
|
||||||
|
$all_objects = 0;
|
||||||
|
if (!empty($beatmaps[$beatmap_id]["count_circles"])) $all_objects += $beatmaps[$beatmap_id]["count_circles"];
|
||||||
|
if (!empty($beatmaps[$beatmap_id]["count_sliders"]) && $score["game"]["mode"] != "taiko") $all_objects += $beatmaps[$beatmap_id]["count_sliders"];
|
||||||
|
if (!empty($beatmaps[$beatmap_id]["count_spinners"]) && $score["game"]["mode"] != "taiko") $all_objects += $beatmaps[$beatmap_id]["count_spinners"];
|
||||||
|
|
||||||
|
$maxcombo = $score["maxcombo"];
|
||||||
|
if (!empty($beatmaps[$beatmap_id]["max_combo"]))
|
||||||
|
{
|
||||||
|
if (isset($beatmaps[$beatmap_id]["convert"]) && $beatmaps[$beatmap_id]["convert"] != true)
|
||||||
|
{
|
||||||
|
$maxcombo .= "/" . $beatmaps[$beatmap_id]["max_combo"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$stars = 0;
|
||||||
|
if (!empty($beatmaps[$beatmap_id]["difficulty_rating"]))
|
||||||
|
{
|
||||||
|
$stars = number_format($beatmaps[$beatmap_id]["difficulty_rating"], 2, '.', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
$version = "";
|
||||||
|
if (!empty($beatmaps[$beatmap_id]["version"]))
|
||||||
|
{
|
||||||
|
$version = $beatmaps[$beatmap_id]["version"];
|
||||||
|
}
|
||||||
|
|
||||||
|
$accuracy = number_format($score["accuracy"], 2, '.', '');
|
||||||
|
$status = '';
|
||||||
|
if ($all_objects > $score["all_notes"])
|
||||||
|
{
|
||||||
|
$status = '<span class="negative-color">QUIT</span>';
|
||||||
|
}
|
||||||
|
else if ($score["pass"] != 1)
|
||||||
|
{
|
||||||
|
$status = '<span class="negative-color">FAILED</span>';
|
||||||
|
}
|
||||||
|
else if (!empty($beatmaps[$beatmap_id]["max_combo"]) && $score["maxcombo"] >= $beatmaps[$beatmap_id]["max_combo"])
|
||||||
|
{
|
||||||
|
$status = '<span class="positive-color">FC</span>';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// $status = '<span class="positive-color">PASS</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$mode_text = "?";
|
||||||
|
if ($score["game"]["mode"] == "osu")
|
||||||
|
{
|
||||||
|
// $mode_text = "standard";
|
||||||
|
$mode_text = "osu";
|
||||||
|
}
|
||||||
|
else if ($score["game"]["mode"] == "taiko")
|
||||||
|
{
|
||||||
|
$mode_text = "taiko";
|
||||||
|
}
|
||||||
|
else if ($score["game"]["mode"] == "mania")
|
||||||
|
{
|
||||||
|
$mode_text = "mania";
|
||||||
|
}
|
||||||
|
else if ($score["game"]["mode"] == "fruits")
|
||||||
|
{
|
||||||
|
$mode_text = "catch";
|
||||||
|
}
|
||||||
|
// $mode_text = "osu!" . $mode_text;
|
||||||
|
|
||||||
|
$score_replaced = str_replace(
|
||||||
|
[
|
||||||
|
"[[ PLACE ]]",
|
||||||
|
"[[ NAME ]]",
|
||||||
|
"[[ STATUS ]]",
|
||||||
|
"[[ ACCURACY ]]",
|
||||||
|
"[[ MODE ]]",
|
||||||
|
"[[ MAXCOMBO ]]",
|
||||||
|
"[[ STARS ]]",
|
||||||
|
"[[ VERSION ]]",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
$score["place"],
|
||||||
|
$name,
|
||||||
|
$status,
|
||||||
|
$accuracy,
|
||||||
|
$mode_text,
|
||||||
|
$maxcombo,
|
||||||
|
$stars,
|
||||||
|
$version,
|
||||||
|
],
|
||||||
|
$score_template);
|
||||||
|
|
||||||
|
$scores .= $score_replaced;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cover = "/Unalike/img/covers/c4.jpg";
|
||||||
|
if (!empty($beatmaps[$sample_beatmap]["beatmapset"]["covers"]["cover@2x"]))
|
||||||
|
{
|
||||||
|
$cover = $beatmaps[$sample_beatmap]["beatmapset"]["covers"]["cover@2x"];
|
||||||
|
}
|
||||||
|
else if (!empty($beatmaps[$sample_beatmap]["beatmapset"]["covers"]["cover"]))
|
||||||
|
{
|
||||||
|
$cover = $beatmaps[$sample_beatmap]["beatmapset"]["covers"]["cover"];
|
||||||
|
}
|
||||||
|
|
||||||
|
$artist_components = array();
|
||||||
|
if (!empty($beatmaps[$sample_beatmap]["beatmapset"]["artist"]))
|
||||||
|
{
|
||||||
|
$artist_components[] = $beatmaps[$sample_beatmap]["beatmapset"]["artist"];
|
||||||
|
}
|
||||||
|
if (!empty($beatmaps[$sample_beatmap]["beatmapset"]["creator"]))
|
||||||
|
{
|
||||||
|
$artist_components[] = $beatmaps[$sample_beatmap]["beatmapset"]["creator"];
|
||||||
|
}
|
||||||
|
|
||||||
|
$artist = "";
|
||||||
|
if (!empty($artist_components))
|
||||||
|
{
|
||||||
|
$artist = implode(" // ", $artist_components);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = str_replace(
|
||||||
|
[
|
||||||
|
"[[ LINK ]]",
|
||||||
|
"[[ TITLE ]]",
|
||||||
|
"[[ ARTIST ]]",
|
||||||
|
"[[ COVER_IMAGE ]]",
|
||||||
|
"[[ SCORES ]]",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
$beatmaps[$sample_beatmap]["url"],
|
||||||
|
$beatmaps[$sample_beatmap]["beatmapset"]["title"],
|
||||||
|
$artist,
|
||||||
|
$cover,
|
||||||
|
$scores,
|
||||||
|
],
|
||||||
|
$match_template);
|
||||||
|
|
||||||
|
echo $response;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
header("Content-Type: application/json");
|
||||||
|
echo json_encode($output);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<div class="card-title">
|
||||||
|
<h3 class="cover-image song-info" style="padding:30px 50px;background: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.6)), url('[[ COVER_IMAGE ]]');background-size:cover;">
|
||||||
|
<a href="[[ LINK ]]" class="link-osu" style="text-decoration:inherit;color:inherit;">
|
||||||
|
<div>
|
||||||
|
<span class="song-title">[[ TITLE ]]</span><br>
|
||||||
|
<span class="song-artist">[[ ARTIST ]]</span>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div style="margin-top:25px;"><table class="scores">[[ SCORES ]]</table></div>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<tr>
|
||||||
|
<td class="rowspan score-place" rowspan="2">#[[ PLACE ]]</td>
|
||||||
|
<td class="rowspan score-name" rowspan="2">[[ NAME ]]</td>
|
||||||
|
<td class="rowspan score-accuracy" rowspan="2">
|
||||||
|
<span class="score-status">[[ STATUS ]]</span>
|
||||||
|
<span>[[ ACCURACY ]]%</span>
|
||||||
|
</td>
|
||||||
|
<td class="row-upper">[[ MODE ]] [[ MAXCOMBO ]]x</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td class="row-lower">[[ STARS ]]★ [[ VERSION ]]</td>
|
||||||
|
</tr>
|
||||||
@@ -0,0 +1,270 @@
|
|||||||
|
<?php
|
||||||
|
include "../api_key.php";
|
||||||
|
include "../local_secret.php";
|
||||||
|
|
||||||
|
$trusted = false;
|
||||||
|
|
||||||
|
if (!empty($_GET["secret"]) && $_GET["secret"] == $local_secret)
|
||||||
|
{
|
||||||
|
$trusted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($trusted)
|
||||||
|
{
|
||||||
|
$url_base = "http://localhost:80/Unalike/API/~Unalike/m/";
|
||||||
|
|
||||||
|
$source = array();
|
||||||
|
if (!empty($_GET["source"]))
|
||||||
|
{
|
||||||
|
foreach (explode(";", $_GET["source"]) as $list)
|
||||||
|
{
|
||||||
|
$entry = explode(",", $list);
|
||||||
|
$lobby = array();
|
||||||
|
|
||||||
|
if (isset($entry[0]) && isset($entry[1]))
|
||||||
|
{
|
||||||
|
$lobby["match"] = $entry[0];
|
||||||
|
$lobby["round"] = $entry[1];
|
||||||
|
$source[] = $lobby;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$beatmapset = -4;
|
||||||
|
if (isset($_GET["beatmapset"]))
|
||||||
|
{
|
||||||
|
$beatmapset = $_GET["beatmapset"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($source) && isset($beatmapset))
|
||||||
|
{
|
||||||
|
$beatmap_url_v1 = "https://osu.ppy.sh/api/get_beatmaps?k={$api_key}&";
|
||||||
|
|
||||||
|
$match_id = "ual" . strval(floor(time()));
|
||||||
|
$merged = array(
|
||||||
|
"match" => array(
|
||||||
|
"match_id" => $match_id,
|
||||||
|
),
|
||||||
|
"games" => array(),
|
||||||
|
);
|
||||||
|
|
||||||
|
$merged_game = array(
|
||||||
|
"game_id" => $match_id,
|
||||||
|
"beatmapset_id" => $beatmapset,
|
||||||
|
// "beatmapset" => [ "id" => $beatmapset ],
|
||||||
|
);
|
||||||
|
|
||||||
|
$modes = array(
|
||||||
|
"0" => "osu",
|
||||||
|
"1" => "taiko",
|
||||||
|
"2" => "fruits",
|
||||||
|
"3" => "mania",
|
||||||
|
);
|
||||||
|
|
||||||
|
$scores = array();
|
||||||
|
foreach ($source as $lobby)
|
||||||
|
{
|
||||||
|
$url = $url_base . $lobby["match"];
|
||||||
|
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $url);
|
||||||
|
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
$data = curl_exec($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
$json = json_decode($data, true);
|
||||||
|
|
||||||
|
if (!empty($json) &&
|
||||||
|
!empty($json["match"]) &&
|
||||||
|
isset($json["match"]["name"]) &&
|
||||||
|
!empty($json["games"]))
|
||||||
|
{
|
||||||
|
$real_round = array_key_first($json["games"]);
|
||||||
|
$lobby["round"] = intval($lobby["round"]);
|
||||||
|
if ($lobby["round"] > 0)
|
||||||
|
{
|
||||||
|
$real_round = intval($lobby["round"]) - 1;
|
||||||
|
}
|
||||||
|
else if ($lobby["round"] == -1)
|
||||||
|
{
|
||||||
|
$real_round = array_key_last($json["games"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!empty($json["games"][$real_round]) &&
|
||||||
|
isset($json["games"][$real_round]["scores"]) )
|
||||||
|
{
|
||||||
|
$lobby_name = $json["match"]["name"];
|
||||||
|
|
||||||
|
$bancho_game = $json["games"][$real_round];
|
||||||
|
|
||||||
|
$lobby_beatmap = $bancho_game["beatmap_id"];
|
||||||
|
|
||||||
|
$api_url = $beatmap_url_v1 . "b=" . $lobby_beatmap;
|
||||||
|
|
||||||
|
|
||||||
|
$ch = curl_init();
|
||||||
|
curl_setopt($ch, CURLOPT_URL, $api_url);
|
||||||
|
curl_setopt($ch, CURLOPT_HEADER, false);
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
$api_response = curl_exec($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
$api_json = json_decode($api_response, true);
|
||||||
|
|
||||||
|
$mode = "osu";
|
||||||
|
if (!empty($api_response) && !empty($api_json) && isset($api_json[0]["mode"]))
|
||||||
|
{
|
||||||
|
$mode = "osu";
|
||||||
|
if ($api_json[0]["mode"] != "0")
|
||||||
|
{
|
||||||
|
$mode = $modes[$api_json[0]["mode"]];
|
||||||
|
}
|
||||||
|
else if (isset($bancho_game["play_mode"]) && $bancho_game["play_mode"] != "0")
|
||||||
|
{
|
||||||
|
$mode = $modes[$bancho_game["play_mode"]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach ($bancho_game["scores"] as $souce_score)
|
||||||
|
{
|
||||||
|
$score = array(
|
||||||
|
"user_id" => $souce_score["user_id"],
|
||||||
|
"place" => 0,
|
||||||
|
"accuracy" => 0,
|
||||||
|
"maxcombo" => 0,
|
||||||
|
"beatmap_id" => "0",
|
||||||
|
"score" => 0,
|
||||||
|
"game" => [],
|
||||||
|
);
|
||||||
|
|
||||||
|
// $score["source"] = $souce_score;
|
||||||
|
$score["source_id"] = $lobby["match"];
|
||||||
|
$score["source_round"] = $real_round + 1;
|
||||||
|
$score["lobby_name"] = $lobby_name;
|
||||||
|
|
||||||
|
$score["beatmap_id"] = $lobby_beatmap;
|
||||||
|
// $score["beatmap"] = array("id" => $lobby_beatmap);
|
||||||
|
|
||||||
|
$score["game"]["play_mode"] = $bancho_game["play_mode"];
|
||||||
|
$score["game"]["mode"] = $mode;
|
||||||
|
$score["game"]["match_type"] = $bancho_game["match_type"];
|
||||||
|
$score["game"]["scoring_type"] = $bancho_game["scoring_type"];
|
||||||
|
$score["game"]["team_type"] = $bancho_game["team_type"];
|
||||||
|
$score["game"]["mods"] = $bancho_game["mods"];
|
||||||
|
|
||||||
|
$hit0 = intval($souce_score["countmiss"]);
|
||||||
|
$hit50 = intval($souce_score["count50"]);
|
||||||
|
$hit100 = intval($souce_score["count100"]);
|
||||||
|
$hit300 = intval($souce_score["count300"]);
|
||||||
|
$hitGeki = intval($souce_score["countgeki"]);
|
||||||
|
$hitKatsu = intval($souce_score["countkatu"]);
|
||||||
|
|
||||||
|
$score["countmiss"] = $hit0;
|
||||||
|
$score["count50"] = $hit50;
|
||||||
|
$score["count100"] = $hit100;
|
||||||
|
$score["count300"] = $hit300;
|
||||||
|
$score["countgeki"] = $hitGeki;
|
||||||
|
$score["countkatu"] = $hitKatsu;
|
||||||
|
|
||||||
|
if ($mode == "mania")
|
||||||
|
{
|
||||||
|
$all_notes = $hit0 + $hit50 + $hit100 + $hitKatsu + $hit300 + $hitGeki;
|
||||||
|
$flat_score = ($hit50 * 50) + ($hit100 * 100) + ($hitKatsu * 200) + (($hit300 + $hitGeki) * 300);
|
||||||
|
$max_score = $all_notes * 300;
|
||||||
|
}
|
||||||
|
else if ($mode == "fruits")
|
||||||
|
{
|
||||||
|
$all_notes = $hit0 + $hitKatsu + $hit50 + $hit100 + $hit300;
|
||||||
|
$flat_score = $hit50 + $hit100 + $hit300;
|
||||||
|
$max_score = $all_notes;
|
||||||
|
}
|
||||||
|
else if ($mode == "taiko")
|
||||||
|
{
|
||||||
|
$all_notes = $hit0 + $hit100 + $hit300;
|
||||||
|
$flat_score = $hit100 + ($hit300 * 2);
|
||||||
|
$max_score = $all_notes * 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$all_notes = $hit0 + $hit50 + $hit100 + $hit300;
|
||||||
|
$flat_score = ($hit50 * 50) + ($hit100 * 100) + ($hit300 * 300);
|
||||||
|
$max_score = $all_notes * 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
$accuracy = round(($flat_score * 100) / $max_score, 2);
|
||||||
|
|
||||||
|
$score["all_notes"] = $all_notes;
|
||||||
|
$score["accuracy"] = $accuracy;
|
||||||
|
$score["maxcombo"] = intval($souce_score["maxcombo"]);
|
||||||
|
$score["score"] = intval($souce_score["score"]);
|
||||||
|
$score["pass"] = intval($souce_score["pass"]);
|
||||||
|
|
||||||
|
$scores[] = $score;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usort($scores, function($a, $b) {
|
||||||
|
if ($a["pass"] == $b["pass"])
|
||||||
|
{
|
||||||
|
if ($a["accuracy"] == $b["accuracy"])
|
||||||
|
{
|
||||||
|
if ($a["maxcombo"] == $b["maxcombo"])
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if ($a["maxcombo"] < $b["maxcombo"])
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ($a["accuracy"] < $b["accuracy"])
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ($a["pass"] < $b["pass"])
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$counter = 1;
|
||||||
|
foreach ($scores as $key => $score)
|
||||||
|
{
|
||||||
|
$scores[$key]["place"] = $counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
$merged_game["scores"] = $scores;
|
||||||
|
|
||||||
|
$merged["games"][] = $merged_game;
|
||||||
|
|
||||||
|
file_put_contents("../matches/{$match_id}.json", json_encode($merged));
|
||||||
|
|
||||||
|
header("Content-Type: application/json");
|
||||||
|
echo json_encode(["status" => "success"]);
|
||||||
|
// echo json_encode($merged);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
echo json_encode(["status" => "error", "error" => "missing_argument"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
echo json_encode(["status" => "error", "error" => "unauthenticated"]);
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 311 KiB |
|
After Width: | Height: | Size: 282 KiB |
|
After Width: | Height: | Size: 115 KiB |
|
After Width: | Height: | Size: 149 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 931 B |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
// http://zovguran.net/Unalike/login/
|
||||||
|
include "../api_key.php";
|
||||||
|
$scope = implode("+", [ "identify", "public" ]);
|
||||||
|
|
||||||
|
$params = array(
|
||||||
|
"client_id={$client_id}",
|
||||||
|
"redirect_uri={$callback_uri}",
|
||||||
|
"response_type=code",
|
||||||
|
"scope={$scope}",
|
||||||
|
);
|
||||||
|
|
||||||
|
$url = "https://osu.ppy.sh/oauth/authorize?" . implode("&", $params);
|
||||||
|
header("Location: {$url}");
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
// http://zovguran.net/Unalike/logout
|
||||||
|
unset($_SESSION["unalike-osu-id"]);
|
||||||
|
unset($_SESSION["unalike-osu-username"]);
|
||||||
|
unset($_SESSION["unalike-granted"]);
|
||||||
|
header("Location: ../");
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
// Server: irc.ppy.sh
|
||||||
|
// Port: 6667
|
||||||
|
// Username: username_with_underscores_instead_of_spaces
|
||||||
|
// Server Password: xxxxxxxx
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// -------------------------------------------
|
||||||
|
// You can just copy-paste your "IRC details"
|
||||||
|
// from https://osu.ppy.sh/p/irc to this file.
|
||||||
|
//
|
||||||
|
// Make sure to keep the first line as "<?php"
|
||||||
|
// without the quotes because it "hides" your
|
||||||
|
// sensitive information without further
|
||||||
|
// configuration.
|
||||||
|
//
|
||||||
|
// You can also keep it outside of your web
|
||||||
|
// directory and save it as a plain text file
|
||||||
|
// That way you will never have to worry
|
||||||
|
// about accidentally sharing sensitive
|
||||||
|
// information.
|
||||||
|
// -------------------------------------------
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
// for api v1
|
||||||
|
$api_key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; // osu! API v1 key, get one at https://osu.ppy.sh/p/api
|
||||||
|
|
||||||
|
// for api v2
|
||||||
|
$client_id = "1234"; // osu! API v2 client ID, register one at https://osu.ppy.sh/home/account/edit#new-oauth-application
|
||||||
|
$client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; // v2 client secret, you will get one with registering a client ID
|
||||||
|
$callback_uri = "https://example.com/path/to/Unalike/OAuth/"; // the location where users will be redirected after logging in
|
||||||
|
// note that you will have to provide the same path when registering your client on the osu website!
|
||||||
|
|
||||||
|
// the comments are not needed for your live api_key.php file. the order of the lines are not important except for the very first line
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
// Copy this file to the unalike root and change the $local_secret variable to something unique.
|
||||||
|
$local_secret = "xxxxxSomethingUniqueHerePls12345";
|
||||||
|
|
||||||
|
// It is recommended to choose a long and complicated secret (at least a 100 characters long alphanumeric string)
|
||||||
|
|
||||||
|
// Using special characters is not advised because this is sent through the HTTP(S) protocol GET method with
|
||||||
|
// god knows what encoding...
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#Requires -Version 7.0
|
||||||
|
|
||||||
|
$Host.UI.RawUI.WindowTitle = "osu! Unalike IRC worker"
|
||||||
|
$file = "requests.json"
|
||||||
|
Write-Host "[Unalike] Service loop started."
|
||||||
|
while($true)
|
||||||
|
{
|
||||||
|
$content = Get-Content $file
|
||||||
|
$decision = $content -eq "{}"
|
||||||
|
if ($decision)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Write-Host "[Unalike] Starting IRC bot..."
|
||||||
|
Set-Content -Path $file -Value "{}"
|
||||||
|
$flags = "unalike.py"
|
||||||
|
$flagArray = $flags -split " "
|
||||||
|
Start-Process -FilePath python -ArgumentList $flagArray -NoNewWindow -Wait
|
||||||
|
Set-Content -Path $file -Value "{}"
|
||||||
|
Write-Host "[Unalike] The bot is offline. Initialize it using the request file."
|
||||||
|
}
|
||||||
|
|
||||||
|
Start-Sleep -Seconds 2
|
||||||
|
}
|
||||||
@@ -0,0 +1,861 @@
|
|||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import socket
|
||||||
|
import requests
|
||||||
|
import string
|
||||||
|
import random
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
import msvcrt
|
||||||
|
import os.path
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
# CONFIGURATION
|
||||||
|
|
||||||
|
# location of the account files
|
||||||
|
account_path = "account.php" # take a look at "setup_help/account_template.php"
|
||||||
|
local_secret_path = "local_secret.php" # take a look at "setup_help/local_secret_template.php"
|
||||||
|
|
||||||
|
# how many seconds should be between commands
|
||||||
|
global_irc_send_timeout = 4 # in seconds (3 didn't work sometimes, 7 should always work)
|
||||||
|
|
||||||
|
# how many seconds should
|
||||||
|
global_composer_delay = 1 # in seconds (wait for osu API to catch up)
|
||||||
|
|
||||||
|
# reason of introduction: when two players selected a map at the same time, it created an endless loop
|
||||||
|
global_sync_init_timeout = 10 # in seconds (to prevent looping due to Bancho lag)
|
||||||
|
|
||||||
|
# how many lobbies should the script be able to manage (there is a limit by peppy!)
|
||||||
|
global_max_lobbies = 4 # this is the default for normal accounts by peppy
|
||||||
|
|
||||||
|
# when a lobby is created, how many people should be able to join
|
||||||
|
lobby_default_size = 1
|
||||||
|
|
||||||
|
# checks per second (Hz) [a range between 0.5 and 4 is recommended, can be any arbitrary number]
|
||||||
|
polling_rate = 2 # 2 = report to the web api every 0.5 seconds (also affects IRC ping)
|
||||||
|
|
||||||
|
# this will be used in chat messages (can be anything, does not have to point to your Unalike)
|
||||||
|
unalike_url = "http://zovguran.net/Unalike/"
|
||||||
|
|
||||||
|
# change it to match your location of the Unalike API (does not have to be local)
|
||||||
|
unalike_api = "http://localhost:80/Unalike/API"
|
||||||
|
|
||||||
|
# change it to match your location of the Unalike Composer (does not have to be local)
|
||||||
|
unalike_composer = "http://localhost:80/Unalike/compose/?"
|
||||||
|
|
||||||
|
# where the script will listen for requests from the web
|
||||||
|
requests_file = "requests.json"
|
||||||
|
|
||||||
|
# where the script will tell stuff to the web
|
||||||
|
report_file = "unalike.json"
|
||||||
|
|
||||||
|
# where the script will log the created lobbies
|
||||||
|
lobbies_dir = "lobbies/"
|
||||||
|
|
||||||
|
# the encoding used for IRC
|
||||||
|
encoding = "utf-8"
|
||||||
|
|
||||||
|
# the size of the socket buffer
|
||||||
|
buffer_size = 16384 # you might need to lower this. the bot should work with as low as 1024
|
||||||
|
|
||||||
|
# set to True if you want to use the console to send custom commands
|
||||||
|
console_input_allowed = False
|
||||||
|
|
||||||
|
# set to True if you want to see what the IRC bot is sending to Bancho
|
||||||
|
send_command_feedback = False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# initializing some variables
|
||||||
|
server = "irc.ppy.sh"
|
||||||
|
port = 6667
|
||||||
|
bot_name = ""
|
||||||
|
bot_pass = ""
|
||||||
|
|
||||||
|
lobby_default_pass = "unset"
|
||||||
|
local_secret = "unset"
|
||||||
|
|
||||||
|
# folder structure setup
|
||||||
|
os.makedirs(lobbies_dir, exist_ok=True)
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
with open(account_path, "r") as file:
|
||||||
|
lines = file.readlines()
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
if line.lower().find("server:") != -1:
|
||||||
|
server = line.split(":")[1].strip()
|
||||||
|
if line.lower().find("port:") != -1:
|
||||||
|
port = int(line.split(":")[1].strip())
|
||||||
|
if line.lower().find("name:") != -1:
|
||||||
|
bot_name = line.split(":")[1].strip()
|
||||||
|
if line.lower().find("password:") != -1:
|
||||||
|
bot_pass = line.split(":")[1].strip()
|
||||||
|
|
||||||
|
lines = []
|
||||||
|
with open(local_secret_path, "r") as file:
|
||||||
|
lines = file.readlines()
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
if line.lower().find("$local_secret") != -1:
|
||||||
|
local_secret = line.split("\"")[1].strip()
|
||||||
|
|
||||||
|
if bot_name == "" or bot_pass == "":
|
||||||
|
print(account_path + " does not contain login details!")
|
||||||
|
exit()
|
||||||
|
|
||||||
|
irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
irc.connect((server, port))
|
||||||
|
irc.setblocking(False)
|
||||||
|
|
||||||
|
|
||||||
|
# actually irc_queue but for compatibility...
|
||||||
|
def irc_send(command, argument1="", argument2="", argument3="", argument4="", argument5="", argument6="", custom_delay="global"):
|
||||||
|
global global_irc_send_queue, global_irc_send_timeout
|
||||||
|
|
||||||
|
line = command.upper()
|
||||||
|
|
||||||
|
if argument1 != "":
|
||||||
|
line = line + " " + argument1
|
||||||
|
if argument2 != "":
|
||||||
|
line = line + " " + argument2
|
||||||
|
if argument3 != "":
|
||||||
|
line = line + " " + argument3
|
||||||
|
if argument4 != "":
|
||||||
|
line = line + " " + argument4
|
||||||
|
if argument5 != "":
|
||||||
|
line = line + " " + argument5
|
||||||
|
if argument6 != "":
|
||||||
|
line = line + " " + argument6
|
||||||
|
|
||||||
|
line = line + "\r\n"
|
||||||
|
|
||||||
|
delay = global_irc_send_timeout
|
||||||
|
if custom_delay != "global":
|
||||||
|
delay = custom_delay
|
||||||
|
|
||||||
|
global_irc_send_queue.append({ "line": line, "delay": delay })
|
||||||
|
|
||||||
|
def irc_send_real(line, delay):
|
||||||
|
global irc, encoding, current_irc_send_timeout
|
||||||
|
|
||||||
|
irc.send(line.encode(encoding))
|
||||||
|
|
||||||
|
current_irc_send_timeout = delay
|
||||||
|
if send_command_feedback:
|
||||||
|
print("SEND: " + line)
|
||||||
|
|
||||||
|
def irc_send_pm(recipent, message):
|
||||||
|
irc_send("PRIVMSG", recipent, ":"+message)
|
||||||
|
|
||||||
|
def irc_send_links(recipient, channel_id=False):
|
||||||
|
global managed_lobbies
|
||||||
|
|
||||||
|
temp_lobbies = []
|
||||||
|
|
||||||
|
counter = 1
|
||||||
|
if channel_id != False and channel_id in managed_lobbies:
|
||||||
|
temp_lobbies.append("[" + "osump://" + str(managed_lobbies[channel_id]["lobby"]) + "/" + str(managed_lobbies[channel_id]["password"]) + " " + str(channel_id) + "]")
|
||||||
|
counter += 1
|
||||||
|
else:
|
||||||
|
for lobby in managed_lobbies:
|
||||||
|
if "password" in managed_lobbies[lobby]:
|
||||||
|
temp_lobbies.append("[" + "osump://" + str(managed_lobbies[lobby]["lobby"]) + "/" + str(managed_lobbies[lobby]["password"]) + " Lobby #" + str(counter) + "]")
|
||||||
|
counter += 1
|
||||||
|
|
||||||
|
msg = "No Unalike lobbies are ready!"
|
||||||
|
if counter > 1:
|
||||||
|
msg = "[" + unalike_url + " Unalike > ] invite: " + " ".join(temp_lobbies)
|
||||||
|
|
||||||
|
print("Sending invite to: " + recipient)
|
||||||
|
print("Invite content: " + msg)
|
||||||
|
irc_send_pm(recipient, msg)
|
||||||
|
|
||||||
|
def irc_sync_lobbies_to(originating_channel, beatmapset_id, beatmap_id):
|
||||||
|
global managed_lobbies, global_sync_init_timeout
|
||||||
|
|
||||||
|
timestamp_now = math.floor(time.time())
|
||||||
|
if global_last_mapset_played == beatmapset_id:
|
||||||
|
print(originating_channel + " tried to sync back the last played map!")
|
||||||
|
else:
|
||||||
|
syncAllowed = False
|
||||||
|
if originating_channel in managed_lobbies and "lastSyncInit" in managed_lobbies[originating_channel]:
|
||||||
|
if abs(timestamp_now - managed_lobbies[originating_channel]["lastSyncInit"]) > global_sync_init_timeout:
|
||||||
|
managed_lobbies[originating_channel]["lastSyncInit"] = timestamp_now
|
||||||
|
syncAllowed = True
|
||||||
|
else:
|
||||||
|
print(originating_channel + " attempted syncing too frequently!")
|
||||||
|
elif originating_channel == "WebUI":
|
||||||
|
syncAllowed = True
|
||||||
|
|
||||||
|
if syncAllowed:
|
||||||
|
for lobby in managed_lobbies:
|
||||||
|
if lobby != originating_channel and "beatmapset" in managed_lobbies[lobby] and managed_lobbies[lobby]["beatmapset"] != beatmapset_id:
|
||||||
|
skipSync = False
|
||||||
|
if "desynced" in managed_lobbies[lobby]:
|
||||||
|
if managed_lobbies[lobby]["desynced"] == True:
|
||||||
|
skipSync = True
|
||||||
|
|
||||||
|
if not skipSync:
|
||||||
|
if "channel" in managed_lobbies[lobby]:
|
||||||
|
print("Bringing " + managed_lobbies[lobby]["channel"] + " to compliance...")
|
||||||
|
irc_send_pm(managed_lobbies[lobby]["channel"], "!mp map " + str(beatmap_id))
|
||||||
|
managed_lobbies[lobby]["beatmapset"] = beatmapset_id
|
||||||
|
managed_lobbies[lobby]["beatmap"] = beatmap_id
|
||||||
|
else:
|
||||||
|
print("Attempted to set a non-existent lobby's map...")
|
||||||
|
else:
|
||||||
|
print("Skipping " + managed_lobbies[lobby]["channel"] + "... (Reason: desynced)")
|
||||||
|
else:
|
||||||
|
print(originating_channel + " does not have a sync property!")
|
||||||
|
|
||||||
|
|
||||||
|
def fix_mp_prefix(channel_id):
|
||||||
|
if channel_id.find("#") == -1:
|
||||||
|
channel_id = "#mp_" + channel_id
|
||||||
|
|
||||||
|
return channel_id
|
||||||
|
|
||||||
|
def irc_close_lobby(channel_id, abandon=False):
|
||||||
|
global managed_lobbies, lobbies_changed
|
||||||
|
|
||||||
|
channel_id = fix_mp_prefix(channel_id)
|
||||||
|
|
||||||
|
if not abandon:
|
||||||
|
irc_send_pm(channel_id, "!mp close")
|
||||||
|
|
||||||
|
managed_lobbies.pop(channel_id, None)
|
||||||
|
|
||||||
|
if abandon:
|
||||||
|
print(channel_id + " abandoned!")
|
||||||
|
else:
|
||||||
|
print(channel_id + " closed!")
|
||||||
|
|
||||||
|
lobbies_changed = True
|
||||||
|
|
||||||
|
def irc_start_managing(lobby_channel, lobby_name=False, join=False):
|
||||||
|
global managed_lobbies, lobbies_changed
|
||||||
|
|
||||||
|
lobby_channel = fix_mp_prefix(lobby_channel)
|
||||||
|
print("Lobby registered: " + lobby_channel)
|
||||||
|
|
||||||
|
if join:
|
||||||
|
print("Joining channel: " + lobby_channel)
|
||||||
|
irc_send("JOIN", lobby_channel)
|
||||||
|
|
||||||
|
|
||||||
|
if not (lobby_channel in managed_lobbies):
|
||||||
|
managed_lobbies[lobby_channel] = {}
|
||||||
|
|
||||||
|
managed_lobbies[lobby_channel]["channel"] = lobby_channel
|
||||||
|
if lobby_name != False:
|
||||||
|
managed_lobbies[lobby_channel]["name"] = lobby_name
|
||||||
|
if join:
|
||||||
|
managed_lobbies[lobby_channel]["skipModeSetup"] = True
|
||||||
|
|
||||||
|
lobbies_changed = True
|
||||||
|
|
||||||
|
def irc_auth(the_name, the_pass=""):
|
||||||
|
if the_pass != "":
|
||||||
|
irc_send("PASS", the_pass, custom_delay=0)
|
||||||
|
irc_send("NICK", the_name, custom_delay=0)
|
||||||
|
irc_send("USER", the_name, the_name, the_name, the_name, custom_delay=0)
|
||||||
|
|
||||||
|
default_sender = "SERVER"
|
||||||
|
class Command():
|
||||||
|
def __init__(self):
|
||||||
|
global default_sender
|
||||||
|
self.sender = default_sender
|
||||||
|
self.raw = ""
|
||||||
|
self.cmd = ""
|
||||||
|
self.args = []
|
||||||
|
self.message = ""
|
||||||
|
self.channel = ""
|
||||||
|
|
||||||
|
def irc_to_Command(lines):
|
||||||
|
cmds = []
|
||||||
|
for line in lines:
|
||||||
|
args_start = 1
|
||||||
|
has_sender = False
|
||||||
|
if line.find(":") == 0:
|
||||||
|
args_start = 2
|
||||||
|
has_sender = True
|
||||||
|
|
||||||
|
expl = line.split(" ")
|
||||||
|
|
||||||
|
cmd = Command()
|
||||||
|
cmd.raw = line
|
||||||
|
cmd.cmd = expl[args_start-1].upper()
|
||||||
|
cmd.args = expl[args_start:]
|
||||||
|
if has_sender:
|
||||||
|
temp_sender = expl[0][1:]
|
||||||
|
if temp_sender.find("!") != -1:
|
||||||
|
temp_sender = temp_sender.split("!")[0]
|
||||||
|
cmd.sender = temp_sender
|
||||||
|
if cmd.cmd in [ "PRIVMSG", "001", "332", "372", "375", "376", "401", "403" ]:
|
||||||
|
cmd.channel = expl[args_start]
|
||||||
|
if (cmd.cmd in ["401", "403"]):
|
||||||
|
cmd.channel = expl[args_start+1]
|
||||||
|
temp_msg = " ".join(expl[(args_start+1):])
|
||||||
|
if len(temp_msg) > 1:
|
||||||
|
cmd.message = temp_msg[1:].replace(b'\x01ACTION'.decode(encoding), "[STATUS]").replace(b'\x01'.decode(encoding), "");
|
||||||
|
|
||||||
|
cmds.append(cmd)
|
||||||
|
|
||||||
|
return cmds
|
||||||
|
|
||||||
|
def irc_read():
|
||||||
|
global irc, encoding, buffer_size
|
||||||
|
text = ""
|
||||||
|
|
||||||
|
|
||||||
|
reading = True
|
||||||
|
while reading:
|
||||||
|
remaining = ""
|
||||||
|
|
||||||
|
try:
|
||||||
|
remaining = irc.recv(buffer_size).decode(encoding, "replace")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if remaining == "":
|
||||||
|
if (len(text) >= 2 and text[-1] == "\n") or text == "":
|
||||||
|
reading = False
|
||||||
|
else:
|
||||||
|
remaining = remaining.replace("\r\n", "\n") # unstandard bancho fix
|
||||||
|
text = text + remaining
|
||||||
|
|
||||||
|
if text == "":
|
||||||
|
return []
|
||||||
|
else:
|
||||||
|
return [x for x in text.split("\n") if len(x.strip()) > 0]
|
||||||
|
|
||||||
|
def reset_lobby_states():
|
||||||
|
global global_playing, managed_lobbies, lobbies_changed
|
||||||
|
|
||||||
|
global_playing = False
|
||||||
|
for lobby in managed_lobbies:
|
||||||
|
managed_lobbies[lobby]["ready"] = False
|
||||||
|
managed_lobbies[lobby]["playing"] = False
|
||||||
|
lobbies_changed = True
|
||||||
|
|
||||||
|
print("Lobby states reset.")
|
||||||
|
|
||||||
|
def generate_new_password():
|
||||||
|
global lobby_default_pass
|
||||||
|
lobby_default_pass = ''.join(random.choice(string.ascii_letters) for i in range(10))
|
||||||
|
print("A new default password has been generated.")
|
||||||
|
|
||||||
|
if console_input_allowed:
|
||||||
|
print("--- HELP ---")
|
||||||
|
print("")
|
||||||
|
print("ESC: Quit")
|
||||||
|
print(" c: Command")
|
||||||
|
print(" t: Message")
|
||||||
|
print(" r: Reply (last channel)")
|
||||||
|
print(" b: Message BanchoBot")
|
||||||
|
print(" p: Responsivity test")
|
||||||
|
print(" n: Create lobby (+shift: auto-name)")
|
||||||
|
print(" s: Send links")
|
||||||
|
print(" x: Close lobby")
|
||||||
|
print(" Q: RESET STATES")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
print("")
|
||||||
|
print("--- START ---")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
with open(requests_file, "w") as json_file:
|
||||||
|
json.dump({}, json_file)
|
||||||
|
print("Requests JSON reset.")
|
||||||
|
|
||||||
|
with open(report_file, "w") as outfile:
|
||||||
|
json.dump({}, outfile)
|
||||||
|
print("Report JSON reset.")
|
||||||
|
|
||||||
|
managed_lobbies = {}
|
||||||
|
lobbies_changed = False
|
||||||
|
current_mapset = 0
|
||||||
|
current_mapset_default_beatmap = 0
|
||||||
|
api_player = ""
|
||||||
|
global_playing = False
|
||||||
|
global_rounds_played = 0
|
||||||
|
global_polling_rate = float(1)/polling_rate
|
||||||
|
global_last_mapset_played = -5
|
||||||
|
generate_new_password()
|
||||||
|
global_authenticated = False
|
||||||
|
boot_timestamp = math.floor(time.time())
|
||||||
|
current_irc_send_timeout = 0
|
||||||
|
global_irc_send_queue = []
|
||||||
|
print("First password: " + lobby_default_pass)
|
||||||
|
|
||||||
|
tick = True
|
||||||
|
|
||||||
|
print("Beginning authentication...")
|
||||||
|
irc_auth(bot_name, bot_pass)
|
||||||
|
last_channel = "BanchoBot"
|
||||||
|
|
||||||
|
running = True
|
||||||
|
while running:
|
||||||
|
time.sleep(global_polling_rate)
|
||||||
|
lines = irc_to_Command(irc_read())
|
||||||
|
|
||||||
|
request_json = {}
|
||||||
|
if path.exists(requests_file):
|
||||||
|
with open(requests_file, "r") as json_file:
|
||||||
|
request_json = json.load(json_file)
|
||||||
|
if len(request_json) > 0:
|
||||||
|
print("NEW REQUEST:", request_json)
|
||||||
|
with open(requests_file, "w") as json_file:
|
||||||
|
json.dump({}, json_file)
|
||||||
|
|
||||||
|
for request in request_json:
|
||||||
|
if "type" in request:
|
||||||
|
if request["type"] == "invite" and "target" in request:
|
||||||
|
filter = False;
|
||||||
|
if "filter" in request:
|
||||||
|
filter = fix_mp_prefix(request["filter"])
|
||||||
|
|
||||||
|
irc_send_links(request["target"].replace(" ", "_"), filter)
|
||||||
|
elif request["type"] == "new_lobby":
|
||||||
|
if len(managed_lobbies) < global_max_lobbies:
|
||||||
|
lobby_name = "Unalike"
|
||||||
|
if "name" in request:
|
||||||
|
lobby_name = request["name"]
|
||||||
|
irc_send_pm("BanchoBot", "!mp make "+lobby_name)
|
||||||
|
elif request["type"] == "close" and "target" in request:
|
||||||
|
irc_close_lobby(request["target"])
|
||||||
|
elif request["type"] == "set_delay" and "target" in request:
|
||||||
|
if str(request["target"]).isnumeric() and request["target"] >= 1 and request["target"] <= 7:
|
||||||
|
global_irc_send_timeout = float(request["target"])
|
||||||
|
print("Global delay has been updated: " + str(global_irc_send_timeout))
|
||||||
|
elif request["type"] == "results_fetched" and "target" in request:
|
||||||
|
if request["target"] in managed_lobbies and "finished" in managed_lobbies[request["target"]]:
|
||||||
|
managed_lobbies[request["target"]]["finished"] = False
|
||||||
|
lobbies_changed = True
|
||||||
|
elif request["type"] == "ping" and "target" in request:
|
||||||
|
channel_id = fix_mp_prefix(request["target"])
|
||||||
|
if channel_id in managed_lobbies:
|
||||||
|
print("Pinging " + str(channel_id) + " by request.")
|
||||||
|
irc_send_pm(channel_id, "[" + unalike_url + " Unalike > ] Someone pinged this lobby.")
|
||||||
|
elif request["type"] == "sync_all":
|
||||||
|
if current_mapset != 0 and current_mapset_default_beatmap != 0:
|
||||||
|
print("Syncing all lobbies...")
|
||||||
|
irc_sync_lobbies_to("WebUI", current_mapset, current_mapset_default_beatmap)
|
||||||
|
elif request["type"] == "register" and "target" in request:
|
||||||
|
print("Registering lobby: " + str(request["target"]))
|
||||||
|
irc_start_managing(request["target"], join=True)
|
||||||
|
elif request["type"] == "shutdown":
|
||||||
|
running = False
|
||||||
|
break
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
|
if line.cmd in [ "001" ]:
|
||||||
|
print(line.message)
|
||||||
|
global_authenticated = True
|
||||||
|
elif line.cmd == "PRIVMSG" and line.sender == "BanchoBot":
|
||||||
|
if line.message.find("Created the tournament match ") != -1:
|
||||||
|
new_lobby_info = line.message.replace("Created the tournament match https://osu.ppy.sh/mp/", "").split(" ")
|
||||||
|
|
||||||
|
lobby_channel = new_lobby_info[0]
|
||||||
|
lobby_name = " ".join(new_lobby_info[1:])
|
||||||
|
last_channel = lobby_channel
|
||||||
|
|
||||||
|
irc_start_managing(lobby_channel, lobby_name)
|
||||||
|
|
||||||
|
elif line.message.find("The match has finished!") != -1 or line.message.find("Aborted the match") != -1:
|
||||||
|
lobby_channel = line.channel
|
||||||
|
print(line.channel + " ended.")
|
||||||
|
|
||||||
|
if not (lobby_channel in managed_lobbies):
|
||||||
|
managed_lobbies[lobby_channel] = {}
|
||||||
|
|
||||||
|
managed_lobbies[lobby_channel]["ready"] = False
|
||||||
|
managed_lobbies[lobby_channel]["playing"] = False
|
||||||
|
managed_lobbies[lobby_channel]["finished"] = True
|
||||||
|
|
||||||
|
lobbies_changed = True
|
||||||
|
elif line.message.find("Match starts in ") != -1 or line.message.find("Good luck, have fun!") != -1:
|
||||||
|
pass
|
||||||
|
elif line.message.find(" finished playing (") != -1:
|
||||||
|
player = line.message.split(" finished playing (")[0]
|
||||||
|
|
||||||
|
elif line.message.find("The match has started!") != -1:
|
||||||
|
lobby_channel = line.channel
|
||||||
|
print(line.channel + " started.")
|
||||||
|
|
||||||
|
if not (lobby_channel in managed_lobbies):
|
||||||
|
managed_lobbies[lobby_channel] = {}
|
||||||
|
|
||||||
|
managed_lobbies[lobby_channel]["playing"] = True
|
||||||
|
|
||||||
|
lobbies_changed = True
|
||||||
|
elif line.message.find("All players are ready") != -1:
|
||||||
|
lobby_channel = line.channel
|
||||||
|
print(line.channel + " is ready.")
|
||||||
|
|
||||||
|
if not (lobby_channel in managed_lobbies):
|
||||||
|
managed_lobbies[lobby_channel] = {}
|
||||||
|
|
||||||
|
managed_lobbies[lobby_channel]["ready"] = True
|
||||||
|
|
||||||
|
lobbies_changed = True
|
||||||
|
elif line.message.find(" left the game.") != -1:
|
||||||
|
lobby_channel = line.channel
|
||||||
|
player = line.message.split(" left the game.")[0]
|
||||||
|
print(player + " left." + "(" + lobby_channel + ")")
|
||||||
|
|
||||||
|
if not (lobby_channel in managed_lobbies):
|
||||||
|
managed_lobbies[lobby_channel] = {}
|
||||||
|
|
||||||
|
managed_lobbies[lobby_channel]["ready"] = False
|
||||||
|
if not ("players" in managed_lobbies[lobby_channel]):
|
||||||
|
managed_lobbies[lobby_channel]["players"] = []
|
||||||
|
managed_lobbies[lobby_channel]["players"].remove(player)
|
||||||
|
elif line.message.find(" joined in slot ") != -1:
|
||||||
|
lobby_channel = line.channel
|
||||||
|
player = line.message.split(" joined in slot ")[0]
|
||||||
|
print(player + " joined." + "(" + lobby_channel + ")")
|
||||||
|
|
||||||
|
temp_api_player = player.replace(" ", "_")
|
||||||
|
httpRequest = requests.get(unalike_api + "/" + temp_api_player + "/t/test")
|
||||||
|
if httpRequest.text.find("YES") != -1:
|
||||||
|
print("New API token provider elected: " + api_player + " -> " + temp_api_player)
|
||||||
|
api_player = temp_api_player
|
||||||
|
elif httpRequest.text.find("EXPIRING") != -1:
|
||||||
|
irc_send_pm(temp_api_player, "Your API key is expiring soon. Please click [" + unalike_url + " here] to refresh it.")
|
||||||
|
elif httpRequest.text.find("NO") != -1:
|
||||||
|
irc_send_pm(temp_api_player, "Your API key has expired. Please click [" + unalike_url + " here] to refresh it.")
|
||||||
|
irc_send_pm(lobby_channel, "!mp kick " + player)
|
||||||
|
else:
|
||||||
|
irc_send_pm(temp_api_player, "Unalike is having connection issues...")
|
||||||
|
print("API connection issues for player (unalike-side!): " + player)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if not (lobby_channel in managed_lobbies):
|
||||||
|
managed_lobbies[lobby_channel] = {}
|
||||||
|
|
||||||
|
managed_lobbies[lobby_channel]["ready"] = False
|
||||||
|
|
||||||
|
if not ("players" in managed_lobbies[lobby_channel]):
|
||||||
|
managed_lobbies[lobby_channel]["players"] = []
|
||||||
|
|
||||||
|
if len(managed_lobbies[lobby_channel]["players"]) < 1:
|
||||||
|
irc_send_pm(line.channel, "!mp host " + player) # auto host
|
||||||
|
|
||||||
|
managed_lobbies[lobby_channel]["players"].append(player)
|
||||||
|
elif line.message.find("Changed the match password") != -1:
|
||||||
|
lobby_channel = line.channel
|
||||||
|
print("Password set in " + line.channel)
|
||||||
|
|
||||||
|
if not (lobby_channel in managed_lobbies):
|
||||||
|
managed_lobbies[lobby_channel] = {}
|
||||||
|
|
||||||
|
managed_lobbies[lobby_channel]["password"] = lobby_default_pass
|
||||||
|
generate_new_password() # let's hope there won't be any random changes
|
||||||
|
|
||||||
|
lobbies_changed = True
|
||||||
|
elif line.message.find("Changed match settings to ") != -1:
|
||||||
|
lobby_channel = line.channel
|
||||||
|
lobby_settings = line.message.replace("Changed match settings to ", "").replace(" slots", "").split(", ") #Changed match settings to 1 slots, HeadToHead, Accuracy
|
||||||
|
lobby_size = int(lobby_settings[0])
|
||||||
|
lobby_mode = lobby_settings[1]
|
||||||
|
lobby_win_condition = lobby_settings[2]
|
||||||
|
|
||||||
|
print("New settings in " + line.channel + ":")
|
||||||
|
print(" Win Condition: " + lobby_win_condition)
|
||||||
|
print(" Mode: " + lobby_mode)
|
||||||
|
print(" Size: " + str(lobby_size))
|
||||||
|
|
||||||
|
if not (lobby_channel in managed_lobbies):
|
||||||
|
managed_lobbies[lobby_channel] = {}
|
||||||
|
|
||||||
|
managed_lobbies[lobby_channel]["winCondition"] = lobby_win_condition
|
||||||
|
managed_lobbies[lobby_channel]["mode"] = lobby_mode
|
||||||
|
managed_lobbies[lobby_channel]["size"] = lobby_size
|
||||||
|
|
||||||
|
lobbies_changed = True
|
||||||
|
elif line.message.find("Changed match host to ") != -1:
|
||||||
|
pass # already announced, this is a duplicate
|
||||||
|
elif line.message.find(" became the host.") != -1:
|
||||||
|
player = line.message.split(" became the host.")[0]
|
||||||
|
print("Host changed: " + player)
|
||||||
|
elif (line.message.find("Beatmap changed to:") != -1 or line.message.find("Changed beatmap to ") != -1) and line.message.find("osu.ppy.sh/b/"):
|
||||||
|
lobby_channel = line.channel
|
||||||
|
try:
|
||||||
|
temp = line.message.split("osu.ppy.sh/b/")[1].replace(")", "")
|
||||||
|
if temp.find(" ") != -1:
|
||||||
|
temp = temp.split(" ")[0]
|
||||||
|
beatmap_id = int(temp)
|
||||||
|
except Exception:
|
||||||
|
beatmap_id = -1
|
||||||
|
|
||||||
|
http_request = requests.get(unalike_api + "/" + api_player + "/y/" + str(beatmap_id))
|
||||||
|
if (http_request.text.isnumeric()):
|
||||||
|
beatmapset_id = int(http_request.text)
|
||||||
|
else:
|
||||||
|
beatmapset_id = -1
|
||||||
|
|
||||||
|
print("Beatmap changed to: " + str(beatmap_id) + " (" + str(beatmapset_id) + ")")
|
||||||
|
|
||||||
|
if not (lobby_channel in managed_lobbies):
|
||||||
|
managed_lobbies[lobby_channel] = {}
|
||||||
|
|
||||||
|
managed_lobbies[lobby_channel]["beatmap"] = beatmap_id
|
||||||
|
managed_lobbies[lobby_channel]["ready"] = False
|
||||||
|
|
||||||
|
if beatmapset_id > 0:
|
||||||
|
managed_lobbies[lobby_channel]["beatmapset"] = beatmapset_id
|
||||||
|
|
||||||
|
skipSync = False
|
||||||
|
if "desynced" in managed_lobbies[lobby_channel]:
|
||||||
|
if managed_lobbies[lobby_channel]["desynced"] == True:
|
||||||
|
skipSync = True
|
||||||
|
|
||||||
|
if skipSync:
|
||||||
|
print("Skipping sync of " + str(lobby_channel) + "... (Reason: desynced)")
|
||||||
|
else:
|
||||||
|
if current_mapset != beatmapset_id:
|
||||||
|
print("Syncing other lobbies to the new beatmapset... (" + str(current_mapset) + " previously)")
|
||||||
|
current_mapset = beatmapset_id
|
||||||
|
current_mapset_default_beatmap = beatmap_id
|
||||||
|
irc_sync_lobbies_to(lobby_channel, current_mapset, current_mapset_default_beatmap)
|
||||||
|
else:
|
||||||
|
print("The beatmap is a part of the current set.")
|
||||||
|
|
||||||
|
lobbies_changed = True
|
||||||
|
elif line.message.find("Host is changing map...") != -1:
|
||||||
|
lobby_channel = line.channel
|
||||||
|
|
||||||
|
beatmap_id = -2
|
||||||
|
print("Selecting beatmap...")
|
||||||
|
|
||||||
|
if not (lobby_channel in managed_lobbies):
|
||||||
|
managed_lobbies[lobby_channel] = {}
|
||||||
|
|
||||||
|
managed_lobbies[lobby_channel]["beatmap"] = beatmap_id
|
||||||
|
managed_lobbies[lobby_channel]["ready"] = False
|
||||||
|
|
||||||
|
lobbies_changed = True
|
||||||
|
else:
|
||||||
|
print("[" + line.channel + "] " + line.sender + ": " + line.message)
|
||||||
|
|
||||||
|
elif line.cmd == "PRIVMSG" and line.channel in managed_lobbies:
|
||||||
|
if len(line.message) >= 1 and line.message[0] == ".":
|
||||||
|
if line.message == ".close":
|
||||||
|
irc_close_lobby(line.channel)
|
||||||
|
elif line.message == ".desync":
|
||||||
|
managed_lobbies[line.channel]["desynced"] = True
|
||||||
|
print("Setting " + line.channel + " to desynced mode.")
|
||||||
|
irc_send_pm(channel_id, "[" + unalike_url + " Unalike > ] The mapset will not sync while desynced.")
|
||||||
|
lobbies_changed = True
|
||||||
|
elif line.message == ".sync":
|
||||||
|
managed_lobbies[line.channel]["desynced"] = False
|
||||||
|
print("Setting " + line.channel + " to synced mode.")
|
||||||
|
irc_send_pm(channel_id, "!mp map " + str(current_mapset_default_beatmap))
|
||||||
|
lobbies_changed = True
|
||||||
|
elif line.cmd == "PRIVMSG" and line.sender != "BanchoBot":
|
||||||
|
print("[" + line.channel + "] " + line.sender + ": " + line.message)
|
||||||
|
elif line.cmd in [ "401", "403" ]: # 401 = No such nick (bancho bug), 403 = No such channel
|
||||||
|
irc_close_lobby(line.channel, True) # abandon = don't announce close (don't loop endlessly)
|
||||||
|
elif line.cmd == "332": # Topic (has game number)
|
||||||
|
if line.message.find("multiplayer game #") != -1:
|
||||||
|
temp_topic = line.message.replace(":multiplayer game #", "").split(" ")
|
||||||
|
lobby_id = int(temp_topic[1])
|
||||||
|
channel_id = temp_topic[0]
|
||||||
|
print("Received lobby ID (" + str(lobby_id) + ") for channel " + channel_id + ".")
|
||||||
|
|
||||||
|
last_channel = channel_id
|
||||||
|
|
||||||
|
if channel_id.find("#") == -1:
|
||||||
|
channel_id = "#" + channel_id
|
||||||
|
|
||||||
|
if not (channel_id in managed_lobbies):
|
||||||
|
managed_lobbies[channel_id] = {}
|
||||||
|
|
||||||
|
managed_lobbies[channel_id]["channel"] = channel_id
|
||||||
|
managed_lobbies[channel_id]["lobby"] = lobby_id
|
||||||
|
|
||||||
|
lobbies_changed = True
|
||||||
|
elif line.cmd in [ "372", "375", "376", "333", "366", "353" ]:
|
||||||
|
pass
|
||||||
|
elif line.cmd == "QUIT":
|
||||||
|
pass
|
||||||
|
elif line.cmd in [ "JOIN", "PART" ]:
|
||||||
|
pass # other bancho messages are more useful
|
||||||
|
elif not (line.cmd in [ "PING", "MODE" ]):
|
||||||
|
print("")
|
||||||
|
print(line.raw)
|
||||||
|
print(line.sender)
|
||||||
|
print(line.cmd)
|
||||||
|
print(" ".join(line.args))
|
||||||
|
print("")
|
||||||
|
|
||||||
|
if line.cmd == "PING":
|
||||||
|
if len(line.args) >= 1:
|
||||||
|
irc_send("PONG", line.args[0])
|
||||||
|
|
||||||
|
if current_irc_send_timeout > 0:
|
||||||
|
current_irc_send_timeout -= global_polling_rate
|
||||||
|
if current_irc_send_timeout < 0:
|
||||||
|
current_irc_send_timeout = 0
|
||||||
|
elif len(global_irc_send_queue) > 0:
|
||||||
|
irc_enqueued_obj = global_irc_send_queue.pop(0)
|
||||||
|
if "line" in irc_enqueued_obj and "delay" in irc_enqueued_obj:
|
||||||
|
irc_send_real(irc_enqueued_obj["line"], irc_enqueued_obj["delay"])
|
||||||
|
|
||||||
|
|
||||||
|
if global_authenticated:
|
||||||
|
temp_output = {}
|
||||||
|
temp_output["lobbies"] = managed_lobbies
|
||||||
|
temp_output["playing"] = global_playing
|
||||||
|
temp_output["apiPlayer"] = api_player
|
||||||
|
temp_output["roundsPlayed"] = global_rounds_played
|
||||||
|
temp_output["timestamp"] = math.floor(time.time());
|
||||||
|
temp_output["boot"] = boot_timestamp;
|
||||||
|
temp_output["delay"] = global_irc_send_timeout;
|
||||||
|
temp_output["maxLobbies"] = global_max_lobbies;
|
||||||
|
temp_output["current_mapset"] = current_mapset;
|
||||||
|
|
||||||
|
# uncomment to expose commands to the public
|
||||||
|
# temp_output["command_queue"] = global_irc_send_queue;
|
||||||
|
|
||||||
|
with open(report_file, "w") as outfile:
|
||||||
|
json.dump(temp_output, outfile)
|
||||||
|
|
||||||
|
if lobbies_changed:
|
||||||
|
lobbies_changed = False
|
||||||
|
all_ready = True
|
||||||
|
all_finished = True
|
||||||
|
if len(managed_lobbies) > 0:
|
||||||
|
print("Managed lobbies (" + str(len(managed_lobbies)) + "):")
|
||||||
|
for channel_id in managed_lobbies:
|
||||||
|
print(" ", managed_lobbies[channel_id])
|
||||||
|
if not ("configured" in managed_lobbies[channel_id]):
|
||||||
|
managed_lobbies[channel_id]["configured"] = True
|
||||||
|
managed_lobbies[channel_id]["ready"] = False
|
||||||
|
managed_lobbies[channel_id]["playing"] = False
|
||||||
|
managed_lobbies[channel_id]["channel"] = channel_id
|
||||||
|
managed_lobbies[channel_id]["match"] = channel_id.replace("#mp_", "")
|
||||||
|
managed_lobbies[channel_id]["roundsPlayed"] = 0
|
||||||
|
managed_lobbies[channel_id]["players"] = []
|
||||||
|
managed_lobbies[channel_id]["finished"] = False
|
||||||
|
managed_lobbies[channel_id]["desynced"] = False
|
||||||
|
managed_lobbies[channel_id]["lastSyncInit"] = 0
|
||||||
|
if not ("skipModeSetup" in managed_lobbies[channel_id]):
|
||||||
|
managed_lobbies[channel_id]["skipModeSetup"] = False
|
||||||
|
|
||||||
|
print("Performing basic setup on " + channel_id + "...")
|
||||||
|
irc_send_pm(channel_id, "!mp password " + str(lobby_default_pass))
|
||||||
|
if not managed_lobbies[channel_id]["skipModeSetup"]:
|
||||||
|
irc_send_pm(channel_id, "!mp set 0 1 " + str(lobby_default_size))
|
||||||
|
|
||||||
|
lobbies_changed = True
|
||||||
|
if managed_lobbies[channel_id]["ready"] == False:
|
||||||
|
all_ready = False
|
||||||
|
if managed_lobbies[channel_id]["playing"] == True:
|
||||||
|
all_finished = False
|
||||||
|
with open(lobbies_dir + managed_lobbies[channel_id]["match"] + ".json", "w") as json_file:
|
||||||
|
json.dump(managed_lobbies[channel_id], json_file)
|
||||||
|
if global_playing:
|
||||||
|
if all_finished:
|
||||||
|
print("All lobbies finished playing!")
|
||||||
|
global_playing = False
|
||||||
|
for channel_id in managed_lobbies:
|
||||||
|
managed_lobbies[channel_id]["finished"] = False
|
||||||
|
# irc_send_pm(channel_id, "No results system yet, but the message works. xD")
|
||||||
|
global_rounds_played += 1
|
||||||
|
|
||||||
|
request_matches = []
|
||||||
|
for channel_id in managed_lobbies:
|
||||||
|
if "roundsPlayed" in managed_lobbies[channel_id] and "match" in managed_lobbies[channel_id]:
|
||||||
|
request_matches.append(str(managed_lobbies[channel_id]["match"]) + ",-1")
|
||||||
|
|
||||||
|
composer_url = unalike_composer + "secret=" + local_secret + "&source=" + ";".join(request_matches) + "&beatmapset=" + str(current_mapset);
|
||||||
|
|
||||||
|
print("Finished. Request forwarded to: Unalike Composer")
|
||||||
|
|
||||||
|
time.sleep(global_composer_delay)
|
||||||
|
requests.get(composer_url)
|
||||||
|
|
||||||
|
lobbies_changed = True
|
||||||
|
else:
|
||||||
|
if all_ready:
|
||||||
|
print("All lobbies are ready!")
|
||||||
|
global_playing = True
|
||||||
|
global_last_mapset_played = current_mapset
|
||||||
|
temp_timer = len(managed_lobbies) * global_irc_send_timeout
|
||||||
|
for channel_id in managed_lobbies:
|
||||||
|
managed_lobbies[channel_id]["roundsPlayed"] += 1
|
||||||
|
irc_send_pm(channel_id, "!mp start " + str(temp_timer))
|
||||||
|
print("Started " + channel_id + " with a " + str(temp_timer) + " second timer.")
|
||||||
|
temp_timer = temp_timer - global_irc_send_timeout
|
||||||
|
else:
|
||||||
|
print("No lobbies are managed by Unalike.")
|
||||||
|
|
||||||
|
if console_input_allowed:
|
||||||
|
if msvcrt.kbhit():
|
||||||
|
pressed_button = msvcrt.getch()
|
||||||
|
|
||||||
|
if pressed_button == b'\x1b': # ESC
|
||||||
|
print("EXITING APPLICATION")
|
||||||
|
break
|
||||||
|
|
||||||
|
elif pressed_button == b'p': # p
|
||||||
|
print("Pong!")
|
||||||
|
|
||||||
|
elif pressed_button == b'c': # c
|
||||||
|
print("COMMAND MODE")
|
||||||
|
temp_input = input("Command: ")
|
||||||
|
if temp_input.find(" "):
|
||||||
|
temp_args = temp_input.split()
|
||||||
|
else:
|
||||||
|
temp_args = [temp_input, ""]
|
||||||
|
irc_send(temp_args[0], " ".join(temp_args[1:]))
|
||||||
|
|
||||||
|
elif pressed_button == b't': # t
|
||||||
|
print("MESSAGE MODE")
|
||||||
|
temp_channel = input("Channel/User: ")
|
||||||
|
temp_message = input("Message: ")
|
||||||
|
irc_send_pm(temp_channel, temp_message)
|
||||||
|
|
||||||
|
print("")
|
||||||
|
print("--- END ---")
|
||||||
|
print("")
|
||||||
|
|
||||||
|
print("Starting shutdown process...")
|
||||||
|
|
||||||
|
with open(requests_file, "w") as json_file:
|
||||||
|
json.dump({}, json_file)
|
||||||
|
print("Requests JSON reset.")
|
||||||
|
|
||||||
|
to_close_list = []
|
||||||
|
for channel_id in managed_lobbies:
|
||||||
|
to_close_list.append(channel_id)
|
||||||
|
|
||||||
|
if global_irc_send_timeout < 5:
|
||||||
|
global_irc_send_timeout = 5
|
||||||
|
|
||||||
|
for channel_id in to_close_list:
|
||||||
|
irc_close_lobby(channel_id)
|
||||||
|
|
||||||
|
irc_send("QUIT", custom_delay=0)
|
||||||
|
|
||||||
|
time.sleep(global_irc_send_timeout)
|
||||||
|
for irc_enqueued_obj in global_irc_send_queue:
|
||||||
|
if "line" in irc_enqueued_obj and "delay" in irc_enqueued_obj:
|
||||||
|
irc_send_real(irc_enqueued_obj["line"], irc_enqueued_obj["delay"])
|
||||||
|
# print("SENT: " + str(irc_enqueued_obj["line"]).replace("\r\n", ""))
|
||||||
|
time.sleep(irc_enqueued_obj["delay"])
|
||||||
|
|
||||||
|
with open(report_file, "w") as outfile:
|
||||||
|
json.dump({}, outfile)
|
||||||
|
print("Report JSON reset.")
|
||||||
|
|
||||||
|
print("Quit request sent!")
|
||||||