Beispiel #1
0
async def update_action(user: Player, p: bytes) -> None:
    d = reader.handle_packet(
        p,
        (
            ("actionid", osuTypes.u8),
            ("base_info", osuTypes.string),
            ("md5", osuTypes.string),
            ("mods", osuTypes.u32),
            ("mode", osuTypes.u8),
            ("mid", osuTypes.i32),
        ),
    )

    if d["actionid"] == 0 and d["mods"] & Mods.RELAX:
        d["base_info"] = "on Relax"
    elif d["actionid"] == 0 and d["mods"] & Mods.AUTOPILOT:
        d["base_info"] = "on Autopilot"

    user.action = d["actionid"]
    user.base_info = d["base_info"]
    user.map_md5 = d["md5"]
    user.mods = d["mods"]

    m = lbModes(d["mode"], d["mods"])
    user.mode = m.value
    user.mode_vn = m.as_vn

    user.map_id = d["mid"]

    if d["actionid"] == 2:
        user.base_info += f" +{(Mods(user.mods))!r}"  # ugly and i dont care!

    if not user.restricted:
        glob.players.enqueue(writer.userStats(user))
Beispiel #2
0
async def update_action(user: Player, p: bytes) -> None:
    d = reader.handle_packet(p, (
        ('actionid', osuTypes.u8),
        ('info', osuTypes.string),
        ('md5', osuTypes.string),
        ('mods', osuTypes.u32),
        ('mode', osuTypes.u8),
        ('mid', osuTypes.i32)
    ))

    if d['actionid'] == 0 and d['mods'] & Mods.RELAX:
        d['info'] = 'on Relax'
    elif d['actionid'] == 0 and d['mods'] & Mods.AUTOPILOT:
        d['info'] = 'on Autopilot'

    user.action = d['actionid']
    user.info = d['info']
    user.map_md5 = d['md5']
    user.mods = d['mods']

    m = lbModes(d['mode'], d['mods'])
    user.mode = m.value
    user.mode_vn = m.as_vn

    user.map_id = d['mid']

    if d['actionid'] == 2:
        user.info += f' +{(Mods(user.mods))!r}' # ugly and i dont care!

    if not user.restricted:
        glob.players.enqueue(writer.userStats(user))
Beispiel #3
0
async def mostPlayed(req: Request) -> Union[tuple, dict]:
    args = req.args

    uid = int(args.get('id', 0))
    username = args.get('username', None)

    m = int(args.get('mode', 0))
    r = int(args.get('rx', 0))

    limit = int(args.get('limit', 5))

    if r == 0: rx = Mods.NOMOD
    elif r == 1: rx = Mods.RELAX
    elif r == 2: rx = Mods.AUTOPILOT

    mode = lbModes(m, rx)

    if not uid and not username:
        return (400, {
            'message': 'please provide either a username or user id!'
        })

    if not uid:
        uid = await glob.db.fetchval('SELECT id FROM users WHERE name = %s',
                                     [username])

    if not (user := await glob.players.get(id=uid, sql=True)):
        return (400, {'message': "user couldn't be found!"})
Beispiel #4
0
    async def from_sql(
        cls,
        sid: int,
        table: str,
        sort: str,
        t: int,
        ensure: bool = False,
    ) -> Optional["Score"]:
        score = await glob.db.fetchrow(f"SELECT * FROM {table} WHERE id = %s", [sid])

        if not score:
            return

        self = cls()

        self.id = sid

        self.map = await Beatmap.from_md5(score["md5"])

        if not self.map:
            return  # ?

        self.user = await glob.players.get(id=score["uid"], sql=ensure)

        if not self.user:
            return self

        self.pp = score["pp"]
        self.score = score["score"]
        self.combo = score["combo"]
        self.mods = Mods(score["mods"])
        self.acc = score["acc"]
        self.n300 = score["n300"]
        self.n100 = score["n100"]
        self.n50 = score["n50"]
        self.miss = score["miss"]
        self.geki = score["geki"]
        self.katu = score["katu"]
        self.grade = score["grade"]
        self.fc = score["fc"]
        self.status = scoreStatuses(score["status"])
        self.mode = lbModes(score["mode"], self.mods)

        self.time = score["time"]
        self.passed = self.status.value != 0

        if not self.user.restricted:
            self.rank = await self.calc_lb(table, sort, t)
        else:
            self.rank = 0

        self.osuver = score["osuver"]

        return self
Beispiel #5
0
    async def from_sql(cls,
                       sid: int,
                       table: str,
                       sort: str,
                       t: int,
                       ensure: bool = False) -> Optional['Score']:
        score = await glob.db.fetchrow(f'SELECT * FROM {table} WHERE id = %s',
                                       [sid])

        if not score:
            return

        self = cls()

        self.id = sid

        self.map = await Beatmap.from_md5(score['md5'])

        if not self.map:
            return  # ?

        self.user = await glob.players.get(id=score['uid'], sql=ensure)

        if not self.user:
            return self

        self.pp = score['pp']
        self.score = score['score']
        self.combo = score['combo']
        self.mods = Mods(score['mods'])
        self.acc = score['acc']
        self.n300 = score['n300']
        self.n100 = score['n100']
        self.n50 = score['n50']
        self.miss = score['miss']
        self.geki = score['geki']
        self.katu = score['katu']
        self.grade = score['grade']
        self.fc = score['fc']
        self.status = scoreStatuses(score['status'])
        self.mode = lbModes(score['mode'].as_vn, self.mods)

        self.time = score['time']
        self.passed = self.status.value != 0

        if not self.user.restricted:
            self.rank = await self.calc_lb(table, sort, t)
        else:
            self.rank = 0

        self.osuver = score['osuver']

        return self
Beispiel #6
0
async def mostPlayed(req: Request) -> Union[tuple, dict]:
    args = req.args

    uid = int(args.get("id", 0))
    username = make_safe(args.get("username", None))

    m = int(args.get("mode", 0))
    r = int(args.get("rx", 0))

    limit = int(args.get("limit", 6))

    if not 0 <= r < 3:
        return (400, {"message": "invalid relax value (must be 0, 1 or 2)"})

    if r == 0:
        rx = Mods.NOMOD
    elif r == 1:
        rx = Mods.RELAX
    elif r == 2:
        rx = Mods.AUTOPILOT

    mode = lbModes(m, rx)

    if not uid and not username:
        return (400, {
            "message": "please provide either a username or user id!"
        })

    if not uid:
        uid = await glob.db.fetchval(
            "SELECT id FROM users WHERE safe_name = %s",
            [username],
        )

    if not (user := await glob.players.get(id=uid, sql=True)):
        return (400, {"message": "user couldn't be found!"})
Beispiel #7
0
class Score:
    __slots__ = (
        "id",
        "map",
        "user",
        "score",
        "acc",
        "n300",
        "n100",
        "n50",
        "miss",
        "geki",
        "katu",
        "grade",
        "mods",
        "readable_mods",
        "combo",
        "mode",
        "rank",
        "pp",
        "sr",
        "fc",
        "passed",
        "status",
        "time",
        "old_best",
        "osuver",
        "ur",
    )

    def __init__(self) -> None:
        self.id: Optional[int] = None
        self.map: Optional[Beatmap] = None
        self.user: Optional[Player] = None

        self.score: Optional[int] = None
        self.acc: Optional[float] = None
        self.n300: Optional[int] = None
        self.n100: Optional[int] = None
        self.n50: Optional[int] = None
        self.miss: Optional[int] = None
        self.geki: Optional[int] = None
        self.katu: Optional[int] = None
        self.grade: Optional[Grade] = None
        self.mods: Optional[Mods] = None
        self.readable_mods: Optional[str] = None
        self.combo: Optional[int] = None
        self.mode: Optional[osuModes] = None

        self.rank: Optional[int] = None
        self.pp: Optional[float] = None
        self.sr: Optional[float] = None

        self.fc: Optional[bool] = None
        self.passed: Optional[bool] = None
        self.status: Optional[scoreStatuses] = None
        self.time: Optional[int] = None

        self.old_best: Optional[Score] = None

        self.osuver: Optional[float] = None
        self.ur: Optional[float] = None

    async def format(self) -> str:
        msg = (
            f"{self.user.name} | {self.map.name} +{self.readable_mods} {self.acc:.2f}% "
            f'{"FC" if not self.miss else f"{self.miss}xMiss"} {self.pp:,.0f}pp'
        )

        if self.miss:
            fc_score = copy.copy(self)

            fc_score.fc = True
            fc_score.combo = 0  # oppai will take max combo
            pp, _ = await fc_score.calc_pp(self.mode.as_vn)

            msg += f" (~{round(pp):,}pp for FC)"

        if self.mode.value == 0 and self.ur:
            msg += f" | {self.ur:.2f} (cv)UR"

        return msg

    @classmethod
    async def from_sql(
        cls,
        sid: int,
        table: str,
        sort: str,
        t: int,
        ensure: bool = False,
    ) -> Optional["Score"]:
        score = await glob.db.fetchrow(f"SELECT * FROM {table} WHERE id = %s", [sid])

        if not score:
            return

        self = cls()

        self.id = sid

        self.map = await Beatmap.from_md5(score["md5"])

        if not self.map:
            return  # ?

        self.user = await glob.players.get(id=score["uid"], sql=ensure)

        if not self.user:
            return self

        self.pp = score["pp"]
        self.score = score["score"]
        self.combo = score["combo"]
        self.mods = Mods(score["mods"])
        self.acc = score["acc"]
        self.n300 = score["n300"]
        self.n100 = score["n100"]
        self.n50 = score["n50"]
        self.miss = score["miss"]
        self.geki = score["geki"]
        self.katu = score["katu"]
        self.grade = score["grade"]
        self.fc = score["fc"]
        self.status = scoreStatuses(score["status"])
        self.mode = lbModes(score["mode"], self.mods)

        self.time = score["time"]
        self.passed = self.status.value != 0

        if not self.user.restricted:
            self.rank = await self.calc_lb(table, sort, t)
        else:
            self.rank = 0

        self.osuver = score["osuver"]

        return self

    @classmethod
    async def from_submission(
        cls,
        base: str,
        iv: str,
        pw: str,
        ver: str,
    ) -> Optional["Score"]:
        rijndael = RijndaelCbc(  # much better f**k one liners
            key=f"osu!-scoreburgr---------{ver}".encode(),
            iv=b64decode(iv),
            padding=Pkcs7Padding(32),
            block_size=32,
        )

        data = rijndael.decrypt(b64decode(base)).decode().split(":")

        self = cls()

        self.map = await Beatmap.from_md5(data[0])

        if (u := await glob.players.get(name=data[1].rstrip())) and u.pw == pw:
            self.user = u

        if not self.user:
            return self  # even if user isnt found, may be related to connection and we want to tell the client to retry

        if not self.map:
            return  # ??

        # i wanted to make everything be set in the same order as init but some require all score info to exist first so sadly not :c
        self.score = int(data[9])
        self.n300 = int(data[3])
        self.n100 = int(data[4])
        self.n50 = int(data[5])
        self.miss = int(data[8])
        self.geki = int(data[6])
        self.katu = int(data[7])
        self.mods = Mods(int(data[13]))
        self.readable_mods = repr(Mods(int(data[13])))
        self.combo = int(data[10])
        self.mode = lbModes(int(data[15]), self.mods)

        self.fc = data[11] == "True"  # WHY IS OSU GIVING STRING FOR BOOL!!!!!!
        self.passed = data[14] == "True"  # AGAIN OSU WHY!!!!
        self.time = round(time.time())  # have to add round cast cus it gives float smh

        self.grade = data[12] if self.passed else "F"

        await self.calc_info()
        self.pp, self.sr = await self.calc_pp(self.mode.as_vn)
        await self.score_order()

        if self.user.restricted:
            self.rank = 0

        self.osuver = float(re.sub("[^0-9]", "", ver))  # lol

        return self
Beispiel #8
0
                   f'{_map["status"]}|{"|".join(grades)}')

    return '\n'.join(ret).encode()


@web.route("/web/osu-osz2-getscores.php")
async def getMapScores(request: Request) -> bytes:
    args = request.args
    if not await auth(args['us'], args['ha'], request):
        return b''

    if (md5 := args['c']) in glob.cache['unsub']:
        return b'-1|false'  # tell client map is unsub xd

    mods = int(args['mods'])
    mode = lbModes(int(args['m']), mods)
    lbm = int(args['v'])

    player = request.extras.get('player')

    if mode.value != player.mode or mods != player.mods:
        player.mode = mode.value
        player.mode_vn = mode.as_vn
        player.mods = mods

        if not player.restricted:
            glob.players.enqueue(writer.userStats(player))

    bmap = await Beatmap.from_md5(md5)

    if not bmap:
Beispiel #9
0
async def getLb(request: Request) -> list:
    args = request.args

    mode = int(args.get("mode", 0))
    rx = int(args.get("rx", 0))

    search = make_safe(args.get("u", None))

    limit = int(args.get("limit", 50))
    page = int(args.get("p", 0))

    country = args.get("country", None)

    if rx == 0:
        rx = Mods.NOMOD
    elif rx == 1:
        rx = Mods.RELAX
    elif rx == 2:
        rx = Mods.AUTOPILOT

    lb_mode = lbModes(mode, rx)
    lb_str = f"asahi:leaderboard:{lb_mode.name}"

    if country:
        lb_str += f":{country.upper()}"

    lb = [int(u) for u in await glob.redis.zrevrangebyscore(lb_str)]

    # limit amount of users to return
    lb = lb[:limit]

    if page:
        offset = limit * page  # ?
        lb = lb[offset:]

    ret = []

    # TODO: clean this?

    if not search:
        for rank, uid in enumerate(lb):
            info = await glob.db.fetchrow(
                "SELECT users.name, users.country, stats.pp_{0} pp, stats.acc_{0} acc, stats.pc_{0} pc FROM users "
                "LEFT OUTER JOIN stats ON stats.id = users.id WHERE users.id = %s"
                .format(lb_mode.name, ),
                [uid],
            )

            db_grades = await glob.db.fetchrow(
                'SELECT SUM(grade IN ("X", "XH")) AS ss, '
                'SUM(grade IN ("S", "SH")) AS s, '
                'SUM(grade = "A") AS a FROM {0} WHERE uid = %s AND mode = %s'.
                format(lb_mode.table, ),
                [uid, mode],
            )

            ret.append(
                {
                    "rank": rank + 1,
                    "userid": uid,
                    "name": info["name"],
                    "country": info["country"],
                    "pp": info["pp"],
                    "acc": info["acc"],
                    "playcount": info["pc"],
                    "grades":
                    {key: int(val or 0)
                     for key, val in db_grades.items()},
                }, )

        return ret

    users = await glob.db.fetch(
        f"SELECT users.name, users.id, users.country, stats.pp_{lb_mode.name} pp, stats.acc_{lb_mode.name} acc, stats.pc_{lb_mode.name} pc "
        f"FROM users LEFT OUTER JOIN stats ON stats.id = users.id WHERE users.safe_name LIKE %s",
        [f"{search}%"],
    )

    for info in users:
        if info["id"] not in lb:
            continue

        db_grades = await glob.db.fetchrow(
            'SELECT SUM(grade IN ("SS", "SSH")) AS ss, '
            'SUM(grade IN ("S", "SH")) AS s, '
            'SUM(grade = "A") AS a FROM {0} WHERE uid = %s AND mode = %s'.
            format(lb_mode.table, ),
            [info["id"], mode],
        )

        ret.append(
            {
                "rank": lb.index(info["id"]) + 1,
                "userid": info["id"],
                "name": info["name"],
                "country": info["country"],
                "pp": info["pp"],
                "acc": info["acc"],
                "playcount": info["pc"],
                "grades": {key: int(val)
                           for key, val in db_grades.items()},
            }, )

    return ret
Beispiel #10
0
        )

    if not (user := await glob.players.get(id=id, sql=True)):
        return (400, {"message": "user couldn't be found!"})

    if user.priv & Privileges.Disallowed:
        return (400, {"message": "user is restricted/banned!"})

    if rx == 0:
        rx = Mods.NOMOD
    elif rx == 1:
        rx = Mods.RELAX
    elif rx == 2:
        rx = Mods.AUTOPILOT

    mode = lbModes(m, rx)

    info = {
        "id": user.id,
        "name": user.name,
        "country": user.country_iso,
        "priv": user.priv,
        "clan": {
            "id": user.clan.id,
            "name": user.clan.name,
            "tag": user.clan.tag
        } if user.clan else None,
    }

    return {"info": info, "stats": user.stats[mode.value]}
Beispiel #11
0
class Score:
    __slots__ = ('id', 'map', 'user', 'score', 'acc', 'n300', 'n100', 'n50',
                 'miss', 'geki', 'katu', 'grade', 'mods', 'readable_mods',
                 'combo', 'mode', 'rank', 'pp', 'sr', 'fc', 'passed', 'status',
                 'time', 'old_best', 'osuver', 'ur')

    def __init__(self) -> None:
        self.id: Optional[int] = None
        self.map: Optional[Beatmap] = None
        self.user: Optional[Player] = None

        self.score: Optional[int] = None
        self.acc: Optional[float] = None
        self.n300: Optional[int] = None
        self.n100: Optional[int] = None
        self.n50: Optional[int] = None
        self.miss: Optional[int] = None
        self.geki: Optional[int] = None
        self.katu: Optional[int] = None
        self.grade: Optional[Grade] = None
        self.mods: Optional[Mods] = None
        self.readable_mods: Optional[str] = None
        self.combo: Optional[int] = None
        self.mode: Optional[osuModes] = None

        self.rank: Optional[int] = None
        self.pp: Optional[float] = None
        self.sr: Optional[float] = None

        self.fc: Optional[bool] = None
        self.passed: Optional[bool] = None
        self.status: Optional[scoreStatuses] = None
        self.time: Optional[int] = None

        self.old_best: Optional[Score] = None

        self.osuver: Optional[int] = None
        self.ur: Optional[float] = None

    async def format(self) -> str:
        msg = (
            f'{self.user.name} | {self.map.name} +{self.readable_mods} {self.acc:.2f}% '
            f'{"FC" if not self.miss else f"{self.miss}xMiss"} {self.pp:,.0f}pp'
        )

        if self.miss:
            fc_score = copy.copy(self)

            fc_score.fc = True
            fc_score.combo = 0  # oppai will take max combo
            pp, _ = await fc_score.calc_pp(self.mode.as_vn)

            msg += f' (~{round(pp):,}pp for FC)'

        if self.mode.value == 0 and self.ur:
            msg += f' | {self.ur:.2f} (cv)UR'

        return msg

    @classmethod
    async def from_sql(cls,
                       sid: int,
                       table: str,
                       sort: str,
                       t: int,
                       ensure: bool = False) -> Optional['Score']:
        score = await glob.db.fetchrow(f'SELECT * FROM {table} WHERE id = %s',
                                       [sid])

        if not score:
            return

        self = cls()

        self.id = sid

        self.map = await Beatmap.from_md5(score['md5'])

        if not self.map:
            return  # ?

        self.user = await glob.players.get(id=score['uid'], sql=ensure)

        if not self.user:
            return self

        self.pp = score['pp']
        self.score = score['score']
        self.combo = score['combo']
        self.mods = Mods(score['mods'])
        self.acc = score['acc']
        self.n300 = score['n300']
        self.n100 = score['n100']
        self.n50 = score['n50']
        self.miss = score['miss']
        self.geki = score['geki']
        self.katu = score['katu']
        self.grade = score['grade']
        self.fc = score['fc']
        self.status = scoreStatuses(score['status'])
        self.mode = lbModes(score['mode'].as_vn, self.mods)

        self.time = score['time']
        self.passed = self.status.value != 0

        if not self.user.restricted:
            self.rank = await self.calc_lb(table, sort, t)
        else:
            self.rank = 0

        self.osuver = score['osuver']

        return self

    @classmethod
    async def from_submission(cls, base: str, iv: str, pw: str,
                              ver: str) -> Optional['Score']:
        rijndael = RijndaelCbc(  # much better f**k one liners
            key=f'osu!-scoreburgr---------{ver}',
            iv=b64decode(iv),
            padding=Pkcs7Padding(32),
            block_size=32)

        data = rijndael.decrypt(b64decode(base)).decode().split(':')

        self = cls()

        self.map = await Beatmap.from_md5(data[0])

        if (u := await glob.players.get(name=data[1].rstrip())) and u.pw == pw:
            self.user = u

        if not self.user:
            return self  # even if user isnt found, may be related to connection and we want to tell the client to retry

        if not self.map:
            return  # ??

        # i wanted to make everything be set in the same order as init but some require all score info to exist first so sadly not :c
        self.score = int(data[9])
        self.n300 = int(data[3])
        self.n100 = int(data[4])
        self.n50 = int(data[5])
        self.miss = int(data[8])
        self.geki = int(data[6])
        self.katu = int(data[7])
        self.mods = Mods(int(data[13]))
        self.readable_mods = repr(Mods(int(data[13])))
        self.combo = int(data[10])
        self.mode = lbModes(int(data[15]), self.mods)

        self.fc = data[11] == 'True'  # WHY IS OSU GIVING STRING FOR BOOL!!!!!!
        self.passed = data[14] == 'True'  # AGAIN OSU WHY!!!!
        self.time = round(
            time.time())  # have to add round cast cus it gives float smh

        self.grade = data[12] if self.passed else 'F'

        await self.calc_info()
        self.pp, self.sr = await self.calc_pp(self.mode.as_vn)
        await self.score_order()

        if self.user.restricted:
            self.rank = 0

        self.osuver = float(re.sub("[^0-9]", "", ver))  # lol

        return self
Beispiel #12
0
        if user.priv & Privileges.Disallowed:
            return await ctx.send("This user is banned/restricted!")

        m = 0

        if "-m" in args:
            m = int(args[args.index("-m") + 1])

        if "-rx" in args:
            rx = Mods.RELAX
        elif "-ap" in args:
            rx = Mods.AUTOPILOT
        else:
            rx = Mods.NOMOD

        mode = lbModes(m, rx)
        stats = user.stats[mode.value]

        embed = Embed(title="")
        embed.set_author(
            name=
            f"{mode!r} profile for {user.full_name} - {stats.pp}pp (#{stats.rank} // {user.country_iso.upper()}#{stats.country_rank})",
            url=f"https://{glob.config.domain}/u/{user.id}",
            icon_url=f"https://countryflags.io/{user.country_iso}/flat/64.png",
        )
        embed.set_thumbnail(url=f"https://a.{glob.config.domain}/{user.id}")

        # TODO: finish embed lol
        return await ctx.send(embed=embed)

Beispiel #13
0
async def getLb(request: Request) -> list:
    args = request.args

    mode = int(args.get('mode', 0))
    rx = int(args.get('rx', 0))

    search = args.get('u', None)

    limit = int(args.get('limit', 50))
    page = int(args.get('p', 0))

    country = args.get('country', None)

    if rx == 0: rx = Mods.NOMOD
    elif rx == 1: rx = Mods.RELAX
    elif rx == 2: rx = Mods.AUTOPILOT

    lb_mode = lbModes(mode, rx)
    lb_str = f'asahi:leaderboard:{lb_mode.name}'

    if country:
        lb_str += f':{country.upper()}'

    lb = [int(u) for u in await glob.redis.zrangebyscore(lb_str)]
    lb.reverse()  # redis returns backwards??

    # limit amount of users to return
    lb = lb[:limit]

    if page:
        offset = limit * page  # ?
        lb = lb[offset:]

    ret = []

    # TODO: clean this?

    if not search:
        for rank, uid in enumerate(lb):
            info = await glob.db.fetchrow(
                'SELECT users.name, users.country, stats.pp_{0} pp, stats.acc_{0} acc, stats.pc_{0} pc FROM users '
                'LEFT OUTER JOIN stats ON stats.id = users.id WHERE users.id = %s'
                .format(lb_mode.name), [uid])

            db_grades = await glob.db.fetchrow(
                'SELECT SUM(grade IN ("SS", "SSH")) AS ss, '
                'SUM(grade IN ("S", "SH")) AS s, '
                'SUM(grade = "A") AS a FROM {0} WHERE uid = %s AND mode = %s'.
                format(lb_mode.table), [uid, mode])

            ret.append({
                'rank': rank + 1,
                'userid': uid,
                'name': info['name'],
                'country': info['country'],
                'pp': info['pp'],
                'acc': info['acc'],
                'playcount': info['pc'],
                'grades': {key: int(val)
                           for key, val in db_grades.items()}
            })

        return ret

    users = await glob.db.fetch(
        f'SELECT users.name, users.id, users.country, stats.pp_{lb_mode.name} pp, stats.acc_{lb_mode.name} acc, stats.pc_{lb_mode.name} pc '
        f'FROM users LEFT OUTER JOIN stats ON stats.id = users.id WHERE users.name LIKE %s',
        [f'{search}%'])

    for info in users:
        if info['id'] not in lb:
            continue

        db_grades = await glob.db.fetchrow(
            'SELECT SUM(grade IN ("SS", "SSH")) AS ss, '
            'SUM(grade IN ("S", "SH")) AS s, '
            'SUM(grade = "A") AS a FROM {0} WHERE uid = %s AND mode = %s'.
            format(lb_mode.table), [info['id'], mode])

        ret.append({
            'rank': lb.index(info['id']) + 1,
            'userid': info['id'],
            'name': info['name'],
            'country': info['country'],
            'pp': info['pp'],
            'acc': info['acc'],
            'playcount': info['pc'],
            'grades': {key: int(val)
                       for key, val in db_grades.items()}
        })

    return ret
Beispiel #14
0
            f'{_map["status"]}|{"|".join(grades)}', )

    return "\n".join(ret).encode()


@web.route("/web/osu-osz2-getscores.php")
async def getMapScores(request: Request) -> bytes:
    args = request.args
    if not await auth(args["us"], args["ha"], request):
        return b""

    if (md5 := args["c"]) in glob.cache["unsub"]:
        return b"-1|false"  # tell client map is unsub xd

    mods = int(args["mods"])
    mode = lbModes(int(args["m"]), mods)
    lbm = int(args["v"])

    player = request.extras["player"]

    if mode.value != player.mode or mods != player.mods:
        player.mode = mode.value
        player.mode_vn = mode.as_vn
        player.mods = mods

        if not player.restricted:
            glob.players.enqueue(writer.userStats(player))

    bmap = await Beatmap.from_md5(md5)

    if not bmap: